vcl/inc/pdf/PDFEncryptorR6.hxx                 |    5 +
 vcl/qa/cppunit/pdfexport/PDFEncryptionTest.cxx |   66 ++++++++++++++++++++++++-
 vcl/source/pdf/PDFEncryptorR6.cxx              |   33 +++++-------
 3 files changed, 82 insertions(+), 22 deletions(-)

New commits:
commit 973d8c1d8909922bbb51e14d6243c4e3a48c2387
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu Nov 21 13:13:14 2024 +0900
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Wed Dec 11 09:46:37 2024 +0100

    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 <vmik...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>

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 17e0f10b9afe..fdb8cce0906e 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");
+
+    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

Reply via email to