Hi,

yes, it's possible to always call idn_free. Changed this with attached patch. But only in Windows it is necessary to use this function, because of the heap concept of Windows. So the same reason why use podofo_free that always calls just free in the context of the module.

Regards

Andy

Am 01.02.2022 um 08:33 schrieb zyx:
On Mon, 2022-01-31 at 17:59 +0100, Andreas Brzesowsky wrote:
+#ifdef _WIN32
+    // In Windows the libidn.dll could use an other heap and then
the normal free will crash.
+    idn_free(password_sasl);
+#else
        Hi,
would it make sense to always call the right function, not only
sometimes? If the two can differ, no matter if only sometimes or
always, then I'd say it's better to always use the right function.

Pity the stringprep_profile() man page does not specify what function
should be used to free the output buffer.

It seems the idn_free() calls just free() on Linux, thus it might be
possible to use that function unconditionally.
        Bye,
        zyx


_______________________________________________
Podofo-users mailing list
Podofo-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/podofo-users

--

dots Software <http://www.dots.de/en/>

Andreas Brzesowsky
Software Developer

dots Gesellschaft für Softwareentwicklung mbH
Schlesische Str. 27, 10997 Berlin, Germany

Tel: +49 (0)30 695 799-33

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

District court | Amtsgericht: Berlin Charlottenburg HRB 65201
Managing Director | Geschäftsführer: Katsuji Kondo
Index: src/podofo/base/PdfEncrypt.cpp
===================================================================
--- src/podofo/base/PdfEncrypt.cpp      (revision 2047)
+++ src/podofo/base/PdfEncrypt.cpp      (working copy)
@@ -45,7 +45,9 @@
 typedef SSIZE_T ssize_t;
 #endif
 #include <stringprep.h>
+#include <idn-free.h> // The entry point to the Windows memory de-allocation 
function
 #include <openssl/sha.h>
+#include <openssl/aes.h>
 #endif // PODOFO_HAVE_LIBIDN
 
 #include <openssl/opensslconf.h>
@@ -68,7 +70,8 @@
 ePdfEncryptAlgorithm_RC4V2 |
 #endif // PODOFO_HAVE_OPENSSL_NO_RC4
 ePdfEncryptAlgorithm_AESV2 |
-ePdfEncryptAlgorithm_AESV3;
+ePdfEncryptAlgorithm_AESV3 |
+ePdfEncryptAlgorithm_AESV3R6;
 #else // PODOFO_HAVE_LIBIDN
 int PdfEncrypt::s_nEnabledEncryptionAlgorithms =
 #ifndef PODOFO_HAVE_OPENSSL_NO_RC4
@@ -527,7 +530,8 @@
             break;
 #ifdef PODOFO_HAVE_LIBIDN
         case ePdfEncryptAlgorithm_AESV3:
-            pdfEncrypt = new PdfEncryptAESV3(userPassword, ownerPassword, 
protection);
+        case ePdfEncryptAlgorithm_AESV3R6:
+            pdfEncrypt = new PdfEncryptAESV3(userPassword, ownerPassword, 
protection, eAlgorithm);
             break;
 #endif // PODOFO_HAVE_LIBIDN
 #ifndef PODOFO_HAVE_OPENSSL_NO_RC4
@@ -631,14 +635,16 @@
         pdfEncrypt = new PdfEncryptAESV2(oValue, uValue, pValue, 
encryptMetadata);      
     }
 #ifdef PODOFO_HAVE_LIBIDN
