|
|
1.1.1.3 root 1: /* The source code contained in this file has been derived from the source code
2: of Encryption for the Masses 2.02a by Paul Le Roux. Modifications and
3: additions to that source code contained in this file are Copyright (c) 2004
1.1.1.4 ! root 4: TrueCrypt Foundation and Copyright (c) 2004 TrueCrypt Team. Unmodified
1.1.1.3 root 5: parts are Copyright (c) 1998-99 Paul Le Roux. This is a TrueCrypt Foundation
6: release. Please see the file license.txt for full license details. */
1.1 root 7:
8: #include "TCdefs.h"
9:
10: #include "crypto.h"
11: #include "fat.h"
12: #include "format.h"
13: #include "volumes.h"
14: #include "progress.h"
15: #include "apidrvr.h"
16: #include "dlgcode.h"
1.1.1.4 ! root 17: #include "resource.h"
1.1 root 18:
1.1.1.3 root 19:
1.1 root 20: int
21: FormatVolume (char *lpszFilename,
22: BOOL bDevice,
1.1.1.3 root 23: char *volumePath,
1.1 root 24: unsigned __int64 size,
1.1.1.4 ! root 25: unsigned __int64 hiddenVolHostSize,
1.1 root 26: char *lpszPassword,
27: int cipher,
28: int pkcs5,
29: BOOL quickFormat,
1.1.1.3 root 30: int fileSystem,
31: int clusterSize,
32: char * summaryMsg,
1.1.1.4 ! root 33: HWND hwndDlg,
! 34: BOOL hiddenVol,
! 35: int *realClusterSize)
1.1 root 36: {
37: int nStatus;
38: PCRYPTO_INFO cryptoInfo;
1.1.1.4 ! root 39: HANDLE dev = INVALID_HANDLE_VALUE;
1.1 root 40: OPEN_TEST_STRUCT driver;
1.1.1.3 root 41: DWORD dwError, dwThen, dwNow;
1.1 root 42: diskio_f write;
1.1.1.3 root 43: char header[SECTOR_SIZE];
1.1.1.4 ! root 44: unsigned __int64 num_sectors, startSector;
1.1.1.3 root 45: fatparams ft;
1.1.1.4 ! root 46: FILETIME ftCreationTime;
! 47: FILETIME ftLastWriteTime;
! 48: FILETIME ftLastAccessTime;
! 49: BOOL bTimeStampValid = FALSE;
1.1.1.3 root 50:
1.1.1.4 ! root 51: if (!hiddenVol)
! 52: size -= HEADER_SIZE;
1.1 root 53:
1.1.1.4 ! root 54: num_sectors = size / SECTOR_SIZE;
1.1.1.3 root 55: VirtualLock (header, sizeof (header));
1.1 root 56:
1.1.1.3 root 57: /* Copies any header structures into header, but does not do any
1.1 root 58: disk io */
1.1.1.3 root 59: nStatus = VolumeWriteHeader (header,
1.1 root 60: cipher,
61: lpszPassword,
62: pkcs5,
63: 0,
64: 0,
1.1.1.4 ! root 65: &cryptoInfo,
! 66: hiddenVol ? size : 0);
1.1 root 67:
68: if (nStatus != 0)
1.1.1.3 root 69: {
70: burn (header, sizeof (header));
71: VirtualUnlock (header, sizeof (header));
1.1 root 72: return nStatus;
1.1.1.3 root 73: }
74:
75: write = (diskio_f) _lwrite;
76:
77: if (bDevice == TRUE)
78: {
79: dev = CreateFile (lpszFilename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
1.1.1.4 ! root 80: if (dev == INVALID_HANDLE_VALUE)
! 81: {
! 82: // Try opening device in shared mode
! 83: dev = CreateFile (lpszFilename, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
! 84: if (dev != INVALID_HANDLE_VALUE)
! 85: {
! 86: if (IDNO == MessageBox (hwndDlg, getstr (IDS_DEVICE_IN_USE_FORMAT), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2))
! 87: {
! 88: CloseHandle (dev);
! 89: dev = INVALID_HANDLE_VALUE;
! 90: }
! 91: }
! 92: }
1.1.1.3 root 93: }
94: else
95: {
1.1.1.4 ! root 96: // We could support FILE_ATTRIBUTE_HIDDEN as an option
! 97: // (Now if the container has hidden or system file attribute, the OS will not allow
! 98: // overwritting it; so the user will have to delete it manually).
! 99: dev = CreateFile (lpszFilename, GENERIC_WRITE,
! 100: hiddenVol ? (FILE_SHARE_READ | FILE_SHARE_WRITE) : 0,
! 101: NULL, hiddenVol ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
1.1.1.3 root 102: }
103:
104: if (dev == INVALID_HANDLE_VALUE)
105: {
1.1.1.4 ! root 106: nStatus = ERR_OS_ERROR; goto error;
! 107: }
! 108:
! 109: if (hiddenVol && !bDevice)
! 110: {
! 111: /* Remember the container timestamp (used to reset file date and time of file-hosted
! 112: containers to preserve plausible deniability of hidden volume) */
! 113: if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
! 114: {
! 115: bTimeStampValid = FALSE;
! 116: MessageBox (hwndDlg, getstr (IDS_GETFILETIME_FAILED_IMPLANT), "TrueCrypt", MB_OK | MB_ICONEXCLAMATION);
! 117: }
! 118: else
! 119: bTimeStampValid = TRUE;
1.1.1.3 root 120: }
1.1 root 121:
122: KillTimer (hwndDlg, 0xff);
123:
1.1.1.3 root 124: InitProgressBar (num_sectors);
125: dwThen = GetTickCount ();
1.1.1.2 root 126:
1.1.1.4 ! root 127:
! 128: //// Volume header
! 129:
! 130: // Hidden volume setup
! 131: if (hiddenVol)
! 132: {
! 133: // Check hidden volume size
! 134: if (hiddenVolHostSize < MIN_HIDDEN_VOLUME_HOST_SIZE || hiddenVolHostSize > MAX_HIDDEN_VOLUME_HOST_SIZE)
! 135: {
! 136: nStatus = ERR_VOL_SIZE_WRONG; goto error;
! 137: }
! 138:
! 139: // Seek to hidden volume header location
! 140: if (!SeekHiddenVolHeader ((HFILE) dev, hiddenVolHostSize, bDevice))
! 141: {
! 142: nStatus = ERR_VOL_SEEKING; goto error;
! 143: }
! 144:
! 145: }
! 146:
! 147: // Write the volume header
! 148: if ((*write) ((HFILE) dev, header, HEADER_SIZE) == HFILE_ERROR)
! 149: return ERR_OS_ERROR;
! 150:
! 151:
! 152: //// Data area
! 153:
! 154: startSector = 1; // Data area of normal volume starts right after volume header
! 155:
! 156: if (hiddenVol)
! 157: {
! 158: // Calculate data area position of hidden volume
! 159: unsigned __int64 startOffset = hiddenVolHostSize - size - HIDDEN_VOL_HEADER_OFFSET;
! 160:
! 161: // Validate the offset
! 162: if (startOffset % SECTOR_SIZE != 0)
! 163: {
! 164: nStatus = ERR_VOL_SIZE_WRONG; goto error;
! 165: }
! 166:
! 167: startSector = startOffset / SECTOR_SIZE;
! 168: quickFormat = TRUE; // To entirely format a hidden volume would be redundant
! 169: }
! 170:
! 171: // Format filesystem
! 172:
1.1.1.3 root 173: switch (fileSystem)
174: {
175: case FILESYS_NONE:
1.1.1.4 ! root 176: case FILESYS_NTFS: // NTFS volume is just prepared for quick format performed by system
! 177: nStatus = FormatNoFs (startSector, num_sectors, (HFILE) dev, cryptoInfo, 1000, write, quickFormat);
1.1.1.3 root 178: break;
179:
180: case FILESYS_FAT:
1.1.1.4 ! root 181: if (num_sectors > 0xFFFFffff)
! 182: {
! 183: nStatus = ERR_VOL_SIZE_WRONG; goto error;
! 184: }
! 185:
! 186: // Calculate the fats, root dir etc
! 187: ft.num_sectors = (unsigned int) (num_sectors);
! 188: ft.cluster_size = clusterSize;
! 189: memcpy (ft.volume_name, " ", 11);
! 190: GetFatParams (&ft);
! 191: *realClusterSize = ft.cluster_size * SECTOR_SIZE;
! 192:
! 193: nStatus = FormatFat (startSector, &ft, (HFILE) dev, cryptoInfo, 1000, write, quickFormat);
1.1.1.3 root 194: break;
195: }
1.1 root 196:
1.1.1.4 ! root 197: error:
! 198:
1.1.1.3 root 199: dwNow = GetTickCount ();
200:
201: burn (header, sizeof (header));
202: VirtualUnlock (header, sizeof (header));
1.1 root 203:
204: crypto_close (cryptoInfo);
1.1.1.4 ! root 205:
! 206: if (bTimeStampValid)
! 207: {
! 208: // Restore the container timestamp (to preserve plausible deniability of the hidden volume)
! 209: if (SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
! 210: MessageBox (hwndDlg, getstr (IDS_SETFILETIME_FAILED_IMPLANT), "TrueCrypt", MB_OK | MB_ICONEXCLAMATION);
! 211: }
! 212:
1.1.1.3 root 213: CloseHandle (dev);
1.1 root 214:
1.1.1.3 root 215: dwError = GetLastError();
1.1 root 216:
217: if (nStatus!=0)
218: SetLastError(dwError);
1.1.1.3 root 219: else
220: {
221: switch (fileSystem)
222: {
223: case FILESYS_NONE:
224: sprintf (summaryMsg, "Volume size:\t\t%I64d sectors (%I64d MB)\nFile system:\t\tNone"
225: "\n\nFormatting took %lu seconds."
226: , num_sectors, num_sectors*512/1024/1024
227: , (dwNow - dwThen)/1000);
228: break;
229:
230: case FILESYS_FAT:
231: sprintf (summaryMsg,
232: "Volume size:\t\t%d sectors (%I64d MB)\nFile system:\t\tFAT%d\n"
233: "FAT size:\t\t%d bytes\nCluster size:\t\t%d bytes\nClusters available:\t%d"
234: "\n\nFormatting took %lu seconds."
235: , ft.num_sectors, ((__int64) ft.num_sectors*512)/1024/1024, ft.size_fat
236: , (int) (512*ft.fats*ft.fat_length),
237: (int) (512*ft.cluster_size), ft.cluster_count,
238: (dwNow - dwThen)/1000);
239: break;
240:
241: case FILESYS_NTFS:
242: {
1.1.1.4 ! root 243: // NTFS format is performed by system so we first need to mount the volume
! 244: int driveNo = GetLastAvailableDrive ();
1.1.1.3 root 245: DWORD os_error;
246: int err;
247:
248: if (driveNo == -1)
249: {
1.1.1.4 ! root 250: MessageBox (hwndDlg, "No free drive letter available. NTFS formatting cannot continue.", lpszTitle, ICON_HAND);
1.1.1.3 root 251: return ERR_NO_FREE_DRIVES;
252: }
253:
1.1.1.4 ! root 254: if (MountVolume (hwndDlg, driveNo, volumePath, lpszPassword, FALSE, TRUE, FALSE) < 1)
1.1.1.3 root 255: {
256: MessageBox (hwndDlg, "Cannot mount volume. NTFS formatting cannot continue.", lpszTitle, ICON_HAND);
257: return ERR_VOL_MOUNT_FAILED;
258: }
259:
1.1.1.4 ! root 260: // Quickformat volume as NTFS
1.1.1.3 root 261: if (!FormatNtfs (driveNo, clusterSize))
262: {
1.1.1.4 ! root 263: MessageBox (hwndDlg, "NTFS formatting failed.\nTry using FAT file system instead.", lpszTitle, MB_ICONERROR);
! 264:
! 265: if (!UnmountVolume (hwndDlg, driveNo, FALSE))
! 266: MessageBox (hwndDlg, "Volume dismount failed.", lpszTitle, MB_ICONERROR);
! 267:
1.1.1.3 root 268: return ERR_VOL_FORMAT_BAD;
269: }
270:
1.1.1.4 ! root 271: if (!UnmountVolume (hwndDlg, driveNo, FALSE))
! 272: MessageBox (hwndDlg, "Formatting succeeded but volume cannot be dismounted.", lpszTitle, MB_ICONEXCLAMATION);
1.1.1.3 root 273:
274: dwNow = GetTickCount ();
275:
276: sprintf (summaryMsg, "Volume size:\t\t%I64d sectors (%I64d MB)\nFile system:\t\tNTFS"
277: "\n\nFormatting took %lu seconds."
278: , num_sectors, num_sectors*512/1024/1024
279: , (dwNow - dwThen)/1000);
280:
281: break;
282: }
283: }
284: }
285:
1.1 root 286: return nStatus;
1.1.1.3 root 287: }
1.1 root 288:
1.1.1.3 root 289:
1.1.1.4 ! root 290: int FormatNoFs (unsigned __int64 startSector, __int64 num_sectors, HFILE dev, PCRYPTO_INFO cryptoInfo, int nFrequency, diskio_f write, BOOL quickFormat)
1.1.1.3 root 291: {
292: int write_buf_cnt = 0;
293: char sector[SECTOR_SIZE], *write_buf;
294: int progress = 0;
1.1.1.4 ! root 295: unsigned __int64 nSecNo = startSector;
! 296: LARGE_INTEGER startOffset;
! 297: LARGE_INTEGER newOffset;
! 298:
! 299: // Seek to start sector
! 300: startOffset.QuadPart = startSector * SECTOR_SIZE;
! 301: if (SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN) == 0
! 302: || newOffset.QuadPart != newOffset.QuadPart)
! 303: {
! 304: return ERR_VOL_SEEKING;
! 305: }
1.1.1.3 root 306:
307: write_buf = TCalloc (WRITE_BUF_SIZE);
308: memset (sector, 0, sizeof (sector));
309:
1.1.1.4 ! root 310: // Write sectors
1.1.1.3 root 311: if(!quickFormat)
312: {
1.1.1.4 ! root 313: /* Generate a random key and IV to be used for "dummy" encryption that will fill the
! 314: free disk space (data area) with random data. That will reduce the amount of
! 315: predictable plaintext within the volume and also increase the level of plausible
! 316: deniability of hidden volumes. */
! 317: char key[DISKKEY_SIZE];
! 318: RandgetBytes (key, DISKKEY_SIZE, FALSE);
! 319: RandgetBytes (cryptoInfo->iv, sizeof cryptoInfo->iv, FALSE);
! 320: EAInit (cryptoInfo->ea, key, cryptoInfo->ks);
! 321: RandgetBytes (sector, 256, FALSE);
! 322: RandgetBytes (sector + 256, 256, FALSE);
! 323:
1.1.1.3 root 324: while (num_sectors--)
325: {
326: if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, &progress,
327: cryptoInfo, nFrequency, write) == FALSE)
328: goto fail;
329: }
330: if (write_buf_cnt != 0 && (*write) (dev, write_buf, write_buf_cnt) == HFILE_ERROR)
331: goto fail;
332: }
333: else
334: nSecNo = num_sectors;
335:
336: UpdateProgressBar (nSecNo);
337:
338: TCfree (write_buf);
339: return 0;
340:
341: fail:
342:
343: TCfree (write_buf);
344: return ERR_OS_ERROR;
1.1 root 345: }
1.1.1.3 root 346:
347:
348: volatile BOOLEAN FormatExResult;
349:
350: BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID parameter)
351: {
352: if (command == FMIFS_DONE)
353: FormatExResult = *(BOOLEAN *) parameter;
354: return TRUE;
355: }
356:
357: BOOL FormatNtfs (int driveNo, int clusterSize)
358: {
359: WCHAR dir[8] = { driveNo + 'A', 0 };
360: PFORMATEX FormatEx;
361: HMODULE hModule = LoadLibrary ("fmifs.dll");
362:
363: if (hModule == NULL)
364: return FALSE;
365:
366: if (!(FormatEx = (void *) GetProcAddress (GetModuleHandle("fmifs.dll"), "FormatEx")))
367: {
368: FreeLibrary (hModule);
369: return FALSE;
370: }
371:
372: wcscat (dir, L":\\");
373:
374: FormatExResult = FALSE;
375:
376: if (*(char *)dir > 'C' && *(char *)dir <= 'Z')
377: FormatEx (dir, FMIFS_HARDDISK, L"NTFS", L"", TRUE, clusterSize * 512, FormatExCallback);
378:
379: FreeLibrary (hModule);
380: return FormatExResult;
381: }
382:
383: BOOL
384: WriteSector (HFILE dev, char *sector,
385: char *write_buf, int *write_buf_cnt,
386: __int64 *nSecNo, int *progress, PCRYPTO_INFO cryptoInfo,
387: int nFrequency, diskio_f write)
388: {
1.1.1.4 ! root 389:
! 390: EncryptSectors ((unsigned long *) sector,
! 391: (*nSecNo)++, 1, cryptoInfo->ks, cryptoInfo->iv, cryptoInfo->ea);
! 392:
1.1.1.3 root 393: memcpy (write_buf + *write_buf_cnt, sector, SECTOR_SIZE);
394: (*write_buf_cnt) += SECTOR_SIZE;
395:
396:
397: if (*write_buf_cnt == WRITE_BUF_SIZE)
398: {
399: if ((*write) (dev, write_buf, WRITE_BUF_SIZE) == HFILE_ERROR)
400: return FALSE;
401: else
402: *write_buf_cnt = 0;
403: }
404:
405: if (++(*progress) == nFrequency)
406: {
407: if (UpdateProgressBar (*nSecNo) == TRUE)
408: return FALSE;
409: *progress = 0;
410: }
411:
412: return TRUE;
413:
414: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.