Compare commits

..

1 Commits

Author SHA1 Message Date
ad0f2c89e0 fix bug #35277
XlsFormatReader - adding decrypt for format 1995, adding xor method decrypting
2018-02-05 17:38:14 +03:00
12 changed files with 392 additions and 44 deletions

View File

@ -60,7 +60,7 @@ HRESULT convert_single(std::wstring srcFileName)
std::wstring dstPath;
bool bMacros = true;
hr = ConvertXls2Xlsx(srcFileName, dstTempPath, L"password", L"C:\\Windows\\Fonts", L"C:\\Windows\\Temp", NULL, bMacros);
hr = ConvertXls2Xlsx(srcFileName, dstTempPath, L"2222", L"C:\\Windows\\Fonts", L"C:\\Windows\\Temp", NULL, bMacros);
if (bMacros)
{

View File

@ -56,6 +56,8 @@ CFRecord::CFRecord(CFStreamPtr stream, GlobalWorkbookInfoPtr global_info)
stream->read(data_, size_);
if(global_info->decryptor && 0 != size_)
{
size_t block_size = global_info->Version == 0x0500 ? 16 : 1024;
switch (type_id_) // this would decrease number of checks
{
case rt_BOF:
@ -67,11 +69,16 @@ CFRecord::CFRecord(CFStreamPtr stream, GlobalWorkbookInfoPtr global_info)
case rt_RRDHead:
break;
case rt_BoundSheet8:
global_info->decryptor->Decrypt(data_ + sizeof(unsigned int), size_ - sizeof(unsigned int), rec_data_pos + sizeof(unsigned int), 1024);
break;
{
if (global_info->Version == 0x0500)
global_info->decryptor->Decrypt(data_/* + sizeof(unsigned int)*/, size_/* - sizeof(unsigned int)*/, rec_data_pos, block_size);
else
global_info->decryptor->Decrypt(data_ + sizeof(unsigned int), size_ - sizeof(unsigned int), rec_data_pos + sizeof(unsigned int), block_size);
}break;
default:
global_info->decryptor->Decrypt(data_, size_, rec_data_pos, 1024);
break;
{
global_info->decryptor->Decrypt(data_, size_, rec_data_pos, block_size);
}break;
}
}
}

View File

@ -71,13 +71,6 @@ namespace CRYPT
virtual void Decrypt(char* data, const size_t size, const unsigned long stream_pos, const size_t block_size) = 0;
virtual void Decrypt(char* data, const size_t size, const unsigned long block_index) = 0;
typedef enum
{
RC4,
RC4CryptoAPI,
XOR
} crypt_type;
virtual bool IsVerify() = 0;
};

View File

@ -33,6 +33,7 @@
#include "Decryptor.h"
#include "RC4Crypt.h"
#include "XORCrypt.h"
#include <Logic/Biff_structures/RC4EncryptionHeader.h>
namespace CRYPT
@ -61,6 +62,37 @@ namespace CRYPT
crypt.reset();
crypt = CryptPtr(new RC4Crypt(crypt_data, password));
if (crypt) return crypt->IsVerify();
else return false;
}
//----------------------------------------------------------------------------------------
XOR::XOR(int type, unsigned short key, unsigned short hash, std::wstring password) :
crypt(new XORCrypt(type, key, hash, password))
{
nKey = key;
nHash = hash;
nType = type;
}
void XOR::Decrypt(char* data, const size_t size, const unsigned long stream_pos, const size_t block_size)
{
crypt->Decrypt(data, size, stream_pos, block_size);
}
void XOR::Decrypt(char* data, const size_t size, const unsigned long block_index)
{
crypt->Decrypt(data, size, block_index);
}
bool XOR::IsVerify()
{
return crypt->IsVerify();
}
bool XOR::SetPassword(std::wstring password)
{
crypt.reset();
crypt = CryptPtr(new XORCrypt(nType, nKey, nHash, password));
if (crypt) return crypt->IsVerify();
else return false;
}

View File

