From fc37cc4a02ed13d1a73b941a9f80975600fd1b99 Mon Sep 17 00:00:00 2001 From: David Foerster Date: Tue, 10 May 2016 20:20:14 +0200 Subject: Normalize all line terminators --- src/Common/Crypto.c | 2116 +++++++++++++++++++++++++-------------------------- 1 file changed, 1058 insertions(+), 1058 deletions(-) (limited to 'src/Common/Crypto.c') diff --git a/src/Common/Crypto.c b/src/Common/Crypto.c index d940a453..a524fd97 100644 --- a/src/Common/Crypto.c +++ b/src/Common/Crypto.c @@ -1,1058 +1,1058 @@ -/* - Legal Notice: Some portions of the source code contained in this file were - derived from the source code of TrueCrypt 7.1a, which is - Copyright (c) 2003-2012 TrueCrypt Developers Association and which is - governed by the TrueCrypt License 3.0, also 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) 2013-2016 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 "Tcdefs.h" -#include "Crypto.h" -#include "Xts.h" -#include "Crc.h" -#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: - - Crypto.h: - ID #define - MAX_EXPANDED_KEY #define - - Crypto.c: - Ciphers[] - EncryptionAlgorithms[] - CipherInit() - EncipherBlock() - DecipherBlock() - -*/ - -#ifndef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE - -// Cipher configuration -static Cipher Ciphers[] = -{ -// Block Size Key Size Key Schedule Size -// ID Name (Bytes) (Bytes) (Bytes) -#ifdef TC_WINDOWS_BOOT - { AES, "AES", 16, 32, AES_KS }, - { SERPENT, "Serpent", 16, 32, 140*4 }, - { TWOFISH, "Twofish", 16, 32, TWOFISH_KS }, -#else - { AES, L"AES", 16, 32, AES_KS }, - { SERPENT, L"Serpent", 16, 32, 140*4 }, - { TWOFISH, L"Twofish", 16, 32, TWOFISH_KS }, -#endif - { 0, 0, 0, 0, 0 } -}; - - -// Encryption algorithm configuration -static EncryptionAlgorithm EncryptionAlgorithms[] = -{ - // Cipher(s) Modes FormatEnabled - -#ifndef TC_WINDOWS_BOOT - - { { 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 - -#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 - -}; - - -#ifndef TC_WINDOWS_BOOT -// Hash algorithms -static Hash Hashes[] = -{ // ID Name Deprecated System Encryption - { SHA512, L"SHA-512", FALSE, FALSE }, - { WHIRLPOOL, L"Whirlpool", FALSE, FALSE }, - { SHA256, L"SHA-256", FALSE, TRUE }, - { RIPEMD160, L"RIPEMD-160", TRUE, TRUE }, - { 0, 0, 0 } -}; -#endif - -/* 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 = ERR_SUCCESS; - - switch (cipher) - { - case AES: -#ifndef TC_WINDOWS_BOOT - 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; -#else - if (aes_set_key (key, (length_type) CipherGetKeySize(AES), (aes_context *) ks) != 0) - return ERR_CIPHER_INIT_FAILURE; -#endif - break; - - case SERPENT: - serpent_set_key (key, ks); - break; - - case TWOFISH: - twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key); - break; - - default: - // Unknown/wrong cipher ID - return ERR_CIPHER_INIT_FAILURE; - } - - return retVal; -} - -void EncipherBlock(int cipher, void *data, void *ks) -{ - switch (cipher) - { - 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; - 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 SERPENT: serpent_decrypt (data, data, ks); 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; - -#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) -{ - int i; - for (i = 0; Ciphers[i].Id != 0; i++) - if (Ciphers[i].Id == id) - return &Ciphers[i]; - - return NULL; -} - -#ifndef TC_WINDOWS_BOOT -const wchar_t *CipherGetName (int cipherId) -{ - Cipher* pCipher = CipherGet (cipherId); - return pCipher? pCipher -> Name : L""; -} -#endif - -int CipherGetBlockSize (int cipherId) -{ -#ifdef TC_WINDOWS_BOOT - return CipherGet (cipherId) -> BlockSize; -#else - Cipher* pCipher = CipherGet (cipherId); - return pCipher? pCipher -> BlockSize : 0; -#endif -} - -int CipherGetKeySize (int cipherId) -{ -#ifdef TC_WINDOWS_BOOT - return CipherGet (cipherId) -> KeySize; -#else - Cipher* pCipher = CipherGet (cipherId); - return pCipher? pCipher -> KeySize : 0; -#endif -} - -int CipherGetKeyScheduleSize (int cipherId) -{ -#ifdef TC_WINDOWS_BOOT - return CipherGet (cipherId) -> KeyScheduleSize; -#else - Cipher* pCipher = CipherGet (cipherId); - return pCipher? pCipher -> KeyScheduleSize : 0; -#endif -} - -#ifndef TC_WINDOWS_BOOT - -BOOL CipherSupportsIntraDataUnitParallelization (int cipher) -{ - return cipher == AES && IsAesHwCpuSupported(); -} - -#endif - - -// Encryption algorithms support - -int EAGetFirst () -{ - return 1; -} - -// Returns number of EAs -int EAGetCount (void) -{ - int ea, count = 0; - - for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea)) - { - count++; - } - return count; -} - -int EAGetNext (int previousEA) -{ - int id = previousEA + 1; - if (EncryptionAlgorithms[id].Ciphers[0] != 0) return id; - return 0; -} - - -// 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 = ERR_SUCCESS; - - if (ea == 0) - return ERR_CIPHER_INIT_FAILURE; - - for (c = EAGetFirstCipher (ea); c != 0; c = EAGetNextCipher (ea, c)) - { - switch (CipherInit (c, key, ks)) - { - case ERR_CIPHER_INIT_FAILURE: - return ERR_CIPHER_INIT_FAILURE; - - case ERR_CIPHER_INIT_WEAK_KEY: - retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error - break; - } - - key += CipherGetKeySize (c); - ks += CipherGetKeyScheduleSize (c); - } - return retVal; -} - - -#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; - - default: - // Unknown/wrong ID - TC_THROW_FATAL_EXCEPTION; - } - return TRUE; -} - -static void EAGetDisplayName(wchar_t *buf, int ea, int i) -{ - wcscpy (buf, CipherGetName (i)); - if (i = EAGetPreviousCipher(ea, i)) - { - wcscat (buf, L"("); - EAGetDisplayName (&buf[wcslen(buf)], ea, i); - wcscat (buf, L")"); - } -} - -// Returns name of EA, cascaded cipher names are separated by hyphens -wchar_t *EAGetName (wchar_t *buf, int ea, int guiDisplay) -{ - if (guiDisplay) - { - EAGetDisplayName (buf, ea, EAGetLastCipher(ea)); - } - else - { - int i = EAGetLastCipher(ea); - wcscpy (buf, (i != 0) ? CipherGetName (i) : L"?"); - - while (i = EAGetPreviousCipher(ea, i)) - { - wcscat (buf, L"-"); - wcscat (buf, CipherGetName (i)); - } - } - return buf; -} - - -int EAGetByName (wchar_t *name) -{ - int ea = EAGetFirst (); - wchar_t n[128]; - - do - { - EAGetName (n, ea, 1); - if (_wcsicmp (n, name) == 0) - return ea; - } - while (ea = EAGetNext (ea)); - - return 0; -} - -#endif // TC_WINDOWS_BOOT - -// Returns sum of key sizes of all ciphers of the EA (in bytes) -int EAGetKeySize (int ea) -{ - int i = EAGetFirstCipher (ea); - int size = CipherGetKeySize (i); - - while (i = EAGetNextCipher (ea, i)) - { - size += CipherGetKeySize (i); - } - - return size; -} - - -// Returns the first mode of operation of EA -int EAGetFirstMode (int ea) -{ - return (EncryptionAlgorithms[ea].Modes[0]); -} - - -int EAGetNextMode (int ea, int previousModeId) -{ - int c, i = 0; - while (c = EncryptionAlgorithms[ea].Modes[i++]) - { - if (c == previousModeId) - return EncryptionAlgorithms[ea].Modes[i]; - } - - return 0; -} - - -#ifndef TC_WINDOWS_BOOT - -// Returns the name of the mode of operation of the whole EA -wchar_t *EAGetModeName (int ea, int mode, BOOL capitalLetters) -{ - switch (mode) - { - case XTS: - - return L"XTS"; - - } - return L"[unknown]"; -} - -#endif // TC_WINDOWS_BOOT - - -// Returns sum of key schedule sizes of all ciphers of the EA -int EAGetKeyScheduleSize (int ea) -{ - int i = EAGetFirstCipher(ea); - int size = CipherGetKeyScheduleSize (i); - - while (i = EAGetNextCipher(ea, i)) - { - size += CipherGetKeyScheduleSize (i); - } - - return size; -} - - -// 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)) - { - if (EAGetKeySize (ea) >= key) - key = EAGetKeySize (ea); - } - - return key; -} - - -// Returns number of ciphers in EA -int EAGetCipherCount (int ea) -{ - int i = 0; - while (EncryptionAlgorithms[ea].Ciphers[i++]); - - return i - 1; -} - - -int EAGetFirstCipher (int ea) -{ - return EncryptionAlgorithms[ea].Ciphers[0]; -} - - -int EAGetLastCipher (int ea) -{ - int c, i = 0; - while (c = EncryptionAlgorithms[ea].Ciphers[i++]); - - return EncryptionAlgorithms[ea].Ciphers[i - 2]; -} - - -int EAGetNextCipher (int ea, int previousCipherId) -{ - int c, i = 0; - while (c = EncryptionAlgorithms[ea].Ciphers[i++]) - { - if (c == previousCipherId) - return EncryptionAlgorithms[ea].Ciphers[i]; - } - - return 0; -} - - -int EAGetPreviousCipher (int ea, int previousCipherId) -{ - int c, i = 0; - - if (EncryptionAlgorithms[ea].Ciphers[i++] == previousCipherId) - return 0; - - while (c = EncryptionAlgorithms[ea].Ciphers[i++]) - { - if (c == previousCipherId) - return EncryptionAlgorithms[ea].Ciphers[i - 2]; - } - - return 0; -} - - -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; -} - -#ifndef TC_WINDOWS_BOOT -Hash *HashGet (int id) -{ - int i; - for (i = 0; Hashes[i].Id != 0; i++) - if (Hashes[i].Id == id) - return &Hashes[i]; - - return 0; -} - - -int HashGetIdByName (wchar_t *name) -{ - int i; - for (i = 0; Hashes[i].Id != 0; i++) - if (wcscmp (Hashes[i].Name, name) == 0) - return Hashes[i].Id; - - return 0; -} - -const wchar_t *HashGetName (int hashId) -{ - Hash* pHash = HashGet(hashId); - return pHash? pHash -> Name : L""; -} - -void HashGetName2 (wchar_t *buf, int hashId) -{ - Hash* pHash = HashGet(hashId); - if (pHash) - wcscpy(buf, pHash -> Name); - else - buf[0] = L'\0'; -} - -BOOL HashIsDeprecated (int hashId) -{ - Hash* pHash = HashGet(hashId); - return pHash? pHash -> Deprecated : FALSE; - -} - -BOOL HashForSystemEncryption (int hashId) -{ - Hash* pHash = HashGet(hashId); - return pHash? pHash -> SystemEncryption : FALSE; - -} - -// 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 - - return size; -} - -#endif - - -#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 - VirtualLock (cryptoInfo, sizeof (CRYPTO_INFO)); -#endif - - 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 -} - -#ifndef TC_WINDOWS_BOOT -void crypto_loadkey (PKEY_INFO keyInfo, char *lpszUserKey, int nUserKeyLen) -{ - keyInfo->keyLength = nUserKeyLen; - burn (keyInfo->userKey, sizeof (keyInfo->userKey)); - memcpy (keyInfo->userKey, lpszUserKey, nUserKeyLen); -} -#endif - -void crypto_close (PCRYPTO_INFO cryptoInfo) -{ -#ifndef TC_WINDOWS_BOOT - - if (cryptoInfo != NULL) - { - burn (cryptoInfo, sizeof (CRYPTO_INFO)); -#ifndef DEVICE_DRIVER - VirtualUnlock (cryptoInfo, sizeof (CRYPTO_INFO)); -#endif - TCfree (cryptoInfo); - } - -#else // TC_WINDOWS_BOOT - - burn (&CryptoInfoBuffer, sizeof (CryptoInfoBuffer)); - CryptoInfoBufferInUse = FALSE; - -#endif // TC_WINDOWS_BOOT -} - - -#ifndef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE - - - -// 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) -{ - switch (cryptoInfo->mode) - { - case XTS: - { - 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)) - { - EncryptBufferXTS (buf, len, &dataUnitNo, 0, ks, ks2, cipher); - - ks += CipherGetKeyScheduleSize (cipher); - ks2 += CipherGetKeyScheduleSize (cipher); - } - } - break; - - default: - // Unknown/wrong ID - TC_THROW_FATAL_EXCEPTION; - } -} - - -// buf: data to be encrypted -// 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 EncryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) -#endif // !TC_WINDOWS_BOOT -{ - int ea = ci->ea; - unsigned __int8 *ks = ci->ks; - unsigned __int8 *ks2 = ci->ks2; - int cipher; - - 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; - - default: - // Unknown/wrong ID - TC_THROW_FATAL_EXCEPTION; - } -} - -// DecryptBuffer -// -// 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; - - default: - // Unknown/wrong ID - TC_THROW_FATAL_EXCEPTION; - } -} - -// buf: data to be decrypted -// 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 DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) -#endif // !TC_WINDOWS_BOOT -{ - int ea = ci->ea; - unsigned __int8 *ks = ci->ks; - unsigned __int8 *ks2 = ci->ks2; - int cipher; - - - 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; - - default: - // Unknown/wrong ID - TC_THROW_FATAL_EXCEPTION; - } -} - - -#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 -} - - -#ifdef TC_WINDOWS_BOOT_AES - -int EAInit (unsigned char *key, unsigned __int8 *ks) -{ - 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; - - return ERR_SUCCESS; -} - -#endif - - -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 +/* + Legal Notice: Some portions of the source code contained in this file were + derived from the source code of TrueCrypt 7.1a, which is + Copyright (c) 2003-2012 TrueCrypt Developers Association and which is + governed by the TrueCrypt License 3.0, also 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) 2013-2016 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 "Tcdefs.h" +#include "Crypto.h" +#include "Xts.h" +#include "Crc.h" +#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: + + Crypto.h: + ID #define + MAX_EXPANDED_KEY #define + + Crypto.c: + Ciphers[] + EncryptionAlgorithms[] + CipherInit() + EncipherBlock() + DecipherBlock() + +*/ + +#ifndef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + +// Cipher configuration +static Cipher Ciphers[] = +{ +// Block Size Key Size Key Schedule Size +// ID Name (Bytes) (Bytes) (Bytes) +#ifdef TC_WINDOWS_BOOT + { AES, "AES", 16, 32, AES_KS }, + { SERPENT, "Serpent", 16, 32, 140*4 }, + { TWOFISH, "Twofish", 16, 32, TWOFISH_KS }, +#else + { AES, L"AES", 16, 32, AES_KS }, + { SERPENT, L"Serpent", 16, 32, 140*4 }, + { TWOFISH, L"Twofish", 16, 32, TWOFISH_KS }, +#endif + { 0, 0, 0, 0, 0 } +}; + + +// Encryption algorithm configuration +static EncryptionAlgorithm EncryptionAlgorithms[] = +{ + // Cipher(s) Modes FormatEnabled + +#ifndef TC_WINDOWS_BOOT + + { { 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 + +#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 + +}; + + +#ifndef TC_WINDOWS_BOOT +// Hash algorithms +static Hash Hashes[] = +{ // ID Name Deprecated System Encryption + { SHA512, L"SHA-512", FALSE, FALSE }, + { WHIRLPOOL, L"Whirlpool", FALSE, FALSE }, + { SHA256, L"SHA-256", FALSE, TRUE }, + { RIPEMD160, L"RIPEMD-160", TRUE, TRUE }, + { 0, 0, 0 } +}; +#endif + +/* 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 = ERR_SUCCESS; + + switch (cipher) + { + case AES: +#ifndef TC_WINDOWS_BOOT + 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; +#else + if (aes_set_key (key, (length_type) CipherGetKeySize(AES), (aes_context *) ks) != 0) + return ERR_CIPHER_INIT_FAILURE; +#endif + break; + + case SERPENT: + serpent_set_key (key, ks); + break; + + case TWOFISH: + twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key); + break; + + default: + // Unknown/wrong cipher ID + return ERR_CIPHER_INIT_FAILURE; + } + + return retVal; +} + +void EncipherBlock(int cipher, void *data, void *ks) +{ + switch (cipher) + { + 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; + 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 SERPENT: serpent_decrypt (data, data, ks); 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; + +#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) +{ + int i; + for (i = 0; Ciphers[i].Id != 0; i++) + if (Ciphers[i].Id == id) + return &Ciphers[i]; + + return NULL; +} + +#ifndef TC_WINDOWS_BOOT +const wchar_t *CipherGetName (int cipherId) +{ + Cipher* pCipher = CipherGet (cipherId); + return pCipher? pCipher -> Name : L""; +} +#endif + +int CipherGetBlockSize (int cipherId) +{ +#ifdef TC_WINDOWS_BOOT + return CipherGet (cipherId) -> BlockSize; +#else + Cipher* pCipher = CipherGet (cipherId); + return pCipher? pCipher -> BlockSize : 0; +#endif +} + +int CipherGetKeySize (int cipherId) +{ +#ifdef TC_WINDOWS_BOOT + return CipherGet (cipherId) -> KeySize; +#else + Cipher* pCipher = CipherGet (cipherId); + return pCipher? pCipher -> KeySize : 0; +#endif +} + +int CipherGetKeyScheduleSize (int cipherId) +{ +#ifdef TC_WINDOWS_BOOT + return CipherGet (cipherId) -> KeyScheduleSize; +#else + Cipher* pCipher = CipherGet (cipherId); + return pCipher? pCipher -> KeyScheduleSize : 0; +#endif +} + +#ifndef TC_WINDOWS_BOOT + +BOOL CipherSupportsIntraDataUnitParallelization (int cipher) +{ + return cipher == AES && IsAesHwCpuSupported(); +} + +#endif + + +// Encryption algorithms support + +int EAGetFirst () +{ + return 1; +} + +// Returns number of EAs +int EAGetCount (void) +{ + int ea, count = 0; + + for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea)) + { + count++; + } + return count; +} + +int EAGetNext (int previousEA) +{ + int id = previousEA + 1; + if (EncryptionAlgorithms[id].Ciphers[0] != 0) return id; + return 0; +} + + +// 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 = ERR_SUCCESS; + + if (ea == 0) + return ERR_CIPHER_INIT_FAILURE; + + for (c = EAGetFirstCipher (ea); c != 0; c = EAGetNextCipher (ea, c)) + { + switch (CipherInit (c, key, ks)) + { + case ERR_CIPHER_INIT_FAILURE: + return ERR_CIPHER_INIT_FAILURE; + + case ERR_CIPHER_INIT_WEAK_KEY: + retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error + break; + } + + key += CipherGetKeySize (c); + ks += CipherGetKeyScheduleSize (c); + } + return retVal; +} + + +#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; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } + return TRUE; +} + +static void EAGetDisplayName(wchar_t *buf, int ea, int i) +{ + wcscpy (buf, CipherGetName (i)); + if (i = EAGetPreviousCipher(ea, i)) + { + wcscat (buf, L"("); + EAGetDisplayName (&buf[wcslen(buf)], ea, i); + wcscat (buf, L")"); + } +} + +// Returns name of EA, cascaded cipher names are separated by hyphens +wchar_t *EAGetName (wchar_t *buf, int ea, int guiDisplay) +{ + if (guiDisplay) + { + EAGetDisplayName (buf, ea, EAGetLastCipher(ea)); + } + else + { + int i = EAGetLastCipher(ea); + wcscpy (buf, (i != 0) ? CipherGetName (i) : L"?"); + + while (i = EAGetPreviousCipher(ea, i)) + { + wcscat (buf, L"-"); + wcscat (buf, CipherGetName (i)); + } + } + return buf; +} + + +int EAGetByName (wchar_t *name) +{ + int ea = EAGetFirst (); + wchar_t n[128]; + + do + { + EAGetName (n, ea, 1); + if (_wcsicmp (n, name) == 0) + return ea; + } + while (ea = EAGetNext (ea)); + + return 0; +} + +#endif // TC_WINDOWS_BOOT + +// Returns sum of key sizes of all ciphers of the EA (in bytes) +int EAGetKeySize (int ea) +{ + int i = EAGetFirstCipher (ea); + int size = CipherGetKeySize (i); + + while (i = EAGetNextCipher (ea, i)) + { + size += CipherGetKeySize (i); + } + + return size; +} + + +// Returns the first mode of operation of EA +int EAGetFirstMode (int ea) +{ + return (EncryptionAlgorithms[ea].Modes[0]); +} + + +int EAGetNextMode (int ea, int previousModeId) +{ + int c, i = 0; + while (c = EncryptionAlgorithms[ea].Modes[i++]) + { + if (c == previousModeId) + return EncryptionAlgorithms[ea].Modes[i]; + } + + return 0; +} + + +#ifndef TC_WINDOWS_BOOT + +// Returns the name of the mode of operation of the whole EA +wchar_t *EAGetModeName (int ea, int mode, BOOL capitalLetters) +{ + switch (mode) + { + case XTS: + + return L"XTS"; + + } + return L"[unknown]"; +} + +#endif // TC_WINDOWS_BOOT + + +// Returns sum of key schedule sizes of all ciphers of the EA +int EAGetKeyScheduleSize (int ea) +{ + int i = EAGetFirstCipher(ea); + int size = CipherGetKeyScheduleSize (i); + + while (i = EAGetNextCipher(ea, i)) + { + size += CipherGetKeyScheduleSize (i); + } + + return size; +} + + +// 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)) + { + if (EAGetKeySize (ea) >= key) + key = EAGetKeySize (ea); + } + + return key; +} + + +// Returns number of ciphers in EA +int EAGetCipherCount (int ea) +{ + int i = 0; + while (EncryptionAlgorithms[ea].Ciphers[i++]); + + return i - 1; +} + + +int EAGetFirstCipher (int ea) +{ + return EncryptionAlgorithms[ea].Ciphers[0]; +} + + +int EAGetLastCipher (int ea) +{ + int c, i = 0; + while (c = EncryptionAlgorithms[ea].Ciphers[i++]); + + return EncryptionAlgorithms[ea].Ciphers[i - 2]; +} + + +int EAGetNextCipher (int ea, int previousCipherId) +{ + int c, i = 0; + while (c = EncryptionAlgorithms[ea].Ciphers[i++]) + { + if (c == previousCipherId) + return EncryptionAlgorithms[ea].Ciphers[i]; + } + + return 0; +} + + +int EAGetPreviousCipher (int ea, int previousCipherId) +{ + int c, i = 0; + + if (EncryptionAlgorithms[ea].Ciphers[i++] == previousCipherId) + return 0; + + while (c = EncryptionAlgorithms[ea].Ciphers[i++]) + { + if (c == previousCipherId) + return EncryptionAlgorithms[ea].Ciphers[i - 2]; + } + + return 0; +} + + +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; +} + +#ifndef TC_WINDOWS_BOOT +Hash *HashGet (int id) +{ + int i; + for (i = 0; Hashes[i].Id != 0; i++) + if (Hashes[i].Id == id) + return &Hashes[i]; + + return 0; +} + + +int HashGetIdByName (wchar_t *name) +{ + int i; + for (i = 0; Hashes[i].Id != 0; i++) + if (wcscmp (Hashes[i].Name, name) == 0) + return Hashes[i].Id; + + return 0; +} + +const wchar_t *HashGetName (int hashId) +{ + Hash* pHash = HashGet(hashId); + return pHash? pHash -> Name : L""; +} + +void HashGetName2 (wchar_t *buf, int hashId) +{ + Hash* pHash = HashGet(hashId); + if (pHash) + wcscpy(buf, pHash -> Name); + else + buf[0] = L'\0'; +} + +BOOL HashIsDeprecated (int hashId) +{ + Hash* pHash = HashGet(hashId); + return pHash? pHash -> Deprecated : FALSE; + +} + +BOOL HashForSystemEncryption (int hashId) +{ + Hash* pHash = HashGet(hashId); + return pHash? pHash -> SystemEncryption : FALSE; + +} + +// 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 + + return size; +} + +#endif + + +#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 + VirtualLock (cryptoInfo, sizeof (CRYPTO_INFO)); +#endif + + 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 +} + +#ifndef TC_WINDOWS_BOOT +void crypto_loadkey (PKEY_INFO keyInfo, char *lpszUserKey, int nUserKeyLen) +{ + keyInfo->keyLength = nUserKeyLen; + burn (keyInfo->userKey, sizeof (keyInfo->userKey)); + memcpy (keyInfo->userKey, lpszUserKey, nUserKeyLen); +} +#endif + +void crypto_close (PCRYPTO_INFO cryptoInfo) +{ +#ifndef TC_WINDOWS_BOOT + + if (cryptoInfo != NULL) + { + burn (cryptoInfo, sizeof (CRYPTO_INFO)); +#ifndef DEVICE_DRIVER + VirtualUnlock (cryptoInfo, sizeof (CRYPTO_INFO)); +#endif + TCfree (cryptoInfo); + } + +#else // TC_WINDOWS_BOOT + + burn (&CryptoInfoBuffer, sizeof (CryptoInfoBuffer)); + CryptoInfoBufferInUse = FALSE; + +#endif // TC_WINDOWS_BOOT +} + + +#ifndef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + + + +// 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) +{ + switch (cryptoInfo->mode) + { + case XTS: + { + 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)) + { + EncryptBufferXTS (buf, len, &dataUnitNo, 0, ks, ks2, cipher); + + ks += CipherGetKeyScheduleSize (cipher); + ks2 += CipherGetKeyScheduleSize (cipher); + } + } + break; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } +} + + +// buf: data to be encrypted +// 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 EncryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) +#endif // !TC_WINDOWS_BOOT +{ + int ea = ci->ea; + unsigned __int8 *ks = ci->ks; + unsigned __int8 *ks2 = ci->ks2; + int cipher; + + 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; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } +} + +// DecryptBuffer +// +// 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; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } +} + +// buf: data to be decrypted +// 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 DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci) +#endif // !TC_WINDOWS_BOOT +{ + int ea = ci->ea; + unsigned __int8 *ks = ci->ks; + unsigned __int8 *ks2 = ci->ks2; + int cipher; + + + 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; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } +} + + +#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 +} + + +#ifdef TC_WINDOWS_BOOT_AES + +int EAInit (unsigned char *key, unsigned __int8 *ks) +{ + 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; + + return ERR_SUCCESS; +} + +#endif + + +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 -- cgit v1.2.3