|
|
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
7: this file are Copyright (c) 2003-2008 TrueCrypt Foundation and are governed
1.1.1.14! root 8: by the TrueCrypt License 2.5 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. */
11:
12: #include <stdlib.h>
13: #include <string.h>
1.1.1.6 root 14:
15: #include "Tcdefs.h"
16:
1.1.1.9 root 17: #include "Common.h"
1.1.1.6 root 18: #include "Crypto.h"
19: #include "Fat.h"
20: #include "Format.h"
1.1.1.9 root 21: #include "Random.h"
1.1.1.6 root 22: #include "Volumes.h"
1.1.1.8 root 23:
1.1.1.6 root 24: #include "Apidrvr.h"
25: #include "Dlgcode.h"
26: #include "Language.h"
1.1.1.8 root 27: #include "Progress.h"
1.1.1.6 root 28: #include "Resource.h"
1.1.1.10 root 29: #include "../Format/FormatCom.h"
1.1.1.3 root 30:
1.1.1.14! root 31:
! 32: uint64 GetVolumeDataAreaSize (BOOL hiddenVolume, uint64 volumeSize)
! 33: {
! 34: uint64 reservedSize;
! 35:
! 36: if (hiddenVolume)
! 37: {
! 38: // Reserve free space at the end of the host filesystem
! 39: if (volumeSize < TC_VOLUME_SMALL_SIZE_THRESHOLD)
! 40: reservedSize = TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE;
! 41: else
! 42: reservedSize = TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH; // Ensure size of a hidden volume larger than TC_VOLUME_SMALL_SIZE_THRESHOLD is a multiple of the maximum supported sector size
! 43: }
! 44: else
! 45: {
! 46: reservedSize = TC_TOTAL_VOLUME_HEADERS_SIZE;
! 47: }
! 48:
! 49: if (volumeSize < reservedSize)
! 50: return 0;
! 51:
! 52: return volumeSize - reservedSize;
! 53: }
! 54:
! 55:
1.1.1.12 root 56: int FormatVolume (char *volumePath,
1.1 root 57: BOOL bDevice,
58: unsigned __int64 size,
1.1.1.4 root 59: unsigned __int64 hiddenVolHostSize,
1.1.1.6 root 60: Password *password,
1.1.1.7 root 61: int ea,
1.1 root 62: int pkcs5,
63: BOOL quickFormat,
1.1.1.8 root 64: BOOL sparseFileSwitch,
1.1.1.3 root 65: int fileSystem,
66: int clusterSize,
1.1.1.4 root 67: HWND hwndDlg,
68: BOOL hiddenVol,
1.1.1.10 root 69: int *realClusterSize,
1.1.1.14! root 70: uint32 headerFlags)
1.1 root 71: {
72: int nStatus;
1.1.1.12 root 73: PCRYPTO_INFO cryptoInfo = NULL;
1.1.1.4 root 74: HANDLE dev = INVALID_HANDLE_VALUE;
1.1.1.10 root 75: DWORD dwError;
1.1.1.14! root 76: char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
1.1.1.4 root 77: unsigned __int64 num_sectors, startSector;
1.1.1.3 root 78: fatparams ft;
1.1.1.4 root 79: FILETIME ftCreationTime;
80: FILETIME ftLastWriteTime;
81: FILETIME ftLastAccessTime;
82: BOOL bTimeStampValid = FALSE;
1.1.1.12 root 83: BOOL bInstantRetryOtherFilesys = FALSE;
1.1.1.10 root 84: char dosDev[TC_MAX_PATH] = { 0 };
85: char devName[MAX_PATH] = { 0 };
86: int driveLetter = -1;
87: WCHAR deviceName[MAX_PATH];
1.1.1.14! root 88: uint64 dataOffset;
! 89: LARGE_INTEGER offset;
1.1.1.10 root 90:
1.1.1.12 root 91: /* WARNING: Note that if Windows fails to format the volume as NTFS and the volume size is
1.1.1.14! root 92: less than TC_MAX_FAT_FS_SIZE, the user is asked within this function whether he wants to instantly
1.1.1.12 root 93: retry FAT format instead (to avoid having to re-create the whole container again). If the user
94: answers yes, some of the input parameters are modified, the code below 'begin_format' is re-executed
95: and some destructive operations that were performed during the first attempt must be (and are) skipped.
96: Therefore, whenever adding or modifying any potentially destructive operations below 'begin_format',
97: determine whether they (or their portions) need to be skipped during such a second attempt; if so,
98: use the 'bInstantRetryOtherFilesys' flag to skip them. */
99:
1.1.1.14! root 100: if (hiddenVol)
! 101: {
! 102: dataOffset = hiddenVolHostSize - TC_VOLUME_HEADER_GROUP_SIZE - size;
! 103: }
! 104: else
! 105: {
! 106: if (size <= TC_TOTAL_VOLUME_HEADERS_SIZE)
! 107: return ERR_VOL_SIZE_WRONG;
! 108:
! 109: dataOffset = TC_VOLUME_DATA_OFFSET;
! 110: }
! 111:
! 112: size = GetVolumeDataAreaSize (hiddenVol, size);
1.1 root 113:
1.1.1.4 root 114: num_sectors = size / SECTOR_SIZE;
1.1.1.10 root 115:
116: if (bDevice)
117: {
118: strcpy ((char *)deviceName, volumePath);
119: ToUNICODE ((char *)deviceName);
120:
121: driveLetter = GetDiskDeviceDriveLetter (deviceName);
122: }
123:
1.1.1.3 root 124: VirtualLock (header, sizeof (header));
1.1 root 125:
1.1.1.12 root 126: /* Copies any header structures into header, but does not do any disk I/O */
127: nStatus = VolumeWriteHeader (FALSE,
128: header,
1.1.1.7 root 129: ea,
1.1.1.12 root 130: FIRST_MODE_OF_OPERATION_ID,
1.1.1.6 root 131: password,
1.1 root 132: pkcs5,
1.1.1.12 root 133: NULL,
1.1.1.4 root 134: &cryptoInfo,
1.1.1.12 root 135: size,
1.1.1.6 root 136: hiddenVol ? size : 0,
1.1.1.14! root 137: dataOffset,
1.1.1.12 root 138: size,
1.1.1.14! root 139: 0,
! 140: headerFlags,
1.1.1.6 root 141: FALSE);
1.1 root 142:
143: if (nStatus != 0)
1.1.1.3 root 144: {
145: burn (header, sizeof (header));
146: VirtualUnlock (header, sizeof (header));
1.1 root 147: return nStatus;
1.1.1.3 root 148: }
149:
1.1.1.12 root 150: begin_format:
151:
1.1.1.6 root 152: if (bDevice)
1.1.1.3 root 153: {
1.1.1.10 root 154: /* Device-hosted volume */
1.1.1.14! root 155:
1.1.1.11 root 156: DWORD dwResult;
1.1.1.10 root 157: int nPass;
158:
159: if (FakeDosNameForDevice (volumePath, dosDev, devName, FALSE) != 0)
1.1.1.14! root 160: return ERR_OS_ERROR;
1.1.1.10 root 161:
162: if (IsDeviceMounted (devName))
163: {
164: if ((dev = DismountDrive (devName)) == INVALID_HANDLE_VALUE)
1.1.1.4 root 165: {
1.1.1.11 root 166: Error ("FORMAT_CANT_DISMOUNT_FILESYS");
167: nStatus = ERR_DONT_REPORT;
168: goto error;
1.1.1.10 root 169: }
170: }
171: else if (nCurrentOS == WIN_VISTA_OR_LATER && driveLetter == -1)
172: {
173: // Windows Vista doesn't allow overwriting sectors belonging to an unformatted partition
174: // to which no drive letter has been assigned under the system. This problem can be worked
175: // around by assigning a drive letter to the partition temporarily.
176:
177: char szDriveLetter[] = { 'A', ':', 0 };
178: char rootPath[] = { 'A', ':', '\\', 0 };
179: char uniqVolName[MAX_PATH+1] = { 0 };
180: int tmpDriveLetter = -1;
181: BOOL bResult = FALSE;
182:
183: tmpDriveLetter = GetFirstAvailableDrive ();
184:
185: if (tmpDriveLetter != -1)
186: {
187: rootPath[0] += tmpDriveLetter;
188: szDriveLetter[0] += tmpDriveLetter;
189:
190: if (DefineDosDevice (DDD_RAW_TARGET_PATH, szDriveLetter, volumePath))
191: {
192: bResult = GetVolumeNameForVolumeMountPoint (rootPath, uniqVolName, MAX_PATH);
193:
194: DefineDosDevice (DDD_RAW_TARGET_PATH|DDD_REMOVE_DEFINITION|DDD_EXACT_MATCH_ON_REMOVE,
195: szDriveLetter,
196: volumePath);
197:
198: if (bResult
199: && SetVolumeMountPoint (rootPath, uniqVolName))
200: {
1.1.1.14! root 201: // The drive letter can be removed now
1.1.1.10 root 202: DeleteVolumeMountPoint (rootPath);
203: }
204: }
205: }
206: }
207:
208: // Perform open - 'quick format' - close - open to prevent Windows from restoring NTFS boot sector backup
209: for (nPass = 0; nPass < 2; nPass++)
210: {
1.1.1.14! root 211: int retryCount;
! 212:
! 213: retryCount = 0;
! 214:
1.1.1.10 root 215: // Try exclusive access mode first
1.1.1.14! root 216: // Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries).
! 217: while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES)
! 218: {
1.1.1.10 root 219: dev = CreateFile (devName, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
220:
1.1.1.14! root 221: if (retryCount > 1)
! 222: Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY);
! 223: }
! 224:
1.1.1.10 root 225: if (dev == INVALID_HANDLE_VALUE)
226: {
1.1.1.14! root 227: // Exclusive access denied -- retry in shared mode
1.1.1.10 root 228: dev = CreateFile (devName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
229: if (dev != INVALID_HANDLE_VALUE)
230: {
231: if (IDNO == MessageBoxW (hwndDlg, GetString ("DEVICE_IN_USE_FORMAT"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2))
232: {
233: nStatus = ERR_DONT_REPORT;
234: goto error;
235: }
236: }
237: else
238: {
1.1.1.14! root 239: nStatus = ERR_OS_ERROR;
1.1.1.10 root 240: goto error;
241: }
242: }
243:
1.1.1.12 root 244: if (hiddenVol || bInstantRetryOtherFilesys)
1.1.1.10 root 245: break; // The following "quick format" operation would damage the outer volume
246:
247: if (nPass == 0)
248: {
249: char buf[65536];
250: DWORD bw;
251:
252: // Pseudo "quick format" to prevent Windows from restoring NTFS boot sector backup
253: memset (buf, 0, sizeof (buf));
254: WriteFile (dev, buf, sizeof (buf), &bw, NULL);
255: FlushFileBuffers (dev);
256: CloseHandle (dev);
257: dev = INVALID_HANDLE_VALUE;
1.1.1.4 root 258: }
259: }
1.1.1.11 root 260:
261: if (DeviceIoControl (dev, FSCTL_IS_VOLUME_MOUNTED, NULL, 0, NULL, 0, &dwResult, NULL))
262: {
263: Error ("FORMAT_CANT_DISMOUNT_FILESYS");
264: nStatus = ERR_DONT_REPORT;
265: goto error;
266: }
1.1.1.3 root 267: }
268: else
269: {
1.1.1.10 root 270: /* File-hosted volume */
271:
1.1.1.4 root 272: // We could support FILE_ATTRIBUTE_HIDDEN as an option
273: // (Now if the container has hidden or system file attribute, the OS will not allow
274: // overwritting it; so the user will have to delete it manually).
1.1.1.10 root 275: dev = CreateFile (volumePath, GENERIC_WRITE,
1.1.1.12 root 276: (hiddenVol || bInstantRetryOtherFilesys) ? (FILE_SHARE_READ | FILE_SHARE_WRITE) : 0,
277: NULL, (hiddenVol || bInstantRetryOtherFilesys) ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
1.1.1.6 root 278:
1.1.1.8 root 279: if (dev == INVALID_HANDLE_VALUE)
280: {
1.1.1.14! root 281: nStatus = ERR_OS_ERROR;
1.1.1.8 root 282: goto error;
283: }
284:
1.1.1.12 root 285: if (!hiddenVol && !bInstantRetryOtherFilesys)
1.1.1.6 root 286: {
287: LARGE_INTEGER volumeSize;
1.1.1.14! root 288: volumeSize.QuadPart = size + TC_VOLUME_HEADER_GROUP_SIZE;
1.1.1.6 root 289:
1.1.1.8 root 290: if (sparseFileSwitch && quickFormat)
291: {
292: // Create as sparse file container
293: DWORD tmp;
294: if (!DeviceIoControl (dev, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &tmp, NULL))
295: {
1.1.1.14! root 296: nStatus = ERR_OS_ERROR;
1.1.1.8 root 297: goto error;
298: }
299: }
300:
301: // Preallocate the file
1.1.1.6 root 302: if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN)
303: || !SetEndOfFile (dev)
304: || SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0)
305: {
1.1.1.14! root 306: nStatus = ERR_OS_ERROR;
1.1.1.7 root 307: goto error;
1.1.1.6 root 308: }
309: }
1.1.1.3 root 310: }
311:
1.1.1.6 root 312: if (hiddenVol && !bDevice && bPreserveTimestamp)
1.1.1.4 root 313: {
314: /* Remember the container timestamp (used to reset file date and time of file-hosted
315: containers to preserve plausible deniability of hidden volume) */
316: if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
317: {
318: bTimeStampValid = FALSE;
1.1.1.6 root 319: MessageBoxW (hwndDlg, GetString ("GETFILETIME_FAILED_IMPLANT"), lpszTitle, MB_OK | MB_ICONEXCLAMATION);
1.1.1.4 root 320: }
321: else
322: bTimeStampValid = TRUE;
1.1.1.3 root 323: }
1.1 root 324:
325: KillTimer (hwndDlg, 0xff);
326:
1.1.1.6 root 327: /* Volume header */
1.1.1.4 root 328:
329: // Hidden volume setup
330: if (hiddenVol)
331: {
1.1.1.14! root 332: LARGE_INTEGER headerOffset;
! 333:
1.1.1.4 root 334: // Check hidden volume size
1.1.1.14! root 335: if (hiddenVolHostSize < TC_MIN_HIDDEN_VOLUME_HOST_SIZE || hiddenVolHostSize > TC_MAX_HIDDEN_VOLUME_HOST_SIZE)
1.1.1.4 root 336: {
1.1.1.7 root 337: nStatus = ERR_VOL_SIZE_WRONG;
338: goto error;
1.1.1.4 root 339: }
340:
341: // Seek to hidden volume header location
1.1.1.14! root 342:
! 343: headerOffset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET;
! 344:
! 345: if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
1.1.1.4 root 346: {
1.1.1.14! root 347: nStatus = ERR_OS_ERROR;
1.1.1.7 root 348: goto error;
1.1.1.4 root 349: }
350: }
1.1.1.12 root 351: else if (bInstantRetryOtherFilesys)
352: {
353: // The previous file system format failed and the user wants to try again with a different file system.
354: // The volume header had been written successfully so we need to seek to the byte after the header.
355:
1.1.1.14! root 356: LARGE_INTEGER offset;
! 357: offset.QuadPart = TC_VOLUME_DATA_OFFSET;
! 358: if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN))
1.1.1.12 root 359: {
1.1.1.14! root 360: nStatus = ERR_OS_ERROR;
1.1.1.12 root 361: goto error;
362: }
363: }
1.1.1.4 root 364:
1.1.1.12 root 365: if (!bInstantRetryOtherFilesys)
1.1.1.10 root 366: {
1.1.1.12 root 367: // Write the volume header
1.1.1.14! root 368: if (_lwrite ((HFILE) dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE) == HFILE_ERROR)
1.1.1.12 root 369: {
1.1.1.14! root 370: nStatus = ERR_OS_ERROR;
1.1.1.12 root 371: goto error;
372: }
1.1.1.4 root 373:
1.1.1.14! root 374: // To prevent fragmentation, write zeroes to reserved header sectors which are going to be filled with random data
! 375: if (!hiddenVol)
! 376: {
! 377: byte buf[TC_VOLUME_HEADER_GROUP_SIZE - TC_VOLUME_HEADER_EFFECTIVE_SIZE];
! 378: ZeroMemory (buf, sizeof (buf));
! 379: if (_lwrite ((HFILE) dev, buf, sizeof (buf)) == HFILE_ERROR)
! 380: {
! 381: nStatus = ERR_OS_ERROR;
! 382: goto error;
! 383: }
! 384: }
! 385: }
1.1.1.4 root 386:
387: if (hiddenVol)
388: {
389: // Calculate data area position of hidden volume
1.1.1.14! root 390: cryptoInfo->hiddenVolumeOffset = dataOffset;
1.1.1.4 root 391:
392: // Validate the offset
1.1.1.14! root 393: if (dataOffset % SECTOR_SIZE != 0)
1.1.1.4 root 394: {
1.1.1.6 root 395: nStatus = ERR_VOL_SIZE_WRONG;
396: goto error;
1.1.1.4 root 397: }
398:
399: quickFormat = TRUE; // To entirely format a hidden volume would be redundant
400: }
401:
1.1.1.14! root 402: /* Data area */
! 403: startSector = dataOffset / SECTOR_SIZE;
! 404:
1.1.1.4 root 405: // Format filesystem
406:
1.1.1.3 root 407: switch (fileSystem)
408: {
409: case FILESYS_NONE:
1.1.1.10 root 410: case FILESYS_NTFS:
1.1.1.8 root 411: nStatus = FormatNoFs (startSector, num_sectors, dev, cryptoInfo, quickFormat);
1.1.1.3 root 412: break;
1.1.1.10 root 413:
1.1.1.3 root 414: case FILESYS_FAT:
1.1.1.4 root 415: if (num_sectors > 0xFFFFffff)
416: {
1.1.1.6 root 417: nStatus = ERR_VOL_SIZE_WRONG;
418: goto error;
1.1.1.4 root 419: }
420:
421: // Calculate the fats, root dir etc
422: ft.num_sectors = (unsigned int) (num_sectors);
423: ft.cluster_size = clusterSize;
1.1.1.6 root 424: memcpy (ft.volume_name, "NO NAME ", 11);
1.1.1.4 root 425: GetFatParams (&ft);
426: *realClusterSize = ft.cluster_size * SECTOR_SIZE;
427:
1.1.1.8 root 428: nStatus = FormatFat (startSector, &ft, (void *) dev, cryptoInfo, quickFormat);
1.1.1.3 root 429: break;
1.1.1.13 root 430:
431: default:
432: nStatus = ERR_PARAMETER_INCORRECT;
433: goto error;
1.1.1.3 root 434: }
1.1 root 435:
1.1.1.14! root 436: // Write header backup
! 437: offset.QuadPart = hiddenVol ? hiddenVolHostSize - TC_HIDDEN_VOLUME_HEADER_OFFSET : size + TC_VOLUME_HEADER_GROUP_SIZE;
! 438:
! 439: if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN))
! 440: {
! 441: nStatus = ERR_OS_ERROR;
! 442: goto error;
! 443: }
! 444:
! 445: nStatus = VolumeWriteHeader (FALSE,
! 446: header,
! 447: ea,
! 448: FIRST_MODE_OF_OPERATION_ID,
! 449: password,
! 450: pkcs5,
! 451: cryptoInfo->master_keydata,
! 452: &cryptoInfo,
! 453: size,
! 454: hiddenVol ? size : 0,
! 455: dataOffset,
! 456: size,
! 457: 0,
! 458: headerFlags,
! 459: FALSE);
! 460:
! 461: if (_lwrite ((HFILE) dev, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE) == HFILE_ERROR)
! 462: {
! 463: nStatus = ERR_OS_ERROR;
! 464: goto error;
! 465: }
! 466:
! 467: // Fill reserved header sectors with random data
! 468: if (!hiddenVol)
! 469: {
! 470: char temporaryKey[MASTER_KEYDATA_SIZE];
! 471: char originalK2[MASTER_KEYDATA_SIZE];
! 472:
! 473: byte buf[TC_VOLUME_HEADER_GROUP_SIZE - TC_VOLUME_HEADER_EFFECTIVE_SIZE];
! 474: BOOL backupHeaders = FALSE;
! 475:
! 476: memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2));
! 477:
! 478: while (TRUE)
! 479: {
! 480: // Temporary keys
! 481: if (!RandgetBytes (temporaryKey, EAGetKeySize (cryptoInfo->ea), TRUE)
! 482: || !RandgetBytes (cryptoInfo->k2, sizeof (cryptoInfo->k2), FALSE))
! 483: {
! 484: nStatus = ERR_PARAMETER_INCORRECT;
! 485: goto error;
! 486: }
! 487:
! 488: nStatus = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
! 489: if (nStatus != ERR_SUCCESS)
! 490: goto error;
! 491:
! 492: if (!EAInitMode (cryptoInfo))
! 493: {
! 494: nStatus = ERR_MODE_INIT_FAILED;
! 495: goto error;
! 496: }
! 497:
! 498: offset.QuadPart = backupHeaders ? size + TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
! 499: offset.QuadPart += TC_VOLUME_HEADER_EFFECTIVE_SIZE;
! 500:
! 501: if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN))
! 502: {
! 503: nStatus = ERR_OS_ERROR;
! 504: goto error;
! 505: }
! 506:
! 507: EncryptBuffer (buf, sizeof (buf), cryptoInfo);
! 508:
! 509: if (_lwrite ((HFILE) dev, buf, sizeof (buf)) == HFILE_ERROR)
! 510: {
! 511: nStatus = ERR_OS_ERROR;
! 512: goto error;
! 513: }
! 514:
! 515: if (backupHeaders)
! 516: break;
! 517:
! 518: backupHeaders = TRUE;
! 519: }
! 520:
! 521: memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2));
! 522:
! 523: nStatus = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks);
! 524: if (nStatus != ERR_SUCCESS)
! 525: goto error;
! 526:
! 527: if (!EAInitMode (cryptoInfo))
! 528: {
! 529: nStatus = ERR_MODE_INIT_FAILED;
! 530: goto error;
! 531: }
! 532:
! 533: burn (temporaryKey, sizeof (temporaryKey));
! 534: burn (originalK2, sizeof (originalK2));
! 535: }
! 536:
1.1.1.10 root 537: error:
538: dwError = GetLastError();
1.1.1.3 root 539:
540: burn (header, sizeof (header));
541: VirtualUnlock (header, sizeof (header));
1.1 root 542:
1.1.1.11 root 543: if (dev != INVALID_HANDLE_VALUE)
1.1.1.4 root 544: {
1.1.1.11 root 545: if (!bDevice && !hiddenVol && nStatus != 0)
546: {
547: // Remove preallocated part before closing file handle if format failed
548: if (SetFilePointer (dev, 0, NULL, FILE_BEGIN) == 0)
549: SetEndOfFile (dev);
550: }
1.1.1.6 root 551:
1.1.1.11 root 552: FlushFileBuffers (dev);
1.1.1.4 root 553:
1.1.1.11 root 554: if (bTimeStampValid)
555: {
556: // Restore the container timestamp (to preserve plausible deniability of the hidden volume)
557: if (SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
558: MessageBoxW (hwndDlg, GetString ("SETFILETIME_FAILED_IMPLANT"), lpszTitle, MB_OK | MB_ICONEXCLAMATION);
559: }
560:
561: CloseHandle (dev);
562: dev = INVALID_HANDLE_VALUE;
563: }
1.1 root 564:
1.1.1.6 root 565: if (nStatus != 0)
1.1.1.3 root 566: {
1.1.1.10 root 567: SetLastError(dwError);
1.1.1.12 root 568: goto fv_end;
1.1.1.10 root 569: }
1.1.1.6 root 570:
1.1.1.10 root 571: if (fileSystem == FILESYS_NTFS)
572: {
573: // Quick-format volume as NTFS
574: int driveNo = GetLastAvailableDrive ();
575: MountOptions mountOptions;
576: int retCode;
1.1.1.3 root 577:
1.1.1.10 root 578: ZeroMemory (&mountOptions, sizeof (mountOptions));
1.1.1.5 root 579:
1.1.1.10 root 580: if (driveNo == -1)
581: {
582: MessageBoxW (hwndDlg, GetString ("NO_FREE_DRIVES"), lpszTitle, ICON_HAND);
583: MessageBoxW (hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND);
1.1.1.3 root 584:
1.1.1.12 root 585: nStatus = ERR_NO_FREE_DRIVES;
586: goto fv_end;
1.1.1.10 root 587: }
1.1.1.4 root 588:
1.1.1.10 root 589: mountOptions.ReadOnly = FALSE;
590: mountOptions.Removable = FALSE;
591: mountOptions.ProtectHiddenVolume = FALSE;
592: mountOptions.PreserveTimestamp = bPreserveTimestamp;
1.1.1.13 root 593: mountOptions.PartitionInInactiveSysEncScope = FALSE;
1.1.1.14! root 594: mountOptions.UseBackupHeader = FALSE;
1.1.1.3 root 595:
1.1.1.10 root 596: if (MountVolume (hwndDlg, driveNo, volumePath, password, FALSE, TRUE, &mountOptions, FALSE, TRUE) < 1)
597: {
598: MessageBoxW (hwndDlg, GetString ("CANT_MOUNT_VOLUME"), lpszTitle, ICON_HAND);
599: MessageBoxW (hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND);
1.1.1.12 root 600: nStatus = ERR_VOL_MOUNT_FAILED;
601: goto fv_end;
1.1.1.10 root 602: }
1.1.1.3 root 603:
1.1.1.10 root 604: if (!IsAdmin () && IsUacSupported ())
605: retCode = UacFormatNtfs (hwndDlg, driveNo, clusterSize);
606: else
607: retCode = FormatNtfs (driveNo, clusterSize);
1.1.1.3 root 608:
1.1.1.10 root 609: if (retCode != TRUE)
610: {
611: if (!UnmountVolume (hwndDlg, driveNo, FALSE))
612: MessageBoxW (hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND);
1.1.1.3 root 613:
1.1.1.14! root 614: if (size <= TC_MAX_FAT_FS_SIZE)
1.1.1.12 root 615: {
616: if (AskErrYesNo ("FORMAT_NTFS_FAILED_ASK_FAT") == IDYES)
617: {
618: // NTFS format failed and the user wants to try FAT format immediately
619: fileSystem = FILESYS_FAT;
620: bInstantRetryOtherFilesys = TRUE;
621: quickFormat = TRUE; // Volume has already been successfully TC-formatted
622: clusterSize = 0; // Default cluster size
623: goto begin_format;
624: }
625: }
626: else
627: Error ("FORMAT_NTFS_FAILED");
628:
629: nStatus = ERR_DONT_REPORT;
630: goto fv_end;
1.1.1.3 root 631: }
1.1.1.10 root 632:
633: if (!UnmountVolume (hwndDlg, driveNo, FALSE))
634: MessageBoxW (hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND);
1.1.1.3 root 635: }
636:
1.1.1.12 root 637: fv_end:
638:
639: if (dosDev[0])
640: RemoveFakeDosName (volumePath, dosDev);
641:
642: crypto_close (cryptoInfo);
643:
1.1 root 644: return nStatus;
1.1.1.3 root 645: }
1.1 root 646:
1.1.1.3 root 647:
1.1.1.8 root 648: int FormatNoFs (unsigned __int64 startSector, __int64 num_sectors, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat)
1.1.1.3 root 649: {
650: int write_buf_cnt = 0;
1.1.1.14! root 651: char sector[SECTOR_SIZE], write_buf[WRITE_BUF_SIZE];
1.1.1.4 root 652: unsigned __int64 nSecNo = startSector;
1.1.1.12 root 653: int retVal = 0;
654: char temporaryKey[MASTER_KEYDATA_SIZE];
655: char originalK2[MASTER_KEYDATA_SIZE];
1.1.1.4 root 656:
1.1.1.8 root 657: LARGE_INTEGER startOffset;
658: LARGE_INTEGER newOffset;
659:
1.1.1.4 root 660: // Seek to start sector
661: startOffset.QuadPart = startSector * SECTOR_SIZE;
1.1.1.6 root 662: if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN)
663: || newOffset.QuadPart != startOffset.QuadPart)
1.1.1.4 root 664: {
1.1.1.14! root 665: return ERR_OS_ERROR;
1.1.1.4 root 666: }
1.1.1.12 root 667:
668: VirtualLock (temporaryKey, sizeof (temporaryKey));
669: VirtualLock (originalK2, sizeof (originalK2));
1.1.1.3 root 670:
671: memset (sector, 0, sizeof (sector));
672:
1.1.1.12 root 673: // Remember the original secondary key (XTS mode) before generating a temporary one
674: memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2));
675:
1.1.1.7 root 676: /* Fill the rest of the data area with random data */
677:
1.1.1.3 root 678: if(!quickFormat)
679: {
1.1.1.7 root 680: /* Generate a random temporary key set to be used for "dummy" encryption that will fill
681: the free disk space (data area) with random data. This is necessary for plausible
1.1.1.12 root 682: deniability of hidden volumes. */
1.1.1.6 root 683:
1.1.1.9 root 684: // Temporary master key
685: if (!RandgetBytes (temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE))
686: goto fail;
1.1.1.12 root 687:
688: // Temporary secondary key (XTS mode)
689: if (!RandgetBytes (cryptoInfo->k2, sizeof cryptoInfo->k2, FALSE))
1.1.1.9 root 690: goto fail;
1.1.1.7 root 691:
692: retVal = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
1.1.1.12 root 693: if (retVal != ERR_SUCCESS)
694: goto fail;
695:
1.1.1.7 root 696: if (!EAInitMode (cryptoInfo))
697: {
1.1.1.12 root 698: retVal = ERR_MODE_INIT_FAILED;
699: goto fail;
1.1.1.7 root 700: }
1.1.1.4 root 701:
1.1.1.3 root 702: while (num_sectors--)
703: {
1.1.1.12 root 704: /* Generate random plaintext. Note that reused plaintext blocks are not a concern here
705: since XTS mode is designed to hide patterns. Furthermore, patterns in plaintext do
706: occur commonly on media in the "real world", so it might actually be a fatal mistake
707: to try to avoid them completely. */
1.1.1.9 root 708:
1.1.1.12 root 709: #if RNG_POOL_SIZE < SECTOR_SIZE
710: #error RNG_POOL_SIZE < SECTOR_SIZE
1.1.1.7 root 711: #endif
712:
1.1.1.12 root 713: if (!RandpeekBytes (sector, SECTOR_SIZE))
1.1.1.9 root 714: goto fail;
1.1.1.14! root 715:
1.1.1.7 root 716: // Encrypt the random plaintext and write it to the disk
1.1.1.6 root 717: if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
1.1.1.8 root 718: cryptoInfo) == FALSE)
1.1.1.3 root 719: goto fail;
720: }
1.1.1.14! root 721:
! 722: if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo))
1.1.1.3 root 723: goto fail;
724: }
725: else
726: nSecNo = num_sectors;
727:
728: UpdateProgressBar (nSecNo);
729:
1.1.1.12 root 730: // Restore the original secondary key (XTS mode) in case NTFS format fails and the user wants to try FAT immediately
731: memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2));
732:
733: // Reinitialize the encryption algorithm and mode in case NTFS format fails and the user wants to try FAT immediately
734: retVal = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks);
735: if (retVal != ERR_SUCCESS)
736: goto fail;
737: if (!EAInitMode (cryptoInfo))
738: {
739: retVal = ERR_MODE_INIT_FAILED;
740: goto fail;
741: }
742:
1.1.1.7 root 743: burn (temporaryKey, sizeof(temporaryKey));
1.1.1.12 root 744: burn (originalK2, sizeof(originalK2));
745: VirtualUnlock (temporaryKey, sizeof (temporaryKey));
746: VirtualUnlock (originalK2, sizeof (originalK2));
1.1.1.3 root 747: return 0;
748:
749: fail:
750:
1.1.1.7 root 751: burn (temporaryKey, sizeof(temporaryKey));
1.1.1.12 root 752: burn (originalK2, sizeof(originalK2));
753: VirtualUnlock (temporaryKey, sizeof (temporaryKey));
754: VirtualUnlock (originalK2, sizeof (originalK2));
755: return (retVal ? retVal : ERR_OS_ERROR);
1.1 root 756: }
1.1.1.3 root 757:
758:
759: volatile BOOLEAN FormatExResult;
760:
761: BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID parameter)
762: {
763: if (command == FMIFS_DONE)
764: FormatExResult = *(BOOLEAN *) parameter;
765: return TRUE;
766: }
767:
768: BOOL FormatNtfs (int driveNo, int clusterSize)
769: {
770: WCHAR dir[8] = { driveNo + 'A', 0 };
771: PFORMATEX FormatEx;
772: HMODULE hModule = LoadLibrary ("fmifs.dll");
1.1.1.10 root 773: int i;
1.1.1.3 root 774:
775: if (hModule == NULL)
776: return FALSE;
777:
778: if (!(FormatEx = (void *) GetProcAddress (GetModuleHandle("fmifs.dll"), "FormatEx")))
779: {
780: FreeLibrary (hModule);
781: return FALSE;
782: }
783:
784: wcscat (dir, L":\\");
785:
786: FormatExResult = FALSE;
787:
1.1.1.12 root 788: // Windows sometimes fails to format a volume (hosted on a removable medium) as NTFS.
1.1.1.10 root 789: // It often helps to retry several times.
790: for (i = 0; i < 10 && FormatExResult != TRUE; i++)
791: {
1.1.1.11 root 792: FormatEx (dir, FMIFS_HARDDISK, L"NTFS", L"", TRUE, clusterSize * SECTOR_SIZE, FormatExCallback);
1.1.1.10 root 793: }
1.1.1.3 root 794:
795: FreeLibrary (hModule);
796: return FormatExResult;
797: }
798:
1.1.1.8 root 799:
1.1.1.12 root 800: BOOL WriteSector (void *dev, char *sector,
1.1.1.3 root 801: char *write_buf, int *write_buf_cnt,
1.1.1.8 root 802: __int64 *nSecNo, PCRYPTO_INFO cryptoInfo)
1.1.1.3 root 803: {
1.1.1.8 root 804: static __int32 updateTime = 0;
1.1.1.4 root 805:
1.1.1.12 root 806: (*nSecNo)++;
1.1.1.4 root 807:
1.1.1.3 root 808: memcpy (write_buf + *write_buf_cnt, sector, SECTOR_SIZE);
809: (*write_buf_cnt) += SECTOR_SIZE;
810:
1.1.1.14! root 811: if (*write_buf_cnt == WRITE_BUF_SIZE && !FlushFormatWriteBuffer (dev, write_buf, write_buf_cnt, nSecNo, cryptoInfo))
! 812: return FALSE;
1.1.1.6 root 813:
814: if (GetTickCount () - updateTime > 25)
1.1.1.3 root 815: {
1.1.1.6 root 816: if (UpdateProgressBar (*nSecNo))
1.1.1.3 root 817: return FALSE;
1.1.1.6 root 818:
819: updateTime = GetTickCount ();
1.1.1.3 root 820: }
821:
822: return TRUE;
823:
824: }
1.1.1.14! root 825:
! 826:
! 827: BOOL FlushFormatWriteBuffer (void *dev, char *write_buf, int *write_buf_cnt, __int64 *nSecNo, PCRYPTO_INFO cryptoInfo)
! 828: {
! 829: UINT64_STRUCT unitNo;
! 830: DWORD bytesWritten;
! 831:
! 832: if (*write_buf_cnt == 0)
! 833: return TRUE;
! 834:
! 835: unitNo.Value = (*nSecNo - *write_buf_cnt / SECTOR_SIZE) * SECTOR_SIZE / ENCRYPTION_DATA_UNIT_SIZE;
! 836:
! 837: EncryptDataUnits (write_buf, &unitNo, *write_buf_cnt / ENCRYPTION_DATA_UNIT_SIZE, cryptoInfo);
! 838:
! 839: if (!WriteFile ((HANDLE) dev, write_buf, *write_buf_cnt, &bytesWritten, NULL))
! 840: return FALSE;
! 841:
! 842: *write_buf_cnt = 0;
! 843: return TRUE;
! 844: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.