diff options
Diffstat (limited to 'src/Common/Password.c')
-rw-r--r-- | src/Common/Password.c | 982 |
1 files changed, 491 insertions, 491 deletions
diff --git a/src/Common/Password.c b/src/Common/Password.c index 8a93065d..4d7c7952 100644 --- a/src/Common/Password.c +++ b/src/Common/Password.c @@ -1,491 +1,491 @@ -/*
- Legal Notice: Some portions of the source code contained in this file were
- derived from the source code of TrueCrypt 7.1a, which is
- Copyright (c) 2003-2012 TrueCrypt Developers Association and which is
- governed by the TrueCrypt License 3.0, also from the source code of
- Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux
- and which is governed by the 'License Agreement for Encryption for the Masses'
- Modifications and additions to the original source code (contained in this file)
- and all other portions of this file are Copyright (c) 2013-2016 IDRIX
- and are governed by the Apache License 2.0 the full text of which is
- contained in the file License.txt included in VeraCrypt binary and source
- code distribution packages. */
-
-#include "Tcdefs.h"
-
-#include "Crypto.h"
-#include "Volumes.h"
-#include "Password.h"
-#include "Dlgcode.h"
-#include "Language.h"
-#include "Pkcs5.h"
-#include "Endian.h"
-#include "Random.h"
-
-#include <io.h>
-
-#ifndef SRC_POS
-#define SRC_POS (__FUNCTION__ ":" TC_TO_STRING(__LINE__))
-#endif
-
-void VerifyPasswordAndUpdate (HWND hwndDlg, HWND hButton, HWND hPassword,
- HWND hVerify, unsigned char *szPassword,
- char *szVerify,
- BOOL keyFilesEnabled)
-{
- wchar_t szTmp1[MAX_PASSWORD + 1];
- wchar_t szTmp2[MAX_PASSWORD + 1];
- char szTmp1Utf8[MAX_PASSWORD + 1];
- char szTmp2Utf8[MAX_PASSWORD + 1];
- int k = GetWindowTextLength (hPassword);
- BOOL bEnable = FALSE;
- int utf8Len1, utf8Len2;
-
- UNREFERENCED_PARAMETER (hwndDlg); /* Remove warning */
-
- GetWindowText (hPassword, szTmp1, ARRAYSIZE (szTmp1));
- GetWindowText (hVerify, szTmp2, ARRAYSIZE (szTmp2));
-
- utf8Len1 = WideCharToMultiByte (CP_UTF8, 0, szTmp1, -1, szTmp1Utf8, MAX_PASSWORD + 1, NULL, NULL);
- utf8Len2 = WideCharToMultiByte (CP_UTF8, 0, szTmp2, -1, szTmp2Utf8, MAX_PASSWORD + 1, NULL, NULL);
-
- if (wcscmp (szTmp1, szTmp2) != 0)
- bEnable = FALSE;
- else if (utf8Len1 <= 0)
- bEnable = FALSE;
- else
- {
- if (k >= MIN_PASSWORD || keyFilesEnabled)
- bEnable = TRUE;
- else
- bEnable = FALSE;
- }
-
- if (szPassword != NULL)
- {
- if (utf8Len1 > 0)
- memcpy (szPassword, szTmp1Utf8, sizeof (szTmp1Utf8));
- else
- szPassword [0] = 0;
- }
-
- if (szVerify != NULL)
- {
- if (utf8Len2 > 0)
- memcpy (szVerify, szTmp2Utf8, sizeof (szTmp2Utf8));
- else
- szVerify [0] = 0;
- }
-
- burn (szTmp1, sizeof (szTmp1));
- burn (szTmp2, sizeof (szTmp2));
- burn (szTmp1Utf8, sizeof (szTmp1Utf8));
- burn (szTmp2Utf8, sizeof (szTmp2Utf8));
-
- EnableWindow (hButton, bEnable);
-}
-
-
-BOOL CheckPasswordCharEncoding (HWND hPassword, Password *ptrPw)
-{
- int i, len;
-
- if (hPassword == NULL)
- {
- if (ptrPw)
- {
- unsigned char *pw;
- len = ptrPw->Length;
- pw = (unsigned char *) ptrPw->Text;
-
- for (i = 0; i < len; i++)
- {
- if (pw[i] >= 0x7f || pw[i] < 0x20) // A non-ASCII or non-printable character?
- return FALSE;
- }
- }
- else
- return FALSE;
- }
- else
- {
- wchar_t s[MAX_PASSWORD + 1];
- len = GetWindowTextLength (hPassword);
-
- if (len > MAX_PASSWORD)
- return FALSE;
-
- GetWindowTextW (hPassword, s, sizeof (s) / sizeof (wchar_t));
-
- for (i = 0; i < len; i++)
- {
- if (s[i] >= 0x7f || s[i] < 0x20) // A non-ASCII or non-printable character?
- break;
- }
-
- burn (s, sizeof(s));
-
- if (i < len)
- return FALSE;
- }
-
- return TRUE;
-}
-
-
-BOOL CheckPasswordLength (HWND hwndDlg, unsigned __int32 passwordLength, int pim, BOOL bForBoot, BOOL bSkipPasswordWarning, BOOL bSkipPimWarning)
-{
- BOOL bCustomPimSmall = ((pim != 0) && (pim < (bForBoot? 98 : 485)))? TRUE : FALSE;
- if (passwordLength < PASSWORD_LEN_WARNING)
- {
- if (bCustomPimSmall)
- {
- Error (bForBoot? "BOOT_PIM_REQUIRE_LONG_PASSWORD": "PIM_REQUIRE_LONG_PASSWORD", hwndDlg);
- return FALSE;
- }
-
-#ifndef _DEBUG
- if (!bSkipPasswordWarning && (MessageBoxW (hwndDlg, GetString ("PASSWORD_LENGTH_WARNING"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) != IDYES))
- return FALSE;
-#endif
- }
-#ifndef _DEBUG
- else if (bCustomPimSmall)
- {
- if (!bSkipPimWarning && AskWarnNoYes ("PIM_SMALL_WARNING", hwndDlg) != IDYES)
- return FALSE;
- }
-#endif
-
- if ((pim != 0) && (pim > (bForBoot? 98 : 485)))
- {
- // warn that mount/boot will take more time
- Warning ("PIM_LARGE_WARNING", hwndDlg);
-
- }
- return TRUE;
-}
-
-int ChangePwd (const wchar_t *lpszVolume, Password *oldPassword, int old_pkcs5, int old_pim, BOOL truecryptMode, Password *newPassword, int pkcs5, int pim, int wipePassCount, HWND hwndDlg)
-{
- 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;
- DWORD bytesRead;
- BOOL bDevice;
- unsigned __int64 hostSize = 0;
- int volumeType;
- int wipePass;
- FILETIME ftCreationTime;
- FILETIME ftLastWriteTime;
- FILETIME ftLastAccessTime;
- BOOL bTimeStampValid = FALSE;
- LARGE_INTEGER headerOffset;
- BOOL backupHeader;
- DISK_GEOMETRY driveInfo;
-
- if (oldPassword->Length == 0 || newPassword->Length == 0) return -1;
-
- if ((wipePassCount <= 0) || (truecryptMode && (old_pkcs5 == SHA256)))
- {
- nStatus = ERR_PARAMETER_INCORRECT;
- handleError (hwndDlg, nStatus, SRC_POS);
- return nStatus;
- }
-
- if (!lpszVolume)
- {
- nStatus = ERR_OUTOFMEMORY;
- handleError (hwndDlg, nStatus, SRC_POS);
- return nStatus;
- }
-
- 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)
- 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 = DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
- &driveInfo, sizeof (driveInfo), &dwResult, NULL);
-
- if (!bResult)
- goto error;
-
- bResult = GetPartitionInfo (lpszVolume, &diskInfo);
-
- if (bResult)
- {
- hostSize = diskInfo.PartitionLength.QuadPart;
- }
- else
- {
- hostSize = driveInfo.Cylinders.QuadPart * driveInfo.BytesPerSector *
- driveInfo.SectorsPerTrack * driveInfo.TracksPerCylinder;
- }
-
- 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;
- }
-
- if (Randinit ())
- {
- if (CryptoAPILastError == ERROR_SUCCESS)
- nStatus = ERR_RAND_INIT_FAILED;
- else
- nStatus = ERR_CAPI_INIT_FAILED;
- goto error;
- }
-
- SetRandomPoolEnrichedByUserStatus (FALSE); /* force the display of the random enriching dialog */
-
- if (!bDevice && bPreserveTimestamp)
- {
- if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
- bTimeStampValid = FALSE;
- else
- bTimeStampValid = TRUE;
- }
-
- for (volumeType = TC_VOLUME_TYPE_NORMAL; volumeType < TC_VOLUME_TYPE_COUNT; volumeType++)
- {
- // Seek the volume header
- switch (volumeType)
- {
- case TC_VOLUME_TYPE_NORMAL:
- headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET;
- break;
-
- case TC_VOLUME_TYPE_HIDDEN:
- if (TC_HIDDEN_VOLUME_HEADER_OFFSET + TC_VOLUME_HEADER_SIZE > hostSize)
- continue;
-
- headerOffset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET;
- break;
-
- }
-
- if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
- {
- nStatus = ERR_OS_ERROR;
- goto error;
- }
-
- /* Read in volume header */
- if (!ReadEffectiveVolumeHeader (bDevice, dev, buffer, &bytesRead))
- {
- nStatus = ERR_OS_ERROR;
- goto error;
- }
-
- if (bytesRead != 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, oldPassword, old_pkcs5, old_pim, truecryptMode, &cryptoInfo, NULL);
- if (nStatus == ERR_CIPHER_INIT_WEAK_KEY)
- nStatus = 0; // We can ignore this error here
-
- if (nStatus == ERR_PASSWORD_WRONG)
- {
- continue; // Try next volume type
- }
- else if (nStatus != 0)
- {
- cryptoInfo = NULL;
- goto error;
- }
- else
- break;
- }
-
- 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;
- }
-
- // Change the PKCS-5 PRF if requested by user
- if (pkcs5 != 0)
- cryptoInfo->pkcs5 = pkcs5;
-
- RandSetHashFunction (cryptoInfo->pkcs5);
-
- NormalCursor();
- UserEnrichRandomPool (hwndDlg);
- EnableElevatedCursorChange (hwndDlg);
- WaitCursor();
-
- /* Re-encrypt the volume header */
- backupHeader = FALSE;
-
- while (TRUE)
- {
- /* The header will be re-encrypted wipePassCount times to prevent adversaries from using
- techniques such as magnetic force microscopy or magnetic force scanning tunnelling microscopy
- to recover the overwritten header. According to Peter Gutmann, data should be overwritten 22
- times (ideally, 35 times) using non-random patterns and pseudorandom data. However, as users might
- impatiently interupt the process (etc.) we will not use the Gutmann's patterns but will write the
- valid re-encrypted header, i.e. pseudorandom data, and there will be many more passes than Guttman
- recommends. During each pass we will write a valid working header. Each pass will use the same master
- key, and also the same header key, secondary key (XTS), etc., derived from the new password. The only
- item that will be different for each pass will be the salt. This is sufficient to cause each "version"
- of the header to differ substantially and in a random manner from the versions written during the
- other passes. */
-
- for (wipePass = 0; wipePass < wipePassCount; wipePass++)
- {
- // Prepare new volume header
- nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE,
- buffer,
- cryptoInfo->ea,
- cryptoInfo->mode,
- newPassword,
- cryptoInfo->pkcs5,
- pim,
- cryptoInfo->master_keydata,
- &ci,
- cryptoInfo->VolumeSize.Value,
- (volumeType == TC_VOLUME_TYPE_HIDDEN) ? cryptoInfo->hiddenVolumeSize : 0,
- cryptoInfo->EncryptedAreaStart.Value,
- cryptoInfo->EncryptedAreaLength.Value,
- truecryptMode? 0 : cryptoInfo->RequiredProgramVersion,
- cryptoInfo->HeaderFlags,
- cryptoInfo->SectorSize,
- wipePass < wipePassCount - 1);
-
- 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;
- }
-
- if (!WriteEffectiveVolumeHeader (bDevice, dev, buffer))
- {
- nStatus = ERR_OS_ERROR;
- goto error;
- }
-
- if (bDevice
- && !cryptoInfo->LegacyVolume
- && !cryptoInfo->hiddenVolume
- && cryptoInfo->HeaderVersion == 4
- && (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC) != 0
- && (cryptoInfo->HeaderFlags & ~TC_HEADER_FLAG_NONSYS_INPLACE_ENC) == 0)
- {
- nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, cryptoInfo->VolumeSize.Value, !backupHeader, backupHeader);
- if (nStatus != ERR_SUCCESS)
- goto error;
- }
-
- FlushFileBuffers (dev);
- }
-
- if (backupHeader || cryptoInfo->LegacyVolume)
- break;
-
- backupHeader = TRUE;
- headerOffset.QuadPart += hostSize - TC_VOLUME_HEADER_GROUP_SIZE;
- }
-
- /* Password successfully changed */
- nStatus = 0;
-
-error:
- dwError = GetLastError ();
-
- burn (buffer, sizeof (buffer));
-
- if (cryptoInfo != NULL)
- crypto_close (cryptoInfo);
-
- if (bTimeStampValid)
- SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime);
-
- if (dev != INVALID_HANDLE_VALUE)
- CloseHandle ((HANDLE) dev);
-
- if (nDosLinkCreated == 0)
- RemoveFakeDosName (szDiskFile, szDosDevice);
-
- RandStop (FALSE);
- NormalCursor ();
-
- SetLastError (dwError);
-
- if (nStatus == ERR_OS_ERROR && dwError == ERROR_ACCESS_DENIED
- && bDevice
- && !UacElevated
- && IsUacSupported ())
- return nStatus;
-
- if (nStatus != 0)
- handleError (hwndDlg, nStatus, SRC_POS);
-
- return nStatus;
-}
-
+/* + Legal Notice: Some portions of the source code contained in this file were + derived from the source code of TrueCrypt 7.1a, which is + Copyright (c) 2003-2012 TrueCrypt Developers Association and which is + governed by the TrueCrypt License 3.0, also from the source code of + Encryption for the Masses 2.02a, which is Copyright (c) 1998-2000 Paul Le Roux + and which is governed by the 'License Agreement for Encryption for the Masses' + Modifications and additions to the original source code (contained in this file) + and all other portions of this file are Copyright (c) 2013-2016 IDRIX + and are governed by the Apache License 2.0 the full text of which is + contained in the file License.txt included in VeraCrypt binary and source + code distribution packages. */ + +#include "Tcdefs.h" + +#include "Crypto.h" +#include "Volumes.h" +#include "Password.h" +#include "Dlgcode.h" +#include "Language.h" +#include "Pkcs5.h" +#include "Endian.h" +#include "Random.h" + +#include <io.h> + +#ifndef SRC_POS +#define SRC_POS (__FUNCTION__ ":" TC_TO_STRING(__LINE__)) +#endif + +void VerifyPasswordAndUpdate (HWND hwndDlg, HWND hButton, HWND hPassword, + HWND hVerify, unsigned char *szPassword, + char *szVerify, + BOOL keyFilesEnabled) +{ + wchar_t szTmp1[MAX_PASSWORD + 1]; + wchar_t szTmp2[MAX_PASSWORD + 1]; + char szTmp1Utf8[MAX_PASSWORD + 1]; + char szTmp2Utf8[MAX_PASSWORD + 1]; + int k = GetWindowTextLength (hPassword); + BOOL bEnable = FALSE; + int utf8Len1, utf8Len2; + + UNREFERENCED_PARAMETER (hwndDlg); /* Remove warning */ + + GetWindowText (hPassword, szTmp1, ARRAYSIZE (szTmp1)); + GetWindowText (hVerify, szTmp2, ARRAYSIZE (szTmp2)); + + utf8Len1 = WideCharToMultiByte (CP_UTF8, 0, szTmp1, -1, szTmp1Utf8, MAX_PASSWORD + 1, NULL, NULL); + utf8Len2 = WideCharToMultiByte (CP_UTF8, 0, szTmp2, -1, szTmp2Utf8, MAX_PASSWORD + 1, NULL, NULL); + + if (wcscmp (szTmp1, szTmp2) != 0) + bEnable = FALSE; + else if (utf8Len1 <= 0) + bEnable = FALSE; + else + { + if (k >= MIN_PASSWORD || keyFilesEnabled) + bEnable = TRUE; + else + bEnable = FALSE; + } + + if (szPassword != NULL) + { + if (utf8Len1 > 0) + memcpy (szPassword, szTmp1Utf8, sizeof (szTmp1Utf8)); + else + szPassword [0] = 0; + } + + if (szVerify != NULL) + { + if (utf8Len2 > 0) + memcpy (szVerify, szTmp2Utf8, sizeof (szTmp2Utf8)); + else + szVerify [0] = 0; + } + + burn (szTmp1, sizeof (szTmp1)); + burn (szTmp2, sizeof (szTmp2)); + burn (szTmp1Utf8, sizeof (szTmp1Utf8)); + burn (szTmp2Utf8, sizeof (szTmp2Utf8)); + + EnableWindow (hButton, bEnable); +} + + +BOOL CheckPasswordCharEncoding (HWND hPassword, Password *ptrPw) +{ + int i, len; + + if (hPassword == NULL) + { + if (ptrPw) + { + unsigned char *pw; + len = ptrPw->Length; + pw = (unsigned char *) ptrPw->Text; + + for (i = 0; i < len; i++) + { + if (pw[i] >= 0x7f || pw[i] < 0x20) // A non-ASCII or non-printable character? + return FALSE; + } + } + else + return FALSE; + } + else + { + wchar_t s[MAX_PASSWORD + 1]; + len = GetWindowTextLength (hPassword); + + if (len > MAX_PASSWORD) + return FALSE; + + GetWindowTextW (hPassword, s, sizeof (s) / sizeof (wchar_t)); + + for (i = 0; i < len; i++) + { + if (s[i] >= 0x7f || s[i] < 0x20) // A non-ASCII or non-printable character? + break; + } + + burn (s, sizeof(s)); + + if (i < len) + return FALSE; + } + + return TRUE; +} + + +BOOL CheckPasswordLength (HWND hwndDlg, unsigned __int32 passwordLength, int pim, BOOL bForBoot, BOOL bSkipPasswordWarning, BOOL bSkipPimWarning) +{ + BOOL bCustomPimSmall = ((pim != 0) && (pim < (bForBoot? 98 : 485)))? TRUE : FALSE; + if (passwordLength < PASSWORD_LEN_WARNING) + { + if (bCustomPimSmall) + { + Error (bForBoot? "BOOT_PIM_REQUIRE_LONG_PASSWORD": "PIM_REQUIRE_LONG_PASSWORD", hwndDlg); + return FALSE; + } + +#ifndef _DEBUG + if (!bSkipPasswordWarning && (MessageBoxW (hwndDlg, GetString ("PASSWORD_LENGTH_WARNING"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) != IDYES)) + return FALSE; +#endif + } +#ifndef _DEBUG + else if (bCustomPimSmall) + { + if (!bSkipPimWarning && AskWarnNoYes ("PIM_SMALL_WARNING", hwndDlg) != IDYES) + return FALSE; + } +#endif + + if ((pim != 0) && (pim > (bForBoot? 98 : 485))) + { + // warn that mount/boot will take more time + Warning ("PIM_LARGE_WARNING", hwndDlg); + + } + return TRUE; +} + +int ChangePwd (const wchar_t *lpszVolume, Password *oldPassword, int old_pkcs5, int old_pim, BOOL truecryptMode, Password *newPassword, int pkcs5, int pim, int wipePassCount, HWND hwndDlg) +{ + 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; + DWORD bytesRead; + BOOL bDevice; + unsigned __int64 hostSize = 0; + int volumeType; + int wipePass; + FILETIME ftCreationTime; + FILETIME ftLastWriteTime; + FILETIME ftLastAccessTime; + BOOL bTimeStampValid = FALSE; + LARGE_INTEGER headerOffset; + BOOL backupHeader; + DISK_GEOMETRY driveInfo; + + if (oldPassword->Length == 0 || newPassword->Length == 0) return -1; + + if ((wipePassCount <= 0) || (truecryptMode && (old_pkcs5 == SHA256))) + { + nStatus = ERR_PARAMETER_INCORRECT; + handleError (hwndDlg, nStatus, SRC_POS); + return nStatus; + } + + if (!lpszVolume) + { + nStatus = ERR_OUTOFMEMORY; + handleError (hwndDlg, nStatus, SRC_POS); + return nStatus; + } + + 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) + 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 = DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, + &driveInfo, sizeof (driveInfo), &dwResult, NULL); + + if (!bResult) + goto error; + + bResult = GetPartitionInfo (lpszVolume, &diskInfo); + + if (bResult) + { + hostSize = diskInfo.PartitionLength.QuadPart; + } + else + { + hostSize = driveInfo.Cylinders.QuadPart * driveInfo.BytesPerSector * + driveInfo.SectorsPerTrack * driveInfo.TracksPerCylinder; + } + + 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; + } + + if (Randinit ()) + { + if (CryptoAPILastError == ERROR_SUCCESS) + nStatus = ERR_RAND_INIT_FAILED; + else + nStatus = ERR_CAPI_INIT_FAILED; + goto error; + } + + SetRandomPoolEnrichedByUserStatus (FALSE); /* force the display of the random enriching dialog */ + + if (!bDevice && bPreserveTimestamp) + { + if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0) + bTimeStampValid = FALSE; + else + bTimeStampValid = TRUE; + } + + for (volumeType = TC_VOLUME_TYPE_NORMAL; volumeType < TC_VOLUME_TYPE_COUNT; volumeType++) + { + // Seek the volume header + switch (volumeType) + { + case TC_VOLUME_TYPE_NORMAL: + headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET; + break; + + case TC_VOLUME_TYPE_HIDDEN: + if (TC_HIDDEN_VOLUME_HEADER_OFFSET + TC_VOLUME_HEADER_SIZE > hostSize) + continue; + + headerOffset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET; + break; + + } + + if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + /* Read in volume header */ + if (!ReadEffectiveVolumeHeader (bDevice, dev, buffer, &bytesRead)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + if (bytesRead != 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, oldPassword, old_pkcs5, old_pim, truecryptMode, &cryptoInfo, NULL); + if (nStatus == ERR_CIPHER_INIT_WEAK_KEY) + nStatus = 0; // We can ignore this error here + + if (nStatus == ERR_PASSWORD_WRONG) + { + continue; // Try next volume type + } + else if (nStatus != 0) + { + cryptoInfo = NULL; + goto error; + } + else + break; + } + + 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; + } + + // Change the PKCS-5 PRF if requested by user + if (pkcs5 != 0) + cryptoInfo->pkcs5 = pkcs5; + + RandSetHashFunction (cryptoInfo->pkcs5); + + NormalCursor(); + UserEnrichRandomPool (hwndDlg); + EnableElevatedCursorChange (hwndDlg); + WaitCursor(); + + /* Re-encrypt the volume header */ + backupHeader = FALSE; + + while (TRUE) + { + /* The header will be re-encrypted wipePassCount times to prevent adversaries from using + techniques such as magnetic force microscopy or magnetic force scanning tunnelling microscopy + to recover the overwritten header. According to Peter Gutmann, data should be overwritten 22 + times (ideally, 35 times) using non-random patterns and pseudorandom data. However, as users might + impatiently interupt the process (etc.) we will not use the Gutmann's patterns but will write the + valid re-encrypted header, i.e. pseudorandom data, and there will be many more passes than Guttman + recommends. During each pass we will write a valid working header. Each pass will use the same master + key, and also the same header key, secondary key (XTS), etc., derived from the new password. The only + item that will be different for each pass will be the salt. This is sufficient to cause each "version" + of the header to differ substantially and in a random manner from the versions written during the + other passes. */ + + for (wipePass = 0; wipePass < wipePassCount; wipePass++) + { + // Prepare new volume header + nStatus = CreateVolumeHeaderInMemory (hwndDlg, FALSE, + buffer, + cryptoInfo->ea, + cryptoInfo->mode, + newPassword, + cryptoInfo->pkcs5, + pim, + cryptoInfo->master_keydata, + &ci, + cryptoInfo->VolumeSize.Value, + (volumeType == TC_VOLUME_TYPE_HIDDEN) ? cryptoInfo->hiddenVolumeSize : 0, + cryptoInfo->EncryptedAreaStart.Value, + cryptoInfo->EncryptedAreaLength.Value, + truecryptMode? 0 : cryptoInfo->RequiredProgramVersion, + cryptoInfo->HeaderFlags, + cryptoInfo->SectorSize, + wipePass < wipePassCount - 1); + + 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; + } + + if (!WriteEffectiveVolumeHeader (bDevice, dev, buffer)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + if (bDevice + && !cryptoInfo->LegacyVolume + && !cryptoInfo->hiddenVolume + && cryptoInfo->HeaderVersion == 4 + && (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC) != 0 + && (cryptoInfo->HeaderFlags & ~TC_HEADER_FLAG_NONSYS_INPLACE_ENC) == 0) + { + nStatus = WriteRandomDataToReservedHeaderAreas (hwndDlg, dev, cryptoInfo, cryptoInfo->VolumeSize.Value, !backupHeader, backupHeader); + if (nStatus != ERR_SUCCESS) + goto error; + } + + FlushFileBuffers (dev); + } + + if (backupHeader || cryptoInfo->LegacyVolume) + break; + + backupHeader = TRUE; + headerOffset.QuadPart += hostSize - TC_VOLUME_HEADER_GROUP_SIZE; + } + + /* Password successfully changed */ + nStatus = 0; + +error: + dwError = GetLastError (); + + burn (buffer, sizeof (buffer)); + + if (cryptoInfo != NULL) + crypto_close (cryptoInfo); + + if (bTimeStampValid) + SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime); + + if (dev != INVALID_HANDLE_VALUE) + CloseHandle ((HANDLE) dev); + + if (nDosLinkCreated == 0) + RemoveFakeDosName (szDiskFile, szDosDevice); + + RandStop (FALSE); + NormalCursor (); + + SetLastError (dwError); + + if (nStatus == ERR_OS_ERROR && dwError == ERROR_ACCESS_DENIED + && bDevice + && !UacElevated + && IsUacSupported ()) + return nStatus; + + if (nStatus != 0) + handleError (hwndDlg, nStatus, SRC_POS); + + return nStatus; +} + |