comphelper/qa/unit/CryptoTest.cxx           |   98 ++++++++++++++++++++++++++++
 comphelper/source/crypto/Crypto_NSS.cxx     |    5 -
 comphelper/source/crypto/Crypto_OpenSSL.cxx |    4 +
 include/comphelper/crypto/Crypto.hxx        |    2 
 include/oox/crypto/AgileEngine.hxx          |    1 
 oox/source/crypto/AgileEngine.cxx           |   24 +++++-
 6 files changed, 127 insertions(+), 7 deletions(-)

New commits:
commit a399c4fae0a3f7dfd00565929e7ad6a41bde0df8
Author:     Julien Nabet <serval2...@yahoo.fr>
AuthorDate: Mon Apr 21 15:17:06 2025 +0200
Commit:     Julien Nabet <serval2...@yahoo.fr>
CommitDate: Wed Apr 23 17:22:07 2025 +0200

    tdf#166241: add AES_192_CBC/AES_192_EBC
    
    + improve SALT management by taking the max between 
encryptedHashInput.size()
    and comphelper::roundUp(mInfo.saltSize, mInfo.blockSize)
    
    + add QA tests
    
    Change-Id: I90dce73928e0b204500ac659eb80cd1499a4f065
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/184407
    Tested-by: Jenkins
    Reviewed-by: Julien Nabet <serval2...@yahoo.fr>
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/comphelper/qa/unit/CryptoTest.cxx 
b/comphelper/qa/unit/CryptoTest.cxx
index 4c7603d88eb6..95b7a1b11781 100644
--- a/comphelper/qa/unit/CryptoTest.cxx
+++ b/comphelper/qa/unit/CryptoTest.cxx
@@ -185,4 +185,102 @@ CPPUNIT_TEST_FIXTURE(CryptoTest, testEncrypt_AES256_ECB)
     }
 }
 
