diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2024-11-21 13:13:14 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2024-12-23 15:22:39 +0100 |
commit | b8ea5a835ec07d0f84cd8ec2d0dab976edcfcebe (patch) | |
tree | 813d0ba80ea3dbd6df73d74756856804e923cc5f /vcl | |
parent | 807f977b389f196d17701f01ddbb40b297face95 (diff) |
pdf: change encryption to use new random IV on each encrypt call
This is how it's supposed to work - not to have same IV all the
time we are encoding (that's why the IV is written to the stream).
Change-Id: I17a1d98bd5cf6f06b830eaea04822b8793d4e0d7
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176984
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/178761
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Tested-by: Jenkins
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/pdf/PDFEncryptorR6.hxx | 5 | ||||
-rw-r--r-- | vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx | 66 | ||||
-rw-r--r-- | vcl/source/pdf/PDFEncryptorR6.cxx | 33 |
3 files changed, 82 insertions, 22 deletions
diff --git a/vcl/inc/pdf/PDFEncryptorR6.hxx b/vcl/inc/pdf/PDFEncryptorR6.hxx index a8812fefcd21..56fe094469c6 100644 --- a/vcl/inc/pdf/PDFEncryptorR6.hxx +++ b/vcl/inc/pdf/PDFEncryptorR6.hxx @@ -146,14 +146,15 @@ public: void setupEncryption(std::vector<sal_uInt8>& rEncryptionKey, sal_Int32 nObject) override; - void setupEncryptionWithIV(std::vector<sal_uInt8>& rInitvector, std::vector<sal_uInt8>& rIV); - /** Encrypts using Algorithm 1.A: Encryption of data using the AES algorithms * * Described in ISO 32000-2:2020(E) - 7.6.3.3 */ void encrypt(const void* pInput, sal_uInt64 nInputSize, std::vector<sal_uInt8>& rOutput, sal_uInt64 nOutputsSize) override; + + void encryptWithIV(const void* pInput, sal_uInt64 nInputSize, std::vector<sal_uInt8>& rOutput, + std::vector<sal_uInt8>& rIV); }; } // end vcl::pdf diff --git a/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx b/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx index f4eeb2a9fd05..2126cc0eb7f7 100644 --- a/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx +++ b/vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx @@ -356,8 +356,8 @@ CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testFileEncryption) std::vector<sal_uInt8> aEncryptedBuffer; vcl::pdf::PDFEncryptorR6 aEncryptor; - aEncryptor.setupEncryptionWithIV(aKey, aIV); - aEncryptor.encrypt(aData.data(), aData.size(), aEncryptedBuffer, aData.size()); + aEncryptor.setupEncryption(aKey, 0); + aEncryptor.encryptWithIV(aData.data(), aData.size(), aEncryptedBuffer, aIV); CPPUNIT_ASSERT_EQUAL( std::string("d07efca5cce3c18fd8e344d45d826886d1774c5e1e310c971f8578924f848fc6"), @@ -375,6 +375,68 @@ CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testFileEncryption) comphelper::hashToString(aOutputString)); } +std::vector<sal_uInt8> decrypt_AES_256_CBC(std::vector<sal_uInt8>& rKey, + std::vector<sal_uInt8>& rIV, + std::vector<sal_uInt8>& rEncryptedBuffer) +{ + std::vector<sal_uInt8> aDecryptedBuffer(rEncryptedBuffer.size()); + comphelper::Decrypt aDecryptor(rKey, rIV, comphelper::CryptoType::AES_256_CBC); + aDecryptor.update(aDecryptedBuffer, rEncryptedBuffer); + return aDecryptedBuffer; +} + +CPPUNIT_TEST_FIXTURE(PDFEncryptionTest, testFileEncryption_checkDifferentIV) +{ + // Check each call to encrypt is usign a different IV (initialization vector) + + std::vector<sal_uInt8> aKey + = parseHex("90e657b78c0315610f3f421bd396ff635fa8fe3cf2ea399e7e1ae23e6185b4fc"); + + static constexpr const auto aData = std::to_array<sal_uInt8>({ 'a', 'b', 'c' }); + + vcl::pdf::PDFEncryptorR6 aEncryptor; + aEncryptor.setupEncryption(aKey, 0); + + std::vector<sal_uInt8> aEncrypted_1; + aEncryptor.encrypt(aData.data(), aData.size(), aEncrypted_1, aData.size()); + std::vector<sal_uInt8> aIV_1(aEncrypted_1.begin(), aEncrypted_1.begin() + 16); + + std::vector<sal_uInt8> aEncrypted_2; + aEncryptor.encrypt(aData.data(), aData.size(), aEncrypted_2, aData.size()); + std::vector<sal_uInt8> aIV_2(aEncrypted_2.begin(), aEncrypted_2.begin() + 16); + + std::vector<sal_uInt8> aEncrypted_3; + aEncryptor.encrypt(aData.data(), aData.size(), aEncrypted_3, aData.size()); + std::vector<sal_uInt8> aIV_3(aEncrypted_3.begin(), aEncrypted_3.begin() + 16); + + // All IV should be different + CPPUNIT_ASSERT(!std::equal(aIV_1.begin(), aIV_1.end(), aIV_2.begin())); + CPPUNIT_ASSERT(!std::equal(aIV_1.begin(), aIV_1.end(), aIV_3.begin())); + CPPUNIT_ASSERT(!std::equal(aIV_2.begin(), aIV_2.end(), aIV_3.begin())); + + { + std::vector<sal_uInt8> aEncrypted(aEncrypted_1.begin() + 16, aEncrypted_1.end()); + // expected 'a', 'b', 'c' + padding + CPPUNIT_ASSERT_EQUAL( + std::string("6162630d0d0d0d0d0d0d0d0d0d0d0d0d"), + comphelper::hashToString(decrypt_AES_256_CBC(aKey, aIV_1, aEncrypted))); + } + + { + std::vector<sal_uInt8> aEncrypted(aEncrypted_2.begin() + 16, aEncrypted_2.end()); + CPPUNIT_ASSERT_EQUAL( + std::string("6162630d0d0d0d0d0d0d0d0d0d0d0d0d"), + comphelper::hashToString(decrypt_AES_256_CBC(aKey, aIV_2, aEncrypted))); + } + + { + std::vector<sal_uInt8> aEncrypted(aEncrypted_3.begin() + 16, aEncrypted_3.end()); + CPPUNIT_ASSERT_EQUAL( + std::string("6162630d0d0d0d0d0d0d0d0d0d0d0d0d"), + comphelper::hashToString(decrypt_AES_256_CBC(aKey, aIV_3, aEncrypted))); + } +} + } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/vcl/source/pdf/PDFEncryptorR6.cxx b/vcl/source/pdf/PDFEncryptorR6.cxx index c16d7cb1a276..d951b738246f 100644 --- a/vcl/source/pdf/PDFEncryptorR6.cxx +++ b/vcl/source/pdf/PDFEncryptorR6.cxx @@ -256,28 +256,25 @@ class VCL_DLLPUBLIC EncryptionContext { private: std::vector<sal_uInt8> maKey; - std::vector<sal_uInt8> maInitVector; public: - EncryptionContext(std::vector<sal_uInt8> const& rKey, std::vector<sal_uInt8> const& rIV) + EncryptionContext(std::vector<sal_uInt8> const& rKey) : maKey(rKey) - , maInitVector(rIV) { } - /** Algorithm 1.A: Encryption of data using the AES algorithms - * - **/ - void encrypt(const void* pInput, sal_uInt64 nInputSize, std::vector<sal_uInt8>& rOutput) + /** Algorithm 1.A: Encryption of data using the AES algorithms */ + void encrypt(const void* pInput, sal_uInt64 nInputSize, std::vector<sal_uInt8>& rOutput, + std::vector<sal_uInt8>& rIV) { - comphelper::Encrypt aEncrypt(maKey, maInitVector, comphelper::CryptoType::AES_256_CBC); + comphelper::Encrypt aEncrypt(maKey, rIV, comphelper::CryptoType::AES_256_CBC); const sal_uInt8* pInputBytes = static_cast<const sal_uInt8*>(pInput); std::vector<sal_uInt8> aInput(pInputBytes, pInputBytes + nInputSize); size_t nPaddedSize = addPaddingToVector(aInput, BLOCK_SIZE); std::vector<sal_uInt8> aOutput(nPaddedSize); aEncrypt.update(aOutput, aInput); rOutput.resize(nPaddedSize + IV_SIZE); - std::copy(maInitVector.begin(), maInitVector.end(), rOutput.begin()); + std::copy(rIV.begin(), rIV.end(), rOutput.begin()); std::copy(aOutput.begin(), aOutput.end(), rOutput.begin() + IV_SIZE); } }; @@ -357,21 +354,21 @@ sal_uInt64 PDFEncryptorR6::calculateSizeIncludingHeader(sal_uInt64 nSize) void PDFEncryptorR6::setupEncryption(std::vector<sal_uInt8>& rEncryptionKey, sal_Int32 /*nObject*/) { - std::vector<sal_uInt8> aInitVector; - generateBytes(aInitVector, IV_SIZE); - m_pEncryptionContext = std::make_unique<EncryptionContext>(rEncryptionKey, aInitVector); + m_pEncryptionContext = std::make_unique<EncryptionContext>(rEncryptionKey); } -void PDFEncryptorR6::setupEncryptionWithIV(std::vector<sal_uInt8>& rEncryptionKey, - std::vector<sal_uInt8>& rInitvector) +void PDFEncryptorR6::encrypt(const void* pInput, sal_uInt64 nInputSize, + std::vector<sal_uInt8>& rOutput, sal_uInt64 /*nOutputSize*/) { - m_pEncryptionContext = std::make_unique<EncryptionContext>(rEncryptionKey, rInitvector); + std::vector<sal_uInt8> aIV; + generateBytes(aIV, IV_SIZE); + m_pEncryptionContext->encrypt(pInput, nInputSize, rOutput, aIV); } -void PDFEncryptorR6::encrypt(const void* pInput, sal_uInt64 nInputSize, - std::vector<sal_uInt8>& rOutput, sal_uInt64 /*nOutputSize*/) +void PDFEncryptorR6::encryptWithIV(const void* pInput, sal_uInt64 nInputSize, + std::vector<sal_uInt8>& rOutput, std::vector<sal_uInt8>& rIV) { - m_pEncryptionContext->encrypt(pInput, nInputSize, rOutput); + m_pEncryptionContext->encrypt(pInput, nInputSize, rOutput, rIV); } } // end vcl::pdf |