|
|
1.1.1.10 root 1: /*
1.1.1.12 root 2: Legal Notice: Some portions of the source code contained in this file were
3: derived from the source code of Encryption for the Masses 2.02a, which is
4: Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
5: Agreement for Encryption for the Masses'. Modifications and additions to
6: the original source code (contained in this file) and all other portions of
1.1.1.15! root 7: this file are Copyright (c) 2003-2009 TrueCrypt Foundation and are governed
1.1.1.14 root 8: by the TrueCrypt License 2.6 the full text of which is contained in the
1.1.1.12 root 9: file License.txt included in TrueCrypt binary and source code distribution
1.1.1.10 root 10: packages. */
1.1.1.6 root 11:
12: #include "Tcdefs.h"
13:
14: #include "Crypto.h"
15: #include "Volumes.h"
16: #include "Password.h"
17: #include "Dlgcode.h"
18: #include "Language.h"
19: #include "Pkcs5.h"
1.1.1.14 root 20: #include "Endian.h"
1.1.1.6 root 21: #include "Random.h"
1.1 root 22:
23: #include <io.h>
24:
1.1.1.14 root 25: void VerifyPasswordAndUpdate (HWND hwndDlg, HWND hButton, HWND hPassword,
1.1.1.12 root 26: HWND hVerify, unsigned char *szPassword,
1.1.1.6 root 27: char *szVerify,
28: BOOL keyFilesEnabled)
1.1 root 29: {
30: char szTmp1[MAX_PASSWORD + 1];
31: char szTmp2[MAX_PASSWORD + 1];
32: int k = GetWindowTextLength (hPassword);
33: BOOL bEnable = FALSE;
34:
35: if (hwndDlg); /* Remove warning */
36:
37: GetWindowText (hPassword, szTmp1, sizeof (szTmp1));
38: GetWindowText (hVerify, szTmp2, sizeof (szTmp2));
39:
40: if (strcmp (szTmp1, szTmp2) != 0)
41: bEnable = FALSE;
42: else
43: {
1.1.1.6 root 44: if (k >= MIN_PASSWORD || keyFilesEnabled)
1.1 root 45: bEnable = TRUE;
46: else
47: bEnable = FALSE;
48: }
49:
50: if (szPassword != NULL)
51: memcpy (szPassword, szTmp1, sizeof (szTmp1));
52:
53: if (szVerify != NULL)
54: memcpy (szVerify, szTmp2, sizeof (szTmp2));
55:
56: burn (szTmp1, sizeof (szTmp1));
57: burn (szTmp2, sizeof (szTmp2));
58:
59: EnableWindow (hButton, bEnable);
60: }
61:
1.1.1.6 root 62:
63: BOOL CheckPasswordCharEncoding (HWND hPassword, Password *ptrPw)
64: {
1.1.1.8 root 65: int i, len;
1.1.1.6 root 66:
67: if (hPassword == NULL)
68: {
1.1.1.8 root 69: unsigned char *pw;
1.1.1.6 root 70: len = ptrPw->Length;
71: pw = (unsigned char *) ptrPw->Text;
1.1.1.8 root 72:
73: for (i = 0; i < len; i++)
74: {
75: if (pw[i] >= 0x7f || pw[i] < 0x20) // A non-ASCII or non-printable character?
76: return FALSE;
77: }
1.1.1.6 root 78: }
79: else
80: {
1.1.1.8 root 81: wchar_t s[MAX_PASSWORD + 1];
1.1.1.6 root 82: len = GetWindowTextLength (hPassword);
83:
1.1.1.8 root 84: if (len > MAX_PASSWORD)
85: return FALSE;
86:
87: GetWindowTextW (hPassword, s, sizeof (s) / sizeof (wchar_t));
88:
89: for (i = 0; i < len; i++)
90: {
91: if (s[i] >= 0x7f || s[i] < 0x20) // A non-ASCII or non-printable character?
92: break;
93: }
94:
95: burn (s, sizeof(s));
96:
97: if (i < len)
98: return FALSE;
1.1.1.6 root 99: }
1.1.1.8 root 100:
1.1.1.6 root 101: return TRUE;
102: }
103:
104:
105: BOOL CheckPasswordLength (HWND hwndDlg, HWND hwndItem)
106: {
107: if (GetWindowTextLength (hwndItem) < PASSWORD_LEN_WARNING)
108: {
1.1.1.14 root 109: #ifndef _DEBUG
1.1.1.6 root 110: if (MessageBoxW (hwndDlg, GetString ("PASSWORD_LENGTH_WARNING"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) != IDYES)
111: return FALSE;
1.1.1.14 root 112: #endif
1.1.1.6 root 113: }
114: return TRUE;
115: }
116:
1.1.1.14 root 117: int ChangePwd (char *lpszVolume, Password *oldPassword, Password *newPassword, int pkcs5, HWND hwndDlg)
1.1 root 118: {
1.1.1.10 root 119: int nDosLinkCreated = 1, nStatus = ERR_OS_ERROR;
1.1 root 120: char szDiskFile[TC_MAX_PATH], szCFDevice[TC_MAX_PATH];
121: char szDosDevice[TC_MAX_PATH];
1.1.1.13 root 122: char buffer[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
1.1 root 123: PCRYPTO_INFO cryptoInfo = NULL, ci = NULL;
124: void *dev = INVALID_HANDLE_VALUE;
125: DWORD dwError;
126: BOOL bDevice;
1.1.1.13 root 127: unsigned __int64 hostSize = 0;
1.1.1.6 root 128: int volumeType;
129: int wipePass;
1.1.1.4 root 130: FILETIME ftCreationTime;
131: FILETIME ftLastWriteTime;
132: FILETIME ftLastAccessTime;
133: BOOL bTimeStampValid = FALSE;
1.1.1.13 root 134: LARGE_INTEGER headerOffset;
135: BOOL backupHeader;
1.1.1.10 root 136:
1.1.1.6 root 137: if (oldPassword->Length == 0 || newPassword->Length == 0) return -1;
1.1 root 138:
1.1.1.10 root 139: WaitCursor ();
140:
1.1 root 141: CreateFullVolumePath (szDiskFile, lpszVolume, &bDevice);
142:
1.1.1.4 root 143: if (bDevice == FALSE)
144: {
145: strcpy (szCFDevice, szDiskFile);
146: }
147: else
1.1 root 148: {
1.1.1.4 root 149: nDosLinkCreated = FakeDosNameForDevice (szDiskFile, szDosDevice, szCFDevice, FALSE);
1.1.1.10 root 150:
1.1.1.4 root 151: if (nDosLinkCreated != 0)
1.1.1.10 root 152: goto error;
1.1.1.4 root 153: }
1.1 root 154:
1.1.1.4 root 155: dev = CreateFile (szCFDevice, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
156:
1.1.1.14 root 157: if (dev == INVALID_HANDLE_VALUE)
158: goto error;
159:
1.1.1.6 root 160: if (bDevice)
1.1.1.4 root 161: {
1.1.1.6 root 162: /* This is necessary to determine the hidden volume header offset */
1.1.1.4 root 163:
164: if (dev == INVALID_HANDLE_VALUE)
1.1 root 165: {
1.1.1.10 root 166: goto error;
1.1 root 167: }
168: else
169: {
1.1.1.6 root 170: PARTITION_INFORMATION diskInfo;
1.1.1.4 root 171: DWORD dwResult;
172: BOOL bResult;
173:
1.1.1.10 root 174: bResult = GetPartitionInfo (lpszVolume, &diskInfo);
1.1.1.4 root 175:
1.1.1.6 root 176: if (bResult)
1.1 root 177: {
1.1.1.13 root 178: hostSize = diskInfo.PartitionLength.QuadPart;
1.1.1.6 root 179: }
180: else
181: {
182: DISK_GEOMETRY driveInfo;
1.1.1.4 root 183:
1.1.1.6 root 184: bResult = DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
185: &driveInfo, sizeof (driveInfo), &dwResult, NULL);
1.1.1.4 root 186:
1.1.1.6 root 187: if (!bResult)
1.1.1.10 root 188: goto error;
1.1.1.6 root 189:
1.1.1.13 root 190: hostSize = driveInfo.Cylinders.QuadPart * driveInfo.BytesPerSector *
1.1.1.4 root 191: driveInfo.SectorsPerTrack * driveInfo.TracksPerCylinder;
1.1 root 192: }
1.1.1.6 root 193:
1.1.1.13 root 194: if (hostSize == 0)
1.1.1.6 root 195: {
1.1.1.10 root 196: nStatus = ERR_VOL_SIZE_WRONG;
197: goto error;
1.1.1.6 root 198: }
1.1 root 199: }
200: }
1.1.1.13 root 201: else
202: {
203: LARGE_INTEGER fileSize;
204: if (!GetFileSizeEx (dev, &fileSize))
205: {
206: nStatus = ERR_OS_ERROR;
207: goto error;
208: }
209:
210: hostSize = fileSize.QuadPart;
211: }
1.1.1.4 root 212:
1.1.1.6 root 213: if (Randinit ())
1.1.1.10 root 214: goto error;
1.1.1.6 root 215:
216: if (!bDevice && bPreserveTimestamp)
1.1 root 217: {
1.1.1.4 root 218: /* Remember the container modification/creation date and time, (used to reset file date and time of
1.1.1.6 root 219: file-hosted volumes after password change (or attempt to), in order to preserve plausible deniability
1.1.1.4 root 220: of hidden volumes (last password change time is stored in the volume header). */
1.1 root 221:
1.1.1.4 root 222: if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
1.1 root 223: {
1.1.1.4 root 224: bTimeStampValid = FALSE;
1.1.1.6 root 225: MessageBoxW (hwndDlg, GetString ("GETFILETIME_FAILED_PW"), L"TrueCrypt", MB_OK | MB_ICONEXCLAMATION);
1.1 root 226: }
1.1.1.4 root 227: else
228: bTimeStampValid = TRUE;
1.1 root 229: }
230:
1.1.1.13 root 231: for (volumeType = TC_VOLUME_TYPE_NORMAL; volumeType < TC_VOLUME_TYPE_COUNT; volumeType++)
1.1 root 232: {
1.1.1.13 root 233: // Seek the volume header
234: switch (volumeType)
235: {
236: case TC_VOLUME_TYPE_NORMAL:
237: headerOffset.QuadPart = TC_VOLUME_HEADER_OFFSET;
238: break;
1.1 root 239:
1.1.1.13 root 240: case TC_VOLUME_TYPE_HIDDEN:
241: if (TC_HIDDEN_VOLUME_HEADER_OFFSET + TC_VOLUME_HEADER_SIZE > hostSize)
242: continue;
1.1 root 243:
1.1.1.13 root 244: headerOffset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET;
245: break;
246:
247: case TC_VOLUME_TYPE_HIDDEN_LEGACY:
248: headerOffset.QuadPart = hostSize - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY;
249: break;
250: }
251:
252: if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
1.1.1.6 root 253: {
1.1.1.13 root 254: nStatus = ERR_OS_ERROR;
255: goto error;
1.1.1.6 root 256: }
1.1 root 257:
1.1.1.13 root 258: /* Read in volume header */
1.1.1.8 root 259: nStatus = _lread ((HFILE) dev, buffer, sizeof (buffer));
1.1.1.6 root 260: if (nStatus != sizeof (buffer))
261: {
1.1.1.14 root 262: // Windows may report EOF when reading sectors from the last cluster of a device formatted as NTFS
263: memset (buffer, 0, sizeof (buffer));
1.1.1.6 root 264: }
1.1 root 265:
1.1.1.6 root 266: /* Try to decrypt the header */
1.1 root 267:
1.1.1.14 root 268: nStatus = ReadVolumeHeader (FALSE, buffer, oldPassword, &cryptoInfo, NULL);
1.1.1.6 root 269: if (nStatus == ERR_CIPHER_INIT_WEAK_KEY)
270: nStatus = 0; // We can ignore this error here
1.1 root 271:
1.1.1.6 root 272: if (nStatus == ERR_PASSWORD_WRONG)
273: {
274: continue; // Try next volume type
275: }
276: else if (nStatus != 0)
277: {
278: cryptoInfo = NULL;
279: goto error;
280: }
281: else
282: break;
283: }
1.1.1.4 root 284:
1.1 root 285: if (nStatus != 0)
286: {
287: cryptoInfo = NULL;
288: goto error;
289: }
290:
1.1.1.13 root 291: if (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM)
292: {
293: nStatus = ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG;
294: goto error;
295: }
296:
1.1.1.6 root 297: // Change the PKCS-5 PRF if requested by user
298: if (pkcs5 != 0)
299: cryptoInfo->pkcs5 = pkcs5;
1.1 root 300:
1.1.1.13 root 301: RandSetHashFunction (cryptoInfo->pkcs5);
302:
1.1.1.15! root 303: NormalCursor();
! 304: UserEnrichRandomPool (hwndDlg);
! 305: WaitCursor();
1.1 root 306:
1.1.1.6 root 307: /* Re-encrypt the volume header */
1.1.1.13 root 308: backupHeader = FALSE;
1.1.1.6 root 309:
1.1.1.13 root 310: while (TRUE)
1.1.1.6 root 311: {
1.1.1.13 root 312: /* The header will be re-encrypted PRAND_DISK_WIPE_PASSES times to prevent adversaries from using
313: techniques such as magnetic force microscopy or magnetic force scanning tunnelling microscopy
314: to recover the overwritten header. According to Peter Gutmann, data should be overwritten 22
315: times (ideally, 35 times) using non-random patterns and pseudorandom data. However, as users might
316: impatiently interupt the process (etc.) we will not use the Gutmann's patterns but will write the
317: valid re-encrypted header, i.e. pseudorandom data, and there will be many more passes than Guttman
318: recommends. During each pass we will write a valid working header. Each pass will use the same master
319: key, and also the same header key, secondary key (XTS), etc., derived from the new password. The only
320: item that will be different for each pass will be the salt. This is sufficient to cause each "version"
321: of the header to differ substantially and in a random manner from the versions written during the
322: other passes. */
323:
324: for (wipePass = 0; wipePass < PRAND_DISK_WIPE_PASSES; wipePass++)
325: {
326: // Prepare new volume header
1.1.1.14 root 327: nStatus = CreateVolumeHeaderInMemory (FALSE,
1.1.1.13 root 328: buffer,
329: cryptoInfo->ea,
330: cryptoInfo->mode,
331: newPassword,
332: cryptoInfo->pkcs5,
333: cryptoInfo->master_keydata,
334: &ci,
335: cryptoInfo->VolumeSize.Value,
336: (volumeType == TC_VOLUME_TYPE_HIDDEN || volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY) ? cryptoInfo->hiddenVolumeSize : 0,
337: cryptoInfo->EncryptedAreaStart.Value,
338: cryptoInfo->EncryptedAreaLength.Value,
339: cryptoInfo->RequiredProgramVersion,
340: cryptoInfo->HeaderFlags,
341: wipePass < PRAND_DISK_WIPE_PASSES - 1);
342:
343: if (ci != NULL)
344: crypto_close (ci);
345:
346: if (nStatus != 0)
347: goto error;
348:
349: if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
1.1.1.6 root 350: {
1.1.1.13 root 351: nStatus = ERR_OS_ERROR;
1.1.1.6 root 352: goto error;
353: }
1.1.1.3 root 354:
1.1.1.13 root 355: nStatus = _lwrite ((HFILE) dev, buffer, TC_VOLUME_HEADER_EFFECTIVE_SIZE);
356: if (nStatus != TC_VOLUME_HEADER_EFFECTIVE_SIZE)
1.1.1.6 root 357: {
1.1.1.13 root 358: nStatus = ERR_OS_ERROR;
1.1.1.6 root 359: goto error;
360: }
1.1 root 361:
1.1.1.15! root 362: if (bDevice
! 363: && !cryptoInfo->LegacyVolume
! 364: && !cryptoInfo->hiddenVolume
! 365: && cryptoInfo->HeaderVersion == 4
! 366: && (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC) != 0
! 367: && (cryptoInfo->HeaderFlags & ~TC_HEADER_FLAG_NONSYS_INPLACE_ENC) == 0)
! 368: {
! 369: nStatus = WriteRandomDataToReservedHeaderAreas (dev, cryptoInfo, cryptoInfo->VolumeSize.Value, !backupHeader, backupHeader);
! 370: if (nStatus != ERR_SUCCESS)
! 371: goto error;
! 372: }
! 373:
1.1.1.13 root 374: FlushFileBuffers (dev);
1.1.1.6 root 375: }
1.1.1.13 root 376:
377: if (backupHeader || cryptoInfo->LegacyVolume)
378: break;
379:
380: backupHeader = TRUE;
381: headerOffset.QuadPart += hostSize - TC_VOLUME_HEADER_GROUP_SIZE;
1.1 root 382: }
383:
1.1.1.6 root 384: /* Password successfully changed */
1.1 root 385: nStatus = 0;
386:
1.1.1.6 root 387: error:
1.1.1.10 root 388: dwError = GetLastError ();
389:
1.1 root 390: burn (buffer, sizeof (buffer));
391:
392: if (cryptoInfo != NULL)
393: crypto_close (cryptoInfo);
394:
1.1.1.4 root 395: if (bTimeStampValid)
1.1 root 396: {
1.1.1.4 root 397: // Restore the container timestamp (to preserve plausible deniability of possible hidden volume).
398: if (SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
1.1.1.6 root 399: MessageBoxW (hwndDlg, GetString ("SETFILETIME_FAILED_PW"), L"TrueCrypt", MB_OK | MB_ICONEXCLAMATION);
1.1.1.4 root 400: }
401:
1.1.1.10 root 402: if (dev != INVALID_HANDLE_VALUE)
403: CloseHandle ((HANDLE) dev);
1.1 root 404:
1.1.1.10 root 405: if (nDosLinkCreated == 0)
406: RemoveFakeDosName (szDiskFile, szDosDevice);
407:
1.1.1.15! root 408: RandStop (FALSE);
1.1.1.10 root 409: NormalCursor ();
1.1 root 410:
411: SetLastError (dwError);
412:
1.1.1.10 root 413: if (nStatus == ERR_OS_ERROR && dwError == ERROR_ACCESS_DENIED
414: && bDevice
415: && !UacElevated
416: && IsUacSupported ())
417: return nStatus;
1.1 root 418:
1.1.1.10 root 419: if (nStatus != 0)
420: handleError (hwndDlg, nStatus);
1.1.1.6 root 421:
1.1 root 422: return nStatus;
423: }
1.1.1.4 root 424:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.