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