summaryrefslogtreecommitdiff
path: root/oox/source/crypto
diff options
context:
space:
mode:
authorTomaž Vajngerl <quikee@gmail.com>2013-08-24 22:40:54 +0200
committerTomaž Vajngerl <quikee@gmail.com>2013-08-24 22:53:04 +0200
commit4323c66840e4c7dcacda0e33d33d7e67fdb08f09 (patch)
tree5359bfda1a78e99f8fa2f8543b918e0f847ae230 /oox/source/crypto
parent4d688beb2b2183ced387270e051dc25ee340fb4b (diff)
fdo#35422 Support to open encrypted Office 2010 and 2013 formats
Additionally encryption and decryption has been refactored. 2 engines have been added: AgileEngine and Standard2007Engine, which contain core functions for encryption and decryption. Standard2007Engine refers to encryption and decryption as used in Office 2007 and AgileEngine refers to encryption and decryption as used in Office 2010 and 2013. AgileEngine does not yet support encryption. Change-Id: Ica1d4d5a109fb204012b92a0c39325fe0b99b793
Diffstat (limited to 'oox/source/crypto')
-rw-r--r--oox/source/crypto/AgileEngine.cxx218
-rw-r--r--oox/source/crypto/CryptTools.cxx255
-rw-r--r--oox/source/crypto/DocumentDecryption.cxx400
-rw-r--r--oox/source/crypto/DocumentEncryption.cxx79
-rw-r--r--oox/source/crypto/Standard2007Engine.cxx288
5 files changed, 1240 insertions, 0 deletions
diff --git a/oox/source/crypto/AgileEngine.cxx b/oox/source/crypto/AgileEngine.cxx
new file mode 100644
index 000000000000..d0bebe9c1a7d
--- /dev/null
+++ b/oox/source/crypto/AgileEngine.cxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include "oox/crypto/AgileEngine.hxx"
+
+namespace oox {
+namespace core {
+
+using namespace std;
+
+namespace {
+
+static const vector<sal_uInt8> vectorBlock1({ 0xfe, 0xa7, 0xd2, 0x76, 0x3b, 0x4b, 0x9e, 0x79 });
+static const vector<sal_uInt8> vectorBlock2({ 0xd7, 0xaa, 0x0f, 0x6d, 0x30, 0x61, 0x34, 0x4e });
+static const vector<sal_uInt8> vectorBlock3({ 0x14, 0x6e, 0x0b, 0xe7, 0xab, 0xac, 0xd0, 0xd6 });
+
+bool hashCalc( std::vector<sal_uInt8>& output,
+ std::vector<sal_uInt8>& input,
+ const OUString& algorithm )
+{
+ if (algorithm == "SHA1")
+ return sha1(output, input);
+ else if (algorithm == "SHA512")
+ return sha512(output, input);
+ return false;
+}
+
+} // namespace
+
+AgileEngine::AgileEngine() :
+ CryptoEngine()
+{}
+
+AgileEngine::~AgileEngine()
+{}
+
+AgileEncryptionInfo& AgileEngine::getInfo()
+{
+ return mInfo;
+}
+
+Crypto::CryptoType AgileEngine::cryptoType(const AgileEncryptionInfo& rInfo)
+{
+ if (rInfo.keyBits == 128 && rInfo.cipherAlgorithm == "AES" && rInfo.cipherChaining == "ChainingModeCBC")
+ return Crypto::AES_128_CBC;
+ else if (rInfo.keyBits == 256 && rInfo.cipherAlgorithm == "AES" && rInfo.cipherChaining == "ChainingModeCBC")
+ return Crypto::AES_256_CBC;
+ return Crypto::UNKNOWN;
+}
+
+bool AgileEngine::calculateBlock(
+ const vector<sal_uInt8>& rBlock,
+ vector<sal_uInt8>& rHashFinal,
+ vector<sal_uInt8>& rInput,
+ vector<sal_uInt8>& rOutput)
+{
+ vector<sal_uInt8> hash(mInfo.hashSize, 0);
+ vector<sal_uInt8> salt = mInfo.saltValue;
+ vector<sal_uInt8> dataFinal(mInfo.hashSize + rBlock.size(), 0);
+ std::copy(rHashFinal.begin(), rHashFinal.end(), dataFinal.begin());
+ std::copy(
+ rBlock.begin(),
+ rBlock.begin() + rBlock.size(),
+ dataFinal.begin() + mInfo.hashSize);
+
+ hashCalc(hash, dataFinal, mInfo.hashAlgorithm);
+
+ sal_Int32 keySize = mInfo.keyBits / 8;
+ vector<sal_uInt8> key(keySize, 0);
+
+ std::copy(hash.begin(), hash.begin() + keySize, key.begin());
+
+ Decrypt aDecryptor(key, salt, cryptoType(mInfo));
+ aDecryptor.update(rOutput, rInput);
+
+ return true;
+}
+
+bool AgileEngine::calculateHashFinal(const OUString& rPassword, vector<sal_uInt8>& aHashFinal)
+{
+ sal_Int32 saltSize = mInfo.saltSize;
+ vector<sal_uInt8> salt = mInfo.saltValue;
+ sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
+
+ vector<sal_uInt8> initialData(saltSize + passwordByteLength);
+ std::copy(salt.begin(), salt.end(), initialData.begin());
+
+ const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
+
+ std::copy(
+ passwordByteArray,
+ passwordByteArray + passwordByteLength,
+ initialData.begin() + saltSize);
+
+ vector<sal_uInt8> hash(mInfo.hashSize, 0);
+
+ hashCalc(hash, initialData, mInfo.hashAlgorithm);
+
+ vector<sal_uInt8> data(mInfo.hashSize + 4, 0);
+
+ for (int i = 0; i < mInfo.spinCount; i++)
+ {
+ ByteOrderConverter::writeLittleEndian( &data[0], i );
+ std::copy(hash.begin(), hash.end(), data.begin() + 4);
+ hashCalc(hash, data, mInfo.hashAlgorithm);
+ }
+
+ std::copy(hash.begin(), hash.end(), aHashFinal.begin());
+
+ return true;
+}
+
+bool AgileEngine::generateEncryptionKey(const OUString& rPassword)
+{
+ mKey.clear();
+ mKey.resize(mInfo.keyBits / 8, 0);
+
+ vector<sal_uInt8> hashFinal(mInfo.hashSize, 0);
+ calculateHashFinal(rPassword, hashFinal);
+
+ vector<sal_uInt8> encryptedHashInput = mInfo.encryptedVerifierHashInput;
+ vector<sal_uInt8> hashInput(mInfo.saltSize, 0);
+ calculateBlock(vectorBlock1, hashFinal, encryptedHashInput, hashInput);
+
+ vector<sal_uInt8> encryptedHashValue = mInfo.encryptedVerifierHashValue;
+ vector<sal_uInt8> hashValue(encryptedHashValue.size(), 0);
+ calculateBlock(vectorBlock2, hashFinal, encryptedHashValue, hashValue);
+
+ vector<sal_uInt8> hash(mInfo.hashSize, 0);
+ hashCalc(hash, hashInput, mInfo.hashAlgorithm);
+
+ if (std::equal (hash.begin(), hash.end(), hashValue.begin()) )
+ {
+ vector<sal_uInt8> encryptedKeyValue = mInfo.encryptedKeyValue;
+ calculateBlock(vectorBlock3, hashFinal, encryptedKeyValue, mKey);
+ return true;
+ }
+
+ return false;
+}
+
+bool AgileEngine::decrypt(
+ BinaryXInputStream& aInputStream,
+ BinaryXOutputStream& aOutputStream)
+{
+ sal_uInt32 totalSize;
+ aInputStream >> totalSize; // Document unencrypted size - 4 bytes
+ aInputStream.skip( 4 ); // Reserved 4 Bytes
+
+ vector<sal_uInt8> keyDataSalt = mInfo.keyDataSalt;
+
+ sal_uInt32 saltSize = mInfo.saltSize;
+ sal_uInt32 keySize = mInfo.keyBits / 8;
+
+ sal_uInt32 segment = 0;
+
+ vector<sal_uInt8> saltWithBlockKey(saltSize + sizeof(segment), 0);
+ std::copy(keyDataSalt.begin(), keyDataSalt.end(), saltWithBlockKey.begin());
+
+ vector<sal_uInt8> hash(mInfo.hashSize, 0);
+ vector<sal_uInt8> iv(keySize, 0);
+
+ vector<sal_uInt8> inputBuffer (SEGMENT_LENGTH);
+ vector<sal_uInt8> outputBuffer(SEGMENT_LENGTH);
+ sal_uInt32 inputLength;
+ sal_uInt32 outputLength;
+ sal_uInt32 remaining = totalSize;
+
+ while( (inputLength = aInputStream.readMemory( &inputBuffer[0], SEGMENT_LENGTH )) > 0 )
+ {
+ sal_uInt8* segmentBegin = reinterpret_cast<sal_uInt8*>(&segment);
+ sal_uInt8* segmentEnd = segmentBegin + sizeof(segment);
+ 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());
+
+ Decrypt aDecryptor(mKey, iv, AgileEngine::cryptoType(mInfo));
+ outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
+
+ sal_uInt32 writeLength = outputLength > remaining ? remaining : outputLength;
+ aOutputStream.writeMemory( &outputBuffer[0], writeLength );
+
+ remaining -= outputLength;
+ segment++;
+ }
+
+ return true;
+}
+
+bool AgileEngine::writeEncryptionInfo(
+ const OUString& /*aPassword*/,
+ BinaryXOutputStream& /*rStream*/)
+{
+ return false; // Agile encrypting is not supported for now
+}
+
+bool AgileEngine::encrypt(
+ BinaryXInputStream& /*aInputStream*/,
+ BinaryXOutputStream& /*aOutputStream*/)
+{
+ return false; // Agile encrypting is not supported for now
+}
+
+
+} // namespace core
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/crypto/CryptTools.cxx b/oox/source/crypto/CryptTools.cxx
new file mode 100644
index 000000000000..a2a75733aade
--- /dev/null
+++ b/oox/source/crypto/CryptTools.cxx
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include "oox/crypto/CryptTools.hxx"
+
+namespace oox {
+namespace core {
+
+using namespace std;
+
+Crypto::Crypto(CryptoType type) :
+ mType(type)
+{
+#if USE_TLS_NSS
+ // Initialize NSS, database functions are not needed
+ NSS_NoDB_Init(NULL);
+#endif // USE_TLS_NSS
+}
+
+Crypto::~Crypto()
+{
+#if USE_TLS_OPENSSL
+ EVP_CIPHER_CTX_cleanup( &mContext );
+#endif
+#if USE_TLS_NSS
+ PK11_DestroyContext( mContext, PR_TRUE );
+ PK11_FreeSymKey( mSymKey );
+ SECITEM_FreeItem( mSecParam, PR_TRUE );
+#endif
+}
+
+#if USE_TLS_OPENSSL
+const EVP_CIPHER* Crypto::getCipher(CryptoType type)
+{
+ switch(type)
+ {
+ case AES_128_ECB:
+ return EVP_aes_128_ecb();
+ case AES_128_CBC:
+ return EVP_aes_128_cbc();
+ case AES_256_CBC:
+ return EVP_aes_256_cbc();
+ default:
+ break;
+ }
+ return NULL;
+}
+#endif
+
+#if USE_TLS_NSS
+void Crypto::setupContext(vector<sal_uInt8>& key, vector<sal_uInt8>& iv, CryptoType type, CK_ATTRIBUTE_TYPE operation)
+{
+ CK_MECHANISM_TYPE mechanism = -1;
+
+ SECItem ivItem;
+ ivItem.type = siBuffer;
+ ivItem.data = &iv[0];
+ ivItem.len = iv.size();
+
+ SECItem* pIvItem = NULL;
+
+ switch(type)
+ {
+ case AES_128_ECB:
+ mechanism = CKM_AES_ECB;
+ break;
+ case AES_128_CBC:
+ mechanism = CKM_AES_CBC;
+ pIvItem = &ivItem;
+ break;
+ case AES_256_CBC:
+ mechanism = CKM_AES_CBC;
+ pIvItem = &ivItem;
+ break;
+ default:
+ break;
+ }
+
+ PK11SlotInfo* aSlot( PK11_GetBestSlot( mechanism, NULL ) );
+
+ SECItem keyItem;
+ keyItem.type = siBuffer;
+ keyItem.data = &key[0];
+ keyItem.len = key.size();
+
+ mSymKey = PK11_ImportSymKey( aSlot, mechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL );
+ mSecParam = PK11_ParamFromIV( mechanism, pIvItem );
+ mContext = PK11_CreateContextBySymKey( mechanism, operation, mSymKey, mSecParam );
+}
+#endif // USE_TLS_NSS
+
+// DECRYPT
+
+Decrypt::Decrypt(vector<sal_uInt8>& key, vector<sal_uInt8>& iv, CryptoType type) :
+ Crypto(type)
+{
+#if USE_TLS_OPENSSL
+ EVP_CIPHER_CTX_init( &mContext );
+
+ const EVP_CIPHER* cipher = getCipher(type);
+
+ if (iv.empty())
+ EVP_DecryptInit_ex( &mContext, cipher, NULL, &key[0], 0 );
+ else
+ EVP_DecryptInit_ex( &mContext, cipher, NULL, &key[0], &iv[0] );
+ EVP_CIPHER_CTX_set_padding( &mContext, 0 );
+#endif
+
+#if USE_TLS_NSS
+ setupContext(key, iv, type, CKA_DECRYPT);
+#endif // USE_TLS_NSS
+}
+
+sal_uInt32 Decrypt::update(vector<sal_uInt8>& output, vector<sal_uInt8>& input, sal_uInt32 inputLength)
+{
+ int outputLength = 0;
+
+ sal_uInt32 actualInputLength = inputLength == 0 || inputLength > input.size() ? input.size() : inputLength;
+
+#if USE_TLS_OPENSSL
+ EVP_DecryptUpdate( &mContext, &output[0], &outputLength, &input[0], actualInputLength );
+#endif // USE_TLS_OPENSSL
+
+#if USE_TLS_NSS
+ PK11_CipherOp( mContext, &output[0], &outputLength, actualInputLength, &input[0], actualInputLength );
+#endif // USE_TLS_NSS
+
+ return static_cast<sal_uInt32>(outputLength);
+}
+
+sal_uInt32 Decrypt::aes128ecb(vector<sal_uInt8>& output, vector<sal_uInt8>& input, vector<sal_uInt8>& key)
+{
+ sal_uInt32 outputLength = 0;
+ vector<sal_uInt8> iv;
+ Decrypt crypto(key, iv, Crypto::AES_128_ECB);
+ outputLength = crypto.update(output, input);
+ return outputLength;
+}
+
+sal_uInt32 Decrypt::aes128cbc(vector<sal_uInt8>& output, vector<sal_uInt8>& input, vector<sal_uInt8>& key, vector<sal_uInt8>& iv)
+{
+ sal_uInt32 outputLength = 0;
+ Decrypt crypto(key, iv, Crypto::AES_128_CBC);
+ outputLength = crypto.update(output, input);
+ return outputLength;
+}
+
+// ENCRYPT
+
+Encrypt::Encrypt(vector<sal_uInt8>& key, vector<sal_uInt8>& iv, CryptoType type) :
+ Crypto(type)
+{
+#if USE_TLS_OPENSSL
+ EVP_CIPHER_CTX_init( &mContext );
+
+ const EVP_CIPHER* cipher = getCipher(type);
+
+ if (iv.empty())
+ EVP_EncryptInit_ex( &mContext, cipher, NULL, &key[0], 0 );
+ else
+ EVP_EncryptInit_ex( &mContext, cipher, NULL, &key[0], &iv[0] );
+ EVP_CIPHER_CTX_set_padding( &mContext, 0 );
+#endif
+
+#if USE_TLS_NSS
+ setupContext(key, iv, type, CKA_ENCRYPT);
+#endif // USE_TLS_NSS
+}
+
+sal_uInt32 Encrypt::update(vector<sal_uInt8>& output, vector<sal_uInt8>& input, sal_uInt32 inputLength)
+{
+ int outputLength = 0;
+
+ sal_uInt32 actualInputLength = inputLength == 0 || inputLength > input.size() ? input.size() : inputLength;
+
+#if USE_TLS_OPENSSL
+ EVP_EncryptUpdate( &mContext, &output[0], &outputLength, &input[0], actualInputLength );
+#endif // USE_TLS_OPENSSL
+
+#if USE_TLS_NSS
+ PK11_CipherOp( mContext, &output[0], &outputLength, actualInputLength, &input[0], actualInputLength );
+#endif // USE_TLS_NSS
+
+ return static_cast<sal_uInt32>(outputLength);
+}
+
+bool sha1(vector<sal_uInt8>& output, vector<sal_uInt8>& input)
+{
+ output.clear();
+ output.resize(RTL_DIGEST_LENGTH_SHA1, 0);
+
+ rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
+ rtl_digest_update( aDigest, &input[0], input.size() );
+ rtl_digest_get( aDigest, &output[0], RTL_DIGEST_LENGTH_SHA1 );
+ rtl_digest_destroy( aDigest );
+
+ return true;
+}
+
+bool sha512(vector<sal_uInt8>& output, vector<sal_uInt8>& input)
+{
+ bool aResult = false;
+
+#if USE_TLS_OPENSSL
+ output.clear();
+ output.resize(SHA512_DIGEST_LENGTH, 0);
+
+ SHA512_CTX context;
+ SHA512_Init(&context);
+ SHA512_Update(&context, &input[0], input.size());
+ SHA512_Final(&output[0], &context);
+ aResult = true;
+#endif
+
+#if USE_TLS_NSS
+ output.clear();
+ output.resize(SHA512_LENGTH, 0);
+
+ // Initialize NSS, database functions are not needed
+ NSS_NoDB_Init(NULL);
+ SECStatus status;
+
+ PK11Context* mContext = PK11_CreateDigestContext(SEC_OID_SHA512);
+ status = PK11_DigestBegin(mContext);
+ if (status != SECSuccess)
+ return false;
+
+ status = PK11_DigestOp(mContext, &input[0], input.size());
+ if (status != SECSuccess)
+ return false;
+
+ sal_uInt32 outputLength = 0;
+
+ status = PK11_DigestFinal(mContext, &output[0], &outputLength, SHA512_LENGTH);
+ if (status != SECSuccess || outputLength != SHA512_LENGTH)
+ return false;
+
+ PK11_DestroyContext(mContext, PR_TRUE);
+
+ aResult = true;
+#endif
+ return aResult;
+}
+
+} // namespace core
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/crypto/DocumentDecryption.cxx b/oox/source/crypto/DocumentDecryption.cxx
new file mode 100644
index 000000000000..64281981ab29
--- /dev/null
+++ b/oox/source/crypto/DocumentDecryption.cxx
@@ -0,0 +1,400 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include "oox/crypto/DocumentDecryption.hxx"
+
+#include <comphelper/sequenceashashmap.hxx>
+#include <sax/tools/converter.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/xml/sax/XFastParser.hpp>
+#include <com/sun/star/xml/sax/XFastTokenHandler.hpp>
+#include <com/sun/star/xml/sax/FastToken.hpp>
+
+namespace oox {
+namespace core {
+
+using namespace css::beans;
+using namespace css::io;
+using namespace css::lang;
+using namespace css::uno;
+using namespace css::xml::sax;
+using namespace css::xml;
+
+using namespace std;
+
+using ::comphelper::SequenceAsHashMap;
+using ::sax::Converter;
+
+namespace {
+
+vector<sal_uInt8> convertToVector(Sequence<sal_Int8>& input)
+{
+ const sal_uInt8* inputArray = reinterpret_cast<const sal_uInt8*>( input.getConstArray() );
+ return vector<sal_uInt8>(inputArray, inputArray + input.getLength());
+}
+
+class AgileTokenHandler : public cppu::WeakImplHelper1< XFastTokenHandler >
+{
+public:
+ virtual sal_Int32 SAL_CALL getToken( const OUString& /*nIdentifier*/ ) throw (RuntimeException)
+ {
+ return FastToken::DONTKNOW;
+ }
+
+ virtual sal_Int32 SAL_CALL getTokenFromUTF8( const Sequence< sal_Int8 >& /*nIdentifier*/ ) throw (RuntimeException)
+ {
+ return FastToken::DONTKNOW;
+ }
+
+ virtual OUString SAL_CALL getIdentifier( sal_Int32 /*nToken*/ ) throw (RuntimeException)
+ {
+ return OUString();
+ }
+
+ virtual Sequence<sal_Int8> SAL_CALL getUTF8Identifier(sal_Int32 /*nToken*/) throw (RuntimeException)
+ {
+ return Sequence<sal_Int8>();
+ }
+};
+
+class AgileDocumentHandler : public ::cppu::WeakImplHelper1< XFastDocumentHandler >
+{
+public:
+ AgileDocumentHandler(AgileEncryptionInfo& rInfo) :
+ mInfo(rInfo)
+ {}
+
+ AgileEncryptionInfo& mInfo;
+ void startDocument() {}
+ void endDocument() {}
+ void SAL_CALL setDocumentLocator( const Reference< XLocator >& /*xLocator*/ ) {}
+ void startFastElement( sal_Int32 /*Element*/, const Reference< XFastAttributeList >& /*Attribs*/ ) {}
+
+ void startUnknownElement( const OUString& /*aNamespace*/, const OUString& aName, const Reference< XFastAttributeList >& aAttributeList )
+ {
+ if(aName == "keyData")
+ {
+ Sequence<Attribute> aAttributes(aAttributeList->getUnknownAttributes());
+
+ for (int i=0; i<aAttributes.getLength(); i++)
+ {
+ if (aAttributes[i].Name == "saltValue")
+ {
+ Sequence<sal_Int8> keyDataSalt;
+ Converter::decodeBase64(keyDataSalt, aAttributes[i].Value);
+ mInfo.keyDataSalt = convertToVector(keyDataSalt);
+ }
+ }
+ }
+ else if(aName == "encryptedKey")
+ {
+ Sequence<Attribute> aAttributes(aAttributeList->getUnknownAttributes());
+ for (int i=0; i<aAttributes.getLength(); i++)
+ {
+ if (aAttributes[i].Name == "spinCount")
+ {
+ Converter::convertNumber(mInfo.spinCount, aAttributes[i].Value);
+ }
+ else if (aAttributes[i].Name == "saltSize")
+ {
+ Converter::convertNumber(mInfo.saltSize, aAttributes[i].Value);
+ }
+ else if (aAttributes[i].Name == "blockSize")
+ {
+ Converter::convertNumber(mInfo.blockSize, aAttributes[i].Value);
+ }
+ else if (aAttributes[i].Name == "keyBits")
+ {
+ Converter::convertNumber(mInfo.keyBits, aAttributes[i].Value);
+ }
+ else if (aAttributes[i].Name == "hashSize")
+ {
+ Converter::convertNumber(mInfo.hashSize, aAttributes[i].Value);
+ }
+ else if (aAttributes[i].Name == "cipherAlgorithm")
+ {
+ mInfo.cipherAlgorithm = aAttributes[i].Value;
+ }
+ else if (aAttributes[i].Name == "cipherChaining")
+ {
+ mInfo.cipherChaining = aAttributes[i].Value;
+ }
+ else if (aAttributes[i].Name == "hashAlgorithm")
+ {
+ mInfo.hashAlgorithm = aAttributes[i].Value;
+ }
+ else if (aAttributes[i].Name == "saltValue")
+ {
+ Sequence<sal_Int8> saltValue;
+ Converter::decodeBase64(saltValue, aAttributes[i].Value);
+ mInfo.saltValue = convertToVector(saltValue);
+ }
+ else if (aAttributes[i].Name == "encryptedVerifierHashInput")
+ {
+ Sequence<sal_Int8> encryptedVerifierHashInput;
+ Converter::decodeBase64(encryptedVerifierHashInput, aAttributes[i].Value);
+ mInfo.encryptedVerifierHashInput = convertToVector(encryptedVerifierHashInput);
+ }
+ else if (aAttributes[i].Name == "encryptedVerifierHashValue")
+ {
+ Sequence<sal_Int8> encryptedVerifierHashValue;
+ Converter::decodeBase64(encryptedVerifierHashValue, aAttributes[i].Value);
+ mInfo.encryptedVerifierHashValue = convertToVector(encryptedVerifierHashValue);
+ }
+ else if (aAttributes[i].Name == "encryptedKeyValue")
+ {
+ Sequence<sal_Int8> encryptedKeyValue;
+ Converter::decodeBase64(encryptedKeyValue, aAttributes[i].Value);
+ mInfo.encryptedKeyValue = convertToVector(encryptedKeyValue);
+ }
+ }
+ }
+ }
+
+ void endFastElement( sal_Int32 /*aElement*/ ) {}
+ void endUnknownElement( const OUString& /*aNamespace*/, const OUString& /*aName*/ ) {}
+
+ Reference< XFastContextHandler > createFastChildContext( sal_Int32 /*aElement*/, const Reference< XFastAttributeList >& /*aAttribs*/ )
+ {
+ return NULL;
+ }
+
+ Reference< XFastContextHandler > createUnknownChildContext( const OUString& /*aNamespace*/, const OUString& /*aName*/, const Reference< XFastAttributeList >& /*aAttribs*/ )
+ {
+ return this;
+ }
+
+ void characters( const OUString& /*aChars*/ ) {}
+};
+
+} // namespace
+
+DocumentDecryption::DocumentDecryption(oox::ole::OleStorage& rOleStorage, Reference<XComponentContext> xContext) :
+ mxContext(xContext),
+ mrOleStorage(rOleStorage),
+ mCryptoType(UNKNOWN)
+{}
+
+bool DocumentDecryption::checkEncryptionData(const Sequence<NamedValue>& rEncryptionData)
+{
+ SequenceAsHashMap aHashData( rEncryptionData );
+ OUString type = aHashData.getUnpackedValueOrDefault( "CryptoType", OUString("Unknown") );
+ if (type == "Standard")
+ {
+ Sequence<sal_Int8> aKeySeq = aHashData.getUnpackedValueOrDefault( "AES128EncryptionKey", Sequence<sal_Int8>() );
+ Sequence<sal_Int8> aVerifierSeq = aHashData.getUnpackedValueOrDefault( "AES128EncryptionVerifier", Sequence<sal_Int8>() );
+ Sequence<sal_Int8> aHashSeq = aHashData.getUnpackedValueOrDefault( "AES128EncryptionVerifierHash", Sequence<sal_Int8>() );
+
+ vector<sal_uInt8> key = convertToVector(aKeySeq);
+ vector<sal_uInt8> verifier = convertToVector(aVerifierSeq);
+ vector<sal_uInt8> hash = convertToVector(aHashSeq);
+
+ return Standard2007Engine::checkEncryptionData( key, key.size(), verifier, verifier.size(), hash, hash.size() );
+ }
+ return type == "Agile";
+}
+
+bool DocumentDecryption::generateEncryptionKey(const OUString& rPassword)
+{
+ if (mEngine.get())
+ return mEngine->generateEncryptionKey(rPassword);
+ return false;
+}
+
+bool DocumentDecryption::readAgileEncryptionInfo(Reference< XInputStream >& xInputStream)
+{
+ AgileEngine* engine = new AgileEngine();
+ mEngine.reset(engine);
+ AgileEncryptionInfo& info = engine->getInfo();
+
+ Reference<XMultiComponentFactory> xFactory( mxContext->getServiceManager(), UNO_SET_THROW );
+ Reference<XFastDocumentHandler> xFastDocumentHandler( new AgileDocumentHandler(info) );
+ Reference<XFastTokenHandler> xFastTokenHandler ( new AgileTokenHandler );
+
+ Reference<XFastParser> xParser;
+ xParser.set( xFactory->createInstanceWithContext( "com.sun.star.xml.sax.FastParser", mxContext ), UNO_QUERY_THROW );
+
+ if (!xParser.is())
+ return false;
+
+ xParser->setFastDocumentHandler( xFastDocumentHandler );
+ xParser->setTokenHandler( xFastTokenHandler );
+
+ InputSource aInputSource;
+ aInputSource.aInputStream = xInputStream;
+ xParser->parseStream( aInputSource );
+
+ // CHECK info data
+ if (2 > info.blockSize || info.blockSize > 4096)
+ return false;
+
+ if (0 > info.spinCount || info.spinCount > 10000000)
+ return false;
+
+ if (1 > info.saltSize|| info.saltSize > 65536) // Check
+ return false;
+
+ // AES 128 CBC with SHA1
+ if (info.keyBits == 128 &&
+ info.cipherAlgorithm == "AES" &&
+ info.cipherChaining == "ChainingModeCBC" &&
+ info.hashAlgorithm == "SHA1" &&
+ info.hashSize == 20)
+ {
+ return true;
+ }
+
+ // AES 256 CBC with SHA512
+ if (info.keyBits == 256 &&
+ info.cipherAlgorithm == "AES" &&
+ info.cipherChaining == "ChainingModeCBC" &&
+ info.hashAlgorithm == "SHA512" &&
+ info.hashSize == 64 )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+bool DocumentDecryption::readStandard2007EncryptionInfo(BinaryInputStream& rStream)
+{
+ Standard2007Engine* engine = new Standard2007Engine();
+ mEngine.reset(engine);
+ StandardEncryptionInfo& info = engine->getInfo();
+
+
+ rStream >> info.header.flags;
+ if( getFlag( info.header.flags, ENCRYPTINFO_EXTERNAL ) )
+ return false;
+
+ sal_uInt32 nHeaderSize;
+ rStream >> nHeaderSize;
+
+ sal_uInt32 actualHeaderSize = sizeof(info.header);
+
+ if( (nHeaderSize < actualHeaderSize) )
+ return false;
+
+ rStream >> info.header;
+ rStream.skip( nHeaderSize - actualHeaderSize );
+ rStream >> info.verifier;
+
+ if( info.verifier.saltSize != 16 )
+ return false;
+
+ // check flags and algorithm IDs, required are AES128 and SHA-1
+ if( !getFlag( info.header.flags , ENCRYPTINFO_CRYPTOAPI ) )
+ return false;
+
+ if( !getFlag( info.header.flags, ENCRYPTINFO_AES ) )
+ return false;
+
+ // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set
+ if( info.header.algId != 0 && info.header.algId != ENCRYPT_ALGO_AES128 )
+ return false;
+
+ // hash algorithm ID 0 defaults to SHA-1 too
+ if( info.header.algIdHash != 0 && info.header.algIdHash != ENCRYPT_HASH_SHA1 )
+ return false;
+
+ if( info.verifier.encryptedVerifierHashSize != 20 )
+ return false;
+
+ return !rStream.isEof();
+}
+
+bool DocumentDecryption::readEncryptionInfo()
+{
+ if( !mrOleStorage.isStorage() )
+ return false;
+
+ Reference< XInputStream > xEncryptionInfo( mrOleStorage.openInputStream( "EncryptionInfo" ), UNO_SET_THROW );
+
+ bool bResult = false;
+
+ BinaryXInputStream aBinaryInputStream( xEncryptionInfo, true );
+
+ sal_uInt32 aVersion;
+ aBinaryInputStream >> aVersion;
+
+ switch (aVersion)
+ {
+ case VERSION_INFO_2007_FORMAT:
+ mCryptoType = STANDARD_2007; // Set encryption info format
+ bResult = readStandard2007EncryptionInfo( aBinaryInputStream );
+ break;
+ case VERSION_INFO_AGILE:
+ mCryptoType = AGILE; // Set encryption info format
+ aBinaryInputStream.skip(4);
+ bResult = readAgileEncryptionInfo( xEncryptionInfo );
+ break;
+ default:
+ break;
+ }
+
+ return bResult;
+}
+
+Sequence<NamedValue> DocumentDecryption::createEncryptionData()
+{
+ Sequence<NamedValue> aResult;
+
+ vector<sal_uInt8>& key = mEngine->getKey();
+
+ if (key.size() > 0)
+ {
+ SequenceAsHashMap aEncryptionData;
+ if (mCryptoType == AGILE)
+ {
+ aEncryptionData["CryptoType"] <<= OUString("Agile");
+ aEncryptionData["AES128EncryptionKey"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( &key[0] ), key.size() );
+ aResult = aEncryptionData.getAsConstNamedValueList();
+ }
+ else if (mCryptoType == STANDARD_2007)
+ {
+ aEncryptionData["CryptoType"] <<= OUString("Standard");
+ aEncryptionData["AES128EncryptionKey"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( &key[0] ), key.size() );
+ aResult = aEncryptionData.getAsConstNamedValueList();
+ }
+ }
+
+ return aResult;
+}
+
+bool DocumentDecryption::decrypt(Reference<XStream> xDocumentStream)
+{
+ bool aResult = false;
+
+ if( !mrOleStorage.isStorage() )
+ return false;
+
+ // open the required input streams in the encrypted package
+ Reference< XInputStream > xEncryptedPackage( mrOleStorage.openInputStream( "EncryptedPackage" ), UNO_SET_THROW );
+
+ // create temporary file for unencrypted package
+ Reference< XOutputStream > xDecryptedPackage( xDocumentStream->getOutputStream(), UNO_SET_THROW );
+ BinaryXOutputStream aDecryptedPackage( xDecryptedPackage, true );
+ BinaryXInputStream aEncryptedPackage( xEncryptedPackage, true );
+
+ aResult = mEngine->decrypt(aEncryptedPackage, aDecryptedPackage);
+
+ xDecryptedPackage->flush();
+ aDecryptedPackage.seekToStart();
+
+ return aResult;
+}
+
+} // namespace core
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/crypto/DocumentEncryption.cxx b/oox/source/crypto/DocumentEncryption.cxx
new file mode 100644
index 000000000000..e0941cfa5d95
--- /dev/null
+++ b/oox/source/crypto/DocumentEncryption.cxx
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include "oox/crypto/DocumentEncryption.hxx"
+
+#include <com/sun/star/io/XSeekable.hpp>
+
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/helper/binaryoutputstream.hxx"
+
+namespace oox {
+namespace core {
+
+using namespace css::beans;
+using namespace css::io;
+using namespace css::lang;
+using namespace css::uno;
+
+using namespace std;
+
+DocumentEncryption::DocumentEncryption(Reference< XStream > xDocumentStream, oox::ole::OleStorage& rOleStorage, OUString aPassword) :
+ mxDocumentStream(xDocumentStream),
+ mrOleStorage(rOleStorage),
+ maPassword(aPassword)
+{}
+
+bool DocumentEncryption::encrypt()
+{
+ Reference< XInputStream > xInputStream ( mxDocumentStream->getInputStream(), UNO_SET_THROW );
+ Reference< XSeekable > xSeekable( xInputStream, UNO_QUERY );
+
+ if (!xSeekable.is())
+ return false;
+
+ sal_uInt32 aLength = xSeekable->getLength();
+
+ if (!mrOleStorage.isStorage())
+ return false;
+
+ Reference< XOutputStream > xEncryptionInfo( mrOleStorage.openOutputStream( "EncryptionInfo" ), UNO_SET_THROW );
+ BinaryXOutputStream aEncryptionInfoBinaryOutputStream( xEncryptionInfo, false );
+
+ mEngine.writeEncryptionInfo(maPassword, 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.writeValue<sal_uInt32>( aLength ); // size
+ aEncryptedPackageStream.writeValue<sal_uInt32>( 0 ); // reserved
+
+ mEngine.encrypt(aDocumentInputStream, aEncryptedPackageStream);
+
+ aEncryptedPackageStream.close();
+ aDocumentInputStream.close();
+
+ xEncryptedPackage->flush();
+ xEncryptedPackage->closeOutput();
+
+ return true;
+}
+
+} // namespace core
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/crypto/Standard2007Engine.cxx b/oox/source/crypto/Standard2007Engine.cxx
new file mode 100644
index 000000000000..3c17bb60907c
--- /dev/null
+++ b/oox/source/crypto/Standard2007Engine.cxx
@@ -0,0 +1,288 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include "oox/crypto/Standard2007Engine.hxx"
+
+#include <osl/time.h>
+#include <rtl/random.h>
+
+namespace oox {
+namespace core {
+
+using namespace std;
+
+/* =========================================================================== */
+/* Kudos to Caolan McNamara who provided the core decryption implementations. */
+/* =========================================================================== */
+namespace
+{
+
+void lclRandomGenerateValues(sal_uInt8* aArray, sal_uInt32 aSize)
+{
+ TimeValue aTime;
+ osl_getSystemTime( &aTime );
+ rtlRandomPool aRandomPool = rtl_random_createPool ();
+ rtl_random_addBytes ( aRandomPool, &aTime, 8 );
+ rtl_random_getBytes ( aRandomPool, aArray, aSize );
+ rtl_random_destroyPool ( aRandomPool );
+}
+
+static const OUString lclCspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
+
+} // namespace
+
+EncryptionStandardHeader::EncryptionStandardHeader()
+{
+ flags = 0;
+ sizeExtra = 0;
+ algId = 0;
+ algIdHash = 0;
+ keyBits = 0;
+ providedType = 0;
+ reserved1 = 0;
+ reserved2 = 0;
+}
+
+EncryptionVerifierAES::EncryptionVerifierAES()
+{
+ saltSize = SALT_LENGTH;
+ memset(salt, 0, sizeof(salt));
+ memset(encryptedVerifier, 0, sizeof(encryptedVerifier));
+ memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash));
+}
+
+Standard2007Engine::Standard2007Engine() :
+ CryptoEngine()
+{}
+
+Standard2007Engine::~Standard2007Engine()
+{}
+
+StandardEncryptionInfo& Standard2007Engine::getInfo()
+{
+ return mInfo;
+}
+
+bool Standard2007Engine::generateVerifier()
+{
+ // only support key of size 128 bit (16 byte)
+ if (mKey.size() != 16)
+ return false;
+
+ sal_uInt32 outputLength;
+ vector<sal_uInt8> verifier(ENCRYPTED_VERIFIER_LENGTH);
+ vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
+
+ lclRandomGenerateValues(&verifier[0], verifier.size());
+
+ vector<sal_uInt8> iv;
+ Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
+ outputLength = aEncryptorVerifier.update(encryptedVerifier, verifier);
+ if (outputLength != ENCRYPTED_VERIFIER_LENGTH)
+ return false;
+ std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
+
+ vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
+ mInfo.verifier.encryptedVerifierHashSize = RTL_DIGEST_LENGTH_SHA1;
+ sha1(hash, verifier);
+ hash.resize(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
+
+ vector<sal_uInt8> encryptedHash(ENCRYPTED_VERIFIER_HASH_LENGTH, 0);
+
+ Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
+ outputLength = aEncryptorHash.update(encryptedHash, hash, hash.size());
+ std::copy(encryptedHash.begin(), encryptedHash.end(), mInfo.verifier.encryptedVerifierHash);
+
+ return true;
+}
+
+bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
+{
+ sal_uInt32 saltSize = mInfo.verifier.saltSize;
+ sal_uInt32 passwordByteLength = rPassword.getLength() * 2;
+ const sal_uInt8* saltArray = mInfo.verifier.salt;
+
+ // Prepare initial data -> salt + password (in 16-bit chars)
+ vector<sal_uInt8> initialData(saltSize + passwordByteLength);
+ std::copy(saltArray, saltArray + saltSize, initialData.begin());
+
+ const sal_uInt8* passwordByteArray = reinterpret_cast<const sal_uInt8*>(rPassword.getStr());
+
+ std::copy(
+ passwordByteArray,
+ passwordByteArray + passwordByteLength,
+ initialData.begin() + saltSize);
+
+ // use "hash" vector for result of sha1 hashing
+ vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
+
+ // calculate SHA1 hash of initialData
+ sha1(hash, initialData);
+
+ // data = iterator (4bytes) + hash
+ vector<sal_uInt8> data(RTL_DIGEST_LENGTH_SHA1 + 4, 0);
+
+ for (int i = 0; i < 50000; i++)
+ {
+ ByteOrderConverter::writeLittleEndian( &data[0], i );
+ std::copy(hash.begin(), hash.end(), data.begin() + 4);
+ sha1(hash, data);
+ }
+ std::copy(hash.begin(), hash.end(), data.begin() );
+ std::fill(data.begin() + RTL_DIGEST_LENGTH_SHA1, data.end(), 0 );
+
+ sha1(hash, data);
+
+ // derive key
+ vector<sal_uInt8> buffer(64, 0x36);
+ for( sal_uInt32 i = 0; i < hash.size(); ++i )
+ buffer[i] ^= hash[i];
+
+ sha1(hash, buffer);
+ std::copy(hash.begin(), hash.begin() + mKey.size(), mKey.begin());
+
+ return true;
+}
+
+bool Standard2007Engine::generateEncryptionKey(const OUString& password)
+{
+ mKey.clear();
+ mKey.resize(mInfo.header.keyBits / 8, 0);
+
+ calculateEncryptionKey(password);
+
+ vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
+ std::copy(
+ mInfo.verifier.encryptedVerifier,
+ mInfo.verifier.encryptedVerifier + ENCRYPTED_VERIFIER_LENGTH,
+ encryptedVerifier.begin());
+
+ vector<sal_uInt8> encryptedVerifierHash(ENCRYPTED_VERIFIER_HASH_LENGTH);
+ std::copy(
+ mInfo.verifier.encryptedVerifierHash,
+ mInfo.verifier.encryptedVerifierHash + ENCRYPTED_VERIFIER_HASH_LENGTH,
+ encryptedVerifierHash.begin());
+
+ return checkEncryptionData(
+ mKey, mKey.size(),
+ encryptedVerifier, encryptedVerifier.size(),
+ encryptedVerifierHash, encryptedVerifierHash.size() );
+}
+
+bool Standard2007Engine::decrypt(
+ BinaryXInputStream& aInputStream,
+ BinaryXOutputStream& aOutputStream)
+{
+ sal_uInt32 totalSize;
+ aInputStream >> totalSize; // Document unencrypted size - 4 bytes
+ aInputStream.skip( 4 ); // Reserved 4 Bytes
+
+ vector<sal_uInt8> iv;
+ Decrypt aDecryptor(mKey, iv, Crypto::AES_128_ECB);
+ vector<sal_uInt8> inputBuffer (4096);
+ vector<sal_uInt8> outputBuffer(4096);
+ sal_uInt32 inputLength;
+ sal_uInt32 outputLength;
+
+ while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
+ {
+ outputLength = aDecryptor.update(outputBuffer, inputBuffer, inputLength);
+ aOutputStream.writeMemory( &outputBuffer[0], outputLength );
+ }
+ return true;
+}
+
+bool Standard2007Engine::checkEncryptionData(
+ vector<sal_uInt8> key, sal_uInt32 keySize,
+ vector<sal_uInt8> encryptedVerifier, sal_uInt32 verifierSize,
+ vector<sal_uInt8> encryptedHash, sal_uInt32 hashSize )
+{
+ // the only currently supported algorithm needs key size 128
+ if ( keySize != 16 || verifierSize != 16 )
+ return false;
+
+ vector<sal_uInt8> verifier(verifierSize, 0);
+ Decrypt::aes128ecb(verifier, encryptedVerifier, key);
+
+ vector<sal_uInt8> verifierHash(hashSize, 0);
+ Decrypt::aes128ecb(verifierHash, encryptedHash, key);
+
+ vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
+ sha1(hash, verifier);
+
+ return std::equal( hash.begin(), hash.end(), verifierHash.begin() );
+}
+
+bool Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOutputStream& rStream)
+{
+ mInfo.header.flags = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
+ mInfo.header.algId = ENCRYPT_ALGO_AES128;
+ mInfo.header.algIdHash = ENCRYPT_HASH_SHA1;
+ mInfo.header.keyBits = ENCRYPT_KEY_SIZE_AES_128;
+ mInfo.header.providedType = ENCRYPT_PROVIDER_TYPE_AES;
+
+ lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
+ const sal_Int32 keyLength = mInfo.header.keyBits / 8;
+
+ mKey.clear();
+ mKey.resize(keyLength, 0);
+
+ if (!calculateEncryptionKey(password))
+ return false;
+
+ if (!generateVerifier())
+ return false;
+
+ rStream.writeValue(VERSION_INFO_2007_FORMAT);
+
+ sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
+
+ sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(EncryptionStandardHeader));
+
+ rStream << mInfo.header.flags;
+ sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
+ rStream << headerSize;
+
+ rStream.writeMemory(&mInfo.header, encryptionHeaderSize);
+ rStream.writeUnicodeArray(lclCspName);
+ rStream.writeValue<sal_uInt16>(0);
+
+ sal_uInt32 encryptionVerifierSize = static_cast<sal_uInt32>(sizeof(EncryptionVerifierAES));
+ rStream.writeMemory(&mInfo.verifier, encryptionVerifierSize);
+
+ return true;
+}
+
+bool Standard2007Engine::encrypt(
+ BinaryXInputStream& aInputStream,
+ BinaryXOutputStream& aOutputStream)
+{
+ vector<sal_uInt8> inputBuffer(1024);
+ vector<sal_uInt8> outputBuffer(1024);
+
+ sal_uInt32 inputLength;
+ sal_uInt32 outputLength;
+
+ vector<sal_uInt8> iv;
+ Encrypt aEncryptor(mKey, iv, Crypto::AES_128_ECB);
+
+ while( (inputLength = aInputStream.readMemory( &inputBuffer[0], inputBuffer.size() )) > 0 )
+ {
+ inputLength = inputLength % 16 == 0 ? inputLength : ((inputLength / 16) * 16) + 16;
+ outputLength = aEncryptor.update(outputBuffer, inputBuffer, inputLength);
+ aOutputStream.writeMemory( &outputBuffer[0], outputLength );
+ }
+ return true;
+}
+
+} // namespace core
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */