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; }
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); #elif defined (TC_WINDOWS_BOOT_CAMELLIA) camellia_set_key (dk, cryptoInfo->ks); #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)); #elif defined (TC_WINDOWS_BOOT_CAMELLIA) camellia_set_key (dk + 32, cryptoInfo->ks2); #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); #elif defined (TC_WINDOWS_BOOT_CAMELLIA) camellia_set_key (dk, cryptoInfo->ks); #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)); #elif defined (TC_WINDOWS_BOOT_CAMELLIA) camellia_set_key (dk + 32, cryptoInfo->ks2); #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; }
int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo) { char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; 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 (retHeaderCryptoInfo != NULL) { cryptoInfo = retHeaderCryptoInfo; } else { cryptoInfo = *retInfo = crypto_open (); if (cryptoInfo == NULL) return ERR_OUTOFMEMORY; } if (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) { BOOL lrw64InitDone = FALSE; // Deprecated/legacy BOOL lrw128InitDone = FALSE; // Deprecated/legacy if (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, 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, 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, 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 SHA1: // Deprecated/legacy derive_key_sha1 (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; } } // 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) { case LRW: case CBC: case INNER_CBC: case OUTER_CBC: // For LRW (deprecated/legacy), copy the tweak key // For CBC (deprecated/legacy), copy the IV/whitening seed memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE); primaryKeyOffset = LEGACY_VOL_IV_SIZE; break; 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 if (cryptoInfo->mode == LRW && (blockSize == 8 && !lrw64InitDone || blockSize == 16 && !lrw128InitDone)) { // Deprecated/legacy if (!EAInitMode (cryptoInfo)) { status = ERR_MODE_INIT_FAILED; goto err; } if (blockSize == 8) lrw64InitDone = TRUE; else if (blockSize == 16) lrw128InitDone = TRUE; } // 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 'TRUE' if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545) 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); cryptoInfo->LegacyVolume = cryptoInfo->RequiredProgramVersion < 0x600; // 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 (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; 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; // 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) { 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)); } 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 (encryptionThreadCount > 1) { TC_WAIT_EVENT (noOutstandingWorkItemEvent); burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount); TCfree (keyDerivationWorkItems); #ifndef DEVICE_DRIVER CloseHandle (keyDerivationCompletedEvent); CloseHandle (noOutstandingWorkItemEvent); #endif } return status; }
int cpu_Xts(int encryptionAlgorithm, char *encryptedHeader, char *headerKey, int headerKey_length, char *masterKey, int *masterKey_length) { BOOL ReadVolumeHeaderRecoveryMode = FALSE; char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; PCRYPTO_INFO cryptoInfo; uint16 headerVersion; int status = ERR_PARAMETER_INCORRECT; int primaryKeyOffset=0; CRYPTO_INFO cryptoInfo_struct; //int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1; int i,j; cryptoInfo=&cryptoInfo_struct; memset (cryptoInfo, 0, sizeof (CRYPTO_INFO)); if (cryptoInfo == NULL) return ERR_OUT_OF_MEMORY; // Support only XTS cryptoInfo->mode= XTS ; if(encryptionAlgorithm!=AES && encryptionAlgorithm!=SERPENT && encryptionAlgorithm!=TWOFISH) return ERR_CIPHER_INIT; cryptoInfo->ea=encryptionAlgorithm; status = cpu_EAInit (cryptoInfo->ea, headerKey + primaryKeyOffset, cryptoInfo->ks); if (status == ERR_CIPHER_INIT_FAILURE) return ERR_CIPHER_INIT; // Init objects related to the mode of operation // Copy the secondary key (if cascade, multiple concatenated) //memcpy (cryptoInfo->km2, headerKey + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); memcpy (cryptoInfo->km2, headerKey + 32, 32); // Secondary key schedule if (!cpu_EAInitMode (cryptoInfo)) { return ERR_MODE_INIT; } // Copy the header for decryption memcpy (header, encryptedHeader, 512*sizeof(unsigned char)); // Try to decrypt header cpu_DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); // Magic 'TRUE' if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545) return ERR_MAGIC_TRUE; // Header version headerVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION); if (headerVersion > VOLUME_HEADER_VERSION) { return ERR_VERSION_REQUIRED; } // 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)) return ERR_CRC_HEADER_FIELDS; // Required program version //cryptoInfo->RequiredProgramVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_REQUIRED_VERSION); //cryptoInfo->LegacyVolume = cryptoInfo->RequiredProgramVersion < 0x600; // 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)) return ERR_CRC_KEY_SET; /* // Now we have the correct password, cipher, hash algorithm, and volume type // Check the version required to handle this volume if (cryptoInfo->RequiredProgramVersion > VERSION_NUM){ return ERR_NEW_VERSION_REQUIRED; } // 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){ return ERR_PARAMETER_INCORRECT; } */ // Master key data if (masterKey!=NULL && masterKey_length!=NULL) { memcpy (masterKey, header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE); *masterKey_length= 64; } return SUCCESS; }