|
|
1.1.1.6 root 1: /* Legal Notice: The source code contained in this file has been derived from
2: the source code of Encryption for the Masses 2.02a, which is Copyright (c)
3: 1998-99 Paul Le Roux and which is covered by the 'License Agreement for
4: Encryption for the Masses'. Modifications and additions to that source code
5: contained in this file are Copyright (c) 2004-2005 TrueCrypt Foundation and
6: Copyright (c) 2004 TrueCrypt Team, and are covered by TrueCrypt License 2.0
7: the full text of which is contained in the file License.txt included in
8: TrueCrypt binary and source code distribution archives. */
9:
10: #include "Tcdefs.h"
11:
12: #include "Crypto.h"
13: #include "Fat.h"
14: #include "Format.h"
15: #include "Volumes.h"
16: #include "Progress.h"
17: #include "Apidrvr.h"
18: #include "Dlgcode.h"
19: #include "Language.h"
20: #include "Resource.h"
21: #include "Common.h"
22: #include "Random.h"
1.1.1.3 root 23:
1.1 root 24: int
25: FormatVolume (char *lpszFilename,
26: BOOL bDevice,
1.1.1.3 root 27: char *volumePath,
1.1 root 28: unsigned __int64 size,
1.1.1.4 root 29: unsigned __int64 hiddenVolHostSize,
1.1.1.6 root 30: Password *password,
1.1.1.7 ! root 31: int ea,
1.1 root 32: int pkcs5,
33: BOOL quickFormat,
1.1.1.3 root 34: int fileSystem,
35: int clusterSize,
1.1.1.6 root 36: wchar_t *summaryMsg,
1.1.1.4 root 37: HWND hwndDlg,
38: BOOL hiddenVol,
39: int *realClusterSize)
1.1 root 40: {
41: int nStatus;
42: PCRYPTO_INFO cryptoInfo;
1.1.1.4 root 43: HANDLE dev = INVALID_HANDLE_VALUE;
1.1.1.3 root 44: DWORD dwError, dwThen, dwNow;
1.1 root 45: diskio_f write;
1.1.1.3 root 46: char header[SECTOR_SIZE];
1.1.1.4 root 47: unsigned __int64 num_sectors, startSector;
1.1.1.3 root 48: fatparams ft;
1.1.1.4 root 49: FILETIME ftCreationTime;
50: FILETIME ftLastWriteTime;
51: FILETIME ftLastAccessTime;
52: BOOL bTimeStampValid = FALSE;
1.1.1.3 root 53:
1.1.1.4 root 54: if (!hiddenVol)
55: size -= HEADER_SIZE;
1.1 root 56:
1.1.1.4 root 57: num_sectors = size / SECTOR_SIZE;
1.1.1.3 root 58: VirtualLock (header, sizeof (header));
1.1 root 59:
1.1.1.3 root 60: /* Copies any header structures into header, but does not do any
1.1 root 61: disk io */
1.1.1.3 root 62: nStatus = VolumeWriteHeader (header,
1.1.1.7 ! root 63: ea,
! 64: LRW, // The only supported mode of operation when creating new volumes
1.1.1.6 root 65: password,
1.1 root 66: pkcs5,
67: 0,
68: 0,
1.1.1.4 root 69: &cryptoInfo,
1.1.1.6 root 70: hiddenVol ? size : 0,
71: FALSE);
1.1 root 72:
73: if (nStatus != 0)
1.1.1.3 root 74: {
75: burn (header, sizeof (header));
76: VirtualUnlock (header, sizeof (header));
1.1 root 77: return nStatus;
1.1.1.3 root 78: }
79:
80: write = (diskio_f) _lwrite;
81:
1.1.1.6 root 82: if (bDevice)
1.1.1.3 root 83: {
84: dev = CreateFile (lpszFilename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
1.1.1.4 root 85: if (dev == INVALID_HANDLE_VALUE)
86: {
1.1.1.7 ! root 87: // Try opening the device in shared mode
1.1.1.4 root 88: dev = CreateFile (lpszFilename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
89: if (dev != INVALID_HANDLE_VALUE)
90: {
1.1.1.6 root 91: if (IDNO == MessageBoxW (hwndDlg, GetString ("DEVICE_IN_USE_FORMAT"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2))
1.1.1.4 root 92: {
93: CloseHandle (dev);
94: dev = INVALID_HANDLE_VALUE;
95: }
96: }
97: }
1.1.1.3 root 98: }
99: else
100: {
1.1.1.4 root 101: // We could support FILE_ATTRIBUTE_HIDDEN as an option
102: // (Now if the container has hidden or system file attribute, the OS will not allow
103: // overwritting it; so the user will have to delete it manually).
104: dev = CreateFile (lpszFilename, GENERIC_WRITE,
105: hiddenVol ? (FILE_SHARE_READ | FILE_SHARE_WRITE) : 0,
106: NULL, hiddenVol ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
1.1.1.6 root 107:
108: if (!hiddenVol)
109: {
1.1.1.7 ! root 110: // Preallocate the file
1.1.1.6 root 111: LARGE_INTEGER volumeSize;
112: volumeSize.QuadPart = size;
113:
114: if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN)
115: || !SetEndOfFile (dev)
116: || SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0)
117: {
118: handleWin32Error (hwndDlg);
1.1.1.7 ! root 119: nStatus = ERR_OS_ERROR;
! 120: goto error;
1.1.1.6 root 121: }
122: }
1.1.1.3 root 123: }
124:
125: if (dev == INVALID_HANDLE_VALUE)
126: {
1.1.1.6 root 127: handleWin32Error (hwndDlg);
128: nStatus = ERR_OS_ERROR;
129: goto error;
1.1.1.4 root 130: }
131:
1.1.1.6 root 132: if (hiddenVol && !bDevice && bPreserveTimestamp)
1.1.1.4 root 133: {
134: /* Remember the container timestamp (used to reset file date and time of file-hosted
135: containers to preserve plausible deniability of hidden volume) */
136: if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
137: {
138: bTimeStampValid = FALSE;
1.1.1.6 root 139: MessageBoxW (hwndDlg, GetString ("GETFILETIME_FAILED_IMPLANT"), lpszTitle, MB_OK | MB_ICONEXCLAMATION);
1.1.1.4 root 140: }
141: else
142: bTimeStampValid = TRUE;
1.1.1.3 root 143: }
1.1 root 144:
145: KillTimer (hwndDlg, 0xff);
146:
1.1.1.3 root 147: InitProgressBar (num_sectors);
148: dwThen = GetTickCount ();
1.1.1.2 root 149:
1.1.1.4 root 150:
1.1.1.6 root 151: /* Volume header */
1.1.1.4 root 152:
153: // Hidden volume setup
154: if (hiddenVol)
155: {
156: // Check hidden volume size
157: if (hiddenVolHostSize < MIN_HIDDEN_VOLUME_HOST_SIZE || hiddenVolHostSize > MAX_HIDDEN_VOLUME_HOST_SIZE)
158: {
1.1.1.7 ! root 159: nStatus = ERR_VOL_SIZE_WRONG;
! 160: goto error;
1.1.1.4 root 161: }
162:
163: // Seek to hidden volume header location
164: if (!SeekHiddenVolHeader ((HFILE) dev, hiddenVolHostSize, bDevice))
165: {
1.1.1.7 ! root 166: nStatus = ERR_VOL_SEEKING;
! 167: goto error;
1.1.1.4 root 168: }
169:
170: }
171:
172: // Write the volume header
173: if ((*write) ((HFILE) dev, header, HEADER_SIZE) == HFILE_ERROR)
174: return ERR_OS_ERROR;
175:
176:
1.1.1.6 root 177: /* Data area */
1.1.1.4 root 178:
179: startSector = 1; // Data area of normal volume starts right after volume header
180:
181: if (hiddenVol)
182: {
183: // Calculate data area position of hidden volume
184: unsigned __int64 startOffset = hiddenVolHostSize - size - HIDDEN_VOL_HEADER_OFFSET;
1.1.1.7 ! root 185: cryptoInfo->hiddenVolumeOffset = startOffset;
1.1.1.4 root 186:
187: // Validate the offset
188: if (startOffset % SECTOR_SIZE != 0)
189: {
1.1.1.6 root 190: nStatus = ERR_VOL_SIZE_WRONG;
191: goto error;
1.1.1.4 root 192: }
193:
194: startSector = startOffset / SECTOR_SIZE;
195: quickFormat = TRUE; // To entirely format a hidden volume would be redundant
196: }
197:
198: // Format filesystem
199:
1.1.1.3 root 200: switch (fileSystem)
201: {
202: case FILESYS_NONE:
1.1.1.4 root 203: case FILESYS_NTFS: // NTFS volume is just prepared for quick format performed by system
1.1.1.6 root 204: nStatus = FormatNoFs (startSector, num_sectors, (HFILE) dev, cryptoInfo, write, quickFormat);
1.1.1.3 root 205: break;
206:
207: case FILESYS_FAT:
1.1.1.4 root 208: if (num_sectors > 0xFFFFffff)
209: {
1.1.1.6 root 210: nStatus = ERR_VOL_SIZE_WRONG;
211: goto error;
1.1.1.4 root 212: }
213:
214: // Calculate the fats, root dir etc
215: ft.num_sectors = (unsigned int) (num_sectors);
216: ft.cluster_size = clusterSize;
1.1.1.6 root 217: memcpy (ft.volume_name, "NO NAME ", 11);
1.1.1.4 root 218: GetFatParams (&ft);
219: *realClusterSize = ft.cluster_size * SECTOR_SIZE;
220:
1.1.1.6 root 221: nStatus = FormatFat (startSector, &ft, (HFILE) dev, cryptoInfo, write, quickFormat);
1.1.1.3 root 222: break;
223: }
1.1 root 224:
1.1.1.4 root 225: error:
226:
1.1.1.3 root 227: dwNow = GetTickCount ();
228:
229: burn (header, sizeof (header));
230: VirtualUnlock (header, sizeof (header));
1.1 root 231:
232: crypto_close (cryptoInfo);
1.1.1.4 root 233:
234: if (bTimeStampValid)
235: {
236: // Restore the container timestamp (to preserve plausible deniability of the hidden volume)
237: if (SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
1.1.1.6 root 238: MessageBoxW (hwndDlg, GetString ("SETFILETIME_FAILED_IMPLANT"), lpszTitle, MB_OK | MB_ICONEXCLAMATION);
239: }
240:
241: if (!bDevice && !hiddenVol && nStatus != 0)
242: {
243: // Remove preallocated part before closing file handle if format failed
244: if (SetFilePointer (dev, 0, NULL, FILE_BEGIN) == 0)
245: SetEndOfFile (dev);
1.1.1.4 root 246: }
247:
1.1.1.3 root 248: CloseHandle (dev);
1.1 root 249:
1.1.1.3 root 250: dwError = GetLastError();
1.1 root 251:
1.1.1.6 root 252: if (nStatus != 0)
1.1 root 253: SetLastError(dwError);
1.1.1.3 root 254: else
255: {
256: switch (fileSystem)
257: {
258: case FILESYS_NONE:
1.1.1.6 root 259: swprintf (summaryMsg
260: , GetString ("FORMAT_STAT")
1.1.1.3 root 261: , num_sectors, num_sectors*512/1024/1024
1.1.1.6 root 262: , GetString ("NONE")
1.1.1.3 root 263: , (dwNow - dwThen)/1000);
264: break;
265:
266: case FILESYS_FAT:
1.1.1.6 root 267: swprintf (summaryMsg
268: , GetString ("FORMAT_STAT_FAT")
1.1.1.3 root 269: , ft.num_sectors, ((__int64) ft.num_sectors*512)/1024/1024, ft.size_fat
270: , (int) (512*ft.fats*ft.fat_length),
271: (int) (512*ft.cluster_size), ft.cluster_count,
272: (dwNow - dwThen)/1000);
273: break;
274:
275: case FILESYS_NTFS:
276: {
1.1.1.4 root 277: // NTFS format is performed by system so we first need to mount the volume
278: int driveNo = GetLastAvailableDrive ();
1.1.1.5 root 279: MountOptions mountOptions;
280:
1.1.1.3 root 281: if (driveNo == -1)
282: {
1.1.1.6 root 283: MessageBoxW (hwndDlg, GetString ("NO_FREE_DRIVES"), lpszTitle, ICON_HAND);
284: MessageBoxW (hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND);
285:
1.1.1.3 root 286: return ERR_NO_FREE_DRIVES;
287: }
288:
1.1.1.5 root 289: mountOptions.ReadOnly = FALSE;
290: mountOptions.Removable = FALSE;
1.1.1.6 root 291: mountOptions.ProtectHiddenVolume = FALSE;
292: mountOptions.PreserveTimestamp = bPreserveTimestamp;
1.1.1.5 root 293:
1.1.1.6 root 294: if (MountVolume (hwndDlg, driveNo, volumePath, password, FALSE, TRUE, &mountOptions, FALSE, TRUE) < 1)
1.1.1.3 root 295: {
1.1.1.6 root 296: MessageBoxW (hwndDlg, GetString ("CANT_MOUNT_VOLUME"), lpszTitle, ICON_HAND);
297: MessageBoxW (hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND);
1.1.1.3 root 298: return ERR_VOL_MOUNT_FAILED;
299: }
300:
1.1.1.7 ! root 301: // Quick-format volume as NTFS
1.1.1.3 root 302: if (!FormatNtfs (driveNo, clusterSize))
303: {
1.1.1.6 root 304: MessageBoxW (hwndDlg, GetString ("FORMAT_NTFS_FAILED"), lpszTitle, MB_ICONERROR);
1.1.1.4 root 305:
306: if (!UnmountVolume (hwndDlg, driveNo, FALSE))
1.1.1.6 root 307: MessageBoxW (hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND);
1.1.1.4 root 308:
1.1.1.3 root 309: return ERR_VOL_FORMAT_BAD;
310: }
311:
1.1.1.4 root 312: if (!UnmountVolume (hwndDlg, driveNo, FALSE))
1.1.1.6 root 313: MessageBoxW (hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND);
1.1.1.3 root 314:
315: dwNow = GetTickCount ();
316:
1.1.1.6 root 317: swprintf (summaryMsg,
318: GetString ("FORMAT_STAT")
319: , num_sectors
320: , num_sectors*512/1024/1024
321: , L"NTFS"
1.1.1.3 root 322: , (dwNow - dwThen)/1000);
323:
324: break;
325: }
326: }
327: }
328:
1.1 root 329: return nStatus;
1.1.1.3 root 330: }
1.1 root 331:
1.1.1.3 root 332:
1.1.1.6 root 333: int FormatNoFs (unsigned __int64 startSector, __int64 num_sectors, HFILE dev, PCRYPTO_INFO cryptoInfo, diskio_f write, BOOL quickFormat)
1.1.1.3 root 334: {
335: int write_buf_cnt = 0;
336: char sector[SECTOR_SIZE], *write_buf;
1.1.1.4 root 337: unsigned __int64 nSecNo = startSector;
338: LARGE_INTEGER startOffset;
339: LARGE_INTEGER newOffset;
1.1.1.6 root 340: int retVal;
1.1.1.7 ! root 341: char temporaryKey[DISKKEY_SIZE];
1.1.1.4 root 342:
343: // Seek to start sector
344: startOffset.QuadPart = startSector * SECTOR_SIZE;
1.1.1.6 root 345: if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN)
346: || newOffset.QuadPart != startOffset.QuadPart)
1.1.1.4 root 347: {
348: return ERR_VOL_SEEKING;
349: }
1.1.1.3 root 350:
351: write_buf = TCalloc (WRITE_BUF_SIZE);
352: memset (sector, 0, sizeof (sector));
353:
1.1.1.7 ! root 354: /* Fill the rest of the data area with random data */
! 355:
1.1.1.3 root 356: if(!quickFormat)
357: {
1.1.1.7 ! root 358: /* Generate a random temporary key set to be used for "dummy" encryption that will fill
! 359: the free disk space (data area) with random data. This is necessary for plausible
! 360: deniability of hidden volumes (and also reduces the amount of predictable plaintext
! 361: within the volume). */
1.1.1.6 root 362:
1.1.1.7 ! root 363: RandgetBytes (temporaryKey, DISKKEY_SIZE, FALSE); // Temporary master key
! 364: RandgetBytes (cryptoInfo->iv, sizeof cryptoInfo->iv, FALSE); // Secondary key (LRW mode)
! 365:
! 366: retVal = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
1.1.1.6 root 367: if (retVal != 0)
1.1.1.7 ! root 368: {
! 369: burn (temporaryKey, sizeof(temporaryKey));
1.1.1.6 root 370: return retVal;
1.1.1.7 ! root 371: }
! 372: if (!EAInitMode (cryptoInfo))
! 373: {
! 374: burn (temporaryKey, sizeof(temporaryKey));
! 375: return ERR_MODE_INIT_FAILED;
! 376: }
1.1.1.4 root 377:
1.1.1.3 root 378: while (num_sectors--)
379: {
1.1.1.7 ! root 380: /* Generate random plaintext. Note that reused plaintext blocks are not a concern
! 381: here since LRW mode is designed to hide patterns. Furthermore, patterns in plaintext
! 382: do occur commonly on media in the "real world", so it might actually be a fatal
! 383: mistake to try to avoid them completely. */
! 384: #if RNG_POOL_SIZE < SECTOR_SIZE
! 385: RandpeekBytes (sector, RNG_POOL_SIZE);
! 386: RandpeekBytes (sector + RNG_POOL_SIZE, SECTOR_SIZE - RNG_POOL_SIZE);
! 387: #else
! 388: RandpeekBytes (sector, SECTOR_SIZE);
! 389: #endif
! 390:
! 391: // Encrypt the random plaintext and write it to the disk
1.1.1.6 root 392: if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
393: cryptoInfo, write) == FALSE)
1.1.1.3 root 394: goto fail;
395: }
396: if (write_buf_cnt != 0 && (*write) (dev, write_buf, write_buf_cnt) == HFILE_ERROR)
397: goto fail;
398: }
399: else
400: nSecNo = num_sectors;
401:
402: UpdateProgressBar (nSecNo);
403:
404: TCfree (write_buf);
1.1.1.7 ! root 405: burn (temporaryKey, sizeof(temporaryKey));
1.1.1.3 root 406: return 0;
407:
408: fail:
409:
410: TCfree (write_buf);
1.1.1.7 ! root 411: burn (temporaryKey, sizeof(temporaryKey));
1.1.1.3 root 412: return ERR_OS_ERROR;
1.1 root 413: }
1.1.1.3 root 414:
415:
416: volatile BOOLEAN FormatExResult;
417:
418: BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID parameter)
419: {
420: if (command == FMIFS_DONE)
421: FormatExResult = *(BOOLEAN *) parameter;
422: return TRUE;
423: }
424:
425: BOOL FormatNtfs (int driveNo, int clusterSize)
426: {
427: WCHAR dir[8] = { driveNo + 'A', 0 };
428: PFORMATEX FormatEx;
429: HMODULE hModule = LoadLibrary ("fmifs.dll");
430:
431: if (hModule == NULL)
432: return FALSE;
433:
434: if (!(FormatEx = (void *) GetProcAddress (GetModuleHandle("fmifs.dll"), "FormatEx")))
435: {
436: FreeLibrary (hModule);
437: return FALSE;
438: }
439:
440: wcscat (dir, L":\\");
441:
442: FormatExResult = FALSE;
443:
444: if (*(char *)dir > 'C' && *(char *)dir <= 'Z')
445: FormatEx (dir, FMIFS_HARDDISK, L"NTFS", L"", TRUE, clusterSize * 512, FormatExCallback);
446:
447: FreeLibrary (hModule);
448: return FormatExResult;
449: }
450:
451: BOOL
452: WriteSector (HFILE dev, char *sector,
453: char *write_buf, int *write_buf_cnt,
1.1.1.6 root 454: __int64 *nSecNo, PCRYPTO_INFO cryptoInfo,
455: diskio_f write)
1.1.1.3 root 456: {
1.1.1.6 root 457: static DWORD updateTime = 0;
1.1.1.4 root 458:
1.1.1.6 root 459: EncryptSectors ((unsigned __int32 *) sector,
1.1.1.7 ! root 460: (*nSecNo)++, 1, cryptoInfo);
1.1.1.4 root 461:
1.1.1.3 root 462: memcpy (write_buf + *write_buf_cnt, sector, SECTOR_SIZE);
463: (*write_buf_cnt) += SECTOR_SIZE;
464:
465: if (*write_buf_cnt == WRITE_BUF_SIZE)
466: {
467: if ((*write) (dev, write_buf, WRITE_BUF_SIZE) == HFILE_ERROR)
468: return FALSE;
469: else
470: *write_buf_cnt = 0;
471: }
1.1.1.6 root 472:
473: if (GetTickCount () - updateTime > 25)
1.1.1.3 root 474: {
1.1.1.6 root 475: if (UpdateProgressBar (*nSecNo))
1.1.1.3 root 476: return FALSE;
1.1.1.6 root 477:
478: updateTime = GetTickCount ();
1.1.1.3 root 479: }
480:
481: return TRUE;
482:
483: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.