[Libreoffice-commits] core.git: 2 commits - filter/source include/oox oox/source sfx2/source

Tomaž Vajngerl quikee at gmail.com
Thu Aug 15 08:20:56 PDT 2013


 filter/source/config/fragments/filters/MS_Word_2007_XML.xcu                        |    2 
 filter/source/config/fragments/filters/OOXML_Text.xcu                              |    2 
 filter/source/config/fragments/filters/calc_OOXML.xcu                              |    2 
 filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML.xcu          |    2 
 filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_AutoPlay.xcu |    2 
 filter/source/config/fragments/filters/impress_OOXML.xcu                           |    2 
 filter/source/config/fragments/filters/impress_OOXML_AutoPlay.xcu                  |    2 
 include/oox/core/DocumentCrypt.hxx                                                 |   95 +
 oox/source/core/DocumentCrypt.cxx                                                  |  564 ++++++----
 oox/source/core/filterdetect.cxx                                                   |  515 +--------
 sfx2/source/dialog/filedlghelper.cxx                                               |   18 
 11 files changed, 552 insertions(+), 654 deletions(-)

New commits:
commit 0566ddb1841ac1e8c87db6d766739e6df7e1856d
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Thu Aug 15 17:11:04 2013 +0200

    Move OOXML decryption to DocumentCrypt.
    
    OOXML decryption was implemented in filterdetect. With this the
    decryption was moved to a common place where it shares functions
    and constants with encryption.
    
    Change-Id: Id334daf7c2eb1e18735d6a500132f6bb61bb3ba0

diff --git a/include/oox/core/DocumentCrypt.hxx b/include/oox/core/DocumentCrypt.hxx
index 3010236..9831c19 100644
--- a/include/oox/core/DocumentCrypt.hxx
+++ b/include/oox/core/DocumentCrypt.hxx
@@ -23,11 +23,77 @@
 #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:
@@ -35,6 +101,11 @@ private:
     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,
@@ -42,8 +113,32 @@ public:
         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
diff --git a/oox/source/core/DocumentCrypt.cxx b/oox/source/core/DocumentCrypt.cxx
index 9ec9f8d..ac0b255 100644
--- a/oox/source/core/DocumentCrypt.cxx
+++ b/oox/source/core/DocumentCrypt.cxx
@@ -11,8 +11,6 @@
 #include "oox/core/DocumentCrypt.hxx"
 #include <config_oox.h>
 
-#include <comphelper/docpasswordhelper.hxx>
-#include <comphelper/mediadescriptor.hxx>
 #if USE_TLS_OPENSSL
 #include <openssl/evp.h>
 #endif // USE_TLS_OPENSSL
@@ -21,8 +19,9 @@
 #include <pk11pub.h>
 #endif // USE_TLS_NSS
 #include <rtl/digest.h>
-#include "oox/helper/binaryinputstream.hxx"
-#include "oox/helper/binaryoutputstream.hxx"
+
+#include <comphelper/docpasswordhelper.hxx>
+#include <comphelper/mediadescriptor.hxx>
 
 #include <osl/time.h>
 #include <rtl/random.h>
@@ -40,44 +39,14 @@ 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 {
 
-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;
-
-struct PackageEncryptionInfo
-{
-    sal_uInt8           mpnSalt[ 16 ];
-    sal_uInt8           mpnEncrVerifier[ 16 ];
-    sal_uInt8           mpnEncrVerifierHash[ 32 ];
-    sal_uInt32          mnFlags;
-    sal_uInt32          mnAlgorithmId;
-    sal_uInt32          mnAlgorithmIdHash;
-    sal_uInt32          mnKeySize;
-    sal_uInt32          mnSaltSize;
-    sal_uInt32          mnVerifierHashSize;
-};
-
 void lclRandomGenerateValues( sal_Int32 nLength, sal_uInt8* aArray )
 {
     TimeValue aTime;
@@ -88,81 +57,10 @@ void lclRandomGenerateValues( sal_Int32 nLength, sal_uInt8* aArray )
     rtl_random_destroyPool ( aRandomPool );
 }
 
-struct EncryptionStandardHeader {
-    sal_uInt32 flags;
-    sal_uInt32 sizeExtra;
-    sal_uInt32 algId;         // if flag AES && CRYPTOAPI this defaults to 128-bit AES
-    sal_uInt32 algIdHash;     // 0 - determined by flags - defaults to SHA-1 if not external
-    sal_uInt32 keySize;       // 0 - determined by flags, 128, 192, 256 for AES
-    sal_uInt32 providedType;
-    sal_uInt32 reserved1;
-    sal_uInt32 reserved2;
-};
-
-struct EncryptionVerifierAES {
-    sal_uInt32 saltSize; // must be 0x00000010
-    sal_uInt8  salt[16]; //
-    sal_uInt8  encryptedVerifier[16];     // randomly generated verifier value
-    sal_uInt32 verifierHashSize;
-    sal_uInt8  encryptedVerifierHash[32];
-};
-
-bool lclWriteEncryptionInfo( PackageEncryptionInfo& rEncrInfo, BinaryOutputStream& rStream )
-{
-    const sal_uInt16 versionInfoMajor = 0x003;
-    const sal_uInt16 versionInfoMinor = 0x002;
-
-    rStream.writeValue(versionInfoMajor);
-    rStream.writeValue(versionInfoMinor);
-
-    const OUString cspName = "Microsoft Enhanced RSA and AES Cryptographic Provider";
-    sal_Int32      cspNameSize = (cspName.getLength() * 2) + 2;
-
-    EncryptionStandardHeader encryptionHeader;
-    sal_Int32 encryptionHeaderSize = static_cast<sal_Int32>(sizeof(EncryptionStandardHeader));
-    memset(&encryptionHeader, 0, encryptionHeaderSize);
-
-    EncryptionVerifierAES encryptionVerifier;
-    sal_Int32 encryptionVerifierSize = static_cast<sal_Int32>(sizeof(EncryptionVerifierAES));
-    memset(&encryptionVerifier, 0, encryptionVerifierSize);
-
-    rStream << rEncrInfo.mnFlags;
-
-    sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
-    rStream << headerSize;
-
-    encryptionHeader.flags = rEncrInfo.mnFlags;
-    encryptionHeader.algId = rEncrInfo.mnAlgorithmId;
-    encryptionHeader.algIdHash = rEncrInfo.mnAlgorithmIdHash;
-    encryptionHeader.keySize = rEncrInfo.mnKeySize;
-    encryptionHeader.providedType = ENCRYPT_PROVIDER_TYPE_AES;
-
-    rStream.writeMemory(&encryptionHeader, encryptionHeaderSize);
-    rStream.writeUnicodeArray(cspName);
-    rStream.writeValue<sal_uInt16>(0);
-
-    if (rEncrInfo.mnSaltSize != 16)
-        return false;
-
-    encryptionVerifier.saltSize = rEncrInfo.mnSaltSize;
-
-    memcpy(&encryptionVerifier.salt, rEncrInfo.mpnSalt, 16);
-
-    memcpy(&encryptionVerifier.encryptedVerifier, rEncrInfo.mpnEncrVerifier, 16);
-
-    encryptionVerifier.verifierHashSize = rEncrInfo.mnVerifierHashSize;
-
-    memcpy(encryptionVerifier.encryptedVerifierHash, rEncrInfo.mpnEncrVerifierHash, 32);
-
-    rStream.writeMemory(&encryptionVerifier, encryptionVerifierSize);
-
-    return true;
-}
-
-void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKeyDerived, sal_uInt32 nRequiredKeyLen )
+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(nRequiredKeyLen == 16);
+    assert(aKeyLength == 16);
 
     sal_uInt8 pnBuffer[ 64 ];
     memset( pnBuffer, 0x36, sizeof( pnBuffer ) );
