📄 volumes.c
字号:
TC_WAIT_EVENT (noOutstandingWorkItemEvent);
burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount);
TCfree (keyDerivationWorkItems);
#ifndef DEVICE_DRIVER
CloseHandle (keyDerivationCompletedEvent);
CloseHandle (noOutstandingWorkItemEvent);
#endif
}
return status;
}
#else // TC_WINDOWS_BOOT
int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo)
{
#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
char dk[32 * 2]; // 2 * 256-bit key
char masterKey[32 * 2];
#else
char dk[32 * 2 * 3]; // 6 * 256-bit key
char masterKey[32 * 2 * 3];
#endif
PCRYPTO_INFO cryptoInfo;
int status;
if (retHeaderCryptoInfo != NULL)
cryptoInfo = retHeaderCryptoInfo;
else
cryptoInfo = *retInfo = crypto_open ();
// PKCS5 PRF
derive_key_ripemd160 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET,
PKCS5_SALT_SIZE, bBoot ? 1000 : 2000, dk, sizeof (dk));
// Mode of operation
cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID;
// Test all available encryption algorithms
for (cryptoInfo->ea = EAGetFirst (); cryptoInfo->ea != 0; cryptoInfo->ea = EAGetNext (cryptoInfo->ea))
{
status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks);
if (status == ERR_CIPHER_INIT_FAILURE)
goto err;
// Secondary key schedule
EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2);
// Try to decrypt header
DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
// Check magic 'TRUE' and CRC-32 of header fields and master keydata
if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545
|| (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);
continue;
}
// 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);
memcpy (masterKey, header + HEADER_MASTER_KEYDATA_OFFSET, sizeof (masterKey));
EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
if (retHeaderCryptoInfo)
goto ret;
// Init the encryption algorithm with the decrypted master key
status = EAInit (cryptoInfo->ea, masterKey, cryptoInfo->ks);
if (status == ERR_CIPHER_INIT_FAILURE)
goto err;
// The secondary master key (if cascade, multiple concatenated)
EAInit (cryptoInfo->ea, masterKey + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2);
goto ret;
}
status = ERR_PASSWORD_WRONG;
err:
if (cryptoInfo != retHeaderCryptoInfo)
{
crypto_close(cryptoInfo);
*retInfo = NULL;
}
ret:
burn (dk, sizeof(dk));
burn (masterKey, sizeof(masterKey));
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 (BOOL bBoot, char *header, int ea, int mode, Password *password,
int pkcs5_prf, char *masterKeydata, PCRYPTO_INFO *retInfo,
unsigned __int64 volumeSize, unsigned __int64 hiddenVolumeSize,
unsigned __int64 encryptedAreaStart, unsigned __int64 encryptedAreaLength, uint16 requiredProgramVersion, uint32 headerFlags, BOOL bWipeMode)
{
unsigned char *p = (unsigned char *) header;
static 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;
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)
{
case LRW:
case CBC:
case INNER_CBC:
case OUTER_CBC:
// Deprecated/legacy modes of operation
bytesNeeded = LEGACY_VOL_IV_SIZE + EAGetKeySize (ea);
/* In fact, this should never be the case since new volumes are not supposed to use
any deprecated mode of operation. */
return ERR_VOL_FORMAT_BAD;
default:
bytesNeeded = EAGetKeySize (ea) * 2; // Size of primary + secondary key(s)
}
if (!RandgetBytes (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, bBoot);
// User selected encryption algorithm
cryptoInfo->ea = ea;
// Mode of operation
cryptoInfo->mode = mode;
// Salt for header key derivation
if (!RandgetBytes (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 SHA1:
// Deprecated/legacy
derive_key_sha1 (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, 0x54525545);
// Header version
switch (mode)
{
case LRW:
case CBC:
case OUTER_CBC:
case INNER_CBC:
// Deprecated/legacy modes (used before TrueCrypt 5.0)
mputWord (p, 0x0002);
break;
default:
mputWord (p, VOLUME_HEADER_VERSION);
}
// Required program version to handle this volume
switch (mode)
{
case LRW:
// Deprecated/legacy
mputWord (p, 0x0410);
break;
case OUTER_CBC:
case INNER_CBC:
// Deprecated/legacy
mputWord (p, 0x0300);
break;
case CBC:
// Deprecated/legacy
mputWord (p, hiddenVolumeSize > 0 ? 0x0300 : 0x0100);
break;
default:
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);
// 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)
{
case LRW:
case CBC:
case INNER_CBC:
case OUTER_CBC:
// For LRW (deprecated/legacy), the tweak key
// For CBC (deprecated/legacy), the IV/whitening seed
memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE);
primaryKeyOffset = LEGACY_VOL_IV_SIZE;
break;
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)
{
case LRW:
case CBC:
case INNER_CBC:
case OUTER_CBC:
// For LRW (deprecated/legacy), the tweak key
// For CBC (deprecated/legacy), the IV/whitening seed
memcpy (cryptoInfo->k2, keyInfo.master_keydata, LEGACY_VOL_IV_SIZE);
break;
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 (showKeys && !bInPlaceEncNonSys)
{
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++)
{
char tmp2[8] = {0};
sprintf (tmp2, "%02X", (int) (unsigned char) keyInfo.master_keydata[i + primaryKeyOffset]);
strcat (MasterKeyGUIView, tmp2);
}
if (dots3)
{
strcat (MasterKeyGUIView, "...");
}
SendMessage (hMasterKey, WM_SETTEXT, 0, (LPARAM) MasterKeyGUIView);
HeaderKeyGUIView[0] = 0;
for (i = 0; i < NBR_KEY_BYTES_TO_DISPLAY; i++)
{
char tmp2[8];
sprintf (tmp2, "%02X", (int) (unsigned char) dk[primaryKeyOffset + i]);
strcat (HeaderKeyGUIView, tmp2);
}
if (dots3)
{
strcat (HeaderKeyGUIView, "...");
}
SendMessage (hHeaderKey, WM_SETTEXT, 0, (LPARAM) HeaderKeyGUIView);
}
#endif // #ifdef VOLFORMAT
burn (dk, sizeof(dk));
burn (&keyInfo, sizeof (keyInfo));
*retInfo = cryptoInfo;
return 0;
}
// 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 (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 - TC_VOLUME_HEADER_EFFECTIVE_SIZE];
LARGE_INTEGER offset;
int nStatus = ERR_SUCCESS;
DWORD dwError;
BOOL backupHeaders = bBackupOnly;
if (bPrimaryOnly && bBackupOnly)
TC_THROW_FATAL_EXCEPTION;
memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2));
while (TRUE)
{
// Temporary keys
if (!RandgetBytes (temporaryKey, EAGetKeySize (cryptoInfo->ea), TRUE)
|| !RandgetBytes (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;
offset.QuadPart += TC_VOLUME_HEADER_EFFECTIVE_SIZE;
if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN))
{
nStatus = ERR_OS_ERROR;
goto final_seq;
}
EncryptBuffer (buf, sizeof (buf), cryptoInfo);
if (_lwrite ((HFILE) dev, buf, sizeof (buf)) == HFILE_ERROR)
{
nStatus = ERR_OS_ERROR;
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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -