int FormatNoFs (HWND hwndDlg, unsigned __int64 startSector, __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat) { int write_buf_cnt = 0; char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf; unsigned __int64 nSecNo = startSector; int retVal = 0; DWORD err; char temporaryKey[MASTER_KEYDATA_SIZE]; char originalK2[MASTER_KEYDATA_SIZE]; LARGE_INTEGER startOffset; LARGE_INTEGER newOffset; // Seek to start sector startOffset.QuadPart = startSector * FormatSectorSize; if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN) || newOffset.QuadPart != startOffset.QuadPart) { return ERR_OS_ERROR; } write_buf = (char *)TCalloc (FormatWriteBufferSize); if (!write_buf) return ERR_OUTOFMEMORY; VirtualLock (temporaryKey, sizeof (temporaryKey)); VirtualLock (originalK2, sizeof (originalK2)); memset (sector, 0, sizeof (sector)); // Remember the original secondary key (XTS mode) before generating a temporary one memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2)); /* Fill the rest of the data area with random data */ if(!quickFormat) { /* Generate a random temporary key set to be used for "dummy" encryption that will fill the free disk space (data area) with random data. This is necessary for plausible deniability of hidden volumes. */ // Temporary master key if (!RandgetBytes (hwndDlg, temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE)) goto fail; // Temporary secondary key (XTS mode) if (!RandgetBytes (hwndDlg, cryptoInfo->k2, sizeof cryptoInfo->k2, FALSE)) goto fail; retVal = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks); if (retVal != ERR_SUCCESS) goto fail; if (!EAInitMode (cryptoInfo)) { retVal = ERR_MODE_INIT_FAILED; goto fail; } while (num_sectors--) { if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo) == FALSE) goto fail; } if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo)) goto fail; } else nSecNo = num_sectors; UpdateProgressBar (nSecNo * FormatSectorSize); // Restore the original secondary key (XTS mode) in case NTFS format fails and the user wants to try FAT immediately memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2)); // Reinitialize the encryption algorithm and mode in case NTFS format fails and the user wants to try FAT immediately retVal = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks); if (retVal != ERR_SUCCESS) goto fail; if (!EAInitMode (cryptoInfo)) { retVal = ERR_MODE_INIT_FAILED; goto fail; } burn (temporaryKey, sizeof(temporaryKey)); burn (originalK2, sizeof(originalK2)); VirtualUnlock (temporaryKey, sizeof (temporaryKey)); VirtualUnlock (originalK2, sizeof (originalK2)); TCfree (write_buf); return 0; fail: err = GetLastError(); burn (temporaryKey, sizeof(temporaryKey)); burn (originalK2, sizeof(originalK2)); VirtualUnlock (temporaryKey, sizeof (temporaryKey)); VirtualUnlock (originalK2, sizeof (originalK2)); TCfree (write_buf); SetLastError (err); return (retVal ? retVal : ERR_OS_ERROR); }
// 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, uint32 sectorSize, 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 volumes being newly created are not // supposed to use any deprecated mode of operation. TC_THROW_FATAL_EXCEPTION; break; 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 mputWord (p, VOLUME_HEADER_VERSION); cryptoInfo->HeaderVersion = 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); // 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) { 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); } 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) { 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; }
/* ExpandVolume Sets the volume size in the volume header (and backup header) to a larger value, and resizes the filesystem within the volume (only NTFS supported) Parameters: hwndDlg : HWND [in] handle to progress dialog lpszVolume : char * [in] Pointer to a string that contains the path to the truecrypt volume pVolumePassword : Password * [in] Pointer to the volume password newHostSize : uint64 [in] new value of the volume host size (can be zero for devices, which means the volume should use all space of the host device) initFreeSpace : BOOL [in] if true, the new volume space will be initalized with random data Return value: int with Truecrypt error code (ERR_SUCCESS on success) Remarks: a lot of code is from TrueCrypt 'Common\Password.c' :: ChangePwd() */ static int ExpandVolume (HWND hwndDlg, wchar_t *lpszVolume, Password *pVolumePassword, int VolumePkcs5, int VolumePim, uint64 newHostSize, BOOL initFreeSpace) { int nDosLinkCreated = 1, nStatus = ERR_OS_ERROR; wchar_t szDiskFile[TC_MAX_PATH], szCFDevice[TC_MAX_PATH]; wchar_t szDosDevice[TC_MAX_PATH]; char buffer[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; PCRYPTO_INFO cryptoInfo = NULL, ci = NULL; void *dev = INVALID_HANDLE_VALUE; DWORD dwError; BOOL bDevice; uint64 hostSize=0, newDataAreaSize, currentVolSize; DWORD HostSectorSize; FILETIME ftCreationTime; FILETIME ftLastWriteTime; FILETIME ftLastAccessTime; BOOL bTimeStampValid = FALSE; LARGE_INTEGER headerOffset; BOOL backupHeader; byte *wipeBuffer = NULL; uint32 workChunkSize = TC_VOLUME_HEADER_GROUP_SIZE; if (pVolumePassword->Length == 0) return -1; WaitCursor (); CreateFullVolumePath (szDiskFile, sizeof(szDiskFile), lpszVolume, &bDevice); if (bDevice == FALSE) { wcscpy (szCFDevice, szDiskFile); } else { nDosLinkCreated = FakeDosNameForDevice (szDiskFile, szDosDevice, sizeof(szDosDevice), szCFDevice, sizeof(szCFDevice), FALSE); if (nDosLinkCreated != 0) // note: nStatus == ERR_OS_ERROR goto error; } dev = CreateFile (szCFDevice, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (dev == INVALID_HANDLE_VALUE) goto error; if (bDevice) { /* This is necessary to determine the hidden volume header offset */ if (dev == INVALID_HANDLE_VALUE) { goto error; } else { PARTITION_INFORMATION diskInfo; DWORD dwResult; BOOL bResult; bResult = GetPartitionInfo (lpszVolume, &diskInfo); if (bResult) { hostSize = diskInfo.PartitionLength.QuadPart; HostSectorSize = TC_SECTOR_SIZE_FILE_HOSTED_VOLUME; //TO DO: get the real host disk sector size } else { DISK_GEOMETRY driveInfo; bResult = DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveInfo, sizeof (driveInfo), &dwResult, NULL); if (!bResult) goto error; hostSize = driveInfo.Cylinders.QuadPart * driveInfo.BytesPerSector * driveInfo.SectorsPerTrack * driveInfo.TracksPerCylinder; HostSectorSize = driveInfo.BytesPerSector; } if (hostSize == 0) { nStatus = ERR_VOL_SIZE_WRONG; goto error; } } } else { LARGE_INTEGER fileSize; if (!GetFileSizeEx (dev, &fileSize)) { nStatus = ERR_OS_ERROR; goto error; } hostSize = fileSize.QuadPart; HostSectorSize = TC_SECTOR_SIZE_FILE_HOSTED_VOLUME; //TO DO: get the real host disk sector size } if (Randinit ()) { if (CryptoAPILastError == ERROR_SUCCESS) nStatus = ERR_RAND_INIT_FAILED; else nStatus = ERR_CAPI_INIT_FAILED; goto error; } if (!bDevice && bPreserveTimestamp) { /* Remember the container modification/creation date and time, (used to reset file date and time of file-hosted volumes after password change (or attempt to), in order to preserve plausible deniability of hidden volumes (last password change time is stored in the volume header). */ if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0) { bTimeStampValid = FALSE; MessageBoxW (hwndDlg, GetString ("GETFILETIME_FAILED_PW"), lpszTitle, MB_OK | MB_ICONEXCLAMATION); } else bTimeStampValid = TRUE; } // Seek the volume header headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET; if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN)) { nStatus = ERR_OS_ERROR; goto error; } /* Read in volume header */ nStatus = _lread ((HFILE) dev, buffer, sizeof (buffer)); if (nStatus != sizeof (buffer)) { // Windows may report EOF when reading sectors from the last cluster of a device formatted as NTFS memset (buffer, 0, sizeof (buffer)); } /* Try to decrypt the header */ nStatus = ReadVolumeHeader (FALSE, buffer, pVolumePassword, VolumePkcs5, VolumePim, FALSE, &cryptoInfo, NULL); if (nStatus == ERR_CIPHER_INIT_WEAK_KEY) nStatus = 0; // We can ignore this error here if (nStatus != 0) { cryptoInfo = NULL; goto error; } if (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM) { nStatus = ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG; goto error; } if (bDevice && newHostSize == 0) { // this means we shall take all host space as new volume size newHostSize = hostSize; } if ( newHostSize % cryptoInfo->SectorSize != 0 || newHostSize > TC_MAX_VOLUME_SIZE || (bDevice && newHostSize > hostSize) ) { // 1. must be multiple of sector size // 2. truecrypt volume size limit // 3. for devices volume size can't be larger than host size cryptoInfo = NULL; nStatus = ERR_PARAMETER_INCORRECT; goto error; } newDataAreaSize = GetVolumeDataAreaSize (newHostSize, cryptoInfo->LegacyVolume); if (cryptoInfo->LegacyVolume) { if (bDevice) { if (initFreeSpace) { // unsupported cryptoInfo = NULL; nStatus = ERR_PARAMETER_INCORRECT; goto error; } else { // note: dummy value (only used for parameter checks) cryptoInfo->VolumeSize.Value = newDataAreaSize - TC_MINVAL_FS_EXPAND; } } else { cryptoInfo->VolumeSize.Value = GetVolumeDataAreaSize (hostSize, TRUE); } } currentVolSize = GetVolumeSizeByDataAreaSize (cryptoInfo->VolumeSize.Value, cryptoInfo->LegacyVolume); if ( newDataAreaSize < cryptoInfo->VolumeSize.Value + TC_MINVAL_FS_EXPAND ) { // shrinking a volume or enlarging by less then TC_MINVAL_FS_EXPAND is not allowed cryptoInfo = NULL; nStatus = ERR_PARAMETER_INCORRECT; goto error; } InitProgressBar ( newHostSize, currentVolSize, FALSE, FALSE, FALSE, TRUE); if (bVolTransformThreadCancel) { SetLastError(0); nStatus = ERR_USER_ABORT; goto error; } if (!bDevice) { LARGE_INTEGER liNewSize; liNewSize.QuadPart=(LONGLONG)newHostSize; // Preallocate the file if (!SetFilePointerEx (dev, liNewSize, NULL, FILE_BEGIN) || !SetEndOfFile (dev) || SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0) { nStatus = ERR_OS_ERROR; goto error; } } if (initFreeSpace) { uint64 startSector; int64 num_sectors; // fill new space with random data startSector = currentVolSize/HostSectorSize ; num_sectors = (newHostSize/HostSectorSize) - startSector; if (bDevice && !StartFormatWriteThread()) { nStatus = ERR_OS_ERROR; goto error; } DebugAddProgressDlgStatus(hwndDlg, L"Writing random data to new space ...\r\n"); SetFormatSectorSize(HostSectorSize); nStatus = FormatNoFs (hwndDlg, startSector, num_sectors, dev, cryptoInfo, FALSE); dwError = GetLastError(); StopFormatWriteThread(); SetLastError (dwError); } else { UpdateProgressBar(newHostSize); } if (nStatus != ERR_SUCCESS) { dwError = GetLastError(); DebugAddProgressDlgStatus(hwndDlg, L"Error: failed to write random data ...\r\n"); if ( !bDevice ) { // restore original size of the container file LARGE_INTEGER liOldSize; liOldSize.QuadPart=(LONGLONG)hostSize; if (!SetFilePointerEx (dev, liOldSize, NULL, FILE_BEGIN) || !SetEndOfFile (dev)) { DebugAddProgressDlgStatus(hwndDlg, L"Warning: failed to restore original size of the container file\r\n"); } } SetLastError (dwError); goto error; } RandSetHashFunction (cryptoInfo->pkcs5); // Re-encrypt the volume header forn non-legacy volumes: backup header first backupHeader = TRUE; headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET + newHostSize - TC_VOLUME_HEADER_GROUP_SIZE; /* note: updating the header is not neccessary for legay volumes */ while ( !cryptoInfo->LegacyVolume ) { if (backupHeader) DebugAddProgressDlgStatus(hwndDlg, L"Writing re-encrypted backup header ...\r\n"); else DebugAddProgressDlgStatus(hwndDlg, L"Writing re-encrypted primary header ...\r\n"); // Prepare new volume header nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE, buffer, cryptoInfo->ea, cryptoInfo->mode, pVolumePassword, cryptoInfo->pkcs5, VolumePim, (char*)(cryptoInfo->master_keydata), &ci, newDataAreaSize, 0, // hiddenVolumeSize cryptoInfo->EncryptedAreaStart.Value, newDataAreaSize, cryptoInfo->RequiredProgramVersion, cryptoInfo->HeaderFlags, cryptoInfo->SectorSize, TRUE ); // use slow poll if (ci != NULL) crypto_close (ci); if (nStatus != 0) goto error; if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN)) { nStatus = ERR_OS_ERROR; goto error; } nStatus = _lwrite ((HFILE) dev, buffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE); if (nStatus != TC_VOLUME_HEADER_EFFECTIVE_SIZE) { nStatus = ERR_OS_ERROR; goto error; } if ( ( backupHeader && !initFreeSpace ) || ( bDevice && !cryptoInfo->LegacyVolume && !cryptoInfo->hiddenVolume && cryptoInfo->HeaderVersion == 4 // BUG in TrueCrypt: doing this only for v4 make no sense && (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC) != 0 && (cryptoInfo->HeaderFlags & ~TC_HEADER_FLAG_NONSYS_INPLACE_ENC) == 0 ) ) { //DebugAddProgressDlgStatus(hwndDlg, L"WriteRandomDataToReservedHeaderAreas() ...\r\n"); nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, newDataAreaSize, !backupHeader, backupHeader); if (nStatus != ERR_SUCCESS) goto error; } FlushFileBuffers (dev); if (!backupHeader) break; backupHeader = FALSE; headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET; // offset for main header } /* header successfully updated */ nStatus = ERR_SUCCESS; if (bVolTransformThreadCancel) { nStatus = ERR_USER_ABORT; goto error; } /* wipe old backup header */ if ( !cryptoInfo->LegacyVolume ) { byte wipeRandChars [TC_WIPE_RAND_CHAR_COUNT]; byte wipeRandCharsUpdate [TC_WIPE_RAND_CHAR_COUNT]; byte wipePass; UINT64_STRUCT unitNo; LARGE_INTEGER offset; WipeAlgorithmId wipeAlgorithm = TC_WIPE_35_GUTMANN; if ( !RandgetBytes (hwndDlg, wipeRandChars, TC_WIPE_RAND_CHAR_COUNT, TRUE) || !RandgetBytes (hwndDlg, wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT, TRUE) ) { nStatus = ERR_OS_ERROR; goto error; } DebugAddProgressDlgStatus(hwndDlg, L"Wiping old backup header ...\r\n"); wipeBuffer = (byte *) TCalloc (workChunkSize); if (!wipeBuffer) { nStatus = ERR_OUTOFMEMORY; goto error; } offset.QuadPart = currentVolSize - TC_VOLUME_HEADER_GROUP_SIZE; unitNo.Value = offset.QuadPart; for (wipePass = 1; wipePass <= GetWipePassCount (wipeAlgorithm); ++wipePass) { if (!WipeBuffer (wipeAlgorithm, wipeRandChars, wipePass, wipeBuffer, workChunkSize)) { ULONG i; for (i = 0; i < workChunkSize; ++i) { wipeBuffer[i] = wipePass; } EncryptDataUnits (wipeBuffer, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, cryptoInfo); memcpy (wipeRandCharsUpdate, wipeBuffer, sizeof (wipeRandCharsUpdate)); } if ( !SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) || _lwrite ((HFILE)dev, (LPCSTR)wipeBuffer, workChunkSize) == HFILE_ERROR ) { // Write error DebugAddProgressDlgStatus(hwndDlg, L"Warning: Failed to wipe old backup header\r\n"); MessageBoxW (hwndDlg, L"WARNING: Failed to wipe old backup header!\n\nIt may be possible to use the current volume password to decrypt the old backup header even after a future password change.\n", lpszTitle, MB_OK | MB_ICONEXCLAMATION); if (wipePass == 1) continue; // retry once // non-critical error - it's better to continue nStatus = ERR_SUCCESS; goto error; } FlushFileBuffers(dev); // we don't check FlushFileBuffers() return code, because it fails for devices // (same implementation in password.c - a bug or not ???) } burn (wipeRandChars, TC_WIPE_RAND_CHAR_COUNT); burn (wipeRandCharsUpdate, TC_WIPE_RAND_CHAR_COUNT); } error: dwError = GetLastError (); if (wipeBuffer) { burn (wipeBuffer, workChunkSize); TCfree (wipeBuffer); wipeBuffer = NULL; } burn (buffer, sizeof (buffer)); if (cryptoInfo != NULL) crypto_close (cryptoInfo); if (bTimeStampValid) { // Restore the container timestamp (to preserve plausible deniability of possible hidden volume). if (SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0) MessageBoxW (hwndDlg, GetString ("SETFILETIME_FAILED_PW"), lpszTitle, MB_OK | MB_ICONEXCLAMATION); } if (dev != INVALID_HANDLE_VALUE) CloseHandle ((HANDLE) dev); if (nDosLinkCreated == 0) RemoveFakeDosName (szDiskFile, szDosDevice); RandStop (FALSE); if (bVolTransformThreadCancel) nStatus = ERR_USER_ABORT; SetLastError (dwError); if (nStatus == ERR_SUCCESS) { nStatus = ExtendFileSystem (hwndDlg, lpszVolume, pVolumePassword, VolumePkcs5, VolumePim, newDataAreaSize); } return nStatus; }
// 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]; 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 (temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE) || !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; 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; }