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