@@ -187,46 +85,47 @@ void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKe
 
 #if 0 // for now nRequiredKeyLen will always be 16 and thus less than
       // RTL_DIGEST_LENGTH_SHA1==20, see assert above...
-    if( nRequiredKeyLen > RTL_DIGEST_LENGTH_SHA1 )
+    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.
-        memcpy( pnKeyDerived + RTL_DIGEST_LENGTH_SHA1, pnX2, nRequiredKeyLen - RTL_DIGEST_LENGTH_SHA1 );
-        nRequiredKeyLen = RTL_DIGEST_LENGTH_SHA1;
+        std::copy(pnX1, pnX1 + aKeyLength - RTL_DIGEST_LENGTH_SHA1, rKey.begin() + RTL_DIGEST_LENGTH_SHA1);
+        aKeyLength = RTL_DIGEST_LENGTH_SHA1;
     }
 #endif
-    memcpy( pnKeyDerived, pnX1, nRequiredKeyLen );
+    std::copy(pnX1, pnX1 + aKeyLength, rKey.begin());
+    //memcpy( pnKeyDerived, pnX1, nRequiredKeyLen );
 }
 
-bool lclGenerateVerifier(PackageEncryptionInfo& rEncryptionInfo, const sal_uInt8* pKey, sal_uInt32 nKeySize)
+bool lclGenerateVerifier(PackageEncryptionInfo& rEncryptionInfo, const vector<sal_uInt8>& rKey, sal_uInt32 nKeySize)
 {
-    bool bResult = false;
-
+    // only support key of size 128 bit (16 byte)
     if (nKeySize != 16)
-        return bResult;
+        return false;
 
-    sal_uInt8 aVerifier[16];
+    sal_uInt8 aVerifier[ENCRYPTED_VERIFIER_LENGTH];
     sal_Int32 aVerifierSize = sizeof(aVerifier);
-    memset( aVerifier, 0, aVerifierSize );
     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, pKey, 0 );
+        EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, &rKey[0], 0 );
         EVP_CIPHER_CTX_set_padding( &aContext, 0 );
-        int aEncryptedVerifierSize = 0;
-        EVP_EncryptUpdate( &aContext, rEncryptionInfo.mpnEncrVerifier, &aEncryptedVerifierSize, aVerifier, aVerifierSize );
+        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[ 32 ];
-    memset(pSha1Hash, 0, 32);
-    rEncryptionInfo.mnVerifierHashSize = RTL_DIGEST_LENGTH_SHA1;
+    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 );
@@ -235,106 +134,95 @@ bool lclGenerateVerifier(PackageEncryptionInfo& rEncryptionInfo, const sal_uInt8
 
 #if USE_TLS_OPENSSL
     {
-        memset(rEncryptionInfo.mpnEncrVerifierHash, 0, rEncryptionInfo.mnVerifierHashSize);
-        int written = 0;
+        int aWrittenLength = 0;
 
         EVP_CIPHER_CTX aContext;
         EVP_CIPHER_CTX_init( &aContext );
-        EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, pKey, 0 );
+        EVP_EncryptInit_ex( &aContext, EVP_aes_128_ecb(), NULL, &rKey[0], 0 );
         EVP_CIPHER_CTX_set_padding( &aContext, 0 );
-        EVP_EncryptUpdate( &aContext, rEncryptionInfo.mpnEncrVerifierHash, &written, pSha1Hash, 32 );
+        EVP_EncryptUpdate( &aContext, rEncryptionInfo.verifier.encryptedVerifierHash, &aWrittenLength, pSha1Hash, sizeof(pSha1Hash) );
         EVP_CIPHER_CTX_cleanup( &aContext );
     }
-
 #endif // USE_TLS_OPENSSL
 
-    bResult = true;
-
-    return bResult;
+    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 )
 {
-    bool bResult = false;
-
     // the only currently supported algorithm needs key size 128
-    if ( nKeySize == 16 && nVerifierSize == 16 )
-    {
-        // check password
+    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 );
+    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) );
+    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;
+    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 ) );
+    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) );
+    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 );
+    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 );
+    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;
+    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 );
-
-        bResult = ( memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0 );
-    }
+    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 bResult;
+    return memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0;
 }
 
-// ----------------------------------------------------------------------------
-
-Sequence< NamedValue > lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncrInfo, const OUString& rPassword, sal_uInt8* pnKey, sal_uInt32 nRequiredKeyLen )
+bool lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncryptionInfo, const OUString& rPassword, vector<sal_uInt8>& aKey, sal_uInt32 aKeyLength )
 {
-    size_t nBufferSize = rEncrInfo.mnSaltSize + 2 * rPassword.getLength();
+    size_t nBufferSize = rEncryptionInfo.verifier.saltSize + 2 * rPassword.getLength();
     sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ];
