From a61abdd02e1fdf9de28617f41ee1dd909611cfae Mon Sep 17 00:00:00 2001 From: ElenaSubbotina Date: Thu, 28 Jul 2016 15:06:38 +0300 Subject: [PATCH] EcmaCryptReader/Decoder - agile + standart --- .../DocDocxConverter/MemoryStream.h | 1 + Common/OfficeFileFormatChecker2.cpp | 9 +- OfficeCryptReader/source/CryptTransform.cpp | 245 +++++++---- OfficeCryptReader/source/CryptTransform.h | 15 +- OfficeCryptReader/source/ECMACryptReader.cpp | 400 ++++++++++++------ OfficeCryptReader/source/ECMACryptReader.h | 31 -- 6 files changed, 443 insertions(+), 258 deletions(-) diff --git a/ASCOfficeDocFile/DocDocxConverter/MemoryStream.h b/ASCOfficeDocFile/DocDocxConverter/MemoryStream.h index cec39a9599..cb29b27225 100644 --- a/ASCOfficeDocFile/DocDocxConverter/MemoryStream.h +++ b/ASCOfficeDocFile/DocDocxConverter/MemoryStream.h @@ -32,6 +32,7 @@ #pragma once #include "IBinaryReader.h" +#include "../Common/FormatUtils.h" class MemoryStream: public IBinaryReader { diff --git a/Common/OfficeFileFormatChecker2.cpp b/Common/OfficeFileFormatChecker2.cpp index b5744f1670..fdbd2e24ac 100644 --- a/Common/OfficeFileFormatChecker2.cpp +++ b/Common/OfficeFileFormatChecker2.cpp @@ -116,8 +116,15 @@ bool COfficeFileFormatChecker::isDocFormatFile (POLE::Storage * storage) POLE::Stream stream(storage, "WordDocument"); unsigned char buffer[10]; - if (stream.read(buffer,10) >0) + if (stream.read(buffer,10) > 0) + { + //ms office 2007 encrypted contains stream WordDocument !! + std::list entries = storage->entries("DataSpaces"); + if (entries.size() > 0) + return false; + return true; + } return false; } diff --git a/OfficeCryptReader/source/CryptTransform.cpp b/OfficeCryptReader/source/CryptTransform.cpp index c63b8be33a..4979c64ce6 100644 --- a/OfficeCryptReader/source/CryptTransform.cpp +++ b/OfficeCryptReader/source/CryptTransform.cpp @@ -51,22 +51,6 @@ static const unsigned char encrDataIntegrityHmacValueBlockKey[8] = { 0xa0, 0x67, ECMADecryptor::ECMADecryptor() { -//default ms2010 - cryptData.cipherAlgorithm = CRYPT_METHOD::AES_CBC; - cryptData.hashAlgorithm = CRYPT_METHOD::SHA1; - cryptData.spinCount = 100000; - cryptData.keySize = 0x10; - cryptData.hashSize = 0x14; - cryptData.blockSize = 0x10; - cryptData.saltSize = 0x10; -//default ms2013/ms2016 - //cryptData.cipherAlgorithm = AES_CBC; - //cryptData.hashAlgorithm = SHA256; - //cryptData.spinCount = 100000; - //cryptData.keySize = 0x20; - //cryptData.hashSize = 0x40; - //cryptData.blockSize = 0x10; - //cryptData.saltSize = 0x10; } class _buf @@ -133,17 +117,13 @@ public: return *this; } - _buf& operator=(_buf& oSrc) + void Clear() { - Clear(); + if (bDelete && ptr) delete []ptr; + ptr = NULL; size = 0; - size = oSrc.size; - ptr = new unsigned char [oSrc.size]; - memcpy(ptr, oSrc.ptr, oSrc.size); bDelete = true; - - return *this; - } + } //---------------------------------------------------------------------- private: bool bDelete; @@ -162,13 +142,6 @@ private: } } - void Clear() - { - if (bDelete && ptr) delete []ptr; - ptr = NULL; size = 0; - - bDelete = true; - } }; bool operator==(const _buf& oBuf1, const _buf& oBuf2) @@ -185,7 +158,8 @@ void CorrectHashSize(_buf & hashBuf, int size, unsigned char padding) unsigned char *newPtr = new unsigned char[size]; memset(newPtr, padding, size); memcpy(newPtr, hashBuf.ptr, hashBuf.size); - delete []hashBuf.ptr; + + hashBuf.Clear(); hashBuf.ptr = newPtr; hashBuf.size = size; @@ -238,7 +212,7 @@ _buf HashAppend(_buf & hashBuf, _buf & block, CRYPT_METHOD::_hashAlgorithm algo return _buf(); } -_buf GenerateKey(_buf & salt, _buf & password, _buf & blockKey, int hashSize, int spin, CRYPT_METHOD::_hashAlgorithm algorithm) +_buf GenerateAgileKey(_buf & salt, _buf & password, _buf & blockKey, int hashSize, int spin, CRYPT_METHOD::_hashAlgorithm algorithm) { _buf pHashBuf = HashAppend(salt, password, algorithm); @@ -255,19 +229,64 @@ _buf GenerateKey(_buf & salt, _buf & password, _buf & blockKey, int hashSize, in return _buf(pHashBuf.ptr, pHashBuf.size); } -bool DecryptAES(_buf & key, _buf & iv, _buf & data_inp, _buf & data_out) +_buf GenerateHashKey(_buf & salt, _buf & password, int hashSize, int spin, CRYPT_METHOD::_hashAlgorithm algorithm) { - CryptoPP::AES::Decryption aesDecryption(key.ptr, key.size); - CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption( aesDecryption, iv.ptr ); - - if (!data_out.ptr) + _buf empty (NULL, 0, false); + _buf pHashBuf = HashAppend(salt, password, algorithm); + + int i = 0; + for (i = 0; i < spin; i++) { - data_out = _buf(data_inp.size); + _buf iterator((unsigned char*)&i, 4, false); + pHashBuf = HashAppend(iterator, pHashBuf, algorithm); + } + i = 0; + _buf iterator((unsigned char*)&i, 4, false); + pHashBuf = HashAppend(pHashBuf, iterator, algorithm); + + _buf derivedKey(64); + for (int i = 0; i < derivedKey.size; i++) + { + derivedKey.ptr[i] = (i < pHashBuf.size ? 0x36 ^ pHashBuf.ptr[i] : 0x36); + } + + pHashBuf = HashAppend(derivedKey, empty, algorithm); + + return _buf(pHashBuf.ptr, hashSize); +} + +bool DecryptCipher(_buf & key, _buf & iv, _buf & data_inp, _buf & data_out, CRYPT_METHOD::_cipherAlgorithm algorithm) +{ + if (algorithm == CRYPT_METHOD::RC4) + { + } + else + { + CryptoPP::AES::Decryption aesDecryption(key.ptr, key.size); + CryptoPP::StreamTransformation *modeDecryption = NULL; + + switch(algorithm) + { + case CRYPT_METHOD::AES_ECB: + modeDecryption = new CryptoPP::ECB_Mode_ExternalCipher::Decryption(aesDecryption, iv.ptr ); + break; + case CRYPT_METHOD::AES_CBC: + modeDecryption = new CryptoPP::CBC_Mode_ExternalCipher::Decryption(aesDecryption, iv.ptr ); + break; + } + if (!modeDecryption) return false; + + if (!data_out.ptr) + { + data_out = _buf(data_inp.size); + } + CryptoPP::StreamTransformationFilter stfDecryptor(*modeDecryption, new CryptoPP::ArraySink( data_out.ptr, data_out.size), CryptoPP::StreamTransformationFilter::NO_PADDING); + + stfDecryptor.Put( data_inp.ptr, data_inp.size ); + stfDecryptor.MessageEnd(); + + delete modeDecryption; } - CryptoPP::StreamTransformationFilter stfDecryptor(cbcDecryption, new CryptoPP::ArraySink( data_out.ptr, data_out.size), CryptoPP::StreamTransformationFilter::NO_PADDING); - - stfDecryptor.Put( data_inp.ptr, data_inp.size ); - stfDecryptor.MessageEnd(); return true; } @@ -275,32 +294,59 @@ bool DecryptAES(_buf & key, _buf & iv, _buf & data_inp, _buf & data_out) bool ECMADecryptor::SetPassword(std::wstring password_) { password = password_; - - _buf pPassword (password); - _buf pSalt (cryptData.saltValue); - _buf pInputBlockKey ((unsigned char*)encrVerifierHashInputBlockKey, 8); - _buf pValueBlockKey ((unsigned char*)encrVerifierHashValueBlockKey, 8); - - _buf pEncVerInput (cryptData.encryptedVerifierInput); - _buf pEncVerValue (cryptData.encryptedVerifierValue); - - _buf verifierInputKey = GenerateKey( pSalt, pPassword, pInputBlockKey, cryptData.keySize, cryptData.spinCount, cryptData.hashAlgorithm ); - _buf decryptedVerifierHashInputBytes; - - DecryptAES(verifierInputKey, pSalt, pEncVerInput, decryptedVerifierHashInputBytes); -//-------------------------------------------- + if (cryptData.bAgile) + { + _buf pPassword (password); + _buf pSalt (cryptData.saltValue); + _buf pInputBlockKey ((unsigned char*)encrVerifierHashInputBlockKey, 8); + _buf pValueBlockKey ((unsigned char*)encrVerifierHashValueBlockKey, 8); + _buf empty (NULL, 0, false); + + _buf pEncVerInput (cryptData.encryptedVerifierInput); + _buf pEncVerValue (cryptData.encryptedVerifierValue); + + _buf verifierInputKey = GenerateAgileKey( pSalt, pPassword, pInputBlockKey, cryptData.keySize, cryptData.spinCount, cryptData.hashAlgorithm ); + _buf decryptedVerifierHashInputBytes; + + DecryptCipher(verifierInputKey, pSalt, pEncVerInput, decryptedVerifierHashInputBytes, cryptData.cipherAlgorithm); + //-------------------------------------------- - _buf empty(NULL,0,false); - _buf hashBuf = HashAppend(decryptedVerifierHashInputBytes, empty, cryptData.hashAlgorithm); + _buf hashBuf = HashAppend(decryptedVerifierHashInputBytes, empty, cryptData.hashAlgorithm); -//-------------------------------------------- - _buf decryptedVerifierHashBytes; - - _buf verifierHashKey = GenerateKey(pSalt, pPassword, pValueBlockKey, cryptData.keySize, cryptData.spinCount, cryptData.hashAlgorithm); - DecryptAES(verifierHashKey, pSalt, pEncVerValue, decryptedVerifierHashBytes); + //-------------------------------------------- + _buf decryptedVerifierHashBytes; + + _buf verifierHashKey = GenerateAgileKey(pSalt, pPassword, pValueBlockKey, cryptData.keySize, cryptData.spinCount, cryptData.hashAlgorithm); + DecryptCipher(verifierHashKey, pSalt, pEncVerValue, decryptedVerifierHashBytes, cryptData.cipherAlgorithm); - return (decryptedVerifierHashBytes==hashBuf); + return (decryptedVerifierHashBytes==hashBuf); + } + else + { + _buf pPassword (password); + _buf pSalt (cryptData.saltValue); + _buf empty (NULL, 0, false); + + _buf pEncVerInput (cryptData.encryptedVerifierInput); + _buf pEncVerValue (cryptData.encryptedVerifierValue); + + _buf hashKey = GenerateHashKey(pSalt, pPassword, cryptData.keySize, cryptData.spinCount, cryptData.hashAlgorithm); + + _buf decryptedVerifierHashInputBytes; + DecryptCipher(hashKey, empty, pEncVerInput, decryptedVerifierHashInputBytes, cryptData.cipherAlgorithm); + + //-------------------------------------------- + + _buf hashBuf = HashAppend(decryptedVerifierHashInputBytes, empty, cryptData.hashAlgorithm); + + //-------------------------------------------- + _buf decryptedVerifierHashBytes; + + DecryptCipher(hashKey, empty, pEncVerValue, decryptedVerifierHashBytes, cryptData.cipherAlgorithm); + + return (decryptedVerifierHashBytes==hashBuf); + } } void ECMADecryptor::SetCryptData(_cryptData &data) @@ -311,41 +357,54 @@ void ECMADecryptor::SetCryptData(_cryptData &data) void ECMADecryptor::Decrypt(unsigned char* data_inp, int size, unsigned char*& data_out) { data_out = NULL; - - _buf pBlockKey ((unsigned char*)encrKeyValueBlockKey, 8); - _buf pPassword (password); - _buf pDataSalt (cryptData.dataSaltValue); + _buf pPassword (password); _buf pSalt (cryptData.saltValue); - _buf pKeyValue (cryptData.encryptedKeyValue); - - _buf Key = GenerateKey( pSalt, pPassword, pBlockKey, cryptData.keySize, cryptData.spinCount, cryptData.hashAlgorithm); - - _buf pDecryptedKey; - DecryptAES( Key, pSalt, pKeyValue, pDecryptedKey); - - _buf iv(cryptData.blockSize); - memset( iv.ptr, 0x00, cryptData.blockSize ); - - int i = 0, sz = 4096, pos = 0; + _buf empty (NULL, 0, false); data_out = new unsigned char[size]; - - while (pos < size) - { - if (pos + sz > size) - sz = size - pos; - - _buf pIndex((unsigned char*)&i, 4); - iv = HashAppend(pDataSalt, pIndex, cryptData.hashAlgorithm); - CorrectHashSize(iv, cryptData.blockSize, 0x36); + if (cryptData.bAgile) + { + _buf pBlockKey ((unsigned char*)encrKeyValueBlockKey, 8); + _buf pDataSalt (cryptData.dataSaltValue); + _buf pKeyValue (cryptData.encryptedKeyValue); + + _buf agileKey = GenerateAgileKey( pSalt, pPassword, pBlockKey, cryptData.keySize, cryptData.spinCount, cryptData.hashAlgorithm); + + _buf pDecryptedKey; + DecryptCipher( agileKey, pSalt, pKeyValue, pDecryptedKey, cryptData.cipherAlgorithm); + + _buf iv(cryptData.blockSize); + memset( iv.ptr, 0x00, cryptData.blockSize ); + + int i = 0, sz = 4096, pos = 0; - _buf pInp(data_inp + pos, sz, false); - _buf pOut(data_out + pos, sz, false); + while (pos < size) + { + if (pos + sz > size) + sz = size - pos; - DecryptAES(pDecryptedKey, iv, pInp, pOut); + _buf pIndex((unsigned char*)&i, 4); + iv = HashAppend(pDataSalt, pIndex, cryptData.hashAlgorithm); - pos += sz; i++; + CorrectHashSize(iv, cryptData.blockSize, 0x36); + + _buf pInp(data_inp + pos, sz, false); + _buf pOut(data_out + pos, sz, false); + + DecryptCipher(pDecryptedKey, iv, pInp, pOut, cryptData.cipherAlgorithm); + + pos += sz; i++; + } + } + else + { + _buf hashKey = GenerateHashKey(pSalt, pPassword, cryptData.keySize, cryptData.spinCount, cryptData.hashAlgorithm); + + _buf pInp(data_inp, size, false); + _buf pOut(data_out, size, false); + + DecryptCipher(hashKey, empty, pInp, pOut, cryptData.cipherAlgorithm); } } diff --git a/OfficeCryptReader/source/CryptTransform.h b/OfficeCryptReader/source/CryptTransform.h index 2af1908de0..a257c5128b 100644 --- a/OfficeCryptReader/source/CryptTransform.h +++ b/OfficeCryptReader/source/CryptTransform.h @@ -50,7 +50,8 @@ namespace CRYPT_METHOD XOR, RC4, AES_CBC, - AES_CFB + AES_CFB, + AES_ECB }; } @@ -60,6 +61,14 @@ public: struct _cryptData { +//default ms2010 + _cryptData() : cipherAlgorithm(CRYPT_METHOD::AES_CBC), hashAlgorithm(CRYPT_METHOD::SHA1), spinCount(100000), + keySize(0x10), hashSize(0x14), blockSize(0x10), saltSize(0x10), bAgile(true) +//default ms2013/ms2016 + //_cryptData(): cipherAlgorithm(CRYPT_METHOD::AES_CBC), hashAlgorithm(CRYPT_METHOD::SHA256), spinCount(100000), + // keySize(0x20), hashSize(0x40), blockSize(0x10), saltSize(0x10), bAgile(true) + { + } CRYPT_METHOD::_cipherAlgorithm cipherAlgorithm; CRYPT_METHOD::_hashAlgorithm hashAlgorithm; @@ -78,6 +87,8 @@ public: std::string encryptedHmacKey; std::string encryptedHmacValue; + bool bAgile; + //.......... }; @@ -86,8 +97,6 @@ public: void Decrypt(unsigned char* data, int size, unsigned char*& data_out); - bool IsVerify(){} - bool SetPassword(std::wstring password); void SetCryptData(_cryptData &data); diff --git a/OfficeCryptReader/source/ECMACryptReader.cpp b/OfficeCryptReader/source/ECMACryptReader.cpp index dd0527063c..5f83082bf1 100644 --- a/OfficeCryptReader/source/ECMACryptReader.cpp +++ b/OfficeCryptReader/source/ECMACryptReader.cpp @@ -39,6 +39,10 @@ #include "../../DesktopEditor/common/File.h" +#include "../../ASCOfficeDocFile/DocDocxConverter/MemoryStream.h" + +#define GETBIT(from, num) ((from & (1 << num)) != 0) + #define WritingElement_ReadAttributes_Start(Reader) \ if ( Reader.GetAttributesCount() <= 0 )\ return false;\ @@ -87,6 +91,7 @@ std::wstring ReadUnicodeLP(POLE::Stream *pStream) return res; } + void ReadMapEntry(POLE::Stream *pStream, ECMACryptReader::_mapEntry & m) { if (!pStream) return; @@ -122,139 +127,30 @@ std::string DecodeBase64(const std::string & value) } return result; } -//-------------------------------------------------------------- -bool ECMACryptReader::DecryptOfficeFile(std::wstring file_name_inp, std::wstring file_name_out, std::wstring password) +//----------------------------------------------------------------------------------------------------------------------- +struct _keyEncryptor { - POLE::Storage *pStorage = new POLE::Storage(file_name_inp.c_str()); - - if (!pStorage)return false; + std::string spinCount; + std::string saltSize; + std::string blockSize; + std::string keyBits; + std::string hashSize; - if (!pStorage->open()) - { - delete pStorage; - return false; - } + std::string cipherAlgorithm; + std::string cipherChaining; + std::string hashAlgorithm; - POLE::Stream *pStream = new POLE::Stream(pStorage, "EncryptionInfo"); - if (pStream) - { - _UINT32 nEncryptionInfoSize = 0; - int sz = pStream->read((unsigned char*)&nEncryptionInfoSize, 4); //size uncrypt ?? - - _UINT32 nEncryptionInfoSize1 = 0; - sz = pStream->read((unsigned char*)&nEncryptionInfoSize1, 4); //??? (64) - - unsigned char* byteEncryptionInfo = new unsigned char[nEncryptionInfoSize]; - if (!byteEncryptionInfo) - { - delete pStream; - delete pStorage; - return false; - } - sz = pStream->read(byteEncryptionInfo, nEncryptionInfoSize); - - std::string xml_string((char*) byteEncryptionInfo, sz); - delete []byteEncryptionInfo; - delete pStream; - - if (!ReadEncryptionInfo(xml_string)) - { - delete pStorage; - return false; - } - } - - ECMADecryptor decryptor; - - ECMADecryptor::_cryptData cryptData; - - cryptData.spinCount = atoi(keyEncryptors[0].spinCount.c_str()); - cryptData.blockSize = atoi(keyEncryptors[0].blockSize.c_str()); - cryptData.hashSize = atoi(keyEncryptors[0].hashSize.c_str()); - cryptData.saltSize = atoi(keyEncryptors[0].saltSize.c_str()); - cryptData.keySize = atoi(keyEncryptors[0].keyBits.c_str() ) / 8; - - cryptData.dataSaltValue = DecodeBase64(keyData.saltValue); - cryptData.saltValue = DecodeBase64(keyEncryptors[0].saltValue); - cryptData.encryptedKeyValue = DecodeBase64(keyEncryptors[0].encryptedKeyValue); - cryptData.encryptedVerifierInput = DecodeBase64(keyEncryptors[0].encryptedVerifierHashInput); - cryptData.encryptedVerifierValue = DecodeBase64(keyEncryptors[0].encryptedVerifierHashValue); - - cryptData.encryptedHmacKey = DecodeBase64(dataIntegrity.encryptedHmacKey); - cryptData.encryptedHmacValue = DecodeBase64(dataIntegrity.encryptedHmacValue); - - if (keyData.cipherAlgorithm == "AES") - { - if (keyData.cipherChaining == "ChainingModeCBC") cryptData.cipherAlgorithm = CRYPT_METHOD::AES_CBC; - if (keyData.cipherChaining == "ChainingModeCFB") cryptData.cipherAlgorithm = CRYPT_METHOD::AES_CFB; - } - else - { - } - - if (keyData.hashAlgorithm == "SHA1") cryptData.hashAlgorithm = CRYPT_METHOD::SHA1; - if (keyData.hashAlgorithm == "SHA224") cryptData.hashAlgorithm = CRYPT_METHOD::SHA224; - if (keyData.hashAlgorithm == "SHA256") cryptData.hashAlgorithm = CRYPT_METHOD::SHA256; - if (keyData.hashAlgorithm == "SHA384") cryptData.hashAlgorithm = CRYPT_METHOD::SHA384; - if (keyData.hashAlgorithm == "SHA512") cryptData.hashAlgorithm = CRYPT_METHOD::SHA512; - - decryptor.SetCryptData(cryptData); - - if (!decryptor.SetPassword(password)) - return false; - - //pStream = new POLE::Stream(pStorage, "DataSpaces/DataSpaceMap"); // савершенно ненужная инфа - //if (pStream) - //{ - // _UINT32 size = 0; - // _UINT32 count = 0; - // - // pStream->read((unsigned char*)&size, 4); - // pStream->read((unsigned char*)&count, 4); - - // for (int i = 0 ; i < count; i++) - // { - // _mapEntry m; - // ReadMapEntry(pStream, m); - - // mapEntries.push_back(m); - // } - // delete pStream; - //} - - bool result = false; - - pStream = new POLE::Stream(pStorage, "EncryptedPackage"); - if (pStream->size() > 0) - { - _UINT64 lengthData, lengthRead = pStream->size() - 8; - pStream->read((unsigned char*)&lengthData, 8); - - unsigned char* data = new unsigned char[lengthRead]; - unsigned char* data_out = NULL; - - pStream->read(data, lengthRead); - - decryptor.Decrypt(data, lengthRead, data_out);//todoo сделать покусочное чтение декриптование - delete pStream; - - if (data_out) - { - NSFile::CFileBinary f; - f.CreateFileW(file_name_out); - f.WriteFile(data_out, lengthData); - f.CloseFile(); - - result = true; - } - } -//------------------------------------------------------------------- - delete pStorage; - return result; -} - - -bool ECMACryptReader::ReadEncryptionInfo(const std::string & xml_string) + std::string saltValue; + std::string encryptedVerifierHashInput; + std::string encryptedVerifierHashValue; + std::string encryptedKeyValue; +}; +struct _dataIntegrity +{ + std::string encryptedHmacKey; + std::string encryptedHmacValue; +}; +bool ReadXmlEncryptionInfo(const std::string & xml_string, ECMADecryptor::_cryptData & cryptData) { XmlUtils::CXmlLiteReader xmlReader; @@ -264,6 +160,10 @@ bool ECMACryptReader::ReadEncryptionInfo(const std::string & xml_string) if ( !xmlReader.ReadNextNode() ) return false; + _dataIntegrity dataIntegrity; + _keyEncryptor keyData; + std::vector<_keyEncryptor> keyEncryptors; + int nCurDepth = xmlReader.GetDepth(); while( xmlReader.ReadNextSiblingNode( nCurDepth ) ) { @@ -324,6 +224,246 @@ bool ECMACryptReader::ReadEncryptionInfo(const std::string & xml_string) } } } + + if (keyEncryptors.empty()) return false; + + cryptData.spinCount = atoi(keyEncryptors[0].spinCount.c_str()); + cryptData.blockSize = atoi(keyEncryptors[0].blockSize.c_str()); + cryptData.hashSize = atoi(keyEncryptors[0].hashSize.c_str()); + cryptData.saltSize = atoi(keyEncryptors[0].saltSize.c_str()); + cryptData.keySize = atoi(keyEncryptors[0].keyBits.c_str() ) / 8; + + cryptData.dataSaltValue = DecodeBase64(keyData.saltValue); + cryptData.saltValue = DecodeBase64(keyEncryptors[0].saltValue); + cryptData.encryptedKeyValue = DecodeBase64(keyEncryptors[0].encryptedKeyValue); + cryptData.encryptedVerifierInput = DecodeBase64(keyEncryptors[0].encryptedVerifierHashInput); + cryptData.encryptedVerifierValue = DecodeBase64(keyEncryptors[0].encryptedVerifierHashValue); + + cryptData.encryptedHmacKey = DecodeBase64(dataIntegrity.encryptedHmacKey); + cryptData.encryptedHmacValue = DecodeBase64(dataIntegrity.encryptedHmacValue); + + if (keyData.cipherAlgorithm == "AES") + { + if (keyData.cipherChaining == "ChainingModeCBC") cryptData.cipherAlgorithm = CRYPT_METHOD::AES_CBC; + if (keyData.cipherChaining == "ChainingModeCFB") cryptData.cipherAlgorithm = CRYPT_METHOD::AES_CFB; + } + + if (keyData.hashAlgorithm == "SHA1") cryptData.hashAlgorithm = CRYPT_METHOD::SHA1; + if (keyData.hashAlgorithm == "SHA224") cryptData.hashAlgorithm = CRYPT_METHOD::SHA224; + if (keyData.hashAlgorithm == "SHA256") cryptData.hashAlgorithm = CRYPT_METHOD::SHA256; + if (keyData.hashAlgorithm == "SHA384") cryptData.hashAlgorithm = CRYPT_METHOD::SHA384; + if (keyData.hashAlgorithm == "SHA512") cryptData.hashAlgorithm = CRYPT_METHOD::SHA512; + return true; } +bool ReadStandartEncryptionInfo(unsigned char* data, int size, ECMADecryptor::_cryptData & cryptData) +{ + if (!data || size < 1) return false; + MemoryStream mem_stream(data, size, false); + +//EncryptionHeader + int HeaderSize = mem_stream.ReadUInt32(); + int Flags = mem_stream.ReadUInt32(); + int SizeExtra = mem_stream.ReadUInt32(); + int AlgID = mem_stream.ReadUInt32(); + int AlgIDHash = mem_stream.ReadUInt32(); + int KeySize = mem_stream.ReadUInt32(); + int ProviderType= mem_stream.ReadUInt32(); + int Reserved1 = mem_stream.ReadUInt32(); + int Reserved2 = mem_stream.ReadUInt32(); + + int pos = mem_stream.GetPosition(); + + while(pos < size - 1) + { + if (data[pos] == 0 && data[pos + 1] == 0) + { + break; + } + pos+=2;//unicode null-terminate string + } + int szCSPName = pos - mem_stream.GetPosition() + 2; + + unsigned char* strData = mem_stream.ReadBytes(szCSPName, true); + if (strData) + { + delete []strData; + } +//EncryptionVerifier + cryptData.saltSize = mem_stream.ReadUInt32(); + + cryptData.saltValue = std::string((char*)data + mem_stream.GetPosition(), cryptData.saltSize); + mem_stream.ReadBytes(cryptData.saltSize, false); + + cryptData.encryptedVerifierInput = std::string((char*)data + mem_stream.GetPosition(), 0x10); + mem_stream.ReadBytes(0x10, false); + + cryptData.hashSize = mem_stream.ReadUInt32(); + + int szEncryptedVerifierHash = (ProviderType == 0x0001) ? 0x14 : 0x20; + cryptData.encryptedVerifierValue = std::string((char*)data + mem_stream.GetPosition(), szEncryptedVerifierHash); + mem_stream.ReadBytes(szEncryptedVerifierHash, false); + + pos = mem_stream.GetPosition(); + +//------------------------------------------------------------------------------------------ + cryptData.hashAlgorithm = CRYPT_METHOD::SHA1; //by AlgIDHash -> 0x0000 || 0x8004 + cryptData.spinCount = 50000; + + switch(AlgID) + { + case 0x6801: + cryptData.cipherAlgorithm = CRYPT_METHOD::RC4; + cryptData.keySize = KeySize / 8; + break; + case 0x660E: + cryptData.cipherAlgorithm = CRYPT_METHOD::AES_ECB; + cryptData.keySize = 128 /8; + break; + case 0x660F: + cryptData.cipherAlgorithm = CRYPT_METHOD::AES_ECB; + cryptData.keySize = 192 /8; + break; + case 0x6610: + cryptData.cipherAlgorithm = CRYPT_METHOD::AES_ECB; + cryptData.keySize = 256 /8; + break; + } + return true; +} + +bool ReadExtensibleEncryptionInfo(unsigned char* data, int size, ECMADecryptor::_cryptData & cryptData) +{ + return false; +} + + +//-------------------------------------------------------------- +bool ECMACryptReader::DecryptOfficeFile(std::wstring file_name_inp, std::wstring file_name_out, std::wstring password) +{ + POLE::Storage *pStorage = new POLE::Storage(file_name_inp.c_str()); + + if (!pStorage)return false; + + if (!pStorage->open()) + { + delete pStorage; + return false; + } + ECMADecryptor::_cryptData cryptData; + bool result = false; + + POLE::Stream *pStream = new POLE::Stream(pStorage, "EncryptionInfo"); + if (pStream) + { + _UINT16 VersionInfoMajor = 0, VersionInfoMinor = 0; + + pStream->read((unsigned char*)&VersionInfoMajor, 2); + pStream->read((unsigned char*)&VersionInfoMinor, 2); + + _UINT32 nEncryptionInfoFlags = 0; + pStream->read((unsigned char*)&nEncryptionInfoFlags, 4); + + int nEncryptionInfoSize = pStream->size() - 8; + unsigned char* byteEncryptionInfo = new unsigned char[nEncryptionInfoSize]; + if (!byteEncryptionInfo) + { + delete pStream; + delete pStorage; + return false; + } + nEncryptionInfoSize = pStream->read(byteEncryptionInfo, nEncryptionInfoSize); + delete pStream; + + if (VersionInfoMajor == 0x0004 && VersionInfoMinor == 0x0004) + {//agile info + std::string xml_string((char*) byteEncryptionInfo, nEncryptionInfoSize); + delete []byteEncryptionInfo; + + cryptData.bAgile = true; + result = ReadXmlEncryptionInfo(xml_string, cryptData); + } + else + { + cryptData.bAgile = false; + bool fCryptoAPI = GETBIT(nEncryptionInfoFlags, 1); + bool fDocProps = GETBIT(nEncryptionInfoFlags, 2); + bool fExternal = GETBIT(nEncryptionInfoFlags, 3); + bool fAES = GETBIT(nEncryptionInfoFlags, 4); + + if ((VersionInfoMajor == 0x0003 || VersionInfoMajor == 0x0004) && VersionInfoMinor == 0x0003) //extensible info + { + result = ReadExtensibleEncryptionInfo(byteEncryptionInfo, nEncryptionInfoSize, cryptData); + } + else if ((VersionInfoMajor == 0x0003 || VersionInfoMajor == 0x0004) && VersionInfoMinor == 0x0002) //standart info + { + result = ReadStandartEncryptionInfo(byteEncryptionInfo, nEncryptionInfoSize, cryptData); + } + else + { + // look in DocFormat + } + delete []byteEncryptionInfo; + } + } + if (!result) + { + delete pStorage; + return false; + } +//------------------------------------------------------------------------------------------------------------ + pStream = new POLE::Stream(pStorage, "DataSpaces/DataSpaceMap"); + if (pStream) + { + _UINT32 size = 0; + _UINT32 count = 0; + + pStream->read((unsigned char*)&size, 4); + pStream->read((unsigned char*)&count, 4); + + for (int i = 0 ; i < count; i++) + { + _mapEntry m; + ReadMapEntry(pStream, m); + + mapEntries.push_back(m); + } + delete pStream; + } +//------------------------------------------------------------------------------------------------------------ + ECMADecryptor decryptor; + + decryptor.SetCryptData(cryptData); + + if (!decryptor.SetPassword(password)) + return false; +//------------------------------------------------------------------------------------------------------------ + pStream = new POLE::Stream(pStorage, "EncryptedPackage"); + if (pStream->size() > 0) + { + _UINT64 lengthData, lengthRead = pStream->size() - 8; + pStream->read((unsigned char*)&lengthData, 8); + + unsigned char* data = new unsigned char[lengthRead]; + unsigned char* data_out = NULL; + + pStream->read(data, lengthRead); + + decryptor.Decrypt(data, lengthRead, data_out);//todoo сделать покусочное чтение декриптование + delete pStream; + + if (data_out) + { + NSFile::CFileBinary f; + f.CreateFileW(file_name_out); + f.WriteFile(data_out, lengthData); + f.CloseFile(); + + result = true; + } + } +//------------------------------------------------------------------- + delete pStorage; + return result; +} diff --git a/OfficeCryptReader/source/ECMACryptReader.h b/OfficeCryptReader/source/ECMACryptReader.h index 684164b6b1..4214bf9d58 100644 --- a/OfficeCryptReader/source/ECMACryptReader.h +++ b/OfficeCryptReader/source/ECMACryptReader.h @@ -38,29 +38,6 @@ class ECMACryptReader { public: bool DecryptOfficeFile(std::wstring file_name_inp, std::wstring file_name_out, std::wstring password); - - struct _keyEncryptor - { - std::string spinCount; - std::string saltSize; - std::string blockSize; - std::string keyBits; - std::string hashSize; - - std::string cipherAlgorithm; - std::string cipherChaining; - std::string hashAlgorithm; - - std::string saltValue; - std::string encryptedVerifierHashInput; - std::string encryptedVerifierHashValue; - std::string encryptedKeyValue; - }; - struct _dataIntegrity - { - std::string encryptedHmacKey; - std::string encryptedHmacValue; - }; struct _refComponent { @@ -72,13 +49,5 @@ public: std::vector<_refComponent> refComponents; std::wstring dataSpaceName; }; -private: - - bool ReadEncryptionInfo(const std::string & xmlString); - std::vector<_mapEntry> mapEntries; -//-------------------------------------------------------------- - _keyEncryptor keyData; - _dataIntegrity dataIntegrity; - std::vector<_keyEncryptor> keyEncryptors; };