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/Volumes.c | 2540 +++++++++++++++++++++++++------------------------- 1 file changed, 1270 insertions(+), 1270 deletions(-) (limited to 'src/Common/Volumes.c') diff --git a/src/Common/Volumes.c b/src/Common/Volumes.c index 955c7e48..d2a54b5c 100644 --- a/src/Common/Volumes.c +++ b/src/Common/Volumes.c @@ -1,1270 +1,1270 @@ -/* - 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" - -#ifndef TC_WINDOWS_BOOT -#include -#include -#include -#include -#include "EncryptionThreadPool.h" -#endif - -#include -#include -#include - -#ifndef DEVICE_DRIVER -#include "Random.h" -#endif - -#include "Crc.h" -#include "Crypto.h" -#include "Endian.h" -#include "Volumes.h" -#include "Pkcs5.h" - -#ifdef _WIN32 -#include -#include "../Boot/Windows/BootCommon.h" -#endif - -/* Volume header v5 structure (used since TrueCrypt 7.0): */ -// -// Offset Length Description -// ------------------------------------------ -// Unencrypted: -// 0 64 Salt -// Encrypted: -// 64 4 ASCII string 'VERA' -// 68 2 Header version -// 70 2 Required program version -// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 -// 76 16 Reserved (must contain zeroes) -// 92 8 Size of hidden volume in bytes (0 = normal volume) -// 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes, valid if field 70 >= 0x600 or flag bit 0 == 1) -// 108 8 Byte offset of the start of the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) -// 116 8 Size of the encrypted area within the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) -// 124 4 Flags: bit 0 set = system encryption; bit 1 set = non-system in-place encryption, bits 2-31 are reserved (set to zero) -// 128 4 Sector size in bytes -// 132 120 Reserved (must contain zeroes) -// 252 4 CRC-32 checksum of the (decrypted) bytes 64-251 -// 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode) - - -/* Deprecated/legacy volume header v4 structure (used by TrueCrypt 6.x): */ -// -// Offset Length Description -// ------------------------------------------ -// Unencrypted: -// 0 64 Salt -// Encrypted: -// 64 4 ASCII string 'VERA' -// 68 2 Header version -// 70 2 Required program version -// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 -// 76 16 Reserved (must contain zeroes) -// 92 8 Size of hidden volume in bytes (0 = normal volume) -// 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes, valid if field 70 >= 0x600 or flag bit 0 == 1) -// 108 8 Byte offset of the start of the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) -// 116 8 Size of the encrypted area within the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) -// 124 4 Flags: bit 0 set = system encryption; bit 1 set = non-system in-place encryption, bits 2-31 are reserved -// 128 124 Reserved (must contain zeroes) -// 252 4 CRC-32 checksum of the (decrypted) bytes 64-251 -// 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode) - - -/* Deprecated/legacy volume header v3 structure (used by TrueCrypt 5.x): */ -// -// Offset Length Description -// ------------------------------------------ -// Unencrypted: -// 0 64 Salt -// Encrypted: -// 64 4 ASCII string 'VERA' -// 68 2 Header version -// 70 2 Required program version -// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 -// 76 8 Volume creation time -// 84 8 Header creation time -// 92 8 Size of hidden volume in bytes (0 = normal volume) -// 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes) -// 108 8 Start byte offset of the encrypted area of the volume -// 116 8 Size of the encrypted area of the volume in bytes -// 124 132 Reserved (must contain zeroes) -// 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode) - - -/* Deprecated/legacy volume header v2 structure (used before TrueCrypt 5.0): */ -// -// Offset Length Description -// ------------------------------------------ -// Unencrypted: -// 0 64 Salt -// Encrypted: -// 64 4 ASCII string 'VERA' -// 68 2 Header version -// 70 2 Required program version -// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 -// 76 8 Volume creation time -// 84 8 Header creation time -// 92 8 Size of hidden volume in bytes (0 = normal volume) -// 100 156 Reserved (must contain zeroes) -// 256 32 For LRW (deprecated/legacy), secondary key -// For CBC (deprecated/legacy), data used to generate IV and whitening values -// 288 224 Master key(s) - - - -uint16 GetHeaderField16 (byte *header, int offset) -{ - return BE16 (*(uint16 *) (header + offset)); -} - - -uint32 GetHeaderField32 (byte *header, int offset) -{ - return BE32 (*(uint32 *) (header + offset)); -} - - -UINT64_STRUCT GetHeaderField64 (byte *header, int offset) -{ - UINT64_STRUCT uint64Struct; - -#ifndef TC_NO_COMPILER_INT64 - uint64Struct.Value = BE64 (*(uint64 *) (header + offset)); -#else - uint64Struct.HighPart = BE32 (*(uint32 *) (header + offset)); - uint64Struct.LowPart = BE32 (*(uint32 *) (header + offset + 4)); -#endif - return uint64Struct; -} - - -#ifndef TC_WINDOWS_BOOT - -typedef struct -{ - char DerivedKey[MASTER_KEYDATA_SIZE]; - BOOL Free; - LONG KeyReady; - int Pkcs5Prf; -} KeyDerivationWorkItem; - - -BOOL ReadVolumeHeaderRecoveryMode = FALSE; - -int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, int selected_pkcs5_prf, int pim, BOOL truecryptMode, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo) -{ - char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; - CRYPTOPP_ALIGN_DATA(16) KEY_INFO keyInfo; - PCRYPTO_INFO cryptoInfo; - char dk[MASTER_KEYDATA_SIZE]; - int enqPkcs5Prf, pkcs5_prf; - uint16 headerVersion; - int status = ERR_PARAMETER_INCORRECT; - int primaryKeyOffset; - - TC_EVENT keyDerivationCompletedEvent; - TC_EVENT noOutstandingWorkItemEvent; - KeyDerivationWorkItem *keyDerivationWorkItems; - KeyDerivationWorkItem *item; - int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1; - size_t encryptionThreadCount = GetEncryptionThreadCount(); - size_t queuedWorkItems = 0; - LONG outstandingWorkItemCount = 0; - int i; - - // if no PIM specified, use default value - if (pim < 0) - pim = 0; - - if (truecryptMode) - { - // SHA-256 not supported in TrueCrypt mode - if (selected_pkcs5_prf == SHA256) - return ERR_PARAMETER_INCORRECT; - pkcs5PrfCount--; // don't count SHA-256 in case of TrueCrypt mode - } - - if (retHeaderCryptoInfo != NULL) - { - cryptoInfo = retHeaderCryptoInfo; - } - else - { - if (!retInfo) - return ERR_PARAMETER_INCORRECT; - - cryptoInfo = *retInfo = crypto_open (); - if (cryptoInfo == NULL) - return ERR_OUTOFMEMORY; - } - - /* use thread pool only if no PRF was specified */ - if ((selected_pkcs5_prf == 0) && (encryptionThreadCount > 1)) - { - keyDerivationWorkItems = TCalloc (sizeof (KeyDerivationWorkItem) * pkcs5PrfCount); - if (!keyDerivationWorkItems) - return ERR_OUTOFMEMORY; - - for (i = 0; i < pkcs5PrfCount; ++i) - keyDerivationWorkItems[i].Free = TRUE; - -#ifdef DEVICE_DRIVER - KeInitializeEvent (&keyDerivationCompletedEvent, SynchronizationEvent, FALSE); - KeInitializeEvent (&noOutstandingWorkItemEvent, SynchronizationEvent, TRUE); -#else - keyDerivationCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL); - if (!keyDerivationCompletedEvent) - { - TCfree (keyDerivationWorkItems); - return ERR_OUTOFMEMORY; - } - - noOutstandingWorkItemEvent = CreateEvent (NULL, FALSE, TRUE, NULL); - if (!noOutstandingWorkItemEvent) - { - CloseHandle (keyDerivationCompletedEvent); - TCfree (keyDerivationWorkItems); - return ERR_OUTOFMEMORY; - } -#endif - } - -#ifndef DEVICE_DRIVER - VirtualLock (&keyInfo, sizeof (keyInfo)); - VirtualLock (&dk, sizeof (dk)); -#endif - - crypto_loadkey (&keyInfo, password->Text, (int) password->Length); - - // PKCS5 is used to derive the primary header key(s) and secondary header key(s) (XTS mode) from the password - memcpy (keyInfo.salt, encryptedHeader + HEADER_SALT_OFFSET, PKCS5_SALT_SIZE); - - // Test all available PKCS5 PRFs - for (enqPkcs5Prf = FIRST_PRF_ID; enqPkcs5Prf <= LAST_PRF_ID || queuedWorkItems > 0; ++enqPkcs5Prf) - { - // if a PRF is specified, we skip all other PRFs - if (selected_pkcs5_prf != 0 && enqPkcs5Prf != selected_pkcs5_prf) - continue; - - // skip SHA-256 in case of TrueCrypt mode - if (truecryptMode && (enqPkcs5Prf == SHA256)) - continue; - - if ((selected_pkcs5_prf == 0) && (encryptionThreadCount > 1)) - { - // Enqueue key derivation on thread pool - if (queuedWorkItems < encryptionThreadCount && enqPkcs5Prf <= LAST_PRF_ID) - { - for (i = 0; i < pkcs5PrfCount; ++i) - { - item = &keyDerivationWorkItems[i]; - if (item->Free) - { - item->Free = FALSE; - item->KeyReady = FALSE; - item->Pkcs5Prf = enqPkcs5Prf; - - EncryptionThreadPoolBeginKeyDerivation (&keyDerivationCompletedEvent, &noOutstandingWorkItemEvent, - &item->KeyReady, &outstandingWorkItemCount, enqPkcs5Prf, keyInfo.userKey, - keyInfo.keyLength, keyInfo.salt, get_pkcs5_iteration_count (enqPkcs5Prf, pim, truecryptMode, bBoot), item->DerivedKey); - - ++queuedWorkItems; - break; - } - } - - if (enqPkcs5Prf < LAST_PRF_ID) - continue; - } - else - --enqPkcs5Prf; - - // Wait for completion of a key derivation - while (queuedWorkItems > 0) - { - for (i = 0; i < pkcs5PrfCount; ++i) - { - item = &keyDerivationWorkItems[i]; - if (!item->Free && InterlockedExchangeAdd (&item->KeyReady, 0) == TRUE) - { - pkcs5_prf = item->Pkcs5Prf; - keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, pim, truecryptMode, bBoot); - memcpy (dk, item->DerivedKey, sizeof (dk)); - - item->Free = TRUE; - --queuedWorkItems; - goto KeyReady; - } - } - - if (queuedWorkItems > 0) - TC_WAIT_EVENT (keyDerivationCompletedEvent); - } - continue; -KeyReady: ; - } - else - { - pkcs5_prf = enqPkcs5Prf; - keyInfo.noIterations = get_pkcs5_iteration_count (enqPkcs5Prf, pim, truecryptMode, bBoot); - - switch (pkcs5_prf) - { - case RIPEMD160: - derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, - PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); - break; - - case SHA512: - derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, - PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); - break; - - case WHIRLPOOL: - derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, - PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); - break; - - case SHA256: - derive_key_sha256 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, - PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); - break; - - default: - // Unknown/wrong ID - TC_THROW_FATAL_EXCEPTION; - } - } - - // Test all available modes of operation - for (cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID; - cryptoInfo->mode <= LAST_MODE_OF_OPERATION; - cryptoInfo->mode++) - { - switch (cryptoInfo->mode) - { - - default: - primaryKeyOffset = 0; - } - - // Test all available encryption algorithms - for (cryptoInfo->ea = EAGetFirst (); - cryptoInfo->ea != 0; - cryptoInfo->ea = EAGetNext (cryptoInfo->ea)) - { - int blockSize; - - if (!EAIsModeSupported (cryptoInfo->ea, cryptoInfo->mode)) - continue; // This encryption algorithm has never been available with this mode of operation - - blockSize = CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea)); - - status = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks); - if (status == ERR_CIPHER_INIT_FAILURE) - goto err; - - // Init objects related to the mode of operation - - if (cryptoInfo->mode == XTS) - { - // Copy the secondary key (if cascade, multiple concatenated) - memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); - - // Secondary key schedule - if (!EAInitMode (cryptoInfo)) - { - status = ERR_MODE_INIT_FAILED; - goto err; - } - } - else - { - continue; - } - - // Copy the header for decryption - memcpy (header, encryptedHeader, sizeof (header)); - - // Try to decrypt header - - DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); - - // Magic 'VERA' or 'TRUE' depending if we are in TrueCrypt mode or not - if ((truecryptMode && GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545) - || (!truecryptMode && GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x56455241) - ) - continue; - - // Header version - headerVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION); - - if (headerVersion > VOLUME_HEADER_VERSION) - { - status = ERR_NEW_VERSION_REQUIRED; - goto err; - } - - // Check CRC of the header fields - if (!ReadVolumeHeaderRecoveryMode - && headerVersion >= 4 - && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)) - continue; - - // Required program version - cryptoInfo->RequiredProgramVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_REQUIRED_VERSION); - if (truecryptMode) - { - if (cryptoInfo->RequiredProgramVersion < 0x600 || cryptoInfo->RequiredProgramVersion > 0x71a) - { - status = ERR_UNSUPPORTED_TRUECRYPT_FORMAT | (((int)cryptoInfo->RequiredProgramVersion) << 16); - goto err; - } - cryptoInfo->LegacyVolume = FALSE; - } - else - cryptoInfo->LegacyVolume = cryptoInfo->RequiredProgramVersion < 0x10b; - - // Check CRC of the key set - if (!ReadVolumeHeaderRecoveryMode - && GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE)) - continue; - - // Now we have the correct password, cipher, hash algorithm, and volume type - - // Check the version required to handle this volume - if (!truecryptMode && (cryptoInfo->RequiredProgramVersion > VERSION_NUM)) - { - status = ERR_NEW_VERSION_REQUIRED; - goto err; - } - - // Header version - cryptoInfo->HeaderVersion = headerVersion; - - // Volume creation time (legacy) - cryptoInfo->volume_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_CREATION_TIME).Value; - - // Header creation time (legacy) - cryptoInfo->header_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_MODIFICATION_TIME).Value; - - // Hidden volume size (if any) - cryptoInfo->hiddenVolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE).Value; - - // Hidden volume status - cryptoInfo->hiddenVolume = (cryptoInfo->hiddenVolumeSize != 0); - - // Volume size - cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE); - - // Encrypted area size and length - cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START); - cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH); - - // Flags - cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS); - - // Sector size - if (headerVersion >= 5) - cryptoInfo->SectorSize = GetHeaderField32 (header, TC_HEADER_OFFSET_SECTOR_SIZE); - else - cryptoInfo->SectorSize = TC_SECTOR_SIZE_LEGACY; - - if (cryptoInfo->SectorSize < TC_MIN_VOLUME_SECTOR_SIZE - || cryptoInfo->SectorSize > TC_MAX_VOLUME_SECTOR_SIZE - || cryptoInfo->SectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) - { - status = ERR_PARAMETER_INCORRECT; - goto err; - } - - // Preserve scheduled header keys if requested - if (retHeaderCryptoInfo) - { - if (retInfo == NULL) - { - cryptoInfo->pkcs5 = pkcs5_prf; - cryptoInfo->noIterations = keyInfo.noIterations; - cryptoInfo->bTrueCryptMode = truecryptMode; - cryptoInfo->volumePim = pim; - goto ret; - } - - cryptoInfo = *retInfo = crypto_open (); - if (cryptoInfo == NULL) - { - status = ERR_OUTOFMEMORY; - goto err; - } - - memcpy (cryptoInfo, retHeaderCryptoInfo, sizeof (*cryptoInfo)); - } - - // Master key data - memcpy (keyInfo.master_keydata, header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE); - memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); - - // PKCS #5 - memcpy (cryptoInfo->salt, keyInfo.salt, PKCS5_SALT_SIZE); - cryptoInfo->pkcs5 = pkcs5_prf; - cryptoInfo->noIterations = keyInfo.noIterations; - cryptoInfo->bTrueCryptMode = truecryptMode; - cryptoInfo->volumePim = pim; - - // Init the cipher with the decrypted master key - status = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks); - if (status == ERR_CIPHER_INIT_FAILURE) - goto err; - - switch (cryptoInfo->mode) - { - - default: - // The secondary master key (if cascade, multiple concatenated) - memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); - - } - - if (!EAInitMode (cryptoInfo)) - { - status = ERR_MODE_INIT_FAILED; - goto err; - } - - status = ERR_SUCCESS; - goto ret; - } - } - } - status = ERR_PASSWORD_WRONG; - -err: - if (cryptoInfo != retHeaderCryptoInfo) - { - crypto_close(cryptoInfo); - *retInfo = NULL; - } - -ret: - burn (&keyInfo, sizeof (keyInfo)); - burn (dk, sizeof(dk)); - -#ifndef DEVICE_DRIVER - VirtualUnlock (&keyInfo, sizeof (keyInfo)); - VirtualUnlock (&dk, sizeof (dk)); -#endif - - if ((selected_pkcs5_prf == 0) && (encryptionThreadCount > 1)) - { - TC_WAIT_EVENT (noOutstandingWorkItemEvent); - - burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount); - TCfree (keyDerivationWorkItems); - -#ifndef DEVICE_DRIVER - CloseHandle (keyDerivationCompletedEvent); - CloseHandle (noOutstandingWorkItemEvent); -#endif - } - - return status; -} - -#ifdef _WIN32 -void ComputeBootloaderFingerprint (byte *bootLoaderBuf, unsigned int bootLoaderSize, byte* fingerprint) -{ - // compute Whirlpool+SHA512 fingerprint of bootloader including MBR - // we skip user configuration fields: - // TC_BOOT_SECTOR_PIM_VALUE_OFFSET = 400 - // TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET = 402 - // => TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE = 4 - // TC_BOOT_SECTOR_USER_MESSAGE_OFFSET = 406 - // => TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH = 24 - // TC_BOOT_SECTOR_USER_CONFIG_OFFSET = 438 - // - // we have: TC_BOOT_SECTOR_USER_MESSAGE_OFFSET = TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE - - WHIRLPOOL_CTX whirlpool; - sha512_ctx sha2; - - WHIRLPOOL_init (&whirlpool); - sha512_begin (&sha2); - - WHIRLPOOL_add (bootLoaderBuf, TC_BOOT_SECTOR_PIM_VALUE_OFFSET * 8, &whirlpool); - sha512_hash (bootLoaderBuf, TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &sha2); - - WHIRLPOOL_add (bootLoaderBuf + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)) * 8, &whirlpool); - sha512_hash (bootLoaderBuf + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)), &sha2); - - WHIRLPOOL_add (bootLoaderBuf + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)) * 8, &whirlpool); - sha512_hash (bootLoaderBuf + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)), &sha2); - - WHIRLPOOL_add (bootLoaderBuf + TC_SECTOR_SIZE_BIOS, (bootLoaderSize - TC_SECTOR_SIZE_BIOS) * 8, &whirlpool); - sha512_hash (bootLoaderBuf + TC_SECTOR_SIZE_BIOS, (bootLoaderSize - TC_SECTOR_SIZE_BIOS), &sha2); - - WHIRLPOOL_finalize (&whirlpool, fingerprint); - sha512_end (&fingerprint [WHIRLPOOL_DIGESTSIZE], &sha2); -} -#endif - -#else // TC_WINDOWS_BOOT - -int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, int pim, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo) -{ -#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE - char dk[32 * 2]; // 2 * 256-bit key -#else - char dk[32 * 2 * 3]; // 6 * 256-bit key -#endif - - PCRYPTO_INFO cryptoInfo; - int status = ERR_SUCCESS; - uint32 iterations = pim; - iterations <<= 16; - iterations |= bBoot; - - if (retHeaderCryptoInfo != NULL) - cryptoInfo = retHeaderCryptoInfo; - else - cryptoInfo = *retInfo = crypto_open (); - - // PKCS5 PRF -#ifdef TC_WINDOWS_BOOT_SHA2 - derive_key_sha256 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET, - PKCS5_SALT_SIZE, iterations, dk, sizeof (dk)); -#else - derive_key_ripemd160 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET, - PKCS5_SALT_SIZE, iterations, dk, sizeof (dk)); -#endif - - // Mode of operation - cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID; - -#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE - cryptoInfo->ea = 1; -#else - // Test all available encryption algorithms - for (cryptoInfo->ea = EAGetFirst (); cryptoInfo->ea != 0; cryptoInfo->ea = EAGetNext (cryptoInfo->ea)) -#endif - { -#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE - #if defined (TC_WINDOWS_BOOT_SERPENT) - serpent_set_key (dk, cryptoInfo->ks); - #elif defined (TC_WINDOWS_BOOT_TWOFISH) - twofish_set_key ((TwofishInstance *) cryptoInfo->ks, (const u4byte *) dk); - #else - status = EAInit (dk, cryptoInfo->ks); - if (status == ERR_CIPHER_INIT_FAILURE) - goto err; - #endif -#else - status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks); - if (status == ERR_CIPHER_INIT_FAILURE) - goto err; -#endif - // Secondary key schedule -#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE - #if defined (TC_WINDOWS_BOOT_SERPENT) - serpent_set_key (dk + 32, cryptoInfo->ks2); - #elif defined (TC_WINDOWS_BOOT_TWOFISH) - twofish_set_key ((TwofishInstance *)cryptoInfo->ks2, (const u4byte *) (dk + 32)); - #else - EAInit (dk + 32, cryptoInfo->ks2); - #endif -#else - EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2); -#endif - - // Try to decrypt header - DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); - - // Check magic 'VERA' and CRC-32 of header fields and master keydata - if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x56455241 - || (GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION) >= 4 && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)) - || GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE)) - { - EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); -#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE - status = ERR_PASSWORD_WRONG; - goto err; -#else - continue; -#endif - } - - // Header decrypted - status = 0; - - // Hidden volume status - cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE); - cryptoInfo->hiddenVolume = (cryptoInfo->VolumeSize.LowPart != 0 || cryptoInfo->VolumeSize.HighPart != 0); - - // Volume size - cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE); - - // Encrypted area size and length - cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START); - cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH); - - // Flags - cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS); - -#ifdef TC_WINDOWS_BOOT_SHA2 - cryptoInfo->pkcs5 = SHA256; -#else - cryptoInfo->pkcs5 = RIPEMD160; -#endif - - memcpy (dk, header + HEADER_MASTER_KEYDATA_OFFSET, sizeof (dk)); - EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); - - if (retHeaderCryptoInfo) - goto ret; - - // Init the encryption algorithm with the decrypted master key -#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE - #if defined (TC_WINDOWS_BOOT_SERPENT) - serpent_set_key (dk, cryptoInfo->ks); - #elif defined (TC_WINDOWS_BOOT_TWOFISH) - twofish_set_key ((TwofishInstance *) cryptoInfo->ks, (const u4byte *) dk); - #else - status = EAInit (dk, cryptoInfo->ks); - if (status == ERR_CIPHER_INIT_FAILURE) - goto err; - #endif -#else - status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks); - if (status == ERR_CIPHER_INIT_FAILURE) - goto err; -#endif - - // The secondary master key (if cascade, multiple concatenated) -#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE - #if defined (TC_WINDOWS_BOOT_SERPENT) - serpent_set_key (dk + 32, cryptoInfo->ks2); - #elif defined (TC_WINDOWS_BOOT_TWOFISH) - twofish_set_key ((TwofishInstance *)cryptoInfo->ks2, (const u4byte *) (dk + 32)); - #else - EAInit (dk + 32, cryptoInfo->ks2); - #endif -#else - EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2); -#endif - goto ret; - } - - status = ERR_PASSWORD_WRONG; - -err: - if (cryptoInfo != retHeaderCryptoInfo) - { - crypto_close(cryptoInfo); - *retInfo = NULL; - } - -ret: - burn (dk, sizeof(dk)); - return status; -} - -#endif // TC_WINDOWS_BOOT - - -#if !defined (DEVICE_DRIVER) && !defined (TC_WINDOWS_BOOT) - -#ifdef VOLFORMAT -# include "../Format/TcFormat.h" -# include "Dlgcode.h" -#endif - -// Creates a volume header in memory -int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea, int mode, Password *password, - int pkcs5_prf, int pim, char *masterKeydata, PCRYPTO_INFO *retInfo, - unsigned __int64 volumeSize, unsigned __int64 hiddenVolumeSize, - unsigned __int64 encryptedAreaStart, unsigned __int64 encryptedAreaLength, uint16 requiredProgramVersion, uint32 headerFlags, uint32 sectorSize, BOOL bWipeMode) -{ - unsigned char *p = (unsigned char *) header; - static CRYPTOPP_ALIGN_DATA(16) KEY_INFO keyInfo; - - int nUserKeyLen = password->Length; - PCRYPTO_INFO cryptoInfo = crypto_open (); - static char dk[MASTER_KEYDATA_SIZE]; - int x; - int retVal = 0; - int primaryKeyOffset; - - if (cryptoInfo == NULL) - return ERR_OUTOFMEMORY; - - // if no PIM specified, use default value - if (pim < 0) - pim = 0; - - memset (header, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE); - - VirtualLock (&keyInfo, sizeof (keyInfo)); - VirtualLock (&dk, sizeof (dk)); - - /* Encryption setup */ - - if (masterKeydata == NULL) - { - // We have no master key data (creating a new volume) so we'll use the TrueCrypt RNG to generate them - - int bytesNeeded; - - switch (mode) - { - - default: - bytesNeeded = EAGetKeySize (ea) * 2; // Size of primary + secondary key(s) - } - - if (!RandgetBytes (hwndDlg, keyInfo.master_keydata, bytesNeeded, TRUE)) - return ERR_CIPHER_INIT_WEAK_KEY; - } - else - { - // We already have existing master key data (the header is being re-encrypted) - memcpy (keyInfo.master_keydata, masterKeydata, MASTER_KEYDATA_SIZE); - } - - // User key - memcpy (keyInfo.userKey, password->Text, nUserKeyLen); - keyInfo.keyLength = nUserKeyLen; - keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, pim, FALSE, bBoot); - - // User selected encryption algorithm - cryptoInfo->ea = ea; - - // User selected PRF - cryptoInfo->pkcs5 = pkcs5_prf; - cryptoInfo->bTrueCryptMode = FALSE; - cryptoInfo->noIterations = keyInfo.noIterations; - cryptoInfo->volumePim = pim; - - // Mode of operation - cryptoInfo->mode = mode; - - // Salt for header key derivation - if (!RandgetBytes (hwndDlg, keyInfo.salt, PKCS5_SALT_SIZE, !bWipeMode)) - return ERR_CIPHER_INIT_WEAK_KEY; - - // PBKDF2 (PKCS5) is used to derive primary header key(s) and secondary header key(s) (XTS) from the password/keyfiles - switch (pkcs5_prf) - { - case SHA512: - derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, - PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); - break; - - case SHA256: - derive_key_sha256 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, - PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); - break; - - case RIPEMD160: - derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, - PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); - break; - - case WHIRLPOOL: - derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, - PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); - break; - - default: - // Unknown/wrong ID - TC_THROW_FATAL_EXCEPTION; - } - - /* Header setup */ - - // Salt - mputBytes (p, keyInfo.salt, PKCS5_SALT_SIZE); - - // Magic - mputLong (p, 0x56455241); - - // Header version - mputWord (p, VOLUME_HEADER_VERSION); - cryptoInfo->HeaderVersion = VOLUME_HEADER_VERSION; - - // Required program version to handle this volume - mputWord (p, requiredProgramVersion != 0 ? requiredProgramVersion : TC_VOLUME_MIN_REQUIRED_PROGRAM_VERSION); - - // CRC of the master key data - x = GetCrc32(keyInfo.master_keydata, MASTER_KEYDATA_SIZE); - mputLong (p, x); - - // Reserved fields - p += 2 * 8; - - // Size of hidden volume (if any) - cryptoInfo->hiddenVolumeSize = hiddenVolumeSize; - mputInt64 (p, cryptoInfo->hiddenVolumeSize); - - cryptoInfo->hiddenVolume = cryptoInfo->hiddenVolumeSize != 0; - - // Volume size - cryptoInfo->VolumeSize.Value = volumeSize; - mputInt64 (p, volumeSize); - - // Encrypted area start - cryptoInfo->EncryptedAreaStart.Value = encryptedAreaStart; - mputInt64 (p, encryptedAreaStart); - - // Encrypted area size - cryptoInfo->EncryptedAreaLength.Value = encryptedAreaLength; - mputInt64 (p, encryptedAreaLength); - - // Flags - cryptoInfo->HeaderFlags = headerFlags; - mputLong (p, headerFlags); - - // Sector size - if (sectorSize < TC_MIN_VOLUME_SECTOR_SIZE - || sectorSize > TC_MAX_VOLUME_SECTOR_SIZE - || sectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) - { - TC_THROW_FATAL_EXCEPTION; - } - - cryptoInfo->SectorSize = sectorSize; - mputLong (p, sectorSize); - - // CRC of the header fields - x = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC); - p = header + TC_HEADER_OFFSET_HEADER_CRC; - mputLong (p, x); - - // The master key data - memcpy (header + HEADER_MASTER_KEYDATA_OFFSET, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); - - - /* Header encryption */ - - switch (mode) - { - - default: - // The secondary key (if cascade, multiple concatenated) - memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); - primaryKeyOffset = 0; - } - - retVal = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks); - if (retVal != ERR_SUCCESS) - return retVal; - - // Mode of operation - if (!EAInitMode (cryptoInfo)) - return ERR_OUTOFMEMORY; - - - // Encrypt the entire header (except the salt) - EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, - HEADER_ENCRYPTED_DATA_SIZE, - cryptoInfo); - - - /* cryptoInfo setup for further use (disk format) */ - - // Init with the master key(s) - retVal = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks); - if (retVal != ERR_SUCCESS) - return retVal; - - memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); - - switch (cryptoInfo->mode) - { - - default: - // The secondary master key (if cascade, multiple concatenated) - memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); - } - - // Mode of operation - if (!EAInitMode (cryptoInfo)) - return ERR_OUTOFMEMORY; - - -#ifdef VOLFORMAT - if (!bInPlaceEncNonSys && (showKeys || (bBoot && !masterKeydata))) - { - BOOL dots3 = FALSE; - int i, j; - - j = EAGetKeySize (ea); - - if (j > NBR_KEY_BYTES_TO_DISPLAY) - { - dots3 = TRUE; - j = NBR_KEY_BYTES_TO_DISPLAY; - } - - MasterKeyGUIView[0] = 0; - for (i = 0; i < j; i++) - { - wchar_t tmp2[8] = {0}; - StringCchPrintfW (tmp2, ARRAYSIZE(tmp2), L"%02X", (int) (unsigned char) keyInfo.master_keydata[i + primaryKeyOffset]); - StringCchCatW (MasterKeyGUIView, ARRAYSIZE(MasterKeyGUIView), tmp2); - } - - HeaderKeyGUIView[0] = 0; - for (i = 0; i < NBR_KEY_BYTES_TO_DISPLAY; i++) - { - wchar_t tmp2[8]; - StringCchPrintfW (tmp2, ARRAYSIZE(tmp2), L"%02X", (int) (unsigned char) dk[primaryKeyOffset + i]); - StringCchCatW (HeaderKeyGUIView, ARRAYSIZE(HeaderKeyGUIView), tmp2); - } - - if (dots3) - { - DisplayPortionsOfKeys (hHeaderKey, hMasterKey, HeaderKeyGUIView, MasterKeyGUIView, !showKeys); - } - else - { - SendMessage (hMasterKey, WM_SETTEXT, 0, (LPARAM) MasterKeyGUIView); - SendMessage (hHeaderKey, WM_SETTEXT, 0, (LPARAM) HeaderKeyGUIView); - } - } -#endif // #ifdef VOLFORMAT - - burn (dk, sizeof(dk)); - burn (&keyInfo, sizeof (keyInfo)); - - *retInfo = cryptoInfo; - return 0; -} - - -BOOL ReadEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header, DWORD *bytesRead) -{ -#if TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE -#error TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE -#endif - - byte sectorBuffer[TC_MAX_VOLUME_SECTOR_SIZE]; - DISK_GEOMETRY geometry; - - if (!device) - return ReadFile (fileHandle, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, bytesRead, NULL); - - if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry), bytesRead, NULL)) - return FALSE; - - if (geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) - { - SetLastError (ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (!ReadFile (fileHandle, sectorBuffer, max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, geometry.BytesPerSector), bytesRead, NULL)) - return FALSE; - - memcpy (header, sectorBuffer, min (*bytesRead, TC_VOLUME_HEADER_EFFECTIVE_SIZE)); - - if (*bytesRead > TC_VOLUME_HEADER_EFFECTIVE_SIZE) - *bytesRead = TC_VOLUME_HEADER_EFFECTIVE_SIZE; - - return TRUE; -} - - -BOOL WriteEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header) -{ -#if TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE -#error TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE -#endif - - byte sectorBuffer[TC_MAX_VOLUME_SECTOR_SIZE]; - DWORD bytesDone; - DISK_GEOMETRY geometry; - - if (!device) - { - if (!WriteFile (fileHandle, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &bytesDone, NULL)) - return FALSE; - - if (bytesDone != TC_VOLUME_HEADER_EFFECTIVE_SIZE) - { - SetLastError (ERROR_INVALID_PARAMETER); - return FALSE; - } - - return TRUE; - } - - if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry), &bytesDone, NULL)) - return FALSE; - - if (geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) - { - SetLastError (ERROR_INVALID_PARAMETER); - return FALSE; - } - - if (geometry.BytesPerSector != TC_VOLUME_HEADER_EFFECTIVE_SIZE) - { - LARGE_INTEGER seekOffset; - - if (!ReadFile (fileHandle, sectorBuffer, geometry.BytesPerSector, &bytesDone, NULL)) - return FALSE; - - if (bytesDone != geometry.BytesPerSector) - { - SetLastError (ERROR_INVALID_PARAMETER); - return FALSE; - } - - seekOffset.QuadPart = -(int) bytesDone; - if (!SetFilePointerEx (fileHandle, seekOffset, NULL, FILE_CURRENT)) - return FALSE; - } - - memcpy (sectorBuffer, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); - - if (!WriteFile (fileHandle, sectorBuffer, geometry.BytesPerSector, &bytesDone, NULL)) - return FALSE; - - if (bytesDone != geometry.BytesPerSector) - { - SetLastError (ERROR_INVALID_PARAMETER); - return FALSE; - } - - return TRUE; -} - - -// Writes randomly generated data to unused/reserved header areas. -// When bPrimaryOnly is TRUE, then only the primary header area (not the backup header area) is filled with random data. -// When bBackupOnly is TRUE, only the backup header area (not the primary header area) is filled with random data. -int WriteRandomDataToReservedHeaderAreas (HWND hwndDlg, HANDLE dev, CRYPTO_INFO *cryptoInfo, uint64 dataAreaSize, BOOL bPrimaryOnly, BOOL bBackupOnly) -{ - char temporaryKey[MASTER_KEYDATA_SIZE]; - char originalK2[MASTER_KEYDATA_SIZE]; - - byte buf[TC_VOLUME_HEADER_GROUP_SIZE]; - - LARGE_INTEGER offset; - int nStatus = ERR_SUCCESS; - DWORD dwError; - DWORD bytesDone; - BOOL backupHeaders = bBackupOnly; - - if (bPrimaryOnly && bBackupOnly) - TC_THROW_FATAL_EXCEPTION; - - memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2)); - - while (TRUE) - { - // Temporary keys - if (!RandgetBytes (hwndDlg, temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE) - || !RandgetBytes (hwndDlg, cryptoInfo->k2, sizeof (cryptoInfo->k2), FALSE)) - { - nStatus = ERR_PARAMETER_INCORRECT; - goto final_seq; - } - - nStatus = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks); - if (nStatus != ERR_SUCCESS) - goto final_seq; - - if (!EAInitMode (cryptoInfo)) - { - nStatus = ERR_MODE_INIT_FAILED; - goto final_seq; - } - - offset.QuadPart = backupHeaders ? dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET; - - if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) - { - nStatus = ERR_OS_ERROR; - goto final_seq; - } - - if (!ReadFile (dev, buf, sizeof (buf), &bytesDone, NULL)) - { - nStatus = ERR_OS_ERROR; - goto final_seq; - } - - if (bytesDone < TC_VOLUME_HEADER_EFFECTIVE_SIZE) - { - SetLastError (ERROR_INVALID_PARAMETER); - nStatus = ERR_OS_ERROR; - goto final_seq; - } - - EncryptBuffer (buf + TC_VOLUME_HEADER_EFFECTIVE_SIZE, sizeof (buf) - TC_VOLUME_HEADER_EFFECTIVE_SIZE, cryptoInfo); - - if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) - { - nStatus = ERR_OS_ERROR; - goto final_seq; - } - - if (!WriteFile (dev, buf, sizeof (buf), &bytesDone, NULL)) - { - nStatus = ERR_OS_ERROR; - goto final_seq; - } - - if (bytesDone != sizeof (buf)) - { - nStatus = ERR_PARAMETER_INCORRECT; - goto final_seq; - } - - if (backupHeaders || bPrimaryOnly) - break; - - backupHeaders = TRUE; - } - - memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2)); - - nStatus = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks); - if (nStatus != ERR_SUCCESS) - goto final_seq; - - if (!EAInitMode (cryptoInfo)) - { - nStatus = ERR_MODE_INIT_FAILED; - goto final_seq; - } - -final_seq: - - dwError = GetLastError(); - - burn (temporaryKey, sizeof (temporaryKey)); - burn (originalK2, sizeof (originalK2)); - - if (nStatus != ERR_SUCCESS) - SetLastError (dwError); - - return nStatus; -} - -#endif // !defined (DEVICE_DRIVER) && !defined (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" + +#ifndef TC_WINDOWS_BOOT +#include +#include +#include +#include +#include "EncryptionThreadPool.h" +#endif + +#include +#include +#include + +#ifndef DEVICE_DRIVER +#include "Random.h" +#endif + +#include "Crc.h" +#include "Crypto.h" +#include "Endian.h" +#include "Volumes.h" +#include "Pkcs5.h" + +#ifdef _WIN32 +#include +#include "../Boot/Windows/BootCommon.h" +#endif + +/* Volume header v5 structure (used since TrueCrypt 7.0): */ +// +// Offset Length Description +// ------------------------------------------ +// Unencrypted: +// 0 64 Salt +// Encrypted: +// 64 4 ASCII string 'VERA' +// 68 2 Header version +// 70 2 Required program version +// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 +// 76 16 Reserved (must contain zeroes) +// 92 8 Size of hidden volume in bytes (0 = normal volume) +// 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes, valid if field 70 >= 0x600 or flag bit 0 == 1) +// 108 8 Byte offset of the start of the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) +// 116 8 Size of the encrypted area within the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) +// 124 4 Flags: bit 0 set = system encryption; bit 1 set = non-system in-place encryption, bits 2-31 are reserved (set to zero) +// 128 4 Sector size in bytes +// 132 120 Reserved (must contain zeroes) +// 252 4 CRC-32 checksum of the (decrypted) bytes 64-251 +// 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode) + + +/* Deprecated/legacy volume header v4 structure (used by TrueCrypt 6.x): */ +// +// Offset Length Description +// ------------------------------------------ +// Unencrypted: +// 0 64 Salt +// Encrypted: +// 64 4 ASCII string 'VERA' +// 68 2 Header version +// 70 2 Required program version +// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 +// 76 16 Reserved (must contain zeroes) +// 92 8 Size of hidden volume in bytes (0 = normal volume) +// 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes, valid if field 70 >= 0x600 or flag bit 0 == 1) +// 108 8 Byte offset of the start of the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) +// 116 8 Size of the encrypted area within the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) +// 124 4 Flags: bit 0 set = system encryption; bit 1 set = non-system in-place encryption, bits 2-31 are reserved +// 128 124 Reserved (must contain zeroes) +// 252 4 CRC-32 checksum of the (decrypted) bytes 64-251 +// 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode) + + +/* Deprecated/legacy volume header v3 structure (used by TrueCrypt 5.x): */ +// +// Offset Length Description +// ------------------------------------------ +// Unencrypted: +// 0 64 Salt +// Encrypted: +// 64 4 ASCII string 'VERA' +// 68 2 Header version +// 70 2 Required program version +// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 +// 76 8 Volume creation time +// 84 8 Header creation time +// 92 8 Size of hidden volume in bytes (0 = normal volume) +// 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes) +// 108 8 Start byte offset of the encrypted area of the volume +// 116 8 Size of the encrypted area of the volume in bytes +// 124 132 Reserved (must contain zeroes) +// 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode) + + +/* Deprecated/legacy volume header v2 structure (used before TrueCrypt 5.0): */ +// +// Offset Length Description +// ------------------------------------------ +// Unencrypted: +// 0 64 Salt +// Encrypted: +// 64 4 ASCII string 'VERA' +// 68 2 Header version +// 70 2 Required program version +// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 +// 76 8 Volume creation time +// 84 8 Header creation time +// 92 8 Size of hidden volume in bytes (0 = normal volume) +// 100 156 Reserved (must contain zeroes) +// 256 32 For LRW (deprecated/legacy), secondary key +// For CBC (deprecated/legacy), data used to generate IV and whitening values +// 288 224 Master key(s) + + + +uint16 GetHeaderField16 (byte *header, int offset) +{ + return BE16 (*(uint16 *) (header + offset)); +} + + +uint32 GetHeaderField32 (byte *header, int offset) +{ + return BE32 (*(uint32 *) (header + offset)); +} + + +UINT64_STRUCT GetHeaderField64 (byte *header, int offset) +{ + UINT64_STRUCT uint64Struct; + +#ifndef TC_NO_COMPILER_INT64 + uint64Struct.Value = BE64 (*(uint64 *) (header + offset)); +#else + uint64Struct.HighPart = BE32 (*(uint32 *) (header + offset)); + uint64Struct.LowPart = BE32 (*(uint32 *) (header + offset + 4)); +#endif + return uint64Struct; +} + + +#ifndef TC_WINDOWS_BOOT + +typedef struct +{ + char DerivedKey[MASTER_KEYDATA_SIZE]; + BOOL Free; + LONG KeyReady; + int Pkcs5Prf; +} KeyDerivationWorkItem; + + +BOOL ReadVolumeHeaderRecoveryMode = FALSE; + +int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, int selected_pkcs5_prf, int pim, BOOL truecryptMode, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo) +{ + char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; + CRYPTOPP_ALIGN_DATA(16) KEY_INFO keyInfo; + PCRYPTO_INFO cryptoInfo; + char dk[MASTER_KEYDATA_SIZE]; + int enqPkcs5Prf, pkcs5_prf; + uint16 headerVersion; + int status = ERR_PARAMETER_INCORRECT; + int primaryKeyOffset; + + TC_EVENT keyDerivationCompletedEvent; + TC_EVENT noOutstandingWorkItemEvent; + KeyDerivationWorkItem *keyDerivationWorkItems; + KeyDerivationWorkItem *item; + int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1; + size_t encryptionThreadCount = GetEncryptionThreadCount(); + size_t queuedWorkItems = 0; + LONG outstandingWorkItemCount = 0; + int i; + + // if no PIM specified, use default value + if (pim < 0) + pim = 0; + + if (truecryptMode) + { + // SHA-256 not supported in TrueCrypt mode + if (selected_pkcs5_prf == SHA256) + return ERR_PARAMETER_INCORRECT; + pkcs5PrfCount--; // don't count SHA-256 in case of TrueCrypt mode + } + + if (retHeaderCryptoInfo != NULL) + { + cryptoInfo = retHeaderCryptoInfo; + } + else + { + if (!retInfo) + return ERR_PARAMETER_INCORRECT; + + cryptoInfo = *retInfo = crypto_open (); + if (cryptoInfo == NULL) + return ERR_OUTOFMEMORY; + } + + /* use thread pool only if no PRF was specified */ + if ((selected_pkcs5_prf == 0) && (encryptionThreadCount > 1)) + { + keyDerivationWorkItems = TCalloc (sizeof (KeyDerivationWorkItem) * pkcs5PrfCount); + if (!keyDerivationWorkItems) + return ERR_OUTOFMEMORY; + + for (i = 0; i < pkcs5PrfCount; ++i) + keyDerivationWorkItems[i].Free = TRUE; + +#ifdef DEVICE_DRIVER + KeInitializeEvent (&keyDerivationCompletedEvent, SynchronizationEvent, FALSE); + KeInitializeEvent (&noOutstandingWorkItemEvent, SynchronizationEvent, TRUE); +#else + keyDerivationCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + if (!keyDerivationCompletedEvent) + { + TCfree (keyDerivationWorkItems); + return ERR_OUTOFMEMORY; + } + + noOutstandingWorkItemEvent = CreateEvent (NULL, FALSE, TRUE, NULL); + if (!noOutstandingWorkItemEvent) + { + CloseHandle (keyDerivationCompletedEvent); + TCfree (keyDerivationWorkItems); + return ERR_OUTOFMEMORY; + } +#endif + } + +#ifndef DEVICE_DRIVER + VirtualLock (&keyInfo, sizeof (keyInfo)); + VirtualLock (&dk, sizeof (dk)); +#endif + + crypto_loadkey (&keyInfo, password->Text, (int) password->Length); + + // PKCS5 is used to derive the primary header key(s) and secondary header key(s) (XTS mode) from the password + memcpy (keyInfo.salt, encryptedHeader + HEADER_SALT_OFFSET, PKCS5_SALT_SIZE); + + // Test all available PKCS5 PRFs + for (enqPkcs5Prf = FIRST_PRF_ID; enqPkcs5Prf <= LAST_PRF_ID || queuedWorkItems > 0; ++enqPkcs5Prf) + { + // if a PRF is specified, we skip all other PRFs + if (selected_pkcs5_prf != 0 && enqPkcs5Prf != selected_pkcs5_prf) + continue; + + // skip SHA-256 in case of TrueCrypt mode + if (truecryptMode && (enqPkcs5Prf == SHA256)) + continue; + + if ((selected_pkcs5_prf == 0) && (encryptionThreadCount > 1)) + { + // Enqueue key derivation on thread pool + if (queuedWorkItems < encryptionThreadCount && enqPkcs5Prf <= LAST_PRF_ID) + { + for (i = 0; i < pkcs5PrfCount; ++i) + { + item = &keyDerivationWorkItems[i]; + if (item->Free) + { + item->Free = FALSE; + item->KeyReady = FALSE; + item->Pkcs5Prf = enqPkcs5Prf; + + EncryptionThreadPoolBeginKeyDerivation (&keyDerivationCompletedEvent, &noOutstandingWorkItemEvent, + &item->KeyReady, &outstandingWorkItemCount, enqPkcs5Prf, keyInfo.userKey, + keyInfo.keyLength, keyInfo.salt, get_pkcs5_iteration_count (enqPkcs5Prf, pim, truecryptMode, bBoot), item->DerivedKey); + + ++queuedWorkItems; + break; + } + } + + if (enqPkcs5Prf < LAST_PRF_ID) + continue; + } + else + --enqPkcs5Prf; + + // Wait for completion of a key derivation + while (queuedWorkItems > 0) + { + for (i = 0; i < pkcs5PrfCount; ++i) + { + item = &keyDerivationWorkItems[i]; + if (!item->Free && InterlockedExchangeAdd (&item->KeyReady, 0) == TRUE) + { + pkcs5_prf = item->Pkcs5Prf; + keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, pim, truecryptMode, bBoot); + memcpy (dk, item->DerivedKey, sizeof (dk)); + + item->Free = TRUE; + --queuedWorkItems; + goto KeyReady; + } + } + + if (queuedWorkItems > 0) + TC_WAIT_EVENT (keyDerivationCompletedEvent); + } + continue; +KeyReady: ; + } + else + { + pkcs5_prf = enqPkcs5Prf; + keyInfo.noIterations = get_pkcs5_iteration_count (enqPkcs5Prf, pim, truecryptMode, bBoot); + + switch (pkcs5_prf) + { + case RIPEMD160: + derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case SHA512: + derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case WHIRLPOOL: + derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case SHA256: + derive_key_sha256 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } + } + + // Test all available modes of operation + for (cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID; + cryptoInfo->mode <= LAST_MODE_OF_OPERATION; + cryptoInfo->mode++) + { + switch (cryptoInfo->mode) + { + + default: + primaryKeyOffset = 0; + } + + // Test all available encryption algorithms + for (cryptoInfo->ea = EAGetFirst (); + cryptoInfo->ea != 0; + cryptoInfo->ea = EAGetNext (cryptoInfo->ea)) + { + int blockSize; + + if (!EAIsModeSupported (cryptoInfo->ea, cryptoInfo->mode)) + continue; // This encryption algorithm has never been available with this mode of operation + + blockSize = CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea)); + + status = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; + + // Init objects related to the mode of operation + + if (cryptoInfo->mode == XTS) + { + // Copy the secondary key (if cascade, multiple concatenated) + memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); + + // Secondary key schedule + if (!EAInitMode (cryptoInfo)) + { + status = ERR_MODE_INIT_FAILED; + goto err; + } + } + else + { + continue; + } + + // Copy the header for decryption + memcpy (header, encryptedHeader, sizeof (header)); + + // Try to decrypt header + + DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); + + // Magic 'VERA' or 'TRUE' depending if we are in TrueCrypt mode or not + if ((truecryptMode && GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545) + || (!truecryptMode && GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x56455241) + ) + continue; + + // Header version + headerVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION); + + if (headerVersion > VOLUME_HEADER_VERSION) + { + status = ERR_NEW_VERSION_REQUIRED; + goto err; + } + + // Check CRC of the header fields + if (!ReadVolumeHeaderRecoveryMode + && headerVersion >= 4 + && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)) + continue; + + // Required program version + cryptoInfo->RequiredProgramVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_REQUIRED_VERSION); + if (truecryptMode) + { + if (cryptoInfo->RequiredProgramVersion < 0x600 || cryptoInfo->RequiredProgramVersion > 0x71a) + { + status = ERR_UNSUPPORTED_TRUECRYPT_FORMAT | (((int)cryptoInfo->RequiredProgramVersion) << 16); + goto err; + } + cryptoInfo->LegacyVolume = FALSE; + } + else + cryptoInfo->LegacyVolume = cryptoInfo->RequiredProgramVersion < 0x10b; + + // Check CRC of the key set + if (!ReadVolumeHeaderRecoveryMode + && GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE)) + continue; + + // Now we have the correct password, cipher, hash algorithm, and volume type + + // Check the version required to handle this volume + if (!truecryptMode && (cryptoInfo->RequiredProgramVersion > VERSION_NUM)) + { + status = ERR_NEW_VERSION_REQUIRED; + goto err; + } + + // Header version + cryptoInfo->HeaderVersion = headerVersion; + + // Volume creation time (legacy) + cryptoInfo->volume_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_CREATION_TIME).Value; + + // Header creation time (legacy) + cryptoInfo->header_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_MODIFICATION_TIME).Value; + + // Hidden volume size (if any) + cryptoInfo->hiddenVolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE).Value; + + // Hidden volume status + cryptoInfo->hiddenVolume = (cryptoInfo->hiddenVolumeSize != 0); + + // Volume size + cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE); + + // Encrypted area size and length + cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START); + cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH); + + // Flags + cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS); + + // Sector size + if (headerVersion >= 5) + cryptoInfo->SectorSize = GetHeaderField32 (header, TC_HEADER_OFFSET_SECTOR_SIZE); + else + cryptoInfo->SectorSize = TC_SECTOR_SIZE_LEGACY; + + if (cryptoInfo->SectorSize < TC_MIN_VOLUME_SECTOR_SIZE + || cryptoInfo->SectorSize > TC_MAX_VOLUME_SECTOR_SIZE + || cryptoInfo->SectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) + { + status = ERR_PARAMETER_INCORRECT; + goto err; + } + + // Preserve scheduled header keys if requested + if (retHeaderCryptoInfo) + { + if (retInfo == NULL) + { + cryptoInfo->pkcs5 = pkcs5_prf; + cryptoInfo->noIterations = keyInfo.noIterations; + cryptoInfo->bTrueCryptMode = truecryptMode; + cryptoInfo->volumePim = pim; + goto ret; + } + + cryptoInfo = *retInfo = crypto_open (); + if (cryptoInfo == NULL) + { + status = ERR_OUTOFMEMORY; + goto err; + } + + memcpy (cryptoInfo, retHeaderCryptoInfo, sizeof (*cryptoInfo)); + } + + // Master key data + memcpy (keyInfo.master_keydata, header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE); + memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); + + // PKCS #5 + memcpy (cryptoInfo->salt, keyInfo.salt, PKCS5_SALT_SIZE); + cryptoInfo->pkcs5 = pkcs5_prf; + cryptoInfo->noIterations = keyInfo.noIterations; + cryptoInfo->bTrueCryptMode = truecryptMode; + cryptoInfo->volumePim = pim; + + // Init the cipher with the decrypted master key + status = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; + + switch (cryptoInfo->mode) + { + + default: + // The secondary master key (if cascade, multiple concatenated) + memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); + + } + + if (!EAInitMode (cryptoInfo)) + { + status = ERR_MODE_INIT_FAILED; + goto err; + } + + status = ERR_SUCCESS; + goto ret; + } + } + } + status = ERR_PASSWORD_WRONG; + +err: + if (cryptoInfo != retHeaderCryptoInfo) + { + crypto_close(cryptoInfo); + *retInfo = NULL; + } + +ret: + burn (&keyInfo, sizeof (keyInfo)); + burn (dk, sizeof(dk)); + +#ifndef DEVICE_DRIVER + VirtualUnlock (&keyInfo, sizeof (keyInfo)); + VirtualUnlock (&dk, sizeof (dk)); +#endif + + if ((selected_pkcs5_prf == 0) && (encryptionThreadCount > 1)) + { + TC_WAIT_EVENT (noOutstandingWorkItemEvent); + + burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount); + TCfree (keyDerivationWorkItems); + +#ifndef DEVICE_DRIVER + CloseHandle (keyDerivationCompletedEvent); + CloseHandle (noOutstandingWorkItemEvent); +#endif + } + + return status; +} + +#ifdef _WIN32 +void ComputeBootloaderFingerprint (byte *bootLoaderBuf, unsigned int bootLoaderSize, byte* fingerprint) +{ + // compute Whirlpool+SHA512 fingerprint of bootloader including MBR + // we skip user configuration fields: + // TC_BOOT_SECTOR_PIM_VALUE_OFFSET = 400 + // TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET = 402 + // => TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE = 4 + // TC_BOOT_SECTOR_USER_MESSAGE_OFFSET = 406 + // => TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH = 24 + // TC_BOOT_SECTOR_USER_CONFIG_OFFSET = 438 + // + // we have: TC_BOOT_SECTOR_USER_MESSAGE_OFFSET = TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE + + WHIRLPOOL_CTX whirlpool; + sha512_ctx sha2; + + WHIRLPOOL_init (&whirlpool); + sha512_begin (&sha2); + + WHIRLPOOL_add (bootLoaderBuf, TC_BOOT_SECTOR_PIM_VALUE_OFFSET * 8, &whirlpool); + sha512_hash (bootLoaderBuf, TC_BOOT_SECTOR_PIM_VALUE_OFFSET, &sha2); + + WHIRLPOOL_add (bootLoaderBuf + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)) * 8, &whirlpool); + sha512_hash (bootLoaderBuf + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH, (TC_BOOT_SECTOR_USER_CONFIG_OFFSET - (TC_BOOT_SECTOR_USER_MESSAGE_OFFSET + TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)), &sha2); + + WHIRLPOOL_add (bootLoaderBuf + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)) * 8, &whirlpool); + sha512_hash (bootLoaderBuf + TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1, (TC_MAX_MBR_BOOT_CODE_SIZE - (TC_BOOT_SECTOR_USER_CONFIG_OFFSET + 1)), &sha2); + + WHIRLPOOL_add (bootLoaderBuf + TC_SECTOR_SIZE_BIOS, (bootLoaderSize - TC_SECTOR_SIZE_BIOS) * 8, &whirlpool); + sha512_hash (bootLoaderBuf + TC_SECTOR_SIZE_BIOS, (bootLoaderSize - TC_SECTOR_SIZE_BIOS), &sha2); + + WHIRLPOOL_finalize (&whirlpool, fingerprint); + sha512_end (&fingerprint [WHIRLPOOL_DIGESTSIZE], &sha2); +} +#endif + +#else // TC_WINDOWS_BOOT + +int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, int pim, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo) +{ +#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + char dk[32 * 2]; // 2 * 256-bit key +#else + char dk[32 * 2 * 3]; // 6 * 256-bit key +#endif + + PCRYPTO_INFO cryptoInfo; + int status = ERR_SUCCESS; + uint32 iterations = pim; + iterations <<= 16; + iterations |= bBoot; + + if (retHeaderCryptoInfo != NULL) + cryptoInfo = retHeaderCryptoInfo; + else + cryptoInfo = *retInfo = crypto_open (); + + // PKCS5 PRF +#ifdef TC_WINDOWS_BOOT_SHA2 + derive_key_sha256 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET, + PKCS5_SALT_SIZE, iterations, dk, sizeof (dk)); +#else + derive_key_ripemd160 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET, + PKCS5_SALT_SIZE, iterations, dk, sizeof (dk)); +#endif + + // Mode of operation + cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID; + +#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + cryptoInfo->ea = 1; +#else + // Test all available encryption algorithms + for (cryptoInfo->ea = EAGetFirst (); cryptoInfo->ea != 0; cryptoInfo->ea = EAGetNext (cryptoInfo->ea)) +#endif + { +#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + #if defined (TC_WINDOWS_BOOT_SERPENT) + serpent_set_key (dk, cryptoInfo->ks); + #elif defined (TC_WINDOWS_BOOT_TWOFISH) + twofish_set_key ((TwofishInstance *) cryptoInfo->ks, (const u4byte *) dk); + #else + status = EAInit (dk, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; + #endif +#else + status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; +#endif + // Secondary key schedule +#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + #if defined (TC_WINDOWS_BOOT_SERPENT) + serpent_set_key (dk + 32, cryptoInfo->ks2); + #elif defined (TC_WINDOWS_BOOT_TWOFISH) + twofish_set_key ((TwofishInstance *)cryptoInfo->ks2, (const u4byte *) (dk + 32)); + #else + EAInit (dk + 32, cryptoInfo->ks2); + #endif +#else + EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2); +#endif + + // Try to decrypt header + DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); + + // Check magic 'VERA' and CRC-32 of header fields and master keydata + if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x56455241 + || (GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION) >= 4 && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)) + || GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE)) + { + EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); +#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + status = ERR_PASSWORD_WRONG; + goto err; +#else + continue; +#endif + } + + // Header decrypted + status = 0; + + // Hidden volume status + cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE); + cryptoInfo->hiddenVolume = (cryptoInfo->VolumeSize.LowPart != 0 || cryptoInfo->VolumeSize.HighPart != 0); + + // Volume size + cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE); + + // Encrypted area size and length + cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START); + cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH); + + // Flags + cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS); + +#ifdef TC_WINDOWS_BOOT_SHA2 + cryptoInfo->pkcs5 = SHA256; +#else + cryptoInfo->pkcs5 = RIPEMD160; +#endif + + memcpy (dk, header + HEADER_MASTER_KEYDATA_OFFSET, sizeof (dk)); + EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); + + if (retHeaderCryptoInfo) + goto ret; + + // Init the encryption algorithm with the decrypted master key +#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + #if defined (TC_WINDOWS_BOOT_SERPENT) + serpent_set_key (dk, cryptoInfo->ks); + #elif defined (TC_WINDOWS_BOOT_TWOFISH) + twofish_set_key ((TwofishInstance *) cryptoInfo->ks, (const u4byte *) dk); + #else + status = EAInit (dk, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; + #endif +#else + status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; +#endif + + // The secondary master key (if cascade, multiple concatenated) +#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + #if defined (TC_WINDOWS_BOOT_SERPENT) + serpent_set_key (dk + 32, cryptoInfo->ks2); + #elif defined (TC_WINDOWS_BOOT_TWOFISH) + twofish_set_key ((TwofishInstance *)cryptoInfo->ks2, (const u4byte *) (dk + 32)); + #else + EAInit (dk + 32, cryptoInfo->ks2); + #endif +#else + EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2); +#endif + goto ret; + } + + status = ERR_PASSWORD_WRONG; + +err: + if (cryptoInfo != retHeaderCryptoInfo) + { + crypto_close(cryptoInfo); + *retInfo = NULL; + } + +ret: + burn (dk, sizeof(dk)); + return status; +} + +#endif // TC_WINDOWS_BOOT + + +#if !defined (DEVICE_DRIVER) && !defined (TC_WINDOWS_BOOT) + +#ifdef VOLFORMAT +# include "../Format/TcFormat.h" +# include "Dlgcode.h" +#endif + +// Creates a volume header in memory +int CreateVolumeHeaderInMemory (HWND hwndDlg, BOOL bBoot, char *header, int ea, int mode, Password *password, + int pkcs5_prf, int pim, char *masterKeydata, PCRYPTO_INFO *retInfo, + unsigned __int64 volumeSize, unsigned __int64 hiddenVolumeSize, + unsigned __int64 encryptedAreaStart, unsigned __int64 encryptedAreaLength, uint16 requiredProgramVersion, uint32 headerFlags, uint32 sectorSize, BOOL bWipeMode) +{ + unsigned char *p = (unsigned char *) header; + static CRYPTOPP_ALIGN_DATA(16) KEY_INFO keyInfo; + + int nUserKeyLen = password->Length; + PCRYPTO_INFO cryptoInfo = crypto_open (); + static char dk[MASTER_KEYDATA_SIZE]; + int x; + int retVal = 0; + int primaryKeyOffset; + + if (cryptoInfo == NULL) + return ERR_OUTOFMEMORY; + + // if no PIM specified, use default value + if (pim < 0) + pim = 0; + + memset (header, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE); + + VirtualLock (&keyInfo, sizeof (keyInfo)); + VirtualLock (&dk, sizeof (dk)); + + /* Encryption setup */ + + if (masterKeydata == NULL) + { + // We have no master key data (creating a new volume) so we'll use the TrueCrypt RNG to generate them + + int bytesNeeded; + + switch (mode) + { + + default: + bytesNeeded = EAGetKeySize (ea) * 2; // Size of primary + secondary key(s) + } + + if (!RandgetBytes (hwndDlg, keyInfo.master_keydata, bytesNeeded, TRUE)) + return ERR_CIPHER_INIT_WEAK_KEY; + } + else + { + // We already have existing master key data (the header is being re-encrypted) + memcpy (keyInfo.master_keydata, masterKeydata, MASTER_KEYDATA_SIZE); + } + + // User key + memcpy (keyInfo.userKey, password->Text, nUserKeyLen); + keyInfo.keyLength = nUserKeyLen; + keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, pim, FALSE, bBoot); + + // User selected encryption algorithm + cryptoInfo->ea = ea; + + // User selected PRF + cryptoInfo->pkcs5 = pkcs5_prf; + cryptoInfo->bTrueCryptMode = FALSE; + cryptoInfo->noIterations = keyInfo.noIterations; + cryptoInfo->volumePim = pim; + + // Mode of operation + cryptoInfo->mode = mode; + + // Salt for header key derivation + if (!RandgetBytes (hwndDlg, keyInfo.salt, PKCS5_SALT_SIZE, !bWipeMode)) + return ERR_CIPHER_INIT_WEAK_KEY; + + // PBKDF2 (PKCS5) is used to derive primary header key(s) and secondary header key(s) (XTS) from the password/keyfiles + switch (pkcs5_prf) + { + case SHA512: + derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case SHA256: + derive_key_sha256 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case RIPEMD160: + derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case WHIRLPOOL: + derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } + + /* Header setup */ + + // Salt + mputBytes (p, keyInfo.salt, PKCS5_SALT_SIZE); + + // Magic + mputLong (p, 0x56455241); + + // Header version + mputWord (p, VOLUME_HEADER_VERSION); + cryptoInfo->HeaderVersion = VOLUME_HEADER_VERSION; + + // Required program version to handle this volume + mputWord (p, requiredProgramVersion != 0 ? requiredProgramVersion : TC_VOLUME_MIN_REQUIRED_PROGRAM_VERSION); + + // CRC of the master key data + x = GetCrc32(keyInfo.master_keydata, MASTER_KEYDATA_SIZE); + mputLong (p, x); + + // Reserved fields + p += 2 * 8; + + // Size of hidden volume (if any) + cryptoInfo->hiddenVolumeSize = hiddenVolumeSize; + mputInt64 (p, cryptoInfo->hiddenVolumeSize); + + cryptoInfo->hiddenVolume = cryptoInfo->hiddenVolumeSize != 0; + + // Volume size + cryptoInfo->VolumeSize.Value = volumeSize; + mputInt64 (p, volumeSize); + + // Encrypted area start + cryptoInfo->EncryptedAreaStart.Value = encryptedAreaStart; + mputInt64 (p, encryptedAreaStart); + + // Encrypted area size + cryptoInfo->EncryptedAreaLength.Value = encryptedAreaLength; + mputInt64 (p, encryptedAreaLength); + + // Flags + cryptoInfo->HeaderFlags = headerFlags; + mputLong (p, headerFlags); + + // Sector size + if (sectorSize < TC_MIN_VOLUME_SECTOR_SIZE + || sectorSize > TC_MAX_VOLUME_SECTOR_SIZE + || sectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) + { + TC_THROW_FATAL_EXCEPTION; + } + + cryptoInfo->SectorSize = sectorSize; + mputLong (p, sectorSize); + + // CRC of the header fields + x = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC); + p = header + TC_HEADER_OFFSET_HEADER_CRC; + mputLong (p, x); + + // The master key data + memcpy (header + HEADER_MASTER_KEYDATA_OFFSET, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); + + + /* Header encryption */ + + switch (mode) + { + + default: + // The secondary key (if cascade, multiple concatenated) + memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); + primaryKeyOffset = 0; + } + + retVal = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks); + if (retVal != ERR_SUCCESS) + return retVal; + + // Mode of operation + if (!EAInitMode (cryptoInfo)) + return ERR_OUTOFMEMORY; + + + // Encrypt the entire header (except the salt) + EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, + HEADER_ENCRYPTED_DATA_SIZE, + cryptoInfo); + + + /* cryptoInfo setup for further use (disk format) */ + + // Init with the master key(s) + retVal = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks); + if (retVal != ERR_SUCCESS) + return retVal; + + memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); + + switch (cryptoInfo->mode) + { + + default: + // The secondary master key (if cascade, multiple concatenated) + memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); + } + + // Mode of operation + if (!EAInitMode (cryptoInfo)) + return ERR_OUTOFMEMORY; + + +#ifdef VOLFORMAT + if (!bInPlaceEncNonSys && (showKeys || (bBoot && !masterKeydata))) + { + BOOL dots3 = FALSE; + int i, j; + + j = EAGetKeySize (ea); + + if (j > NBR_KEY_BYTES_TO_DISPLAY) + { + dots3 = TRUE; + j = NBR_KEY_BYTES_TO_DISPLAY; + } + + MasterKeyGUIView[0] = 0; + for (i = 0; i < j; i++) + { + wchar_t tmp2[8] = {0}; + StringCchPrintfW (tmp2, ARRAYSIZE(tmp2), L"%02X", (int) (unsigned char) keyInfo.master_keydata[i + primaryKeyOffset]); + StringCchCatW (MasterKeyGUIView, ARRAYSIZE(MasterKeyGUIView), tmp2); + } + + HeaderKeyGUIView[0] = 0; + for (i = 0; i < NBR_KEY_BYTES_TO_DISPLAY; i++) + { + wchar_t tmp2[8]; + StringCchPrintfW (tmp2, ARRAYSIZE(tmp2), L"%02X", (int) (unsigned char) dk[primaryKeyOffset + i]); + StringCchCatW (HeaderKeyGUIView, ARRAYSIZE(HeaderKeyGUIView), tmp2); + } + + if (dots3) + { + DisplayPortionsOfKeys (hHeaderKey, hMasterKey, HeaderKeyGUIView, MasterKeyGUIView, !showKeys); + } + else + { + SendMessage (hMasterKey, WM_SETTEXT, 0, (LPARAM) MasterKeyGUIView); + SendMessage (hHeaderKey, WM_SETTEXT, 0, (LPARAM) HeaderKeyGUIView); + } + } +#endif // #ifdef VOLFORMAT + + burn (dk, sizeof(dk)); + burn (&keyInfo, sizeof (keyInfo)); + + *retInfo = cryptoInfo; + return 0; +} + + +BOOL ReadEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header, DWORD *bytesRead) +{ +#if TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE +#error TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE +#endif + + byte sectorBuffer[TC_MAX_VOLUME_SECTOR_SIZE]; + DISK_GEOMETRY geometry; + + if (!device) + return ReadFile (fileHandle, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, bytesRead, NULL); + + if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry), bytesRead, NULL)) + return FALSE; + + if (geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!ReadFile (fileHandle, sectorBuffer, max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, geometry.BytesPerSector), bytesRead, NULL)) + return FALSE; + + memcpy (header, sectorBuffer, min (*bytesRead, TC_VOLUME_HEADER_EFFECTIVE_SIZE)); + + if (*bytesRead > TC_VOLUME_HEADER_EFFECTIVE_SIZE) + *bytesRead = TC_VOLUME_HEADER_EFFECTIVE_SIZE; + + return TRUE; +} + + +BOOL WriteEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header) +{ +#if TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE +#error TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE +#endif + + byte sectorBuffer[TC_MAX_VOLUME_SECTOR_SIZE]; + DWORD bytesDone; + DISK_GEOMETRY geometry; + + if (!device) + { + if (!WriteFile (fileHandle, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &bytesDone, NULL)) + return FALSE; + + if (bytesDone != TC_VOLUME_HEADER_EFFECTIVE_SIZE) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + return TRUE; + } + + if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry), &bytesDone, NULL)) + return FALSE; + + if (geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (geometry.BytesPerSector != TC_VOLUME_HEADER_EFFECTIVE_SIZE) + { + LARGE_INTEGER seekOffset; + + if (!ReadFile (fileHandle, sectorBuffer, geometry.BytesPerSector, &bytesDone, NULL)) + return FALSE; + + if (bytesDone != geometry.BytesPerSector) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + seekOffset.QuadPart = -(int) bytesDone; + if (!SetFilePointerEx (fileHandle, seekOffset, NULL, FILE_CURRENT)) + return FALSE; + } + + memcpy (sectorBuffer, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); + + if (!WriteFile (fileHandle, sectorBuffer, geometry.BytesPerSector, &bytesDone, NULL)) + return FALSE; + + if (bytesDone != geometry.BytesPerSector) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + return TRUE; +} + + +// Writes randomly generated data to unused/reserved header areas. +// When bPrimaryOnly is TRUE, then only the primary header area (not the backup header area) is filled with random data. +// When bBackupOnly is TRUE, only the backup header area (not the primary header area) is filled with random data. +int WriteRandomDataToReservedHeaderAreas (HWND hwndDlg, HANDLE dev, CRYPTO_INFO *cryptoInfo, uint64 dataAreaSize, BOOL bPrimaryOnly, BOOL bBackupOnly) +{ + char temporaryKey[MASTER_KEYDATA_SIZE]; + char originalK2[MASTER_KEYDATA_SIZE]; + + byte buf[TC_VOLUME_HEADER_GROUP_SIZE]; + + LARGE_INTEGER offset; + int nStatus = ERR_SUCCESS; + DWORD dwError; + DWORD bytesDone; + BOOL backupHeaders = bBackupOnly; + + if (bPrimaryOnly && bBackupOnly) + TC_THROW_FATAL_EXCEPTION; + + memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2)); + + while (TRUE) + { + // Temporary keys + if (!RandgetBytes (hwndDlg, temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE) + || !RandgetBytes (hwndDlg, cryptoInfo->k2, sizeof (cryptoInfo->k2), FALSE)) + { + nStatus = ERR_PARAMETER_INCORRECT; + goto final_seq; + } + + nStatus = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks); + if (nStatus != ERR_SUCCESS) + goto final_seq; + + if (!EAInitMode (cryptoInfo)) + { + nStatus = ERR_MODE_INIT_FAILED; + goto final_seq; + } + + offset.QuadPart = backupHeaders ? dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET; + + if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) + { + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + if (!ReadFile (dev, buf, sizeof (buf), &bytesDone, NULL)) + { + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + if (bytesDone < TC_VOLUME_HEADER_EFFECTIVE_SIZE) + { + SetLastError (ERROR_INVALID_PARAMETER); + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + EncryptBuffer (buf + TC_VOLUME_HEADER_EFFECTIVE_SIZE, sizeof (buf) - TC_VOLUME_HEADER_EFFECTIVE_SIZE, cryptoInfo); + + if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) + { + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + if (!WriteFile (dev, buf, sizeof (buf), &bytesDone, NULL)) + { + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + if (bytesDone != sizeof (buf)) + { + nStatus = ERR_PARAMETER_INCORRECT; + goto final_seq; + } + + if (backupHeaders || bPrimaryOnly) + break; + + backupHeaders = TRUE; + } + + memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2)); + + nStatus = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks); + if (nStatus != ERR_SUCCESS) + goto final_seq; + + if (!EAInitMode (cryptoInfo)) + { + nStatus = ERR_MODE_INIT_FAILED; + goto final_seq; + } + +final_seq: + + dwError = GetLastError(); + + burn (temporaryKey, sizeof (temporaryKey)); + burn (originalK2, sizeof (originalK2)); + + if (nStatus != ERR_SUCCESS) + SetLastError (dwError); + + return nStatus; +} + +#endif // !defined (DEVICE_DRIVER) && !defined (TC_WINDOWS_BOOT) -- cgit v1.2.3