@ -37,6 +37,27 @@
namespace CRYPT
{
class XOR : public Decryptor
{
public:
XOR(int type, unsigned short key, unsigned short hash, std::wstring password);
virtual void Decrypt(char* data, const size_t size, const unsigned long stream_pos, const size_t block_size);
virtual void Decrypt(char* data, const size_t size, const unsigned long block_index);
virtual bool SetPassword(std::wstring password);
virtual bool IsVerify();
private:
CryptPtr crypt;
unsigned short nKey;
unsigned short nHash;
unsigned short nType;
};
typedef boost::shared_ptr<XOR> XORPtr;
class RC4Decryptor : public Decryptor
{
public:

View File

@ -0,0 +1,218 @@
/*
* (c) Copyright Ascensio System SIA 2010-2017
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
* EU, LV-1021.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#include "XORCrypt.h"
#include <boost/scoped_array.hpp>
typedef unsigned char SVBT16[2];
inline void ShortToSVBT16( unsigned short n, SVBT16 p ) { p[0] = (unsigned char) n;
p[1] = (unsigned char)(n >> 8); }
template< typename Type >
inline void lclRotateLeft( Type& rnValue, int nBits )
{
//OSL_ASSERT(
// nBits >= 0 &&
// sal::static_int_cast< unsigned int >(nBits) < sizeof( Type ) * 8 );
rnValue = static_cast< Type >( (rnValue << nBits) | (rnValue >> (sizeof( Type ) * 8 - nBits)) );
}
template< typename Type >
inline void lclRotateLeft( Type& rnValue, unsigned char nBits, unsigned char nWidth )
{
//OSL_ASSERT( (nBits < nWidth) && (nWidth < sizeof( Type ) * 8) );
Type nMask = static_cast< Type >( (1UL << nWidth) - 1 );
rnValue = static_cast< Type >(
((rnValue << nBits) | ((rnValue & nMask) >> (nWidth - nBits))) & nMask );
}
namespace CRYPT
{
size_t lclGetLen( const unsigned char* pnPassData, size_t nBufferSize )
{
size_t nLen = 0;
while( (nLen < nBufferSize) && pnPassData[ nLen ] ) ++nLen;
return nLen;
}
unsigned short lclGetKey( const unsigned char* pnPassData, size_t nBufferSize )
{
size_t nLen = lclGetLen( pnPassData, nBufferSize );
if( !nLen ) return 0;
unsigned short nKey = 0;
unsigned short nKeyBase = 0x8000;
unsigned short nKeyEnd = 0xFFFF;
const unsigned char* pnChar = pnPassData + nLen - 1;
for( size_t nIndex = 0; nIndex < nLen; ++nIndex, --pnChar )
{
unsigned char cChar = *pnChar & 0x7F;
for( unsigned char nBit = 0; nBit < 8; ++nBit )
{
lclRotateLeft( nKeyBase, 1 );
if( nKeyBase & 1 ) nKeyBase ^= 0x1020;
if( cChar & 1 ) nKey ^= nKeyBase;
cChar >>= 1;
lclRotateLeft( nKeyEnd, 1 );
if( nKeyEnd & 1 ) nKeyEnd ^= 0x1020;
}
}
return nKey ^ nKeyEnd;
}
unsigned short lclGetHash( const unsigned char* pnPassData, size_t nBufferSize )
{
size_t nLen = lclGetLen( pnPassData, nBufferSize );
unsigned short nHash = static_cast< unsigned short >( nLen );
if( nLen )
nHash ^= 0xCE4B;
const unsigned char* pnChar = pnPassData;
for( size_t nIndex = 0; nIndex < nLen; ++nIndex, ++pnChar )
{
unsigned short cChar = *pnChar;
unsigned char nRot = static_cast< unsigned char >( (nIndex + 1) % 15 );
lclRotateLeft( cChar, nRot, 15 );
nHash ^= cChar;
}
return nHash;
}
XORCrypt::XORCrypt(int type, unsigned short key, unsigned short hash, std::wstring password) :
m_nOffset(0),
m_nKey(0),
m_nHash(0)
{
if (type == 1) m_nRotateDistance = 7; //doc
else if (type == 2) m_nRotateDistance = 2; //xls
memset( m_pnKey, 0, sizeof( m_pnKey ) );
m_VerifyPassword = false;
size_t nLen = password.length();
if (nLen > 16) return;
m_sPassword = std::string(password.begin(), password.end());
unsigned char* pnPassData = (unsigned char*)m_sPassword.c_str();
m_nKey = lclGetKey( pnPassData, 16 );
m_nHash = lclGetHash( pnPassData, 16 );
memcpy( m_pnKey, pnPassData, 16 );
static const unsigned char spnFillChars[] =
{
0xBB, 0xFF, 0xFF, 0xBA, 0xFF, 0xFF, 0xB9, 0x80, 0x00, 0xBE, 0x0F, 0x00, 0xBF, 0x0F, 0x00
};
nLen = lclGetLen( pnPassData, 16 );
const unsigned char* pnFillChar = spnFillChars;
for ( size_t nIndex = nLen; nIndex < sizeof( m_pnKey ); ++nIndex, ++pnFillChar )
m_pnKey[ nIndex ] = *pnFillChar;
SVBT16 pnOrigKey;
ShortToSVBT16( m_nKey, pnOrigKey );
unsigned char* pnKeyChar = m_pnKey;
for ( size_t nIndex = 0; nIndex < sizeof( m_pnKey ); ++nIndex, ++pnKeyChar )
{
*pnKeyChar ^= pnOrigKey[ nIndex & 0x01 ];
lclRotateLeft( *pnKeyChar, m_nRotateDistance );
}
m_VerifyPassword = (key == m_nKey) && (hash == m_nHash);
}
bool XORCrypt::IsVerify()
{
return m_VerifyPassword;
}
void XORCrypt::Decrypt(char* data, const size_t size, const unsigned long block_index)
{
}
void XORCrypt::Decrypt(char* data, const size_t size, const unsigned long stream_pos, const size_t block_size)
{
m_nOffset = (stream_pos + size) & 0x0F;
unsigned char* pnData = (unsigned char*)data;
const unsigned char* pnCurrKey = m_pnKey + m_nOffset;
const unsigned char* pnKeyLast = m_pnKey + 0x0F;
if (m_nRotateDistance == 7)
{
for( const unsigned char* pnDataEnd = pnData + size; pnData < pnDataEnd; ++pnData )
{
const unsigned char cChar = *pnData ^ *pnCurrKey;
if (*pnData && cChar)
*pnData = cChar;
if( pnCurrKey < pnKeyLast )
++pnCurrKey;
else
pnCurrKey = m_pnKey;
}
}
if (m_nRotateDistance == 2)
{
for( const unsigned char* pnDataEnd = pnData + size; pnData < pnDataEnd; ++pnData )
{
lclRotateLeft( *pnData, 3 );
*pnData ^= *pnCurrKey;
if( pnCurrKey < pnKeyLast )
++pnCurrKey;
else
pnCurrKey = m_pnKey;
}
}
}
void XORCrypt::Skip( size_t size )
{
m_nOffset = (m_nOffset + size) & 0x0F;
}
};

View File

@ -0,0 +1,66 @@
/*
* (c) Copyright Ascensio System SIA 2010-2017
*
* This program is a free software product. You can redistribute it and/or
* modify it under the terms of the GNU Affero General Public License (AGPL)
* version 3 as published by the Free Software Foundation. In accordance with
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
* that Ascensio System SIA expressly excludes the warranty of non-infringement
* of any third-party rights.
*
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
*
* You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
* EU, LV-1021.
*
* The interactive user interfaces in modified source and object code versions
* of the Program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU AGPL version 3.
*
* Pursuant to Section 7(b) of the License you must retain the original Product
* logo when distributing the program. Pursuant to Section 7(e) we decline to
* grant you any rights under trademark law for use of our trademarks.
*
* All the Product's GUI elements, including illustrations and icon sets, as
* well as technical writing content are licensed under the terms of the
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
*
*/
#pragma once
#include "Crypt.h"
#include <Logic/Biff_structures/RC4EncryptionHeader.h>
#include "BiffDecoder_RCF.h"
namespace CRYPT
{
class XORCrypt : public Crypt
{
public:
XORCrypt(int type, unsigned short key, unsigned short hash, std::wstring password);
virtual void Decrypt(char* data, const size_t size, const unsigned long stream_pos, const size_t block_size);
virtual void Decrypt(char* data, const size_t size, const unsigned long block_index);
virtual bool IsVerify();
private:
void Skip( size_t size );
unsigned short m_nKey;
unsigned short m_nHash;
std::string m_sPassword;
bool m_VerifyPassword;
unsigned char m_pnKey[ 16 ]; // Encryption key.
size_t m_nOffset; // Key offset.
int m_nRotateDistance;
};
} // namespace CRYPT

View File

@ -54,48 +54,51 @@ BaseObjectPtr FilePass::clone()
void FilePass::readFields(CFRecord& record)
{
bool bEnabled = false;
record >> wEncryptionType;
if(wEncryptionType == 0)
if (record.getGlobalWorkbookInfo()->Version == 0x0500)
{
record >> key;
Log::info("FilePass: Encryption type: XOR");
return;
record >> key.key >> key.verificationBytes;
record.getGlobalWorkbookInfo()->decryptor =
CRYPT::DecryptorPtr(new CRYPT::XOR(2, key.key, key.verificationBytes, record.getGlobalWorkbookInfo()->password));
}
else
{
bEnabled = true;
majorVer = *record.getCurData<unsigned short>();
cryptHeaderPtr = CRYPTO::RC4EncryptionHeaderPtr(new CRYPTO::RC4EncryptionHeader());
cryptHeaderPtr->bStandard = 0x0001 == majorVer ? true : false; // _S2dvT1xU_R3bOPwre4_.xls
cryptHeaderPtr->load (record);
record >> wEncryptionType;
if (cryptHeaderPtr->bStandard)
if(wEncryptionType == 0)
{
record >> key;
record.getGlobalWorkbookInfo()->decryptor =
CRYPT::DecryptorPtr(new CRYPT::RC4Decryptor(cryptHeaderPtr->crypt_data_rc4, record.getGlobalWorkbookInfo()->password));
CRYPT::DecryptorPtr(new CRYPT::XOR(2, key.key, key.verificationBytes, record.getGlobalWorkbookInfo()->password));
}
else
{
record.getGlobalWorkbookInfo()->decryptor =
CRYPT::DecryptorPtr(new CRYPT::ECMADecryptor());
CRYPT::ECMADecryptor *crypter = dynamic_cast<CRYPT::ECMADecryptor *>(record.getGlobalWorkbookInfo()->decryptor.get());
majorVer = *record.getCurData<unsigned short>();
crypter->SetCryptData(cryptHeaderPtr->crypt_data_aes);
crypter->SetPassword(record.getGlobalWorkbookInfo()->password);
cryptHeaderPtr = CRYPTO::RC4EncryptionHeaderPtr(new CRYPTO::RC4EncryptionHeader());
cryptHeaderPtr->bStandard = 0x0001 == majorVer ? true : false; // _S2dvT1xU_R3bOPwre4_.xls
cryptHeaderPtr->load (record);
if (cryptHeaderPtr->bStandard)
{
record.getGlobalWorkbookInfo()->decryptor =
CRYPT::DecryptorPtr(new CRYPT::RC4Decryptor(cryptHeaderPtr->crypt_data_rc4, record.getGlobalWorkbookInfo()->password));
}
else
{
record.getGlobalWorkbookInfo()->decryptor =
CRYPT::DecryptorPtr(new CRYPT::ECMADecryptor());
CRYPT::ECMADecryptor *crypter = dynamic_cast<CRYPT::ECMADecryptor *>(record.getGlobalWorkbookInfo()->decryptor.get());
crypter->SetCryptData(cryptHeaderPtr->crypt_data_aes);
crypter->SetPassword(record.getGlobalWorkbookInfo()->password);
}
}
}
if (bEnabled == false && record.getGlobalWorkbookInfo()->decryptor)
record.getGlobalWorkbookInfo()->decryptor.reset();
}
} // namespace XLS

View File

@ -32,8 +32,6 @@
#pragma once
#include "BiffStructure.h"
//#include <Logic/Biff_structures/Phs.h>
//#include <Logic/Biff_structures/BiffString.h>
namespace XLS
{

View File

@ -822,6 +822,7 @@ SOURCES += \
../XlsFormat/Crypt/BinaryCodec_RCF.cpp \
../XlsFormat/Crypt/Decryptor.cpp \
../XlsFormat/Crypt/RC4Crypt.cpp \
../XlsFormat/Crypt/XORCrypt.cpp \
../XlsFormat/Logging/Log.cpp \
../XlsFormat/Logging/Logger.cpp \
../Common/utils.cpp \
@ -1179,6 +1180,7 @@ HEADERS += \
../XlsFormat/Crypt/Crypt.h \
../XlsFormat/Crypt/Decryptor.h \
../XlsFormat/Crypt/RC4Crypt.h \
../XlsFormat/Crypt/XORCrypt.h \
../XlsFormat/Logging/Log.h \
../XlsFormat/Logging/Logger.h \
../XlsFormat/Logic/Biff_structures/AddinUdf.h \

View File

@ -6612,6 +6612,14 @@
RelativePath="..\XlsFormat\Crypt\RC4Crypt.h"
>
</File>
<File
RelativePath="..\XlsFormat\Crypt\XORCrypt.cpp"
>
</File>
<File
RelativePath="..\XlsFormat\Crypt\XORCrypt.h"
>
</File>
<Filter
Name="rtl"
>

View File

@ -1,4 +1,4 @@
VERSION = 2.4.515.0
VERSION = 2.4.516.0
DEFINES += INTVER=$$VERSION
# CONFIGURATION