From b082ffe20cd2addb2b6f2a0bda9f46ea61ad810b Mon Sep 17 00:00:00 2001 From: ElenaSubbotina Date: Wed, 16 May 2018 18:24:41 +0300 Subject: [PATCH] PdfReader - decrypt files revision 6(fix bug #17002) --- PdfReader/PdfReaderTest/PdfReaderTest.cpp | 17 +-- PdfReader/Src/Decrypt.cpp | 135 +++++++++++++++++++--- PdfReader/Src/Decrypt.h | 1 + 3 files changed, 130 insertions(+), 23 deletions(-) diff --git a/PdfReader/PdfReaderTest/PdfReaderTest.cpp b/PdfReader/PdfReaderTest/PdfReaderTest.cpp index ea7e8a4ddb..b77455ff9c 100644 --- a/PdfReader/PdfReaderTest/PdfReaderTest.cpp +++ b/PdfReader/PdfReaderTest/PdfReaderTest.cpp @@ -62,10 +62,8 @@ #pragma comment(lib, "../../build/bin/icu/win_32/icuuc.lib") #endif -HRESULT convert_single(PdfReader::CPdfReader& oReader, std::wstring srcFileName) +HRESULT convert_single(PdfReader::CPdfReader& oReader, const std::wstring & srcFileName, const std::wstring & sPassword) { - std::wstring sPassword = L"58455fdc2013"; - if (oReader.LoadFromFile(srcFileName.c_str(), L"", sPassword, sPassword)) { int nPagesCount = oReader.GetPagesCount(); @@ -99,7 +97,7 @@ HRESULT convert_single(PdfReader::CPdfReader& oReader, std::wstring srcFileName) return S_FALSE; } -HRESULT convert_directory(PdfReader::CPdfReader& oReader, std::wstring pathName) +HRESULT convert_directory(PdfReader::CPdfReader& oReader, std::wstring pathName, const std::wstring & sPassword) { HRESULT hr = S_OK; @@ -107,7 +105,7 @@ HRESULT convert_directory(PdfReader::CPdfReader& oReader, std::wstring pathName) for (size_t i = 0; i < arFiles.size(); i++) { - hr = convert_single(oReader, arFiles[i]); + hr = convert_single(oReader, arFiles[i], sPassword); printf("%d of %d %S \tresult = %d\n", i + 1, arFiles.size(), arFiles[i].c_str(), hr); @@ -124,14 +122,17 @@ int _tmain(int argc, _TCHAR* argv[]) PdfReader::CPdfReader oPdfReader(pApplicationFonts); - HRESULT hr = -1; + HRESULT hr = S_FALSE; + + std::wstring sPassword = argc > 2 ? argv[2] : L""; + if (NSFile::CFileBinary::Exists(argv[1])) { - hr = convert_single(oPdfReader, argv[1]); + hr = convert_single(oPdfReader, argv[1], sPassword); } else if (NSDirectory::Exists(argv[1])) { - hr = convert_directory(oPdfReader, argv[1]); + hr = convert_directory(oPdfReader, argv[1], sPassword); } return hr; } diff --git a/PdfReader/Src/Decrypt.cpp b/PdfReader/Src/Decrypt.cpp index bc025f14f4..581a0fa1de 100644 --- a/PdfReader/Src/Decrypt.cpp +++ b/PdfReader/Src/Decrypt.cpp @@ -57,17 +57,46 @@ namespace PdfReader memcpy(sDigest, buffer.BytePtr(), buffer.SizeInBytes()); return; } - static void SHA256(unsigned char *sMessage, int nMessageLen, unsigned char *sDigest) + static int SHA(int type, unsigned char *sMessage, int nMessageLen, unsigned char *sDigest) { - CryptoPP::SHA256 hash; - - hash.Update( sMessage, nMessageLen); + int res = 0; + switch(type) + { + case 0: + case 256: + { + CryptoPP::SHA256 hash; + hash.Update( sMessage, nMessageLen > 0 ? nMessageLen : hash.DigestSize()); - CryptoPP::SecByteBlock buffer(hash.DigestSize()); - hash.Final(buffer); + CryptoPP::SecByteBlock buffer(res = hash.DigestSize()); + hash.Final(buffer); - memcpy(sDigest, buffer.BytePtr(), buffer.SizeInBytes()); - return; + memcpy(sDigest, buffer.BytePtr(), buffer.SizeInBytes()); + }break; + case 1: + case 384: + { + CryptoPP::SHA384 hash; + hash.Update( sMessage, nMessageLen > 0 ? nMessageLen : hash.DigestSize()); + + CryptoPP::SecByteBlock buffer(res = hash.DigestSize()); + hash.Final(buffer); + + memcpy(sDigest, buffer.BytePtr(), buffer.SizeInBytes()); + }break; + case 2: + case 512: + { + CryptoPP::SHA512 hash; + hash.Update( sMessage, nMessageLen > 0 ? nMessageLen : hash.DigestSize()); + + CryptoPP::SecByteBlock buffer(res = hash.DigestSize()); + hash.Final(buffer); + + memcpy(sDigest, buffer.BytePtr(), buffer.SizeInBytes()); + }break; + } + return res; } static unsigned char passwordPad[32] = { @@ -150,8 +179,10 @@ namespace PdfReader std::string sUserPassword = NSFile::CUtf8Converter::GetUtf8StringFromUnicode(wsUserPassword); return MakeFileKey2(handler, sUserPassword); } - else if ( handler->m_nEncryptRevision == 5 ) + else { + bool bValidate = false; + NSUnicodeConverter::CUnicodeConverter conv; std::string sUserPassword = conv.SASLprepToUtf8(wsUserPassword); int len = sUserPassword.length() < 127 ? sUserPassword.length() : 127; @@ -164,7 +195,12 @@ namespace PdfReader CryptoPP::SecByteBlock buffer(hash.DigestSize()); hash.Final(buffer); - bool bValidate = (0 == memcmp(buffer.BytePtr(), handler->m_seUserKey->GetUBuffer(), 32)); + if ( handler->m_nEncryptRevision > 5 ) + { + MakeFileKey3(sUserPassword, buffer.BytePtr(), buffer.SizeInBytes()); + } + + bValidate = (0 == memcmp(buffer.BytePtr(), handler->m_seUserKey->GetUBuffer(), 32)); if (bValidate) { @@ -174,9 +210,14 @@ namespace PdfReader CryptoPP::SecByteBlock buffer(hash.DigestSize()); hash.Final(buffer); + if ( handler->m_nEncryptRevision > 5 ) + { + MakeFileKey3(sUserPassword, buffer.BytePtr(), buffer.SizeInBytes()); + } + CryptoPP::AES::Decryption aesDecryption(buffer.BytePtr(), buffer.SizeInBytes()); - unsigned char* empty[16] = {}; - CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, (unsigned char*)empty ); + unsigned char empty[16] = {}; + CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, empty ); CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::ArraySink( (unsigned char*)handler->m_sFileKey, 32), CryptoPP::StreamTransformationFilter::NO_PADDING ); stfDecryptor.Put( handler->m_seUserEncryptionKey->GetUBuffer(), 32); @@ -193,6 +234,11 @@ namespace PdfReader CryptoPP::SecByteBlock buffer(hash.DigestSize()); hash.Final(buffer); + if ( handler->m_nEncryptRevision > 5 ) + { + MakeFileKey3(sOwnerPassword, buffer.BytePtr(), buffer.SizeInBytes(), handler->m_seUserKey->GetUBuffer(), 48); + } + bValidate = (0 == memcmp(buffer.BytePtr(), handler->m_seOwnerKey->GetUBuffer(), 32)); if (bValidate) @@ -203,10 +249,15 @@ namespace PdfReader CryptoPP::SecByteBlock buffer(hash.DigestSize()); hash.Final(buffer); + + if ( handler->m_nEncryptRevision > 5 ) + { + MakeFileKey3(sOwnerPassword, buffer.BytePtr(), buffer.SizeInBytes(), handler->m_seUserKey->GetUBuffer(), 48); + } CryptoPP::AES::Decryption aesDecryption(buffer.BytePtr(), buffer.SizeInBytes()); - unsigned char* empty[16] = {}; - CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, (unsigned char*)empty ); + unsigned char empty[16] = {}; + CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, empty ); CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::ArraySink( (unsigned char*)handler->m_sFileKey, 32), CryptoPP::StreamTransformationFilter::NO_PADDING ); stfDecryptor.Put(handler->m_seOwnerEncryptionKey->GetUBuffer(), 32); @@ -216,9 +267,63 @@ namespace PdfReader handler->m_bOwnerPasswordValid = bValidate; return bValidate; } - else if ( handler->m_nEncryptRevision == 6 ) + } + + bool Decrypt::MakeFileKey3(const std::string &sPassword, unsigned char *pHash, int nHashSize, unsigned char *pHash2, int nHashSize2) + { + if (!pHash) return false; + + int len = sPassword.length() < 127 ? sPassword.length() : 127; + int size = 64 * (len + 64 + nHashSize2); // max + + unsigned char K[64]; //max size sha + unsigned char *K1 = new unsigned char[size]; + unsigned char *E = new unsigned char[size]; + + int hash_size = nHashSize; + memcpy(K, pHash, nHashSize); + + int iteration = 0; + + while( (iteration < 64) || (iteration < E[size - 1] + 32)) { + CryptoPP::SecByteBlock key(K, 16), iv(K + 16, 16); + + size = 0; + for (int i = 0; i < 64; i++) + { + memcpy(K1 + size, sPassword.c_str(), len); size += len; + memcpy(K1 + size, K, hash_size); size += hash_size; + if (pHash2) + { + memcpy(K1 + size, pHash2, nHashSize2); size += nHashSize2; + } + } + + CryptoPP::CBC_Mode< CryptoPP::AES >::Encryption encryption; + encryption.SetKeyWithIV( key, key.size(), iv ); + + CryptoPP::StreamTransformationFilter stfEncryption(encryption, new CryptoPP::ArraySink( E, size), CryptoPP::StreamTransformationFilter::NO_PADDING ); + stfEncryption.Put2(K1, size, 1, true); + stfEncryption.MessageEnd(); +//---------------------------------------------------------- + int E_mod_3 = 0; + for (unsigned int i = 0; i < 16; ++i) + { + E_mod_3 += E[i]; + } + E_mod_3 %= 3; + + hash_size = SHA(E_mod_3, E, size, K); + + iteration++; } + + delete []K1; + delete []E; + + memcpy (pHash, K, 32); // pHash - from sha256 + return true; } bool Decrypt::MakeFileKey2(StandardSecurityHandler *handler, const std::string &sUserPassword) diff --git a/PdfReader/Src/Decrypt.h b/PdfReader/Src/Decrypt.h index 92ee54c728..b421cb8d02 100644 --- a/PdfReader/Src/Decrypt.h +++ b/PdfReader/Src/Decrypt.h @@ -53,6 +53,7 @@ namespace PdfReader private: + static bool MakeFileKey3(const std::string &sPassword, unsigned char *pHash, int nHashSize, unsigned char *pHash2 = NULL, int nHashSize2 = 0); static bool MakeFileKey2(StandardSecurityHandler *handler, const std::string &userPassword); };