summaryrefslogtreecommitdiff
path: root/oox
diff options
context:
space:
mode:
Diffstat (limited to 'oox')
-rw-r--r--oox/qa/unit/CryptoTest.cxx281
-rw-r--r--oox/source/core/filterdetect.cxx21
-rw-r--r--oox/source/crypto/AgileEngine.cxx481
-rw-r--r--oox/source/crypto/DocumentDecryption.cxx3
-rw-r--r--oox/source/crypto/DocumentEncryption.cxx31
-rw-r--r--oox/source/crypto/Standard2007Engine.cxx39
6 files changed, 788 insertions, 68 deletions
diff --git a/oox/qa/unit/CryptoTest.cxx b/oox/qa/unit/CryptoTest.cxx
index 0dead9dcec6e..e17f3cc91e9a 100644
--- a/oox/qa/unit/CryptoTest.cxx
+++ b/oox/qa/unit/CryptoTest.cxx
@@ -15,8 +15,8 @@
#include <tools/stream.hxx>
#include <unotools/streamwrap.hxx>
-#include <oox/crypto/CryptTools.hxx>
#include <oox/crypto/Standard2007Engine.hxx>
+#include <oox/crypto/AgileEngine.hxx>
#include <oox/helper/binaryinputstream.hxx>
#include <oox/helper/binaryoutputstream.hxx>
@@ -28,11 +28,19 @@ public:
void testCryptoHash();
void testRoundUp();
void testStandard2007();
+ void testAgileEncryptionVerifier();
+ void testAgileEncrpytionInfoWritingAndParsing();
+ void testAgileDataIntegrityHmacKey();
+ void testAgileEncryptingAndDecrypting();
CPPUNIT_TEST_SUITE(CryptoTest);
CPPUNIT_TEST(testCryptoHash);
CPPUNIT_TEST(testRoundUp);
CPPUNIT_TEST(testStandard2007);
+ CPPUNIT_TEST(testAgileEncryptionVerifier);
+ CPPUNIT_TEST(testAgileEncrpytionInfoWritingAndParsing);
+ CPPUNIT_TEST(testAgileDataIntegrityHmacKey);
+ CPPUNIT_TEST(testAgileEncryptingAndDecrypting);
CPPUNIT_TEST_SUITE_END();
};
@@ -100,11 +108,13 @@ void CryptoTest::testStandard2007()
{
oox::core::Standard2007Engine aEngine;
{
+ aEngine.setupEncryption("Password");
+
SvMemoryStream aEncryptionInfo;
oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), false);
- aEngine.writeEncryptionInfo("Password", aBinaryEncryptionInfoOutputStream);
+ aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
aBinaryEncryptionInfoOutputStream.close();
CPPUNIT_ASSERT_EQUAL(sal_uInt64(224), aEncryptionInfo.GetSize());
@@ -119,17 +129,14 @@ void CryptoTest::testStandard2007()
aUnencryptedInput.Seek(STREAM_SEEK_TO_BEGIN);
{
- oox::BinaryXInputStream aBinaryInputStream(
- new utl::OSeekableInputStreamWrapper(aUnencryptedInput), true);
- oox::BinaryXOutputStream aBinaryOutputStream(
- new utl::OSeekableOutputStreamWrapper(aEncryptedStream), true);
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aUnencryptedInput));
+ uno::Reference<io::XOutputStream> xOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptedStream));
- aEncryptedStream.WriteUInt32(aUnencryptedInput.GetSize());
- aEncryptedStream.WriteUInt32(0U);
+ aEngine.encrypt(xInputStream, xOutputStream, aUnencryptedInput.GetSize());
- aEngine.encrypt(aBinaryInputStream, aBinaryOutputStream);
- aBinaryOutputStream.close();
- aBinaryInputStream.close();
+ xOutputStream->flush();
const sal_uInt8* pData = static_cast<const sal_uInt8*>(aEncryptedStream.GetData());
sal_uInt64 nSize = aEncryptedStream.GetSize();
@@ -164,6 +171,258 @@ void CryptoTest::testStandard2007()
}
}
+void CryptoTest::testAgileEncryptionVerifier()
+{
+ oox::core::AgileEngine aEngine;
+
+ OUString aPassword("Password");
+
+ aEngine.setupEncryptionParameters({ 100000, 16, 128, 20, 16, OUString("AES"),
+ OUString("ChainingModeCBC"), OUString("SHA1") });
+
+ 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") });
+
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.generateAndEncryptVerifierHash(aPassword));
+ CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
+}
+
+void CryptoTest::testAgileEncrpytionInfoWritingAndParsing()
+{
+ OUString aPassword("Password");
+ std::vector<sal_uInt8> aKeyDataSalt;
+
+ { // Preset AES128 - SHA1
+ SvMemoryStream aEncryptionInfo;
+ {
+ oox::core::AgileEngine aEngine;
+
+ aEngine.setPreset(oox::core::AgileEncryptionPreset::AES_128_SHA1);
+ 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(996), aEncryptionInfo.GetSize());
+ }
+
+ aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
+
+ {
+ oox::core::AgileEngine aEngine;
+
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
+
+ xInputStream->skipBytes(4); // Encryption type -> Agile
+ xInputStream->skipBytes(4); // Reserved
+
+ CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
+
+ oox::core::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(20), 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("SHA1"), 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;
+ {
+ oox::core::AgileEngine aEngine;
+
+ aEngine.setPreset(oox::core::AgileEncryptionPreset::AES_256_SHA512);
+ 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(1112), aEncryptionInfo.GetSize());
+ }
+
+ aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
+
+ {
+ oox::core::AgileEngine aEngine;
+
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
+
+ xInputStream->skipBytes(4); // Encryption type -> Agile
+ xInputStream->skipBytes(4); // Reserved
+
+ CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
+
+ oox::core::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(256), rInfo.keyBits);
+ CPPUNIT_ASSERT_EQUAL(sal_Int32(64), 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("SHA512"), rInfo.hashAlgorithm);
+ CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), toString(rInfo.keyDataSalt));
+
+ CPPUNIT_ASSERT_EQUAL(false, aEngine.decryptAndCheckVerifierHash("Wrong"));
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.decryptAndCheckVerifierHash(aPassword));
+ }
+ }
+}
+
+void CryptoTest::testAgileDataIntegrityHmacKey()
+{
+ OUString aPassword("Password");
+
+ std::vector<sal_uInt8> aKeyDataSalt;
+
+ std::vector<sal_uInt8> aHmacKey;
+ std::vector<sal_uInt8> aHmacEncryptedKey;
+
+ SvMemoryStream aEncryptionInfo;
+ {
+ oox::core::AgileEngine aEngine;
+ aEngine.setupEncryption(aPassword);
+ oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
+ aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
+ aBinaryEncryptionInfoOutputStream.close();
+
+ aHmacKey = aEngine.getInfo().hmacKey;
+ aKeyDataSalt = aEngine.getInfo().keyDataSalt;
+ aHmacEncryptedKey = aEngine.getInfo().hmacEncryptedKey;
+ }
+
+ aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
+
+ {
+ oox::core::AgileEngine aEngine;
+
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
+
+ xInputStream->skipBytes(4); // Encryption type -> Agile
+ xInputStream->skipBytes(4); // Reserved
+
+ CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xInputStream));
+ CPPUNIT_ASSERT(aEngine.generateEncryptionKey(aPassword));
+
+ CPPUNIT_ASSERT_EQUAL(toString(aKeyDataSalt), toString(aEngine.getInfo().keyDataSalt));
+
+ CPPUNIT_ASSERT_EQUAL(toString(aHmacEncryptedKey),
+ toString(aEngine.getInfo().hmacEncryptedKey));
+
+ CPPUNIT_ASSERT_EQUAL(size_t(64), aHmacKey.size());
+ CPPUNIT_ASSERT_EQUAL(toString(aHmacKey), toString(aEngine.getInfo().hmacKey));
+ }
+}
+
+void CryptoTest::testAgileEncryptingAndDecrypting()
+{
+ OUString aPassword("Password");
+
+ SvMemoryStream aEncryptionInfo;
+ SvMemoryStream aEncryptedStream;
+
+ OString aTestString = OUStringToOString("1234567890ABCDEFGH", RTL_TEXTENCODING_UTF8);
+
+ {
+ oox::core::AgileEngine aEngine;
+
+ // Setup input
+ SvMemoryStream aUnencryptedInput;
+ uno::Reference<io::XInputStream> xInputStream(
+ new utl::OSeekableInputStreamWrapper(aUnencryptedInput));
+
+ aUnencryptedInput.WriteBytes(aTestString.getStr(), aTestString.getLength() + 1);
+ aUnencryptedInput.Seek(STREAM_SEEK_TO_BEGIN);
+
+ // Setup output
+ uno::Reference<io::XOutputStream> xOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptedStream));
+
+ // Write content
+ aEngine.setupEncryption(aPassword);
+ aEngine.encrypt(xInputStream, xOutputStream, aUnencryptedInput.GetSize());
+ xOutputStream->flush();
+
+ // Check content
+ sal_uInt64 nSize = aEncryptedStream.GetSize();
+
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(40), nSize);
+
+ // Setup and write encryption info
+ oox::BinaryXOutputStream aBinaryEncryptionInfoOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aEncryptionInfo), true);
+ aEngine.writeEncryptionInfo(aBinaryEncryptionInfoOutputStream);
+ aBinaryEncryptionInfoOutputStream.close();
+ }
+
+ aEncryptedStream.Seek(STREAM_SEEK_TO_BEGIN);
+ aEncryptionInfo.Seek(STREAM_SEEK_TO_BEGIN);
+
+ {
+ oox::core::AgileEngine aEngine;
+
+ // Read encryption info
+ uno::Reference<io::XInputStream> xEncryptionInfo(
+ new utl::OSeekableInputStreamWrapper(aEncryptionInfo));
+
+ xEncryptionInfo->skipBytes(4); // Encryption type -> Agile
+ xEncryptionInfo->skipBytes(4); // Reserved
+
+ CPPUNIT_ASSERT(aEngine.readEncryptionInfo(xEncryptionInfo));
+
+ // Setup password
+ CPPUNIT_ASSERT(aEngine.generateEncryptionKey(aPassword));
+
+ // Setup encrypted input stream
+ oox::BinaryXInputStream aBinaryInputStream(
+ new utl::OSeekableInputStreamWrapper(aEncryptedStream), true);
+
+ // Setup output stream
+ SvMemoryStream aUnencryptedOutput;
+ oox::BinaryXOutputStream aBinaryOutputStream(
+ new utl::OSeekableOutputStreamWrapper(aUnencryptedOutput), true);
+
+ // Decrypt
+ aEngine.decrypt(aBinaryInputStream, aBinaryOutputStream);
+ aBinaryOutputStream.close();
+ aBinaryInputStream.close();
+
+ // Check decrypted output
+ CPPUNIT_ASSERT_EQUAL(sal_uInt64(19), aUnencryptedOutput.GetSize());
+
+ OString aString(static_cast<const sal_Char*>(aUnencryptedOutput.GetData()));
+ CPPUNIT_ASSERT_EQUAL(aTestString, aString);
+
+ // Check data integrity
+ CPPUNIT_ASSERT_EQUAL(true, aEngine.checkDataIntegrity());
+ }
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(CryptoTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx
index 1af982c07480..805d2fb4b01d 100644
--- a/oox/source/core/filterdetect.cxx
+++ b/oox/source/core/filterdetect.cxx
@@ -348,14 +348,21 @@ Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescript
{
// create temporary file for unencrypted package
Reference<XStream> xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
- aDecryptor.decrypt( xTempFile );
- // store temp file in media descriptor to keep it alive
- rMediaDescriptor.setComponentDataEntry( "DecryptedPackage", Any( xTempFile ) );
-
- Reference<XInputStream> xDecryptedInputStream = xTempFile->getInputStream();
- if( lclIsZipPackage( mxContext, xDecryptedInputStream ) )
- return xDecryptedInputStream;
+ // if decryption was unsuccessful (corrupted file or any other reason)
+ if (!aDecryptor.decrypt(xTempFile))
+ {
+ rMediaDescriptor[ MediaDescriptor::PROP_ABORTED() ] <<= true;
+ }
+ else
+ {
+ // store temp file in media descriptor to keep it alive
+ rMediaDescriptor.setComponentDataEntry( "DecryptedPackage", Any( xTempFile ) );
+
+ Reference<XInputStream> xDecryptedInputStream = xTempFile->getInputStream();
+ if( lclIsZipPackage( mxContext, xDecryptedInputStream ) )
+ return xDecryptedInputStream;
+ }
}
}
}
diff --git a/oox/source/crypto/AgileEngine.cxx b/oox/source/crypto/AgileEngine.cxx
index 72cd51e16986..a4fa8c476c74 100644
--- a/oox/source/crypto/AgileEngine.cxx
+++ b/oox/source/crypto/AgileEngine.cxx
@@ -23,6 +23,7 @@
#include <comphelper/sequence.hxx>
#include <filter/msfilter/mscodec.hxx>
+#include <tools/XmlWriter.hxx>
#include <com/sun/star/io/XSeekable.hpp>
#include <com/sun/star/io/XStream.hpp>
@@ -146,6 +147,18 @@ public:
comphelper::Base64::decode(encryptedKeyValue, rAttribute.Value);
mInfo.encryptedKeyValue = comphelper::sequenceToContainer<std::vector<sal_uInt8>>(encryptedKeyValue);
}
+ if (rAttrLocalName == "encryptedHmacKey")
+ {
+ Sequence<sal_Int8> aValue;
+ comphelper::Base64::decode(aValue, rAttribute.Value);
+ mInfo.hmacEncryptedKey = comphelper::sequenceToContainer<std::vector<sal_uInt8>>(aValue);
+ }
+ if (rAttrLocalName == "encryptedHmacValue")
+ {
+ Sequence<sal_Int8> aValue;
+ comphelper::Base64::decode(aValue, rAttribute.Value);
+ mInfo.hmacEncryptedValue = comphelper::sequenceToContainer<std::vector<sal_uInt8>>(aValue);
+ }
}
}
@@ -168,7 +181,13 @@ public:
{}
};
-const sal_uInt32 constSegmentLength = 4096;
+constexpr const sal_uInt32 constSegmentLength = 4096;
+
+static const std::vector<sal_uInt8> constBlock1 { 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 };
+static const std::vector<sal_uInt8> constBlock2 { 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e };
+static const std::vector<sal_uInt8> constBlock3 { 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 };
+static const std::vector<sal_uInt8> constBlockHmac1 { 0x5f, 0xb2, 0xad, 0x01, 0x0c, 0xb9, 0xe1, 0xf6 };
+static const std::vector<sal_uInt8> constBlockHmac2 { 0xa0, 0x67, 0x7f, 0x02, 0xb2, 0x2c, 0x84, 0x33 };
bool hashCalc(std::vector<sal_uInt8>& output,
std::vector<sal_uInt8>& input,
@@ -189,8 +208,19 @@ bool hashCalc(std::vector<sal_uInt8>& output,
return false;
}
+CryptoHashType cryptoHashTypeFromString(OUString const & sAlgorithm)
+{
+ if (sAlgorithm == "SHA512")
+ return CryptoHashType::SHA512;
+ return CryptoHashType::SHA1;
+}
+
} // namespace
+AgileEngine::AgileEngine()
+ : meEncryptionPreset(AgileEncryptionPreset::AES_256_SHA512)
+{}
+
Crypto::CryptoType AgileEngine::cryptoType(const AgileEncryptionInfo& rInfo)
{
if (rInfo.keyBits == 128 && rInfo.cipherAlgorithm == "AES" && rInfo.cipherChaining == "ChainingModeCBC")
@@ -200,6 +230,19 @@ Crypto::CryptoType AgileEngine::cryptoType(const AgileEncryptionInfo& rInfo)
return Crypto::UNKNOWN;
}
+std::vector<sal_uInt8> calculateIV(comphelper::HashType eType,
+ std::vector<sal_uInt8> const & rSalt,
+ std::vector<sal_uInt8> const & rBlock,
+ sal_Int32 nCipherBlockSize)
+{
+ comphelper::Hash aHasher(eType);
+ aHasher.update(rSalt.data(), rSalt.size());
+ aHasher.update(rBlock.data(), rBlock.size());
+ std::vector<sal_uInt8> aIV = aHasher.finalize();
+ aIV.resize(roundUp(sal_Int32(aIV.size()), nCipherBlockSize), 0x36);
+ return aIV;
+}
+
void AgileEngine::calculateBlock(
std::vector<sal_uInt8> const & rBlock,
std::vector<sal_uInt8>& rHashFinal,
@@ -222,21 +265,55 @@ void AgileEngine::calculateBlock(
aDecryptor.update(rOutput, rInput);
}
+void AgileEngine::encryptBlock(
+ std::vector<sal_uInt8> const & rBlock,
+ std::vector<sal_uInt8> & rHashFinal,
+ std::vector<sal_uInt8> & rInput,
+ std::vector<sal_uInt8> & rOutput)
+{
+ std::vector<sal_uInt8> hash(mInfo.hashSize, 0);
+ std::vector<sal_uInt8> dataFinal(mInfo.hashSize + rBlock.size(), 0);
+ std::copy(rHashFinal.begin(), rHashFinal.end(), dataFinal.begin());
+ std::copy(rBlock.begin(), rBlock.end(), dataFinal.begin() + mInfo.hashSize);
+
+ hashCalc(hash, dataFinal, mInfo.hashAlgorithm);
+
+ sal_Int32 keySize = mInfo.keyBits / 8;
+ std::vector<sal_uInt8> key(keySize, 0);
+
+ std::copy(hash.begin(), hash.begin() + keySize, key.begin());
+
+ Encrypt aEncryptor(key, mInfo.saltValue, cryptoType(mInfo));
+
+ aEncryptor.update(rOutput, rInput);
+}
+
void AgileEngine::calculateHashFinal(const OUString& rPassword, std::vector<sal_uInt8>& aHashFinal)
{
- aHashFinal = comphelper::DocPasswordHelper::GetOoxHashAsVector( rPassword, mInfo.saltValue,
- mInfo.spinCount, comphelper::Hash::IterCount::PREPEND, mInfo.hashAlgorithm);
+ aHashFinal = comphelper::DocPasswordHelper::GetOoxHashAsVector(
+ rPassword, mInfo.saltValue, mInfo.spinCount,
+ comphelper::Hash::IterCount::PREPEND, mInfo.hashAlgorithm);
}
-bool AgileEngine::generateEncryptionKey(const OUString& rPassword)
+namespace
{
- static const std::vector<sal_uInt8> constBlock1{ 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 };
- static const std::vector<sal_uInt8> constBlock2{ 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e };
- static const std::vector<sal_uInt8> constBlock3{ 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 };
- mKey.clear();
- mKey.resize(mInfo.keyBits / 8, 0);
+bool generateBytes(std::vector<sal_uInt8> & rBytes, sal_Int32 nSize)
+{
+ size_t nMax = std::min(rBytes.size(), size_t(nSize));
+
+ for (size_t i = 0; i < nMax; ++i)
+ {
+ rBytes[i] = sal_uInt8(comphelper::rng::uniform_uint_distribution(0, 0xFF));
+ }
+ return true;
+}
+
+} // end anonymous namespace
+
+bool AgileEngine::decryptAndCheckVerifierHash(OUString const & rPassword)
+{
std::vector<sal_uInt8> hashFinal(mInfo.hashSize, 0);
calculateHashFinal(rPassword, hashFinal);
@@ -251,22 +328,114 @@ bool AgileEngine::generateEncryptionKey(const OUString& rPassword)
std::vector<sal_uInt8> hash(mInfo.hashSize, 0);
hashCalc(hash, hashInput, mInfo.hashAlgorithm);
- if (hash.size() <= hashValue.size() && std::equal(hash.begin(), hash.end(), hashValue.begin()))
+ return (hash.size() <= hashValue.size() && std::equal(hash.begin(), hash.end(), hashValue.begin()));
+}
+
+bool AgileEngine::decryptEncryptionKey(OUString const & rPassword)
+{
+ sal_Int32 nKeySize = mInfo.keyBits / 8;
+
+ mKey.clear();
+ mKey.resize(nKeySize, 0);
+
+ std::vector<sal_uInt8> aPasswordHash(mInfo.hashSize, 0);
+ calculateHashFinal(rPassword, aPasswordHash);
+
+ calculateBlock(constBlock3, aPasswordHash, mInfo.encryptedKeyValue, mKey);
+
+ return true;
+}
+
+// TODO: Rename
+bool AgileEngine::generateEncryptionKey(OUString const & rPassword)
+{
+ bool bResult = decryptAndCheckVerifierHash(rPassword);
+
+ if (bResult)
{
- std::vector<sal_uInt8>& encryptedKeyValue = mInfo.encryptedKeyValue;
- calculateBlock(constBlock3, hashFinal, encryptedKeyValue, mKey);
- return true;
+ decryptEncryptionKey(rPassword);
+ decryptHmacKey();
+ decryptHmacValue();
}
+ return bResult;
+}
- return false;
+bool AgileEngine::decryptHmacKey()
+{
+ // Initialize hmacKey
+ mInfo.hmacKey.clear();
+ mInfo.hmacKey.resize(mInfo.hmacEncryptedKey.size(), 0);
+
+ // Calculate IV
+ comphelper::HashType eType;
+ if (mInfo.hashAlgorithm == "SHA1")
+ eType = comphelper::HashType::SHA1;
+ else if (mInfo.hashAlgorithm == "SHA512")
+ eType = comphelper::HashType::SHA512;
+ else
+ return false;
+
+ std::vector<sal_uInt8> iv = calculateIV(eType, mInfo.keyDataSalt, constBlockHmac1, mInfo.blockSize);
+
+ // Decrypt with out key, calculated iv
+ Decrypt aDecrypt(mKey, iv, cryptoType(mInfo));
+ aDecrypt.update(mInfo.hmacKey, mInfo.hmacEncryptedKey);
+
+ mInfo.hmacKey.resize(mInfo.hashSize, 0);
+
+ return true;
+}
+
+bool AgileEngine::decryptHmacValue()
+{
+ // Initialize hmacHash
+ mInfo.hmacHash.clear();
+ mInfo.hmacHash.resize(mInfo.hmacEncryptedValue.size(), 0);
+
+ // Calculate IV
+ comphelper::HashType eType;
+ if (mInfo.hashAlgorithm == "SHA1")
+ eType = comphelper::HashType::SHA1;
+ else if (mInfo.hashAlgorithm == "SHA512")
+ eType = comphelper::HashType::SHA512;
+ else
+ return false;
+ std::vector<sal_uInt8> iv = calculateIV(eType, mInfo.keyDataSalt, constBlockHmac2, mInfo.blockSize);
+
+ // Decrypt with out key, calculated iv
+ Decrypt aDecrypt(mKey, iv, cryptoType(mInfo));
+ aDecrypt.update(mInfo.hmacHash, mInfo.hmacEncryptedValue);
+
+ mInfo.hmacHash.resize(mInfo.hashSize, 0);
+
+ return true;
+}
+
+bool AgileEngine::checkDataIntegrity()
+{
+ bool bResult = (mInfo.hmacHash.size() == mInfo.hmacCalculatedHash.size() &&
+ std::equal(mInfo.hmacHash.begin(), mInfo.hmacHash.end(), mInfo.hmacCalculatedHash.begin()));
+
+ return bResult;
}
bool AgileEngine::decrypt(BinaryXInputStream& aInputStream,
BinaryXOutputStream& aOutputStream)
{
+ CryptoHash aCryptoHash(mInfo.hmacKey, cryptoHashTypeFromString(mInfo.hashAlgorithm));
+
sal_uInt32 totalSize = aInputStream.readuInt32(); // Document unencrypted size - 4 bytes
+ // account for size in HMAC
+ std::vector<sal_uInt8> aSizeBytes(sizeof(sal_uInt32));
+ ByteOrderConverter::writeLittleEndian(aSizeBytes.data(), totalSize);
+ aCryptoHash.update(aSizeBytes);
+
aInputStream.skip(4); // Reserved 4 Bytes
+ // accout for reserved 4 bytes (must be 0)
+ std::vector<sal_uInt8> aReserved{0,0,0,0};
+ aCryptoHash.update(aReserved);
+ // setup decryption
std::vector<sal_uInt8>& keyDataSalt = mInfo.keyDataSalt;
sal_uInt32 saltSize = mInfo.saltSize;
@@ -286,7 +455,7 @@ bool AgileEngine::decrypt(BinaryXInputStream& aInputStream,
sal_uInt32 outputLength;
sal_uInt32 remaining = totalSize;
- while ((inputLength = aInputStream.readMemory(inputBuffer.data(), constSegmentLength)) > 0)
+ while ((inputLength = aInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
{
sal_uInt8* segmentBegin = reinterpret_cast<sal_uInt8*>(&segment);
sal_uInt8* segmentEnd = segmentBegin + sizeof(segment);
@@ -301,12 +470,17 @@ bool AgileEngine::decrypt(BinaryXInputStream& aInputStream,
outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
sal_uInt32 writeLength = std::min(outputLength, remaining);
+
+ aCryptoHash.update(inputBuffer, inputLength);
+
aOutputStream.writeMemory(outputBuffer.data(), writeLength);
remaining -= outputLength;
segment++;
}
+ mInfo.hmacCalculatedHash = aCryptoHash.finalize();
+
return true;
}
@@ -363,18 +537,279 @@ bool AgileEngine::readEncryptionInfo(uno::Reference<io::XInputStream> & rxInputS
return false;
}
-void AgileEngine::writeEncryptionInfo(
- const OUString& /*aPassword*/,
- BinaryXOutputStream& /*rStream*/)
+bool AgileEngine::generateAndEncryptVerifierHash(OUString const & rPassword)
+{
+ if (!generateBytes(mInfo.saltValue, mInfo.saltSize))
+ return false;
+
+ std::vector<sal_uInt8> unencryptedVerifierHashInput(mInfo.saltSize);
+ if (!generateBytes(unencryptedVerifierHashInput, mInfo.saltSize))
+ return false;
+
+ // HASH - needs to be modified to be multiple of block size
+ sal_Int32 nVerifierHash = roundUp(mInfo.hashSize, mInfo.blockSize);
+ std::vector<sal_uInt8> unencryptedVerifierHashValue;
+ if (!hashCalc(unencryptedVerifierHashValue, unencryptedVerifierHashInput, mInfo.hashAlgorithm))
+ return false;
+ unencryptedVerifierHashValue.resize(nVerifierHash, 0);
+
+ std::vector<sal_uInt8> hashFinal(mInfo.hashSize, 0);
+ calculateHashFinal(rPassword, hashFinal);
+
+ encryptBlock(constBlock1, hashFinal, unencryptedVerifierHashInput, mInfo.encryptedVerifierHashInput);
+
+ encryptBlock(constBlock2, hashFinal, unencryptedVerifierHashValue, mInfo.encryptedVerifierHashValue);
+
+ return true;
+}
+
+bool AgileEngine::encryptHmacKey()
+{
+ // Initialize hmacKey
+ mInfo.hmacKey.clear();
+ mInfo.hmacKey.resize(mInfo.hashSize, 0);
+
+ if (!generateBytes(mInfo.hmacKey, mInfo.hashSize))
+ return false;
+
+ // Encrypted salt must be multiple of block size
+ sal_Int32 nEncryptedSaltSize = oox::core::roundUp(mInfo.hashSize, mInfo.blockSize);
+
+ // We need to extend hmacSalt to multiple of block size, padding with 0x36
+ std::vector<sal_uInt8> extendedSalt(mInfo.hmacKey);
+ extendedSalt.resize(nEncryptedSaltSize, 0x36);
+
+ // Initialize hmacEncryptedKey
+ mInfo.hmacEncryptedKey.clear();
+ mInfo.hmacEncryptedKey.resize(nEncryptedSaltSize, 0);
+
+ // Calculate IV
+ comphelper::HashType eType;
+ if (mInfo.hashAlgorithm == "SHA1")
+ eType = comphelper::HashType::SHA1;
+ else if (mInfo.hashAlgorithm == "SHA512")
+ eType = comphelper::HashType::SHA512;
+ else
+ return false;
+
+ std::vector<sal_uInt8> iv = calculateIV(eType, mInfo.keyDataSalt, constBlockHmac1, mInfo.blockSize);
+
+ // Encrypt with out key, calculated iv
+ Encrypt aEncryptor(mKey, iv, cryptoType(mInfo));
+ aEncryptor.update(mInfo.hmacEncryptedKey, extendedSalt);
+
+ return true;
+}
+
+bool AgileEngine::encryptHmacValue()
+{
+ sal_Int32 nEncryptedValueSize = roundUp(mInfo.hashSize, mInfo.blockSize);
+ mInfo.hmacEncryptedValue.clear();
+ mInfo.hmacEncryptedValue.resize(nEncryptedValueSize, 0);
+
+ std::vector<sal_uInt8> extendedHash(mInfo.hmacHash);
+ extendedHash.resize(nEncryptedValueSize, 0x36);
+
+ // Calculate IV
+ comphelper::HashType eType;
+ if (mInfo.hashAlgorithm == "SHA1")
+ eType = comphelper::HashType::SHA1;
+ else if (mInfo.hashAlgorithm == "SHA512")
+ eType = comphelper::HashType::SHA512;
+ else
+ return false;
+
+ std::vector<sal_uInt8> iv = calculateIV(eType, mInfo.keyDataSalt, constBlockHmac2, mInfo.blockSize);
+
+ // Encrypt with out key, calculated iv
+ Encrypt aEncryptor(mKey, iv, cryptoType(mInfo));
+ aEncryptor.update(mInfo.hmacEncryptedValue, extendedHash);
+
+ return true;
+}
+
+bool AgileEngine::encryptEncryptionKey(OUString const & rPassword)
+{
+ sal_Int32 nKeySize = mInfo.keyBits / 8;
+
+ mKey.clear();
+ mKey.resize(nKeySize, 0);
+
+ mInfo.encryptedKeyValue.clear();
+ mInfo.encryptedKeyValue.resize(nKeySize, 0);
+
+ if (!generateBytes(mKey, nKeySize))
+ return false;
+
+ std::vector<sal_uInt8> aPasswordHash(mInfo.hashSize, 0);
+ calculateHashFinal(rPassword, aPasswordHash);
+
+ encryptBlock(constBlock3, aPasswordHash, mKey, mInfo.encryptedKeyValue);
+
+ return true;
+}
+
+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
+ setupEncryptionParameters({ 100000, 16, 256, 64, 16, OUString("AES"), OUString("ChainingModeCBC"), OUString("SHA512") });
+
+ if (!setupEncryptionKey(rPassword))
+ return false;
+ return true;
+}
+
+void AgileEngine::setupEncryptionParameters(AgileEncryptionParameters const & rAgileEncryptionParameters)
+{
+ mInfo.spinCount = rAgileEncryptionParameters.spinCount;
+ mInfo.saltSize = rAgileEncryptionParameters.saltSize;
+ mInfo.keyBits = rAgileEncryptionParameters.keyBits;
+ mInfo.hashSize = rAgileEncryptionParameters.hashSize;
+ mInfo.blockSize = rAgileEncryptionParameters.blockSize;
+
+ mInfo.cipherAlgorithm = rAgileEncryptionParameters.cipherAlgorithm;
+ mInfo.cipherChaining = rAgileEncryptionParameters.cipherChaining;
+ mInfo.hashAlgorithm = rAgileEncryptionParameters.hashAlgorithm;
+
+ mInfo.keyDataSalt.resize(mInfo.saltSize);
+ mInfo.saltValue.resize(mInfo.saltSize);
+ mInfo.encryptedVerifierHashInput.resize(mInfo.saltSize);
+ mInfo.encryptedVerifierHashValue.resize(roundUp(mInfo.hashSize, mInfo.blockSize), 0);
+}
+
+bool AgileEngine::setupEncryptionKey(OUString const & rPassword)
{
- // Agile encrypting is not supported for now
+ if (!generateAndEncryptVerifierHash(rPassword))
+ return false;
+ if (!encryptEncryptionKey(rPassword))
+ return false;
+ if (!generateBytes(mInfo.keyDataSalt, mInfo.saltSize))
+ return false;
+ if (!encryptHmacKey())
+ return false;
+ return true;
}
-void AgileEngine::encrypt(
- BinaryXInputStream& /*aInputStream*/,
- BinaryXOutputStream& /*aOutputStream*/)
+void AgileEngine::writeEncryptionInfo(BinaryXOutputStream & rStream)
{
- // Agile encrypting is not supported for now
+ rStream.WriteUInt32(msfilter::VERSION_INFO_AGILE);
+ rStream.WriteUInt32(0); // reserved
+
+ SvMemoryStream aMemStream;
+ tools::XmlWriter aXmlWriter(&aMemStream);
+
+ if (aXmlWriter.startDocument(0/*nIndent*/))
+ {
+ aXmlWriter.startElement("", "encryption", "http://schemas.microsoft.com/office/2006/encryption");
+ aXmlWriter.attribute("xmlns:p", OString("http://schemas.microsoft.com/office/2006/keyEncryptor/password"));
+
+ aXmlWriter.startElement("keyData");
+ aXmlWriter.attribute("saltSize", mInfo.saltSize);
+ aXmlWriter.attribute("blockSize", mInfo.blockSize);
+ aXmlWriter.attribute("keyBits", mInfo.keyBits);
+ aXmlWriter.attribute("hashSize", mInfo.hashSize);
+ aXmlWriter.attribute("cipherAlgorithm", mInfo.cipherAlgorithm);
+ aXmlWriter.attribute("cipherChaining", mInfo.cipherChaining);
+ aXmlWriter.attribute("hashAlgorithm", mInfo.hashAlgorithm);
+ aXmlWriter.attributeBase64("saltValue", mInfo.keyDataSalt);
+ aXmlWriter.endElement();
+
+ aXmlWriter.startElement("dataIntegrity");
+ aXmlWriter.attributeBase64("encryptedHmacKey", mInfo.hmacEncryptedKey);
+ aXmlWriter.attributeBase64("encryptedHmacValue", mInfo.hmacEncryptedValue);
+ aXmlWriter.endElement();
+
+ aXmlWriter.startElement("keyEncryptors");
+ aXmlWriter.startElement("keyEncryptor");
+ aXmlWriter.attribute("uri", OString("http://schemas.microsoft.com/office/2006/keyEncryptor/password"));
+
+ aXmlWriter.startElement("p", "encryptedKey", "");
+ aXmlWriter.attribute("spinCount", mInfo.spinCount);
+ aXmlWriter.attribute("saltSize", mInfo.saltSize);
+ aXmlWriter.attribute("blockSize", mInfo.blockSize);
+ aXmlWriter.attribute("keyBits", mInfo.keyBits);
+ aXmlWriter.attribute("hashSize", mInfo.hashSize);
+ aXmlWriter.attribute("cipherAlgorithm", mInfo.cipherAlgorithm);
+ aXmlWriter.attribute("cipherChaining", mInfo.cipherChaining);
+ aXmlWriter.attribute("hashAlgorithm", mInfo.hashAlgorithm);
+ aXmlWriter.attributeBase64("saltValue", mInfo.saltValue);
+ aXmlWriter.attributeBase64("encryptedVerifierHashInput", mInfo.encryptedVerifierHashInput);
+ aXmlWriter.attributeBase64("encryptedVerifierHashValue", mInfo.encryptedVerifierHashValue);
+ aXmlWriter.attributeBase64("encryptedKeyValue", mInfo.encryptedKeyValue);
+ aXmlWriter.endElement();
+
+ aXmlWriter.endElement();
+ aXmlWriter.endElement();
+
+ aXmlWriter.endElement();
+ aXmlWriter.endDocument();
+ }
+ rStream.writeMemory(aMemStream.GetData(), aMemStream.GetSize());
+}
+
+void AgileEngine::encrypt(css::uno::Reference<css::io::XInputStream> & rxInputStream,
+ css::uno::Reference<css::io::XOutputStream> & rxOutputStream,
+ sal_uInt32 nSize)
+{
+ CryptoHash aCryptoHash(mInfo.hmacKey, cryptoHashTypeFromString(mInfo.hashAlgorithm));
+
+ BinaryXOutputStream aBinaryOutputStream(rxOutputStream, false);
+ BinaryXInputStream aBinaryInputStream(rxInputStream, false);
+
+ std::vector<sal_uInt8> aSizeBytes(sizeof(sal_uInt32));
+ ByteOrderConverter::writeLittleEndian(aSizeBytes.data(), nSize);
+ aBinaryOutputStream.writeMemory(aSizeBytes.data(), aSizeBytes.size()); // size
+ aCryptoHash.update(aSizeBytes, aSizeBytes.size());
+
+ std::vector<sal_uInt8> aNull{0,0,0,0};
+ aBinaryOutputStream.writeMemory(aNull.data(), aNull.size()); // reserved
+ aCryptoHash.update(aNull, aNull.size());
+
+ std::vector<sal_uInt8>& keyDataSalt = mInfo.keyDataSalt;
+
+ sal_uInt32 saltSize = mInfo.saltSize;
+ sal_uInt32 keySize = mInfo.keyBits / 8;
+
+ sal_uInt32 nSegment = 0;
+ sal_uInt32 nSegmentByteSize = sizeof(nSegment);
+
+ std::vector<sal_uInt8> saltWithBlockKey(saltSize + nSegmentByteSize, 0);
+ std::copy(keyDataSalt.begin(), keyDataSalt.end(), saltWithBlockKey.begin());
+
+ std::vector<sal_uInt8> hash(mInfo.hashSize, 0);
+ std::vector<sal_uInt8> iv(keySize, 0);
+
+ std::vector<sal_uInt8> inputBuffer(constSegmentLength);
+ std::vector<sal_uInt8> outputBuffer(constSegmentLength);
+ sal_uInt32 inputLength;
+ sal_uInt32 outputLength;
+
+ while ((inputLength = aBinaryInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
+ {
+ sal_uInt32 correctedInputLength = inputLength % mInfo.blockSize == 0 ?
+ inputLength : oox::core::roundUp(inputLength, sal_uInt32(mInfo.blockSize));
+
+ // Update Key
+ sal_uInt8* segmentBegin = reinterpret_cast<sal_uInt8*>(&nSegment);
+ sal_uInt8* segmentEnd = segmentBegin + nSegmentByteSize;
+ std::copy(segmentBegin, segmentEnd, saltWithBlockKey.begin() + saltSize);
+
+ hashCalc(hash, saltWithBlockKey, mInfo.hashAlgorithm);
+
+ // Only if hash > keySize
+ std::copy(hash.begin(), hash.begin() + keySize, iv.begin());
+
+ Encrypt aEncryptor(mKey, iv, AgileEngine::cryptoType(mInfo));
+ outputLength = aEncryptor.update(outputBuffer, inputBuffer, correctedInputLength);
+ aBinaryOutputStream.writeMemory(outputBuffer.data(), outputLength);
+ aCryptoHash.update(outputBuffer, outputLength);
+
+ nSegment++;
+ }
+ mInfo.hmacHash = aCryptoHash.finalize();
+ encryptHmacValue();
}
} // namespace core
diff --git a/oox/source/crypto/DocumentDecryption.cxx b/oox/source/crypto/DocumentDecryption.cxx
index 40d854123568..b68882ad6b03 100644
--- a/oox/source/crypto/DocumentDecryption.cxx
+++ b/oox/source/crypto/DocumentDecryption.cxx
@@ -106,6 +106,9 @@ bool DocumentDecryption::decrypt(const uno::Reference<io::XStream>& xDocumentStr
xDecryptedPackage->flush();
aDecryptedPackage.seekToStart();
+ if (bResult)
+ return mEngine->checkDataIntegrity();
+
return bResult;
}
diff --git a/oox/source/crypto/DocumentEncryption.cxx b/oox/source/crypto/DocumentEncryption.cxx
index d8b783ac2d41..8cb62c23f006 100644
--- a/oox/source/crypto/DocumentEncryption.cxx
+++ b/oox/source/crypto/DocumentEncryption.cxx
@@ -41,37 +41,30 @@ bool DocumentEncryption::encrypt()
if (!xSeekable.is())
return false;
- sal_uInt32 aLength = xSeekable->getLength();
+ sal_uInt32 aLength = xSeekable->getLength(); // check length of the stream
+ xSeekable->seek(0); // seek to begin of the document stream
if (!mrOleStorage.isStorage())
return false;
+ mEngine.setupEncryption(maPassword);
+
+ Reference<XOutputStream> xOutputStream(mrOleStorage.openOutputStream("EncryptedPackage"), UNO_SET_THROW);
+
+ mEngine.encrypt(xInputStream, xOutputStream, aLength);
+
+ xOutputStream->flush();
+ xOutputStream->closeOutput();
+
Reference<XOutputStream> xEncryptionInfo(mrOleStorage.openOutputStream("EncryptionInfo"), UNO_SET_THROW);
BinaryXOutputStream aEncryptionInfoBinaryOutputStream(xEncryptionInfo, false);
- mEngine.writeEncryptionInfo(maPassword, aEncryptionInfoBinaryOutputStream);
+ mEngine.writeEncryptionInfo(aEncryptionInfoBinaryOutputStream);
aEncryptionInfoBinaryOutputStream.close();
xEncryptionInfo->flush();
xEncryptionInfo->closeOutput();
- Reference<XOutputStream> xEncryptedPackage(mrOleStorage.openOutputStream("EncryptedPackage"), UNO_SET_THROW);
- BinaryXOutputStream aEncryptedPackageStream(xEncryptedPackage, false);
-
- BinaryXInputStream aDocumentInputStream(xInputStream, false);
- aDocumentInputStream.seekToStart();
-
- aEncryptedPackageStream.WriteUInt32(aLength); // size
- aEncryptedPackageStream.WriteUInt32(0U); // reserved
-
- mEngine.encrypt(aDocumentInputStream, aEncryptedPackageStream);
-
- aEncryptedPackageStream.close();
- aDocumentInputStream.close();
-
- xEncryptedPackage->flush();
- xEncryptedPackage->closeOutput();
-
return true;
}
diff --git a/oox/source/crypto/Standard2007Engine.cxx b/oox/source/crypto/Standard2007Engine.cxx
index d1d92269d96c..6dd3e758b641 100644
--- a/oox/source/crypto/Standard2007Engine.cxx
+++ b/oox/source/crypto/Standard2007Engine.cxx
@@ -35,6 +35,7 @@ void lclRandomGenerateValues(sal_uInt8* aArray, sal_uInt32 aSize)
}
static const OUString lclCspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
+constexpr const sal_uInt32 AES128Size = 16;
} // end anonymous namespace
@@ -172,7 +173,12 @@ bool Standard2007Engine::decrypt(BinaryXInputStream& aInputStream,
return true;
}
-void Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOutputStream& rStream)
+bool Standard2007Engine::checkDataIntegrity()
+{
+ return true;
+}
+
+bool Standard2007Engine::setupEncryption(OUString const & password)
{
mInfo.header.flags = msfilter::ENCRYPTINFO_AES | msfilter::ENCRYPTINFO_CRYPTOAPI;
mInfo.header.algId = msfilter::ENCRYPT_ALGO_AES128;
@@ -187,11 +193,16 @@ void Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOu
mKey.resize(keyLength, 0);
if (!calculateEncryptionKey(password))
- return;
+ return false;
if (!generateVerifier())
- return;
+ return false;
+ return true;
+}
+
+void Standard2007Engine::writeEncryptionInfo(BinaryXOutputStream& rStream)
+{
rStream.WriteUInt32(msfilter::VERSION_INFO_2007_FORMAT);
sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
@@ -209,9 +220,19 @@ void Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOu
rStream.writeMemory(&mInfo.verifier, sizeof(msfilter::EncryptionVerifierAES));
}
-void Standard2007Engine::encrypt(BinaryXInputStream& aInputStream,
- BinaryXOutputStream& aOutputStream)
+void Standard2007Engine::encrypt(css::uno::Reference<css::io::XInputStream> & rxInputStream,
+ css::uno::Reference<css::io::XOutputStream> & rxOutputStream,
+ sal_uInt32 nSize)
{
+ if (mKey.empty())
+ return;
+
+ BinaryXOutputStream aBinaryOutputStream(rxOutputStream, false);
+ BinaryXInputStream aBinaryInputStream(rxInputStream, false);
+
+ aBinaryOutputStream.WriteUInt32(nSize); // size
+ aBinaryOutputStream.WriteUInt32(0U); // reserved
+
std::vector<sal_uInt8> inputBuffer(1024);
std::vector<sal_uInt8> outputBuffer(1024);
@@ -221,11 +242,13 @@ void Standard2007Engine::encrypt(BinaryXInputStream& aInputStream,
std::vector<sal_uInt8> iv;
Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
- while ((inputLength = aInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
+ while ((inputLength = aBinaryInputStream.readMemory(inputBuffer.data(), inputBuffer.size())) > 0)
{
- inputLength = inputLength % 16 == 0 ? inputLength : ((inputLength / 16) * 16) + 16;
+ // increase size to multiple of 16 (size of mKey) if necessary
+ inputLength = inputLength % AES128Size == 0 ?
+ inputLength : roundUp(inputLength, AES128Size);
outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
- aOutputStream.writeMemory(outputBuffer.data(), outputLength);
+ aBinaryOutputStream.writeMemory(outputBuffer.data(), outputLength);
}
}