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