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 <serval2412@yahoo.fr>
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
This commit is contained in:
Julien Nabet
2025-04-21 15:17:06 +02:00
parent a28af31770
commit a399c4fae0
6 changed files with 127 additions and 7 deletions

View File

@@ -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', '\0' };
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', '\0' };
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: */

View File

@@ -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;

View File

@@ -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:

View File

@@ -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,
};

View File

@@ -65,6 +65,7 @@ enum class AgileEncryptionPreset
{
AES_128_SHA1,
AES_128_SHA384,
AES_192_SHA384,
AES_256_SHA512,
};

View File

@@ -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 });