filter/source/pdf/impdialog.cxx | 3 filter/source/pdf/pdfexport.cxx | 3 include/vcl/pdf/PDFEncryptionInitialization.hxx | 31 ++++ include/vcl/pdfwriter.hxx | 39 ++---- vcl/Library_vcl.mk | 1 vcl/inc/pdf/IPDFEncryptor.hxx | 19 +-- vcl/inc/pdf/PDFEncryptor.hxx | 30 +--- vcl/inc/pdf/PDFEncryptorR6.hxx | 81 ++++++++++++ vcl/inc/pdf/pdfwriter_impl.hxx | 3 vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx | 117 ++++++++++++++++++ vcl/source/gdi/pdfwriter.cxx | 3 vcl/source/gdi/pdfwriter_impl.cxx | 20 +-- vcl/source/gdi/pdfwriter_impl2.cxx | 5 vcl/source/pdf/PDFEncryptionInitialization.cxx | 32 +++++ vcl/source/pdf/PDFEncryptor.cxx | 35 +---- vcl/source/pdf/PDFEncryptorR6.cxx | 150 +++++++++++++++++++++++- 16 files changed, 476 insertions(+), 96 deletions(-)
New commits: commit 2d286deb40ca980176aa22823b6e9557b2336429 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Wed Nov 20 18:33:40 2024 +0900 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Fri Feb 14 13:52:06 2025 +0100 pdf: add /Perm encrypted access permission algorithm + add test Change-Id: Iba54dab6738c9707b37e434bab23ae286675436d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176882 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178756 Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> Tested-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/vcl/inc/pdf/PDFEncryptorR6.hxx b/vcl/inc/pdf/PDFEncryptorR6.hxx index e6efdeb5768d..70f7a3422f3a 100644 --- a/vcl/inc/pdf/PDFEncryptorR6.hxx +++ b/vcl/inc/pdf/PDFEncryptorR6.hxx @@ -76,6 +76,31 @@ VCL_DLLPUBLIC std::vector<sal_uInt8> decryptKey(const sal_uInt8* pUserPass, size std::vector<sal_uInt8>& U, std::vector<sal_uInt8>& UE); +/** Algorithm 13: Validating the permissions (Security handlers of revision 6) + * + * Described in ISO 32000-2:2020(E) - 7.6.4.4.12 + */ +VCL_DLLPUBLIC std::vector<sal_uInt8> decryptPerms(std::vector<sal_uInt8>& rPermsEncrypted, + std::vector<sal_uInt8>& rFileEncryptionKey); + +/** Algorithm 10 step f) + * + * Computing the encryption dictionary’s Perms (permissions) value (Security handlers of revision 6) + * + * Described in ISO 32000-2:2020(E) - 7.6.4.4.9 + */ +VCL_DLLPUBLIC std::vector<sal_uInt8> encryptPerms(std::vector<sal_uInt8>& rPerms, + std::vector<sal_uInt8>& rFileEncryptionKey); + +/** Algorithm 10 steps a) - e) + * + * Computing the encryption dictionary’s Perms (permissions) value (Security handlers of revision 6) + * + * Described in ISO 32000-2:2020(E) - 7.6.4.4.9 + */ +VCL_DLLPUBLIC std::vector<sal_uInt8> createPerms(sal_Int32 nAccessPermissions, + bool bEncryptMetadata); + } // end vcl::pdf /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx b/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx index 6f1e868564e6..408735d12ca2 100644 --- a/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx +++ b/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx @@ -180,6 +180,70 @@ CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testGenerateOandOE) CPPUNIT_ASSERT_EQUAL( true, vcl::pdf::validateOwnerPassword(aOwnerPass.data(), aOwnerPass.size(), U, O)); } + +CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testPermsEncryption) +{ + // Encrypts file permissions for /Perms entry + + // We use a existing encrypted /Perm to validate the decryption and re-encryption + // algorithm works correctly. + + const sal_uInt8 pUserPass[] = { 'T', 'e', 's', 't' }; + + // U and UE taken from an PDF that was encrypted with "Test" as password + std::vector<sal_uInt8> U = parseHex("7BD210807A0277FECC52C261C442F02E1AD62C1A23553348B8F8AF7320" + "DC9978FAB7E65E1BF4CA76F4BE5E6D2AA8C7D5"); + std::vector<sal_uInt8> UE + = parseHex("67022D91A6BDF3179F488DC9658E54B78A0AD05C6A9C419DCD17A6941C151197"); + + // We decrypt the key, which is needed to decrypt and encrypt the /Perms content + std::vector<sal_uInt8> aKey = vcl::pdf::decryptKey(pUserPass, 4, U, UE); + + // Known encrypted /Perms content taken from the PDF + std::vector<sal_uInt8> aPermEncrypted = parseHex("6a2306c6e5e71a5bbd8404b07abec38f"); + + // Decrypt + std::vector<sal_uInt8> aPermsDecrpyted = vcl::pdf::decryptPerms(aPermEncrypted, aKey); + + // Encrypt again + std::vector<sal_uInt8> aPermsReencrypted = vcl::pdf::encryptPerms(aPermsDecrpyted, aKey); + + // Original encrypted /Perm content should be equal to decrypted and encrypted again + CPPUNIT_ASSERT_EQUAL(std::string("6a2306c6e5e71a5bbd8404b07abec38f"), + comphelper::hashToString(aPermsReencrypted)); + + // Always should be a,b,d + CPPUNIT_ASSERT_EQUAL(sal_uInt8('a'), aPermsDecrpyted[9]); + CPPUNIT_ASSERT_EQUAL(sal_uInt8('d'), aPermsDecrpyted[10]); + CPPUNIT_ASSERT_EQUAL(sal_uInt8('b'), aPermsDecrpyted[11]); + + // Metadata encrypted? - T or F + CPPUNIT_ASSERT_EQUAL(sal_uInt8('T'), aPermsDecrpyted[8]); + + // Decrypting the access permissions + sal_Int32 aAccessPermissions + = sal_Int32(aPermsDecrpyted[0]) + sal_Int32(aPermsDecrpyted[1] << 8) + + sal_Int32(aPermsDecrpyted[2] << 16) + sal_Int32(aPermsDecrpyted[3] << 24); + + // Taken from the PDF (/P entry) + sal_Int32 nExpectedAccessPermisssions = -4; + CPPUNIT_ASSERT_EQUAL(nExpectedAccessPermisssions, aAccessPermissions); + + // the whole decrypted /Perms content + CPPUNIT_ASSERT_EQUAL(std::string("fcffffffffffffff54616462bb609a8a"), + comphelper::hashToString(aPermsDecrpyted)); + + // Check the creating /Perm content from access permissions works correctly + std::vector<sal_uInt8> aPermsCreated = vcl::pdf::createPerms(nExpectedAccessPermisssions, true); + + // Last 12 bytes are random, so we shouldn't check those + std::vector<sal_uInt8> aPermsWithoutRandomBytes(aPermsCreated.begin(), + aPermsCreated.begin() + 12); + + // Should match the decrypted content + CPPUNIT_ASSERT_EQUAL(std::string("fcffffffffffffff54616462"), + comphelper::hashToString(aPermsWithoutRandomBytes)); +} } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/vcl/source/pdf/PDFEncryptorR6.cxx b/vcl/source/pdf/PDFEncryptorR6.cxx index 9f0670f1fe1f..b3850a5929f8 100644 --- a/vcl/source/pdf/PDFEncryptorR6.cxx +++ b/vcl/source/pdf/PDFEncryptorR6.cxx @@ -129,6 +129,48 @@ std::vector<sal_uInt8> decryptKey(const sal_uInt8* pPass, size_t nLength, std::v return aFileEncryptionKey; } +/** Algorithm 13: Validating the permissions */ +std::vector<sal_uInt8> decryptPerms(std::vector<sal_uInt8>& rPermsEncrypted, + std::vector<sal_uInt8>& rFileEncryptionKey) +{ + std::vector<sal_uInt8> aPermsDecrpyted(rPermsEncrypted.size()); + std::vector<sal_uInt8> iv(IV_SIZE, 0); + comphelper::Decrypt aDecryptor(rFileEncryptionKey, iv, comphelper::CryptoType::AES_256_ECB); + aDecryptor.update(aPermsDecrpyted, rPermsEncrypted); + return aPermsDecrpyted; +} + +/** Algorithm 10 step f) */ +std::vector<sal_uInt8> encryptPerms(std::vector<sal_uInt8>& rPerms, + std::vector<sal_uInt8>& rFileEncryptionKey) +{ + std::vector<sal_uInt8> aPermsEncrypted(rPerms.size()); + std::vector<sal_uInt8> iv(IV_SIZE, 0); + comphelper::Encrypt aEncryptor(rFileEncryptionKey, iv, comphelper::CryptoType::AES_256_ECB); + aEncryptor.update(aPermsEncrypted, rPerms); + return aPermsEncrypted; +} + +/** Algorithm 10 steps a) - e) */ +std::vector<sal_uInt8> createPerms(sal_Int32 nAccessPermissions, bool bEncryptMetadata) +{ + std::vector<sal_uInt8> aPermsCreated; + generateBytes(aPermsCreated, 16); + aPermsCreated[0] = sal_uInt8(nAccessPermissions); + aPermsCreated[1] = sal_uInt8(nAccessPermissions >> 8); + aPermsCreated[2] = sal_uInt8(nAccessPermissions >> 16); + aPermsCreated[3] = sal_uInt8(nAccessPermissions >> 24); + aPermsCreated[4] = sal_uInt8(0xff); + aPermsCreated[5] = sal_uInt8(0xff); + aPermsCreated[6] = sal_uInt8(0xff); + aPermsCreated[7] = sal_uInt8(0xff); + aPermsCreated[8] = bEncryptMetadata ? 'T' : 'F'; // Encrypt metadata + aPermsCreated[9] = 'a'; + aPermsCreated[10] = 'd'; + aPermsCreated[11] = 'b'; + return aPermsCreated; +} + /** Algorithm 2.B: Computing a hash (revision 6 and later) */ std::vector<sal_uInt8> computeHashR6(const sal_uInt8* pPassword, size_t nPasswordLength, std::vector<sal_uInt8> const& rValidationSalt, commit 3ca27525c717be9e5967b1eaf8577f1f97b806f6 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Wed Nov 20 17:25:26 2024 +0900 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Fri Feb 14 13:50:44 2025 +0100 pdf: generate U, UE and O, OE keys for R6 encryption Also test the algorithm against the known values from an example, to be sure we are calculating the values correctly. For this we need a couple of decryption algorithms, but those do mostly just the reverse of the encryption. Change-Id: I5499ed0b57671f44e48fe68961e07cde22be6b39 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176881 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178755 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/vcl/inc/pdf/PDFEncryptorR6.hxx b/vcl/inc/pdf/PDFEncryptorR6.hxx index 7234e96f6af1..e6efdeb5768d 100644 --- a/vcl/inc/pdf/PDFEncryptorR6.hxx +++ b/vcl/inc/pdf/PDFEncryptorR6.hxx @@ -9,17 +9,73 @@ #pragma once +#include <rtl/ustring.hxx> #include <string_view> #include <vector> #include <vcl/dllapi.h> namespace vcl::pdf { +/** Algorithm 2.B: Computing a hash (revision 6 and later) + * + * Described in ISO 32000-2:2020(E) - 7.6.4.3.4 + */ VCL_DLLPUBLIC std::vector<sal_uInt8> computeHashR6(const sal_uInt8* pPassword, size_t nPasswordLength, std::vector<sal_uInt8> const& rValidationSalt, std::vector<sal_uInt8> const& rUserKey = std::vector<sal_uInt8>()); +/** Algorithm 11: Authenticating the user password (Security handlers of revision 6) + * + * Described in ISO 32000-2:2020(E) - 7.6.4.4.10 + */ +VCL_DLLPUBLIC bool validateUserPassword(const sal_uInt8* pUserPass, size_t nPasswordLength, + std::vector<sal_uInt8>& U); + +/** Algorithm 12: Authenticating the owner password (Security handlers of revision 6) + * + * Described in ISO 32000-2:2020(E) - 7.6.4.4.11 + */ +VCL_DLLPUBLIC bool validateOwnerPassword(const sal_uInt8* pUserPass, size_t nPasswordLength, + std::vector<sal_uInt8>& U, std::vector<sal_uInt8>& O); + +/** Generates the encryption key - random data 32-byte */ +VCL_DLLPUBLIC std::vector<sal_uInt8> generateKey(); + +/** Algorithm 8: U and UE + * + * Computing the encryption dictionary’s U (user password) and UE (user encryption) values + * (Security handlers of revision 6) + * + * Described in ISO 32000-2:2020(E) - 7.6.4.4.7 + */ +VCL_DLLPUBLIC void generateUandUE(const sal_uInt8* pUserPass, size_t nPasswordLength, + std::vector<sal_uInt8>& rFileEncryptionKey, + std::vector<sal_uInt8>& U, std::vector<sal_uInt8>& UE); + +/** Algorithm 9: O and OE + * + * Computing the encryption dictionary’s O (owner password) and OE (owner encryption) values + * (Security handlers of revision 6) + * + * Described in ISO 32000-2:2020(E) - 7.6.4.4.8 + */ +VCL_DLLPUBLIC void generateOandOE(const sal_uInt8* pUserPass, size_t nPasswordLength, + std::vector<sal_uInt8>& rFileEncryptionKey, + std::vector<sal_uInt8>& U, std::vector<sal_uInt8>& O, + std::vector<sal_uInt8>& OE); + +/** Algorithm 8 step b) in reverse + * + * Described in ISO 32000-2:2020(E) - 7.6.4.4.7 + * + * - compute the hash with password and user key salt + * - decrypt with hash as key and zero IV + */ +VCL_DLLPUBLIC std::vector<sal_uInt8> decryptKey(const sal_uInt8* pUserPass, size_t nPasswordLength, + std::vector<sal_uInt8>& U, + std::vector<sal_uInt8>& UE); + } // end vcl::pdf /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx b/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx index 4f2239bc01b8..6f1e868564e6 100644 --- a/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx +++ b/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx @@ -127,6 +127,59 @@ CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testComputeHashForR6) } } +CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testGenerateUandUE) +{ + // Checks we calculate U and UE correctly + const sal_uInt8 pUserPass[] = { 'T', 'e', 's', 't' }; + + std::vector<sal_uInt8> aInputKey = vcl::pdf::generateKey(); + + std::vector<sal_uInt8> U; + std::vector<sal_uInt8> UE; + + // Generate the U and UE from the user password and encrypt the + // encryption key into UE + vcl::pdf::generateUandUE(pUserPass, 4, aInputKey, U, UE); + + // Checks that the U validates the password (would fail if the U + // would be calculated wrongly). + CPPUNIT_ASSERT_EQUAL(true, vcl::pdf::validateUserPassword(pUserPass, 4, U)); + + // Decrypt the key - this would fail if U and UE would be calculated + // wrongly + auto aDecryptedKey = vcl::pdf::decryptKey(pUserPass, 4, U, UE); + + // Decrypted key and input key need to match + CPPUNIT_ASSERT_EQUAL(comphelper::hashToString(aInputKey), + comphelper::hashToString(aDecryptedKey)); +} + +CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testGenerateOandOE) +{ + // Checks we calculate O and OE correctly + + const auto aUserPass = std::to_array<sal_uInt8>({ 'T', 'e', 's', 't' }); + const auto aOwnerPass = std::to_array<sal_uInt8>({ 'T', 'e', 's', 't', '2' }); + + std::vector<sal_uInt8> aInputKey = vcl::pdf::generateKey(); + + std::vector<sal_uInt8> U; + std::vector<sal_uInt8> UE; + std::vector<sal_uInt8> O; + std::vector<sal_uInt8> OE; + + // Generates U and UE - we need U in generateOandOE + vcl::pdf::generateUandUE(aUserPass.data(), aUserPass.size(), aInputKey, U, UE); + vcl::pdf::generateOandOE(aOwnerPass.data(), aOwnerPass.size(), aInputKey, U, O, OE); + + // Checks the user password is valid + CPPUNIT_ASSERT_EQUAL(true, + vcl::pdf::validateUserPassword(aUserPass.data(), aUserPass.size(), U)); + + // Checks the owner password is valid + CPPUNIT_ASSERT_EQUAL( + true, vcl::pdf::validateOwnerPassword(aOwnerPass.data(), aOwnerPass.size(), U, O)); +} } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/vcl/source/pdf/PDFEncryptorR6.cxx b/vcl/source/pdf/PDFEncryptorR6.cxx index 64e668dca598..9f0670f1fe1f 100644 --- a/vcl/source/pdf/PDFEncryptorR6.cxx +++ b/vcl/source/pdf/PDFEncryptorR6.cxx @@ -18,6 +18,10 @@ namespace vcl::pdf { namespace { +constexpr size_t IV_SIZE = 16; +constexpr size_t KEY_SIZE = 32; +constexpr size_t SALT_SIZE = 8; + /** Calculates modulo 3 of the 128-bit integer, using the first 16 bytes of the vector */ sal_Int32 calculateModulo3(std::vector<sal_uInt8> const& rInput) { @@ -26,12 +30,106 @@ sal_Int32 calculateModulo3(std::vector<sal_uInt8> const& rInput) nSum += rInput[i]; return nSum % 3; } + +void generateBytes(std::vector<sal_uInt8>& rBytes, size_t nSize) +{ + rBytes.resize(nSize); + + for (size_t i = 0; i < rBytes.size(); ++i) + rBytes[i] = sal_uInt8(comphelper::rng::uniform_uint_distribution(0, 0xFF)); } -/** Algorithm 2.B: Computing a hash (revision 6 and later) - * - * Described in ISO 32000-2:2020(E) - 7.6.4.3.4 - */ +} // end anonymous + +std::vector<sal_uInt8> generateKey() +{ + std::vector<sal_uInt8> aKey; + generateBytes(aKey, KEY_SIZE); + return aKey; +} + +bool validateUserPassword(const sal_uInt8* pPass, size_t nLength, std::vector<sal_uInt8>& U) +{ + std::vector<sal_uInt8> aHash(U.begin(), U.begin() + KEY_SIZE); + std::vector<sal_uInt8> aValidationSalt(U.begin() + KEY_SIZE, U.begin() + KEY_SIZE + SALT_SIZE); + std::vector<sal_uInt8> aCalculatedHash + = vcl::pdf::computeHashR6(pPass, nLength, aValidationSalt); + return aHash == aCalculatedHash; +} + +bool validateOwnerPassword(const sal_uInt8* pPass, size_t nLength, std::vector<sal_uInt8>& U, + std::vector<sal_uInt8>& O) +{ + std::vector<sal_uInt8> aHash(O.begin(), O.begin() + KEY_SIZE); + std::vector<sal_uInt8> aValidationSalt(O.begin() + KEY_SIZE, O.begin() + KEY_SIZE + SALT_SIZE); + std::vector<sal_uInt8> aCalculatedHash + = vcl::pdf::computeHashR6(pPass, nLength, aValidationSalt, U); + return aHash == aCalculatedHash; +} + +/** Algorithm 8 */ +void generateUandUE(const sal_uInt8* pPass, size_t nLength, + std::vector<sal_uInt8>& rFileEncryptionKey, std::vector<sal_uInt8>& U, + std::vector<sal_uInt8>& UE) +{ + std::vector<sal_uInt8> aValidationSalt; + generateBytes(aValidationSalt, SALT_SIZE); + std::vector<sal_uInt8> aKeySalt; + generateBytes(aKeySalt, SALT_SIZE); + + U = vcl::pdf::computeHashR6(pPass, nLength, aValidationSalt); + U.insert(U.end(), aValidationSalt.begin(), aValidationSalt.end()); + U.insert(U.end(), aKeySalt.begin(), aKeySalt.end()); + + std::vector<sal_uInt8> aKeyHash = vcl::pdf::computeHashR6(pPass, nLength, aKeySalt); + std::vector<sal_uInt8> iv(IV_SIZE, 0); // zero IV + UE = std::vector<sal_uInt8>(rFileEncryptionKey.size(), 0); + comphelper::Encrypt aEncrypt(aKeyHash, iv, comphelper::CryptoType::AES_256_CBC); + aEncrypt.update(UE, rFileEncryptionKey); +} + +/** Algorithm 9 */ +void generateOandOE(const sal_uInt8* pPass, size_t nLength, + std::vector<sal_uInt8>& rFileEncryptionKey, std::vector<sal_uInt8>& U, + std::vector<sal_uInt8>& O, std::vector<sal_uInt8>& OE) +{ + std::vector<sal_uInt8> aValidationSalt; + generateBytes(aValidationSalt, SALT_SIZE); + std::vector<sal_uInt8> aKeySalt; + generateBytes(aKeySalt, SALT_SIZE); + + O = vcl::pdf::computeHashR6(pPass, nLength, aValidationSalt, U); + O.insert(O.end(), aValidationSalt.begin(), aValidationSalt.end()); + O.insert(O.end(), aKeySalt.begin(), aKeySalt.end()); + + std::vector<sal_uInt8> aKeyHash = vcl::pdf::computeHashR6(pPass, nLength, aKeySalt, U); + std::vector<sal_uInt8> iv(IV_SIZE, 0); // zero IV + OE = std::vector<sal_uInt8>(rFileEncryptionKey.size(), 0); + comphelper::Encrypt aEncrypt(aKeyHash, iv, comphelper::CryptoType::AES_256_CBC); + aEncrypt.update(OE, rFileEncryptionKey); +} + +/** Algorithm 8 step b) */ +std::vector<sal_uInt8> decryptKey(const sal_uInt8* pPass, size_t nLength, std::vector<sal_uInt8>& U, + std::vector<sal_uInt8>& UE) +{ + std::vector<sal_uInt8> aKeySalt(U.begin() + KEY_SIZE + SALT_SIZE, + U.begin() + KEY_SIZE + SALT_SIZE + SALT_SIZE); + + auto aKeyHash = vcl::pdf::computeHashR6(pPass, nLength, aKeySalt); + + std::vector<sal_uInt8> aEncryptedKey(UE.begin(), UE.begin() + KEY_SIZE); + std::vector<sal_uInt8> iv(IV_SIZE, 0); + + comphelper::Decrypt aDecryptCBC(aKeyHash, iv, comphelper::CryptoType::AES_256_CBC); + std::vector<sal_uInt8> aFileEncryptionKey(aEncryptedKey.size()); + sal_uInt32 nDecrypted = aDecryptCBC.update(aFileEncryptionKey, aEncryptedKey); + if (nDecrypted == 0) + return std::vector<sal_uInt8>(); + return aFileEncryptionKey; +} + +/** Algorithm 2.B: Computing a hash (revision 6 and later) */ std::vector<sal_uInt8> computeHashR6(const sal_uInt8* pPassword, size_t nPasswordLength, std::vector<sal_uInt8> const& rValidationSalt, std::vector<sal_uInt8> const& rUserKey) @@ -47,7 +145,7 @@ std::vector<sal_uInt8> computeHashR6(const sal_uInt8* pPassword, size_t nPasswor std::vector<sal_uInt8> E; - sal_Int32 nRound = 1; + sal_Int32 nRound = 1; // round 0 is done already do { // Step a) commit 53896e425579695c3a8f76fd77cc20802e0dea0b Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Wed Nov 20 17:04:48 2024 +0900 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Fri Feb 14 13:50:26 2025 +0100 pdf: move common things to interface, prepare methods Move common flag, if the stream is encrypted from PDFEncryptor impl. to the IPDFEncryptor "interface". Change setupEncryption and encrypt methods to be closer to what will be needed in R6 implementation. Change-Id: I4dbd787c29e2a13ac900c6df360538b7e06af4ec Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176880 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178754 Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> Tested-by: Jenkins diff --git a/vcl/inc/pdf/IPDFEncryptor.hxx b/vcl/inc/pdf/IPDFEncryptor.hxx index bcd90dcef4bf..706eb82c71ed 100644 --- a/vcl/inc/pdf/IPDFEncryptor.hxx +++ b/vcl/inc/pdf/IPDFEncryptor.hxx @@ -39,6 +39,10 @@ namespace vcl::pdf */ class IPDFEncryptor { +private: + /* set to true if the following stream must be encrypted, used inside writeBuffer() */ + bool m_bEncryptThisStream = false; + public: virtual ~IPDFEncryptor() {} @@ -73,17 +77,16 @@ public: virtual void setupKeysAndCheck(PDFEncryptionProperties& rProperties) = 0; /** Setup before we start encrypting - remembers the key */ - virtual void setupEncryption(std::vector<sal_uInt8> const& rEncryptionKey, sal_Int32 nObject) - = 0; - - virtual void enableStreamEncryption() = 0; - virtual void disableStreamEncryption() = 0; - virtual bool isStreamEncryptionEnabled() = 0; + virtual void setupEncryption(std::vector<sal_uInt8>& rEncryptionKey, sal_Int32 nObject) = 0; /** Encrypts the input and stores into the output */ - virtual void encrypt(const void* pInput, sal_uInt64 nInputSize, sal_uInt8* pOutput, - sal_uInt64 nOutputsSize) + virtual void encrypt(const void* pInput, sal_uInt64 nInputSize, std::vector<sal_uInt8>& rOutput, + sal_uInt64 nOutputSize) = 0; + + void enableStreamEncryption() { m_bEncryptThisStream = true; } + void disableStreamEncryption() { m_bEncryptThisStream = false; } + bool isStreamEncryptionEnabled() { return m_bEncryptThisStream; } }; } diff --git a/vcl/inc/pdf/PDFEncryptor.hxx b/vcl/inc/pdf/PDFEncryptor.hxx index e4134605c194..9a65c5a0043b 100644 --- a/vcl/inc/pdf/PDFEncryptor.hxx +++ b/vcl/inc/pdf/PDFEncryptor.hxx @@ -15,11 +15,6 @@ #include <vector> #include <pdf/IPDFEncryptor.hxx> -namespace vcl -{ -struct PDFEncryptionProperties; -} - namespace com::sun::star::uno { template <typename> class Reference; @@ -41,9 +36,6 @@ private: sal_Int32 m_nKeyLength = 0; // key length, 16 or 5 sal_Int32 m_nRC4KeyLength = 0; // key length, 16 or 10, to be input to the algorithm 3.1 - /* set to true if the following stream must be encrypted, used inside writeBuffer() */ - bool m_bEncryptThisStream = false; - /* used to cipher the stream data and for password management */ rtlCipher m_aCipher = nullptr; @@ -67,14 +59,10 @@ public: void setupKeysAndCheck(PDFEncryptionProperties& rProperties) override; - void setupEncryption(std::vector<sal_uInt8> const& rEncryptionKey, sal_Int32 nObject) override; - void enableStreamEncryption() override; - void disableStreamEncryption() override; - - bool isStreamEncryptionEnabled() override { return m_bEncryptThisStream; } + void setupEncryption(std::vector<sal_uInt8>& rEncryptionKey, sal_Int32 nObject) override; - void encrypt(const void* pInput, sal_uInt64 nInputSize, sal_uInt8* pOutput, - sal_uInt64 nOutputsSize) override; + void encrypt(const void* pInput, sal_uInt64 nInputSize, std::vector<sal_uInt8>& rOutput, + sal_uInt64 nOutputSize) override; }; } diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 6ea3b49f156a..34e4a83a7a55 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -1618,7 +1618,7 @@ inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const OUString& rInSt *pCopy++ = static_cast<sal_uInt8>( aUnChar & 255 ); } //encrypt in place - m_pPDFEncryptor->encrypt(m_vEncryptionBuffer.data(), nChars, m_vEncryptionBuffer.data(), nChars); + m_pPDFEncryptor->encrypt(m_vEncryptionBuffer.data(), nChars, m_vEncryptionBuffer, nChars); //now append, hexadecimal (appendHex), the encrypted result for(int i = 0; i < nChars; i++) appendHex( m_vEncryptionBuffer[i], rOutBuffer ); @@ -1638,7 +1638,7 @@ inline void PDFWriterImpl::appendLiteralStringEncrypt( std::string_view rInStrin m_vEncryptionBuffer.resize(nChars); //encrypt the string in a buffer, then append it enableStringEncryption(nInObjectNumber); - m_pPDFEncryptor->encrypt(rInString.data(), nChars, m_vEncryptionBuffer.data(), nChars); + m_pPDFEncryptor->encrypt(rInString.data(), nChars, m_vEncryptionBuffer, nChars); appendLiteralString( reinterpret_cast<char*>(m_vEncryptionBuffer.data()), nChars, rOutBuffer ); } else @@ -1749,7 +1749,7 @@ bool PDFWriterImpl::writeBufferBytes( const void* pBuffer, sal_uInt64 nBytes ) if (bStreamEncryption) { m_vEncryptionBuffer.resize(nBytes); - m_pPDFEncryptor->encrypt(pBuffer, nBytes, m_vEncryptionBuffer.data(), nBytes); + m_pPDFEncryptor->encrypt(pBuffer, nBytes, m_vEncryptionBuffer, nBytes); } const void* pWriteBuffer = bStreamEncryption ? m_vEncryptionBuffer.data() : pBuffer; @@ -9825,7 +9825,7 @@ bool PDFWriterImpl::writeBitmapObject( const BitmapEmit& rObject, bool bMask ) m_vEncryptionBuffer[nChar++] = rColor.GetBlue(); } //encrypt the colorspace lookup table - m_pPDFEncryptor->encrypt(m_vEncryptionBuffer.data(), nChar, m_vEncryptionBuffer.data(), nChar); + m_pPDFEncryptor->encrypt(m_vEncryptionBuffer.data(), nChar, m_vEncryptionBuffer, nChar); //now queue the data for output nChar = 0; for( sal_uInt16 i = 0; i < pAccess->GetPaletteEntryCount(); i++ ) diff --git a/vcl/source/pdf/PDFEncryptor.cxx b/vcl/source/pdf/PDFEncryptor.cxx index 63bb49c05425..a5425f014ae0 100644 --- a/vcl/source/pdf/PDFEncryptor.cxx +++ b/vcl/source/pdf/PDFEncryptor.cxx @@ -393,11 +393,7 @@ void PDFEncryptor::setupKeysAndCheck(vcl::PDFEncryptionProperties& rProperties) } } -void PDFEncryptor::enableStreamEncryption() { m_bEncryptThisStream = true; } - -void PDFEncryptor::disableStreamEncryption() { m_bEncryptThisStream = false; } - -void PDFEncryptor::setupEncryption(std::vector<sal_uInt8> const& rEncryptionKey, sal_Int32 nObject) +void PDFEncryptor::setupEncryption(std::vector<sal_uInt8>& rEncryptionKey, sal_Int32 nObject) { std::vector<sal_uInt8> aKey(rEncryptionKey.begin(), rEncryptionKey.begin() + m_nKeyLength); std::vector<sal_uInt8> aObjectArray{ @@ -418,10 +414,10 @@ void PDFEncryptor::setupEncryption(std::vector<sal_uInt8> const& rEncryptionKey, } /* implement the encryption part of the PDF spec encryption algorithm 3.1 */ -void PDFEncryptor::encrypt(const void* pInput, sal_uInt64 nInputSize, sal_uInt8* pOutput, - sal_uInt64 nOutputsSize) +void PDFEncryptor::encrypt(const void* pInput, sal_uInt64 nInputSize, + std::vector<sal_uInt8>& rOutput, sal_uInt64 nOutputsSize) { - rtl_cipher_encodeARCFOUR(m_aCipher, pInput, sal_Size(nInputSize), pOutput, + rtl_cipher_encodeARCFOUR(m_aCipher, pInput, sal_Size(nInputSize), rOutput.data(), sal_Size(nOutputsSize)); } commit 22ba67f0500a66a0e172b5911a30d5471a7ab3d7 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Mon Nov 11 22:53:26 2024 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Fri Feb 14 13:44:06 2025 +0100 pdf: forward declare IPDFEncryptor To compile less when changing PDFEncryptor. Change-Id: I56e19e12494488fedb929998f8e6d0ff3bf8008c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176456 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177875 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/vcl/inc/pdf/pdfwriter_impl.hxx b/vcl/inc/pdf/pdfwriter_impl.hxx index 3f09038068b8..4b7b72dce4fc 100644 --- a/vcl/inc/pdf/pdfwriter_impl.hxx +++ b/vcl/inc/pdf/pdfwriter_impl.hxx @@ -34,7 +34,6 @@ #include <pdf/ResourceDict.hxx> #include <pdf/BitmapID.hxx> #include <pdf/Matrix3.hxx> -#include <pdf/PDFEncryptor.hxx> #include <com/sun/star/lang/Locale.hpp> #include <com/sun/star/util/XURLTransformer.hpp> @@ -684,6 +683,8 @@ struct PDFDocumentAttachedFile sal_Int32 mnObjectId; }; +class IPDFEncryptor; + } // end pdf namespace class PDFWriterImpl final : public VirtualDevice, public PDFObjectContainer diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index 711783309aaf..6ea3b49f156a 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -96,6 +96,8 @@ #include <pdf/objectcopier.hxx> #include <pdf/pdfwriter_impl.hxx> #include <pdf/PdfConfig.hxx> +#include <pdf/IPDFEncryptor.hxx> +#include <pdf/PDFEncryptor.hxx> #include <o3tl/sorted_vector.hxx> #include <frozen/bits/defines.h> #include <frozen/bits/elsa_std.h> diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index ec4adefa47c7..2f06a292c936 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -25,6 +25,7 @@ #include <vcl/metaact.hxx> #include <vcl/BitmapReadAccess.hxx> #include <vcl/graph.hxx> +#include <pdf/IPDFEncryptor.hxx> #include <unotools/streamwrap.hxx> commit 8b9aacc39a56bbf7824fef3f885ee1dee1ca0e26 Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Mon Nov 11 22:48:34 2024 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Fri Feb 14 13:43:53 2025 +0100 pdf: cleanup and improve PDFEncryptionProperties Add clear method to clear the variables that we usually want to be cleared. Also rename Encrypt to canEncrypt - which is more clear what it means. Cleanup initializers. Change-Id: I96735eb6f73a699fb0759496fc8781bcff3854de Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176455 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177874 Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> Tested-by: Jenkins diff --git a/include/vcl/pdfwriter.hxx b/include/vcl/pdfwriter.hxx index a863b17c1879..14c6265f3d88 100644 --- a/include/vcl/pdfwriter.hxx +++ b/include/vcl/pdfwriter.hxx @@ -77,15 +77,16 @@ class VCL_DLLPUBLIC PDFOutputStream struct PDFEncryptionProperties { //for both 40 and 128 bit security, see 3.5.2 PDF v 1.4 table 3.15, v 1.5 and v 1.6 table 3.20. - bool CanPrintTheDocument; - bool CanModifyTheContent; - bool CanCopyOrExtract; - bool CanAddOrModify; + bool CanPrintTheDocument = false; + bool CanModifyTheContent = false; + bool CanCopyOrExtract = false; + bool CanAddOrModify = false; + //for revision 3 (bit 128 security) only - bool CanFillInteractive; - bool CanExtractForAccessibility; - bool CanAssemble; - bool CanPrintFull; + bool CanFillInteractive = false; + bool CanExtractForAccessibility = true; + bool CanAssemble = false; + bool CanPrintFull = false; // encryption will only happen if EncryptionKey is not empty // EncryptionKey is actually a construct out of OValue, UValue and DocumentIdentifier @@ -98,22 +99,16 @@ struct PDFEncryptionProperties std::vector<sal_uInt8> EncryptionKey; std::vector<sal_uInt8> DocumentIdentifier; - //permission default set for 128 bit, accessibility only - PDFEncryptionProperties() : - CanPrintTheDocument ( false ), - CanModifyTheContent ( false ), - CanCopyOrExtract ( false ), - CanAddOrModify ( false ), - CanFillInteractive ( false ), - CanExtractForAccessibility ( true ), - CanAssemble ( false ), - CanPrintFull ( false ) - {} - + bool canEncrypt() const + { + return !OValue.empty() && !UValue.empty() && !DocumentIdentifier.empty(); + } - bool Encrypt() const + void clear() { - return ! OValue.empty() && ! UValue.empty() && ! DocumentIdentifier.empty(); + OValue.clear(); + UValue.clear(); + EncryptionKey.clear(); } }; diff --git a/vcl/source/gdi/pdfwriter_impl.cxx b/vcl/source/gdi/pdfwriter_impl.cxx index b86e84c03e79..711783309aaf 100644 --- a/vcl/source/gdi/pdfwriter_impl.cxx +++ b/vcl/source/gdi/pdfwriter_impl.cxx @@ -1461,7 +1461,7 @@ PDFWriterImpl::PDFWriterImpl( const PDFWriter::PDFWriterContext& rContext, m_pPDFEncryptor->prepareEncryption(xEncryptionMaterialHolder, m_aContext.Encryption); } - if (m_pPDFEncryptor && m_aContext.Encryption.Encrypt()) + if (m_pPDFEncryptor && m_aContext.Encryption.canEncrypt()) { m_pPDFEncryptor->setupKeysAndCheck(m_aContext.Encryption); } @@ -1597,7 +1597,7 @@ append the string as unicode hex, encrypted if needed inline void PDFWriterImpl::appendUnicodeTextStringEncrypt( const OUString& rInString, const sal_Int32 nInObjectNumber, OStringBuffer& rOutBuffer ) { rOutBuffer.append( "<" ); - if (m_aContext.Encryption.Encrypt()) + if (m_aContext.Encryption.canEncrypt()) { const sal_Unicode* pStr = rInString.getStr(); sal_Int32 nLen = rInString.getLength(); @@ -1631,7 +1631,7 @@ inline void PDFWriterImpl::appendLiteralStringEncrypt( std::string_view rInStrin rOutBuffer.append( "(" ); sal_Int32 nChars = rInString.size(); //check for encryption, if ok, encrypt the string, then convert with appndLiteralString - if (m_aContext.Encryption.Encrypt()) + if (m_aContext.Encryption.canEncrypt()) { m_vEncryptionBuffer.resize(nChars); //encrypt the string in a buffer, then append it @@ -6184,7 +6184,7 @@ bool PDFWriterImpl::emitTrailer() sal_Int32 nSecObject = 0; - if( m_aContext.Encryption.Encrypt() ) + if (m_aContext.Encryption.canEncrypt()) { nSecObject = emitEncrypt(); } @@ -9808,7 +9808,7 @@ bool PDFWriterImpl::writeBitmapObject( const BitmapEmit& rObject, bool bMask ) aLine.append( "[ /Indexed/DeviceRGB " ); aLine.append( static_cast<sal_Int32>(pAccess->GetPaletteEntryCount()-1) ); aLine.append( " <" ); - if( m_aContext.Encryption.Encrypt() ) + if (m_aContext.Encryption.canEncrypt()) { enableStringEncryption(rObject.m_nObject); //check encryption buffer size diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx b/vcl/source/gdi/pdfwriter_impl2.cxx index 3efc67a32b61..ec4adefa47c7 100644 --- a/vcl/source/gdi/pdfwriter_impl2.cxx +++ b/vcl/source/gdi/pdfwriter_impl2.cxx @@ -1079,7 +1079,7 @@ void PDFWriterImpl::playMetafile( const GDIMetaFile& i_rMtf, vcl::PDFExtOutDevDa void PDFWriterImpl::checkAndEnableStreamEncryption(sal_Int32 nObject) { - if (!m_aContext.Encryption.Encrypt() || !m_pPDFEncryptor) + if (!m_aContext.Encryption.canEncrypt() || !m_pPDFEncryptor) return; m_pPDFEncryptor->enableStreamEncryption(); @@ -1094,7 +1094,7 @@ void PDFWriterImpl::disableStreamEncryption() void PDFWriterImpl::enableStringEncryption(sal_Int32 nObject) { - if (!m_aContext.Encryption.Encrypt() || !m_pPDFEncryptor) + if (!m_aContext.Encryption.canEncrypt() || !m_pPDFEncryptor) return; m_pPDFEncryptor->setupEncryption(m_aContext.Encryption.EncryptionKey, nObject); diff --git a/vcl/source/pdf/PDFEncryptor.cxx b/vcl/source/pdf/PDFEncryptor.cxx index 183e66e8e713..63bb49c05425 100644 --- a/vcl/source/pdf/PDFEncryptor.cxx +++ b/vcl/source/pdf/PDFEncryptor.cxx @@ -369,9 +369,7 @@ bool PDFEncryptor::prepareEncryption( if (!bSuccess) { - rProperties.OValue.clear(); - rProperties.UValue.clear(); - rProperties.EncryptionKey.clear(); + rProperties.clear(); } return bSuccess; } @@ -386,8 +384,7 @@ void PDFEncryptor::setupKeysAndCheck(vcl::PDFEncryptionProperties& rProperties) { // the field lengths are invalid ? This was not setup by initEncryption. // do not encrypt after all - rProperties.OValue.clear(); - rProperties.UValue.clear(); + rProperties.clear(); OSL_ENSURE(false, "encryption data failed sanity check, encryption disabled"); } else // setup key lengths commit dd1cff06e20e09784950327d744b68f75048b70a Author: Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk> AuthorDate: Mon Nov 11 19:14:49 2024 +0100 Commit: Andras Timar <andras.ti...@collabora.com> CommitDate: Fri Feb 14 13:43:39 2025 +0100 pdf: refactor and move encryption init. to a common function This is needed because we have to separate the init. for both encryption methods and we have to init both when the password is entered. Currently we only prepared this, to make this possible when we introduce the other encryption method. Change-Id: Id6556ddc6a6218164a93bb689f03d6ec6dbad8b9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176454 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Miklos Vajna <vmik...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177873 Tested-by: Jenkins Reviewed-by: Tomaž Vajngerl <qui...@gmail.com> diff --git a/filter/source/pdf/impdialog.cxx b/filter/source/pdf/impdialog.cxx index 482d523bed63..b62fb69158a7 100644 --- a/filter/source/pdf/impdialog.cxx +++ b/filter/source/pdf/impdialog.cxx @@ -23,6 +23,7 @@ #include <vcl/errinf.hxx> #include <vcl/graphic/GraphicMetadata.hxx> #include <vcl/svapp.hxx> +#include <vcl/pdf/PDFEncryptionInitialization.hxx> #include <vcl/weld.hxx> #include <sfx2/passwd.hxx> #include <comphelper/diagnose_ex.hxx> @@ -1418,7 +1419,7 @@ IMPL_LINK_NOARG(ImpPDFTabSecurityPage, ClickmaPbSetPwdHdl, weld::Button&, void) mbHaveUserPassword = !aUserPW.isEmpty(); mbHaveOwnerPassword = !aOwnerPW.isEmpty(); - mxPreparedPasswords = vcl::PDFWriter::InitEncryption( aOwnerPW, aUserPW ); + mxPreparedPasswords = vcl::pdf::initEncryption(aOwnerPW, aUserPW); if (!mxPreparedPasswords.is()) { OUString msg; diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx index 5956933154c6..cca7703c50c8 100644 --- a/filter/source/pdf/pdfexport.cxx +++ b/filter/source/pdf/pdfexport.cxx @@ -28,6 +28,7 @@ #include <vcl/mapmod.hxx> #include <vcl/gdimtf.hxx> #include <vcl/graphic/GraphicMetadata.hxx> +#include <vcl/pdf/PDFEncryptionInitialization.hxx> #include <rtl/ustring.hxx> #include <comphelper/propertyvalue.hxx> #include <comphelper/sequence.hxx> @@ -931,7 +932,7 @@ bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& aContext.Encryption.CanCopyOrExtract = bCanCopyOrExtract; aContext.Encryption.CanExtractForAccessibility = bCanExtractForAccessibility; if( bEncrypt && ! xEnc.is() ) - xEnc = vcl::PDFWriter::InitEncryption( aPermissionPassword, aOpenPassword ); + xEnc = vcl::pdf::initEncryption(aPermissionPassword, aOpenPassword); if( bEncrypt && !aPermissionPassword.isEmpty() && ! aPreparedPermissionPassword.hasElements() ) aPreparedPermissionPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword ); } diff --git a/include/vcl/pdf/PDFEncryptionInitialization.hxx b/include/vcl/pdf/PDFEncryptionInitialization.hxx new file mode 100644 index 000000000000..93b57476d7e4 --- /dev/null +++ b/include/vcl/pdf/PDFEncryptionInitialization.hxx @@ -0,0 +1,31 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#pragma once + +#include <rtl/ustring.hxx> +#include <vcl/dllapi.h> + +namespace com::sun::star::beans +{ +class XMaterialHolder; +} +namespace com::sun::star::uno +{ +template <typename> class Reference; +} + +namespace vcl::pdf +{ +VCL_DLLPUBLIC css::uno::Reference<css::beans::XMaterialHolder> +initEncryption(const OUString& i_rOwnerPassword, const OUString& i_rUserPassword); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk index 199792d2feba..f6a37a2c6228 100644 --- a/vcl/Library_vcl.mk +++ b/vcl/Library_vcl.mk @@ -511,6 +511,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\ vcl/source/pdf/EncryptionHashTransporter \ vcl/source/pdf/ExternalPDFStreams \ vcl/source/pdf/PDFiumTools \ + vcl/source/pdf/PDFEncryptionInitialization \ vcl/source/pdf/PDFEncryptor \ vcl/source/pdf/PDFEncryptorR6 \ vcl/source/pdf/PdfConfig \ diff --git a/vcl/inc/pdf/PDFEncryptor.hxx b/vcl/inc/pdf/PDFEncryptor.hxx index be4b99f9b7d6..e4134605c194 100644 --- a/vcl/inc/pdf/PDFEncryptor.hxx +++ b/vcl/inc/pdf/PDFEncryptor.hxx @@ -20,10 +20,6 @@ namespace vcl struct PDFEncryptionProperties; } -namespace com::sun::star::beans -{ -class XMaterialHolder; -} namespace com::sun::star::uno { template <typename> class Reference; @@ -31,6 +27,8 @@ template <typename> class Reference; namespace vcl::pdf { +class EncryptionHashTransporter; + class PDFEncryptor : public IPDFEncryptor { private: @@ -60,10 +58,10 @@ public: sal_Int32 getKeyLength() override { return m_nKeyLength; } sal_Int32 getRC4KeyLength() { return m_nRC4KeyLength; } - static css::uno::Reference<css::beans::XMaterialHolder> - initEncryption(const OUString& i_rOwnerPassword, const OUString& i_rUserPassword); + static void initEncryption(EncryptionHashTransporter& rEncryptionHashTransporter, + const OUString& i_rOwnerPassword, const OUString& i_rUserPassword); - virtual bool prepareEncryption( + bool prepareEncryption( const css::uno::Reference<css::beans::XMaterialHolder>& xEncryptionMaterialHolder, PDFEncryptionProperties& rProperties) override; diff --git a/vcl/source/gdi/pdfwriter.cxx b/vcl/source/gdi/pdfwriter.cxx index ee762e2fca47..ca91054c53de 100644 --- a/vcl/source/gdi/pdfwriter.cxx +++ b/vcl/source/gdi/pdfwriter.cxx @@ -20,6 +20,7 @@ #include <vcl/bitmapex.hxx> #include <pdf/pdfwriter_impl.hxx> +#include <vcl/pdf/PDFEncryptionInitialization.hxx> using namespace vcl; @@ -471,7 +472,7 @@ std::set< PDFWriter::ErrorCode > const & PDFWriter::GetErrors() const css::uno::Reference< css::beans::XMaterialHolder > PDFWriter::InitEncryption(const OUString& i_rOwnerPassword, const OUString& i_rUserPassword) { - return PDFEncryptor::initEncryption(i_rOwnerPassword, i_rUserPassword); + return vcl::pdf::initEncryption(i_rOwnerPassword, i_rUserPassword); } void PDFWriter::PlayMetafile( const GDIMetaFile& i_rMTF, const vcl::PDFWriter::PlayMetafileContext& i_rPlayContext, PDFExtOutDevData* i_pData ) diff --git a/vcl/source/pdf/PDFEncryptionInitialization.cxx b/vcl/source/pdf/PDFEncryptionInitialization.cxx new file mode 100644 index 000000000000..df06968fc290 --- /dev/null +++ b/vcl/source/pdf/PDFEncryptionInitialization.cxx @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + */ + +#include <vcl/pdf/PDFEncryptionInitialization.hxx> +#include <pdf/EncryptionHashTransporter.hxx> +#include <com/sun/star/beans/XMaterialHolder.hpp> +#include <rtl/ref.hxx> +#include <pdf/PDFEncryptor.hxx> +#include <pdf/PDFEncryptorR6.hxx> + +using namespace css; + +namespace vcl::pdf +{ +css::uno::Reference<css::beans::XMaterialHolder> initEncryption(const OUString& i_rOwnerPassword, + const OUString& i_rUserPassword) +{ + rtl::Reference<EncryptionHashTransporter> pTransporter = new EncryptionHashTransporter; + PDFEncryptor::initEncryption(*pTransporter, i_rOwnerPassword, i_rUserPassword); + return pTransporter; +} + +} // end vcl::pdf + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/vcl/source/pdf/PDFEncryptor.cxx b/vcl/source/pdf/PDFEncryptor.cxx index d97e671247de..183e66e8e713 100644 --- a/vcl/source/pdf/PDFEncryptor.cxx +++ b/vcl/source/pdf/PDFEncryptor.cxx @@ -327,32 +327,26 @@ PDFEncryptor::~PDFEncryptor() { rtl_cipher_destroyARCFOUR(m_aCipher); } 1. init the document id, used both for building the document id and for building the encryption key(s) 2. build the encryption key following algorithms described in the PDF specification */ -uno::Reference<beans::XMaterialHolder> -PDFEncryptor::initEncryption(const OUString& i_rOwnerPassword, const OUString& i_rUserPassword) +void PDFEncryptor::initEncryption(EncryptionHashTransporter& rEncryptionHashTransporter, + const OUString& i_rOwnerPassword, const OUString& i_rUserPassword) { - uno::Reference<beans::XMaterialHolder> xResult; if (!i_rOwnerPassword.isEmpty() || !i_rUserPassword.isEmpty()) { - rtl::Reference<EncryptionHashTransporter> pTransporter = new EncryptionHashTransporter; - xResult = pTransporter; - // get padded passwords sal_uInt8 aPadUPW[ENCRYPTED_PWD_SIZE], aPadOPW[ENCRYPTED_PWD_SIZE]; padPassword(i_rOwnerPassword.isEmpty() ? i_rUserPassword : i_rOwnerPassword, aPadOPW); padPassword(i_rUserPassword, aPadUPW); - if (computeODictionaryValue(aPadOPW, aPadUPW, pTransporter->getOValue(), SECUR_128BIT_KEY)) + if (computeODictionaryValue(aPadOPW, aPadUPW, rEncryptionHashTransporter.getOValue(), + SECUR_128BIT_KEY)) { - pTransporter->getUDigest()->update(aPadUPW, ENCRYPTED_PWD_SIZE); + rEncryptionHashTransporter.getUDigest()->update(aPadUPW, ENCRYPTED_PWD_SIZE); } - else - xResult.clear(); // trash temporary padded cleartext PWDs rtl_secureZeroMemory(aPadOPW, sizeof(aPadOPW)); rtl_secureZeroMemory(aPadUPW, sizeof(aPadUPW)); } - return xResult; } bool PDFEncryptor::prepareEncryption(