-    else if( (lV == 5L) && (rValue == 5L) 
-            && PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_AESV3 ) ) 
+    else if( (lV == 5L) && (
+            ( rValue == 5L && PdfEncrypt::IsEncryptionEnabled( 
ePdfEncryptAlgorithm_AESV3 ) ) 
+            || ( rValue == 6L && PdfEncrypt::IsEncryptionEnabled( 
ePdfEncryptAlgorithm_AESV3R6 ) ) ) )
     {
         PdfString permsValue   = pObject->GetDictionary().GetKey( 
PdfName("Perms") )->GetString();
         PdfString oeValue      = pObject->GetDictionary().GetKey( 
PdfName("OE") )->GetString();
         PdfString ueValue      = pObject->GetDictionary().GetKey( 
PdfName("UE") )->GetString();
         
-        pdfEncrypt = new PdfEncryptAESV3(oValue, oeValue, uValue, ueValue, 
pValue, permsValue);     
+        EPdfEncryptAlgorithm eAlgorithm = rValue == 6L ? 
ePdfEncryptAlgorithm_AESV3R6 : ePdfEncryptAlgorithm_AESV3;
+        pdfEncrypt = new PdfEncryptAESV3(oValue, oeValue, uValue, ueValue, 
pValue, permsValue, eAlgorithm);
     }
 #endif // PODOFO_HAVE_LIBIDN
     else
@@ -658,7 +664,7 @@
     if (rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV2)
         pdfEncrypt = new PdfEncryptAESV2(rhs);
 #ifdef PODOFO_HAVE_LIBIDN
-    else if (rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV3)
+    else if (rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV3 || 
rhs.m_eAlgorithm == ePdfEncryptAlgorithm_AESV3R6)
         pdfEncrypt = new PdfEncryptAESV3(rhs);
 #endif // PODOFO_HAVE_LIBIDN
 #ifndef PODOFO_HAVE_OPENSSL_NO_RC4
@@ -1229,6 +1235,7 @@
         case ePdfEncryptAlgorithm_AESV2:
 #ifdef PODOFO_HAVE_LIBIDN
         case ePdfEncryptAlgorithm_AESV3:
+        case ePdfEncryptAlgorithm_AESV3R6:
 #endif // PODOFO_HAVE_LIBIDN
             break;
     }
@@ -1505,6 +1512,70 @@
     memcpy( m_oeValue, static_cast<const PdfEncryptSHABase*>(ptr)->m_oeValue, 
sizeof(unsigned char) * 32 );
 }
     
