Am 11.03.2014 08:50, schrieb zyx:By the way, would you mind to look on AESv3 too? As you mentioned earlier, with AESv2 being done the AESv3 should not be a big problem, and you have the code fresh in your mind, thus it might be even easier for you? Maybe :)Hi, okay now I have the patch for AESv3 decryption finished: - PdfAESStream::Decrypt - Corrected block size to 16, as AESv3 block size and IV size is still 16, not key length - PdfEncryptMD5Base::CreateObjKey - Removed ePdfEncryptAlgorithm_AESV3 condition, because AESv3 does never use object key, it always uses the file key - PdfEncryptAESV3::Authenticate - Getting the file key (m_encryptionKey) was missing - PdfEncryptAESV3::CreateEncryptionInputStream - Create PdfAESInputStream with m_encryptionKey, because AESv3 does never use object key, it always uses the file key Bye Andreas --
Andreas Brzesowsky
dots Software GmbH http://www.dots.de
Amtsgericht (District Court): Berlin Charlottenburg HRB 65201
|
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* )
------------------------------------------------------------------------------
_______________________________________________ Podofo-users mailing list Podofo-users@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/podofo-users