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
--

dots

Andreas Brzesowsky

dots Software GmbH
Schlesische Str. 27, 10997 Berlin, Germany
Phone: +49 (0)30 695 799-34, Fax: +49 (0)30 695 799-55

andreas.brzesow...@dots.de
http://www.dots.de

Amtsgericht (District Court): Berlin Charlottenburg HRB 65201
Geschäftsführer (Managing Directors): Olaf Lorenz, Ken Osuga

Follow us on: Twitter Youtube Xing
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

Reply via email to