+void PdfEncryptSHABase::ComputeHash(const unsigned char * pswd, int pswdLen, 
unsigned char salt[8], unsigned char uValue[48], unsigned char hashValue[32])
+{
+    SHA256_CTX sha256;
+    SHA256_Init(&sha256);
+    if(pswdLen)
+        SHA256_Update(&sha256, pswd, pswdLen);
+    SHA256_Update(&sha256, salt, 8);
+    if(uValue)
+        SHA256_Update(&sha256, uValue, 48);
+    SHA256_Final(hashValue, &sha256);
+    
+    if(m_rValue > 5) // AES-256 according to PDF 1.7 Adobe Extension Level 8 
(PDF 2.0)
+    {
+        SHA512_CTX sha384;
+        SHA512_CTX sha512;
+        AES_KEY aes;
+        int dataLen = 0;
+        int blockLen = 32; // Start with current SHA256 hash
+        unsigned char data[(127 + 64 + 48) * 64]; // 127 for password, 64 for 
hash up to SHA512, 48 for uValue
+        unsigned char block[64];
+        memcpy(block, hashValue, 32);
+        
+        for(int i = 0; i < 64 || i < 32 + data[dataLen - 1]; ++i)
+        {
+            dataLen = pswdLen + blockLen;
+            memcpy(data, pswd, pswdLen);
+            memcpy(data + pswdLen, block, blockLen);
+            if (uValue) {
+                memcpy(data + dataLen, uValue, 48);
+                dataLen += 48;
+            }
+            for(int j = 1; j < 64; ++j)
+                memcpy(data + j * dataLen, data, dataLen);
+            dataLen *= 64;
+            
+            AES_set_encrypt_key(block, 128, &aes);
+            AES_cbc_encrypt(data, data, dataLen, &aes, block + 16, 
AES_ENCRYPT);
+            int sum = 0;
+            for(int j = 0; j < 16; ++j)
+                sum += data[j];
+            blockLen = 32 + (sum % 3) * 16;
+            
+            if(blockLen == 32) {
+                SHA256_Init(&sha256);
+                SHA256_Update(&sha256, data, dataLen);
+                SHA256_Final(block, &sha256);
+            }
+            else if(blockLen == 48)
+            {
+                SHA384_Init(&sha384);
+                SHA384_Update(&sha384, data, dataLen);
+                SHA384_Final(block, &sha384);
+            }
+            else
+            {
+                SHA512_Init(&sha512);
+                SHA512_Update(&sha512, data, dataLen);
+                SHA512_Final(block, &sha512);
+            }
+        }
+        memcpy(hashValue, block, 32);
+    }
+}
+
 void PdfEncryptSHABase::ComputeUserKey(const unsigned char * userpswd, int len)
 {
     // Generate User Salts
@@ -1520,13 +1591,8 @@
     // Generate hash for U
     unsigned char hashValue[32];
     
-    SHA256_CTX context;
-    SHA256_Init(&context);
+    ComputeHash(userpswd, len, vSalt, 0, hashValue);
     
-    SHA256_Update(&context, userpswd, len);
-    SHA256_Update(&context, vSalt, 8);
-    SHA256_Final(hashValue, &context);
-    
     // U = hash + validation salt + key salt
     memcpy(m_uValue, hashValue, 32);
     memcpy(m_uValue+32, vSalt, 8);
@@ -1533,10 +1599,7 @@
     memcpy(m_uValue+32+8, kSalt, 8);
     
     // Generate hash for UE
-    SHA256_Init(&context);
-    SHA256_Update(&context, userpswd, len);
-    SHA256_Update(&context, kSalt, 8);
-    SHA256_Final(hashValue, &context);
+    ComputeHash(userpswd, len, kSalt, 0, hashValue);
     
     // UE = AES-256 encoded file encryption key with key=hash
     // CBC mode, no padding, init vector=0
@@ -1585,12 +1648,7 @@
     
     // Generate hash for O
     unsigned char hashValue[32];
-    SHA256_CTX context;
-    SHA256_Init(&context);
-    SHA256_Update(&context, ownerpswd, len);
-    SHA256_Update(&context, vSalt, 8);
-    SHA256_Update(&context, m_uValue, 48);
-    SHA256_Final(hashValue, &context);
+    ComputeHash(ownerpswd, len, vSalt, m_uValue, hashValue);
     
     // O = hash + validation salt + key salt
     memcpy(m_oValue, hashValue, 32);
@@ -1598,11 +1656,7 @@
     memcpy(m_oValue+32+8, kSalt, 8);
     
     // Generate hash for OE
-    SHA256_Init(&context);
-    SHA256_Update(&context, ownerpswd, len);
-    SHA256_Update(&context, kSalt, 8);
-    SHA256_Update(&context, m_uValue, 48);
-    SHA256_Final(hashValue, &context);
+    ComputeHash(ownerpswd, len, kSalt, m_uValue, hashValue);
     
     // OE = AES-256 encoded file encryption key with key=hash
     // CBC mode, no padding, init vector=0
@@ -1650,7 +1704,9 @@
     len = l > 127 ? 127 : l;
     
     memcpy(outBuf, password_sasl, len);
-    free(password_sasl); // Do not change to podofo_free, as memory is 
allocated by stringprep_profile
+    // password_sasl is allocated by stringprep_profile (libidn), so use 
idn_free
+    // (In Windows the libidn.dll could use an other heap and then the normal 
free or podofo_free will crash while debugging podofo.)
+    idn_free(password_sasl);
 }
 
 void
@@ -1697,7 +1753,7 @@
     PdfDictionary stdCf;
     
     rDictionary.AddKey( PdfName("V"), 
static_cast<pdf_int64>(PODOFO_LL_LITERAL(5)) );
-    rDictionary.AddKey( PdfName("R"), 
static_cast<pdf_int64>(PODOFO_LL_LITERAL(5)) );
+    rDictionary.AddKey( PdfName("R"), static_cast<pdf_int64>(m_rValue) );
     rDictionary.AddKey( PdfName("Length"), 
static_cast<pdf_int64>(PODOFO_LL_LITERAL(256)) );
     
     stdCf.AddKey( PdfName("CFM"), PdfName("AESV3") );
