comphelper/source/misc/docpasswordhelper.cxx |    2 
 comphelper/source/misc/hash.cxx              |    6 ++
 include/comphelper/hash.hxx                  |    2 
 include/oox/crypto/AgileEngine.hxx           |    1 
 include/oox/crypto/CryptTools.hxx            |    1 
 oox/qa/unit/CryptoTest.cxx                   |   62 +++++++++++++++++++++++++++
 oox/source/crypto/AgileEngine.cxx            |   31 +++++++++++++
 oox/source/crypto/CryptTools.cxx             |    6 ++
 8 files changed, 110 insertions(+), 1 deletion(-)

New commits:
commit 9254fbce6b9e20a75aa2a379bcf2fc9dc41a5b44
Author:     Balazs Varga <balazs.varga.ext...@allotropia.de>
AuthorDate: Tue Aug 22 22:10:20 2023 +0200
Commit:     Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de>
CommitDate: Wed Aug 30 14:34:39 2023 +0200

    tdf#156835 - FILEOPEN XLSX: add SHA-384 encryption support for ooxml import
    
    Password protected file with SHA-384 encryption does not open before this
    patch.
    
    Change-Id: I482233f788b8e9da210ad6d2a6c4ece18d05d248
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156282
    Tested-by: Jenkins
    Reviewed-by: Samuel Mehrbrodt <samuel.mehrbr...@allotropia.de>

diff --git a/comphelper/source/misc/docpasswordhelper.cxx 
b/comphelper/source/misc/docpasswordhelper.cxx
index 5489690fae6a..0adb6eff9a4a 100644
--- a/comphelper/source/misc/docpasswordhelper.cxx
+++ b/comphelper/source/misc/docpasswordhelper.cxx
@@ -373,6 +373,8 @@ std::vector<unsigned char> 
DocPasswordHelper::GetOoxHashAsVector(
         eType = comphelper::HashType::SHA512;
     else if (rAlgorithmName == u"SHA-256" || rAlgorithmName == u"SHA256")
         eType = comphelper::HashType::SHA256;
+    else if (rAlgorithmName == u"SHA-384" || rAlgorithmName == u"SHA384")
+        eType = comphelper::HashType::SHA384;
     else if (rAlgorithmName == u"SHA-1" || rAlgorithmName == u"SHA1") // 
"SHA1" might be in the wild
         eType = comphelper::HashType::SHA1;
     else if (rAlgorithmName == u"MD5")
diff --git a/comphelper/source/misc/hash.cxx b/comphelper/source/misc/hash.cxx
index d537b9eeff72..25b93ad87e54 100644
--- a/comphelper/source/misc/hash.cxx
+++ b/comphelper/source/misc/hash.cxx
@@ -43,6 +43,8 @@ struct HashImpl
                 return HASH_AlgSHA1;
             case HashType::SHA256:
                 return HASH_AlgSHA256;
+            case HashType::SHA384:
+                return HASH_AlgSHA384;
             case HashType::SHA512:
                 return HASH_AlgSHA512;
         }
@@ -62,6 +64,8 @@ struct HashImpl
                 return EVP_sha1();
             case HashType::SHA256:
                 return EVP_sha256();
+            case HashType::SHA384:
+                return EVP_sha384();
             case HashType::SHA512:
                 return EVP_sha512();
         }
@@ -151,6 +155,8 @@ size_t Hash::getLength() const
             return SHA1_HASH_LENGTH;
         case HashType::SHA256:
             return SHA256_HASH_LENGTH;
+        case HashType::SHA384:
+            return SHA384_HASH_LENGTH;
         case HashType::SHA512:
             return SHA512_HASH_LENGTH;
     }
diff --git a/include/comphelper/hash.hxx b/include/comphelper/hash.hxx
index 54ab3a25105c..a3ad468d3eb5 100644
--- a/include/comphelper/hash.hxx
+++ b/include/comphelper/hash.hxx
@@ -27,12 +27,14 @@ enum class HashType
     MD5,
     SHA1,
     SHA256,
