www.pudn.com > truecrypt-4.2-source-code.zip > Volumes.c
/* Legal Notice: The source code contained in this file has been derived from the source code of Encryption for the Masses 2.02a, which is Copyright (c) 1998-99 Paul Le Roux and which is covered by the 'License Agreement for Encryption for the Masses'. Modifications and additions to that source code contained in this file are Copyright (c) 2004-2006 TrueCrypt Foundation and Copyright (c) 2004 TrueCrypt Team, and are covered by TrueCrypt License 2.0 the full text of which is contained in the file License.txt included in TrueCrypt binary and source code distribution archives. */ #include "Tcdefs.h" #include#include #include #include #ifdef _WIN32 #include #include "Random.h" #endif #include "Crypto.h" #include "Endian.h" #include "Volumes.h" #include "Pkcs5.h" #include "Crc.h" #define NBR_KEY_BYTES_TO_DISPLAY 16 // Volume header structure: // // Offset Length Description // ------------------------------------------ // Unencrypted: // 0 64 Salt // Encrypted: // 64 4 ASCII string 'TRUE' // 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 (set to zero) // 256 32 Secondary key (LRW mode) // 288 224 Master key(s) int VolumeReadHeader (char *encryptedHeader, Password *password, PCRYPTO_INFO *retInfo) { char header[HEADER_SIZE]; unsigned char *input = (unsigned char *) header; KEY_INFO keyInfo; PCRYPTO_INFO cryptoInfo; int nKeyLen; char dk[DISKKEY_SIZE]; int pkcs5; int headerVersion, requiredVersion; int status; cryptoInfo = *retInfo = crypto_open (); if (cryptoInfo == NULL) return ERR_OUTOFMEMORY; crypto_loadkey (&keyInfo, password->Text, password->Length); // PKCS5 is used to derive the header key and the secondary header key (LRW mode) from the user password memcpy (keyInfo.key_salt, encryptedHeader + HEADER_USERKEY_SALT, PKCS5_SALT_SIZE); // Test all available PKCS5 PRFs for (pkcs5 = 1; pkcs5 <= LAST_PRF_ID; pkcs5++) { BOOL lrw64InitDone = FALSE; BOOL lrw128InitDone = FALSE; keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5); switch (pkcs5) { case SHA1: derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.key_salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, DISK_IV_SIZE + EAGetLargestKey()); break; case RIPEMD160: derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.key_salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, DISK_IV_SIZE + EAGetLargestKey()); break; case WHIRLPOOL: derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.key_salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, DISK_IV_SIZE + EAGetLargestKey()); break; } // Test all available encryption algorithms for (cryptoInfo->ea = EAGetFirst (); cryptoInfo->ea != 0; cryptoInfo->ea = EAGetNext (cryptoInfo->ea)) { int blockSize = CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea)); status = EAInit (cryptoInfo->ea, dk + DISK_IV_SIZE, cryptoInfo->ks); if (status == ERR_CIPHER_INIT_FAILURE) goto err; // Test all available modes of operation for (cryptoInfo->mode = EAGetFirstMode (cryptoInfo->ea); cryptoInfo->mode != 0; cryptoInfo->mode = EAGetNextMode (cryptoInfo->ea, cryptoInfo->mode)) { // Copy header for decryption and init an encryption algorithm memcpy (header, encryptedHeader, SECTOR_SIZE); memcpy (cryptoInfo->iv, dk, DISK_IV_SIZE); if (cryptoInfo->mode == LRW && (blockSize == 8 && !lrw64InitDone || blockSize == 16 && !lrw128InitDone)) { if (!EAInitMode (cryptoInfo)) { status = ERR_MODE_INIT_FAILED; goto err; } if (blockSize == 8) lrw64InitDone = TRUE; else if (blockSize == 16) lrw128InitDone = TRUE; } input = header; // Try to decrypt header DecryptBuffer ((unsigned __int32 *) (header + HEADER_ENCRYPTEDDATA), HEADER_ENCRYPTEDDATASIZE, cryptoInfo); input += HEADER_ENCRYPTEDDATA; // Magic 'TRUE' if (mgetLong (input) != 0x54525545) continue; // Header version headerVersion = mgetWord (input); // Required program version requiredVersion = mgetWord (input); // Check CRC of the key set if (mgetLong (input) != crc32 (header + HEADER_DISKKEY, DISKKEY_SIZE)) continue; // Now we have the correct password, cipher, hash algorithm, and volume type // Check the version required to handle this volume if (requiredVersion > VERSION_NUM) { status = ERR_NEW_VERSION_REQUIRED; goto err; } // Volume creation time cryptoInfo->volume_creation_time = mgetInt64 (input); // Header creation time cryptoInfo->header_creation_time = mgetInt64 (input); // Hidden volume size (if any) cryptoInfo->hiddenVolumeSize = mgetInt64 (input); // Disk key nKeyLen = DISKKEY_SIZE; memcpy (keyInfo.key, header + HEADER_DISKKEY, nKeyLen); memcpy (cryptoInfo->master_key, keyInfo.key, nKeyLen); memcpy (cryptoInfo->key_salt, keyInfo.key_salt, PKCS5_SALT_SIZE); cryptoInfo->pkcs5 = pkcs5; cryptoInfo->noIterations = keyInfo.noIterations; // Init the encryption algorithm with the decrypted master key status = EAInit (cryptoInfo->ea, keyInfo.key + DISK_IV_SIZE, cryptoInfo->ks); if (status == ERR_CIPHER_INIT_FAILURE) goto err; // The secondary key (LRW mode) for the data area memcpy (cryptoInfo->iv, keyInfo.key, DISK_IV_SIZE); // Mode of operation if (!EAInitMode (cryptoInfo)) { status = ERR_MODE_INIT_FAILED; goto err; } // Clear out the temp. key buffers burn (dk, sizeof(dk)); return 0; } } } status = ERR_PASSWORD_WRONG; err: crypto_close(cryptoInfo); *retInfo = NULL; burn (&keyInfo, sizeof (keyInfo)); return status; } #ifndef DEVICE_DRIVER #ifdef VOLFORMAT extern BOOL showKeys; extern HWND hDiskKey; extern HWND hHeaderKey; #endif // VolumeWriteHeader: // Creates volume header in memory int VolumeWriteHeader (char *header, int ea, int mode, Password *password, int pkcs5, char *masterKey, unsigned __int64 volumeCreationTime, PCRYPTO_INFO * retInfo, unsigned __int64 hiddenVolumeSize, BOOL bWipeMode) { unsigned char *p = (unsigned char *) header; static KEY_INFO keyInfo; int nUserKeyLen = password->Length; PCRYPTO_INFO cryptoInfo = crypto_open (); static char dk[DISKKEY_SIZE]; int x; int retVal = 0; if (cryptoInfo == NULL) return ERR_OUTOFMEMORY; memset (header, 0, SECTOR_SIZE); #ifdef _WIN32 VirtualLock (&keyInfo, sizeof (keyInfo)); VirtualLock (&dk, sizeof (dk)); #endif /* Encryption setup */ // If necessary, generate the master key and the secondary key (LRW mode) if(masterKey == 0) { if (!RandgetBytes (keyInfo.key, DISK_IV_SIZE + EAGetKeySize (ea), TRUE)) return ERR_CIPHER_INIT_WEAK_KEY; // Verify that the secondary key is not weak if (DetectWeakSecondaryKey (keyInfo.key, CipherGetBlockSize (EAGetFirstCipher (ea)))) return ERR_CIPHER_INIT_WEAK_KEY; } else memcpy (keyInfo.key, masterKey, DISKKEY_SIZE); // User key memcpy (keyInfo.userKey, password->Text, nUserKeyLen); keyInfo.keyLength = nUserKeyLen; keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5); // User selected encryption algorithm cryptoInfo->ea = ea; // Mode of operation cryptoInfo->mode = mode; // Salt for header key derivation #ifdef _WIN32 if (!RandgetBytes (keyInfo.key_salt, PKCS5_SALT_SIZE, !bWipeMode)) return ERR_CIPHER_INIT_WEAK_KEY; #else if (!bWipeMode) { if (!RandgetBytes (keyInfo.key_salt, PKCS5_SALT_SIZE, FALSE)) return ERR_CIPHER_INIT_WEAK_KEY; } else { if (!RandpeekBytes (keyInfo.key_salt, PKCS5_SALT_SIZE)) return ERR_CIPHER_INIT_WEAK_KEY; } #endif // PKCS5 is used to derive the header key and the secondary header key (LRW mode) from the password switch (pkcs5) { case SHA1: derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.key_salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, DISK_IV_SIZE + EAGetLargestKey()); break; case RIPEMD160: derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.key_salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, DISK_IV_SIZE + EAGetLargestKey()); break; case WHIRLPOOL: derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.key_salt, PKCS5_SALT_SIZE, keyInfo.noIterations, dk, DISK_IV_SIZE + EAGetLargestKey()); break; } // Verify that the secondary key is not weak if (DetectWeakSecondaryKey (dk, CipherGetBlockSize (EAGetFirstCipher (ea)))) return ERR_CIPHER_INIT_WEAK_KEY; /* Header setup */ // Salt mputBytes (p, keyInfo.key_salt, PKCS5_SALT_SIZE); // Magic mputLong (p, 0x54525545); // Header version mputWord (p, VOLUME_HEADER_VERSION); // Required program version to handle this volume mputWord (p, VOL_REQ_PROG_VERSION); // CRC of the key set x = crc32(keyInfo.key, DISKKEY_SIZE); mputLong (p, x); // Time { #ifdef _WIN32 SYSTEMTIME st; FILETIME ft; // Volume creation time if (volumeCreationTime == 0) { GetLocalTime (&st); SystemTimeToFileTime (&st, &ft); } else { ft.dwHighDateTime = (DWORD)(volumeCreationTime >> 32); ft.dwLowDateTime = (DWORD)volumeCreationTime; } mputLong (p, ft.dwHighDateTime); mputLong (p, ft.dwLowDateTime); // Header modification time/date GetLocalTime (&st); SystemTimeToFileTime (&st, &ft); mputLong (p, ft.dwHighDateTime); mputLong (p, ft.dwLowDateTime); #else struct timeval tv; unsigned __int64 ct, wt; gettimeofday (&tv, NULL); // Unix time => Windows file time wt = ((unsigned __int64)tv.tv_sec + 134774LL * 24 * 3600) * 1000LL * 1000 * 10; if (volumeCreationTime == 0) ct = wt; else ct = volumeCreationTime; mputInt64 (p, ct); mputInt64 (p, wt); #endif } // Hidden volume size cryptoInfo->hiddenVolumeSize = hiddenVolumeSize; mputInt64 (p, cryptoInfo->hiddenVolumeSize); cryptoInfo->hiddenVolume = cryptoInfo->hiddenVolumeSize != 0; // The key set memcpy (header + HEADER_DISKKEY, keyInfo.key, DISKKEY_SIZE); /* Header encryption */ memcpy (cryptoInfo->iv, dk, DISK_IV_SIZE); retVal = EAInit (cryptoInfo->ea, dk + DISK_IV_SIZE, cryptoInfo->ks); if (retVal != 0) return retVal; // Mode of operation if (!EAInitMode (cryptoInfo)) return ERR_OUTOFMEMORY; EncryptBuffer ((unsigned __int32 *) (header + HEADER_ENCRYPTEDDATA), HEADER_ENCRYPTEDDATASIZE, cryptoInfo); /* cryptoInfo setup for further use (disk format) */ // Init with the master key retVal = EAInit (cryptoInfo->ea, keyInfo.key + DISK_IV_SIZE, cryptoInfo->ks); if (retVal != 0) return retVal; memcpy (cryptoInfo->master_key, keyInfo.key + DISK_IV_SIZE, sizeof (keyInfo.key) - DISK_IV_SIZE); // The secondary key (LRW mode) memcpy (cryptoInfo->iv, keyInfo.key, DISK_IV_SIZE); // Mode of operation if (!EAInitMode (cryptoInfo)) return ERR_OUTOFMEMORY; #ifdef VOLFORMAT if (showKeys) { char tmp[64]; BOOL dots3 = FALSE; int i, j; j = EAGetKeySize (ea); if (j > NBR_KEY_BYTES_TO_DISPLAY) { dots3 = TRUE; j = NBR_KEY_BYTES_TO_DISPLAY; } tmp[0] = 0; for (i = 0; i < j; i++) { char tmp2[8] = {0}; sprintf (tmp2, "%02X", (int) (unsigned char) keyInfo.key[i + DISK_IV_SIZE]); strcat (tmp, tmp2); } if (dots3) { strcat (tmp, "..."); } SetWindowText (hDiskKey, tmp); tmp[0] = 0; for (i = 0; i < NBR_KEY_BYTES_TO_DISPLAY; i++) { char tmp2[8]; sprintf (tmp2, "%02X", (int) (unsigned char) dk[DISK_IV_SIZE + i]); strcat (tmp, tmp2); } if (dots3) { strcat (tmp, "..."); } SetWindowText (hHeaderKey, tmp); } #endif burn (dk, sizeof(dk)); burn (&keyInfo, sizeof (keyInfo)); *retInfo = cryptoInfo; return 0; } #endif /* !NT4_DRIVER */