@@ -1774,7 +1830,7 @@
     aes = &aes_local;
     #endif
     
-    int status = EVP_EncryptInit_ex(aes, EVP_aes_256_ecb(), NULL, 
m_encryptionKey, NULL);
+    int status = EVP_EncryptInit_ex(aes, EVP_aes_256_cbc(), NULL, 
m_encryptionKey, NULL);
     if(status != 1)
         PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing 
AES encryption engine" );
     EVP_CIPHER_CTX_set_padding(aes, 0); // disable padding
@@ -1806,21 +1862,13 @@
     
     // Test 1: is it the user key ?
     unsigned char hashValue[32];
-    SHA256_CTX context;
-    SHA256_Init(&context);
-    SHA256_Update(&context, pswd_sasl, pswdLen); // password
-    SHA256_Update(&context, m_uValue + 32, 8); // user Validation Salt
-    SHA256_Final(hashValue, &context);
+    ComputeHash(pswd_sasl, pswdLen, m_uValue + 32, 0, hashValue); // user 
Validation Salt
     
     ok = CheckKey(hashValue, m_uValue);
     if(!ok)
     {
         // Test 2: is it the owner key ?
-        SHA256_Init(&context);
-        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);
+        ComputeHash(pswd_sasl, pswdLen, m_oValue + 32, m_uValue, hashValue); 
// owner Validation Salt
         
         ok = CheckKey(hashValue, m_oValue);
         
@@ -1829,11 +1877,7 @@
             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);
+                       ComputeHash(pswd_sasl, pswdLen, m_oValue + 40, 
m_uValue, hashValue); // owner Key Salt
 
                        // 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.
@@ -1850,10 +1894,7 @@
         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);
+               ComputeHash(pswd_sasl, pswdLen, m_uValue + 40, 0, hashValue); 
// user Key Salt
 
                // 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.
@@ -1890,18 +1931,22 @@
                          unsigned char* outStr, pdf_long &outLen) const
 {
     pdf_long offset = CalculateStreamOffset();
+    if( inLen <= offset ) { // Is empty
+        outLen = 0;
+        return;
+    }
     
     const_cast<PdfEncryptAESV3*>(this)->BaseDecrypt(const_cast<unsigned 
char*>(m_encryptionKey), m_keyLength, inStr, &inStr[offset], inLen-offset, 
outStr, outLen);
 }
 
-PdfEncryptAESV3::PdfEncryptAESV3( const std::string & userPassword, const 
std::string & ownerPassword, int protection) : PdfEncryptAESBase()
+PdfEncryptAESV3::PdfEncryptAESV3( const std::string & userPassword, const 
std::string & ownerPassword, int protection, EPdfEncryptAlgorithm eAlgorithm) : 
PdfEncryptAESBase()
 {
     // setup object
     m_userPass = userPassword;
     m_ownerPass = ownerPassword;
-    m_eAlgorithm = ePdfEncryptAlgorithm_AESV3;
+    m_eAlgorithm = eAlgorithm == ePdfEncryptAlgorithm_AESV3R6 ? 
ePdfEncryptAlgorithm_AESV3R6 : ePdfEncryptAlgorithm_AESV3;
     
-    m_rValue = 5;
+    m_rValue = eAlgorithm == ePdfEncryptAlgorithm_AESV3R6 ? 6 : 5;
     m_eKeyLength = ePdfKeyLength_256;
     m_keyLength = ePdfKeyLength_256 / 8;
     
@@ -1916,14 +1961,14 @@
     m_pValue = PERMS_DEFAULT | protection;
 }
 
