504 lines
12 KiB
C++
504 lines
12 KiB
C++
#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 <cryptopp/modes.h>
|
|
#include <cryptopp/osrng.h>
|
|
|
|
using namespace CryptoPP;
|
|
|
|
#define CIPHER_MODE CTR_Mode
|
|
|
|
#ifdef __THEMIDA__
|
|
#include <ThemidaSDK.h>
|
|
#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<Camellia>::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<Twofish>::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<XTEA>::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<Camellia>::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<Twofish>::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<XTEA>::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<BYTE>& 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<BYTE>& 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<BYTE>& 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<BYTE> 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;
|
|
}
|