diff options
Diffstat (limited to 'src/Common/Crypto.c')
-rw-r--r-- | src/Common/Crypto.c | 2116 |
1 files changed, 1058 insertions, 1058 deletions
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 <string.h>
-#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 <string.h> +#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 |