|
|
1.1 root 1: /*
2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
3:
1.1.1.5 ! root 4: Governed by the TrueCrypt License 2.5 the full text of which is contained
1.1 root 5: in the file License.txt included in TrueCrypt binary and source code
6: distribution packages.
7: */
8:
9: #include "Crc.h"
10: #include "Crypto.h"
11: #include "Password.h"
12: #include "Volumes.h"
13:
14: #include "Platform.h"
15: #include "Bios.h"
16: #include "BootConfig.h"
17: #include "BootMain.h"
18: #include "BootDefs.h"
19: #include "BootCommon.h"
20: #include "BootConsoleIo.h"
21: #include "BootDebug.h"
22: #include "BootDiskIo.h"
23: #include "BootEncryptedIo.h"
1.1.1.2 root 24: #include "BootMemory.h"
1.1 root 25: #include "IntFilter.h"
26:
27:
28: static void InitScreen ()
29: {
30: ClearScreen();
31:
1.1.1.5 ! root 32: Print (
! 33: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 34: " TrueCrypt Boot Loader "
! 35: #else
! 36: " TrueCrypt Rescue Disk "
! 37: #endif
! 38: VERSION_STRING " Copyright (C) 2008 TrueCrypt Foundation\r\n");
1.1 root 39:
1.1.1.5 ! root 40: PrintRepeatedChar ('\xDC', TC_BIOS_MAX_CHARS_PER_LINE);
1.1 root 41: PrintEndl (2);
42: }
43:
44:
45: static void PrintMainMenu ()
46: {
47: Print (" Keyboard Controls:\r\n");
1.1.1.5 ! root 48: Print (" [Esc] ");
! 49:
! 50: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 51:
! 52: Print ((BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) == TC_HIDDEN_OS_CREATION_PHASE_CLONING
! 53: ? "Postpone system cloning (boot now)"
! 54: : "Skip Authentication (Boot Manager)");
! 55:
! 56: #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 57:
! 58: Print ("Skip Authentication (Boot Manager)");
! 59: Print ("\r\n [F8] "); Print ("Repair Options");
! 60:
! 61: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1.1 root 62:
63: PrintEndl (3);
64: }
65:
66:
67: static bool IsMenuKey (byte scanCode)
68: {
1.1.1.5 ! root 69: #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1.1 root 70: return scanCode == TC_MENU_KEY_REPAIR;
1.1.1.5 ! root 71: #else
! 72: return false;
! 73: #endif
1.1 root 74: }
75:
76:
77: static bool AskYesNo (const char *message)
78: {
79: Print (message);
80: Print ("? (y/n): ");
81: while (true)
82: {
83: switch (GetKeyboardChar())
84: {
85: case 'y':
86: case 'Y':
1.1.1.3 root 87: case 'z':
1.1 root 88: PrintEndl();
89: return true;
90:
91: case 'n':
92: case 'N':
93: PrintEndl();
94: return false;
95:
96: default:
97: Beep();
98: }
99: }
100: }
101:
102:
103: static int AskSelection (const char *options[], size_t optionCount)
104: {
105: for (int i = 0; i < optionCount; ++i)
106: {
107: Print ("["); Print (i + 1); Print ("] ");
108: Print (options[i]);
109: PrintEndl();
110: }
111: Print ("[Esc] Cancel\r\n\r\n");
112:
113: Print ("To select, press 1-9: ");
114:
115: char str;
116:
117: while (true)
118: {
119: if (GetString (&str, 1) == 0)
120: return 0;
121:
122: if (str >= '1' && str <= optionCount + '0')
123: return str - '0';
124:
125: Beep();
126: PrintBackspace();
127: }
128: }
129:
130:
1.1.1.5 ! root 131: static byte AskPassword (Password &password, bool hiddenSystem)
1.1 root 132: {
133: size_t pos = 0;
134: byte scanCode;
135: byte asciiCode;
136:
1.1.1.5 ! root 137: Print ("Enter password");
! 138: if (PreventHiddenSystemBoot)
! 139: Print (hiddenSystem ? " for hidden system:\r\n" : " for decoy system:\r\n");
! 140: else
! 141: Print (": ");
1.1 root 142:
143: while (true)
144: {
145: asciiCode = GetKeyboardChar (&scanCode);
146:
147: switch (scanCode)
148: {
149: case TC_BIOS_KEY_ENTER:
1.1.1.2 root 150: ClearBiosKeystrokeBuffer();
1.1 root 151: PrintEndl();
1.1.1.2 root 152:
153: password.Length = pos;
154: return scanCode;
1.1 root 155:
156: case TC_BIOS_KEY_BACKSPACE:
157: if (pos > 0)
158: {
159: if (pos < MAX_PASSWORD)
160: PrintBackspace();
161: else
162: PrintCharAtCusor (' ');
163:
164: --pos;
165: }
166: continue;
167:
168: default:
169: if (scanCode == TC_BIOS_KEY_ESC || IsMenuKey (scanCode))
170: {
171: burn (password.Text, sizeof (password.Text));
1.1.1.2 root 172: ClearBiosKeystrokeBuffer();
173:
1.1 root 174: PrintEndl();
175: return scanCode;
176: }
177: }
178:
179: if (!IsPrintable (asciiCode) || pos == MAX_PASSWORD)
180: {
181: Beep();
182: continue;
183: }
184:
185: password.Text[pos++] = asciiCode;
186: if (pos < MAX_PASSWORD)
187: PrintChar ('*');
188: else
189: PrintCharAtCusor ('*');
190: }
191: }
192:
193:
194: static void ExecuteBootSector (byte drive, byte *sectorBuffer)
195: {
196: Print ("Booting...\r\n");
197: CopyMemory (sectorBuffer, 0x0000, 0x7c00, TC_LB_SIZE);
1.1.1.3 root 198:
199: uint32 addr = 0x7c00;
200: __asm
201: {
202: cli
203: mov dl, drive
204: xor ax, ax
205: mov ds, ax
206: mov es, ax
207: mov ss, ax
208: mov sp, 0xffff
209: sti
210: jmp cs:addr
211: }
1.1 root 212: }
213:
214:
1.1.1.5 ! root 215: static bool OpenVolume (byte drive, Password &password, CRYPTO_INFO **cryptoInfo, uint32 *headSaltCrc32, bool skipNormal, bool skipHidden)
1.1 root 216: {
1.1.1.3 root 217: bool status = false;
1.1.1.5 ! root 218: bool hiddenVolume = false;
! 219:
1.1 root 220: uint64 headerSec;
221: headerSec.HighPart = 0;
222: headerSec.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
1.1.1.5 ! root 223:
1.1.1.3 root 224: AcquireSectorBuffer();
1.1 root 225:
1.1.1.5 ! root 226: while (true)
1.1 root 227: {
1.1.1.5 ! root 228: if (ReadSectors (SectorBuffer, drive, headerSec, 1) != BiosResultSuccess)
! 229: goto ret;
! 230:
! 231: if ((!skipNormal || hiddenVolume) && VolumeReadHeader (!hiddenVolume, (char *) SectorBuffer, &password, cryptoInfo, nullptr) == 0)
! 232: status = true;
! 233:
1.1 root 234: if (headSaltCrc32)
1.1.1.3 root 235: *headSaltCrc32 = GetCrc32 (SectorBuffer, PKCS5_SALT_SIZE);
1.1.1.5 ! root 236:
! 237: if (!status && !hiddenVolume && !skipHidden && PartitionFollowingActive.Drive == drive
! 238: && PartitionFollowingActive.SectorCount > ActivePartition.SectorCount)
! 239: {
! 240: hiddenVolume = true;
! 241: headerSec.LowPart = PartitionFollowingActive.StartSector.LowPart + TC_HIDDEN_VOLUME_HEADER_OFFSET / TC_LB_SIZE;
! 242: continue;
! 243: }
! 244:
! 245: // Prevent opening of a non-system hidden volume
! 246: if (status && hiddenVolume && !((*cryptoInfo)->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM))
! 247: {
! 248: status = false;
! 249: crypto_close (*cryptoInfo);
! 250: }
! 251:
! 252: break;
1.1 root 253: }
254:
1.1.1.3 root 255: ret:
256: ReleaseSectorBuffer();
257: return status;
1.1 root 258: }
259:
260:
1.1.1.2 root 261: static bool CheckMemoryRequirements ()
262: {
263: uint16 codeSeg;
264: __asm mov codeSeg, cs
265: if (codeSeg == TC_BOOT_LOADER_LOWMEM_SEGMENT)
266: {
267: PrintError ("Insufficient base memory: ", true, false);
268:
269: uint16 memFree;
270: __asm
271: {
272: push es
273: xor ax, ax
274: mov es, ax
275: mov ax, es:[0x413]
276: mov memFree, ax
277: pop es
278: }
279:
280: Print (memFree); Print (" KB\r\n");
281:
1.1.1.5 ! root 282: Print ("Try disabling unneeded components (RAID, AHCI, integrated audio card, etc.) in\r\n"
! 283: "BIOS setup menu (invoked by pressing Del or F2 after turning on your computer).\r\n");
! 284: #ifndef TC_WINDOWS_BOOT_AES
! 285: Print ("If it does not help, try using the AES encryption algorithm to reduce memory\r\nrequirements.\r\n");
! 286: #endif
! 287:
1.1.1.2 root 288: return false;
289: }
290:
291: return true;
292: }
293:
294:
1.1.1.5 ! root 295: static bool MountVolume (byte drive, byte &exitKey, bool skipNormal, bool skipHidden)
1.1 root 296: {
297: BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
1.1.1.3 root 298: int incorrectPasswordCount = 0;
1.1 root 299:
1.1.1.5 ! root 300: EraseMemory (bootArguments, sizeof (*bootArguments));
! 301:
1.1 root 302: // Open volume header
303: while (true)
304: {
1.1.1.5 ! root 305: exitKey = AskPassword (bootArguments->BootPassword, skipNormal);
1.1 root 306:
307: if (exitKey != TC_BIOS_KEY_ENTER)
308: return false;
309:
1.1.1.5 ! root 310: if (OpenVolume (BootDrive, bootArguments->BootPassword, &BootCryptoInfo, &bootArguments->HeaderSaltCrc32, skipNormal, skipHidden))
1.1 root 311: break;
312:
1.1.1.5 ! root 313: if (GetShiftFlags() & TC_BIOS_SHIFTMASK_CAPSLOCK)
! 314: Print ("Warning: Caps Lock is on.\r\n");
! 315:
1.1.1.4 root 316: Print ("Incorrect password.\r\n\r\n");
1.1.1.3 root 317:
318: if (++incorrectPasswordCount == 5)
319: {
320: Print ("If you are sure the password is correct, the key data may be damaged. Boot your\r\n"
321: "TrueCrypt Rescue Disk and select 'Repair Options' > 'Restore key data'.\r\n\r\n");
322: }
1.1 root 323: }
324:
325: // Setup boot arguments
1.1.1.5 ! root 326: bootArguments->BootLoaderVersion = VERSION_NUM;
1.1 root 327: bootArguments->CryptoInfoOffset = (uint16) BootCryptoInfo;
328: bootArguments->CryptoInfoLength = sizeof (*BootCryptoInfo);
1.1.1.5 ! root 329:
! 330: if (BootCryptoInfo->hiddenVolume)
! 331: bootArguments->HiddenSystemPartitionStart = PartitionFollowingActive.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
! 332:
1.1 root 333: TC_SET_BOOT_ARGUMENTS_SIGNATURE (bootArguments->Signature);
334:
1.1.1.5 ! root 335: // Setup virtual encrypted partition
1.1 root 336: if (BootCryptoInfo->EncryptedAreaLength.HighPart != 0 || BootCryptoInfo->EncryptedAreaLength.LowPart != 0)
337: {
338: EncryptedVirtualPartition.Drive = BootDrive;
339:
1.1.1.5 ! root 340: EncryptedVirtualPartition.StartSector = BootCryptoInfo->EncryptedAreaStart >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
! 341:
! 342: HiddenVolumeStartUnitNo = EncryptedVirtualPartition.StartSector;
! 343: HiddenVolumeStartSector = PartitionFollowingActive.StartSector;
! 344: HiddenVolumeStartSector += EncryptedVirtualPartition.StartSector;
! 345:
! 346: EncryptedVirtualPartition.SectorCount = BootCryptoInfo->EncryptedAreaLength >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
! 347:
! 348: EncryptedVirtualPartition.EndSector = EncryptedVirtualPartition.SectorCount - 1;
! 349: EncryptedVirtualPartition.EndSector += EncryptedVirtualPartition.StartSector;
1.1 root 350: }
351: else
352: {
353: // Drive not encrypted
1.1.1.5 ! root 354: EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
1.1 root 355: }
356:
357: return true;
358: }
359:
360:
361: static byte BootEncryptedDrive ()
362: {
1.1.1.3 root 363: BootCryptoInfo = NULL;
1.1.1.5 ! root 364: BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
1.1 root 365:
1.1.1.5 ! root 366: if (!GetActiveAndFollowingPartition (BootDrive))
1.1 root 367: goto err;
368:
369: byte exitKey;
1.1.1.5 ! root 370: if (!MountVolume (BootDrive, exitKey, false, PreventHiddenSystemBoot))
1.1 root 371: return exitKey;
372:
1.1.1.2 root 373: if (!CheckMemoryRequirements ())
374: goto err;
1.1.1.5 ! root 375:
! 376: if (BootCryptoInfo->hiddenVolume)
! 377: {
! 378: EncryptedVirtualPartition = ActivePartition;
! 379: bootArguments->DecoySystemPartitionStart = ActivePartition.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
1.1.1.2 root 380: }
381:
382: if (!InstallInterruptFilters())
383: goto err;
1.1 root 384:
1.1.1.5 ! root 385: bootArguments->BootArgumentsCrc32 = GetCrc32 ((byte *) bootArguments, (byte *) &bootArguments->BootArgumentsCrc32 - (byte *) bootArguments);
! 386:
1.1.1.3 root 387: while (true)
1.1 root 388: {
1.1.1.3 root 389: // Execute boot sector of the active partition
1.1.1.5 ! root 390: if (ReadSectors (SectorBuffer, ActivePartition.Drive, ActivePartition.StartSector, 1) == BiosResultSuccess)
1.1.1.3 root 391: {
1.1.1.5 ! root 392: ExecuteBootSector (ActivePartition.Drive, SectorBuffer);
1.1.1.3 root 393: }
394:
395: GetKeyboardChar();
1.1 root 396: }
397:
398: err:
1.1.1.3 root 399: if (BootCryptoInfo)
400: {
401: crypto_close (BootCryptoInfo);
402: BootCryptoInfo = NULL;
403: }
404:
1.1.1.5 ! root 405: EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
! 406: EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
1.1.1.2 root 407:
1.1 root 408: byte scanCode;
409: GetKeyboardChar (&scanCode);
410: return scanCode;
411: }
412:
413:
414: static void BootMenu ()
415: {
416: BiosResult result;
417: Partition partitions[16];
418: Partition bootablePartitions[9];
419: size_t partitionCount;
420: size_t bootablePartitionCount = 0;
421:
422: for (byte drive = TC_FIRST_BIOS_DRIVE; drive <= TC_LAST_BIOS_DRIVE; ++drive)
423: {
1.1.1.5 ! root 424: if (GetDrivePartitions (drive, partitions, array_capacity (partitions), partitionCount, false, nullptr, true) == BiosResultSuccess)
1.1 root 425: {
426: for (size_t i = 0; i < partitionCount; ++i)
427: {
428: const Partition &partition = partitions[i];
1.1.1.3 root 429: result = ReadSectors (SectorBuffer, drive, partition.StartSector, 1);
1.1 root 430:
1.1.1.3 root 431: if (result == BiosResultSuccess && *(uint16 *) (SectorBuffer + TC_LB_SIZE - 2) == 0xaa55)
1.1 root 432: {
433: // Windows writes boot loader on all NTFS/FAT filesytems it creates and, therefore,
434: // NTFS/FAT partitions must have the boot indicator set to be considered bootable.
435: if (!partition.Active
1.1.1.3 root 436: && (*(uint32 *) (SectorBuffer + 3) == 0x5346544e // 'NTFS'
437: || *(uint16 *) (SectorBuffer + 54) == 0x4146 && SectorBuffer[56] == 'T' // 'FAT'
438: || *(uint16 *) (SectorBuffer + 82) == 0x4146 && SectorBuffer[84] == 'T'))
1.1 root 439: {
440: continue;
441: }
442:
443: // Bootable sector found
444: if (bootablePartitionCount < array_capacity (bootablePartitions))
445: bootablePartitions[bootablePartitionCount++] = partition;
446: }
447: }
448: }
449: }
450:
451: if (bootablePartitionCount < 1)
452: {
453: PrintError ("No bootable partition found");
454: GetKeyboardChar();
455: return;
456: }
457:
458: char partChar;
459: while (true)
460: {
461: InitScreen();
462: Print ("Bootable Partitions:\r\n");
463: PrintRepeatedChar ('\xC4', 20);
464: Print ("\r\n");
465:
466: for (size_t i = 0; i < bootablePartitionCount; ++i)
467: {
468: const Partition &partition = bootablePartitions[i];
469: Print ("["); Print (i + 1); Print ("] ");
470: Print ("Drive: "); Print (partition.Drive - TC_FIRST_BIOS_DRIVE);
471: Print (", Partition: "); Print (partition.Number + 1);
1.1.1.5 ! root 472: Print (", Size: "); PrintSectorCountInMB (partition.SectorCount); PrintEndl();
1.1 root 473: }
474:
475: if (bootablePartitionCount == 1)
476: {
477: // There's only one bootable partition so we'll boot it directly instead of showing boot manager
478: partChar = '1';
479: }
480: else
481: {
482: Print ("[Esc] Cancel\r\n\r\n");
483: Print ("Press 1-9 to select partition: ");
484:
485: if (GetString (&partChar, 1) == 0)
486: return;
487:
488: PrintEndl();
489:
490: if (partChar < '1' || partChar > '0' + bootablePartitionCount)
491: {
492: Beep();
493: continue;
494: }
495: }
496:
497: const Partition &partition = bootablePartitions[partChar - '0' - 1];
498:
1.1.1.3 root 499: if (ReadSectors (SectorBuffer, partition.Drive, partition.StartSector, 1) == BiosResultSuccess)
1.1 root 500: {
1.1.1.3 root 501: ExecuteBootSector (partition.Drive, SectorBuffer);
1.1 root 502: }
503: }
504: }
505:
506:
1.1.1.5 ! root 507: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 508:
! 509: static bool CopyActivePartitionToHiddenVolume (byte drive, byte &exitKey)
! 510: {
! 511: bool status = false;
! 512:
! 513: uint64 sectorsRemaining;
! 514: uint64 sectorOffset;
! 515: sectorOffset.LowPart = 0;
! 516: sectorOffset.HighPart = 0;
! 517:
! 518: int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
! 519: int statCount;
! 520:
! 521: if (!CheckMemoryRequirements ())
! 522: goto err;
! 523:
! 524: if (!GetActiveAndFollowingPartition (drive))
! 525: goto err;
! 526:
! 527: if (PartitionFollowingActive.Drive == TC_INVALID_BIOS_DRIVE)
! 528: {
! 529: PrintError ("No partition follows the active");
! 530: goto err;
! 531: }
! 532:
! 533: if (!MountVolume (drive, exitKey, true, false))
! 534: return false;
! 535:
! 536: sectorsRemaining = EncryptedVirtualPartition.SectorCount;
! 537:
! 538: if (!(sectorsRemaining == ActivePartition.SectorCount))
! 539: {
! 540: PrintError ("Hidden volume size differs from system partition");
! 541: crypto_close (BootCryptoInfo);
! 542: goto err;
! 543: }
! 544:
! 545: InitScreen();
! 546: Print ("\r\nCopying system to hidden volume. To abort, press Esc.\r\n\r\n");
! 547:
! 548: while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
! 549: {
! 550: if (EscKeyPressed())
! 551: {
! 552: Print ("\rIf aborted, copying will have to start from the beginning (if attempted again).\r\n");
! 553: if (AskYesNo ("Abort"))
! 554: break;
! 555: }
! 556:
! 557: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
! 558: fragmentSectorCount = sectorsRemaining.LowPart;
! 559:
! 560: if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, ActivePartition.StartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
! 561: break;
! 562:
! 563: AcquireSectorBuffer();
! 564:
! 565: for (int i = 0; i < fragmentSectorCount; ++i)
! 566: {
! 567: CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
! 568:
! 569: uint64 s = HiddenVolumeStartUnitNo + sectorOffset + i;
! 570: EncryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
! 571:
! 572: CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
! 573: }
! 574:
! 575: ReleaseSectorBuffer();
! 576:
! 577: if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, HiddenVolumeStartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
! 578: break;
! 579:
! 580: sectorsRemaining = sectorsRemaining - fragmentSectorCount;
! 581: sectorOffset = sectorOffset + fragmentSectorCount;
! 582:
! 583: if (!(statCount++ & 0xf))
! 584: {
! 585: Print ("\rRemaining: ");
! 586: PrintSectorCountInMB (sectorsRemaining);
! 587: }
! 588: }
! 589:
! 590: crypto_close (BootCryptoInfo);
! 591:
! 592: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
! 593: {
! 594: status = true;
! 595: Print ("\rCopying completed.");
! 596: }
! 597:
! 598: PrintEndl (2);
! 599: goto ret;
! 600:
! 601: err:
! 602: exitKey = TC_BIOS_KEY_ESC;
! 603: GetKeyboardChar();
! 604:
! 605: ret:
! 606: EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
! 607: return status;
! 608: }
! 609:
! 610:
! 611: #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 612:
! 613:
1.1 root 614: static void DecryptDrive (byte drive)
615: {
616: byte exitKey;
1.1.1.5 ! root 617: if (!MountVolume (drive, exitKey, false, true))
1.1 root 618: return;
619:
1.1.1.5 ! root 620: BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
1.1 root 621:
622: bool headerUpdateRequired = false;
623: uint64 sectorsRemaining = EncryptedVirtualPartition.EndSector + 1 - EncryptedVirtualPartition.StartSector;
624: uint64 sector = EncryptedVirtualPartition.EndSector + 1;
625:
1.1.1.5 ! root 626: int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
1.1 root 627: int statCount;
628:
1.1.1.5 ! root 629: bool skipBadSectors = false;
! 630:
! 631: Print ("\r\nIMPORTANT: Use this only if Windows cannot start. Decryption under Windows is\r\n"
! 632: "much faster. To decrypt under Windows, run TrueCrypt and select 'System' >\r\n"
! 633: "'Permanently Decrypt'.\r\n\r\n");
! 634:
! 635: if (!AskYesNo ("Decrypt now"))
! 636: {
! 637: crypto_close (BootCryptoInfo);
! 638: goto ret;
! 639: }
! 640:
! 641: if (EncryptedVirtualPartition.Drive == TC_INVALID_BIOS_DRIVE)
1.1 root 642: {
1.1.1.3 root 643: // Drive already decrypted
1.1 root 644: sectorsRemaining.HighPart = 0;
645: sectorsRemaining.LowPart = 0;
646: }
647: else
648: {
1.1.1.3 root 649: Print ("\r\nTo safely interrupt and defer decryption, press Esc.\r\n"
650: "WARNING: You can turn off power only after you press Esc.\r\n\r\n");
1.1 root 651: }
652:
653: while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
654: {
1.1.1.5 ! root 655: if (EscKeyPressed())
! 656: break;
1.1 root 657:
658: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
659: fragmentSectorCount = sectorsRemaining.LowPart;
660:
661: sector = sector - fragmentSectorCount;
662:
663: if (!(statCount++ & 0xf))
664: {
665: Print ("\rRemaining: ");
1.1.1.5 ! root 666: PrintSectorCountInMB (sectorsRemaining);
1.1 root 667: }
668:
1.1.1.5 ! root 669: if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) == BiosResultSuccess)
1.1 root 670: {
1.1.1.5 ! root 671: AcquireSectorBuffer();
1.1 root 672:
1.1.1.5 ! root 673: for (int i = 0; i < fragmentSectorCount; ++i)
! 674: {
! 675: CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
1.1 root 676:
1.1.1.5 ! root 677: uint64 s = sector + i;
! 678: DecryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
1.1 root 679:
1.1.1.5 ! root 680: CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
! 681: }
1.1.1.3 root 682:
1.1.1.5 ! root 683: ReleaseSectorBuffer();
! 684:
! 685: if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) != BiosResultSuccess && !skipBadSectors)
! 686: goto askBadSectorSkip;
! 687: }
! 688: else if (!skipBadSectors)
! 689: goto askBadSectorSkip;
1.1 root 690:
691: sectorsRemaining = sectorsRemaining - fragmentSectorCount;
692: headerUpdateRequired = true;
1.1.1.5 ! root 693: continue;
! 694:
! 695: askBadSectorSkip:
! 696: if (!AskYesNo ("Skip all bad sectors"))
! 697: break;
! 698:
! 699: skipBadSectors = true;
! 700: sector = sector + fragmentSectorCount;
! 701: fragmentSectorCount = 1;
1.1 root 702: }
703:
704: crypto_close (BootCryptoInfo);
705:
706: if (headerUpdateRequired)
707: {
1.1.1.3 root 708: AcquireSectorBuffer();
1.1 root 709: uint64 headerSector;
710: headerSector.HighPart = 0;
711: headerSector.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
712:
1.1.1.3 root 713: // Update encrypted area size in volume header
1.1 root 714:
1.1.1.3 root 715: CRYPTO_INFO *headerCryptoInfo = crypto_open();
1.1.1.5 ! root 716: while (ReadSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
1.1 root 717:
1.1.1.3 root 718: if (VolumeReadHeader (TRUE, (char *) SectorBuffer, &bootArguments->BootPassword, NULL, headerCryptoInfo) == 0)
719: {
720: DecryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1.1 root 721:
1.1.1.3 root 722: uint64 encryptedAreaLength = sectorsRemaining << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
1.1 root 723:
1.1.1.3 root 724: for (int i = 7; i >= 0; --i)
725: {
1.1.1.5 ! root 726: SectorBuffer[TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH + i] = (byte) encryptedAreaLength.LowPart;
1.1.1.3 root 727: encryptedAreaLength = encryptedAreaLength >> 8;
1.1 root 728: }
729:
1.1.1.5 ! root 730: uint32 headerCrc32 = GetCrc32 (SectorBuffer + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
! 731:
! 732: for (i = 3; i >= 0; --i)
! 733: {
! 734: SectorBuffer[TC_HEADER_OFFSET_HEADER_CRC + i] = (byte) headerCrc32;
! 735: headerCrc32 >>= 8;
! 736: }
! 737:
1.1.1.3 root 738: EncryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1.1 root 739: }
740:
1.1.1.3 root 741: crypto_close (headerCryptoInfo);
742:
1.1.1.5 ! root 743: while (WriteSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
1.1.1.3 root 744: ReleaseSectorBuffer();
1.1 root 745: }
746:
1.1.1.3 root 747: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
748: Print ("\rDrive decrypted.\r\n");
749: else
750: Print ("\r\nDecryption deferred.\r\n");
751:
1.1 root 752: GetKeyboardChar();
1.1.1.5 ! root 753: ret:
! 754: EraseMemory (bootArguments, sizeof (*bootArguments));
1.1 root 755: }
756:
757:
758: static void RepairMenu ()
759: {
760: DriveGeometry bootLoaderDriveGeometry;
761: if (GetDriveGeometry (BootLoaderDrive, bootLoaderDriveGeometry) != BiosResultSuccess)
762: {
763: GetKeyboardChar();
764: return;
765: }
766:
767: while (true)
768: {
769: InitScreen();
770: Print ("Available "); Print ("Repair Options"); Print (":\r\n");
771: PrintRepeatedChar ('\xC4', 25);
1.1.1.5 ! root 772: PrintEndl();
1.1 root 773:
774: enum
775: {
776: RestoreNone = 0,
777: DecryptVolume,
778: RestoreTrueCryptLoader,
779: RestoreVolumeHeader,
780: RestoreOriginalSystemLoader
781: };
782:
783: static const char *options[] = { "Permanently decrypt system partition/drive", "Restore TrueCrypt Boot Loader", "Restore key data (volume header)", "Restore original system loader" };
784:
1.1.1.5 ! root 785: int selection = AskSelection (options,
! 786: (BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER) ? array_capacity (options) : array_capacity (options) - 1);
1.1 root 787:
788: PrintEndl();
789:
1.1.1.2 root 790: switch (selection)
1.1 root 791: {
1.1.1.2 root 792: case RestoreNone:
793: return;
794:
795: case DecryptVolume:
1.1.1.5 ! root 796: DecryptDrive (BootDrive);
1.1.1.2 root 797: continue;
798:
799: case RestoreOriginalSystemLoader:
800: if (!AskYesNo ("Is the drive decrypted"))
1.1.1.3 root 801: {
802: Print ("Please decrypt it first.\r\n");
803: GetKeyboardChar();
1.1.1.2 root 804: continue;
1.1.1.3 root 805: }
1.1.1.4 root 806: break;
1.1 root 807: }
808:
809: bool writeConfirmed = false;
810: BiosResult result;
811:
812: uint64 sector;
813: sector.HighPart = 0;
814: ChsAddress chs;
815:
1.1.1.3 root 816: byte mbrPartTable[TC_LB_SIZE - TC_MAX_MBR_BOOT_CODE_SIZE];
817: AcquireSectorBuffer();
818:
1.1 root 819: for (int i = (selection == RestoreVolumeHeader ? TC_BOOT_VOLUME_HEADER_SECTOR : TC_MBR_SECTOR);
820: i < TC_BOOT_LOADER_AREA_SECTOR_COUNT; ++i)
821: {
1.1.1.5 ! root 822: sector.LowPart = i;
! 823:
! 824: if (selection == RestoreOriginalSystemLoader)
! 825: sector.LowPart += TC_ORIG_BOOT_LOADER_BACKUP_SECTOR;
! 826: else if (selection == RestoreTrueCryptLoader)
! 827: sector.LowPart += TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR;
1.1 root 828:
829: // The backup medium may be a floppy-emulated bootable CD. The emulation may fail if LBA addressing is used.
830: // Therefore, only CHS addressing can be used.
831: LbaToChs (bootLoaderDriveGeometry, sector, chs);
832: sector.LowPart = i;
833:
834: if (i == TC_MBR_SECTOR)
835: {
1.1.1.3 root 836: // Read current partition table
837: result = ReadSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1);
1.1 root 838: if (result != BiosResultSuccess)
839: goto err;
840:
1.1.1.3 root 841: memcpy (mbrPartTable, SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbrPartTable));
842: }
843:
844: result = ReadSectors (SectorBuffer, BootLoaderDrive, chs, 1);
845: if (result != BiosResultSuccess)
846: goto err;
847:
848: if (i == TC_MBR_SECTOR)
849: {
850: // Preserve current partition table
851: memcpy (SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, mbrPartTable, sizeof (mbrPartTable));
1.1 root 852: }
853:
854: // Volume header
855: if (i == TC_BOOT_VOLUME_HEADER_SECTOR)
856: {
857: if (selection == RestoreTrueCryptLoader)
858: continue;
859:
860: if (selection == RestoreVolumeHeader)
861: {
862: while (true)
863: {
864: Password password;
865: byte exitKey = AskPassword (password);
866:
867: if (exitKey != TC_BIOS_KEY_ENTER)
868: goto abort;
869:
870: CRYPTO_INFO *cryptoInfo;
871:
1.1.1.3 root 872: CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, TC_LB_SIZE);
873: ReleaseSectorBuffer();
874:
1.1 root 875: // Restore volume header only if the current one cannot be used
1.1.1.5 ! root 876: if (OpenVolume (TC_FIRST_BIOS_DRIVE, password, &cryptoInfo, nullptr, false, true))
1.1 root 877: {
878: Print ("Original header preserved.\r\n");
879: crypto_close (cryptoInfo);
880: goto err;
881: }
882:
1.1.1.3 root 883: AcquireSectorBuffer();
884: CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, 0, SectorBuffer, TC_LB_SIZE);
885:
886: if (VolumeReadHeader (TRUE, (char *) SectorBuffer, &password, &cryptoInfo, nullptr) == 0)
1.1 root 887: {
888: crypto_close (cryptoInfo);
889: break;
890: }
891:
1.1.1.4 root 892: Print ("Incorrect password.\r\n\r\n");
1.1 root 893: }
894: }
895: }
896:
1.1.1.3 root 897: if (!writeConfirmed && !AskYesNo ("Modify drive 0"))
1.1 root 898: goto abort;
899: writeConfirmed = true;
900:
1.1.1.3 root 901: if (WriteSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1) != BiosResultSuccess)
1.1 root 902: goto err;
903: }
904: done:
905: switch (selection)
906: {
907: case RestoreTrueCryptLoader:
908: Print ("TrueCrypt Boot Loader");
909: break;
910:
911: case RestoreVolumeHeader:
912: Print ("Header");
913: break;
914:
915: case RestoreOriginalSystemLoader:
916: Print ("System loader");
917: break;
918: }
919: Print (" restored.\r\n");
920:
921: err: GetKeyboardChar();
1.1.1.3 root 922: abort: ReleaseSectorBuffer();
1.1 root 923: }
924: }
925:
1.1.1.5 ! root 926: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 927:
1.1 root 928:
929: #ifndef DEBUG
930: extern "C" void _acrtused () { } // Required by linker
931: #endif
932:
933:
934: void main ()
935: {
936: __asm mov BootLoaderDrive, dl
937: __asm mov BootSectorFlags, dh
938:
1.1.1.3 root 939: #ifdef TC_BOOT_TRACING_ENABLED
1.1 root 940: InitDebugPort();
941: #endif
942:
1.1.1.3 root 943: #ifdef TC_BOOT_STACK_CHECKING_ENABLED
944: InitStackChecker();
945: #endif
946:
1.1.1.5 ! root 947: InitVideoMode();
! 948: InitScreen();
! 949:
! 950: // Determine boot drive
1.1 root 951: BootDrive = BootLoaderDrive;
952: if (BootDrive < TC_FIRST_BIOS_DRIVE)
953: BootDrive = TC_FIRST_BIOS_DRIVE;
954:
1.1.1.5 ! root 955: // Query boot drive geometry
1.1 root 956: if (GetDriveGeometry (BootDrive, BootDriveGeometry, true) != BiosResultSuccess)
957: {
958: BootDrive = TC_FIRST_BIOS_DRIVE;
959: if (GetDriveGeometry (BootDrive, BootDriveGeometry) == BiosResultSuccess)
960: BootDriveGeometryValid = TRUE;
961: }
962: else
963: BootDriveGeometryValid = TRUE;
964:
1.1.1.5 ! root 965:
! 966: #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 967:
! 968: // Check whether the user is not using the Rescue Disk to create a hidden system
! 969:
! 970: if (ReadWriteMBR (false, BootDrive, true) == BiosResultSuccess
! 971: && *(uint32 *) (SectorBuffer + 6) == 0x65757254
! 972: && *(uint32 *) (SectorBuffer + 10) == 0x70797243
! 973: && (SectorBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) != TC_HIDDEN_OS_CREATION_PHASE_NONE)
! 974: {
! 975: PrintError ("It appears you are creating a hidden OS.");
! 976: if (AskYesNo ("Is this correct"))
! 977: {
! 978: Print ("Please remove the Rescue Disk from the drive and restart.");
! 979: while (true);
! 980: }
! 981: }
! 982:
! 983: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 984:
! 985:
! 986: // Main menu
! 987:
1.1 root 988: while (true)
989: {
1.1.1.5 ! root 990: byte exitKey;
1.1 root 991: InitScreen();
992:
1.1.1.5 ! root 993: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 994:
! 995: // Hidden system setup
! 996: byte hiddenSystemCreationPhase = BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
! 997:
! 998: if (hiddenSystemCreationPhase != TC_HIDDEN_OS_CREATION_PHASE_NONE)
! 999: {
! 1000: PreventHiddenSystemBoot = true;
! 1001: PrintMainMenu();
! 1002:
! 1003: if (hiddenSystemCreationPhase == TC_HIDDEN_OS_CREATION_PHASE_CLONING)
! 1004: {
! 1005: if (CopyActivePartitionToHiddenVolume (BootDrive, exitKey))
! 1006: {
! 1007: BootSectorFlags = (BootSectorFlags & ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) | TC_HIDDEN_OS_CREATION_PHASE_DECOY_OS;
! 1008: UpdateBootSectorConfiguration (BootLoaderDrive);
! 1009: }
! 1010: else if (exitKey == TC_BIOS_KEY_ESC)
! 1011: goto bootMenu;
! 1012: else
! 1013: continue;
! 1014: }
! 1015: }
! 1016: else
! 1017: PrintMainMenu();
! 1018:
! 1019: exitKey = BootEncryptedDrive();
! 1020:
! 1021: #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1.1 root 1022:
1.1.1.5 ! root 1023: PrintMainMenu();
! 1024: exitKey = BootEncryptedDrive();
! 1025:
1.1 root 1026: if (exitKey == TC_MENU_KEY_REPAIR)
1027: {
1028: RepairMenu();
1029: continue;
1030: }
1031:
1.1.1.5 ! root 1032: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
! 1033:
! 1034: bootMenu:
1.1 root 1035: BootMenu();
1036: }
1037: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.