www.pudn.com > truecrypt.zip > VOLUMES.C
/* Copyright (C) 2004 TrueCrypt Team, truecrypt.org This product uses components written by Paul Le Roux*/ #include "TCdefs.h" #include #include #include #include #include #include "crypto.h" #include "random.h" #include "endian.h" #include "fat.h" #include "volumes.h" #include "pkcs5.h" #include "crc.h" void _cdecl EncryptSector8 (unsigned long *data, unsigned __int64 secNo, unsigned long noSectors, unsigned char *ks, unsigned char *iv, int cipher) { unsigned long sectorIV[2]; unsigned long *IV = (unsigned long *) iv; unsigned __int64 *IV64 = (unsigned __int64 *) iv; unsigned long x1, x2; unsigned long j; while (noSectors--) { // Sector encryption is implemented by making IV unique for each // sector and obfuscating cipher text IV64[0] ^= secNo; IV64[1] ^= secNo; IV64[2] ^= secNo; sectorIV[0] = IV[0]; sectorIV[1] = IV[1]; x1 = crc32long ( &IV[2] ) ^ crc32long ( &IV[5] ); x2 = crc32long ( &IV[3] ) ^ crc32long ( &IV[4] ); IV64[0] ^= secNo; IV64[1] ^= secNo; IV64[2] ^= secNo; // CBC encrypt the entire sector for (j = 0; j < 64; j++) { // CBC data[0] ^= sectorIV[0]; data[1] ^= sectorIV[1]; encipher_block (cipher, data, ks); sectorIV[0] = data[0]; sectorIV[1] = data[1]; // Cipher text XOR data[0] ^= x1; data[1] ^= x2; data += 2; } secNo++; } } void _cdecl DecryptSector8 (unsigned long *data, unsigned __int64 secNo, unsigned long noSectors, unsigned char *ks, unsigned char *iv, int cipher) { unsigned long sectorIV[2]; unsigned long *IV = (unsigned long *) iv; unsigned __int64 *IV64 = (unsigned __int64 *) iv; unsigned long x1, x2; int j; while (noSectors--) { IV64[0] ^= secNo; IV64[1] ^= secNo; IV64[2] ^= secNo; sectorIV[0] = IV[0]; sectorIV[1] = IV[1]; x1 = crc32long ( &IV[2] ) ^ crc32long ( &IV[5] ); x2 = crc32long ( &IV[3] ) ^ crc32long ( &IV[4] ); IV64[0] ^= secNo; IV64[1] ^= secNo; IV64[2] ^= secNo; // CBC decrypt the sector for (j = 0; j < 64; j++) { unsigned long a, b; // Cipher text XOR data[0] ^= x1; data[1] ^= x2; // CBC a = data[0]; b = data[1]; decipher_block (cipher, data, ks); data[0] ^= sectorIV[0]; data[1] ^= sectorIV[1]; sectorIV[0] = a; sectorIV[1] = b; data += 2; } secNo++; } } // EncryptBuffer // // Encrypts data in buffer // Returns number of bytes encrypted // // len = length of data in bytes int _cdecl EncryptBuffer (unsigned char *buf, unsigned long len, unsigned char *ks, unsigned char *iv, int cipher) { unsigned long *data = (unsigned long *) buf; unsigned long *IV = (unsigned long *) iv; unsigned long bufIV[2]; unsigned long j; len /= get_block_size (cipher); bufIV[0] = IV[0]; bufIV[1] = IV[1]; if (get_block_size (cipher) == 8) { /* CBC encrypt the buffer */ for (j = 0; j < len; j++) { // CBC data[0] ^= bufIV[0]; data[1] ^= bufIV[1]; encipher_block (cipher, data, ks); bufIV[0] = data[0]; bufIV[1] = data[1]; // Cipher text XOR data[0] ^= IV[2]; data[1] ^= IV[3]; data += 2; } } else return 0; return len; } // DecryptBuffer // // Decrypts data in buffer // Returns number of bytes encrypted // // len = length of data in bytes int _cdecl DecryptBuffer (unsigned char *buf, unsigned long len, unsigned char *ks, unsigned char *iv, int cipher) { unsigned long *data = (unsigned long *)buf; unsigned long *IV = (unsigned long *) iv; unsigned long bufIV[2]; unsigned long j; len /= get_block_size (cipher); bufIV[0] = IV[0]; bufIV[1] = IV[1]; if (get_block_size (cipher) == 8) { /* CBC encrypt the buffer */ for (j = 0; j < len; j++) { unsigned long a, b; // Cipher text XOR data[0] ^= IV[2]; data[1] ^= IV[3]; // CBC a = data[0]; b = data[1]; decipher_block (cipher, data, ks); data[0] ^= bufIV[0]; data[1] ^= bufIV[1]; bufIV[0] = a; bufIV[1] = b; data += 2; } } else return 0; return len; } // Volume header structure: // // Offset Length Description // ------------------------------------------ // Unencrypted: // 0 64 Key salt // Encrypted: // 64 4 Magic 'TRUE' // 68 2 Header version // 70 2 Required program version // 72 4 CRC32 of disk IV and key // 76 8 Volume creation time // 84 8 Header creation time // 92 164 unused // 256 32 Disk IV // 288 224 Disk key int VolumeReadHeader (char *encryptedHeader, char *lpszPassword, PCRYPTO_INFO * retInfo) { char header[SECTOR_SIZE]; unsigned char *input = (unsigned char *) header; KEY_INFO keyInfo; PCRYPTO_INFO cryptoInfo; int nStatus = 0, nKeyLen; char dk[DISKKEY_SIZE]; int pkcs5; int headerVersion, requiredVersion; cryptoInfo = *retInfo = crypto_open (); if (cryptoInfo == NULL) return ERR_OUTOFMEMORY; crypto_loadkey (&keyInfo, lpszPassword, strlen (lpszPassword)); // PKCS5 is used to derive header key and IV from user password memcpy (keyInfo.key_salt, encryptedHeader + HEADER_USERKEY_SALT, USERKEY_SALT_SIZE); keyInfo.noIterations = USERKEY_ITERATIONS; pkcs5 = SHA1; if (pkcs5 == SHA1) { derive_sha_key (keyInfo.userKey, keyInfo.keyLength, keyInfo.key_salt, USERKEY_SALT_SIZE, keyInfo.noIterations, dk, DISK_IV_SIZE + MAX_CIPHER_KEY); } // IV for header decryption memcpy (cryptoInfo->iv, dk, DISK_IV_SIZE); // Test all available ciphers for (cryptoInfo->cipher = 1; cryptoInfo->cipher <= LAST_CIPHER_ID; cryptoInfo->cipher++) { // Copy header for decryption memcpy (header, encryptedHeader, SECTOR_SIZE); input = header; // Try to decrypt header init_cipher (cryptoInfo->cipher, dk + DISK_IV_SIZE, cryptoInfo->ks); DecryptBuffer (header + HEADER_ENCRYPTEDDATA, HEADER_ENCRYPTEDDATASIZE, cryptoInfo->ks, cryptoInfo->iv, cryptoInfo->cipher); input += HEADER_ENCRYPTEDDATA; // Magic if (mgetLong (input) != 'TRUE') continue; // Header version headerVersion = mgetWord (input); // Required program version requiredVersion = mgetWord (input); // Check CRC of disk IV and key if (mgetLong (input) != crc32 (header + HEADER_DISKKEY, DISKKEY_SIZE)) continue; // Volume creation time ((unsigned long *)(&cryptoInfo->volume_creation_time))[1] = mgetLong (input); ((unsigned long *)(&cryptoInfo->volume_creation_time))[0] = mgetLong (input); // Header creation time ((unsigned long *)(&cryptoInfo->header_creation_time))[1] = mgetLong (input); ((unsigned long *)(&cryptoInfo->header_creation_time))[0] = mgetLong (input); // Password and cipher OK // Check the version required to handle this volume if (requiredVersion > VERSION_NUM) return ERR_NEW_VERSION_REQUIRED; // Disk key nKeyLen = DISKKEY_SIZE; memcpy (keyInfo.key, header + HEADER_DISKKEY, nKeyLen); memcpy (cryptoInfo->master_decrypted_key, keyInfo.key, nKeyLen); memcpy (cryptoInfo->key_salt, keyInfo.key_salt, USERKEY_SALT_SIZE); cryptoInfo->pkcs5 = pkcs5; cryptoInfo->noIterations = keyInfo.noIterations; // Init with decrypted master disk key for sector decryption init_cipher (cryptoInfo->cipher, keyInfo.key + DISK_IV_SIZE, cryptoInfo->ks); // Disk IV memcpy (cryptoInfo->iv, keyInfo.key, DISK_IV_SIZE); /* Clear out the temp. key buffer */ burn (dk, sizeof(dk)); cryptoInfo->encrypt_sector = &EncryptSector8; cryptoInfo->decrypt_sector = &DecryptSector8; return 0; } crypto_close(cryptoInfo); burn (&keyInfo, sizeof (keyInfo)); return ERR_PASSWORD_WRONG; } #ifndef DEVICE_DRIVER #ifdef VOLFORMAT extern HWND hDiskKey; extern HWND hKeySalt; #endif // VolumeWriteHeader: // Creates volume header in memory int VolumeWriteHeader (char *header, int cipher, char *lpszPassword, int pkcs5, char *masterKey, unsigned __int64 volumeCreationTime, PCRYPTO_INFO * retInfo ) { unsigned char *p = (unsigned char *) header; KEY_INFO keyInfo; int nUserKeyLen = strlen(lpszPassword); PCRYPTO_INFO cryptoInfo = crypto_open (); char dk[DISKKEY_SIZE]; int x; if (cryptoInfo == NULL) return ERR_OUTOFMEMORY; memset (header, 0, SECTOR_SIZE); //// Encryption setup // User key memcpy (keyInfo.userKey, lpszPassword, nUserKeyLen); keyInfo.keyLength = nUserKeyLen; keyInfo.noIterations = USERKEY_ITERATIONS; // User selected encryption algorithm cryptoInfo->cipher = cipher; // Salt for header key derivation RandgetBytes (keyInfo.key_salt, USERKEY_SALT_SIZE); // PKCS5 is used to derive header key and IV from user password if (pkcs5 == SHA1) { derive_sha_key (keyInfo.userKey, keyInfo.keyLength, keyInfo.key_salt, USERKEY_SALT_SIZE, keyInfo.noIterations, dk, DISK_IV_SIZE + MAX_CIPHER_KEY ); } // Generate disk key and IV if(masterKey == 0) RandgetBytes (keyInfo.key, DISKKEY_SIZE); else memcpy(keyInfo.key, masterKey, DISKKEY_SIZE); //// Header setup // Salt mputBytes (p, keyInfo.key_salt, USERKEY_SALT_SIZE); // Magic mputLong (p, 'TRUE'); // Header version mputWord (p, 0x0001); // Required program version to handle this volume mputWord (p, VOLUME_VERSION_NUM); // CRC of disk key x = crc32(keyInfo.key, DISKKEY_SIZE); mputLong (p, x); // Time { 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); // Password change time GetLocalTime (&st); SystemTimeToFileTime (&st, &ft); mputLong (p, ft.dwHighDateTime); mputLong (p, ft.dwLowDateTime); } // Disk key and IV memcpy (header + HEADER_DISKKEY, keyInfo.key, DISKKEY_SIZE); //// Header encryption memcpy (cryptoInfo->iv, dk, DISK_IV_SIZE); init_cipher (cryptoInfo->cipher, dk + DISK_IV_SIZE, cryptoInfo->ks); EncryptBuffer (header + HEADER_ENCRYPTEDDATA, HEADER_ENCRYPTEDDATASIZE, cryptoInfo->ks, cryptoInfo->iv, cryptoInfo->cipher); //// cryptoInfo setup for further use (disk format) // Init with master disk key for sector decryption init_cipher (cryptoInfo->cipher, keyInfo.key + DISK_IV_SIZE, cryptoInfo->ks); // Disk IV memcpy (cryptoInfo->iv, keyInfo.key, DISK_IV_SIZE); // Clear out the temp. key buffer burn (dk, sizeof(dk)); if (get_block_size(cipher) == 8) { cryptoInfo->encrypt_sector = &EncryptSector8; cryptoInfo->decrypt_sector = &DecryptSector8; } #ifdef VOLFORMAT { char tmp[64]; BOOL dots3 = FALSE; int i, j; j = get_key_size (cipher); if (j > 21) { dots3 = TRUE; j = 21; } 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 == TRUE) { strcat (tmp, "..."); } SetWindowText (hDiskKey, tmp); tmp[0] = 0; for (i = 0; i < 20; i++) { char tmp2[8]; sprintf (tmp2, "%02X", (int) (unsigned char) keyInfo.key_salt[i]); strcat (tmp, tmp2); } SetWindowText (hKeySalt, tmp); } #endif burn (&keyInfo, sizeof (keyInfo)); *retInfo = cryptoInfo; return 0; } #endif /* !NT4_DRIVER */