--- truecrypt/common/crypto.c 2018/04/24 16:44:45 1.1.1.9 +++ truecrypt/common/crypto.c 2018/04/24 17:11:32 1.1.1.22 @@ -1,21 +1,24 @@ -/* Legal Notice: The source code contained in this file has been derived from - the source code of Encryption for the Masses 2.02a, which is Copyright (c) - 1998-99 Paul Le Roux and which is covered by the 'License Agreement for - Encryption for the Masses'. Modifications and additions to that source code - contained in this file are Copyright (c) 2004-2006 TrueCrypt Foundation and - Copyright (c) 2004 TrueCrypt Team, and are covered by TrueCrypt License 2.0 - the full text of which is contained in the file License.txt included in - TrueCrypt binary and source code distribution archives. */ +/* + Legal Notice: Some portions of the source code contained in this file were + derived from the source code of Encryption for the Masses 2.02a, which is + Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License + Agreement for Encryption for the Masses'. Modifications and additions to + the original source code (contained in this file) and all other portions + of this file are Copyright (c) 2003-2010 TrueCrypt Developers Association + and are governed by the TrueCrypt License 3.0 the full text of which is + contained in the file License.txt included in TrueCrypt binary and source + code distribution packages. */ #include "Tcdefs.h" #include "Crypto.h" +#include "Xts.h" #include "Crc.h" -#include "Endian.h" - -#ifdef LINUX_DRIVER -#include -#include +#include "Common/Endian.h" +#include +#ifndef TC_WINDOWS_BOOT +#include "EncryptionThreadPool.h" #endif +#include "Volumes.h" /* Update the following when adding a new cipher or EA: @@ -32,131 +35,140 @@ */ +#ifndef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + // Cipher configuration static Cipher Ciphers[] = { // Block Size Key Size Key Schedule Size // ID Name (Bytes) (Bytes) (Bytes) - { AES, "AES", 16, 32, sizeof(aes_encrypt_ctx)+sizeof(aes_decrypt_ctx) }, - { BLOWFISH, "Blowfish", 8, 56, 4168 }, - { CAST, "CAST5", 8, 16, 128 }, - { DES56, "DES", 8, 7, 128 }, - { SERPENT, "Serpent", 16, 32, 140*4 }, - { TRIPLEDES,"Triple DES", 8, 8*3, 128*3 }, - { TWOFISH, "Twofish", 16, 32, TWOFISH_KS }, - { 0, 0, 0, 0, 0 } + { AES, "AES", 16, 32, AES_KS }, + { SERPENT, "Serpent", 16, 32, 140*4 }, + { TWOFISH, "Twofish", 16, 32, TWOFISH_KS }, +#ifndef TC_WINDOWS_BOOT + { BLOWFISH, "Blowfish", 8, 56, sizeof (BF_KEY) }, // Deprecated/legacy + { CAST, "CAST5", 8, 16, sizeof (CAST_KEY) }, // Deprecated/legacy + { TRIPLEDES,"Triple DES", 8, 8*3, sizeof (TDES_KEY) }, // Deprecated/legacy +#endif + { 0, 0, 0, 0, 0 } }; + // Encryption algorithm configuration -// The following modes have been deprecated (legacy): CBC, INNER_CBC, OUTER_CBC +// The following modes have been deprecated (legacy): LRW, CBC, INNER_CBC, OUTER_CBC static EncryptionAlgorithm EncryptionAlgorithms[] = { - // Cipher(s) Modes - { { 0, 0 } , { 0, 0, 0 } }, // Must be all-zero - { { AES, 0 } , { LRW, CBC, 0 } }, - { { BLOWFISH, 0 } , { LRW, CBC, 0 } }, - { { CAST, 0 } , { LRW, CBC, 0 } }, - { { SERPENT, 0 } , { LRW, CBC, 0 } }, - { { TRIPLEDES, 0 } , { LRW, CBC, 0 } }, - { { TWOFISH, 0 } , { LRW, CBC, 0 } }, - { { TWOFISH, AES, 0 } , { LRW, OUTER_CBC, 0 } }, - { { SERPENT, TWOFISH, AES, 0 } , { LRW, OUTER_CBC, 0 } }, - { { AES, SERPENT, 0 } , { LRW, OUTER_CBC, 0 } }, - { { AES, TWOFISH, SERPENT, 0 } , { LRW, OUTER_CBC, 0 } }, - { { SERPENT, TWOFISH, 0 } , { LRW, OUTER_CBC, 0 } }, - { { BLOWFISH, AES, 0 } , { INNER_CBC, 0, 0 } }, - { { SERPENT, BLOWFISH, AES, 0 } , { INNER_CBC, 0, 0 } }, - { { 0, 0 } , { 0, 0, 0 } } // Must be all-zero + // Cipher(s) Modes FormatEnabled + +#ifndef TC_WINDOWS_BOOT + + { { 0, 0 }, { 0, 0, 0, 0 }, 0 }, // Must be all-zero + { { AES, 0 }, { XTS, LRW, CBC, 0 }, 1 }, + { { SERPENT, 0 }, { XTS, LRW, CBC, 0 }, 1 }, + { { TWOFISH, 0 }, { XTS, LRW, CBC, 0 }, 1 }, + { { TWOFISH, AES, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 }, + { { SERPENT, TWOFISH, AES, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 }, + { { AES, SERPENT, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 }, + { { AES, TWOFISH, SERPENT, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 }, + { { SERPENT, TWOFISH, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 }, + { { BLOWFISH, 0 }, { LRW, CBC, 0, 0 }, 0 }, // Deprecated/legacy + { { CAST, 0 }, { LRW, CBC, 0, 0 }, 0 }, // Deprecated/legacy + { { TRIPLEDES, 0 }, { LRW, CBC, 0, 0 }, 0 }, // Deprecated/legacy + { { BLOWFISH, AES, 0 }, { INNER_CBC, 0, 0, 0 }, 0 }, // Deprecated/legacy + { { SERPENT, BLOWFISH, AES, 0 }, { INNER_CBC, 0, 0, 0 }, 0 }, // Deprecated/legacy + { { 0, 0 }, { 0, 0, 0, 0 }, 0 } // Must be all-zero + +#else // TC_WINDOWS_BOOT + + // Encryption algorithms available for boot drive encryption + { { 0, 0 }, { 0, 0 }, 0 }, // Must be all-zero + { { AES, 0 }, { XTS, 0 }, 1 }, + { { SERPENT, 0 }, { XTS, 0 }, 1 }, + { { TWOFISH, 0 }, { XTS, 0 }, 1 }, + { { TWOFISH, AES, 0 }, { XTS, 0 }, 1 }, + { { SERPENT, TWOFISH, AES, 0 }, { XTS, 0 }, 1 }, + { { AES, SERPENT, 0 }, { XTS, 0 }, 1 }, + { { AES, TWOFISH, SERPENT, 0 }, { XTS, 0 }, 1 }, + { { SERPENT, TWOFISH, 0 }, { XTS, 0 }, 1 }, + { { 0, 0 }, { 0, 0 }, 0 }, // Must be all-zero + +#endif + }; + + // Hash algorithms static Hash Hashes[] = -{ - { RIPEMD160, "RIPEMD-160" }, - { SHA1, "SHA-1" }, - { WHIRLPOOL, "Whirlpool" }, - { 0, 0 } +{ // ID Name Deprecated System Encryption + { RIPEMD160, "RIPEMD-160", FALSE, TRUE }, +#ifndef TC_WINDOWS_BOOT + { SHA512, "SHA-512", FALSE, FALSE }, + { WHIRLPOOL, "Whirlpool", FALSE, FALSE }, + { SHA1, "SHA-1", TRUE, FALSE }, // Deprecated/legacy +#endif + { 0, 0, 0 } }; /* Return values: 0 = success, ERR_CIPHER_INIT_FAILURE (fatal), ERR_CIPHER_INIT_WEAK_KEY (non-fatal) */ int CipherInit (int cipher, unsigned char *key, unsigned __int8 *ks) { - int retVal = 0; + int retVal = ERR_SUCCESS; switch (cipher) { - case BLOWFISH: - BF_set_key ((BF_KEY *)ks, CipherGetKeySize(BLOWFISH), key); - break; - case AES: - if (aes_encrypt_key(key, CipherGetKeySize(AES), (aes_encrypt_ctx *) ks) != EXIT_SUCCESS) +#ifndef TC_WINDOWS_BOOT + if (aes_encrypt_key256 (key, (aes_encrypt_ctx *) ks) != EXIT_SUCCESS) return ERR_CIPHER_INIT_FAILURE; - if (aes_decrypt_key(key, CipherGetKeySize(AES), (aes_decrypt_ctx *) (ks + sizeof(aes_encrypt_ctx))) != EXIT_SUCCESS) + if (aes_decrypt_key256 (key, (aes_decrypt_ctx *) (ks + sizeof(aes_encrypt_ctx))) != EXIT_SUCCESS) return ERR_CIPHER_INIT_FAILURE; - +#else + if (aes_set_key (key, (length_type) CipherGetKeySize(AES), (aes_context *) ks) != 0) + return ERR_CIPHER_INIT_FAILURE; +#endif break; - case DES56: - /* Included for testing purposes only */ - switch (des_key_sched ((des_cblock *) key, (struct des_ks_struct *) ks)) - { - case -1: - return ERR_CIPHER_INIT_FAILURE; - case -2: - retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error - break; - } + case SERPENT: + serpent_set_key (key, CipherGetKeySize(SERPENT) * 8, ks); + break; + + case TWOFISH: + twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key, CipherGetKeySize(TWOFISH) * 8); break; - case CAST: - CAST_set_key((CAST_KEY *) ks, CipherGetKeySize(CAST), key); +#ifndef TC_WINDOWS_BOOT + + case BLOWFISH: + /* Deprecated/legacy */ + BlowfishSetKey ((BF_KEY *)ks, CipherGetKeySize(BLOWFISH), key); break; - case SERPENT: - serpent_set_key (key, CipherGetKeySize(SERPENT) * 8, ks); + case CAST: + /* Deprecated/legacy */ + Cast5SetKey ((CAST_KEY *) ks, CipherGetKeySize(CAST), key); break; case TRIPLEDES: - switch (des_key_sched ((des_cblock *) key, (struct des_ks_struct *) ks)) - { - case -1: - return ERR_CIPHER_INIT_FAILURE; - case -2: - retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error - break; - } - switch (des_key_sched ((des_cblock *) ((char*)(key)+8), (struct des_ks_struct *) (ks + CipherGetKeyScheduleSize (DES56)))) - { - case -1: - return ERR_CIPHER_INIT_FAILURE; - case -2: - retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error - break; - } - switch (des_key_sched ((des_cblock *) ((char*)(key)+16), (struct des_ks_struct *) (ks + CipherGetKeyScheduleSize (DES56) * 2))) - { - case -1: - return ERR_CIPHER_INIT_FAILURE; - case -2: - retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error - break; - } + /* Deprecated/legacy */ + TripleDesSetKey (key, CipherGetKeySize (TRIPLEDES), (TDES_KEY *) ks); // Verify whether all three DES keys are mutually different - if (((*((__int64 *) key) ^ *((__int64 *) key+1)) & 0xFEFEFEFEFEFEFEFE) == 0 - || ((*((__int64 *) key+1) ^ *((__int64 *) key+2)) & 0xFEFEFEFEFEFEFEFE) == 0 - || ((*((__int64 *) key) ^ *((__int64 *) key+2)) & 0xFEFEFEFEFEFEFEFE) == 0) + if (((*((__int64 *) key) ^ *((__int64 *) key+1)) & 0xFEFEFEFEFEFEFEFEULL) == 0 + || ((*((__int64 *) key+1) ^ *((__int64 *) key+2)) & 0xFEFEFEFEFEFEFEFEULL) == 0 + || ((*((__int64 *) key) ^ *((__int64 *) key+2)) & 0xFEFEFEFEFEFEFEFEULL) == 0) retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error break; - case TWOFISH: - twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key, CipherGetKeySize(TWOFISH) * 8); - break; +#endif // TC_WINDOWS_BOOT + default: + // Unknown/wrong cipher ID + return ERR_CIPHER_INIT_FAILURE; } + return retVal; } @@ -164,33 +176,139 @@ void EncipherBlock(int cipher, void *dat { switch (cipher) { - case BLOWFISH: BF_ecb_le_encrypt (data, data, ks, 1); break; - case AES: aes_encrypt (data, data, ks); break; - case DES56: des_encrypt (data, ks, 1); break; - case CAST: CAST_ecb_encrypt (data, data, ks, 1); break; - case SERPENT: serpent_encrypt (data, data, ks); break; - case TRIPLEDES: des_ecb3_encrypt (data, data, ks, - (void*)((char*) ks + CipherGetKeyScheduleSize (DES56)), (void*)((char*) ks + CipherGetKeyScheduleSize (DES56) * 2), 1); break; + case AES: + // In 32-bit kernel mode, due to KeSaveFloatingPointState() overhead, AES instructions can be used only when processing the whole data unit. +#if (defined (_WIN64) || !defined (TC_WINDOWS_DRIVER)) && !defined (TC_WINDOWS_BOOT) + if (IsAesHwCpuSupported()) + aes_hw_cpu_encrypt (ks, data); + else +#endif + aes_encrypt (data, data, ks); + break; + case TWOFISH: twofish_encrypt (ks, data, data); break; + case SERPENT: serpent_encrypt (data, data, ks); break; +#ifndef TC_WINDOWS_BOOT + case BLOWFISH: BlowfishEncryptLE (data, data, ks, 1); break; // Deprecated/legacy + case CAST: Cast5Encrypt (data, data, ks); break; // Deprecated/legacy + case TRIPLEDES: TripleDesEncrypt (data, data, ks, 1); break; // Deprecated/legacy +#endif + default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID } } +#ifndef TC_WINDOWS_BOOT + +void EncipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount) +{ + byte *data = dataPtr; +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + KFLOATING_SAVE floatingPointState; +#endif + + if (cipher == AES + && (blockCount & (32 - 1)) == 0 + && IsAesHwCpuSupported() +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + && NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState)) +#endif + ) + { + while (blockCount > 0) + { + aes_hw_cpu_encrypt_32_blocks (ks, data); + + data += 32 * 16; + blockCount -= 32; + } + +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + KeRestoreFloatingPointState (&floatingPointState); +#endif + } + else + { + size_t blockSize = CipherGetBlockSize (cipher); + while (blockCount-- > 0) + { + EncipherBlock (cipher, data, ks); + data += blockSize; + } + } +} + +#endif // !TC_WINDOWS_BOOT + void DecipherBlock(int cipher, void *data, void *ks) { switch (cipher) { - case BLOWFISH: BF_ecb_le_encrypt (data, data, ks, 0); break; - case AES: aes_decrypt (data, data, (void *) ((char *) ks + sizeof(aes_encrypt_ctx))); break; - case DES56: des_encrypt (data, ks, 0); break; - case CAST: CAST_ecb_encrypt (data, data, ks,0); break; case SERPENT: serpent_decrypt (data, data, ks); break; - case TRIPLEDES: des_ecb3_encrypt (data, data, ks, - (void*)((char*) ks + CipherGetKeyScheduleSize (DES56)), - (void*)((char*) ks + CipherGetKeyScheduleSize (DES56) * 2), 0); break; case TWOFISH: twofish_decrypt (ks, data, data); break; +#ifndef TC_WINDOWS_BOOT + + case AES: +#if defined (_WIN64) || !defined (TC_WINDOWS_DRIVER) + if (IsAesHwCpuSupported()) + aes_hw_cpu_decrypt ((byte *) ks + sizeof (aes_encrypt_ctx), data); + else +#endif + aes_decrypt (data, data, (void *) ((char *) ks + sizeof(aes_encrypt_ctx))); + break; + + case BLOWFISH: BlowfishEncryptLE (data, data, ks, 0); break; // Deprecated/legacy + case CAST: Cast5Decrypt (data, data, ks); break; // Deprecated/legacy + case TRIPLEDES: TripleDesEncrypt (data, data, ks, 0); break; // Deprecated/legacy +#else + case AES: aes_decrypt (data, data, ks); break; +#endif + default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID + } +} + +#ifndef TC_WINDOWS_BOOT + +void DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount) +{ + byte *data = dataPtr; +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + KFLOATING_SAVE floatingPointState; +#endif + + if (cipher == AES + && (blockCount & (32 - 1)) == 0 + && IsAesHwCpuSupported() +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + && NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState)) +#endif + ) + { + while (blockCount > 0) + { + aes_hw_cpu_decrypt_32_blocks ((byte *) ks + sizeof (aes_encrypt_ctx), data); + + data += 32 * 16; + blockCount -= 32; + } + +#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64) + KeRestoreFloatingPointState (&floatingPointState); +#endif + } + else + { + size_t blockSize = CipherGetBlockSize (cipher); + while (blockCount-- > 0) + { + DecipherBlock (cipher, data, ks); + data += blockSize; + } } } +#endif // !TC_WINDOWS_BOOT + + // Ciphers support Cipher *CipherGet (int id) @@ -200,7 +318,7 @@ Cipher *CipherGet (int id) if (Ciphers[i].Id == id) return &Ciphers[i]; - return 0; + return NULL; } char *CipherGetName (int cipherId) @@ -223,6 +341,15 @@ int CipherGetKeyScheduleSize (int cipher return CipherGet (cipherId) -> KeyScheduleSize; } +#ifndef TC_WINDOWS_BOOT + +BOOL CipherSupportsIntraDataUnitParallelization (int cipher) +{ + return cipher == AES && IsAesHwCpuSupported(); +} + +#endif + // Encryption algorithms support @@ -254,7 +381,10 @@ int EAGetNext (int previousEA) // Return values: 0 = success, ERR_CIPHER_INIT_FAILURE (fatal), ERR_CIPHER_INIT_WEAK_KEY (non-fatal) int EAInit (int ea, unsigned char *key, unsigned __int8 *ks) { - int c, retVal = 0; + int c, retVal = ERR_SUCCESS; + + if (ea == 0) + return ERR_CIPHER_INIT_FAILURE; for (c = EAGetFirstCipher (ea); c != 0; c = EAGetNextCipher (ea, c)) { @@ -275,24 +405,50 @@ int EAInit (int ea, unsigned char *key, } -int EAInitMode (PCRYPTO_INFO ci) +#ifndef TC_WINDOWS_BOOT + +BOOL EAInitMode (PCRYPTO_INFO ci) { switch (ci->mode) { + case XTS: + // Secondary key schedule + if (EAInit (ci->ea, ci->k2, ci->ks2) != ERR_SUCCESS) + return FALSE; + + /* Note: XTS mode could potentially be initialized with a weak key causing all blocks in one data unit + on the volume to be tweaked with zero tweaks (i.e. 512 bytes of the volume would be encrypted in ECB + mode). However, to create a TrueCrypt volume with such a weak key, each human being on Earth would have + to create approximately 11,378,125,361,078,862 (about eleven quadrillion) TrueCrypt volumes (provided + that the size of each of the volumes is 1024 terabytes). */ + break; + case LRW: switch (CipherGetBlockSize (EAGetFirstCipher (ci->ea))) { case 8: - return Gf64TabInit (ci->iv, &ci->gf_ctx); + /* Deprecated/legacy */ + return Gf64TabInit (ci->k2, &ci->gf_ctx); case 16: - return Gf128Tab64Init (ci->iv, &ci->gf_ctx); + return Gf128Tab64Init (ci->k2, &ci->gf_ctx); default: - return FALSE; + TC_THROW_FATAL_EXCEPTION; } - } + break; + + case CBC: + case INNER_CBC: + case OUTER_CBC: + // The mode does not need to be initialized or is initialized elsewhere + return TRUE; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } return TRUE; } @@ -301,7 +457,7 @@ int EAInitMode (PCRYPTO_INFO ci) char *EAGetName (char *buf, int ea) { int i = EAGetLastCipher(ea); - strcpy (buf, CipherGetName (i)); + strcpy (buf, (i != 0) ? CipherGetName (i) : "?"); while (i = EAGetPreviousCipher(ea, i)) { @@ -329,8 +485,9 @@ int EAGetByName (char *name) return 0; } +#endif // TC_WINDOWS_BOOT -// Returns sum of key sizes of all EA ciphers +// Returns sum of key sizes of all ciphers of the EA (in bytes) int EAGetKeySize (int ea) { int i = EAGetFirstCipher (ea); @@ -365,12 +522,21 @@ int EAGetNextMode (int ea, int previousM } +#ifndef TC_WINDOWS_BOOT + // Returns the name of the mode of operation of the whole EA char *EAGetModeName (int ea, int mode, BOOL capitalLetters) { switch (mode) { + case XTS: + + return "XTS"; + case LRW: + + /* Deprecated/legacy */ + return "LRW"; case CBC: @@ -402,8 +568,10 @@ char *EAGetModeName (int ea, int mode, B return "[unknown]"; } +#endif // TC_WINDOWS_BOOT + -// Returns sum of key schedule sizes of all EA ciphers +// Returns sum of key schedule sizes of all ciphers of the EA int EAGetKeyScheduleSize (int ea) { int i = EAGetFirstCipher(ea); @@ -418,12 +586,29 @@ int EAGetKeyScheduleSize (int ea) } -// Returns largest key needed by all EAs +// Returns the largest key size needed by an EA for the specified mode of operation +int EAGetLargestKeyForMode (int mode) +{ + int ea, key = 0; + + for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea)) + { + if (!EAIsModeSupported (ea, mode)) + continue; + + if (EAGetKeySize (ea) >= key) + key = EAGetKeySize (ea); + } + return key; +} + + +// Returns the largest key needed by any EA for any mode int EAGetLargestKey () { int ea, key = 0; - for (ea = EAGetFirst (); ea != 0 ; ea = EAGetNext (ea)) + for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea)) { if (EAGetKeySize (ea) >= key) key = EAGetKeySize (ea); @@ -488,6 +673,26 @@ int EAGetPreviousCipher (int ea, int pre } +int EAIsFormatEnabled (int ea) +{ + return EncryptionAlgorithms[ea].FormatEnabled; +} + + +// Returns TRUE if the mode of operation is supported for the encryption algorithm +BOOL EAIsModeSupported (int ea, int testedMode) +{ + int mode; + + for (mode = EAGetFirstMode (ea); mode != 0; mode = EAGetNextMode (ea, mode)) + { + if (mode == testedMode) + return TRUE; + } + return FALSE; +} + + Hash *HashGet (int id) { int i; @@ -516,96 +721,288 @@ char *HashGetName (int hashId) } -PCRYPTO_INFO -crypto_open () +BOOL HashIsDeprecated (int hashId) +{ + return HashGet (hashId) -> Deprecated; +} + + +#endif // TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + + +#ifdef TC_WINDOWS_BOOT + +static byte CryptoInfoBufferInUse = 0; +CRYPTO_INFO CryptoInfoBuffer; + +#endif + +PCRYPTO_INFO crypto_open () { +#ifndef TC_WINDOWS_BOOT + /* Do the crt allocation */ PCRYPTO_INFO cryptoInfo = (PCRYPTO_INFO) TCalloc (sizeof (CRYPTO_INFO)); + if (cryptoInfo == NULL) + return NULL; + memset (cryptoInfo, 0, sizeof (CRYPTO_INFO)); #ifndef DEVICE_DRIVER -#ifdef _WIN32 VirtualLock (cryptoInfo, sizeof (CRYPTO_INFO)); #endif -#endif - - if (cryptoInfo == NULL) - return NULL; cryptoInfo->ea = -1; return cryptoInfo; + +#else // TC_WINDOWS_BOOT + +#if 0 + if (CryptoInfoBufferInUse) + TC_THROW_FATAL_EXCEPTION; +#endif + CryptoInfoBufferInUse = 1; + return &CryptoInfoBuffer; + +#endif // TC_WINDOWS_BOOT } -void -crypto_loadkey (PKEY_INFO keyInfo, char *lpszUserKey, int nUserKeyLen) +void crypto_loadkey (PKEY_INFO keyInfo, char *lpszUserKey, int nUserKeyLen) { keyInfo->keyLength = nUserKeyLen; burn (keyInfo->userKey, sizeof (keyInfo->userKey)); memcpy (keyInfo->userKey, lpszUserKey, nUserKeyLen); } -void -crypto_close (PCRYPTO_INFO cryptoInfo) +void crypto_close (PCRYPTO_INFO cryptoInfo) { +#ifndef TC_WINDOWS_BOOT + if (cryptoInfo != NULL) { burn (cryptoInfo, sizeof (CRYPTO_INFO)); #ifndef DEVICE_DRIVER -#ifdef _WIN32 VirtualUnlock (cryptoInfo, sizeof (CRYPTO_INFO)); #endif -#endif TCfree (cryptoInfo); } + +#else // TC_WINDOWS_BOOT + + burn (&CryptoInfoBuffer, sizeof (CryptoInfoBuffer)); + CryptoInfoBufferInUse = FALSE; + +#endif // TC_WINDOWS_BOOT +} + + +#ifndef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + + +#ifndef TC_NO_COMPILER_INT64 +void Xor128 (unsigned __int64 *a, unsigned __int64 *b) +{ + *a++ ^= *b++; + *a ^= *b; +} + + +void Xor64 (unsigned __int64 *a, unsigned __int64 *b) +{ + *a ^= *b; } -// Detect weak and potentially weak secondary LRW keys. -// Remark: These tests reduce the key search space by approximately 0.001% -BOOL DetectWeakSecondaryKey (unsigned char *key, int len) +void EncryptBufferLRW128 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo) { -#define LRW_MAX_SUCCESSIVE_IDENTICAL_BITS 24 -#define LRW_MIN_HAMMING_WEIGHT_16 39 -#define LRW_MIN_HAMMING_WEIGHT_8 15 + /* Deprecated/legacy */ - int minWeight = (len == 16 ? LRW_MIN_HAMMING_WEIGHT_16 : LRW_MIN_HAMMING_WEIGHT_8); - int i, b, zero = 0, one = 0, zeroTotal = 0, oneTotal = 0; + int cipher = EAGetFirstCipher (cryptoInfo->ea); + int cipherCount = EAGetCipherCount (cryptoInfo->ea); + unsigned __int8 *p = buffer; + unsigned __int8 *ks = cryptoInfo->ks; + unsigned __int8 i[8]; + unsigned __int8 t[16]; + unsigned __int64 b; - for (i = 0; i < len; i++) + *(unsigned __int64 *)i = BE64(blockIndex); + + if (length % 16) + TC_THROW_FATAL_EXCEPTION; + + // Note that the maximum supported volume size is 8589934592 GB (i.e., 2^63 bytes). + + for (b = 0; b < length >> 4; b++) { - for (b = 7; b >= 0; b--) + Gf128MulBy64Tab (i, t, &cryptoInfo->gf_ctx); + Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); + + if (cipherCount > 1) { - if ((key[i] & (1 << b)) == 0) + // Cipher cascade + for (cipher = EAGetFirstCipher (cryptoInfo->ea); + cipher != 0; + cipher = EAGetNextCipher (cryptoInfo->ea, cipher)) { - zeroTotal++; - zero++; - one = 0; + EncipherBlock (cipher, p, ks); + ks += CipherGetKeyScheduleSize (cipher); } - else + ks = cryptoInfo->ks; + } + else + { + EncipherBlock (cipher, p, ks); + } + + Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); + + p += 16; + + if (i[7] != 0xff) + i[7]++; + else + *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); + } + + FAST_ERASE64 (t, sizeof(t)); +} + + +void EncryptBufferLRW64 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo) +{ + /* Deprecated/legacy */ + + int cipher = EAGetFirstCipher (cryptoInfo->ea); + unsigned __int8 *p = buffer; + unsigned __int8 *ks = cryptoInfo->ks; + unsigned __int8 i[8]; + unsigned __int8 t[8]; + unsigned __int64 b; + + *(unsigned __int64 *)i = BE64(blockIndex); + + if (length % 8) + TC_THROW_FATAL_EXCEPTION; + + for (b = 0; b < length >> 3; b++) + { + Gf64MulTab (i, t, &cryptoInfo->gf_ctx); + Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); + + EncipherBlock (cipher, p, ks); + + Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); + + p += 8; + + if (i[7] != 0xff) + i[7]++; + else + *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); + } + + FAST_ERASE64 (t, sizeof(t)); +} + + +void DecryptBufferLRW128 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo) +{ + /* Deprecated/legacy */ + + int cipher = EAGetFirstCipher (cryptoInfo->ea); + int cipherCount = EAGetCipherCount (cryptoInfo->ea); + unsigned __int8 *p = buffer; + unsigned __int8 *ks = cryptoInfo->ks; + unsigned __int8 i[8]; + unsigned __int8 t[16]; + unsigned __int64 b; + + *(unsigned __int64 *)i = BE64(blockIndex); + + if (length % 16) + TC_THROW_FATAL_EXCEPTION; + + // Note that the maximum supported volume size is 8589934592 GB (i.e., 2^63 bytes). + + for (b = 0; b < length >> 4; b++) + { + Gf128MulBy64Tab (i, t, &cryptoInfo->gf_ctx); + Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); + + if (cipherCount > 1) + { + // Cipher cascade + ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); + + for (cipher = EAGetLastCipher (cryptoInfo->ea); + cipher != 0; + cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher)) { - oneTotal++; - one++; - zero = 0; + ks -= CipherGetKeyScheduleSize (cipher); + DecipherBlock (cipher, p, ks); } - - // Maximum number of consecutive identical bit values - if (one >= LRW_MAX_SUCCESSIVE_IDENTICAL_BITS || zero >= LRW_MAX_SUCCESSIVE_IDENTICAL_BITS) - return TRUE; } + else + { + DecipherBlock (cipher, p, ks); + } + + Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); + + p += 16; + + if (i[7] != 0xff) + i[7]++; + else + *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); } - // Minimum and maximum Hamming weight - if (zeroTotal < minWeight || oneTotal < minWeight) - return TRUE; + FAST_ERASE64 (t, sizeof(t)); +} - return FALSE; + + +void DecryptBufferLRW64 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo) +{ + /* Deprecated/legacy */ + + int cipher = EAGetFirstCipher (cryptoInfo->ea); + unsigned __int8 *p = buffer; + unsigned __int8 *ks = cryptoInfo->ks; + unsigned __int8 i[8]; + unsigned __int8 t[8]; + unsigned __int64 b; + + *(unsigned __int64 *)i = BE64(blockIndex); + + if (length % 8) + TC_THROW_FATAL_EXCEPTION; + + for (b = 0; b < length >> 3; b++) + { + Gf64MulTab (i, t, &cryptoInfo->gf_ctx); + Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); + + DecipherBlock (cipher, p, ks); + + Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); + + p += 8; + + if (i[7] != 0xff) + i[7]++; + else + *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); + } + + FAST_ERASE64 (t, sizeof(t)); } // Initializes IV and whitening values for sector encryption/decryption in CBC mode. // IMPORTANT: This function has been deprecated (legacy). static void -InitSectorIVAndWhitening (unsigned __int64 secNo, +InitSectorIVAndWhitening (unsigned __int64 unitNo, int blockSize, unsigned __int32 *iv, unsigned __int64 *ivSeed, @@ -617,12 +1014,12 @@ InitSectorIVAndWhitening (unsigned __int unsigned __int64 iv64[4]; unsigned __int32 *iv32 = (unsigned __int32 *) iv64; - iv64[0] = ivSeed[0] ^ LE64(secNo); - iv64[1] = ivSeed[1] ^ LE64(secNo); - iv64[2] = ivSeed[2] ^ LE64(secNo); + iv64[0] = ivSeed[0] ^ LE64(unitNo); + iv64[1] = ivSeed[1] ^ LE64(unitNo); + iv64[2] = ivSeed[2] ^ LE64(unitNo); if (blockSize == 16) { - iv64[3] = ivSeed[3] ^ LE64(secNo); + iv64[3] = ivSeed[3] ^ LE64(unitNo); } iv[0] = iv32[0]; @@ -648,6 +1045,9 @@ InitSectorIVAndWhitening (unsigned __int whitening[0] = LE32( crc32int ( &iv32[2] ) ^ crc32int ( &iv32[5] ) ); whitening[1] = LE32( crc32int ( &iv32[3] ) ^ crc32int ( &iv32[4] ) ); break; + + default: + TC_THROW_FATAL_EXCEPTION; } } @@ -677,6 +1077,9 @@ EncryptBufferCBC (unsigned __int32 *data unsigned __int64 i; int blockSize = CipherGetBlockSize (ea != 0 ? EAGetFirstCipher (ea) : cipher); + if (len % blockSize) + TC_THROW_FATAL_EXCEPTION; + // IV bufIV[0] = iv[0]; bufIV[1] = iv[1]; @@ -764,6 +1167,9 @@ DecryptBufferCBC (unsigned __int32 *data unsigned __int32 ct[4]; int blockSize = CipherGetBlockSize (ea != 0 ? EAGetFirstCipher (ea) : cipher); + if (len % blockSize) + TC_THROW_FATAL_EXCEPTION; + // IV bufIV[0] = iv[0]; bufIV[1] = iv[1]; @@ -826,211 +1232,60 @@ DecryptBufferCBC (unsigned __int32 *data data += blockSize / sizeof(*data); } } +#endif // #ifndef TC_NO_COMPILER_INT64 -void Xor128 (unsigned __int64 *a, unsigned __int64 *b) -{ - *a++ ^= *b++; - *a ^= *b; -} - - -void Xor64 (unsigned __int64 *a, unsigned __int64 *b) -{ - *a ^= *b; -} - - -void EncryptBufferLRW128 (unsigned __int8 *plainText, unsigned int length, unsigned __int64 blockIndex, PCRYPTO_INFO cryptoInfo) +// EncryptBuffer +// +// buf: data to be encrypted; the start of the buffer is assumed to be aligned with the start of a data unit. +// len: number of bytes to encrypt; must be divisible by the block size (for cascaded ciphers, divisible +// by the largest block size used within the cascade) +void EncryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo) { - int cipher = EAGetFirstCipher (cryptoInfo->ea); - int cipherCount = EAGetCipherCount (cryptoInfo->ea); - unsigned __int8 *p = plainText; - unsigned __int8 *ks = cryptoInfo->ks; - unsigned __int8 i[8]; - unsigned __int8 t[16]; - unsigned int b; - - *(unsigned __int64 *)i = BE64(blockIndex); - - // Note that the maximum supported volume size is 8589934592 GB (i.e., 2^63 bytes). - - for (b = 0; b < length >> 4; b++) + switch (cryptoInfo->mode) { - Gf128MulBy64Tab (i, t, &cryptoInfo->gf_ctx); - Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); - - if (cipherCount > 1) + case XTS: { - // Cipher cascade + unsigned __int8 *ks = cryptoInfo->ks; + unsigned __int8 *ks2 = cryptoInfo->ks2; + UINT64_STRUCT dataUnitNo; + int cipher; + + // When encrypting/decrypting a buffer (typically a volume header) the sequential number + // of the first XTS data unit in the buffer is always 0 and the start of the buffer is + // always assumed to be aligned with the start of a data unit. + dataUnitNo.LowPart = 0; + dataUnitNo.HighPart = 0; + for (cipher = EAGetFirstCipher (cryptoInfo->ea); cipher != 0; cipher = EAGetNextCipher (cryptoInfo->ea, cipher)) { - EncipherBlock (cipher, p, ks); - ks += CipherGetKeyScheduleSize (cipher); - } - ks = cryptoInfo->ks; - } - else - { - EncipherBlock (cipher, p, ks); - } - - Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); - - p += 16; - - if (i[7] != 0xff) - i[7]++; - else - *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); - } - - memset (t, 0, sizeof (t)); -} - - -void EncryptBufferLRW64 (unsigned __int8 *plainText, unsigned int length, unsigned __int64 blockIndex, PCRYPTO_INFO cryptoInfo) -{ - int cipher = EAGetFirstCipher (cryptoInfo->ea); - unsigned __int8 *p = plainText; - unsigned __int8 *ks = cryptoInfo->ks; - unsigned __int8 i[8]; - unsigned __int8 t[8]; - unsigned int b; - - *(unsigned __int64 *)i = BE64(blockIndex); - - for (b = 0; b < length >> 3; b++) - { - Gf64MulTab (i, t, &cryptoInfo->gf_ctx); - Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); - - EncipherBlock (cipher, p, ks); - - Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); + EncryptBufferXTS (buf, len, &dataUnitNo, 0, ks, ks2, cipher); - p += 8; - - if (i[7] != 0xff) - i[7]++; - else - *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); - } - - memset (t, 0, sizeof (t)); -} - - -void DecryptBufferLRW128 (unsigned __int8 *plainText, int length, unsigned __int64 blockIndex, PCRYPTO_INFO cryptoInfo) -{ - int cipher = EAGetFirstCipher (cryptoInfo->ea); - int cipherCount = EAGetCipherCount (cryptoInfo->ea); - unsigned __int8 *p = plainText; - unsigned __int8 *ks = cryptoInfo->ks; - unsigned __int8 i[8]; - unsigned __int8 t[16]; - int b; - - *(unsigned __int64 *)i = BE64(blockIndex); - - // Note that the maximum supported volume size is 8589934592 GB (i.e., 2^63 bytes). - - for (b = 0; b < length >> 4; b++) - { - Gf128MulBy64Tab (i, t, &cryptoInfo->gf_ctx); - Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); - - if (cipherCount > 1) - { - // Cipher cascade - ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); - - for (cipher = EAGetLastCipher (cryptoInfo->ea); - cipher != 0; - cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher)) - { - ks -= CipherGetKeyScheduleSize (cipher); - DecipherBlock (cipher, p, ks); + ks += CipherGetKeyScheduleSize (cipher); + ks2 += CipherGetKeyScheduleSize (cipher); } } - else - { - DecipherBlock (cipher, p, ks); - } - - Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t); - - p += 16; - - if (i[7] != 0xff) - i[7]++; - else - *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); - } - - memset (t, 0, sizeof (t)); -} - - - -void DecryptBufferLRW64 (unsigned __int8 *plainText, int length, unsigned __int64 blockIndex, PCRYPTO_INFO cryptoInfo) -{ - int cipher = EAGetFirstCipher (cryptoInfo->ea); - unsigned __int8 *p = plainText; - unsigned __int8 *ks = cryptoInfo->ks; - unsigned __int8 i[8]; - unsigned __int8 t[8]; - int b; - - *(unsigned __int64 *)i = BE64(blockIndex); - - for (b = 0; b < length >> 3; b++) - { - Gf64MulTab (i, t, &cryptoInfo->gf_ctx); - Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); - - DecipherBlock (cipher, p, ks); - - Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t); - - p += 8; - - if (i[7] != 0xff) - i[7]++; - else - *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 ); - } - - memset (t, 0, sizeof (t)); -} - + break; -// EncryptBuffer -// -// buf: data to be encrypted -// len: number of bytes to encrypt; must be divisible by the block size (for cascaded -// ciphers divisible by the largest block size used within the cascade) +#ifndef TC_NO_COMPILER_INT64 + case LRW: -void -EncryptBuffer (unsigned __int32 *buf, - unsigned __int64 len, - PCRYPTO_INFO cryptoInfo) -{ + /* Deprecated/legacy */ - switch (cryptoInfo->mode) - { - case LRW: switch (CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea))) { case 8: - EncryptBufferLRW64 ((unsigned __int8 *)buf, (unsigned int) len, 1, cryptoInfo); + EncryptBufferLRW64 ((unsigned __int8 *)buf, (unsigned __int64) len, 1, cryptoInfo); break; case 16: - EncryptBufferLRW128 ((unsigned __int8 *)buf, (unsigned int) len, 1, cryptoInfo); + EncryptBufferLRW128 ((unsigned __int8 *)buf, (unsigned __int64) len, 1, cryptoInfo); break; + + default: + TC_THROW_FATAL_EXCEPTION; } break; @@ -1041,15 +1296,16 @@ EncryptBuffer (unsigned __int32 *buf, unsigned __int8 *ks = cryptoInfo->ks; int cipher; + for (cipher = EAGetFirstCipher (cryptoInfo->ea); cipher != 0; cipher = EAGetNextCipher (cryptoInfo->ea, cipher)) { - EncryptBufferCBC (buf, + EncryptBufferCBC ((unsigned __int32 *) buf, (unsigned int) len, ks, - (unsigned __int32 *) cryptoInfo->iv, - (unsigned __int32 *) &cryptoInfo->iv[8], + (unsigned __int32 *) cryptoInfo->k2, + (unsigned __int32 *) &cryptoInfo->k2[8], 0, cipher); @@ -1062,83 +1318,118 @@ EncryptBuffer (unsigned __int32 *buf, /* Deprecated/legacy */ - EncryptBufferCBC (buf, + EncryptBufferCBC ((unsigned __int32 *) buf, (unsigned int) len, cryptoInfo->ks, - (unsigned __int32 *) cryptoInfo->iv, - (unsigned __int32 *) &cryptoInfo->iv[8], + (unsigned __int32 *) cryptoInfo->k2, + (unsigned __int32 *) &cryptoInfo->k2[8], cryptoInfo->ea, 0); break; +#endif // #ifndef TC_NO_COMPILER_INT64 + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; } } -// Convert sector number to the index of the first LRW block in the sector. +#ifndef TC_NO_COMPILER_INT64 +// Converts a data unit number to the index of the first LRW block in the data unit. // Note that the maximum supported volume size is 8589934592 GB (i.e., 2^63 bytes). -unsigned __int64 LRWSector2Index (unsigned __int64 sector, int blockSize, PCRYPTO_INFO ci) +uint64 DataUnit2LRWIndex (uint64 dataUnit, int blockSize, PCRYPTO_INFO ci) { + /* Deprecated/legacy */ + if (ci->hiddenVolume) - sector -= ci->hiddenVolumeOffset / SECTOR_SIZE; + dataUnit -= ci->hiddenVolumeOffset / ENCRYPTION_DATA_UNIT_SIZE; else - sector -= HEADER_SIZE / SECTOR_SIZE; // Compensate for the volume header size + dataUnit -= TC_VOLUME_HEADER_SIZE_LEGACY / ENCRYPTION_DATA_UNIT_SIZE; // Compensate for the volume header size switch (blockSize) { case 8: - return (sector << 6) | 1; + return (dataUnit << 6) | 1; case 16: - return (sector << 5) | 1; + return (dataUnit << 5) | 1; + + default: + TC_THROW_FATAL_EXCEPTION; } return 0; } +#endif // #ifndef TC_NO_COMPILER_INT64 -// EncryptSectors -// // buf: data to be encrypted -// secNo: sector number relative to volume start -// noSectors: number of sectors in buffer -// ks: scheduled key -// iv: IV -// ea: encryption algorithm +// unitNo: sequential number of the data unit with which the buffer starts +// nbrUnits: number of data units in the buffer +void EncryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, uint32 nbrUnits, PCRYPTO_INFO ci) +#ifndef TC_WINDOWS_BOOT +{ + EncryptionThreadPoolDoWork (EncryptDataUnitsWork, buf, structUnitNo, nbrUnits, ci); +} -void _cdecl -EncryptSectors (unsigned __int32 *buf, - unsigned __int64 secNo, - unsigned __int64 noSectors, - PCRYPTO_INFO ci) +void EncryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) +#endif // !TC_WINDOWS_BOOT { int ea = ci->ea; - void *iv = ci->iv; // Deprecated/legacy unsigned __int8 *ks = ci->ks; - unsigned __int64 *iv64 = (unsigned __int64 *) iv; // Deprecated/legacy - unsigned __int32 sectorIV[4]; // Deprecated/legacy - unsigned __int32 secWhitening[2]; // Deprecated/legacy + unsigned __int8 *ks2 = ci->ks2; int cipher; +#ifndef TC_NO_COMPILER_INT64 + void *iv = ci->k2; // Deprecated/legacy + unsigned __int64 unitNo = structUnitNo->Value; + unsigned __int64 *iv64 = (unsigned __int64 *) iv; // Deprecated/legacy + unsigned __int32 sectorIV[4]; // Deprecated/legacy + unsigned __int32 secWhitening[2]; // Deprecated/legacy +#endif + switch (ci->mode) { + case XTS: + for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher)) + { + EncryptBufferXTS (buf, + nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, + structUnitNo, + 0, + ks, + ks2, + cipher); + + ks += CipherGetKeyScheduleSize (cipher); + ks2 += CipherGetKeyScheduleSize (cipher); + } + break; + +#ifndef TC_NO_COMPILER_INT64 case LRW: + + /* Deprecated/legacy */ + + switch (CipherGetBlockSize (EAGetFirstCipher (ea))) { - switch (CipherGetBlockSize (EAGetFirstCipher (ea))) - { - case 8: - EncryptBufferLRW64 ((unsigned __int8 *)buf, - (unsigned int) noSectors * SECTOR_SIZE, - LRWSector2Index (secNo, 8, ci), - ci); - break; - - case 16: - EncryptBufferLRW128 ((unsigned __int8 *)buf, - (unsigned int) noSectors * SECTOR_SIZE, - LRWSector2Index (secNo, 16, ci), - ci); - break; - } + case 8: + EncryptBufferLRW64 (buf, + (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, + DataUnit2LRWIndex (unitNo, 8, ci), + ci); + break; + + case 16: + EncryptBufferLRW128 (buf, + (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, + DataUnit2LRWIndex (unitNo, 16, ci), + ci); + break; + + default: + TC_THROW_FATAL_EXCEPTION; } break; @@ -1147,14 +1438,14 @@ EncryptSectors (unsigned __int32 *buf, /* Deprecated/legacy */ - while (noSectors--) + while (nbrUnits--) { for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher)) { - InitSectorIVAndWhitening (secNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening); + InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening); - EncryptBufferCBC (buf, - SECTOR_SIZE, + EncryptBufferCBC ((unsigned __int32 *) buf, + ENCRYPTION_DATA_UNIT_SIZE, ks, sectorIV, secWhitening, @@ -1164,8 +1455,8 @@ EncryptSectors (unsigned __int32 *buf, ks += CipherGetKeyScheduleSize (cipher); } ks -= EAGetKeyScheduleSize (ea); - buf += SECTOR_SIZE / sizeof(*buf); - secNo++; + buf += ENCRYPTION_DATA_UNIT_SIZE; + unitNo++; } break; @@ -1173,54 +1464,87 @@ EncryptSectors (unsigned __int32 *buf, /* Deprecated/legacy */ - while (noSectors--) + while (nbrUnits--) { - InitSectorIVAndWhitening (secNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening); + InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening); - EncryptBufferCBC (buf, - SECTOR_SIZE, + EncryptBufferCBC ((unsigned __int32 *) buf, + ENCRYPTION_DATA_UNIT_SIZE, ks, sectorIV, secWhitening, ea, 0); - buf += SECTOR_SIZE / sizeof(*buf); - secNo++; + buf += ENCRYPTION_DATA_UNIT_SIZE; + unitNo++; } break; +#endif // #ifndef TC_NO_COMPILER_INT64 + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; } } // DecryptBuffer // -// buf: data to be decrypted -// len: number of bytes to decrypt; must be divisible by the block size (for cascaded -// ciphers divisible by the largest block size used within the cascade) -void -DecryptBuffer (unsigned __int32 *buf, - unsigned __int64 len, - PCRYPTO_INFO cryptoInfo) +// buf: data to be decrypted; the start of the buffer is assumed to be aligned with the start of a data unit. +// len: number of bytes to decrypt; must be divisible by the block size (for cascaded ciphers, divisible +// by the largest block size used within the cascade) +void DecryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo) { switch (cryptoInfo->mode) { + case XTS: + { + unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); + unsigned __int8 *ks2 = cryptoInfo->ks2 + EAGetKeyScheduleSize (cryptoInfo->ea); + UINT64_STRUCT dataUnitNo; + int cipher; + + // When encrypting/decrypting a buffer (typically a volume header) the sequential number + // of the first XTS data unit in the buffer is always 0 and the start of the buffer is + // always assumed to be aligned with the start of the data unit 0. + dataUnitNo.LowPart = 0; + dataUnitNo.HighPart = 0; + + for (cipher = EAGetLastCipher (cryptoInfo->ea); + cipher != 0; + cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher)) + { + ks -= CipherGetKeyScheduleSize (cipher); + ks2 -= CipherGetKeyScheduleSize (cipher); + + DecryptBufferXTS (buf, len, &dataUnitNo, 0, ks, ks2, cipher); + } + } + break; + +#ifndef TC_NO_COMPILER_INT64 case LRW: + + /* Deprecated/legacy */ + switch (CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea))) { case 8: - DecryptBufferLRW64 ((unsigned __int8 *)buf, (unsigned int) len, 1, cryptoInfo); + DecryptBufferLRW64 (buf, (unsigned __int64) len, 1, cryptoInfo); break; case 16: - DecryptBufferLRW128 ((unsigned __int8 *)buf, (unsigned int) len, 1, cryptoInfo); + DecryptBufferLRW128 (buf, (unsigned __int64) len, 1, cryptoInfo); break; + + default: + TC_THROW_FATAL_EXCEPTION; } break; case CBC: case INNER_CBC: { - /* Deprecated/legacy */ unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea); @@ -1231,11 +1555,11 @@ DecryptBuffer (unsigned __int32 *buf, { ks -= CipherGetKeyScheduleSize (cipher); - DecryptBufferCBC (buf, + DecryptBufferCBC ((unsigned __int32 *) buf, (unsigned int) len, ks, - (unsigned __int32 *) cryptoInfo->iv, - (unsigned __int32 *) &cryptoInfo->iv[8], + (unsigned __int32 *) cryptoInfo->k2, + (unsigned __int32 *) &cryptoInfo->k2[8], 0, cipher); } @@ -1246,62 +1570,93 @@ DecryptBuffer (unsigned __int32 *buf, /* Deprecated/legacy */ - DecryptBufferCBC (buf, + DecryptBufferCBC ((unsigned __int32 *) buf, (unsigned int) len, cryptoInfo->ks, - (unsigned __int32 *) cryptoInfo->iv, - (unsigned __int32 *) &cryptoInfo->iv[8], + (unsigned __int32 *) cryptoInfo->k2, + (unsigned __int32 *) &cryptoInfo->k2[8], cryptoInfo->ea, 0); break; +#endif // #ifndef TC_NO_COMPILER_INT64 + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; } } -// DecryptSectors -// // buf: data to be decrypted -// secNo: sector number relative to volume start -// noSectors: number of sectors in buffer -// ks: scheduled key -// iv: IV -// ea: encryption algorithm +// unitNo: sequential number of the data unit with which the buffer starts +// nbrUnits: number of data units in the buffer +void DecryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, uint32 nbrUnits, PCRYPTO_INFO ci) +#ifndef TC_WINDOWS_BOOT +{ + EncryptionThreadPoolDoWork (DecryptDataUnitsWork, buf, structUnitNo, nbrUnits, ci); +} -void _cdecl -DecryptSectors (unsigned __int32 *buf, - unsigned __int64 secNo, - unsigned __int64 noSectors, - PCRYPTO_INFO ci -) +void DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) +#endif // !TC_WINDOWS_BOOT { int ea = ci->ea; - void *iv = ci->iv; // Deprecated/legacy unsigned __int8 *ks = ci->ks; - unsigned __int64 *iv64 = (unsigned __int64 *) iv; // Deprecated/legacy - unsigned __int32 sectorIV[4]; // Deprecated/legacy - unsigned __int32 secWhitening[2]; // Deprecated/legacy + unsigned __int8 *ks2 = ci->ks2; int cipher; +#ifndef TC_NO_COMPILER_INT64 + void *iv = ci->k2; // Deprecated/legacy + unsigned __int64 unitNo = structUnitNo->Value; + unsigned __int64 *iv64 = (unsigned __int64 *) iv; // Deprecated/legacy + unsigned __int32 sectorIV[4]; // Deprecated/legacy + unsigned __int32 secWhitening[2]; // Deprecated/legacy +#endif // #ifndef TC_NO_COMPILER_INT64 + + switch (ci->mode) { + case XTS: + ks += EAGetKeyScheduleSize (ea); + ks2 += EAGetKeyScheduleSize (ea); + + for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher)) + { + ks -= CipherGetKeyScheduleSize (cipher); + ks2 -= CipherGetKeyScheduleSize (cipher); + + DecryptBufferXTS (buf, + nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, + structUnitNo, + 0, + ks, + ks2, + cipher); + } + break; + +#ifndef TC_NO_COMPILER_INT64 case LRW: + + /* Deprecated/legacy */ + + switch (CipherGetBlockSize (EAGetFirstCipher (ea))) { - switch (CipherGetBlockSize (EAGetFirstCipher (ea))) - { - case 8: - DecryptBufferLRW64 ((unsigned __int8 *)buf, - (unsigned int) noSectors * SECTOR_SIZE, - LRWSector2Index (secNo, 8, ci), - ci); - break; - - case 16: - DecryptBufferLRW128 ((unsigned __int8 *)buf, - (unsigned int) noSectors * SECTOR_SIZE, - LRWSector2Index (secNo, 16, ci), - ci); - break; - } + case 8: + DecryptBufferLRW64 (buf, + (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, + DataUnit2LRWIndex (unitNo, 8, ci), + ci); + break; + + case 16: + DecryptBufferLRW128 (buf, + (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, + DataUnit2LRWIndex (unitNo, 16, ci), + ci); + break; + + default: + TC_THROW_FATAL_EXCEPTION; } break; @@ -1310,25 +1665,25 @@ DecryptSectors (unsigned __int32 *buf, /* Deprecated/legacy */ - while (noSectors--) + while (nbrUnits--) { ks += EAGetKeyScheduleSize (ea); for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher)) { - InitSectorIVAndWhitening (secNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening); + InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening); ks -= CipherGetKeyScheduleSize (cipher); - DecryptBufferCBC (buf, - SECTOR_SIZE, + DecryptBufferCBC ((unsigned __int32 *) buf, + ENCRYPTION_DATA_UNIT_SIZE, ks, sectorIV, secWhitening, 0, cipher); } - buf += SECTOR_SIZE / sizeof(*buf); - secNo++; + buf += ENCRYPTION_DATA_UNIT_SIZE; + unitNo++; } break; @@ -1336,22 +1691,181 @@ DecryptSectors (unsigned __int32 *buf, /* Deprecated/legacy */ - while (noSectors--) + while (nbrUnits--) { - InitSectorIVAndWhitening (secNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening); + InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening); - DecryptBufferCBC (buf, - SECTOR_SIZE, + DecryptBufferCBC ((unsigned __int32 *) buf, + ENCRYPTION_DATA_UNIT_SIZE, ks, sectorIV, secWhitening, ea, 0); - buf += SECTOR_SIZE / sizeof(*buf); - secNo++; + buf += ENCRYPTION_DATA_UNIT_SIZE; + unitNo++; } break; +#endif // #ifndef TC_NO_COMPILER_INT64 + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; } } + +// Returns the maximum number of bytes necessary to be generated by the PBKDF2 (PKCS #5) +int GetMaxPkcs5OutSize (void) +{ + int size = 32; + + size = max (size, EAGetLargestKeyForMode (XTS) * 2); // Sizes of primary + secondary keys + +#ifndef TC_WINDOWS_BOOT + size = max (size, LEGACY_VOL_IV_SIZE + EAGetLargestKeyForMode (LRW)); // Deprecated/legacy + size = max (size, LEGACY_VOL_IV_SIZE + EAGetLargestKeyForMode (CBC)); // Deprecated/legacy + size = max (size, LEGACY_VOL_IV_SIZE + EAGetLargestKeyForMode (OUTER_CBC)); // Deprecated/legacy + size = max (size, LEGACY_VOL_IV_SIZE + EAGetLargestKeyForMode (INNER_CBC)); // Deprecated/legacy +#endif + + return size; +} + + +#else // TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + + +#if !defined (TC_WINDOWS_BOOT_AES) && !defined (TC_WINDOWS_BOOT_SERPENT) && !defined (TC_WINDOWS_BOOT_TWOFISH) +#error No cipher defined +#endif + +void EncipherBlock(int cipher, void *data, void *ks) +{ +#ifdef TC_WINDOWS_BOOT_AES + if (IsAesHwCpuSupported()) + aes_hw_cpu_encrypt ((byte *) ks, data); + else + aes_encrypt (data, data, ks); +#elif defined (TC_WINDOWS_BOOT_SERPENT) + serpent_encrypt (data, data, ks); +#elif defined (TC_WINDOWS_BOOT_TWOFISH) + twofish_encrypt (ks, data, data); +#endif +} + +void DecipherBlock(int cipher, void *data, void *ks) +{ +#ifdef TC_WINDOWS_BOOT_AES + if (IsAesHwCpuSupported()) + aes_hw_cpu_decrypt ((byte *) ks + sizeof (aes_encrypt_ctx) + 14 * 16, data); + else + aes_decrypt (data, data, (aes_decrypt_ctx *) ((byte *) ks + sizeof(aes_encrypt_ctx))); +#elif defined (TC_WINDOWS_BOOT_SERPENT) + serpent_decrypt (data, data, ks); +#elif defined (TC_WINDOWS_BOOT_TWOFISH) + twofish_decrypt (ks, data, data); +#endif +} + +int EAGetFirst () +{ + return 1; +} + +int EAGetNext (int previousEA) +{ + return 0; +} + +int EAInit (int ea, unsigned char *key, unsigned __int8 *ks) +{ +#ifdef TC_WINDOWS_BOOT_AES + + aes_init(); + + if (aes_encrypt_key256 (key, (aes_encrypt_ctx *) ks) != EXIT_SUCCESS) + return ERR_CIPHER_INIT_FAILURE; + if (aes_decrypt_key256 (key, (aes_decrypt_ctx *) (ks + sizeof (aes_encrypt_ctx))) != EXIT_SUCCESS) + return ERR_CIPHER_INIT_FAILURE; + +#elif defined (TC_WINDOWS_BOOT_SERPENT) + serpent_set_key (key, 32 * 8, ks); +#elif defined (TC_WINDOWS_BOOT_TWOFISH) + twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key, 32 * 8); +#endif + return ERR_SUCCESS; +} + +int EAGetKeySize (int ea) +{ + return 32; +} + +int EAGetFirstCipher (int ea) +{ + return 1; +} + +void EncryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo) +{ + UINT64_STRUCT dataUnitNo; + dataUnitNo.LowPart = 0; dataUnitNo.HighPart = 0; + EncryptBufferXTS (buf, len, &dataUnitNo, 0, cryptoInfo->ks, cryptoInfo->ks2, 1); +} + +void EncryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) +{ + EncryptBufferXTS (buf, nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, structUnitNo, 0, ci->ks, ci->ks2, 1); +} + +void DecryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo) +{ + UINT64_STRUCT dataUnitNo; + dataUnitNo.LowPart = 0; dataUnitNo.HighPart = 0; + DecryptBufferXTS (buf, len, &dataUnitNo, 0, cryptoInfo->ks, cryptoInfo->ks2, 1); +} + +void DecryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) +{ + DecryptBufferXTS (buf, nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, structUnitNo, 0, ci->ks, ci->ks2, 1); +} + +#endif // TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + + +#if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_AES) + +static BOOL HwEncryptionDisabled = FALSE; + +BOOL IsAesHwCpuSupported () +{ + static BOOL state = FALSE; + static BOOL stateValid = FALSE; + + if (!stateValid) + { + state = is_aes_hw_cpu_supported() ? TRUE : FALSE; + stateValid = TRUE; + } + + return state && !HwEncryptionDisabled; +} + +void EnableHwEncryption (BOOL enable) +{ +#if defined (TC_WINDOWS_BOOT) + if (enable) + aes_hw_cpu_enable_sse(); +#endif + + HwEncryptionDisabled = !enable; +} + +BOOL IsHwEncryptionEnabled () +{ + return !HwEncryptionDisabled; +} + +#endif // !TC_WINDOWS_BOOT