--- truecrypt/boot/windows/bootmain.cpp 2018/04/24 16:55:32 1.1.1.5 +++ truecrypt/boot/windows/bootmain.cpp 2018/04/24 17:09:53 1.1.1.12 @@ -1,9 +1,9 @@ /* - Copyright (c) 2008 TrueCrypt Foundation. All rights reserved. + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. - Governed by the TrueCrypt License 2.5 the full text of which is contained - in the file License.txt included in TrueCrypt binary and source code - distribution packages. + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. */ #include "Crc.h" @@ -22,6 +22,7 @@ #include "BootDiskIo.h" #include "BootEncryptedIo.h" #include "BootMemory.h" +#include "BootStrings.h" #include "IntFilter.h" @@ -29,28 +30,42 @@ static void InitScreen () { ClearScreen(); - Print ( + const char *title = #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE " TrueCrypt Boot Loader " #else " TrueCrypt Rescue Disk " #endif - VERSION_STRING " Copyright (C) 2008 TrueCrypt Foundation\r\n"); + VERSION_STRING "\r\n"; + + Print (title); PrintRepeatedChar ('\xDC', TC_BIOS_MAX_CHARS_PER_LINE); + +#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE + if (CustomUserMessage[0]) + { + PrintEndl(); + Print (CustomUserMessage); + } +#endif + PrintEndl (2); } static void PrintMainMenu () { + if (PreventBootMenu) + return; + Print (" Keyboard Controls:\r\n"); Print (" [Esc] "); #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE - Print ((BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) == TC_HIDDEN_OS_CREATION_PHASE_CLONING - ? "Postpone system cloning (boot now)" + Print ((BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) != TC_HIDDEN_OS_CREATION_PHASE_NONE + ? "Boot Non-Hidden System (Boot Manager)" : "Skip Authentication (Boot Manager)"); #else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE @@ -85,12 +100,13 @@ static bool AskYesNo (const char *messag case 'y': case 'Y': case 'z': - PrintEndl(); + case 'Z': + Print ("y\r\n"); return true; case 'n': case 'N': - PrintEndl(); + Print ("n\r\n"); return false; default: @@ -128,17 +144,14 @@ static int AskSelection (const char *opt } -static byte AskPassword (Password &password, bool hiddenSystem) +static byte AskPassword (Password &password) { size_t pos = 0; byte scanCode; byte asciiCode; Print ("Enter password"); - if (PreventHiddenSystemBoot) - Print (hiddenSystem ? " for hidden system:\r\n" : " for decoy system:\r\n"); - else - Print (": "); + Print (PreventNormalSystemBoot ? " for hidden system:\r\n" : ": "); while (true) { @@ -159,7 +172,7 @@ static byte AskPassword (Password &passw if (pos < MAX_PASSWORD) PrintBackspace(); else - PrintCharAtCusor (' '); + PrintCharAtCursor (' '); --pos; } @@ -186,7 +199,7 @@ static byte AskPassword (Password &passw if (pos < MAX_PASSWORD) PrintChar ('*'); else - PrintCharAtCusor ('*'); + PrintCharAtCursor ('*'); } } @@ -196,65 +209,76 @@ static void ExecuteBootSector (byte driv Print ("Booting...\r\n"); CopyMemory (sectorBuffer, 0x0000, 0x7c00, TC_LB_SIZE); + BootStarted = true; + uint32 addr = 0x7c00; __asm { cli - mov dl, drive + mov dl, drive // Boot drive + mov dh, 0 xor ax, ax + mov si, ax mov ds, ax mov es, ax mov ss, ax - mov sp, 0xffff + mov sp, 0x7c00 sti + jmp cs:addr } } -static bool OpenVolume (byte drive, Password &password, CRYPTO_INFO **cryptoInfo, uint32 *headSaltCrc32, bool skipNormal, bool skipHidden) +static bool OpenVolume (byte drive, Password &password, CRYPTO_INFO **cryptoInfo, uint32 *headerSaltCrc32, bool skipNormal, bool skipHidden) { - bool status = false; - bool hiddenVolume = false; - + int volumeType; + bool hiddenVolume; uint64 headerSec; - headerSec.HighPart = 0; - headerSec.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR; AcquireSectorBuffer(); - while (true) + for (volumeType = 1; volumeType <= 2; ++volumeType) { - if (ReadSectors (SectorBuffer, drive, headerSec, 1) != BiosResultSuccess) - goto ret; - - if ((!skipNormal || hiddenVolume) && VolumeReadHeader (!hiddenVolume, (char *) SectorBuffer, &password, cryptoInfo, nullptr) == 0) - status = true; + hiddenVolume = (volumeType == 2); - if (headSaltCrc32) - *headSaltCrc32 = GetCrc32 (SectorBuffer, PKCS5_SALT_SIZE); + if (hiddenVolume) + { + if (skipHidden || PartitionFollowingActive.Drive != drive || PartitionFollowingActive.SectorCount <= ActivePartition.SectorCount) + continue; - if (!status && !hiddenVolume && !skipHidden && PartitionFollowingActive.Drive == drive - && PartitionFollowingActive.SectorCount > ActivePartition.SectorCount) + headerSec = PartitionFollowingActive.StartSector + TC_HIDDEN_VOLUME_HEADER_OFFSET / TC_LB_SIZE; + } + else { - hiddenVolume = true; - headerSec.LowPart = PartitionFollowingActive.StartSector.LowPart + TC_HIDDEN_VOLUME_HEADER_OFFSET / TC_LB_SIZE; - continue; + if (skipNormal) + continue; + + headerSec.HighPart = 0; + headerSec.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR; } - // Prevent opening of a non-system hidden volume - if (status && hiddenVolume && !((*cryptoInfo)->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM)) + if (ReadSectors (SectorBuffer, drive, headerSec, 1) != BiosResultSuccess) + continue; + + if (ReadVolumeHeader (!hiddenVolume, (char *) SectorBuffer, &password, cryptoInfo, nullptr) == ERR_SUCCESS) { - status = false; - crypto_close (*cryptoInfo); - } + // Prevent opening a non-system hidden volume + if (hiddenVolume && !((*cryptoInfo)->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM)) + { + crypto_close (*cryptoInfo); + continue; + } + + if (headerSaltCrc32) + *headerSaltCrc32 = GetCrc32 (SectorBuffer, PKCS5_SALT_SIZE); - break; + break; + } } -ret: ReleaseSectorBuffer(); - return status; + return volumeType != 3; } @@ -264,7 +288,7 @@ static bool CheckMemoryRequirements () __asm mov codeSeg, cs if (codeSeg == TC_BOOT_LOADER_LOWMEM_SEGMENT) { - PrintError ("Insufficient base memory: ", true, false); + PrintErrorNoEndl ("BIOS reserved too much memory: "); uint16 memFree; __asm @@ -277,13 +301,9 @@ static bool CheckMemoryRequirements () pop es } - Print (memFree); Print (" KB\r\n"); - - Print ("Try disabling unneeded components (RAID, AHCI, integrated audio card, etc.) in\r\n" - "BIOS setup menu (invoked by pressing Del or F2 after turning on your computer).\r\n"); -#ifndef TC_WINDOWS_BOOT_AES - Print ("If it does not help, try using the AES encryption algorithm to reduce memory\r\nrequirements.\r\n"); -#endif + Print (memFree); + PrintEndl(); + Print (TC_BOOT_STR_UPGRADE_BIOS); return false; } @@ -302,7 +322,7 @@ static bool MountVolume (byte drive, byt // Open volume header while (true) { - exitKey = AskPassword (bootArguments->BootPassword, skipNormal); + exitKey = AskPassword (bootArguments->BootPassword); if (exitKey != TC_BIOS_KEY_ENTER) return false; @@ -315,10 +335,15 @@ static bool MountVolume (byte drive, byt Print ("Incorrect password.\r\n\r\n"); - if (++incorrectPasswordCount == 5) + if (++incorrectPasswordCount == 4) { +#ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE + Print ("If you are sure the password is correct, the key data may be damaged.\r\n" + "If so, use 'Repair Options' > 'Restore key data'.\r\n\r\n"); +#else Print ("If you are sure the password is correct, the key data may be damaged. Boot your\r\n" "TrueCrypt Rescue Disk and select 'Repair Options' > 'Restore key data'.\r\n\r\n"); +#endif } } @@ -326,10 +351,13 @@ static bool MountVolume (byte drive, byt bootArguments->BootLoaderVersion = VERSION_NUM; bootArguments->CryptoInfoOffset = (uint16) BootCryptoInfo; bootArguments->CryptoInfoLength = sizeof (*BootCryptoInfo); - + if (BootCryptoInfo->hiddenVolume) bootArguments->HiddenSystemPartitionStart = PartitionFollowingActive.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR; + if (ExtraBootPartitionPresent) + bootArguments->Flags |= TC_BOOT_ARGS_FLAG_EXTRA_BOOT_PARTITION; + TC_SET_BOOT_ARGUMENTS_SIGNATURE (bootArguments->Signature); // Setup virtual encrypted partition @@ -358,16 +386,41 @@ static bool MountVolume (byte drive, byt } +static bool GetSystemPartitions (byte drive) +{ + size_t partCount; + + if (!GetActivePartition (drive)) + return false; + + // Find partition following the active one + GetDrivePartitions (drive, &PartitionFollowingActive, 1, partCount, false, &ActivePartition); + + // If there is an extra boot partition, use the partitions following it. + // The real boot partition is determined in BootEncryptedDrive(). + if (ActivePartition.SectorCount.HighPart == 0 && ActivePartition.SectorCount.LowPart <= TC_MAX_EXTRA_BOOT_PARTITION_SIZE / TC_LB_SIZE + && PartitionFollowingActive.Drive != TC_INVALID_BIOS_DRIVE) + { + ExtraBootPartitionPresent = true; + + ActivePartition = PartitionFollowingActive; + GetDrivePartitions (drive, &PartitionFollowingActive, 1, partCount, false, &ActivePartition); + } + + return true; +} + + static byte BootEncryptedDrive () { - BootCryptoInfo = NULL; BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET; + byte exitKey; + BootCryptoInfo = NULL; - if (!GetActiveAndFollowingPartition (BootDrive)) + if (!GetSystemPartitions (BootDrive)) goto err; - byte exitKey; - if (!MountVolume (BootDrive, exitKey, false, PreventHiddenSystemBoot)) + if (!MountVolume (BootDrive, exitKey, PreventNormalSystemBoot, false)) return exitKey; if (!CheckMemoryRequirements ()) @@ -379,6 +432,9 @@ static byte BootEncryptedDrive () bootArguments->DecoySystemPartitionStart = ActivePartition.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR; } + if (ExtraBootPartitionPresent && !GetActivePartition (BootDrive)) + goto err; + if (!InstallInterruptFilters()) goto err; @@ -389,6 +445,12 @@ static byte BootEncryptedDrive () // Execute boot sector of the active partition if (ReadSectors (SectorBuffer, ActivePartition.Drive, ActivePartition.StartSector, 1) == BiosResultSuccess) { + if (*(uint16 *) (SectorBuffer + 510) != 0xaa55) + { + PrintError (TC_BOOT_STR_NO_BOOT_PARTITION); + GetKeyboardChar(); + } + ExecuteBootSector (ActivePartition.Drive, SectorBuffer); } @@ -434,6 +496,7 @@ static void BootMenu () // NTFS/FAT partitions must have the boot indicator set to be considered bootable. if (!partition.Active && (*(uint32 *) (SectorBuffer + 3) == 0x5346544e // 'NTFS' + || *(uint32 *) (SectorBuffer + 3) == 0x41465845 && SectorBuffer[7] == 'T' // 'exFAT' || *(uint16 *) (SectorBuffer + 54) == 0x4146 && SectorBuffer[56] == 'T' // 'FAT' || *(uint16 *) (SectorBuffer + 82) == 0x4146 && SectorBuffer[84] == 'T')) { @@ -450,7 +513,7 @@ static void BootMenu () if (bootablePartitionCount < 1) { - PrintError ("No bootable partition found"); + PrintError (TC_BOOT_STR_NO_BOOT_PARTITION); GetKeyboardChar(); return; } @@ -506,7 +569,7 @@ static void BootMenu () #ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE -static bool CopyActivePartitionToHiddenVolume (byte drive, byte &exitKey) +static bool CopySystemPartitionToHiddenVolume (byte drive, byte &exitKey) { bool status = false; @@ -521,26 +584,36 @@ static bool CopyActivePartitionToHiddenV if (!CheckMemoryRequirements ()) goto err; - if (!GetActiveAndFollowingPartition (drive)) + if (!GetSystemPartitions (drive)) goto err; if (PartitionFollowingActive.Drive == TC_INVALID_BIOS_DRIVE) + TC_THROW_FATAL_EXCEPTION; + + // Check if BIOS can read the last sector of the hidden system + AcquireSectorBuffer(); + + if (ReadSectors (SectorBuffer, PartitionFollowingActive.Drive, PartitionFollowingActive.EndSector - (TC_VOLUME_HEADER_GROUP_SIZE / TC_LB_SIZE - 2), 1) != BiosResultSuccess + || GetCrc32 (SectorBuffer, sizeof (SectorBuffer)) != OuterVolumeBackupHeaderCrc) { - PrintError ("No partition follows the active"); + PrintErrorNoEndl ("Your BIOS does not support large drives"); + Print (IsLbaSupported (PartitionFollowingActive.Drive) ? " due to a bug" : "\r\n- Enable LBA in BIOS"); + PrintEndl(); + Print (TC_BOOT_STR_UPGRADE_BIOS); + + ReleaseSectorBuffer(); goto err; } + ReleaseSectorBuffer(); + if (!MountVolume (drive, exitKey, true, false)) return false; sectorsRemaining = EncryptedVirtualPartition.SectorCount; if (!(sectorsRemaining == ActivePartition.SectorCount)) - { - PrintError ("Hidden volume size differs from system partition"); - crypto_close (BootCryptoInfo); - goto err; - } + TC_THROW_FATAL_EXCEPTION; InitScreen(); Print ("\r\nCopying system to hidden volume. To abort, press Esc.\r\n\r\n"); @@ -555,10 +628,14 @@ static bool CopyActivePartitionToHiddenV } if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount) - fragmentSectorCount = sectorsRemaining.LowPart; + fragmentSectorCount = (int) sectorsRemaining.LowPart; if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, ActivePartition.StartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess) - break; + { + Print ("To fix bad sectors: 1) Terminate 2) Encrypt and decrypt sys partition 3) Retry\r\n"); + crypto_close (BootCryptoInfo); + goto err; + } AcquireSectorBuffer(); @@ -575,7 +652,10 @@ static bool CopyActivePartitionToHiddenV ReleaseSectorBuffer(); if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, HiddenVolumeStartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess) - break; + { + crypto_close (BootCryptoInfo); + goto err; + } sectorsRemaining = sectorsRemaining - fragmentSectorCount; sectorOffset = sectorOffset + fragmentSectorCount; @@ -628,9 +708,8 @@ static void DecryptDrive (byte drive) bool skipBadSectors = false; - Print ("\r\nIMPORTANT: Use this only if Windows cannot start. Decryption under Windows is\r\n" - "much faster. To decrypt under Windows, run TrueCrypt and select 'System' >\r\n" - "'Permanently Decrypt'.\r\n\r\n"); + Print ("\r\nUse only if Windows cannot start. Decryption under Windows is much faster\r\n" + "(in TrueCrypt, select 'System' > 'Permanently Decrypt').\r\n\r\n"); if (!AskYesNo ("Decrypt now")) { @@ -656,7 +735,7 @@ static void DecryptDrive (byte drive) break; if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount) - fragmentSectorCount = sectorsRemaining.LowPart; + fragmentSectorCount = (int) sectorsRemaining.LowPart; sector = sector - fragmentSectorCount; @@ -715,7 +794,7 @@ askBadSectorSkip: CRYPTO_INFO *headerCryptoInfo = crypto_open(); while (ReadSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess); - if (VolumeReadHeader (TRUE, (char *) SectorBuffer, &bootArguments->BootPassword, NULL, headerCryptoInfo) == 0) + if (ReadVolumeHeader (TRUE, (char *) SectorBuffer, &bootArguments->BootPassword, NULL, headerCryptoInfo) == 0) { DecryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo); @@ -758,10 +837,13 @@ ret: static void RepairMenu () { DriveGeometry bootLoaderDriveGeometry; - if (GetDriveGeometry (BootLoaderDrive, bootLoaderDriveGeometry) != BiosResultSuccess) + + if (GetDriveGeometry (BootLoaderDrive, bootLoaderDriveGeometry, true) != BiosResultSuccess) { - GetKeyboardChar(); - return; + // Some BIOSes may fail to get the geometry of an emulated floppy drive + bootLoaderDriveGeometry.Cylinders = 80; + bootLoaderDriveGeometry.Heads = 2; + bootLoaderDriveGeometry.Sectors = 18; } while (true) @@ -797,7 +879,7 @@ static void RepairMenu () continue; case RestoreOriginalSystemLoader: - if (!AskYesNo ("Is the drive decrypted")) + if (!AskYesNo ("Is the system partition/drive decrypted")) { Print ("Please decrypt it first.\r\n"); GetKeyboardChar(); @@ -861,6 +943,9 @@ static void RepairMenu () { while (true) { + bool validHeaderPresent = false; + uint32 masterKeyScheduleCrc; + Password password; byte exitKey = AskPassword (password); @@ -875,16 +960,27 @@ static void RepairMenu () // Restore volume header only if the current one cannot be used if (OpenVolume (TC_FIRST_BIOS_DRIVE, password, &cryptoInfo, nullptr, false, true)) { - Print ("Original header preserved.\r\n"); + validHeaderPresent = true; + masterKeyScheduleCrc = GetCrc32 (cryptoInfo->ks, sizeof (cryptoInfo->ks)); crypto_close (cryptoInfo); - goto err; } AcquireSectorBuffer(); CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, 0, SectorBuffer, TC_LB_SIZE); - if (VolumeReadHeader (TRUE, (char *) SectorBuffer, &password, &cryptoInfo, nullptr) == 0) + if (ReadVolumeHeader (TRUE, (char *) SectorBuffer, &password, &cryptoInfo, nullptr) == 0) { + if (validHeaderPresent) + { + if (masterKeyScheduleCrc == GetCrc32 (cryptoInfo->ks, sizeof (cryptoInfo->ks))) + { + Print ("Original header preserved.\r\n"); + goto err; + } + + Print ("WARNING: Drive 0 contains a valid header!\r\n"); + } + crypto_close (cryptoInfo); break; } @@ -944,6 +1040,12 @@ void main () InitStackChecker(); #endif +#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE + ReadBootSectorUserConfiguration(); +#elif defined (TC_WINDOWS_BOOT_AES) + EnableHwEncryption (!(BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION)); +#endif + InitVideoMode(); InitScreen(); @@ -953,15 +1055,21 @@ void main () BootDrive = TC_FIRST_BIOS_DRIVE; // Query boot drive geometry - if (GetDriveGeometry (BootDrive, BootDriveGeometry, true) != BiosResultSuccess) + if (GetDriveGeometry (BootDrive, BootDriveGeometry) != BiosResultSuccess) { BootDrive = TC_FIRST_BIOS_DRIVE; - if (GetDriveGeometry (BootDrive, BootDriveGeometry) == BiosResultSuccess) - BootDriveGeometryValid = TRUE; + if (GetDriveGeometry (BootDrive, BootDriveGeometry) != BiosResultSuccess) + { +#ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE + Print ("- Connect system drive to (SATA) port 1\r\n"); +#endif + GetKeyboardChar(); + } + else + BootDriveGeometryValid = true; } else - BootDriveGeometryValid = TRUE; - + BootDriveGeometryValid = true; #ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE @@ -997,14 +1105,14 @@ void main () if (hiddenSystemCreationPhase != TC_HIDDEN_OS_CREATION_PHASE_NONE) { - PreventHiddenSystemBoot = true; + PreventNormalSystemBoot = true; PrintMainMenu(); if (hiddenSystemCreationPhase == TC_HIDDEN_OS_CREATION_PHASE_CLONING) { - if (CopyActivePartitionToHiddenVolume (BootDrive, exitKey)) + if (CopySystemPartitionToHiddenVolume (BootDrive, exitKey)) { - BootSectorFlags = (BootSectorFlags & ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) | TC_HIDDEN_OS_CREATION_PHASE_DECOY_OS; + BootSectorFlags = (BootSectorFlags & ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) | TC_HIDDEN_OS_CREATION_PHASE_WIPING; UpdateBootSectorConfiguration (BootLoaderDrive); } else if (exitKey == TC_BIOS_KEY_ESC) @@ -1032,6 +1140,7 @@ void main () #endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE bootMenu: - BootMenu(); + if (!PreventBootMenu) + BootMenu(); } }