Factorize decryptADEPTKey() for ePub and PDF

This commit is contained in:
Grégory Soutadé 2022-12-21 20:56:26 +01:00
parent afab1c0012
commit 24bae89095
2 changed files with 54 additions and 75 deletions

View File

@ -232,7 +232,7 @@ namespace gourou
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); std::string encryptedKeyFirstPass(pugi::xml_document& rightsDoc, const std::string& encryptedKey, const std::string& keyType);
void decryptADEPTKey(const std::string& encryptedKey, unsigned char* decryptedKey); void decryptADEPTKey(pugi::xml_document& rightsDoc, unsigned char* decryptedKey, const unsigned char* encryptionKey=0, unsigned encryptionKeySize=0);
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,
const unsigned char* masterKey, unsigned int masterKeyLength, const unsigned char* masterKey, unsigned int masterKeyLength,

View File

@ -944,23 +944,6 @@ namespace gourou
int DRMProcessor::getLogLevel() {return (int)gourou::logLevel;} int DRMProcessor::getLogLevel() {return (int)gourou::logLevel;}
void DRMProcessor::setLogLevel(int logLevel) {gourou::logLevel = (GOUROU_LOG_LEVEL)logLevel;} void DRMProcessor::setLogLevel(int logLevel) {gourou::logLevel = (GOUROU_LOG_LEVEL)logLevel;}
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);
dumpBuffer(gourou::LG_LOG_DEBUG, "To decrypt : ", arrayEncryptedKey.data(), arrayEncryptedKey.length());
client->RSAPrivateDecrypt(privateRSAKey.data(), privateRSAKey.length(),
RSAInterface::RSA_KEY_PKCS8, "",
arrayEncryptedKey.data(), arrayEncryptedKey.length(), decryptedKey);
}
/** /**
* RSA Key can be over encrypted with AES128-CBC if keyType attribute is set * RSA Key can be over encrypted with AES128-CBC if keyType attribute is set
* remainder = keyType % 16 * remainder = keyType % 16
@ -1009,11 +992,10 @@ namespace gourou
for(unsigned int i=0; i<sizeof(iv); i++) for(unsigned int i=0; i<sizeof(iv); i++)
iv[i] = _deviceId[i] ^ _fulfillmentId[i] ^ _voucherId[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 key : ", key, sizeof(key));
dumpBuffer(gourou::LG_LOG_DEBUG, "First pass IV : ", iv, sizeof(iv)); dumpBuffer(gourou::LG_LOG_DEBUG, "First pass IV : ", iv, sizeof(iv));
ByteArray arrayEncryptedKey = ByteArray::fromBase64(encryptedKey);
unsigned char* clearRSAKey = new unsigned char[arrayEncryptedKey.size()]; unsigned char* clearRSAKey = new unsigned char[arrayEncryptedKey.size()];
client->decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC, client->decrypt(CryptoInterface::ALGO_AES, CryptoInterface::CHAIN_CBC,
@ -1042,6 +1024,50 @@ namespace gourou
return res.toBase64(); return res.toBase64();
} }
void DRMProcessor::decryptADEPTKey(pugi::xml_document& rightsDoc, unsigned char* decryptedKey, const unsigned char* encryptionKey, unsigned encryptionKeySize)
{
unsigned char rsaKey[RSA_KEY_SIZE];
if (!encryptionKey)
{
std::string encryptedKey = extractTextElem(rightsDoc, "/adept:rights/licenseToken/encryptedKey");
std::string keyType = extractTextAttribute(rightsDoc, "/adept:rights/licenseToken/encryptedKey", "keyType", false);
if (keyType != "")
encryptedKey = encryptedKeyFirstPass(rightsDoc, encryptedKey, keyType);
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);
dumpBuffer(gourou::LG_LOG_DEBUG, "To decrypt : ", arrayEncryptedKey.data(), arrayEncryptedKey.length());
client->RSAPrivateDecrypt(privateRSAKey.data(), privateRSAKey.length(),
RSAInterface::RSA_KEY_PKCS8, "",
arrayEncryptedKey.data(), arrayEncryptedKey.length(), rsaKey);
dumpBuffer(gourou::LG_LOG_DEBUG, "Decrypted : ", rsaKey, sizeof(rsaKey));
if (rsaKey[0] != 0x00 || rsaKey[1] != 0x02 ||
rsaKey[RSA_KEY_SIZE-16-1] != 0x00)
EXCEPTION(DRM_ERR_ENCRYPTION_KEY, "Unable to retrieve encryption key");
memcpy(decryptedKey, &rsaKey[sizeof(rsaKey)-16], 16);
}
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, encryptionKey, encryptionKeySize);
}
}
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)
{ {
@ -1053,32 +1079,9 @@ namespace gourou
pugi::xml_document rightsDoc; pugi::xml_document rightsDoc;
rightsDoc.load_string((const char*)zipData.data()); rightsDoc.load_string((const char*)zipData.data());
std::string encryptedKey = extractTextElem(rightsDoc, "/adept:rights/licenseToken/encryptedKey"); unsigned char decryptedKey[16];
unsigned char decryptedKey[RSA_KEY_SIZE];
if (!encryptionKey) decryptADEPTKey(rightsDoc, decryptedKey, encryptionKey, encryptionKeySize);
{
std::string keyType = extractTextAttribute(rightsDoc, "/adept:rights/licenseToken/encryptedKey", "keyType", false);
if (keyType != "")
encryptedKey = encryptedKeyFirstPass(rightsDoc, encryptedKey, keyType);
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
{
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); client->zipReadFile(zipHandler, "META-INF/encryption.xml", zipData);
pugi::xml_document encryptionDoc; pugi::xml_document encryptionDoc;
@ -1117,7 +1120,7 @@ namespace gourou
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), /* Key */
_data, 16, /* IV */ _data, 16, /* IV */
&_data[16], zipData.length()-16, &_data[16], zipData.length()-16,
_clearData, &dataOutLength); _clearData, &dataOutLength);
@ -1210,7 +1213,7 @@ namespace gourou
std::vector<uPDFParser::Object*> objects = parser.objects(); std::vector<uPDFParser::Object*> objects = parser.objects();
std::vector<uPDFParser::Object*>::iterator it; std::vector<uPDFParser::Object*>::iterator it;
std::vector<uPDFParser::Object*>::reverse_iterator rIt; std::vector<uPDFParser::Object*>::reverse_iterator rIt;
unsigned char decryptedKey[RSA_KEY_SIZE]; unsigned char decryptedKey[16];
int ebxId; int ebxId;
for(rIt = objects.rbegin(); rIt != objects.rend(); rIt++) for(rIt = objects.rbegin(); rIt != objects.rend(); rIt++)
@ -1249,31 +1252,7 @@ namespace gourou
pugi::xml_document rightsDoc; pugi::xml_document rightsDoc;
rightsDoc.load_string((const char*)rightsStr.data()); rightsDoc.load_string((const char*)rightsStr.data());
std::string encryptedKey = extractTextElem(rightsDoc, "/adept:rights/licenseToken/encryptedKey"); decryptADEPTKey(rightsDoc, decryptedKey, encryptionKey, encryptionKeySize);
if (!encryptionKey)
{
std::string keyType = extractTextAttribute(rightsDoc, "/adept:rights/licenseToken/encryptedKey", "keyType", false);
if (keyType != "")
encryptedKey = encryptedKeyFirstPass(rightsDoc, encryptedKey, keyType);
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
{
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(); ebxId = ebx->objectId();
@ -1305,10 +1284,10 @@ namespace gourou
GOUROU_LOG(DEBUG, "Obj " << object->objectId()); GOUROU_LOG(DEBUG, "Obj " << object->objectId());
unsigned char tmpKey[16]; unsigned char tmpKey[sizeof(decryptedKey)];
generatePDFObjectKey(ebxVersion->value(), generatePDFObjectKey(ebxVersion->value(),
decryptedKey+sizeof(decryptedKey)-16, 16, decryptedKey, sizeof(decryptedKey),
object->objectId(), object->generationNumber(), object->objectId(), object->generationNumber(),
tmpKey); tmpKey);