-PdfEncryptAESV3::PdfEncryptAESV3(PdfString oValue,PdfString oeValue, PdfString 
uValue, PdfString ueValue, int pValue, PdfString permsValue) : 
PdfEncryptAESBase()
+PdfEncryptAESV3::PdfEncryptAESV3(PdfString oValue,PdfString oeValue, PdfString 
uValue, PdfString ueValue, int pValue, PdfString permsValue, 
EPdfEncryptAlgorithm eAlgorithm) : PdfEncryptAESBase()
 {
     m_pValue = pValue;
-    m_eAlgorithm = ePdfEncryptAlgorithm_AESV3;
+    m_eAlgorithm = eAlgorithm == ePdfEncryptAlgorithm_AESV3R6 ? 
ePdfEncryptAlgorithm_AESV3R6 : ePdfEncryptAlgorithm_AESV3;
     
     m_eKeyLength = ePdfKeyLength_256;
     m_keyLength  = ePdfKeyLength_256 / 8;
-    m_rValue    = 5;
+    m_rValue    = eAlgorithm == ePdfEncryptAlgorithm_AESV3R6 ? 6 : 5;
     memcpy( m_oValue, oValue.GetString(), 48 );
     memcpy( m_oeValue, oeValue.GetString(), 32 );
     memcpy( m_uValue, uValue.GetString(), 48 );
Index: src/podofo/base/PdfEncrypt.h
===================================================================
--- src/podofo/base/PdfEncrypt.h        (revision 2047)
+++ src/podofo/base/PdfEncrypt.h        (working copy)
@@ -120,6 +120,7 @@
         ePdfEncryptAlgorithm_AESV2 = 4  ///< AES encryption with a 128 bit key 
(PDF1.6)
 #ifdef PODOFO_HAVE_LIBIDN
         ,ePdfEncryptAlgorithm_AESV3 = 8 ///< AES encryption with a 256 bit key 
(PDF1.7 extension 3) - Support added by P. Zent
+        ,ePdfEncryptAlgorithm_AESV3R6 = 16 ///< AES encryption with a 256 bit 
key, Revision 6 (PDF1.7 extension 8, PDF 2.0)
 #endif //PODOFO_HAVE_LIBIDN
     } EPdfEncryptAlgorithm;
 
@@ -495,6 +496,9 @@
     /// Compute encryption key to be used with AES-256
     void ComputeEncryptionKey();
     
+    /// Compute hash for password and salt with optional uValue
+    void ComputeHash(const unsigned char * pswd, int pswdLen, unsigned char 
salt[8], unsigned char uValue[48], unsigned char hashValue[32]);
+    
     /// Generate the U and UE entries 
     void ComputeUserKey(const unsigned char * userpswd, int len);
     
@@ -710,7 +714,7 @@
     /*
      * Constructors of PdfEncryptAESV3
      */
-    PdfEncryptAESV3(PdfString oValue, PdfString oeValue, PdfString uValue, 
PdfString ueValue, int pValue, PdfString permsValue);
+    PdfEncryptAESV3(PdfString oValue, PdfString oeValue, PdfString uValue, 
PdfString ueValue, int pValue, PdfString permsValue, EPdfEncryptAlgorithm 
eAlgorithm = ePdfEncryptAlgorithm_AESV3);
     PdfEncryptAESV3( const PdfEncrypt & rhs ) : PdfEncryptSHABase(rhs) {}
     PdfEncryptAESV3( const std::string & userPassword,
                   const std::string & ownerPassword, 
@@ -721,7 +725,8 @@
                   ePdfPermissions_FillAndSign |
                   ePdfPermissions_Accessible |
                   ePdfPermissions_DocAssembly |
-                  ePdfPermissions_HighPrint
+                  ePdfPermissions_HighPrint,
+                  EPdfEncryptAlgorithm eAlgorithm = ePdfEncryptAlgorithm_AESV3
                   );   
     
     /*
_______________________________________________
Podofo-users mailing list
Podofo-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/podofo-users

Reply via email to