/* Derived from source code of TrueCrypt 7.1a, which is Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed by the TrueCrypt License 3.0. Modifications and additions to the original source code (contained in this file) and all other portions of this file are Copyright (c) 2013-2017 IDRIX and are governed by the Apache License 2.0 the full text of which is contained in the file License.txt included in VeraCrypt binary and source code distribution packages.*/#include"Platform/Platform.h"#include"Cipher.h"#include"Crypto/Aes.h"#include"Crypto/SerpentFast.h"#include"Crypto/Twofish.h"#include"Crypto/Camellia.h"#include"Crypto/GostCipher.h"#include"Crypto/kuznyechik.h"#ifdef TC_AES_HW_CPU# include "Crypto/Aes_hw_cpu.h"#endif#include"Crypto/cpu.h"extern"C"intIsAesHwCpuSupported(){#ifdef TC_AES_HW_CPUstaticboolstate=false;staticboolstateValid=false;if(!stateValid){state=g_hasAESNI?true:false;stateValid=true;}returnstate&&VeraCrypt::Cipher::IsHwSupportEnabled();#elsereturnfalse;#endif}namespaceVeraCrypt{Cipher::Cipher():Initialized(false){}Cipher::~Cipher(){}voidCipher::DecryptBlock(byte*data)const{if(!Initialized)throwNotInitialized(SRC_POS);Decrypt(data);}voidCipher::DecryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);while(blockCount-->0){Decrypt(data);data+=GetBlockSize();}}voidCipher::EncryptBlock(byte*data)const{if(!Initialized)throwNotInitialized(SRC_POS);Encrypt(data);}voidCipher::EncryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);while(blockCount-->0){Encrypt(data);data+=GetBlockSize();}}CipherListCipher::GetAvailableCiphers(){CipherListl;l.push_back(shared_ptr<Cipher>(newCipherAES()));l.push_back(shared_ptr<Cipher>(newCipherSerpent()));l.push_back(shared_ptr<Cipher>(newCipherTwofish()));l.push_back(shared_ptr<Cipher>(newCipherCamellia()));l.push_back(shared_ptr<Cipher>(newCipherGost89()));l.push_back(shared_ptr<Cipher>(newCipherKuznyechik()));returnl;}voidCipher::SetKey(constConstBufferPtr&key){if(key.Size()!=GetKeySize())throwParameterIncorrect(SRC_POS);if(!Initialized)ScheduledKey.Allocate(GetScheduledKeySize());SetCipherKey(key);Key.CopyFrom(key);Initialized=true;}#define TC_EXCEPTION(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE)#undef TC_EXCEPTION_NODECL#define TC_EXCEPTION_NODECL(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE)TC_SERIALIZER_FACTORY_ADD_EXCEPTION_SET(CipherException);// AESvoidCipherAES::Decrypt(byte*data)const{#ifdef TC_AES_HW_CPUif(IsHwSupportAvailable())aes_hw_cpu_decrypt(ScheduledKey.Ptr()+sizeof(aes_encrypt_ctx),data);else#endifaes_decrypt(data,data,(aes_decrypt_ctx*)(ScheduledKey.Ptr()+sizeof(aes_encrypt_ctx)));}voidCipherAES::DecryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);#ifdef TC_AES_HW_CPUif((blockCount&(32-1))==0&&IsHwSupportAvailable()){while(blockCount>0){aes_hw_cpu_decrypt_32_blocks(ScheduledKey.Ptr()+sizeof(aes_encrypt_ctx),data);data+=32*GetBlockSize();blockCount-=32;}}else#endifCipher::DecryptBlocks(data,blockCount);}voidCipherAES::Encrypt(byte*data)const{#ifdef TC_AES_HW_CPUif(IsHwSupportAvailable())aes_hw_cpu_encrypt(ScheduledKey.Ptr(),data);else#endifaes_encrypt(data,data,(aes_encrypt_ctx*)ScheduledKey.Ptr());}voidCipherAES::EncryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);#ifdef TC_AES_HW_CPUif((blockCount&(32-1))==0&&IsHwSupportAvailable()){while(blockCount>0){aes_hw_cpu_encrypt_32_blocks(ScheduledKey.Ptr(),data);data+=32*GetBlockSize();blockCount-=32;}}else#endifCipher::EncryptBlocks(data,blockCount);}size_tCipherAES::GetScheduledKeySize()const{returnsizeof(aes_encrypt_ctx)+sizeof(aes_decrypt_ctx);}boolCipherAES::IsHwSupportAvailable()const{#ifdef TC_AES_HW_CPUstaticboolstate=false;staticboolstateValid=false;if(!stateValid){state=g_hasAESNI?true:false;stateValid=true;}returnstate&&HwSupportEnabled;#elsereturnfalse;#endif}voidCipherAES::SetCipherKey(constbyte*key){if(aes_encrypt_key256(key,(aes_encrypt_ctx*)ScheduledKey.Ptr())!=EXIT_SUCCESS)throwCipherInitError(SRC_POS);if(aes_decrypt_key256(key,(aes_decrypt_ctx*)(ScheduledKey.Ptr()+sizeof(aes_encrypt_ctx)))!=EXIT_SUCCESS)throwCipherInitError(SRC_POS);}// SerpentvoidCipherSerpent::Decrypt(byte*data)const{serpent_decrypt(data,data,ScheduledKey);}voidCipherSerpent::Encrypt(byte*data)const{serpent_encrypt(data,data,ScheduledKey);}size_tCipherSerpent::GetScheduledKeySize()const{return140*4;}voidCipherSerpent::SetCipherKey(constbyte*key){serpent_set_key(key,ScheduledKey);}voidCipherSerpent::EncryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLEif((blockCount>=4)&&IsHwSupportAvailable()){serpent_encrypt_blocks(data,data,blockCount,ScheduledKey.Ptr());}else#endifCipher::EncryptBlocks(data,blockCount);}voidCipherSerpent::DecryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLEif((blockCount>=4)&&IsHwSupportAvailable()){serpent_decrypt_blocks(data,data,blockCount,ScheduledKey.Ptr());}else#endifCipher::DecryptBlocks(data,blockCount);}boolCipherSerpent::IsHwSupportAvailable()const{#if CRYPTOPP_BOOL_SSE2_INTRINSICS_AVAILABLEstaticboolstate=false;staticboolstateValid=false;if(!stateValid){state=HasSSE2()?true:false;stateValid=true;}returnstate;#elsereturnfalse;#endif}// TwofishvoidCipherTwofish::Decrypt(byte*data)const{twofish_decrypt((TwofishInstance*)ScheduledKey.Ptr(),(unsignedint*)data,(unsignedint*)data);}voidCipherTwofish::Encrypt(byte*data)const{twofish_encrypt((TwofishInstance*)ScheduledKey.Ptr(),(unsignedint*)data,(unsignedint*)data);}size_tCipherTwofish::GetScheduledKeySize()const{returnTWOFISH_KS;}voidCipherTwofish::SetCipherKey(constbyte*key){twofish_set_key((TwofishInstance*)ScheduledKey.Ptr(),(unsignedint*)key);}voidCipherTwofish::EncryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);#if CRYPTOPP_BOOL_X64twofish_encrypt_blocks((TwofishInstance*)ScheduledKey.Ptr(),data,data,blockCount);#elseCipher::EncryptBlocks(data,blockCount);#endif}voidCipherTwofish::DecryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);#if CRYPTOPP_BOOL_X64twofish_decrypt_blocks((TwofishInstance*)ScheduledKey.Ptr(),data,data,blockCount);#elseCipher::DecryptBlocks(data,blockCount);#endif}boolCipherTwofish::IsHwSupportAvailable()const{#if CRYPTOPP_BOOL_X64returntrue;#elsereturnfalse;#endif}// CamelliavoidCipherCamellia::Decrypt(byte*data)const{camellia_decrypt(data,data,ScheduledKey.Ptr());}voidCipherCamellia::Encrypt(byte*data)const{camellia_encrypt(data,data,ScheduledKey.Ptr());}size_tCipherCamellia::GetScheduledKeySize()const{returnCAMELLIA_KS;}voidCipherCamellia::SetCipherKey(constbyte*key){camellia_set_key(key,ScheduledKey.Ptr());}voidCipherCamellia::EncryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);#if CRYPTOPP_BOOL_X64camellia_encrypt_blocks(ScheduledKey.Ptr(),data,data,blockCount);#elseCipher::EncryptBlocks(data,blockCount);#endif}voidCipherCamellia::DecryptBlocks(byte*data,size_tblockCount)const{if(!Initialized)throwNotInitialized(SRC_POS);#if CRYPTOPP_BOOL_X64camellia_decrypt_blocks(ScheduledKey.Ptr(),data,data,blockCount);#elseCipher::DecryptBlocks(data,blockCount);#endif}boolCipherCamellia::IsHwSupportAvailable()const{#if CRYPTOPP_BOOL_X64returntrue;#elsereturnfalse;#endif}// GOST89voidCipherGost89::Decrypt(byte*data)const{gost_decrypt(data,data,(gost_kds*)ScheduledKey.Ptr(),1);}voidCipherGost89::Encrypt(byte*data)const{gost_encrypt(data,data,(gost_kds*)ScheduledKey.Ptr(),1);}size_tCipherGost89::GetScheduledKeySize()const{returnGOST_KS;}voidCipherGost89::SetCipherKey(constbyte*key){gost_set_key(key,(gost_kds*)ScheduledKey.Ptr(),1);}// GOST89 with static SBOXvoidCipherGost89StaticSBOX::Decrypt(byte*data)const{gost_decrypt(data,data,(gost_kds*)ScheduledKey.Ptr(),1);}voidCipherGost89StaticSBOX::Encrypt(byte*data)const{gost_encrypt(data,data,(gost_kds*)ScheduledKey.Ptr(),1);}size_tCipherGost89StaticSBOX::GetScheduledKeySize()const{returnGOST_KS;}voidCipherGost89StaticSBOX::SetCipherKey(constbyte*key){gost_set_key(key,(gost_kds*)ScheduledKey.Ptr(),0);}// KuznyechikvoidCipherKuznyechik::Decrypt(byte*data)const{kuznyechik_decrypt_block(data,data,(kuznyechik_kds*)ScheduledKey.Ptr());}voidCipherKuznyechik::Encrypt(byte*data)const{kuznyechik_encrypt_block(data,data,(kuznyechik_kds*)ScheduledKey.Ptr());}size_tCipherKuznyechik::GetScheduledKeySize()const{returnKUZNYECHIK_KS;}voidCipherKuznyechik::SetCipherKey(constbyte*key){kuznyechik_set_key(key,(kuznyechik_kds*)ScheduledKey.Ptr());}boolCipher::HwSupportEnabled=true;}