#include "Stdafx.h" #include "EterPackPolicy_CSHybridCrypt.h" #include "../EterBase/Stl.h" #include "../EterBase/FileName.h" #include "../EterBase/FileBase.h" #include "../EterBase/Crc32.h" #include "../EterBase/lzo.h" #include "../EterBase/Random.h" #include #include using namespace CryptoPP; #define CIPHER_MODE CTR_Mode #ifdef __THEMIDA__ #include #endif //Cipher //Block Size //Key Length // //Default Minimum Maximum //AES(Rijndael) 16 16 16 32 //Blowfish 8 16 0 56 //Camellia 16 16 16 32 //CAST-128 8 16 5 16 //CAST-256 16 16 16 32 //DES 8 8 8 8 //DES-EDE2 8 16 16 16 //DES-EDE3 8 24 24 24 //DES-XEX3 8 24 24 24 //GOST 8 32 32 32 //IDEA 8 16 16 16 //MARS 16 16 16 56 //RC2 8 16 1 128 //RC5 8 16 0 255 //RC6 16 16 0 255 //SAFER-K 8 16 8 16 //SAFER-SK 8 16 8 16 //Serpent 16 16 1 32 //SHACAL-2 32 16 1 64 //SHARK-E 8 16 1 16 //SKIPJACK 8 10 1 10 //3-Way 12 12 1 12 //Twofish 16 16 0 32 //XTEA 8 16 1 16 inline std::string GetFileExt( std::string& rfileName ) { stl_lowers(rfileName); return CFileNameHelper::GetExtension(rfileName); } EterPackPolicy_CSHybridCrypt::~EterPackPolicy_CSHybridCrypt() { m_mapHybridCryptKey.clear(); m_mapSDBMap.clear(); } bool EterPackPolicy_CSHybridCrypt::IsContainingCryptKey() const { return (m_mapHybridCryptKey.size() > 0) ? true : false; } bool EterPackPolicy_CSHybridCrypt::GenerateCryptKey( std::string& rfileName ) { #ifdef __THEMIDA__ VM_START #endif //make lower & extract ext std::string extName = GetFileExt(rfileName); stl_lowers(extName); DWORD dwExtHash = stringhash().GetHash(extName); TCSHybridCryptKeyMap::const_iterator cit = m_mapHybridCryptKey.find( dwExtHash ); if( cit != m_mapHybridCryptKey.end() ) { //TODO : log already registered return false; } static AutoSeededRandomPool rnd; TCSHybridCryptKey info; { rnd.GenerateBlock( &(info.uEncryptKey.key[0]), sizeof(info.uEncryptKey) ); rnd.GenerateBlock( &(info.uEncryptIV.iv[0]), sizeof(info.uEncryptIV) ); //for test /* memset( &info.uEncryptKey.key, 0x10, sizeof(info.uEncryptKey) ); memset( &info.uEncryptIV.iv, 0x10, sizeof(info.uEncryptIV) ); */ } m_mapHybridCryptKey[dwExtHash] = info; #ifdef __THEMIDA__ VM_END #endif return true; } bool EterPackPolicy_CSHybridCrypt::GetPerFileCryptKey( std::string& rfileName, eHybridCipherAlgorithm& eAlgorithm, TEncryptKey& key, TEncryptIV& iv ) { #ifdef __THEMIDA__ VM_START #endif std::string fileNamelower = rfileName; stl_lowers(fileNamelower); std::string extName = GetFileExt(fileNamelower); TCSHybridCryptKeyMap::const_iterator cit = m_mapHybridCryptKey.find( stringhash().GetHash(extName)); if( cit == m_mapHybridCryptKey.end() ) { //TODO : log no file ext info return false; } DWORD dwfileNameCrc = GetCRC32(fileNamelower.c_str(), fileNamelower.size()); //make file specific algorithm & key & iv eAlgorithm = (eHybridCipherAlgorithm)(dwfileNameCrc % Num_Of_Ciphers); ::memcpy(key.key, cit->second.uEncryptKey.key, sizeof(key) ); ::memcpy(iv.iv, cit->second.uEncryptIV.iv, sizeof(iv) ); //Themida Warning for( int i = 0; i < (sizeof(key)/sizeof(dwfileNameCrc)); ++i) { *((DWORD*)key.key + i) ^= dwfileNameCrc; } for( int i = 0; i < (sizeof(iv)/sizeof(dwfileNameCrc)); ++i) { *((DWORD*)iv.iv + i) ^= dwfileNameCrc; } #ifdef __THEMIDA__ VM_END #endif return true; } bool EterPackPolicy_CSHybridCrypt::EncryptMemory( std::string& rfileName, IN const BYTE* pSrcData, IN int iSrcLen, OUT CLZObject& zObj ) { #ifdef __THEMIDA__ VM_START #endif eHybridCipherAlgorithm eAlgorithm; TEncryptKey key; TEncryptIV iv; if( !GetPerFileCryptKey( rfileName, eAlgorithm, key, iv ) ) { return false; } // start cipher std::string strCipher; //NOTE : ciphered stream size could be different from original size if you choose diffrent cipher mode & algorithm //( i.e ECB or CBC mode ) strCipher.reserve(iSrcLen); if( eAlgorithm == e_Cipher_Camellia ) { // Encryptor CIPHER_MODE::Encryption Encryptor; Encryptor.SetKeyWithIV(key.keyCamellia, sizeof(key.keyCamellia), iv.ivCamellia, sizeof(iv.ivCamellia)); ArraySource(pSrcData, iSrcLen, true, new StreamTransformationFilter(Encryptor, new CryptoPP::StringSink(strCipher))); } else if( eAlgorithm == e_Cipher_Twofish ) { // Encryptor CIPHER_MODE::Encryption Encryptor; Encryptor.SetKeyWithIV(key.keyTwofish, sizeof(key.keyTwofish), iv.ivTwofish, sizeof(iv.ivTwofish)); ArraySource(pSrcData, iSrcLen, true, new StreamTransformationFilter(Encryptor, new CryptoPP::StringSink(strCipher))); } else if( eAlgorithm == e_Cipher_XTEA ) { // Encryptor CIPHER_MODE::Encryption Encryptor; Encryptor.SetKeyWithIV(key.keyXTEA, sizeof(key.keyXTEA), iv.ivXTEA, sizeof(iv.ivXTEA)); ArraySource(pSrcData, iSrcLen, true, new StreamTransformationFilter(Encryptor, new CryptoPP::StringSink(strCipher))); } if (strCipher.length() != iSrcLen) { //TODO: size error log return false; } zObj.AllocBuffer(iSrcLen); memcpy(zObj.GetBuffer(), strCipher.c_str(), strCipher.length() ); #ifdef __THEMIDA__ VM_END #endif return true; } bool EterPackPolicy_CSHybridCrypt::DecryptMemory( std::string& rfilename, IN const BYTE* pEncryptedData, IN int iEncryptedLen, OUT CLZObject& zObj ) { #ifdef __THEMIDA__ VM_START #endif eHybridCipherAlgorithm eAlgorithm; TEncryptKey key; TEncryptIV iv; if( !GetPerFileCryptKey( rfilename, eAlgorithm, key, iv ) ) { return false; } // start decipher std::string strDecipher; //NOTE : ciphered stream size could be different from original size if you choose diffrent cipher mode & algorithm //( i.e ECB or CBC mode ) strDecipher.reserve(iEncryptedLen); if( eAlgorithm == e_Cipher_Camellia ) { // Decryptor CIPHER_MODE::Decryption Decryptor; Decryptor.SetKeyWithIV(key.keyCamellia, sizeof(key.keyCamellia), iv.ivCamellia, sizeof(iv.ivCamellia)); ArraySource(pEncryptedData, iEncryptedLen, true, new StreamTransformationFilter(Decryptor, new CryptoPP::StringSink(strDecipher))); } else if( eAlgorithm == e_Cipher_Twofish ) { // Decryptor CIPHER_MODE::Decryption Decryptor; Decryptor.SetKeyWithIV(key.keyTwofish, sizeof(key.keyTwofish), iv.ivTwofish, sizeof(iv.ivTwofish)); ArraySource(pEncryptedData, iEncryptedLen, true, new StreamTransformationFilter(Decryptor, new CryptoPP::StringSink(strDecipher))); } else if( eAlgorithm == e_Cipher_XTEA ) { // Decryptor CIPHER_MODE::Decryption Decryptor; Decryptor.SetKeyWithIV(key.keyXTEA, sizeof(key.keyXTEA), iv.ivXTEA, sizeof(iv.ivXTEA)); ArraySource(pEncryptedData, iEncryptedLen, true, new StreamTransformationFilter(Decryptor, new CryptoPP::StringSink(strDecipher))); } if (strDecipher.length() != iEncryptedLen) { //TODO: size error log return false; } zObj.AllocBuffer(iEncryptedLen); memcpy(zObj.GetBuffer(), strDecipher.c_str(), strDecipher.length() ); #ifdef __THEMIDA__ VM_END #endif return true; } void EterPackPolicy_CSHybridCrypt::WriteCryptKeyToFile( CFileBase& rFile ) { // ext cnt 4byte // for ext hash ( crc32 ) // key-16byte // iv-16byte DWORD dwCryptKeySize = m_mapHybridCryptKey.size(); rFile.Write( &dwCryptKeySize, sizeof(DWORD) ); TCSHybridCryptKeyMap::const_iterator cit; for( cit = m_mapHybridCryptKey.begin(); cit != m_mapHybridCryptKey.end(); ++cit ) { DWORD extNamehash = cit->first; const TCSHybridCryptKey& CryptKey = cit->second; rFile.Write( &extNamehash, sizeof(DWORD) ); rFile.Write( CryptKey.uEncryptKey.key, sizeof(TEncryptKey) ); rFile.Write( CryptKey.uEncryptIV.iv, sizeof(TEncryptIV) ); } } int EterPackPolicy_CSHybridCrypt::ReadCryptKeyInfoFromStream( IN const BYTE* pStream ) { int iStreamOffset = 0; DWORD dwCryptoInfoSize; memcpy(&dwCryptoInfoSize, pStream, sizeof(DWORD) ); iStreamOffset += sizeof(DWORD); DWORD dwExtHash; m_mapHybridCryptKey.clear(); for( int i = 0; i < dwCryptoInfoSize; ++i ) { memcpy(&dwExtHash, pStream + iStreamOffset, sizeof(DWORD) ); iStreamOffset += sizeof(DWORD); TCSHybridCryptKey info; { memcpy(info.uEncryptKey.key, pStream + iStreamOffset, sizeof(TEncryptKey) ); iStreamOffset += sizeof(TEncryptKey); memcpy(info.uEncryptIV.iv, pStream + iStreamOffset, sizeof(TEncryptIV) ); iStreamOffset += sizeof(TEncryptIV); } m_mapHybridCryptKey[dwExtHash] = info; } return iStreamOffset; } bool EterPackPolicy_CSHybridCrypt::GenerateSupplementaryDataBlock(std::string& rfilename, const std::string& strMapName, IN const BYTE* pSrcData, IN int iSrcLen, OUT LPBYTE& pDestData, OUT int& iDestLen ) { #ifdef __THEMIDA__ VM_START #endif std::string fileNamelower = rfilename; stl_lowers( fileNamelower ); DWORD dwFileNameHash = stringhash().GetHash(fileNamelower); TSupplementaryDataBlockMap::const_iterator cit = m_mapSDBMap.find( dwFileNameHash ); if( cit != m_mapSDBMap.end() ) { //TODO : log already registered return false; } //TODO : Find Better Method for deciding SDB Postion & Size //prevent stream copy duplication TSupplementaryDataBlockInfo info; m_mapSDBMap[dwFileNameHash] = info; std::string& strRelatedMapName = m_mapSDBMap[dwFileNameHash].strRelatedMapName; std::vector& sdbVector = m_mapSDBMap[dwFileNameHash].vecStream; //fill the data!! { strRelatedMapName = strMapName; int iSDBSize = random_range( 64, 128 ); if( iSrcLen < iSDBSize ) { iSDBSize = iSrcLen - 1; if( iSDBSize <= 0 ) { //TODO : is there 1byte file exist??? return false; } } sdbVector.resize( iSDBSize ); iDestLen = iSrcLen - iSDBSize; pDestData = (LPBYTE)pSrcData; memcpy( &sdbVector[0], pDestData + iDestLen, iSDBSize ); } #ifdef __THEMIDA__ VM_END #endif return true; } bool EterPackPolicy_CSHybridCrypt::GetSupplementaryDataBlock( std::string& rfilename, OUT LPBYTE& pSDB, OUT int& iSDBSize ) { #ifdef __THEMIDA__ VM_START #endif std::string fileNamelower = rfilename; stl_lowers( fileNamelower ); DWORD dwFileNameHash = stringhash().GetHash(fileNamelower); TSupplementaryDataBlockMap::const_iterator cit = m_mapSDBMap.find( dwFileNameHash ); if( cit == m_mapSDBMap.end() ) { //TODO : log already registered return false; } const std::vector& vecSDB = cit->second.vecStream; iSDBSize = vecSDB.size(); if(iSDBSize <= 0) { pSDB = NULL; return false; } pSDB = (BYTE*)&vecSDB[0]; #ifdef __THEMIDA__ VM_END #endif return true; } bool EterPackPolicy_CSHybridCrypt::IsContainingSDBFile() const { return m_mapSDBMap.size() > 0 ? true : false; } void EterPackPolicy_CSHybridCrypt::WriteSupplementaryDataBlockToFile( CFileBase& rFile ) { //about SDB data // sdb file cnt( 4byte ) // for sdb file cnt // filename hash ( stl.h stringhash ) // related map name size(4), relate map name // sdb block size( 1byte ) // sdb blocks DWORD dwSDBMapSize = m_mapSDBMap.size(); rFile.Write( &dwSDBMapSize, sizeof(DWORD) ); TSupplementaryDataBlockMap::const_iterator cit; for( cit = m_mapSDBMap.begin(); cit != m_mapSDBMap.end(); ++cit ) { DWORD dwFileNamehash = cit->first; rFile.Write( &dwFileNamehash, sizeof(DWORD) ); const std::string strRelatedMapName = cit->second.strRelatedMapName; DWORD dwMapNameSize = strRelatedMapName.size(); rFile.Write( &dwMapNameSize, sizeof(DWORD) ); rFile.Write( strRelatedMapName.c_str(), dwMapNameSize ); const std::vector& sdbVector = cit->second.vecStream; BYTE bSDBSize = (BYTE)(sdbVector.size()); rFile.Write( &bSDBSize, sizeof(bSDBSize) ); if( bSDBSize > 0 ) rFile.Write( &sdbVector[0], bSDBSize ); } } int EterPackPolicy_CSHybridCrypt::ReadSupplementatyDataBlockFromStream( IN const BYTE* pStream ) { #ifdef __THEMIDA__ VM_START #endif //DWORD dwFileIdentifier; //std::vector vecSDBStream; DWORD dwFileNameHash; BYTE bSDBSize; int iStreamOffset = 0; memcpy(&dwFileNameHash, pStream + iStreamOffset, sizeof(DWORD) ); iStreamOffset += sizeof(DWORD); memcpy(&bSDBSize, pStream + iStreamOffset, sizeof(BYTE) ); iStreamOffset += sizeof(BYTE); // NOTE : related map name isn`t required in client. so we don`t recv it from stream to reduce packet size. TSupplementaryDataBlockInfo info; { info.vecStream.resize( bSDBSize ); memcpy(&info.vecStream[0], pStream + iStreamOffset, bSDBSize ); iStreamOffset += bSDBSize; m_mapSDBMap[dwFileNameHash] = info; } #ifdef __THEMIDA__ VM_END #endif return iStreamOffset; }