Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f475423c0 | ||
|
|
9b946a62b4 | ||
|
|
432eb6f6cb | ||
|
|
85b65f8d61 | ||
|
|
25f5049ab9 | ||
|
|
16a13eed89 | ||
|
|
479869b7f2 | ||
|
|
41f1a1e980 | ||
|
|
9648157bf7 | ||
|
|
a97a915bc8 | ||
|
|
a623a3d796 | ||
|
|
7d161133c3 | ||
|
|
7d93817e49 |
4
Makefile
4
Makefile
@@ -53,8 +53,8 @@ $(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
|
||||
|
||||
libgourou: libgourou.a libgourou.so
|
||||
|
||||
libgourou.a: $(OBJECTS)
|
||||
$(AR) crs $@ obj/*.o ./lib/updfparser/obj/*.o
|
||||
libgourou.a: $(OBJECTS) $(UPDFPARSERLIB)
|
||||
$(AR) crs $@ obj/*.o $(UPDFPARSERLIB)
|
||||
|
||||
libgourou.so: $(OBJECTS) $(UPDFPARSERLIB)
|
||||
$(CXX) obj/*.o $(LDFLAGS) -o $@ -shared
|
||||
|
||||
10
README.md
10
README.md
@@ -70,10 +70,10 @@ BUILD_SHARED build libgourou.so if 1, nothing if 0, can be combined with BUILD_S
|
||||
Utils
|
||||
-----
|
||||
|
||||
You can import configuration from your eReader or create a new one with utils/activate :
|
||||
You can import configuration from your eReader or create a new one with _utils/adept\_activate_ :
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./utils/activate -u <AdobeID USERNAME>
|
||||
./utils/adept_activate -u <AdobeID USERNAME>
|
||||
|
||||
Then a _./.adept_ directory is created with all configuration file
|
||||
|
||||
@@ -82,7 +82,7 @@ To download an ePub/PDF :
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./utils/acsmdownloader -f <ACSM_FILE>
|
||||
|
||||
To export your private key :
|
||||
To export your private key (for DeDRM software) :
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./utils/acsmdownloader --export-private-key [-o adobekey_1.der]
|
||||
@@ -92,6 +92,9 @@ To remove ADEPT DRM :
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./utils/adept_remove -f <encryptedFile>
|
||||
|
||||
You can get utils full options description with -h or --help switch
|
||||
|
||||
|
||||
|
||||
Copyright
|
||||
---------
|
||||
@@ -113,3 +116,4 @@ Special thanks
|
||||
--------------
|
||||
|
||||
* _Jens_ for all test samples and utils testing
|
||||
* _Milian_ for debug & code
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
Introduction
|
||||
------------
|
||||
|
||||
libgourou is a free implementation of Adobe's ADEPT protocol used to add DRM on ePub/PDF files. It overcome the lacks of Adobe support for Linux platforms.
|
||||
|
||||
|
||||
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
For libgourou :
|
||||
|
||||
* None
|
||||
|
||||
For utils :
|
||||
|
||||
* QT5Core
|
||||
* QT5Network
|
||||
* OpenSSL
|
||||
* libzip
|
||||
|
||||
|
||||
|
||||
Utils
|
||||
-----
|
||||
|
||||
You can import configuration from your eReader or create a new one with utils/activate :
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./activate -u <AdobeID USERNAME>
|
||||
|
||||
Then a _./.adept_ directory is created with all configuration file
|
||||
|
||||
To download an ePub/PDF :
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./acsmdownloader -f <ACSM_FILE>
|
||||
|
||||
To export your private key :
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./acsmdownloader --export-private-key [-o adobekey_1.der]
|
||||
|
||||
To remove ADEPT DRM :
|
||||
|
||||
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$PWD
|
||||
./adept_remove -f <encryptedFile>
|
||||
|
||||
|
||||
Copyright
|
||||
---------
|
||||
|
||||
Grégory Soutadé
|
||||
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
libgourou : LGPL v3 or later
|
||||
|
||||
utils : BSD
|
||||
|
||||
|
||||
|
||||
Special thanks
|
||||
--------------
|
||||
|
||||
* _Jens_ for all test samples and utils testing
|
||||
@@ -40,7 +40,7 @@
|
||||
#define ACS_SERVER "http://adeactivate.adobe.com/adept"
|
||||
#endif
|
||||
|
||||
#define LIBGOUROU_VERSION "0.5.1"
|
||||
#define LIBGOUROU_VERSION "0.5.3"
|
||||
|
||||
namespace gourou
|
||||
{
|
||||
@@ -185,10 +185,16 @@ namespace gourou
|
||||
DRMProcessorClient* getClient() { return client; }
|
||||
|
||||
/**
|
||||
* @brief Remove ADEPT DRM.
|
||||
* @brief Remove ADEPT DRM
|
||||
* Warning: for PDF format, filenameIn must be different than filenameOut
|
||||
*
|
||||
* @param filenameIn Input file (with ADEPT DRM)
|
||||
* @param filenameOut Output file (without ADEPT DRM)
|
||||
* @param type Type of file (ePub or PDF)
|
||||
* @param encryptionKey Optional encryption key, do not try to decrypt the one inside input file
|
||||
* @param encryptionKeySize Size of encryption key (if provided)
|
||||
*/
|
||||
void removeDRM(const std::string& filenameIn, const std::string& filenameOut, ITEM_TYPE type);
|
||||
void removeDRM(const std::string& filenameIn, const std::string& filenameOut, ITEM_TYPE type, const unsigned char* encryptionKey=0, unsigned encryptionKeySize=0);
|
||||
|
||||
private:
|
||||
gourou::DRMProcessorClient* client;
|
||||
@@ -214,12 +220,12 @@ namespace gourou
|
||||
void fetchLicenseServiceCertificate(const std::string& licenseURL,
|
||||
const std::string& operatorURL);
|
||||
void decryptADEPTKey(const std::string& encryptedKey, unsigned char* decryptedKey);
|
||||
void removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut);
|
||||
void removeEPubDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
||||
void generatePDFObjectKey(int version,
|
||||
const unsigned char* masterKey, unsigned int masterKeyLength,
|
||||
int objectId, int objectGenerationNumber,
|
||||
unsigned char* keyOut);
|
||||
void removePDFDRM(const std::string& filenameIn, const std::string& filenameOut);
|
||||
void removePDFDRM(const std::string& filenameIn, const std::string& filenameOut, const unsigned char* encryptionKey, unsigned encryptionKeySize);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -92,6 +92,7 @@ namespace gourou
|
||||
USER_INVALID_ACTIVATION_FILE,
|
||||
USER_NO_AUTHENTICATION_URL,
|
||||
USER_NO_PROPERTY,
|
||||
USER_INVALID_INPUT,
|
||||
};
|
||||
|
||||
enum FULFILL_ITEM_ERROR {
|
||||
@@ -110,6 +111,7 @@ namespace gourou
|
||||
CLIENT_ZIP_ERROR,
|
||||
CLIENT_GENERIC_EXCEPTION,
|
||||
CLIENT_NETWORK_ERROR,
|
||||
CLIENT_INVALID_PKCS8
|
||||
};
|
||||
|
||||
enum DRM_REMOVAL_ERROR {
|
||||
@@ -118,7 +120,8 @@ namespace gourou
|
||||
DRM_FILE_ERROR,
|
||||
DRM_FORMAT_NOT_SUPPORTED,
|
||||
DRM_IN_OUT_EQUALS,
|
||||
DRM_MISSING_PARAMETER
|
||||
DRM_MISSING_PARAMETER,
|
||||
DRM_INVALID_KEY_SIZE
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -927,8 +927,12 @@ namespace gourou
|
||||
|
||||
void DRMProcessor::decryptADEPTKey(const std::string& encryptedKey, unsigned char* decryptedKey)
|
||||
{
|
||||
if (encryptedKey.size() != 172)
|
||||
EXCEPTION(DRM_INVALID_KEY_SIZE, "Invalid encrypted key size (" << encryptedKey.size() << "). DRM version not supported");
|
||||
|
||||
ByteArray arrayEncryptedKey = ByteArray::fromBase64(encryptedKey);
|
||||
|
||||
|
||||
std::string privateKeyData = user->getPrivateLicenseKey();
|
||||
ByteArray privateRSAKey = ByteArray::fromBase64(privateKeyData);
|
||||
|
||||
@@ -945,7 +949,8 @@ namespace gourou
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
ByteArray zipData;
|
||||
bool removeEncryptionXML = true;
|
||||
@@ -958,7 +963,16 @@ namespace gourou
|
||||
std::string encryptedKey = extractTextElem(rightsDoc, "/adept:rights/licenseToken/encryptedKey");
|
||||
unsigned char decryptedKey[RSA_KEY_SIZE];
|
||||
|
||||
decryptADEPTKey(encryptedKey, decryptedKey);
|
||||
if (!encryptionKey)
|
||||
decryptADEPTKey(encryptedKey, decryptedKey);
|
||||
else
|
||||
{
|
||||
GOUROU_LOG(DEBUG, "Use provided encryption key");
|
||||
if (encryptionKeySize != 16)
|
||||
EXCEPTION(DRM_ERR_ENCRYPTION_KEY, "Provided encryption key must be 16 bytes");
|
||||
|
||||
memcpy(&decryptedKey[sizeof(decryptedKey)-16], encryptionKey, encryptionKeySize);
|
||||
}
|
||||
|
||||
client->zipReadFile(zipHandler, "META-INF/encryption.xml", zipData);
|
||||
pugi::xml_document encryptionDoc;
|
||||
@@ -997,7 +1011,7 @@ namespace gourou
|
||||
unsigned int dataOutLength;
|
||||
|
||||
client->Decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
|
||||
decryptedKey+RSA_KEY_SIZE-16, 16, /* Key */
|
||||
decryptedKey+sizeof(decryptedKey)-16, 16, /* Key */
|
||||
_data, 16, /* IV */
|
||||
&_data[16], zipData.length()-16,
|
||||
_clearData, &dataOutLength);
|
||||
@@ -1006,9 +1020,20 @@ namespace gourou
|
||||
_clearData[dataOutLength] = 'Z';
|
||||
clearData.resize(dataOutLength+1);
|
||||
|
||||
client->inflate(clearData, inflateData);
|
||||
|
||||
client->zipWriteFile(zipHandler, encryptedFile, inflateData);
|
||||
try
|
||||
{
|
||||
client->inflate(clearData, inflateData);
|
||||
client->zipWriteFile(zipHandler, encryptedFile, inflateData);
|
||||
}
|
||||
catch(gourou::Exception& e)
|
||||
{
|
||||
if (e.getErrorCode() == CLIENT_ZIP_ERROR)
|
||||
{
|
||||
GOUROU_LOG(ERROR, e.what() << std::endl << "Skip file " << encryptedFile);
|
||||
}
|
||||
else
|
||||
throw e;
|
||||
}
|
||||
|
||||
it->node().parent().remove_child(it->node());
|
||||
}
|
||||
@@ -1053,7 +1078,8 @@ namespace gourou
|
||||
}
|
||||
}
|
||||
|
||||
void DRMProcessor::removePDFDRM(const std::string& filenameIn, const std::string& filenameOut)
|
||||
void DRMProcessor::removePDFDRM(const std::string& filenameIn, const std::string& filenameOut,
|
||||
const unsigned char* encryptionKey, unsigned encryptionKeySize)
|
||||
{
|
||||
uPDFParser::Parser parser;
|
||||
bool EBXHandlerFound = false;
|
||||
@@ -1076,16 +1102,18 @@ namespace gourou
|
||||
|
||||
uPDFParser::Integer* ebxVersion;
|
||||
std::vector<uPDFParser::Object*> objects = parser.objects();
|
||||
std::vector<uPDFParser::Object*>::reverse_iterator it;
|
||||
std::vector<uPDFParser::Object*>::iterator it;
|
||||
std::vector<uPDFParser::Object*>::reverse_iterator rIt;
|
||||
unsigned char decryptedKey[RSA_KEY_SIZE];
|
||||
int ebxId;
|
||||
|
||||
for(it = objects.rbegin(); it != objects.rend(); it++)
|
||||
for(rIt = objects.rbegin(); rIt != objects.rend(); rIt++)
|
||||
{
|
||||
// Update EBX_HANDLER with rights
|
||||
if ((*it)->hasKey("Filter") && (**it)["Filter"]->str() == "/EBX_HANDLER")
|
||||
if ((*rIt)->hasKey("Filter") && (**rIt)["Filter"]->str() == "/EBX_HANDLER")
|
||||
{
|
||||
EBXHandlerFound = true;
|
||||
uPDFParser::Object* ebx = *it;
|
||||
uPDFParser::Object* ebx = *rIt;
|
||||
|
||||
ebxVersion = (uPDFParser::Integer*)(*ebx)["V"];
|
||||
if (ebxVersion->value() != 4)
|
||||
@@ -1100,7 +1128,15 @@ namespace gourou
|
||||
|
||||
uPDFParser::String* licenseObject = (uPDFParser::String*)(*ebx)["ADEPT_LICENSE"];
|
||||
|
||||
ByteArray zippedData = ByteArray::fromBase64(licenseObject->value());
|
||||
std::string value = licenseObject->value();
|
||||
// Pad with '='
|
||||
while ((value.size() % 4))
|
||||
value += "=";
|
||||
ByteArray zippedData = ByteArray::fromBase64(value);
|
||||
|
||||
if (zippedData.size() == 0)
|
||||
EXCEPTION(DRM_ERR_ENCRYPTION_KEY, "Invalid ADEPT_LICENSE");
|
||||
|
||||
ByteArray rightsStr;
|
||||
client->inflate(zippedData, rightsStr);
|
||||
|
||||
@@ -1109,7 +1145,19 @@ namespace gourou
|
||||
|
||||
std::string encryptedKey = extractTextElem(rightsDoc, "/adept:rights/licenseToken/encryptedKey");
|
||||
|
||||
decryptADEPTKey(encryptedKey, decryptedKey);
|
||||
if (!encryptionKey)
|
||||
decryptADEPTKey(encryptedKey, decryptedKey);
|
||||
else
|
||||
{
|
||||
GOUROU_LOG(DEBUG, "Use provided encryption key");
|
||||
if (encryptionKeySize != 16)
|
||||
EXCEPTION(DRM_ERR_ENCRYPTION_KEY, "Provided encryption key must be 16 bytes");
|
||||
|
||||
memcpy(&decryptedKey[sizeof(decryptedKey)-16], encryptionKey, encryptionKeySize);
|
||||
}
|
||||
|
||||
ebxId = ebx->objectId();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1119,28 +1167,29 @@ namespace gourou
|
||||
EXCEPTION(DRM_ERR_ENCRYPTION_KEY, "EBX_HANDLER not found");
|
||||
}
|
||||
|
||||
std::vector<uPDFParser::XRefValue> xrefTable = parser.xrefTable();
|
||||
std::vector<uPDFParser::XRefValue>::iterator xrefIt;
|
||||
|
||||
for(xrefIt = xrefTable.begin(); xrefIt != xrefTable.end(); xrefIt++)
|
||||
for(it = objects.begin(); it != objects.end(); it++)
|
||||
{
|
||||
GOUROU_LOG(DEBUG, "XREF obj " << (*xrefIt).objectId() << " used " << (*xrefIt).used());
|
||||
uPDFParser::Object* object = *it;
|
||||
|
||||
if (!(*xrefIt).used())
|
||||
continue;
|
||||
|
||||
uPDFParser::Object* object = (*xrefIt).object();
|
||||
|
||||
if (!object)
|
||||
if (object->objectId() == ebxId)
|
||||
{
|
||||
GOUROU_LOG(DEBUG, "No object");
|
||||
// object->deleteKey("Filter");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Should not decrypt XRef stream
|
||||
if (object->hasKey("Type") && (*object)["Type"]->str() == "/XRef")
|
||||
{
|
||||
GOUROU_LOG(DEBUG, "XRef stream at " << object->offset());
|
||||
continue;
|
||||
}
|
||||
|
||||
GOUROU_LOG(DEBUG, "Obj " << object->objectId());
|
||||
|
||||
unsigned char tmpKey[16];
|
||||
|
||||
generatePDFObjectKey(ebxVersion->value(),
|
||||
decryptedKey+RSA_KEY_SIZE-16, 16,
|
||||
decryptedKey+sizeof(decryptedKey)-16, 16,
|
||||
object->objectId(), object->generationNumber(),
|
||||
tmpKey);
|
||||
|
||||
@@ -1182,7 +1231,7 @@ namespace gourou
|
||||
dictionary.replace(dictIt->first, dictIt->second);
|
||||
|
||||
std::vector<uPDFParser::DataType*>::iterator datasIt;
|
||||
std::vector<uPDFParser::DataType*>& datas = (*xrefIt).object()->data();
|
||||
std::vector<uPDFParser::DataType*>& datas = object->data();
|
||||
uPDFParser::Stream* stream;
|
||||
|
||||
for (datasIt = datas.begin(); datasIt != datas.end(); datasIt++)
|
||||
@@ -1190,14 +1239,14 @@ namespace gourou
|
||||
if ((*datasIt)->type() != uPDFParser::DataType::STREAM)
|
||||
continue;
|
||||
|
||||
GOUROU_LOG(DEBUG, "Decrypt stream id " << object->objectId());
|
||||
|
||||
stream = (uPDFParser::Stream*) (*datasIt);
|
||||
unsigned char* encryptedData = stream->data();
|
||||
unsigned int dataLength = stream->dataLength();
|
||||
unsigned char* clearData = new unsigned char[dataLength];
|
||||
unsigned int dataOutLength;
|
||||
|
||||
GOUROU_LOG(DEBUG, "Decrypt stream id " << object->objectId() << ", size " << stream->dataLength());
|
||||
|
||||
client->Decrypt(CryptoInterface::ALGO_RC4, CryptoInterface::CHAIN_ECB,
|
||||
tmpKey, 16, /* Key */
|
||||
NULL, 0, /* IV */
|
||||
@@ -1205,6 +1254,8 @@ namespace gourou
|
||||
clearData, &dataOutLength);
|
||||
|
||||
stream->setData(clearData, dataOutLength, true);
|
||||
if (dataOutLength != dataLength)
|
||||
GOUROU_LOG(DEBUG, "New size " << dataOutLength);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1215,11 +1266,11 @@ namespace gourou
|
||||
}
|
||||
|
||||
void DRMProcessor::removeDRM(const std::string& filenameIn, const std::string& filenameOut,
|
||||
ITEM_TYPE type)
|
||||
ITEM_TYPE type, const unsigned char* encryptionKey, unsigned encryptionKeySize)
|
||||
{
|
||||
if (type == PDF)
|
||||
removePDFDRM(filenameIn, filenameOut);
|
||||
removePDFDRM(filenameIn, filenameOut, encryptionKey, encryptionKeySize);
|
||||
else
|
||||
removeEPubDRM(filenameIn, filenameOut);
|
||||
removeEPubDRM(filenameIn, filenameOut, encryptionKey, encryptionKeySize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,17 +282,19 @@ int main(int argc, char** argv)
|
||||
goto end;
|
||||
if (key == 'y' || key == 'Y')
|
||||
break;
|
||||
// Clean STDIN buf
|
||||
while ((key = getchar()) != '\n')
|
||||
;
|
||||
}
|
||||
|
||||
// Clean STDIN buf
|
||||
while ((key = getchar()) != '\n')
|
||||
;
|
||||
}
|
||||
|
||||
std::string pass;
|
||||
if (!password)
|
||||
{
|
||||
char prompt[128];
|
||||
std::snprintf(prompt, sizeof(prompt), "Enter password for <%s> : ", username);
|
||||
std::string pass = getpass((const char*)prompt, false);
|
||||
pass = getpass((const char*)prompt, false);
|
||||
password = pass.c_str();
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,23 @@ static const char* defaultDirs[] = {
|
||||
"./adobe-digital-editions/",
|
||||
"./.adobe-digital-editions/"
|
||||
};
|
||||
static char* encryptionKeyUser = 0;
|
||||
static unsigned char* encryptionKey = 0;
|
||||
static unsigned encryptionKeySize = 0;
|
||||
|
||||
static inline unsigned char htoi(unsigned char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
c -= '0';
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
c -= 'a' - 10;
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
c -= 'A' - 10;
|
||||
else
|
||||
EXCEPTION(gourou::USER_INVALID_INPUT, "Invalid character " << c << " in encryption key");
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline bool endsWith(const std::string& s, const std::string& suffix)
|
||||
{
|
||||
@@ -110,7 +127,7 @@ public:
|
||||
{
|
||||
EXCEPTION(gourou::DRM_FILE_ERROR, "Unable to copy " << inputFile << " into " << filename);
|
||||
}
|
||||
processor.removeDRM(inputFile, filename, type);
|
||||
processor.removeDRM(inputFile, filename, type, encryptionKey, encryptionKeySize);
|
||||
std::cout << "DRM removed into new file " << filename << std::endl;
|
||||
}
|
||||
else
|
||||
@@ -121,7 +138,7 @@ public:
|
||||
QTemporaryFile tempFile;
|
||||
tempFile.open();
|
||||
tempFile.setAutoRemove(false); // In case of failure
|
||||
processor.removeDRM(inputFile, tempFile.fileName().toStdString(), type);
|
||||
processor.removeDRM(inputFile, tempFile.fileName().toStdString(), type, encryptionKey, encryptionKeySize);
|
||||
/* Original file must be removed before doing a copy... */
|
||||
QFile origFile(inputFile);
|
||||
origFile.remove();
|
||||
@@ -132,7 +149,7 @@ public:
|
||||
tempFile.setAutoRemove(true);
|
||||
}
|
||||
else
|
||||
processor.removeDRM(inputFile, filename, type);
|
||||
processor.removeDRM(inputFile, filename, type, encryptionKey, encryptionKeySize);
|
||||
std::cout << "DRM removed from " << filename << std::endl;
|
||||
}
|
||||
} catch(std::exception& e)
|
||||
@@ -213,14 +230,14 @@ int main(int argc, char** argv)
|
||||
{"output-dir", required_argument, 0, 'O' },
|
||||
{"output-file", required_argument, 0, 'o' },
|
||||
{"input-file", required_argument, 0, 'f' },
|
||||
{"export-private-key",no_argument, 0, 'e' },
|
||||
{"encryption-key", required_argument, 0, 'K' }, // Private option
|
||||
{"verbose", no_argument, 0, 'v' },
|
||||
{"version", no_argument, 0, 'V' },
|
||||
{"help", no_argument, 0, 'h' },
|
||||
{0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
c = getopt_long(argc, argv, "d:a:k:O:o:f:evVh",
|
||||
c = getopt_long(argc, argv, "d:a:k:O:o:f:K:vVh",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
@@ -244,6 +261,9 @@ int main(int argc, char** argv)
|
||||
case 'o':
|
||||
outputFile = optarg;
|
||||
break;
|
||||
case 'K':
|
||||
encryptionKeyUser = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
verbose++;
|
||||
break;
|
||||
@@ -286,6 +306,32 @@ int main(int argc, char** argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (encryptionKeyUser)
|
||||
{
|
||||
int size = std::string(encryptionKeyUser).size();
|
||||
if ((size % 2))
|
||||
{
|
||||
std::cout << "Error : Encryption key must be odd length" << std::endl;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (encryptionKeyUser[0] == '0' && encryptionKeyUser[1] == 'x')
|
||||
{
|
||||
encryptionKeyUser += 2;
|
||||
size -= 2;
|
||||
}
|
||||
|
||||
encryptionKey = new unsigned char[size/2];
|
||||
|
||||
for(i=0; i<size; i+=2)
|
||||
{
|
||||
encryptionKey[i/2] = htoi(encryptionKeyUser[i]) << 4;
|
||||
encryptionKey[i/2] |= htoi(encryptionKeyUser[i+1]);
|
||||
}
|
||||
|
||||
encryptionKeySize = size/2;
|
||||
}
|
||||
|
||||
if (hasErrors)
|
||||
goto end;
|
||||
|
||||
@@ -300,5 +346,8 @@ end:
|
||||
free((void*)*files[i]);
|
||||
}
|
||||
|
||||
if (encryptionKey)
|
||||
free(encryptionKey);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,20 @@ void DRMProcessorClientImpl::randBytes(unsigned char* bytesOut, unsigned int len
|
||||
}
|
||||
|
||||
/* HTTP interface */
|
||||
#define DISPLAY_THRESHOLD 10*1024 // Threshold to display download progression
|
||||
|
||||
static void downloadProgress(qint64 bytesReceived, qint64 bytesTotal) {
|
||||
// For "big" files only
|
||||
if (bytesTotal >= DISPLAY_THRESHOLD && gourou::logLevel >= gourou::WARN)
|
||||
{
|
||||
int percent = 0;
|
||||
if (bytesTotal)
|
||||
percent = (bytesReceived * 100) / bytesTotal;
|
||||
|
||||
std::cout << "\rDownload " << percent << "%" << std::flush;
|
||||
}
|
||||
}
|
||||
|
||||
std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, const std::string& POSTData, const std::string& contentType, std::map<std::string, std::string>* responseHeaders)
|
||||
{
|
||||
QNetworkRequest request(QUrl(URL.c_str()));
|
||||
@@ -112,10 +126,14 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
||||
else
|
||||
reply = networkManager.get(request);
|
||||
|
||||
QCoreApplication* app = QCoreApplication::instance();
|
||||
networkManager.moveToThread(app->thread());
|
||||
while (!reply->isFinished())
|
||||
app->processEvents();
|
||||
QEventLoop loop;
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
// Handled just below
|
||||
QObject::connect(reply, &QNetworkReply::errorOccurred, &loop, &QEventLoop::quit);
|
||||
QObject::connect(reply, &QNetworkReply::downloadProgress, &loop, downloadProgress);
|
||||
|
||||
loop.exec();
|
||||
|
||||
QByteArray location = reply->rawHeader("Location");
|
||||
if (location.size() != 0)
|
||||
@@ -136,6 +154,8 @@ std::string DRMProcessorClientImpl::sendHTTPRequest(const std::string& URL, cons
|
||||
}
|
||||
|
||||
replyData = reply->readAll();
|
||||
if (replyData.size() >= DISPLAY_THRESHOLD && gourou::logLevel >= gourou::WARN)
|
||||
std::cout << std::endl;
|
||||
if (reply->rawHeader("Content-Type") == "application/vnd.adobe.adept+xml")
|
||||
{
|
||||
GOUROU_LOG(gourou::DEBUG, ">>> " << std::endl << replyData.data());
|
||||
@@ -184,7 +204,7 @@ void DRMProcessorClientImpl::RSAPrivateDecrypt(const unsigned char* RSAKey, unsi
|
||||
PKCS8_PRIV_KEY_INFO* p8inf = d2i_PKCS8_PRIV_KEY_INFO_bio(mem, NULL);
|
||||
|
||||
if (!p8inf)
|
||||
EXCEPTION(gourou::CLIENT_INVALID_PKCS12, ERR_error_string(ERR_get_error(), NULL));
|
||||
EXCEPTION(gourou::CLIENT_INVALID_PKCS8, ERR_error_string(ERR_get_error(), NULL));
|
||||
|
||||
EVP_PKEY* pkey = EVP_PKCS82PKEY(p8inf);
|
||||
RSA * rsa;
|
||||
@@ -510,7 +530,12 @@ void DRMProcessorClientImpl::inflate(gourou::ByteArray& data, gourou::ByteArray&
|
||||
ret = ::inflate(&infstream, Z_FINISH);
|
||||
while (ret == Z_OK || ret == Z_STREAM_END || ret == Z_BUF_ERROR)
|
||||
{
|
||||
// Real error
|
||||
if (ret == Z_BUF_ERROR && infstream.avail_out == (uInt)dataSize)
|
||||
break;
|
||||
|
||||
result.append(buffer, dataSize-infstream.avail_out);
|
||||
|
||||
if ((ret == Z_OK && infstream.avail_out != 0) || ret == Z_STREAM_END)
|
||||
break;
|
||||
infstream.avail_out = (uInt)dataSize; // size of output
|
||||
@@ -518,7 +543,6 @@ void DRMProcessorClientImpl::inflate(gourou::ByteArray& data, gourou::ByteArray&
|
||||
ret = ::inflate(&infstream, Z_FINISH);
|
||||
}
|
||||
|
||||
|
||||
if (ret == Z_STREAM_END)
|
||||
ret = inflateEnd(&infstream);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user