Kaydet (Commit) 1473ce03 authored tarafından Caolán McNamara's avatar Caolán McNamara

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
üst 06916c83
...@@ -245,30 +245,36 @@ void MSCodec_Xor95::Skip( std::size_t nBytes ) ...@@ -245,30 +245,36 @@ void MSCodec_Xor95::Skip( std::size_t nBytes )
mnOffset = (mnOffset + nBytes) & 0x0F; mnOffset = (mnOffset + nBytes) & 0x0F;
} }
MSCodec97::MSCodec97(rtlCipher hCipher) MSCodec97::MSCodec97(size_t nHashLen)
: m_hCipher(hCipher) : 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() 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); m_hDigest = rtl_digest_create(rtl_Digest_AlgorithmMD5);
assert(m_hDigest != nullptr); 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() MSCodec97::~MSCodec97()
{ {
(void)memset(m_aDigestValue.data(), 0, m_aDigestValue.size());
(void)memset(m_pDocId, 0, sizeof(m_pDocId));
rtl_cipher_destroy(m_hCipher); rtl_cipher_destroy(m_hCipher);
} }
MSCodec_Std97::~MSCodec_Std97() 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_digest_destroy(m_hDigest);
} }
...@@ -286,7 +292,7 @@ static inline void lcl_PrintDigest(const sal_uInt8* /*pDigest*/, const char* /*m ...@@ -286,7 +292,7 @@ static inline void lcl_PrintDigest(const sal_uInt8* /*pDigest*/, const char* /*m
} }
#endif #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 #if DEBUG_MSO_ENCRYPTION_STD97
fprintf(stdout, "MSCodec_Std97::InitCodec: --begin\n");fflush(stdout); fprintf(stdout, "MSCodec_Std97::InitCodec: --begin\n");fflush(stdout);
...@@ -295,16 +301,17 @@ bool MSCodec_Std97::InitCodec( const uno::Sequence< beans::NamedValue >& aData ) ...@@ -295,16 +301,17 @@ bool MSCodec_Std97::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
::comphelper::SequenceAsHashMap aHashData( aData ); ::comphelper::SequenceAsHashMap aHashData( aData );
uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("STD97EncryptionKey", uno::Sequence< sal_Int8 >() ); uno::Sequence< sal_Int8 > aKey = aHashData.getUnpackedValueOrDefault("STD97EncryptionKey", uno::Sequence< sal_Int8 >() );
const size_t nKeyLen = aKey.getLength();
if ( aKey.getLength() == RTL_DIGEST_LENGTH_MD5 ) 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 >() ); uno::Sequence< sal_Int8 > aUniqueID = aHashData.getUnpackedValueOrDefault("STD97UniqueID", uno::Sequence< sal_Int8 >() );
if ( aUniqueID.getLength() == 16 ) if ( aUniqueID.getLength() == 16 )
{ {
(void)memcpy( m_pDocId, aUniqueID.getConstArray(), 16 ); (void)memcpy( m_pDocId, aUniqueID.getConstArray(), 16 );
bResult = true; bResult = true;
lcl_PrintDigest(m_pDigestValue, "digest value"); lcl_PrintDigest(m_aDigestValue.data(), "digest value");
lcl_PrintDigest(m_pDocId, "DocId value"); lcl_PrintDigest(m_pDocId, "DocId value");
} }
else else
...@@ -316,10 +323,11 @@ bool MSCodec_Std97::InitCodec( const uno::Sequence< beans::NamedValue >& aData ) ...@@ -316,10 +323,11 @@ bool MSCodec_Std97::InitCodec( const uno::Sequence< beans::NamedValue >& aData )
return bResult; return bResult;
} }
uno::Sequence< beans::NamedValue > MSCodec_Std97::GetEncryptionData() uno::Sequence< beans::NamedValue > MSCodec97::GetEncryptionData()
{ {
::comphelper::SequenceAsHashMap aHashData; ::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 ); aHashData[ OUString( "STD97UniqueID" ) ] <<= uno::Sequence< sal_Int8 >( reinterpret_cast<sal_Int8*>(m_pDocId), 16 );
return aHashData.getAsConstNamedValueList(); return aHashData.getAsConstNamedValueList();
...@@ -335,26 +343,51 @@ void MSCodec_Std97::InitKey ( ...@@ -335,26 +343,51 @@ void MSCodec_Std97::InitKey (
uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key(pPassData, pDocId); uno::Sequence< sal_Int8 > aKey = ::comphelper::DocPasswordHelper::GenerateStd97Key(pPassData, pDocId);
// Fill raw digest of above updates into DigestValue. // Fill raw digest of above updates into DigestValue.
if ( aKey.getLength() == sizeof(m_pDigestValue) ) const size_t nKeyLen = aKey.getLength();
(void)memcpy ( m_pDigestValue, aKey.getConstArray(), sizeof(m_pDigestValue) ); if (m_aDigestValue.size() == nKeyLen)
(void)memcpy(m_aDigestValue.data(), aKey.getConstArray(), m_aDigestValue.size());
else 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); (void)memcpy (m_pDocId, pDocId, 16);
lcl_PrintDigest(m_pDocId, "DocId value"); lcl_PrintDigest(m_pDocId, "DocId value");
} }
bool MSCodec_Std97::VerifyKey ( bool MSCodec97::VerifyKey(const sal_uInt8* pSaltData, const sal_uInt8* pSaltDigest)
const sal_uInt8 pSaltData[16],
const sal_uInt8 pSaltDigest[16])
{ {
// both the salt data and salt digest (hash) come from the document being imported. // both the salt data and salt digest (hash) come from the document being imported.
#if DEBUG_MSO_ENCRYPTION_STD97 #if DEBUG_MSO_ENCRYPTION_STD97
fprintf(stdout, "MSCodec_Std97::VerifyKey: \n"); fprintf(stdout, "MSCodec97::VerifyKey: \n");
lcl_PrintDigest(pSaltData, "salt data"); lcl_PrintDigest(pSaltData, "salt data");
lcl_PrintDigest(pSaltDigest, "salt hash"); lcl_PrintDigest(pSaltDigest, "salt hash");
#endif #endif
...@@ -362,35 +395,42 @@ bool MSCodec_Std97::VerifyKey ( ...@@ -362,35 +395,42 @@ bool MSCodec_Std97::VerifyKey (
if (InitCipher(0)) if (InitCipher(0))
{ {
sal_uInt8 pDigest[RTL_DIGEST_LENGTH_MD5]; std::vector<sal_uInt8> aDigest(m_nHashLen);
GetDigestFromSalt(pSaltData, pDigest); GetDigestFromSalt(pSaltData, aDigest.data());
sal_uInt8 pBuffer[16]; std::vector<sal_uInt8> aBuffer(m_nHashLen);
// Decode original SaltDigest into Buffer. // Decode original SaltDigest into Buffer.
rtl_cipher_decode ( rtl_cipher_decode(m_hCipher, pSaltDigest, m_nHashLen, aBuffer.data(), m_nHashLen);
m_hCipher, pSaltDigest, 16, pBuffer, sizeof(pBuffer));
// Compare Buffer with computed Digest. // 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. // Erase Buffer and Digest arrays.
rtl_secureZeroMemory (pBuffer, sizeof(pBuffer)); rtl_secureZeroMemory(aBuffer.data(), m_nHashLen);
rtl_secureZeroMemory (pDigest, sizeof(pDigest)); rtl_secureZeroMemory(aDigest.data(), m_nHashLen);
} }
return result; 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 sal_uInt8 pKeyData[64]; // 512-bit message block
// Initialize KeyData array. // Initialize KeyData array.
(void)memset (pKeyData, 0, sizeof(pKeyData)); (void)memset (pKeyData, 0, sizeof(pKeyData));
// Fill 40 bit of DigestValue into [0..4]. // 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]. // Fill counter into [5..8].
pKeyData[ 5] = sal_uInt8((nCounter >> 0) & 0xff); pKeyData[ 5] = sal_uInt8((nCounter >> 0) & 0xff);
...@@ -408,7 +448,7 @@ bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter) ...@@ -408,7 +448,7 @@ bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
m_hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5); m_hDigest, pKeyData, RTL_DIGEST_LENGTH_MD5);
// Initialize Cipher with KeyData (for decoding). // Initialize Cipher with KeyData (for decoding).
result = rtl_cipher_init ( rtlCipherError result = rtl_cipher_init (
m_hCipher, rtl_Cipher_DirectionBoth, m_hCipher, rtl_Cipher_DirectionBoth,
pKeyData, RTL_DIGEST_LENGTH_MD5, nullptr, 0); pKeyData, RTL_DIGEST_LENGTH_MD5, nullptr, 0);
...@@ -418,6 +458,25 @@ bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter) ...@@ -418,6 +458,25 @@ bool MSCodec_Std97::InitCipher (sal_uInt32 nCounter)
return (result == rtl_Cipher_E_None); 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] ) void MSCodec_Std97::CreateSaltDigest( const sal_uInt8 nSaltData[16], sal_uInt8 nSaltDigest[16] )
{ {
#if DEBUG_MSO_ENCRYPTION_STD97 #if DEBUG_MSO_ENCRYPTION_STD97
...@@ -471,7 +530,7 @@ bool MSCodec97::Skip(std::size_t nDatLen) ...@@ -471,7 +530,7 @@ bool MSCodec97::Skip(std::size_t nDatLen)
return bResult; 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 pBuffer[64];
sal_uInt8 pDigestLocal[16]; sal_uInt8 pDigestLocal[16];
...@@ -530,7 +589,7 @@ void MSCodec_Std97::GetEncryptKey ( ...@@ -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 ) if ( sizeof( m_pDocId ) == 16 )
(void)memcpy( pDocId, m_pDocId, 16 ); (void)memcpy( pDocId, m_pDocId, 16 );
...@@ -557,6 +616,15 @@ EncryptionVerifierAES::EncryptionVerifierAES() ...@@ -557,6 +616,15 @@ EncryptionVerifierAES::EncryptionVerifierAES()
memset(encryptedVerifierHash, 0, sizeof(encryptedVerifierHash)); 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: */ /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <rtl/cipher.h> #include <rtl/cipher.h>
#include <rtl/digest.h> #include <rtl/digest.h>
#include <sal/types.h> #include <sal/types.h>
#include <vector>
namespace com { namespace sun { namespace star { namespace com { namespace sun { namespace star {
namespace beans { struct NamedValue; } namespace beans { struct NamedValue; }
...@@ -177,7 +178,7 @@ public: ...@@ -177,7 +178,7 @@ public:
class MSFILTER_DLLPUBLIC MSCodec97 class MSFILTER_DLLPUBLIC MSCodec97
{ {
public: public:
MSCodec97(rtlCipher m_hCipher); MSCodec97(size_t nHashLen);
virtual ~MSCodec97(); virtual ~MSCodec97();
/** Initializes the algorithm with the encryption data. /** Initializes the algorithm with the encryption data.
...@@ -186,7 +187,7 @@ public: ...@@ -186,7 +187,7 @@ public:
The sequence contains the necessary data to initialize The sequence contains the necessary data to initialize
the codec. 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 /** Retrieves the encryption data
...@@ -194,8 +195,37 @@ public: ...@@ -194,8 +195,37 @@ public:
The sequence contains the necessary data to initialize The sequence contains the necessary data to initialize
the codec. 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. /** Rekeys the codec using the specified counter.
...@@ -278,12 +308,19 @@ public: ...@@ -278,12 +308,19 @@ public:
*/ */
bool Skip(std::size_t nDatLen); bool Skip(std::size_t nDatLen);
/* allows to get the unique document id from the codec
*/
void GetDocId( sal_uInt8 pDocId[16] );
private: private:
MSCodec97(const MSCodec97&) = delete; MSCodec97(const MSCodec97&) = delete;
MSCodec97& operator=(const MSCodec97&) = delete; MSCodec97& operator=(const MSCodec97&) = delete;
protected: protected:
size_t m_nHashLen;
rtlCipher m_hCipher; rtlCipher m_hCipher;
sal_uInt8 m_pDocId[16];
std::vector<sal_uInt8> m_aDigestValue;
}; };
/** Encodes and decodes data from protected MSO 97+ documents. /** Encodes and decodes data from protected MSO 97+ documents.
...@@ -295,25 +332,8 @@ protected: ...@@ -295,25 +332,8 @@ protected:
class MSFILTER_DLLPUBLIC MSCodec_Std97 : public MSCodec97 class MSFILTER_DLLPUBLIC MSCodec_Std97 : public MSCodec97
{ {
public: public:
explicit MSCodec_Std97(); MSCodec_Std97();
~MSCodec_Std97(); virtual ~MSCodec_Std97() override;
/** 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. /** Initializes the algorithm with the specified password and document ID.
...@@ -323,27 +343,8 @@ public: ...@@ -323,27 +343,8 @@ public:
@param pDocId @param pDocId
Unique document identifier read from or written to the file. Unique document identifier read from or written to the file.
*/ */
void InitKey( virtual void InitKey(const sal_uInt16 pPassData[16],
const sal_uInt16 pPassData[ 16 ], const sal_uInt8 pDocId[16]) override;
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. /** Rekeys the codec using the specified counter.
...@@ -384,19 +385,24 @@ public: ...@@ -384,19 +385,24 @@ public:
sal_uInt8 pSaltData[16], sal_uInt8 pSaltData[16],
sal_uInt8 pSaltDigest[16]); sal_uInt8 pSaltDigest[16]);
/* allows to get the unique document id from the codec virtual void GetDigestFromSalt(const sal_uInt8* pSaltData, sal_uInt8* pDigest) override;
*/
void GetDocId( sal_uInt8 pDocId[16] );
void GetDigestFromSalt( const sal_uInt8 pSaltData[16], sal_uInt8 pDigest[16] );
private: private:
MSCodec_Std97( const MSCodec_Std97& ) = delete; MSCodec_Std97( const MSCodec_Std97& ) = delete;
MSCodec_Std97& operator=( const MSCodec_Std97& ) = delete; MSCodec_Std97& operator=( const MSCodec_Std97& ) = delete;
rtlDigest m_hDigest; 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; const sal_uInt32 ENCRYPTINFO_CRYPTOAPI = 0x00000004;
...@@ -459,12 +465,28 @@ struct MSFILTER_DLLPUBLIC EncryptionVerifierAES ...@@ -459,12 +465,28 @@ struct MSFILTER_DLLPUBLIC EncryptionVerifierAES
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 struct MSFILTER_DLLPUBLIC StandardEncryptionInfo
{ {
EncryptionStandardHeader header; EncryptionStandardHeader header;
EncryptionVerifierAES verifier; EncryptionVerifierAES verifier;
}; };
struct MSFILTER_DLLPUBLIC RC4EncryptionInfo
{
EncryptionStandardHeader header;
EncryptionVerifierRC4 verifier;
};
} // namespace msfilter } // namespace msfilter
......
...@@ -64,6 +64,7 @@ ...@@ -64,6 +64,7 @@
#include <memory> #include <memory>
#include <utility> #include <utility>
#include <o3tl/make_unique.hxx> #include <o3tl/make_unique.hxx>
#include <oox/helper/helper.hxx>
using ::com::sun::star::uno::Sequence; using ::com::sun::star::uno::Sequence;
using ::std::unique_ptr; using ::std::unique_ptr;
...@@ -1110,21 +1111,80 @@ XclImpDecrypterRef lclReadFilepass8_Standard( XclImpStream& rStrm ) ...@@ -1110,21 +1111,80 @@ XclImpDecrypterRef lclReadFilepass8_Standard( XclImpStream& rStrm )
OSL_ENSURE( rStrm.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" ); OSL_ENSURE( rStrm.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
if( rStrm.GetRecLeft() == 48 ) if( rStrm.GetRecLeft() == 48 )
{ {
sal_uInt8 pnSalt[ 16 ]; std::vector<sal_uInt8> aSalt(16);
sal_uInt8 pnVerifier[ 16 ]; std::vector<sal_uInt8> aVerifier(16);
sal_uInt8 pnVerifierHash[ 16 ]; std::vector<sal_uInt8> aVerifierHash(16);
rStrm.Read( pnSalt, 16 ); rStrm.Read(aSalt.data(), 16);
rStrm.Read( pnVerifier, 16 ); rStrm.Read(aVerifier.data(), 16);
rStrm.Read( pnVerifierHash, 16 ); rStrm.Read(aVerifierHash.data(), 16);
xDecr.reset( new XclImpBiff8Decrypter( pnSalt, pnVerifier, pnVerifierHash ) ); xDecr.reset(new XclImpBiff8StdDecrypter(aSalt, aVerifier, aVerifierHash));
} }
return xDecr; return xDecr;
} }
XclImpDecrypterRef lclReadFilepass8_Strong( XclImpStream& /*rStrm*/ ) XclImpDecrypterRef lclReadFilepass8_Strong(XclImpStream& rStream)
{ {
// not supported //Its possible there are other variants in existance but these
return XclImpDecrypterRef(); //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 ) XclImpDecrypterRef lclReadFilepass8( XclImpStream& rStrm )
......
...@@ -192,28 +192,50 @@ sal_uInt16 XclImpBiff5Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal ...@@ -192,28 +192,50 @@ sal_uInt16 XclImpBiff5Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal
return nRet; return nRet;
} }
XclImpBiff8Decrypter::XclImpBiff8Decrypter( sal_uInt8 pnSalt[ 16 ], XclImpBiff8Decrypter::XclImpBiff8Decrypter(const std::vector<sal_uInt8>& rSalt,
sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] ) : const std::vector<sal_uInt8>& rVerifier,
maSalt( pnSalt, pnSalt + 16 ), const std::vector<sal_uInt8>& rVerifierHash)
maVerifier( pnVerifier, pnVerifier + 16 ), : maSalt(rSalt)
maVerifierHash( pnVerifierHash, pnVerifierHash + 16 ) , maVerifier(rVerifier)
, maVerifierHash(rVerifierHash)
, mpCodec(nullptr)
{ {
} }
XclImpBiff8Decrypter::XclImpBiff8Decrypter( const XclImpBiff8Decrypter& rSrc ) : XclImpBiff8Decrypter::XclImpBiff8Decrypter(const XclImpBiff8Decrypter& rSrc)
XclImpDecrypter( rSrc ), : XclImpDecrypter(rSrc)
maEncryptionData( rSrc.maEncryptionData ), , maEncryptionData(rSrc.maEncryptionData)
maSalt( rSrc.maSalt ), , maSalt(rSrc.maSalt)
maVerifier( rSrc.maVerifier ), , maVerifier(rSrc.maVerifier)
maVerifierHash( rSrc.maVerifierHash ) , 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 ) uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const OUString& rPassword )
...@@ -232,9 +254,9 @@ uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const ...@@ -232,9 +254,9 @@ uno::Sequence< beans::NamedValue > XclImpBiff8Decrypter::OnVerifyPassword( const
*aIt = static_cast< sal_uInt16 >( *pcChar ); *aIt = static_cast< sal_uInt16 >( *pcChar );
// init codec // init codec
maCodec.InitKey( &aPassVect.front(), &maSalt.front() ); mpCodec->InitKey( &aPassVect.front(), &maSalt.front() );
if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) ) if ( mpCodec->VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
maEncryptionData = maCodec.GetEncryptionData(); maEncryptionData = mpCodec->GetEncryptionData();
} }
return maEncryptionData; return maEncryptionData;
...@@ -247,9 +269,9 @@ bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::N ...@@ -247,9 +269,9 @@ bool XclImpBiff8Decrypter::OnVerifyEncryptionData( const uno::Sequence< beans::N
if( rEncryptionData.getLength() ) if( rEncryptionData.getLength() )
{ {
// init codec // init codec
maCodec.InitCodec( rEncryptionData ); mpCodec->InitCodec( rEncryptionData );
if ( maCodec.VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) ) if ( mpCodec->VerifyKey( &maVerifier.front(), &maVerifierHash.front() ) )
maEncryptionData = rEncryptionData; maEncryptionData = rEncryptionData;
} }
...@@ -269,13 +291,13 @@ void XclImpBiff8Decrypter::OnUpdate( std::size_t nOldStrmPos, std::size_t nNewSt ...@@ -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. */ /* Rekey cipher, if block changed or if previous offset in same block. */
if( (nNewBlock != nOldBlock) || (nNewOffset < nOldOffset) ) if( (nNewBlock != nOldBlock) || (nNewOffset < nOldOffset) )
{ {
maCodec.InitCipher( nNewBlock ); mpCodec->InitCipher( nNewBlock );
nOldOffset = 0; // reset nOldOffset for next if() statement nOldOffset = 0; // reset nOldOffset for next if() statement
} }
/* Seek to correct offset. */ /* Seek to correct offset. */
if( nNewOffset > nOldOffset ) 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 ...@@ -293,9 +315,9 @@ sal_uInt16 XclImpBiff8Decrypter::OnRead( SvStream& rStrm, sal_uInt8* pnData, sal
// read the block from stream // read the block from stream
nRet = nRet + static_cast<sal_uInt16>(rStrm.ReadBytes(pnCurrData, nDecBytes)); nRet = nRet + static_cast<sal_uInt16>(rStrm.ReadBytes(pnCurrData, nDecBytes));
// decode the block inplace // decode the block inplace
maCodec.Decode( pnCurrData, nDecBytes, pnCurrData, nDecBytes ); mpCodec->Decode( pnCurrData, nDecBytes, pnCurrData, nDecBytes );
if( GetOffset( rStrm.Tell() ) == 0 ) if( GetOffset( rStrm.Tell() ) == 0 )
maCodec.InitCipher( GetBlock( rStrm.Tell() ) ); mpCodec->InitCipher( GetBlock( rStrm.Tell() ) );
pnCurrData += nDecBytes; pnCurrData += nDecBytes;
nBytesLeft = nBytesLeft - nDecBytes; nBytesLeft = nBytesLeft - nDecBytes;
......
...@@ -119,16 +119,7 @@ private: ...@@ -119,16 +119,7 @@ private:
/** Decrypts BIFF8 stream contents using the given document identifier. */ /** Decrypts BIFF8 stream contents using the given document identifier. */
class XclImpBiff8Decrypter : public XclImpDecrypter class XclImpBiff8Decrypter : public XclImpDecrypter
{ {
public:
explicit XclImpBiff8Decrypter( sal_uInt8 pnSalt[ 16 ],
sal_uInt8 pnVerifier[ 16 ], sal_uInt8 pnVerifierHash[ 16 ] );
private: 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. */ /** Implements password verification and initialization of the decoder. */
virtual css::uno::Sequence< css::beans::NamedValue > virtual css::uno::Sequence< css::beans::NamedValue >
OnVerifyPassword( const OUString& rPassword ) override; OnVerifyPassword( const OUString& rPassword ) override;
...@@ -143,12 +134,62 @@ private: ...@@ -143,12 +134,62 @@ private:
/** Returns the block offset corresponding to the passed stream position. */ /** Returns the block offset corresponding to the passed stream position. */
static sal_uInt16 GetOffset( std::size_t nStrmPos ); 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: private:
::msfilter::MSCodec_Std97 maCodec; /// Crypto algorithm implementation. ::msfilter::MSCodec_Std97 maCodec; /// Crypto algorithm implementation.
css::uno::Sequence< css::beans::NamedValue > maEncryptionData; };
::std::vector< sal_uInt8 > maSalt;
::std::vector< sal_uInt8 > maVerifier; class XclImpBiff8CryptoAPIDecrypter : public XclImpBiff8Decrypter
::std::vector< sal_uInt8 > maVerifierHash; {
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 // Stream
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment