[Libreoffice-commits] core.git: 5 commits - filter/source include/filter include/oox oox/source sc/source

Caolán McNamara caolanm at redhat.com
Fri Oct 21 10:16:47 UTC 2016


 filter/source/msfilter/mscodec.cxx        |  184 +++++++++++++++++++-------
 include/filter/msfilter/mscodec.hxx       |  208 ++++++++++++++++++++++++------
 include/oox/crypto/CryptTools.hxx         |    3 
 include/oox/crypto/Standard2007Engine.hxx |   70 ----------
 oox/source/crypto/CryptTools.cxx          |   14 --
 oox/source/crypto/DocumentDecryption.cxx  |   22 +--
 oox/source/crypto/Standard2007Engine.cxx  |   67 +++------
 sc/source/filter/excel/xicontent.cxx      |  106 ++++++++++++---
 sc/source/filter/excel/xistream.cxx       |   70 ++++++----
 sc/source/filter/inc/xistream.hxx         |   67 +++++++--
 sc/source/filter/inc/xlcontent.hxx        |    2 
 11 files changed, 533 insertions(+), 280 deletions(-)

New commits:
commit 1473ce030314027c01c98f513407ed0897328585
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Oct 20 16:07:11 2016 +0100

    implement CryptoAPI RC4+SHA1 encryption scheme for xls import
    
    there might be other variants out there in practice, but this
    works for default encrypted xls of excel 2013
    
    Change-Id: I91c0e1d1d95fbd1c68966650e7ac7d23276bcbe3

diff --git a/filter/source/msfilter/mscodec.cxx b/filter/source/msfilter/mscodec.cxx
index 20a1f4a..ffbbd09 100644
--- a/filter/source/msfilter/mscodec.cxx
+++ b/filter/source/msfilter/mscodec.cxx
@@ -245,30 +245,36 @@ void MSCodec_Xor95::Skip( std::size_t nBytes )
     mnOffset = (mnOffset + nBytes) & 0x0F;
 }
 
-MSCodec97::MSCodec97(rtlCipher hCipher)
-    : m_hCipher(hCipher)
+MSCodec97::MSCodec97(size_t nHashLen)
+    : m_nHashLen(nHashLen)
+    , m_hCipher(rtl_cipher_create(rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream))
+    , m_aDigestValue(nHashLen, 0)
 {
+    assert(m_hCipher != nullptr);
+    (void)memset (m_pDocId, 0, sizeof(m_pDocId));
 }
 
 MSCodec_Std97::MSCodec_Std97()
-    : MSCodec97(rtl_cipher_create(rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream))
+    : MSCodec97(RTL_DIGEST_LENGTH_MD5)
 {
-    assert(m_hCipher != nullptr);
     m_hDigest = rtl_digest_create(rtl_Digest_AlgorithmMD5);
     assert(m_hDigest != nullptr);
-    (void)memset (m_pDigestValue, 0, sizeof(m_pDigestValue));
-    (void)memset (m_pDocId, 0, sizeof(m_pDocId));
+}
+
+MSCodec_CryptoAPI::MSCodec_CryptoAPI()
+    : MSCodec97(RTL_DIGEST_LENGTH_SHA1)
+{
 }
 
 MSCodec97::~MSCodec97()
 {
+    (void)memset(m_aDigestValue.data(), 0, m_aDigestValue.size());
+    (void)memset(m_pDocId, 0, sizeof(m_pDocId));
     rtl_cipher_destroy(m_hCipher);
 }
 
 MSCodec_Std97::~MSCodec_Std97()
 {
-    (void)memset (m_pDigestValue, 0, sizeof(m_pDigestValue));
-    (void)memset (m_pDocId, 0, sizeof(m_pDocId));
     rtl_digest_destroy(m_hDigest);
 }
 
