[Libreoffice-commits] core.git: include/oox oox/Library_oox.mk oox/source

Tomaž Vajngerl quikee at gmail.com
Sat Aug 24 13:55:36 PDT 2013


 include/oox/core/DocumentCrypt.hxx        |  148 -------
 include/oox/crypto/AgileEngine.hxx        |   81 +++
 include/oox/crypto/CryptTools.hxx         |  134 ++++++
 include/oox/crypto/CryptoEngine.hxx       |   59 ++
 include/oox/crypto/DocumentDecryption.hxx |   72 +++
 include/oox/crypto/DocumentEncryption.hxx |   55 ++
 include/oox/crypto/Standard2007Engine.hxx |  118 +++++
 oox/Library_oox.mk                        |    6 
 oox/source/core/DocumentCrypt.cxx         |  610 ------------------------------
 oox/source/core/filterdetect.cxx          |   25 -
 oox/source/core/xmlfilterbase.cxx         |    6 
 oox/source/crypto/AgileEngine.cxx         |  218 ++++++++++
 oox/source/crypto/CryptTools.cxx          |  255 ++++++++++++
 oox/source/crypto/DocumentDecryption.cxx  |  400 +++++++++++++++++++
 oox/source/crypto/DocumentEncryption.cxx  |   79 +++
 oox/source/crypto/Standard2007Engine.cxx  |  288 ++++++++++++++
 16 files changed, 1780 insertions(+), 774 deletions(-)

New commits:
commit 4323c66840e4c7dcacda0e33d33d7e67fdb08f09
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Sat Aug 24 22:40:54 2013 +0200

    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

diff --git a/include/oox/core/DocumentCrypt.hxx b/include/oox/core/DocumentCrypt.hxx
deleted file mode 100644
index 9831c19..0000000
--- 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 0000000..ddd7a3f
--- /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 0000000..3c9bf0b
--- /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 0000000..68bb0a8
--- /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 0000000..768cdbf
--- /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 0000000..b4e142e
--- /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 0000000..c53ec22
--- /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 f847736..a20b548 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 ac0b255..0000000
--- 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 2328642..7dd3f92 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 0b723a4..763090a 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 0000000..d0bebe9
--- /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 0000000..a2a7573
--- /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 0000000..64281981
--- /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 0000000..e0941cf
--- /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 0000000..3c17bb6
--- /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: */


More information about the Libreoffice-commits mailing list