Re: [Podofo-users] what is the status of AES Decrypt/Encrypt
A PDF parsing, modification and creation library.
Brought to you by:
domseichter
|
From: Andreas B. <and...@do...> - 2014-03-31 12:05:02
|
Index: src/base/PdfEncrypt.cpp
===================================================================
--- src/base/PdfEncrypt.cpp (revision 1586)
+++ src/base/PdfEncrypt.cpp (working copy)
@@ -352,8 +352,8 @@
{
if (pTotalLeft == 0)
PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption needs pTotalLeft" );
- if( lLen % keyLen != 0 )
- PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data length not a multiple of the key length" );
+ if( lLen % 16 != 0 )
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data length not a multiple of 16" );
EVP_CIPHER_CTX* aes = m_aes->getEngine();
int lOutLen = 0, lStepOutLen;
int status = 1;
@@ -370,12 +370,12 @@
}
if(status != 1)
PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES encryption engine" );
- status = EVP_DecryptUpdate( aes, pBuffer, &lOutLen, pBuffer + keyLen, lLen - keyLen );
+ status = EVP_DecryptUpdate( aes, pBuffer, &lOutLen, pBuffer + AES_IV_LENGTH, lLen - AES_IV_LENGTH );
} else if( !bOnlyFinalLeft ) {
// Quote openssl.org: "the decrypted data buffer out passed to EVP_DecryptUpdate() should have sufficient room
// for (inl + cipher_block_size) bytes unless the cipher block size is 1 in which case inl bytes is sufficient."
// So we need to create a buffer that is bigger than lLen.
- unsigned char* tempBuffer = new unsigned char[lLen + keyLen];
+ unsigned char* tempBuffer = new unsigned char[lLen + 16];
status = EVP_DecryptUpdate( aes, tempBuffer, &lOutLen, pBuffer, lLen );
memcpy( pBuffer, tempBuffer, lOutLen );
delete[] tempBuffer;
@@ -387,7 +387,7 @@
if( lLen == lOutLen ) {
// Buffer is full, so we need an other round for EVP_DecryptFinal_ex.
bOnlyFinalLeft = true;
- *pTotalLeft += keyLen;
+ *pTotalLeft += 16;
} else {
status = EVP_DecryptFinal_ex( aes, pBuffer + lOutLen, &lStepOutLen );
if( status != 1 )
@@ -909,11 +909,7 @@
nkey[m_keyLength+3] = static_cast<unsigned char>(0xff & g);
nkey[m_keyLength+4] = static_cast<unsigned char>(0xff & (g >> 8));
- if (m_eAlgorithm == ePdfEncryptAlgorithm_AESV2
-#ifdef PODOFO_HAVE_LIBIDN
- || m_eAlgorithm == ePdfEncryptAlgorithm_AESV3
-#endif
- )
+ if (m_eAlgorithm == ePdfEncryptAlgorithm_AESV2)
{
// AES encryption needs some 'salt'
nkeylen += 4;
@@ -1822,17 +1818,12 @@
int pswdLen;
PreprocessPassword(password, pswd_sasl, pswdLen);
- unsigned char valSalt[8];
- unsigned char keySalt[8];
-
// Test 1: is it the user key ?
- memcpy(valSalt, &m_uValue[32], 8);
- memcpy(keySalt, &m_uValue[40], 8);
unsigned char hashValue[32];
SHA256_CTX context;
SHA256_Init(&context);
- SHA256_Update(&context, pswd_sasl, pswdLen);
- SHA256_Update(&context, valSalt, 8);
+ SHA256_Update(&context, pswd_sasl, pswdLen); // password
+ SHA256_Update(&context, m_uValue + 32, 8); // user Validation Salt
SHA256_Final(hashValue, &context);
ok = CheckKey(hashValue, m_uValue);
@@ -1839,21 +1830,54 @@
if(!ok)
{
// Test 2: is it the owner key ?
- memcpy(valSalt, &m_oValue[32], 8);
- memcpy(keySalt, &m_oValue[40], 8);
SHA256_Init(&context);
- SHA256_Update(&context, pswd_sasl, pswdLen);
- SHA256_Update(&context, valSalt, 8);
- SHA256_Update(&context, m_uValue, 48);
+ SHA256_Update(&context, pswd_sasl, pswdLen); // password
+ SHA256_Update(&context, m_oValue + 32, 8); // owner Validation Salt
+ SHA256_Update(&context, m_uValue, 48); // U string
SHA256_Final(hashValue, &context);
ok = CheckKey(hashValue, m_oValue);
if(ok)
+ {
m_ownerPass = password;
+ // ISO 32000: "Compute an intermediate owner key by computing the SHA-256 hash of
+ // the UTF-8 password concatenated with the 8 bytes of owner Key Salt, concatenated with the 48-byte U string."
+ SHA256_Init(&context);
+ SHA256_Update(&context, pswd_sasl, pswdLen); // password
+ SHA256_Update(&context, m_oValue + 40, 8); // owner Key Salt
+ SHA256_Update(&context, m_uValue, 48); // U string
+ SHA256_Final(hashValue, &context);
+
+ // ISO 32000: "The 32-byte result is the key used to decrypt the 32-byte OE string using
+ // AES-256 in CBC mode with no padding and an initialization vector of zero.
+ // The 32-byte result is the file encryption key"
+ EVP_CIPHER_CTX* aes = m_aes->getEngine();
+ EVP_DecryptInit_ex( aes, EVP_aes_256_cbc(), NULL, hashValue, 0 ); // iv zero
+ EVP_CIPHER_CTX_set_padding( aes, 0 ); // no padding
+ int lOutLen;
+ EVP_DecryptUpdate( aes, m_encryptionKey, &lOutLen, m_oeValue, 32 );
+ }
}
else
+ {
m_userPass = password;
+ // ISO 32000: "Compute an intermediate user key by computing the SHA-256 hash of
+ // the UTF-8 password concatenated with the 8 bytes of user Key Salt"
+ SHA256_Init(&context);
+ SHA256_Update(&context, pswd_sasl, pswdLen); // password
+ SHA256_Update(&context, m_uValue + 40, 8); // user Key Salt
+ SHA256_Final(hashValue, &context);
+
+ // ISO 32000: "The 32-byte result is the key used to decrypt the 32-byte UE string using
+ // AES-256 in CBC mode with no padding and an initialization vector of zero.
+ // The 32-byte result is the file encryption key"
+ EVP_CIPHER_CTX* aes = m_aes->getEngine();
+ EVP_DecryptInit_ex( aes, EVP_aes_256_cbc(), NULL, hashValue, 0 ); // iv zero
+ EVP_CIPHER_CTX_set_padding( aes, 0 ); // no padding
+ int lOutLen;
+ EVP_DecryptUpdate( aes, m_encryptionKey, &lOutLen, m_ueValue, 32 );
+ }
// TODO Validate permissions (or not...)
@@ -1934,9 +1958,9 @@
return realLength;
}
-PdfInputStream* PdfEncryptAESV3::CreateEncryptionInputStream( PdfInputStream* )
+PdfInputStream* PdfEncryptAESV3::CreateEncryptionInputStream( PdfInputStream* pInputStream )
{
- PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "CreateEncryptionInputStream does not yet support AESV3" );
+ return new PdfAESInputStream( pInputStream, m_encryptionKey, 32 );
}
PdfOutputStream* PdfEncryptAESV3::CreateEncryptionOutputStream( PdfOutputStream* ) |