@@ -286,7 +292,7 @@ static inline void lcl_PrintDigest(const sal_uInt8* /*pDigest*/, const char* /*m
 }
 #endif
 
-bool MSCodec_Std97::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
+bool MSCodec97::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
 {
 #if DEBUG_MSO_ENCRYPTION_STD97
     fprintf(stdout, "MSCodec_Std97::InitCodec: --begin\n");fflush(stdout);
@@ -295,16 +301,17 @@ bool MSCodec_Std97::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
 
     ::comphelper::SequenceAsHashMap aHashData( aData );
     uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("STD97EncryptionKey", uno::Sequence< sal_Int8 >() );
-
-    if ( aKey.getLength() == RTL_DIGEST_LENGTH_MD5 )
+    const size_t nKeyLen = aKey.getLength();
+    if (nKeyLen == m_nHashLen)
     {
-        (void)memcpy( m_pDigestValue, aKey.getConstArray(), RTL_DIGEST_LENGTH_MD5 );
+        assert(m_aDigestValue.size() == m_nHashLen);
+        (void)memcpy(m_aDigestValue.data(), aKey.getConstArray(), m_nHashLen);
         uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault("STD97UniqueID", uno::Sequence< sal_Int8 >() );
         if ( aUniqueID.getLength() == 16 )
         {
             (void)memcpy( m_pDocId, aUniqueID.getConstArray(), 16 );
             bResult = true;
-            lcl_PrintDigest(m_pDigestValue, "digest value");
+            lcl_PrintDigest(m_aDigestValue.data(), "digest value");
             lcl_PrintDigest(m_pDocId, "DocId value");
         }
         else
@@ -316,10 +323,11 @@ bool MSCodec_Std97::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
     return bResult;
 }
 
-uno::Sequence< beans::NamedValue > MSCodec_Std97::GetEncryptionData()
+uno::Sequence< beans::NamedValue > MSCodec97::GetEncryptionData()
 {
     ::comphelper::SequenceAsHashMap aHashData;
-    aHashData[ OUString( "STD97EncryptionKey" ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(m_pDigestValue), RTL_DIGEST_LENGTH_MD5 );
+    assert(m_aDigestValue.size() == m_nHashLen);
+    aHashData[ OUString( "STD97EncryptionKey" ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(m_aDigestValue.data()), m_nHashLen );
     aHashData[ OUString( "STD97UniqueID" ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(m_pDocId), 16 );
 
     return aHashData.getAsConstNamedValueList();
@@ -335,26 +343,51 @@ void MSCodec_Std97::InitKey (
     uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key(pPassData, pDocId);
     // Fill raw digest of above updates into DigestValue.
 
-    if ( aKey.getLength() == sizeof(m_pDigestValue) )
-        (void)memcpy ( m_pDigestValue, aKey.getConstArray(), sizeof(m_pDigestValue) );
+    const size_t nKeyLen = aKey.getLength();
+    if (m_aDigestValue.size() == nKeyLen)
+        (void)memcpy(m_aDigestValue.data(), aKey.getConstArray(), m_aDigestValue.size());
     else
-        memset( m_pDigestValue, 0, sizeof(m_pDigestValue) );
+        memset(m_aDigestValue.data(), 0, m_aDigestValue.size());
+
+    lcl_PrintDigest(m_aDigestValue.data(), "digest value");
+
+    (void)memcpy (m_pDocId, pDocId, 16);
+
+    lcl_PrintDigest(m_pDocId, "DocId value");
+}
+
+void MSCodec_CryptoAPI::InitKey (
+    const sal_uInt16 pPassData[16],
+    const sal_uInt8  pDocId[16])
+{
+    sal_uInt32 saltSize = 16;
+
+    // Prepare initial data -> salt + password (in 16-bit chars)
+    std::vector<sal_uInt8> initialData(pDocId, pDocId + saltSize);
+
+    // Fill PassData into KeyData.
+    for (sal_Int32 nInd = 0; nInd < 16 && pPassData[nInd]; ++nInd)
+    {
+        initialData.push_back(sal::static_int_cast<sal_uInt8>((pPassData[nInd] >> 0) & 0xff));
+        initialData.push_back(sal::static_int_cast<sal_uInt8>((pPassData[nInd] >> 8) & 0xff));
+    }
+
+    // calculate SHA1 hash of initialData
+    rtl_digest_SHA1(initialData.data(), initialData.size(), m_aDigestValue.data(), m_aDigestValue.size());
 
-    lcl_PrintDigest(m_pDigestValue, "digest value");
+    lcl_PrintDigest(m_aDigestValue.data(), "digest value");
 
     (void)memcpy (m_pDocId, pDocId, 16);
 
     lcl_PrintDigest(m_pDocId, "DocId value");
 }
 
-bool MSCodec_Std97::VerifyKey (
-    const sal_uInt8 pSaltData[16],
-    const sal_uInt8 pSaltDigest[16])
+bool MSCodec97::VerifyKey(const sal_uInt8* pSaltData, const sal_uInt8* pSaltDigest)
 {
     // both the salt data and salt digest (hash) come from the document being imported.
 
 #if DEBUG_MSO_ENCRYPTION_STD97
-    fprintf(stdout, "MSCodec_Std97::VerifyKey: \n");
+    fprintf(stdout, "MSCodec97::VerifyKey: \n");
     lcl_PrintDigest(pSaltData, "salt data");
     lcl_PrintDigest(pSaltDigest, "salt hash");
 #endif
@@ -362,35 +395,42 @@ bool MSCodec_Std97::VerifyKey (
 
     if (InitCipher(0))
     {
-        sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5];
-        GetDigestFromSalt(pSaltData, pDigest);
+        std::vector<sal_uInt8> aDigest(m_nHashLen);
+        GetDigestFromSalt(pSaltData, aDigest.data());
 
-        sal_uInt8 pBuffer[16];
+        std::vector<sal_uInt8> aBuffer(m_nHashLen);
         // Decode original SaltDigest into Buffer.
-        rtl_cipher_decode (
-            m_hCipher, pSaltDigest, 16, pBuffer, sizeof(pBuffer));
+        rtl_cipher_decode(m_hCipher, pSaltDigest, m_nHashLen, aBuffer.data(), m_nHashLen);
 
         // Compare Buffer with computed Digest.
-        result = (memcmp (pBuffer, pDigest, sizeof(pDigest)) == 0);
+        result = (memcmp(aBuffer.data(), aDigest.data(), m_nHashLen) == 0);
 
         // Erase Buffer and Digest arrays.
-        rtl_secureZeroMemory (pBuffer, sizeof(pBuffer));
-        rtl_secureZeroMemory (pDigest, sizeof(pDigest));
+        rtl_secureZeroMemory(aBuffer.data(), m_nHashLen);
+        rtl_secureZeroMemory(aDigest.data(), m_nHashLen);
     }
 
     return result;
 }
 
-bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
+void MSCodec_CryptoAPI::GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest)
+{
+    std::vector<sal_uInt8> verifier(16);
+    rtl_cipher_decode(m_hCipher,
+        pSaltData, 16, verifier.data(), verifier.size());
+
+    rtl_digest_SHA1(verifier.data(), verifier.size(), pDigest, RTL_DIGEST_LENGTH_SHA1);
+}
+
+bool MSCodec_Std97::InitCipher(sal_uInt32 nCounter)
 {
-    rtlCipherError result;
     sal_uInt8      pKeyData[64]; // 512-bit message block
 
     // Initialize KeyData array.
     (void)memset (pKeyData, 0, sizeof(pKeyData));
 
     // Fill 40 bit of DigestValue into [0..4].
-    (void)memcpy (pKeyData, m_pDigestValue, 5);
+    (void)memcpy (pKeyData, m_aDigestValue.data(), 5);
 
     // Fill counter into [5..8].
     pKeyData[ 5] = sal_uInt8((nCounter >>  0) & 0xff);
@@ -408,7 +448,7 @@ bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
         m_hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5);
 
     // Initialize Cipher with KeyData (for decoding).
-    result = rtl_cipher_init (
+    rtlCipherError result = rtl_cipher_init (
         m_hCipher, rtl_Cipher_DirectionBoth,
         pKeyData, RTL_DIGEST_LENGTH_MD5, nullptr, 0);
 
@@ -418,6 +458,25 @@ bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
     return (result == rtl_Cipher_E_None);
 }
 
+bool MSCodec_CryptoAPI::InitCipher(sal_uInt32 nCounter)
+{
+    // data = hash + iterator (4bytes)
+    std::vector<sal_uInt8> aKeyData(m_aDigestValue);
+    aKeyData.push_back(sal_uInt8((nCounter >>  0) & 0xff));
+    aKeyData.push_back(sal_uInt8((nCounter >>  8) & 0xff));
+    aKeyData.push_back(sal_uInt8((nCounter >> 16) & 0xff));
+    aKeyData.push_back(sal_uInt8((nCounter >> 24) & 0xff));
+
+    std::vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1);
+    rtl_digest_SHA1(aKeyData.data(), aKeyData.size(), hash.data(), RTL_DIGEST_LENGTH_SHA1);
+
+    rtlCipherError result =
+        rtl_cipher_init(m_hCipher, rtl_Cipher_DirectionDecode,
+                        hash.data(), ENCRYPT_KEY_SIZE_AES_128/8, nullptr, 0);
+
+    return (result == rtl_Cipher_E_None);
+}
+
 void MSCodec_Std97::CreateSaltDigest( const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] )
 {
 #if DEBUG_MSO_ENCRYPTION_STD97
@@ -471,7 +530,7 @@ bool MSCodec97::Skip(std::size_t nDatLen)
     return bResult;
 }
 
-void MSCodec_Std97::GetDigestFromSalt( const sal_uInt8 pSaltData[16], sal_uInt8 pDigest[16] )
+void MSCodec_Std97::GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest)
 {
     sal_uInt8 pBuffer[64];
     sal_uInt8 pDigestLocal[16];
@@ -530,7 +589,7 @@ void MSCodec_Std97::GetEncryptKey (
     }
 }
 
-void MSCodec_Std97::GetDocId( sal_uInt8 pDocId[16] )
+void MSCodec97::GetDocId( sal_uInt8 pDocId[16] )
 {
     if ( sizeof( m_pDocId ) == 16 )
         (void)memcpy( pDocId, m_pDocId, 16 );
@@ -557,6 +616,15 @@ EncryptionVerifierAES::EncryptionVerifierAES()
     memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash));
 }
 
+EncryptionVerifierRC4::EncryptionVerifierRC4()
+    : saltSize(SALT_LENGTH)
+    , encryptedVerifierHashSize(SHA1_HASH_LENGTH)
+{
+    memset(salt, 0, sizeof(salt));
+    memset(encryptedVerifier, 0, sizeof(encryptedVerifier));
+    memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash));
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/filter/msfilter/mscodec.hxx b/include/filter/msfilter/mscodec.hxx
index afdf163..52846f8 100644
--- a/include/filter/msfilter/mscodec.hxx
+++ b/include/filter/msfilter/mscodec.hxx
@@ -25,6 +25,7 @@
 #include <rtl/cipher.h>
 #include <rtl/digest.h>
 #include <sal/types.h>
+#include <vector>
 
 namespace com { namespace sun { namespace star {
     namespace beans { struct NamedValue; }
@@ -177,7 +178,7 @@ public:
 class MSFILTER_DLLPUBLIC MSCodec97
 {
 public:
-    MSCodec97(rtlCipher m_hCipher);
+    MSCodec97(size_t nHashLen);
     virtual ~MSCodec97();
 
     /** Initializes the algorithm with the encryption data.
@@ -186,7 +187,7 @@ public:
             The sequence contains the necessary data to initialize
             the codec.
      */
-    virtual bool InitCodec(const css::uno::Sequence< css::beans::NamedValue >& aData) = 0;
+    bool InitCodec(const css::uno::Sequence< css::beans::NamedValue >& aData);
 
     /** Retrieves the encryption data
 
@@ -194,8 +195,37 @@ public:
             The sequence contains the necessary data to initialize
             the codec.
      */
-    virtual css::uno::Sequence< css::beans::NamedValue > GetEncryptionData() = 0;
+    css::uno::Sequence< css::beans::NamedValue > GetEncryptionData();
+
+    /** Initializes the algorithm with the specified password and document ID.
+
+        @param pPassData
+            Wide character array containing the password. Must be zero
+            terminated, which results in a maximum length of 15 characters.
+        @param pDocId
+            Unique document identifier read from or written to the file.
+     */
+    virtual void InitKey(const sal_uInt16 pPassData[16],
+                         const sal_uInt8 pDocId[16]) = 0;
+
+
+    /** Verifies the validity of the password using the passed salt data.
+
+        @precond
+            The codec must be initialized with InitKey() before this function
+            can be used.
+
+        @param pSaltData
+            Salt data block read from the file.
+        @param pSaltDigest
+            Salt digest read from the file.
+
+        @return
+            true = Test was successful.
+     */
+    bool VerifyKey(const sal_uInt8* pSaltData, const sal_uInt8* pSaltDigest);
 
+    virtual void GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest) = 0;
 
     /** Rekeys the codec using the specified counter.
 
@@ -278,12 +308,19 @@ public:
      */
     bool                Skip(std::size_t nDatLen);
 
+    /* allows to get the unique document id from the codec
+     */
+    void                GetDocId( sal_uInt8 pDocId[16] );
+
 private:
                         MSCodec97(const MSCodec97&) = delete;
     MSCodec97&          operator=(const MSCodec97&) = delete;
 
 protected:
+    size_t              m_nHashLen;
     rtlCipher           m_hCipher;
+    sal_uInt8           m_pDocId[16];
+    std::vector<sal_uInt8> m_aDigestValue;
 };
 
 /** Encodes and decodes data from protected MSO 97+ documents.
@@ -295,25 +332,8 @@ protected:
 class MSFILTER_DLLPUBLIC MSCodec_Std97 :  public MSCodec97
 {
 public:
-    explicit            MSCodec_Std97();
-                        ~MSCodec_Std97();
-
-    /** Initializes the algorithm with the encryption data.
-
-        @param aData
-            The sequence contains the necessary data to initialize
-            the codec.
-     */
-    virtual bool InitCodec(const css::uno::Sequence< css::beans::NamedValue >& aData) override;
-
-    /** Retrieves the encryption data
-
-        @return
-            The sequence contains the necessary data to initialize
-            the codec.
-     */
-    virtual css::uno::Sequence<css::beans::NamedValue> GetEncryptionData() override;
-
+    MSCodec_Std97();
+    virtual ~MSCodec_Std97() override;
 
     /** Initializes the algorithm with the specified password and document ID.
 
@@ -323,27 +343,8 @@ public:
         @param pDocId
             Unique document identifier read from or written to the file.
      */
-    void                InitKey(
-                            const sal_uInt16 pPassData[ 16 ],
-                            const sal_uInt8 pDocId[ 16 ] );
-
-    /** Verifies the validity of the password using the passed salt data.
-
-        @precond
-            The codec must be initialized with InitKey() before this function
-            can be used.
-
-        @param pSaltData
-            Salt data block read from the file.
-        @param pSaltDigest
-            Salt digest read from the file.
-
-        @return
-            true = Test was successful.
-     */
-    bool                VerifyKey(
-                            const sal_uInt8 pSaltData[ 16 ],
-                            const sal_uInt8 pSaltDigest[ 16 ] );
+    virtual void InitKey(const sal_uInt16 pPassData[16],
+                         const sal_uInt8 pDocId[16]) override;
 
     /** Rekeys the codec using the specified counter.
 
@@ -384,19 +385,24 @@ public:
                             sal_uInt8 pSaltData[16],
                             sal_uInt8 pSaltDigest[16]);
 
-    /* allows to get the unique document id from the codec
-     */
-    void                GetDocId( sal_uInt8 pDocId[16] );
-
-    void                GetDigestFromSalt( const sal_uInt8 pSaltData[16], sal_uInt8 pDigest[16] );
+    virtual void        GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest) override;
 
 private:
                         MSCodec_Std97( const MSCodec_Std97& ) = delete;
     MSCodec_Std97&      operator=( const MSCodec_Std97& ) = delete;
 
     rtlDigest           m_hDigest;
