|
|
1.1 root 1: /*
2: Copyright (c) 2008 TrueCrypt Foundation. All rights reserved.
3:
4: Governed by the TrueCrypt License 2.4 the full text of which is contained
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"
24: #include "IntFilter.h"
25:
26:
27: static void InitScreen ()
28: {
29: ClearScreen();
30:
31: Print (" TrueCrypt Boot Loader " VERSION_STRING " Copyright (C) 2008 TrueCrypt Foundation\r\n");
32: PrintRepeatedChar ('\xDC', TC_BIOS_MAX_CHARS_PER_LINE);
33:
34: PrintEndl (2);
35: }
36:
37:
38: static void PrintMainMenu ()
39: {
40: Print (" Keyboard Controls:\r\n");
41: Print (" [Esc] Skip Authentication (Boot Manager)\r\n");
42: Print (" [F8] "); Print ("Repair Options");
43:
44: PrintEndl (3);
45: }
46:
47:
48: static bool IsMenuKey (byte scanCode)
49: {
50: return scanCode == TC_MENU_KEY_REPAIR;
51: }
52:
53:
54: static bool AskYesNo (const char *message)
55: {
56: Print (message);
57: Print ("? (y/n): ");
58: while (true)
59: {
60: switch (GetKeyboardChar())
61: {
62: case 'y':
63: case 'Y':
64: PrintEndl();
65: return true;
66:
67: case 'n':
68: case 'N':
69: PrintEndl();
70: return false;
71:
72: default:
73: Beep();
74: }
75: }
76: }
77:
78:
79: static int AskSelection (const char *options[], size_t optionCount)
80: {
81: for (int i = 0; i < optionCount; ++i)
82: {
83: Print ("["); Print (i + 1); Print ("] ");
84: Print (options[i]);
85: PrintEndl();
86: }
87: Print ("[Esc] Cancel\r\n\r\n");
88:
89: Print ("To select, press 1-9: ");
90:
91: char str;
92:
93: while (true)
94: {
95: if (GetString (&str, 1) == 0)
96: return 0;
97:
98: if (str >= '1' && str <= optionCount + '0')
99: return str - '0';
100:
101: Beep();
102: PrintBackspace();
103: }
104: }
105:
106:
107: static byte AskPassword (Password &password)
108: {
109: size_t pos = 0;
110: byte scanCode;
111: byte asciiCode;
112:
113: Print ("Enter password: ");
114:
115: while (true)
116: {
117: asciiCode = GetKeyboardChar (&scanCode);
118:
119: switch (scanCode)
120: {
121: case TC_BIOS_KEY_ENTER:
122: PrintEndl();
123: goto ret;
124:
125: case TC_BIOS_KEY_BACKSPACE:
126: if (pos > 0)
127: {
128: if (pos < MAX_PASSWORD)
129: PrintBackspace();
130: else
131: PrintCharAtCusor (' ');
132:
133: --pos;
134: }
135: continue;
136:
137: default:
138: if (scanCode == TC_BIOS_KEY_ESC || IsMenuKey (scanCode))
139: {
140: burn (password.Text, sizeof (password.Text));
141: PrintEndl();
142: return scanCode;
143: }
144: }
145:
146: if (!IsPrintable (asciiCode) || pos == MAX_PASSWORD)
147: {
148: Beep();
149: continue;
150: }
151:
152: password.Text[pos++] = asciiCode;
153: if (pos < MAX_PASSWORD)
154: PrintChar ('*');
155: else
156: PrintCharAtCusor ('*');
157: }
158:
159: ret:
160: password.Length = pos;
161: return TC_BIOS_KEY_ENTER;
162: }
163:
164:
165: static void ExecuteBootSector (byte drive, byte *sectorBuffer)
166: {
167: Print ("Booting...\r\n");
168: CopyMemory (sectorBuffer, 0x0000, 0x7c00, TC_LB_SIZE);
169: Jump (0x0000, 0x7c00, drive);
170: }
171:
172:
173: static bool OpenVolume (byte drive, Password &password, CRYPTO_INFO **cryptoInfo, uint32 *headSaltCrc32)
174: {
175: byte header[HEADER_SIZE];
176: uint64 headerSec;
177: headerSec.HighPart = 0;
178: headerSec.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
179:
180: if (ReadSectors (header, drive, headerSec, 1) != BiosResultSuccess)
181: return false;
182:
183: if (VolumeReadHeader (TRUE, (char *) header, &password, cryptoInfo, nullptr) == 0)
184: {
185: if (headSaltCrc32)
186: *headSaltCrc32 = GetCrc32 (header, PKCS5_SALT_SIZE);
187: return true;
188: }
189:
190: return false;
191: }
192:
193:
194: static bool MountVolume (byte drive, byte &exitKey)
195: {
196: BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
197:
198: // Open volume header
199: while (true)
200: {
201: exitKey = AskPassword (bootArguments->BootPassword);
202:
203: if (exitKey != TC_BIOS_KEY_ENTER)
204: return false;
205:
206: if (OpenVolume (BootDrive, bootArguments->BootPassword, &BootCryptoInfo, &bootArguments->HeaderSaltCrc32))
207: break;
208:
209: Print ("Incorrect password or not a TrueCrypt volume.\r\n\r\n");
210: }
211:
212: // Check memory
213: uint16 codeSeg;
214: __asm mov codeSeg, cs
215: if (codeSeg == TC_BOOT_LOADER_LOWMEM_SEGMENT)
216: {
217: PrintError ("Insufficient memory for encryption");
218: EncryptedVirtualPartition.Drive = TC_FIRST_BIOS_DRIVE - 1;
219: GetKeyboardChar ();
220: return false;
221: }
222:
223: // Setup boot arguments
224: bootArguments->CryptoInfoOffset = (uint16) BootCryptoInfo;
225: bootArguments->CryptoInfoLength = sizeof (*BootCryptoInfo);
226: bootArguments->BootLoaderVersion = VERSION_NUM;
227: TC_SET_BOOT_ARGUMENTS_SIGNATURE (bootArguments->Signature);
228:
229: if (BootCryptoInfo->EncryptedAreaLength.HighPart != 0 || BootCryptoInfo->EncryptedAreaLength.LowPart != 0)
230: {
231: // Setup virtual encrypted partition
232: EncryptedVirtualPartition.Drive = BootDrive;
233:
234: EncryptedVirtualPartition.StartSector.HighPart = BootCryptoInfo->EncryptedAreaStart.HighPart;
235: EncryptedVirtualPartition.StartSector.LowPart = BootCryptoInfo->EncryptedAreaStart.LowPart;
236: EncryptedVirtualPartition.StartSector = EncryptedVirtualPartition.StartSector >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
237:
238: EncryptedVirtualPartition.EndSector.HighPart = BootCryptoInfo->EncryptedAreaLength.HighPart;
239: EncryptedVirtualPartition.EndSector.LowPart = BootCryptoInfo->EncryptedAreaLength.LowPart;
240: EncryptedVirtualPartition.EndSector = (EncryptedVirtualPartition.EndSector - 1) >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
241: EncryptedVirtualPartition.EndSector = EncryptedVirtualPartition.EndSector + EncryptedVirtualPartition.StartSector;
242: }
243: else
244: {
245: // Drive not encrypted
246: EncryptedVirtualPartition.Drive = TC_FIRST_BIOS_DRIVE - 1;
247: }
248:
249: return true;
250: }
251:
252:
253: static byte BootEncryptedDrive ()
254: {
255: Partition partition;
256: size_t partCount;
257:
258: // Find active partition
259: if (GetActivePartition (BootDrive, partition, partCount, false) != BiosResultSuccess || partCount < 1)
260: {
261: PrintError ("No bootable partition found");
262: goto err;
263: }
264:
265: byte exitKey;
266: if (!MountVolume (BootDrive, exitKey))
267: return exitKey;
268:
269: InstallInterruptFilters();
270:
271: // Execute boot sector of the active partition
272: byte bootSector[TC_LB_SIZE];
273: if (ReadSectors (bootSector, partition.Drive, partition.StartSector, 1) == BiosResultSuccess)
274: {
275: ExecuteBootSector (partition.Drive, bootSector);
276: }
277:
278: err:
279: byte scanCode;
280: GetKeyboardChar (&scanCode);
281: return scanCode;
282: }
283:
284:
285: static void BootMenu ()
286: {
287: BiosResult result;
288: Partition partitions[16];
289: Partition bootablePartitions[9];
290: size_t partitionCount;
291: size_t bootablePartitionCount = 0;
292:
293: for (byte drive = TC_FIRST_BIOS_DRIVE; drive <= TC_LAST_BIOS_DRIVE; ++drive)
294: {
295: if (GetDrivePartitions (drive, partitions, array_capacity (partitions), partitionCount, false, true) == BiosResultSuccess)
296: {
297: for (size_t i = 0; i < partitionCount; ++i)
298: {
299: const Partition &partition = partitions[i];
300:
301: byte bootSector[TC_LB_SIZE];
302: result = ReadSectors (bootSector, drive, partition.StartSector, 1);
303:
304: if (result == BiosResultSuccess && *(uint16 *) (bootSector + TC_LB_SIZE - 2) == 0xaa55)
305: {
306: // Windows writes boot loader on all NTFS/FAT filesytems it creates and, therefore,
307: // NTFS/FAT partitions must have the boot indicator set to be considered bootable.
308: if (!partition.Active
309: && (*(uint32 *) (bootSector + 3) == 0x5346544e // 'NTFS'
310: || *(uint16 *) (bootSector + 54) == 0x4146 && bootSector[56] == 'T' // 'FAT'
311: || *(uint16 *) (bootSector + 82) == 0x4146 && bootSector[84] == 'T'))
312: {
313: continue;
314: }
315:
316: // Bootable sector found
317: if (bootablePartitionCount < array_capacity (bootablePartitions))
318: bootablePartitions[bootablePartitionCount++] = partition;
319: }
320: }
321: }
322: }
323:
324: if (bootablePartitionCount < 1)
325: {
326: PrintError ("No bootable partition found");
327: GetKeyboardChar();
328: return;
329: }
330:
331: char partChar;
332: while (true)
333: {
334: InitScreen();
335: Print ("Bootable Partitions:\r\n");
336: PrintRepeatedChar ('\xC4', 20);
337: Print ("\r\n");
338:
339: for (size_t i = 0; i < bootablePartitionCount; ++i)
340: {
341: const Partition &partition = bootablePartitions[i];
342: Print ("["); Print (i + 1); Print ("] ");
343: Print ("Drive: "); Print (partition.Drive - TC_FIRST_BIOS_DRIVE);
344: Print (", Partition: "); Print (partition.Number + 1);
345: Print (", Size: "); Print (partition.SectorCount >> 11); Print (" MB\r\n");
346: }
347:
348: if (bootablePartitionCount == 1)
349: {
350: // There's only one bootable partition so we'll boot it directly instead of showing boot manager
351: partChar = '1';
352: }
353: else
354: {
355: Print ("[Esc] Cancel\r\n\r\n");
356: Print ("Press 1-9 to select partition: ");
357:
358: if (GetString (&partChar, 1) == 0)
359: return;
360:
361: PrintEndl();
362:
363: if (partChar < '1' || partChar > '0' + bootablePartitionCount)
364: {
365: Beep();
366: continue;
367: }
368: }
369:
370: const Partition &partition = bootablePartitions[partChar - '0' - 1];
371:
372: byte bootSector[TC_LB_SIZE];
373: if (ReadSectors (bootSector, partition.Drive, partition.StartSector, 1) == BiosResultSuccess)
374: {
375: ExecuteBootSector (partition.Drive, bootSector);
376: }
377: }
378: }
379:
380:
381: static void DecryptDrive (byte drive)
382: {
383: byte exitKey;
384: if (!MountVolume (drive, exitKey))
385: return;
386:
387: const int sectorsPerIoBlock = 0x7f; // Maximum safe value supported by BIOS
388:
389: bool headerUpdateRequired = false;
390: uint64 sectorsRemaining = EncryptedVirtualPartition.EndSector + 1 - EncryptedVirtualPartition.StartSector;
391: uint64 sector = EncryptedVirtualPartition.EndSector + 1;
392:
393: byte sectorBuf[TC_LB_SIZE];
394: int fragmentSectorCount = sectorsPerIoBlock;
395: int statCount;
396:
397: if (EncryptedVirtualPartition.Drive == TC_FIRST_BIOS_DRIVE - 1)
398: {
399: // Drive not encrypted
400: sectorsRemaining.HighPart = 0;
401: sectorsRemaining.LowPart = 0;
402: headerUpdateRequired = true;
403: }
404: else
405: {
406: Print ("\r\nDo NOT turn off power. Press ESC to abort.\r\n");
407: }
408:
409: while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
410: {
411: if (IsKeyboardCharAvailable ())
412: {
413: byte keyScanCode;
414: GetKeyboardChar (&keyScanCode);
415: if (keyScanCode == TC_BIOS_KEY_ESC)
416: break;
417: }
418:
419: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
420: fragmentSectorCount = sectorsRemaining.LowPart;
421:
422: sector = sector - fragmentSectorCount;
423:
424: if (!(statCount++ & 0xf))
425: {
426: Print ("\rRemaining: ");
427: Print (sectorsRemaining >> 11); Print (" MB ");
428: }
429:
430: if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, false) != BiosResultSuccess)
431: break;
432:
433: for (int i = 0; i < fragmentSectorCount; ++i)
434: {
435: CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * sizeof (sectorBuf), sectorBuf, sizeof (sectorBuf));
436:
437: uint64 s = sector + i;
438: DecryptDataUnits (sectorBuf, &s, 1, BootCryptoInfo);
439:
440: CopyMemory (sectorBuf, TC_BOOT_LOADER_BUFFER_SEGMENT, i * sizeof (sectorBuf), sizeof (sectorBuf));
441: }
442:
443: if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, false) != BiosResultSuccess)
444: break;
445:
446: sectorsRemaining = sectorsRemaining - fragmentSectorCount;
447: headerUpdateRequired = true;
448: }
449:
450: crypto_close (BootCryptoInfo);
451: BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
452:
453: if (headerUpdateRequired)
454: {
455: byte header[HEADER_SIZE];
456: uint64 headerSector;
457: headerSector.HighPart = 0;
458: headerSector.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
459:
460: if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
461: {
462: memset (header, 0, sizeof (header));
463: Print ("\rDrive decrypted.\r\n");
464: }
465: else
466: {
467: // Update encrypted area size in volume header
468:
469: CRYPTO_INFO *headerCryptoInfo = crypto_open();
470: ReadSectors (header, drive, headerSector, 1);
471:
472: if (VolumeReadHeader (TRUE, (char *) header, &bootArguments->BootPassword, NULL, headerCryptoInfo) == 0)
473: {
474: DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
475:
476: byte *sizeField = header + TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH;
477: uint64 encryptedAreaLength = sectorsRemaining << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
478:
479: for (int i = 7; i >= 0; --i)
480: {
481: sizeField[i] = (byte) encryptedAreaLength.LowPart;
482: encryptedAreaLength = encryptedAreaLength >> 8;
483: }
484:
485: EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
486: }
487:
488: crypto_close (headerCryptoInfo);
489: Print ("\r\nAborted.\r\n");
490: }
491:
492: WriteSectors (header, drive, headerSector, 1);
493: }
494:
495: err:
496: memset (bootArguments, 0, sizeof (*bootArguments));
497: GetKeyboardChar();
498: }
499:
500:
501: static void RepairMenu ()
502: {
503: DriveGeometry bootLoaderDriveGeometry;
504: if (GetDriveGeometry (BootLoaderDrive, bootLoaderDriveGeometry) != BiosResultSuccess)
505: {
506: GetKeyboardChar();
507: return;
508: }
509:
510: while (true)
511: {
512: InitScreen();
513: Print ("Available "); Print ("Repair Options"); Print (":\r\n");
514: PrintRepeatedChar ('\xC4', 25);
515: Print ("\r\n");
516:
517: enum
518: {
519: RestoreNone = 0,
520: DecryptVolume,
521: RestoreTrueCryptLoader,
522: RestoreVolumeHeader,
523: RestoreOriginalSystemLoader
524: };
525:
526: static const char *options[] = { "Permanently decrypt system partition/drive", "Restore TrueCrypt Boot Loader", "Restore key data (volume header)", "Restore original system loader" };
527:
528: int optionCount = 1;
529: if (BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER)
530: optionCount = array_capacity (options);
531: else if (BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISK)
532: optionCount = array_capacity (options) - 1;
533:
534: int selection = AskSelection (options, optionCount);
535: PrintEndl();
536:
537: if (selection == RestoreNone)
538: return;
539:
540: if (selection == DecryptVolume)
541: {
542: DecryptDrive (BootDrive);
543: continue;
544: }
545:
546: bool writeConfirmed = false;
547: BiosResult result;
548: byte sectorBuf[TC_LB_SIZE];
549:
550: uint64 sector;
551: sector.HighPart = 0;
552: ChsAddress chs;
553:
554: for (int i = (selection == RestoreVolumeHeader ? TC_BOOT_VOLUME_HEADER_SECTOR : TC_MBR_SECTOR);
555: i < TC_BOOT_LOADER_AREA_SECTOR_COUNT; ++i)
556: {
557: sector.LowPart = (selection == RestoreOriginalSystemLoader ? TC_ORIG_BOOT_LOADER_BACKUP_SECTOR : 0) + i;
558:
559: // The backup medium may be a floppy-emulated bootable CD. The emulation may fail if LBA addressing is used.
560: // Therefore, only CHS addressing can be used.
561: LbaToChs (bootLoaderDriveGeometry, sector, chs);
562:
563: result = ReadSectors (sectorBuf, BootLoaderDrive, chs, 1);
564: if (result != BiosResultSuccess)
565: goto err;
566:
567: sector.LowPart = i;
568:
569: // MBR
570: if (i == TC_MBR_SECTOR)
571: {
572: // Preserve partition table
573: byte bootSecBuf[TC_LB_SIZE];
574:
575: result = ReadSectors (bootSecBuf, TC_FIRST_BIOS_DRIVE, sector, 1);
576: if (result != BiosResultSuccess)
577: goto err;
578:
579: memcpy (sectorBuf + TC_MAX_MBR_BOOT_CODE_SIZE,
580: bootSecBuf + TC_MAX_MBR_BOOT_CODE_SIZE,
581: sizeof (bootSecBuf) - TC_MAX_MBR_BOOT_CODE_SIZE);
582:
583: // Clear rescue disk flags
584: if (selection == RestoreTrueCryptLoader)
585: sectorBuf[TC_BOOT_SECTOR_CONFIG_OFFSET] &= ~(TC_BOOT_CFG_FLAG_RESCUE_DISK | TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER);
586: }
587:
588: // Volume header
589: if (i == TC_BOOT_VOLUME_HEADER_SECTOR)
590: {
591: if (selection == RestoreTrueCryptLoader)
592: continue;
593:
594: if (selection == RestoreVolumeHeader)
595: {
596: while (true)
597: {
598: Password password;
599: byte exitKey = AskPassword (password);
600:
601: if (exitKey != TC_BIOS_KEY_ENTER)
602: goto abort;
603:
604: CRYPTO_INFO *cryptoInfo;
605:
606: // Restore volume header only if the current one cannot be used
607: if (OpenVolume (TC_FIRST_BIOS_DRIVE, password, &cryptoInfo))
608: {
609: Print ("Original header preserved.\r\n");
610: crypto_close (cryptoInfo);
611: goto err;
612: }
613:
614: if (VolumeReadHeader (TRUE, (char *) sectorBuf, &password, &cryptoInfo, nullptr) == 0)
615: {
616: crypto_close (cryptoInfo);
617: break;
618: }
619:
620: Print ("Incorrect password or not a TrueCrypt volume.\r\n\r\n");
621: }
622: }
623: }
624:
625: if (!writeConfirmed && !AskYesNo ("Modify Drive 0"))
626: goto abort;
627: writeConfirmed = true;
628:
629: if (WriteSectors (sectorBuf, TC_FIRST_BIOS_DRIVE, sector, 1) != BiosResultSuccess)
630: goto err;
631: }
632: done:
633: switch (selection)
634: {
635: case RestoreTrueCryptLoader:
636: Print ("TrueCrypt Boot Loader");
637: break;
638:
639: case RestoreVolumeHeader:
640: Print ("Header");
641: break;
642:
643: case RestoreOriginalSystemLoader:
644: Print ("System loader");
645: break;
646: }
647: Print (" restored.\r\n");
648:
649: err: GetKeyboardChar();
650: abort: ;
651: }
652: }
653:
654:
655: #ifndef DEBUG
656: extern "C" void _acrtused () { } // Required by linker
657: #endif
658:
659:
660: void main ()
661: {
662: __asm mov BootLoaderDrive, dl
663: __asm mov BootSectorFlags, dh
664:
665: #ifdef TC_TRACING_ENABLED
666: InitDebugPort();
667: #endif
668:
669: BootDrive = BootLoaderDrive;
670: if (BootDrive < TC_FIRST_BIOS_DRIVE)
671: BootDrive = TC_FIRST_BIOS_DRIVE;
672:
673: if (GetDriveGeometry (BootDrive, BootDriveGeometry, true) != BiosResultSuccess)
674: {
675: BootDrive = TC_FIRST_BIOS_DRIVE;
676: if (GetDriveGeometry (BootDrive, BootDriveGeometry) == BiosResultSuccess)
677: BootDriveGeometryValid = TRUE;
678: }
679: else
680: BootDriveGeometryValid = TRUE;
681:
682: while (true)
683: {
684: InitScreen();
685: PrintMainMenu();
686:
687: byte exitKey = BootEncryptedDrive();
688:
689: if (exitKey == TC_MENU_KEY_REPAIR)
690: {
691: RepairMenu();
692: continue;
693: }
694:
695: BootMenu();
696: }
697: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.