+CPPUNIT_TEST_FIXTURE(CryptoTest, testEncrypt_AES192_CBC)
+{
+    std::vector<sal_uInt8> key = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
0x08, 0x09, 0x10, 0x11,
+                                   0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 
0x19, 0x20, 0x21, 0x22,
+                                   0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 
0x30, 0x31, 0x32 };
+
+    std::vector<sal_uInt8> iv = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
0x08,
+                                  0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 
0x16 };
+
+    std::vector<sal_uInt8> original = { 's', 'e', 'c', 'r', 'e', 't', '
+
+    std::vector<sal_uInt8> encrypted(original.size());
+
+    {
+        sal_uInt32 nWrittenSize = 0;
+        comphelper::Encrypt aEncryptor(key, iv, 
comphelper::CryptoType::AES_192_CBC);
+        nWrittenSize = aEncryptor.update(encrypted, original);
+
+        // nothing should be written as the size of the input is not a 
multiple of block size
+        CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), nWrittenSize);
+    }
+
+    {
+        sal_uInt32 nWrittenSize = 0;
+        comphelper::Encrypt aEncryptor(key, iv, 
comphelper::CryptoType::AES_192_CBC);
+
+        original.resize(16, 0); // apply padding to make it multiple of block 
size
+        encrypted.resize(16, 0);
+
+        CPPUNIT_ASSERT_EQUAL(std::string("73656372657400000000000000000000"),
+                             comphelper::hashToString(original));
+
+        nWrittenSize = aEncryptor.update(encrypted, original);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt32(16), nWrittenSize);
+
+        CPPUNIT_ASSERT_EQUAL(std::string("e75cb91a34377c09c354c24fcef345a6"),
+                             comphelper::hashToString(encrypted));
+
+        std::vector<sal_uInt8> decrypted(encrypted.size(), 0);
+
+        comphelper::Decrypt aDecryptor(key, iv, 
comphelper::CryptoType::AES_192_CBC);
+        nWrittenSize = aDecryptor.update(decrypted, encrypted);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt32(16), nWrittenSize);
+
+        CPPUNIT_ASSERT_EQUAL(std::string("73656372657400000000000000000000"),
+                             comphelper::hashToString(decrypted));
+    }
+}
+
+CPPUNIT_TEST_FIXTURE(CryptoTest, testEncrypt_AES192_ECB)
+{
+    std::vector<sal_uInt8> key = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
0x08, 0x09, 0x10, 0x11,
+                                   0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 
0x19, 0x20, 0x21, 0x22,
+                                   0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 
0x30, 0x31, 0x32 };
+
+    std::vector<sal_uInt8> iv = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 
0x08,
+                                  0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 
0x16 };
+
+    std::vector<sal_uInt8> original = { 's', 'e', 'c', 'r', 'e', 't', '
+
+    std::vector<sal_uInt8> encrypted(original.size());
+
+    {
+        sal_uInt32 nWrittenSize = 0;
+        comphelper::Encrypt aEncryptor(key, iv, 
comphelper::CryptoType::AES_192_ECB);
+        nWrittenSize = aEncryptor.update(encrypted, original);
+
+        // nothing should be written as the size of the input is not a 
multiple of block size
+        CPPUNIT_ASSERT_EQUAL(sal_uInt32(0), nWrittenSize);
+    }
+
+    {
+        sal_uInt32 nWrittenSize = 0;
+        comphelper::Encrypt aEncryptor(key, iv, 
comphelper::CryptoType::AES_192_ECB);
+
+        original.resize(16, 0); // apply padding to make it multiple of block 
size
+        encrypted.resize(16, 0);
+
+        CPPUNIT_ASSERT_EQUAL(std::string("73656372657400000000000000000000"),
+                             comphelper::hashToString(original));
+
+        nWrittenSize = aEncryptor.update(encrypted, original);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt32(16), nWrittenSize);
+
+        CPPUNIT_ASSERT_EQUAL(std::string("abf7abec9a6b58c089e902397c47ac49"),
+                             comphelper::hashToString(encrypted));
+
+        std::vector<sal_uInt8> decrypted(encrypted.size(), 0);
+
+        comphelper::Decrypt aDecryptor(key, iv, 
comphelper::CryptoType::AES_192_ECB);
+        nWrittenSize = aDecryptor.update(decrypted, encrypted);
+        CPPUNIT_ASSERT_EQUAL(sal_uInt32(16), nWrittenSize);
+
+        CPPUNIT_ASSERT_EQUAL(std::string("73656372657400000000000000000000"),
+                             comphelper::hashToString(decrypted));
+    }
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/comphelper/source/crypto/Crypto_NSS.cxx 
b/comphelper/source/crypto/Crypto_NSS.cxx
index 4f850735a42f..08c8bb85c288 100644
--- a/comphelper/source/crypto/Crypto_NSS.cxx
+++ b/comphelper/source/crypto/Crypto_NSS.cxx
@@ -169,13 +169,12 @@ public:
         switch (type)
         {
             case CryptoType::AES_128_ECB:
+            case CryptoType::AES_192_ECB:
             case CryptoType::AES_256_ECB:
                 mechanism = CKM_AES_ECB;
                 break;
             case CryptoType::AES_128_CBC:
-                mechanism = CKM_AES_CBC;
-                pIvItem = &ivItem;
-                break;
+            case CryptoType::AES_192_CBC:
             case CryptoType::AES_256_CBC:
                 mechanism = CKM_AES_CBC;
                 pIvItem = &ivItem;
diff --git a/comphelper/source/crypto/Crypto_OpenSSL.cxx 
b/comphelper/source/crypto/Crypto_OpenSSL.cxx
index 37c5ff44e222..c4501052ec17 100644
--- a/comphelper/source/crypto/Crypto_OpenSSL.cxx
+++ b/comphelper/source/crypto/Crypto_OpenSSL.cxx
@@ -144,10 +144,14 @@ public:
         {
             case CryptoType::AES_128_ECB:
                 return EVP_aes_128_ecb();
+            case CryptoType::AES_192_ECB:
+                return EVP_aes_192_ecb();
             case CryptoType::AES_256_ECB:
                 return EVP_aes_256_ecb();
             case CryptoType::AES_128_CBC:
                 return EVP_aes_128_cbc();
+            case CryptoType::AES_192_CBC:
+                return EVP_aes_192_cbc();
             case CryptoType::AES_256_CBC:
                 return EVP_aes_256_cbc();
             default:
diff --git a/include/comphelper/crypto/Crypto.hxx 
b/include/comphelper/crypto/Crypto.hxx
index abebf9440a5a..bacc2c7bb535 100644
--- a/include/comphelper/crypto/Crypto.hxx
+++ b/include/comphelper/crypto/Crypto.hxx
@@ -46,6 +46,8 @@ enum class CryptoType
     UNKNOWN,
     AES_128_ECB,
     AES_128_CBC,
+    AES_192_ECB,
+    AES_192_CBC,
     AES_256_ECB,
     AES_256_CBC,
 };
diff --git a/include/oox/crypto/AgileEngine.hxx 
b/include/oox/crypto/AgileEngine.hxx
index e3daf7f971a9..787a311c4487 100644
--- a/include/oox/crypto/AgileEngine.hxx
+++ b/include/oox/crypto/AgileEngine.hxx
@@ -65,6 +65,7 @@ enum class AgileEncryptionPreset
 {
     AES_128_SHA1,
     AES_128_SHA384,
+    AES_192_SHA384,
     AES_256_SHA512,
 };
 
diff --git a/oox/source/crypto/AgileEngine.cxx 
b/oox/source/crypto/AgileEngine.cxx
index 6b552620f24d..a74533f95849 100644
--- a/oox/source/crypto/AgileEngine.cxx
+++ b/oox/source/crypto/AgileEngine.cxx
@@ -8,6 +8,7 @@
  *
  */
 
+#include <algorithm>
 #include <oox/crypto/AgileEngine.hxx>
 
 #include <oox/helper/binaryinputstream.hxx>
@@ -238,6 +239,8 @@ comphelper::CryptoType AgileEngine::cryptoType(const 
AgileEncryptionInfo& rInfo)
 {
     if (rInfo.keyBits == 128 && rInfo.cipherAlgorithm == "AES" && 
rInfo.cipherChaining == "ChainingModeCBC")
         return comphelper::CryptoType::AES_128_CBC;
+    else if (rInfo.keyBits == 192 && rInfo.cipherAlgorithm == "AES" && 
rInfo.cipherChaining == "ChainingModeCBC")
+        return comphelper::CryptoType::AES_192_CBC;
     else if (rInfo.keyBits == 256 && rInfo.cipherAlgorithm == "AES" && 
rInfo.cipherChaining == "ChainingModeCBC")
         return comphelper::CryptoType::AES_256_CBC;
     return comphelper::CryptoType::UNKNOWN;
@@ -337,10 +340,7 @@ bool AgileEngine::decryptAndCheckVerifierHash(OUString 
const & rPassword)
     calculateHashFinal(rPassword, hashFinal);
 
     std::vector<sal_uInt8>& encryptedHashInput = 
mInfo.encryptedVerifierHashInput;
-    // SALT - needs to be a multiple of block size (?)
-    sal_uInt32 nSaltSize = comphelper::roundUp(mInfo.saltSize, 
mInfo.blockSize);
-    if (nSaltSize < encryptedHashInput.size())
-        return false;
+    sal_uInt32 nSaltSize = 
std::max<sal_uInt32>(comphelper::roundUp(mInfo.saltSize, mInfo.blockSize), 
encryptedHashInput.size());
     std::vector<sal_uInt8> hashInput(nSaltSize, 0);
     calculateBlock(constBlock1, hashFinal, encryptedHashInput, hashInput);
 
@@ -358,6 +358,10 @@ void AgileEngine::decryptEncryptionKey(OUString const & 
rPassword)
     sal_Int32 nKeySize = mInfo.keyBits / 8;
 
     mKey.clear();
+    // tdf#166241: for AES 192
+    // mKey is the outbuf and in that moment, mInfo.encryptedKeyValue length 
is 32, while mKey size is 24.
+    // so the end result is: we simply need to reserve mKey for 
mInfo.encryptedKeyValue.size() before resizing.
+    mKey.reserve(mInfo.encryptedKeyValue.size());
     mKey.resize(nKeySize, 0);
 
     std::vector<sal_uInt8> aPasswordHash(mInfo.hashSize, 0);
@@ -570,6 +574,16 @@ bool 
AgileEngine::readEncryptionInfo(uno::Reference<io::XInputStream> & rxInputS
         return true;
     }
 
+    // AES 192 CBC with SHA384
+    if (mInfo.keyBits         == 192 &&
+        mInfo.cipherAlgorithm == "AES" &&
+        mInfo.cipherChaining  == "ChainingModeCBC" &&
+        mInfo.hashAlgorithm   == "SHA384" &&
+        mInfo.hashSize        == comphelper::SHA384_HASH_LENGTH)
+    {
+        return true;
+    }
+
     // AES 256 CBC with SHA512
     if (mInfo.keyBits         == 256 &&
         mInfo.cipherAlgorithm == "AES" &&
@@ -705,6 +719,8 @@ bool AgileEngine::setupEncryption(OUString const & 
rPassword)
         setupEncryptionParameters({ 100000, 16, 128, 20, 16, u"AES"_ustr, 
u"ChainingModeCBC"_ustr, u"SHA1"_ustr });
     else if (meEncryptionPreset == AgileEncryptionPreset::AES_128_SHA384)
         setupEncryptionParameters({ 100000, 16, 128, 48, 16, u"AES"_ustr, 
u"ChainingModeCBC"_ustr, u"SHA384"_ustr });
+    else if (meEncryptionPreset == AgileEncryptionPreset::AES_192_SHA384)
+        setupEncryptionParameters({ 100000, 16, 192, 48, 16, u"AES"_ustr, 
u"ChainingModeCBC"_ustr, u"SHA384"_ustr });
     else
         setupEncryptionParameters({ 100000, 16, 256, 64, 16, u"AES"_ustr, 
u"ChainingModeCBC"_ustr, u"SHA512"_ustr });
 

Reply via email to