-    memcpy( pnBuffer, rEncrInfo.mpnSalt, rEncrInfo.mnSaltSize );
+    memcpy( pnBuffer, rEncryptionInfo.verifier.salt, rEncryptionInfo.verifier.saltSize );
 
-    sal_uInt8* pnPasswordLoc = pnBuffer + rEncrInfo.mnSaltSize;
+    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 ) );
@@ -364,24 +252,32 @@ Sequence< NamedValue > lclGenerateEncryptionKey( const PackageEncryptionInfo& rE
     rtl_digest_get( aDigest, pnHash, RTL_DIGEST_LENGTH_SHA1 );
     rtl_digest_destroy( aDigest );
 
-    lclDeriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, pnKey, nRequiredKeyLen );
+    lclDeriveKey( pnHash, RTL_DIGEST_LENGTH_SHA1, aKey, aKeyLength );
     delete[] pnHash;
+    return true;
+}
 
-    Sequence< NamedValue > aResult;
-    if( lclCheckEncryptionData( pnKey, nRequiredKeyLen, rEncrInfo.mpnEncrVerifier, sizeof( rEncrInfo.mpnEncrVerifier ), rEncrInfo.mpnEncrVerifierHash, sizeof( rEncrInfo.mpnEncrVerifierHash ) ) )
-    {
-        SequenceAsHashMap aEncryptionData;
-        aEncryptionData[ "AES128EncryptionKey" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pnKey ), nRequiredKeyLen );
-        aEncryptionData[ "AES128EncryptionSalt" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnSalt ), rEncrInfo.mnSaltSize );
-        aEncryptionData[ "AES128EncryptionVerifier" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifier ), sizeof( rEncrInfo.mpnEncrVerifier ) );
-        aEncryptionData[ "AES128EncryptionVerifierHash" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifierHash ), sizeof( rEncrInfo.mpnEncrVerifierHash ) );
-        aResult = aEncryptionData.getAsConstNamedValueList();
-    }
+} // namespace
 
-    return aResult;
+EncryptionStandardHeader::EncryptionStandardHeader()
+{
+    flags        = 0;
+    sizeExtra    = 0;
+    algId        = 0;
+    algIdHash    = 0;
+    keySize      = 0;
+    providedType = 0;
+    reserved1    = 0;
+    reserved2    = 0;
 }
 
-} // namespace
+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),
@@ -390,6 +286,37 @@ AesEncoder::AesEncoder(Reference< XStream > xDocumentStream, oox::ole::OleStorag
 {
 }
 
+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 );
@@ -405,31 +332,32 @@ bool AesEncoder::encode()
 
     Reference< XOutputStream > xEncryptionInfo( mrOleStorage.openOutputStream( "EncryptionInfo" ), UNO_SET_THROW );
 
-    PackageEncryptionInfo rEncrInfo;
-    rEncrInfo.mnFlags = ENCRYPTINFO_AES | ENCRYPTINFO_CRYPTOAPI;
-    rEncrInfo.mnAlgorithmId = ENCRYPT_ALGO_AES128;
-    rEncrInfo.mnAlgorithmIdHash = ENCRYPT_HASH_SHA1;
-    rEncrInfo.mnKeySize = ENCRYPT_KEY_SIZE_AES_128;
+    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;
 
-    rEncrInfo.mnSaltSize = 16;
+    lclRandomGenerateValues( mEncryptionInfo.verifier.saltSize, mEncryptionInfo.verifier.salt );
 
-    lclRandomGenerateValues( rEncrInfo.mnSaltSize, rEncrInfo.mpnSalt );
+    const sal_Int32 keyLength = mEncryptionInfo.header.keySize / 8;
+    vector<sal_uInt8> aKey;
+    aKey.resize(keyLength, 0);
 
-    const sal_Int32 keyLength = rEncrInfo.mnKeySize / 8;
-    sal_uInt8 key[16];
     assert(keyLength == 16);
-    memset(key, 0, keyLength);
 
-    lclGenerateEncryptionKey(rEncrInfo, maPassword, key, keyLength);
+    lclGenerateEncryptionKey(mEncryptionInfo, maPassword, aKey, keyLength);
+
+    sal_uInt8 key[16];
+    std::copy(aKey.begin(), aKey.end(), key);
 
-    lclGenerateVerifier(rEncrInfo, key, keyLength);
+    lclGenerateVerifier(mEncryptionInfo, aKey, keyLength);
 
-    bool aResult = lclCheckEncryptionData(key, keyLength, rEncrInfo.mpnEncrVerifier, 16, rEncrInfo.mpnEncrVerifierHash, 32);
-    if (!aResult)
+    if (!checkEncryptionInfo(aKey, keyLength))
         return false;
 
     BinaryXOutputStream aEncryptionInfoBinaryOutputStream( xEncryptionInfo, false );
-    lclWriteEncryptionInfo( rEncrInfo, aEncryptionInfoBinaryOutputStream );
+    writeEncryptionInfo( aEncryptionInfoBinaryOutputStream );
     aEncryptionInfoBinaryOutputStream.close();
 
     xEncryptionInfo->flush();
@@ -484,6 +412,198 @@ bool AesEncoder::encode()
     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
 
diff --git a/oox/source/core/filterdetect.cxx b/oox/source/core/filterdetect.cxx
index 12f53e4..2328642 100644
--- a/oox/source/core/filterdetect.cxx
+++ b/oox/source/core/filterdetect.cxx
@@ -19,45 +19,37 @@
 
 #include "oox/core/filterdetect.hxx"
 
-#include <config_oox.h>
 #include <com/sun/star/io/TempFile.hpp>
 #include <com/sun/star/io/XStream.hpp>
 #include <comphelper/docpasswordhelper.hxx>
 #include <comphelper/mediadescriptor.hxx>
-#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 "oox/core/DocumentCrypt.hxx"
 #include "oox/core/fastparser.hxx"
 #include "oox/helper/attributelist.hxx"
