|
|
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))
1.1.1.7 ! root 585: TC_THROW_FATAL_EXCEPTION;
1.1.1.5 root 586:
587: InitScreen();
588: Print ("\r\nCopying system to hidden volume. To abort, press Esc.\r\n\r\n");
589:
590: while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
591: {
592: if (EscKeyPressed())
593: {
594: Print ("\rIf aborted, copying will have to start from the beginning (if attempted again).\r\n");
595: if (AskYesNo ("Abort"))
596: break;
597: }
598:
599: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
600: fragmentSectorCount = sectorsRemaining.LowPart;
601:
602: if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, ActivePartition.StartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
1.1.1.7 ! root 603: {
! 604: Print ("To fix bad sectors: 1) Terminate 2) Encrypt and decrypt sys partition 3) Retry\r\n");
! 605: crypto_close (BootCryptoInfo);
! 606: goto err;
! 607: }
1.1.1.5 root 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)
1.1.1.7 ! root 624: {
! 625: crypto_close (BootCryptoInfo);
! 626: goto err;
! 627: }
1.1.1.5 root 628:
629: sectorsRemaining = sectorsRemaining - fragmentSectorCount;
630: sectorOffset = sectorOffset + fragmentSectorCount;
631:
632: if (!(statCount++ & 0xf))
633: {
634: Print ("\rRemaining: ");
635: PrintSectorCountInMB (sectorsRemaining);
636: }
637: }
638:
639: crypto_close (BootCryptoInfo);
640:
641: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
642: {
643: status = true;
644: Print ("\rCopying completed.");
645: }
646:
647: PrintEndl (2);
648: goto ret;
649:
650: err:
651: exitKey = TC_BIOS_KEY_ESC;
652: GetKeyboardChar();
653:
654: ret:
655: EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
656: return status;
657: }
658:
659:
660: #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
661:
662:
1.1 root 663: static void DecryptDrive (byte drive)
664: {
665: byte exitKey;
1.1.1.5 root 666: if (!MountVolume (drive, exitKey, false, true))
1.1 root 667: return;
668:
1.1.1.5 root 669: BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
1.1 root 670:
671: bool headerUpdateRequired = false;
672: uint64 sectorsRemaining = EncryptedVirtualPartition.EndSector + 1 - EncryptedVirtualPartition.StartSector;
673: uint64 sector = EncryptedVirtualPartition.EndSector + 1;
674:
1.1.1.5 root 675: int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
1.1 root 676: int statCount;
677:
1.1.1.5 root 678: bool skipBadSectors = false;
679:
1.1.1.6 root 680: Print ("\r\nUse only if Windows cannot start. Decryption under Windows is much faster\r\n"
681: "(in TrueCrypt, select 'System' > 'Permanently Decrypt').\r\n\r\n");
1.1.1.5 root 682:
683: if (!AskYesNo ("Decrypt now"))
684: {
685: crypto_close (BootCryptoInfo);
686: goto ret;
687: }
688:
689: if (EncryptedVirtualPartition.Drive == TC_INVALID_BIOS_DRIVE)
1.1 root 690: {
1.1.1.3 root 691: // Drive already decrypted
1.1 root 692: sectorsRemaining.HighPart = 0;
693: sectorsRemaining.LowPart = 0;
694: }
695: else
696: {
1.1.1.3 root 697: Print ("\r\nTo safely interrupt and defer decryption, press Esc.\r\n"
698: "WARNING: You can turn off power only after you press Esc.\r\n\r\n");
1.1 root 699: }
700:
701: while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
702: {
1.1.1.5 root 703: if (EscKeyPressed())
704: break;
1.1 root 705:
706: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
707: fragmentSectorCount = sectorsRemaining.LowPart;
708:
709: sector = sector - fragmentSectorCount;
710:
711: if (!(statCount++ & 0xf))
712: {
713: Print ("\rRemaining: ");
1.1.1.5 root 714: PrintSectorCountInMB (sectorsRemaining);
1.1 root 715: }
716:
1.1.1.5 root 717: if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) == BiosResultSuccess)
1.1 root 718: {
1.1.1.5 root 719: AcquireSectorBuffer();
1.1 root 720:
1.1.1.5 root 721: for (int i = 0; i < fragmentSectorCount; ++i)
722: {
723: CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
1.1 root 724:
1.1.1.5 root 725: uint64 s = sector + i;
726: DecryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
1.1 root 727:
1.1.1.5 root 728: CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
729: }
1.1.1.3 root 730:
1.1.1.5 root 731: ReleaseSectorBuffer();
732:
733: if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) != BiosResultSuccess && !skipBadSectors)
734: goto askBadSectorSkip;
735: }
736: else if (!skipBadSectors)
737: goto askBadSectorSkip;
1.1 root 738:
739: sectorsRemaining = sectorsRemaining - fragmentSectorCount;
740: headerUpdateRequired = true;
1.1.1.5 root 741: continue;
742:
743: askBadSectorSkip:
744: if (!AskYesNo ("Skip all bad sectors"))
745: break;
746:
747: skipBadSectors = true;
748: sector = sector + fragmentSectorCount;
749: fragmentSectorCount = 1;
1.1 root 750: }
751:
752: crypto_close (BootCryptoInfo);
753:
754: if (headerUpdateRequired)
755: {
1.1.1.3 root 756: AcquireSectorBuffer();
1.1 root 757: uint64 headerSector;
758: headerSector.HighPart = 0;
759: headerSector.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
760:
1.1.1.3 root 761: // Update encrypted area size in volume header
1.1 root 762:
1.1.1.3 root 763: CRYPTO_INFO *headerCryptoInfo = crypto_open();
1.1.1.5 root 764: while (ReadSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
1.1 root 765:
1.1.1.6 root 766: if (ReadVolumeHeader (TRUE, (char *) SectorBuffer, &bootArguments->BootPassword, NULL, headerCryptoInfo) == 0)
1.1.1.3 root 767: {
768: DecryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1.1 root 769:
1.1.1.3 root 770: uint64 encryptedAreaLength = sectorsRemaining << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
1.1 root 771:
1.1.1.3 root 772: for (int i = 7; i >= 0; --i)
773: {
1.1.1.5 root 774: SectorBuffer[TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH + i] = (byte) encryptedAreaLength.LowPart;
1.1.1.3 root 775: encryptedAreaLength = encryptedAreaLength >> 8;
1.1 root 776: }
777:
1.1.1.5 root 778: uint32 headerCrc32 = GetCrc32 (SectorBuffer + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
779:
780: for (i = 3; i >= 0; --i)
781: {
782: SectorBuffer[TC_HEADER_OFFSET_HEADER_CRC + i] = (byte) headerCrc32;
783: headerCrc32 >>= 8;
784: }
785:
1.1.1.3 root 786: EncryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
1.1 root 787: }
788:
1.1.1.3 root 789: crypto_close (headerCryptoInfo);
790:
1.1.1.5 root 791: while (WriteSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
1.1.1.3 root 792: ReleaseSectorBuffer();
1.1 root 793: }
794:
1.1.1.3 root 795: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
796: Print ("\rDrive decrypted.\r\n");
797: else
798: Print ("\r\nDecryption deferred.\r\n");
799:
1.1 root 800: GetKeyboardChar();
1.1.1.5 root 801: ret:
802: EraseMemory (bootArguments, sizeof (*bootArguments));
1.1 root 803: }
804:
805:
806: static void RepairMenu ()
807: {
808: DriveGeometry bootLoaderDriveGeometry;
1.1.1.6 root 809:
810: if (GetDriveGeometry (BootLoaderDrive, bootLoaderDriveGeometry, true) != BiosResultSuccess)
1.1 root 811: {
1.1.1.6 root 812: // Some BIOSes may fail to get the geometry of an emulated floppy drive
813: bootLoaderDriveGeometry.Cylinders = 80;
814: bootLoaderDriveGeometry.Heads = 2;
815: bootLoaderDriveGeometry.Sectors = 18;
1.1 root 816: }
817:
818: while (true)
819: {
820: InitScreen();
821: Print ("Available "); Print ("Repair Options"); Print (":\r\n");
822: PrintRepeatedChar ('\xC4', 25);
1.1.1.5 root 823: PrintEndl();
1.1 root 824:
825: enum
826: {
827: RestoreNone = 0,
828: DecryptVolume,
829: RestoreTrueCryptLoader,
830: RestoreVolumeHeader,
831: RestoreOriginalSystemLoader
832: };
833:
834: static const char *options[] = { "Permanently decrypt system partition/drive", "Restore TrueCrypt Boot Loader", "Restore key data (volume header)", "Restore original system loader" };
835:
1.1.1.5 root 836: int selection = AskSelection (options,
837: (BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER) ? array_capacity (options) : array_capacity (options) - 1);
1.1 root 838:
839: PrintEndl();
840:
1.1.1.2 root 841: switch (selection)
1.1 root 842: {
1.1.1.2 root 843: case RestoreNone:
844: return;
845:
846: case DecryptVolume:
1.1.1.5 root 847: DecryptDrive (BootDrive);
1.1.1.2 root 848: continue;
849:
850: case RestoreOriginalSystemLoader:
1.1.1.6 root 851: if (!AskYesNo ("Is the system partition/drive decrypted"))
1.1.1.3 root 852: {
853: Print ("Please decrypt it first.\r\n");
854: GetKeyboardChar();
1.1.1.2 root 855: continue;
1.1.1.3 root 856: }
1.1.1.4 root 857: break;
1.1 root 858: }
859:
860: bool writeConfirmed = false;
861: BiosResult result;
862:
863: uint64 sector;
864: sector.HighPart = 0;
865: ChsAddress chs;
866:
1.1.1.3 root 867: byte mbrPartTable[TC_LB_SIZE - TC_MAX_MBR_BOOT_CODE_SIZE];
868: AcquireSectorBuffer();
869:
1.1 root 870: for (int i = (selection == RestoreVolumeHeader ? TC_BOOT_VOLUME_HEADER_SECTOR : TC_MBR_SECTOR);
871: i < TC_BOOT_LOADER_AREA_SECTOR_COUNT; ++i)
872: {
1.1.1.5 root 873: sector.LowPart = i;
874:
875: if (selection == RestoreOriginalSystemLoader)
876: sector.LowPart += TC_ORIG_BOOT_LOADER_BACKUP_SECTOR;
877: else if (selection == RestoreTrueCryptLoader)
878: sector.LowPart += TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR;
1.1 root 879:
880: // The backup medium may be a floppy-emulated bootable CD. The emulation may fail if LBA addressing is used.
881: // Therefore, only CHS addressing can be used.
882: LbaToChs (bootLoaderDriveGeometry, sector, chs);
883: sector.LowPart = i;
884:
885: if (i == TC_MBR_SECTOR)
886: {
1.1.1.3 root 887: // Read current partition table
888: result = ReadSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1);
1.1 root 889: if (result != BiosResultSuccess)
890: goto err;
891:
1.1.1.3 root 892: memcpy (mbrPartTable, SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbrPartTable));
893: }
894:
895: result = ReadSectors (SectorBuffer, BootLoaderDrive, chs, 1);
896: if (result != BiosResultSuccess)
897: goto err;
898:
899: if (i == TC_MBR_SECTOR)
900: {
901: // Preserve current partition table
902: memcpy (SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, mbrPartTable, sizeof (mbrPartTable));
1.1 root 903: }
904:
905: // Volume header
906: if (i == TC_BOOT_VOLUME_HEADER_SECTOR)
907: {
908: if (selection == RestoreTrueCryptLoader)
909: continue;
910:
911: if (selection == RestoreVolumeHeader)
912: {
913: while (true)
914: {
915: Password password;
916: byte exitKey = AskPassword (password);
917:
918: if (exitKey != TC_BIOS_KEY_ENTER)
919: goto abort;
920:
921: CRYPTO_INFO *cryptoInfo;
922:
1.1.1.3 root 923: CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, TC_LB_SIZE);
924: ReleaseSectorBuffer();
925:
1.1 root 926: // Restore volume header only if the current one cannot be used
1.1.1.5 root 927: if (OpenVolume (TC_FIRST_BIOS_DRIVE, password, &cryptoInfo, nullptr, false, true))
1.1 root 928: {
929: Print ("Original header preserved.\r\n");
930: crypto_close (cryptoInfo);
931: goto err;
932: }
933:
1.1.1.3 root 934: AcquireSectorBuffer();
935: CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, 0, SectorBuffer, TC_LB_SIZE);
936:
1.1.1.6 root 937: if (ReadVolumeHeader (TRUE, (char *) SectorBuffer, &password, &cryptoInfo, nullptr) == 0)
1.1 root 938: {
939: crypto_close (cryptoInfo);
940: break;
941: }
942:
1.1.1.4 root 943: Print ("Incorrect password.\r\n\r\n");
1.1 root 944: }
945: }
946: }
947:
1.1.1.3 root 948: if (!writeConfirmed && !AskYesNo ("Modify drive 0"))
1.1 root 949: goto abort;
950: writeConfirmed = true;
951:
1.1.1.3 root 952: if (WriteSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1) != BiosResultSuccess)
1.1 root 953: goto err;
954: }
955: done:
956: switch (selection)
957: {
958: case RestoreTrueCryptLoader:
959: Print ("TrueCrypt Boot Loader");
960: break;
961:
962: case RestoreVolumeHeader:
963: Print ("Header");
964: break;
965:
966: case RestoreOriginalSystemLoader:
967: Print ("System loader");
968: break;
969: }
970: Print (" restored.\r\n");
971:
972: err: GetKeyboardChar();
1.1.1.3 root 973: abort: ReleaseSectorBuffer();
1.1 root 974: }
975: }
976:
1.1.1.5 root 977: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
978:
1.1 root 979:
980: #ifndef DEBUG
981: extern "C" void _acrtused () { } // Required by linker
982: #endif
983:
984:
985: void main ()
986: {
987: __asm mov BootLoaderDrive, dl
988: __asm mov BootSectorFlags, dh
989:
1.1.1.3 root 990: #ifdef TC_BOOT_TRACING_ENABLED
1.1 root 991: InitDebugPort();
992: #endif
993:
1.1.1.3 root 994: #ifdef TC_BOOT_STACK_CHECKING_ENABLED
995: InitStackChecker();
996: #endif
997:
1.1.1.6 root 998: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
999: ReadBootSectorUserConfiguration();
1000: #endif
1001:
1.1.1.5 root 1002: InitVideoMode();
1003: InitScreen();
1004:
1005: // Determine boot drive
1.1 root 1006: BootDrive = BootLoaderDrive;
1007: if (BootDrive < TC_FIRST_BIOS_DRIVE)
1008: BootDrive = TC_FIRST_BIOS_DRIVE;
1009:
1.1.1.5 root 1010: // Query boot drive geometry
1.1 root 1011: if (GetDriveGeometry (BootDrive, BootDriveGeometry, true) != BiosResultSuccess)
1012: {
1013: BootDrive = TC_FIRST_BIOS_DRIVE;
1014: if (GetDriveGeometry (BootDrive, BootDriveGeometry) == BiosResultSuccess)
1015: BootDriveGeometryValid = TRUE;
1016: }
1017: else
1018: BootDriveGeometryValid = TRUE;
1019:
1.1.1.5 root 1020:
1021: #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1022:
1023: // Check whether the user is not using the Rescue Disk to create a hidden system
1024:
1025: if (ReadWriteMBR (false, BootDrive, true) == BiosResultSuccess
1026: && *(uint32 *) (SectorBuffer + 6) == 0x65757254
1027: && *(uint32 *) (SectorBuffer + 10) == 0x70797243
1028: && (SectorBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) != TC_HIDDEN_OS_CREATION_PHASE_NONE)
1029: {
1030: PrintError ("It appears you are creating a hidden OS.");
1031: if (AskYesNo ("Is this correct"))
1032: {
1033: Print ("Please remove the Rescue Disk from the drive and restart.");
1034: while (true);
1035: }
1036: }
1037:
1038: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1039:
1040:
1041: // Main menu
1042:
1.1 root 1043: while (true)
1044: {
1.1.1.5 root 1045: byte exitKey;
1.1 root 1046: InitScreen();
1047:
1.1.1.5 root 1048: #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1049:
1050: // Hidden system setup
1051: byte hiddenSystemCreationPhase = BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
1052:
1053: if (hiddenSystemCreationPhase != TC_HIDDEN_OS_CREATION_PHASE_NONE)
1054: {
1.1.1.6 root 1055: PreventNormalSystemBoot = true;
1.1.1.5 root 1056: PrintMainMenu();
1057:
1058: if (hiddenSystemCreationPhase == TC_HIDDEN_OS_CREATION_PHASE_CLONING)
1059: {
1060: if (CopyActivePartitionToHiddenVolume (BootDrive, exitKey))
1061: {
1.1.1.6 root 1062: BootSectorFlags = (BootSectorFlags & ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) | TC_HIDDEN_OS_CREATION_PHASE_WIPING;
1.1.1.5 root 1063: UpdateBootSectorConfiguration (BootLoaderDrive);
1064: }
1065: else if (exitKey == TC_BIOS_KEY_ESC)
1066: goto bootMenu;
1067: else
1068: continue;
1069: }
1070: }
1071: else
1072: PrintMainMenu();
1073:
1074: exitKey = BootEncryptedDrive();
1075:
1076: #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1.1 root 1077:
1.1.1.5 root 1078: PrintMainMenu();
1079: exitKey = BootEncryptedDrive();
1080:
1.1 root 1081: if (exitKey == TC_MENU_KEY_REPAIR)
1082: {
1083: RepairMenu();
1084: continue;
1085: }
1086:
1.1.1.5 root 1087: #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
1088:
1089: bootMenu:
1.1.1.6 root 1090: if (!PreventBootMenu)
1091: BootMenu();
1.1 root 1092: }
1093: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.