summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/oox/core/DocumentCrypt.hxx148
-rw-r--r--include/oox/crypto/AgileEngine.hxx81
-rw-r--r--include/oox/crypto/CryptTools.hxx134
-rw-r--r--include/oox/crypto/CryptoEngine.hxx59
-rw-r--r--include/oox/crypto/DocumentDecryption.hxx72
-rw-r--r--include/oox/crypto/DocumentEncryption.hxx55
-rw-r--r--include/oox/crypto/Standard2007Engine.hxx118
-rw-r--r--oox/Library_oox.mk6
-rw-r--r--oox/source/core/DocumentCrypt.cxx610
-rw-r--r--oox/source/core/filterdetect.cxx25
-rw-r--r--oox/source/core/xmlfilterbase.cxx6
-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
16 files changed, 1780 insertions, 774 deletions
diff --git a/include/oox/core/DocumentCrypt.hxx b/include/oox/core/DocumentCrypt.hxx
deleted file mode 100644
index 9831c190fdcf..000000000000
--- a/include/oox/core/DocumentCrypt.hxx
+++ /dev/null
@@ -1,148 +0,0 @@
-/* -*- 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/.
- *
- * This file incorporates work covered by the following license notice:
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed
- * with this work for additional information regarding copyright
- * ownership. The ASF licenses this file to you under the Apache
- * License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.apache.org/licenses/LICENSE-2.0 .
- */
-
-#ifndef DOCUMENTCRYPTO_HXX
-#define DOCUMENTCRYPTO_HXX
-
-#include "oox/dllapi.h"
-
-#include "oox/ole/olestorage.hxx"
-#include "oox/helper/binaryinputstream.hxx"
-#include "oox/helper/binaryoutputstream.hxx"
-
-#include <com/sun/star/io/XStream.hpp>
-#include <com/sun/star/beans/NamedValue.hpp>
-#include <com/sun/star/uno/Sequence.hxx>
-
-#include <vector>
-
-
-namespace oox {
-namespace core {
-
-const sal_uInt32 ENCRYPTINFO_CRYPTOAPI = 0x00000004;
-const sal_uInt32 ENCRYPTINFO_DOCPROPS = 0x00000008;
-const sal_uInt32 ENCRYPTINFO_EXTERNAL = 0x00000010;
-const sal_uInt32 ENCRYPTINFO_AES = 0x00000020;
-
-const sal_uInt32 ENCRYPT_ALGO_AES128 = 0x0000660E;
-const sal_uInt32 ENCRYPT_ALGO_AES192 = 0x0000660F;
-const sal_uInt32 ENCRYPT_ALGO_AES256 = 0x00006610;
-const sal_uInt32 ENCRYPT_ALGO_RC4 = 0x00006801;
-
-const sal_uInt32 ENCRYPT_HASH_SHA1 = 0x00008004;
-
-const sal_uInt32 ENCRYPT_KEY_SIZE_AES_128 = 0x00000080;
-const sal_uInt32 ENCRYPT_KEY_SIZE_AES_192 = 0x000000C0;
-const sal_uInt32 ENCRYPT_KEY_SIZE_AES_256 = 0x00000100;
-
-const sal_uInt32 ENCRYPT_PROVIDER_TYPE_AES = 0x00000018;
-const sal_uInt32 ENCRYPT_PROVIDER_TYPE_RC4 = 0x00000001;
-
-// version of encryption info used in MS Office 2007 (major = 3, minor = 2)
-const sal_uInt32 VERSION_INFO_2007_FORMAT = 0x00030002;
-
-const sal_Int32 SALT_LENGTH = 16;
-const sal_Int32 ENCRYPTED_VERIFIER_LENGTH = 16;
-const sal_Int32 ENCRYPTED_VERIFIER_HASH_LENGTH = 32;
-
-struct EncryptionStandardHeader
-{
- sal_uInt32 flags;
- sal_uInt32 sizeExtra; // 0
- sal_uInt32 algId; // if flag AES && CRYPTOAPI this defaults to 128-bit AES
- sal_uInt32 algIdHash; // 0: determine by flags - defaults to SHA-1 if not external
- sal_uInt32 keySize; // key size in bits: 0 (determine by flags), 128, 192, 256
- sal_uInt32 providedType; // AES or RC4
- sal_uInt32 reserved1; // 0
- sal_uInt32 reserved2; // 0
-
- EncryptionStandardHeader();
-};
-
-
-struct EncryptionVerifierAES
-{
- sal_uInt32 saltSize; // must be 0x00000010
- sal_uInt8 salt[SALT_LENGTH]; // random generated salt value
- sal_uInt8 encryptedVerifier[ENCRYPTED_VERIFIER_LENGTH]; // randomly generated verifier value
- sal_uInt32 encryptedVerifierHashSize; // actually written hash size - depends on algorithm
- sal_uInt8 encryptedVerifierHash[ENCRYPTED_VERIFIER_HASH_LENGTH]; // verifier value hash - itself also encrypted
-
- EncryptionVerifierAES();
-};
-
-struct PackageEncryptionInfo
-{
- EncryptionStandardHeader header;
- EncryptionVerifierAES verifier;
-};
-
-class OOX_DLLPUBLIC AesEncoder
-{
-private:
- com::sun::star::uno::Reference< com::sun::star::io::XStream > mxDocumentStream;
- oox::ole::OleStorage& mrOleStorage;
- OUString maPassword;
-
- PackageEncryptionInfo mEncryptionInfo;
-
- bool checkEncryptionInfo(std::vector<sal_uInt8>& aKey, sal_uInt32 aKeyLength);
- bool writeEncryptionInfo( BinaryOutputStream& rStream );
-
-public:
- AesEncoder(
- com::sun::star::uno::Reference< com::sun::star::io::XStream > xDocumentStream,
- oox::ole::OleStorage& rOleStorage,
- OUString aPassword);
-
- bool encode();
-
-};
-
-class OOX_DLLPUBLIC AesDecoder
-{
-private:
- oox::ole::OleStorage& mrOleStorage;
- PackageEncryptionInfo mEncryptionInfo;
- std::vector<sal_uInt8> mKey;
- sal_uInt32 mKeyLength;
-
- bool readEncryptionInfoFromStream( BinaryInputStream& rStream );
-
-public:
- AesDecoder(oox::ole::OleStorage& rOleStorage);
-
- bool decode(com::sun::star::uno::Reference< com::sun::star::io::XStream > xDocumentStream);
- bool readEncryptionInfo();
- bool generateEncryptionKey(const OUString& rPassword);
-
- com::sun::star::uno::Sequence< com::sun::star::beans::NamedValue > createEncryptionData();
-
- bool checkCurrentEncryptionData();
-
- static bool checkEncryptionData( const com::sun::star::uno::Sequence< com::sun::star::beans::NamedValue >& rEncryptionData );
-};
-
-} // namespace core
-} // namespace oox
-
-#endif
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/oox/crypto/AgileEngine.hxx b/include/oox/crypto/AgileEngine.hxx
new file mode 100644
index 000000000000..ddd7a3fffb50
--- /dev/null
+++ b/include/oox/crypto/AgileEngine.hxx
@@ -0,0 +1,81 @@
+/* -*- 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/.
+ *
+ */
+
+#ifndef AGILE_ENGINE_HXX
+#define AGILE_ENGINE_HXX
+
+#include "CryptTools.hxx"
+#include "CryptoEngine.hxx"
+
+namespace oox {
+namespace core {
+
+const sal_uInt32 SEGMENT_LENGTH = 4096;
+
+struct AgileEncryptionInfo
+{
+ sal_Int32 spinCount;
+ sal_Int32 saltSize;
+ sal_Int32 keyBits;
+ sal_Int32 hashSize;
+ sal_Int32 blockSize;
+
+ OUString cipherAlgorithm;
+ OUString cipherChaining;
+ OUString hashAlgorithm;
+
+ std::vector<sal_uInt8> keyDataSalt;
+ std::vector<sal_uInt8> saltValue;
+ std::vector<sal_uInt8> encryptedVerifierHashInput;
+ std::vector<sal_uInt8> encryptedVerifierHashValue;
+ std::vector<sal_uInt8> encryptedKeyValue;
+};
+
+class AgileEngine : public CryptoEngine
+{
+ AgileEncryptionInfo mInfo;
+
+ bool calculateHashFinal(const OUString& rPassword, std::vector<sal_uInt8>& aHashFinal);
+
+ bool calculateBlock(
+ const std::vector<sal_uInt8>& rBlock,
+ std::vector<sal_uInt8>& rHashFinal,
+ std::vector<sal_uInt8>& rInput,
+ std::vector<sal_uInt8>& rOutput);
+
+ Crypto::CryptoType cryptoType(const AgileEncryptionInfo& rInfo);
+
+public:
+ AgileEngine();
+ virtual ~AgileEngine();
+
+ AgileEncryptionInfo& getInfo();
+
+ virtual bool writeEncryptionInfo(
+ const OUString& rPassword,
+ BinaryXOutputStream& rStream);
+
+ virtual bool generateEncryptionKey(const OUString& rPassword);
+
+ virtual bool decrypt(
+ BinaryXInputStream& aInputStream,
+ BinaryXOutputStream& aOutputStream);
+
+ virtual bool encrypt(
+ BinaryXInputStream& aInputStream,
+ BinaryXOutputStream& aOutputStream);
+};
+
+} // namespace core
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/oox/crypto/CryptTools.hxx b/include/oox/crypto/CryptTools.hxx
new file mode 100644
index 000000000000..3c9bf0ba0426
--- /dev/null
+++ b/include/oox/crypto/CryptTools.hxx
@@ -0,0 +1,134 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifndef CRYPT_TOOLS_HXX
+#define CRYPT_TOOLS_HXX
+
+#include <config_oox.h>
+
+#include <rtl/ustring.hxx>
+
+#if USE_TLS_OPENSSL
+#include <openssl/evp.h>
+#include <openssl/sha.h>
+#endif // USE_TLS_OPENSSL
+#if USE_TLS_NSS
+#include <nss.h>
+#include <pk11pub.h>
+#endif // USE_TLS_NSS
+
+#include <rtl/digest.h>
+#include <vector>
+
+namespace oox {
+namespace core {
+
+class Crypto
+{
+public:
+ enum CryptoType
+ {
+ UNKNOWN,
+ AES_128_ECB,
+ AES_128_CBC,
+ AES_256_CBC,
+ };
+
+protected:
+#if USE_TLS_OPENSSL
+ EVP_CIPHER_CTX mContext;
+#endif
+#if USE_TLS_NSS
+ PK11Context* mContext;
+ SECItem* mSecParam;
+ PK11SymKey* mSymKey;
+#endif
+ CryptoType mType;
+
+#if USE_TLS_OPENSSL
+ const EVP_CIPHER* getCipher(CryptoType type);
+#endif
+#if USE_TLS_NSS
+ void setupContext(
+ std::vector<sal_uInt8>& key,
+ std::vector<sal_uInt8>& iv,
+ CryptoType type,
+ CK_ATTRIBUTE_TYPE operation);
+#endif
+
+public:
+ Crypto(CryptoType type);
+
+ virtual ~Crypto();
+
+ virtual sal_uInt32 update(
+ std::vector<sal_uInt8>& output,
+ std::vector<sal_uInt8>& input,
+ sal_uInt32 inputLength = 0) = 0;
+};
+
+class Decrypt : public Crypto
+{
+public:
+ Decrypt(std::vector<sal_uInt8>& key, CryptoType type);
+ Decrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, CryptoType type);
+
+ virtual sal_uInt32 update(
+ std::vector<sal_uInt8>& output,
+ std::vector<sal_uInt8>& input,
+ sal_uInt32 inputLength = 0);
+
+
+ static sal_uInt32 aes128ecb(
+ std::vector<sal_uInt8>& output,
+ std::vector<sal_uInt8>& input,
+ std::vector<sal_uInt8>& key );
+
+ static sal_uInt32 aes128cbc(
+ std::vector<sal_uInt8>& output,
+ std::vector<sal_uInt8>& input,
+ std::vector<sal_uInt8>& key,
+ std::vector<sal_uInt8>& iv );
+};
+
+class Encrypt : public Crypto
+{
+public:
+ Encrypt(std::vector<sal_uInt8>& key, CryptoType type);
+ Encrypt(std::vector<sal_uInt8>& key, std::vector<sal_uInt8>& iv, CryptoType type);
+
+ virtual sal_uInt32 update(
+ std::vector<sal_uInt8>& output,
+ std::vector<sal_uInt8>& input,
+ sal_uInt32 inputLength = 0);
+};
+
+const sal_uInt32 SHA1_LENGTH = 20;
+const sal_uInt32 SHA512_LENGTH = 64;
+
+bool sha1( std::vector<sal_uInt8>& output, std::vector<sal_uInt8>& input );
+
+bool sha512( std::vector<sal_uInt8>& output, std::vector<sal_uInt8>& input );
+
+} // namespace core
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/oox/crypto/CryptoEngine.hxx b/include/oox/crypto/CryptoEngine.hxx
new file mode 100644
index 000000000000..68bb0a8fa3f1
--- /dev/null
+++ b/include/oox/crypto/CryptoEngine.hxx
@@ -0,0 +1,59 @@
+/* -*- 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/.
+ *
+ */
+
+#ifndef CRYPTO_ENGINE_HXX
+#define CRYPTO_ENGINE_HXX
+
+#include <vector>
+
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/helper/binaryoutputstream.hxx"
+
+namespace oox {
+namespace core {
+
+class CryptoEngine
+{
+protected:
+ std::vector<sal_uInt8> mKey;
+
+public:
+ CryptoEngine()
+ {}
+
+ virtual ~CryptoEngine()
+ {}
+
+ virtual std::vector<sal_uInt8>& getKey()
+ {
+ return mKey;
+ }
+
+ virtual bool writeEncryptionInfo(
+ const OUString& rPassword,
+ BinaryXOutputStream& rStream) = 0;
+
+ virtual bool generateEncryptionKey(const OUString& rPassword) = 0;
+
+ virtual bool decrypt(
+ BinaryXInputStream& aInputStream,
+ BinaryXOutputStream& aOutputStream) = 0;
+
+ virtual bool encrypt(
+ BinaryXInputStream& aInputStream,
+ BinaryXOutputStream& aOutputStream) = 0;
+};
+
+} // namespace core
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/oox/crypto/DocumentDecryption.hxx b/include/oox/crypto/DocumentDecryption.hxx
new file mode 100644
index 000000000000..768cdbf6b275
--- /dev/null
+++ b/include/oox/crypto/DocumentDecryption.hxx
@@ -0,0 +1,72 @@
+/* -*- 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/.
+ *
+ */
+
+#ifndef DOCUMENT_DECRYPTION_HXX
+#define DOCUMENT_DECRYPTION_HXX
+
+#include "oox/dllapi.h"
+
+#include "oox/ole/olestorage.hxx"
+#include "oox/helper/binaryinputstream.hxx"
+#include "oox/helper/binaryoutputstream.hxx"
+
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "CryptTools.hxx"
+#include "AgileEngine.hxx"
+#include "Standard2007Engine.hxx"
+
+#include <boost/scoped_ptr.hpp>
+#include <vector>
+
+namespace oox {
+namespace core {
+
+class OOX_DLLPUBLIC DocumentDecryption
+{
+private:
+ com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > mxContext;
+
+ enum CryptoType
+ {
+ UNKNOWN,
+ STANDARD_2007,
+ AGILE
+ };
+
+ oox::ole::OleStorage& mrOleStorage;
+ boost::scoped_ptr<CryptoEngine> mEngine;
+ CryptoType mCryptoType;
+
+ bool readAgileEncryptionInfo( com::sun::star::uno::Reference< com::sun::star::io::XInputStream >& rStream );
+ bool readStandard2007EncryptionInfo( BinaryInputStream& rStream );
+
+public:
+ DocumentDecryption(
+ oox::ole::OleStorage& rOleStorage,
+ com::sun::star::uno::Reference< com::sun::star::uno::XComponentContext > xContext);
+
+ bool decrypt(com::sun::star::uno::Reference< com::sun::star::io::XStream > xDocumentStream);
+ bool readEncryptionInfo();
+ bool generateEncryptionKey(const OUString& rPassword);
+
+ com::sun::star::uno::Sequence< com::sun::star::beans::NamedValue > createEncryptionData();
+
+ static bool checkEncryptionData( const com::sun::star::uno::Sequence< com::sun::star::beans::NamedValue >& rEncryptionData );
+};
+
+} // namespace core
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/oox/crypto/DocumentEncryption.hxx b/include/oox/crypto/DocumentEncryption.hxx
new file mode 100644
index 000000000000..b4e142ea2ade
--- /dev/null
+++ b/include/oox/crypto/DocumentEncryption.hxx
@@ -0,0 +1,55 @@
+/* -*- 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/.
+ *
+ */
+
+#ifndef DOCUMENT_ENCRYPTION_HXX
+#define DOCUMENT_ENCRYPTION_HXX
+
+#include "oox/dllapi.h"
+
+#include "oox/ole/olestorage.hxx"
+
+#include <com/sun/star/io/XStream.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include "CryptTools.hxx"
+#include "Standard2007Engine.hxx"
+
+#include <vector>
+
+
+namespace oox {
+namespace core {
+
+class OOX_DLLPUBLIC DocumentEncryption
+{
+private:
+ com::sun::star::uno::Reference< com::sun::star::io::XStream > mxDocumentStream;
+ oox::ole::OleStorage& mrOleStorage;
+ OUString maPassword;
+
+ Standard2007Engine mEngine;
+
+public:
+ DocumentEncryption(
+ com::sun::star::uno::Reference< com::sun::star::io::XStream > xDocumentStream,
+ oox::ole::OleStorage& rOleStorage,
+ OUString aPassword);
+
+ bool encrypt();
+
+};
+
+} // namespace core
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/oox/crypto/Standard2007Engine.hxx b/include/oox/crypto/Standard2007Engine.hxx
new file mode 100644
index 000000000000..c53ec22cd124
--- /dev/null
+++ b/include/oox/crypto/Standard2007Engine.hxx
@@ -0,0 +1,118 @@
+/* -*- 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/.
+ *
+ */
+
+#ifndef STANDARD_2007_ENGINE_HXX
+#define STANDARD_2007_ENGINE_HXX
+
+#include "CryptTools.hxx"
+#include "CryptoEngine.hxx"
+
+namespace oox {
+namespace core {
+
+const sal_uInt32 ENCRYPTINFO_CRYPTOAPI = 0x00000004;
+const sal_uInt32 ENCRYPTINFO_DOCPROPS = 0x00000008;
+const sal_uInt32 ENCRYPTINFO_EXTERNAL = 0x00000010;
+const sal_uInt32 ENCRYPTINFO_AES = 0x00000020;
+
+const sal_uInt32 ENCRYPT_ALGO_AES128 = 0x0000660E;
+const sal_uInt32 ENCRYPT_ALGO_AES192 = 0x0000660F;
+const sal_uInt32 ENCRYPT_ALGO_AES256 = 0x00006610;
+const sal_uInt32 ENCRYPT_ALGO_RC4 = 0x00006801;
+
+const sal_uInt32 ENCRYPT_HASH_SHA1 = 0x00008004;
+
+const sal_uInt32 ENCRYPT_KEY_SIZE_AES_128 = 0x00000080;
+const sal_uInt32 ENCRYPT_KEY_SIZE_AES_192 = 0x000000C0;
+const sal_uInt32 ENCRYPT_KEY_SIZE_AES_256 = 0x00000100;
+
+const sal_uInt32 ENCRYPT_PROVIDER_TYPE_AES = 0x00000018;
+const sal_uInt32 ENCRYPT_PROVIDER_TYPE_RC4 = 0x00000001;
+
+// version of encryption info used in MS Office 2007 (major = 3, minor = 2)
+const sal_uInt32 VERSION_INFO_2007_FORMAT = 0x00020003;
+// version of encryption info - agile (major = 4, minor = 4)
+const sal_uInt32 VERSION_INFO_AGILE = 0x00040004;
+
+const sal_uInt32 SALT_LENGTH = 16;
+const sal_uInt32 ENCRYPTED_VERIFIER_LENGTH = 16;
+const sal_uInt32 ENCRYPTED_VERIFIER_HASH_LENGTH = 32;
+
+struct EncryptionStandardHeader
+{
+ sal_uInt32 flags;
+ sal_uInt32 sizeExtra; // 0
+ sal_uInt32 algId; // if flag AES && CRYPTOAPI this defaults to 128-bit AES
+ sal_uInt32 algIdHash; // 0: determine by flags - defaults to SHA-1 if not external
+ sal_uInt32 keyBits; // key size in bits: 0 (determine by flags), 128, 192, 256
+ sal_uInt32 providedType; // AES or RC4
+ sal_uInt32 reserved1; // 0
+ sal_uInt32 reserved2; // 0
+
+ EncryptionStandardHeader();
+};
+
+struct EncryptionVerifierAES
+{
+ sal_uInt32 saltSize; // must be 0x00000010
+ sal_uInt8 salt[SALT_LENGTH]; // random generated salt value
+ sal_uInt8 encryptedVerifier[ENCRYPTED_VERIFIER_LENGTH]; // randomly generated verifier value
+ sal_uInt32 encryptedVerifierHashSize; // actually written hash size - depends on algorithm
+ sal_uInt8 encryptedVerifierHash[ENCRYPTED_VERIFIER_HASH_LENGTH]; // verifier value hash - itself also encrypted
+
+ EncryptionVerifierAES();
+};
+
+struct StandardEncryptionInfo
+{
+ EncryptionStandardHeader header;
+ EncryptionVerifierAES verifier;
+};
+
+class Standard2007Engine : public CryptoEngine
+{
+ StandardEncryptionInfo mInfo;
+
+ bool generateVerifier();
+ bool calculateEncryptionKey(const OUString& rPassword);
+
+public:
+ Standard2007Engine();
+ virtual ~Standard2007Engine();
+
+ StandardEncryptionInfo& getInfo();
+
+ static bool checkEncryptionData(
+ std::vector<sal_uInt8> key, sal_uInt32 keySize,
+ std::vector<sal_uInt8> encryptedVerifier, sal_uInt32 verifierSize,
+ std::vector<sal_uInt8> encryptedHash, sal_uInt32 hashSize );
+
+ virtual bool generateEncryptionKey(const OUString& rPassword);
+
+ virtual bool writeEncryptionInfo(
+ const OUString& rPassword,
+ BinaryXOutputStream& rStream);
+
+ virtual bool decrypt(
+ BinaryXInputStream& aInputStream,
+ BinaryXOutputStream& aOutputStream);
+
+ virtual bool encrypt(
+ BinaryXInputStream& aInputStream,
+ BinaryXOutputStream& aOutputStream);
+
+};
+
+} // namespace core
+} // namespace oox
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/Library_oox.mk b/oox/Library_oox.mk
index f8477369319b..a20b548c2e48 100644
--- a/oox/Library_oox.mk
+++ b/oox/Library_oox.mk
@@ -78,7 +78,6 @@ $(eval $(call gb_Library_add_exception_objects,oox,\
oox/source/core/binarycodec \
oox/source/core/contexthandler2 \
oox/source/core/contexthandler \
- oox/source/core/DocumentCrypt \
oox/source/core/fastparser \
oox/source/core/fasttokenhandler \
oox/source/core/filterbase \
@@ -90,6 +89,11 @@ $(eval $(call gb_Library_add_exception_objects,oox,\
oox/source/core/relationshandler \
oox/source/core/services \
oox/source/core/xmlfilterbase \
+ oox/source/crypto/AgileEngine \
+ oox/source/crypto/CryptTools \
+ oox/source/crypto/DocumentEncryption \
+ oox/source/crypto/DocumentDecryption \
+ oox/source/crypto/Standard2007Engine \
oox/source/docprop/docprophandler \
oox/source/docprop/ooxmldocpropimport \
oox/source/drawingml/chart/axiscontext \
diff --git a/oox/source/core/DocumentCrypt.cxx b/oox/source/core/DocumentCrypt.cxx
deleted file mode 100644
index ac0b255b1703..000000000000
--- a/oox/source/core/DocumentCrypt.cxx
+++ /dev/null
@@ -1,610 +0,0 @@
-/* -*- 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/core/DocumentCrypt.hxx"
-#include <config_oox.h>
-
-#if USE_TLS_OPENSSL
-#include <openssl/evp.h>
-#endif // USE_TLS_OPENSSL
-#if USE_TLS_NSS
-#include <nss.h>
-#include <pk11pub.h>
-#endif // USE_TLS_NSS
-#include <rtl/digest.h>
-
-#include <comphelper/docpasswordhelper.hxx>
-#include <comphelper/mediadescriptor.hxx>
-
-#include <osl/time.h>
-#include <rtl/random.h>
-
-#include <com/sun/star/io/XSeekable.hpp>
-
-namespace oox {
-namespace core {
-
-using namespace ::com::sun::star::beans;
-using namespace ::com::sun::star::io;
-using namespace ::com::sun::star::lang;
-using namespace ::com::sun::star::uno;
-
-using ::comphelper::MediaDescriptor;
-using ::comphelper::SequenceAsHashMap;
-
-using namespace std;
-
-/* =========================================================================== */
-/* Kudos to Caolan McNamara who provided the core decryption implementations. */
-/* =========================================================================== */
-
-namespace {
-
-void lclRandomGenerateValues( sal_Int32 nLength, sal_uInt8* aArray )
-{
- TimeValue aTime;
- osl_getSystemTime( &aTime );
- rtlRandomPool aRandomPool = rtl_random_createPool ();
- rtl_random_addBytes ( aRandomPool, &aTime, 8 );
- rtl_random_getBytes ( aRandomPool, aArray, nLength );
- rtl_random_destroyPool ( aRandomPool );
-}
-
-void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, vector<sal_uInt8>& rKey, sal_uInt32 aKeyLength )
-{
- // De facto we are always called with nRequiredKeyLen == 16, at least currently
- assert(aKeyLength == 16);
-
- sal_uInt8 pnBuffer[ 64 ];
- memset( pnBuffer, 0x36, sizeof( pnBuffer ) );
- for( sal_uInt32 i = 0; i < nHashLen; ++i )
- pnBuffer[ i ] ^= pnHash[ i ];
-
- rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) );
- sal_uInt8 pnX1[ RTL_DIGEST_LENGTH_SHA1 ];
- rtl_digest_get( aDigest, pnX1, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- memset( pnBuffer, 0x5C, sizeof( pnBuffer ) );
- for( sal_uInt32 i = 0; i < nHashLen; ++i )
- pnBuffer[ i ] ^= pnHash[ i ];
-
- aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnBuffer, sizeof( pnBuffer ) );
- sal_uInt8 pnX2[ RTL_DIGEST_LENGTH_SHA1 ];
- rtl_digest_get( aDigest, pnX2, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
-#if 0 // for now nRequiredKeyLen will always be 16 and thus less than
- // RTL_DIGEST_LENGTH_SHA1==20, see assert above...
- if( aKeyLength > RTL_DIGEST_LENGTH_SHA1 )
- {
- // This memcpy call generates a (bogus?) warning when
- // compiling with gcc 4.7 and 4.8 and optimising: array
- // subscript is above array bounds.
- std::copy(pnX1, pnX1 + aKeyLength - RTL_DIGEST_LENGTH_SHA1, rKey.begin() + RTL_DIGEST_LENGTH_SHA1);
- aKeyLength = RTL_DIGEST_LENGTH_SHA1;
- }
-#endif
- std::copy(pnX1, pnX1 + aKeyLength, rKey.begin());
- //memcpy( pnKeyDerived, pnX1, nRequiredKeyLen );
-}
-
-bool lclGenerateVerifier(PackageEncryptionInfo& rEncryptionInfo, const vector<sal_uInt8>& rKey, sal_uInt32 nKeySize)
-{
- // only support key of size 128 bit (16 byte)
- if (nKeySize != 16)
- return false;
-
- sal_uInt8 aVerifier[ENCRYPTED_VERIFIER_LENGTH];
- sal_Int32 aVerifierSize = sizeof(aVerifier);
- lclRandomGenerateValues(aVerifierSize, aVerifier);
-
-#if USE_TLS_OPENSSL
- {
- EVP_CIPHER_CTX aContext;
- EVP_CIPHER_CTX_init( &aContext );
- EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, &rKey[0], 0 );
- EVP_CIPHER_CTX_set_padding( &aContext, 0 );
- int aWrittenLength = 0;
- EVP_EncryptUpdate( &aContext, rEncryptionInfo.verifier.encryptedVerifier, &aWrittenLength, aVerifier, aVerifierSize );
- if (aWrittenLength != ENCRYPTED_VERIFIER_LENGTH)
- return false;
- EVP_CIPHER_CTX_cleanup( &aContext );
- }
-
-#endif // USE_TLS_OPENSSL
-
- sal_uInt8 pSha1Hash[ENCRYPTED_VERIFIER_HASH_LENGTH];
- memset(pSha1Hash, 0, sizeof(pSha1Hash));
- rEncryptionInfo.verifier.encryptedVerifierHashSize = RTL_DIGEST_LENGTH_SHA1;
-
- rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, aVerifier, aVerifierSize );
- rtl_digest_get( aDigest, pSha1Hash, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
-#if USE_TLS_OPENSSL
- {
- int aWrittenLength = 0;
-
- EVP_CIPHER_CTX aContext;
- EVP_CIPHER_CTX_init( &aContext );
- EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, &rKey[0], 0 );
- EVP_CIPHER_CTX_set_padding( &aContext, 0 );
- EVP_EncryptUpdate( &aContext, rEncryptionInfo.verifier.encryptedVerifierHash, &aWrittenLength, pSha1Hash, sizeof(pSha1Hash) );
- EVP_CIPHER_CTX_cleanup( &aContext );
- }
-#endif // USE_TLS_OPENSSL
-
- return true;
-}
-
-bool lclCheckEncryptionData( const sal_uInt8* pnKey, sal_uInt32 nKeySize, const sal_uInt8* pnVerifier, sal_uInt32 nVerifierSize, const sal_uInt8* pnVerifierHash, sal_uInt32 nVerifierHashSize )
-{
- // the only currently supported algorithm needs key size 128
- if ( nKeySize != 16 || nVerifierSize != 16 )
- return false;
-
- // check password
-#if USE_TLS_OPENSSL
- EVP_CIPHER_CTX aes_ctx;
- EVP_CIPHER_CTX_init( &aes_ctx );
- EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
- EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
- int nOutLen = 0;
- sal_uInt8 pnTmpVerifier[ 16 ];
- (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
-
- /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifier, &nOutLen, pnVerifier, nVerifierSize );
- EVP_CIPHER_CTX_cleanup( &aes_ctx );
-
- EVP_CIPHER_CTX_init( &aes_ctx );
- EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, pnKey, 0 );
- EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
- sal_uInt8* pnTmpVerifierHash = new sal_uInt8[nVerifierHashSize];
- (void) memset( pnTmpVerifierHash, 0, nVerifierHashSize );
-
- /*int*/ EVP_DecryptUpdate( &aes_ctx, pnTmpVerifierHash, &nOutLen, pnVerifierHash, nVerifierHashSize );
- EVP_CIPHER_CTX_cleanup( &aes_ctx );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- PK11SlotInfo *aSlot( PK11_GetBestSlot( CKM_AES_ECB, NULL ) );
- sal_uInt8 *key( new sal_uInt8[ nKeySize ] );
- (void) memcpy( key, pnKey, nKeySize * sizeof(sal_uInt8) );
-
- SECItem keyItem;
- keyItem.type = siBuffer;
- keyItem.data = key;
- keyItem.len = nKeySize;
-
- PK11SymKey *symKey( PK11_ImportSymKey( aSlot, CKM_AES_ECB, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL ) );
- SECItem *secParam( PK11_ParamFromIV( CKM_AES_ECB, NULL ) );
- PK11Context *encContext( PK11_CreateContextBySymKey( CKM_AES_ECB, CKA_DECRYPT, symKey, secParam ) );
-
- int nOutLen(0);
- sal_uInt8 pnTmpVerifier[ 16 ];
- (void) memset( pnTmpVerifier, 0, sizeof(pnTmpVerifier) );
-
- PK11_CipherOp( encContext, pnTmpVerifier, &nOutLen, sizeof(pnTmpVerifier), const_cast<sal_uInt8*>(pnVerifier), nVerifierSize );
-
- sal_uInt8* pnTmpVerifierHash = new sal_uInt8[nVerifierHashSize];
- (void) memset( pnTmpVerifierHash, 0, nVerifierHashSize );
- PK11_CipherOp( encContext, pnTmpVerifierHash, &nOutLen, nVerifierHashSize, const_cast<sal_uInt8*>(pnVerifierHash), nVerifierHashSize );
-
- PK11_DestroyContext( encContext, PR_TRUE );
- PK11_FreeSymKey( symKey );
- SECITEM_FreeItem( secParam, PR_TRUE );
- delete[] key;
-#endif // USE_TLS_NSS
-
- rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnTmpVerifier, sizeof( pnTmpVerifier ) );
- sal_uInt8 pnSha1Hash[ RTL_DIGEST_LENGTH_SHA1 ];
- rtl_digest_get( aDigest, pnSha1Hash, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- return memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0;
-}
-
-bool lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncryptionInfo, const OUString& rPassword, vector<sal_uInt8>& aKey, sal_uInt32 aKeyLength )
-{
- size_t nBufferSize = rEncryptionInfo.verifier.saltSize + 2 * rPassword.getLength();
- sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ];
- memcpy( pnBuffer, rEncryptionInfo.verifier.salt, rEncryptionInfo.verifier.saltSize );
-
- sal_uInt8* pnPasswordLoc = pnBuffer + rEncryptionInfo.verifier.saltSize;
- const sal_Unicode* pStr = rPassword.getStr();
- for( sal_Int32 i = 0, nLen = rPassword.getLength(); i < nLen; ++i, ++pStr, pnPasswordLoc += 2 )
- ByteOrderConverter::writeLittleEndian( pnPasswordLoc, static_cast< sal_uInt16 >( *pStr ) );
-
- rtlDigest aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnBuffer, nBufferSize );
- delete[] pnBuffer;
-
- size_t nHashSize = RTL_DIGEST_LENGTH_SHA1 + 4;
- sal_uInt8* pnHash = new sal_uInt8[ nHashSize ];
- rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- for( sal_uInt32 i = 0; i < 50000; ++i )
- {
- ByteOrderConverter::writeLittleEndian( pnHash, i );
- aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnHash, nHashSize );
- rtl_digest_get( aDigest, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
- }
-
- memmove( pnHash, pnHash + 4, RTL_DIGEST_LENGTH_SHA1 );
- memset( pnHash + RTL_DIGEST_LENGTH_SHA1, 0, 4 );
- aDigest = rtl_digest_create( rtl_Digest_AlgorithmSHA1 );
- rtl_digest_update( aDigest, pnHash, nHashSize );
- rtl_digest_get( aDigest, pnHash, RTL_DIGEST_LENGTH_SHA1 );
- rtl_digest_destroy( aDigest );
-
- lclDeriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, aKey, aKeyLength );
- delete[] pnHash;
- return true;
-}
-
-} // namespace
-
-EncryptionStandardHeader::EncryptionStandardHeader()
-{
- flags = 0;
- sizeExtra = 0;
- algId = 0;
- algIdHash = 0;
- keySize = 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));
-}
-
-AesEncoder::AesEncoder(Reference< XStream > xDocumentStream, oox::ole::OleStorage& rOleStorage, OUString aPassword) :
- mxDocumentStream(xDocumentStream),
- mrOleStorage(rOleStorage),
- maPassword(aPassword)
-{
-}
-
-bool AesEncoder::checkEncryptionInfo(vector<sal_uInt8>& aKey, sal_uInt32 aKeyLength)
-{
- return lclCheckEncryptionData(
- &aKey[0], aKeyLength,
- mEncryptionInfo.verifier.encryptedVerifier, sizeof(mEncryptionInfo.verifier.encryptedVerifier),
- mEncryptionInfo.verifier.encryptedVerifierHash, ENCRYPTED_VERIFIER_HASH_LENGTH);
-}
-
-bool AesEncoder::writeEncryptionInfo( BinaryOutputStream& rStream )
-{
- rStream.writeValue(VERSION_INFO_2007_FORMAT);
-
- const OUString cspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
- sal_Int32 cspNameSize = (cspName.getLength() * 2) + 2;
-
- sal_Int32 encryptionHeaderSize = static_cast<sal_Int32>(sizeof(EncryptionStandardHeader));
-
- rStream << mEncryptionInfo.header.flags;
- sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
- rStream << headerSize;
-
- rStream.writeMemory(&mEncryptionInfo.header, encryptionHeaderSize);
- rStream.writeUnicodeArray(cspName);
- rStream.writeValue<sal_uInt16>(0);
-
- sal_Int32 encryptionVerifierSize = static_cast<sal_Int32>(sizeof(EncryptionVerifierAES));
- rStream.writeMemory(&mEncryptionInfo.verifier, encryptionVerifierSize);
-
- return true;
-}
-
-bool AesEncoder::encode()
-{
- 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 );
-
- mEncryptionInfo.header.flags = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
- mEncryptionInfo.header.algId = ENCRYPT_ALGO_AES128;
- mEncryptionInfo.header.algIdHash = ENCRYPT_HASH_SHA1;
- mEncryptionInfo.header.keySize = ENCRYPT_KEY_SIZE_AES_128;
- mEncryptionInfo.header.providedType = ENCRYPT_PROVIDER_TYPE_AES;
-
- lclRandomGenerateValues( mEncryptionInfo.verifier.saltSize, mEncryptionInfo.verifier.salt );
-
- const sal_Int32 keyLength = mEncryptionInfo.header.keySize / 8;
- vector<sal_uInt8> aKey;
- aKey.resize(keyLength, 0);
-
- assert(keyLength == 16);
-
- lclGenerateEncryptionKey(mEncryptionInfo, maPassword, aKey, keyLength);
-
- sal_uInt8 key[16];
- std::copy(aKey.begin(), aKey.end(), key);
-
- lclGenerateVerifier(mEncryptionInfo, aKey, keyLength);
-
- if (!checkEncryptionInfo(aKey, keyLength))
- return false;
-
- BinaryXOutputStream aEncryptionInfoBinaryOutputStream( xEncryptionInfo, false );
- 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();
-
-#if USE_TLS_OPENSSL
- EVP_CIPHER_CTX aContext;
- EVP_CIPHER_CTX_init( &aContext );
- EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, key, 0 );
- EVP_CIPHER_CTX_set_padding( &aContext, 0 );
-
- sal_uInt8 inBuffer[ 1024 ];
- sal_uInt8 outBuffer[ 1024 ];
-
- sal_Int32 inLength;
- int outLength;
-
- aEncryptedPackageStream.writeValue<sal_uInt32>( aLength ); // size
- aEncryptedPackageStream.writeValue<sal_uInt32>( 0 ); // size
-
- do
- {
- inLength = aDocumentInputStream.readMemory( inBuffer, sizeof( inBuffer ) );
- if (inLength > 0)
- {
- inLength = inLength % 16 == 0 ? inLength : ((inLength/16)*16)+16;
- EVP_EncryptUpdate( &aContext, outBuffer, &outLength, inBuffer, inLength );
- aEncryptedPackageStream.writeMemory( outBuffer, outLength );
- }
- }
- while (inLength > 0);
-
- EVP_CIPHER_CTX_cleanup( &aContext );
-
-#endif // USE_TLS_OPENSSL
-
- aEncryptedPackageStream.seekToStart();
- aEncryptedPackageStream.close();
-
- aDocumentInputStream.seekToStart();
- aDocumentInputStream.close();
-
- xEncryptedPackage->flush();
- xEncryptedPackage->closeOutput();
-
- return true;
-}
-
-bool AesDecoder::checkCurrentEncryptionData()
-{
- return lclCheckEncryptionData(
- &mKey[0], mKeyLength,
- mEncryptionInfo.verifier.encryptedVerifier, ENCRYPTED_VERIFIER_LENGTH,
- mEncryptionInfo.verifier.encryptedVerifierHash, ENCRYPTED_VERIFIER_HASH_LENGTH );
-}
-
-bool AesDecoder::checkEncryptionData(const Sequence<NamedValue>& rEncryptionData)
-{
- SequenceAsHashMap aHashData( rEncryptionData );
- Sequence<sal_Int8> aKey = aHashData.getUnpackedValueOrDefault( "AES128EncryptionKey", Sequence<sal_Int8>() );
- Sequence<sal_Int8> aVerifier = aHashData.getUnpackedValueOrDefault( "AES128EncryptionVerifier", Sequence<sal_Int8>() );
- Sequence<sal_Int8> aVerifierHash = aHashData.getUnpackedValueOrDefault( "AES128EncryptionVerifierHash", Sequence<sal_Int8>() );
-
- return lclCheckEncryptionData(
- reinterpret_cast<const sal_uInt8*>( aKey.getConstArray() ), aKey.getLength(),
- reinterpret_cast<const sal_uInt8*>( aVerifier.getConstArray() ), aVerifier.getLength(),
- reinterpret_cast<const sal_uInt8*>( aVerifierHash.getConstArray() ), aVerifierHash.getLength() );
-}
-
-bool AesDecoder::generateEncryptionKey(const OUString& rPassword)
-{
- return lclGenerateEncryptionKey(mEncryptionInfo, rPassword, mKey, mKeyLength);
-}
-
-AesDecoder::AesDecoder(oox::ole::OleStorage& rOleStorage) :
- mrOleStorage(rOleStorage),
- mKeyLength(0)
-{
-#if USE_TLS_NSS
- // Initialize NSS, database functions are not needed
- NSS_NoDB_Init( NULL );
-#endif // USE_TLS_NSS
-}
-
-bool AesDecoder::readEncryptionInfoFromStream( BinaryInputStream& rStream )
-{
- sal_uInt32 aVersion;
- rStream >> aVersion;
-
- if (aVersion != VERSION_INFO_2007_FORMAT)
- return false;
-
- rStream >> mEncryptionInfo.header.flags;
- if( getFlag( mEncryptionInfo.header.flags, ENCRYPTINFO_EXTERNAL ) )
- return false;
-
- sal_uInt32 nHeaderSize;
- rStream >> nHeaderSize;
-
- sal_uInt32 actualHeaderSize = sizeof(mEncryptionInfo.header);
-
- if( (nHeaderSize < actualHeaderSize) )
- return false;
-
- rStream >> mEncryptionInfo.header;
- rStream.skip( nHeaderSize - actualHeaderSize );
- rStream >> mEncryptionInfo.verifier;
-
- if( mEncryptionInfo.verifier.saltSize != 16 )
- return false;
- return !rStream.isEof();
-}
-
-bool AesDecoder::readEncryptionInfo()
-{
- if( !mrOleStorage.isStorage() )
- return false;
-
- Reference< XInputStream > xEncryptionInfo( mrOleStorage.openInputStream( "EncryptionInfo" ), UNO_SET_THROW );
-
- // read the encryption info stream
- BinaryXInputStream aInputStream( xEncryptionInfo, true );
- bool bValidInfo = readEncryptionInfoFromStream( aInputStream );
-
- if (!bValidInfo)
- return false;
-
- // check flags and algorithm IDs, required are AES128 and SHA-1
- bool bImplemented =
- getFlag( mEncryptionInfo.header.flags , ENCRYPTINFO_CRYPTOAPI ) &&
- getFlag( mEncryptionInfo.header.flags, ENCRYPTINFO_AES ) &&
- // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set
- ((mEncryptionInfo.header.algId == 0) || (mEncryptionInfo.header.algId == ENCRYPT_ALGO_AES128)) &&
- // hash algorithm ID 0 defaults to SHA-1 too
- ((mEncryptionInfo.header.algIdHash == 0) || (mEncryptionInfo.header.algIdHash == ENCRYPT_HASH_SHA1)) &&
- (mEncryptionInfo.verifier.encryptedVerifierHashSize == 20);
-
- mKeyLength = (mEncryptionInfo.header.keySize / 8);
- mKey.clear();
- mKey.resize(mKeyLength, 0);
-
- return bImplemented;
-}
-
-Sequence<NamedValue> AesDecoder::createEncryptionData()
-{
- Sequence<NamedValue> aResult;
-
- if (mKeyLength > 0)
- {
- SequenceAsHashMap aEncryptionData;
- EncryptionVerifierAES& verifier = mEncryptionInfo.verifier;
- aEncryptionData["AES128EncryptionKey"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( &mKey[0] ), mKeyLength );
- aEncryptionData["AES128EncryptionSalt"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( verifier.salt ), verifier.saltSize );
- aEncryptionData["AES128EncryptionVerifier"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( verifier.encryptedVerifier ), sizeof( verifier.encryptedVerifier ) );
- aEncryptionData["AES128EncryptionVerifierHash"] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( verifier.encryptedVerifierHash ), sizeof( verifier.encryptedVerifierHash ) );
- aResult = aEncryptionData.getAsConstNamedValueList();
- }
-
- return aResult;
-}
-
-bool AesDecoder::decode( com::sun::star::uno::Reference< com::sun::star::io::XStream > xDocumentStream )
-{
- 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 );
-
-#if USE_TLS_OPENSSL
- EVP_CIPHER_CTX aes_ctx;
- EVP_CIPHER_CTX_init( &aes_ctx );
- EVP_DecryptInit_ex( &aes_ctx, EVP_aes_128_ecb(), 0, &mKey.front(), 0 );
- EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- PK11SlotInfo* aSlot( PK11_GetBestSlot( CKM_AES_ECB, NULL ) );
- sal_uInt8* key = new sal_uInt8[ mKeyLength ];
- std::copy(mKey.begin(), mKey.end(), key);
-
- SECItem keyItem;
- keyItem.type = siBuffer;
- keyItem.data = key;
- keyItem.len = mKeyLength;
-
- PK11SymKey* symKey( PK11_ImportSymKey( aSlot, CKM_AES_ECB, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, NULL ) );
- SECItem* secParam( PK11_ParamFromIV( CKM_AES_ECB, NULL ) );
- PK11Context* encContext( PK11_CreateContextBySymKey( CKM_AES_ECB, CKA_DECRYPT, symKey, secParam ) );
-#endif // USE_TLS_NSS
-
- sal_uInt8 pnInBuffer[ 1024 ];
- sal_uInt8 pnOutBuffer[ 1024 ];
- sal_Int32 nInLen;
- int nOutLen;
- aEncryptedPackage.skip( 8 ); // decrypted size
- while( (nInLen = aEncryptedPackage.readMemory( pnInBuffer, sizeof( pnInBuffer ) )) > 0 )
- {
-#if USE_TLS_OPENSSL
- EVP_DecryptUpdate( &aes_ctx, pnOutBuffer, &nOutLen, pnInBuffer, nInLen );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- PK11_CipherOp( encContext, pnOutBuffer, &nOutLen, sizeof(pnOutBuffer), pnInBuffer, nInLen );
-#endif // USE_TLS_NSS
- aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
- }
-#if USE_TLS_OPENSSL
- EVP_DecryptFinal_ex( &aes_ctx, pnOutBuffer, &nOutLen );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- uint finalLength;
- PK11_DigestFinal( encContext, pnOutBuffer, &finalLength, nInLen - nOutLen );
- nOutLen = finalLength;
-#endif // USE_TLS_NSS
- aDecryptedPackage.writeMemory( pnOutBuffer, nOutLen );
-
-#if USE_TLS_OPENSSL
- EVP_CIPHER_CTX_cleanup( &aes_ctx );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
- PK11_DestroyContext( encContext, PR_TRUE );
- PK11_FreeSymKey( symKey );
- SECITEM_FreeItem( secParam, PR_TRUE );
- delete[] key;
-#endif // USE_TLS_NSS
- xDecryptedPackage->flush();
- aDecryptedPackage.seekToStart();
-
- return true;
-}
-
-} // namespace core
-} // namespace oox
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx
index 232864211bbe..7dd3f9210003 100644
--- a/oox/source/core/filterdetect.cxx
+++ b/oox/source/core/filterdetect.cxx
@@ -24,12 +24,13 @@
#include <comphelper/docpasswordhelper.hxx>
#include <comphelper/mediadescriptor.hxx>
-#include "oox/core/DocumentCrypt.hxx"
#include "oox/core/fastparser.hxx"
#include "oox/helper/attributelist.hxx"
#include "oox/helper/zipstorage.hxx"
#include "oox/ole/olestorage.hxx"
+#include "oox/crypto/DocumentDecryption.hxx"
+
#include <com/sun/star/uri/UriReferenceFactory.hpp>
namespace oox {
@@ -270,23 +271,23 @@ bool lclIsZipPackage( const Reference< XComponentContext >& rxContext, const Ref
class PasswordVerifier : public IDocPasswordVerifier
{
public:
- explicit PasswordVerifier( AesDecoder& decoder );
+ explicit PasswordVerifier( DocumentDecryption& aDecryptor );
virtual DocPasswordVerifierResult verifyPassword( const OUString& rPassword, Sequence<NamedValue>& rEncryptionData );
virtual DocPasswordVerifierResult verifyEncryptionData( const Sequence<NamedValue>& rEncryptionData );
private:
- AesDecoder& mDecoder;
+ DocumentDecryption& mDecryptor;
};
-PasswordVerifier::PasswordVerifier( AesDecoder& decoder ) :
- mDecoder(decoder)
+PasswordVerifier::PasswordVerifier( DocumentDecryption& aDecryptor ) :
+ mDecryptor(aDecryptor)
{}
comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword, Sequence<NamedValue>& rEncryptionData )
{
- if( mDecoder.generateEncryptionKey(rPassword) && mDecoder.checkCurrentEncryptionData() )
- rEncryptionData = mDecoder.createEncryptionData();
+ if( mDecryptor.generateEncryptionKey(rPassword) )
+ rEncryptionData = mDecryptor.createEncryptionData();
return rEncryptionData.hasElements() ? comphelper::DocPasswordVerifierResult_OK : comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
}
@@ -294,7 +295,7 @@ comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OU
comphelper::DocPasswordVerifierResult PasswordVerifier::verifyEncryptionData( const Sequence<NamedValue>& rEncryptionData )
{
comphelper::DocPasswordVerifierResult aResult = comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
- if (AesDecoder::checkEncryptionData(rEncryptionData))
+ if (DocumentDecryption::checkEncryptionData(rEncryptionData))
aResult = comphelper::DocPasswordVerifierResult_OK;
return aResult;
}
@@ -324,9 +325,9 @@ Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescript
{
try
{
- AesDecoder aDecoder(aOleStorage);
+ DocumentDecryption aDecryptor(aOleStorage, mxContext);
- if( aDecoder.readEncryptionInfo() )
+ if( aDecryptor.readEncryptionInfo() )
{
/* "VelvetSweatshop" is the built-in default encryption
password used by MS Excel for the "workbook protection"
@@ -339,7 +340,7 @@ Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescript
This helper returns either with the correct password
(according to the verifier), or with an empty string if
user has cancelled the password input dialog. */
- PasswordVerifier aVerifier( aDecoder );
+ PasswordVerifier aVerifier( aDecryptor );
Sequence<NamedValue> aEncryptionData;
aEncryptionData = comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
aVerifier, rMediaDescriptor,
@@ -354,7 +355,7 @@ Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescript
{
// create temporary file for unencrypted package
Reference<XStream> xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
- aDecoder.decode( xTempFile );
+ aDecryptor.decrypt( xTempFile );
// store temp file in media descriptor to keep it alive
rMediaDescriptor.setComponentDataEntry( "DecryptedPackage", Any( xTempFile ) );
diff --git a/oox/source/core/xmlfilterbase.cxx b/oox/source/core/xmlfilterbase.cxx
index 0b723a4a3c69..763090ab2b20 100644
--- a/oox/source/core/xmlfilterbase.cxx
+++ b/oox/source/core/xmlfilterbase.cxx
@@ -49,7 +49,7 @@
#include <oox/core/filterdetect.hxx>
#include <comphelper/storagehelper.hxx>
-#include <oox/core/DocumentCrypt.hxx>
+#include <oox/crypto/DocumentEncryption.hxx>
using ::com::sun::star::xml::dom::DocumentBuilder;
using ::com::sun::star::xml::dom::XDocument;
@@ -704,8 +704,8 @@ bool XmlFilterBase::implFinalizeExport( MediaDescriptor& rMediaDescriptor )
Reference< XStream> xDocumentStream (FilterBase::implGetOutputStream(rMediaDescriptor));
oox::ole::OleStorage aOleStorage( getComponentContext(), xDocumentStream, true );
- AesEncoder encoder(getMainDocumentStream(), aOleStorage, aPassword);
- bRet = encoder.encode();
+ DocumentEncryption encryptor(getMainDocumentStream(), aOleStorage, aPassword);
+ bRet = encryptor.encrypt();
if (bRet)
aOleStorage.commit();
}
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: */