Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e3958f09e | ||
|
|
2dbd4cc343 | ||
|
|
e28dc39a68 | ||
|
|
7b8c7acbad | ||
|
|
56b3231f92 | ||
|
|
7084fb7025 | ||
|
|
7f5b787cb9 | ||
|
|
086e9b0610 | ||
|
|
600535d52c | ||
|
|
57c3a58994 | ||
|
|
210b265693 | ||
|
|
33bb983283 | ||
|
|
3c73b8ccb3 | ||
|
|
4acf401031 | ||
|
|
7666d2a241 | ||
|
|
201ec69b11 | ||
|
|
5e018ddbd8 | ||
|
|
81563056e0 | ||
|
|
22880c71c6 | ||
|
|
4f288f4e24 | ||
|
|
3d4e6e3918 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
obj
|
obj
|
||||||
lib
|
lib
|
||||||
|
*.o
|
||||||
*.a
|
*.a
|
||||||
*.so
|
*.so
|
||||||
*~
|
*~
|
||||||
|
|||||||
12
Makefile
12
Makefile
@@ -1,10 +1,9 @@
|
|||||||
|
|
||||||
AR ?= $(CROSS)ar
|
AR ?= $(CROSS)ar
|
||||||
CXX ?= $(CROSS)g++
|
CXX ?= $(CROSS)g++
|
||||||
|
|
||||||
UPDFPARSERLIB = ./lib/updfparser/libupdfparser.a
|
UPDFPARSERLIB = ./lib/updfparser/libupdfparser.a
|
||||||
|
|
||||||
CXXFLAGS=-Wall -fPIC -I./include -I./lib -I./lib/pugixml/src/ -I./lib/updfparser/include
|
CXXFLAGS=-Wall -fPIC -I./include -I./lib/pugixml/src/ -I./lib/updfparser/include
|
||||||
LDFLAGS = $(UPDFPARSERLIB)
|
LDFLAGS = $(UPDFPARSERLIB)
|
||||||
|
|
||||||
BUILD_STATIC ?= 0
|
BUILD_STATIC ?= 0
|
||||||
@@ -24,11 +23,15 @@ endif
|
|||||||
|
|
||||||
|
|
||||||
ifneq ($(DEBUG),)
|
ifneq ($(DEBUG),)
|
||||||
CXXFLAGS += -ggdb -O0
|
CXXFLAGS += -ggdb -O0 -DDEBUG
|
||||||
else
|
else
|
||||||
CXXFLAGS += -O2
|
CXXFLAGS += -O2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq ($(STATIC_NONCE),)
|
||||||
|
CXXFLAGS += -DSTATIC_NONCE=1
|
||||||
|
endif
|
||||||
|
|
||||||
SRCDIR := src
|
SRCDIR := src
|
||||||
INCDIR := inc
|
INCDIR := inc
|
||||||
BUILDDIR := obj
|
BUILDDIR := obj
|
||||||
@@ -45,6 +48,9 @@ lib:
|
|||||||
mkdir lib
|
mkdir lib
|
||||||
./scripts/setup.sh
|
./scripts/setup.sh
|
||||||
|
|
||||||
|
update_lib:
|
||||||
|
./scripts/update_lib.sh
|
||||||
|
|
||||||
obj:
|
obj:
|
||||||
mkdir obj
|
mkdir obj
|
||||||
|
|
||||||
|
|||||||
23
README.md
23
README.md
@@ -35,8 +35,16 @@ Dependencies
|
|||||||
|
|
||||||
For libgourou :
|
For libgourou :
|
||||||
|
|
||||||
|
_externals_ :
|
||||||
|
|
||||||
* None
|
* None
|
||||||
|
|
||||||
|
_internals_ :
|
||||||
|
|
||||||
|
* PugiXML
|
||||||
|
* Base64
|
||||||
|
* uPDFParser
|
||||||
|
|
||||||
For utils :
|
For utils :
|
||||||
|
|
||||||
* libcurl
|
* libcurl
|
||||||
@@ -44,12 +52,18 @@ For utils :
|
|||||||
* libzip
|
* libzip
|
||||||
|
|
||||||
|
|
||||||
|
Internal libraries are automatically fetched and statically compiled during the first run.
|
||||||
|
When you update libgourou's repository, **don't forget to update internal libraries** with :
|
||||||
|
|
||||||
|
make update_lib
|
||||||
|
|
||||||
|
|
||||||
Compilation
|
Compilation
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
Use _make_ command
|
Use _make_ command
|
||||||
|
|
||||||
make [CROSS=XXX] [DEBUG=(0*|1)] [STATIC_UTILS=(0*|1)] [BUILD_UTILS=(0|1*)] [BUILD_STATIC=(0*|1)] [BUILD_SHARED=(0|1*)]
|
make [CROSS=XXX] [DEBUG=(0*|1)] [STATIC_UTILS=(0*|1)] [BUILD_UTILS=(0|1*)] [BUILD_STATIC=(0*|1)] [BUILD_SHARED=(0|1*)] [all*|clean|ultraclean|build_utils]
|
||||||
|
|
||||||
CROSS can define a cross compiler prefix (ie arm-linux-gnueabihf-)
|
CROSS can define a cross compiler prefix (ie arm-linux-gnueabihf-)
|
||||||
|
|
||||||
@@ -104,6 +118,11 @@ To return a loaned book :
|
|||||||
You can get utils full options description with -h or --help switch
|
You can get utils full options description with -h or --help switch
|
||||||
|
|
||||||
|
|
||||||
|
Docker
|
||||||
|
------
|
||||||
|
|
||||||
|
A docker image (by bcliang) is available at [https://github.com/bcliang/docker-libgourou/](https://github.com/bcliang/docker-libgourou/)
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
---------
|
---------
|
||||||
@@ -111,7 +130,6 @@ Copyright
|
|||||||
Grégory Soutadé
|
Grégory Soutadé
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
@@ -120,7 +138,6 @@ libgourou : LGPL v3 or later
|
|||||||
utils : BSD
|
utils : BSD
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Special thanks
|
Special thanks
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
|||||||
124
include/Base64.h
Normal file
124
include/Base64.h
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
#ifndef _MACARON_BASE64_H_
|
||||||
|
#define _MACARON_BASE64_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MIT License (MIT)
|
||||||
|
* Copyright (c) 2016 tomykaira
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace macaron {
|
||||||
|
|
||||||
|
class Base64 {
|
||||||
|
public:
|
||||||
|
|
||||||
|
static std::string Encode(const std::string data) {
|
||||||
|
static constexpr char sEncodingTable[] = {
|
||||||
|
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||||
|
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||||
|
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||||
|
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||||
|
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||||
|
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||||
|
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||||
|
'4', '5', '6', '7', '8', '9', '+', '/'
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t in_len = data.size();
|
||||||
|
size_t out_len = 4 * ((in_len + 2) / 3);
|
||||||
|
std::string ret(out_len, '\0');
|
||||||
|
size_t i;
|
||||||
|
char *p = const_cast<char*>(ret.c_str());
|
||||||
|
|
||||||
|
for (i = 0; i < in_len - 2; i += 3) {
|
||||||
|
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
|
||||||
|
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)];
|
||||||
|
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2) | ((int) (data[i + 2] & 0xC0) >> 6)];
|
||||||
|
*p++ = sEncodingTable[data[i + 2] & 0x3F];
|
||||||
|
}
|
||||||
|
if (i < in_len) {
|
||||||
|
*p++ = sEncodingTable[(data[i] >> 2) & 0x3F];
|
||||||
|
if (i == (in_len - 1)) {
|
||||||
|
*p++ = sEncodingTable[((data[i] & 0x3) << 4)];
|
||||||
|
*p++ = '=';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*p++ = sEncodingTable[((data[i] & 0x3) << 4) | ((int) (data[i + 1] & 0xF0) >> 4)];
|
||||||
|
*p++ = sEncodingTable[((data[i + 1] & 0xF) << 2)];
|
||||||
|
}
|
||||||
|
*p++ = '=';
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string Decode(const std::string& input, std::string& out) {
|
||||||
|
static constexpr unsigned char kDecodingTable[] = {
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
|
||||||
|
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||||
|
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
|
||||||
|
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||||
|
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
|
||||||
|
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t in_len = input.size();
|
||||||
|
if (in_len % 4 != 0) return "Input data size is not a multiple of 4";
|
||||||
|
|
||||||
|
size_t out_len = in_len / 4 * 3;
|
||||||
|
if (input[in_len - 1] == '=') out_len--;
|
||||||
|
if (input[in_len - 2] == '=') out_len--;
|
||||||
|
|
||||||
|
out.resize(out_len);
|
||||||
|
|
||||||
|
for (size_t i = 0, j = 0; i < in_len;) {
|
||||||
|
uint32_t a = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||||
|
uint32_t b = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||||
|
uint32_t c = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||||
|
uint32_t d = input[i] == '=' ? 0 & i++ : kDecodingTable[static_cast<int>(input[i++])];
|
||||||
|
|
||||||
|
uint32_t triple = (a << 3 * 6) + (b << 2 * 6) + (c << 1 * 6) + (d << 0 * 6);
|
||||||
|
|
||||||
|
if (j < out_len) out[j++] = (triple >> 2 * 8) & 0xFF;
|
||||||
|
if (j < out_len) out[j++] = (triple >> 1 * 8) & 0xFF;
|
||||||
|
if (j < out_len) out[j++] = (triple >> 0 * 8) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _MACARON_BASE64_H_ */
|
||||||
@@ -104,6 +104,13 @@ namespace gourou
|
|||||||
*/
|
*/
|
||||||
std::string toBase64();
|
std::string toBase64();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert hex string into bytes
|
||||||
|
*
|
||||||
|
* @param str Hex string
|
||||||
|
*/
|
||||||
|
static ByteArray fromHex(const std::string& str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Return a string with human readable hex encoded internal data
|
* @brief Return a string with human readable hex encoded internal data
|
||||||
*/
|
*/
|
||||||
@@ -130,7 +137,7 @@ namespace gourou
|
|||||||
void append(const std::string& str);
|
void append(const std::string& str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get internal data. Must bot be freed
|
* @brief Get internal data. Must not be freed
|
||||||
*/
|
*/
|
||||||
unsigned char* data() {return _data;}
|
unsigned char* data() {return _data;}
|
||||||
|
|
||||||
|
|||||||
@@ -47,20 +47,16 @@ namespace gourou
|
|||||||
* @param handler Digest handler
|
* @param handler Digest handler
|
||||||
* @param data Data to digest
|
* @param data Data to digest
|
||||||
* @param length Length of data
|
* @param length Length of data
|
||||||
*
|
|
||||||
* @return OK/KO
|
|
||||||
*/
|
*/
|
||||||
virtual int digestUpdate(void* handler, unsigned char* data, unsigned int length) = 0;
|
virtual void digestUpdate(void* handler, unsigned char* data, unsigned int length) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Finalize digest with remained buffered data and destroy handler
|
* @brief Finalize digest with remained buffered data and destroy handler
|
||||||
*
|
*
|
||||||
* @param handler Digest handler
|
* @param handler Digest handler
|
||||||
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
||||||
*
|
|
||||||
* @return OK/KO
|
|
||||||
*/
|
*/
|
||||||
virtual int digestFinalize(void* handler, unsigned char* digestOut) = 0;
|
virtual void digestFinalize(void* handler, unsigned char* digestOut) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Global digest function
|
* @brief Global digest function
|
||||||
@@ -69,10 +65,8 @@ namespace gourou
|
|||||||
* @param data Data to digest
|
* @param data Data to digest
|
||||||
* @param length Length of data
|
* @param length Length of data
|
||||||
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
* @param digestOut Digest result (buffer must be pre allocated with right size)
|
||||||
*
|
|
||||||
* @return OK/KO
|
|
||||||
*/
|
*/
|
||||||
virtual int digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut) = 0;
|
virtual void digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RandomInterface
|
class RandomInterface
|
||||||
@@ -111,6 +105,7 @@ namespace gourou
|
|||||||
public:
|
public:
|
||||||
enum RSA_KEY_TYPE {
|
enum RSA_KEY_TYPE {
|
||||||
RSA_KEY_PKCS12 = 0,
|
RSA_KEY_PKCS12 = 0,
|
||||||
|
RSA_KEY_PKCS8,
|
||||||
RSA_KEY_X509
|
RSA_KEY_X509
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -238,7 +233,7 @@ namespace gourou
|
|||||||
* @param dataOut Encrypted data
|
* @param dataOut Encrypted data
|
||||||
* @param dataOutLength Length of encrypted data
|
* @param dataOutLength Length of encrypted data
|
||||||
*/
|
*/
|
||||||
virtual void Encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength,
|
const unsigned char* iv, unsigned int ivLength,
|
||||||
const unsigned char* dataIn, unsigned int dataInLength,
|
const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
@@ -255,7 +250,7 @@ namespace gourou
|
|||||||
*
|
*
|
||||||
* @return AES handler
|
* @return AES handler
|
||||||
*/
|
*/
|
||||||
virtual void* EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void* encryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
||||||
|
|
||||||
@@ -268,7 +263,7 @@ namespace gourou
|
|||||||
* @param dataOut Encrypted data
|
* @param dataOut Encrypted data
|
||||||
* @param dataOutLength Length of encrypted data
|
* @param dataOutLength Length of encrypted data
|
||||||
*/
|
*/
|
||||||
virtual void EncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
virtual void encryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -279,7 +274,7 @@ namespace gourou
|
|||||||
* @param dataOut Last block of encrypted data
|
* @param dataOut Last block of encrypted data
|
||||||
* @param dataOutLength Length of encrypted data
|
* @param dataOutLength Length of encrypted data
|
||||||
*/
|
*/
|
||||||
virtual void EncryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
virtual void encryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Do decryption. If length of data is not multiple of block size, PKCS#5 padding is done
|
* @brief Do decryption. If length of data is not multiple of block size, PKCS#5 padding is done
|
||||||
@@ -295,7 +290,7 @@ namespace gourou
|
|||||||
* @param dataOut Encrypted data
|
* @param dataOut Encrypted data
|
||||||
* @param dataOutLength Length of encrypted data
|
* @param dataOutLength Length of encrypted data
|
||||||
*/
|
*/
|
||||||
virtual void Decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength,
|
const unsigned char* iv, unsigned int ivLength,
|
||||||
const unsigned char* dataIn, unsigned int dataInLength,
|
const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
@@ -312,7 +307,7 @@ namespace gourou
|
|||||||
*
|
*
|
||||||
* @return AES handler
|
* @return AES handler
|
||||||
*/
|
*/
|
||||||
virtual void* DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void* decryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
const unsigned char* iv=0, unsigned int ivLength=0) = 0;
|
||||||
|
|
||||||
@@ -325,7 +320,7 @@ namespace gourou
|
|||||||
* @param dataOut Decrypted data
|
* @param dataOut Decrypted data
|
||||||
* @param dataOutLength Length of decrypted data
|
* @param dataOutLength Length of decrypted data
|
||||||
*/
|
*/
|
||||||
virtual void DecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
virtual void decryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||||
/**
|
/**
|
||||||
* @brief Finalize decryption (decrypt last block and remove padding if it is set).
|
* @brief Finalize decryption (decrypt last block and remove padding if it is set).
|
||||||
@@ -335,7 +330,7 @@ namespace gourou
|
|||||||
* @param dataOut Last block decrypted data
|
* @param dataOut Last block decrypted data
|
||||||
* @param dataOutLength Length of decrypted data
|
* @param dataOutLength Length of decrypted data
|
||||||
*/
|
*/
|
||||||
virtual void DecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
virtual void decryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
|
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LIBGOUROU_VERSION "0.7.1"
|
#define LIBGOUROU_VERSION "0.8"
|
||||||
|
|
||||||
namespace gourou
|
namespace gourou
|
||||||
{
|
{
|
||||||
@@ -231,6 +231,7 @@ namespace gourou
|
|||||||
void buildSignInRequest(pugi::xml_document& signInRequest, const std::string& adobeID, const std::string& adobePassword, const std::string& authenticationCertificate);
|
void buildSignInRequest(pugi::xml_document& signInRequest, const std::string& adobeID, const std::string& adobePassword, const std::string& authenticationCertificate);
|
||||||
void fetchLicenseServiceCertificate(const std::string& licenseURL,
|
void fetchLicenseServiceCertificate(const std::string& licenseURL,
|
||||||
const std::string& operatorURL);
|
const std::string& operatorURL);
|
||||||
|
std::string encryptedKeyFirstPass(pugi::xml_document& rightsDoc, const std::string& encryptedKey, const std::string& keyType, ITEM_TYPE type);
|
||||||
void decryptADEPTKey(const std::string& encryptedKey, unsigned char* decryptedKey);
|
void decryptADEPTKey(const std::string& encryptedKey, unsigned char* decryptedKey);
|
||||||
void removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
void removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
||||||
void generatePDFObjectKey(int version,
|
void generatePDFObjectKey(int version,
|
||||||
|
|||||||
@@ -106,6 +106,7 @@ namespace gourou
|
|||||||
CLIENT_INVALID_PKCS12,
|
CLIENT_INVALID_PKCS12,
|
||||||
CLIENT_INVALID_CERTIFICATE,
|
CLIENT_INVALID_CERTIFICATE,
|
||||||
CLIENT_NO_PRIV_KEY,
|
CLIENT_NO_PRIV_KEY,
|
||||||
|
CLIENT_NO_PUB_KEY,
|
||||||
CLIENT_RSA_ERROR,
|
CLIENT_RSA_ERROR,
|
||||||
CLIENT_BAD_CHAINING,
|
CLIENT_BAD_CHAINING,
|
||||||
CLIENT_BAD_KEY_SIZE,
|
CLIENT_BAD_KEY_SIZE,
|
||||||
@@ -114,7 +115,10 @@ namespace gourou
|
|||||||
CLIENT_GENERIC_EXCEPTION,
|
CLIENT_GENERIC_EXCEPTION,
|
||||||
CLIENT_NETWORK_ERROR,
|
CLIENT_NETWORK_ERROR,
|
||||||
CLIENT_INVALID_PKCS8,
|
CLIENT_INVALID_PKCS8,
|
||||||
CLIENT_FILE_ERROR
|
CLIENT_FILE_ERROR,
|
||||||
|
CLIENT_OSSL_ERROR,
|
||||||
|
CLIENT_CRYPT_ERROR,
|
||||||
|
CLIENT_DIGEST_ERROR,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DRM_REMOVAL_ERROR {
|
enum DRM_REMOVAL_ERROR {
|
||||||
@@ -124,7 +128,8 @@ namespace gourou
|
|||||||
DRM_FORMAT_NOT_SUPPORTED,
|
DRM_FORMAT_NOT_SUPPORTED,
|
||||||
DRM_IN_OUT_EQUALS,
|
DRM_IN_OUT_EQUALS,
|
||||||
DRM_MISSING_PARAMETER,
|
DRM_MISSING_PARAMETER,
|
||||||
DRM_INVALID_KEY_SIZE
|
DRM_INVALID_KEY_SIZE,
|
||||||
|
DRM_ERR_ENCRYPTION_KEY_FP
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -139,7 +144,7 @@ namespace gourou
|
|||||||
std::stringstream msg;
|
std::stringstream msg;
|
||||||
msg << "Exception code : 0x" << std::setbase(16) << code << std::endl;
|
msg << "Exception code : 0x" << std::setbase(16) << code << std::endl;
|
||||||
msg << "Message : " << message << std::endl;
|
msg << "Message : " << message << std::endl;
|
||||||
if (logLevel >= DEBUG)
|
if (logLevel >= LG_LOG_DEBUG)
|
||||||
msg << "File : " << file << ":" << std::setbase(10) << line << std::endl;
|
msg << "File : " << file << ":" << std::setbase(10) << line << std::endl;
|
||||||
fullmessage = strdup(msg.str().c_str());
|
fullmessage = strdup(msg.str().c_str());
|
||||||
}
|
}
|
||||||
@@ -223,35 +228,9 @@ namespace gourou
|
|||||||
* It can throw an exception if tag does not exists
|
* It can throw an exception if tag does not exists
|
||||||
* or just return an empty value
|
* or just return an empty value
|
||||||
*/
|
*/
|
||||||
static inline std::string extractTextElem(const pugi::xml_document& doc, const char* tagName, bool throwOnNull=true)
|
static inline std::string extractTextElem(const pugi::xml_node& root, const char* tagName, bool throwOnNull=true)
|
||||||
{
|
{
|
||||||
pugi::xpath_node xpath_node = doc.select_node(tagName);
|
pugi::xpath_node xpath_node = root.select_node(tagName);
|
||||||
|
|
||||||
if (!xpath_node)
|
|
||||||
{
|
|
||||||
if (throwOnNull)
|
|
||||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
pugi::xml_node node = xpath_node.node().first_child();
|
|
||||||
|
|
||||||
if (!node)
|
|
||||||
{
|
|
||||||
if (throwOnNull)
|
|
||||||
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Text element for tag " << tagName << " not found");
|
|
||||||
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string res = node.value();
|
|
||||||
return trim(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline std::string extractTextElem(const pugi::xml_node& doc, const char* tagName, bool throwOnNull=true)
|
|
||||||
{
|
|
||||||
pugi::xpath_node xpath_node = doc.select_node(tagName);
|
|
||||||
|
|
||||||
if (!xpath_node)
|
if (!xpath_node)
|
||||||
{
|
{
|
||||||
@@ -275,6 +254,37 @@ namespace gourou
|
|||||||
return trim(res);
|
return trim(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Extract text attribute from tag in document
|
||||||
|
* It can throw an exception if attribute does not exists
|
||||||
|
* or just return an empty value
|
||||||
|
*/
|
||||||
|
static inline std::string extractTextAttribute(const pugi::xml_node& root, const char* tagName, const char* attributeName, bool throwOnNull=true)
|
||||||
|
{
|
||||||
|
pugi::xpath_node xpath_node = root.select_node(tagName);
|
||||||
|
|
||||||
|
if (!xpath_node)
|
||||||
|
{
|
||||||
|
if (throwOnNull)
|
||||||
|
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Tag " << tagName << " not found");
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
pugi::xml_attribute attr = xpath_node.node().attribute(attributeName);
|
||||||
|
|
||||||
|
if (!attr)
|
||||||
|
{
|
||||||
|
if (throwOnNull)
|
||||||
|
EXCEPTION(GOUROU_TAG_NOT_FOUND, "Attribute element " << attributeName << " for tag " << tagName << " not found");
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string res = attr.value();
|
||||||
|
return trim(res);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Append an element to root with a sub text element
|
* @brief Append an element to root with a sub text element
|
||||||
*
|
*
|
||||||
@@ -288,6 +298,29 @@ namespace gourou
|
|||||||
node.append_child(pugi::node_pcdata).set_value(value.c_str());
|
node.append_child(pugi::node_pcdata).set_value(value.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove "urn:uuid:" prefix and all '-' from uuid
|
||||||
|
* urn:uuid:9cb786e8-586a-4950-8901-fff8d2ee6025
|
||||||
|
* ->
|
||||||
|
* 9cb786e8586a49508901fff8d2ee6025
|
||||||
|
*/
|
||||||
|
static inline std::string extractIdFromUUID(const std::string& uuid)
|
||||||
|
{
|
||||||
|
unsigned int i = 0;
|
||||||
|
std::string res;
|
||||||
|
|
||||||
|
if (uuid.find("urn:uuid:") == 0)
|
||||||
|
i = 9;
|
||||||
|
|
||||||
|
for(; i<uuid.size(); i++)
|
||||||
|
{
|
||||||
|
if (uuid[i] != '-')
|
||||||
|
res += uuid[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Open a file descriptor on path. If it already exists and truncate == true, it's truncated
|
* @brief Open a file descriptor on path. If it already exists and truncate == true, it's truncated
|
||||||
*
|
*
|
||||||
@@ -413,6 +446,20 @@ namespace gourou
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void dumpBuffer(GOUROU_LOG_LEVEL level, const char* title, const unsigned char* data, unsigned int len)
|
||||||
|
{
|
||||||
|
if (gourou::logLevel < level)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("%s", title);
|
||||||
|
for(unsigned int i=0; i<len; i++)
|
||||||
|
{
|
||||||
|
if (i && !(i%16)) printf("\n");
|
||||||
|
printf("%02x ", data[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -24,16 +24,16 @@
|
|||||||
|
|
||||||
namespace gourou {
|
namespace gourou {
|
||||||
enum GOUROU_LOG_LEVEL {
|
enum GOUROU_LOG_LEVEL {
|
||||||
ERROR,
|
LG_LOG_ERROR,
|
||||||
WARN,
|
LG_LOG_WARN,
|
||||||
INFO,
|
LG_LOG_INFO,
|
||||||
DEBUG,
|
LG_LOG_DEBUG,
|
||||||
TRACE
|
LG_LOG_TRACE
|
||||||
};
|
};
|
||||||
|
|
||||||
extern GOUROU_LOG_LEVEL logLevel;
|
extern GOUROU_LOG_LEVEL logLevel;
|
||||||
|
|
||||||
#define GOUROU_LOG(__lvl, __msg) if (__lvl <= gourou::logLevel) {std::cout << __msg << std::endl << std::flush;}
|
#define GOUROU_LOG(__lvl, __msg) if (gourou::LG_LOG_##__lvl <= gourou::logLevel) {std::cout << __msg << std::endl << std::flush;}
|
||||||
#define GOUROU_LOG_FUNC() GOUROU_LOG(TRACE, __FUNCTION__ << "() @ " << __FILE__ << ":" << __LINE__)
|
#define GOUROU_LOG_FUNC() GOUROU_LOG(TRACE, __FUNCTION__ << "() @ " << __FILE__ << ":" << __LINE__)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -8,11 +8,6 @@ if [ ! -d lib/pugixml ] ; then
|
|||||||
popd
|
popd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Base64
|
|
||||||
if [ ! -d lib/base64 ] ; then
|
|
||||||
git clone https://gist.github.com/f0fd86b6c73063283afe550bc5d77594.git lib/base64
|
|
||||||
fi
|
|
||||||
|
|
||||||
# uPDFParser
|
# uPDFParser
|
||||||
if [ ! -d lib/updfparser ] ; then
|
if [ ! -d lib/updfparser ] ; then
|
||||||
git clone git://soutade.fr/updfparser.git lib/updfparser
|
git clone git://soutade.fr/updfparser.git lib/updfparser
|
||||||
|
|||||||
18
scripts/update_lib.sh
Executable file
18
scripts/update_lib.sh
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
if [ ! -d lib/pugixml -o ! -d lib/updfparser ] ; then
|
||||||
|
echo "Some libraries are missing"
|
||||||
|
echo "You must run this script at the top of libgourou working direcotry."
|
||||||
|
echo "./lib/setup.sh must be called first (make all)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Pugixml
|
||||||
|
pushd lib/pugixml
|
||||||
|
git pull origin latest
|
||||||
|
popd
|
||||||
|
|
||||||
|
# uPDFParser
|
||||||
|
pushd lib/updfparser
|
||||||
|
git pull origin master
|
||||||
|
make clean all BUILD_STATIC=1 BUILD_SHARED=0
|
||||||
@@ -17,8 +17,9 @@
|
|||||||
along with libgourou. If not, see <http://www.gnu.org/licenses/>.
|
along with libgourou. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <base64/Base64.h>
|
#include <Base64.h>
|
||||||
|
|
||||||
#include <bytearray.h>
|
#include <bytearray.h>
|
||||||
|
|
||||||
@@ -155,6 +156,47 @@ namespace gourou
|
|||||||
return macaron::Base64::Encode(std::string((char*)_data, _length));
|
return macaron::Base64::Encode(std::string((char*)_data, _length));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteArray ByteArray::fromHex(const std::string& str)
|
||||||
|
{
|
||||||
|
if (str.size() % 2)
|
||||||
|
throw std::invalid_argument("Size of hex string not multiple of 2");
|
||||||
|
|
||||||
|
ByteArray res((unsigned int)(str.size()/2));
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
unsigned char* data = res.data();
|
||||||
|
unsigned char cur, tmp;
|
||||||
|
|
||||||
|
for (i=0; i<str.size(); i+=2)
|
||||||
|
{
|
||||||
|
cur = 0;
|
||||||
|
|
||||||
|
tmp = str[i];
|
||||||
|
if (tmp >= 'a' && tmp <= 'f')
|
||||||
|
cur = (tmp - 'a' + 10) << 4;
|
||||||
|
else if (tmp >= 'A' && tmp <= 'F')
|
||||||
|
cur = (tmp - 'A' + 10) << 4;
|
||||||
|
else if (tmp >= '0' && tmp <= '9')
|
||||||
|
cur = (tmp - '0') << 4;
|
||||||
|
else
|
||||||
|
throw std::invalid_argument("Invalid character in hex string");
|
||||||
|
|
||||||
|
tmp = str[i+1];
|
||||||
|
if (tmp >= 'a' && tmp <= 'f')
|
||||||
|
cur += tmp - 'a' + 10;
|
||||||
|
else if (tmp >= 'A' && tmp <= 'F')
|
||||||
|
cur += tmp - 'A' + 10;
|
||||||
|
else if (tmp >= '0' && tmp <= '9')
|
||||||
|
cur += tmp - '0';
|
||||||
|
else
|
||||||
|
throw std::invalid_argument("Invalid character in hex string");
|
||||||
|
|
||||||
|
data[i/2] = cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
std::string ByteArray::toHex()
|
std::string ByteArray::toHex()
|
||||||
{
|
{
|
||||||
char* tmp = new char[_length*2+1];
|
char* tmp = new char[_length*2+1];
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
namespace gourou
|
namespace gourou
|
||||||
{
|
{
|
||||||
GOUROU_LOG_LEVEL logLevel = WARN;
|
GOUROU_LOG_LEVEL logLevel = LG_LOG_WARN;
|
||||||
const std::string DRMProcessor::VERSION = LIBGOUROU_VERSION;
|
const std::string DRMProcessor::VERSION = LIBGOUROU_VERSION;
|
||||||
|
|
||||||
DRMProcessor::DRMProcessor(DRMProcessorClient* client):client(client), device(0), user(0)
|
DRMProcessor::DRMProcessor(DRMProcessorClient* client):client(client), device(0), user(0)
|
||||||
@@ -89,7 +89,7 @@ namespace gourou
|
|||||||
uint16_t nlength = htons(length);
|
uint16_t nlength = htons(length);
|
||||||
char c;
|
char c;
|
||||||
|
|
||||||
if (logLevel >= TRACE)
|
if (logLevel >= LG_LOG_TRACE)
|
||||||
printf("%02x %02x ", ((uint8_t*)&nlength)[0], ((uint8_t*)&nlength)[1]);
|
printf("%02x %02x ", ((uint8_t*)&nlength)[0], ((uint8_t*)&nlength)[1]);
|
||||||
|
|
||||||
client->digestUpdate(sha_ctx, (unsigned char*)&nlength, sizeof(nlength));
|
client->digestUpdate(sha_ctx, (unsigned char*)&nlength, sizeof(nlength));
|
||||||
@@ -98,17 +98,17 @@ namespace gourou
|
|||||||
{
|
{
|
||||||
c = string[i];
|
c = string[i];
|
||||||
client->digestUpdate(sha_ctx, (unsigned char*)&c, 1);
|
client->digestUpdate(sha_ctx, (unsigned char*)&c, 1);
|
||||||
if (logLevel >= TRACE)
|
if (logLevel >= LG_LOG_TRACE)
|
||||||
printf("%c", c);
|
printf("%c", c);
|
||||||
}
|
}
|
||||||
if (logLevel >= TRACE)
|
if (logLevel >= LG_LOG_TRACE)
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessor::pushTag(void* sha_ctx, uint8_t tag)
|
void DRMProcessor::pushTag(void* sha_ctx, uint8_t tag)
|
||||||
{
|
{
|
||||||
client->digestUpdate(sha_ctx, &tag, sizeof(tag));
|
client->digestUpdate(sha_ctx, &tag, sizeof(tag));
|
||||||
if (logLevel >= TRACE)
|
if (logLevel >= LG_LOG_TRACE)
|
||||||
printf("%02x ", tag);
|
printf("%02x ", tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,14 +226,7 @@ namespace gourou
|
|||||||
|
|
||||||
client->digestFinalize(sha_ctx, sha_out);
|
client->digestFinalize(sha_ctx, sha_out);
|
||||||
|
|
||||||
if (logLevel >= DEBUG)
|
dumpBuffer(gourou::LG_LOG_DEBUG, "\nSHA OUT : ", sha_out, SHA1_LEN);
|
||||||
{
|
|
||||||
printf("\nSHA OUT : ");
|
|
||||||
for(int i=0; i<(int)SHA1_LEN; i++)
|
|
||||||
printf("%02x ", sha_out[i]);
|
|
||||||
printf("\n");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessor::signNode(pugi::xml_node& rootNode)
|
void DRMProcessor::signNode(pugi::xml_node& rootNode)
|
||||||
@@ -252,13 +245,8 @@ namespace gourou
|
|||||||
client->RSAPrivateEncrypt(privateRSAKey.data(), privateRSAKey.length(),
|
client->RSAPrivateEncrypt(privateRSAKey.data(), privateRSAKey.length(),
|
||||||
RSAInterface::RSA_KEY_PKCS12, deviceKey.toBase64().data(),
|
RSAInterface::RSA_KEY_PKCS12, deviceKey.toBase64().data(),
|
||||||
sha_out, sizeof(sha_out), res);
|
sha_out, sizeof(sha_out), res);
|
||||||
if (logLevel >= DEBUG)
|
|
||||||
{
|
dumpBuffer(gourou::LG_LOG_DEBUG, "Sig : ", res, sizeof(res));
|
||||||
printf("Sig : ");
|
|
||||||
for(int i=0; i<(int)sizeof(res); i++)
|
|
||||||
printf("%02x ", res[i]);
|
|
||||||
printf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string signature = ByteArray(res, sizeof(res)).toBase64();
|
std::string signature = ByteArray(res, sizeof(res)).toBase64();
|
||||||
appendTextElem(rootNode, "adept:signature", signature);
|
appendTextElem(rootNode, "adept:signature", signature);
|
||||||
@@ -282,7 +270,11 @@ namespace gourou
|
|||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
gettimeofday(&tv, 0);
|
gettimeofday(&tv, 0);
|
||||||
uint32_t nonce32[2] = {0x6f046000, 0x388a};
|
uint32_t nonce32[2] = {0x6f046000, 0x388a};
|
||||||
|
#ifdef STATIC_NONCE
|
||||||
|
uint64_t bigtime = 0xAA001122BBCCAAULL;
|
||||||
|
#else
|
||||||
uint64_t bigtime = tv.tv_sec*1000;
|
uint64_t bigtime = tv.tv_sec*1000;
|
||||||
|
#endif
|
||||||
nonce32[0] += (bigtime & 0xFFFFFFFF) + (tv.tv_usec/1000);
|
nonce32[0] += (bigtime & 0xFFFFFFFF) + (tv.tv_usec/1000);
|
||||||
nonce32[1] += ((bigtime >> 32) & 0xFFFFFFFF);
|
nonce32[1] += ((bigtime >> 32) & 0xFFFFFFFF);
|
||||||
|
|
||||||
@@ -877,7 +869,7 @@ namespace gourou
|
|||||||
// Generate IV in front
|
// Generate IV in front
|
||||||
client->randBytes(encrypted_data, 16);
|
client->randBytes(encrypted_data, 16);
|
||||||
|
|
||||||
client->Encrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
|
client->encrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
|
||||||
deviceKey, 16, encrypted_data, 16,
|
deviceKey, 16, encrypted_data, 16,
|
||||||
data, len,
|
data, len,
|
||||||
encrypted_data+16, &outLen);
|
encrypted_data+16, &outLen);
|
||||||
@@ -896,7 +888,7 @@ namespace gourou
|
|||||||
const unsigned char* deviceKey = device->getDeviceKey();
|
const unsigned char* deviceKey = device->getDeviceKey();
|
||||||
unsigned char* decrypted_data = new unsigned char[len-16];
|
unsigned char* decrypted_data = new unsigned char[len-16];
|
||||||
|
|
||||||
client->Decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
|
client->decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
|
||||||
deviceKey, 16, data, 16,
|
deviceKey, 16, data, 16,
|
||||||
data+16, len-16,
|
data+16, len-16,
|
||||||
decrypted_data, &outLen);
|
decrypted_data, &outLen);
|
||||||
@@ -959,22 +951,102 @@ namespace gourou
|
|||||||
|
|
||||||
ByteArray arrayEncryptedKey = ByteArray::fromBase64(encryptedKey);
|
ByteArray arrayEncryptedKey = ByteArray::fromBase64(encryptedKey);
|
||||||
|
|
||||||
|
|
||||||
std::string privateKeyData = user->getPrivateLicenseKey();
|
std::string privateKeyData = user->getPrivateLicenseKey();
|
||||||
ByteArray privateRSAKey = ByteArray::fromBase64(privateKeyData);
|
ByteArray privateRSAKey = ByteArray::fromBase64(privateKeyData);
|
||||||
|
|
||||||
ByteArray deviceKey(device->getDeviceKey(), Device::DEVICE_KEY_SIZE);
|
dumpBuffer(gourou::LG_LOG_DEBUG, "To decrypt : ", arrayEncryptedKey.data(), arrayEncryptedKey.length());
|
||||||
std::string pkcs12 = user->getPKCS12();
|
|
||||||
|
|
||||||
client->RSAPrivateDecrypt(privateRSAKey.data(), privateRSAKey.length(),
|
client->RSAPrivateDecrypt(privateRSAKey.data(), privateRSAKey.length(),
|
||||||
RSAInterface::RSA_KEY_PKCS12, deviceKey.toBase64().data(),
|
RSAInterface::RSA_KEY_PKCS8, "",
|
||||||
arrayEncryptedKey.data(), arrayEncryptedKey.length(), decryptedKey);
|
arrayEncryptedKey.data(), arrayEncryptedKey.length(), decryptedKey);
|
||||||
|
|
||||||
if (decryptedKey[0] != 0x00 || decryptedKey[1] != 0x02 ||
|
|
||||||
decryptedKey[RSA_KEY_SIZE-16-1] != 0x00)
|
|
||||||
EXCEPTION(DRM_ERR_ENCRYPTION_KEY, "Unable to retrieve encryption key");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* RSA Key can be over encrypted with AES128-CBC if keyType attribute is set
|
||||||
|
* For EPUB, Key = SHA256(keyType)[14:22] || SHA256(keyType)[7:13]
|
||||||
|
* For PDF, Key = SHA256(keyType)[6:19] || SHA256(keyType)[3:6]
|
||||||
|
* IV = DeviceID ^ FulfillmentId ^ VoucherId
|
||||||
|
*
|
||||||
|
* @return Base64 encoded decrypted key
|
||||||
|
*/
|
||||||
|
std::string DRMProcessor::encryptedKeyFirstPass(pugi::xml_document& rightsDoc, const std::string& encryptedKey, const std::string& keyType, ITEM_TYPE type)
|
||||||
|
{
|
||||||
|
unsigned char digest[32], key[16], iv[16];
|
||||||
|
unsigned int dataOutLength;
|
||||||
|
std::string id;
|
||||||
|
|
||||||
|
client->digest("SHA256", (unsigned char*)keyType.c_str(), keyType.size(), digest);
|
||||||
|
|
||||||
|
dumpBuffer(gourou::LG_LOG_DEBUG, "SHA of KeyType : ", digest, sizeof(digest));
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case EPUB:
|
||||||
|
memcpy(key, &digest[14], 9);
|
||||||
|
memcpy(&key[9], &digest[7], 7);
|
||||||
|
break;
|
||||||
|
case PDF:
|
||||||
|
memcpy(key, &digest[6], 13);
|
||||||
|
memcpy(&key[13], &digest[3], 3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = extractTextElem(rightsDoc, "/adept:rights/licenseToken/device");
|
||||||
|
if (id == "")
|
||||||
|
EXCEPTION(DRM_ERR_ENCRYPTION_KEY_FP, "Device id not found in rights.xml");
|
||||||
|
ByteArray deviceId = ByteArray::fromHex(extractIdFromUUID(id));
|
||||||
|
unsigned char* _deviceId = deviceId.data();
|
||||||
|
|
||||||
|
id = extractTextElem(rightsDoc, "/adept:rights/licenseToken/fulfillment");
|
||||||
|
if (id == "")
|
||||||
|
EXCEPTION(DRM_ERR_ENCRYPTION_KEY_FP, "Fulfillment id not found in rights.xml");
|
||||||
|
ByteArray fulfillmentId = ByteArray::fromHex(extractIdFromUUID(id));
|
||||||
|
unsigned char* _fulfillmentId = fulfillmentId.data();
|
||||||
|
|
||||||
|
id = extractTextElem(rightsDoc, "/adept:rights/licenseToken/voucher");
|
||||||
|
if (id == "")
|
||||||
|
EXCEPTION(DRM_ERR_ENCRYPTION_KEY_FP, "Voucher id not found in rights.xml");
|
||||||
|
ByteArray voucherId = ByteArray::fromHex(extractIdFromUUID(id));
|
||||||
|
unsigned char* _voucherId = voucherId.data();
|
||||||
|
|
||||||
|
if (deviceId.size() < sizeof(iv) || fulfillmentId.size() < sizeof(iv) || voucherId.size() < sizeof(iv))
|
||||||
|
EXCEPTION(DRM_ERR_ENCRYPTION_KEY_FP, "One id has a bad length");
|
||||||
|
|
||||||
|
for(unsigned int i=0; i<sizeof(iv); i++)
|
||||||
|
iv[i] = _deviceId[i] ^ _fulfillmentId[i] ^ _voucherId[i];
|
||||||
|
|
||||||
|
ByteArray arrayEncryptedKey = ByteArray::fromBase64(encryptedKey);
|
||||||
|
|
||||||
|
dumpBuffer(gourou::LG_LOG_DEBUG, "First pass key : ", key, sizeof(key));
|
||||||
|
dumpBuffer(gourou::LG_LOG_DEBUG, "First pass IV : ", iv, sizeof(iv));
|
||||||
|
|
||||||
|
unsigned char* clearRSAKey = new unsigned char[arrayEncryptedKey.size()];
|
||||||
|
|
||||||
|
client->decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
|
||||||
|
(const unsigned char*)key, (unsigned int)sizeof(key),
|
||||||
|
(const unsigned char*)iv, (unsigned int)sizeof(iv),
|
||||||
|
(const unsigned char*)arrayEncryptedKey.data(), arrayEncryptedKey.size(),
|
||||||
|
(unsigned char*)clearRSAKey, &dataOutLength);
|
||||||
|
|
||||||
|
dumpBuffer(gourou::LG_LOG_DEBUG, "\nDecrypted key : ", clearRSAKey, dataOutLength);
|
||||||
|
|
||||||
|
/* Last block could be 0x10*16 which is OpenSSL padding, remove it if it's the case */
|
||||||
|
bool skipLastLine = true;
|
||||||
|
for(unsigned int i=dataOutLength-16; i<dataOutLength; i++)
|
||||||
|
{
|
||||||
|
if (clearRSAKey[i] != 0x10)
|
||||||
|
{
|
||||||
|
skipLastLine = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteArray res(clearRSAKey, (skipLastLine)?dataOutLength-16:dataOutLength);
|
||||||
|
|
||||||
|
delete[] clearRSAKey;
|
||||||
|
|
||||||
|
return res.toBase64();
|
||||||
|
}
|
||||||
|
|
||||||
void DRMProcessor::removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut,
|
void DRMProcessor::removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut,
|
||||||
const unsigned char* encryptionKey, unsigned encryptionKeySize)
|
const unsigned char* encryptionKey, unsigned encryptionKeySize)
|
||||||
@@ -991,7 +1063,20 @@ namespace gourou
|
|||||||
unsigned char decryptedKey[RSA_KEY_SIZE];
|
unsigned char decryptedKey[RSA_KEY_SIZE];
|
||||||
|
|
||||||
if (!encryptionKey)
|
if (!encryptionKey)
|
||||||
|
{
|
||||||
|
std::string keyType = extractTextAttribute(rightsDoc, "/adept:rights/licenseToken/encryptedKey", "keyType", false);
|
||||||
|
|
||||||
|
if (keyType != "")
|
||||||
|
encryptedKey = encryptedKeyFirstPass(rightsDoc, encryptedKey, keyType, EPUB);
|
||||||
|
|
||||||
decryptADEPTKey(encryptedKey, decryptedKey);
|
decryptADEPTKey(encryptedKey, decryptedKey);
|
||||||
|
|
||||||
|
dumpBuffer(gourou::LG_LOG_DEBUG, "Decrypted : ", decryptedKey, RSA_KEY_SIZE);
|
||||||
|
|
||||||
|
if (decryptedKey[0] != 0x00 || decryptedKey[1] != 0x02 ||
|
||||||
|
decryptedKey[RSA_KEY_SIZE-16-1] != 0x00)
|
||||||
|
EXCEPTION(DRM_ERR_ENCRYPTION_KEY, "Unable to retrieve encryption key");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GOUROU_LOG(DEBUG, "Use provided encryption key");
|
GOUROU_LOG(DEBUG, "Use provided encryption key");
|
||||||
@@ -1037,7 +1122,7 @@ namespace gourou
|
|||||||
gourou::ByteArray inflateData(true);
|
gourou::ByteArray inflateData(true);
|
||||||
unsigned int dataOutLength;
|
unsigned int dataOutLength;
|
||||||
|
|
||||||
client->Decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
|
client->decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
|
||||||
decryptedKey+sizeof(decryptedKey)-16, 16, /* Key */
|
decryptedKey+sizeof(decryptedKey)-16, 16, /* Key */
|
||||||
_data, 16, /* IV */
|
_data, 16, /* IV */
|
||||||
&_data[16], zipData.length()-16,
|
&_data[16], zipData.length()-16,
|
||||||
@@ -1173,7 +1258,20 @@ namespace gourou
|
|||||||
std::string encryptedKey = extractTextElem(rightsDoc, "/adept:rights/licenseToken/encryptedKey");
|
std::string encryptedKey = extractTextElem(rightsDoc, "/adept:rights/licenseToken/encryptedKey");
|
||||||
|
|
||||||
if (!encryptionKey)
|
if (!encryptionKey)
|
||||||
|
{
|
||||||
|
std::string keyType = extractTextAttribute(rightsDoc, "/adept:rights/licenseToken/encryptedKey", "keyType", false);
|
||||||
|
|
||||||
|
if (keyType != "")
|
||||||
|
encryptedKey = encryptedKeyFirstPass(rightsDoc, encryptedKey, keyType, PDF);
|
||||||
|
|
||||||
decryptADEPTKey(encryptedKey, decryptedKey);
|
decryptADEPTKey(encryptedKey, decryptedKey);
|
||||||
|
|
||||||
|
dumpBuffer(gourou::LG_LOG_DEBUG, "Decrypted : ", decryptedKey, RSA_KEY_SIZE);
|
||||||
|
|
||||||
|
if (decryptedKey[0] != 0x00 || decryptedKey[1] != 0x02 ||
|
||||||
|
decryptedKey[RSA_KEY_SIZE-16-1] != 0x00)
|
||||||
|
EXCEPTION(DRM_ERR_ENCRYPTION_KEY, "Unable to retrieve encryption key");
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GOUROU_LOG(DEBUG, "Use provided encryption key");
|
GOUROU_LOG(DEBUG, "Use provided encryption key");
|
||||||
@@ -1241,8 +1339,8 @@ namespace gourou
|
|||||||
|
|
||||||
GOUROU_LOG(DEBUG, "Decrypt string " << dictIt->first << " " << dataLength);
|
GOUROU_LOG(DEBUG, "Decrypt string " << dictIt->first << " " << dataLength);
|
||||||
|
|
||||||
client->Decrypt(CryptoInterface::ALGO_RC4, CryptoInterface::CHAIN_ECB,
|
client->decrypt(CryptoInterface::ALGO_RC4, CryptoInterface::CHAIN_ECB,
|
||||||
tmpKey, 16, /* Key */
|
tmpKey, sizeof(tmpKey), /* Key */
|
||||||
NULL, 0, /* IV */
|
NULL, 0, /* IV */
|
||||||
encryptedData, dataLength,
|
encryptedData, dataLength,
|
||||||
clearData, &dataOutLength);
|
clearData, &dataOutLength);
|
||||||
@@ -1274,8 +1372,8 @@ namespace gourou
|
|||||||
|
|
||||||
GOUROU_LOG(DEBUG, "Decrypt stream id " << object->objectId() << ", size " << stream->dataLength());
|
GOUROU_LOG(DEBUG, "Decrypt stream id " << object->objectId() << ", size " << stream->dataLength());
|
||||||
|
|
||||||
client->Decrypt(CryptoInterface::ALGO_RC4, CryptoInterface::CHAIN_ECB,
|
client->decrypt(CryptoInterface::ALGO_RC4, CryptoInterface::CHAIN_ECB,
|
||||||
tmpKey, 16, /* Key */
|
tmpKey, sizeof(tmpKey), /* Key */
|
||||||
NULL, 0, /* IV */
|
NULL, 0, /* IV */
|
||||||
encryptedData, dataLength,
|
encryptedData, dataLength,
|
||||||
clearData, &dataOutLength);
|
clearData, &dataOutLength);
|
||||||
|
|||||||
@@ -31,10 +31,23 @@ namespace gourou
|
|||||||
|
|
||||||
node = doc.select_node("/envelope/loanToken/loan").node();
|
node = doc.select_node("/envelope/loanToken/loan").node();
|
||||||
|
|
||||||
if (!node)
|
if (node)
|
||||||
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/loan element in document");
|
|
||||||
|
|
||||||
properties["id"] = node.first_child().value();
|
properties["id"] = node.first_child().value();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/display/loan").node();
|
||||||
|
|
||||||
|
if (node)
|
||||||
|
properties["id"] = node.first_child().value();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/play/loan").node();
|
||||||
|
if (node)
|
||||||
|
properties["id"] = node.first_child().value();
|
||||||
|
else
|
||||||
|
EXCEPTION(FFI_INVALID_LOAN_TOKEN, "No loanToken/loan element in document");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
node = doc.select_node("/envelope/loanToken/operatorURL").node();
|
node = doc.select_node("/envelope/loanToken/operatorURL").node();
|
||||||
|
|
||||||
@@ -50,6 +63,7 @@ namespace gourou
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/play/until").node();
|
node = doc.select_node("/envelope/fulfillmentResult/resourceItemInfo/licenseToken/permissions/play/until").node();
|
||||||
|
|
||||||
if (node)
|
if (node)
|
||||||
properties["validity"] = node.first_child().value();
|
properties["validity"] = node.first_child().value();
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
|
||||||
TARGETS=acsmdownloader adept_activate adept_remove adept_loan_mgt
|
TARGETS=acsmdownloader adept_activate adept_remove adept_loan_mgt launcher
|
||||||
|
|
||||||
CXXFLAGS=-Wall -fPIC -I$(ROOT)/include -I$(ROOT)/lib/pugixml/src/
|
CXXFLAGS=-Wall -fPIC -I$(ROOT)/include -I$(ROOT)/lib/pugixml/src/
|
||||||
|
|
||||||
STATIC_DEP=
|
STATIC_DEP=
|
||||||
LDFLAGS=-L$(ROOT) -lcrypto -lzip -lz -lcurl
|
LDFLAGS += -L$(ROOT) -lcrypto -lzip -lz -lcurl
|
||||||
|
|
||||||
ifneq ($(STATIC_UTILS),)
|
ifneq ($(STATIC_UTILS),)
|
||||||
STATIC_DEP = $(ROOT)/libgourou.a
|
STATIC_DEP = $(ROOT)/libgourou.a
|
||||||
@@ -13,11 +13,12 @@ LDFLAGS += -lgourou
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(DEBUG),)
|
ifneq ($(DEBUG),)
|
||||||
CXXFLAGS += -ggdb -O0
|
CXXFLAGS += -ggdb -O0 -DDEBUG
|
||||||
else
|
else
|
||||||
CXXFLAGS += -O2
|
CXXFLAGS += -O2
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
COMMON_DEPS = drmprocessorclientimpl.cpp utils_common.cpp
|
COMMON_DEPS = drmprocessorclientimpl.cpp utils_common.cpp
|
||||||
COMMON_OBJECTS = $(COMMON_DEPS:.cpp=.o)
|
COMMON_OBJECTS = $(COMMON_DEPS:.cpp=.o)
|
||||||
COMMON_LIB = utils.a
|
COMMON_LIB = utils.a
|
||||||
@@ -28,19 +29,10 @@ ${COMMON_LIB}: ${COMMON_DEPS} ${STATIC_DEP}
|
|||||||
$(CXX) $(CXXFLAGS) ${COMMON_DEPS} $(LDFLAGS) -c
|
$(CXX) $(CXXFLAGS) ${COMMON_DEPS} $(LDFLAGS) -c
|
||||||
$(AR) crs $@ ${COMMON_OBJECTS} $(STATIC_DEP)
|
$(AR) crs $@ ${COMMON_OBJECTS} $(STATIC_DEP)
|
||||||
|
|
||||||
acsmdownloader: acsmdownloader.cpp ${COMMON_LIB}
|
%: %.cpp ${COMMON_LIB}
|
||||||
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
adept_activate: adept_activate.cpp ${COMMON_LIB}
|
|
||||||
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
adept_remove: adept_remove.cpp ${COMMON_LIB}
|
|
||||||
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
|
||||||
|
|
||||||
adept_loan_mgt: adept_loan_mgt.cpp ${COMMON_LIB}
|
|
||||||
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
$(CXX) $(CXXFLAGS) $^ $(LDFLAGS) -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f $(TARGETS)
|
rm -f $(TARGETS) $(COMMON_LIB)
|
||||||
|
|
||||||
ultraclean: clean
|
ultraclean: clean
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ static void usage(const char* cmd)
|
|||||||
{
|
{
|
||||||
std::cout << "Download EPUB file from ACSM request file" << std::endl;
|
std::cout << "Download EPUB file from ACSM request file" << std::endl;
|
||||||
|
|
||||||
std::cout << "Usage: " << cmd << " [(-d|--device-file) device.xml] [(-a|--activation-file) activation.xml] [(-k|--device-key-file) devicesalt] [(-O|--output-dir) dir] [(-o|--output-file) output(.epub|.pdf|.der)] [(-r|--resume)] [(-v|--verbose)] [(-h|--help)] (-f|--acsm-file) file.acsm|(-e|--export-private-key)" << std::endl << std::endl;
|
std::cout << "Usage: " << basename((char*)cmd) << " [(-d|--device-file) device.xml] [(-a|--activation-file) activation.xml] [(-k|--device-key-file) devicesalt] [(-O|--output-dir) dir] [(-o|--output-file) output(.epub|.pdf|.der)] [(-r|--resume)] [(-v|--verbose)] [(-h|--help)] (-f|--acsm-file) file.acsm|(-e|--export-private-key)" << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << " " << "-d|--device-file" << "\t" << "device.xml file from eReader" << std::endl;
|
std::cout << " " << "-d|--device-file" << "\t" << "device.xml file from eReader" << std::endl;
|
||||||
std::cout << " " << "-a|--activation-file" << "\t" << "activation.xml file from eReader" << std::endl;
|
std::cout << " " << "-a|--activation-file" << "\t" << "activation.xml file from eReader" << std::endl;
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ static void usage(const char* cmd)
|
|||||||
{
|
{
|
||||||
std::cout << "Create new device files used by ADEPT DRM" << std::endl;
|
std::cout << "Create new device files used by ADEPT DRM" << std::endl;
|
||||||
|
|
||||||
std::cout << "Usage: " << cmd << " (-a|--anonymous) | ( (-u|--username) username [(-p|--password) password] ) [(-O|--output-dir) dir] [(-r|--random-serial)] [(-v|--verbose)] [(-h|--help)]" << std::endl << std::endl;
|
std::cout << "Usage: " << basename((char*)cmd) << " (-a|--anonymous) | ( (-u|--username) username [(-p|--password) password] ) [(-O|--output-dir) dir] [(-r|--random-serial)] [(-v|--verbose)] [(-h|--help)]" << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << " " << "-a|--anonymous" << "\t" << "Anonymous account, no need for username/password (Use it only with a DRM removal software)" << std::endl;
|
std::cout << " " << "-a|--anonymous" << "\t" << "Anonymous account, no need for username/password (Use it only with a DRM removal software)" << std::endl;
|
||||||
std::cout << " " << "-u|--username" << "\t\t" << "AdobeID username (ie adobe.com email account)" << std::endl;
|
std::cout << " " << "-u|--username" << "\t\t" << "AdobeID username (ie adobe.com email account)" << std::endl;
|
||||||
|
|||||||
@@ -336,7 +336,7 @@ static void usage(const char* cmd)
|
|||||||
{
|
{
|
||||||
std::cout << "Manage loaned books" << std::endl;
|
std::cout << "Manage loaned books" << std::endl;
|
||||||
|
|
||||||
std::cout << "Usage: " << cmd << " [(-d|--activation-dir) dir] (-l|--list)|(-D|--delete loanID)|(-R|--delete loanID) [(-v|--verbose)] [(-h|--help)]" << std::endl << std::endl;
|
std::cout << "Usage: " << basename((char*)cmd) << " [(-d|--activation-dir) dir] (-l|--list)|(-D|--delete loanID)|(-R|--delete loanID) [(-v|--verbose)] [(-h|--help)]" << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << " " << "-d|--activation-dir" << "\t" << "Directory of device.xml/activation.xml and device key" << std::endl;
|
std::cout << " " << "-d|--activation-dir" << "\t" << "Directory of device.xml/activation.xml and device key" << std::endl;
|
||||||
std::cout << " " << "-l|--list" << "\t\t" << "List all loaned books" << std::endl;
|
std::cout << " " << "-l|--list" << "\t\t" << "List all loaned books" << std::endl;
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ static void usage(const char* cmd)
|
|||||||
{
|
{
|
||||||
std::cout << "Remove ADEPT DRM (from Adobe) of EPUB/PDF file" << std::endl;
|
std::cout << "Remove ADEPT DRM (from Adobe) of EPUB/PDF file" << std::endl;
|
||||||
|
|
||||||
std::cout << "Usage: " << cmd << " [(-d|--device-file) device.xml] [(-a|--activation-file) activation.xml] [(-k|--device-key-file) devicesalt] [(-O|--output-dir) dir] [(-o|--output-file) output(.epub|.pdf|.der)] [(-v|--verbose)] [(-h|--help)] (-f|--input-file) file(.epub|pdf)" << std::endl << std::endl;
|
std::cout << "Usage: " << basename((char*)cmd) << " [(-d|--device-file) device.xml] [(-a|--activation-file) activation.xml] [(-k|--device-key-file) devicesalt] [(-O|--output-dir) dir] [(-o|--output-file) output(.epub|.pdf|.der)] [(-v|--verbose)] [(-h|--help)] (-f|--input-file) file(.epub|pdf)" << std::endl << std::endl;
|
||||||
|
|
||||||
std::cout << " " << "-d|--device-file" << "\t" << "device.xml file from eReader" << std::endl;
|
std::cout << " " << "-d|--device-file" << "\t" << "device.xml file from eReader" << std::endl;
|
||||||
std::cout << " " << "-a|--activation-file" << "\t" << "activation.xml file from eReader" << std::endl;
|
std::cout << " " << "-a|--activation-file" << "\t" << "activation.xml file from eReader" << std::endl;
|
||||||
|
|||||||
@@ -31,10 +31,14 @@
|
|||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
|
||||||
|
#define OPENSSL_NO_DEPRECATED 1
|
||||||
|
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/pkcs12.h>
|
#include <openssl/pkcs12.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
@@ -42,9 +46,33 @@
|
|||||||
#include <zip.h>
|
#include <zip.h>
|
||||||
|
|
||||||
#include <libgourou_common.h>
|
#include <libgourou_common.h>
|
||||||
#include <libgourou_log.h>
|
|
||||||
#include "drmprocessorclientimpl.h"
|
#include "drmprocessorclientimpl.h"
|
||||||
|
|
||||||
|
DRMProcessorClientImpl::DRMProcessorClientImpl():
|
||||||
|
legacy(0), deflt(0)
|
||||||
|
{
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
legacy = OSSL_PROVIDER_load(NULL, "legacy");
|
||||||
|
if (!legacy)
|
||||||
|
EXCEPTION(gourou::CLIENT_OSSL_ERROR, "Error, OpenSSL legacy provider not available");
|
||||||
|
|
||||||
|
deflt = OSSL_PROVIDER_load(NULL, "default");
|
||||||
|
if (!deflt)
|
||||||
|
EXCEPTION(gourou::CLIENT_OSSL_ERROR, "Error, OpenSSL default provider not available");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DRMProcessorClientImpl::~DRMProcessorClientImpl()
|
||||||
|
{
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
if (legacy)
|
||||||
|
OSSL_PROVIDER_unload(legacy);
|
||||||
|
|
||||||
|
if (deflt)
|
||||||
|
OSSL_PROVIDER_unload(deflt);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* Digest interface */
|
/* Digest interface */
|
||||||
void* DRMProcessorClientImpl::createDigest(const std::string& digestName)
|
void* DRMProcessorClientImpl::createDigest(const std::string& digestName)
|
||||||
{
|
{
|
||||||
@@ -54,32 +82,32 @@ void* DRMProcessorClientImpl::createDigest(const std::string& digestName)
|
|||||||
if (EVP_DigestInit(md_ctx, md) != 1)
|
if (EVP_DigestInit(md_ctx, md) != 1)
|
||||||
{
|
{
|
||||||
EVP_MD_CTX_free(md_ctx);
|
EVP_MD_CTX_free(md_ctx);
|
||||||
return 0;
|
EXCEPTION(gourou::CLIENT_DIGEST_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
return md_ctx;
|
return md_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int DRMProcessorClientImpl::digestUpdate(void* handler, unsigned char* data, unsigned int length)
|
void DRMProcessorClientImpl::digestUpdate(void* handler, unsigned char* data, unsigned int length)
|
||||||
{
|
{
|
||||||
return (EVP_DigestUpdate((EVP_MD_CTX *)handler, data, length)) ? 0 : -1;
|
if (EVP_DigestUpdate((EVP_MD_CTX *)handler, data, length) != 1)
|
||||||
|
EXCEPTION(gourou::CLIENT_DIGEST_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
int DRMProcessorClientImpl::digestFinalize(void* handler, unsigned char* digestOut)
|
void DRMProcessorClientImpl::digestFinalize(void* handler, unsigned char* digestOut)
|
||||||
{
|
{
|
||||||
int res = EVP_DigestFinal((EVP_MD_CTX *)handler, digestOut, NULL);
|
int res = EVP_DigestFinal((EVP_MD_CTX *)handler, digestOut, NULL);
|
||||||
EVP_MD_CTX_free((EVP_MD_CTX *)handler);
|
EVP_MD_CTX_free((EVP_MD_CTX *)handler);
|
||||||
return (res == 1) ? 0 : -1;
|
|
||||||
|
if (res <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_DIGEST_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
int DRMProcessorClientImpl::digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut)
|
void DRMProcessorClientImpl::digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut)
|
||||||
{
|
{
|
||||||
void* handler = createDigest(digestName);
|
void* handler = createDigest(digestName);
|
||||||
if (!handler)
|
digestUpdate(handler, data, length);
|
||||||
return -1;
|
digestFinalize(handler, digestOut);
|
||||||
if (digestUpdate(handler, data, length))
|
|
||||||
return -1;
|
|
||||||
return digestFinalize(handler, digestOut);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Random interface */
|
/* Random interface */
|
||||||
@@ -97,7 +125,7 @@ static int downloadProgress(void *clientp, curl_off_t dltotal, curl_off_t dlnow,
|
|||||||
curl_off_t ultotal, curl_off_t ulnow)
|
curl_off_t ultotal, curl_off_t ulnow)
|
||||||
{
|
{
|
||||||
// For "big" files only
|
// For "big" files only
|
||||||
if (dltotal >= DISPLAY_THRESHOLD && gourou::logLevel >= gourou::WARN)
|
if (dltotal >= DISPLAY_THRESHOLD && gourou::logLevel >= gourou::LG_LOG_WARN)
|
||||||
{
|
{
|
||||||
int percent = 0;
|
int percent = 0;
|
||||||
if (dltotal)
|
if (dltotal)
|
||||||
@@ -147,7 +175,7 @@ static size_t curlHeaders(char *buffer, size_t size, size_t nitems, void *userda
|
|||||||
|
|
||||||
(*responseHeaders)[key] = value;
|
(*responseHeaders)[key] = value;
|
||||||
|
|
||||||
if (gourou::logLevel >= gourou::DEBUG)
|
if (gourou::logLevel >= gourou::LG_LOG_DEBUG)
|
||||||
std::cout << key << " : " << value << std::endl;
|
std::cout << key << " : " << value << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,10 +190,10 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
|||||||
if (!responseHeaders)
|
if (!responseHeaders)
|
||||||
responseHeaders = &localHeaders;
|
responseHeaders = &localHeaders;
|
||||||
|
|
||||||
GOUROU_LOG(gourou::INFO, "Send request to " << URL);
|
GOUROU_LOG(INFO, "Send request to " << URL);
|
||||||
if (POSTData.size())
|
if (POSTData.size())
|
||||||
{
|
{
|
||||||
GOUROU_LOG(gourou::DEBUG, "<<< " << std::endl << POSTData);
|
GOUROU_LOG(DEBUG, "<<< " << std::endl << POSTData);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned prevDownloadedBytes;
|
unsigned prevDownloadedBytes;
|
||||||
@@ -175,11 +203,11 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
|||||||
struct stat _stat;
|
struct stat _stat;
|
||||||
if (!fstat(fd, &_stat))
|
if (!fstat(fd, &_stat))
|
||||||
{
|
{
|
||||||
GOUROU_LOG(gourou::WARN, "Resume download @ " << _stat.st_size << " bytes");
|
GOUROU_LOG(WARN, "Resume download @ " << _stat.st_size << " bytes");
|
||||||
downloadedBytes = _stat.st_size;
|
downloadedBytes = _stat.st_size;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
GOUROU_LOG(gourou::WARN, "Want to resume, but fstat failed");
|
GOUROU_LOG(WARN, "Want to resume, but fstat failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
CURL *curl = curl_easy_init();
|
CURL *curl = curl_easy_init();
|
||||||
@@ -235,7 +263,7 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
|||||||
// Connexion failed, wait & retry
|
// Connexion failed, wait & retry
|
||||||
if (res == CURLE_COULDNT_CONNECT)
|
if (res == CURLE_COULDNT_CONNECT)
|
||||||
{
|
{
|
||||||
GOUROU_LOG(gourou::WARN, "\nConnection failed, attempt " << (i+1) << "/" << HTTP_REQ_MAX_RETRY);
|
GOUROU_LOG(WARN, "\nConnection failed, attempt " << (i+1) << "/" << HTTP_REQ_MAX_RETRY);
|
||||||
}
|
}
|
||||||
// Transfer failed but some data has been received
|
// Transfer failed but some data has been received
|
||||||
// --> try again without incrementing tries
|
// --> try again without incrementing tries
|
||||||
@@ -243,11 +271,11 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
|||||||
{
|
{
|
||||||
if (prevDownloadedBytes != downloadedBytes)
|
if (prevDownloadedBytes != downloadedBytes)
|
||||||
{
|
{
|
||||||
GOUROU_LOG(gourou::WARN, "\nConnection broken, but data received, try again");
|
GOUROU_LOG(WARN, "\nConnection broken, but data received, try again");
|
||||||
i--;
|
i--;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
GOUROU_LOG(gourou::WARN, "\nConnection broken and no data received, attempt " << (i+1) << "/" << HTTP_REQ_MAX_RETRY);
|
GOUROU_LOG(WARN, "\nConnection broken and no data received, attempt " << (i+1) << "/" << HTTP_REQ_MAX_RETRY);
|
||||||
}
|
}
|
||||||
// Other error --> fail
|
// Other error --> fail
|
||||||
else
|
else
|
||||||
@@ -264,46 +292,79 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
|||||||
EXCEPTION(gourou::CLIENT_NETWORK_ERROR, "Error " << curl_easy_strerror(res));
|
EXCEPTION(gourou::CLIENT_NETWORK_ERROR, "Error " << curl_easy_strerror(res));
|
||||||
|
|
||||||
if ((downloadedBytes >= DISPLAY_THRESHOLD || replyData.size() >= DISPLAY_THRESHOLD) &&
|
if ((downloadedBytes >= DISPLAY_THRESHOLD || replyData.size() >= DISPLAY_THRESHOLD) &&
|
||||||
gourou::logLevel >= gourou::WARN)
|
gourou::logLevel >= gourou::LG_LOG_WARN)
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
|
||||||
if ((*responseHeaders)["Content-Type"] == "application/vnd.adobe.adept+xml")
|
if ((*responseHeaders)["Content-Type"] == "application/vnd.adobe.adept+xml")
|
||||||
{
|
{
|
||||||
GOUROU_LOG(gourou::DEBUG, ">>> " << std::endl << replyData.data());
|
GOUROU_LOG(DEBUG, ">>> " << std::endl << replyData.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
return std::string((char*)replyData.data(), replyData.length());
|
return std::string((char*)replyData.data(), replyData.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DRMProcessorClientImpl::padWithPKCS1(unsigned char* out, unsigned int outLength,
|
||||||
|
const unsigned char* in, unsigned int inLength)
|
||||||
|
{
|
||||||
|
if (outLength < (inLength + 3))
|
||||||
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, "Not enough space for PKCS1 padding");
|
||||||
|
|
||||||
|
/*
|
||||||
|
PKCS1v5 Padding is :
|
||||||
|
0x00 0x01 0xff * n 0x00 dataIn
|
||||||
|
*/
|
||||||
|
|
||||||
|
memset(out, 0xFF, outLength);
|
||||||
|
|
||||||
|
out[0] = 0x0;
|
||||||
|
out[1] = 0x1;
|
||||||
|
out[outLength - inLength - 1] = 0x00;
|
||||||
|
memcpy(&out[outLength - inLength], in, inLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void DRMProcessorClientImpl::RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
void DRMProcessorClientImpl::RSAPrivateEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
const RSA_KEY_TYPE keyType, const std::string& password,
|
const RSA_KEY_TYPE keyType, const std::string& password,
|
||||||
const unsigned char* data, unsigned dataLength,
|
const unsigned char* data, unsigned dataLength,
|
||||||
unsigned char* res)
|
unsigned char* res)
|
||||||
{
|
{
|
||||||
PKCS12 * pkcs12;
|
PKCS12 * pkcs12;
|
||||||
EVP_PKEY* pkey;
|
EVP_PKEY_CTX *ctx;
|
||||||
X509* cert;
|
EVP_PKEY* pkey = NULL;
|
||||||
STACK_OF(X509)* ca;
|
size_t outlen;
|
||||||
RSA * rsa;
|
unsigned char* tmp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
pkcs12 = d2i_PKCS12(NULL, &RSAKey, RSAKeyLength);
|
pkcs12 = d2i_PKCS12(NULL, &RSAKey, RSAKeyLength);
|
||||||
if (!pkcs12)
|
if (!pkcs12)
|
||||||
EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
|
EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
|
||||||
PKCS12_parse(pkcs12, password.c_str(), &pkey, &cert, &ca);
|
|
||||||
rsa = EVP_PKEY_get1_RSA(pkey);
|
|
||||||
|
|
||||||
int ret = RSA_private_encrypt(dataLength, data, res, rsa, RSA_PKCS1_PADDING);
|
if (PKCS12_parse(pkcs12, password.c_str(), &pkey, NULL, NULL) <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
if (ret < 0)
|
outlen = EVP_PKEY_get_size(pkey);
|
||||||
|
|
||||||
|
ctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||||
|
|
||||||
|
/* Use RSA private key */
|
||||||
|
if (EVP_PKEY_decrypt_init(ctx) <= 0)
|
||||||
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
if (gourou::logLevel >= gourou::DEBUG)
|
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0)
|
||||||
{
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
printf("Encrypted : ");
|
|
||||||
for(int i=0; i<ret; i++)
|
tmp = (unsigned char*)malloc(outlen);
|
||||||
printf("%02x ", res[i]);
|
|
||||||
printf("\n");
|
/* PKCS1 functions are no more exported */
|
||||||
}
|
padWithPKCS1(tmp, outlen, data, dataLength);
|
||||||
|
|
||||||
|
ret = EVP_PKEY_decrypt(ctx, res, &outlen, tmp, outlen);
|
||||||
|
|
||||||
|
EVP_PKEY_CTX_free(ctx);
|
||||||
|
free(tmp);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::RSAPrivateDecrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
void DRMProcessorClientImpl::RSAPrivateDecrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
@@ -317,24 +378,30 @@ void DRMProcessorClientImpl::RSAPrivateDecrypt(const unsigned char* RSAKey, unsi
|
|||||||
if (!p8inf)
|
if (!p8inf)
|
||||||
EXCEPTION(gourou::CLIENT_INVALID_PKCS8, ERR_error_string(ERR_get_error(), NULL));
|
EXCEPTION(gourou::CLIENT_INVALID_PKCS8, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
|
EVP_PKEY_CTX *ctx;
|
||||||
EVP_PKEY* pkey = EVP_PKCS82PKEY(p8inf);
|
EVP_PKEY* pkey = EVP_PKCS82PKEY(p8inf);
|
||||||
RSA * rsa;
|
size_t outlen = dataLength;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
rsa = EVP_PKEY_get1_RSA(pkey);
|
if (!pkey)
|
||||||
|
EXCEPTION(gourou::CLIENT_INVALID_PKCS8, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
ret = RSA_private_decrypt(dataLength, data, res, rsa, RSA_NO_PADDING);
|
ctx = EVP_PKEY_CTX_new(pkey, NULL);
|
||||||
|
|
||||||
if (ret < 0)
|
if (EVP_PKEY_decrypt_init(ctx) <= 0)
|
||||||
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
if (gourou::logLevel >= gourou::DEBUG)
|
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0)
|
||||||
{
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
printf("Decrypted : ");
|
|
||||||
for(int i=0; i<ret; i++)
|
ret = EVP_PKEY_decrypt(ctx, res, &outlen, data, dataLength);
|
||||||
printf("%02x ", res[i]);
|
|
||||||
printf("\n");
|
PKCS8_PRIV_KEY_INFO_free(p8inf);
|
||||||
}
|
EVP_PKEY_CTX_free(ctx);
|
||||||
|
BIO_free(mem);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
void DRMProcessorClientImpl::RSAPublicEncrypt(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
@@ -342,61 +409,79 @@ void DRMProcessorClientImpl::RSAPublicEncrypt(const unsigned char* RSAKey, unsig
|
|||||||
const unsigned char* data, unsigned dataLength,
|
const unsigned char* data, unsigned dataLength,
|
||||||
unsigned char* res)
|
unsigned char* res)
|
||||||
{
|
{
|
||||||
|
size_t outlen;
|
||||||
|
|
||||||
X509 * x509 = d2i_X509(0, &RSAKey, RSAKeyLength);
|
X509 * x509 = d2i_X509(0, &RSAKey, RSAKeyLength);
|
||||||
if (!x509)
|
if (!x509)
|
||||||
EXCEPTION(gourou::CLIENT_INVALID_CERTIFICATE, "Invalid certificate");
|
EXCEPTION(gourou::CLIENT_INVALID_CERTIFICATE, "Invalid certificate");
|
||||||
|
|
||||||
|
EVP_PKEY_CTX *ctx;
|
||||||
EVP_PKEY * evpKey = X509_get_pubkey(x509);
|
EVP_PKEY * evpKey = X509_get_pubkey(x509);
|
||||||
RSA* rsa = EVP_PKEY_get1_RSA(evpKey);
|
|
||||||
EVP_PKEY_free(evpKey);
|
|
||||||
|
|
||||||
if (!rsa)
|
if (!evpKey)
|
||||||
EXCEPTION(gourou::CLIENT_NO_PRIV_KEY, "No private key in certificate");
|
EXCEPTION(gourou::CLIENT_NO_PUB_KEY, "No public key in certificate");
|
||||||
|
|
||||||
|
ctx = EVP_PKEY_CTX_new(evpKey, NULL);
|
||||||
|
|
||||||
|
if (EVP_PKEY_encrypt_init(ctx) <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
|
if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
|
int ret = EVP_PKEY_encrypt(ctx, res, &outlen, data, dataLength);
|
||||||
|
|
||||||
|
EVP_PKEY_CTX_free(ctx);
|
||||||
|
|
||||||
int ret = RSA_public_encrypt(dataLength, data, res, rsa, RSA_PKCS1_PADDING);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
EXCEPTION(gourou::CLIENT_RSA_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
|
EVP_PKEY_free(evpKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DRMProcessorClientImpl::generateRSAKey(int keyLengthBits)
|
void* DRMProcessorClientImpl::generateRSAKey(int keyLengthBits)
|
||||||
{
|
{
|
||||||
BIGNUM * bn = BN_new();
|
BIGNUM * bn = BN_new();
|
||||||
RSA * rsa = RSA_new();
|
EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
|
||||||
|
EVP_PKEY *key = NULL;
|
||||||
|
|
||||||
BN_set_word(bn, 0x10001);
|
BN_set_word(bn, 0x10001);
|
||||||
RSA_generate_key_ex(rsa, keyLengthBits, bn, 0);
|
|
||||||
|
EVP_PKEY_keygen_init(ctx);
|
||||||
|
|
||||||
|
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, keyLengthBits);
|
||||||
|
EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING);
|
||||||
|
EVP_PKEY_CTX_set1_rsa_keygen_pubexp(ctx, bn);
|
||||||
|
EVP_PKEY_keygen(ctx, &key);
|
||||||
|
|
||||||
|
EVP_PKEY_CTX_free(ctx);
|
||||||
BN_free(bn);
|
BN_free(bn);
|
||||||
|
|
||||||
return rsa;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::destroyRSAHandler(void* handler)
|
void DRMProcessorClientImpl::destroyRSAHandler(void* handler)
|
||||||
{
|
{
|
||||||
RSA_free((RSA*)handler);
|
free(handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::extractRSAPublicKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength)
|
void DRMProcessorClientImpl::extractRSAPublicKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength)
|
||||||
{
|
{
|
||||||
EVP_PKEY * evpKey = EVP_PKEY_new();
|
|
||||||
EVP_PKEY_set1_RSA(evpKey, (RSA*)handler);
|
|
||||||
X509_PUBKEY *x509_pubkey = 0;
|
X509_PUBKEY *x509_pubkey = 0;
|
||||||
X509_PUBKEY_set(&x509_pubkey, evpKey);
|
X509_PUBKEY_set(&x509_pubkey, (EVP_PKEY*)handler);
|
||||||
|
|
||||||
*keyOutLength = i2d_X509_PUBKEY(x509_pubkey, keyOut);
|
*keyOutLength = i2d_X509_PUBKEY(x509_pubkey, keyOut);
|
||||||
|
|
||||||
X509_PUBKEY_free(x509_pubkey);
|
X509_PUBKEY_free(x509_pubkey);
|
||||||
EVP_PKEY_free(evpKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::extractRSAPrivateKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength)
|
void DRMProcessorClientImpl::extractRSAPrivateKey(void* handler, unsigned char** keyOut, unsigned int* keyOutLength)
|
||||||
{
|
{
|
||||||
EVP_PKEY * evpKey = EVP_PKEY_new();
|
PKCS8_PRIV_KEY_INFO * privKey = EVP_PKEY2PKCS8((EVP_PKEY*)handler);
|
||||||
EVP_PKEY_set1_RSA(evpKey, (RSA*)handler);
|
|
||||||
PKCS8_PRIV_KEY_INFO * privKey = EVP_PKEY2PKCS8(evpKey);
|
|
||||||
|
|
||||||
*keyOutLength = i2d_PKCS8_PRIV_KEY_INFO(privKey, keyOut);
|
*keyOutLength = i2d_PKCS8_PRIV_KEY_INFO(privKey, keyOut);
|
||||||
|
|
||||||
PKCS8_PRIV_KEY_INFO_free(privKey);
|
PKCS8_PRIV_KEY_INFO_free(privKey);
|
||||||
EVP_PKEY_free(evpKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::extractCertificate(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
void DRMProcessorClientImpl::extractCertificate(const unsigned char* RSAKey, unsigned int RSAKeyLength,
|
||||||
@@ -406,12 +491,14 @@ void DRMProcessorClientImpl::extractCertificate(const unsigned char* RSAKey, uns
|
|||||||
PKCS12 * pkcs12;
|
PKCS12 * pkcs12;
|
||||||
EVP_PKEY* pkey = 0;
|
EVP_PKEY* pkey = 0;
|
||||||
X509* cert = 0;
|
X509* cert = 0;
|
||||||
STACK_OF(X509)* ca;
|
|
||||||
|
|
||||||
pkcs12 = d2i_PKCS12(NULL, &RSAKey, RSAKeyLength);
|
pkcs12 = d2i_PKCS12(NULL, &RSAKey, RSAKeyLength);
|
||||||
if (!pkcs12)
|
if (!pkcs12)
|
||||||
EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
|
EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
|
||||||
PKCS12_parse(pkcs12, password.c_str(), &pkey, &cert, &ca);
|
PKCS12_parse(pkcs12, password.c_str(), &pkey, &cert, NULL);
|
||||||
|
|
||||||
|
if (!cert)
|
||||||
|
EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
|
||||||
*certOutLength = i2d_X509(cert, certOut);
|
*certOutLength = i2d_X509(cert, certOut);
|
||||||
|
|
||||||
@@ -419,24 +506,27 @@ void DRMProcessorClientImpl::extractCertificate(const unsigned char* RSAKey, uns
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Crypto interface */
|
/* Crypto interface */
|
||||||
void DRMProcessorClientImpl::Encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
void DRMProcessorClientImpl::encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength,
|
const unsigned char* iv, unsigned int ivLength,
|
||||||
const unsigned char* dataIn, unsigned int dataInLength,
|
const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength)
|
unsigned char* dataOut, unsigned int* dataOutLength)
|
||||||
{
|
{
|
||||||
void* handler = EncryptInit(algo, chaining, key, keyLength, iv, ivLength);
|
void* handler = encryptInit(algo, chaining, key, keyLength, iv, ivLength);
|
||||||
EncryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
|
encryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
|
||||||
EncryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
|
encryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DRMProcessorClientImpl::EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
void* DRMProcessorClientImpl::encryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength)
|
const unsigned char* iv, unsigned int ivLength)
|
||||||
{
|
{
|
||||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (algo == ALGO_AES)
|
switch (algo)
|
||||||
|
{
|
||||||
|
case ALGO_AES:
|
||||||
{
|
{
|
||||||
switch(keyLength)
|
switch(keyLength)
|
||||||
{
|
{
|
||||||
@@ -444,10 +534,10 @@ void* DRMProcessorClientImpl::EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaini
|
|||||||
switch(chaining)
|
switch(chaining)
|
||||||
{
|
{
|
||||||
case CHAIN_ECB:
|
case CHAIN_ECB:
|
||||||
EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, iv);
|
ret = EVP_EncryptInit(ctx, EVP_aes_128_ecb(), key, iv);
|
||||||
break;
|
break;
|
||||||
case CHAIN_CBC:
|
case CHAIN_CBC:
|
||||||
EVP_EncryptInit(ctx, EVP_aes_128_cbc(), key, iv);
|
ret = EVP_EncryptInit(ctx, EVP_aes_128_cbc(), key, iv);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
|
EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
|
||||||
@@ -457,26 +547,39 @@ void* DRMProcessorClientImpl::EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaini
|
|||||||
EVP_CIPHER_CTX_free(ctx);
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
|
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (algo == ALGO_RC4)
|
case ALGO_RC4:
|
||||||
{
|
{
|
||||||
if (keyLength != 16)
|
if (keyLength != 16)
|
||||||
{
|
{
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
|
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
|
||||||
}
|
}
|
||||||
EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
|
ret = EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
|
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
|
}
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DRMProcessorClientImpl::DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
void* DRMProcessorClientImpl::decryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength)
|
const unsigned char* iv, unsigned int ivLength)
|
||||||
{
|
{
|
||||||
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
if (algo == ALGO_AES)
|
switch(algo)
|
||||||
|
{
|
||||||
|
case ALGO_AES:
|
||||||
{
|
{
|
||||||
switch(keyLength)
|
switch(keyLength)
|
||||||
{
|
{
|
||||||
@@ -484,10 +587,10 @@ void* DRMProcessorClientImpl::DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaini
|
|||||||
switch(chaining)
|
switch(chaining)
|
||||||
{
|
{
|
||||||
case CHAIN_ECB:
|
case CHAIN_ECB:
|
||||||
EVP_DecryptInit(ctx, EVP_aes_128_ecb(), key, iv);
|
ret = EVP_DecryptInit(ctx, EVP_aes_128_ecb(), key, iv);
|
||||||
break;
|
break;
|
||||||
case CHAIN_CBC:
|
case CHAIN_CBC:
|
||||||
EVP_DecryptInit(ctx, EVP_aes_128_cbc(), key, iv);
|
ret = EVP_DecryptInit(ctx, EVP_aes_128_cbc(), key, iv);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
|
EXCEPTION(gourou::CLIENT_BAD_CHAINING, "Unknown chaining mode " << chaining);
|
||||||
@@ -497,58 +600,81 @@ void* DRMProcessorClientImpl::DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaini
|
|||||||
EVP_CIPHER_CTX_free(ctx);
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
|
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else if (algo == ALGO_RC4)
|
case ALGO_RC4:
|
||||||
{
|
{
|
||||||
if (keyLength != 16)
|
if (keyLength != 16)
|
||||||
{
|
{
|
||||||
EVP_CIPHER_CTX_free(ctx);
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
|
EXCEPTION(gourou::CLIENT_BAD_KEY_SIZE, "Invalid key size " << keyLength);
|
||||||
}
|
}
|
||||||
EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
|
ret = EVP_DecryptInit(ctx, EVP_rc4(), key, iv);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
{
|
||||||
|
EVP_CIPHER_CTX_free(ctx);
|
||||||
|
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::EncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
void DRMProcessorClientImpl::encryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength)
|
unsigned char* dataOut, unsigned int* dataOutLength)
|
||||||
{
|
{
|
||||||
EVP_EncryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
|
int ret = EVP_EncryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::EncryptFinalize(void* handler,
|
void DRMProcessorClientImpl::encryptFinalize(void* handler,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength)
|
unsigned char* dataOut, unsigned int* dataOutLength)
|
||||||
{
|
{
|
||||||
int len;
|
int len, ret;
|
||||||
EVP_EncryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
|
|
||||||
|
ret = EVP_EncryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
|
||||||
*dataOutLength += len;
|
*dataOutLength += len;
|
||||||
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
|
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::Decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
void DRMProcessorClientImpl::decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength,
|
const unsigned char* iv, unsigned int ivLength,
|
||||||
const unsigned char* dataIn, unsigned int dataInLength,
|
const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength)
|
unsigned char* dataOut, unsigned int* dataOutLength)
|
||||||
{
|
{
|
||||||
void* handler = DecryptInit(algo, chaining, key, keyLength, iv, ivLength);
|
void* handler = decryptInit(algo, chaining, key, keyLength, iv, ivLength);
|
||||||
DecryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
|
decryptUpdate(handler, dataIn, dataInLength, dataOut, dataOutLength);
|
||||||
DecryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
|
decryptFinalize(handler, dataOut+*dataOutLength, dataOutLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::DecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
void DRMProcessorClientImpl::decryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength)
|
unsigned char* dataOut, unsigned int* dataOutLength)
|
||||||
{
|
{
|
||||||
EVP_DecryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
|
int ret = EVP_DecryptUpdate((EVP_CIPHER_CTX*)handler, dataOut, (int*)dataOutLength, dataIn, dataInLength);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DRMProcessorClientImpl::DecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength)
|
void DRMProcessorClientImpl::decryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength)
|
||||||
{
|
{
|
||||||
int len;
|
int len, ret;
|
||||||
EVP_DecryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
|
|
||||||
|
ret = EVP_DecryptFinal_ex((EVP_CIPHER_CTX*)handler, dataOut, &len);
|
||||||
*dataOutLength += len;
|
*dataOutLength += len;
|
||||||
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
|
EVP_CIPHER_CTX_free((EVP_CIPHER_CTX*)handler);
|
||||||
|
|
||||||
|
if (ret <= 0)
|
||||||
|
EXCEPTION(gourou::CLIENT_CRYPT_ERROR, ERR_error_string(ERR_get_error(), NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
void* DRMProcessorClientImpl::zipOpen(const std::string& path)
|
void* DRMProcessorClientImpl::zipOpen(const std::string& path)
|
||||||
|
|||||||
@@ -31,16 +31,23 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
#include <openssl/provider.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <drmprocessorclient.h>
|
#include <drmprocessorclient.h>
|
||||||
|
|
||||||
class DRMProcessorClientImpl : public gourou::DRMProcessorClient
|
class DRMProcessorClientImpl : public gourou::DRMProcessorClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
DRMProcessorClientImpl();
|
||||||
|
~DRMProcessorClientImpl();
|
||||||
|
|
||||||
/* Digest interface */
|
/* Digest interface */
|
||||||
virtual void* createDigest(const std::string& digestName);
|
virtual void* createDigest(const std::string& digestName);
|
||||||
virtual int digestUpdate(void* handler, unsigned char* data, unsigned int length);
|
virtual void digestUpdate(void* handler, unsigned char* data, unsigned int length);
|
||||||
virtual int digestFinalize(void* handler,unsigned char* digestOut);
|
virtual void digestFinalize(void* handler,unsigned char* digestOut);
|
||||||
virtual int digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut);
|
virtual void digest(const std::string& digestName, unsigned char* data, unsigned int length, unsigned char* digestOut);
|
||||||
|
|
||||||
/* Random interface */
|
/* Random interface */
|
||||||
virtual void randBytes(unsigned char* bytesOut, unsigned int length);
|
virtual void randBytes(unsigned char* bytesOut, unsigned int length);
|
||||||
@@ -73,34 +80,34 @@ public:
|
|||||||
unsigned char** certOut, unsigned int* certOutLength);
|
unsigned char** certOut, unsigned int* certOutLength);
|
||||||
|
|
||||||
/* Crypto interface */
|
/* Crypto interface */
|
||||||
virtual void Encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void encrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength,
|
const unsigned char* iv, unsigned int ivLength,
|
||||||
const unsigned char* dataIn, unsigned int dataInLength,
|
const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength);
|
unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
|
|
||||||
virtual void* EncryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void* encryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv=0, unsigned int ivLength=0);
|
const unsigned char* iv=0, unsigned int ivLength=0);
|
||||||
|
|
||||||
|
|
||||||
virtual void EncryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
virtual void encryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength);
|
unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
virtual void EncryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
|
virtual void encryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
|
|
||||||
virtual void Decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void decrypt(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv, unsigned int ivLength,
|
const unsigned char* iv, unsigned int ivLength,
|
||||||
const unsigned char* dataIn, unsigned int dataInLength,
|
const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength);
|
unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
|
|
||||||
virtual void* DecryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
virtual void* decryptInit(CRYPTO_ALGO algo, CHAINING_MODE chaining,
|
||||||
const unsigned char* key, unsigned int keyLength,
|
const unsigned char* key, unsigned int keyLength,
|
||||||
const unsigned char* iv=0, unsigned int ivLength=0);
|
const unsigned char* iv=0, unsigned int ivLength=0);
|
||||||
|
|
||||||
virtual void DecryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
virtual void decryptUpdate(void* handler, const unsigned char* dataIn, unsigned int dataInLength,
|
||||||
unsigned char* dataOut, unsigned int* dataOutLength);
|
unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
virtual void DecryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
|
virtual void decryptFinalize(void* handler, unsigned char* dataOut, unsigned int* dataOutLength);
|
||||||
|
|
||||||
/* ZIP Interface */
|
/* ZIP Interface */
|
||||||
virtual void* zipOpen(const std::string& path);
|
virtual void* zipOpen(const std::string& path);
|
||||||
@@ -118,6 +125,17 @@ public:
|
|||||||
|
|
||||||
virtual void deflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
virtual void deflate(gourou::ByteArray& data, gourou::ByteArray& result,
|
||||||
int wbits=-15, int compressionLevel=8);
|
int wbits=-15, int compressionLevel=8);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
void padWithPKCS1(unsigned char* out, unsigned int outLength,
|
||||||
|
const unsigned char* in, unsigned int inLength);
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
OSSL_PROVIDER *legacy, *deflt;
|
||||||
|
#else
|
||||||
|
void *legacy, *deflt;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
40
utils/launcher.cpp
Normal file
40
utils/launcher.cpp
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utils_common.h"
|
||||||
|
|
||||||
|
#ifndef DEFAULT_UTIL
|
||||||
|
#define DEFAULT_UTIL "acsmdownloader"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Inspired from https://discourse.appimage.org/t/call-alternative-binary-from-appimage/93/10*/
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
char* util, *argv0;
|
||||||
|
char* mountPoint = getenv("APPDIR");
|
||||||
|
std::string fullPath;
|
||||||
|
|
||||||
|
/* Original command is in ARGV0 env variable*/
|
||||||
|
argv0 = strdup(getenv("ARGV0"));
|
||||||
|
util = basename(argv0);
|
||||||
|
|
||||||
|
fullPath = std::string(mountPoint) + util;
|
||||||
|
|
||||||
|
if (std::string(util) == "launcher" || !fileExists(fullPath.c_str()))
|
||||||
|
fullPath = std::string(mountPoint) + DEFAULT_UTIL;
|
||||||
|
|
||||||
|
free(argv0);
|
||||||
|
|
||||||
|
argv[0] = strdup(fullPath.c_str());
|
||||||
|
|
||||||
|
if (execvp(argv[0], argv))
|
||||||
|
std::cout << "Unable to launch '" << argv[0] << "'" << std::endl;
|
||||||
|
|
||||||
|
/* Should not happens */
|
||||||
|
free(argv[0]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user