-#include "oox/helper/binaryinputstream.hxx"
-#include "oox/helper/binaryoutputstream.hxx"
 #include "oox/helper/zipstorage.hxx"
 #include "oox/ole/olestorage.hxx"
+
 #include <com/sun/star/uri/UriReferenceFactory.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 namespace ::com::sun::star::xml::sax;
+using namespace ::com::sun::star::uri;
 
-using ::comphelper::MediaDescriptor;
-using ::comphelper::SequenceAsHashMap;
-
-// ============================================================================
+using comphelper::MediaDescriptor;
+using comphelper::SequenceAsHashMap;
+using comphelper::IDocPasswordVerifier;
+using comphelper::DocPasswordVerifierResult;
 
 FilterDetectDocHandler::FilterDetectDocHandler( const  Reference< XComponentContext >& rxContext, OUString& rFilterName ) :
-    mrFilterName( rFilterName ), mxContext( rxContext )
+    mrFilterName( rFilterName ),
+    mxContext( rxContext )
 {
     maContextStack.reserve( 2 );
 }
@@ -163,15 +155,15 @@ void FilterDetectDocHandler::parseRelationship( const AttributeList& rAttribs )
     OUString aType = rAttribs.getString( XML_Type, OUString() );
     if ( aType == "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" )
     {
-        Reference< com::sun::star::uri::XUriReferenceFactory > xFac =  com::sun::star::uri::UriReferenceFactory::create( mxContext );
+        Reference<XUriReferenceFactory> xFactory = UriReferenceFactory::create( mxContext );
         try
         {
              // use '/' to representent the root of the zip package ( and provide a 'file' scheme to
              // keep the XUriReference implementation happy )
-             Reference< com::sun::star::uri::XUriReference > xBase = xFac->parse( OUString("file:///") );
+             Reference< XUriReference > xBase = xFactory->parse( OUString("file:///") );
 
-             Reference< com::sun::star::uri::XUriReference > xPart = xFac->parse(  rAttribs.getString( XML_Target, OUString() ) );
-             Reference< com::sun::star::uri::XUriReference > xAbs = xFac->makeAbsolute(  xBase, xPart, sal_True, com::sun::star::uri::RelativeUriExcessParentSegments_RETAIN );
+             Reference< XUriReference > xPart = xFactory->parse(  rAttribs.getString( XML_Target, OUString() ) );
+             Reference< XUriReference > xAbs = xFactory->makeAbsolute(  xBase, xPart, sal_True, RelativeUriExcessParentSegments_RETAIN );
 
              if ( xAbs.is() )
                  maTargetPath = xAbs->getPath();
@@ -237,8 +229,6 @@ void FilterDetectDocHandler::parseContentTypesOverride( const AttributeList& rAt
         mrFilterName = getFilterNameFromContentType( rAttribs.getString( XML_ContentType, OUString() ) );
 }
 
-// ============================================================================
-
 /* Helper for XServiceInfo */
 Sequence< OUString > FilterDetect_getSupportedServiceNames()
 {
@@ -259,8 +249,6 @@ Reference< XInterface > SAL_CALL FilterDetect_createInstance( const Reference< X
     return static_cast< ::cppu::OWeakObject* >( new FilterDetect( rxContext ) );
 }
 
-// ----------------------------------------------------------------------------
-
 FilterDetect::FilterDetect( const Reference< XComponentContext >& rxContext ) throw( RuntimeException ) :
     mxContext( rxContext, UNO_SET_THROW )
 {
@@ -270,25 +258,8 @@ FilterDetect::~FilterDetect()
 {
 }
 
-/* =========================================================================== */
-/*  Kudos to Caolan McNamara who provided the core decryption implementations. */
-/* =========================================================================== */
-
-namespace {
-
-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;
-
-// ----------------------------------------------------------------------------
+namespace
+{
 
 bool lclIsZipPackage( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm )
 {
@@ -296,413 +267,109 @@ bool lclIsZipPackage( const Reference< XComponentContext >& rxContext, const Ref
     return aZipStorage.isStorage();
 }
 
-// ----------------------------------------------------------------------------
-
-struct PackageEncryptionInfo
-{
-    sal_uInt8           mpnSalt[ 16 ];
-    sal_uInt8           mpnEncrVerifier[ 16 ];
-    sal_uInt8           mpnEncrVerifierHash[ 32 ];
-    sal_uInt32          mnFlags;
-    sal_uInt32          mnAlgorithmId;
-    sal_uInt32          mnAlgorithmIdHash;
-    sal_uInt32          mnKeySize;
-    sal_uInt32          mnSaltSize;
-    sal_uInt32          mnVerifierHashSize;
-};
-
-bool lclReadEncryptionInfo( PackageEncryptionInfo& rEncrInfo, BinaryInputStream& rStrm )
-{
-    rStrm.skip( 4 );
-    rStrm >> rEncrInfo.mnFlags;
-    if( getFlag( rEncrInfo.mnFlags, ENCRYPTINFO_EXTERNAL ) )
-        return false;
-
-    sal_uInt32 nHeaderSize, nRepeatedFlags;
-    rStrm >> nHeaderSize >> nRepeatedFlags;
-    if( (nHeaderSize < 20) || (nRepeatedFlags != rEncrInfo.mnFlags) )
-        return false;
-
-    rStrm.skip( 4 );
-    rStrm >> rEncrInfo.mnAlgorithmId >> rEncrInfo.mnAlgorithmIdHash >> rEncrInfo.mnKeySize;
-    rStrm.skip( nHeaderSize - 20 );
-    rStrm >> rEncrInfo.mnSaltSize;
-    if( rEncrInfo.mnSaltSize != 16 )
-        return false;
-
-    rStrm.readMemory( rEncrInfo.mpnSalt, 16 );
-    rStrm.readMemory( rEncrInfo.mpnEncrVerifier, 16 );
-    rStrm >> rEncrInfo.mnVerifierHashSize;
-    rStrm.readMemory( rEncrInfo.mpnEncrVerifierHash, 32 );
-    return !rStrm.isEof();
-}
-
-// ----------------------------------------------------------------------------
-
-void lclDeriveKey( const sal_uInt8* pnHash, sal_uInt32 nHashLen, sal_uInt8* pnKeyDerived, sal_uInt32 nRequiredKeyLen )
-{
-    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( nRequiredKeyLen > RTL_DIGEST_LENGTH_SHA1 )
-    {
-        memcpy( pnKeyDerived + RTL_DIGEST_LENGTH_SHA1, pnX2, nRequiredKeyLen - RTL_DIGEST_LENGTH_SHA1 );
-        nRequiredKeyLen = RTL_DIGEST_LENGTH_SHA1;
-    }
-    memcpy( pnKeyDerived, pnX1, nRequiredKeyLen );
-}
-
-// ----------------------------------------------------------------------------
-
-bool lclCheckEncryptionData( const sal_uInt8* pnKey, sal_uInt32 nKeySize, const sal_uInt8* pnVerifier, sal_uInt32 nVerifierSize, const sal_uInt8* pnVerifierHash, sal_uInt32 nVerifierHashSize )
-{
-    bool bResult = false;
-
-    // the only currently supported algorithm needs key size 128
-    if ( nKeySize == 16 && nVerifierSize == 16 && nVerifierHashSize == 32 )
-    {
-        // 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[ 32 ];
-        (void) memset( pnTmpVerifierHash, 0, sizeof(pnTmpVerifierHash) );
-
-        /*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[ 32 ];
-        (void) memset( pnTmpVerifierHash, 0, sizeof(pnTmpVerifierHash) );
-        PK11_CipherOp( encContext, pnTmpVerifierHash, &nOutLen, sizeof(pnTmpVerifierHash), 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 );
-
-        bResult = ( memcmp( pnSha1Hash, pnTmpVerifierHash, RTL_DIGEST_LENGTH_SHA1 ) == 0 );
-    }
-
-    return bResult;
-}
-
-// ----------------------------------------------------------------------------
-
-Sequence< NamedValue > lclGenerateEncryptionKey( const PackageEncryptionInfo& rEncrInfo, const OUString& rPassword, sal_uInt8* pnKey, sal_uInt32 nRequiredKeyLen )
-{
-    size_t nBufferSize = rEncrInfo.mnSaltSize + 2 * rPassword.getLength();
-    sal_uInt8* pnBuffer = new sal_uInt8[ nBufferSize ];
-    memcpy( pnBuffer, rEncrInfo.mpnSalt, rEncrInfo.mnSaltSize );
-
-    sal_uInt8* pnPasswordLoc = pnBuffer + rEncrInfo.mnSaltSize;
-    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, pnKey, nRequiredKeyLen );
-    delete[] pnHash;
-
-    Sequence< NamedValue > aResult;
-    if( lclCheckEncryptionData( pnKey, nRequiredKeyLen, rEncrInfo.mpnEncrVerifier, sizeof( rEncrInfo.mpnEncrVerifier ), rEncrInfo.mpnEncrVerifierHash, sizeof( rEncrInfo.mpnEncrVerifierHash ) ) )
-    {
-        SequenceAsHashMap aEncryptionData;
-        aEncryptionData[ "AES128EncryptionKey" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( pnKey ), nRequiredKeyLen );
-        aEncryptionData[ "AES128EncryptionSalt" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnSalt ), rEncrInfo.mnSaltSize );
-        aEncryptionData[ "AES128EncryptionVerifier" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifier ), sizeof( rEncrInfo.mpnEncrVerifier ) );
-        aEncryptionData[ "AES128EncryptionVerifierHash" ] <<= Sequence< sal_Int8 >( reinterpret_cast< const sal_Int8* >( rEncrInfo.mpnEncrVerifierHash ), sizeof( rEncrInfo.mpnEncrVerifierHash ) );
-        aResult = aEncryptionData.getAsConstNamedValueList();
-    }
-
-    return aResult;
-}
-
-// the password verifier ------------------------------------------------------
-
-class PasswordVerifier : public ::comphelper::IDocPasswordVerifier
+class PasswordVerifier : public IDocPasswordVerifier
 {
 public:
-    explicit            PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo );
-
-    virtual ::comphelper::DocPasswordVerifierResult
-                        verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData );
-    virtual ::comphelper::DocPasswordVerifierResult
-                        verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData );
+    explicit PasswordVerifier( AesDecoder& decoder );
 
-    inline const sal_uInt8* getKey() const { return &maKey.front(); }
+    virtual DocPasswordVerifierResult verifyPassword( const OUString& rPassword, Sequence<NamedValue>& rEncryptionData );
 
+    virtual DocPasswordVerifierResult verifyEncryptionData( const Sequence<NamedValue>& rEncryptionData );
 private:
-    const PackageEncryptionInfo& mrEncryptInfo;
-    ::std::vector< sal_uInt8 > maKey;
+    AesDecoder& mDecoder;
 };
 
-PasswordVerifier::PasswordVerifier( const PackageEncryptionInfo& rEncryptInfo ) :
-    mrEncryptInfo( rEncryptInfo ),
-    maKey( static_cast< size_t >( rEncryptInfo.mnKeySize / 8 ), 0 )
-{
-}
+PasswordVerifier::PasswordVerifier( AesDecoder& decoder ) :
+    mDecoder(decoder)
+{}
 
-::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword, Sequence< NamedValue >& o_rEncryptionData )
+comphelper::DocPasswordVerifierResult PasswordVerifier::verifyPassword( const OUString& rPassword, Sequence<NamedValue>& rEncryptionData )
 {
-    // verifies the password and writes the related decryption key into maKey
-    o_rEncryptionData = lclGenerateEncryptionKey( mrEncryptInfo, rPassword, &maKey.front(), maKey.size() );
-    return o_rEncryptionData.hasElements() ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+    if( mDecoder.generateEncryptionKey(rPassword) && mDecoder.checkCurrentEncryptionData() )
+        rEncryptionData = mDecoder.createEncryptionData();
+
+    return rEncryptionData.hasElements() ? comphelper::DocPasswordVerifierResult_OK : comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
 }
 
-::comphelper::DocPasswordVerifierResult PasswordVerifier::verifyEncryptionData( const Sequence< NamedValue >& rEncryptionData )
+comphelper::DocPasswordVerifierResult PasswordVerifier::verifyEncryptionData( 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 >() );
-
-    bool bResult = 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() );
-
-    return bResult ? ::comphelper::DocPasswordVerifierResult_OK : ::comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+    comphelper::DocPasswordVerifierResult aResult = comphelper::DocPasswordVerifierResult_WRONG_PASSWORD;
+    if (AesDecoder::checkEncryptionData(rEncryptionData))
+        aResult = comphelper::DocPasswordVerifierResult_OK;
+    return aResult;
 }
 
 } // namespace
 
-// ----------------------------------------------------------------------------
 
-Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescriptor& rMediaDesc ) const
+Reference< XInputStream > FilterDetect::extractUnencryptedPackage( MediaDescriptor& rMediaDescriptor ) const
 {
     // try the plain input stream
-    Reference< XInputStream > xInStrm( rMediaDesc[ MediaDescriptor::PROP_INPUTSTREAM() ], UNO_QUERY );
-    if( !xInStrm.is() || lclIsZipPackage( mxContext, xInStrm ) )
-        return xInStrm;
+    Reference<XInputStream> xInputStream( rMediaDescriptor[ MediaDescriptor::PROP_INPUTSTREAM() ], UNO_QUERY );
+    if( !xInputStream.is() || lclIsZipPackage( mxContext, xInputStream ) )
+        return xInputStream;
 
     // check if a temporary file is passed in the 'ComponentData' property
-    Reference< XStream > xDecrypted( rMediaDesc.getComponentDataEntry( "DecryptedPackage" ), UNO_QUERY );
+    Reference<XStream> xDecrypted( rMediaDescriptor.getComponentDataEntry( "DecryptedPackage" ), UNO_QUERY );
     if( xDecrypted.is() )
     {
-        Reference< XInputStream > xDecrInStrm = xDecrypted->getInputStream();
-        if( lclIsZipPackage( mxContext, xDecrInStrm ) )
-            return xDecrInStrm;
+        Reference<XInputStream> xDecryptedInputStream = xDecrypted->getInputStream();
+        if( lclIsZipPackage( mxContext, xDecryptedInputStream ) )
+            return xDecryptedInputStream;
     }
 
     // try to decrypt an encrypted OLE package
-    ::oox::ole::OleStorage aOleStorage( mxContext, xInStrm, false );
-    if( aOleStorage.isStorage() ) try
+    oox::ole::OleStorage aOleStorage( mxContext, xInputStream, false );
+    if( aOleStorage.isStorage() )
     {
-        // open the required input streams in the encrypted package
-        Reference< XInputStream > xEncryptionInfo( aOleStorage.openInputStream( "EncryptionInfo" ), UNO_SET_THROW );
-        Reference< XInputStream > xEncryptedPackage( aOleStorage.openInputStream( "EncryptedPackage" ), UNO_SET_THROW );
-
-        // read the encryption info stream
-        PackageEncryptionInfo aEncryptInfo;
-        BinaryXInputStream aInfoStrm( xEncryptionInfo, true );
-        bool bValidInfo = lclReadEncryptionInfo( aEncryptInfo, aInfoStrm );
-
-        // check flags and algorithm IDs, required are AES128 and SHA-1
-        bool bImplemented = bValidInfo &&
-            getFlag( aEncryptInfo.mnFlags, ENCRYPTINFO_CRYPTOAPI ) &&
-            getFlag( aEncryptInfo.mnFlags, ENCRYPTINFO_AES ) &&
-            // algorithm ID 0 defaults to AES128 too, if ENCRYPTINFO_AES flag is set
-            ((aEncryptInfo.mnAlgorithmId == 0) || (aEncryptInfo.mnAlgorithmId == ENCRYPT_ALGO_AES128)) &&
-            // hash algorithm ID 0 defaults to SHA-1 too
-            ((aEncryptInfo.mnAlgorithmIdHash == 0) || (aEncryptInfo.mnAlgorithmIdHash == ENCRYPT_HASH_SHA1)) &&
-            (aEncryptInfo.mnVerifierHashSize == 20);
-
-        if( bImplemented )
+        try
         {
-#if USE_TLS_NSS
-            // Initialize NSS, database functions are not needed
-            NSS_NoDB_Init( NULL );
-#endif // USE_TLS_NSS
-
-            /*  "VelvetSweatshop" is the built-in default encryption
-                password used by MS Excel for the "workbook protection"
-                feature with password. Try this first before prompting the
-                user for a password. */
-            ::std::vector< OUString > aDefaultPasswords;
-            aDefaultPasswords.push_back( "VelvetSweatshop" );
-
-            /*  Use the comphelper password helper to request a password.
-                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( aEncryptInfo );
-            Sequence< NamedValue > aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
-                aVerifier, rMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords );
-
-            if( aEncryptionData.getLength() == 0 )
-            {
-                rMediaDesc[ MediaDescriptor::PROP_ABORTED() ] <<= true;
-            }
-            else
+            AesDecoder aDecoder(aOleStorage);
+
+            if( aDecoder.readEncryptionInfo() )
             {
-                // create temporary file for unencrypted package
-                Reference< XStream > xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
-                Reference< XOutputStream > xDecryptedPackage( xTempFile->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, aVerifier.getKey(), 0 );
-                EVP_CIPHER_CTX_set_padding( &aes_ctx, 0 );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
-                // Retrieve the valid key so we can get its size later
-                SequenceAsHashMap aHashData( aEncryptionData );
-                Sequence<sal_Int8> validKey( aHashData.getUnpackedValueOrDefault("AES128EncryptionKey", Sequence<sal_Int8>() ) );
-
-                PK11SlotInfo *aSlot( PK11_GetBestSlot( CKM_AES_ECB, NULL ) );
-                sal_uInt8 *key = new sal_uInt8[ validKey.getLength() ];
-                (void) memcpy( key, aVerifier.getKey(), validKey.getLength() );
-
-                SECItem keyItem;
-                keyItem.type = siBuffer;
-                keyItem.data = key;
-                keyItem.len  = validKey.getLength();
-
-                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 )
+                /*  "VelvetSweatshop" is the built-in default encryption
+                    password used by MS Excel for the "workbook protection"
+                    feature with password. Try this first before prompting the
+                    user for a password. */
+                std::vector<OUString> aDefaultPasswords;
+                aDefaultPasswords.push_back("VelvetSweatshop");
+
+                /*  Use the comphelper password helper to request a password.
+                    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 );
+                Sequence<NamedValue> aEncryptionData;
+                aEncryptionData = comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
+                                                aVerifier, rMediaDescriptor,
+                                                comphelper::DocPasswordRequestType_MS,
+                                                &aDefaultPasswords );
+
+                if( aEncryptionData.getLength() == 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 );
+                    rMediaDescriptor[ MediaDescriptor::PROP_ABORTED() ] <<= true;
+                }
+                else
+                {
+                    // create temporary file for unencrypted package
+                    Reference<XStream> xTempFile( TempFile::create(mxContext), UNO_QUERY_THROW );
+                    aDecoder.decode( xTempFile );
+
+                    // store temp file in media descriptor to keep it alive
+                    rMediaDescriptor.setComponentDataEntry( "DecryptedPackage", Any( xTempFile ) );
+
+                    Reference<XInputStream> xDecryptedInputStream = xTempFile->getInputStream();
+                    if( lclIsZipPackage( mxContext, xDecryptedInputStream ) )
+                        return xDecryptedInputStream;
                 }
-#if USE_TLS_OPENSSL
-                EVP_DecryptFinal_ex( &aes_ctx, pnOutBuffer, &nOutLen );
-#endif // USE_TLS_OPENSSL
-
-#if USE_TLS_NSS
-                uint final;
-                PK11_DigestFinal( encContext, pnOutBuffer, &final, nInLen - nOutLen );
-                nOutLen = final;
-#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();
-
-                // store temp file in media descriptor to keep it alive
-                rMediaDesc.setComponentDataEntry( "DecryptedPackage", Any( xTempFile ) );
-
-                Reference< XInputStream > xDecrInStrm = xTempFile->getInputStream();
-                if( lclIsZipPackage( mxContext, xDecrInStrm ) )
-                    return xDecrInStrm;
             }
         }
+        catch( const Exception& )
+        {
+        }
     }
-    catch( const Exception& )
-    {
-    }
-
-    return Reference< XInputStream >();
+    return Reference<XInputStream>();
 }
 
 // com.sun.star.lang.XServiceInfo interface -----------------------------------
@@ -730,24 +397,24 @@ Sequence< OUString > SAL_CALL FilterDetect::getSupportedServiceNames() throw( Ru
 OUString SAL_CALL FilterDetect::detect( Sequence< PropertyValue >& rMediaDescSeq ) throw( RuntimeException )
 {
     OUString aFilterName;
-    MediaDescriptor aMediaDesc( rMediaDescSeq );
+    MediaDescriptor aMediaDescriptor( rMediaDescSeq );
 
     /*  Check that the user has not choosen to abort detection, e.g. by hitting
         'Cancel' in the password input dialog. This may happen because this
         filter detection is used by different filters. */
-    bool bAborted = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_ABORTED(), false );
+    bool bAborted = aMediaDescriptor.getUnpackedValueOrDefault( MediaDescriptor::PROP_ABORTED(), false );
     if( !bAborted ) try
     {
-        aMediaDesc.addInputStream();
+        aMediaDescriptor.addInputStream();
 
         /*  Get the unencrypted input stream. This may include creation of a
             temporary file that contains the decrypted package. This temporary
             file will be stored in the 'ComponentData' property of the media
             descriptor. */
-        Reference< XInputStream > xInStrm( extractUnencryptedPackage( aMediaDesc ), UNO_SET_THROW );
+        Reference< XInputStream > xInputStream( extractUnencryptedPackage( aMediaDescriptor ), UNO_SET_THROW );
 
         // stream must be a ZIP package
-        ZipStorage aZipStorage( mxContext, xInStrm );
+        ZipStorage aZipStorage( mxContext, xInputStream );
         if( aZipStorage.isStorage() )
         {
             // create the fast parser, register the XML namespaces, set document handler
@@ -768,7 +435,7 @@ OUString SAL_CALL FilterDetect::detect( Sequence< PropertyValue >& rMediaDescSeq
     }
 
     // write back changed media descriptor members
-    aMediaDesc >> rMediaDescSeq;
+    aMediaDescriptor >> rMediaDescSeq;
     return aFilterName;
 }
 
commit ef947839c9e6e5e86e11f7a7cbf13470010ca48f
Author: Tomaž Vajngerl <quikee at gmail.com>
Date:   Thu Aug 15 11:04:59 2013 +0200

    fdo#59524 Enable encryption for docx, pptx and standard OOXML formats
    
    Change-Id: Id00fde15188be3fb7209d8f14f2f2f07ebd211b0

diff --git a/filter/source/config/fragments/filters/MS_Word_2007_XML.xcu b/filter/source/config/fragments/filters/MS_Word_2007_XML.xcu
index 7c0b36a..6ad137f 100644
--- a/filter/source/config/fragments/filters/MS_Word_2007_XML.xcu
+++ b/filter/source/config/fragments/filters/MS_Word_2007_XML.xcu
@@ -16,7 +16,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 -->
     <node oor:name="MS Word 2007 XML" oor:op="replace">
-        <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER</value></prop>
+        <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER ENCRYPTION PASSWORDTOMODIFY</value></prop>
         <prop oor:name="UIComponent"/>
         <prop oor:name="FilterService"><value>com.sun.star.comp.Writer.WriterFilter</value></prop>
         <prop oor:name="UserData"><value>OXML</value></prop>
diff --git a/filter/source/config/fragments/filters/OOXML_Text.xcu b/filter/source/config/fragments/filters/OOXML_Text.xcu
index e53e1dd..f1065e9 100644
--- a/filter/source/config/fragments/filters/OOXML_Text.xcu
+++ b/filter/source/config/fragments/filters/OOXML_Text.xcu
@@ -16,7 +16,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 -->
     <node oor:name="Office Open XML Text" oor:op="replace">
-        <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER</value></prop>
+        <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER ENCRYPTION PASSWORDTOMODIFY</value></prop>
         <prop oor:name="UIComponent"/>
         <prop oor:name="FilterService"><value>com.sun.star.comp.Writer.WriterFilter</value></prop>
         <prop oor:name="UserData"><value></value></prop>
diff --git a/filter/source/config/fragments/filters/calc_OOXML.xcu b/filter/source/config/fragments/filters/calc_OOXML.xcu
index f9ae123..ce4bc40 100644
--- a/filter/source/config/fragments/filters/calc_OOXML.xcu
+++ b/filter/source/config/fragments/filters/calc_OOXML.xcu
@@ -16,7 +16,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 -->
 <node oor:name="Calc Office Open XML" oor:op="replace">
-    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED</value></prop>
+    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED ENCRYPTION PASSWORDTOMODIFY</value></prop>
     <prop oor:name="UIComponent"/>
     <prop oor:name="FilterService"><value>com.sun.star.comp.oox.xls.ExcelFilter</value></prop>
     <prop oor:name="UserData"><value>OOXML</value></prop>
diff --git a/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML.xcu b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML.xcu
index 0e6d5a7..14c3ca8 100644
--- a/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML.xcu
+++ b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML.xcu
@@ -16,7 +16,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 -->
 <node oor:name="Impress MS PowerPoint 2007 XML" oor:op="replace">
-    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED</value></prop>
+    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED ENCRYPTION PASSWORDTOMODIFY</value></prop>
     <prop oor:name="UIComponent"/>
     <prop oor:name="FilterService"><value>com.sun.star.comp.oox.ppt.PowerPointImport</value></prop>
     <prop oor:name="UserData"/>
diff --git a/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_AutoPlay.xcu b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_AutoPlay.xcu
index de51369..112e254 100644
--- a/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_AutoPlay.xcu
+++ b/filter/source/config/fragments/filters/impress_MS_PowerPoint_2007_XML_AutoPlay.xcu
@@ -16,7 +16,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 -->
 <node oor:name="Impress MS PowerPoint 2007 XML AutoPlay" oor:op="replace">
-    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED STARTPRESENTATION</value></prop>
+    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED STARTPRESENTATION ENCRYPTION PASSWORDTOMODIFY</value></prop>
     <prop oor:name="UIComponent"/>
     <prop oor:name="FilterService"><value>com.sun.star.comp.oox.ppt.PowerPointImport</value></prop>
     <prop oor:name="UserData"/>
diff --git a/filter/source/config/fragments/filters/impress_OOXML.xcu b/filter/source/config/fragments/filters/impress_OOXML.xcu
index 5784ae1..d2e1366 100644
--- a/filter/source/config/fragments/filters/impress_OOXML.xcu
+++ b/filter/source/config/fragments/filters/impress_OOXML.xcu
@@ -16,7 +16,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 -->
 <node oor:name="Impress Office Open XML" oor:op="replace">
-    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED</value></prop>
+    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED ENCRYPTION PASSWORDTOMODIFY</value></prop>
     <prop oor:name="UIComponent"/>
     <prop oor:name="FilterService"><value>com.sun.star.comp.oox.ppt.PowerPointImport</value></prop>
     <prop oor:name="UserData"><value>OOXML</value></prop>
diff --git a/filter/source/config/fragments/filters/impress_OOXML_AutoPlay.xcu b/filter/source/config/fragments/filters/impress_OOXML_AutoPlay.xcu
index 79fcb8e..44451a9 100644
--- a/filter/source/config/fragments/filters/impress_OOXML_AutoPlay.xcu
+++ b/filter/source/config/fragments/filters/impress_OOXML_AutoPlay.xcu
@@ -16,7 +16,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 -->
 <node oor:name="Impress Office Open XML AutoPlay" oor:op="replace">
-    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED STARTPRESENTATION</value></prop>
+    <prop oor:name="Flags"><value>IMPORT EXPORT ALIEN 3RDPARTYFILTER PREFERRED STARTPRESENTATION ENCRYPTION PASSWORDTOMODIFY</value></prop>
     <prop oor:name="UIComponent"/>
     <prop oor:name="FilterService"><value>com.sun.star.comp.oox.ppt.PowerPointImport</value></prop>
     <prop oor:name="UserData"/>
diff --git a/sfx2/source/dialog/filedlghelper.cxx b/sfx2/source/dialog/filedlghelper.cxx
index b9132eb..60de267 100644
--- a/sfx2/source/dialog/filedlghelper.cxx
+++ b/sfx2/source/dialog/filedlghelper.cxx
@@ -122,6 +122,21 @@ using namespace ::cppu;
 namespace sfx2
 {
 
+namespace
+{
+    bool lclSupportsOOXMLEncryption(OUString aFilterName)
+    {
+        return  aFilterName == "Calc MS Excel 2007 XML"
+                ||  aFilterName == "MS Word 2007 XML"
+                ||  aFilterName == "Impress MS PowerPoint 2007 XML"
+                ||  aFilterName == "Impress MS PowerPoint 2007 XML AutoPlay"
+                ||  aFilterName == "Calc Office Open XML"
+                ||  aFilterName == "Impress Office Open XML"
+                ||  aFilterName == "Impress Office Open XML AutoPlay"
+                ||  aFilterName == "Office Open XML Text";
+    }
+}
+
 const OUString* GetLastFilterConfigId( FileDialogHelper::Context _eContext )
 {
     static const OUString aSD_EXPORT_IDENTIFIER( "SdExportLastFilter"  );
@@ -2719,7 +2734,8 @@ ErrCode RequestPassword(const SfxFilter* pCurrentFilter, OUString& aURL, SfxItem
             // TODO/LATER: The filters should show the password dialog themself in future
             if ( bMSType )
             {
-                if ( pCurrentFilter->GetFilterName() == "Calc MS Excel 2007 XML" )
+                // Check if filter supports OOXML encryption
+                if ( lclSupportsOOXMLEncryption( pCurrentFilter->GetFilterName() ) )
                 {
                     ::comphelper::SequenceAsHashMap aHashData;
                     aHashData[ OUString( "Password"  ) ] <<= pPasswordRequest->getPassword();


More information about the Libreoffice-commits mailing list