diff options
| author | Caolán McNamara <caolanm@redhat.com> | 2016-10-20 16:07:11 +0100 |
|---|---|---|
| committer | Caolán McNamara <caolanm@redhat.com> | 2016-10-21 11:16:11 +0100 |
| commit | 1473ce030314027c01c98f513407ed0897328585 (patch) | |
| tree | 857b5173bcaf0ca44dff6533f69eb92440088a56 | |
| parent | 06916c839b16866b47235306d2db50850df0ad7c (diff) | |
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
| -rw-r--r-- | filter/source/msfilter/mscodec.cxx | 142 | ||||
| -rw-r--r-- | include/filter/msfilter/mscodec.hxx | 122 | ||||
| -rw-r--r-- | sc/source/filter/excel/xicontent.cxx | 80 | ||||
| -rw-r--r-- | sc/source/filter/excel/xistream.cxx | 70 | ||||
| -rw-r--r-- | sc/source/filter/inc/xistream.hxx | 67 |
5 files changed, 347 insertions, 134 deletions
diff --git a/filter/source/msfilter/mscodec.cxx b/filter/source/msfilter/mscodec.cxx index 20a1f4aa8fc4..ffbbd0992275 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 afdf163b747b..52846f8899f6 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 fdd43aef03e6..c854d75af154 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 31cf3d5ced08..4f28d9c5101f 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 4e0e63bd84e5..3a53643ef1cf 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 |