-    sal_uInt8           m_pDigestValue[ RTL_DIGEST_LENGTH_MD5 ];
-    sal_uInt8           m_pDocId[16];
+};
+
+class MSFILTER_DLLPUBLIC MSCodec_CryptoAPI :  public MSCodec97
+{
+public:
+    MSCodec_CryptoAPI();
+
+    virtual void InitKey(const sal_uInt16 pPassData[16],
+                         const sal_uInt8 pDocId[16]) override;
+    virtual bool InitCipher(sal_uInt32 nCounter) override;
+    virtual void GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest) override;
 };
 
 const sal_uInt32 ENCRYPTINFO_CRYPTOAPI      = 0x00000004;
@@ -459,12 +465,28 @@ struct MSFILTER_DLLPUBLIC EncryptionVerifierAES
     EncryptionVerifierAES();
 };
 
+struct MSFILTER_DLLPUBLIC EncryptionVerifierRC4
+{
+    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[SHA1_HASH_LENGTH];                 // verifier value hash - itself also encrypted
+
+    EncryptionVerifierRC4();
+};
+
 struct MSFILTER_DLLPUBLIC StandardEncryptionInfo
 {
     EncryptionStandardHeader header;
     EncryptionVerifierAES    verifier;
 };
 
+struct MSFILTER_DLLPUBLIC RC4EncryptionInfo
+{
+    EncryptionStandardHeader header;
+    EncryptionVerifierRC4 verifier;
+};
 
 } // namespace msfilter
 
diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx
index fdd43ae..c854d75 100644
--- a/sc/source/filter/excel/xicontent.cxx
+++ b/sc/source/filter/excel/xicontent.cxx
@@ -64,6 +64,7 @@
 #include <memory>
 #include <utility>
 #include <o3tl/make_unique.hxx>
+#include <oox/helper/helper.hxx>
 
 using ::com::sun::star::uno::Sequence;
 using ::std::unique_ptr;
@@ -1110,21 +1111,80 @@ XclImpDecrypterRef lclReadFilepass8_Standard( XclImpStream& rStrm )
     OSL_ENSURE( rStrm.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
     if( rStrm.GetRecLeft() == 48 )
     {
-        sal_uInt8 pnSalt[ 16 ];
-        sal_uInt8 pnVerifier[ 16 ];
-        sal_uInt8 pnVerifierHash[ 16 ];
-        rStrm.Read( pnSalt, 16 );
-        rStrm.Read( pnVerifier, 16 );
-        rStrm.Read( pnVerifierHash, 16 );
-        xDecr.reset( new XclImpBiff8Decrypter( pnSalt, pnVerifier, pnVerifierHash ) );
+        std::vector<sal_uInt8> aSalt(16);
+        std::vector<sal_uInt8> aVerifier(16);
+        std::vector<sal_uInt8> aVerifierHash(16);
+        rStrm.Read(aSalt.data(), 16);
+        rStrm.Read(aVerifier.data(), 16);
+        rStrm.Read(aVerifierHash.data(), 16);
+        xDecr.reset(new XclImpBiff8StdDecrypter(aSalt, aVerifier, aVerifierHash));
     }
     return xDecr;
 }
 
-XclImpDecrypterRef lclReadFilepass8_Strong( XclImpStream& /*rStrm*/ )
+XclImpDecrypterRef lclReadFilepass8_Strong(XclImpStream& rStream)
 {
-    // not supported
-    return XclImpDecrypterRef();
+    //Its possible there are other variants in existance but these
+    //are the defaults I get with Excel 2013
+    XclImpDecrypterRef xDecr;
+
+    msfilter::RC4EncryptionInfo info;
+
+    info.header.flags = rStream.ReaduInt32();
+    if (oox::getFlag( info.header.flags, msfilter::ENCRYPTINFO_EXTERNAL))
+        return xDecr;
+
+    sal_uInt32 nHeaderSize = rStream.ReaduInt32();
+    sal_uInt32 actualHeaderSize = sizeof(info.header);
+
+    if( (nHeaderSize < actualHeaderSize) )
+        return xDecr;
+
+    info.header.flags = rStream.ReaduInt32();
+    info.header.sizeExtra = rStream.ReaduInt32();
+    info.header.algId = rStream.ReaduInt32();
+    info.header.algIdHash = rStream.ReaduInt32();
+    info.header.keyBits = rStream.ReaduInt32();
+    info.header.providedType = rStream.ReaduInt32();
+    info.header.reserved1 = rStream.ReaduInt32();
+    info.header.reserved2 = rStream.ReaduInt32();
+
+    rStream.Ignore(nHeaderSize - actualHeaderSize);
+
+    info.verifier.saltSize = rStream.ReaduInt32();
+    if (info.verifier.saltSize != 16)
+        return xDecr;
+    rStream.Read(&info.verifier.salt, sizeof(info.verifier.salt));
+    rStream.Read(&info.verifier.encryptedVerifier, sizeof(info.verifier.encryptedVerifier));
+
+    info.verifier.encryptedVerifierHashSize = rStream.ReaduInt32();
+    if (info.verifier.encryptedVerifierHashSize != RTL_DIGEST_LENGTH_SHA1)
+        return xDecr;
+    rStream.Read(&info.verifier.encryptedVerifierHash, info.verifier.encryptedVerifierHashSize);
+
+    // check flags and algorithm IDs, required are AES128 and SHA-1
+    if (!oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_CRYPTOAPI))
+        return xDecr;
+
+    if (oox::getFlag(info.header.flags, msfilter::ENCRYPTINFO_AES))
+        return xDecr;
+
+    if (info.header.algId != msfilter::ENCRYPT_ALGO_RC4)
+        return xDecr;
+
+    // hash algorithm ID 0 defaults to SHA-1 too
+    if (info.header.algIdHash != 0 && info.header.algIdHash != msfilter::ENCRYPT_HASH_SHA1)
+        return xDecr;
+
+    xDecr.reset(new XclImpBiff8CryptoAPIDecrypter(
+        std::vector<sal_uInt8>(info.verifier.salt,
+            info.verifier.salt + SAL_N_ELEMENTS(info.verifier.salt)),
+        std::vector<sal_uInt8>(info.verifier.encryptedVerifier,
+            info.verifier.encryptedVerifier + SAL_N_ELEMENTS(info.verifier.encryptedVerifier)),
+        std::vector<sal_uInt8>(info.verifier.encryptedVerifierHash,
+            info.verifier.encryptedVerifierHash + SAL_N_ELEMENTS(info.verifier.encryptedVerifierHash))));
+
+    return xDecr;
 }
 
 XclImpDecrypterRef lclReadFilepass8( XclImpStream& rStrm )
diff --git a/sc/source/filter/excel/xistream.cxx b/sc/source/filter/excel/xistream.cxx
index 31cf3d5..4f28d9c 100644
--- a/sc/source/filter/excel/xistream.cxx
+++ b/sc/source/filter/excel/xistream.cxx
@@ -192,28 +192,50 @@ sal_uInt16 XclImpBiff5Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal
     return nRet;
 }
 
-XclImpBiff8Decrypter::XclImpBiff8Decrypter( sal_uInt8 pnSalt[ 16 ],
-        sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ) :
-    maSalt( pnSalt, pnSalt + 16 ),
-    maVerifier( pnVerifier, pnVerifier + 16 ),
-    maVerifierHash( pnVerifierHash, pnVerifierHash + 16 )
+XclImpBiff8Decrypter::XclImpBiff8Decrypter(const std::vector<sal_uInt8>& rSalt,
+                                           const std::vector<sal_uInt8>& rVerifier,
+                                           const std::vector<sal_uInt8>& rVerifierHash)
+    : maSalt(rSalt)
+    , maVerifier(rVerifier)
+    , maVerifierHash(rVerifierHash)
+    , mpCodec(nullptr)
 {
 }
 
-XclImpBiff8Decrypter::XclImpBiff8Decrypter( const XclImpBiff8Decrypter& rSrc ) :
-    XclImpDecrypter( rSrc ),
-    maEncryptionData( rSrc.maEncryptionData ),
-    maSalt( rSrc.maSalt ),
-    maVerifier( rSrc.maVerifier ),
-    maVerifierHash( rSrc.maVerifierHash )
+XclImpBiff8Decrypter::XclImpBiff8Decrypter(const XclImpBiff8Decrypter& rSrc)
+    : XclImpDecrypter(rSrc)
+    , maEncryptionData(rSrc.maEncryptionData)
+    , maSalt(rSrc.maSalt)
+    , maVerifier(rSrc.maVerifier)
+    , maVerifierHash(rSrc.maVerifierHash)
+    , mpCodec(nullptr)
 {
-    if( IsValid() )
-        maCodec.InitCodec( maEncryptionData );
 }
 
-XclImpBiff8Decrypter* XclImpBiff8Decrypter::OnClone() const
+XclImpBiff8StdDecrypter::XclImpBiff8StdDecrypter(const XclImpBiff8StdDecrypter& rSrc)
+    : XclImpBiff8Decrypter(rSrc)
 {
-    return new XclImpBiff8Decrypter( *this );
+    mpCodec = &maCodec;
+    if (IsValid())
+        maCodec.InitCodec(maEncryptionData);
+}
+
+XclImpBiff8StdDecrypter* XclImpBiff8StdDecrypter::OnClone() const
+{
+    return new XclImpBiff8StdDecrypter(*this);
+}
+
+XclImpBiff8CryptoAPIDecrypter::XclImpBiff8CryptoAPIDecrypter(const XclImpBiff8CryptoAPIDecrypter& rSrc)
+    : XclImpBiff8Decrypter(rSrc)
+{
+    mpCodec = &maCodec;
+    if (IsValid())
+        maCodec.InitCodec(maEncryptionData);
+}
+
+XclImpBiff8CryptoAPIDecrypter* XclImpBiff8CryptoAPIDecrypter::OnClone() const
+{
+    return new XclImpBiff8CryptoAPIDecrypter(*this);
 }
 
 uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const OUString& rPassword )
