mirror of
https://github.com/ONLYOFFICE/core.git
synced 2026-04-07 13:55:33 +08:00
DocFormatReader - анализ зашифрованности файла
XlsFormatReader - чтение зашифрованных файлов (введен параметр password на вход)
This commit is contained in:
committed by
Alexander Trofimov
parent
ea0ffa7960
commit
27c67d0aa4
@ -457,37 +457,37 @@ namespace DocFileFormat
|
||||
unsigned char flag8 = 0;
|
||||
|
||||
//read the FIB base
|
||||
this->m_FibBase.wIdent = reader.ReadUInt16(); //0
|
||||
this->m_FibBase.nFib = (FibVersion)reader.ReadUInt16(); //2
|
||||
this->m_FibBase.wIdent = reader.ReadUInt16(); //0
|
||||
this->m_FibBase.nFib = (FibVersion)reader.ReadUInt16(); //2
|
||||
reader.ReadBytes( 2, false ); //4
|
||||
this->m_FibBase.lid = reader.ReadUInt16(); //6
|
||||
this->m_FibBase.pnNext = reader.ReadInt16(); //8
|
||||
this->m_FibBase.lid = reader.ReadUInt16(); //6
|
||||
this->m_FibBase.pnNext = reader.ReadInt16(); //8
|
||||
flag16 = reader.ReadUInt16(); //10
|
||||
this->m_FibBase.fDot = FormatUtils::BitmaskToBool((int)flag16, 0x0001);
|
||||
this->m_FibBase.fGlsy = FormatUtils::BitmaskToBool((int)flag16, 0x0002);
|
||||
this->m_FibBase.fComplex = FormatUtils::BitmaskToBool((int)flag16, 0x0002);
|
||||
this->m_FibBase.fHasPic = FormatUtils::BitmaskToBool((int)flag16, 0x0008);
|
||||
this->m_FibBase.cQuickSaves = (WORD)(((int)flag16 & 0x00F0) >> 4);
|
||||
this->m_FibBase.fEncrypted = FormatUtils::BitmaskToBool((int)flag16, 0x0100);
|
||||
this->m_FibBase.fWhichTblStm = FormatUtils::BitmaskToBool((int)flag16, 0x0200);
|
||||
this->m_FibBase.fDot = FormatUtils::BitmaskToBool((int)flag16, 0x0001);
|
||||
this->m_FibBase.fGlsy = FormatUtils::BitmaskToBool((int)flag16, 0x0002);
|
||||
this->m_FibBase.fComplex = FormatUtils::BitmaskToBool((int)flag16, 0x0002);
|
||||
this->m_FibBase.fHasPic = FormatUtils::BitmaskToBool((int)flag16, 0x0008);
|
||||
this->m_FibBase.cQuickSaves = (WORD)(((int)flag16 & 0x00F0) >> 4);
|
||||
this->m_FibBase.fEncrypted = FormatUtils::BitmaskToBool((int)flag16, 0x0100);
|
||||
this->m_FibBase.fWhichTblStm = FormatUtils::BitmaskToBool((int)flag16, 0x0200);
|
||||
this->m_FibBase.fReadOnlyRecommended = FormatUtils::BitmaskToBool((int)flag16, 0x0400);
|
||||
this->m_FibBase.fWriteReservation = FormatUtils::BitmaskToBool((int)flag16, 0x0800);
|
||||
this->m_FibBase.fExtChar = FormatUtils::BitmaskToBool((int)flag16, 0x1000);
|
||||
this->m_FibBase.fLoadOverwrite = FormatUtils::BitmaskToBool((int)flag16, 0x2000);
|
||||
this->m_FibBase.fFarEast = FormatUtils::BitmaskToBool((int)flag16, 0x4000);
|
||||
this->m_FibBase.fCrypto = FormatUtils::BitmaskToBool((int)flag16, 0x8000);
|
||||
this->m_FibBase.nFibBack = reader.ReadUInt16(); //12
|
||||
this->m_FibBase.lKey = reader.ReadInt32(); //14
|
||||
this->m_FibBase.envr = reader.ReadByte(); //18
|
||||
this->m_FibBase.fExtChar = FormatUtils::BitmaskToBool((int)flag16, 0x1000);
|
||||
this->m_FibBase.fLoadOverwrite = FormatUtils::BitmaskToBool((int)flag16, 0x2000);
|
||||
this->m_FibBase.fFarEast = FormatUtils::BitmaskToBool((int)flag16, 0x4000);
|
||||
this->m_FibBase.fCrypto = FormatUtils::BitmaskToBool((int)flag16, 0x8000);
|
||||
this->m_FibBase.nFibBack = reader.ReadUInt16(); //12
|
||||
this->m_FibBase.lKey = reader.ReadInt32(); //14
|
||||
this->m_FibBase.envr = reader.ReadByte(); //18
|
||||
flag8 = reader.ReadByte(); //19
|
||||
this->m_FibBase.fMac = FormatUtils::BitmaskToBool((int)flag8, 0x01);
|
||||
this->m_FibBase.fEmptySpecial = FormatUtils::BitmaskToBool((int)flag8, 0x02);
|
||||
this->m_FibBase.fMac = FormatUtils::BitmaskToBool((int)flag8, 0x01);
|
||||
this->m_FibBase.fEmptySpecial = FormatUtils::BitmaskToBool((int)flag8, 0x02);
|
||||
this->m_FibBase.fLoadOverridePage = FormatUtils::BitmaskToBool((int)flag8, 0x04);
|
||||
this->m_FibBase.fFutureSavedUndo = FormatUtils::BitmaskToBool((int)flag8, 0x08);
|
||||
this->m_FibBase.fWord97Saved = FormatUtils::BitmaskToBool((int)flag8, 0x10);
|
||||
this->m_FibBase.fWord97Saved = FormatUtils::BitmaskToBool((int)flag8, 0x10);
|
||||
reader.ReadBytes( 4, false ); //20
|
||||
this->m_FibBase.fcMin = reader.ReadInt32(); //24
|
||||
this->m_FibBase.fcMac = reader.ReadInt32(); //28
|
||||
this->m_FibBase.fcMin = reader.ReadInt32(); //24
|
||||
this->m_FibBase.fcMac = reader.ReadInt32(); //28
|
||||
|
||||
this->csw = reader.ReadUInt16(); //32
|
||||
|
||||
|
||||
@ -178,6 +178,9 @@ namespace DocFileFormat
|
||||
}
|
||||
}
|
||||
|
||||
if (FIB->m_FibBase.fEncrypted)
|
||||
return AVS_ERROR_DRM;
|
||||
|
||||
// Get the streams
|
||||
if (FIB->m_FibBase.fWhichTblStm)
|
||||
{
|
||||
|
||||
@ -26,7 +26,7 @@ int _tmain(int argc, _TCHAR* argv[])
|
||||
|
||||
std::wstring dstTempPath = FileSystem::Directory::CreateDirectoryWithUniqueName(outputDir);
|
||||
|
||||
hr = ConvertXls2Xlsx(srcFileName, dstTempPath, L"C:\\Windows\\Fonts", NULL);
|
||||
hr = ConvertXls2Xlsx(srcFileName, dstTempPath, L"password1", L"C:\\Windows\\Fonts", NULL);
|
||||
|
||||
if (hr != S_OK) return hr;
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace CRYPT
|
||||
@ -19,6 +20,8 @@ public:
|
||||
XOR
|
||||
} crypt_type;
|
||||
|
||||
virtual bool IsVerify() = 0;
|
||||
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<Crypt> CryptPtr;
|
||||
|
||||
@ -8,16 +8,31 @@
|
||||
namespace CRYPT
|
||||
{
|
||||
|
||||
Decryptor::Decryptor(const CRYPTO::RC4EncryptionHeader& header)
|
||||
: crypt(new RC4Crypt(header)),
|
||||
type(Crypt::RC4)
|
||||
{
|
||||
}
|
||||
Decryptor::Decryptor(CRYPTO::RC4EncryptionHeaderPtr & header, std::wstring password) :
|
||||
crypt (new RC4Crypt(header, password)),
|
||||
type (Crypt::RC4)
|
||||
{
|
||||
crypt_header = header;
|
||||
}
|
||||
|
||||
void Decryptor::Decrypt(char* data, const size_t size, const unsigned long stream_pos)
|
||||
{
|
||||
crypt->Decrypt(data, size, stream_pos);
|
||||
}
|
||||
void Decryptor::Decrypt(char* data, const size_t size, const unsigned long stream_pos)
|
||||
{
|
||||
crypt->Decrypt(data, size, stream_pos);
|
||||
}
|
||||
|
||||
bool Decryptor::IsVerify()
|
||||
{
|
||||
return crypt->IsVerify();
|
||||
}
|
||||
|
||||
bool Decryptor::SetPassword(std::wstring password)
|
||||
{
|
||||
crypt.reset();
|
||||
crypt = CryptPtr(new RC4Crypt(crypt_header, password));
|
||||
|
||||
if (crypt) return crypt->IsVerify();
|
||||
else return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -4,7 +4,9 @@
|
||||
|
||||
namespace CRYPTO
|
||||
{
|
||||
class RC4EncryptionHeader;
|
||||
class RC4EncryptionHeader;
|
||||
typedef boost::shared_ptr<RC4EncryptionHeader> RC4EncryptionHeaderPtr;
|
||||
|
||||
} // namespace CRYPTO
|
||||
|
||||
namespace CRYPT
|
||||
@ -13,13 +15,18 @@ namespace CRYPT
|
||||
class Decryptor
|
||||
{
|
||||
public:
|
||||
Decryptor(const CRYPTO::RC4EncryptionHeader& header);
|
||||
Decryptor(CRYPTO::RC4EncryptionHeaderPtr & header, std::wstring password);
|
||||
|
||||
void Decrypt(char* data, const size_t size, const unsigned long stream_pos);
|
||||
|
||||
bool IsVerify();
|
||||
|
||||
bool SetPassword(std::wstring password);
|
||||
|
||||
private:
|
||||
CryptPtr crypt;
|
||||
Crypt::crypt_type type;
|
||||
CryptPtr crypt;
|
||||
Crypt::crypt_type type;
|
||||
CRYPTO::RC4EncryptionHeaderPtr crypt_header;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<Decryptor> DecryptorPtr;
|
||||
|
||||
@ -7,14 +7,19 @@
|
||||
namespace CRYPT
|
||||
{
|
||||
|
||||
RC4Crypt::RC4Crypt(const CRYPTO::RC4EncryptionHeader& header)
|
||||
RC4Crypt::RC4Crypt(CRYPTO::RC4EncryptionHeaderPtr & header, std::wstring password)
|
||||
{
|
||||
CopyDWORDs2Bytes(header.Salt.b1, header.Salt.b2, header.Salt.b3, header.Salt.b4, pnSalt);
|
||||
CopyDWORDs2Bytes(header.EncryptedVerifier.b1, header.EncryptedVerifier.b2, header.EncryptedVerifier.b3, header.EncryptedVerifier.b4, pnVerifier);
|
||||
CopyDWORDs2Bytes(header.EncryptedVerifierHash.b1, header.EncryptedVerifierHash.b2, header.EncryptedVerifierHash.b3, header.EncryptedVerifierHash.b4, pnVerifierHash);
|
||||
m_VerifyPassword = false;
|
||||
|
||||
if (!header) return;
|
||||
|
||||
CopyDWORDs2Bytes(header->Salt.b1, header->Salt.b2, header->Salt.b3, header->Salt.b4, pnSalt);
|
||||
CopyDWORDs2Bytes(header->EncryptedVerifier.b1 , header->EncryptedVerifier.b2, header->EncryptedVerifier.b3, header->EncryptedVerifier.b4, pnVerifier);
|
||||
CopyDWORDs2Bytes(header->EncryptedVerifierHash.b1, header->EncryptedVerifierHash.b2, header->EncryptedVerifierHash.b3, header->EncryptedVerifierHash.b4, pnVerifierHash);
|
||||
|
||||
mxDecoder.reset(new BiffDecoder_RCF(pnSalt, pnVerifier, pnVerifierHash));
|
||||
|
||||
mxDecoder->verifyPassword(L"VelvetSweatshop");
|
||||
m_VerifyPassword = mxDecoder->verifyPassword(password);
|
||||
}
|
||||
|
||||
void RC4Crypt::Encrypt(char* data, const size_t size)
|
||||
@ -22,6 +27,11 @@ void RC4Crypt::Encrypt(char* data, const size_t size)
|
||||
|
||||
}
|
||||
|
||||
bool RC4Crypt::IsVerify()
|
||||
{
|
||||
return m_VerifyPassword;
|
||||
}
|
||||
|
||||
void RC4Crypt::CopyDWORDs2Bytes(const unsigned int b1, const unsigned int b2, const unsigned int b3, const unsigned int b4, unsigned char* byte_array)
|
||||
{
|
||||
byte_array[0] = static_cast<unsigned char>((b1 & 0x000000ff) >> 0);
|
||||
|
||||
@ -10,20 +10,23 @@ namespace CRYPT
|
||||
class RC4Crypt : public Crypt
|
||||
{
|
||||
public:
|
||||
RC4Crypt(const CRYPTO::RC4EncryptionHeader& header);
|
||||
RC4Crypt(CRYPTO::RC4EncryptionHeaderPtr & header, std::wstring password);
|
||||
|
||||
virtual void Encrypt(char* data, const size_t size);
|
||||
virtual void Decrypt(char* data, const size_t size, const unsigned long stream_pos);
|
||||
|
||||
virtual bool IsVerify();
|
||||
|
||||
private:
|
||||
void CopyDWORDs2Bytes(const unsigned int b1, const unsigned int b2, const unsigned int b3, const unsigned int b4, unsigned char* byte_array);
|
||||
|
||||
private:
|
||||
unsigned char pnSalt[16];
|
||||
unsigned char pnVerifier[16];
|
||||
unsigned char pnVerifierHash[16];
|
||||
|
||||
BiffDecoderRef mxDecoder;
|
||||
|
||||
bool m_VerifyPassword;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -45,8 +45,13 @@ void FilePass::readFields(CFRecord& record)
|
||||
majorVer = *record.getCurData<unsigned short>();
|
||||
if(0x0001 == majorVer) // RC4 encryption header structure
|
||||
{
|
||||
record >> rc4Header;
|
||||
record.getGlobalWorkbookInfo()->decryptor = CRYPT::DecryptorPtr(new CRYPT::Decryptor(rc4Header));
|
||||
rc4HeaderPtr = CRYPTO::RC4EncryptionHeaderPtr(new CRYPTO::RC4EncryptionHeader());
|
||||
|
||||
rc4HeaderPtr->load (record);
|
||||
|
||||
record.getGlobalWorkbookInfo()->decryptor =
|
||||
CRYPT::DecryptorPtr(new CRYPT::Decryptor(rc4HeaderPtr, record.getGlobalWorkbookInfo()->password));
|
||||
|
||||
Log::info("Encryption type: RC4 Standard");
|
||||
}
|
||||
else // RC4 CryptoAPI encryption header structuren
|
||||
|
||||
@ -28,10 +28,11 @@ public:
|
||||
|
||||
//-----------------------------
|
||||
Boolean<unsigned short> wEncryptionType;
|
||||
XORObfuscation key;
|
||||
_UINT16 majorVer;
|
||||
CRYPTO::RC4EncryptionHeader rc4Header;
|
||||
CRYPTO::RC4CryptoAPIEncryptionHeader rc4CryptoAPIHeader;
|
||||
XORObfuscation key;
|
||||
_UINT16 majorVer;
|
||||
|
||||
CRYPTO::RC4EncryptionHeaderPtr rc4HeaderPtr;
|
||||
CRYPTO::RC4CryptoAPIEncryptionHeader rc4CryptoAPIHeader;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -19,19 +19,25 @@ public:
|
||||
static const XLS::ElementType type = XLS::typeRC4EncryptionHeader;
|
||||
|
||||
Version EncryptionVersionInfo;
|
||||
struct SALT_TAG {
|
||||
|
||||
struct SALT_TAG
|
||||
{
|
||||
_UINT32 b1;
|
||||
_UINT32 b2;
|
||||
_UINT32 b3;
|
||||
_UINT32 b4;
|
||||
} Salt;
|
||||
struct ENCRYPTED_VERIFIER_TAG {
|
||||
|
||||
struct ENCRYPTED_VERIFIER_TAG
|
||||
{
|
||||
_UINT32 b1;
|
||||
_UINT32 b2;
|
||||
_UINT32 b3;
|
||||
_UINT32 b4;
|
||||
} EncryptedVerifier;
|
||||
struct ENCRYPTED_VERIFIER_HASH_TAG {
|
||||
|
||||
struct ENCRYPTED_VERIFIER_HASH_TAG
|
||||
{
|
||||
_UINT32 b1;
|
||||
_UINT32 b2;
|
||||
_UINT32 b3;
|
||||
@ -39,5 +45,7 @@ public:
|
||||
} EncryptedVerifierHash;
|
||||
};
|
||||
|
||||
typedef boost::shared_ptr<RC4EncryptionHeader> RC4EncryptionHeaderPtr;
|
||||
|
||||
} // namespace CRYPTO
|
||||
|
||||
|
||||
@ -106,6 +106,11 @@ const bool BinReaderProcessor::readChild(BaseObject& object, const bool is_manda
|
||||
ret_val = object.read(reader_, parent_, is_mandatory /* log warning if mandatory tag absent*/);
|
||||
if(!ret_val && is_mandatory)
|
||||
{
|
||||
if (global_info_->decryptor)
|
||||
{
|
||||
if (global_info_->decryptor->IsVerify() == false)
|
||||
return false;
|
||||
}
|
||||
// We don't update ret_val here because we are reading to the copy of the object.
|
||||
// And the real object will remain uninitialized
|
||||
wanted_objects.push_back(object.clone()); // store the copy of the object that was not found (this line is here to take another chance to be read after some trash processed)
|
||||
|
||||
@ -47,6 +47,7 @@ public:
|
||||
|
||||
unsigned short CodePage;
|
||||
CRYPT::DecryptorPtr decryptor;
|
||||
std::wstring password;
|
||||
|
||||
std::vector<std::wstring> sheets_state;
|
||||
std::vector<std::wstring> sheets_names;
|
||||
|
||||
@ -144,7 +144,17 @@ const bool GlobalsSubstream::loadContent(BinProcessor& proc)
|
||||
}
|
||||
}break;
|
||||
case rt_WriteProtect: proc.optional<WriteProtect>(); break;
|
||||
case rt_FilePass: proc.optional<FilePass>(); break;
|
||||
case rt_FilePass:
|
||||
{
|
||||
if (proc.optional<FilePass>())
|
||||
{
|
||||
if (( proc.getGlobalWorkbookInfo()->decryptor) &&
|
||||
( proc.getGlobalWorkbookInfo()->decryptor->IsVerify() == false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}break;
|
||||
case rt_Template:
|
||||
{
|
||||
if (proc.optional<Template>())
|
||||
|
||||
@ -5,14 +5,19 @@
|
||||
#include "../../../Common/OfficeFileErrorDescription.h"
|
||||
|
||||
|
||||
long ConvertXls2Xlsx(const std::wstring & srcFile, const std::wstring & dstPath, const std::wstring & fontsPath, const ProgressCallback* pCallBack)
|
||||
long ConvertXls2Xlsx(const std::wstring & srcFile, const std::wstring & dstPath, const std::wstring & password, const std::wstring & fontsPath, const ProgressCallback* pCallBack)
|
||||
{
|
||||
XlsConverter converter(srcFile, dstPath, fontsPath, pCallBack);
|
||||
XlsConverter converter(srcFile, dstPath, password, fontsPath, pCallBack);
|
||||
|
||||
if (converter.isError())
|
||||
{
|
||||
if (converter.is_older_version)
|
||||
return AVS_MSFILE_ERROR_OLDER;
|
||||
if (converter.is_encrypted)
|
||||
{
|
||||
if (password.empty()) return AVS_ERROR_DRM;
|
||||
else return AVS_ERROR_PASSWORD;
|
||||
}
|
||||
else return AVS_ERROR_FILEFORMAT;
|
||||
}
|
||||
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
|
||||
struct ProgressCallback;
|
||||
|
||||
long ConvertXls2Xlsx(const std::wstring & srcFile, const std::wstring & dstPath, const std::wstring& fontsPath, const ProgressCallback* CallBack);
|
||||
long ConvertXls2Xlsx(const std::wstring & srcFile, const std::wstring & dstPath, const std::wstring & password, const std::wstring& fontsPath, const ProgressCallback* CallBack);
|
||||
@ -86,7 +86,7 @@ typedef struct tagBITMAPCOREHEADER {
|
||||
} BITMAPCOREHEADER;
|
||||
#endif
|
||||
|
||||
XlsConverter::XlsConverter(const std::wstring & xls_file, const std::wstring & _xlsx_path, const std::wstring & fontsPath, const ProgressCallback* CallBack)
|
||||
XlsConverter::XlsConverter(const std::wstring & xls_file, const std::wstring & _xlsx_path, const std::wstring & password, const std::wstring & fontsPath, const ProgressCallback* CallBack)
|
||||
{
|
||||
xlsx_path = _xlsx_path;
|
||||
output_document = NULL;
|
||||
@ -95,6 +95,7 @@ XlsConverter::XlsConverter(const std::wstring & xls_file, const std::wstring & _
|
||||
pCallBack = CallBack;
|
||||
bUserStopConvert = false;
|
||||
is_older_version = false;
|
||||
is_encrypted = false;
|
||||
|
||||
try{
|
||||
XLS::CompoundFile cfile(xls_file, XLS::CompoundFile::cf_ReadMode);
|
||||
@ -138,15 +139,24 @@ XlsConverter::XlsConverter(const std::wstring & xls_file, const std::wstring & _
|
||||
}
|
||||
|
||||
xls_global_info = boost::shared_ptr<XLS::GlobalWorkbookInfo>(new XLS::GlobalWorkbookInfo(workbook_code_page, this));
|
||||
|
||||
xls_global_info->fontsDirectory = fontsPath;
|
||||
xls_global_info->password = password;
|
||||
|
||||
XLS::CFStreamCacheReader stream_reader(cfile.getWorkbookStream(), xls_global_info);
|
||||
|
||||
xls_document = boost::shared_ptr<XLS::WorkbookStreamObject>(new XLS::WorkbookStreamObject(workbook_code_page));
|
||||
|
||||
|
||||
XLS::BinReaderProcessor proc(stream_reader , xls_document.get() , true);
|
||||
proc.mandatory(*xls_document.get());
|
||||
|
||||
if (xls_global_info->decryptor)
|
||||
{
|
||||
is_encrypted = true;
|
||||
if (xls_global_info->decryptor->IsVerify() == false) return;
|
||||
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
|
||||
@ -59,7 +59,7 @@ namespace ODRAW
|
||||
class XlsConverter
|
||||
{
|
||||
public:
|
||||
XlsConverter(const std::wstring & xls_file, const std::wstring & xlsx_path, const std::wstring & fontsPath, const ProgressCallback* ffCallBack);
|
||||
XlsConverter(const std::wstring & xls_file, const std::wstring & xlsx_path, const std::wstring & password, const std::wstring & fontsPath, const ProgressCallback* ffCallBack);
|
||||
~XlsConverter() ;
|
||||
|
||||
oox::xlsx_conversion_context * xlsx_context;
|
||||
@ -95,6 +95,7 @@ public:
|
||||
std::wstring GetTargetMoniker(XLS::BiffStructure *moniker);
|
||||
|
||||
bool isError();
|
||||
bool is_encrypted;
|
||||
bool is_older_version;
|
||||
|
||||
std::wstring WriteMediaFile (char *data, int size, std::wstring type_ext, int id = -1);
|
||||
|
||||
Reference in New Issue
Block a user