+    SHA384,
     SHA512
 };
 
 const sal_uInt32 MD5_HASH_LENGTH = RTL_DIGEST_LENGTH_MD5;
 const sal_uInt32 SHA1_HASH_LENGTH = RTL_DIGEST_LENGTH_SHA1;
 const sal_uInt32 SHA256_HASH_LENGTH = 32;
+const sal_uInt32 SHA384_HASH_LENGTH = 48;
 const sal_uInt32 SHA512_HASH_LENGTH = 64;
 
 struct HashImpl;
diff --git a/include/oox/crypto/AgileEngine.hxx 
b/include/oox/crypto/AgileEngine.hxx
index ece492871163..07ce3cb5eeb1 100644
--- a/include/oox/crypto/AgileEngine.hxx
+++ b/include/oox/crypto/AgileEngine.hxx
@@ -70,6 +70,7 @@ struct OOX_DLLPUBLIC AgileEncryptionParameters
 enum class AgileEncryptionPreset
 {
     AES_128_SHA1,
+    AES_128_SHA384,
     AES_256_SHA512,
 };
 
diff --git a/include/oox/crypto/CryptTools.hxx 
b/include/oox/crypto/CryptTools.hxx
index c8c1420079bd..10382b979380 100644
--- a/include/oox/crypto/CryptTools.hxx
+++ b/include/oox/crypto/CryptTools.hxx
@@ -48,6 +48,7 @@ enum class CryptoHashType
 {
     SHA1,
     SHA256,
+    SHA384,
     SHA512
 };
 
diff --git a/oox/qa/unit/CryptoTest.cxx b/oox/qa/unit/CryptoTest.cxx
index cbdf99b65216..290fce38eb4b 100644
--- a/oox/qa/unit/CryptoTest.cxx
+++ b/oox/qa/unit/CryptoTest.cxx
@@ -95,6 +95,15 @@ void CryptoTest::testCryptoHash()
             toString(aHash));
     }
 
+    {
+        oox::crypto::CryptoHash aCryptoHash(aKey, 
oox::crypto::CryptoHashType::SHA384);
+        aCryptoHash.update(aContent);
+        std::vector<sal_uInt8> aHash = aCryptoHash.finalize();
+        
CPPUNIT_ASSERT_EQUAL(std::string("d7f4727e2c0b39ae0f1e40cc96f60242d5b7801841cea6fc592c5d3e1"
+                                         
"ae50700582a96cf35e1e554995fe4e03381c237"),
+                             toString(aHash));
+    }
+
     {
         oox::crypto::CryptoHash aCryptoHash(aKey, 
oox::crypto::CryptoHashType::SHA512);
         aCryptoHash.update(aContent);
@@ -197,6 +206,13 @@ void CryptoTest::testAgileEncryptionVerifier()
     CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
     CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
 
+    aEngine.setupEncryptionParameters({ 100000, 16, 128, 48, 16, 
OUString("AES"),
+                                        OUString("ChainingModeCBC"), 
OUString("SHA384") });
+
+    CPPUNIT_ASSERT_EQUAL(true, 
aEngine.generateAndEncryptVerifierHash(aPassword));
+    CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
+    CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
+
     aEngine.setupEncryptionParameters({ 100000, 16, 256, 64, 16, 
OUString("AES"),
                                         OUString("ChainingModeCBC"), 
OUString("SHA512") });
 
@@ -256,6 +272,52 @@ void CryptoTest::testAgileEncryptionInfoWritingAndParsing()
         }
     }
 