@@ -232,9 +254,9 @@ uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const
             *aIt = static_cast< sal_uInt16 >( *pcChar );
 
         // init codec
-        maCodec.InitKey( &aPassVect.front(), &maSalt.front() );
-        if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
-            maEncryptionData = maCodec.GetEncryptionData();
+        mpCodec->InitKey( &aPassVect.front(), &maSalt.front() );
+        if ( mpCodec->VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
+            maEncryptionData = mpCodec->GetEncryptionData();
     }
 
     return maEncryptionData;
@@ -247,9 +269,9 @@ bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::N
     if( rEncryptionData.getLength() )
     {
         // init codec
-        maCodec.InitCodec( rEncryptionData );
+        mpCodec->InitCodec( rEncryptionData );
 
-        if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
+        if ( mpCodec->VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
             maEncryptionData = rEncryptionData;
     }
 
@@ -269,13 +291,13 @@ void XclImpBiff8Decrypter::OnUpdate( std::size_t nOldStrmPos, std::size_t nNewSt
         /*  Rekey cipher, if block changed or if previous offset in same block. */
         if( (nNewBlock != nOldBlock) || (nNewOffset < nOldOffset) )
         {
-            maCodec.InitCipher( nNewBlock );
+            mpCodec->InitCipher( nNewBlock );
             nOldOffset = 0;     // reset nOldOffset for next if() statement
         }
 
         /*  Seek to correct offset. */
         if( nNewOffset > nOldOffset )
-            maCodec.Skip( nNewOffset - nOldOffset );
+            mpCodec->Skip( nNewOffset - nOldOffset );
     }
 }
 
@@ -293,9 +315,9 @@ sal_uInt16 XclImpBiff8Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal
         // read the block from stream
         nRet = nRet + static_cast<sal_uInt16>(rStrm.ReadBytes(pnCurrData, nDecBytes));
         // decode the block inplace
-        maCodec.Decode( pnCurrData, nDecBytes, pnCurrData, nDecBytes );
+        mpCodec->Decode( pnCurrData, nDecBytes, pnCurrData, nDecBytes );
         if( GetOffset( rStrm.Tell() ) == 0 )
-            maCodec.InitCipher( GetBlock( rStrm.Tell() ) );
+            mpCodec->InitCipher( GetBlock( rStrm.Tell() ) );
 
         pnCurrData += nDecBytes;
         nBytesLeft = nBytesLeft - nDecBytes;
diff --git a/sc/source/filter/inc/xistream.hxx b/sc/source/filter/inc/xistream.hxx
index 4e0e63b..3a53643 100644
--- a/sc/source/filter/inc/xistream.hxx
+++ b/sc/source/filter/inc/xistream.hxx
@@ -119,16 +119,7 @@ private:
 /** Decrypts BIFF8 stream contents using the given document identifier. */
 class XclImpBiff8Decrypter : public XclImpDecrypter
 {
-public:
-    explicit            XclImpBiff8Decrypter( sal_uInt8 pnSalt[ 16 ],
-                            sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] );
-
 private:
-    /** Private copy c'tor for OnClone(). */
-    explicit            XclImpBiff8Decrypter( const XclImpBiff8Decrypter& rSrc );
-
-    /** Implementation of cloning this object. */
-    virtual XclImpBiff8Decrypter* OnClone() const override;
     /** Implements password verification and initialization of the decoder. */
     virtual css::uno::Sequence< css::beans::NamedValue >
         OnVerifyPassword( const OUString& rPassword ) override;
@@ -143,12 +134,62 @@ private:
     /** Returns the block offset corresponding to the passed stream position. */
     static sal_uInt16   GetOffset( std::size_t nStrmPos );
 
+protected:
+    explicit  XclImpBiff8Decrypter(const std::vector<sal_uInt8>& rSalt,
+                                   const std::vector<sal_uInt8>& rVerifier,
+                                   const std::vector<sal_uInt8>& rVerifierHash);
+
+    explicit  XclImpBiff8Decrypter(const XclImpBiff8Decrypter& rSrc);
+
+    css::uno::Sequence< css::beans::NamedValue > maEncryptionData;
+    std::vector< sal_uInt8 > maSalt;
+    std::vector< sal_uInt8 > maVerifier;
+    std::vector< sal_uInt8 > maVerifierHash;
+    msfilter::MSCodec97* mpCodec;       /// Crypto algorithm implementation.
+};
+
+class XclImpBiff8StdDecrypter : public XclImpBiff8Decrypter
+{
+public:
+    explicit XclImpBiff8StdDecrypter(const std::vector<sal_uInt8>& rSalt,
+                                     const std::vector<sal_uInt8>& rVerifier,
+                                     const std::vector<sal_uInt8>& rVerifierHash)
+        : XclImpBiff8Decrypter(rSalt, rVerifier, rVerifierHash)
+    {
+        mpCodec = &maCodec;
+    }
+
+private:
+    /** Private copy c'tor for OnClone(). */
+    explicit XclImpBiff8StdDecrypter(const XclImpBiff8StdDecrypter& rSrc);
+
+    /** Implementation of cloning this object. */
+    virtual XclImpBiff8StdDecrypter* OnClone() const override;
+
 private:
     ::msfilter::MSCodec_Std97 maCodec;       /// Crypto algorithm implementation.
-    css::uno::Sequence< css::beans::NamedValue > maEncryptionData;
-    ::std::vector< sal_uInt8 > maSalt;
-    ::std::vector< sal_uInt8 > maVerifier;
-    ::std::vector< sal_uInt8 > maVerifierHash;
+};
+
+class XclImpBiff8CryptoAPIDecrypter : public XclImpBiff8Decrypter
+{
+public:
+    explicit XclImpBiff8CryptoAPIDecrypter(const std::vector<sal_uInt8>& rSalt,
+                                           const std::vector<sal_uInt8>& rVerifier,
+                                           const std::vector<sal_uInt8>& rVerifierHash)
+        : XclImpBiff8Decrypter(rSalt, rVerifier, rVerifierHash)
+    {
+        mpCodec = &maCodec;
+    }
+
+private:
+    /** Private copy c'tor for OnClone(). */
+    explicit XclImpBiff8CryptoAPIDecrypter(const XclImpBiff8CryptoAPIDecrypter& rSrc);
+
+    /** Implementation of cloning this object. */
+    virtual XclImpBiff8CryptoAPIDecrypter* OnClone() const override;
+
+private:
+    ::msfilter::MSCodec_CryptoAPI maCodec;       /// Crypto algorithm implementation.
 };
 
 // Stream
commit 06916c839b16866b47235306d2db50850df0ad7c
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Oct 20 14:52:26 2016 +0100

    split MSCodec_Std97 into a baseclass MSCodec97
    
    Change-Id: Ia3c41a048169c78684800def94e53fc9f3201e30

diff --git a/filter/source/msfilter/mscodec.cxx b/filter/source/msfilter/mscodec.cxx
index 9b9d243..20a1f4a 100644
--- a/filter/source/msfilter/mscodec.cxx
+++ b/filter/source/msfilter/mscodec.cxx
@@ -245,27 +245,31 @@ void MSCodec_Xor95::Skip( std::size_t nBytes )
     mnOffset = (mnOffset + nBytes) & 0x0F;
 }
 
-
-MSCodec_Std97::MSCodec_Std97 ()
+MSCodec97::MSCodec97(rtlCipher hCipher)
+    : m_hCipher(hCipher)
 {
-    m_hCipher = rtl_cipher_create (
-        rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream);
-    OSL_ASSERT(m_hCipher != nullptr);
-
-    m_hDigest = rtl_digest_create (
-        rtl_Digest_AlgorithmMD5);
-    OSL_ASSERT(m_hDigest != nullptr);
+}
 
+MSCodec_Std97::MSCodec_Std97()
+    : MSCodec97(rtl_cipher_create(rtl_Cipher_AlgorithmARCFOUR, rtl_Cipher_ModeStream))
+{
+    assert(m_hCipher != nullptr);
+    m_hDigest = rtl_digest_create(rtl_Digest_AlgorithmMD5);
+    assert(m_hDigest != nullptr);
     (void)memset (m_pDigestValue, 0, sizeof(m_pDigestValue));
     (void)memset (m_pDocId, 0, sizeof(m_pDocId));
 }
 
-MSCodec_Std97::~MSCodec_Std97 ()
+MSCodec97::~MSCodec97()
+{
+    rtl_cipher_destroy(m_hCipher);
+}
+
+MSCodec_Std97::~MSCodec_Std97()
 {
     (void)memset (m_pDigestValue, 0, sizeof(m_pDigestValue));
     (void)memset (m_pDocId, 0, sizeof(m_pDocId));
-    rtl_digest_destroy (m_hDigest);
-    rtl_cipher_destroy (m_hCipher);
+    rtl_digest_destroy(m_hDigest);
 }
 
 #if DEBUG_MSO_ENCRYPTION_STD97
@@ -431,7 +435,7 @@ void MSCodec_Std97::CreateSaltDigest( const sal_uInt8 nSaltData[16], sal_uInt8 n
     }
 }
 
