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-05 17:11:05
|
Index: src/base/PdfEncrypt.cpp
===================================================================
--- src/base/PdfEncrypt.cpp (revision 1582)
+++ src/base/PdfEncrypt.cpp (working copy)
@@ -311,7 +311,7 @@
* \returns the number of bytes read, -1 if an error ocurred
* and zero if no more bytes are available for reading.
*/
- virtual pdf_long Read( char* pBuffer, pdf_long lLen )
+ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long* )
{
// Do not encode data with no length
if( !lLen )
@@ -328,6 +328,122 @@
PdfRC4Stream m_stream;
};
+/** A class that can encrypt/decrpyt streamed data block wise
+ * This is used in the input and output stream encryption implementation.
+ */
+class PdfAESStream : public PdfEncryptAESBase {
+public:
+ PdfAESStream( unsigned char* key, const size_t keylen )
+ : bFirstRead( true ), bOnlyFinalLeft( false ), keyLen( keylen )
+ {
+ memcpy( this->key, key, keylen );
+ }
+
+ ~PdfAESStream() {}
+
+ /** Decrypt a block
+ *
+ * \param pBuffer the input/output buffer. Data is read from this buffer and also stored here
+ * \param lLen the size of the buffer
+ * \param pTotalLeft total bytes left (needed for AES IV and padding)
+ */
+ pdf_long Decrypt( unsigned char* pBuffer, pdf_long lLen, pdf_long* pTotalLeft )
+ {
+ 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" );
+ EVP_CIPHER_CTX* aes = m_aes->getEngine();
+ pdf_long lOutLen = 0, lStepOutLen;
+ int status = 1;
+ if( bFirstRead ) {
+ bFirstRead = false;
+ if( keyLen == PdfEncrypt::ePdfKeyLength_128/8 ) {
+ status = EVP_DecryptInit_ex( aes, EVP_aes_128_cbc(), NULL, key, pBuffer );
+#ifdef PODOFO_HAVE_LIBIDN
+ } else if( keyLen == PdfEncrypt::ePdfKeyLength_256/8 ) {
+ status = EVP_DecryptInit_ex( aes, EVP_aes_256_cbc(), NULL, key, pBuffer );
+#endif
+ } else {
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Invalid AES key length" );
+ }
+ if(status != 1)
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES encryption engine" );
+ status = EVP_DecryptUpdate( aes, pBuffer, &lOutLen, pBuffer + keyLen, lLen - keyLen );
+ } 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];
+ status = EVP_DecryptUpdate( aes, tempBuffer, &lOutLen, pBuffer, lLen );
+ memcpy( pBuffer, tempBuffer, lOutLen );
+ delete[] tempBuffer;
+ }
+ if( status != 1 )
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data" );
+ if( lLen == *pTotalLeft ) {
+ // Last chunk of the stream
+ if( lLen == lOutLen ) {
+ // Buffer is full, so we need an other round for EVP_DecryptFinal_ex.
+ bOnlyFinalLeft = true;
+ *pTotalLeft += keyLen;
+ } else {
+ status = EVP_DecryptFinal_ex( aes, pBuffer + lOutLen, &lStepOutLen );
+ if( status != 1 )
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data padding" );
+ lOutLen += lStepOutLen;
+ }
+ }
+ *pTotalLeft -= lLen - lOutLen; // AES makes the resulting buffer shorter (IV and padding)
+ return lOutLen;
+ }
+
+private:
+ unsigned char key[32];
+ const size_t keyLen;
+ bool bFirstRead;
+ bool bOnlyFinalLeft;
+};
+
+/** A PdfAESInputStream that decrypts all data read
+ * using the AES encryption algorithm
+ */
+class PdfAESInputStream : public PdfInputStream {
+public:
+ PdfAESInputStream( PdfInputStream* pInputStream, unsigned char* key, int keylen )
+ : m_pInputStream( pInputStream ), m_stream( key, keylen )
+ {
+ }
+
+ virtual ~PdfAESInputStream()
+ {
+ }
+
+ /** Read data from the input stream
+ *
+ * \param pBuffer the data will be stored into this buffer
+ * \param lLen the size of the buffer and number of bytes
+ * that will be read
+ * \param pTotalLeft total bytes left (needed for AES IV and padding)
+ *
+ * \returns the number of bytes read, -1 if an error ocurred
+ * and zero if no more bytes are available for reading.
+ */
+ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long *pTotalLeft )
+ {
+ // Do not encode data with no length
+ if( !lLen )
+ return lLen;
+
+ m_pInputStream->Read( pBuffer, lLen );
+ return m_stream.Decrypt( (unsigned char*)pBuffer, lLen, pTotalLeft );
+ }
+
+private:
+ PdfInputStream* m_pInputStream;
+ PdfAESStream m_stream;
+};
+
/***************************************************************************
* Copyright (C) 2006 by Dominik Seichter *
* dom...@we... *
@@ -409,6 +525,8 @@
int pValue;
PdfString oValue;
PdfString uValue;
+ PdfName cfmName;
+ bool encryptMetadata = true;
try {
PdfString sTmp;
@@ -429,7 +547,21 @@
{
lLength = 0;
}
-
+ const PdfObject *encryptMetadataObj = pObject->GetDictionary().GetKey( PdfName("EncryptMetadata") );
+ if( encryptMetadataObj && encryptMetadataObj->IsBool() )
+ encryptMetadata = encryptMetadataObj->GetBool();
+ const PdfObject *stmfObj = pObject->GetDictionary().GetKey( PdfName("StmF") );
+ if( stmfObj && stmfObj->IsName() ) {
+ const PdfObject *obj = pObject->GetDictionary().GetKey( PdfName("CF") );
+ if( obj && obj->IsDictionary() ) {
+ obj = obj->GetDictionary().GetKey( stmfObj->GetName() );
+ if( obj && obj->IsDictionary() ) {
+ obj = obj->GetDictionary().GetKey( PdfName("CFM") );
+ if( obj && obj->IsName() )
+ cfmName = obj->GetName();
+ }
+ }
+ }
} catch( PdfError & e ) {
e.AddToCallstack( __FILE__, __LINE__, "Invalid key in encryption dictionary" );
throw e;
@@ -438,18 +570,18 @@
if( (lV == 1L) && (rValue == 2L || rValue == 3L)
&& PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_RC4V1 ) )
{
- pdfEncrypt = new PdfEncryptRC4(oValue, uValue, pValue, rValue, ePdfEncryptAlgorithm_RC4V1, 40);
+ pdfEncrypt = new PdfEncryptRC4(oValue, uValue, pValue, rValue, ePdfEncryptAlgorithm_RC4V1, 40, encryptMetadata);
}
- else if( (lV == 2L) && (rValue == 3L)
+ else if( (((lV == 2L) && (rValue == 3L)) || cfmName == "V2")
&& PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_RC4V2 ) )
{
// [Alexey] - lLength is long long. Please make changes in encryption algorithms
- pdfEncrypt = new PdfEncryptRC4(oValue, uValue, pValue, rValue, ePdfEncryptAlgorithm_RC4V2, static_cast<int>(lLength));
+ pdfEncrypt = new PdfEncryptRC4(oValue, uValue, pValue, rValue, ePdfEncryptAlgorithm_RC4V2, static_cast<int>(lLength), encryptMetadata);
}
else if( (lV == 4L) && (rValue == 4L)
&& PdfEncrypt::IsEncryptionEnabled( ePdfEncryptAlgorithm_AESV2 ) )
{
- pdfEncrypt = new PdfEncryptAESV2(oValue, uValue, pValue);
+ pdfEncrypt = new PdfEncryptAESV2(oValue, uValue, pValue, encryptMetadata);
}
#ifdef PODOFO_HAVE_LIBIDN
else if( (lV == 5L) && (rValue == 5L)
@@ -520,6 +652,7 @@
m_documentId = rhs.m_documentId;
m_userPass = rhs.m_userPass;
m_ownerPass = rhs.m_ownerPass;
+ m_bEncryptMetadata = rhs.m_bEncryptMetadata;
}
bool
@@ -528,8 +661,7 @@
// Check whether the right password had been given
bool ok = true;
int k;
- int kmax = (m_rValue == 3) ? 16 : 32;
- for (k = 0; ok && k < kmax; k++)
+ for (k = 0; ok && k < m_keyLength; k++)
{
ok = ok && (key1[k] == key2[k]);
}
@@ -548,6 +680,7 @@
memcpy( m_rc4key, static_cast<const PdfEncryptMD5Base*>(ptr)->m_rc4key, sizeof(unsigned char) * 16 );
memcpy( m_rc4last, static_cast<const PdfEncryptMD5Base*>(ptr)->m_rc4last, sizeof(unsigned char) * 256 );
+ m_bEncryptMetadata = static_cast<const PdfEncryptMD5Base*>(ptr)->m_bEncryptMetadata;
}
void
@@ -641,7 +774,7 @@
PdfEncryptMD5Base::ComputeEncryptionKey(const std::string& documentId,
unsigned char userPad[32], unsigned char ownerKey[32],
int pValue, int keyLength, int revision,
- unsigned char userKey[32])
+ unsigned char userKey[32], bool encryptMetadata)
{
int j;
int k;
@@ -682,9 +815,13 @@
PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error MD5-hashing data" );
}
- // TODO: (Revision 3 or greater) If document metadata is not being encrypted,
- // pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash function.
-
+ // If document metadata is not being encrypted,
+ // pass 4 bytes with the value 0xFFFFFFFF to the MD5 hash function.
+ if( !encryptMetadata ) {
+ unsigned char noMetaAddition[4] = { 0xff, 0xff, 0xff, 0xff };
+ status = MD5_Update(&ctx, noMetaAddition, 4);
+ }
+
unsigned char digest[MD5_DIGEST_LENGTH];
status = MD5_Final(digest,&ctx);
if(status != 1)
@@ -771,7 +908,7 @@
nkey[m_keyLength+3] = static_cast<unsigned char>(0xff & g);
nkey[m_keyLength+4] = static_cast<unsigned char>(0xff & (g >> 8));
- if (m_rValue == 4)
+ if (m_eAlgorithm == ePdfEncryptAlgorithm_AESV2 || m_eAlgorithm == ePdfEncryptAlgorithm_AESV3)
{
// AES encryption needs some 'salt'
nkeylen += 4;
@@ -897,12 +1034,15 @@
{
rDictionary.AddKey( PdfName("Filter"), PdfName("Standard") );
- if(m_eAlgorithm == ePdfEncryptAlgorithm_AESV2)
+ if(m_eAlgorithm == ePdfEncryptAlgorithm_AESV2 || !m_bEncryptMetadata)
{
PdfDictionary cf;
PdfDictionary stdCf;
- stdCf.AddKey( PdfName("CFM"), PdfName("AESV2") );
+ if(m_eAlgorithm == ePdfEncryptAlgorithm_RC4V2)
+ stdCf.AddKey( PdfName("CFM"), PdfName("V2") );
+ else
+ stdCf.AddKey( PdfName("CFM"), PdfName("AESV2") );
stdCf.AddKey( PdfName("Length"), static_cast<pdf_int64>(16LL) );
rDictionary.AddKey( PdfName("O"), PdfString( reinterpret_cast<const char*>(this->GetOValue()), 32, true ) );
@@ -918,7 +1058,9 @@
rDictionary.AddKey( PdfName("V"), static_cast<pdf_int64>(4LL) );
rDictionary.AddKey( PdfName("R"), static_cast<pdf_int64>(4LL) );
rDictionary.AddKey( PdfName("Length"), static_cast<pdf_int64>(128LL) );
- }
+ if(!m_bEncryptMetadata)
+ rDictionary.AddKey( PdfName("EncryptMetadata"), PdfVariant( false ) );
+ }
else if(m_eAlgorithm == ePdfEncryptAlgorithm_RC4V1)
{
rDictionary.AddKey( PdfName("V"), static_cast<pdf_int64>(1LL) );
@@ -929,7 +1071,7 @@
{
rDictionary.AddKey( PdfName("V"), static_cast<pdf_int64>(2LL) );
rDictionary.AddKey( PdfName("R"), static_cast<pdf_int64>(3LL) );
- rDictionary.AddKey( PdfName("Length"), PdfVariant( static_cast<pdf_int64>(m_eKeyLength) ) );
+ rDictionary.AddKey( PdfName("Length"), PdfVariant( static_cast<pdf_int64>(m_eKeyLength) ) );
}
rDictionary.AddKey( PdfName("O"), PdfString( reinterpret_cast<const char*>(this->GetOValue()), 32, true ) );
@@ -953,7 +1095,7 @@
// Compute encryption key and U value
m_documentId = std::string( documentId.GetString(), documentId.GetLength() );
ComputeEncryptionKey(m_documentId, userpswd,
- m_oValue, m_pValue, m_eKeyLength, m_rValue, m_uValue);
+ m_oValue, m_pValue, m_eKeyLength, m_rValue, m_uValue, m_bEncryptMetadata);
}
bool PdfEncryptRC4::Authenticate( const std::string & password, const PdfString & documentId )
@@ -968,7 +1110,7 @@
PadPassword( password, pswd );
// Check password: 1) as user password, 2) as owner password
- ComputeEncryptionKey(m_documentId, pswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey);
+ ComputeEncryptionKey(m_documentId, pswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey, m_bEncryptMetadata);
ok = CheckKey(userKey, m_uValue);
if (!ok)
@@ -975,7 +1117,7 @@
{
unsigned char userpswd[32];
ComputeOwnerKey( m_oValue, pswd, m_keyLength, m_rValue, true, userpswd );
- ComputeEncryptionKey( m_documentId, userpswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey );
+ ComputeEncryptionKey( m_documentId, userpswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey, m_bEncryptMetadata );
ok = CheckKey( userKey, m_uValue );
if( ok )
@@ -986,7 +1128,7 @@
return ok;
}
-
+
pdf_long PdfEncryptRC4::CalculateStreamOffset() const
{
return 0;
@@ -1012,7 +1154,7 @@
void
PdfEncryptRC4::Decrypt(const unsigned char* inStr, pdf_long inLen,
- unsigned char* outStr, pdf_long outLen) const
+ unsigned char* outStr, pdf_long &outLen) const
{
Encrypt(inStr, inLen, outStr, outLen);
}
@@ -1027,7 +1169,7 @@
return new PdfRC4InputStream( pInputStream, m_rc4key, m_rc4last, objkey, keylen );
}
-PdfEncryptRC4::PdfEncryptRC4(PdfString oValue, PdfString uValue, int pValue, int rValue, EPdfEncryptAlgorithm eAlgorithm, long length)
+PdfEncryptRC4::PdfEncryptRC4(PdfString oValue, PdfString uValue, int pValue, int rValue, EPdfEncryptAlgorithm eAlgorithm, long length, bool encryptMetadata)
{
m_pValue = pValue;
m_rValue = rValue;
@@ -1034,6 +1176,7 @@
m_eAlgorithm = eAlgorithm;
m_eKeyLength = static_cast<EPdfKeyLength>(length);
m_keyLength = length/8;
+ m_bEncryptMetadata = encryptMetadata;
memcpy( m_oValue, oValue.GetString(), 32 );
memcpy( m_uValue, uValue.GetString(), 32 );
@@ -1107,7 +1250,7 @@
#ifdef __APPLE__
void
-PdfEncryptAESBase::AES(const unsigned char* key, int keyLen, const unsigned char* iv,
+PdfEncryptAESBase::Encrypt(const unsigned char* key, int keyLen, const unsigned char* iv,
const unsigned char* textin, pdf_long textlen,
unsigned char* textout, pdf_long textoutlen)
{
@@ -1132,9 +1275,42 @@
}
#else // __APPLE__
+
+void
+PdfEncryptAESBase::BaseDecrypt(const unsigned char* key, int keyLen, const unsigned char* iv,
+ const unsigned char* textin, pdf_long textlen,
+ unsigned char* textout, pdf_long &outLen ) // To avoid Wunused-parameter
+{
+ if (textlen % keyLen != 0)
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data length not a multiple of the key length" );
+
+ EVP_CIPHER_CTX* aes = m_aes->getEngine();
+ int status;
+ if(keyLen == PdfEncrypt::ePdfKeyLength_128/8)
+ status = EVP_DecryptInit_ex(aes, EVP_aes_128_cbc(), NULL, key, iv);
+#ifdef PODOFO_HAVE_LIBIDN
+ else if (keyLen == PdfEncrypt::ePdfKeyLength_256/8)
+ status = EVP_DecryptInit_ex(aes, EVP_aes_256_cbc(), NULL, key, iv);
+#endif
+ else
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Invalid AES key length" );
+ if(status != 1)
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error initializing AES decryption engine" );
+
+ status = EVP_DecryptUpdate(aes, textout, &outLen, textin, textlen);
+ if(status != 1)
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data" );
+
+ int finalOutLen;
+ status = EVP_DecryptFinal_ex(aes, textout + outLen, &finalOutLen);
+ outLen += finalOutLen;
+ if(status != 1)
+ PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "Error AES-decryption data final" );
+}
+
void
-PdfEncryptAESBase::AES(const unsigned char* key, int keyLen, const unsigned char* iv,
+PdfEncryptAESBase::BaseEncrypt(const unsigned char* key, int keyLen, const unsigned char* iv,
const unsigned char* textin, pdf_long textlen,
unsigned char* textout, pdf_long ) // To avoid Wunused-parameter
{
@@ -1179,7 +1355,7 @@
// Compute encryption key and U value
m_documentId = std::string( documentId.GetString(), documentId.GetLength() );
ComputeEncryptionKey(m_documentId, userpswd,
- m_oValue, m_pValue, m_eKeyLength, m_rValue, m_uValue);
+ m_oValue, m_pValue, m_eKeyLength, m_rValue, m_uValue, m_bEncryptMetadata);
}
bool PdfEncryptAESV2::Authenticate( const std::string & password, const PdfString & documentId )
@@ -1194,7 +1370,7 @@
PadPassword( password, pswd );
// Check password: 1) as user password, 2) as owner password
- ComputeEncryptionKey(m_documentId, pswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey);
+ ComputeEncryptionKey(m_documentId, pswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey, m_bEncryptMetadata);
ok = CheckKey(userKey, m_uValue);
if (!ok)
@@ -1201,7 +1377,7 @@
{
unsigned char userpswd[32];
ComputeOwnerKey( m_oValue, pswd, m_keyLength, m_rValue, true, userpswd );
- ComputeEncryptionKey( m_documentId, userpswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey );
+ ComputeEncryptionKey( m_documentId, userpswd, m_oValue, m_pValue, m_eKeyLength, m_rValue, userKey, m_bEncryptMetadata );
ok = CheckKey( userKey, m_uValue );
if( ok )
@@ -1230,12 +1406,12 @@
pdf_long offset = CalculateStreamOffset();
const_cast<PdfEncryptAESV2*>(this)->GenerateInitialVector(outStr);
- const_cast<PdfEncryptAESV2*>(this)->AES(objkey, keylen, outStr, inStr, inLen, &outStr[offset], outLen-offset);
+ const_cast<PdfEncryptAESV2*>(this)->BaseEncrypt(objkey, keylen, outStr, inStr, inLen, &outStr[offset], outLen-offset);
}
void
PdfEncryptAESV2::Decrypt(const unsigned char* inStr, pdf_long inLen,
- unsigned char* outStr, pdf_long outLen) const
+ unsigned char* outStr, pdf_long &outLen) const
{
unsigned char objkey[MD5_DIGEST_LENGTH];
int keylen;
@@ -1243,8 +1419,12 @@
CreateObjKey( objkey, &keylen );
pdf_long offset = CalculateStreamOffset();
+ if( inLen <= offset ) { // Is empty
+ outLen = 0;
+ return;
+ }
- const_cast<PdfEncryptAESV2*>(this)->AES(objkey, keylen, inStr, &inStr[offset], inLen-offset, outStr, outLen);
+ const_cast<PdfEncryptAESV2*>(this)->BaseDecrypt(objkey, keylen, inStr, &inStr[offset], inLen-offset, outStr, outLen);
}
PdfEncryptAESV2::PdfEncryptAESV2( const std::string & userPassword, const std::string & ownerPassword, int protection) : PdfEncryptAESBase()
@@ -1269,7 +1449,7 @@
m_pValue = PERMS_DEFAULT | protection;
}
-PdfEncryptAESV2::PdfEncryptAESV2(PdfString oValue, PdfString uValue, int pValue) : PdfEncryptAESBase()
+PdfEncryptAESV2::PdfEncryptAESV2(PdfString oValue, PdfString uValue, int pValue, bool encryptMetadata) : PdfEncryptAESBase()
{
m_pValue = pValue;
m_eAlgorithm = ePdfEncryptAlgorithm_AESV2;
@@ -1277,6 +1457,7 @@
m_eKeyLength = ePdfKeyLength_128;
m_keyLength = ePdfKeyLength_128 / 8;
m_rValue = 4;
+ m_bEncryptMetadata = encryptMetadata;
memcpy( m_oValue, oValue.GetString(), 32 );
memcpy( m_uValue, uValue.GetString(), 32 );
@@ -1298,14 +1479,14 @@
return realLength;
}
-PdfInputStream* PdfEncryptAESV2::CreateEncryptionInputStream( PdfInputStream* )
+PdfInputStream* PdfEncryptAESV2::CreateEncryptionInputStream( PdfInputStream* pInputStream )
{
- /*unsigned char objkey[MD5_DIGEST_LENGTH];
- int keylen;
+ unsigned char objkey[MD5_DIGEST_LENGTH];
+ int keylen;
- this->CreateObjKey( objkey, &keylen );*/
-
- PODOFO_RAISE_ERROR_INFO( ePdfError_InternalLogic, "CreateEncryptionInputStream does not yet support AESV2" );
+ this->CreateObjKey( objkey, &keylen );
+
+ return new PdfAESInputStream( pInputStream, objkey, keylen );
}
PdfOutputStream* PdfEncryptAESV2::CreateEncryptionOutputStream( PdfOutputStream* )
@@ -1582,8 +1763,8 @@
perms[5] = 0xff;
perms[6] = 0xff;
perms[7] = 0xff;
- // TODO : if EncryptMetadata is false, this value shoud be set to 'F'
- perms[8] = 'T';
+ // if EncryptMetadata is false, this value should be set to 'F'
+ perms[8] = m_bEncryptMetadata ? 'T' : 'F';
// Next 3 bytes are mandatory
perms[9] = 'a';
perms[10] = 'd';
@@ -1685,16 +1866,16 @@
pdf_long offset = CalculateStreamOffset();
const_cast<PdfEncryptAESV3*>(this)->GenerateInitialVector(outStr);
- const_cast<PdfEncryptAESV3*>(this)->AES(const_cast<unsigned char*>(m_encryptionKey), m_keyLength, outStr, inStr, inLen, &outStr[offset], outLen-offset);
+ const_cast<PdfEncryptAESV3*>(this)->BaseEncrypt(const_cast<unsigned char*>(m_encryptionKey), m_keyLength, outStr, inStr, inLen, &outStr[offset], outLen-offset);
}
void
PdfEncryptAESV3::Decrypt(const unsigned char* inStr, pdf_long inLen,
- unsigned char* outStr, pdf_long outLen) const
+ unsigned char* outStr, pdf_long &outLen) const
{
pdf_long offset = CalculateStreamOffset();
- const_cast<PdfEncryptAESV3*>(this)->AES(const_cast<unsigned char*>(m_encryptionKey), m_keyLength, inStr, &inStr[offset], inLen-offset, outStr, outLen);
+ 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()
Index: src/base/PdfEncrypt.h
===================================================================
--- src/base/PdfEncrypt.h (revision 1582)
+++ src/base/PdfEncrypt.h (working copy)
@@ -344,6 +344,9 @@
/// Get the key length of the encryption key in bits
int GetKeyLength() const { return m_keyLength*8; }
+
+ /// Is metadata encrypted
+ bool IsMetadataEncrypted() const { return m_bEncryptMetadata; }
/// Encrypt a wxString
//void Encrypt( std::string & str, pdf_long inputLen ) const;
@@ -362,11 +365,11 @@
// outStr: the output buffer
// outLen: length of the output buffer
virtual void Decrypt(const unsigned char* inStr, pdf_long inLen,
- unsigned char* outStr, pdf_long outLen) const = 0;
+ unsigned char* outStr, pdf_long &outLen) const = 0;
/// Calculate stream size
virtual pdf_long CalculateStreamLength(pdf_long length) const = 0;
-
+
/// Calculate stream offset
virtual pdf_long CalculateStreamOffset() const = 0;
@@ -381,7 +384,7 @@
inline void SetCurrentReference( const PdfReference & rRef );
protected:
- PdfEncrypt() {};
+ PdfEncrypt() : m_bEncryptMetadata(true) {};
PdfEncrypt( const PdfEncrypt & rhs );
/// Check two keys for equality
@@ -399,6 +402,7 @@
unsigned char m_encryptionKey[32]; ///< Encryption key
PdfReference m_curReference; ///< Reference of the current PdfObject
std::string m_documentId; ///< DocumentID of the current document
+ bool m_bEncryptMetadata; ///< Is metadata encrypted
private:
static int s_nEnabledEncryptionAlgorithms; ///< Or'ed int containing the enabled encryption algorithms
@@ -446,7 +450,7 @@
/// Get the Perms object value (encrypted protection)
const unsigned char* GetPermsValue() const { return m_permsValue; }
-
+
virtual pdf_long CalculateStreamOffset() const = 0;
virtual pdf_long CalculateStreamLength(pdf_long length) const = 0;
@@ -504,9 +508,11 @@
protected:
PdfEncryptAESBase();
- /// AES encryption
- void AES(const unsigned char* key, int keylen, const unsigned char* iv,
+ void BaseDecrypt(const unsigned char* key, int keylen, const unsigned char* iv,
const unsigned char* textin, pdf_long textlen,
+ unsigned char* textout, pdf_long &textoutlen);
+ void BaseEncrypt(const unsigned char* key, int keylen, const unsigned char* iv,
+ const unsigned char* textin, pdf_long textlen,
unsigned char* textout, pdf_long textoutlen);
AESCryptoEngine* m_aes; ///< AES encryptor
@@ -596,7 +602,7 @@
void ComputeEncryptionKey(const std::string & documentID,
unsigned char userPad[32], unsigned char ownerKey[32],
int pValue, int keyLength, int revision,
- unsigned char userKey[32]);
+ unsigned char userKey[32], bool bEncryptMetadata);
/** Create the encryption key for the current object.
*
@@ -622,7 +628,7 @@
/*
* Constructors of PdfEncryptAESV2
*/
- PdfEncryptAESV2(PdfString oValue, PdfString uValue, int pValue);
+ PdfEncryptAESV2(PdfString oValue, PdfString uValue, int pValue, bool bEncryptMetadata);
PdfEncryptAESV2( const PdfEncrypt & rhs ) : PdfEncryptMD5Base(rhs) {}
PdfEncryptAESV2( const std::string & userPassword,
const std::string & ownerPassword,
@@ -650,7 +656,7 @@
virtual void Encrypt(const unsigned char* inStr, pdf_long inLen,
unsigned char* outStr, pdf_long outLen) const;
virtual void Decrypt(const unsigned char* inStr, pdf_long inLen,
- unsigned char* outStr, pdf_long outLen) const;
+ unsigned char* outStr, pdf_long &outLen) const;
virtual void GenerateEncryptionKey(const PdfString & documentId);
@@ -700,10 +706,10 @@
virtual void Encrypt(const unsigned char* inStr, pdf_long inLen,
unsigned char* outStr, pdf_long outLen) const;
virtual void Decrypt(const unsigned char* inStr, pdf_long inLen,
- unsigned char* outStr, pdf_long outLen) const;
+ unsigned char* outStr, pdf_long &outLen) const;
virtual void GenerateEncryptionKey(const PdfString & documentId);
-
+
virtual pdf_long CalculateStreamOffset() const;
virtual pdf_long CalculateStreamLength(pdf_long length) const;
@@ -724,7 +730,7 @@
* Constructors of PdfEncryptRC4 objects
*/
PdfEncryptRC4(PdfString oValue, PdfString uValue,
- int pValue, int rValue, EPdfEncryptAlgorithm eAlgorithm, long length);
+ int pValue, int rValue, EPdfEncryptAlgorithm eAlgorithm, long length, bool bEncryptMetadata);
PdfEncryptRC4( const PdfEncrypt & rhs ) : PdfEncryptMD5Base(rhs) {}
PdfEncryptRC4( const std::string & userPassword,
const std::string & ownerPassword,
@@ -750,7 +756,7 @@
virtual void Encrypt(const unsigned char* inStr, pdf_long inLen,
unsigned char* outStr, pdf_long outLen) const;
virtual void Decrypt(const unsigned char* inStr, pdf_long inLen,
- unsigned char* outStr, pdf_long outLen) const;
+ unsigned char* outStr, pdf_long &outLen) const;
virtual PdfInputStream* CreateEncryptionInputStream( PdfInputStream* pInputStream );
virtual PdfOutputStream* CreateEncryptionOutputStream( PdfOutputStream* pOutputStream );
Index: src/base/PdfInputStream.cpp
===================================================================
--- src/base/PdfInputStream.cpp (revision 1582)
+++ src/base/PdfInputStream.cpp (working copy)
@@ -69,7 +69,7 @@
fclose( m_hFile );
}
-pdf_long PdfFileInputStream::Read( char* pBuffer, pdf_long lLen )
+pdf_long PdfFileInputStream::Read( char* pBuffer, pdf_long lLen, pdf_long* )
{
if( !pBuffer )
{
@@ -114,7 +114,7 @@
{
}
-pdf_long PdfMemoryInputStream::Read( char* pBuffer, pdf_long lLen )
+pdf_long PdfMemoryInputStream::Read( char* pBuffer, pdf_long lLen, pdf_long* )
{
if( !pBuffer )
{
@@ -143,7 +143,7 @@
{
}
-pdf_long PdfDeviceInputStream::Read( char* pBuffer, pdf_long lLen )
+pdf_long PdfDeviceInputStream::Read( char* pBuffer, pdf_long lLen, pdf_long* )
{
return m_pDevice->Read( pBuffer, lLen );
}
Index: src/base/PdfInputStream.h
===================================================================
--- src/base/PdfInputStream.h (revision 1582)
+++ src/base/PdfInputStream.h (working copy)
@@ -49,14 +49,15 @@
/** Read data from the input stream
*
- * \param pBuffer the data will be stored into this buffer
- * \param lLen the size of the buffer and number of bytes
- * that will be read
+ * \param pBuffer the data will be stored into this buffer
+ * \param lLen the size of the buffer and number of bytes
+ * that will be read
+ * \param pTotalLeft total bytes left (needed for AES IV and padding)
*
* \returns the number of bytes read, -1 if an error ocurred
* and zero if no more bytes are available for reading.
*/
- virtual pdf_long Read( char* pBuffer, pdf_long lLen ) = 0;
+ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long *pTotalLeft = 0 ) = 0;
};
@@ -94,7 +95,7 @@
* \returns the number of bytes read, -1 if an error ocurred
* and zero if no more bytes are available for reading.
*/
- virtual pdf_long Read( char* pBuffer, pdf_long lLen );
+ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long* );
/** Get the length of the file.
* \return the file length
@@ -132,7 +133,7 @@
* \returns the number of bytes read, -1 if an error ocurred
* and zero if no more bytes are available for reading.
*/
- virtual pdf_long Read( char* pBuffer, pdf_long lLen );
+ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long* );
private:
const char* m_pBuffer;
@@ -162,7 +163,7 @@
* \returns the number of bytes read, -1 if an error ocurred
* and zero if no more bytes are available for reading.
*/
- virtual pdf_long Read( char* pBuffer, pdf_long lLen );
+ virtual pdf_long Read( char* pBuffer, pdf_long lLen, pdf_long* );
private:
PdfInputDevice* m_pDevice;
Index: src/base/PdfObjectStreamParserObject.cpp
===================================================================
--- src/base/PdfObjectStreamParserObject.cpp (revision 1582)
+++ src/base/PdfObjectStreamParserObject.cpp (working copy)
@@ -99,7 +99,10 @@
// use a second tokenizer here so that anything that gets dequeued isn't left in the tokenizer that reads the offsets and lengths
PdfTokenizer variantTokenizer( device, m_buffer );
- variantTokenizer.GetNextVariant( var, m_pEncrypt );
+ if( m_pEncrypt && m_pEncrypt->GetEncryptAlgorithm() == PdfEncrypt::ePdfEncryptAlgorithm_AESV2 )
+ variantTokenizer.GetNextVariant( var, 0 ); // Stream is already decrypted
+ else
+ variantTokenizer.GetNextVariant( var, m_pEncrypt );
bool should_read = std::find(list.begin(), list.end(), lObj) != list.end();
#if defined(PODOFO_VERBOSE_DEBUG)
std::cerr << "ReadObjectsFromStream STREAM=" << m_pParser->Reference().ToString() <<
Index: src/base/PdfParser.cpp
===================================================================
--- src/base/PdfParser.cpp (revision 1582)
+++ src/base/PdfParser.cpp (working copy)
@@ -741,7 +741,7 @@
// to recover from a missing /Size entry.
PdfError::LogMessage( eLogSeverity_Warning,
"There are more objects (%lli) in this XRef table than "
- "specified in the size key of the trailer directory (%lli)!\n",
+ "specified in the size key of the trailer directory (%li)!\n",
nFirstObject + nNumObjects, m_nNumObjects );
#ifdef _WIN32
@@ -952,13 +952,19 @@
void PdfParser::ReadObjectsInternal()
{
- int i = 0;
- int nLast = 0;
- PdfParserObject* pObject = NULL;
+ int i = 0;
+ int nLast = 0;
+ PdfParserObject* pObject = NULL;
+ int trailerObjNo = m_pTrailer->Reference().ObjectNumber();
// Read objects
for( i=0; i < m_nNumObjects; i++ )
{
+ // Never add the XRef/Trailer to m_vecObjects
+ // (For AESV2 the XRef has cUsed == 'n' and XRef stream is not encrypted.
+ // So setting m_pEncrypt for it would throw exception if the stream is read later on.)
+ if (i == trailerObjNo)
+ continue;
#ifdef PODOFO_VERBOSE_DEBUG
std::cerr << "ReadObjectsInteral\t" << i << " "
<< (m_offsets[i].bParsed ? "parsed" : "unparsed") << " "
Index: src/base/PdfParserObject.cpp
===================================================================
--- src/base/PdfParserObject.cpp (revision 1582)
+++ src/base/PdfParserObject.cpp (working copy)
@@ -32,6 +32,7 @@
#include "PdfParserObject.h"
+#include "PdfArray.h"
#include "PdfDictionary.h"
#include "PdfEncrypt.h"
#include "PdfInputDevice.h"
@@ -326,6 +327,19 @@
m_device.Device()->Seek( fLoc ); // reset it before reading!
PdfDeviceInputStream reader( m_device.Device() );
+
+ if( m_pEncrypt && !m_pEncrypt->IsMetadataEncrypted() ) {
+ // If metadata is not encrypted the Filter is set to "Crypt"
+ PdfObject* pFilterObj = this->GetDictionary_NoDL().GetKey( PdfName::KeyFilter );
+ if( pFilterObj && pFilterObj->IsArray() ) {
+ PdfArray filters = pFilterObj->GetArray();
+ for(PdfArray::iterator it = filters.begin(); it != filters.end(); it++) {
+ if( (*it).IsName() )
+ if( (*it).GetName() == "Crypt" )
+ m_pEncrypt = 0;
+ }
+ }
+ }
if( m_pEncrypt )
{
m_pEncrypt->SetCurrentReference( m_reference );
Index: src/base/PdfStream.cpp
===================================================================
--- src/base/PdfStream.cpp (revision 1582)
+++ src/base/PdfStream.cpp (working copy)
@@ -178,7 +178,7 @@
else
{
do {
- lRead = pStream->Read( buffer, PDF_MIN( BUFFER_SIZE, lLen ) );
+ lRead = pStream->Read( buffer, PDF_MIN( BUFFER_SIZE, lLen ), &lLen );
lLen -= lRead;
this->Append( buffer, lRead );
} while( lLen && lRead > 0 );
Index: src/base/PdfString.cpp
===================================================================
--- src/base/PdfString.cpp (revision 1582)
+++ src/base/PdfString.cpp (working copy)
@@ -302,8 +302,8 @@
pEncrypt->Decrypt( reinterpret_cast<unsigned char*>(m_buffer.GetBuffer()),
static_cast<unsigned int>(m_buffer.GetSize()-2),
reinterpret_cast<unsigned char*>(outBuffer.GetBuffer()),
- static_cast<unsigned int>(outBufferLen));
-
+ outBufferLen);
+ outBuffer.Resize(outBufferLen);
// Replace buffer with decrypted value
m_buffer = outBuffer;
} |