+    { // Preset AES128 - SHA384
+        SvMemoryStream aEncryptionInfo;
+        {
+            oox::crypto::AgileEngine aEngine;
+
+            
aEngine.setPreset(oox::crypto::AgileEncryptionPreset::AES_128_SHA384);
+            aEngine.setupEncryption(aPassword);
+            aKeyDataSalt = aEngine.getInfo().keyDataSalt;
+
+            oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
+                new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
+
+            aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
+            aBinaryEncryptionInfoOutputStream.close();
+
+            CPPUNIT_ASSERT_EQUAL(sal_uInt64(1040), aEncryptionInfo.GetSize());
+        }
+
+        aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
+
+        {
+            oox::crypto::AgileEngine aEngine;
+
+            uno::Reference<io::XInputStream> xInputStream(
+                new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
+
+            xInputStream->skipBytes(4); // Encryption type -> Agile
+
+            CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
+
+            oox::crypto::AgileEncryptionInfo& rInfo = aEngine.getInfo();
+            CPPUNIT_ASSERT_EQUAL(sal_Int32(100000), rInfo.spinCount);
+            CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.saltSize);
+            CPPUNIT_ASSERT_EQUAL(sal_Int32(128), rInfo.keyBits);
+            CPPUNIT_ASSERT_EQUAL(sal_Int32(48), rInfo.hashSize);
+            CPPUNIT_ASSERT_EQUAL(sal_Int32(16), rInfo.blockSize);
+            CPPUNIT_ASSERT_EQUAL(OUString("AES"), rInfo.cipherAlgorithm);
+            CPPUNIT_ASSERT_EQUAL(OUString("ChainingModeCBC"), 
rInfo.cipherChaining);
+            CPPUNIT_ASSERT_EQUAL(OUString("SHA384"), rInfo.hashAlgorithm);
+            CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), 
toString(rInfo.keyDataSalt));
+
+            CPPUNIT_ASSERT_EQUAL(false, 
aEngine.decryptAndCheckVerifierHash("Wrong"));
+            CPPUNIT_ASSERT_EQUAL(true, 
aEngine.decryptAndCheckVerifierHash(aPassword));
+        }
+    }
+
     { // Preset AES256 - SHA512
         SvMemoryStream aEncryptionInfo;
         {
diff --git a/oox/source/crypto/AgileEngine.cxx 
b/oox/source/crypto/AgileEngine.cxx
index f7518498171d..ae2568d0f3f6 100644
--- a/oox/source/crypto/AgileEngine.cxx
+++ b/oox/source/crypto/AgileEngine.cxx
@@ -206,6 +206,12 @@ bool hashCalc(std::vector<sal_uInt8>& output,
         output = out;
         return true;
     }
+    else if (sAlgorithm == u"SHA384")
+    {
+        std::vector<unsigned char> out = 
comphelper::Hash::calculateHash(input.data(), input.size(), 
comphelper::HashType::SHA384);
+        output = out;
+        return true;
+    }
     else if (sAlgorithm == u"SHA512")
     {
         std::vector<unsigned char> out = 
comphelper::Hash::calculateHash(input.data(), input.size(), 
comphelper::HashType::SHA512);
@@ -219,7 +225,10 @@ CryptoHashType 
cryptoHashTypeFromString(std::u16string_view sAlgorithm)
 {
     if (sAlgorithm == u"SHA512")
         return CryptoHashType::SHA512;
-    return CryptoHashType::SHA1;
+    else if (sAlgorithm == u"SHA384")
+        return CryptoHashType::SHA384;
+    else
+        return CryptoHashType::SHA1;
 }
 
 } // namespace
@@ -384,6 +393,8 @@ bool AgileEngine::decryptHmacKey()
     comphelper::HashType eType;
     if (mInfo.hashAlgorithm == "SHA1")
         eType = comphelper::HashType::SHA1;
+    else if (mInfo.hashAlgorithm == "SHA384")
+        eType = comphelper::HashType::SHA384;
     else if (mInfo.hashAlgorithm == "SHA512")
         eType = comphelper::HashType::SHA512;
     else
@@ -410,6 +421,8 @@ bool AgileEngine::decryptHmacValue()
     comphelper::HashType eType;
     if (mInfo.hashAlgorithm == "SHA1")
         eType = comphelper::HashType::SHA1;
+    else if (mInfo.hashAlgorithm == "SHA384")
+        eType = comphelper::HashType::SHA384;
     else if (mInfo.hashAlgorithm == "SHA512")
         eType = comphelper::HashType::SHA512;
     else
@@ -550,6 +563,16 @@ bool 
AgileEngine::readEncryptionInfo(uno::Reference<io::XInputStream> & rxInputS
         return true;
     }
 
+    // AES 128 CBC with SHA384
+    if (mInfo.keyBits         == 128 &&
+        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" &&
@@ -613,6 +636,8 @@ bool AgileEngine::encryptHmacKey()
     comphelper::HashType eType;
     if (mInfo.hashAlgorithm == "SHA1")
         eType = comphelper::HashType::SHA1;
+    else if (mInfo.hashAlgorithm == "SHA384")
+        eType = comphelper::HashType::SHA384;
     else if (mInfo.hashAlgorithm == "SHA512")
         eType = comphelper::HashType::SHA512;
     else
@@ -640,6 +665,8 @@ bool AgileEngine::encryptHmacValue()
     comphelper::HashType eType;
     if (mInfo.hashAlgorithm == "SHA1")
         eType = comphelper::HashType::SHA1;
+    else if (mInfo.hashAlgorithm == "SHA384")
+        eType = comphelper::HashType::SHA384;
     else if (mInfo.hashAlgorithm == "SHA512")
         eType = comphelper::HashType::SHA512;
     else
@@ -679,6 +706,8 @@ bool AgileEngine::setupEncryption(OUString const & 
rPassword)
 {
     if (meEncryptionPreset == AgileEncryptionPreset::AES_128_SHA1)
         setupEncryptionParameters({ 100000, 16, 128, 20, 16, OUString("AES"), 
OUString("ChainingModeCBC"), OUString("SHA1") });
+    else if (meEncryptionPreset == AgileEncryptionPreset::AES_128_SHA384)
+        setupEncryptionParameters({ 100000, 16, 128, 48, 16, OUString("AES"), 
OUString("ChainingModeCBC"), OUString("SHA384") });
     else
         setupEncryptionParameters({ 100000, 16, 256, 64, 16, OUString("AES"), 
OUString("ChainingModeCBC"), OUString("SHA512") });
 
diff --git a/oox/source/crypto/CryptTools.cxx b/oox/source/crypto/CryptTools.cxx
index e0a4b9d686cc..86d8ab270d19 100644
--- a/oox/source/crypto/CryptTools.cxx
+++ b/oox/source/crypto/CryptTools.cxx
@@ -117,6 +117,8 @@ struct CryptoImpl
                 aEvpMd = EVP_sha1(); break;
             case CryptoHashType::SHA256:
                 aEvpMd = EVP_sha256(); break;
+            case CryptoHashType::SHA384:
+                aEvpMd = EVP_sha384(); break;
             case CryptoHashType::SHA512:
                 aEvpMd = EVP_sha512(); break;
         }
@@ -318,6 +320,9 @@ struct CryptoImpl
             case CryptoHashType::SHA256:
                 aMechanism = CKM_SHA256_HMAC;
                 break;
+            case CryptoHashType::SHA384:
+                aMechanism = CKM_SHA384_HMAC;
+                break;
             case CryptoHashType::SHA512:
                 aMechanism = CKM_SHA512_HMAC;
                 break;
@@ -460,6 +465,7 @@ sal_Int32 getSizeForHashType(CryptoHashType eType)
     {
         case CryptoHashType::SHA1: return 20;
         case CryptoHashType::SHA256: return 32;
+        case CryptoHashType::SHA384: return 48;
         case CryptoHashType::SHA512: return 64;
     }
     return 0;

Reply via email to