-bool MSCodec_Std97::Encode (
+bool MSCodec97::Encode (
     const void *pData,   std::size_t nDatLen,
     sal_uInt8  *pBuffer, std::size_t nBufLen)
 {
@@ -441,7 +445,7 @@ bool MSCodec_Std97::Encode (
     return (result == rtl_Cipher_E_None);
 }
 
-bool MSCodec_Std97::Decode (
+bool MSCodec97::Decode (
     const void *pData,   std::size_t nDatLen,
     sal_uInt8  *pBuffer, std::size_t nBufLen)
 {
@@ -451,7 +455,7 @@ bool MSCodec_Std97::Decode (
     return (result == rtl_Cipher_E_None);
 }
 
-bool MSCodec_Std97::Skip( std::size_t nDatLen )
+bool MSCodec97::Skip(std::size_t nDatLen)
 {
     sal_uInt8 pnDummy[ 1024 ];
     std::size_t nDatLeft = nDatLen;
diff --git a/include/filter/msfilter/mscodec.hxx b/include/filter/msfilter/mscodec.hxx
index fa71a15..afdf163 100644
--- a/include/filter/msfilter/mscodec.hxx
+++ b/include/filter/msfilter/mscodec.hxx
@@ -174,18 +174,11 @@ public:
     virtual void                Decode( sal_uInt8* pnData, std::size_t nBytes ) override;
 };
 
-
-/** Encodes and decodes data from protected MSO 97+ documents.
-
-    This is a wrapper class around low level cryptographic functions from RTL.
-    Implementation is based on the wvDecrypt package by Caolan McNamara:
-    http://www.csn.ul.ie/~caolan/docs/wvDecrypt.html
- */
-class MSFILTER_DLLPUBLIC MSCodec_Std97
+class MSFILTER_DLLPUBLIC MSCodec97
 {
 public:
-    explicit            MSCodec_Std97();
-                        ~MSCodec_Std97();
+    MSCodec97(rtlCipher m_hCipher);
+    virtual ~MSCodec97();
 
     /** Initializes the algorithm with the encryption data.
 
@@ -193,7 +186,7 @@ public:
             The sequence contains the necessary data to initialize
             the codec.
      */
-    bool                InitCodec( const css::uno::Sequence< css::beans::NamedValue >& aData );
+    virtual bool InitCodec(const css::uno::Sequence< css::beans::NamedValue >& aData) = 0;
 
     /** Retrieves the encryption data
 
@@ -201,38 +194,8 @@ public:
             The sequence contains the necessary data to initialize
             the codec.
      */
-    css::uno::Sequence< css::beans::NamedValue > GetEncryptionData();
-
-
-    /** Initializes the algorithm with the specified password and document ID.
-
-        @param pPassData
-            Wide character array containing the password. Must be zero
-            terminated, which results in a maximum length of 15 characters.
-        @param pDocId
-            Unique document identifier read from or written to the file.
-     */
-    void                InitKey(
-                            const sal_uInt16 pPassData[ 16 ],
-                            const sal_uInt8 pDocId[ 16 ] );
-
-    /** Verifies the validity of the password using the passed salt data.
-
-        @precond
-            The codec must be initialized with InitKey() before this function
-            can be used.
-
-        @param pSaltData
-            Salt data block read from the file.
-        @param pSaltDigest
-            Salt digest read from the file.
+    virtual css::uno::Sequence< css::beans::NamedValue > GetEncryptionData() = 0;
 
-        @return
-            true = Test was successful.
-     */
-    bool                VerifyKey(
-                            const sal_uInt8 pSaltData[ 16 ],
-                            const sal_uInt8 pSaltDigest[ 16 ] );
 
     /** Rekeys the codec using the specified counter.
 
@@ -249,11 +212,7 @@ public:
         @param nCounter
             Block counter used to rekey the cipher.
      */
-    bool                InitCipher( sal_uInt32 nCounter );
-
-    /** Creates an MD5 digest of salt digest. */
-    void               CreateSaltDigest(
-                            const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] );
+    virtual bool                InitCipher(sal_uInt32 nCounter) = 0;
 
     /** Encodes a block of memory.
 
@@ -277,9 +236,8 @@ public:
         @return
             true = Encoding was successful (no error occurred).
     */
-    bool                Encode(
-                            const void* pData, std::size_t nDatLen,
-                            sal_uInt8* pBuffer, std::size_t nBufLen );
+    bool                Encode(const void* pData, std::size_t nDatLen,
+                               sal_uInt8* pBuffer, std::size_t nBufLen);
 
     /** Decodes a block of memory.
 
@@ -303,9 +261,8 @@ public:
         @return
             true = Decoding was successful (no error occurred).
     */
-    bool                Decode(
-                            const void* pData, std::size_t nDatLen,
-                            sal_uInt8* pBuffer, std::size_t nBufLen );
+    bool                Decode(const void* pData, std::size_t nDatLen,
+                               sal_uInt8* pBuffer, std::size_t nBufLen);
 
     /** Lets the cipher skip a specific amount of bytes.
 
@@ -319,7 +276,95 @@ public:
         @param nDatLen
             Number of bytes to be skipped (cipher "seeks" forward).
      */
-    bool                Skip( std::size_t nDatLen );
+    bool                Skip(std::size_t nDatLen);
+
+private:
+                        MSCodec97(const MSCodec97&) = delete;
+    MSCodec97&          operator=(const MSCodec97&) = delete;
+
+protected:
+    rtlCipher           m_hCipher;
+};
+
+/** Encodes and decodes data from protected MSO 97+ documents.
+
+    This is a wrapper class around low level cryptographic functions from RTL.
+    Implementation is based on the wvDecrypt package by Caolan McNamara:
+    http://www.csn.ul.ie/~caolan/docs/wvDecrypt.html
+ */
+class MSFILTER_DLLPUBLIC MSCodec_Std97 :  public MSCodec97
+{
+public:
+    explicit            MSCodec_Std97();
+                        ~MSCodec_Std97();
+
+    /** Initializes the algorithm with the encryption data.
+
+        @param aData
+            The sequence contains the necessary data to initialize
+            the codec.
+     */
+    virtual bool InitCodec(const css::uno::Sequence< css::beans::NamedValue >& aData) override;
+
+    /** Retrieves the encryption data
+
+        @return
+            The sequence contains the necessary data to initialize
+            the codec.
+     */
+    virtual css::uno::Sequence<css::beans::NamedValue> GetEncryptionData() override;
+
+
+    /** Initializes the algorithm with the specified password and document ID.
+
+        @param pPassData
+            Wide character array containing the password. Must be zero
+            terminated, which results in a maximum length of 15 characters.
+        @param pDocId
+            Unique document identifier read from or written to the file.
+     */
+    void                InitKey(
+                            const sal_uInt16 pPassData[ 16 ],
+                            const sal_uInt8 pDocId[ 16 ] );
+
+    /** Verifies the validity of the password using the passed salt data.
+
+        @precond
+            The codec must be initialized with InitKey() before this function
+            can be used.
+
+        @param pSaltData
+            Salt data block read from the file.
+        @param pSaltDigest
+            Salt digest read from the file.
+
+        @return
+            true = Test was successful.
+     */
+    bool                VerifyKey(
+                            const sal_uInt8 pSaltData[ 16 ],
+                            const sal_uInt8 pSaltDigest[ 16 ] );
+
+    /** Rekeys the codec using the specified counter.
+
+        After reading a specific amount of data the cipher algorithm needs to
+        be rekeyed using a counter that counts the data blocks.
+
+        The block size is for example 512 Bytes for Word files and 1024 Bytes
+        for Excel files.
+
+        @precond
+            The codec must be initialized with InitKey() before this function
+            can be used.
+
+        @param nCounter
+            Block counter used to rekey the cipher.
+     */
+    virtual bool InitCipher(sal_uInt32 nCounter) override;
+
+    /** Creates an MD5 digest of salt digest. */
+    void               CreateSaltDigest(
+                            const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] );
 
     /** Gets salt data and salt digest.
 
@@ -349,7 +394,6 @@ private:
                         MSCodec_Std97( const MSCodec_Std97& ) = delete;
     MSCodec_Std97&      operator=( const MSCodec_Std97& ) = delete;
 
-    rtlCipher           m_hCipher;
     rtlDigest           m_hDigest;
     sal_uInt8           m_pDigestValue[ RTL_DIGEST_LENGTH_MD5 ];
     sal_uInt8           m_pDocId[16];
commit 3fabbd0a22219464545f933fc28c869a6fa89546
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Oct 20 14:31:58 2016 +0100

    rework things in light of now available documentation
    
    Change-Id: If5f75e27191017a8c6a3929e2a70d21840f157c6

diff --git a/include/filter/msfilter/mscodec.hxx b/include/filter/msfilter/mscodec.hxx
index dd3acbc..fa71a15 100644
--- a/include/filter/msfilter/mscodec.hxx
+++ b/include/filter/msfilter/mscodec.hxx
@@ -374,6 +374,8 @@ 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 1997 (major = 1, minor = 1)
+const sal_uInt32 VERSION_INFO_1997_FORMAT       = 0x00010001;
 // 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 used in MS Office 2007 SP2 and older (major = 4, minor = 2)
diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx
index 27e84eb..fdd43ae 100644
--- a/sc/source/filter/excel/xicontent.cxx
+++ b/sc/source/filter/excel/xicontent.cxx
@@ -1141,20 +1141,22 @@ XclImpDecrypterRef lclReadFilepass8( XclImpStream& rStrm )
 
         case EXC_FILEPASS_BIFF8:
         {
-            rStrm.Ignore( 2 );
-            sal_uInt16 nSubMode(0);
-            nSubMode = rStrm.ReaduInt16();
-            switch( nSubMode )
+            sal_uInt32 nVersion = rStrm.ReaduInt32();
+            if (nVersion == msfilter::VERSION_INFO_1997_FORMAT)
             {
-                case EXC_FILEPASS_BIFF8_STD:
-                    xDecr = lclReadFilepass8_Standard( rStrm );
-                break;
-                case EXC_FILEPASS_BIFF8_STRONG:
-                    xDecr = lclReadFilepass8_Strong( rStrm );
-                break;
-                default:
-                    OSL_FAIL( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
+                //A Version structure where Version.vMajor MUST be 0x0001,
+                //and Version.vMinor MUST be 0x0001.
+                xDecr = lclReadFilepass8_Standard(rStrm);
+            }
+            else if (nVersion == msfilter::VERSION_INFO_2007_FORMAT ||
+                     nVersion == msfilter::VERSION_INFO_2007_FORMAT_SP2)
+            {
+                //Version.vMajor MUST be 0x0002, 0x0003 or 0x0004 and
+                //Version.vMinor MUST be 0x0002.
+                xDecr = lclReadFilepass8_Strong(rStrm);
             }
+            else
+                OSL_FAIL("lclReadFilepass8 - unknown BIFF8 encryption sub mode");
         }
         break;
 
diff --git a/sc/source/filter/inc/xlcontent.hxx b/sc/source/filter/inc/xlcontent.hxx
index 6bb7b0b..ec94750 100644
--- a/sc/source/filter/inc/xlcontent.hxx
+++ b/sc/source/filter/inc/xlcontent.hxx
@@ -39,8 +39,6 @@ const sal_uInt16 EXC_ID_FILEPASS            = 0x002F;
 
 const sal_uInt16 EXC_FILEPASS_BIFF5         = 0x0000;
 const sal_uInt16 EXC_FILEPASS_BIFF8         = 0x0001;
-const sal_uInt16 EXC_FILEPASS_BIFF8_STD     = 0x0001;
-const sal_uInt16 EXC_FILEPASS_BIFF8_STRONG  = 0x0002;
 
 // (0x00FC, 0x00FF) SST, EXTSST -----------------------------------------------
 
commit fc514cbf30be1613fdf4d4b7c12cbd55ca08b9b0
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Oct 20 14:25:13 2016 +0100

    move some useful header information to mscodec for reuse
    
    Change-Id: Ic7adf3ed3c8279cc93a06975d6fb337210d1af87

diff --git a/filter/source/msfilter/mscodec.cxx b/filter/source/msfilter/mscodec.cxx
index 141e361..9b9d243 100644
--- a/filter/source/msfilter/mscodec.cxx
+++ b/filter/source/msfilter/mscodec.cxx
@@ -532,6 +532,26 @@ void MSCodec_Std97::GetDocId( sal_uInt8 pDocId[16] )
         (void)memcpy( pDocId, m_pDocId, 16 );
 }
 
+EncryptionStandardHeader::EncryptionStandardHeader()
+{
+    flags        = 0;
+    sizeExtra    = 0;
+    algId        = 0;
+    algIdHash    = 0;
+    keyBits      = 0;
+    providedType = 0;
+    reserved1    = 0;
+    reserved2    = 0;
+}
+
+EncryptionVerifierAES::EncryptionVerifierAES()
+    : saltSize(SALT_LENGTH)
+    , encryptedVerifierHashSize(SHA1_HASH_LENGTH)
+{
+    memset(salt, 0, sizeof(salt));
+    memset(encryptedVerifier, 0, sizeof(encryptedVerifier));
+    memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash));
+}
 
 }
 
diff --git a/include/filter/msfilter/mscodec.hxx b/include/filter/msfilter/mscodec.hxx
index 1b91df6..dd3acbc 100644
--- a/include/filter/msfilter/mscodec.hxx
+++ b/include/filter/msfilter/mscodec.hxx
@@ -355,6 +355,70 @@ private:
     sal_uInt8           m_pDocId[16];
 };
 
+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 used in MS Office 2007 SP2 and older (major = 4, minor = 2)
+const sal_uInt32 VERSION_INFO_2007_FORMAT_SP2   = 0x00020004;
+
+// 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 SHA1_HASH_LENGTH = RTL_DIGEST_LENGTH_SHA1; // 20
+const sal_uInt32 SHA256_HASH_LENGTH = 32;
+const sal_uInt32 SHA512_HASH_LENGTH = 64;
+
+struct MSFILTER_DLLPUBLIC 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 MSFILTER_DLLPUBLIC 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[SHA256_HASH_LENGTH];               // verifier value hash - itself also encrypted
+
+    EncryptionVerifierAES();
+};
+
+struct MSFILTER_DLLPUBLIC StandardEncryptionInfo
+{
+    EncryptionStandardHeader header;
+    EncryptionVerifierAES    verifier;
+};
+
 
 } // namespace msfilter
 
diff --git a/include/oox/crypto/Standard2007Engine.hxx b/include/oox/crypto/Standard2007Engine.hxx
index 1650b62..42998b4 100644
--- a/include/oox/crypto/Standard2007Engine.hxx
+++ b/include/oox/crypto/Standard2007Engine.hxx
@@ -11,6 +11,7 @@
 #ifndef INCLUDED_OOX_CRYPTO_STANDARD2007ENGINE_HXX
 #define INCLUDED_OOX_CRYPTO_STANDARD2007ENGINE_HXX
 
+#include <filter/msfilter/mscodec.hxx>
 #include <oox/crypto/CryptoEngine.hxx>
 #include <rtl/digest.h>
 #include <rtl/ustring.hxx>
@@ -24,73 +25,9 @@ namespace oox {
 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 used in MS Office 2007 SP2 and older (major = 4, minor = 2)
-const sal_uInt32 VERSION_INFO_2007_FORMAT_SP2   = 0x00020004;
-
-// 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 SHA1_HASH_LENGTH = RTL_DIGEST_LENGTH_SHA1; // 20
-const sal_uInt32 SHA256_HASH_LENGTH = 32;
-const sal_uInt32 SHA512_HASH_LENGTH = 64;
-
-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[SHA256_HASH_LENGTH];               // verifier value hash - itself also encrypted
-
-    EncryptionVerifierAES();
-};
-
-struct StandardEncryptionInfo
-{
-    EncryptionStandardHeader header;
-    EncryptionVerifierAES    verifier;
-};
-
 class Standard2007Engine : public CryptoEngine
 {
-    StandardEncryptionInfo mInfo;
+    msfilter::StandardEncryptionInfo mInfo;
 
     bool generateVerifier();
     bool calculateEncryptionKey(const OUString& rPassword);
@@ -99,7 +36,7 @@ public:
     Standard2007Engine();
     virtual ~Standard2007Engine() override;
 
-    StandardEncryptionInfo& getInfo() { return mInfo;}
+    msfilter::StandardEncryptionInfo& getInfo() { return mInfo;}
 
     virtual bool generateEncryptionKey(const OUString& rPassword) override;
 
diff --git a/oox/source/crypto/CryptTools.cxx b/oox/source/crypto/CryptTools.cxx
index d6dbc96..4bb3ec2 100644
--- a/oox/source/crypto/CryptTools.cxx
+++ b/oox/source/crypto/CryptTools.cxx
@@ -9,8 +9,8 @@
  */
 
 #include "oox/crypto/CryptTools.hxx"
+#include <filter/msfilter/mscodec.hxx>
 #include <com/sun/star/uno/RuntimeException.hpp>
-#include "oox/crypto/Standard2007Engine.hxx"
 
 namespace oox {
 namespace core {
@@ -267,9 +267,9 @@ sal_uInt32 Digest::getLength()
     switch(meType)
     {
         case SHA1:
-            return oox::core::SHA1_HASH_LENGTH;
+            return msfilter::SHA1_HASH_LENGTH;
         case SHA512:
-            return oox::core::SHA512_HASH_LENGTH;
+            return msfilter::SHA512_HASH_LENGTH;
         default:
             break;
     }
diff --git a/oox/source/crypto/DocumentDecryption.cxx b/oox/source/crypto/DocumentDecryption.cxx
index c843ad1..3fcbc57 100644
--- a/oox/source/crypto/DocumentDecryption.cxx
+++ b/oox/source/crypto/DocumentDecryption.cxx
@@ -241,7 +241,7 @@ bool DocumentDecryption::readAgileEncryptionInfo(Reference< XInputStream >& xInp
         info.cipherAlgorithm == "AES" &&
         info.cipherChaining  == "ChainingModeCBC" &&
         info.hashAlgorithm   == "SHA1" &&
-        info.hashSize        == SHA1_HASH_LENGTH)
+        info.hashSize        == msfilter::SHA1_HASH_LENGTH)
     {
         return true;
     }
@@ -251,7 +251,7 @@ bool DocumentDecryption::readAgileEncryptionInfo(Reference< XInputStream >& xInp
         info.cipherAlgorithm == "AES" &&
         info.cipherChaining  == "ChainingModeCBC" &&
         info.hashAlgorithm   == "SHA512" &&
-        info.hashSize        == SHA512_HASH_LENGTH)
+        info.hashSize        == msfilter::SHA512_HASH_LENGTH)
     {
         return true;
     }
@@ -263,10 +263,10 @@ bool DocumentDecryption::readStandard2007EncryptionInfo(BinaryInputStream& rStre
 {
     Standard2007Engine* engine = new Standard2007Engine();
     mEngine.reset(engine);
-    StandardEncryptionInfo& info = engine->getInfo();
+    msfilter::StandardEncryptionInfo& info = engine->getInfo();
 
     info.header.flags = rStream.readuInt32();
-    if( getFlag( info.header.flags, ENCRYPTINFO_EXTERNAL ) )
+    if( getFlag( info.header.flags, msfilter::ENCRYPTINFO_EXTERNAL ) )
         return false;
 
     sal_uInt32 nHeaderSize = rStream.readuInt32();
@@ -297,18 +297,18 @@ bool DocumentDecryption::readStandard2007EncryptionInfo(BinaryInputStream& rStre
         return false;
 
     // check flags and algorithm IDs, required are AES128 and SHA-1
-    if( !getFlag( info.header.flags , ENCRYPTINFO_CRYPTOAPI ) )
+    if( !getFlag( info.header.flags, msfilter::ENCRYPTINFO_CRYPTOAPI ) )
         return false;
 
-    if( !getFlag( info.header.flags, ENCRYPTINFO_AES ) )
+    if( !getFlag( info.header.flags, msfilter::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 )
+    if( info.header.algId != 0 && info.header.algId != msfilter::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 )
+    if( info.header.algIdHash != 0 && info.header.algIdHash != msfilter::ENCRYPT_HASH_SHA1 )
         return false;
 
     if( info.verifier.encryptedVerifierHashSize != 20 )
@@ -332,12 +332,12 @@ bool DocumentDecryption::readEncryptionInfo()
 
     switch (aVersion)
     {
-        case VERSION_INFO_2007_FORMAT:
-        case VERSION_INFO_2007_FORMAT_SP2:
+        case msfilter::VERSION_INFO_2007_FORMAT:
+        case msfilter::VERSION_INFO_2007_FORMAT_SP2:
             mCryptoType = STANDARD_2007; // Set encryption info format
             bResult = readStandard2007EncryptionInfo( aBinaryInputStream );
             break;
-        case VERSION_INFO_AGILE:
+        case msfilter::VERSION_INFO_AGILE:
             mCryptoType = AGILE; // Set encryption info format
             aBinaryInputStream.skip(4);
             bResult = readAgileEncryptionInfo( xEncryptionInfo );
diff --git a/oox/source/crypto/Standard2007Engine.cxx b/oox/source/crypto/Standard2007Engine.cxx
index 87ef81b..ecf9d8c 100644
--- a/oox/source/crypto/Standard2007Engine.cxx
+++ b/oox/source/crypto/Standard2007Engine.cxx
@@ -42,27 +42,6 @@ static const OUString lclCspName = "Microsoft Enhanced RSA and AES Cryptographic
 
 } // namespace
 
-EncryptionStandardHeader::EncryptionStandardHeader()
-{
-    flags        = 0;
-    sizeExtra    = 0;
-    algId        = 0;
-    algIdHash    = 0;
-    keyBits      = 0;
-    providedType = 0;
-    reserved1    = 0;
-    reserved2    = 0;
-}
-
-EncryptionVerifierAES::EncryptionVerifierAES()
-    : saltSize(SALT_LENGTH)
-    , encryptedVerifierHashSize(SHA1_HASH_LENGTH)
-{
-    memset(salt, 0, sizeof(salt));
-    memset(encryptedVerifier, 0, sizeof(encryptedVerifier));
-    memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash));
-}
-
 Standard2007Engine::Standard2007Engine() :
     CryptoEngine()
 {}
@@ -76,23 +55,23 @@ bool Standard2007Engine::generateVerifier()
     if (mKey.size() != 16)
         return false;
 
-    vector<sal_uInt8> verifier(ENCRYPTED_VERIFIER_LENGTH);
-    vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
+    vector<sal_uInt8> verifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
+    vector<sal_uInt8> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
 
     lclRandomGenerateValues(&verifier[0], verifier.size());
 
     vector<sal_uInt8> iv;
     Encrypt aEncryptorVerifier(mKey, iv, Crypto::AES_128_ECB);
-    if (aEncryptorVerifier.update(encryptedVerifier, verifier) != ENCRYPTED_VERIFIER_LENGTH)
+    if (aEncryptorVerifier.update(encryptedVerifier, verifier) != msfilter::ENCRYPTED_VERIFIER_LENGTH)
         return false;
     std::copy(encryptedVerifier.begin(), encryptedVerifier.end(), mInfo.verifier.encryptedVerifier);
 
-    vector<sal_uInt8> hash(SHA1_HASH_LENGTH, 0);
-    mInfo.verifier.encryptedVerifierHashSize = SHA1_HASH_LENGTH;
+    vector<sal_uInt8> hash(msfilter::SHA1_HASH_LENGTH, 0);
+    mInfo.verifier.encryptedVerifierHashSize = msfilter::SHA1_HASH_LENGTH;
     Digest::sha1(hash, verifier);
-    hash.resize(SHA256_HASH_LENGTH, 0);
+    hash.resize(msfilter::SHA256_HASH_LENGTH, 0);
 
-    vector<sal_uInt8> encryptedHash(SHA256_HASH_LENGTH, 0);
+    vector<sal_uInt8> encryptedHash(msfilter::SHA256_HASH_LENGTH, 0);
 
     Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
     aEncryptorHash.update(encryptedHash, hash, hash.size());
@@ -119,13 +98,13 @@ bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
         initialData.begin() + saltSize);
 
     // use "hash" vector for result of sha1 hashing
-    vector<sal_uInt8> hash(SHA1_HASH_LENGTH, 0);
+    vector<sal_uInt8> hash(msfilter::SHA1_HASH_LENGTH, 0);
 
     // calculate SHA1 hash of initialData
     Digest::sha1(hash, initialData);
 
     // data = iterator (4bytes) + hash
-    vector<sal_uInt8> data(SHA1_HASH_LENGTH + 4, 0);
+    vector<sal_uInt8> data(msfilter::SHA1_HASH_LENGTH + 4, 0);
 
     for (sal_Int32 i = 0; i < 50000; ++i)
     {
@@ -134,7 +113,7 @@ bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
         Digest::sha1(hash, data);
     }
     std::copy(hash.begin(), hash.end(), data.begin() );
-    std::fill(data.begin() + SHA1_HASH_LENGTH, data.end(), 0 );
+    std::fill(data.begin() + msfilter::SHA1_HASH_LENGTH, data.end(), 0 );
 
     Digest::sha1(hash, data);
 
@@ -156,16 +135,16 @@ bool Standard2007Engine::generateEncryptionKey(const OUString& password)
 
     calculateEncryptionKey(password);
 
-    vector<sal_uInt8> encryptedVerifier(ENCRYPTED_VERIFIER_LENGTH);
+    vector<sal_uInt8> encryptedVerifier(msfilter::ENCRYPTED_VERIFIER_LENGTH);
     std::copy(
         mInfo.verifier.encryptedVerifier,
-        mInfo.verifier.encryptedVerifier + ENCRYPTED_VERIFIER_LENGTH,
+        mInfo.verifier.encryptedVerifier + msfilter::ENCRYPTED_VERIFIER_LENGTH,
         encryptedVerifier.begin());
 
-    vector<sal_uInt8> encryptedHash(SHA256_HASH_LENGTH);
+    vector<sal_uInt8> encryptedHash(msfilter::SHA256_HASH_LENGTH);
     std::copy(
         mInfo.verifier.encryptedVerifierHash,
-        mInfo.verifier.encryptedVerifierHash + SHA256_HASH_LENGTH,
+        mInfo.verifier.encryptedVerifierHash + msfilter::SHA256_HASH_LENGTH,
         encryptedHash.begin());
 
     vector<sal_uInt8> verifier(encryptedVerifier.size(), 0);
@@ -174,7 +153,7 @@ bool Standard2007Engine::generateEncryptionKey(const OUString& password)
     vector<sal_uInt8> verifierHash(encryptedHash.size(), 0);
     Decrypt::aes128ecb(verifierHash, encryptedHash, mKey);
 
-    vector<sal_uInt8> hash(SHA1_HASH_LENGTH, 0);
+    vector<sal_uInt8> hash(msfilter::SHA1_HASH_LENGTH, 0);
     Digest::sha1(hash, verifier);
 
     return std::equal( hash.begin(), hash.end(), verifierHash.begin() );
@@ -204,11 +183,11 @@ bool Standard2007Engine::decrypt(
 
 void 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;
+    mInfo.header.flags        = msfilter::ENCRYPTINFO_AES | msfilter::ENCRYPTINFO_CRYPTOAPI;
+    mInfo.header.algId        = msfilter::ENCRYPT_ALGO_AES128;
+    mInfo.header.algIdHash    = msfilter::ENCRYPT_HASH_SHA1;
+    mInfo.header.keyBits      = msfilter::ENCRYPT_KEY_SIZE_AES_128;
+    mInfo.header.providedType = msfilter::ENCRYPT_PROVIDER_TYPE_AES;
 
     lclRandomGenerateValues(mInfo.verifier.salt, mInfo.verifier.saltSize);
     const sal_Int32 keyLength = mInfo.header.keyBits / 8;
@@ -222,11 +201,11 @@ void Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOu
     if (!generateVerifier())
         return;
 
-    rStream.WriteUInt32(VERSION_INFO_2007_FORMAT);
+    rStream.WriteUInt32(msfilter::VERSION_INFO_2007_FORMAT);
 
     sal_uInt32 cspNameSize = (lclCspName.getLength() * 2) + 2;
 
-    sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(EncryptionStandardHeader));
+    sal_uInt32 encryptionHeaderSize = static_cast<sal_uInt32>(sizeof(msfilter::EncryptionStandardHeader));
 
     rStream.WriteUInt32( mInfo.header.flags );
     sal_uInt32 headerSize = encryptionHeaderSize + cspNameSize;
@@ -236,7 +215,7 @@ void Standard2007Engine::writeEncryptionInfo(const OUString& password, BinaryXOu
     rStream.writeUnicodeArray(lclCspName);
     rStream.WriteUInt16(0);
 
-    sal_uInt32 encryptionVerifierSize = static_cast<sal_uInt32>(sizeof(EncryptionVerifierAES));
+    sal_uInt32 encryptionVerifierSize = static_cast<sal_uInt32>(sizeof(msfilter::EncryptionVerifierAES));
     rStream.writeMemory(&mInfo.verifier, encryptionVerifierSize);
 }
 
commit fcc846e8f29839eaace7e1d28746abea8f4b598a
Author: Caolán McNamara <caolanm at redhat.com>
Date:   Thu Oct 20 14:13:19 2016 +0100

    hash len isn't going to change depending on who implements it
    
    Change-Id: Iee585cba4acad74c11d083085153e2af96c8894f

diff --git a/include/oox/crypto/CryptTools.hxx b/include/oox/crypto/CryptTools.hxx
index d963be2..d4fdda2 100644
--- a/include/oox/crypto/CryptTools.hxx
+++ b/include/oox/crypto/CryptTools.hxx
@@ -123,9 +123,6 @@ public:
         SHA512
     };
 
-    static const sal_uInt32 DIGEST_LENGTH_SHA1;
-    static const sal_uInt32 DIGEST_LENGTH_SHA512;
-
 private:
     DigestType meType;
 
diff --git a/include/oox/crypto/Standard2007Engine.hxx b/include/oox/crypto/Standard2007Engine.hxx
index 2ee4a55..1650b62 100644
--- a/include/oox/crypto/Standard2007Engine.hxx
+++ b/include/oox/crypto/Standard2007Engine.hxx
@@ -12,6 +12,7 @@
 #define INCLUDED_OOX_CRYPTO_STANDARD2007ENGINE_HXX
 
 #include <oox/crypto/CryptoEngine.hxx>
+#include <rtl/digest.h>
 #include <rtl/ustring.hxx>
 #include <sal/types.h>
 
@@ -52,9 +53,9 @@ const sal_uInt32 VERSION_INFO_AGILE         = 0x00040004;
 
 const sal_uInt32 SALT_LENGTH                    = 16;
 const sal_uInt32 ENCRYPTED_VERIFIER_LENGTH      = 16;
-const sal_uInt32 ENCRYPTED_SHA1_VERIFIER_HASH_LENGTH = 20;
-const sal_uInt32 ENCRYPTED_SHA256_VERIFIER_HASH_LENGTH = 32;
-const sal_uInt32 ENCRYPTED_SHA512_VERIFIER_HASH_LENGTH = 64;
+const sal_uInt32 SHA1_HASH_LENGTH = RTL_DIGEST_LENGTH_SHA1; // 20
+const sal_uInt32 SHA256_HASH_LENGTH = 32;
+const sal_uInt32 SHA512_HASH_LENGTH = 64;
 
 struct EncryptionStandardHeader
 {
@@ -76,7 +77,7 @@ struct EncryptionVerifierAES
     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_SHA256_VERIFIER_HASH_LENGTH];   // verifier value hash - itself also encrypted
+    sal_uInt8  encryptedVerifierHash[SHA256_HASH_LENGTH];               // verifier value hash - itself also encrypted
 
     EncryptionVerifierAES();
 };
diff --git a/oox/source/crypto/CryptTools.cxx b/oox/source/crypto/CryptTools.cxx
index 1204877..d6dbc96 100644
--- a/oox/source/crypto/CryptTools.cxx
+++ b/oox/source/crypto/CryptTools.cxx
@@ -10,6 +10,7 @@
 
 #include "oox/crypto/CryptTools.hxx"
 #include <com/sun/star/uno/RuntimeException.hpp>
+#include "oox/crypto/Standard2007Engine.hxx"
 
 namespace oox {
 namespace core {
@@ -196,15 +197,6 @@ sal_uInt32 Encrypt::update(vector<sal_uInt8>& output, vector<sal_uInt8>& input,
 
 // Digest
 
-#if USE_TLS_OPENSSL
-const sal_uInt32 Digest::DIGEST_LENGTH_SHA1 = SHA_DIGEST_LENGTH;
-const sal_uInt32 Digest::DIGEST_LENGTH_SHA512 = SHA512_DIGEST_LENGTH;
-#endif
-#if USE_TLS_NSS
-const sal_uInt32 Digest::DIGEST_LENGTH_SHA1 = SHA1_LENGTH;
-const sal_uInt32 Digest::DIGEST_LENGTH_SHA512 = SHA512_LENGTH;
-#endif
-
 namespace
 {
 
@@ -275,9 +267,9 @@ sal_uInt32 Digest::getLength()
     switch(meType)
     {
         case SHA1:
-            return DIGEST_LENGTH_SHA1;
+            return oox::core::SHA1_HASH_LENGTH;
         case SHA512:
-            return DIGEST_LENGTH_SHA512;
+            return oox::core::SHA512_HASH_LENGTH;
         default:
             break;
     }
diff --git a/oox/source/crypto/DocumentDecryption.cxx b/oox/source/crypto/DocumentDecryption.cxx
index d60c6b3..c843ad1 100644
--- a/oox/source/crypto/DocumentDecryption.cxx
+++ b/oox/source/crypto/DocumentDecryption.cxx
@@ -241,7 +241,7 @@ bool DocumentDecryption::readAgileEncryptionInfo(Reference< XInputStream >& xInp
         info.cipherAlgorithm == "AES" &&
         info.cipherChaining  == "ChainingModeCBC" &&
         info.hashAlgorithm   == "SHA1" &&
-        info.hashSize        == ENCRYPTED_SHA1_VERIFIER_HASH_LENGTH)
+        info.hashSize        == SHA1_HASH_LENGTH)
     {
         return true;
     }
@@ -251,7 +251,7 @@ bool DocumentDecryption::readAgileEncryptionInfo(Reference< XInputStream >& xInp
         info.cipherAlgorithm == "AES" &&
         info.cipherChaining  == "ChainingModeCBC" &&
         info.hashAlgorithm   == "SHA512" &&
-        info.hashSize        == ENCRYPTED_SHA512_VERIFIER_HASH_LENGTH )
+        info.hashSize        == SHA512_HASH_LENGTH)
     {
         return true;
     }
diff --git a/oox/source/crypto/Standard2007Engine.cxx b/oox/source/crypto/Standard2007Engine.cxx
index 2266e44..87ef81b 100644
--- a/oox/source/crypto/Standard2007Engine.cxx
+++ b/oox/source/crypto/Standard2007Engine.cxx
@@ -54,9 +54,9 @@ EncryptionStandardHeader::EncryptionStandardHeader()
     reserved2    = 0;
 }
 
-EncryptionVerifierAES::EncryptionVerifierAES() :
-    saltSize(SALT_LENGTH),
-    encryptedVerifierHashSize(Digest::DIGEST_LENGTH_SHA1)
+EncryptionVerifierAES::EncryptionVerifierAES()
+    : saltSize(SALT_LENGTH)
+    , encryptedVerifierHashSize(SHA1_HASH_LENGTH)
 {
     memset(salt, 0, sizeof(salt));
     memset(encryptedVerifier, 0, sizeof(encryptedVerifier));
@@ -87,12 +87,12 @@ bool Standard2007Engine::generateVerifier()
         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;
+    vector<sal_uInt8> hash(SHA1_HASH_LENGTH, 0);
+    mInfo.verifier.encryptedVerifierHashSize = SHA1_HASH_LENGTH;
     Digest::sha1(hash, verifier);
-    hash.resize(ENCRYPTED_SHA256_VERIFIER_HASH_LENGTH, 0);
+    hash.resize(SHA256_HASH_LENGTH, 0);
 
-    vector<sal_uInt8> encryptedHash(ENCRYPTED_SHA256_VERIFIER_HASH_LENGTH, 0);
+    vector<sal_uInt8> encryptedHash(SHA256_HASH_LENGTH, 0);
 
     Encrypt aEncryptorHash(mKey, iv, Crypto::AES_128_ECB);
     aEncryptorHash.update(encryptedHash, hash, hash.size());
@@ -119,13 +119,13 @@ bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
         initialData.begin() + saltSize);
 
     // use "hash" vector for result of sha1 hashing
-    vector<sal_uInt8> hash(Digest::DIGEST_LENGTH_SHA1, 0);
+    vector<sal_uInt8> hash(SHA1_HASH_LENGTH, 0);
 
     // calculate SHA1 hash of initialData
     Digest::sha1(hash, initialData);
 
     // data = iterator (4bytes) + hash
-    vector<sal_uInt8> data(Digest::DIGEST_LENGTH_SHA1 + 4, 0);
+    vector<sal_uInt8> data(SHA1_HASH_LENGTH + 4, 0);
 
     for (sal_Int32 i = 0; i < 50000; ++i)
     {
@@ -134,7 +134,7 @@ bool Standard2007Engine::calculateEncryptionKey(const OUString& rPassword)
         Digest::sha1(hash, data);
     }
     std::copy(hash.begin(), hash.end(), data.begin() );
-    std::fill(data.begin() + Digest::DIGEST_LENGTH_SHA1, data.end(), 0 );
+    std::fill(data.begin() + SHA1_HASH_LENGTH, data.end(), 0 );
 
     Digest::sha1(hash, data);
 
@@ -162,10 +162,10 @@ bool Standard2007Engine::generateEncryptionKey(const OUString& password)
         mInfo.verifier.encryptedVerifier + ENCRYPTED_VERIFIER_LENGTH,
         encryptedVerifier.begin());
 
-    vector<sal_uInt8> encryptedHash(ENCRYPTED_SHA256_VERIFIER_HASH_LENGTH);
+    vector<sal_uInt8> encryptedHash(SHA256_HASH_LENGTH);
     std::copy(
         mInfo.verifier.encryptedVerifierHash,
-        mInfo.verifier.encryptedVerifierHash + ENCRYPTED_SHA256_VERIFIER_HASH_LENGTH,
+        mInfo.verifier.encryptedVerifierHash + SHA256_HASH_LENGTH,
         encryptedHash.begin());
 
     vector<sal_uInt8> verifier(encryptedVerifier.size(), 0);
@@ -174,7 +174,7 @@ bool Standard2007Engine::generateEncryptionKey(const OUString& password)
     vector<sal_uInt8> verifierHash(encryptedHash.size(), 0);
     Decrypt::aes128ecb(verifierHash, encryptedHash, mKey);
 
-    vector<sal_uInt8> hash(RTL_DIGEST_LENGTH_SHA1, 0);
+    vector<sal_uInt8> hash(SHA1_HASH_LENGTH, 0);
     Digest::sha1(hash, verifier);
 
     return std::equal( hash.begin(), hash.end(), verifierHash.begin() );


More information about the Libreoffice-commits mailing list