VeraCrypt
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Boot/Windows/Bios.h28
-rw-r--r--src/Boot/Windows/Boot.vcproj242
-rw-r--r--src/Boot/Windows/BootCommon.h78
-rw-r--r--src/Boot/Windows/BootConfig.cpp90
-rw-r--r--src/Boot/Windows/BootConfig.h42
-rw-r--r--src/Boot/Windows/BootConsoleIo.cpp330
-rw-r--r--src/Boot/Windows/BootConsoleIo.h67
-rw-r--r--src/Boot/Windows/BootCrt.asm23
-rw-r--r--src/Boot/Windows/BootDebug.cpp177
-rw-r--r--src/Boot/Windows/BootDebug.h56
-rw-r--r--src/Boot/Windows/BootDefs.h188
-rw-r--r--src/Boot/Windows/BootDiskIo.cpp487
-rw-r--r--src/Boot/Windows/BootDiskIo.h116
-rw-r--r--src/Boot/Windows/BootEncryptedIo.cpp128
-rw-r--r--src/Boot/Windows/BootEncryptedIo.h18
-rw-r--r--src/Boot/Windows/BootMain.cpp1151
-rw-r--r--src/Boot/Windows/BootMain.h30
-rw-r--r--src/Boot/Windows/BootMemory.cpp82
-rw-r--r--src/Boot/Windows/BootMemory.h24
-rw-r--r--src/Boot/Windows/BootSector.asm237
-rw-r--r--src/Boot/Windows/BootStrings.h16
-rw-r--r--src/Boot/Windows/Decompressor.c436
-rw-r--r--src/Boot/Windows/IntFilter.cpp641
-rw-r--r--src/Boot/Windows/IntFilter.h16
-rw-r--r--src/Boot/Windows/Makefile184
-rw-r--r--src/Boot/Windows/Platform.cpp226
-rw-r--r--src/Boot/Windows/Platform.h112
-rw-r--r--src/Common/Apidrvr.h317
-rw-r--r--src/Common/BaseCom.cpp231
-rw-r--r--src/Common/BaseCom.h115
-rw-r--r--src/Common/BootEncryption.cpp2457
-rw-r--r--src/Common/BootEncryption.h241
-rw-r--r--src/Common/Cache.c94
-rw-r--r--src/Common/Cache.h23
-rw-r--r--src/Common/Cmdline.c240
-rw-r--r--src/Common/Cmdline.h41
-rw-r--r--src/Common/Combo.c212
-rw-r--r--src/Common/Combo.h27
-rw-r--r--src/Common/Common.h81
-rw-r--r--src/Common/Common.rc541
-rw-r--r--src/Common/Crc.c133
-rw-r--r--src/Common/Crc.h35
-rw-r--r--src/Common/Crypto.c1871
-rw-r--r--src/Common/Crypto.h332
-rw-r--r--src/Common/Dictionary.c80
-rw-r--r--src/Common/Dictionary.h30
-rw-r--r--src/Common/Dlgcode.c9848
-rw-r--r--src/Common/Dlgcode.h532
-rw-r--r--src/Common/EncryptionThreadPool.c507
-rw-r--r--src/Common/EncryptionThreadPool.h38
-rw-r--r--src/Common/Endian.c57
-rw-r--r--src/Common/Endian.h147
-rw-r--r--src/Common/Exception.h81
-rw-r--r--src/Common/Fat.c445
-rw-r--r--src/Common/Fat.h67
-rw-r--r--src/Common/Format.c1010
-rw-r--r--src/Common/Format.h68
-rw-r--r--src/Common/GfMul.c894
-rw-r--r--src/Common/GfMul.h76
-rw-r--r--src/Common/Inflate.c1308
-rw-r--r--src/Common/Inflate.h51
-rw-r--r--src/Common/Keyfiles.c685
-rw-r--r--src/Common/Keyfiles.h48
-rw-r--r--src/Common/Language.c515
-rw-r--r--src/Common/Language.h37
-rw-r--r--src/Common/Language.xml1341
-rw-r--r--src/Common/Makefile1
-rw-r--r--src/Common/Password.c422
-rw-r--r--src/Common/Password.h46
-rw-r--r--src/Common/Pkcs5.c642
-rw-r--r--src/Common/Pkcs5.h41
-rw-r--r--src/Common/Progress.c130
-rw-r--r--src/Common/Progress.h22
-rw-r--r--src/Common/Random.c772
-rw-r--r--src/Common/Random.h62
-rw-r--r--src/Common/Registry.c286
-rw-r--r--src/Common/Registry.h32
-rw-r--r--src/Common/Resource.h174
-rw-r--r--src/Common/SecurityToken.cpp761
-rw-r--r--src/Common/SecurityToken.h216
-rw-r--r--src/Common/Sources17
-rw-r--r--src/Common/Tcdefs.h301
-rw-r--r--src/Common/Tests.c1722
-rw-r--r--src/Common/Tests.h30
-rw-r--r--src/Common/Textual_logo_288dpi.bmpbin0 -> 165726 bytes
-rw-r--r--src/Common/Textual_logo_96dpi.bmpbin0 -> 18462 bytes
-rw-r--r--src/Common/Textual_logo_background.bmpbin0 -> 822 bytes
-rw-r--r--src/Common/TrueCrypt.icobin0 -> 13694 bytes
-rw-r--r--src/Common/TrueCrypt_Volume.icobin0 -> 13382 bytes
-rw-r--r--src/Common/TrueCrypt_mounted.icobin0 -> 13382 bytes
-rw-r--r--src/Common/Volumes.c1198
-rw-r--r--src/Common/Volumes.h144
-rw-r--r--src/Common/Wipe.c187
-rw-r--r--src/Common/Wipe.h40
-rw-r--r--src/Common/Xml.c231
-rw-r--r--src/Common/Xml.h26
-rw-r--r--src/Common/Xts.c746
-rw-r--r--src/Common/Xts.h80
-rw-r--r--src/Crypto/Aes.h215
-rw-r--r--src/Crypto/AesSmall.c953
-rw-r--r--src/Crypto/AesSmall.h169
-rw-r--r--src/Crypto/AesSmall_x86.asm1444
-rw-r--r--src/Crypto/Aes_hw_cpu.asm330
-rw-r--r--src/Crypto/Aes_hw_cpu.h30
-rw-r--r--src/Crypto/Aes_x64.asm907
-rw-r--r--src/Crypto/Aes_x86.asm646
-rw-r--r--src/Crypto/Aescrypt.c311
-rw-r--r--src/Crypto/Aeskey.c573
-rw-r--r--src/Crypto/Aesopt.h734
-rw-r--r--src/Crypto/Aestab.c428
-rw-r--r--src/Crypto/Aestab.h174
-rw-r--r--src/Crypto/Blowfish.c382
-rw-r--r--src/Crypto/Blowfish.h25
-rw-r--r--src/Crypto/Cast.c703
-rw-r--r--src/Crypto/Cast.h24
-rw-r--r--src/Crypto/Crypto.vcproj318
-rw-r--r--src/Crypto/Des.c406
-rw-r--r--src/Crypto/Des.h28
-rw-r--r--src/Crypto/Makefile1
-rw-r--r--src/Crypto/Makefile.inc15
-rw-r--r--src/Crypto/Rmd160.c490
-rw-r--r--src/Crypto/Rmd160.h33
-rw-r--r--src/Crypto/Serpent.c943
-rw-r--r--src/Crypto/Serpent.h19
-rw-r--r--src/Crypto/Sha1.c282
-rw-r--r--src/Crypto/Sha1.h80
-rw-r--r--src/Crypto/Sha2.c770
-rw-r--r--src/Crypto/Sha2.h155
-rw-r--r--src/Crypto/Sources23
-rw-r--r--src/Crypto/Twofish.c548
-rw-r--r--src/Crypto/Twofish.h55
-rw-r--r--src/Crypto/Whirlpool.c1058
-rw-r--r--src/Crypto/Whirlpool.h151
-rw-r--r--src/Driver/BuildDriver.cmd162
-rw-r--r--src/Driver/DriveFilter.c1942
-rw-r--r--src/Driver/DriveFilter.h85
-rw-r--r--src/Driver/Driver.rc101
-rw-r--r--src/Driver/Driver.vcproj414
-rw-r--r--src/Driver/DumpFilter.c244
-rw-r--r--src/Driver/DumpFilter.h21
-rw-r--r--src/Driver/EncryptedIoQueue.c1008
-rw-r--r--src/Driver/EncryptedIoQueue.h161
-rw-r--r--src/Driver/Makefile1
-rw-r--r--src/Driver/Ntdriver.c3293
-rw-r--r--src/Driver/Ntdriver.h174
-rw-r--r--src/Driver/Ntvol.c862
-rw-r--r--src/Driver/Ntvol.h19
-rw-r--r--src/Driver/Resource.h16
-rw-r--r--src/Driver/Sources21
-rw-r--r--src/Driver/VolumeFilter.c290
-rw-r--r--src/Driver/VolumeFilter.h19
-rw-r--r--src/Format/Format.manifest21
-rw-r--r--src/Format/Format.rc698
-rw-r--r--src/Format/Format.vcproj682
-rw-r--r--src/Format/FormatCom.cpp222
-rw-r--r--src/Format/FormatCom.h32
-rw-r--r--src/Format/FormatCom.idl48
-rw-r--r--src/Format/InPlace.c1692
-rw-r--r--src/Format/InPlace.h45
-rw-r--r--src/Format/Resource.h151
-rw-r--r--src/Format/Tcformat.c9004
-rw-r--r--src/Format/Tcformat.h104
-rw-r--r--src/Format/TrueCrypt_Wizard.bmpbin0 -> 166518 bytes
-rw-r--r--src/License.html169
-rw-r--r--src/License.txt503
-rw-r--r--src/Mount/Drive_icon_96dpi.bmpbin0 -> 1206 bytes
-rw-r--r--src/Mount/Drive_icon_mask_96dpi.bmpbin0 -> 110 bytes
-rw-r--r--src/Mount/Favorites.cpp867
-rw-r--r--src/Mount/Favorites.h74
-rw-r--r--src/Mount/Hotkeys.c525
-rw-r--r--src/Mount/Hotkeys.h48
-rw-r--r--src/Mount/Logo_288dpi.bmpbin0 -> 50166 bytes
-rw-r--r--src/Mount/Logo_96dpi.bmpbin0 -> 5622 bytes
-rw-r--r--src/Mount/MainCom.cpp267
-rw-r--r--src/Mount/MainCom.h32
-rw-r--r--src/Mount/MainCom.idl50
-rw-r--r--src/Mount/Mount.c8999
-rw-r--r--src/Mount/Mount.h115
-rw-r--r--src/Mount/Mount.manifest21
-rw-r--r--src/Mount/Mount.rc635
-rw-r--r--src/Mount/Mount.vcproj689
-rw-r--r--src/Mount/Resource.h234
-rw-r--r--src/Mount/System_drive_icon_96dpi.bmpbin0 -> 1206 bytes
-rw-r--r--src/Mount/System_drive_icon_mask_96dpi.bmpbin0 -> 110 bytes
-rw-r--r--src/Platform/Buffer.cpp142
-rw-r--r--src/Platform/Buffer.h115
-rw-r--r--src/Platform/Directory.h29
-rw-r--r--src/Platform/Event.cpp47
-rw-r--r--src/Platform/Event.h86
-rw-r--r--src/Platform/Exception.cpp52
-rw-r--r--src/Platform/Exception.h110
-rw-r--r--src/Platform/File.h110
-rw-r--r--src/Platform/FileCommon.cpp87
-rw-r--r--src/Platform/FileStream.h58
-rw-r--r--src/Platform/FilesystemPath.h73
-rw-r--r--src/Platform/Finally.h46
-rw-r--r--src/Platform/ForEach.h118
-rw-r--r--src/Platform/Functor.h29
-rw-r--r--src/Platform/Memory.cpp58
-rw-r--r--src/Platform/Memory.h174
-rw-r--r--src/Platform/MemoryStream.cpp47
-rw-r--r--src/Platform/MemoryStream.h36
-rw-r--r--src/Platform/Mutex.h61
-rw-r--r--src/Platform/Platform.h28
-rw-r--r--src/Platform/Platform.make35
-rw-r--r--src/Platform/PlatformBase.h134
-rw-r--r--src/Platform/PlatformTest.cpp350
-rw-r--r--src/Platform/PlatformTest.h43
-rw-r--r--src/Platform/Serializable.cpp39
-rw-r--r--src/Platform/Serializable.h82
-rw-r--r--src/Platform/Serializer.cpp299
-rw-r--r--src/Platform/Serializer.h74
-rw-r--r--src/Platform/SerializerFactory.cpp54
-rw-r--r--src/Platform/SerializerFactory.h93
-rw-r--r--src/Platform/SharedPtr.h162
-rw-r--r--src/Platform/SharedVal.h71
-rw-r--r--src/Platform/Stream.h34
-rw-r--r--src/Platform/StringConverter.cpp367
-rw-r--r--src/Platform/StringConverter.h60
-rw-r--r--src/Platform/SyncEvent.h47
-rw-r--r--src/Platform/System.h16
-rw-r--r--src/Platform/SystemException.h46
-rw-r--r--src/Platform/SystemInfo.h28
-rw-r--r--src/Platform/SystemLog.h42
-rw-r--r--src/Platform/TextReader.cpp37
-rw-r--r--src/Platform/TextReader.h35
-rw-r--r--src/Platform/Thread.h74
-rw-r--r--src/Platform/Time.h30
-rw-r--r--src/Platform/User.h32
-rw-r--r--src/Readme.txt209
-rw-r--r--src/Release/Setup Files/License.txt503
-rw-r--r--src/Release/Setup Files/TrueCrypt User Guide.pdfbin0 -> 923969 bytes
-rw-r--r--src/Resources/Texts/License.rtf161
-rw-r--r--src/Setup/ComSetup.cpp88
-rw-r--r--src/Setup/ComSetup.h18
-rw-r--r--src/Setup/ComSetup.rgs92
-rw-r--r--src/Setup/Dir.c104
-rw-r--r--src/Setup/Dir.h21
-rw-r--r--src/Setup/Resource.h64
-rw-r--r--src/Setup/SelfExtract.c734
-rw-r--r--src/Setup/SelfExtract.h39
-rw-r--r--src/Setup/Setup.c2160
-rw-r--r--src/Setup/Setup.h100
-rw-r--r--src/Setup/Setup.icobin0 -> 13382 bytes
-rw-r--r--src/Setup/Setup.manifest21
-rw-r--r--src/Setup/Setup.rc327
-rw-r--r--src/Setup/Setup.vcproj482
-rw-r--r--src/Setup/TrueCrypt_setup.bmpbin0 -> 49398 bytes
-rw-r--r--src/Setup/TrueCrypt_setup_background.bmpbin0 -> 822 bytes
-rw-r--r--src/Setup/Wizard.c1203
-rw-r--r--src/Setup/Wizard.h29
-rw-r--r--src/TrueCrypt.sln178
252 files changed, 96916 insertions, 0 deletions
diff --git a/src/Boot/Windows/Bios.h b/src/Boot/Windows/Bios.h
new file mode 100644
index 00000000..bc410adb
--- /dev/null
+++ b/src/Boot/Windows/Bios.h
@@ -0,0 +1,28 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_Bios
+#define TC_HEADER_Boot_Bios
+
+#include "Platform.h"
+
+#define TC_LB_SIZE_BIT_SHIFT_DIVISOR 9
+
+#define TC_FIRST_BIOS_DRIVE 0x80
+#define TC_LAST_BIOS_DRIVE 0x8f
+#define TC_INVALID_BIOS_DRIVE (TC_FIRST_BIOS_DRIVE - 1)
+
+enum
+{
+ BiosResultSuccess = 0x00,
+ BiosResultInvalidFunction = 0x01
+};
+
+typedef byte BiosResult;
+
+#endif // TC_HEADER_Boot_Bios
diff --git a/src/Boot/Windows/Boot.vcproj b/src/Boot/Windows/Boot.vcproj
new file mode 100644
index 00000000..862f1e33
--- /dev/null
+++ b/src/Boot/Windows/Boot.vcproj
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9.00"
+ Name="Boot"
+ ProjectGUID="{8B7F059F-E4C7-4E11-88F5-EE8B8433072E}"
+ RootNamespace="Boot"
+ Keyword="MakeFileProj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="md Release 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1&#x0D;&#x0A;&#x0D;&#x0A;md Release_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES&#x0D;&#x0A;&#x0D;&#x0A;md Release_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT&#x0D;&#x0A;&#x0D;&#x0A;md Release_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH&#x0D;&#x0A;&#x0D;&#x0A;md Rescue 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;md Rescue_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;md Rescue_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;md Rescue_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH RESCUE_DISK=1"
+ ReBuildCommandLine="del /q /s Release &gt;NUL:&#x0D;&#x0A;md Release 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_AES &gt;NUL:&#x0D;&#x0A;md Release_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_Serpent &gt;NUL:&#x0D;&#x0A;md Release_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_Twofish &gt;NUL:&#x0D;&#x0A;md Release_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Rescue &gt;NUL:&#x0D;&#x0A;md Rescue 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Rescue_AES &gt;NUL:&#x0D;&#x0A;md Rescue_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Rescue_Serpent &gt;NUL:&#x0D;&#x0A;md Rescue_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT RESCUE_DISK=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Rescue_Twofish &gt;NUL:&#x0D;&#x0A;md Rescue_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH RESCUE_DISK=1"
+ CleanCommandLine="del /q /s Release Release_AES Release_Serpent Release_Twofish Rescue Rescue_AES Rescue_Serpent Rescue_Twofish &gt;NUL:"
+ Output="Release\BootLoader.com"
+ PreprocessorDefinitions="WIN32;NDEBUG"
+ IncludeSearchPath="&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(MSVC16_ROOT)\Include&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release Loader|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="md Release 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1&#x0D;&#x0A;&#x0D;&#x0A;md Release_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES&#x0D;&#x0A;&#x0D;&#x0A;md Release_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT&#x0D;&#x0A;&#x0D;&#x0A;md Release_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH"
+ ReBuildCommandLine="del /q /s Release &gt;NUL:&#x0D;&#x0A;md Release 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_AES &gt;NUL:&#x0D;&#x0A;md Release_AES 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=AES&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_Serpent &gt;NUL:&#x0D;&#x0A;md Release_Serpent 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=SERPENT&#x0D;&#x0A;&#x0D;&#x0A;del /q /s Release_Twofish &gt;NUL:&#x0D;&#x0A;md Release_Twofish 2&gt;NUL:&#x0D;&#x0A;nmake.exe /nologo RELEASE=1 SINGLE_CIPHER=TWOFISH"
+ CleanCommandLine="del /q /s Release Release_AES Release_Serpent Release_Twofish &gt;NUL:"
+ Output="Release\BootLoader.com"
+ PreprocessorDefinitions="WIN32;NDEBUG"
+ IncludeSearchPath="&quot;$(SolutionDir)&quot;;&quot;$(SolutionDir)\Common&quot;;&quot;$(SolutionDir)\Crypto&quot;;&quot;$(MSVC16_ROOT)\Include&quot;"
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\BootConfig.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootConsoleIo.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootCrt.asm"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDebug.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDiskIo.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootEncryptedIo.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootMain.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootMemory.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\BootSector.asm"
+ >
+ </File>
+ <File
+ RelativePath=".\Decompressor.c"
+ >
+ </File>
+ <File
+ RelativePath=".\IntFilter.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Platform.cpp"
+ >
+ </File>
+ <Filter
+ Name="Common"
+ >
+ <File
+ RelativePath="..\..\Common\Crc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Crypto.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Endian.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Pkcs5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Volumes.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Common\Xts.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Crypto"
+ >
+ <File
+ RelativePath="..\..\Crypto\Aes_hw_cpu.asm"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\AesSmall.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\AesSmall_x86.asm"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\Rmd160.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\Serpent.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\Crypto\Twofish.c"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\Bios.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootCommon.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootConfig.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootConsoleIo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDebug.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDefs.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootDiskIo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootEncryptedIo.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootMain.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootMemory.h"
+ >
+ </File>
+ <File
+ RelativePath=".\BootStrings.h"
+ >
+ </File>
+ <File
+ RelativePath=".\IntFilter.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Platform.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Build Files"
+ >
+ <File
+ RelativePath=".\Makefile"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/src/Boot/Windows/BootCommon.h b/src/Boot/Windows/BootCommon.h
new file mode 100644
index 00000000..e985a9c5
--- /dev/null
+++ b/src/Boot/Windows/BootCommon.h
@@ -0,0 +1,78 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_BootCommon
+#define TC_HEADER_Boot_BootCommon
+
+#include "Common/Password.h"
+#include "BootDefs.h"
+
+// The user will be advised to upgrade the rescue disk if upgrading from the following or any previous version
+#define TC_RESCUE_DISK_UPGRADE_NOTICE_MAX_VERSION 0x060a
+
+#define TC_BOOT_LOADER_AREA_SIZE (TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
+
+#define TC_BOOT_VOLUME_HEADER_SECTOR (TC_BOOT_LOADER_AREA_SECTOR_COUNT - 1)
+#define TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET (TC_BOOT_VOLUME_HEADER_SECTOR * TC_SECTOR_SIZE_BIOS)
+
+#define TC_CD_BOOTSECTOR_OFFSET 0xd000
+#define TC_CD_BOOT_LOADER_SECTOR 26
+
+#define TC_ORIG_BOOT_LOADER_BACKUP_SECTOR TC_BOOT_LOADER_AREA_SECTOR_COUNT
+#define TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET (TC_ORIG_BOOT_LOADER_BACKUP_SECTOR * TC_SECTOR_SIZE_BIOS)
+
+#define TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR (TC_ORIG_BOOT_LOADER_BACKUP_SECTOR + TC_BOOT_LOADER_AREA_SECTOR_COUNT)
+#define TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR_OFFSET (TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR * TC_SECTOR_SIZE_BIOS)
+
+#define TC_MBR_SECTOR 0
+#define TC_MAX_MBR_BOOT_CODE_SIZE 440
+
+#define TC_MAX_EXTRA_BOOT_PARTITION_SIZE (512UL * 1024UL * 1024UL)
+
+
+#pragma pack (1)
+
+typedef struct
+{
+ byte Flags;
+} BootSectorConfiguration;
+
+
+// Modifying this value can introduce incompatibility with previous versions
+#define TC_BOOT_LOADER_ARGS_OFFSET 0x10
+
+typedef struct
+{
+ // Modifying this structure can introduce incompatibility with previous versions
+ char Signature[8];
+ uint16 BootLoaderVersion;
+ uint16 CryptoInfoOffset;
+ uint16 CryptoInfoLength;
+ uint32 HeaderSaltCrc32;
+ Password BootPassword;
+ uint64 HiddenSystemPartitionStart;
+ uint64 DecoySystemPartitionStart;
+ uint32 Flags;
+ uint32 BootDriveSignature;
+
+ uint32 BootArgumentsCrc32;
+
+} BootArguments;
+
+// Modifying these values can introduce incompatibility with previous versions
+#define TC_BOOT_ARGS_FLAG_EXTRA_BOOT_PARTITION 0x1
+
+#pragma pack ()
+
+// Boot arguments signature should not be defined as a static string
+// Modifying these values can introduce incompatibility with previous versions
+#define TC_SET_BOOT_ARGUMENTS_SIGNATURE(SG) do { SG[0] = 'T'; SG[1] = 'R'; SG[2] = 'U'; SG[3] = 'E'; SG[4] = 0x11; SG[5] = 0x23; SG[6] = 0x45; SG[7] = 0x66; } while (FALSE)
+#define TC_IS_BOOT_ARGUMENTS_SIGNATURE(SG) (SG[0] == 'T' && SG[1] == 'R' && SG[2] == 'U' && SG[3] == 'E' && SG[4] == 0x11 && SG[5] == 0x23 && SG[6] == 0x45 && SG[7] == 0x66)
+
+
+#endif // TC_HEADER_Boot_BootCommon
diff --git a/src/Boot/Windows/BootConfig.cpp b/src/Boot/Windows/BootConfig.cpp
new file mode 100644
index 00000000..eeaed70a
--- /dev/null
+++ b/src/Boot/Windows/BootConfig.cpp
@@ -0,0 +1,90 @@
+/*
+ Copyright (c) 2008-2012 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "BootConfig.h"
+
+byte BootSectorFlags;
+
+byte BootLoaderDrive;
+byte BootDrive;
+bool BootDriveGeometryValid = false;
+bool PreventNormalSystemBoot = false;
+bool PreventBootMenu = false;
+char CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH + 1];
+uint32 OuterVolumeBackupHeaderCrc;
+
+bool BootStarted = false;
+
+DriveGeometry BootDriveGeometry;
+
+CRYPTO_INFO *BootCryptoInfo;
+Partition EncryptedVirtualPartition;
+
+Partition ActivePartition;
+Partition PartitionFollowingActive;
+bool ExtraBootPartitionPresent = false;
+uint64 HiddenVolumeStartUnitNo;
+uint64 HiddenVolumeStartSector;
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+void ReadBootSectorUserConfiguration ()
+{
+ byte userConfig;
+
+ AcquireSectorBuffer();
+
+ if (ReadWriteMBR (false, BootLoaderDrive, true) != BiosResultSuccess)
+ goto ret;
+
+ userConfig = SectorBuffer[TC_BOOT_SECTOR_USER_CONFIG_OFFSET];
+
+#ifdef TC_WINDOWS_BOOT_AES
+ EnableHwEncryption (!(userConfig & TC_BOOT_USER_CFG_FLAG_DISABLE_HW_ENCRYPTION));
+#endif
+
+ PreventBootMenu = (userConfig & TC_BOOT_USER_CFG_FLAG_DISABLE_ESC);
+
+ memcpy (CustomUserMessage, SectorBuffer + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH);
+ CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH] = 0;
+
+ if (userConfig & TC_BOOT_USER_CFG_FLAG_SILENT_MODE)
+ {
+ if (CustomUserMessage[0])
+ {
+ InitVideoMode();
+ Print (CustomUserMessage);
+ }
+
+ DisableScreenOutput();
+ }
+
+ OuterVolumeBackupHeaderCrc = *(uint32 *) (SectorBuffer + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET);
+
+ret:
+ ReleaseSectorBuffer();
+}
+
+
+BiosResult UpdateBootSectorConfiguration (byte drive)
+{
+ AcquireSectorBuffer();
+
+ BiosResult result = ReadWriteMBR (false, drive);
+ if (result != BiosResultSuccess)
+ goto ret;
+
+ SectorBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET] = BootSectorFlags;
+ result = ReadWriteMBR (true, drive);
+
+ret:
+ ReleaseSectorBuffer();
+ return result;
+}
+
+#endif // !TC_WINDOWS_BOOT_RESCUE_DISK_MODE
diff --git a/src/Boot/Windows/BootConfig.h b/src/Boot/Windows/BootConfig.h
new file mode 100644
index 00000000..5fe591fe
--- /dev/null
+++ b/src/Boot/Windows/BootConfig.h
@@ -0,0 +1,42 @@
+/*
+ Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_BootConfig
+#define TC_HEADER_Boot_BootConfig
+
+#include "Crypto.h"
+#include "Platform.h"
+#include "BootDiskIo.h"
+
+extern byte BootSectorFlags;
+
+extern byte BootLoaderDrive;
+extern byte BootDrive;
+extern bool BootDriveGeometryValid;
+extern DriveGeometry BootDriveGeometry;
+extern bool PreventNormalSystemBoot;
+extern bool PreventBootMenu;
+extern char CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH + 1];
+extern uint32 OuterVolumeBackupHeaderCrc;
+
+extern bool BootStarted;
+
+extern CRYPTO_INFO *BootCryptoInfo;
+extern Partition EncryptedVirtualPartition;
+
+extern Partition ActivePartition;
+extern Partition PartitionFollowingActive;
+extern bool ExtraBootPartitionPresent;
+extern uint64 HiddenVolumeStartUnitNo;
+extern uint64 HiddenVolumeStartSector;
+
+
+void ReadBootSectorUserConfiguration ();
+BiosResult UpdateBootSectorConfiguration (byte drive);
+
+#endif // TC_HEADER_Boot_BootConfig
diff --git a/src/Boot/Windows/BootConsoleIo.cpp b/src/Boot/Windows/BootConsoleIo.cpp
new file mode 100644
index 00000000..6558018f
--- /dev/null
+++ b/src/Boot/Windows/BootConsoleIo.cpp
@@ -0,0 +1,330 @@
+/*
+ Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "Platform.h"
+#include "Bios.h"
+#include "BootConsoleIo.h"
+#include "BootDebug.h"
+#include "BootStrings.h"
+
+
+static int ScreenOutputDisabled = 0;
+
+void DisableScreenOutput ()
+{
+ ++ScreenOutputDisabled;
+}
+
+
+void EnableScreenOutput ()
+{
+ --ScreenOutputDisabled;
+}
+
+
+void PrintChar (char c)
+{
+#ifdef TC_BOOT_TRACING_ENABLED
+ WriteDebugPort (c);
+#endif
+
+ if (ScreenOutputDisabled)
+ return;
+
+ __asm
+ {
+ mov bx, 7
+ mov al, c
+ mov ah, 0xe
+ int 0x10
+ }
+}
+
+
+void PrintCharAtCursor (char c)
+{
+ if (ScreenOutputDisabled)
+ return;
+
+ __asm
+ {
+ mov bx, 7
+ mov al, c
+ mov cx, 1
+ mov ah, 0xa
+ int 0x10
+ }
+}
+
+
+void Print (const char *str)
+{
+ char c;
+ while (c = *str++)
+ PrintChar (c);
+}
+
+
+void Print (uint32 number)
+{
+ char str[12];
+ int pos = 0;
+ while (number >= 10)
+ {
+ str[pos++] = (char) (number % 10) + '0';
+ number /= 10;
+ }
+ str[pos] = (char) (number % 10) + '0';
+
+ while (pos >= 0)
+ PrintChar (str[pos--]);
+}
+
+
+void Print (const uint64 &number)
+{
+ if (number.HighPart == 0)
+ Print (number.LowPart);
+ else
+ PrintHex (number);
+}
+
+
+void PrintHex (byte b)
+{
+ PrintChar (((b >> 4) >= 0xA ? 'A' - 0xA : '0') + (b >> 4));
+ PrintChar (((b & 0xF) >= 0xA ? 'A' - 0xA : '0') + (b & 0xF));
+}
+
+
+void PrintHex (uint16 data)
+{
+ PrintHex (byte (data >> 8));
+ PrintHex (byte (data));
+}
+
+
+void PrintHex (uint32 data)
+{
+ PrintHex (uint16 (data >> 16));
+ PrintHex (uint16 (data));
+}
+
+
+void PrintHex (const uint64 &data)
+{
+ PrintHex (data.HighPart);
+ PrintHex (data.LowPart);
+}
+
+void PrintRepeatedChar (char c, int n)
+{
+ while (n-- > 0)
+ PrintChar (c);
+}
+
+
+void PrintEndl ()
+{
+ Print ("\r\n");
+}
+
+
+void PrintEndl (int cnt)
+{
+ while (cnt-- > 0)
+ PrintEndl ();
+}
+
+
+void Beep ()
+{
+ PrintChar (7);
+}
+
+
+void InitVideoMode ()
+{
+ if (ScreenOutputDisabled)
+ return;
+
+ __asm
+ {
+ // Text mode 80x25
+ mov ax, 3
+ int 0x10
+
+ // Page 0
+ mov ax, 0x500
+ int 0x10
+ }
+}
+
+
+void ClearScreen ()
+{
+ if (ScreenOutputDisabled)
+ return;
+
+ __asm
+ {
+ // White text on black
+ mov bh, 7
+ xor cx, cx
+ mov dx, 0x184f
+ mov ax, 0x600
+ int 0x10
+
+ // Cursor at 0,0
+ xor bh, bh
+ xor dx, dx
+ mov ah, 2
+ int 0x10
+ }
+}
+
+
+void PrintBackspace ()
+{
+ PrintChar (TC_BIOS_CHAR_BACKSPACE);
+ PrintCharAtCursor (' ');
+}
+
+
+void PrintError (const char *message)
+{
+ Print (TC_BOOT_STR_ERROR);
+ Print (message);
+ PrintEndl();
+ Beep();
+}
+
+
+void PrintErrorNoEndl (const char *message)
+{
+ Print (TC_BOOT_STR_ERROR);
+ Print (message);
+ Beep();
+}
+
+
+byte GetShiftFlags ()
+{
+ byte flags;
+ __asm
+ {
+ mov ah, 2
+ int 0x16
+ mov flags, al
+ }
+
+ return flags;
+}
+
+
+byte GetKeyboardChar ()
+{
+ return GetKeyboardChar (nullptr);
+}
+
+
+byte GetKeyboardChar (byte *scanCode)
+{
+ // Work around potential BIOS bugs (Windows boot manager polls the keystroke buffer)
+ while (!IsKeyboardCharAvailable());
+
+ byte asciiCode;
+ byte scan;
+ __asm
+ {
+ mov ah, 0
+ int 0x16
+ mov asciiCode, al
+ mov scan, ah
+ }
+
+ if (scanCode)
+ *scanCode = scan;
+
+ return asciiCode;
+}
+
+
+bool IsKeyboardCharAvailable ()
+{
+ bool available = false;
+ __asm
+ {
+ mov ah, 1
+ int 0x16
+ jz not_avail
+ mov available, true
+ not_avail:
+ }
+
+ return available;
+}
+
+
+bool EscKeyPressed ()
+{
+ if (IsKeyboardCharAvailable ())
+ {
+ byte keyScanCode;
+ GetKeyboardChar (&keyScanCode);
+ return keyScanCode == TC_BIOS_KEY_ESC;
+ }
+
+ return false;
+}
+
+
+void ClearBiosKeystrokeBuffer ()
+{
+ __asm
+ {
+ push es
+ xor ax, ax
+ mov es, ax
+ mov di, 0x41e
+ mov cx, 32
+ cld
+ rep stosb
+ pop es
+ }
+}
+
+
+bool IsPrintable (char c)
+{
+ return c >= ' ' && c <= '~';
+}
+
+
+int GetString (char *buffer, size_t bufferSize)
+{
+ byte c;
+ byte scanCode;
+ size_t pos = 0;
+
+ while (pos < bufferSize)
+ {
+ c = GetKeyboardChar (&scanCode);
+
+ if (scanCode == TC_BIOS_KEY_ENTER)
+ break;
+
+ if (scanCode == TC_BIOS_KEY_ESC)
+ return 0;
+
+ buffer[pos++] = c;
+ PrintChar (IsPrintable (c) ? c : ' ');
+ }
+
+ return pos;
+}
diff --git a/src/Boot/Windows/BootConsoleIo.h b/src/Boot/Windows/BootConsoleIo.h
new file mode 100644
index 00000000..daf86633
--- /dev/null
+++ b/src/Boot/Windows/BootConsoleIo.h
@@ -0,0 +1,67 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_BootConsoleIo
+#define TC_HEADER_Boot_BootConsoleIo
+
+#include "Platform.h"
+
+#define TC_DEBUG_PORT 0
+
+#define TC_BIOS_KEY_ESC 1
+#define TC_BIOS_KEY_BACKSPACE 14
+#define TC_BIOS_KEY_ENTER 28
+#define TC_BIOS_KEY_F1 0x3b
+#define TC_BIOS_KEY_F2 0x3c
+#define TC_BIOS_KEY_F3 0x3d
+#define TC_BIOS_KEY_F4 0x3e
+#define TC_BIOS_KEY_F5 0x3f
+#define TC_BIOS_KEY_F6 0x40
+#define TC_BIOS_KEY_F7 0x41
+#define TC_BIOS_KEY_F8 0x42
+#define TC_BIOS_KEY_F9 0x43
+#define TC_BIOS_KEY_F10 0x44
+
+#define TC_BIOS_SHIFTMASK_CAPSLOCK (1 << 6)
+#define TC_BIOS_SHIFTMASK_LSHIFT (1 << 1)
+#define TC_BIOS_SHIFTMASK_RSHIFT (1 << 0)
+
+#define TC_BIOS_CHAR_BACKSPACE 8
+
+#define TC_BIOS_MAX_CHARS_PER_LINE 80
+
+void Beep ();
+void ClearBiosKeystrokeBuffer ();
+void ClearScreen ();
+void DisableScreenOutput ();
+void EnableScreenOutput ();
+bool EscKeyPressed ();
+byte GetKeyboardChar ();
+byte GetKeyboardChar (byte *scanCode);
+byte GetShiftFlags ();
+int GetString (char *buffer, size_t bufferSize);
+void InitVideoMode ();
+bool IsKeyboardCharAvailable ();
+bool IsPrintable (char c);
+void Print (const char *str);
+void Print (uint32 number);
+void Print (const uint64 &number);
+void PrintBackspace ();
+void PrintChar (char c);
+void PrintCharAtCursor (char c);
+void PrintEndl ();
+void PrintEndl (int cnt);
+void PrintRepeatedChar (char c, int n);
+void PrintError (const char *message);
+void PrintErrorNoEndl (const char *message);
+void PrintHex (byte b);
+void PrintHex (uint16 data);
+void PrintHex (uint32 data);
+void PrintHex (const uint64 &data);
+
+#endif // TC_HEADER_Boot_BootConsoleIo
diff --git a/src/Boot/Windows/BootCrt.asm b/src/Boot/Windows/BootCrt.asm
new file mode 100644
index 00000000..9087ad70
--- /dev/null
+++ b/src/Boot/Windows/BootCrt.asm
@@ -0,0 +1,23 @@
+;
+; Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+;
+; 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.
+;
+
+.MODEL tiny, C
+.386
+
+INCLUDE BootDefs.i
+
+EXTERNDEF main:NEAR
+
+_TEXT SEGMENT
+ORG TC_COM_EXECUTABLE_OFFSET
+
+start:
+ jmp main
+
+_TEXT ENDS
+END start
diff --git a/src/Boot/Windows/BootDebug.cpp b/src/Boot/Windows/BootDebug.cpp
new file mode 100644
index 00000000..e422767a
--- /dev/null
+++ b/src/Boot/Windows/BootDebug.cpp
@@ -0,0 +1,177 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "Platform.h"
+#include "Bios.h"
+#include "BootConsoleIo.h"
+#include "BootDefs.h"
+#include "BootDiskIo.h"
+#include "BootDebug.h"
+
+
+#ifdef TC_BOOT_TRACING_ENABLED
+
+void InitDebugPort ()
+{
+ __asm
+ {
+ mov dx, TC_DEBUG_PORT
+ mov ah, 1
+ int 0x17
+ mov dx, TC_DEBUG_PORT
+ mov ah, 0xe2
+ int 0x17
+ }
+}
+
+
+void WriteDebugPort (byte dataByte)
+{
+ __asm
+ {
+ mov al, dataByte
+ mov dx, TC_DEBUG_PORT
+ mov ah, 0
+ int 0x17
+ }
+}
+
+#endif // TC_BOOT_TRACING_ENABLED
+
+
+#ifdef TC_BOOT_DEBUG_ENABLED
+
+extern "C" void PrintDebug (uint32 debugVal)
+{
+ Print (debugVal);
+ PrintEndl();
+}
+
+
+void PrintVal (const char *message, const uint32 value, bool newLine, bool hex)
+{
+ Print (message);
+ Print (": ");
+
+ if (hex)
+ PrintHex (value);
+ else
+ Print (value);
+
+ if (newLine)
+ PrintEndl();
+}
+
+
+void PrintVal (const char *message, const uint64 &value, bool newLine, bool hex)
+{
+ Print (message);
+ Print (": ");
+ PrintHex (value);
+ if (newLine)
+ PrintEndl();
+}
+
+
+void PrintHexDump (byte *mem, size_t size, uint16 *memSegment)
+{
+ const size_t width = 16;
+ for (size_t pos = 0; pos < size; )
+ {
+ for (int pass = 1; pass <= 2; ++pass)
+ {
+ size_t i;
+ for (i = 0; i < width && pos < size; ++i)
+ {
+ byte dataByte;
+ if (memSegment)
+ {
+ __asm
+ {
+ push es
+ mov si, ss:memSegment
+ mov es, ss:[si]
+ mov si, ss:mem
+ add si, pos
+ mov al, es:[si]
+ mov dataByte, al
+ pop es
+ }
+ pos++;
+ }
+ else
+ dataByte = mem[pos++];
+
+ if (pass == 1)
+ {
+ PrintHex (dataByte);
+ PrintChar (' ');
+ }
+ else
+ PrintChar (IsPrintable (dataByte) ? dataByte : '.');
+ }
+
+ if (pass == 1)
+ {
+ pos -= i;
+ PrintChar (' ');
+ }
+ }
+
+ PrintEndl ();
+ }
+}
+
+
+void PrintHexDump (uint16 memSegment, uint16 memOffset, size_t size)
+{
+ PrintHexDump ((byte *) memOffset, size, &memSegment);
+}
+
+#endif // TC_BOOT_DEBUG_ENABLED
+
+
+#ifdef TC_BOOT_STACK_CHECKING_ENABLED
+
+extern "C" char end[];
+
+static void PrintStackInfo ()
+{
+ uint16 spReg;
+ __asm mov spReg, sp
+
+ Print ("Stack: "); Print (TC_BOOT_LOADER_STACK_TOP - spReg);
+ Print ("/"); Print (TC_BOOT_LOADER_STACK_TOP - (uint16) end);
+}
+
+
+void CheckStack ()
+{
+ uint16 spReg;
+ __asm mov spReg, sp
+
+ if (*(uint32 *) end != 0x12345678UL || spReg < (uint16) end)
+ {
+ __asm cli
+ __asm mov sp, TC_BOOT_LOADER_STACK_TOP
+
+ PrintError ("Stack overflow");
+ TC_THROW_FATAL_EXCEPTION;
+ }
+}
+
+
+void InitStackChecker ()
+{
+ *(uint32 *) end = 0x12345678UL;
+
+ PrintStackInfo();
+ PrintEndl();
+}
+
+#endif // TC_BOOT_STACK_CHECKING_ENABLED
diff --git a/src/Boot/Windows/BootDebug.h b/src/Boot/Windows/BootDebug.h
new file mode 100644
index 00000000..1f7b3aac
--- /dev/null
+++ b/src/Boot/Windows/BootDebug.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_BootDebug
+#define TC_HEADER_Boot_BootDebug
+
+#include "Platform.h"
+#include "BootConsoleIo.h"
+
+#if 0
+# define TC_BOOT_DEBUG_ENABLED
+#endif
+
+#if 0 || defined (TC_BOOT_DEBUG_ENABLED)
+# define TC_BOOT_STACK_CHECKING_ENABLED
+ extern "C" void CheckStack ();
+#else
+# define CheckStack()
+#endif
+
+#if 0
+# define TC_BOOT_TRACING_ENABLED
+# if 1
+# define TC_TRACE_INT13
+# endif
+# if 0
+# define TC_TRACE_INT15
+# endif
+#endif
+
+#ifdef TC_BOOT_DEBUG_ENABLED
+# define trace_point do { Print(__FILE__); PrintChar (':'); Print (TC_TO_STRING (__LINE__)); PrintEndl(); } while (false)
+# define trace_val(VAL) PrintVal (#VAL, VAL);
+# define trace_hex(VAL) do { Print (#VAL), PrintChar (':'); PrintHex (VAL); PrintEndl(); } while (false)
+# define assert(COND) do { if (!(COND)) { trace_point; __asm jmp $ } } while (false)
+#else
+# define trace_point
+# define trace_val(VAL)
+# define trace_hex(VAL)
+# define assert(COND)
+#endif
+
+void InitDebugPort ();
+void InitStackChecker ();
+void WriteDebugPort (byte dataByte);
+void PrintHexDump (byte *mem, size_t size, uint16 *memSegment = nullptr);
+void PrintHexDump (uint16 memSegment, uint16 memOffset, size_t size);
+void PrintVal (const char *message, const uint32 value, bool newLine = true, bool hex = false);
+void PrintVal (const char *message, const uint64 &value, bool newLine = true, bool hex = false);
+
+#endif // TC_HEADER_Boot_BootDebug
diff --git a/src/Boot/Windows/BootDefs.h b/src/Boot/Windows/BootDefs.h
new file mode 100644
index 00000000..efb9b5f9
--- /dev/null
+++ b/src/Boot/Windows/BootDefs.h
@@ -0,0 +1,188 @@
+/*
+ Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_BootDefs
+#define TC_HEADER_Boot_BootDefs
+
+// Total memory required (CODE + DATA + BSS + STACK + 0x100) in KBytes - determined from linker map.
+#define TC__BOOT_MEMORY_REQUIRED 42
+
+#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
+# undef TC__BOOT_MEMORY_REQUIRED
+
+# ifdef TC_WINDOWS_BOOT_AES
+# ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+# define TC__BOOT_MEMORY_REQUIRED 30
+# else
+# define TC__BOOT_MEMORY_REQUIRED 28
+# endif
+# elif defined (TC_WINDOWS_BOOT_SERPENT)
+# define TC__BOOT_MEMORY_REQUIRED 32
+# elif defined (TC_WINDOWS_BOOT_TWOFISH)
+# define TC__BOOT_MEMORY_REQUIRED 40
+# endif
+
+#if 0
+# undef TC__BOOT_MEMORY_REQUIRED
+# define TC__BOOT_MEMORY_REQUIRED 60
+#endif
+
+#endif
+
+// Modifying this value can introduce incompatibility with previous versions
+#define TC__BOOT_LOADER_SEGMENT TC_HEX (9000) // Some buggy BIOS routines fail if CS bits 0-10 are not zero
+
+#if TC__BOOT_MEMORY_REQUIRED <= 32
+# define TC__BOOT_LOADER_SEGMENT_LOW (TC__BOOT_LOADER_SEGMENT - 32 * 1024 / 16)
+#else
+# define TC__BOOT_LOADER_SEGMENT_LOW (TC__BOOT_LOADER_SEGMENT - 64 * 1024 / 16)
+#endif
+
+#define TC__COM_EXECUTABLE_OFFSET TC_HEX (100)
+
+#define TC__BOOT_LOADER_LOWMEM_SEGMENT TC_HEX (2000)
+#define TC__BOOT_LOADER_BUFFER_SEGMENT TC_HEX (4000)
+#define TC__BOOT_LOADER_ALT_SEGMENT TC_HEX (6000)
+
+#define TC__BOOT_LOADER_STACK_TOP (TC_BOOT_MEMORY_REQUIRED * TC_UNSIGNED (1024) - 4)
+
+#define TC__LB_SIZE 512
+#define TC__BOOT_LOADER_AREA_SECTOR_COUNT 63
+
+#define TC__BOOT_SECTOR_VERSION_OFFSET 430
+#define TC__BOOT_SECTOR_LOADER_LENGTH_OFFSET 432
+#define TC__BOOT_SECTOR_LOADER_CHECKSUM_OFFSET 434
+#define TC__BOOT_SECTOR_USER_CONFIG_OFFSET 438
+#define TC__BOOT_SECTOR_CONFIG_OFFSET 439 // The last byte that is reserved for the boot loader
+
+#define TC__BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH 24
+#define TC__BOOT_SECTOR_USER_MESSAGE_OFFSET (TC__BOOT_SECTOR_VERSION_OFFSET - TC__BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)
+
+#define TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE 4
+#define TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET (TC__BOOT_SECTOR_USER_MESSAGE_OFFSET - TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE)
+
+#define TC__BOOT_LOADER_DECOMPRESSOR_START_SECTOR 2
+#define TC__BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT 4
+#define TC__BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE 32768
+#define TC__BOOT_LOADER_COMPRESSED_BUFFER_OFFSET (TC_COM_EXECUTABLE_OFFSET + 3072)
+
+#define TC__BOOT_LOADER_START_SECTOR (TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT)
+#define TC__MAX_BOOT_LOADER_SECTOR_COUNT (TC_BOOT_LOADER_AREA_SECTOR_COUNT - TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT - 2)
+#define TC__MAX_BOOT_LOADER_DECOMPRESSED_SIZE ((TC_BOOT_LOADER_AREA_SECTOR_COUNT - 2) * TC_LB_SIZE)
+
+#define TC__BOOT_LOADER_BACKUP_SECTOR_COUNT 30
+
+#define TC__GZIP_HEADER_SIZE 10
+
+#define TC__BOOT_CFG_FLAG_AREA_SIZE 1 // In bytes
+
+// If you add more flags, revise TC__BOOT_CFG_FLAG_AREA_SIZE
+#define TC__BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE TC_HEX (02)
+#define TC__BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER TC_HEX (04)
+#define TC__BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION TC_HEX (10)
+#define TC__BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER TC_HEX (20)
+#define TC__BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE (TC_HEX (40) + TC_HEX (80))
+
+// Modifying the following values can introduce incompatibility with previous versions
+#define TC__BOOT_USER_CFG_FLAG_SILENT_MODE TC_HEX (01)
+#define TC__BOOT_USER_CFG_FLAG_DISABLE_ESC TC_HEX (02)
+#define TC__BOOT_USER_CFG_FLAG_DISABLE_HW_ENCRYPTION TC_HEX (04)
+
+// The following items are treated as a 2-bit value (apply TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE to obtain the value)
+#define TC__HIDDEN_OS_CREATION_PHASE_NONE 0
+#define TC__HIDDEN_OS_CREATION_PHASE_CLONING TC_HEX (40) // The boot loader is to copy the content of the system partition to the hidden volume
+#define TC__HIDDEN_OS_CREATION_PHASE_WIPING TC_HEX (80) // The boot loader has successfully copied the content of the system partition to the hidden volume. The original OS is to be wiped now.
+#define TC__HIDDEN_OS_CREATION_PHASE_WIPED (TC_HEX (40) + TC_HEX (80)) // The original OS has been wiped. The user is required to install a new OS (decoy OS) on the system partition now.
+
+
+#ifdef TC_ASM_PREPROCESS
+
+#define TC_HEX(N) 0##N##h
+#define TC_UNSIGNED(N) N
+
+TC_BOOT_MEMORY_REQUIRED = TC__BOOT_MEMORY_REQUIRED
+TC_BOOT_LOADER_SEGMENT = TC__BOOT_LOADER_SEGMENT
+TC_BOOT_LOADER_SEGMENT_LOW = TC__BOOT_LOADER_SEGMENT_LOW
+TC_COM_EXECUTABLE_OFFSET = TC__COM_EXECUTABLE_OFFSET
+TC_BOOT_LOADER_LOWMEM_SEGMENT = TC__BOOT_LOADER_LOWMEM_SEGMENT
+TC_BOOT_LOADER_BUFFER_SEGMENT = TC__BOOT_LOADER_BUFFER_SEGMENT
+TC_BOOT_LOADER_ALT_SEGMENT = TC__BOOT_LOADER_ALT_SEGMENT
+TC_BOOT_LOADER_STACK_TOP = TC__BOOT_LOADER_STACK_TOP
+TC_LB_SIZE = TC__LB_SIZE
+TC_BOOT_LOADER_AREA_SECTOR_COUNT = TC__BOOT_LOADER_AREA_SECTOR_COUNT
+TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET = TC__BOOT_SECTOR_LOADER_LENGTH_OFFSET
+TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET = TC__BOOT_SECTOR_LOADER_CHECKSUM_OFFSET
+TC_BOOT_SECTOR_CONFIG_OFFSET = TC__BOOT_SECTOR_CONFIG_OFFSET
+TC_BOOT_SECTOR_USER_CONFIG_OFFSET = TC__BOOT_SECTOR_USER_CONFIG_OFFSET
+TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR = TC__BOOT_LOADER_DECOMPRESSOR_START_SECTOR
+TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT = TC__BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT
+TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE = TC__BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE
+TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET = TC__BOOT_LOADER_COMPRESSED_BUFFER_OFFSET
+TC_BOOT_LOADER_START_SECTOR = TC__BOOT_LOADER_START_SECTOR
+TC_MAX_BOOT_LOADER_SECTOR_COUNT = TC__MAX_BOOT_LOADER_SECTOR_COUNT
+TC_MAX_BOOT_LOADER_DECOMPRESSED_SIZE = TC__MAX_BOOT_LOADER_DECOMPRESSED_SIZE
+TC_BOOT_LOADER_BACKUP_SECTOR_COUNT = TC__BOOT_LOADER_BACKUP_SECTOR_COUNT
+TC_GZIP_HEADER_SIZE = TC__GZIP_HEADER_SIZE
+TC_BOOT_CFG_FLAG_AREA_SIZE = TC__BOOT_CFG_FLAG_AREA_SIZE
+TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE = TC__BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE
+TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER = TC__BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER
+TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER = TC__BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER
+TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE = TC__BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE
+TC_BOOT_USER_CFG_FLAG_SILENT_MODE = TC__BOOT_USER_CFG_FLAG_SILENT_MODE
+TC_HIDDEN_OS_CREATION_PHASE_NONE = TC__HIDDEN_OS_CREATION_PHASE_NONE
+TC_HIDDEN_OS_CREATION_PHASE_CLONING = TC__HIDDEN_OS_CREATION_PHASE_CLONING
+TC_HIDDEN_OS_CREATION_PHASE_WIPING = TC__HIDDEN_OS_CREATION_PHASE_WIPING
+TC_HIDDEN_OS_CREATION_PHASE_WIPED = TC__HIDDEN_OS_CREATION_PHASE_WIPED
+
+#else // TC_ASM_PREPROCESS
+
+#define TC_HEX(N) 0x##N
+#define TC_UNSIGNED(N) N##U
+
+#define TC_BOOT_MEMORY_REQUIRED TC__BOOT_MEMORY_REQUIRED
+#define TC_BOOT_LOADER_SEGMENT TC__BOOT_LOADER_SEGMENT
+#define TC_COM_EXECUTABLE_OFFSET TC__COM_EXECUTABLE_OFFSET
+#define TC_BOOT_LOADER_LOWMEM_SEGMENT TC__BOOT_LOADER_LOWMEM_SEGMENT
+#define TC_BOOT_LOADER_BUFFER_SEGMENT TC__BOOT_LOADER_BUFFER_SEGMENT
+#define TC_BOOT_LOADER_ALT_SEGMENT TC__BOOT_LOADER_ALT_SEGMENT
+#define TC_BOOT_LOADER_STACK_TOP (TC__BOOT_LOADER_STACK_TOP)
+#define TC_BOOT_LOADER_AREA_SECTOR_COUNT TC__BOOT_LOADER_AREA_SECTOR_COUNT
+#define TC_BOOT_SECTOR_USER_MESSAGE_OFFSET TC__BOOT_SECTOR_USER_MESSAGE_OFFSET
+#define TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE
+#define TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET TC__BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET
+#define TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH TC__BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH
+#define TC_BOOT_SECTOR_VERSION_OFFSET TC__BOOT_SECTOR_VERSION_OFFSET
+#define TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET TC__BOOT_SECTOR_LOADER_LENGTH_OFFSET
+#define TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET TC__BOOT_SECTOR_LOADER_CHECKSUM_OFFSET
+#define TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR TC__BOOT_LOADER_DECOMPRESSOR_START_SECTOR
+#define TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT TC__BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT
+#define TC_BOOT_SECTOR_CONFIG_OFFSET TC__BOOT_SECTOR_CONFIG_OFFSET
+#define TC_BOOT_SECTOR_USER_CONFIG_OFFSET TC__BOOT_SECTOR_USER_CONFIG_OFFSET
+#define TC_BOOT_LOADER_START_SECTOR TC__BOOT_LOADER_START_SECTOR
+#define TC_LB_SIZE TC__LB_SIZE
+#define TC_MAX_BOOT_LOADER_SECTOR_COUNT TC__MAX_BOOT_LOADER_SECTOR_COUNT
+#define TC_MAX_BOOT_LOADER_DECOMPRESSED_SIZE TC__MAX_BOOT_LOADER_DECOMPRESSED_SIZE
+#define TC_BOOT_LOADER_BACKUP_SECTOR_COUNT TC__BOOT_LOADER_BACKUP_SECTOR_COUNT
+#define TC_GZIP_HEADER_SIZE TC__GZIP_HEADER_SIZE
+#define TC_BOOT_CFG_FLAG_AREA_SIZE TC__BOOT_CFG_FLAG_AREA_SIZE
+#define TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE TC__BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE
+#define TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER TC__BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER
+#define TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER TC__BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER
+#define TC_BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION TC__BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION
+#define TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE TC__BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE
+#define TC_BOOT_USER_CFG_FLAG_SILENT_MODE TC__BOOT_USER_CFG_FLAG_SILENT_MODE
+#define TC_BOOT_USER_CFG_FLAG_DISABLE_ESC TC__BOOT_USER_CFG_FLAG_DISABLE_ESC
+#define TC_BOOT_USER_CFG_FLAG_DISABLE_HW_ENCRYPTION TC__BOOT_USER_CFG_FLAG_DISABLE_HW_ENCRYPTION
+#define TC_HIDDEN_OS_CREATION_PHASE_NONE TC__HIDDEN_OS_CREATION_PHASE_NONE
+#define TC_HIDDEN_OS_CREATION_PHASE_CLONING TC__HIDDEN_OS_CREATION_PHASE_CLONING
+#define TC_HIDDEN_OS_CREATION_PHASE_WIPING TC__HIDDEN_OS_CREATION_PHASE_WIPING
+#define TC_HIDDEN_OS_CREATION_PHASE_WIPED TC__HIDDEN_OS_CREATION_PHASE_WIPED
+
+#endif // TC_ASM_PREPROCESS
+
+#endif // TC_HEADER_Boot_BootDefs
diff --git a/src/Boot/Windows/BootDiskIo.cpp b/src/Boot/Windows/BootDiskIo.cpp
new file mode 100644
index 00000000..84e888e0
--- /dev/null
+++ b/src/Boot/Windows/BootDiskIo.cpp
@@ -0,0 +1,487 @@
+/*
+ Copyright (c) 2008-2011 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "Bios.h"
+#include "BootConsoleIo.h"
+#include "BootConfig.h"
+#include "BootDebug.h"
+#include "BootDefs.h"
+#include "BootDiskIo.h"
+#include "BootStrings.h"
+
+
+byte SectorBuffer[TC_LB_SIZE];
+
+#ifdef TC_BOOT_DEBUG_ENABLED
+static bool SectorBufferInUse = false;
+
+void AcquireSectorBuffer ()
+{
+ if (SectorBufferInUse)
+ TC_THROW_FATAL_EXCEPTION;
+
+ SectorBufferInUse = true;
+}
+
+
+void ReleaseSectorBuffer ()
+{
+ SectorBufferInUse = false;
+}
+
+#endif
+
+
+bool IsLbaSupported (byte drive)
+{
+ static byte CachedDrive = TC_INVALID_BIOS_DRIVE;
+ static bool CachedStatus;
+ uint16 result = 0;
+
+ if (CachedDrive == drive)
+ goto ret;
+
+ __asm
+ {
+ mov bx, 0x55aa
+ mov dl, drive
+ mov ah, 0x41
+ int 0x13
+ jc err
+ mov result, bx
+ err:
+ }
+
+ CachedDrive = drive;
+ CachedStatus = (result == 0xaa55);
+ret:
+ return CachedStatus;
+}
+
+
+void PrintDiskError (BiosResult error, bool write, byte drive, const uint64 *sector, const ChsAddress *chs)
+{
+ PrintEndl();
+ Print (write ? "Write" : "Read"); Print (" error:");
+ Print (error);
+ Print (" Drive:");
+ Print (drive ^ 0x80);
+
+ if (sector)
+ {
+ Print (" Sector:");
+ Print (*sector);
+ }
+
+ if (chs)
+ {
+ Print (" CHS:");
+ Print (*chs);
+ }
+
+ PrintEndl();
+ Beep();
+}
+
+
+void Print (const ChsAddress &chs)
+{
+ Print (chs.Cylinder);
+ PrintChar ('/');
+ Print (chs.Head);
+ PrintChar ('/');
+ Print (chs.Sector);
+}
+
+
+void PrintSectorCountInMB (const uint64 &sectorCount)
+{
+ Print (sectorCount >> (TC_LB_SIZE_BIT_SHIFT_DIVISOR + 2)); Print (" MB ");
+}
+
+
+BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
+{
+ CheckStack();
+
+ byte cylinderLow = (byte) chs.Cylinder;
+ byte sector = chs.Sector;
+ sector |= byte (chs.Cylinder >> 2) & 0xc0;
+ byte function = write ? 0x03 : 0x02;
+
+ BiosResult result;
+ byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES;
+
+ do
+ {
+ result = BiosResultSuccess;
+
+ __asm
+ {
+ push es
+ mov ax, bufferSegment
+ mov es, ax
+ mov bx, bufferOffset
+ mov dl, drive
+ mov ch, cylinderLow
+ mov si, chs
+ mov dh, [si].Head
+ mov cl, sector
+ mov al, sectorCount
+ mov ah, function
+ int 0x13
+ jnc ok // If CF=0, ignore AH to prevent issues caused by potential bugs in BIOSes
+ mov result, ah
+ ok:
+ pop es
+ }
+
+ if (result == BiosResultEccCorrected)
+ result = BiosResultSuccess;
+
+ // Some BIOSes report I/O errors prematurely in some cases
+ } while (result != BiosResultSuccess && --tryCount != 0);
+
+ if (!silent && result != BiosResultSuccess)
+ PrintDiskError (result, write, drive, nullptr, &chs);
+
+ return result;
+}
+
+
+BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
+{
+ uint16 codeSeg;
+ __asm mov codeSeg, cs
+ return ReadWriteSectors (write, codeSeg, (uint16) buffer, drive, chs, sectorCount, silent);
+}
+
+
+BiosResult ReadSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
+{
+ return ReadWriteSectors (false, buffer, drive, chs, sectorCount, silent);
+}
+
+
+BiosResult WriteSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent)
+{
+ return ReadWriteSectors (true, buffer, drive, chs, sectorCount, silent);
+}
+
+
+static BiosResult ReadWriteSectors (bool write, BiosLbaPacket &dapPacket, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ CheckStack();
+
+ if (!IsLbaSupported (drive))
+ {
+ DriveGeometry geometry;
+
+ BiosResult result = GetDriveGeometry (drive, geometry, silent);
+ if (result != BiosResultSuccess)
+ return result;
+
+ ChsAddress chs;
+ LbaToChs (geometry, sector, chs);
+ return ReadWriteSectors (write, (uint16) (dapPacket.Buffer >> 16), (uint16) dapPacket.Buffer, drive, chs, sectorCount, silent);
+ }
+
+ dapPacket.Size = sizeof (dapPacket);
+ dapPacket.Reserved = 0;
+ dapPacket.SectorCount = sectorCount;
+ dapPacket.Sector = sector;
+
+ byte function = write ? 0x43 : 0x42;
+
+ BiosResult result;
+ byte tryCount = TC_MAX_BIOS_DISK_IO_RETRIES;
+
+ do
+ {
+ result = BiosResultSuccess;
+
+ __asm
+ {
+ mov bx, 0x55aa
+ mov dl, drive
+ mov si, [dapPacket]
+ mov ah, function
+ xor al, al
+ int 0x13
+ jnc ok // If CF=0, ignore AH to prevent issues caused by potential bugs in BIOSes
+ mov result, ah
+ ok:
+ }
+
+ if (result == BiosResultEccCorrected)
+ result = BiosResultSuccess;
+
+ // Some BIOSes report I/O errors prematurely in some cases
+ } while (result != BiosResultSuccess && --tryCount != 0);
+
+ if (!silent && result != BiosResultSuccess)
+ PrintDiskError (result, write, drive, &sector);
+
+ return result;
+}
+
+
+static BiosResult ReadWriteSectors (bool write, byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ BiosLbaPacket dapPacket;
+ dapPacket.Buffer = (uint32) buffer;
+ return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
+}
+
+
+BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ BiosLbaPacket dapPacket;
+ dapPacket.Buffer = ((uint32) bufferSegment << 16) | bufferOffset;
+ return ReadWriteSectors (write, dapPacket, drive, sector, sectorCount, silent);
+}
+
+BiosResult ReadSectors (uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ return ReadWriteSectors (false, bufferSegment, bufferOffset, drive, sector, sectorCount, silent);
+}
+
+
+BiosResult ReadSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ BiosResult result;
+ uint16 codeSeg;
+ __asm mov codeSeg, cs
+
+ result = ReadSectors (BootStarted ? codeSeg : TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, drive, sector, sectorCount, silent);
+
+ // Alternative segment is used to prevent memory corruption caused by buggy BIOSes
+ if (!BootStarted)
+ CopyMemory (TC_BOOT_LOADER_ALT_SEGMENT, (uint16) buffer, buffer, sectorCount * TC_LB_SIZE);
+
+ return result;
+}
+
+
+BiosResult WriteSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent)
+{
+ return ReadWriteSectors (true, buffer, drive, sector, sectorCount, silent);
+}
+
+
+BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent)
+{
+ CheckStack();
+
+ byte maxCylinderLow, maxHead, maxSector;
+ BiosResult result;
+ __asm
+ {
+ push es
+ mov dl, drive
+ mov ah, 0x08
+ int 0x13
+
+ mov result, ah
+ mov maxCylinderLow, ch
+ mov maxSector, cl
+ mov maxHead, dh
+ pop es
+ }
+
+ if (result == BiosResultSuccess)
+ {
+ geometry.Cylinders = (maxCylinderLow | (uint16 (maxSector & 0xc0) << 2)) + 1;
+ geometry.Heads = maxHead + 1;
+ geometry.Sectors = maxSector & ~0xc0;
+ }
+ else if (!silent)
+ {
+ Print ("Drive ");
+ Print (drive ^ 0x80);
+ Print (" not found: ");
+ PrintErrorNoEndl ("");
+ Print (result);
+ PrintEndl();
+ }
+
+ return result;
+}
+
+
+void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba)
+{
+ lba.HighPart = 0;
+ lba.LowPart = (uint32 (chs.Cylinder) * geometry.Heads + chs.Head) * geometry.Sectors + chs.Sector - 1;
+}
+
+
+void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs)
+{
+ chs.Sector = (byte) ((lba.LowPart % geometry.Sectors) + 1);
+ uint32 ch = lba.LowPart / geometry.Sectors;
+ chs.Head = (byte) (ch % geometry.Heads);
+ chs.Cylinder = (uint16) (ch / geometry.Heads);
+}
+
+
+void PartitionEntryMBRToPartition (const PartitionEntryMBR &partEntry, Partition &partition)
+{
+ partition.Active = partEntry.BootIndicator == 0x80;
+ partition.EndSector.HighPart = 0;
+ partition.EndSector.LowPart = partEntry.StartLBA + partEntry.SectorCountLBA - 1;
+ partition.SectorCount.HighPart = 0;
+ partition.SectorCount.LowPart = partEntry.SectorCountLBA;
+ partition.StartSector.HighPart = 0;
+ partition.StartSector.LowPart = partEntry.StartLBA;
+ partition.Type = partEntry.Type;
+}
+
+
+BiosResult ReadWriteMBR (bool write, byte drive, bool silent)
+{
+ uint64 mbrSector;
+ mbrSector.HighPart = 0;
+ mbrSector.LowPart = 0;
+
+ if (write)
+ return WriteSectors (SectorBuffer, drive, mbrSector, 1, silent);
+
+ return ReadSectors (SectorBuffer, drive, mbrSector, 1, silent); // Uses alternative segment
+}
+
+
+BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly, Partition *findPartitionFollowingThis, bool silent)
+{
+ Partition *followingPartition;
+ Partition tmpPartition;
+
+ if (findPartitionFollowingThis)
+ {
+ assert (partitionArrayCapacity == 1);
+ partitionArrayCapacity = 0xff;
+ followingPartition = partitionArray;
+ partitionArray = &tmpPartition;
+
+ followingPartition->Drive = TC_INVALID_BIOS_DRIVE;
+ followingPartition->StartSector.LowPart = 0xFFFFffffUL;
+ }
+
+ AcquireSectorBuffer();
+ BiosResult result = ReadWriteMBR (false, drive, silent);
+ ReleaseSectorBuffer();
+
+ partitionCount = 0;
+
+ MBR *mbr = (MBR *) SectorBuffer;
+ if (result != BiosResultSuccess || mbr->Signature != 0xaa55)
+ return result;
+
+ PartitionEntryMBR mbrPartitions[4];
+ memcpy (mbrPartitions, mbr->Partitions, sizeof (mbrPartitions));
+ size_t partitionArrayPos = 0, partitionNumber;
+
+ for (partitionNumber = 0;
+ partitionNumber < array_capacity (mbrPartitions) && partitionArrayPos < partitionArrayCapacity;
+ ++partitionNumber)
+ {
+ const PartitionEntryMBR &partEntry = mbrPartitions[partitionNumber];
+
+ if (partEntry.SectorCountLBA > 0)
+ {
+ Partition &partition = partitionArray[partitionArrayPos];
+ PartitionEntryMBRToPartition (partEntry, partition);
+
+ if (activeOnly && !partition.Active)
+ continue;
+
+ partition.Drive = drive;
+ partition.Number = partitionArrayPos;
+
+ if (partEntry.Type == 0x5 || partEntry.Type == 0xf) // Extended partition
+ {
+ if (IsLbaSupported (drive))
+ {
+ // Find all extended partitions
+ uint64 firstExtStartLBA = partition.StartSector;
+ uint64 extStartLBA = partition.StartSector;
+ MBR *extMbr = (MBR *) SectorBuffer;
+
+ while (partitionArrayPos < partitionArrayCapacity &&
+ (result = ReadSectors ((byte *) extMbr, drive, extStartLBA, 1, silent)) == BiosResultSuccess
+ && extMbr->Signature == 0xaa55)
+ {
+ if (extMbr->Partitions[0].SectorCountLBA > 0)
+ {
+ Partition &logPart = partitionArray[partitionArrayPos];
+ PartitionEntryMBRToPartition (extMbr->Partitions[0], logPart);
+ logPart.Drive = drive;
+
+ logPart.Number = partitionArrayPos;
+ logPart.Primary = false;
+
+ logPart.StartSector.LowPart += extStartLBA.LowPart;
+ logPart.EndSector.LowPart += extStartLBA.LowPart;
+
+ if (findPartitionFollowingThis)
+ {
+ if (logPart.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
+ && logPart.StartSector.LowPart < followingPartition->StartSector.LowPart)
+ {
+ *followingPartition = logPart;
+ }
+ }
+ else
+ ++partitionArrayPos;
+ }
+
+ // Secondary extended
+ if (extMbr->Partitions[1].Type != 0x5 && extMbr->Partitions[1].Type == 0xf
+ || extMbr->Partitions[1].SectorCountLBA == 0)
+ break;
+
+ extStartLBA.LowPart = extMbr->Partitions[1].StartLBA + firstExtStartLBA.LowPart;
+ }
+ }
+ }
+ else
+ {
+ partition.Primary = true;
+
+ if (findPartitionFollowingThis)
+ {
+ if (partition.StartSector.LowPart > findPartitionFollowingThis->EndSector.LowPart
+ && partition.StartSector.LowPart < followingPartition->StartSector.LowPart)
+ {
+ *followingPartition = partition;
+ }
+ }
+ else
+ ++partitionArrayPos;
+ }
+ }
+ }
+
+ partitionCount = partitionArrayPos;
+ return result;
+}
+
+
+bool GetActivePartition (byte drive)
+{
+ size_t partCount;
+
+ if (GetDrivePartitions (drive, &ActivePartition, 1, partCount, true) != BiosResultSuccess || partCount < 1)
+ {
+ ActivePartition.Drive = TC_INVALID_BIOS_DRIVE;
+ PrintError (TC_BOOT_STR_NO_BOOT_PARTITION);
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/Boot/Windows/BootDiskIo.h b/src/Boot/Windows/BootDiskIo.h
new file mode 100644
index 00000000..cc84c018
--- /dev/null
+++ b/src/Boot/Windows/BootDiskIo.h
@@ -0,0 +1,116 @@
+/*
+ Copyright (c) 2008-2011 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_BootDiskIo
+#define TC_HEADER_Boot_BootDiskIo
+
+#include "Bios.h"
+#include "BootDebug.h"
+#include "BootDefs.h"
+
+#define TC_MAX_BIOS_DISK_IO_RETRIES 5
+
+enum
+{
+ BiosResultEccCorrected = 0x11
+};
+
+#pragma pack(1)
+
+struct PartitionEntryMBR
+{
+ byte BootIndicator;
+
+ byte StartHead;
+ byte StartCylSector;
+ byte StartCylinder;
+
+ byte Type;
+
+ byte EndHead;
+ byte EndSector;
+ byte EndCylinder;
+
+ uint32 StartLBA;
+ uint32 SectorCountLBA;
+};
+
+struct MBR
+{
+ byte Code[446];
+ PartitionEntryMBR Partitions[4];
+ uint16 Signature;
+};
+
+struct BiosLbaPacket
+{
+ byte Size;
+ byte Reserved;
+ uint16 SectorCount;
+ uint32 Buffer;
+ uint64 Sector;
+};
+
+#pragma pack()
+
+
+struct ChsAddress
+{
+ uint16 Cylinder;
+ byte Head;
+ byte Sector;
+};
+
+struct Partition
+{
+ byte Number;
+ byte Drive;
+ bool Active;
+ uint64 EndSector;
+ bool Primary;
+ uint64 SectorCount;
+ uint64 StartSector;
+ byte Type;
+};
+
+struct DriveGeometry
+{
+ uint16 Cylinders;
+ byte Heads;
+ byte Sectors;
+};
+
+
+#ifdef TC_BOOT_DEBUG_ENABLED
+void AcquireSectorBuffer ();
+void ReleaseSectorBuffer ();
+#else
+# define AcquireSectorBuffer()
+# define ReleaseSectorBuffer()
+#endif
+
+void ChsToLba (const DriveGeometry &geometry, const ChsAddress &chs, uint64 &lba);
+bool GetActivePartition (byte drive);
+BiosResult GetDriveGeometry (byte drive, DriveGeometry &geometry, bool silent = false);
+BiosResult GetDrivePartitions (byte drive, Partition *partitionArray, size_t partitionArrayCapacity, size_t &partitionCount, bool activeOnly = false, Partition *findPartitionFollowingThis = nullptr, bool silent = false);
+bool IsLbaSupported (byte drive);
+void LbaToChs (const DriveGeometry &geometry, const uint64 &lba, ChsAddress &chs);
+void Print (const ChsAddress &chs);
+void PrintDiskError (BiosResult error, bool write, byte drive, const uint64 *sector, const ChsAddress *chs = nullptr);
+void PrintSectorCountInMB (const uint64 &sectorCount);
+BiosResult ReadWriteMBR (bool write, byte drive, bool silent = false);
+BiosResult ReadSectors (uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent = false);
+BiosResult ReadSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent = false);
+BiosResult ReadSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent = false);
+BiosResult ReadWriteSectors (bool write, uint16 bufferSegment, uint16 bufferOffset, byte drive, const uint64 &sector, uint16 sectorCount, bool silent);
+BiosResult WriteSectors (byte *buffer, byte drive, const uint64 &sector, uint16 sectorCount, bool silent = false);
+BiosResult WriteSectors (byte *buffer, byte drive, const ChsAddress &chs, byte sectorCount, bool silent = false);
+
+extern byte SectorBuffer[TC_LB_SIZE];
+
+#endif // TC_HEADER_Boot_BootDiskIo
diff --git a/src/Boot/Windows/BootEncryptedIo.cpp b/src/Boot/Windows/BootEncryptedIo.cpp
new file mode 100644
index 00000000..ff048991
--- /dev/null
+++ b/src/Boot/Windows/BootEncryptedIo.cpp
@@ -0,0 +1,128 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "Crypto.h"
+#include "Platform.h"
+#include "BootConfig.h"
+#include "BootDebug.h"
+#include "BootDefs.h"
+#include "BootDiskIo.h"
+#include "BootEncryptedIo.h"
+
+
+BiosResult ReadEncryptedSectors (uint16 destSegment, uint16 destOffset, byte drive, uint64 sector, uint16 sectorCount)
+{
+ BiosResult result;
+ bool decrypt = true;
+
+ if (BootCryptoInfo->hiddenVolume)
+ {
+ if (ReadWritePartiallyCoversEncryptedArea (sector, sectorCount))
+ return BiosResultInvalidFunction;
+
+ if (sector >= EncryptedVirtualPartition.StartSector && sector <= EncryptedVirtualPartition.EndSector)
+ {
+ // Remap the request to the hidden volume
+ sector -= EncryptedVirtualPartition.StartSector;
+ sector += HiddenVolumeStartSector;
+ }
+ else
+ decrypt = false;
+ }
+
+ result = ReadSectors (destSegment, destOffset, drive, sector, sectorCount);
+
+ if (result != BiosResultSuccess || !decrypt)
+ return result;
+
+ if (BootCryptoInfo->hiddenVolume)
+ {
+ // Convert sector number to data unit number of the hidden volume
+ sector -= HiddenVolumeStartSector;
+ sector += HiddenVolumeStartUnitNo;
+ }
+
+ if (drive == EncryptedVirtualPartition.Drive)
+ {
+ while (sectorCount-- > 0)
+ {
+ if (BootCryptoInfo->hiddenVolume
+ || (sector >= EncryptedVirtualPartition.StartSector && sector <= EncryptedVirtualPartition.EndSector))
+ {
+ AcquireSectorBuffer();
+ CopyMemory (destSegment, destOffset, SectorBuffer, TC_LB_SIZE);
+
+ DecryptDataUnits (SectorBuffer, &sector, 1, BootCryptoInfo);
+
+ CopyMemory (SectorBuffer, destSegment, destOffset, TC_LB_SIZE);
+ ReleaseSectorBuffer();
+ }
+
+ ++sector;
+ destOffset += TC_LB_SIZE;
+ }
+ }
+
+ return result;
+}
+
+
+BiosResult WriteEncryptedSectors (uint16 sourceSegment, uint16 sourceOffset, byte drive, uint64 sector, uint16 sectorCount)
+{
+ BiosResult result;
+ AcquireSectorBuffer();
+ uint64 dataUnitNo;
+ uint64 writeOffset;
+
+ dataUnitNo = sector;
+ writeOffset.HighPart = 0;
+ writeOffset.LowPart = 0;
+
+ if (BootCryptoInfo->hiddenVolume)
+ {
+ if (ReadWritePartiallyCoversEncryptedArea (sector, sectorCount))
+ return BiosResultInvalidFunction;
+
+ // Remap the request to the hidden volume
+ writeOffset = HiddenVolumeStartSector;
+ writeOffset -= EncryptedVirtualPartition.StartSector;
+ dataUnitNo -= EncryptedVirtualPartition.StartSector;
+ dataUnitNo += HiddenVolumeStartUnitNo;
+ }
+
+ while (sectorCount-- > 0)
+ {
+ CopyMemory (sourceSegment, sourceOffset, SectorBuffer, TC_LB_SIZE);
+
+ if (drive == EncryptedVirtualPartition.Drive && sector >= EncryptedVirtualPartition.StartSector && sector <= EncryptedVirtualPartition.EndSector)
+ {
+ EncryptDataUnits (SectorBuffer, &dataUnitNo, 1, BootCryptoInfo);
+ }
+
+ result = WriteSectors (SectorBuffer, drive, sector + writeOffset, 1);
+
+ if (result != BiosResultSuccess)
+ break;
+
+ ++sector;
+ ++dataUnitNo;
+ sourceOffset += TC_LB_SIZE;
+ }
+
+ ReleaseSectorBuffer();
+ return result;
+}
+
+
+static bool ReadWritePartiallyCoversEncryptedArea (const uint64 &sector, uint16 sectorCount)
+{
+ uint64 readWriteEnd = sector + --sectorCount;
+
+ return ((sector < EncryptedVirtualPartition.StartSector && readWriteEnd >= EncryptedVirtualPartition.StartSector)
+ || (sector >= EncryptedVirtualPartition.StartSector && readWriteEnd > EncryptedVirtualPartition.EndSector));
+}
diff --git a/src/Boot/Windows/BootEncryptedIo.h b/src/Boot/Windows/BootEncryptedIo.h
new file mode 100644
index 00000000..14cf182d
--- /dev/null
+++ b/src/Boot/Windows/BootEncryptedIo.h
@@ -0,0 +1,18 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_BootEncryptionIo
+#define TC_HEADER_Boot_BootEncryptionIo
+
+#include "Platform.h"
+
+BiosResult ReadEncryptedSectors (uint16 destSegment, uint16 destOffset, byte drive, uint64 sector, uint16 sectorCount);
+BiosResult WriteEncryptedSectors (uint16 sourceSegment, uint16 sourceOffset, byte drive, uint64 sector, uint16 sectorCount);
+static bool ReadWritePartiallyCoversEncryptedArea (const uint64 &sector, uint16 sectorCount);
+
+#endif // TC_HEADER_Boot_BootEncryptionIo
diff --git a/src/Boot/Windows/BootMain.cpp b/src/Boot/Windows/BootMain.cpp
new file mode 100644
index 00000000..5d4b942c
--- /dev/null
+++ b/src/Boot/Windows/BootMain.cpp
@@ -0,0 +1,1151 @@
+/*
+ Copyright (c) 2008-2011 TrueCrypt Developers Association. All rights reserved.
+
+ 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"
+#include "Crypto.h"
+#include "Password.h"
+#include "Volumes.h"
+
+#include "Platform.h"
+#include "Bios.h"
+#include "BootConfig.h"
+#include "BootMain.h"
+#include "BootDefs.h"
+#include "BootCommon.h"
+#include "BootConsoleIo.h"
+#include "BootDebug.h"
+#include "BootDiskIo.h"
+#include "BootEncryptedIo.h"
+#include "BootMemory.h"
+#include "BootStrings.h"
+#include "IntFilter.h"
+
+
+static void InitScreen ()
+{
+ ClearScreen();
+
+ const char *title =
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+ " TrueCrypt Boot Loader "
+#else
+ " TrueCrypt Rescue Disk "
+#endif
+ 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_NONE
+ ? "Boot Non-Hidden System (Boot Manager)"
+ : "Skip Authentication (Boot Manager)");
+
+#else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ Print ("Skip Authentication (Boot Manager)");
+ Print ("\r\n [F8] "); Print ("Repair Options");
+
+#endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ PrintEndl (3);
+}
+
+
+static bool IsMenuKey (byte scanCode)
+{
+#ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+ return scanCode == TC_MENU_KEY_REPAIR;
+#else
+ return false;
+#endif
+}
+
+
+static bool AskYesNo (const char *message)
+{
+ Print (message);
+ Print ("? (y/n): ");
+ while (true)
+ {
+ switch (GetKeyboardChar())
+ {
+ case 'y':
+ case 'Y':
+ case 'z':
+ case 'Z':
+ Print ("y\r\n");
+ return true;
+
+ case 'n':
+ case 'N':
+ Print ("n\r\n");
+ return false;
+
+ default:
+ Beep();
+ }
+ }
+}
+
+
+static int AskSelection (const char *options[], size_t optionCount)
+{
+ for (int i = 0; i < optionCount; ++i)
+ {
+ Print ("["); Print (i + 1); Print ("] ");
+ Print (options[i]);
+ PrintEndl();
+ }
+ Print ("[Esc] Cancel\r\n\r\n");
+
+ Print ("To select, press 1-9: ");
+
+ char str;
+
+ while (true)
+ {
+ if (GetString (&str, 1) == 0)
+ return 0;
+
+ if (str >= '1' && str <= optionCount + '0')
+ return str - '0';
+
+ Beep();
+ PrintBackspace();
+ }
+}
+
+
+static byte AskPassword (Password &password)
+{
+ size_t pos = 0;
+ byte scanCode;
+ byte asciiCode;
+
+ Print ("Enter password");
+ Print (PreventNormalSystemBoot ? " for hidden system:\r\n" : ": ");
+
+ while (true)
+ {
+ asciiCode = GetKeyboardChar (&scanCode);
+
+ switch (scanCode)
+ {
+ case TC_BIOS_KEY_ENTER:
+ ClearBiosKeystrokeBuffer();
+ PrintEndl();
+
+ password.Length = pos;
+ return scanCode;
+
+ case TC_BIOS_KEY_BACKSPACE:
+ if (pos > 0)
+ {
+ if (pos < MAX_PASSWORD)
+ PrintBackspace();
+ else
+ PrintCharAtCursor (' ');
+
+ --pos;
+ }
+ continue;
+
+ default:
+ if (scanCode == TC_BIOS_KEY_ESC || IsMenuKey (scanCode))
+ {
+ burn (password.Text, sizeof (password.Text));
+ ClearBiosKeystrokeBuffer();
+
+ PrintEndl();
+ return scanCode;
+ }
+ }
+
+ if (!IsPrintable (asciiCode) || pos == MAX_PASSWORD)
+ {
+ Beep();
+ continue;
+ }
+
+ password.Text[pos++] = asciiCode;
+ if (pos < MAX_PASSWORD)
+ PrintChar ('*');
+ else
+ PrintCharAtCursor ('*');
+ }
+}
+
+
+static void ExecuteBootSector (byte drive, byte *sectorBuffer)
+{
+ Print ("Booting...\r\n");
+ CopyMemory (sectorBuffer, 0x0000, 0x7c00, TC_LB_SIZE);
+
+ BootStarted = true;
+
+ uint32 addr = 0x7c00;
+ __asm
+ {
+ cli
+ 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, 0x7c00
+ sti
+
+ jmp cs:addr
+ }
+}
+
+
+static bool OpenVolume (byte drive, Password &password, CRYPTO_INFO **cryptoInfo, uint32 *headerSaltCrc32, bool skipNormal, bool skipHidden)
+{
+ int volumeType;
+ bool hiddenVolume;
+ uint64 headerSec;
+
+ AcquireSectorBuffer();
+
+ for (volumeType = 1; volumeType <= 2; ++volumeType)
+ {
+ hiddenVolume = (volumeType == 2);
+
+ if (hiddenVolume)
+ {
+ if (skipHidden || PartitionFollowingActive.Drive != drive || PartitionFollowingActive.SectorCount <= ActivePartition.SectorCount)
+ continue;
+
+ headerSec = PartitionFollowingActive.StartSector + TC_HIDDEN_VOLUME_HEADER_OFFSET / TC_LB_SIZE;
+ }
+ else
+ {
+ if (skipNormal)
+ continue;
+
+ headerSec.HighPart = 0;
+ headerSec.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
+ }
+
+ if (ReadSectors (SectorBuffer, drive, headerSec, 1) != BiosResultSuccess)
+ continue;
+
+ if (ReadVolumeHeader (!hiddenVolume, (char *) SectorBuffer, &password, cryptoInfo, nullptr) == ERR_SUCCESS)
+ {
+ // 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;
+ }
+ }
+
+ ReleaseSectorBuffer();
+ return volumeType != 3;
+}
+
+
+static bool CheckMemoryRequirements ()
+{
+ uint16 codeSeg;
+ __asm mov codeSeg, cs
+ if (codeSeg == TC_BOOT_LOADER_LOWMEM_SEGMENT)
+ {
+ PrintErrorNoEndl ("BIOS reserved too much memory: ");
+
+ uint16 memFree;
+ __asm
+ {
+ push es
+ xor ax, ax
+ mov es, ax
+ mov ax, es:[0x413]
+ mov memFree, ax
+ pop es
+ }
+
+ Print (memFree);
+ PrintEndl();
+ Print (TC_BOOT_STR_UPGRADE_BIOS);
+
+ return false;
+ }
+
+ return true;
+}
+
+
+static bool MountVolume (byte drive, byte &exitKey, bool skipNormal, bool skipHidden)
+{
+ BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
+ int incorrectPasswordCount = 0;
+
+ EraseMemory (bootArguments, sizeof (*bootArguments));
+
+ // Open volume header
+ while (true)
+ {
+ exitKey = AskPassword (bootArguments->BootPassword);
+
+ if (exitKey != TC_BIOS_KEY_ENTER)
+ return false;
+
+ if (OpenVolume (BootDrive, bootArguments->BootPassword, &BootCryptoInfo, &bootArguments->HeaderSaltCrc32, skipNormal, skipHidden))
+ break;
+
+ if (GetShiftFlags() & TC_BIOS_SHIFTMASK_CAPSLOCK)
+ Print ("Warning: Caps Lock is on.\r\n");
+
+ Print ("Incorrect password.\r\n\r\n");
+
+ 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
+ }
+ }
+
+ // Setup boot arguments
+ 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
+ if (BootCryptoInfo->EncryptedAreaLength.HighPart != 0 || BootCryptoInfo->EncryptedAreaLength.LowPart != 0)
+ {
+ EncryptedVirtualPartition.Drive = BootDrive;
+
+ EncryptedVirtualPartition.StartSector = BootCryptoInfo->EncryptedAreaStart >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
+
+ HiddenVolumeStartUnitNo = EncryptedVirtualPartition.StartSector;
+ HiddenVolumeStartSector = PartitionFollowingActive.StartSector;
+ HiddenVolumeStartSector += EncryptedVirtualPartition.StartSector;
+
+ EncryptedVirtualPartition.SectorCount = BootCryptoInfo->EncryptedAreaLength >> TC_LB_SIZE_BIT_SHIFT_DIVISOR;
+
+ EncryptedVirtualPartition.EndSector = EncryptedVirtualPartition.SectorCount - 1;
+ EncryptedVirtualPartition.EndSector += EncryptedVirtualPartition.StartSector;
+ }
+ else
+ {
+ // Drive not encrypted
+ EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
+ }
+
+ return true;
+}
+
+
+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 ()
+{
+ BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
+ byte exitKey;
+ BootCryptoInfo = NULL;
+
+ if (!GetSystemPartitions (BootDrive))
+ goto err;
+
+ if (!MountVolume (BootDrive, exitKey, PreventNormalSystemBoot, false))
+ return exitKey;
+
+ if (!CheckMemoryRequirements ())
+ goto err;
+
+ if (BootCryptoInfo->hiddenVolume)
+ {
+ EncryptedVirtualPartition = ActivePartition;
+ bootArguments->DecoySystemPartitionStart = ActivePartition.StartSector << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
+ }
+
+ if (ExtraBootPartitionPresent && !GetActivePartition (BootDrive))
+ goto err;
+
+ if (ReadWriteMBR (false, ActivePartition.Drive) != BiosResultSuccess)
+ goto err;
+
+ bootArguments->BootDriveSignature = *(uint32 *) (SectorBuffer + 0x1b8);
+
+ if (!InstallInterruptFilters())
+ goto err;
+
+ bootArguments->BootArgumentsCrc32 = GetCrc32 ((byte *) bootArguments, (byte *) &bootArguments->BootArgumentsCrc32 - (byte *) bootArguments);
+
+ while (true)
+ {
+ // 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);
+ }
+
+ GetKeyboardChar();
+ }
+
+err:
+ if (BootCryptoInfo)
+ {
+ crypto_close (BootCryptoInfo);
+ BootCryptoInfo = NULL;
+ }
+
+ EncryptedVirtualPartition.Drive = TC_INVALID_BIOS_DRIVE;
+ EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
+
+ byte scanCode;
+ GetKeyboardChar (&scanCode);
+ return scanCode;
+}
+
+
+static void BootMenu ()
+{
+ BiosResult result;
+ Partition partitions[16];
+ Partition bootablePartitions[9];
+ size_t partitionCount;
+ size_t bootablePartitionCount = 0;
+
+ for (byte drive = TC_FIRST_BIOS_DRIVE; drive <= TC_LAST_BIOS_DRIVE; ++drive)
+ {
+ if (GetDrivePartitions (drive, partitions, array_capacity (partitions), partitionCount, false, nullptr, true) == BiosResultSuccess)
+ {
+ for (size_t i = 0; i < partitionCount; ++i)
+ {
+ const Partition &partition = partitions[i];
+ result = ReadSectors (SectorBuffer, drive, partition.StartSector, 1);
+
+ if (result == BiosResultSuccess && *(uint16 *) (SectorBuffer + TC_LB_SIZE - 2) == 0xaa55)
+ {
+ // Windows writes boot loader on all NTFS/FAT filesytems it creates and, therefore,
+ // 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'))
+ {
+ continue;
+ }
+
+ // Bootable sector found
+ if (bootablePartitionCount < array_capacity (bootablePartitions))
+ bootablePartitions[bootablePartitionCount++] = partition;
+ }
+ }
+ }
+ }
+
+ if (bootablePartitionCount < 1)
+ {
+ PrintError (TC_BOOT_STR_NO_BOOT_PARTITION);
+ GetKeyboardChar();
+ return;
+ }
+
+ char partChar;
+ while (true)
+ {
+ InitScreen();
+ Print ("Bootable Partitions:\r\n");
+ PrintRepeatedChar ('\xC4', 20);
+ Print ("\r\n");
+
+ for (size_t i = 0; i < bootablePartitionCount; ++i)
+ {
+ const Partition &partition = bootablePartitions[i];
+ Print ("["); Print (i + 1); Print ("] ");
+ Print ("Drive: "); Print (partition.Drive - TC_FIRST_BIOS_DRIVE);
+ Print (", Partition: "); Print (partition.Number + 1);
+ Print (", Size: "); PrintSectorCountInMB (partition.SectorCount); PrintEndl();
+ }
+
+ if (bootablePartitionCount == 1)
+ {
+ // There's only one bootable partition so we'll boot it directly instead of showing boot manager
+ partChar = '1';
+ }
+ else
+ {
+ Print ("[Esc] Cancel\r\n\r\n");
+ Print ("Press 1-9 to select partition: ");
+
+ if (GetString (&partChar, 1) == 0)
+ return;
+
+ PrintEndl();
+
+ if (partChar < '1' || partChar > '0' + bootablePartitionCount)
+ {
+ Beep();
+ continue;
+ }
+ }
+
+ const Partition &partition = bootablePartitions[partChar - '0' - 1];
+
+ if (ReadSectors (SectorBuffer, partition.Drive, partition.StartSector, 1) == BiosResultSuccess)
+ {
+ ExecuteBootSector (partition.Drive, SectorBuffer);
+ }
+ }
+}
+
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+static bool CopySystemPartitionToHiddenVolume (byte drive, byte &exitKey)
+{
+ bool status = false;
+
+ uint64 sectorsRemaining;
+ uint64 sectorOffset;
+ sectorOffset.LowPart = 0;
+ sectorOffset.HighPart = 0;
+
+ int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
+ int statCount;
+
+ if (!CheckMemoryRequirements ())
+ goto err;
+
+ 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)
+ {
+ 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))
+ TC_THROW_FATAL_EXCEPTION;
+
+ InitScreen();
+ Print ("\r\nCopying system to hidden volume. To abort, press Esc.\r\n\r\n");
+
+ while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
+ {
+ if (EscKeyPressed())
+ {
+ Print ("\rIf aborted, copying will have to start from the beginning (if attempted again).\r\n");
+ if (AskYesNo ("Abort"))
+ break;
+ }
+
+ if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
+ fragmentSectorCount = (int) sectorsRemaining.LowPart;
+
+ if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, ActivePartition.StartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
+ {
+ Print ("To fix bad sectors: 1) Terminate 2) Encrypt and decrypt sys partition 3) Retry\r\n");
+ crypto_close (BootCryptoInfo);
+ goto err;
+ }
+
+ AcquireSectorBuffer();
+
+ for (int i = 0; i < fragmentSectorCount; ++i)
+ {
+ CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
+
+ uint64 s = HiddenVolumeStartUnitNo + sectorOffset + i;
+ EncryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
+
+ CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
+ }
+
+ ReleaseSectorBuffer();
+
+ if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, HiddenVolumeStartSector + sectorOffset, fragmentSectorCount, false) != BiosResultSuccess)
+ {
+ crypto_close (BootCryptoInfo);
+ goto err;
+ }
+
+ sectorsRemaining = sectorsRemaining - fragmentSectorCount;
+ sectorOffset = sectorOffset + fragmentSectorCount;
+
+ if (!(statCount++ & 0xf))
+ {
+ Print ("\rRemaining: ");
+ PrintSectorCountInMB (sectorsRemaining);
+ }
+ }
+
+ crypto_close (BootCryptoInfo);
+
+ if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
+ {
+ status = true;
+ Print ("\rCopying completed.");
+ }
+
+ PrintEndl (2);
+ goto ret;
+
+err:
+ exitKey = TC_BIOS_KEY_ESC;
+ GetKeyboardChar();
+
+ret:
+ EraseMemory ((void *) TC_BOOT_LOADER_ARGS_OFFSET, sizeof (BootArguments));
+ return status;
+}
+
+
+#else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+
+static void DecryptDrive (byte drive)
+{
+ byte exitKey;
+ if (!MountVolume (drive, exitKey, false, true))
+ return;
+
+ BootArguments *bootArguments = (BootArguments *) TC_BOOT_LOADER_ARGS_OFFSET;
+
+ bool headerUpdateRequired = false;
+ uint64 sectorsRemaining = EncryptedVirtualPartition.EndSector + 1 - EncryptedVirtualPartition.StartSector;
+ uint64 sector = EncryptedVirtualPartition.EndSector + 1;
+
+ int fragmentSectorCount = 0x7f; // Maximum safe value supported by BIOS
+ int statCount;
+
+ bool skipBadSectors = false;
+
+ 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"))
+ {
+ crypto_close (BootCryptoInfo);
+ goto ret;
+ }
+
+ if (EncryptedVirtualPartition.Drive == TC_INVALID_BIOS_DRIVE)
+ {
+ // Drive already decrypted
+ sectorsRemaining.HighPart = 0;
+ sectorsRemaining.LowPart = 0;
+ }
+ else
+ {
+ Print ("\r\nTo safely interrupt and defer decryption, press Esc.\r\n"
+ "WARNING: You can turn off power only after you press Esc.\r\n\r\n");
+ }
+
+ while (sectorsRemaining.HighPart != 0 || sectorsRemaining.LowPart != 0)
+ {
+ if (EscKeyPressed())
+ break;
+
+ if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart < fragmentSectorCount)
+ fragmentSectorCount = (int) sectorsRemaining.LowPart;
+
+ sector = sector - fragmentSectorCount;
+
+ if (!(statCount++ & 0xf))
+ {
+ Print ("\rRemaining: ");
+ PrintSectorCountInMB (sectorsRemaining);
+ }
+
+ if (ReadWriteSectors (false, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) == BiosResultSuccess)
+ {
+ AcquireSectorBuffer();
+
+ for (int i = 0; i < fragmentSectorCount; ++i)
+ {
+ CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, SectorBuffer, TC_LB_SIZE);
+
+ uint64 s = sector + i;
+ DecryptDataUnits (SectorBuffer, &s, 1, BootCryptoInfo);
+
+ CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, i * TC_LB_SIZE, TC_LB_SIZE);
+ }
+
+ ReleaseSectorBuffer();
+
+ if (ReadWriteSectors (true, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, drive, sector, fragmentSectorCount, skipBadSectors) != BiosResultSuccess && !skipBadSectors)
+ goto askBadSectorSkip;
+ }
+ else if (!skipBadSectors)
+ goto askBadSectorSkip;
+
+ sectorsRemaining = sectorsRemaining - fragmentSectorCount;
+ headerUpdateRequired = true;
+ continue;
+
+askBadSectorSkip:
+ if (!AskYesNo ("Skip all bad sectors"))
+ break;
+
+ skipBadSectors = true;
+ sector = sector + fragmentSectorCount;
+ fragmentSectorCount = 1;
+ }
+
+ crypto_close (BootCryptoInfo);
+
+ if (headerUpdateRequired)
+ {
+ AcquireSectorBuffer();
+ uint64 headerSector;
+ headerSector.HighPart = 0;
+ headerSector.LowPart = TC_BOOT_VOLUME_HEADER_SECTOR;
+
+ // Update encrypted area size in volume header
+
+ CRYPTO_INFO *headerCryptoInfo = crypto_open();
+ while (ReadSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
+
+ if (ReadVolumeHeader (TRUE, (char *) SectorBuffer, &bootArguments->BootPassword, NULL, headerCryptoInfo) == 0)
+ {
+ DecryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
+
+ uint64 encryptedAreaLength = sectorsRemaining << TC_LB_SIZE_BIT_SHIFT_DIVISOR;
+
+ for (int i = 7; i >= 0; --i)
+ {
+ SectorBuffer[TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH + i] = (byte) encryptedAreaLength.LowPart;
+ encryptedAreaLength = encryptedAreaLength >> 8;
+ }
+
+ uint32 headerCrc32 = GetCrc32 (SectorBuffer + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
+
+ for (i = 3; i >= 0; --i)
+ {
+ SectorBuffer[TC_HEADER_OFFSET_HEADER_CRC + i] = (byte) headerCrc32;
+ headerCrc32 >>= 8;
+ }
+
+ EncryptBuffer (SectorBuffer + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, headerCryptoInfo);
+ }
+
+ crypto_close (headerCryptoInfo);
+
+ while (WriteSectors (SectorBuffer, drive, headerSector, 1) != BiosResultSuccess);
+ ReleaseSectorBuffer();
+ }
+
+ if (sectorsRemaining.HighPart == 0 && sectorsRemaining.LowPart == 0)
+ Print ("\rDrive decrypted.\r\n");
+ else
+ Print ("\r\nDecryption deferred.\r\n");
+
+ GetKeyboardChar();
+ret:
+ EraseMemory (bootArguments, sizeof (*bootArguments));
+}
+
+
+static void RepairMenu ()
+{
+ DriveGeometry bootLoaderDriveGeometry;
+
+ if (GetDriveGeometry (BootLoaderDrive, bootLoaderDriveGeometry, true) != BiosResultSuccess)
+ {
+ // Some BIOSes may fail to get the geometry of an emulated floppy drive
+ bootLoaderDriveGeometry.Cylinders = 80;
+ bootLoaderDriveGeometry.Heads = 2;
+ bootLoaderDriveGeometry.Sectors = 18;
+ }
+
+ while (true)
+ {
+ InitScreen();
+ Print ("Available "); Print ("Repair Options"); Print (":\r\n");
+ PrintRepeatedChar ('\xC4', 25);
+ PrintEndl();
+
+ enum
+ {
+ RestoreNone = 0,
+ DecryptVolume,
+ RestoreTrueCryptLoader,
+ RestoreVolumeHeader,
+ RestoreOriginalSystemLoader
+ };
+
+ static const char *options[] = { "Permanently decrypt system partition/drive", "Restore TrueCrypt Boot Loader", "Restore key data (volume header)", "Restore original system loader" };
+
+ int selection = AskSelection (options,
+ (BootSectorFlags & TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER) ? array_capacity (options) : array_capacity (options) - 1);
+
+ PrintEndl();
+
+ switch (selection)
+ {
+ case RestoreNone:
+ return;
+
+ case DecryptVolume:
+ DecryptDrive (BootDrive);
+ continue;
+
+ case RestoreOriginalSystemLoader:
+ if (!AskYesNo ("Is the system partition/drive decrypted"))
+ {
+ Print ("Please decrypt it first.\r\n");
+ GetKeyboardChar();
+ continue;
+ }
+ break;
+ }
+
+ bool writeConfirmed = false;
+ BiosResult result;
+
+ uint64 sector;
+ sector.HighPart = 0;
+ ChsAddress chs;
+
+ byte mbrPartTable[TC_LB_SIZE - TC_MAX_MBR_BOOT_CODE_SIZE];
+ AcquireSectorBuffer();
+
+ for (int i = (selection == RestoreVolumeHeader ? TC_BOOT_VOLUME_HEADER_SECTOR : TC_MBR_SECTOR);
+ i < TC_BOOT_LOADER_AREA_SECTOR_COUNT; ++i)
+ {
+ sector.LowPart = i;
+
+ if (selection == RestoreOriginalSystemLoader)
+ sector.LowPart += TC_ORIG_BOOT_LOADER_BACKUP_SECTOR;
+ else if (selection == RestoreTrueCryptLoader)
+ sector.LowPart += TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR;
+
+ // The backup medium may be a floppy-emulated bootable CD. The emulation may fail if LBA addressing is used.
+ // Therefore, only CHS addressing can be used.
+ LbaToChs (bootLoaderDriveGeometry, sector, chs);
+ sector.LowPart = i;
+
+ if (i == TC_MBR_SECTOR)
+ {
+ // Read current partition table
+ result = ReadSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1);
+ if (result != BiosResultSuccess)
+ goto err;
+
+ memcpy (mbrPartTable, SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbrPartTable));
+ }
+
+ result = ReadSectors (SectorBuffer, BootLoaderDrive, chs, 1);
+ if (result != BiosResultSuccess)
+ goto err;
+
+ if (i == TC_MBR_SECTOR)
+ {
+ // Preserve current partition table
+ memcpy (SectorBuffer + TC_MAX_MBR_BOOT_CODE_SIZE, mbrPartTable, sizeof (mbrPartTable));
+ }
+
+ // Volume header
+ if (i == TC_BOOT_VOLUME_HEADER_SECTOR)
+ {
+ if (selection == RestoreTrueCryptLoader)
+ continue;
+
+ if (selection == RestoreVolumeHeader)
+ {
+ while (true)
+ {
+ bool validHeaderPresent = false;
+ uint32 masterKeyScheduleCrc;
+
+ Password password;
+ byte exitKey = AskPassword (password);
+
+ if (exitKey != TC_BIOS_KEY_ENTER)
+ goto abort;
+
+ CRYPTO_INFO *cryptoInfo;
+
+ CopyMemory (SectorBuffer, TC_BOOT_LOADER_BUFFER_SEGMENT, 0, TC_LB_SIZE);
+ ReleaseSectorBuffer();
+
+ // Restore volume header only if the current one cannot be used
+ if (OpenVolume (TC_FIRST_BIOS_DRIVE, password, &cryptoInfo, nullptr, false, true))
+ {
+ validHeaderPresent = true;
+ masterKeyScheduleCrc = GetCrc32 (cryptoInfo->ks, sizeof (cryptoInfo->ks));
+ crypto_close (cryptoInfo);
+ }
+
+ AcquireSectorBuffer();
+ CopyMemory (TC_BOOT_LOADER_BUFFER_SEGMENT, 0, SectorBuffer, TC_LB_SIZE);
+
+ 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;
+ }
+
+ Print ("Incorrect password.\r\n\r\n");
+ }
+ }
+ }
+
+ if (!writeConfirmed && !AskYesNo ("Modify drive 0"))
+ goto abort;
+ writeConfirmed = true;
+
+ if (WriteSectors (SectorBuffer, TC_FIRST_BIOS_DRIVE, sector, 1) != BiosResultSuccess)
+ goto err;
+ }
+done:
+ switch (selection)
+ {
+ case RestoreTrueCryptLoader:
+ Print ("TrueCrypt Boot Loader");
+ break;
+
+ case RestoreVolumeHeader:
+ Print ("Header");
+ break;
+
+ case RestoreOriginalSystemLoader:
+ Print ("System loader");
+ break;
+ }
+ Print (" restored.\r\n");
+
+err: GetKeyboardChar();
+abort: ReleaseSectorBuffer();
+ }
+}
+
+#endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+
+#ifndef DEBUG
+extern "C" void _acrtused () { } // Required by linker
+#endif
+
+
+void main ()
+{
+ __asm mov BootLoaderDrive, dl
+ __asm mov BootSectorFlags, dh
+
+#ifdef TC_BOOT_TRACING_ENABLED
+ InitDebugPort();
+#endif
+
+#ifdef TC_BOOT_STACK_CHECKING_ENABLED
+ 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();
+
+ // Determine boot drive
+ BootDrive = BootLoaderDrive;
+ if (BootDrive < TC_FIRST_BIOS_DRIVE)
+ BootDrive = TC_FIRST_BIOS_DRIVE;
+
+ // Query boot drive geometry
+ if (GetDriveGeometry (BootDrive, BootDriveGeometry) != BiosResultSuccess)
+ {
+ BootDrive = TC_FIRST_BIOS_DRIVE;
+ 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;
+
+#ifdef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ // Check whether the user is not using the Rescue Disk to create a hidden system
+
+ if (ReadWriteMBR (false, BootDrive, true) == BiosResultSuccess
+ && *(uint32 *) (SectorBuffer + 6) == 0x65757254
+ && *(uint32 *) (SectorBuffer + 10) == 0x70797243
+ && (SectorBuffer[TC_BOOT_SECTOR_CONFIG_OFFSET] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE) != TC_HIDDEN_OS_CREATION_PHASE_NONE)
+ {
+ PrintError ("It appears you are creating a hidden OS.");
+ if (AskYesNo ("Is this correct"))
+ {
+ Print ("Please remove the Rescue Disk from the drive and restart.");
+ while (true);
+ }
+ }
+
+#endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+
+ // Main menu
+
+ while (true)
+ {
+ byte exitKey;
+ InitScreen();
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ // Hidden system setup
+ byte hiddenSystemCreationPhase = BootSectorFlags & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
+
+ if (hiddenSystemCreationPhase != TC_HIDDEN_OS_CREATION_PHASE_NONE)
+ {
+ PreventNormalSystemBoot = true;
+ PrintMainMenu();
+
+ if (hiddenSystemCreationPhase == TC_HIDDEN_OS_CREATION_PHASE_CLONING)
+ {
+ if (CopySystemPartitionToHiddenVolume (BootDrive, exitKey))
+ {
+ 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)
+ goto bootMenu;
+ else
+ continue;
+ }
+ }
+ else
+ PrintMainMenu();
+
+ exitKey = BootEncryptedDrive();
+
+#else // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ PrintMainMenu();
+ exitKey = BootEncryptedDrive();
+
+ if (exitKey == TC_MENU_KEY_REPAIR)
+ {
+ RepairMenu();
+ continue;
+ }
+
+#endif // TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+bootMenu:
+ if (!PreventBootMenu)
+ BootMenu();
+ }
+}
diff --git a/src/Boot/Windows/BootMain.h b/src/Boot/Windows/BootMain.h
new file mode 100644
index 00000000..2cb4af87
--- /dev/null
+++ b/src/Boot/Windows/BootMain.h
@@ -0,0 +1,30 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_BootMain
+#define TC_HEADER_Boot_BootMain
+
+#include "TCdefs.h"
+#include "Platform.h"
+
+static byte AskPassword (Password &password);
+static int AskSelection (const char *options[], size_t optionCount);
+static bool AskYesNo (const char *message);
+static byte BootEncryptedDrive ();
+static void BootMenu ();
+static void ExecuteBootSector (byte drive, byte *sectorBuffer);
+static void InitScreen ();
+static bool IsMenuKey (byte scanCode);
+static bool MountVolume (byte drive, byte &exitKey);
+static bool OpenVolume (byte drive, Password &password, CRYPTO_INFO **cryptoInfo, uint32 *headerSaltCrc32 = nullptr, bool skipNormal = false, bool skipHidden = false);
+static void PrintMainMenu ();
+static void RepairMenu ();
+
+#define TC_MENU_KEY_REPAIR TC_BIOS_KEY_F8
+
+#endif // TC_HEADER_Boot_BootMain
diff --git a/src/Boot/Windows/BootMemory.cpp b/src/Boot/Windows/BootMemory.cpp
new file mode 100644
index 00000000..c9e11328
--- /dev/null
+++ b/src/Boot/Windows/BootMemory.cpp
@@ -0,0 +1,82 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "BootDefs.h"
+#include "BootMemory.h"
+
+static uint32 MemoryMapContValue;
+
+static bool GetMemoryMapEntry (BiosMemoryMapEntry &entry)
+{
+ static const uint32 function = 0x0000E820UL;
+ static const uint32 magic = 0x534D4150UL;
+ static const uint32 bufferSize = sizeof (BiosMemoryMapEntry);
+
+ bool carry = false;
+ uint32 resultMagic;
+ uint32 resultSize;
+
+ __asm
+ {
+ push es
+
+ lea di, function
+ TC_ASM_MOV_EAX_DI
+ lea di, MemoryMapContValue
+ TC_ASM_MOV_EBX_DI
+ lea di, bufferSize
+ TC_ASM_MOV_ECX_DI
+ lea di, magic
+ TC_ASM_MOV_EDX_DI
+ lea di, MemoryMapContValue
+ TC_ASM_MOV_DI_ECX
+
+ // Use alternative segment to prevent memory corruption caused by buggy BIOSes
+ push TC_BOOT_LOADER_ALT_SEGMENT
+ pop es
+ mov di, 0
+
+ int 0x15
+ jnc no_carry
+ mov carry, true
+ no_carry:
+
+ lea di, resultMagic
+ TC_ASM_MOV_DI_EAX
+ lea di, MemoryMapContValue
+ TC_ASM_MOV_DI_EBX
+ lea di, resultSize
+ TC_ASM_MOV_DI_ECX
+
+ pop es
+ }
+
+ CopyMemory (TC_BOOT_LOADER_ALT_SEGMENT, 0, &entry, sizeof (entry));
+
+ // BIOS may set CF at the end of the list
+ if (carry)
+ MemoryMapContValue = 0;
+
+ return resultMagic == magic && resultSize == bufferSize;
+}
+
+
+bool GetFirstBiosMemoryMapEntry (BiosMemoryMapEntry &entry)
+{
+ MemoryMapContValue = 0;
+ return GetMemoryMapEntry (entry);
+}
+
+
+bool GetNextBiosMemoryMapEntry (BiosMemoryMapEntry &entry)
+{
+ if (MemoryMapContValue == 0)
+ return false;
+
+ return GetMemoryMapEntry (entry);
+}
diff --git a/src/Boot/Windows/BootMemory.h b/src/Boot/Windows/BootMemory.h
new file mode 100644
index 00000000..06b53655
--- /dev/null
+++ b/src/Boot/Windows/BootMemory.h
@@ -0,0 +1,24 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "Platform.h"
+#include "Bios.h"
+
+#pragma pack(1)
+
+struct BiosMemoryMapEntry
+{
+ uint64 BaseAddress;
+ uint64 Length;
+ uint32 Type;
+};
+
+#pragma pack()
+
+bool GetFirstBiosMemoryMapEntry (BiosMemoryMapEntry &entry);
+bool GetNextBiosMemoryMapEntry (BiosMemoryMapEntry &entry);
diff --git a/src/Boot/Windows/BootSector.asm b/src/Boot/Windows/BootSector.asm
new file mode 100644
index 00000000..582505b4
--- /dev/null
+++ b/src/Boot/Windows/BootSector.asm
@@ -0,0 +1,237 @@
+;
+; Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+;
+; 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.
+;
+
+.MODEL tiny
+.386
+_TEXT SEGMENT USE16
+
+INCLUDE BootDefs.i
+
+ORG 7C00h ; Standard boot sector offset
+
+start:
+ ; BIOS executes boot sector from 0:7C00 or 7C0:0000 (default CD boot loader address).
+ ; Far jump to the next instruction sets IP to the standard offset 7C00.
+ db 0EAh ; jmp 0:main
+ dw main, 0
+
+loader_name_msg:
+ db ' TrueCrypt Boot Loader', 13, 10, 0
+
+main:
+ cli
+ xor ax, ax
+ mov ds, ax
+ mov ss, ax
+ mov sp, 7C00h
+ sti
+
+ ; Display boot loader name
+ test byte ptr [start + TC_BOOT_SECTOR_USER_CONFIG_OFFSET], TC_BOOT_USER_CFG_FLAG_SILENT_MODE
+ jnz skip_loader_name_msg
+
+ lea si, loader_name_msg
+ call print
+skip_loader_name_msg:
+
+ ; Determine boot loader segment
+ mov ax, TC_BOOT_LOADER_SEGMENT
+
+ ; Check available memory
+ cmp word ptr [ds:413h], TC_BOOT_LOADER_SEGMENT / 1024 * 16 + TC_BOOT_MEMORY_REQUIRED
+ jge memory_ok
+
+ mov ax, TC_BOOT_LOADER_SEGMENT_LOW
+
+ cmp word ptr [ds:413h], TC_BOOT_LOADER_SEGMENT_LOW / 1024 * 16 + TC_BOOT_MEMORY_REQUIRED
+ jge memory_ok
+
+ ; Insufficient memory
+ mov ax, TC_BOOT_LOADER_LOWMEM_SEGMENT
+
+memory_ok:
+ mov es, ax
+
+ ; Clear BSS section
+ xor al, al
+ mov di, TC_COM_EXECUTABLE_OFFSET
+ mov cx, TC_BOOT_MEMORY_REQUIRED * 1024 - TC_COM_EXECUTABLE_OFFSET - 1
+ cld
+ rep stosb
+
+ mov ax, es
+ sub ax, TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE / 16 ; Decompressor segment
+ mov es, ax
+
+ ; Load decompressor
+ mov cl, TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR
+retry_backup:
+ mov al, TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT
+ mov bx, TC_COM_EXECUTABLE_OFFSET
+ call read_sectors
+
+ ; Decompressor checksum
+ xor ebx, ebx
+ mov si, TC_COM_EXECUTABLE_OFFSET
+ mov cx, TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_LB_SIZE
+ call checksum
+ push ebx
+
+ ; Load compressed boot loader
+ mov bx, TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET
+ mov cl, TC_BOOT_LOADER_START_SECTOR
+ mov al, TC_MAX_BOOT_LOADER_SECTOR_COUNT
+
+ test backup_loader_used, 1
+ jz non_backup
+ mov al, TC_BOOT_LOADER_BACKUP_SECTOR_COUNT - TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT
+ mov cl, TC_BOOT_LOADER_START_SECTOR + TC_BOOT_LOADER_BACKUP_SECTOR_COUNT
+
+non_backup:
+ call read_sectors
+
+ ; Boot loader checksum
+ pop ebx
+ mov si, TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET
+ mov cx, word ptr [start + TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET]
+ call checksum
+
+ ; Verify checksum
+ cmp ebx, dword ptr [start + TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET]
+ je checksum_ok
+
+ ; Checksum incorrect - try using backup if available
+ test backup_loader_used, 1
+ jnz loader_damaged
+
+ mov backup_loader_used, 1
+ mov cl, TC_BOOT_LOADER_DECOMPRESSOR_START_SECTOR + TC_BOOT_LOADER_BACKUP_SECTOR_COUNT
+
+ test TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE, byte ptr [start + TC_BOOT_SECTOR_CONFIG_OFFSET]
+ jnz retry_backup
+
+loader_damaged:
+ lea si, loader_damaged_msg
+ call print
+ lea si, loader_name_msg
+ call print
+ jmp $
+checksum_ok:
+
+ ; Set up decompressor segment
+ mov ax, es
+ mov ds, ax
+ cli
+ mov ss, ax
+ mov sp, TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE
+ sti
+
+ push dx
+
+ ; Decompress boot loader
+ push TC_BOOT_LOADER_COMPRESSED_BUFFER_OFFSET + TC_GZIP_HEADER_SIZE ; Compressed data
+ push TC_MAX_BOOT_LOADER_DECOMPRESSED_SIZE ; Output buffer size
+ push TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE + TC_COM_EXECUTABLE_OFFSET ; Output buffer
+
+ push cs
+ push decompressor_ret
+ push es
+ push TC_COM_EXECUTABLE_OFFSET
+ retf
+decompressor_ret:
+
+ add sp, 6
+ pop dx
+
+ ; Restore boot sector segment
+ push cs
+ pop ds
+
+ ; Check decompression result
+ test ax, ax
+ jz decompression_ok
+
+ lea si, loader_damaged_msg
+ call print
+ jmp $
+decompression_ok:
+
+ ; DH = boot sector flags
+ mov dh, byte ptr [start + TC_BOOT_SECTOR_CONFIG_OFFSET]
+
+ ; Set up boot loader segment
+ mov ax, es
+ add ax, TC_BOOT_LOADER_DECOMPRESSOR_MEMORY_SIZE / 16
+ mov es, ax
+ mov ds, ax
+ cli
+ mov ss, ax
+ mov sp, TC_BOOT_LOADER_STACK_TOP
+ sti
+
+ ; Execute boot loader
+ push es
+ push TC_COM_EXECUTABLE_OFFSET
+ retf
+
+ ; Print string
+print:
+ xor bx, bx
+ mov ah, 0eh
+ cld
+
+@@: lodsb
+ test al, al
+ jz print_end
+
+ int 10h
+ jmp @B
+
+print_end:
+ ret
+
+ ; Read sectors of the first cylinder
+read_sectors:
+ mov ch, 0 ; Cylinder
+ mov dh, 0 ; Head
+ ; DL = drive number passed from BIOS
+ mov ah, 2
+ int 13h
+ jnc read_ok
+
+ lea si, disk_error_msg
+ call print
+read_ok:
+ ret
+
+ ; Calculate checksum
+checksum:
+ push ds
+ push es
+ pop ds
+ xor eax, eax
+ cld
+
+@@: lodsb
+ add ebx, eax
+ rol ebx, 1
+ loop @B
+
+ pop ds
+ ret
+
+backup_loader_used db 0
+
+disk_error_msg db 'Disk error', 13, 10, 7, 0
+loader_damaged_msg db 7, 'Loader damaged! Use Rescue Disk: Repair Options > Restore', 0
+
+ORG 7C00h + 510
+ dw 0AA55h ; Boot sector signature
+
+_TEXT ENDS
+END start
diff --git a/src/Boot/Windows/BootStrings.h b/src/Boot/Windows/BootStrings.h
new file mode 100644
index 00000000..8b6bbbd9
--- /dev/null
+++ b/src/Boot/Windows/BootStrings.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_BootStrings
+#define TC_HEADER_Boot_BootStrings
+
+#define TC_BOOT_STR_ERROR "Error: "
+#define TC_BOOT_STR_NO_BOOT_PARTITION "No bootable partition found"
+#define TC_BOOT_STR_UPGRADE_BIOS "- Upgrade BIOS\r\n- Use a different motherboard model/brand\r\n"
+
+#endif // TC_HEADER_Boot_BootStrings
diff --git a/src/Boot/Windows/Decompressor.c b/src/Boot/Windows/Decompressor.c
new file mode 100644
index 00000000..efdbed91
--- /dev/null
+++ b/src/Boot/Windows/Decompressor.c
@@ -0,0 +1,436 @@
+/*
+ puff.c
+ Copyright (C) 2002-2004 Mark Adler, all rights reserved
+ version 1.8, 9 Jan 2004
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler madler@alumni.caltech.edu
+*/
+
+/* Adapted for TrueCrypt */
+
+
+#define local static /* for local function definitions */
+#define NIL ((unsigned char *)0) /* for no output option */
+
+/*
+ * Maximums for allocations and loops. It is not useful to change these --
+ * they are fixed by the deflate format.
+ */
+#define MAXBITS 15 /* maximum bits in a code */
+#define MAXLCODES 286 /* maximum number of literal/length codes */
+#define MAXDCODES 30 /* maximum number of distance codes */
+#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */
+#define FIXLCODES 288 /* number of fixed literal/length codes */
+
+/* input and output state */
+struct state {
+ /* output state */
+ unsigned char *out; /* output buffer */
+ unsigned int outlen; /* available space at out */
+ unsigned int outcnt; /* bytes written to out so far */
+
+ /* input state */
+ unsigned char *in; /* input buffer */
+ unsigned int incnt; /* bytes read so far */
+ int bitbuf; /* bit buffer */
+ int bitcnt; /* number of bits in bit buffer */
+};
+
+
+local int bits(struct state *s, int need)
+{
+ long val; /* bit accumulator (can use up to 20 bits) */
+
+ /* load at least need bits into val */
+ val = s->bitbuf;
+ while (s->bitcnt < need) {
+ val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */
+ s->bitcnt += 8;
+ }
+
+ /* drop need bits and update buffer, always zero to seven bits left */
+ s->bitbuf = (int)(val >> need);
+ s->bitcnt -= need;
+
+ /* return need bits, zeroing the bits above that */
+ return (int)(val & ((1L << need) - 1));
+}
+
+
+local int stored(struct state *s)
+{
+ unsigned len; /* length of stored block */
+
+ /* discard leftover bits from current byte (assumes s->bitcnt < 8) */
+ s->bitbuf = 0;
+ s->bitcnt = 0;
+
+ /* get length and check against its one's complement */
+ len = s->in[s->incnt++];
+ len |= s->in[s->incnt++] << 8;
+ if (s->in[s->incnt++] != (~len & 0xff) ||
+ s->in[s->incnt++] != ((~len >> 8) & 0xff))
+ return -2; /* didn't match complement! */
+
+ /* copy len bytes from in to out */
+ if (s->out != NIL) {
+ if (s->outcnt + len > s->outlen)
+ return 1; /* not enough output space */
+ while (len--)
+ s->out[s->outcnt++] = s->in[s->incnt++];
+ }
+ else { /* just scanning */
+ s->outcnt += len;
+ s->incnt += len;
+ }
+
+ /* done with a valid stored block */
+ return 0;
+}
+
+
+struct huffman {
+ short *count; /* number of symbols of each length */
+ short *symbol; /* canonically ordered symbols */
+};
+
+
+#ifdef SLOW
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+
+ code = first = index = 0;
+ for (len = 1; len <= MAXBITS; len++) {
+ code |= bits(s, 1); /* get next bit */
+ count = h->count[len];
+ if (code < first + count) /* if length len, return symbol */
+ return h->symbol[index + (code - first)];
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ }
+ return -9; /* ran out of codes */
+}
+
+/*
+ * A faster version of decode() for real applications of this code. It's not
+ * as readable, but it makes puff() twice as fast. And it only makes the code
+ * a few percent larger.
+ */
+#else /* !SLOW */
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+ int bitbuf; /* bits from stream */
+ int left; /* bits left in next or left to process */
+ short *next; /* next number of codes */
+
+ bitbuf = s->bitbuf;
+ left = s->bitcnt;
+ code = first = index = 0;
+ len = 1;
+ next = h->count + 1;
+ while (1) {
+ while (left--) {
+ code |= bitbuf & 1;
+ bitbuf >>= 1;
+ count = *next++;
+ if (code < first + count) { /* if length len, return symbol */
+ s->bitbuf = bitbuf;
+ s->bitcnt = (s->bitcnt - len) & 7;
+ return h->symbol[index + (code - first)];
+ }
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ len++;
+ }
+ left = (MAXBITS+1) - len;
+ if (left == 0) break;
+ bitbuf = s->in[s->incnt++];
+ if (left > 8) left = 8;
+ }
+ return -9; /* ran out of codes */
+}
+#endif /* SLOW */
+
+
+local int construct(struct huffman *h, short *length, int n)
+{
+ int symbol; /* current symbol when stepping through length[] */
+ int len; /* current length when stepping through h->count[] */
+ int left; /* number of possible codes left of current length */
+ short offs[MAXBITS+1]; /* offsets in symbol table for each length */
+
+ /* count number of codes of each length */
+ for (len = 0; len <= MAXBITS; len++)
+ h->count[len] = 0;
+ for (symbol = 0; symbol < n; symbol++)
+ (h->count[length[symbol]])++; /* assumes lengths are within bounds */
+ if (h->count[0] == n) /* no codes! */
+ return 0; /* complete, but decode() will fail */
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1; /* one possible code of zero length */
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1; /* one more bit, double codes left */
+ left -= h->count[len]; /* deduct count from possible codes */
+ if (left < 0) return left; /* over-subscribed--return negative */
+ } /* left > 0 means incomplete */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + h->count[len];
+
+ /*
+ * put symbols in table sorted by length, by symbol order within each
+ * length
+ */
+ for (symbol = 0; symbol < n; symbol++)
+ if (length[symbol] != 0)
+ h->symbol[offs[length[symbol]]++] = symbol;
+
+ /* return zero for complete set, positive for incomplete set */
+ return left;
+}
+
+
+local int codes(struct state *s,
+ struct huffman *lencode,
+ struct huffman *distcode)
+{
+ int symbol; /* decoded symbol */
+ int len; /* length for copy */
+ unsigned dist; /* distance for copy */
+ static const short lens[29] = { /* Size base for length codes 257..285 */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258};
+ static const short lext[29] = { /* Extra bits for length codes 257..285 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
+ static const short dists[30] = { /* Offset base for distance codes 0..29 */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577};
+ static const short dext[30] = { /* Extra bits for distance codes 0..29 */
+ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
+ 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13};
+
+ /* decode literals and length/distance pairs */
+ do {
+ symbol = decode(s, lencode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ if (symbol < 256) { /* literal: symbol is the byte */
+ /* write out the literal */
+ if (s->out != NIL) {
+ if (s->outcnt == s->outlen) return 1;
+ s->out[s->outcnt] = symbol;
+ }
+ s->outcnt++;
+ }
+ else if (symbol > 256) { /* length */
+ /* get and compute length */
+ symbol -= 257;
+ if (symbol >= 29) return -9; /* invalid fixed code */
+ len = lens[symbol] + bits(s, lext[symbol]);
+
+ /* get and check distance */
+ symbol = decode(s, distcode);
+ if (symbol < 0) return symbol; /* invalid symbol */
+ dist = dists[symbol] + bits(s, dext[symbol]);
+ if (dist > s->outcnt)
+ return -10; /* distance too far back */
+
+ /* copy length bytes from distance bytes back */
+ if (s->out != NIL) {
+ if (s->outcnt + len > s->outlen) return 1;
+ while (len--) {
+ s->out[s->outcnt] = s->out[s->outcnt - dist];
+ s->outcnt++;
+ }
+ }
+ else
+ s->outcnt += len;
+ }
+ } while (symbol != 256); /* end of block symbol */
+
+ /* done with a valid fixed or dynamic block */
+ return 0;
+}
+
+
+local int fixed(struct state *s)
+{
+ static int virgin = 1;
+ static short lencnt[MAXBITS+1], lensym[FIXLCODES];
+ static short distcnt[MAXBITS+1], distsym[MAXDCODES];
+ static struct huffman lencode = {lencnt, lensym};
+ static struct huffman distcode = {distcnt, distsym};
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ int symbol;
+ short lengths[FIXLCODES];
+
+ /* literal/length table */
+ for (symbol = 0; symbol < 144; symbol++)
+ lengths[symbol] = 8;
+ for (; symbol < 256; symbol++)
+ lengths[symbol] = 9;
+ for (; symbol < 280; symbol++)
+ lengths[symbol] = 7;
+ for (; symbol < FIXLCODES; symbol++)
+ lengths[symbol] = 8;
+ construct(&lencode, lengths, FIXLCODES);
+
+ /* distance table */
+ for (symbol = 0; symbol < MAXDCODES; symbol++)
+ lengths[symbol] = 5;
+ construct(&distcode, lengths, MAXDCODES);
+
+ /* do this just once */
+ virgin = 0;
+ }
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+
+local int dynamic(struct state *s)
+{
+ int nlen, ndist, ncode; /* number of lengths in descriptor */
+ int index; /* index of lengths[] */
+ int err; /* construct() return value */
+ short lengths[MAXCODES]; /* descriptor code lengths */
+ short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */
+ short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */
+ struct huffman lencode = {lencnt, lensym}; /* length code */
+ struct huffman distcode = {distcnt, distsym}; /* distance code */
+ static const short order[19] = /* permutation of code length codes */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* get number of lengths in each table, check lengths */
+ nlen = bits(s, 5) + 257;
+ ndist = bits(s, 5) + 1;
+ ncode = bits(s, 4) + 4;
+ if (nlen > MAXLCODES || ndist > MAXDCODES)
+ return -3; /* bad counts */
+
+ /* read code length code lengths (really), missing lengths are zero */
+ for (index = 0; index < ncode; index++)
+ lengths[order[index]] = bits(s, 3);
+ for (; index < 19; index++)
+ lengths[order[index]] = 0;
+
+ /* build huffman table for code lengths codes (use lencode temporarily) */
+ err = construct(&lencode, lengths, 19);
+ if (err != 0) return -4; /* require complete code set here */
+
+ /* read length/literal and distance code length tables */
+ index = 0;
+ while (index < nlen + ndist) {
+ int symbol; /* decoded value */
+ int len; /* last length to repeat */
+
+ symbol = decode(s, &lencode);
+ if (symbol < 16) /* length in 0..15 */
+ lengths[index++] = symbol;
+ else { /* repeat instruction */
+ len = 0; /* assume repeating zeros */
+ if (symbol == 16) { /* repeat last length 3..6 times */
+ if (index == 0) return -5; /* no last length! */
+ len = lengths[index - 1]; /* last length */
+ symbol = 3 + bits(s, 2);
+ }
+ else if (symbol == 17) /* repeat zero 3..10 times */
+ symbol = 3 + bits(s, 3);
+ else /* == 18, repeat zero 11..138 times */
+ symbol = 11 + bits(s, 7);
+ if (index + symbol > nlen + ndist)
+ return -6; /* too many lengths! */
+ while (symbol--) /* repeat last or zero symbol times */
+ lengths[index++] = len;
+ }
+ }
+
+ /* build huffman table for literal/length codes */
+ err = construct(&lencode, lengths, nlen);
+ if (err < 0 || (err > 0 && nlen - lencode.count[0] != 1))
+ return -7; /* only allow incomplete codes if just one code */
+
+ /* build huffman table for distance codes */
+ err = construct(&distcode, lengths + nlen, ndist);
+ if (err < 0 || (err > 0 && ndist - distcode.count[0] != 1))
+ return -8; /* only allow incomplete codes if just one code */
+
+ /* decode data until end-of-block code */
+ return codes(s, &lencode, &distcode);
+}
+
+
+void _acrtused () { }
+
+// Decompress deflated data
+int far main (
+ unsigned char *dest, /* pointer to destination pointer */
+ unsigned int destlen, /* amount of output space */
+ unsigned char *source) /* pointer to source data pointer */
+{
+ struct state s; /* input/output state */
+ int last, type; /* block information */
+ int err; /* return value */
+
+ /* initialize output state */
+ s.out = dest;
+ s.outlen = destlen; /* ignored if dest is NIL */
+ s.outcnt = 0;
+
+ /* initialize input state */
+ s.in = source;
+ s.incnt = 0;
+ s.bitbuf = 0;
+ s.bitcnt = 0;
+
+ /* process blocks until last block or error */
+ do {
+ last = bits(&s, 1); /* one if last block */
+ type = bits(&s, 2); /* block type 0..3 */
+ err = type == 0 ? stored(&s) :
+ (type == 1 ? fixed(&s) :
+ (type == 2 ? dynamic(&s) :
+ -1)); /* type == 3, invalid */
+ if (err != 0) break; /* return with error */
+ } while (!last);
+
+ return err;
+}
diff --git a/src/Boot/Windows/IntFilter.cpp b/src/Boot/Windows/IntFilter.cpp
new file mode 100644
index 00000000..cd0ea574
--- /dev/null
+++ b/src/Boot/Windows/IntFilter.cpp
@@ -0,0 +1,641 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "Platform.h"
+#include "BootMemory.h"
+#include "BootConfig.h"
+#include "BootConsoleIo.h"
+#include "BootDebug.h"
+#include "BootDefs.h"
+#include "BootDiskIo.h"
+#include "BootEncryptedIo.h"
+#include "BootStrings.h"
+#include "IntFilter.h"
+
+static uint32 OriginalInt13Handler;
+static uint32 OriginalInt15Handler;
+
+static Registers IntRegisters;
+
+
+bool Int13Filter ()
+{
+ CheckStack();
+
+ Registers regs;
+ memcpy (&regs, &IntRegisters, sizeof (regs));
+ __asm sti
+
+ static int ReEntryCount = -1;
+ ++ReEntryCount;
+
+ byte function = (byte) (regs.AX >> 8);
+
+#ifdef TC_TRACE_INT13
+ DisableScreenOutput();
+
+ PrintHex (function);
+
+ Print (" EN:"); Print (ReEntryCount);
+ Print (" SS:"); PrintHex (regs.SS);
+
+ uint16 spdbg;
+ __asm mov spdbg, sp
+ PrintChar (' ');
+ PrintHex (spdbg);
+ PrintChar ('<'); PrintHex (TC_BOOT_LOADER_STACK_TOP);
+
+#endif
+
+ bool passOriginalRequest = true;
+
+ switch (function)
+ {
+ case 0x2: // Read sectors
+ case 0x3: // Write sectors
+ {
+ byte drive = (byte) regs.DX;
+
+ ChsAddress chs;
+ chs.Cylinder = ((regs.CX << 2) & 0x300) | (regs.CX >> 8);
+ chs.Head = regs.DX >> 8;
+ chs.Sector = regs.CX & 0x3f;
+
+ byte sectorCount = (byte) regs.AX;
+
+#ifdef TC_TRACE_INT13
+ PrintVal (": Drive", drive - TC_FIRST_BIOS_DRIVE, false);
+ Print (" Chs: "); Print (chs);
+#endif
+
+ uint64 sector;
+ if (drive == BootDrive)
+ {
+ if (!BootDriveGeometryValid)
+ TC_THROW_FATAL_EXCEPTION;
+
+ ChsToLba (BootDriveGeometry, chs, sector);
+#ifdef TC_TRACE_INT13
+ PrintVal (" Sec", sector.LowPart, false);
+#endif
+ }
+
+#ifdef TC_TRACE_INT13
+ PrintVal (" Count", sectorCount, false);
+ Print (" Buf: "); PrintHex (regs.ES); PrintChar (':'); PrintHex (regs.BX);
+ PrintEndl();
+#endif
+
+ if (ReEntryCount == 0 && drive == EncryptedVirtualPartition.Drive)
+ {
+ BiosResult result;
+
+ if (function == 0x3)
+ result = WriteEncryptedSectors (regs.ES, regs.BX, drive, sector, sectorCount);
+ else
+ result = ReadEncryptedSectors (regs.ES, regs.BX, drive, sector, sectorCount);
+
+ __asm cli
+
+ memcpy (&IntRegisters, &regs, sizeof (regs));
+ IntRegisters.AX = (uint16) result << 8;
+
+ if (result == BiosResultSuccess)
+ {
+ IntRegisters.AX |= sectorCount;
+ IntRegisters.Flags &= ~TC_X86_CARRY_FLAG;
+ }
+ else
+ IntRegisters.Flags |= TC_X86_CARRY_FLAG;
+
+ passOriginalRequest = false;
+ }
+ }
+ break;
+
+ case 0x42: // Read sectors LBA
+ case 0x43: // Write sectors LBA
+ {
+ byte drive = (byte) regs.DX;
+
+ BiosLbaPacket lba;
+ CopyMemory (regs.DS, regs.SI, (byte *) &lba, sizeof (lba));
+
+#ifdef TC_TRACE_INT13
+ PrintVal (": Drive", drive - TC_FIRST_BIOS_DRIVE, false);
+ PrintVal (" Sec", lba.Sector.LowPart, false);
+ PrintVal (" Count", lba.SectorCount, false);
+ PrintVal (" Buf", lba.Buffer, false, true);
+ PrintEndl();
+#endif
+
+ if (ReEntryCount == 0 && drive == EncryptedVirtualPartition.Drive)
+ {
+ BiosResult result;
+
+ uint16 segment = (uint16) (lba.Buffer >> 16);
+ uint16 offset = (uint16) lba.Buffer;
+
+ if (function == 0x43)
+ result = WriteEncryptedSectors (segment, offset, drive, lba.Sector, lba.SectorCount);
+ else
+ result = ReadEncryptedSectors (segment, offset, drive, lba.Sector, lba.SectorCount);
+
+ __asm cli
+
+ memcpy (&IntRegisters, &regs, sizeof (regs));
+ IntRegisters.AX = (IntRegisters.AX & 0xff) | ((uint16) result << 8);
+
+ if (result == BiosResultSuccess)
+ IntRegisters.Flags &= ~TC_X86_CARRY_FLAG;
+ else
+ IntRegisters.Flags |= TC_X86_CARRY_FLAG;
+
+ passOriginalRequest = false;
+ }
+ }
+ break;
+
+ default:
+#ifdef TC_TRACE_INT13
+ PrintEndl();
+#endif
+ break;
+ }
+
+#ifdef TC_TRACE_INT13
+ EnableScreenOutput();
+#endif
+ --ReEntryCount;
+
+ return passOriginalRequest;
+}
+
+
+#define TC_MAX_MEMORY_MAP_SIZE 80
+
+BiosMemoryMapEntry BiosMemoryMap[TC_MAX_MEMORY_MAP_SIZE];
+static size_t BiosMemoryMapSize;
+
+
+static void CreateBootLoaderMemoryMapEntry (BiosMemoryMapEntry *newMapEntry, uint32 bootLoaderStart)
+{
+ newMapEntry->Type = 0x2;
+ newMapEntry->BaseAddress.HighPart = 0;
+ newMapEntry->BaseAddress.LowPart = bootLoaderStart;
+ newMapEntry->Length.HighPart = 0;
+ newMapEntry->Length.LowPart = TC_BOOT_MEMORY_REQUIRED * 1024UL;
+}
+
+
+static bool CreateNewBiosMemoryMap ()
+{
+ // Create a new BIOS memory map presenting the memory area of the loader as reserved
+
+ BiosMemoryMapSize = 0;
+ BiosMemoryMapEntry entry;
+ BiosMemoryMapEntry *newMapEntry = BiosMemoryMap;
+
+ const BiosMemoryMapEntry *mapEnd = BiosMemoryMap + TC_MAX_MEMORY_MAP_SIZE;
+
+ uint64 bootLoaderStart;
+ bootLoaderStart.HighPart = 0;
+
+ uint16 codeSeg;
+ __asm mov codeSeg, cs
+ bootLoaderStart.LowPart = GetLinearAddress (codeSeg, 0);
+
+ uint64 bootLoaderEnd;
+ bootLoaderEnd.HighPart = 0;
+ bootLoaderEnd.LowPart = bootLoaderStart.LowPart + TC_BOOT_MEMORY_REQUIRED * 1024UL;
+
+ bool loaderEntryInserted = false;
+
+ if (GetFirstBiosMemoryMapEntry (entry))
+ {
+ do
+ {
+ uint64 entryEnd = entry.BaseAddress + entry.Length;
+
+ if (entry.Type == 0x1 && RegionsIntersect (bootLoaderStart, TC_BOOT_MEMORY_REQUIRED * 1024UL, entry.BaseAddress, entryEnd - 1))
+ {
+ // Free map entry covers the boot loader area
+
+ if (entry.BaseAddress < bootLoaderStart)
+ {
+ // Create free entry below the boot loader area
+ if (newMapEntry >= mapEnd)
+ goto mapOverflow;
+
+ *newMapEntry = entry;
+ newMapEntry->Length = bootLoaderStart - entry.BaseAddress;
+ ++newMapEntry;
+ }
+
+ if (!loaderEntryInserted)
+ {
+ // Create reserved entry for the boot loader if it has not been done yet
+ if (newMapEntry >= mapEnd)
+ goto mapOverflow;
+
+ CreateBootLoaderMemoryMapEntry (newMapEntry, bootLoaderStart.LowPart);
+ ++newMapEntry;
+ loaderEntryInserted = true;
+ }
+
+ if (bootLoaderEnd < entryEnd)
+ {
+ // Create free entry above the boot loader area
+ if (newMapEntry >= mapEnd)
+ goto mapOverflow;
+
+ newMapEntry->Type = 0x1;
+ newMapEntry->BaseAddress = bootLoaderEnd;
+ newMapEntry->Length = entryEnd - bootLoaderEnd;
+ ++newMapEntry;
+ }
+ }
+ else
+ {
+ if (newMapEntry >= mapEnd)
+ goto mapOverflow;
+
+ if (!loaderEntryInserted && entry.BaseAddress > bootLoaderStart)
+ {
+ // Create reserved entry for the boot loader if it has not been done yet
+ CreateBootLoaderMemoryMapEntry (newMapEntry, bootLoaderStart.LowPart);
+ ++newMapEntry;
+ loaderEntryInserted = true;
+ }
+
+ // Copy map entry
+ *newMapEntry++ = entry;
+ }
+
+ } while (GetNextBiosMemoryMapEntry (entry));
+ }
+
+ BiosMemoryMapSize = newMapEntry - BiosMemoryMap;
+ return true;
+
+mapOverflow:
+ size_t overSize = 0;
+ while (GetNextBiosMemoryMapEntry (entry))
+ {
+ ++overSize;
+ }
+
+ PrintErrorNoEndl ("MMP:");
+ Print (overSize);
+ PrintEndl();
+
+ return false;
+}
+
+
+bool Int15Filter ()
+{
+ CheckStack();
+
+#ifdef TC_TRACE_INT15
+ DisableScreenOutput();
+
+ Print ("15-");
+ PrintHex (IntRegisters.AX);
+
+ Print (" SS:"); PrintHex (IntRegisters.SS);
+
+ uint16 spdbg;
+ __asm mov spdbg, sp
+ PrintChar (' ');
+ PrintHex (spdbg);
+ PrintChar ('<'); PrintHex (TC_BOOT_LOADER_STACK_TOP);
+
+ Print (" EAX:"); PrintHex (IntRegisters.EAX);
+ Print (" EBX:"); PrintHex (IntRegisters.EBX);
+ Print (" ECX:"); PrintHex (IntRegisters.ECX);
+ Print (" EDX:"); PrintHex (IntRegisters.EDX);
+ Print (" DI:"); PrintHex (IntRegisters.DI);
+ PrintEndl();
+
+#endif
+
+ if (IntRegisters.EBX >= BiosMemoryMapSize)
+ {
+ IntRegisters.Flags |= TC_X86_CARRY_FLAG;
+ IntRegisters.EBX = 0;
+ IntRegisters.AX = -1;
+ }
+ else
+ {
+ CopyMemory ((byte *) &BiosMemoryMap[IntRegisters.EBX], IntRegisters.ES, IntRegisters.DI, sizeof (BiosMemoryMap[0]));
+
+ IntRegisters.Flags &= ~TC_X86_CARRY_FLAG;
+ IntRegisters.EAX = 0x534D4150UL;
+
+ ++IntRegisters.EBX;
+ if (IntRegisters.EBX >= BiosMemoryMapSize)
+ IntRegisters.EBX = 0;
+
+ IntRegisters.ECX = sizeof (BiosMemoryMap[0]);
+ }
+
+ if (IntRegisters.EBX == 0 && !(BootSectorFlags & TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER))
+ {
+ // Uninstall filter when the modified map has been issued three times to prevent
+ // problems with hardware drivers on some notebooks running Windows XP.
+
+ static int CompleteMapIssueCount = 0;
+ if (++CompleteMapIssueCount >= 3)
+ {
+ __asm
+ {
+ cli
+ push es
+
+ lea si, OriginalInt15Handler
+ xor ax, ax
+ mov es, ax
+ mov di, 0x15 * 4
+
+ mov ax, [si]
+ mov es:[di], ax
+ mov ax, [si + 2]
+ mov es:[di + 2], ax
+
+ pop es
+ sti
+ }
+ }
+ }
+
+#ifdef TC_TRACE_INT15
+ BiosMemoryMapEntry entry;
+ CopyMemory (IntRegisters.ES, IntRegisters.DI, (byte *) &entry, sizeof (entry));
+ PrintHex (entry.Type); PrintChar (' ');
+ PrintHex (entry.BaseAddress); PrintChar (' ');
+ PrintHex (entry.Length); PrintChar (' ');
+ PrintHex (entry.BaseAddress + entry.Length); PrintEndl();
+
+ Print ("EAX:"); PrintHex (IntRegisters.EAX);
+ Print (" EBX:"); PrintHex (IntRegisters.EBX);
+ Print (" ECX:"); PrintHex (IntRegisters.ECX);
+ Print (" EDX:"); PrintHex (IntRegisters.EDX);
+ Print (" DI:"); PrintHex (IntRegisters.DI);
+ Print (" FL:"); PrintHex (IntRegisters.Flags);
+ PrintEndl (2);
+#endif
+
+#ifdef TC_TRACE_INT15
+ EnableScreenOutput();
+#endif
+ return false;
+}
+
+
+void IntFilterEntry ()
+{
+ // No automatic variables should be used in this scope as SS may change
+ static uint16 OrigStackPointer;
+ static uint16 OrigStackSegment;
+
+ __asm
+ {
+ pushf
+ pushad
+
+ cli
+ mov cs:IntRegisters.DI, di
+
+ lea di, cs:IntRegisters.EAX
+ TC_ASM_EMIT4 (66,2E,89,05) // mov [cs:di], eax
+ lea di, cs:IntRegisters.EBX
+ TC_ASM_EMIT4 (66,2E,89,1D) // mov [cs:di], ebx
+ lea di, cs:IntRegisters.ECX
+ TC_ASM_EMIT4 (66,2E,89,0D) // mov [cs:di], ecx
+ lea di, cs:IntRegisters.EDX
+ TC_ASM_EMIT4 (66,2E,89,15) // mov [cs:di], edx
+
+ mov ax, [bp + 8]
+ mov cs:IntRegisters.Flags, ax
+
+ mov cs:IntRegisters.SI, si
+ mov si, [bp + 2] // Int number
+
+ mov cs:IntRegisters.DS, ds
+ mov cs:IntRegisters.ES, es
+ mov cs:IntRegisters.SS, ss
+
+ // Compiler assumes SS == DS - use our stack if this condition is not met
+ mov ax, ss
+ mov bx, cs
+ cmp ax, bx
+ jz stack_ok
+
+ mov cs:OrigStackPointer, sp
+ mov cs:OrigStackSegment, ss
+ mov ax, cs
+ mov ss, ax
+ mov sp, TC_BOOT_LOADER_STACK_TOP
+
+ stack_ok:
+ // DS = CS
+ push ds
+ push es
+ mov ax, cs
+ mov ds, ax
+ mov es, ax
+
+ push si // Int number
+
+ // Filter request
+ cmp si, 0x15
+ je filter15
+ cmp si, 0x13
+ jne $
+
+ call Int13Filter
+ jmp s0
+
+ filter15:
+ call Int15Filter
+
+ s0:
+ pop si // Int number
+ pop es
+ pop ds
+
+ // Restore original SS:SP if our stack is empty
+ cli
+ mov bx, TC_BOOT_LOADER_STACK_TOP
+ cmp bx, sp
+ jnz stack_in_use
+
+ mov ss, cs:OrigStackSegment
+ mov sp, cs:OrigStackPointer
+ stack_in_use:
+
+ test ax, ax // passOriginalRequest
+ jnz pass_request
+
+ // Return results of filtered request
+ popad
+ popf
+ mov ax, cs:IntRegisters.Flags
+ mov [bp + 8], ax
+ leave
+
+ lea di, cs:IntRegisters.EAX
+ TC_ASM_EMIT4 (66,2E,8B,05) // mov eax, [cs:di]
+ lea di, cs:IntRegisters.EBX
+ TC_ASM_EMIT4 (66,2E,8B,1D) // mov ebx, [cs:di]
+ lea di, cs:IntRegisters.ECX
+ TC_ASM_EMIT4 (66,2E,8B,0D) // mov ecx, [cs:di]
+ lea di, cs:IntRegisters.EDX
+ TC_ASM_EMIT4 (66,2E,8B,15) // mov edx, [cs:di]
+
+ mov di, cs:IntRegisters.DI
+ mov si, cs:IntRegisters.SI
+ mov es, cs:IntRegisters.ES
+ mov ds, cs:IntRegisters.DS
+
+ sti
+ add sp, 2
+ iret
+
+ // Pass original request
+ pass_request:
+ sti
+ cmp si, 0x15
+ je pass15
+ cmp si, 0x13
+ jne $
+
+ popad
+ popf
+ leave
+ add sp, 2
+ jmp cs:OriginalInt13Handler
+
+ pass15:
+ popad
+ popf
+ leave
+ add sp, 2
+ jmp cs:OriginalInt15Handler
+ }
+}
+
+
+void Int13FilterEntry ()
+{
+ __asm
+ {
+ leave
+ push 0x13
+ jmp IntFilterEntry
+ }
+}
+
+
+static void Int15FilterEntry ()
+{
+ __asm
+ {
+ pushf
+ cmp ax, 0xe820 // Get system memory map
+ je filter
+
+ popf
+ leave
+ jmp cs:OriginalInt15Handler
+
+ filter:
+ leave
+ push 0x15
+ jmp IntFilterEntry
+ }
+}
+
+
+bool InstallInterruptFilters ()
+{
+
+#ifndef TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+
+ // If the filters have already been installed, it usually indicates stack corruption
+ // and a consequent reentry of this routine without a system reset.
+
+ uint32 currentInt13Handler;
+ CopyMemory (0, 0x13 * 4, &currentInt13Handler, sizeof (currentInt13Handler));
+
+ if (currentInt13Handler == (uint32) Int13FilterEntry)
+ {
+ PrintError ("Memory corrupted");
+ Print (TC_BOOT_STR_UPGRADE_BIOS);
+
+ GetKeyboardChar();
+ return true;
+ }
+
+#endif
+
+ if (!CreateNewBiosMemoryMap())
+ return false;
+
+ __asm
+ {
+ cli
+ push es
+
+ // Save original INT 13 handler
+ xor ax, ax
+ mov es, ax
+
+ mov si, 0x13 * 4
+ lea di, OriginalInt13Handler
+
+ mov ax, es:[si]
+ mov [di], ax
+ mov ax, es:[si + 2]
+ mov [di + 2], ax
+
+ // Install INT 13 filter
+ lea ax, Int13FilterEntry
+ mov es:[si], ax
+ mov es:[si + 2], cs
+
+ // Save original INT 15 handler
+ mov si, 0x15 * 4
+ lea di, OriginalInt15Handler
+
+ mov ax, es:[si]
+ mov [di], ax
+ mov ax, es:[si + 2]
+ mov [di + 2], ax
+
+ // Install INT 15 filter
+ lea ax, Int15FilterEntry
+ mov es:[si], ax
+ mov es:[si + 2], cs
+
+ // If the BIOS does not support system memory map (INT15 0xe820),
+ // set amount of available memory to CS:0000 - 0:0000
+ cmp BiosMemoryMapSize, 1
+ jg mem_map_ok
+ mov ax, cs
+ shr ax, 10 - 4 // CS * 16 / 1024
+ mov es:[0x413], ax // = KBytes available
+ mem_map_ok:
+
+ pop es
+ sti
+ }
+
+ return true;
+}
diff --git a/src/Boot/Windows/IntFilter.h b/src/Boot/Windows/IntFilter.h
new file mode 100644
index 00000000..b2e5c5d8
--- /dev/null
+++ b/src/Boot/Windows/IntFilter.h
@@ -0,0 +1,16 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_IntFilter
+#define TC_HEADER_Boot_IntFilter
+
+#include "Platform.h"
+
+bool InstallInterruptFilters ();
+
+#endif TC_HEADER_Boot_IntFilter
diff --git a/src/Boot/Windows/Makefile b/src/Boot/Windows/Makefile
new file mode 100644
index 00000000..737fbe5f
--- /dev/null
+++ b/src/Boot/Windows/Makefile
@@ -0,0 +1,184 @@
+#
+# Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved.
+#
+# 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.
+#
+
+PROJ = BootLoader
+.SILENT:
+
+!ifndef MSVC16_ROOT
+!error Environment variable MSVC16_ROOT must point to the installation directory of MS Visual C++ 1.5
+!endif
+
+ENVPATH = $(PATH)
+
+CC = $(MSVC16_ROOT)\bin\cl.exe
+LD = $(MSVC16_ROOT)\bin\link.exe
+
+AFLAGS = /nologo /omf
+
+CFLAGS = /nologo /W3 /Fc /I "$(MSVC16_ROOT)\Include" /I"..\..\.." /I"..\..\..\Common" /I"..\..\..\Crypto"
+CFLAGS = $(CFLAGS) /D __int8=char /D __int16=int /D __int32=long /D BOOL=char /D FALSE=0 /D TRUE=1
+CFLAGS = $(CFLAGS) /D LITTLE_ENDIAN=1234 /D BYTE_ORDER=1234 /D TC_WINDOWS_BOOT /D TC_MINIMIZE_CODE_SIZE /D TC_NO_COMPILER_INT64
+CFLAGS = $(CFLAGS) /D malloc=malloc_NA
+
+LFLAGS = /NOLOGO /ONERROR:NOEXE /NOI /BATCH
+
+OBJDIR = Release
+
+!ifdef RESCUE_DISK
+OBJDIR = Rescue
+CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_RESCUE_DISK_MODE
+!endif
+
+!ifdef SINGLE_CIPHER
+OBJDIR = $(OBJDIR)_$(SINGLE_CIPHER)
+CFLAGS = $(CFLAGS) /D TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE /D TC_WINDOWS_BOOT_$(SINGLE_CIPHER)
+!endif
+
+OUTDIR = $(OBJDIR)
+TARGETEXT = com
+TARGETS = $(OUTDIR)\BootDefs.i $(OUTDIR)\BootSector.bin $(OUTDIR)\Decompressor.com
+CFLAGS = $(CFLAGS) /AT /Zl /f- /G3 /Oe /Os /Ob1 /OV0 /Gs /Gf /Gy /D NDEBUG
+LFLAGS = $(LFLAGS) /NOD /NOE /TINY
+OBJS = $(OUTDIR)\BootCrt.obj
+LIBS = slibce
+
+!if 1
+SRCDIR = ..
+!else
+SRCDIR = $(MAKEDIR)
+!endif
+
+TARGETS = $(TARGETS) $(OUTDIR)\$(PROJ).$(TARGETEXT)
+
+OBJS = $(OBJS) $(OUTDIR)\BootConfig.obj
+OBJS = $(OBJS) $(OUTDIR)\BootConsoleIo.obj
+OBJS = $(OBJS) $(OUTDIR)\BootDebug.obj
+OBJS = $(OBJS) $(OUTDIR)\BootDiskIo.obj
+OBJS = $(OBJS) $(OUTDIR)\BootEncryptedIo.obj
+OBJS = $(OBJS) $(OUTDIR)\BootMain.obj
+OBJS = $(OBJS) $(OUTDIR)\BootMemory.obj
+OBJS = $(OBJS) $(OUTDIR)\IntFilter.obj
+OBJS = $(OBJS) $(OUTDIR)\Platform.obj
+
+OBJS = $(OBJS) $(OUTDIR)\Crc.obj
+OBJS = $(OBJS) $(OUTDIR)\Crypto.obj
+OBJS = $(OBJS) $(OUTDIR)\Endian.obj
+OBJS = $(OBJS) $(OUTDIR)\Pkcs5.obj
+OBJS = $(OBJS) $(OUTDIR)\Volumes.obj
+OBJS = $(OBJS) $(OUTDIR)\Xts.obj
+
+OBJS = $(OBJS) $(OUTDIR)\Rmd160.obj
+
+!if !DEFINED (SINGLE_CIPHER)
+OBJS = $(OBJS) $(OUTDIR)\AesSmall.obj
+!else if "$(SINGLE_CIPHER)" == "AES"
+OBJS = $(OBJS) $(OUTDIR)\Aes_hw_cpu.obj
+OBJS = $(OBJS) $(OUTDIR)\AesSmall_x86.obj
+OBJS = $(OBJS) $(OUTDIR)\Aestab.obj
+!endif
+
+!if !DEFINED (SINGLE_CIPHER) || "$(SINGLE_CIPHER)" == "SERPENT"
+OBJS = $(OBJS) $(OUTDIR)\Serpent.obj
+!endif
+
+!if !DEFINED (SINGLE_CIPHER) || "$(SINGLE_CIPHER)" == "TWOFISH"
+OBJS = $(OBJS) $(OUTDIR)\Twofish.obj
+!endif
+
+
+all: env $(TARGETS)
+
+env:
+ set INCLUDE=.
+ set LIB=.
+ set LIBPATH=.
+
+clean:
+ -del /q /s $(OBJDIR) >NUL:
+
+
+.asm{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ $(AS) $(AFLAGS) /c "$(SRCDIR)\$<"
+ cd ..
+
+{..\..\Crypto}.asm{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ echo $(<F)
+ nasm.exe -Xvc -f obj -Ox -o "$(<B).obj" -l "$(<B).lst" "$(SRCDIR)\$<"
+ cd ..
+
+{..\..\Crypto}.c{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /c "$(SRCDIR)\$<"
+ set PATH=$(ENVPATH)
+ cd ..
+
+{..\..\Common}.c{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /c "$(SRCDIR)\$<"
+ set PATH=$(ENVPATH)
+ cd ..
+
+.c{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /c "$(SRCDIR)\$<"
+ set PATH=$(ENVPATH)
+ cd ..
+
+.cpp{$(OUTDIR)}.obj:
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /c "$(SRCDIR)\$<"
+ set PATH=$(ENVPATH)
+ cd ..
+
+$(OUTDIR)\BootDefs.i: BootDefs.h
+ cd $(OBJDIR)
+ set PATH=.
+ $(CC) $(CFLAGS) /D TC_ASM_PREPROCESS /P /EP "$(SRCDIR)\BootDefs.h"
+ set PATH=$(ENVPATH)
+ cd ..
+
+$(OUTDIR)\BootSector.bin: $(OUTDIR)\BootSector.obj
+ cd $(OBJDIR)
+ $(LD) $(LFLAGS) BootSector.obj,BootSector.bin,,,, >NUL:
+ -dd.exe conv=notrunc bs=512 if=BootSector.bin of=$(PROJ).flp 2>NUL:
+ cd ..
+
+$(OUTDIR)\Decompressor.com: $(OUTDIR)\BootCrt.obj $(OUTDIR)\Decompressor.obj
+ cd $(OBJDIR)
+ $(LD) $(LFLAGS) BootCrt.obj Decompressor.obj,Decompressor.com,Decompressor.map,$(MSVC16_ROOT)\lib\+slibce,,
+ -dd.exe conv=notrunc,sync bs=512 seek=1 if=Decompressor.com of=$(PROJ).flp 2>NUL:
+ cd ..
+
+$(OUTDIR)\$(PROJ).$(TARGETEXT): $(OBJS)
+ @echo Linking...
+ cd $(OBJDIR)
+
+ echo >NUL: @<<$(PROJ).crf2
+
+$(PROJ).$(TARGETEXT)
+$(PROJ).map
+$(MSVC16_ROOT)\lib\+
+$(LIBS)
+;
+<<
+ del $(PROJ).crf >NUL: 2>NUL:
+ for %F in ($(**F)) do @echo %F + >>$(PROJ).crf
+ type $(PROJ).crf2 >>$(PROJ).crf
+
+ $(LD) $(LFLAGS) @$(PROJ).crf
+ del $(PROJ).crf $(PROJ).crf2
+
+ gzip.exe -c -n --best $(PROJ).$(TARGETEXT) >$(PROJ).$(TARGETEXT).gz
+ -dd.exe conv=notrunc,sync bs=512 seek=5 if=$(PROJ).$(TARGETEXT).gz of=$(PROJ).flp 2>NUL:
+ cd ..
diff --git a/src/Boot/Windows/Platform.cpp b/src/Boot/Windows/Platform.cpp
new file mode 100644
index 00000000..7894bf02
--- /dev/null
+++ b/src/Boot/Windows/Platform.cpp
@@ -0,0 +1,226 @@
+/*
+ Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "Platform.h"
+#include "BootConsoleIo.h"
+
+
+uint64 operator+ (const uint64 &a, const uint64 &b)
+{
+ int carry = 0;
+ uint64 r;
+
+ r.LowPart = a.LowPart + b.LowPart;
+ __asm
+ {
+ jnc nocarry
+ mov carry, 1
+ nocarry:
+ }
+
+ r.HighPart = a.HighPart + b.HighPart + carry;
+
+ return r;
+}
+
+uint64 operator+ (const uint64 &a, uint32 b)
+{
+ uint64 b64;
+ b64.HighPart = 0;
+ b64.LowPart = b;
+ return a + b64;
+}
+
+uint64 &operator+= (uint64 &a, const uint64 &b)
+{
+ return a = a + b;
+}
+
+uint64 operator- (const uint64 &a, const uint64 &b)
+{
+ int carry = 0;
+ uint64 r;
+
+ r.LowPart = a.LowPart - b.LowPart;
+ __asm
+ {
+ jnc nocarry
+ mov carry, 1
+ nocarry:
+ }
+
+ r.HighPart = a.HighPart - b.HighPart - carry;
+
+ return r;
+}
+
+uint64 operator- (const uint64 &a, uint32 b)
+{
+ uint64 b64;
+ b64.HighPart = 0;
+ b64.LowPart = b;
+ return a - b64;
+}
+
+uint64 &operator-= (uint64 &a, const uint64 &b)
+{
+ return a = a - b;
+}
+
+uint64 operator>> (const uint64 &a, int shiftCount)
+{
+ uint64 r = a;
+
+ while (shiftCount--)
+ {
+ r.LowPart >>= 1;
+
+ if ((byte) r.HighPart & 1)
+ r.LowPart |= 0x80000000UL;
+
+ r.HighPart >>= 1;
+ }
+
+ return r;
+}
+
+uint64 operator<< (const uint64 &a, int shiftCount)
+{
+ uint64 r = a;
+
+ while (shiftCount--)
+ r += r;
+
+ return r;
+}
+
+uint64 &operator++ (uint64 &a)
+{
+ uint64 b;
+ b.HighPart = 0;
+ b.LowPart = 1;
+
+ return a += b;
+}
+
+bool operator== (const uint64 &a, const uint64 &b)
+{
+ return a.HighPart == b.HighPart && a.LowPart == b.LowPart;
+}
+
+bool operator> (const uint64 &a, const uint64 &b)
+{
+ return (a.HighPart > b.HighPart) || (a.HighPart == b.HighPart && a.LowPart > b.LowPart);
+}
+
+bool operator< (const uint64 &a, const uint64 &b)
+{
+ return (a.HighPart < b.HighPart) || (a.HighPart == b.HighPart && a.LowPart < b.LowPart);
+}
+
+bool operator>= (const uint64 &a, const uint64 &b)
+{
+ return a > b || a == b;
+}
+
+bool operator<= (const uint64 &a, const uint64 &b)
+{
+ return a < b || a == b;
+}
+
+bool TestInt64 ()
+{
+ uint64 a, b, c;
+ a.HighPart = 0x00112233UL;
+ a.LowPart = 0xabcd1234UL;
+
+ b.HighPart = 0x00ffeeddUL;
+ b.LowPart = 0xffffFFFFUL;
+
+ a += b;
+ a -= b;
+
+ ++a;
+
+ b = b + (uint32) 1UL;
+
+ c = (a - ((a + b) >> 32) - (uint32) 1UL);
+ if (c.HighPart != 0x112233UL || c.LowPart != 0xAABC0123UL)
+ return false;
+
+ c = c << 9;
+ return c.HighPart == 0x22446755UL && c.LowPart == 0x78024600UL;
+}
+
+
+void CopyMemory (void *source, uint16 destSegment, uint16 destOffset, uint16 blockSize)
+{
+ __asm
+ {
+ push es
+ mov si, ss:source
+ mov es, ss:destSegment
+ mov di, ss:destOffset
+ mov cx, ss:blockSize
+ cld
+ rep movsb
+ pop es
+ }
+}
+
+
+void CopyMemory (uint16 sourceSegment, uint16 sourceOffset, void *destination, uint16 blockSize)
+{
+ __asm
+ {
+ push ds
+ push es
+ mov ax, ds
+ mov es, ax
+ mov di, ss:destination
+ mov si, ss:sourceOffset
+ mov cx, ss:blockSize
+ mov ds, ss:sourceSegment
+ cld
+ rep movsb
+ pop es
+ pop ds
+ }
+}
+
+
+void EraseMemory (void *memory, int size)
+{
+ memset (memory, 0, size);
+}
+
+
+uint32 GetLinearAddress (uint16 segment, uint16 offset)
+{
+ return (uint32 (segment) << 4) + offset;
+}
+
+
+bool RegionsIntersect (const uint64 &start1, uint32 length1, const uint64 &start2, const uint64 &end2)
+{
+ uint64 end1 = start1 + length1 - 1UL;
+ uint64 intersectEnd = (end1 <= end2) ? end1 : end2;
+
+ uint64 intersectStart = (start1 >= start2) ? start1 : start2;
+ if (intersectStart > intersectEnd)
+ return false;
+
+ return (intersectEnd + 1UL - intersectStart).LowPart != 0;
+}
+
+
+void ThrowFatalException (int line)
+{
+ PrintChar ('#'); Print (line);
+ while (1);
+}
diff --git a/src/Boot/Windows/Platform.h b/src/Boot/Windows/Platform.h
new file mode 100644
index 00000000..9c923d5e
--- /dev/null
+++ b/src/Boot/Windows/Platform.h
@@ -0,0 +1,112 @@
+/*
+ Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Boot_Platform
+#define TC_HEADER_Boot_Platform
+
+#pragma warning (disable: 4018 4102 4704 4769)
+
+#include "TCdefs.h"
+#include <memory.h>
+
+typedef char bool;
+#define false 0
+#define true 1
+
+#define nullptr 0
+#define NULL 0
+
+typedef UINT64_STRUCT uint64;
+
+#define array_capacity(arr) (sizeof (arr) / sizeof ((arr)[0]))
+
+#define TC_TO_STRING2(n) #n
+#define TC_TO_STRING(n) TC_TO_STRING2(n)
+
+
+#define TC_X86_CARRY_FLAG 0x1
+
+#define TC_ASM_EMIT(A,B) __asm _emit 0x##A __asm _emit 0x##B
+#define TC_ASM_EMIT3(A,B,C) __asm _emit 0x##A __asm _emit 0x##B __asm _emit 0x##C
+#define TC_ASM_EMIT4(A,B,C,D) __asm _emit 0x##A __asm _emit 0x##B __asm _emit 0x##C __asm _emit 0x##D
+
+#define TC_ASM_MOV_EAX_DI TC_ASM_EMIT3 (66, 8B, 05)
+#define TC_ASM_MOV_EBX_DI TC_ASM_EMIT3 (66, 8B, 1D)
+#define TC_ASM_MOV_ECX_DI TC_ASM_EMIT3 (66, 8B, 0D)
+#define TC_ASM_MOV_EDX_DI TC_ASM_EMIT3 (66, 8B, 15)
+
+#define TC_ASM_MOV_DI_EAX TC_ASM_EMIT3 (66, 89, 05)
+#define TC_ASM_MOV_DI_EBX TC_ASM_EMIT3 (66, 89, 1D)
+#define TC_ASM_MOV_DI_ECX TC_ASM_EMIT3 (66, 89, 0D)
+#define TC_ASM_MOV_DI_EDX TC_ASM_EMIT3 (66, 89, 15)
+
+
+#pragma pack(1)
+
+struct Registers
+{
+ uint16 Flags;
+
+ union
+ {
+ uint32 EAX;
+ struct { uint16 AX; uint16 EAXH; };
+ };
+
+ union
+ {
+ uint32 EBX;
+ struct { uint16 BX; uint16 EBXH; };
+ };
+
+ union
+ {
+ uint32 ECX;
+ struct { uint16 CX; uint16 ECXH; };
+ };
+
+ union
+ {
+ uint32 EDX;
+ struct { uint16 DX; uint16 EDXH; };
+ };
+
+ uint16 DI;
+ uint16 SI;
+ uint16 DS;
+ uint16 ES;
+ uint16 SS;
+};
+
+#pragma pack()
+
+
+uint64 operator+ (const uint64 &a, const uint64 &b);
+uint64 operator+ (const uint64 &a, uint32 b);
+uint64 &operator+= (uint64 &a, const uint64 &b);
+uint64 operator- (const uint64 &a, const uint64 &b);
+uint64 operator- (const uint64 &a, uint32 b);
+uint64 &operator-= (uint64 &a, const uint64 &b);
+uint64 operator>> (const uint64 &a, int shiftCount);
+uint64 operator<< (const uint64 &a, int shiftCount);
+uint64 &operator++ (uint64 &a);
+bool operator== (const uint64 &a, const uint64 &b);
+bool operator> (const uint64 &a, const uint64 &b);
+bool operator< (const uint64 &a, const uint64 &b);
+bool operator>= (const uint64 &a, const uint64 &b);
+bool operator<= (const uint64 &a, const uint64 &b);
+
+void CopyMemory (void *source, uint16 destSegment, uint16 destOffset, uint16 blockSize);
+void CopyMemory (uint16 sourceSegment, uint16 sourceOffset, void *destination, uint16 blockSize);
+extern "C" void EraseMemory (void *memory, int size);
+uint32 GetLinearAddress (uint16 segment, uint16 offset);
+bool RegionsIntersect (const uint64 &start1, uint32 length1, const uint64 &start2, const uint64 &end2);
+bool TestInt64 ();
+extern "C" void ThrowFatalException (int line);
+
+#endif // TC_HEADER_Boot_Platform
diff --git a/src/Common/Apidrvr.h b/src/Common/Apidrvr.h
new file mode 100644
index 00000000..b7882665
--- /dev/null
+++ b/src/Common/Apidrvr.h
@@ -0,0 +1,317 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2010 TrueCrypt Developers Association
+ and are 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. */
+
+#pragma once
+
+#include "Tcdefs.h"
+#include "Boot/Windows/BootDefs.h"
+#include "Common.h"
+#include "Crypto.h"
+#include "Volumes.h"
+#include "Wipe.h"
+
+#ifdef _WIN32
+
+/* WARNING: Modifying the following values or their meanings can introduce incompatibility with previous versions. */
+
+#define TC_IOCTL(CODE) (CTL_CODE (FILE_DEVICE_UNKNOWN, 0x800 + (CODE), METHOD_BUFFERED, FILE_ANY_ACCESS))
+
+#define TC_IOCTL_GET_DRIVER_VERSION TC_IOCTL (1)
+#define TC_IOCTL_GET_BOOT_LOADER_VERSION TC_IOCTL (2)
+#define TC_IOCTL_MOUNT_VOLUME TC_IOCTL (3)
+#define TC_IOCTL_DISMOUNT_VOLUME TC_IOCTL (4)
+#define TC_IOCTL_DISMOUNT_ALL_VOLUMES TC_IOCTL (5)
+#define TC_IOCTL_GET_MOUNTED_VOLUMES TC_IOCTL (6)
+#define TC_IOCTL_GET_VOLUME_PROPERTIES TC_IOCTL (7)
+#define TC_IOCTL_GET_DEVICE_REFCOUNT TC_IOCTL (8)
+#define TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED TC_IOCTL (9)
+#define TC_IOCTL_IS_ANY_VOLUME_MOUNTED TC_IOCTL (10)
+#define TC_IOCTL_GET_PASSWORD_CACHE_STATUS TC_IOCTL (11)
+#define TC_IOCTL_WIPE_PASSWORD_CACHE TC_IOCTL (12)
+#define TC_IOCTL_OPEN_TEST TC_IOCTL (13)
+#define TC_IOCTL_GET_DRIVE_PARTITION_INFO TC_IOCTL (14)
+#define TC_IOCTL_GET_DRIVE_GEOMETRY TC_IOCTL (15)
+#define TC_IOCTL_PROBE_REAL_DRIVE_SIZE TC_IOCTL (16)
+#define TC_IOCTL_GET_RESOLVED_SYMLINK TC_IOCTL (17)
+#define TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS TC_IOCTL (18)
+#define TC_IOCTL_BOOT_ENCRYPTION_SETUP TC_IOCTL (19)
+#define TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP TC_IOCTL (20)
+#define TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT TC_IOCTL (21)
+#define TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES TC_IOCTL (22)
+#define TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER TC_IOCTL (23)
+#define TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME TC_IOCTL (24)
+#define TC_IOCTL_GET_PORTABLE_MODE_STATUS TC_IOCTL (25)
+#define TC_IOCTL_SET_PORTABLE_MODE_STATUS TC_IOCTL (26)
+#define TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING TC_IOCTL (27)
+#define TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG TC_IOCTL (28)
+#define TC_IOCTL_DISK_IS_WRITABLE TC_IOCTL (29)
+#define TC_IOCTL_START_DECOY_SYSTEM_WIPE TC_IOCTL (30)
+#define TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE TC_IOCTL (31)
+#define TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS TC_IOCTL (32)
+#define TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT TC_IOCTL (33)
+#define TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR TC_IOCTL (34)
+#define TC_IOCTL_GET_WARNING_FLAGS TC_IOCTL (35)
+#define TC_IOCTL_SET_SYSTEM_FAVORITE_VOLUME_DIRTY TC_IOCTL (36)
+#define TC_IOCTL_REREAD_DRIVER_CONFIG TC_IOCTL (37)
+#define TC_IOCTL_GET_SYSTEM_DRIVE_DUMP_CONFIG TC_IOCTL (38)
+
+// Legacy IOCTLs used before version 5.0
+#define TC_IOCTL_LEGACY_GET_DRIVER_VERSION 466968
+#define TC_IOCTL_LEGACY_GET_MOUNTED_VOLUMES 466948
+
+
+/* Start of driver interface structures, the size of these structures may
+ change between versions; so make sure you first send DRIVER_VERSION to
+ check that it's the correct device driver */
+
+#pragma pack (push)
+#pragma pack(1)
+
+typedef struct
+{
+ int nReturnCode; /* Return code back from driver */
+ BOOL FilesystemDirty;
+ BOOL VolumeMountedReadOnlyAfterAccessDenied;
+ BOOL VolumeMountedReadOnlyAfterDeviceWriteProtected;
+
+ wchar_t wszVolume[TC_MAX_PATH]; /* Volume to be mounted */
+ Password VolumePassword; /* User password */
+ BOOL bCache; /* Cache passwords in driver */
+ int nDosDriveNo; /* Drive number to mount */
+ uint32 BytesPerSector;
+ BOOL bMountReadOnly; /* Mount volume in read-only mode */
+ BOOL bMountRemovable; /* Mount volume as removable media */
+ BOOL bExclusiveAccess; /* Open host file/device in exclusive access mode */
+ BOOL bMountManager; /* Announce volume to mount manager */
+ BOOL bPreserveTimestamp; /* Preserve file container timestamp */
+ BOOL bPartitionInInactiveSysEncScope; /* If TRUE, we are to attempt to mount a partition located on an encrypted system drive without pre-boot authentication. */
+ int nPartitionInInactiveSysEncScopeDriveNo; /* If bPartitionInInactiveSysEncScope is TRUE, this contains the drive number of the system drive on which the partition is located. */
+ BOOL SystemFavorite;
+ // Hidden volume protection
+ BOOL bProtectHiddenVolume; /* TRUE if the user wants the hidden volume within this volume to be protected against being overwritten (damaged) */
+ Password ProtectedHidVolPassword; /* Password to the hidden volume to be protected against overwriting */
+ BOOL UseBackupHeader;
+ BOOL RecoveryMode;
+} MOUNT_STRUCT;
+
+typedef struct
+{
+ int nDosDriveNo; /* Drive letter to unmount */
+ BOOL ignoreOpenFiles;
+ BOOL HiddenVolumeProtectionTriggered;
+ int nReturnCode; /* Return code back from driver */
+} UNMOUNT_STRUCT;
+
+typedef struct
+{
+ unsigned __int32 ulMountedDrives; /* Bitfield of all mounted drive letters */
+ wchar_t wszVolume[26][TC_MAX_PATH]; /* Volume names of mounted volumes */
+ unsigned __int64 diskLength[26];
+ int ea[26];
+ int volumeType[26]; /* Volume type (e.g. PROP_VOL_TYPE_OUTER, PROP_VOL_TYPE_OUTER_VOL_WRITE_PREVENTED, etc.) */
+} MOUNT_LIST_STRUCT;
+
+typedef struct
+{
+ int driveNo;
+ int uniqueId;
+ wchar_t wszVolume[TC_MAX_PATH];
+ unsigned __int64 diskLength;
+ int ea;
+ int mode;
+ int pkcs5;
+ int pkcs5Iterations;
+ BOOL hiddenVolume;
+ BOOL readOnly;
+ BOOL removable;
+ BOOL partitionInInactiveSysEncScope;
+#if 0
+ unsigned __int64 volumeCreationTime; // Deprecated in v6.0
+ unsigned __int64 headerCreationTime; // Deprecated in v6.0
+#endif
+ uint32 volumeHeaderFlags;
+ unsigned __int64 totalBytesRead;
+ unsigned __int64 totalBytesWritten;
+ int hiddenVolProtection; /* Hidden volume protection status (e.g. HIDVOL_PROT_STATUS_NONE, HIDVOL_PROT_STATUS_ACTIVE, etc.) */
+ int volFormatVersion;
+} VOLUME_PROPERTIES_STRUCT;
+
+typedef struct
+{
+ WCHAR symLinkName[TC_MAX_PATH];
+ WCHAR targetName[TC_MAX_PATH];
+} RESOLVE_SYMLINK_STRUCT;
+
+typedef struct
+{
+ WCHAR deviceName[TC_MAX_PATH];
+ PARTITION_INFORMATION partInfo;
+ BOOL IsGPT;
+ BOOL IsDynamic;
+}
+DISK_PARTITION_INFO_STRUCT;
+
+typedef struct
+{
+ WCHAR deviceName[TC_MAX_PATH];
+ DISK_GEOMETRY diskGeometry;
+}
+DISK_GEOMETRY_STRUCT;
+
+typedef struct
+{
+ WCHAR DeviceName[TC_MAX_PATH];
+ LARGE_INTEGER RealDriveSize;
+ BOOL TimeOut;
+} ProbeRealDriveSizeRequest;
+
+typedef struct
+{
+ wchar_t wszFileName[TC_MAX_PATH]; // Volume to be "open tested"
+ BOOL bDetectTCBootLoader; // Whether the driver is to determine if the first sector contains a portion of the TrueCrypt Boot Loader
+ BOOL TCBootLoaderDetected;
+ BOOL DetectFilesystem;
+ BOOL FilesystemDetected;
+} OPEN_TEST_STRUCT;
+
+
+typedef enum
+{
+ SetupNone = 0,
+ SetupEncryption,
+ SetupDecryption
+} BootEncryptionSetupMode;
+
+
+typedef struct
+{
+ // New fields must be added at the end of the structure to maintain compatibility with previous versions
+ BOOL DeviceFilterActive;
+
+ uint16 BootLoaderVersion;
+
+ BOOL DriveMounted;
+ BOOL VolumeHeaderPresent;
+ BOOL DriveEncrypted;
+
+ LARGE_INTEGER BootDriveLength;
+
+ int64 ConfiguredEncryptedAreaStart;
+ int64 ConfiguredEncryptedAreaEnd;
+ int64 EncryptedAreaStart;
+ int64 EncryptedAreaEnd;
+
+ uint32 VolumeHeaderSaltCrc32;
+
+ BOOL SetupInProgress;
+ BootEncryptionSetupMode SetupMode;
+ BOOL TransformWaitingForIdle;
+
+ uint32 HibernationPreventionCount;
+
+ BOOL HiddenSystem;
+ int64 HiddenSystemPartitionStart;
+
+ // Number of times the filter driver answered that an unencrypted volume
+ // is read-only (or mounted an outer/normal TrueCrypt volume as read only)
+ uint32 HiddenSysLeakProtectionCount;
+
+} BootEncryptionStatus;
+
+
+typedef struct
+{
+ BootEncryptionSetupMode SetupMode;
+ WipeAlgorithmId WipeAlgorithm;
+ BOOL ZeroUnreadableSectors;
+ BOOL DiscardUnreadableEncryptedSectors;
+} BootEncryptionSetupRequest;
+
+
+typedef struct
+{
+ Password VolumePassword;
+} ReopenBootVolumeHeaderRequest;
+
+
+typedef struct
+{
+ char BootEncryptionAlgorithmName[256];
+} GetBootEncryptionAlgorithmNameRequest;
+
+typedef struct
+{
+ wchar_t DevicePath[TC_MAX_PATH];
+ byte Configuration;
+ BOOL DriveIsDynamic;
+ uint16 BootLoaderVersion;
+ byte UserConfiguration;
+ char CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH + 1];
+} GetSystemDriveConfigurationRequest;
+
+typedef struct
+{
+ WipeAlgorithmId WipeAlgorithm;
+ byte WipeKey[MASTER_KEYDATA_SIZE];
+} WipeDecoySystemRequest;
+
+typedef struct
+{
+ BOOL WipeInProgress;
+ WipeAlgorithmId WipeAlgorithm;
+ int64 WipedAreaEnd;
+} DecoySystemWipeStatus;
+
+typedef struct
+{
+ LARGE_INTEGER Offset;
+ byte Data[TC_SECTOR_SIZE_BIOS];
+} WriteBootDriveSectorRequest;
+
+typedef struct
+{
+ BOOL PagingFileCreationPrevented;
+ BOOL SystemFavoriteVolumeDirty;
+} GetWarningFlagsRequest;
+
+typedef struct
+{
+ struct _DriveFilterExtension *BootDriveFilterExtension;
+ BOOL HwEncryptionEnabled;
+} GetSystemDriveDumpConfigRequest;
+
+#pragma pack (pop)
+
+#ifdef TC_WINDOWS_DRIVER
+#define DRIVER_STR WIDE
+#else
+#define DRIVER_STR
+#endif
+
+#define TC_UNIQUE_ID_PREFIX "TrueCryptVolume"
+#define TC_MOUNT_PREFIX L"\\Device\\TrueCryptVolume"
+
+#define NT_MOUNT_PREFIX DRIVER_STR("\\Device\\TrueCryptVolume")
+#define NT_ROOT_PREFIX DRIVER_STR("\\Device\\TrueCrypt")
+#define DOS_MOUNT_PREFIX DRIVER_STR("\\DosDevices\\")
+#define DOS_ROOT_PREFIX DRIVER_STR("\\DosDevices\\TrueCrypt")
+#define WIN32_ROOT_PREFIX DRIVER_STR("\\\\.\\TrueCrypt")
+
+#define TC_DRIVER_CONFIG_REG_VALUE_NAME DRIVER_STR("TrueCryptConfig")
+#define TC_ENCRYPTION_FREE_CPU_COUNT_REG_VALUE_NAME DRIVER_STR("TrueCryptEncryptionFreeCpuCount")
+
+// WARNING: Modifying the following values can introduce incompatibility with previous versions.
+#define TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD 0x1
+#define TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES 0x2
+#define TC_DRIVER_CONFIG_DISABLE_NONADMIN_SYS_FAVORITES_ACCESS 0x4
+#define TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION 0x8
+
+#endif /* _WIN32 */
diff --git a/src/Common/BaseCom.cpp b/src/Common/BaseCom.cpp
new file mode 100644
index 00000000..409a653d
--- /dev/null
+++ b/src/Common/BaseCom.cpp
@@ -0,0 +1,231 @@
+/*
+ Copyright (c) 2007-2010 TrueCrypt Developers Association. All rights reserved.
+
+ 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 <atlcomcli.h>
+#include <atlconv.h>
+#include <comutil.h>
+#include <windows.h>
+#include "BaseCom.h"
+#include "BootEncryption.h"
+#include "Dlgcode.h"
+#include "Registry.h"
+
+using namespace TrueCrypt;
+
+HRESULT CreateElevatedComObject (HWND hwnd, REFGUID guid, REFIID iid, void **ppv)
+{
+ WCHAR monikerName[1024];
+ WCHAR clsid[1024];
+ BIND_OPTS3 bo;
+
+ StringFromGUID2 (guid, clsid, sizeof (clsid) / 2);
+ swprintf_s (monikerName, sizeof (monikerName) / 2, L"Elevation:Administrator!new:%s", clsid);
+
+ memset (&bo, 0, sizeof (bo));
+ bo.cbStruct = sizeof (bo);
+ bo.hwnd = hwnd;
+ bo.dwClassContext = CLSCTX_LOCAL_SERVER;
+
+ // Prevent the GUI from being half-rendered when the UAC prompt "freezes" it
+ ProcessPaintMessages (hwnd, 5000);
+
+ return CoGetObject (monikerName, &bo, iid, ppv);
+}
+
+
+BOOL ComGetInstanceBase (HWND hWnd, REFCLSID clsid, REFIID iid, void **tcServer)
+{
+ BOOL r;
+
+ if (IsUacSupported ())
+ r = CreateElevatedComObject (hWnd, clsid, iid, tcServer) == S_OK;
+ else
+ r = CoCreateInstance (clsid, NULL, CLSCTX_LOCAL_SERVER, iid, tcServer) == S_OK;
+
+ if (!r)
+ Error ("UAC_INIT_ERROR");
+
+ return r;
+}
+
+
+DWORD BaseCom::CallDriver (DWORD ioctl, BSTR input, BSTR *output)
+{
+ try
+ {
+ BootEncryption bootEnc (NULL);
+ bootEnc.CallDriver (ioctl,
+ (BYTE *) input, !(BYTE *) input ? 0 : ((DWORD *) ((BYTE *) input))[-1],
+ (BYTE *) *output, !(BYTE *) *output ? 0 : ((DWORD *) ((BYTE *) *output))[-1]);
+ }
+ catch (SystemException &)
+ {
+ return GetLastError();
+ }
+ catch (Exception &e)
+ {
+ e.Show (NULL);
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+ catch (...)
+ {
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+DWORD BaseCom::CopyFile (BSTR sourceFile, BSTR destinationFile)
+{
+ USES_CONVERSION;
+
+ if (!::CopyFile (CW2A (sourceFile), CW2A (destinationFile), FALSE))
+ return GetLastError();
+
+ return ERROR_SUCCESS;
+}
+
+
+DWORD BaseCom::DeleteFile (BSTR file)
+{
+ USES_CONVERSION;
+
+ if (!::DeleteFile (CW2A (file)))
+ return GetLastError();
+
+ return ERROR_SUCCESS;
+}
+
+
+BOOL BaseCom::IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly)
+{
+ return ::IsPagingFileActive (checkNonWindowsPartitionsOnly);
+}
+
+
+DWORD BaseCom::ReadWriteFile (BOOL write, BOOL device, BSTR filePath, BSTR *bufferBstr, unsigned __int64 offset, unsigned __int32 size, DWORD *sizeDone)
+{
+ USES_CONVERSION;
+
+ try
+ {
+ auto_ptr <File> file (device ? new Device (string (CW2A (filePath)), !write) : new File (string (CW2A (filePath)), !write));
+ file->SeekAt (offset);
+
+ if (write)
+ {
+ file->Write ((BYTE *) *bufferBstr, size);
+ *sizeDone = size;
+ }
+ else
+ {
+ *sizeDone = file->Read ((BYTE *) *bufferBstr, size);
+ }
+ }
+ catch (SystemException &)
+ {
+ return GetLastError();
+ }
+ catch (Exception &e)
+ {
+ e.Show (NULL);
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+ catch (...)
+ {
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+DWORD BaseCom::RegisterFilterDriver (BOOL registerDriver, int filterType)
+{
+ try
+ {
+ BootEncryption bootEnc (NULL);
+ bootEnc.RegisterFilterDriver (registerDriver ? true : false, (BootEncryption::FilterType) filterType);
+ }
+ catch (SystemException &)
+ {
+ return GetLastError();
+ }
+ catch (Exception &e)
+ {
+ e.Show (NULL);
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+ catch (...)
+ {
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+DWORD BaseCom::RegisterSystemFavoritesService (BOOL registerService)
+{
+ try
+ {
+ BootEncryption bootEnc (NULL);
+ bootEnc.RegisterSystemFavoritesService (registerService);
+ }
+ catch (SystemException &)
+ {
+ return GetLastError();
+ }
+ catch (Exception &e)
+ {
+ e.Show (NULL);
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+ catch (...)
+ {
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+DWORD BaseCom::SetDriverServiceStartType (DWORD startType)
+{
+ try
+ {
+ BootEncryption bootEnc (NULL);
+ bootEnc.SetDriverServiceStartType (startType);
+ }
+ catch (SystemException &)
+ {
+ return GetLastError();
+ }
+ catch (Exception &e)
+ {
+ e.Show (NULL);
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+ catch (...)
+ {
+ return ERROR_EXCEPTION_IN_SERVICE;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+DWORD BaseCom::WriteLocalMachineRegistryDwordValue (BSTR keyPath, BSTR valueName, DWORD value)
+{
+ USES_CONVERSION;
+ if (!::WriteLocalMachineRegistryDword (CW2A (keyPath), CW2A (valueName), value))
+ return GetLastError();
+
+ return ERROR_SUCCESS;
+}
diff --git a/src/Common/BaseCom.h b/src/Common/BaseCom.h
new file mode 100644
index 00000000..d589d3dd
--- /dev/null
+++ b/src/Common/BaseCom.h
@@ -0,0 +1,115 @@
+/*
+ Copyright (c) 2007-2010 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_BASE_COM
+#define TC_HEADER_BASE_COM
+
+#include <guiddef.h>
+
+template <class TClass>
+class TrueCryptFactory : public IClassFactory
+{
+
+public:
+ TrueCryptFactory (DWORD messageThreadId) :
+ RefCount (1), ServerLockCount (0), MessageThreadId (messageThreadId) { }
+
+ ~TrueCryptFactory () { }
+
+ virtual ULONG STDMETHODCALLTYPE AddRef ()
+ {
+ return InterlockedIncrement (&RefCount) - 1;
+ }
+
+ virtual ULONG STDMETHODCALLTYPE Release ()
+ {
+ ULONG r = InterlockedDecrement (&RefCount) + 1;
+
+ if (r == 0)
+ delete this;
+
+ return r;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface (REFIID riid, void **ppvObject)
+ {
+ if (riid == IID_IUnknown || riid == IID_IClassFactory)
+ *ppvObject = this;
+ else
+ {
+ *ppvObject = NULL;
+ return E_NOINTERFACE;
+ }
+
+ AddRef ();
+ return S_OK;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE CreateInstance (IUnknown *pUnkOuter, REFIID riid, void **ppvObject)
+ {
+ if (pUnkOuter != NULL)
+ return CLASS_E_NOAGGREGATION;
+
+ TClass *tc = new TClass (MessageThreadId);
+ if (tc == NULL)
+ return E_OUTOFMEMORY;
+
+ HRESULT hr = tc->QueryInterface (riid, ppvObject);
+
+ if (hr)
+ delete tc;
+
+ return hr;
+ }
+
+ virtual HRESULT STDMETHODCALLTYPE LockServer (BOOL fLock)
+ {
+ if (fLock)
+ {
+ InterlockedIncrement (&ServerLockCount);
+ }
+ else
+ {
+ if (!InterlockedDecrement (&ServerLockCount))
+ PostThreadMessage (MessageThreadId, WM_APP, 0, 0);
+ }
+
+ return S_OK;
+ }
+
+ virtual bool IsServerLocked ()
+ {
+ return ServerLockCount > 0;
+ }
+
+protected:
+ DWORD MessageThreadId;
+ LONG RefCount;
+ LONG ServerLockCount;
+};
+
+
+class BaseCom
+{
+public:
+ static DWORD CallDriver (DWORD ioctl, BSTR input, BSTR *output);
+ static DWORD CopyFile (BSTR sourceFile, BSTR destinationFile);
+ static DWORD DeleteFile (BSTR file);
+ static BOOL IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly);
+ static DWORD ReadWriteFile (BOOL write, BOOL device, BSTR filePath, BSTR *bufferBstr, unsigned __int64 offset, unsigned __int32 size, DWORD *sizeDone);
+ static DWORD RegisterFilterDriver (BOOL registerDriver, int filterType);
+ static DWORD RegisterSystemFavoritesService (BOOL registerService);
+ static DWORD SetDriverServiceStartType (DWORD startType);
+ static DWORD WriteLocalMachineRegistryDwordValue (BSTR keyPath, BSTR valueName, DWORD value);
+};
+
+
+BOOL ComGetInstanceBase (HWND hWnd, REFCLSID clsid, REFIID iid, void **tcServer);
+HRESULT CreateElevatedComObject (HWND hwnd, REFGUID guid, REFIID iid, void **ppv);
+
+#endif // TC_HEADER_BASE_COM
diff --git a/src/Common/BootEncryption.cpp b/src/Common/BootEncryption.cpp
new file mode 100644
index 00000000..83571ab2
--- /dev/null
+++ b/src/Common/BootEncryption.cpp
@@ -0,0 +1,2457 @@
+/*
+ Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "Tcdefs.h"
+#include "Platform/Finally.h"
+#include "Platform/ForEach.h"
+#include <Setupapi.h>
+#include <devguid.h>
+#include <io.h>
+#include <shlobj.h>
+#include <atlbase.h>
+#include "BootEncryption.h"
+#include "Boot/Windows/BootCommon.h"
+#include "Common/Resource.h"
+#include "Crc.h"
+#include "Crypto.h"
+#include "Dlgcode.h"
+#include "Endian.h"
+#include "Language.h"
+#include "Random.h"
+#include "Registry.h"
+#include "Volumes.h"
+
+#ifdef VOLFORMAT
+#include "Format/FormatCom.h"
+#elif defined (TCMOUNT)
+#include "Mount/MainCom.h"
+#endif
+
+namespace TrueCrypt
+{
+#if !defined (SETUP)
+
+ class Elevator
+ {
+ public:
+
+ static void AddReference ()
+ {
+ ++ReferenceCount;
+ }
+
+
+ static void CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize)
+ {
+ Elevate();
+
+ CComBSTR inputBstr;
+ if (input && inputBstr.AppendBytes ((const char *) input, inputSize) != S_OK)
+ throw ParameterIncorrect (SRC_POS);
+
+ CComBSTR outputBstr;
+ if (output && outputBstr.AppendBytes ((const char *) output, outputSize) != S_OK)
+ throw ParameterIncorrect (SRC_POS);
+
+ DWORD result = ElevatedComInstance->CallDriver (ioctl, inputBstr, &outputBstr);
+
+ if (output)
+ memcpy (output, *(void **) &outputBstr, outputSize);
+
+ if (result != ERROR_SUCCESS)
+ {
+ SetLastError (result);
+ throw SystemException();
+ }
+ }
+
+ static void CopyFile (const string &sourceFile, const string &destinationFile)
+ {
+ Elevate();
+
+ DWORD result = ElevatedComInstance->CopyFile (CComBSTR (sourceFile.c_str()), CComBSTR (destinationFile.c_str()));
+
+ if (result != ERROR_SUCCESS)
+ {
+ SetLastError (result);
+ throw SystemException();
+ }
+ }
+
+ static void DeleteFile (const string &file)
+ {
+ Elevate();
+
+ DWORD result = ElevatedComInstance->DeleteFile (CComBSTR (file.c_str()));
+
+ if (result != ERROR_SUCCESS)
+ {
+ SetLastError (result);
+ throw SystemException();
+ }
+ }
+
+ static void ReadWriteFile (BOOL write, BOOL device, const string &filePath, byte *buffer, uint64 offset, uint32 size, DWORD *sizeDone)
+ {
+ Elevate();
+
+ CComBSTR bufferBstr;
+ if (bufferBstr.AppendBytes ((const char *) buffer, size) != S_OK)
+ throw ParameterIncorrect (SRC_POS);
+ DWORD result = ElevatedComInstance->ReadWriteFile (write, device, CComBSTR (filePath.c_str()), &bufferBstr, offset, size, sizeDone);
+
+ if (result != ERROR_SUCCESS)
+ {
+ SetLastError (result);
+ throw SystemException();
+ }
+
+ if (!write)
+ memcpy (buffer, (BYTE *) bufferBstr.m_str, size);
+ }
+
+ static BOOL IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly)
+ {
+ Elevate();
+
+ return ElevatedComInstance->IsPagingFileActive (checkNonWindowsPartitionsOnly);
+ }
+
+ static void WriteLocalMachineRegistryDwordValue (char *keyPath, char *valueName, DWORD value)
+ {
+ Elevate();
+
+ DWORD result = ElevatedComInstance->WriteLocalMachineRegistryDwordValue (CComBSTR (keyPath), CComBSTR (valueName), value);
+
+ if (result != ERROR_SUCCESS)
+ {
+ SetLastError (result);
+ throw SystemException();
+ }
+ }
+
+ static void RegisterFilterDriver (bool registerDriver, BootEncryption::FilterType filterType)
+ {
+ Elevate();
+
+ DWORD result = ElevatedComInstance->RegisterFilterDriver (registerDriver ? TRUE : FALSE, filterType);
+ if (result != ERROR_SUCCESS)
+ {
+ SetLastError (result);
+ throw SystemException();
+ }
+ }
+
+ static void RegisterSystemFavoritesService (BOOL registerService)
+ {
+ Elevate();
+
+ DWORD result = ElevatedComInstance->RegisterSystemFavoritesService (registerService);
+ if (result != ERROR_SUCCESS)
+ {
+ SetLastError (result);
+ throw SystemException();
+ }
+ }
+
+ static void Release ()
+ {
+ if (--ReferenceCount == 0 && ElevatedComInstance)
+ {
+ ElevatedComInstance->Release();
+ ElevatedComInstance = nullptr;
+ CoUninitialize ();
+ }
+ }
+
+ static void SetDriverServiceStartType (DWORD startType)
+ {
+ Elevate();
+
+ DWORD result = ElevatedComInstance->SetDriverServiceStartType (startType);
+ if (result != ERROR_SUCCESS)
+ {
+ SetLastError (result);
+ throw SystemException();
+ }
+ }
+
+ protected:
+ static void Elevate ()
+ {
+ if (IsAdmin())
+ {
+ SetLastError (ERROR_ACCESS_DENIED);
+ throw SystemException();
+ }
+
+ if (!ElevatedComInstance || ElevatedComInstanceThreadId != GetCurrentThreadId())
+ {
+ CoInitialize (NULL);
+ ElevatedComInstance = GetElevatedInstance (GetActiveWindow() ? GetActiveWindow() : MainDlg);
+ ElevatedComInstanceThreadId = GetCurrentThreadId();
+ }
+ }
+
+#if defined (TCMOUNT)
+ static ITrueCryptMainCom *ElevatedComInstance;
+#elif defined (VOLFORMAT)
+ static ITrueCryptFormatCom *ElevatedComInstance;
+#endif
+ static DWORD ElevatedComInstanceThreadId;
+ static int ReferenceCount;
+ };
+
+#if defined (TCMOUNT)
+ ITrueCryptMainCom *Elevator::ElevatedComInstance;
+#elif defined (VOLFORMAT)
+ ITrueCryptFormatCom *Elevator::ElevatedComInstance;
+#endif
+ DWORD Elevator::ElevatedComInstanceThreadId;
+ int Elevator::ReferenceCount = 0;
+
+#else // SETUP
+
+ class Elevator
+ {
+ public:
+ static void AddReference () { }
+ static void CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize) { throw ParameterIncorrect (SRC_POS); }
+ static void ReadWriteFile (BOOL write, BOOL device, const string &filePath, byte *buffer, uint64 offset, uint32 size, DWORD *sizeDone) { throw ParameterIncorrect (SRC_POS); }
+ static void RegisterFilterDriver (bool registerDriver, BootEncryption::FilterType filterType) { throw ParameterIncorrect (SRC_POS); }
+ static void Release () { }
+ static void SetDriverServiceStartType (DWORD startType) { throw ParameterIncorrect (SRC_POS); }
+ };
+
+#endif // SETUP
+
+
+ File::File (string path, bool readOnly, bool create) : Elevated (false), FileOpen (false)
+ {
+ Handle = CreateFile (path.c_str(),
+ readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, create ? CREATE_ALWAYS : OPEN_EXISTING,
+ FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL);
+
+ try
+ {
+ throw_sys_if (Handle == INVALID_HANDLE_VALUE);
+ }
+ catch (SystemException &)
+ {
+ if (GetLastError() == ERROR_ACCESS_DENIED && IsUacSupported())
+ Elevated = true;
+ else
+ throw;
+ }
+
+ FileOpen = true;
+ FilePointerPosition = 0;
+ IsDevice = false;
+ Path = path;
+ }
+
+ void File::Close ()
+ {
+ if (FileOpen)
+ {
+ if (!Elevated)
+ CloseHandle (Handle);
+
+ FileOpen = false;
+ }
+ }
+
+ DWORD File::Read (byte *buffer, DWORD size)
+ {
+ DWORD bytesRead;
+
+ if (Elevated)
+ {
+ DWORD bytesRead;
+
+ Elevator::ReadWriteFile (false, IsDevice, Path, buffer, FilePointerPosition, size, &bytesRead);
+ FilePointerPosition += bytesRead;
+ return bytesRead;
+ }
+
+ throw_sys_if (!ReadFile (Handle, buffer, size, &bytesRead, NULL));
+ return bytesRead;
+ }
+
+ void File::SeekAt (int64 position)
+ {
+ FilePointerPosition = position;
+
+ if (!Elevated)
+ {
+ LARGE_INTEGER pos;
+ pos.QuadPart = position;
+ throw_sys_if (!SetFilePointerEx (Handle, pos, NULL, FILE_BEGIN));
+ }
+ }
+
+ void File::Write (byte *buffer, DWORD size)
+ {
+ DWORD bytesWritten;
+
+ try
+ {
+ if (Elevated)
+ {
+ Elevator::ReadWriteFile (true, IsDevice, Path, buffer, FilePointerPosition, size, &bytesWritten);
+ FilePointerPosition += bytesWritten;
+ throw_sys_if (bytesWritten != size);
+ }
+ else
+ {
+ throw_sys_if (!WriteFile (Handle, buffer, size, &bytesWritten, NULL) || bytesWritten != size);
+ }
+ }
+ catch (SystemException &e)
+ {
+ if (!IsDevice || e.ErrorCode != ERROR_WRITE_PROTECT)
+ throw;
+
+ BootEncryption bootEnc (NULL);
+
+ while (size >= TC_SECTOR_SIZE_BIOS)
+ {
+ bootEnc.WriteBootDriveSector (FilePointerPosition, buffer);
+
+ FilePointerPosition += TC_SECTOR_SIZE_BIOS;
+ buffer += TC_SECTOR_SIZE_BIOS;
+ size -= TC_SECTOR_SIZE_BIOS;
+ }
+ }
+ }
+
+ void Show (HWND parent, const string &str)
+ {
+ MessageBox (parent, str.c_str(), NULL, 0);
+ }
+
+
+ Device::Device (string path, bool readOnly)
+ {
+ FileOpen = false;
+ Elevated = false;
+
+ Handle = CreateFile ((string ("\\\\.\\") + path).c_str(),
+ readOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
+ FILE_FLAG_RANDOM_ACCESS | FILE_FLAG_WRITE_THROUGH, NULL);
+
+ try
+ {
+ throw_sys_if (Handle == INVALID_HANDLE_VALUE);
+ }
+ catch (SystemException &)
+ {
+ if (GetLastError() == ERROR_ACCESS_DENIED && IsUacSupported())
+ Elevated = true;
+ else
+ throw;
+ }
+
+ FileOpen = true;
+ FilePointerPosition = 0;
+ IsDevice = true;
+ Path = path;
+ }
+
+
+ BootEncryption::BootEncryption (HWND parent)
+ : DriveConfigValid (false),
+ ParentWindow (parent),
+ RealSystemDriveSizeValid (false),
+ RescueIsoImage (nullptr),
+ RescueVolumeHeaderValid (false),
+ SelectedEncryptionAlgorithmId (0),
+ VolumeHeaderValid (false)
+ {
+ Elevator::AddReference();
+ }
+
+
+ BootEncryption::~BootEncryption ()
+ {
+ if (RescueIsoImage)
+ delete[] RescueIsoImage;
+
+ Elevator::Release();
+ }
+
+
+ void BootEncryption::CallDriver (DWORD ioctl, void *input, DWORD inputSize, void *output, DWORD outputSize)
+ {
+ try
+ {
+ DWORD bytesReturned;
+ throw_sys_if (!DeviceIoControl (hDriver, ioctl, input, inputSize, output, outputSize, &bytesReturned, NULL));
+ }
+ catch (SystemException &)
+ {
+ if (GetLastError() == ERROR_ACCESS_DENIED && IsUacSupported())
+ Elevator::CallDriver (ioctl, input, inputSize, output, outputSize);
+ else
+ throw;
+ }
+ }
+
+
+ // Finds the first partition physically located behind the active one and returns its properties
+ Partition BootEncryption::GetPartitionForHiddenOS ()
+ {
+ Partition candidatePartition;
+
+ memset (&candidatePartition, 0, sizeof(candidatePartition));
+
+ // The user may have modified/added/deleted partitions since the time the partition table was last scanned
+ InvalidateCachedSysDriveProperties();
+
+ SystemDriveConfiguration config = GetSystemDriveConfiguration ();
+ bool activePartitionFound = false;
+ bool candidateForHiddenOSFound = false;
+
+ if (config.SystemPartition.IsGPT)
+ throw ParameterIncorrect (SRC_POS); // It is assumed that CheckRequirements() had been called
+
+ // Find the first active partition on the system drive
+ foreach (const Partition &partition, config.Partitions)
+ {
+ if (partition.Info.BootIndicator)
+ {
+ if (partition.Info.PartitionNumber != config.SystemPartition.Number)
+ {
+ // If there is an extra boot partition, the system partition must be located right behind it
+ if (IsOSAtLeast (WIN_7) && config.ExtraBootPartitionPresent)
+ {
+ int64 minOffsetFound = config.DrivePartition.Info.PartitionLength.QuadPart;
+ Partition bootPartition = partition;
+ Partition partitionBehindBoot;
+
+ foreach (const Partition &partition, config.Partitions)
+ {
+ if (partition.Info.StartingOffset.QuadPart > bootPartition.Info.StartingOffset.QuadPart
+ && partition.Info.StartingOffset.QuadPart < minOffsetFound)
+ {
+ minOffsetFound = partition.Info.StartingOffset.QuadPart;
+ partitionBehindBoot = partition;
+ }
+ }
+
+ if (minOffsetFound != config.DrivePartition.Info.PartitionLength.QuadPart
+ && partitionBehindBoot.Number == config.SystemPartition.Number)
+ {
+ activePartitionFound = true;
+ break;
+ }
+ }
+
+ throw ErrorException (wstring (GetString ("SYSTEM_PARTITION_NOT_ACTIVE"))
+ + GetRemarksOnHiddenOS());
+ }
+
+ activePartitionFound = true;
+ break;
+ }
+ }
+
+ /* WARNING: Note that the partition number at the end of a device path (\Device\HarddiskY\PartitionX) must
+ NOT be used to find the first partition physically located behind the active one. The reason is that the
+ user may have deleted and created partitions during this session and e.g. the second partition could have
+ a higer number than the third one. */
+
+
+ // Find the first partition physically located behind the active partition
+ if (activePartitionFound)
+ {
+ int64 minOffsetFound = config.DrivePartition.Info.PartitionLength.QuadPart;
+
+ foreach (const Partition &partition, config.Partitions)
+ {
+ if (partition.Info.StartingOffset.QuadPart > config.SystemPartition.Info.StartingOffset.QuadPart
+ && partition.Info.StartingOffset.QuadPart < minOffsetFound)
+ {
+ minOffsetFound = partition.Info.StartingOffset.QuadPart;
+
+ candidatePartition = partition;
+
+ candidateForHiddenOSFound = true;
+ }
+ }
+
+ if (!candidateForHiddenOSFound)
+ {
+ throw ErrorException (wstring (GetString ("NO_PARTITION_FOLLOWS_BOOT_PARTITION"))
+ + GetRemarksOnHiddenOS());
+ }
+
+ if (config.SystemPartition.Info.PartitionLength.QuadPart > TC_MAX_FAT_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
+ {
+ if ((double) candidatePartition.Info.PartitionLength.QuadPart / config.SystemPartition.Info.PartitionLength.QuadPart < MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_NTFS)
+ {
+ throw ErrorException (wstring (GetString ("PARTITION_TOO_SMALL_FOR_HIDDEN_OS_NTFS"))
+ + GetRemarksOnHiddenOS());
+ }
+ }
+ else if ((double) candidatePartition.Info.PartitionLength.QuadPart / config.SystemPartition.Info.PartitionLength.QuadPart < MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_FAT)
+ {
+ throw ErrorException (wstring (GetString ("PARTITION_TOO_SMALL_FOR_HIDDEN_OS"))
+ + GetRemarksOnHiddenOS());
+ }
+ }
+ else
+ {
+ // No active partition on the system drive
+ throw ErrorException ("SYSTEM_PARTITION_NOT_ACTIVE");
+ }
+
+ HiddenOSCandidatePartition = candidatePartition;
+ return candidatePartition;
+ }
+
+
+ DWORD BootEncryption::GetDriverServiceStartType ()
+ {
+ DWORD startType;
+ throw_sys_if (!ReadLocalMachineRegistryDword ("SYSTEM\\CurrentControlSet\\Services\\truecrypt", "Start", &startType));
+ return startType;
+ }
+
+
+ wstring BootEncryption::GetRemarksOnHiddenOS ()
+ {
+ return (wstring (L"\n\n")
+ + GetString ("TWO_SYSTEMS_IN_ONE_PARTITION_REMARK")
+ + L"\n\n"
+ + GetString ("FOR_MORE_INFO_ON_PARTITIONS"));
+ }
+
+
+ void BootEncryption::SetDriverServiceStartType (DWORD startType)
+ {
+ if (!IsAdmin() && IsUacSupported())
+ {
+ Elevator::SetDriverServiceStartType (startType);
+ return;
+ }
+
+ BOOL startOnBoot = (startType == SERVICE_BOOT_START);
+
+ SC_HANDLE serviceManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ throw_sys_if (!serviceManager);
+
+ finally_do_arg (SC_HANDLE, serviceManager, { CloseServiceHandle (finally_arg); });
+
+ SC_HANDLE service = OpenService (serviceManager, "truecrypt", SERVICE_CHANGE_CONFIG);
+ throw_sys_if (!service);
+
+ finally_do_arg (SC_HANDLE, service, { CloseServiceHandle (finally_arg); });
+
+ // Windows versions preceding Vista can be installed on FAT filesystem which does not
+ // support long filenames during boot. Convert the driver path to short form if required.
+ string driverPath;
+ if (startOnBoot && !IsOSAtLeast (WIN_VISTA))
+ {
+ char pathBuf[MAX_PATH];
+ char filesystem[128];
+
+ string path (GetWindowsDirectory());
+ path += "\\drivers\\truecrypt.sys";
+
+ if (GetVolumePathName (path.c_str(), pathBuf, sizeof (pathBuf))
+ && GetVolumeInformation (pathBuf, NULL, 0, NULL, NULL, NULL, filesystem, sizeof(filesystem))
+ && memcmp (filesystem, "FAT", 3) == 0)
+ {
+ throw_sys_if (GetShortPathName (path.c_str(), pathBuf, sizeof (pathBuf)) == 0);
+
+ // Convert absolute path to relative to the Windows directory
+ driverPath = pathBuf;
+ driverPath = driverPath.substr (driverPath.rfind ("\\", driverPath.rfind ("\\", driverPath.rfind ("\\") - 1) - 1) + 1);
+ }
+ }
+
+ throw_sys_if (!ChangeServiceConfig (service, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE,
+ startOnBoot ? SERVICE_ERROR_SEVERE : SERVICE_ERROR_NORMAL,
+ driverPath.empty() ? NULL : driverPath.c_str(),
+ startOnBoot ? "Filter" : NULL,
+ NULL, NULL, NULL, NULL, NULL));
+
+ // ChangeServiceConfig() rejects SERVICE_BOOT_START with ERROR_INVALID_PARAMETER
+ throw_sys_if (!WriteLocalMachineRegistryDword ("SYSTEM\\CurrentControlSet\\Services\\truecrypt", "Start", startType));
+ }
+
+
+ void BootEncryption::ProbeRealSystemDriveSize ()
+ {
+ if (RealSystemDriveSizeValid)
+ return;
+
+ GetSystemDriveConfiguration();
+
+ ProbeRealDriveSizeRequest request;
+ _snwprintf (request.DeviceName, array_capacity (request.DeviceName), L"%hs", DriveConfig.DrivePartition.DevicePath.c_str());
+
+ CallDriver (TC_IOCTL_PROBE_REAL_DRIVE_SIZE, &request, sizeof (request), &request, sizeof (request));
+ DriveConfig.DrivePartition.Info.PartitionLength = request.RealDriveSize;
+
+ RealSystemDriveSizeValid = true;
+
+ if (request.TimeOut)
+ throw TimeOut (SRC_POS);
+ }
+
+
+ void BootEncryption::InvalidateCachedSysDriveProperties ()
+ {
+ DriveConfigValid = false;
+ RealSystemDriveSizeValid = false;
+ }
+
+
+ PartitionList BootEncryption::GetDrivePartitions (int driveNumber)
+ {
+ PartitionList partList;
+
+ for (int partNumber = 0; partNumber < 64; ++partNumber)
+ {
+ stringstream partPath;
+ partPath << "\\Device\\Harddisk" << driveNumber << "\\Partition" << partNumber;
+
+ DISK_PARTITION_INFO_STRUCT diskPartInfo;
+ _snwprintf (diskPartInfo.deviceName, array_capacity (diskPartInfo.deviceName), L"%hs", partPath.str().c_str());
+
+ try
+ {
+ CallDriver (TC_IOCTL_GET_DRIVE_PARTITION_INFO, &diskPartInfo, sizeof (diskPartInfo), &diskPartInfo, sizeof (diskPartInfo));
+ }
+ catch (...)
+ {
+ continue;
+ }
+
+ Partition part;
+ part.DevicePath = partPath.str();
+ part.Number = partNumber;
+ part.Info = diskPartInfo.partInfo;
+ part.IsGPT = diskPartInfo.IsGPT;
+
+ // Mount point
+ wstringstream ws;
+ ws << partPath.str().c_str();
+ int driveNumber = GetDiskDeviceDriveLetter ((wchar_t *) ws.str().c_str());
+
+ if (driveNumber >= 0)
+ {
+ part.MountPoint += (char) (driveNumber + 'A');
+ part.MountPoint += ":";
+ }
+
+ // Volume ID
+ wchar_t volumePath[TC_MAX_PATH];
+ if (ResolveSymbolicLink ((wchar_t *) ws.str().c_str(), volumePath))
+ {
+ wchar_t volumeName[TC_MAX_PATH];
+ HANDLE fh = FindFirstVolumeW (volumeName, array_capacity (volumeName));
+ if (fh != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ wstring volumeNameStr = volumeName;
+ wchar_t devicePath[TC_MAX_PATH];
+
+ if (QueryDosDeviceW (volumeNameStr.substr (4, volumeNameStr.size() - 1 - 4).c_str(), devicePath, array_capacity (devicePath)) != 0
+ && wcscmp (volumePath, devicePath) == 0)
+ {
+ part.VolumeNameId = volumeName;
+ break;
+ }
+
+ } while (FindNextVolumeW (fh, volumeName, array_capacity (volumeName)));
+
+ FindVolumeClose (fh);
+ }
+ }
+
+ partList.push_back (part);
+ }
+
+ return partList;
+ }
+
+
+ DISK_GEOMETRY BootEncryption::GetDriveGeometry (int driveNumber)
+ {
+ stringstream devName;
+ devName << "\\Device\\Harddisk" << driveNumber << "\\Partition0";
+
+ DISK_GEOMETRY geometry;
+ throw_sys_if (!::GetDriveGeometry ((char *) devName.str().c_str(), &geometry));
+ return geometry;
+ }
+
+
+ string BootEncryption::GetWindowsDirectory ()
+ {
+ char buf[MAX_PATH];
+ throw_sys_if (GetSystemDirectory (buf, sizeof (buf)) == 0);
+
+ return string (buf);
+ }
+
+
+ string BootEncryption::GetTempPath ()
+ {
+ char tempPath[MAX_PATH];
+ DWORD tempLen = ::GetTempPath (sizeof (tempPath), tempPath);
+ if (tempLen == 0 || tempLen > sizeof (tempPath))
+ throw ParameterIncorrect (SRC_POS);
+
+ return string (tempPath);
+ }
+
+
+ uint16 BootEncryption::GetInstalledBootLoaderVersion ()
+ {
+ uint16 version;
+ CallDriver (TC_IOCTL_GET_BOOT_LOADER_VERSION, NULL, 0, &version, sizeof (version));
+ return version;
+ }
+
+
+ // Note that this does not require admin rights (it just requires the driver to be running)
+ bool BootEncryption::IsBootLoaderOnDrive (char *devicePath)
+ {
+ try
+ {
+ OPEN_TEST_STRUCT openTestStruct;
+ memset (&openTestStruct, 0, sizeof (openTestStruct));
+ DWORD dwResult;
+
+ strcpy ((char *) &openTestStruct.wszFileName[0], devicePath);
+ ToUNICODE ((char *) &openTestStruct.wszFileName[0]);
+
+ openTestStruct.bDetectTCBootLoader = TRUE;
+
+ return (DeviceIoControl (hDriver, TC_IOCTL_OPEN_TEST,
+ &openTestStruct, sizeof (OPEN_TEST_STRUCT),
+ &openTestStruct, sizeof (OPEN_TEST_STRUCT),
+ &dwResult, NULL) && openTestStruct.TCBootLoaderDetected);
+ }
+ catch (...)
+ {
+ return false;
+ }
+ }
+
+
+ BootEncryptionStatus BootEncryption::GetStatus ()
+ {
+ /* IMPORTANT: Do NOT add any potentially time-consuming operations to this function. */
+
+ BootEncryptionStatus status;
+ CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_STATUS, NULL, 0, &status, sizeof (status));
+ return status;
+ }
+
+
+ void BootEncryption::GetVolumeProperties (VOLUME_PROPERTIES_STRUCT *properties)
+ {
+ if (properties == NULL)
+ throw ParameterIncorrect (SRC_POS);
+
+ CallDriver (TC_IOCTL_GET_BOOT_DRIVE_VOLUME_PROPERTIES, NULL, 0, properties, sizeof (*properties));
+ }
+
+
+ bool BootEncryption::IsHiddenSystemRunning ()
+ {
+ int hiddenSystemStatus;
+
+ CallDriver (TC_IOCTL_IS_HIDDEN_SYSTEM_RUNNING, nullptr, 0, &hiddenSystemStatus, sizeof (hiddenSystemStatus));
+ return hiddenSystemStatus != 0;
+ }
+
+
+ bool BootEncryption::SystemDriveContainsPartitionType (byte type)
+ {
+ Device device (GetSystemDriveConfiguration().DevicePath, true);
+
+ byte mbrBuf[TC_SECTOR_SIZE_BIOS];
+ device.SeekAt (0);
+ device.Read (mbrBuf, sizeof (mbrBuf));
+
+ MBR *mbr = reinterpret_cast <MBR *> (mbrBuf);
+ if (mbr->Signature != 0xaa55)
+ throw ParameterIncorrect (SRC_POS);
+
+ for (size_t i = 0; i < array_capacity (mbr->Partitions); ++i)
+ {
+ if (mbr->Partitions[i].Type == type)
+ return true;
+ }
+
+ return false;
+ }
+
+
+ bool BootEncryption::SystemDriveContainsExtendedPartition ()
+ {
+ return SystemDriveContainsPartitionType (PARTITION_EXTENDED) || SystemDriveContainsPartitionType (PARTITION_XINT13_EXTENDED);
+ }
+
+
+ bool BootEncryption::SystemDriveContainsNonStandardPartitions ()
+ {
+ for (int partitionType = 1; partitionType <= 0xff; ++partitionType)
+ {
+ switch (partitionType)
+ {
+ case PARTITION_FAT_12:
+ case PARTITION_FAT_16:
+ case PARTITION_EXTENDED:
+ case PARTITION_HUGE:
+ case PARTITION_IFS:
+ case PARTITION_FAT32:
+ case PARTITION_FAT32_XINT13:
+ case PARTITION_XINT13:
+ case PARTITION_XINT13_EXTENDED:
+ continue;
+ }
+
+ if (SystemDriveContainsPartitionType ((byte) partitionType))
+ return true;
+ }
+
+ return false;
+ }
+
+
+ bool BootEncryption::SystemDriveIsDynamic ()
+ {
+ GetSystemDriveConfigurationRequest request;
+ _snwprintf (request.DevicePath, array_capacity (request.DevicePath), L"%hs", GetSystemDriveConfiguration().DeviceKernelPath.c_str());
+
+ CallDriver (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG, &request, sizeof (request), &request, sizeof (request));
+ return request.DriveIsDynamic ? true : false;
+ }
+
+
+ SystemDriveConfiguration BootEncryption::GetSystemDriveConfiguration ()
+ {
+ if (DriveConfigValid)
+ return DriveConfig;
+
+ SystemDriveConfiguration config;
+
+ string winDir = GetWindowsDirectory();
+
+ // Scan all drives
+ for (int driveNumber = 0; driveNumber < 32; ++driveNumber)
+ {
+ bool windowsFound = false;
+ bool activePartitionFound = false;
+ config.ExtraBootPartitionPresent = false;
+ config.SystemLoaderPresent = false;
+
+ PartitionList partitions = GetDrivePartitions (driveNumber);
+ foreach (const Partition &part, partitions)
+ {
+ if (!part.MountPoint.empty()
+ && (_access ((part.MountPoint + "\\bootmgr").c_str(), 0) == 0 || _access ((part.MountPoint + "\\ntldr").c_str(), 0) == 0))
+ {
+ config.SystemLoaderPresent = true;
+ }
+ else if (!part.VolumeNameId.empty()
+ && (_waccess ((part.VolumeNameId + L"\\bootmgr").c_str(), 0) == 0 || _waccess ((part.VolumeNameId + L"\\ntldr").c_str(), 0) == 0))
+ {
+ config.SystemLoaderPresent = true;
+ }
+
+ if (!windowsFound && !part.MountPoint.empty() && ToUpperCase (winDir).find (ToUpperCase (part.MountPoint)) == 0)
+ {
+ config.SystemPartition = part;
+ windowsFound = true;
+ }
+
+ if (!activePartitionFound && part.Info.BootIndicator)
+ {
+ activePartitionFound = true;
+
+ if (part.Info.PartitionLength.QuadPart > 0 && part.Info.PartitionLength.QuadPart <= TC_MAX_EXTRA_BOOT_PARTITION_SIZE)
+ config.ExtraBootPartitionPresent = true;
+ }
+ }
+
+ if (windowsFound)
+ {
+ config.DriveNumber = driveNumber;
+
+ stringstream ss;
+ ss << "PhysicalDrive" << driveNumber;
+ config.DevicePath = ss.str();
+
+ stringstream kernelPath;
+ kernelPath << "\\Device\\Harddisk" << driveNumber << "\\Partition0";
+ config.DeviceKernelPath = kernelPath.str();
+
+ config.DrivePartition = partitions.front();
+ partitions.pop_front();
+ config.Partitions = partitions;
+
+ config.InitialUnallocatedSpace = 0x7fffFFFFffffFFFFull;
+ config.TotalUnallocatedSpace = config.DrivePartition.Info.PartitionLength.QuadPart;
+
+ foreach (const Partition &part, config.Partitions)
+ {
+ if (part.Info.StartingOffset.QuadPart < config.InitialUnallocatedSpace)
+ config.InitialUnallocatedSpace = part.Info.StartingOffset.QuadPart;
+
+ config.TotalUnallocatedSpace -= part.Info.PartitionLength.QuadPart;
+ }
+
+ DriveConfig = config;
+ DriveConfigValid = true;
+ return DriveConfig;
+ }
+ }
+
+ throw ParameterIncorrect (SRC_POS);
+ }
+
+
+ bool BootEncryption::SystemPartitionCoversWholeDrive ()
+ {
+ SystemDriveConfiguration config = GetSystemDriveConfiguration();
+
+ if (IsOSAtLeast (WIN_7)
+ && config.Partitions.size() == 2
+ && config.ExtraBootPartitionPresent
+ && config.DrivePartition.Info.PartitionLength.QuadPart - config.SystemPartition.Info.PartitionLength.QuadPart < 164 * BYTES_PER_MB)
+ {
+ return true;
+ }
+
+ return config.Partitions.size() == 1
+ && config.DrivePartition.Info.PartitionLength.QuadPart - config.SystemPartition.Info.PartitionLength.QuadPart < 64 * BYTES_PER_MB;
+ }
+
+
+ uint32 BootEncryption::GetChecksum (byte *data, size_t size)
+ {
+ uint32 sum = 0;
+
+ while (size-- > 0)
+ {
+ sum += *data++;
+ sum = _rotl (sum, 1);
+ }
+
+ return sum;
+ }
+
+
+ void BootEncryption::CreateBootLoaderInMemory (byte *buffer, size_t bufferSize, bool rescueDisk, bool hiddenOSCreation)
+ {
+ if (bufferSize < TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE)
+ throw ParameterIncorrect (SRC_POS);
+
+ ZeroMemory (buffer, bufferSize);
+
+ int ea = 0;
+ if (GetStatus().DriveMounted)
+ {
+ try
+ {
+ GetBootEncryptionAlgorithmNameRequest request;
+ CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_ALGORITHM_NAME, NULL, 0, &request, sizeof (request));
+
+ if (_stricmp (request.BootEncryptionAlgorithmName, "AES") == 0)
+ ea = AES;
+ else if (_stricmp (request.BootEncryptionAlgorithmName, "Serpent") == 0)
+ ea = SERPENT;
+ else if (_stricmp (request.BootEncryptionAlgorithmName, "Twofish") == 0)
+ ea = TWOFISH;
+ }
+ catch (...)
+ {
+ try
+ {
+ VOLUME_PROPERTIES_STRUCT properties;
+ GetVolumeProperties (&properties);
+ ea = properties.ea;
+ }
+ catch (...) { }
+ }
+ }
+ else
+ {
+ if (SelectedEncryptionAlgorithmId == 0)
+ throw ParameterIncorrect (SRC_POS);
+
+ ea = SelectedEncryptionAlgorithmId;
+ }
+
+ int bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR : IDR_BOOT_SECTOR;
+ int bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER : IDR_BOOT_LOADER;
+
+ switch (ea)
+ {
+ case AES:
+ bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_AES : IDR_BOOT_SECTOR_AES;
+ bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_AES : IDR_BOOT_LOADER_AES;
+ break;
+
+ case SERPENT:
+ bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_SERPENT : IDR_BOOT_SECTOR_SERPENT;
+ bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_SERPENT : IDR_BOOT_LOADER_SERPENT;
+ break;
+
+ case TWOFISH:
+ bootSectorId = rescueDisk ? IDR_RESCUE_BOOT_SECTOR_TWOFISH : IDR_BOOT_SECTOR_TWOFISH;
+ bootLoaderId = rescueDisk ? IDR_RESCUE_LOADER_TWOFISH : IDR_BOOT_LOADER_TWOFISH;
+ break;
+ }
+
+ // Boot sector
+ DWORD size;
+ byte *bootSecResourceImg = MapResource ("BIN", bootSectorId, &size);
+ if (!bootSecResourceImg || size != TC_SECTOR_SIZE_BIOS)
+ throw ParameterIncorrect (SRC_POS);
+
+ memcpy (buffer, bootSecResourceImg, size);
+
+ *(uint16 *) (buffer + TC_BOOT_SECTOR_VERSION_OFFSET) = BE16 (VERSION_NUM);
+
+ if (IsOSAtLeast (WIN_VISTA))
+ buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_WINDOWS_VISTA_OR_LATER;
+
+ if (rescueDisk && (ReadDriverConfigurationFlags() & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION))
+ buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_RESCUE_DISABLE_HW_ENCRYPTION;
+
+ // Checksum of the backup header of the outer volume for the hidden system
+ if (hiddenOSCreation)
+ {
+ Device device (GetSystemDriveConfiguration().DevicePath);
+ byte headerSector[TC_SECTOR_SIZE_BIOS];
+
+ device.SeekAt (HiddenOSCandidatePartition.Info.StartingOffset.QuadPart + HiddenOSCandidatePartition.Info.PartitionLength.QuadPart - TC_VOLUME_HEADER_GROUP_SIZE + TC_VOLUME_HEADER_EFFECTIVE_SIZE);
+ device.Read (headerSector, sizeof (headerSector));
+
+ *(uint32 *) (buffer + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET) = GetCrc32 (headerSector, sizeof (headerSector));
+ }
+
+ // Decompressor
+ byte *decompressor = MapResource ("BIN", IDR_BOOT_LOADER_DECOMPRESSOR, &size);
+ if (!decompressor || size > TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
+ throw ParameterIncorrect (SRC_POS);
+
+ memcpy (buffer + TC_SECTOR_SIZE_BIOS, decompressor, size);
+
+ // Compressed boot loader
+ byte *bootLoader = MapResource ("BIN", bootLoaderId, &size);
+ if (!bootLoader || size > TC_MAX_BOOT_LOADER_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
+ throw ParameterIncorrect (SRC_POS);
+
+ memcpy (buffer + TC_SECTOR_SIZE_BIOS + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS, bootLoader, size);
+
+ // Boot loader and decompressor checksum
+ *(uint16 *) (buffer + TC_BOOT_SECTOR_LOADER_LENGTH_OFFSET) = static_cast <uint16> (size);
+ *(uint32 *) (buffer + TC_BOOT_SECTOR_LOADER_CHECKSUM_OFFSET) = GetChecksum (buffer + TC_SECTOR_SIZE_BIOS,
+ TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS + size);
+
+ // Backup of decompressor and boot loader
+ if (size + TC_BOOT_LOADER_DECOMPRESSOR_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS <= TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS)
+ {
+ memcpy (buffer + TC_SECTOR_SIZE_BIOS + TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS,
+ buffer + TC_SECTOR_SIZE_BIOS, TC_BOOT_LOADER_BACKUP_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS);
+
+ buffer[TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_BACKUP_LOADER_AVAILABLE;
+ }
+ else if (!rescueDisk && bootLoaderId != IDR_BOOT_LOADER)
+ {
+ throw ParameterIncorrect (SRC_POS);
+ }
+ }
+
+
+ void BootEncryption::ReadBootSectorConfig (byte *config, size_t bufLength, byte *userConfig, string *customUserMessage, uint16 *bootLoaderVersion)
+ {
+ if (config && bufLength < TC_BOOT_CFG_FLAG_AREA_SIZE)
+ throw ParameterIncorrect (SRC_POS);
+
+ GetSystemDriveConfigurationRequest request;
+ _snwprintf (request.DevicePath, array_capacity (request.DevicePath), L"%hs", GetSystemDriveConfiguration().DeviceKernelPath.c_str());
+
+ try
+ {
+ CallDriver (TC_IOCTL_GET_SYSTEM_DRIVE_CONFIG, &request, sizeof (request), &request, sizeof (request));
+ if (config)
+ *config = request.Configuration;
+
+ if (userConfig)
+ *userConfig = request.UserConfiguration;
+
+ if (customUserMessage)
+ {
+ request.CustomUserMessage[TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH] = 0;
+ *customUserMessage = request.CustomUserMessage;
+ }
+
+ if (bootLoaderVersion)
+ *bootLoaderVersion = request.BootLoaderVersion;
+ }
+ catch (...)
+ {
+ if (config)
+ *config = 0;
+
+ if (userConfig)
+ *userConfig = 0;
+
+ if (customUserMessage)
+ customUserMessage->clear();
+
+ if (bootLoaderVersion)
+ *bootLoaderVersion = 0;
+ }
+ }
+
+
+ void BootEncryption::WriteBootSectorConfig (const byte newConfig[])
+ {
+ Device device (GetSystemDriveConfiguration().DevicePath);
+ byte mbr[TC_SECTOR_SIZE_BIOS];
+
+ device.SeekAt (0);
+ device.Read (mbr, sizeof (mbr));
+
+ memcpy (mbr + TC_BOOT_SECTOR_CONFIG_OFFSET, newConfig, TC_BOOT_CFG_FLAG_AREA_SIZE);
+
+ device.SeekAt (0);
+ device.Write (mbr, sizeof (mbr));
+
+ byte mbrVerificationBuf[TC_SECTOR_SIZE_BIOS];
+ device.SeekAt (0);
+ device.Read (mbrVerificationBuf, sizeof (mbr));
+
+ if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0)
+ throw ErrorException ("ERROR_MBR_PROTECTED");
+ }
+
+
+ void BootEncryption::WriteBootSectorUserConfig (byte userConfig, const string &customUserMessage)
+ {
+ Device device (GetSystemDriveConfiguration().DevicePath);
+ byte mbr[TC_SECTOR_SIZE_BIOS];
+
+ device.SeekAt (0);
+ device.Read (mbr, sizeof (mbr));
+
+ if (!BufferContainsString (mbr, sizeof (mbr), TC_APP_NAME)
+ || BE16 (*(uint16 *) (mbr + TC_BOOT_SECTOR_VERSION_OFFSET)) != VERSION_NUM)
+ {
+ return;
+ }
+
+ mbr[TC_BOOT_SECTOR_USER_CONFIG_OFFSET] = userConfig;
+
+ memset (mbr + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, 0, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH);
+
+ if (!customUserMessage.empty())
+ {
+ if (customUserMessage.size() > TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH)
+ throw ParameterIncorrect (SRC_POS);
+
+ memcpy (mbr + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, customUserMessage.c_str(), customUserMessage.size());
+ }
+
+ device.SeekAt (0);
+ device.Write (mbr, sizeof (mbr));
+
+ byte mbrVerificationBuf[TC_SECTOR_SIZE_BIOS];
+ device.SeekAt (0);
+ device.Read (mbrVerificationBuf, sizeof (mbr));
+
+ if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0)
+ throw ErrorException ("ERROR_MBR_PROTECTED");
+ }
+
+
+ unsigned int BootEncryption::GetHiddenOSCreationPhase ()
+ {
+ byte configFlags [TC_BOOT_CFG_FLAG_AREA_SIZE];
+
+ ReadBootSectorConfig (configFlags, sizeof(configFlags));
+
+ return (configFlags[0] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE);
+ }
+
+
+ void BootEncryption::SetHiddenOSCreationPhase (unsigned int newPhase)
+ {
+#if TC_BOOT_CFG_FLAG_AREA_SIZE != 1
+# error TC_BOOT_CFG_FLAG_AREA_SIZE != 1; revise GetHiddenOSCreationPhase() and SetHiddenOSCreationPhase()
+#endif
+ byte configFlags [TC_BOOT_CFG_FLAG_AREA_SIZE];
+
+ ReadBootSectorConfig (configFlags, sizeof(configFlags));
+
+ configFlags[0] &= (byte) ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
+
+ configFlags[0] |= newPhase;
+
+ WriteBootSectorConfig (configFlags);
+ }
+
+
+#ifndef SETUP
+
+ void BootEncryption::StartDecoyOSWipe (WipeAlgorithmId wipeAlgorithm)
+ {
+ if (!IsHiddenOSRunning())
+ throw ParameterIncorrect (SRC_POS);
+
+ WipeDecoySystemRequest request;
+ ZeroMemory (&request, sizeof (request));
+
+ request.WipeAlgorithm = wipeAlgorithm;
+
+ if (Randinit() != ERR_SUCCESS)
+ throw ParameterIncorrect (SRC_POS);
+
+ UserEnrichRandomPool (ParentWindow);
+
+ if (!RandgetBytes (request.WipeKey, sizeof (request.WipeKey), TRUE))
+ throw ParameterIncorrect (SRC_POS);
+
+ CallDriver (TC_IOCTL_START_DECOY_SYSTEM_WIPE, &request, sizeof (request), NULL, 0);
+
+ burn (&request, sizeof (request));
+ }
+
+
+ void BootEncryption::AbortDecoyOSWipe ()
+ {
+ CallDriver (TC_IOCTL_ABORT_DECOY_SYSTEM_WIPE);
+ }
+
+
+ DecoySystemWipeStatus BootEncryption::GetDecoyOSWipeStatus ()
+ {
+ DecoySystemWipeStatus status;
+ CallDriver (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_STATUS, NULL, 0, &status, sizeof (status));
+ return status;
+ }
+
+
+ void BootEncryption::CheckDecoyOSWipeResult ()
+ {
+ CallDriver (TC_IOCTL_GET_DECOY_SYSTEM_WIPE_RESULT);
+ }
+
+
+ void BootEncryption::WipeHiddenOSCreationConfig ()
+ {
+ if (IsHiddenOSRunning() || Randinit() != ERR_SUCCESS)
+ throw ParameterIncorrect (SRC_POS);
+
+ Device device (GetSystemDriveConfiguration().DevicePath);
+ byte mbr[TC_SECTOR_SIZE_BIOS];
+
+ device.SeekAt (0);
+ device.Read (mbr, sizeof (mbr));
+
+ finally_do_arg (BootEncryption *, this,
+ {
+ try
+ {
+ finally_arg->SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE);
+ } catch (...) { }
+ });
+
+#if PRAND_DISK_WIPE_PASSES > RNG_POOL_SIZE
+# error PRAND_DISK_WIPE_PASSES > RNG_POOL_SIZE
+#endif
+
+ byte randData[PRAND_DISK_WIPE_PASSES];
+ if (!RandgetBytes (randData, sizeof (randData), FALSE))
+ throw ParameterIncorrect (SRC_POS);
+
+ for (int wipePass = 0; wipePass < PRAND_DISK_WIPE_PASSES; wipePass++)
+ {
+ for (int i = 0; i < TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE; ++i)
+ {
+ mbr[TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET + i] = randData[wipePass];
+ }
+
+ mbr[TC_BOOT_SECTOR_CONFIG_OFFSET] &= (byte) ~TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
+ mbr[TC_BOOT_SECTOR_CONFIG_OFFSET] |= randData[wipePass] & TC_BOOT_CFG_MASK_HIDDEN_OS_CREATION_PHASE;
+
+ if (wipePass == PRAND_DISK_WIPE_PASSES - 1)
+ memset (mbr + TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_OFFSET, 0, TC_BOOT_SECTOR_OUTER_VOLUME_BAK_HEADER_CRC_SIZE);
+
+ device.SeekAt (0);
+ device.Write (mbr, sizeof (mbr));
+ }
+
+ for (int wipePass = 0; wipePass < PRAND_DISK_WIPE_PASSES/4 + 1; wipePass++)
+ {
+ SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE);
+ SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_CLONING);
+ SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_WIPING);
+ SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_WIPED);
+ }
+ SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE);
+ }
+
+#endif // !SETUP
+
+
+ void BootEncryption::InstallBootLoader (bool preserveUserConfig, bool hiddenOSCreation)
+ {
+ byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SIZE - TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE];
+ CreateBootLoaderInMemory (bootLoaderBuf, sizeof (bootLoaderBuf), false, hiddenOSCreation);
+
+ // Write MBR
+ Device device (GetSystemDriveConfiguration().DevicePath);
+ byte mbr[TC_SECTOR_SIZE_BIOS];
+
+ device.SeekAt (0);
+ device.Read (mbr, sizeof (mbr));
+
+ if (preserveUserConfig && BufferContainsString (mbr, sizeof (mbr), TC_APP_NAME))
+ {
+ uint16 version = BE16 (*(uint16 *) (mbr + TC_BOOT_SECTOR_VERSION_OFFSET));
+ if (version != 0)
+ {
+ bootLoaderBuf[TC_BOOT_SECTOR_USER_CONFIG_OFFSET] = mbr[TC_BOOT_SECTOR_USER_CONFIG_OFFSET];
+ memcpy (bootLoaderBuf + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, mbr + TC_BOOT_SECTOR_USER_MESSAGE_OFFSET, TC_BOOT_SECTOR_USER_MESSAGE_MAX_LENGTH);
+ }
+ }
+
+ memcpy (mbr, bootLoaderBuf, TC_MAX_MBR_BOOT_CODE_SIZE);
+
+ device.SeekAt (0);
+ device.Write (mbr, sizeof (mbr));
+
+ byte mbrVerificationBuf[TC_SECTOR_SIZE_BIOS];
+ device.SeekAt (0);
+ device.Read (mbrVerificationBuf, sizeof (mbr));
+
+ if (memcmp (mbr, mbrVerificationBuf, sizeof (mbr)) != 0)
+ throw ErrorException ("ERROR_MBR_PROTECTED");
+
+ // Write boot loader
+ device.SeekAt (TC_SECTOR_SIZE_BIOS);
+ device.Write (bootLoaderBuf + TC_SECTOR_SIZE_BIOS, sizeof (bootLoaderBuf) - TC_SECTOR_SIZE_BIOS);
+ }
+
+
+ string BootEncryption::GetSystemLoaderBackupPath ()
+ {
+ char pathBuf[MAX_PATH];
+
+ throw_sys_if (!SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, pathBuf)));
+
+ string path = string (pathBuf) + "\\" TC_APP_NAME;
+ CreateDirectory (path.c_str(), NULL);
+
+ return path + '\\' + TC_SYS_BOOT_LOADER_BACKUP_NAME;
+ }
+
+
+ void BootEncryption::RenameDeprecatedSystemLoaderBackup ()
+ {
+ char pathBuf[MAX_PATH];
+
+ if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA, NULL, 0, pathBuf)))
+ {
+ string path = string (pathBuf) + "\\" TC_APP_NAME + '\\' + TC_SYS_BOOT_LOADER_BACKUP_NAME_LEGACY;
+
+ if (FileExists (path.c_str()) && !FileExists (GetSystemLoaderBackupPath().c_str()))
+ throw_sys_if (rename (path.c_str(), GetSystemLoaderBackupPath().c_str()) != 0);
+ }
+ }
+
+
+#ifndef SETUP
+ void BootEncryption::CreateRescueIsoImage (bool initialSetup, const string &isoImagePath)
+ {
+ BootEncryptionStatus encStatus = GetStatus();
+ if (encStatus.SetupInProgress)
+ throw ParameterIncorrect (SRC_POS);
+
+ Buffer imageBuf (RescueIsoImageSize);
+
+ byte *image = imageBuf.Ptr();
+ memset (image, 0, RescueIsoImageSize);
+
+ // Primary volume descriptor
+ strcpy ((char *)image + 0x8000, "\001CD001\001");
+ strcpy ((char *)image + 0x7fff + 41, "TrueCrypt Rescue Disk ");
+ *(uint32 *) (image + 0x7fff + 81) = RescueIsoImageSize / 2048;
+ *(uint32 *) (image + 0x7fff + 85) = BE32 (RescueIsoImageSize / 2048);
+ image[0x7fff + 121] = 1;
+ image[0x7fff + 124] = 1;
+ image[0x7fff + 125] = 1;
+ image[0x7fff + 128] = 1;
+ image[0x7fff + 130] = 8;
+ image[0x7fff + 131] = 8;
+
+ image[0x7fff + 133] = 10;
+ image[0x7fff + 140] = 10;
+ image[0x7fff + 141] = 0x14;
+ image[0x7fff + 157] = 0x22;
+ image[0x7fff + 159] = 0x18;
+
+ // Boot record volume descriptor
+ strcpy ((char *)image + 0x8801, "CD001\001EL TORITO SPECIFICATION");
+ image[0x8800 + 0x47] = 0x19;
+
+ // Volume descriptor set terminator
+ strcpy ((char *)image + 0x9000, "\377CD001\001");
+
+ // Path table
+ image[0xA000 + 0] = 1;
+ image[0xA000 + 2] = 0x18;
+ image[0xA000 + 6] = 1;
+
+ // Root directory
+ image[0xc000 + 0] = 0x22;
+ image[0xc000 + 2] = 0x18;
+ image[0xc000 + 9] = 0x18;
+ image[0xc000 + 11] = 0x08;
+ image[0xc000 + 16] = 0x08;
+ image[0xc000 + 25] = 0x02;
+ image[0xc000 + 28] = 0x01;
+ image[0xc000 + 31] = 0x01;
+ image[0xc000 + 32] = 0x01;
+ image[0xc000 + 34] = 0x22;
+ image[0xc000 + 36] = 0x18;
+ image[0xc000 + 43] = 0x18;
+ image[0xc000 + 45] = 0x08;
+ image[0xc000 + 50] = 0x08;
+ image[0xc000 + 59] = 0x02;
+ image[0xc000 + 62] = 0x01;
+ *(uint32 *) (image + 0xc000 + 65) = 0x010101;
+
+ // Validation entry
+ image[0xc800] = 1;
+ int offset = 0xc800 + 0x1c;
+ image[offset++] = 0xaa;
+ image[offset++] = 0x55;
+ image[offset++] = 0x55;
+ image[offset] = 0xaa;
+
+ // Initial entry
+ offset = 0xc820;
+ image[offset++] = 0x88;
+ image[offset++] = 2;
+ image[0xc820 + 6] = 1;
+ image[0xc820 + 8] = TC_CD_BOOT_LOADER_SECTOR;
+
+ // TrueCrypt Boot Loader
+ CreateBootLoaderInMemory (image + TC_CD_BOOTSECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE, true);
+
+ // Volume header
+ if (initialSetup)
+ {
+ if (!RescueVolumeHeaderValid)
+ throw ParameterIncorrect (SRC_POS);
+
+ memcpy (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, RescueVolumeHeader, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ }
+ else
+ {
+ Device bootDevice (GetSystemDriveConfiguration().DevicePath, true);
+ bootDevice.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET);
+ bootDevice.Read (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET, TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE);
+ }
+
+ // Original system loader
+ try
+ {
+ File sysBakFile (GetSystemLoaderBackupPath(), true);
+ sysBakFile.Read (image + TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE);
+
+ image[TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_SECTOR_CONFIG_OFFSET] |= TC_BOOT_CFG_FLAG_RESCUE_DISK_ORIG_SYS_LOADER;
+ }
+ catch (Exception &e)
+ {
+ e.Show (ParentWindow);
+ Warning ("SYS_LOADER_UNAVAILABLE_FOR_RESCUE_DISK");
+ }
+
+ // Boot loader backup
+ CreateBootLoaderInMemory (image + TC_CD_BOOTSECTOR_OFFSET + TC_BOOT_LOADER_BACKUP_RESCUE_DISK_SECTOR_OFFSET, TC_BOOT_LOADER_AREA_SIZE, false);
+
+ RescueIsoImage = new byte[RescueIsoImageSize];
+ if (!RescueIsoImage)
+ throw bad_alloc();
+ memcpy (RescueIsoImage, image, RescueIsoImageSize);
+
+ if (!isoImagePath.empty())
+ {
+ File isoFile (isoImagePath, false, true);
+ isoFile.Write (image, RescueIsoImageSize);
+ }
+ }
+#endif
+
+
+ bool BootEncryption::IsCDDrivePresent ()
+ {
+ for (char drive = 'Z'; drive >= 'C'; --drive)
+ {
+ string path = "X:\\";
+ path[0] = drive;
+
+ if (GetDriveType (path.c_str()) == DRIVE_CDROM)
+ return true;
+ }
+
+ return false;
+ }
+
+
+ bool BootEncryption::VerifyRescueDisk ()
+ {
+ if (!RescueIsoImage)
+ throw ParameterIncorrect (SRC_POS);
+
+ for (char drive = 'Z'; drive >= 'C'; --drive)
+ {
+ try
+ {
+ string path = "X:";
+ path[0] = drive;
+
+ Device driveDevice (path, true);
+ size_t verifiedSectorCount = (TC_CD_BOOTSECTOR_OFFSET + TC_ORIG_BOOT_LOADER_BACKUP_SECTOR_OFFSET + TC_BOOT_LOADER_AREA_SIZE) / 2048;
+ Buffer buffer ((verifiedSectorCount + 1) * 2048);
+
+ DWORD bytesRead = driveDevice.Read (buffer.Ptr(), buffer.Size());
+ if (bytesRead != buffer.Size())
+ continue;
+
+ if (memcmp (buffer.Ptr(), RescueIsoImage, buffer.Size()) == 0)
+ return true;
+ }
+ catch (...) { }
+ }
+
+ return false;
+ }
+
+
+#ifndef SETUP
+
+ void BootEncryption::CreateVolumeHeader (uint64 volumeSize, uint64 encryptedAreaStart, Password *password, int ea, int mode, int pkcs5)
+ {
+ PCRYPTO_INFO cryptoInfo = NULL;
+
+ if (!IsRandomNumberGeneratorStarted())
+ throw ParameterIncorrect (SRC_POS);
+
+ throw_sys_if (CreateVolumeHeaderInMemory (TRUE, (char *) VolumeHeader, ea, mode, password, pkcs5, NULL, &cryptoInfo,
+ volumeSize, 0, encryptedAreaStart, 0, TC_SYSENC_KEYSCOPE_MIN_REQ_PROG_VERSION, TC_HEADER_FLAG_ENCRYPTED_SYSTEM, TC_SECTOR_SIZE_BIOS, FALSE) != 0);
+
+ finally_do_arg (PCRYPTO_INFO*, &cryptoInfo, { crypto_close (*finally_arg); });
+
+ // Initial rescue disk assumes encryption of the drive has been completed (EncryptedAreaLength == volumeSize)
+ memcpy (RescueVolumeHeader, VolumeHeader, sizeof (RescueVolumeHeader));
+ ReadVolumeHeader (TRUE, (char *) RescueVolumeHeader, password, NULL, cryptoInfo);
+
+ DecryptBuffer (RescueVolumeHeader + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
+
+ if (GetHeaderField32 (RescueVolumeHeader, TC_HEADER_OFFSET_MAGIC) != 0x54525545)
+ throw ParameterIncorrect (SRC_POS);
+
+ byte *fieldPos = RescueVolumeHeader + TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH;
+ mputInt64 (fieldPos, volumeSize);
+
+ // CRC of the header fields
+ uint32 crc = GetCrc32 (RescueVolumeHeader + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC);
+ fieldPos = RescueVolumeHeader + TC_HEADER_OFFSET_HEADER_CRC;
+ mputLong (fieldPos, crc);
+
+ EncryptBuffer (RescueVolumeHeader + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo);
+
+ VolumeHeaderValid = true;
+ RescueVolumeHeaderValid = true;
+ }
+
+
+ void BootEncryption::InstallVolumeHeader ()
+ {
+ if (!VolumeHeaderValid)
+ throw ParameterIncorrect (SRC_POS);
+
+ Device device (GetSystemDriveConfiguration().DevicePath);
+
+ device.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET);
+ device.Write ((byte *) VolumeHeader, sizeof (VolumeHeader));
+ }
+
+
+ // For synchronous operations use AbortSetupWait()
+ void BootEncryption::AbortSetup ()
+ {
+ CallDriver (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP);
+ }
+
+
+ // For asynchronous operations use AbortSetup()
+ void BootEncryption::AbortSetupWait ()
+ {
+ CallDriver (TC_IOCTL_ABORT_BOOT_ENCRYPTION_SETUP);
+
+ BootEncryptionStatus encStatus = GetStatus();
+
+ while (encStatus.SetupInProgress)
+ {
+ Sleep (TC_ABORT_TRANSFORM_WAIT_INTERVAL);
+ encStatus = GetStatus();
+ }
+ }
+
+
+ void BootEncryption::BackupSystemLoader ()
+ {
+ Device device (GetSystemDriveConfiguration().DevicePath, true);
+
+ byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS];
+
+ device.SeekAt (0);
+ device.Read (bootLoaderBuf, sizeof (bootLoaderBuf));
+
+ // Prevent TrueCrypt loader from being backed up
+ for (size_t i = 0; i < sizeof (bootLoaderBuf) - strlen (TC_APP_NAME); ++i)
+ {
+ if (memcmp (bootLoaderBuf + i, TC_APP_NAME, strlen (TC_APP_NAME)) == 0)
+ {
+ if (AskWarnNoYes ("TC_BOOT_LOADER_ALREADY_INSTALLED") == IDNO)
+ throw UserAbort (SRC_POS);
+ return;
+ }
+ }
+
+ File backupFile (GetSystemLoaderBackupPath(), false, true);
+ backupFile.Write (bootLoaderBuf, sizeof (bootLoaderBuf));
+ }
+
+
+ void BootEncryption::RestoreSystemLoader ()
+ {
+ byte bootLoaderBuf[TC_BOOT_LOADER_AREA_SECTOR_COUNT * TC_SECTOR_SIZE_BIOS];
+
+ File backupFile (GetSystemLoaderBackupPath(), true);
+
+ if (backupFile.Read (bootLoaderBuf, sizeof (bootLoaderBuf)) != sizeof (bootLoaderBuf))
+ throw ParameterIncorrect (SRC_POS);
+
+ Device device (GetSystemDriveConfiguration().DevicePath);
+
+ // Preserve current partition table
+ byte mbr[TC_SECTOR_SIZE_BIOS];
+ device.SeekAt (0);
+ device.Read (mbr, sizeof (mbr));
+ memcpy (bootLoaderBuf + TC_MAX_MBR_BOOT_CODE_SIZE, mbr + TC_MAX_MBR_BOOT_CODE_SIZE, sizeof (mbr) - TC_MAX_MBR_BOOT_CODE_SIZE);
+
+ device.SeekAt (0);
+ device.Write (bootLoaderBuf, sizeof (bootLoaderBuf));
+ }
+
+#endif // SETUP
+
+ void BootEncryption::RegisterFilter (bool registerFilter, FilterType filterType, const GUID *deviceClassGuid)
+ {
+ string filter;
+ string filterReg;
+ HKEY regKey;
+
+ switch (filterType)
+ {
+ case DriveFilter:
+ case VolumeFilter:
+ filter = "truecrypt";
+ filterReg = "UpperFilters";
+ regKey = SetupDiOpenClassRegKey (deviceClassGuid, KEY_READ | KEY_WRITE);
+ throw_sys_if (regKey == INVALID_HANDLE_VALUE);
+
+ break;
+
+ case DumpFilter:
+ if (!IsOSAtLeast (WIN_VISTA))
+ return;
+
+ filter = "truecrypt.sys";
+ filterReg = "DumpFilters";
+ SetLastError (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\CrashControl", 0, KEY_READ | KEY_WRITE, &regKey));
+ throw_sys_if (GetLastError() != ERROR_SUCCESS);
+
+ break;
+
+ default:
+ throw ParameterIncorrect (SRC_POS);
+ }
+
+ finally_do_arg (HKEY, regKey, { RegCloseKey (finally_arg); });
+
+ if (registerFilter && filterType != DumpFilter)
+ {
+ // Register class filter below all other filters in the stack
+
+ size_t strSize = filter.size() + 1;
+ byte regKeyBuf[65536];
+ DWORD size = sizeof (regKeyBuf) - strSize;
+
+ // SetupInstallFromInfSection() does not support prepending of values so we have to modify the registry directly
+ strncpy ((char *) regKeyBuf, filter.c_str(), sizeof (regKeyBuf));
+
+ if (RegQueryValueEx (regKey, filterReg.c_str(), NULL, NULL, regKeyBuf + strSize, &size) != ERROR_SUCCESS)
+ size = 1;
+
+ SetLastError (RegSetValueEx (regKey, filterReg.c_str(), 0, REG_MULTI_SZ, regKeyBuf, strSize + size));
+ throw_sys_if (GetLastError() != ERROR_SUCCESS);
+ }
+ else
+ {
+ string infFileName = GetTempPath() + "\\truecrypt_driver_setup.inf";
+
+ File infFile (infFileName, false, true);
+ finally_do_arg (string, infFileName, { DeleteFile (finally_arg.c_str()); });
+
+ string infTxt = "[truecrypt]\r\n"
+ + string (registerFilter ? "Add" : "Del") + "Reg=truecrypt_reg\r\n\r\n"
+ "[truecrypt_reg]\r\n"
+ "HKR,,\"" + filterReg + "\",0x0001" + string (registerFilter ? "0008" : "8002") + ",\"" + filter + "\"\r\n";
+
+ infFile.Write ((byte *) infTxt.c_str(), infTxt.size());
+ infFile.Close();
+
+ HINF hInf = SetupOpenInfFile (infFileName.c_str(), NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL);
+ throw_sys_if (hInf == INVALID_HANDLE_VALUE);
+ finally_do_arg (HINF, hInf, { SetupCloseInfFile (finally_arg); });
+
+ throw_sys_if (!SetupInstallFromInfSection (ParentWindow, hInf, "truecrypt", SPINST_REGISTRY, regKey, NULL, 0, NULL, NULL, NULL, NULL));
+ }
+ }
+
+ void BootEncryption::RegisterFilterDriver (bool registerDriver, FilterType filterType)
+ {
+ if (!IsAdmin() && IsUacSupported())
+ {
+ Elevator::RegisterFilterDriver (registerDriver, filterType);
+ return;
+ }
+
+ switch (filterType)
+ {
+ case DriveFilter:
+ RegisterFilter (registerDriver, filterType, &GUID_DEVCLASS_DISKDRIVE);
+ break;
+
+ case VolumeFilter:
+ RegisterFilter (registerDriver, filterType, &GUID_DEVCLASS_VOLUME);
+ RegisterFilter (registerDriver, filterType, &GUID_DEVCLASS_FLOPPYDISK);
+ break;
+
+ case DumpFilter:
+ RegisterFilter (registerDriver, filterType);
+ break;
+
+ default:
+ throw ParameterIncorrect (SRC_POS);
+ }
+ }
+
+#ifndef SETUP
+
+ void BootEncryption::RegisterSystemFavoritesService (BOOL registerService)
+ {
+ if (!IsAdmin() && IsUacSupported())
+ {
+ Elevator::RegisterSystemFavoritesService (registerService);
+ return;
+ }
+
+ SC_HANDLE scm = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ throw_sys_if (!scm);
+
+ string servicePath = GetServiceConfigPath (TC_APP_NAME ".exe");
+
+ if (registerService)
+ {
+ try
+ {
+ RegisterSystemFavoritesService (FALSE);
+ }
+ catch (...) { }
+
+ char appPath[TC_MAX_PATH];
+ throw_sys_if (!GetModuleFileName (NULL, appPath, sizeof (appPath)));
+
+ throw_sys_if (!CopyFile (appPath, servicePath.c_str(), FALSE));
+
+ SC_HANDLE service = CreateService (scm,
+ TC_SYSTEM_FAVORITES_SERVICE_NAME,
+ TC_APP_NAME " System Favorites",
+ SERVICE_ALL_ACCESS,
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_AUTO_START,
+ SERVICE_ERROR_NORMAL,
+ (string ("\"") + servicePath + "\" " TC_SYSTEM_FAVORITES_SERVICE_CMDLINE_OPTION).c_str(),
+ TC_SYSTEM_FAVORITES_SERVICE_LOAD_ORDER_GROUP,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+
+ throw_sys_if (!service);
+
+ SERVICE_DESCRIPTION description;
+ description.lpDescription = "Mounts TrueCrypt system favorite volumes.";
+ ChangeServiceConfig2 (service, SERVICE_CONFIG_DESCRIPTION, &description);
+
+ CloseServiceHandle (service);
+
+ try
+ {
+ WriteLocalMachineRegistryString ("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Minimal\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, NULL, "Service", FALSE);
+ WriteLocalMachineRegistryString ("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Network\\" TC_SYSTEM_FAVORITES_SERVICE_NAME, NULL, "Service", FALSE);
+
+ SetDriverConfigurationFlag (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES, true);
+ }
+ catch (...)
+ {
+ try
+ {
+ RegisterSystemFavoritesService (false);
+ }
+ catch (...) { }
+
+ throw;
+ }
+ }
+ else
+ {
+ SetDriverConfigurationFlag (TC_DRIVER_CONFIG_CACHE_BOOT_PASSWORD_FOR_SYS_FAVORITES, false);
+
+ DeleteLocalMachineRegistryKey ("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Minimal", TC_SYSTEM_FAVORITES_SERVICE_NAME);
+ DeleteLocalMachineRegistryKey ("SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Network", TC_SYSTEM_FAVORITES_SERVICE_NAME);
+
+ SC_HANDLE service = OpenService (scm, TC_SYSTEM_FAVORITES_SERVICE_NAME, SERVICE_ALL_ACCESS);
+ throw_sys_if (!service);
+
+ throw_sys_if (!DeleteService (service));
+ CloseServiceHandle (service);
+
+ DeleteFile (servicePath.c_str());
+ }
+ }
+
+ void BootEncryption::CheckRequirements ()
+ {
+ if (nCurrentOS == WIN_2000)
+ throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_CURRENT_OS");
+
+ if (CurrentOSMajor == 6 && CurrentOSMinor == 0 && CurrentOSServicePack < 1)
+ throw ErrorException ("SYS_ENCRYPTION_UNSUPPORTED_ON_VISTA_SP0");
+
+ if (IsNonInstallMode())
+ throw ErrorException ("FEATURE_REQUIRES_INSTALLATION");
+
+ SystemDriveConfiguration config = GetSystemDriveConfiguration ();
+
+ if (config.SystemPartition.IsGPT)
+ throw ErrorException ("GPT_BOOT_DRIVE_UNSUPPORTED");
+
+ if (SystemDriveIsDynamic())
+ throw ErrorException ("SYSENC_UNSUPPORTED_FOR_DYNAMIC_DISK");
+
+ if (config.InitialUnallocatedSpace < TC_BOOT_LOADER_AREA_SIZE)
+ throw ErrorException ("NO_SPACE_FOR_BOOT_LOADER");
+
+ DISK_GEOMETRY geometry = GetDriveGeometry (config.DriveNumber);
+
+ if (geometry.BytesPerSector != TC_SECTOR_SIZE_BIOS)
+ throw ErrorException ("SYSENC_UNSUPPORTED_SECTOR_SIZE_BIOS");
+
+ bool activePartitionFound = false;
+ if (!config.SystemPartition.IsGPT)
+ {
+ // Determine whether there is an Active partition on the system drive
+ foreach (const Partition &partition, config.Partitions)
+ {
+ if (partition.Info.BootIndicator)
+ {
+ activePartitionFound = true;
+ break;
+ }
+ }
+ }
+
+ if (!config.SystemLoaderPresent || !activePartitionFound)
+ {
+ static bool confirmed = false;
+
+ if (!confirmed && AskWarnNoYes ("WINDOWS_NOT_ON_BOOT_DRIVE_ERROR") == IDNO)
+ throw UserAbort (SRC_POS);
+
+ confirmed = true;
+ }
+ }
+
+
+ void BootEncryption::CheckRequirementsHiddenOS ()
+ {
+ // It is assumed that CheckRequirements() had been called (so we don't check e.g. whether it's GPT).
+
+ // The user may have modified/added/deleted partitions since the partition table was last scanned.
+ InvalidateCachedSysDriveProperties ();
+
+ GetPartitionForHiddenOS ();
+ }
+
+
+ void BootEncryption::InitialSecurityChecksForHiddenOS ()
+ {
+ char windowsDrive = (char) toupper (GetWindowsDirectory()[0]);
+
+ // Paging files
+ bool pagingFilesOk = !IsPagingFileActive (TRUE);
+
+ char pagingFileRegData[65536];
+ DWORD pagingFileRegDataSize = sizeof (pagingFileRegData);
+
+ if (ReadLocalMachineRegistryMultiString ("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", "PagingFiles", pagingFileRegData, &pagingFileRegDataSize)
+ && pagingFileRegDataSize > 4)
+ {
+ for (size_t i = 1; i < pagingFileRegDataSize - 2; ++i)
+ {
+ if (memcmp (pagingFileRegData + i, ":\\", 2) == 0 && toupper (pagingFileRegData[i - 1]) != windowsDrive)
+ {
+ pagingFilesOk = false;
+ break;
+ }
+ }
+ }
+
+ if (!pagingFilesOk)
+ {
+ if (AskWarnYesNoString ((wchar_t *) (wstring (GetString ("PAGING_FILE_NOT_ON_SYS_PARTITION"))
+ + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION")
+ + L"\n\n\n"
+ + GetString ("RESTRICT_PAGING_FILES_TO_SYS_PARTITION")
+ ).c_str()) == IDYES)
+ {
+ RestrictPagingFilesToSystemPartition();
+ RestartComputer();
+ AbortProcessSilent();
+ }
+
+ throw ErrorException (wstring (GetString ("PAGING_FILE_NOT_ON_SYS_PARTITION"))
+ + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"));
+ }
+
+ // User profile
+ char *configPath = GetConfigPath ("dummy");
+ if (configPath && toupper (configPath[0]) != windowsDrive)
+ {
+ throw ErrorException (wstring (GetString ("USER_PROFILE_NOT_ON_SYS_PARTITION"))
+ + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"));
+ }
+
+ // Temporary files
+ if (toupper (GetTempPath()[0]) != windowsDrive)
+ {
+ throw ErrorException (wstring (GetString ("TEMP_NOT_ON_SYS_PARTITION"))
+ + GetString ("LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"));
+ }
+ }
+
+
+ // This operation may take a long time when an antivirus is installed and its real-time protection enabled.
+ // Therefore, if calling it without the wizard displayed, it should be called with displayWaitDialog set to true.
+ void BootEncryption::Deinstall (bool displayWaitDialog)
+ {
+ BootEncryptionStatus encStatus = GetStatus();
+
+ if (encStatus.DriveEncrypted || encStatus.DriveMounted)
+ throw ParameterIncorrect (SRC_POS);
+
+ SystemDriveConfiguration config = GetSystemDriveConfiguration ();
+
+ if (encStatus.VolumeHeaderPresent)
+ {
+ // Verify CRC of header salt
+ Device device (config.DevicePath, true);
+ byte header[TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE];
+
+ device.SeekAt (TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET);
+ device.Read (header, sizeof (header));
+
+ if (encStatus.VolumeHeaderSaltCrc32 != GetCrc32 ((byte *) header, PKCS5_SALT_SIZE))
+ throw ParameterIncorrect (SRC_POS);
+ }
+
+ try
+ {
+ RegisterFilterDriver (false, DriveFilter);
+ RegisterFilterDriver (false, VolumeFilter);
+ RegisterFilterDriver (false, DumpFilter);
+ SetDriverServiceStartType (SERVICE_SYSTEM_START);
+ }
+ catch (...)
+ {
+ try
+ {
+ RegisterBootDriver (IsHiddenSystemRunning());
+ }
+ catch (...) { }
+
+ throw;
+ }
+
+ SetHiddenOSCreationPhase (TC_HIDDEN_OS_CREATION_PHASE_NONE); // In case RestoreSystemLoader() fails
+
+ try
+ {
+ RegisterSystemFavoritesService (false);
+ }
+ catch (...) { }
+
+ try
+ {
+ if (displayWaitDialog)
+ DisplayStaticModelessWaitDlg (ParentWindow);
+
+ finally_do_arg (bool, displayWaitDialog, { if (finally_arg) CloseStaticModelessWaitDlg(); });
+
+ RestoreSystemLoader ();
+ }
+ catch (Exception &e)
+ {
+ e.Show (ParentWindow);
+ throw ErrorException ("SYS_LOADER_RESTORE_FAILED");
+ }
+ }
+
+
+ int BootEncryption::ChangePassword (Password *oldPassword, Password *newPassword, int pkcs5)
+ {
+ BootEncryptionStatus encStatus = GetStatus();
+
+ if (encStatus.SetupInProgress)
+ throw ParameterIncorrect (SRC_POS);
+
+ SystemDriveConfiguration config = GetSystemDriveConfiguration ();
+
+ char header[TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE];
+ Device device (config.DevicePath);
+
+ // Only one algorithm is currently supported
+ if (pkcs5 != 0)
+ throw ParameterIncorrect (SRC_POS);
+
+ int64 headerOffset = TC_BOOT_VOLUME_HEADER_SECTOR_OFFSET;
+ int64 backupHeaderOffset = -1;
+
+ if (encStatus.HiddenSystem)
+ {
+ headerOffset = encStatus.HiddenSystemPartitionStart + TC_HIDDEN_VOLUME_HEADER_OFFSET;
+
+ // Find hidden system partition
+ foreach (const Partition &partition, config.Partitions)
+ {
+ if (partition.Info.StartingOffset.QuadPart == encStatus.HiddenSystemPartitionStart)
+ {
+ backupHeaderOffset = partition.Info.StartingOffset.QuadPart + partition.Info.PartitionLength.QuadPart - TC_VOLUME_HEADER_SIZE;
+ break;
+ }
+ }
+
+ if (backupHeaderOffset == -1)
+ throw ParameterIncorrect (SRC_POS);
+ }
+
+ device.SeekAt (headerOffset);
+ device.Read ((byte *) header, sizeof (header));
+
+ PCRYPTO_INFO cryptoInfo = NULL;
+
+ int status = ReadVolumeHeader (!encStatus.HiddenSystem, header, oldPassword, &cryptoInfo, NULL);
+ finally_do_arg (PCRYPTO_INFO, cryptoInfo, { if (finally_arg) crypto_close (finally_arg); });
+
+ if (status != 0)
+ {
+ handleError (ParentWindow, status);
+ return status;
+ }
+
+ // Change the PKCS-5 PRF if requested by user
+ if (pkcs5 != 0)
+ {
+ cryptoInfo->pkcs5 = pkcs5;
+ RandSetHashFunction (pkcs5);
+ }
+
+ throw_sys_if (Randinit () != 0);
+ finally_do ({ RandStop (FALSE); });
+
+ NormalCursor();
+ UserEnrichRandomPool (ParentWindow);
+ WaitCursor();
+
+ /* The header will be re-encrypted PRAND_DISK_WIPE_PASSES times to prevent adversaries from using
+ techniques such as magnetic force microscopy or magnetic force scanning tunnelling microscopy
+ to recover the overwritten header. According to Peter Gutmann, data should be overwritten 22
+ times (ideally, 35 times) using non-random patterns and pseudorandom data. However, as users might
+ impatiently interupt the process (etc.) we will not use the Gutmann's patterns but will write the
+ valid re-encrypted header, i.e. pseudorandom data, and there will be many more passes than Guttman
+ recommends. During each pass we will write a valid working header. Each pass will use the same master
+ key, and also the same header key, secondary key (XTS), etc., derived from the new password. The only
+ item that will be different for each pass will be the salt. This is sufficient to cause each "version"
+ of the header to differ substantially and in a random manner from the versions written during the
+ other passes. */
+
+ bool headerUpdated = false;
+ int result = ERR_SUCCESS;
+
+ try
+ {
+ BOOL backupHeader = FALSE;
+ while (TRUE)
+ {
+ for (int wipePass = 0; wipePass < PRAND_DISK_WIPE_PASSES; wipePass++)
+ {
+ PCRYPTO_INFO tmpCryptoInfo = NULL;
+
+ status = CreateVolumeHeaderInMemory (!encStatus.HiddenSystem,
+ header,
+ cryptoInfo->ea,
+ cryptoInfo->mode,
+ newPassword,
+ cryptoInfo->pkcs5,
+ (char *) cryptoInfo->master_keydata,
+ &tmpCryptoInfo,
+ cryptoInfo->VolumeSize.Value,
+ cryptoInfo->hiddenVolumeSize,
+ cryptoInfo->EncryptedAreaStart.Value,
+ cryptoInfo->EncryptedAreaLength.Value,
+ cryptoInfo->RequiredProgramVersion,
+ cryptoInfo->HeaderFlags | TC_HEADER_FLAG_ENCRYPTED_SYSTEM,
+ cryptoInfo->SectorSize,
+ wipePass < PRAND_DISK_WIPE_PASSES - 1);
+
+ if (tmpCryptoInfo)
+ crypto_close (tmpCryptoInfo);
+
+ if (status != 0)
+ {
+ handleError (ParentWindow, status);
+ return status;
+ }
+
+ device.SeekAt (headerOffset);
+ device.Write ((byte *) header, sizeof (header));
+ headerUpdated = true;
+ }
+
+ if (!encStatus.HiddenSystem || backupHeader)
+ break;
+
+ backupHeader = TRUE;
+ headerOffset = backupHeaderOffset;
+ }
+ }
+ catch (Exception &e)
+ {
+ e.Show (ParentWindow);
+ result = ERR_OS_ERROR;
+ }
+
+ if (headerUpdated)
+ {
+ ReopenBootVolumeHeaderRequest reopenRequest;
+ reopenRequest.VolumePassword = *newPassword;
+ finally_do_arg (ReopenBootVolumeHeaderRequest*, &reopenRequest, { burn (finally_arg, sizeof (*finally_arg)); });
+
+ CallDriver (TC_IOCTL_REOPEN_BOOT_VOLUME_HEADER, &reopenRequest, sizeof (reopenRequest));
+ }
+
+ return result;
+ }
+
+
+ void BootEncryption::CheckEncryptionSetupResult ()
+ {
+ CallDriver (TC_IOCTL_GET_BOOT_ENCRYPTION_SETUP_RESULT);
+ }
+
+
+ void BootEncryption::Install (bool hiddenSystem)
+ {
+ BootEncryptionStatus encStatus = GetStatus();
+ if (encStatus.DriveMounted)
+ throw ParameterIncorrect (SRC_POS);
+
+ try
+ {
+ InstallBootLoader (false, hiddenSystem);
+
+ if (!hiddenSystem)
+ InstallVolumeHeader ();
+
+ RegisterBootDriver (hiddenSystem);
+ }
+ catch (Exception &)
+ {
+ try
+ {
+ RestoreSystemLoader ();
+ }
+ catch (Exception &e)
+ {
+ e.Show (ParentWindow);
+ }
+
+ throw;
+ }
+ }
+
+
+ void BootEncryption::PrepareHiddenOSCreation (int ea, int mode, int pkcs5)
+ {
+ BootEncryptionStatus encStatus = GetStatus();
+ if (encStatus.DriveMounted)
+ throw ParameterIncorrect (SRC_POS);
+
+ CheckRequirements();
+ BackupSystemLoader();
+
+ SelectedEncryptionAlgorithmId = ea;
+ }
+
+
+ void BootEncryption::PrepareInstallation (bool systemPartitionOnly, Password &password, int ea, int mode, int pkcs5, const string &rescueIsoImagePath)
+ {
+ BootEncryptionStatus encStatus = GetStatus();
+ if (encStatus.DriveMounted)
+ throw ParameterIncorrect (SRC_POS);
+
+ CheckRequirements ();
+
+ SystemDriveConfiguration config = GetSystemDriveConfiguration();
+
+ // Some chipset drivers may prevent access to the last sector of the drive
+ if (!systemPartitionOnly)
+ {
+ DISK_GEOMETRY geometry = GetDriveGeometry (config.DriveNumber);
+ Buffer sector (geometry.BytesPerSector);
+
+ Device device (config.DevicePath);
+
+ try
+ {
+ device.SeekAt (config.DrivePartition.Info.PartitionLength.QuadPart - geometry.BytesPerSector);
+ device.Read (sector.Ptr(), sector.Size());
+ }
+ catch (SystemException &e)
+ {
+ if (e.ErrorCode != ERROR_CRC)
+ {
+ e.Show (ParentWindow);
+ Error ("WHOLE_DRIVE_ENCRYPTION_PREVENTED_BY_DRIVERS");
+ throw UserAbort (SRC_POS);
+ }
+ }
+ }
+
+ BackupSystemLoader ();
+
+ uint64 volumeSize;
+ uint64 encryptedAreaStart;
+
+ if (systemPartitionOnly)
+ {
+ volumeSize = config.SystemPartition.Info.PartitionLength.QuadPart;
+ encryptedAreaStart = config.SystemPartition.Info.StartingOffset.QuadPart;
+ }
+ else
+ {
+ volumeSize = config.DrivePartition.Info.PartitionLength.QuadPart - TC_BOOT_LOADER_AREA_SIZE;
+ encryptedAreaStart = config.DrivePartition.Info.StartingOffset.QuadPart + TC_BOOT_LOADER_AREA_SIZE;
+ }
+
+ SelectedEncryptionAlgorithmId = ea;
+ CreateVolumeHeader (volumeSize, encryptedAreaStart, &password, ea, mode, pkcs5);
+
+ if (!rescueIsoImagePath.empty())
+ CreateRescueIsoImage (true, rescueIsoImagePath);
+ }
+
+ bool BootEncryption::IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly)
+ {
+ if (!IsAdmin() && IsUacSupported())
+ return Elevator::IsPagingFileActive (checkNonWindowsPartitionsOnly) ? true : false;
+
+ return ::IsPagingFileActive (checkNonWindowsPartitionsOnly) ? true : false;
+ }
+
+ void BootEncryption::RestrictPagingFilesToSystemPartition ()
+ {
+ char pagingFiles[128];
+ strncpy (pagingFiles, "X:\\pagefile.sys 0 0", sizeof (pagingFiles));
+ pagingFiles[0] = GetWindowsDirectory()[0];
+
+ throw_sys_if (!WriteLocalMachineRegistryMultiString ("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", "PagingFiles", pagingFiles, strlen (pagingFiles) + 2));
+ }
+
+ void BootEncryption::WriteLocalMachineRegistryDwordValue (char *keyPath, char *valueName, DWORD value)
+ {
+ if (!IsAdmin() && IsUacSupported())
+ {
+ Elevator::WriteLocalMachineRegistryDwordValue (keyPath, valueName, value);
+ return;
+ }
+
+ throw_sys_if (!WriteLocalMachineRegistryDword (keyPath, valueName, value));
+ }
+
+ void BootEncryption::SetDriverConfigurationFlag (uint32 flag, bool state)
+ {
+ DWORD configMap = ReadDriverConfigurationFlags();
+
+ if (state)
+ configMap |= flag;
+ else
+ configMap &= ~flag;
+
+ WriteLocalMachineRegistryDwordValue ("SYSTEM\\CurrentControlSet\\Services\\truecrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, configMap);
+ }
+
+ void BootEncryption::StartDecryption (BOOL discardUnreadableEncryptedSectors)
+ {
+ BootEncryptionStatus encStatus = GetStatus();
+
+ if (!encStatus.DeviceFilterActive || !encStatus.DriveMounted || encStatus.SetupInProgress)
+ throw ParameterIncorrect (SRC_POS);
+
+ BootEncryptionSetupRequest request;
+ ZeroMemory (&request, sizeof (request));
+
+ request.SetupMode = SetupDecryption;
+ request.DiscardUnreadableEncryptedSectors = discardUnreadableEncryptedSectors;
+
+ CallDriver (TC_IOCTL_BOOT_ENCRYPTION_SETUP, &request, sizeof (request), NULL, 0);
+ }
+
+ void BootEncryption::StartEncryption (WipeAlgorithmId wipeAlgorithm, bool zeroUnreadableSectors)
+ {
+ BootEncryptionStatus encStatus = GetStatus();
+
+ if (!encStatus.DeviceFilterActive || !encStatus.DriveMounted || encStatus.SetupInProgress)
+ throw ParameterIncorrect (SRC_POS);
+
+ BootEncryptionSetupRequest request;
+ ZeroMemory (&request, sizeof (request));
+
+ request.SetupMode = SetupEncryption;
+ request.WipeAlgorithm = wipeAlgorithm;
+ request.ZeroUnreadableSectors = zeroUnreadableSectors;
+
+ CallDriver (TC_IOCTL_BOOT_ENCRYPTION_SETUP, &request, sizeof (request), NULL, 0);
+ }
+
+ void BootEncryption::CopyFileAdmin (const string &sourceFile, const string &destinationFile)
+ {
+ if (!IsAdmin())
+ {
+ if (!IsUacSupported())
+ {
+ SetLastError (ERROR_ACCESS_DENIED);
+ throw SystemException();
+ }
+ else
+ Elevator::CopyFile (sourceFile, destinationFile);
+ }
+ else
+ throw_sys_if (!::CopyFile (sourceFile.c_str(), destinationFile.c_str(), FALSE));
+ }
+
+ void BootEncryption::DeleteFileAdmin (const string &file)
+ {
+ if (!IsAdmin() && IsUacSupported())
+ Elevator::DeleteFile (file);
+ else
+ throw_sys_if (!::DeleteFile (file.c_str()));
+ }
+
+#endif // !SETUP
+
+ uint32 BootEncryption::ReadDriverConfigurationFlags ()
+ {
+ DWORD configMap;
+
+ if (!ReadLocalMachineRegistryDword ("SYSTEM\\CurrentControlSet\\Services\\truecrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, &configMap))
+ configMap = 0;
+
+ return configMap;
+ }
+
+ void BootEncryption::WriteBootDriveSector (uint64 offset, byte *data)
+ {
+ WriteBootDriveSectorRequest request;
+ request.Offset.QuadPart = offset;
+ memcpy (request.Data, data, sizeof (request.Data));
+
+ CallDriver (TC_IOCTL_WRITE_BOOT_DRIVE_SECTOR, &request, sizeof (request), NULL, 0);
+ }
+
+ void BootEncryption::RegisterBootDriver (bool hiddenSystem)
+ {
+ SetDriverServiceStartType (SERVICE_BOOT_START);
+
+ try
+ {
+ RegisterFilterDriver (false, DriveFilter);
+ RegisterFilterDriver (false, VolumeFilter);
+ RegisterFilterDriver (false, DumpFilter);
+ }
+ catch (...) { }
+
+ try
+ {
+ RegisterFilterDriver (true, DriveFilter);
+
+ if (hiddenSystem)
+ RegisterFilterDriver (true, VolumeFilter);
+
+ RegisterFilterDriver (true, DumpFilter);
+ }
+ catch (...)
+ {
+ try { RegisterFilterDriver (false, DriveFilter); } catch (...) { }
+ try { RegisterFilterDriver (false, VolumeFilter); } catch (...) { }
+ try { RegisterFilterDriver (false, DumpFilter); } catch (...) { }
+ try { SetDriverServiceStartType (SERVICE_SYSTEM_START); } catch (...) { }
+
+ throw;
+ }
+ }
+
+ bool BootEncryption::RestartComputer (void)
+ {
+ return (::RestartComputer() != FALSE);
+ }
+}
diff --git a/src/Common/BootEncryption.h b/src/Common/BootEncryption.h
new file mode 100644
index 00000000..febbdf5b
--- /dev/null
+++ b/src/Common/BootEncryption.h
@@ -0,0 +1,241 @@
+/*
+ Copyright (c) 2008-2010 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef TC_HEADER_Common_BootEncryption
+#define TC_HEADER_Common_BootEncryption
+
+#include "Tcdefs.h"
+#include "Dlgcode.h"
+#include "Exception.h"
+#include "Platform/PlatformBase.h"
+#include "Volumes.h"
+
+using namespace std;
+
+namespace TrueCrypt
+{
+ class File
+ {
+ public:
+ File () : FileOpen (false) { }
+ File (string path, bool readOnly = false, bool create = false);
+ ~File () { Close(); }
+
+ void Close ();
+ DWORD Read (byte *buffer, DWORD size);
+ void Write (byte *buffer, DWORD size);
+ void SeekAt (int64 position);
+
+ protected:
+ bool Elevated;
+ bool FileOpen;
+ uint64 FilePointerPosition;
+ HANDLE Handle;
+ bool IsDevice;
+ string Path;
+ };
+
+
+ class Device : public File
+ {
+ public:
+ Device (string path, bool readOnly = false);
+ };
+
+
+ class Buffer
+ {
+ public:
+ Buffer (size_t size) : DataSize (size)
+ {
+ DataPtr = new byte[size];
+ if (!DataPtr)
+ throw bad_alloc();
+ }
+
+ ~Buffer () { delete[] DataPtr; }
+ byte *Ptr () const { return DataPtr; }
+ size_t Size () const { return DataSize; }
+
+ protected:
+ byte *DataPtr;
+ size_t DataSize;
+ };
+
+
+ struct Partition
+ {
+ string DevicePath;
+ PARTITION_INFORMATION Info;
+ string MountPoint;
+ size_t Number;
+ BOOL IsGPT;
+ wstring VolumeNameId;
+ };
+
+ typedef list <Partition> PartitionList;
+
+#pragma pack (push)
+#pragma pack(1)
+
+ struct PartitionEntryMBR
+ {
+ byte BootIndicator;
+
+ byte StartHead;
+ byte StartCylSector;
+ byte StartCylinder;
+
+ byte Type;
+
+ byte EndHead;
+ byte EndSector;
+ byte EndCylinder;
+
+ uint32 StartLBA;
+ uint32 SectorCountLBA;
+ };
+
+ struct MBR
+ {
+ byte Code[446];
+ PartitionEntryMBR Partitions[4];
+ uint16 Signature;
+ };
+
+#pragma pack (pop)
+
+ struct SystemDriveConfiguration
+ {
+ string DeviceKernelPath;
+ string DevicePath;
+ int DriveNumber;
+ Partition DrivePartition;
+ bool ExtraBootPartitionPresent;
+ int64 InitialUnallocatedSpace;
+ PartitionList Partitions;
+ Partition SystemPartition;
+ int64 TotalUnallocatedSpace;
+ bool SystemLoaderPresent;
+ };
+
+ class BootEncryption
+ {
+ public:
+ BootEncryption (HWND parent);
+ ~BootEncryption ();
+
+ enum FilterType
+ {
+ DriveFilter,
+ VolumeFilter,
+ DumpFilter
+ };
+
+ void AbortDecoyOSWipe ();
+ void AbortSetup ();
+ void AbortSetupWait ();
+ void CallDriver (DWORD ioctl, void *input = nullptr, DWORD inputSize = 0, void *output = nullptr, DWORD outputSize = 0);
+ int ChangePassword (Password *oldPassword, Password *newPassword, int pkcs5);
+ void CheckDecoyOSWipeResult ();
+ void CheckEncryptionSetupResult ();
+ void CheckRequirements ();
+ void CheckRequirementsHiddenOS ();
+ void CopyFileAdmin (const string &sourceFile, const string &destinationFile);
+ void CreateRescueIsoImage (bool initialSetup, const string &isoImagePath);
+ void Deinstall (bool displayWaitDialog = false);
+ void DeleteFileAdmin (const string &file);
+ DecoySystemWipeStatus GetDecoyOSWipeStatus ();
+ DWORD GetDriverServiceStartType ();
+ unsigned int GetHiddenOSCreationPhase ();
+ uint16 GetInstalledBootLoaderVersion ();
+ Partition GetPartitionForHiddenOS ();
+ bool IsBootLoaderOnDrive (char *devicePath);
+ BootEncryptionStatus GetStatus ();
+ string GetTempPath ();
+ void GetVolumeProperties (VOLUME_PROPERTIES_STRUCT *properties);
+ SystemDriveConfiguration GetSystemDriveConfiguration ();
+ void Install (bool hiddenSystem);
+ void InstallBootLoader (bool preserveUserConfig = false, bool hiddenOSCreation = false);
+ void InvalidateCachedSysDriveProperties ();
+ bool IsCDDrivePresent ();
+ bool IsHiddenSystemRunning ();
+ bool IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly);
+ void PrepareHiddenOSCreation (int ea, int mode, int pkcs5);
+ void PrepareInstallation (bool systemPartitionOnly, Password &password, int ea, int mode, int pkcs5, const string &rescueIsoImagePath);
+ void ProbeRealSystemDriveSize ();
+ void ReadBootSectorConfig (byte *config, size_t bufLength, byte *userConfig = nullptr, string *customUserMessage = nullptr, uint16 *bootLoaderVersion = nullptr);
+ uint32 ReadDriverConfigurationFlags ();
+ void RegisterBootDriver (bool hiddenSystem);
+ void RegisterFilterDriver (bool registerDriver, FilterType filterType);
+ void RegisterSystemFavoritesService (BOOL registerService);
+ void RenameDeprecatedSystemLoaderBackup ();
+ bool RestartComputer (void);
+ void InitialSecurityChecksForHiddenOS ();
+ void RestrictPagingFilesToSystemPartition ();
+ void SetDriverConfigurationFlag (uint32 flag, bool state);
+ void SetDriverServiceStartType (DWORD startType);
+ void SetHiddenOSCreationPhase (unsigned int newPhase);
+ void StartDecryption (BOOL discardUnreadableEncryptedSectors);
+ void StartDecoyOSWipe (WipeAlgorithmId wipeAlgorithm);
+ void StartEncryption (WipeAlgorithmId wipeAlgorithm, bool zeroUnreadableSectors);
+ bool SystemDriveContainsPartitionType (byte type);
+ bool SystemDriveContainsExtendedPartition ();
+ bool SystemDriveContainsNonStandardPartitions ();
+ bool SystemPartitionCoversWholeDrive ();
+ bool SystemDriveIsDynamic ();
+ bool VerifyRescueDisk ();
+ void WipeHiddenOSCreationConfig ();
+ void WriteBootDriveSector (uint64 offset, byte *data);
+ void WriteBootSectorConfig (const byte newConfig[]);
+ void WriteBootSectorUserConfig (byte userConfig, const string &customUserMessage);
+ void WriteLocalMachineRegistryDwordValue (char *keyPath, char *valueName, DWORD value);
+
+ protected:
+ static const uint32 RescueIsoImageSize = 1835008; // Size of ISO9660 image with bootable emulated 1.44MB floppy disk image
+
+ void BackupSystemLoader ();
+ void CreateBootLoaderInMemory (byte *buffer, size_t bufferSize, bool rescueDisk, bool hiddenOSCreation = false);
+ void CreateVolumeHeader (uint64 volumeSize, uint64 encryptedAreaStart, Password *password, int ea, int mode, int pkcs5);
+ string GetSystemLoaderBackupPath ();
+ uint32 GetChecksum (byte *data, size_t size);
+ DISK_GEOMETRY GetDriveGeometry (int driveNumber);
+ PartitionList GetDrivePartitions (int driveNumber);
+ wstring GetRemarksOnHiddenOS ();
+ string GetWindowsDirectory ();
+ void RegisterFilter (bool registerFilter, FilterType filterType, const GUID *deviceClassGuid = nullptr);
+ void RestoreSystemLoader ();
+ void InstallVolumeHeader ();
+
+ HWND ParentWindow;
+ SystemDriveConfiguration DriveConfig;
+ int SelectedEncryptionAlgorithmId;
+ Partition HiddenOSCandidatePartition;
+ byte *RescueIsoImage;
+ byte RescueVolumeHeader[TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE];
+ byte VolumeHeader[TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE];
+ bool DriveConfigValid;
+ bool RealSystemDriveSizeValid;
+ bool RescueVolumeHeaderValid;
+ bool VolumeHeaderValid;
+ };
+}
+
+#define TC_ABORT_TRANSFORM_WAIT_INTERVAL 10
+
+#define MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_NTFS 2.1
+#define MIN_HIDDENOS_DECOY_PARTITION_SIZE_RATIO_FAT 1.05
+
+#define TC_SYS_BOOT_LOADER_BACKUP_NAME "Original System Loader"
+#define TC_SYS_BOOT_LOADER_BACKUP_NAME_LEGACY "Original System Loader.bak" // Deprecated to prevent removal by some "cleaners"
+
+#define TC_SYSTEM_FAVORITES_SERVICE_NAME TC_APP_NAME "SystemFavorites"
+#define TC_SYSTEM_FAVORITES_SERVICE_LOAD_ORDER_GROUP "Event Log"
+#define TC_SYSTEM_FAVORITES_SERVICE_CMDLINE_OPTION "/systemFavoritesService"
+
+#endif // TC_HEADER_Common_BootEncryption
diff --git a/src/Common/Cache.c b/src/Common/Cache.c
new file mode 100644
index 00000000..e119681e
--- /dev/null
+++ b/src/Common/Cache.c
@@ -0,0 +1,94 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2008 TrueCrypt Developers Association
+ and are 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 "Tcdefs.h"
+#include "Crypto.h"
+#include "Fat.h"
+#include "Volumes.h"
+#include "Apidrvr.h"
+#include "Common.h"
+#include "Cache.h"
+
+Password CachedPasswords[CACHE_SIZE];
+int cacheEmpty = 1;
+static int nPasswordIdx = 0;
+
+int ReadVolumeHeaderWCache (BOOL bBoot, BOOL bCache, char *header, Password *password, PCRYPTO_INFO *retInfo)
+{
+ int nReturnCode = ERR_PASSWORD_WRONG;
+ int i;
+
+ /* Attempt to recognize volume using mount password */
+ if (password->Length > 0)
+ {
+ nReturnCode = ReadVolumeHeader (bBoot, header, password, retInfo, NULL);
+
+ /* Save mount passwords back into cache if asked to do so */
+ if (bCache && (nReturnCode == 0 || nReturnCode == ERR_CIPHER_INIT_WEAK_KEY))
+ {
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ if (memcmp (&CachedPasswords[i], password, sizeof (Password)) == 0)
+ break;
+ }
+
+ if (i == CACHE_SIZE)
+ {
+ /* Store the password */
+ CachedPasswords[nPasswordIdx] = *password;
+
+ /* Try another slot */
+ nPasswordIdx = (nPasswordIdx + 1) % CACHE_SIZE;
+
+ cacheEmpty = 0;
+ }
+ }
+ }
+ else if (!cacheEmpty)
+ {
+ /* Attempt to recognize volume using cached passwords */
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ if (CachedPasswords[i].Length > 0)
+ {
+ nReturnCode = ReadVolumeHeader (bBoot, header, &CachedPasswords[i], retInfo, NULL);
+
+ if (nReturnCode != ERR_PASSWORD_WRONG)
+ break;
+ }
+ }
+ }
+
+ return nReturnCode;
+}
+
+
+void AddPasswordToCache (Password *password)
+{
+ int i;
+ for (i = 0; i < CACHE_SIZE; i++)
+ {
+ if (memcmp (&CachedPasswords[i], password, sizeof (Password)) == 0)
+ return;
+ }
+
+ CachedPasswords[nPasswordIdx] = *password;
+ nPasswordIdx = (nPasswordIdx + 1) % CACHE_SIZE;
+ cacheEmpty = 0;
+}
+
+
+void WipeCache ()
+{
+ burn (CachedPasswords, sizeof (CachedPasswords));
+ nPasswordIdx = 0;
+ cacheEmpty = 1;
+}
diff --git a/src/Common/Cache.h b/src/Common/Cache.h
new file mode 100644
index 00000000..18324a5c
--- /dev/null
+++ b/src/Common/Cache.h
@@ -0,0 +1,23 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2008 TrueCrypt Developers Association
+ and are 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 "Common.h"
+
+#ifndef CACHE_SIZE
+/* WARNING: Changing this value might not be safe (some items may be hard coded for 4)! Inspection necessary. */
+#define CACHE_SIZE 4
+#endif
+
+extern int cacheEmpty;
+
+void AddPasswordToCache (Password *password);
+int ReadVolumeHeaderWCache (BOOL bBoot, BOOL bCache, char *header, Password *password, PCRYPTO_INFO *retInfo);
+void WipeCache (void);
diff --git a/src/Common/Cmdline.c b/src/Common/Cmdline.c
new file mode 100644
index 00000000..cf3903d6
--- /dev/null
+++ b/src/Common/Cmdline.c
@@ -0,0 +1,240 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2009 TrueCrypt Developers Association
+ and are 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 "Tcdefs.h"
+
+#include <malloc.h>
+#include <ctype.h>
+#include "Cmdline.h"
+
+#include "Resource.h"
+#include "Crypto.h"
+#include "Apidrvr.h"
+#include "Dlgcode.h"
+#include "Language.h"
+
+/* Except in response to the WM_INITDIALOG message, the dialog box procedure
+ should return nonzero if it processes the message, and zero if it does
+ not. - see DialogProc */
+BOOL CALLBACK CommandHelpDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ if (lParam); /* remove warning */
+ if (wParam); /* remove warning */
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ char * tmp = err_malloc(8192);
+ char tmp2[MAX_PATH * 2];
+ argumentspec *as;
+ int i;
+
+ LocalizeDialog (hwndDlg, "IDD_COMMANDHELP_DLG");
+
+ as = (argumentspec*) lParam;
+
+ *tmp = 0;
+
+ strcpy (tmp, "Command line options:\n\n");
+ for (i = 0; i < as->arg_cnt; i ++)
+ {
+ if (!as->args[i].Internal)
+ {
+ sprintf(tmp2, "%s\t%s\n", as->args[i].short_name, as->args[i].long_name);
+ strcat(tmp,tmp2);
+ }
+ }
+
+ SetWindowText (GetDlgItem (hwndDlg, IDC_COMMANDHELP_TEXT), (char*) tmp);
+ return 1;
+ }
+
+ case WM_COMMAND:
+ EndDialog (hwndDlg, IDOK);
+ return 1;
+ case WM_CLOSE:
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+int Win32CommandLine (char *lpszCommandLine, char ***lpszArgs)
+{
+ int argumentCount;
+ int i;
+
+ LPWSTR *arguments = CommandLineToArgvW (GetCommandLineW(), &argumentCount);
+ if (!arguments)
+ {
+ handleWin32Error (NULL);
+ return 0;
+ }
+
+ --argumentCount;
+ if (argumentCount < 1)
+ {
+ LocalFree (arguments);
+ return 0;
+ }
+
+ *lpszArgs = malloc (sizeof (char *) * argumentCount);
+ if (!*lpszArgs)
+ AbortProcess ("OUTOFMEMORY");
+
+ for (i = 0; i < argumentCount; ++i)
+ {
+ size_t argLen = wcslen (arguments[i + 1]);
+
+ char *arg = malloc (argLen + 1);
+ if (!arg)
+ AbortProcess ("OUTOFMEMORY");
+
+ if (argLen > 0)
+ {
+ int len = WideCharToMultiByte (CP_ACP, 0, arguments[i + 1], -1, arg, argLen + 1, NULL, NULL);
+ if (len == 0)
+ {
+ handleWin32Error (NULL);
+ AbortProcessSilent();
+ }
+ }
+ else
+ arg[0] = 0;
+
+ (*lpszArgs)[i] = arg;
+ }
+
+ LocalFree (arguments);
+ return argumentCount;
+}
+
+int GetArgSepPosOffset (char *lpszArgument)
+{
+ if (lpszArgument[0] == '/')
+ return 1;
+
+ return 0;
+}
+
+int GetArgumentID (argumentspec *as, char *lpszArgument, int *nArgPos)
+{
+ char szTmp[MAX_PATH * 2];
+ int i;
+
+ i = strlen (lpszArgument);
+ szTmp[i] = 0;
+ while (--i >= 0)
+ {
+ szTmp[i] = (char) tolower (lpszArgument[i]);
+ }
+
+ for (i = 0; i < as->arg_cnt; i++)
+ {
+ size_t k;
+
+ k = strlen (as->args[i].long_name);
+ if (memcmp (as->args[i].long_name, szTmp, k * sizeof (char)) == 0)
+ {
+ int x;
+ for (x = i + 1; x < as->arg_cnt; x++)
+ {
+ size_t m;
+
+ m = strlen (as->args[x].long_name);
+ if (memcmp (as->args[x].long_name, szTmp, m * sizeof (char)) == 0)
+ {
+ break;
+ }
+ }
+
+ if (x == as->arg_cnt)
+ {
+ if (strlen (lpszArgument) != k)
+ *nArgPos = k;
+ else
+ *nArgPos = 0;
+ return as->args[i].Id;
+ }
+ }
+ }
+
+ for (i = 0; i < as->arg_cnt; i++)
+ {
+ size_t k;
+
+ if (as->args[i].short_name[0] == 0)
+ continue;
+
+ k = strlen (as->args[i].short_name);
+ if (memcmp (as->args[i].short_name, szTmp, k * sizeof (char)) == 0)
+ {
+ int x;
+ for (x = i + 1; x < as->arg_cnt; x++)
+ {
+ size_t m;
+
+ if (as->args[x].short_name[0] == 0)
+ continue;
+
+ m = strlen (as->args[x].short_name);
+ if (memcmp (as->args[x].short_name, szTmp, m * sizeof (char)) == 0)
+ {
+ break;
+ }
+ }
+
+ if (x == as->arg_cnt)
+ {
+ if (strlen (lpszArgument) != k)
+ *nArgPos = k;
+ else
+ *nArgPos = 0;
+ return as->args[i].Id;
+ }
+ }
+ }
+
+
+ return -1;
+}
+
+int GetArgumentValue (char **lpszCommandLineArgs, int nArgPos, int *nArgIdx,
+ int nNoCommandLineArgs, char *lpszValue, int nValueSize)
+{
+ *lpszValue = 0;
+
+ if (nArgPos)
+ {
+ /* Handles the case of no space between parameter code and
+ value */
+ strncpy (lpszValue, &lpszCommandLineArgs[*nArgIdx][nArgPos], nValueSize);
+ lpszValue[nValueSize - 1] = 0;
+ return HAS_ARGUMENT;
+ }
+ else if (*nArgIdx + 1 < nNoCommandLineArgs)
+ {
+ int x = GetArgSepPosOffset (lpszCommandLineArgs[*nArgIdx + 1]);
+ if (x == 0)
+ {
+ /* Handles the case of space between parameter code
+ and value */
+ strncpy (lpszValue, &lpszCommandLineArgs[*nArgIdx + 1][x], nValueSize);
+ lpszValue[nValueSize - 1] = 0;
+ (*nArgIdx)++;
+ return HAS_ARGUMENT;
+ }
+ }
+
+ return HAS_NO_ARGUMENT;
+}
diff --git a/src/Common/Cmdline.h b/src/Common/Cmdline.h
new file mode 100644
index 00000000..7192c537
--- /dev/null
+++ b/src/Common/Cmdline.h
@@ -0,0 +1,41 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2008 TrueCrypt Developers Association
+ and are 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. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HAS_ARGUMENT 1
+#define HAS_NO_ARGUMENT !HAS_ARGUMENT
+
+typedef struct argument_t
+{
+ int Id;
+ char long_name[32];
+ char short_name[8];
+ BOOL Internal;
+} argument;
+
+typedef struct argumentspec_t
+{
+ argument *args;
+ int arg_cnt;
+} argumentspec;
+
+BOOL CALLBACK CommandHelpDlgProc ( HWND hwndDlg , UINT msg , WPARAM wParam , LPARAM lParam );
+int Win32CommandLine ( char *lpszCommandLine , char ***lpszArgs );
+int GetArgSepPosOffset ( char *lpszArgument );
+int GetArgumentID ( argumentspec *as , char *lpszArgument , int *nArgPos );
+int GetArgumentValue ( char **lpszCommandLineArgs , int nArgPos , int *nArgIdx , int nNoCommandLineArgs , char *lpszValue , int nValueSize );
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/Common/Combo.c b/src/Common/Combo.c
new file mode 100644
index 00000000..850cd020
--- /dev/null
+++ b/src/Common/Combo.c
@@ -0,0 +1,212 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2008 TrueCrypt Developers Association
+ and are 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 "Tcdefs.h"
+#include "Combo.h"
+#include "Dlgcode.h"
+#include "Xml.h"
+
+#include <time.h>
+
+#define SIZEOF_MRU_LIST 20
+
+void AddComboItem (HWND hComboBox, char *lpszFileName, BOOL saveHistory)
+{
+ LPARAM nIndex;
+
+ if (!saveHistory)
+ {
+ SendMessage (hComboBox, CB_RESETCONTENT, 0, 0);
+ SetWindowText (hComboBox, lpszFileName);
+ return;
+ }
+
+ nIndex = SendMessage (hComboBox, CB_FINDSTRINGEXACT, (WPARAM) - 1, (LPARAM) & lpszFileName[0]);
+
+ if (nIndex == CB_ERR && *lpszFileName)
+ {
+ time_t lTime = time (NULL);
+ nIndex = SendMessage (hComboBox, CB_ADDSTRING, 0, (LPARAM) & lpszFileName[0]);
+ if (nIndex != CB_ERR)
+ SendMessage (hComboBox, CB_SETITEMDATA, nIndex, (LPARAM) lTime);
+ }
+
+ if (nIndex != CB_ERR && *lpszFileName)
+ nIndex = SendMessage (hComboBox, CB_SETCURSEL, nIndex, 0);
+
+ if (*lpszFileName == 0)
+ {
+ SendMessage (hComboBox, CB_SETCURSEL, (WPARAM) - 1, 0);
+ }
+}
+
+
+LPARAM MoveEditToCombo (HWND hComboBox, BOOL saveHistory)
+{
+ char szTmp[TC_MAX_PATH] = {0};
+
+ if (!saveHistory)
+ {
+ GetWindowText (hComboBox, szTmp, sizeof (szTmp));
+ SendMessage (hComboBox, CB_RESETCONTENT, 0, 0);
+ SetWindowText (hComboBox, szTmp);
+ return 0;
+ }
+
+ GetWindowText (hComboBox, szTmp, sizeof (szTmp));
+
+ if (strlen (szTmp) > 0)
+ {
+ LPARAM nIndex = SendMessage (hComboBox, CB_FINDSTRINGEXACT, (WPARAM) - 1,
+ (LPARAM) & szTmp[0]);
+ if (nIndex == CB_ERR)
+ {
+ time_t lTime = time (NULL);
+ nIndex = SendMessage (hComboBox, CB_ADDSTRING, 0, (LPARAM) & szTmp[0]);
+ if (nIndex != CB_ERR)
+ SendMessage (hComboBox, CB_SETITEMDATA, nIndex, (DWORD) lTime);
+ }
+ else
+ {
+ time_t lTime = time (NULL);
+ SendMessage (hComboBox, CB_SETITEMDATA, nIndex, (DWORD) lTime);
+ }
+
+ return nIndex;
+ }
+
+ return SendMessage (hComboBox, CB_GETCURSEL, 0, 0);
+}
+
+int GetOrderComboIdx (HWND hComboBox, int *nIdxList, int nElems)
+{
+ int x = (int) SendMessage (hComboBox, CB_GETCOUNT, 0, 0);
+ if (x != CB_ERR)
+ {
+ int i, nHighIdx = CB_ERR;
+ time_t lHighTime = -1;
+
+ for (i = 0; i < x; i++)
+ {
+ time_t lTime = SendMessage (hComboBox, CB_GETITEMDATA, (WPARAM) i, 0);
+ if (lTime > lHighTime)
+ {
+ int n;
+ for (n = 0; n < nElems; n++)
+ if (nIdxList[n] == i)
+ break;
+ if (n == nElems)
+ {
+ lHighTime = lTime;
+ nHighIdx = i;
+ }
+ }
+ }
+
+ return nHighIdx;
+ }
+
+ return CB_ERR;
+}
+
+LPARAM UpdateComboOrder (HWND hComboBox)
+{
+ LPARAM nIndex;
+
+ nIndex = SendMessage (hComboBox, CB_GETCURSEL, 0, 0);
+
+ if (nIndex != CB_ERR)
+ {
+ time_t lTime = time (NULL);
+ nIndex = SendMessage (hComboBox, CB_SETITEMDATA, (WPARAM) nIndex,
+ (LPARAM) lTime);
+ }
+
+ return nIndex;
+}
+
+void LoadCombo (HWND hComboBox)
+{
+ DWORD size;
+ char *history = LoadFile (GetConfigPath (TC_APPD_FILENAME_HISTORY), &size);
+ char *xml = history;
+ char volume[MAX_PATH];
+
+ if (xml == NULL) return;
+
+ while (xml = XmlFindElement (xml, "volume"))
+ {
+ XmlGetNodeText (xml, volume, sizeof (volume));
+ AddComboItem (hComboBox, volume, TRUE);
+ xml++;
+ }
+
+ SendMessage (hComboBox, CB_SETCURSEL, 0, 0);
+
+ free (history);
+}
+
+void DumpCombo (HWND hComboBox, int bClear)
+{
+ FILE *f;
+ int i, nComboIdx[SIZEOF_MRU_LIST];
+
+ if (bClear)
+ {
+ DeleteFile (GetConfigPath (TC_APPD_FILENAME_HISTORY));
+ return;
+ }
+
+ f = fopen (GetConfigPath (TC_APPD_FILENAME_HISTORY), "w");
+ if (f == NULL) return;
+
+ XmlWriteHeader (f);
+ fputs ("\n\t<history>", f);
+
+ /* combo list part:- get mru items */
+ for (i = 0; i < SIZEOF_MRU_LIST; i++)
+ nComboIdx[i] = GetOrderComboIdx (hComboBox, &nComboIdx[0], i);
+
+ /* combo list part:- write out mru items */
+ for (i = 0; i < SIZEOF_MRU_LIST; i++)
+ {
+ char szTmp[MAX_PATH] = { 0 };
+
+ if (SendMessage (hComboBox, CB_GETLBTEXTLEN, nComboIdx[i], 0) < sizeof (szTmp))
+ SendMessage (hComboBox, CB_GETLBTEXT, nComboIdx[i], (LPARAM) & szTmp[0]);
+
+ if (szTmp[0] != 0)
+ {
+ char q[MAX_PATH * 2] = { 0 };
+ XmlQuoteText (szTmp, q, sizeof (q));
+
+ fprintf (f, "\n\t\t<volume>%s</volume>", q);
+ }
+ }
+
+ fputs ("\n\t</history>", f);
+ XmlWriteFooter (f);
+ fclose (f);
+}
+
+void ClearCombo (HWND hComboBox)
+{
+ int i;
+ for (i = 0; i < SIZEOF_MRU_LIST; i++)
+ {
+ SendMessage (hComboBox, CB_DELETESTRING, 0, 0);
+ }
+}
+
+int IsComboEmpty (HWND hComboBox)
+{
+ return SendMessage (hComboBox, CB_GETCOUNT, 0, 0) < 1;
+}
diff --git a/src/Common/Combo.h b/src/Common/Combo.h
new file mode 100644
index 00000000..f79a8df7
--- /dev/null
+++ b/src/Common/Combo.h
@@ -0,0 +1,27 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2008 TrueCrypt Developers Association
+ and are 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. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void AddComboItem (HWND hComboBox, char *lpszFileName, BOOL saveHistory);
+LPARAM MoveEditToCombo (HWND hComboBox, BOOL saveHistory);
+int GetOrderComboIdx ( HWND hComboBox , int *nIdxList , int nElems );
+LPARAM UpdateComboOrder ( HWND hComboBox );
+void LoadCombo ( HWND hComboBox );
+void DumpCombo ( HWND hComboBox , int bClear );
+void ClearCombo (HWND hComboBox);
+int IsComboEmpty (HWND hComboBox);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/src/Common/Common.h b/src/Common/Common.h
new file mode 100644
index 00000000..ef25ec17
--- /dev/null
+++ b/src/Common/Common.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (c) 2005-2009 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "Crypto.h"
+
+#define MIN_MOUNTED_VOLUME_DRIVE_NUMBER ('A' - 'A')
+#define MAX_MOUNTED_VOLUME_DRIVE_NUMBER ('Z' - 'A')
+
+#define MAX_HOST_DRIVE_NUMBER 64
+#define MAX_HOST_PARTITION_NUMBER 32
+
+typedef enum
+{
+ // IMPORTANT: If you add a new item here, update IsOSVersionAtLeast().
+
+ WIN_UNKNOWN = 0,
+ WIN_31,
+ WIN_95,
+ WIN_98,
+ WIN_ME,
+ WIN_NT3,
+ WIN_NT4,
+ WIN_2000,
+ WIN_XP,
+ WIN_XP64,
+ WIN_SERVER_2003,
+ WIN_VISTA,
+ WIN_SERVER_2008,
+ WIN_7,
+ WIN_SERVER_2008_R2,
+} OSVersionEnum;
+
+/* Volume types */
+enum
+{
+ TC_VOLUME_TYPE_NORMAL = 0,
+ TC_VOLUME_TYPE_HIDDEN,
+ TC_VOLUME_TYPE_HIDDEN_LEGACY,
+ TC_VOLUME_TYPE_COUNT
+};
+
+/* Prop volume types */
+enum
+{
+ PROP_VOL_TYPE_NORMAL = 0,
+ PROP_VOL_TYPE_HIDDEN,
+ PROP_VOL_TYPE_OUTER, /* Outer/normal (hidden volume protected) */
+ PROP_VOL_TYPE_OUTER_VOL_WRITE_PREVENTED, /* Outer/normal (hidden volume protected AND write already prevented) */
+ PROP_VOL_TYPE_SYSTEM,
+ PROP_NBR_VOLUME_TYPES
+};
+
+/* Hidden volume protection status */
+enum
+{
+ HIDVOL_PROT_STATUS_NONE = 0,
+ HIDVOL_PROT_STATUS_ACTIVE,
+ HIDVOL_PROT_STATUS_ACTION_TAKEN /* Active + action taken (write operation has already been denied) */
+};
+
+typedef struct
+{
+ BOOL ReadOnly;
+ BOOL Removable;
+ BOOL ProtectHiddenVolume;
+ BOOL PreserveTimestamp;
+ BOOL PartitionInInactiveSysEncScope; /* If TRUE, we are to attempt to mount a partition located on an encrypted system drive without pre-boot authentication. */
+ Password ProtectedHidVolPassword; /* Password of hidden volume to protect against overwriting */
+ BOOL UseBackupHeader;
+ BOOL RecoveryMode;
+} MountOptions;
+
+#endif
diff --git a/src/Common/Common.rc b/src/Common/Common.rc
new file mode 100644
index 00000000..e579fe17
--- /dev/null
+++ b/src/Common/Common.rc
@@ -0,0 +1,541 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUT_DLG DIALOGEX 31, 51, 292, 199
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "About TrueCrypt"
+CLASS "SplashDlg"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ EDITTEXT IDC_ABOUT_CREDITS,7,111,277,45,ES_MULTILINE | WS_VSCROLL | NOT WS_TABSTOP
+ DEFPUSHBUTTON "OK",IDOK,230,178,52,14
+ LTEXT "",IDC_HOMEPAGE,18,87,117,9,SS_NOTIFY
+ LTEXT "",IDT_ABOUT_RELEASE,18,71,235,8
+ CONTROL 517,IDC_ABOUT_BKG,"Static",SS_BITMAP,0,0,12,11,WS_EX_STATICEDGE
+ LTEXT "",IDT_ABOUT_VERSION,18,61,161,8
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,167,291,1,WS_EX_STATICEDGE
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,169,291,1,WS_EX_STATICEDGE
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,107,291,1,WS_EX_STATICEDGE
+ CONTROL "",IDC_ABOUT_LOGO_AREA,"Static",SS_GRAYRECT | NOT WS_VISIBLE,0,0,293,50,WS_EX_TRANSPARENT | WS_EX_STATICEDGE
+ CONTROL 518,IDC_TEXTUAL_LOGO_IMG,"Static",SS_BITMAP,12,26,157,16
+END
+
+IDD_COMMANDHELP_DLG DIALOGEX 0, 0, 249, 213
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Command Line Help"
+CLASS "CustomDlg"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,93,191,59,14
+ LTEXT "",IDC_COMMANDHELP_TEXT,20,11,208,174
+END
+
+IDD_RAWDEVICES_DLG DIALOGEX 0, 0, 305, 209
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Select a Partition or Device"
+FONT 8, "MS Shell Dlg", 400, 0, 0x0
+BEGIN
+ CONTROL "",IDC_DEVICELIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_EDITLABELS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,291,178
+ DEFPUSHBUTTON "OK",IDOK,192,190,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,248,190,50,14
+END
+
+IDD_MOUNT_OPTIONS DIALOGEX 0, 0, 277, 172
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "TrueCrypt - Mount Options"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "Mount volume as read-&only",IDC_MOUNT_READONLY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,11,194,10
+ CONTROL "Mount volume as removable &medium",IDC_MOUNT_REMOVABLE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,25,195,10
+ CONTROL "Mount partition &using system encryption without pre-boot authentication",IDC_MOUNT_SYSENC_PART_WITHOUT_PBA,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,53,259,11
+ CONTROL "&Protect hidden volume against damage caused by writing to outer volume",IDC_PROTECT_HIDDEN_VOL,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,16,86,252,10
+ EDITTEXT IDC_PASSWORD_PROT_HIDVOL,112,104,151,14,ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "&Display password",IDC_SHOW_PASSWORD_MO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,112,123,90,10
+ CONTROL "U&se keyfiles",IDC_KEYFILES_ENABLE_HIDVOL_PROT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,112,136,90,10
+ PUSHBUTTON "&Keyfiles...",IDC_KEYFILES_HIDVOL_PROT,203,125,60,14
+ LTEXT "What is hidden volume protection?",IDC_LINK_HIDVOL_PROTECTION_INFO,16,151,247,10,SS_NOTIFY
+ DEFPUSHBUTTON "OK",IDOK,211,7,60,14
+ PUSHBUTTON "Cancel",IDCANCEL,211,24,60,14
+ RTEXT "P&assword to hidden volume:\n(if empty, cache is used)",IDT_HIDDEN_PROT_PASSWD,15,103,91,17,0,WS_EX_RIGHT
+ GROUPBOX "Hidden Volume Protection",IDT_HIDDEN_VOL_PROTECTION,6,72,265,95
+ CONTROL "Use backup header embedded in &volume if available",IDC_USE_EMBEDDED_HEADER_BAK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,39,257,11
+END
+
+IDD_KEYFILES DIALOGEX 0, 0, 345, 237
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "TrueCrypt - Keyfiles"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_KEYLIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,8,263,118
+ PUSHBUTTON "Add &Files...",IDC_KEYADD,7,132,61,14
+ PUSHBUTTON "Add &Path...",IDC_ADD_KEYFILE_PATH,73,132,61,14
+ PUSHBUTTON "Add &Token Files...",IDC_TOKEN_FILES_ADD,139,132,65,14
+ PUSHBUTTON "&Remove",IDC_KEYREMOVE,209,132,61,14
+ PUSHBUTTON "Remove &All",IDC_KEYREMOVEALL,275,132,61,14
+ CONTROL "U&se keyfiles",IDC_KEYFILES_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,219,83,11
+ PUSHBUTTON "&Generate Random Keyfile...",IDC_GENERATE_KEYFILE,213,217,123,14
+ DEFPUSHBUTTON "OK",IDOK,279,8,59,14
+ PUSHBUTTON "Cancel",IDCANCEL,279,25,59,14
+ LTEXT "",IDT_KEYFILES_NOTE,10,161,324,41,0,WS_EX_TRANSPARENT
+ LTEXT "WARNING: If you lose a keyfile or if any bit of its first 1024 kilobytes changes, it will be impossible to mount volumes that use the keyfile!",IDT_KEYFILE_WARNING,279,44,58,85,0,WS_EX_TRANSPARENT
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,2,154,343,1,WS_EX_STATICEDGE
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,2,209,343,1,WS_EX_STATICEDGE
+ LTEXT "More information on keyfiles",IDC_LINK_KEYFILES_INFO,96,220,108,10,SS_NOTIFY
+END
+
+IDD_LANGUAGE DIALOGEX 0, 0, 209, 183
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "TrueCrypt - Language"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LISTBOX IDC_LANGLIST,6,7,197,67,LBS_SORT | LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_LANGPACK_CREDITS,6,108,197,28,ES_MULTILINE | ES_READONLY | WS_VSCROLL | NOT WS_TABSTOP
+ CTEXT "Download language pack",IDC_GET_LANG_PACKS,2,146,205,10,SS_NOTIFY
+ DEFPUSHBUTTON "OK",IDOK,97,165,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,153,165,50,14
+ LTEXT "Translated by:",IDT_LANGPACK_AUTHORS,6,99,101,9,SS_NOTIFY,WS_EX_TRANSPARENT
+ RTEXT "",IDC_LANGPACK_VERSION,79,86,118,11
+ GROUPBOX "Active language pack",IDT_ACTIVE_LANG_PACK,0,77,209,65
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,158,208,1,WS_EX_STATICEDGE
+END
+
+IDD_BENCHMARK_DLG DIALOGEX 0, 0, 330, 223
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "TrueCrypt - Encryption Algorithm Benchmark"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ COMBOBOX IDC_BENCHMARK_BUFFER_SIZE,55,7,77,129,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_BENCHMARK_SORT_METHOD,207,7,116,74,CBS_DROPDOWNLIST | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+ CONTROL "",IDC_RESULTS,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,37,249,160
+ DEFPUSHBUTTON "Benchmark",IDC_PERFORM_BENCHMARK,265,37,58,14
+ PUSHBUTTON "Close",IDCLOSE,265,55,58,14
+ LTEXT "Hardware-accelerated AES:",IDC_HW_AES_LABEL_LINK,148,210,108,9,SS_NOTIFY,WS_EX_RIGHT
+ CONTROL "",IDC_HW_AES,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,262,209,57,11,WS_EX_STATICEDGE
+ LTEXT "Parallelization:",IDC_PARALLELIZATION_LABEL_LINK,4,210,67,9,SS_NOTIFY,WS_EX_RIGHT
+ CONTROL "",IDC_PARALLELIZATION,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,77,209,57,11,WS_EX_STATICEDGE
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,2,29,328,1,WS_EX_STATICEDGE
+ LTEXT "Buffer Size:",IDT_BUFFER_SIZE,0,9,53,8,0,WS_EX_RIGHT
+ LTEXT "Sort Method:",IDT_SORT_METHOD,135,9,70,8,0,WS_EX_RIGHT
+ LTEXT "Speed is affected by CPU load and storage device characteristics.\n\nThese tests take place in RAM.",IDT_BOX_BENCHMARK_INFO,266,81,57,116
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,2,205,328,1,WS_EX_STATICEDGE
+END
+
+IDD_CIPHER_TEST_DLG DIALOGEX 0, 0, 326, 249
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "TrueCrypt - Test Vectors"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ COMBOBOX IDC_CIPHER,109,10,104,126,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_KEY,8,36,309,14,ES_AUTOHSCROLL
+ COMBOBOX IDC_KEY_SIZE,67,55,42,68,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_SECONDARY_KEY,8,93,309,14,ES_AUTOHSCROLL
+ EDITTEXT IDC_TEST_DATA_UNIT_NUMBER,8,118,84,14,ES_AUTOHSCROLL
+ CONTROL "XTS mode",IDC_XTS_MODE_ENABLED,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,221,12,95,10
+ EDITTEXT IDC_PLAINTEXT,8,151,159,14,ES_AUTOHSCROLL
+ COMBOBOX IDC_PLAINTEXT_SIZE,258,151,36,30,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP
+ EDITTEXT IDC_CIPHERTEXT,8,185,159,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Encrypt",IDC_ENCRYPT,8,229,52,14
+ PUSHBUTTON "&Decrypt",IDC_DECRYPT,65,229,52,14
+ PUSHBUTTON "&Auto-Test All",IDC_AUTO,129,229,67,14,BS_MULTILINE
+ PUSHBUTTON "&Reset",IDC_RESET,208,229,52,14
+ PUSHBUTTON "Close",IDCLOSE,266,229,52,14
+ GROUPBOX "Key (hexadecimal)",IDT_TEST_KEY,1,26,323,49
+ GROUPBOX "Plaintext (hexadecimal)",IDT_TEST_PLAINTEXT,1,140,323,33
+ GROUPBOX "Ciphertext (hexadecimal)",IDT_TEST_CIPHERTEXT,1,174,323,33
+ RTEXT "",IDC_TESTS_MESSAGE,50,213,178,10
+ CONTROL "",IDC_REDTICK,"REDTICK",0x0,234,214,10,8
+ RTEXT "Key size:",IDT_KEY,8,57,56,8
+ RTEXT "Plaintext size:",IDT_PLAINTEXT,190,153,63,8
+ LTEXT "bits",IDT_KEY_UNIT,114,57,45,8
+ RTEXT "Cipher:",IDT_CIPHER,38,13,68,8
+ LTEXT "bits",IDT_PLAINTEXT_SIZE_UNIT,298,153,22,8
+ GROUPBOX "XTS mode",IDT_XTS_MODE,1,75,323,65
+ LTEXT "Secondary key (hexadecimal)",IDT_SECONDARY_KEY,8,84,187,8
+ LTEXT "Data unit number (64-bit hexadecimal, data unit size is 512 bytes)",IDT_TEST_DATA_UNIT_NUMBER,8,109,308,8
+ RTEXT "Block number:",IDT_TEST_BLOCK_NUMBER,134,122,119,8
+ COMBOBOX IDC_TEST_BLOCK_NUMBER,258,119,36,126,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+END
+
+IDD_TEXT_INFO_DIALOG_BOX_DLG DIALOGEX 0, 0, 372, 220
+STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,305,200,58,14
+ PUSHBUTTON "&Print",IDC_PRINT,156,200,58,14
+ CONTROL "",IDC_INFO_BOX_TEXT,"RichEdit20A",ES_MULTILINE | ES_READONLY | ES_NUMBER | WS_BORDER | WS_VSCROLL | WS_TABSTOP,5,6,361,188
+END
+
+IDD_KEYFILE_GENERATOR DIALOGEX 0, 0, 308, 270
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "TrueCrypt - Keyfile Generator"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "Close",IDCLOSE,237,10,59,14
+ COMBOBOX IDC_PRF_ID,79,49,91,90,CBS_DROPDOWNLIST | WS_TABSTOP
+ PUSHBUTTON "Generate and Save Keyfile...",IDC_GENERATE_AND_SAVE_KEYFILE,89,248,131,14
+ LTEXT "IMPORTANT: Move your mouse as randomly as possible within this window. The longer you move it, the better. This significantly increases the cryptographic strength of the keyfile.",IDT_KEYFILE_GENERATOR_NOTE,11,5,213,33
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,40,307,1,WS_EX_STATICEDGE
+ RTEXT "Mixing PRF:",IDT_PRF,6,51,67,10,SS_CENTERIMAGE
+ GROUPBOX "Current Pool Content",IDT_POOL_CONTENTS,6,70,296,170
+ CONTROL "",IDC_POOL_CONTENTS,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,16,83,282,148,WS_EX_TRANSPARENT
+ CONTROL "Display pool content",IDC_DISPLAY_POOL_CONTENTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,191,51,111,10
+END
+
+IDD_MULTI_CHOICE_DLG DIALOGEX 0, 0, 167, 322
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ PUSHBUTTON "",IDC_CHOICE10,7,292,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ PUSHBUTTON "",IDC_CHOICE9,7,268,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ PUSHBUTTON "",IDC_CHOICE8,7,244,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ PUSHBUTTON "",IDC_CHOICE7,7,220,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ PUSHBUTTON "",IDC_CHOICE6,7,196,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ PUSHBUTTON "",IDC_CHOICE5,7,172,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ PUSHBUTTON "",IDC_CHOICE4,7,148,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ PUSHBUTTON "",IDC_CHOICE3,7,124,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ PUSHBUTTON "",IDC_CHOICE2,7,100,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ PUSHBUTTON "",IDC_CHOICE1,7,76,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE
+ LTEXT "",IDC_MULTI_CHOICE_MSG,7,7,153,56,0,WS_EX_TRANSPARENT
+ CONTROL "",IDC_MC_DLG_HR2,"Static",SS_ETCHEDHORZ,0,69,168,1,WS_EX_STATICEDGE
+ CONTROL "",IDC_MC_DLG_HR1,"Static",SS_ETCHEDHORZ,0,1,168,1,WS_EX_STATICEDGE
+END
+
+IDD_AUXILIARY_DLG DIALOGEX 0, 0, 426, 296
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_NOFAILCREATE | WS_POPUP
+EXSTYLE WS_EX_TRANSPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ LTEXT "",IDC_ASPECT_RATIO_CALIBRATION_BOX,3,2,282,282,WS_DISABLED
+END
+
+IDD_TOKEN_PASSWORD DIALOGEX 0, 0, 281, 47
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Security token password/PIN required"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_TOKEN_PASSWORD,8,20,199,14,ES_PASSWORD | ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK",IDOK,215,7,59,14
+ PUSHBUTTON "Cancel",IDCANCEL,215,25,59,14
+ LTEXT "",IDT_TOKEN_PASSWORD_INFO,9,8,196,8
+END
+
+IDD_TOKEN_KEYFILES DIALOGEX 0, 0, 337, 185
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Security Token Keyfiles"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ CONTROL "",IDC_TOKEN_FILE_LIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_EDITLABELS | LVS_ALIGNLEFT | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,7,7,256,152
+ PUSHBUTTON "&Export...",IDC_EXPORT,7,164,55,14
+ PUSHBUTTON "&Delete",IDC_DELETE,66,164,55,14
+ PUSHBUTTON "&Import Keyfile to Token...",IDC_IMPORT_KEYFILE,126,164,137,14
+ DEFPUSHBUTTON "OK",IDOK,271,7,59,14
+ PUSHBUTTON "Cancel",IDCANCEL,271,25,59,14
+END
+
+IDD_NEW_TOKEN_KEYFILE DIALOGEX 0, 0, 239, 82
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "New Security Token Keyfile Properties"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,128,61,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,183,61,50,14
+ COMBOBOX IDC_SELECTED_TOKEN,77,13,140,43,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Security token:",IDT_SECURITY_TOKEN,11,15,62,8,0,WS_EX_RIGHT
+ LTEXT "Keyfile name:",IDT_TOKEN_KEYFILE_NAME,12,34,61,8,0,WS_EX_RIGHT
+ EDITTEXT IDC_TOKEN_KEYFILE_NAME,77,32,140,13,ES_AUTOHSCROLL
+ GROUPBOX "",IDC_STATIC,5,2,228,51
+END
+
+IDD_RANDOM_POOL_ENRICHMENT DIALOGEX 0, 0, 308, 270
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "TrueCrypt - Random Pool Enrichment"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ DEFPUSHBUTTON "&Continue",IDC_CONTINUE,119,248,71,14
+ COMBOBOX IDC_PRF_ID,79,49,91,90,CBS_DROPDOWNLIST | WS_TABSTOP
+ LTEXT "IMPORTANT: Move your mouse as randomly as possible within this window. The longer you move it, the better. This significantly increases security. When done, click 'Continue'.",IDT_RANDOM_POOL_ENRICHMENT_NOTE,11,6,282,25
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,37,307,1,WS_EX_STATICEDGE
+ RTEXT "Mixing PRF:",IDT_PRF,6,51,67,10,SS_CENTERIMAGE
+ GROUPBOX "Current Pool Content",IDT_POOL_CONTENTS,6,70,296,170
+ CONTROL "",IDC_POOL_CONTENTS,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,16,83,282,148,WS_EX_TRANSPARENT
+ CONTROL "Display pool content",IDC_DISPLAY_POOL_CONTENTS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,191,51,111,10
+END
+
+IDD_STATIC_MODELESS_WAIT_DLG DIALOGEX 0, 0, 292, 42
+STYLE DS_SYSMODAL | DS_SETFONT | DS_MODALFRAME | DS_SETFOREGROUND | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION
+EXSTYLE WS_EX_TOPMOST | WS_EX_TOOLWINDOW
+CAPTION "TrueCrypt"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ LTEXT "Please wait. This process may take a long time...",IDT_STATIC_MODELESS_WAIT_DLG_INFO,9,8,274,9
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_COMMANDHELP_DLG, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 205
+ END
+
+ IDD_RAWDEVICES_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 298
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 205
+ END
+
+ IDD_MOUNT_OPTIONS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 166
+ END
+
+ IDD_KEYFILES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 330
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 230
+ END
+
+ IDD_LANGUAGE, DIALOG
+ BEGIN
+ LEFTMARGIN, 6
+ RIGHTMARGIN, 202
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 176
+ END
+
+ IDD_BENCHMARK_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 323
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 216
+ END
+
+ IDD_CIPHER_TEST_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 319
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 242
+ END
+
+ IDD_TEXT_INFO_DIALOG_BOX_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 365
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 213
+ END
+
+ IDD_KEYFILE_GENERATOR, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 299
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 266
+ END
+
+ IDD_MULTI_CHOICE_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 160
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 316
+ END
+
+ IDD_AUXILIARY_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 419
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 289
+ END
+
+ IDD_TOKEN_PASSWORD, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 274
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 40
+ END
+
+ IDD_TOKEN_KEYFILES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 330
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 178
+ END
+
+ IDD_NEW_TOKEN_KEYFILE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 232
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 75
+ END
+
+ IDD_RANDOM_POOL_ENRICHMENT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 301
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 267
+ END
+
+ IDD_STATIC_MODELESS_WAIT_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 285
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 35
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// BIN
+//
+
+IDR_BOOT_SECTOR BIN "..\\Boot\\Windows\\Release\\BootSector.bin"
+IDR_BOOT_SECTOR_AES BIN "..\\Boot\\Windows\\Release_AES\\BootSector.bin"
+IDR_BOOT_SECTOR_SERPENT BIN "..\\Boot\\Windows\\Release_Serpent\\BootSector.bin"
+IDR_BOOT_SECTOR_TWOFISH BIN "..\\Boot\\Windows\\Release_Twofish\\BootSector.bin"
+IDR_BOOT_LOADER_DECOMPRESSOR BIN "..\\Boot\\Windows\\Release\\Decompressor.com"
+IDR_BOOT_LOADER BIN "..\\Boot\\Windows\\Release\\BootLoader.com.gz"
+IDR_BOOT_LOADER_AES BIN "..\\Boot\\Windows\\Release_AES\\BootLoader.com.gz"
+IDR_BOOT_LOADER_SERPENT BIN "..\\Boot\\Windows\\Release_Serpent\\BootLoader.com.gz"
+IDR_BOOT_LOADER_TWOFISH BIN "..\\Boot\\Windows\\Release_Twofish\\BootLoader.com.gz"
+IDR_RESCUE_BOOT_SECTOR BIN "..\\Boot\\Windows\\Rescue\\BootSector.bin"
+IDR_RESCUE_BOOT_SECTOR_AES BIN "..\\Boot\\Windows\\Rescue_AES\\BootSector.bin"
+IDR_RESCUE_BOOT_SECTOR_SERPENT BIN "..\\Boot\\Windows\\Rescue_Serpent\\BootSector.bin"
+IDR_RESCUE_BOOT_SECTOR_TWOFISH BIN "..\\Boot\\Windows\\Rescue_Twofish\\BootSector.bin"
+IDR_RESCUE_LOADER BIN "..\\Boot\\Windows\\Rescue\\BootLoader.com.gz"
+IDR_RESCUE_LOADER_AES BIN "..\\Boot\\Windows\\Rescue_AES\\BootLoader.com.gz"
+IDR_RESCUE_LOADER_SERPENT BIN "..\\Boot\\Windows\\Rescue_Serpent\\BootLoader.com.gz"
+IDR_RESCUE_LOADER_TWOFISH BIN "..\\Boot\\Windows\\Rescue_Twofish\\BootLoader.com.gz"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// XML
+//
+
+IDR_LANGUAGE XML "..\\Common\\Language.xml"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// HEADER
+//
+
+IDR_COMMON_RSRC_HEADER HEADER "..\\Common\\Resource.h"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXT
+//
+
+IDR_LICENSE TEXT "..\\Resources\\Texts\\License.rtf"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_TRUECRYPT_ICON ICON "..\\Common\\TrueCrypt.ico"
+IDI_TRUECRYPT_VOL_ICON ICON "..\\Common\\TrueCrypt_volume.ico"
+IDI_TRUECRYPT_MOUNTED_ICON ICON "..\\Common\\TrueCrypt_mounted.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_TEXTUAL_LOGO_BKG BITMAP "..\\Common\\Textual_logo_background.bmp"
+IDB_TEXTUAL_LOGO_96DPI BITMAP "..\\Common\\Textual_logo_96dpi.bmp"
+IDB_TEXTUAL_LOGO_288DPI BITMAP "..\\Common\\Textual_logo_288dpi.bmp"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/Common/Crc.c b/src/Common/Crc.c
new file mode 100644
index 00000000..3f6e1157
--- /dev/null
+++ b/src/Common/Crc.c
@@ -0,0 +1,133 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2008 TrueCrypt Developers Association
+ and are 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 "Tcdefs.h"
+#include "Crc.h"
+#include "Common/Endian.h"
+
+#ifndef TC_MINIMIZE_CODE_SIZE
+
+/* CRC polynomial 0x04c11db7 */
+unsigned __int32 crc_32_tab[]=
+{
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+unsigned __int32 GetCrc32 (unsigned char *data, int length)
+{
+ unsigned __int32 CRC = 0xffffffff;
+
+ while (length--)
+ {
+ CRC = (CRC >> 8) ^ crc_32_tab[ (CRC ^ *data++) & 0xFF ];
+ }
+
+ return CRC ^ 0xffffffff;
+}
+
+unsigned __int32 crc32int (unsigned __int32 *data)
+{
+ unsigned char *d = (unsigned char *) data;
+ unsigned __int32 CRC = 0xffffffff;
+
+ CRC = (CRC >> 8) ^ crc_32_tab[ (CRC ^ *d++) & 0xFF ];
+ CRC = (CRC >> 8) ^ crc_32_tab[ (CRC ^ *d++) & 0xFF ];
+ CRC = (CRC >> 8) ^ crc_32_tab[ (CRC ^ *d++) & 0xFF ];
+ return (CRC >> 8) ^ crc_32_tab[ (CRC ^ *d) & 0xFF ] ^ 0xffffffff;
+}
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define CRC_SELFTEST 0x6fcf9e13
+#else
+# define CRC_SELFTEST 0xca87914d
+#endif
+
+BOOL crc32_selftests (void)
+{
+ int i;
+ unsigned __int32 crc = 0xffffffff;
+ BOOL bSuccess = FALSE;
+
+ for (i = 0; i < (int)sizeof(crc_32_tab); i++)
+ crc = UPDC32 (((unsigned char *) crc_32_tab)[i], crc);
+
+ bSuccess = CRC_SELFTEST == (crc ^ 0xffffffff);
+
+ bSuccess &= GetCrc32 ((unsigned char *)crc_32_tab, sizeof crc_32_tab) == CRC_SELFTEST;
+
+ return bSuccess;
+}
+
+#else // TC_MINIMIZE_CODE_SIZE
+
+unsigned __int32 GetCrc32 (unsigned char *data, int length)
+{
+ unsigned __int32 r = 0xFFFFFFFFUL;
+ int i, b;
+
+ for (i = 0; i < length; ++i)
+ {
+ r ^= data[i];
+ for (b = 0; b < 8; ++b)
+ {
+ if ((unsigned __int8) r & 1)
+ r = (r >> 1) ^ 0xEDB88320UL;
+ else
+ r >>= 1;
+ }
+ }
+
+ return r ^ 0xFFFFFFFFUL;
+}
+
+BOOL crc32_selftests ()
+{
+ unsigned __int8 testData[32];
+ unsigned __int8 i;
+
+ for (i = 0; i < sizeof (testData); ++i)
+ testData[i] = i;
+
+ return GetCrc32 (testData, sizeof (testData)) == 0x91267E8AUL;
+}
+
+#endif // TC_MINIMIZE_CODE_SIZE
diff --git a/src/Common/Crc.h b/src/Common/Crc.h
new file mode 100644
index 00000000..6b82040c
--- /dev/null
+++ b/src/Common/Crc.h
@@ -0,0 +1,35 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2008 TrueCrypt Developers Association
+ and are 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. */
+
+#ifndef TC_HEADER_CRC
+#define TC_HEADER_CRC
+
+#include "Tcdefs.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#define UPDC32(octet, crc)\
+ (unsigned __int32)((crc_32_tab[(((unsigned __int32)(crc)) ^ ((unsigned char)(octet))) & 0xff] ^ (((unsigned __int32)(crc)) >> 8)))
+
+unsigned __int32 GetCrc32 (unsigned char *data, int length);
+unsigned __int32 crc32int (unsigned __int32 *data);
+BOOL crc32_selftests (void);
+
+extern unsigned __int32 crc_32_tab[];
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // TC_HEADER_CRC
diff --git a/src/Common/Crypto.c b/src/Common/Crypto.c
new file mode 100644
index 00000000..3b87572a
--- /dev/null
+++ b/src/Common/Crypto.c
@@ -0,0 +1,1871 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2010 TrueCrypt Developers Association
+ and are 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 "Tcdefs.h"
+#include "Crypto.h"
+#include "Xts.h"
+#include "Crc.h"
+#include "Common/Endian.h"
+#include <string.h>
+#ifndef TC_WINDOWS_BOOT
+#include "EncryptionThreadPool.h"
+#endif
+#include "Volumes.h"
+
+/* Update the following when adding a new cipher or EA:
+
+ Crypto.h:
+ ID #define
+ MAX_EXPANDED_KEY #define
+
+ Crypto.c:
+ Ciphers[]
+ EncryptionAlgorithms[]
+ CipherInit()
+ EncipherBlock()
+ DecipherBlock()
+
+*/
+
+#ifndef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
+
+// Cipher configuration
+static Cipher Ciphers[] =
+{
+// Block Size Key Size Key Schedule Size
+// ID Name (Bytes) (Bytes) (Bytes)
+ { AES, "AES", 16, 32, AES_KS },
+ { SERPENT, "Serpent", 16, 32, 140*4 },
+ { TWOFISH, "Twofish", 16, 32, TWOFISH_KS },
+#ifndef TC_WINDOWS_BOOT
+ { BLOWFISH, "Blowfish", 8, 56, sizeof (BF_KEY) }, // Deprecated/legacy
+ { CAST, "CAST5", 8, 16, sizeof (CAST_KEY) }, // Deprecated/legacy
+ { TRIPLEDES,"Triple DES", 8, 8*3, sizeof (TDES_KEY) }, // Deprecated/legacy
+#endif
+ { 0, 0, 0, 0, 0 }
+};
+
+
+// Encryption algorithm configuration
+// The following modes have been deprecated (legacy): LRW, CBC, INNER_CBC, OUTER_CBC
+static EncryptionAlgorithm EncryptionAlgorithms[] =
+{
+ // Cipher(s) Modes FormatEnabled
+
+#ifndef TC_WINDOWS_BOOT
+
+ { { 0, 0 }, { 0, 0, 0, 0 }, 0 }, // Must be all-zero
+ { { AES, 0 }, { XTS, LRW, CBC, 0 }, 1 },
+ { { SERPENT, 0 }, { XTS, LRW, CBC, 0 }, 1 },
+ { { TWOFISH, 0 }, { XTS, LRW, CBC, 0 }, 1 },
+ { { TWOFISH, AES, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 },
+ { { SERPENT, TWOFISH, AES, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 },
+ { { AES, SERPENT, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 },
+ { { AES, TWOFISH, SERPENT, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 },
+ { { SERPENT, TWOFISH, 0 }, { XTS, LRW, OUTER_CBC, 0 }, 1 },
+ { { BLOWFISH, 0 }, { LRW, CBC, 0, 0 }, 0 }, // Deprecated/legacy
+ { { CAST, 0 }, { LRW, CBC, 0, 0 }, 0 }, // Deprecated/legacy
+ { { TRIPLEDES, 0 }, { LRW, CBC, 0, 0 }, 0 }, // Deprecated/legacy
+ { { BLOWFISH, AES, 0 }, { INNER_CBC, 0, 0, 0 }, 0 }, // Deprecated/legacy
+ { { SERPENT, BLOWFISH, AES, 0 }, { INNER_CBC, 0, 0, 0 }, 0 }, // Deprecated/legacy
+ { { 0, 0 }, { 0, 0, 0, 0 }, 0 } // Must be all-zero
+
+#else // TC_WINDOWS_BOOT
+
+ // Encryption algorithms available for boot drive encryption
+ { { 0, 0 }, { 0, 0 }, 0 }, // Must be all-zero
+ { { AES, 0 }, { XTS, 0 }, 1 },
+ { { SERPENT, 0 }, { XTS, 0 }, 1 },
+ { { TWOFISH, 0 }, { XTS, 0 }, 1 },
+ { { TWOFISH, AES, 0 }, { XTS, 0 }, 1 },
+ { { SERPENT, TWOFISH, AES, 0 }, { XTS, 0 }, 1 },
+ { { AES, SERPENT, 0 }, { XTS, 0 }, 1 },
+ { { AES, TWOFISH, SERPENT, 0 }, { XTS, 0 }, 1 },
+ { { SERPENT, TWOFISH, 0 }, { XTS, 0 }, 1 },
+ { { 0, 0 }, { 0, 0 }, 0 }, // Must be all-zero
+
+#endif
+
+};
+
+
+
+// Hash algorithms
+static Hash Hashes[] =
+{ // ID Name Deprecated System Encryption
+ { RIPEMD160, "RIPEMD-160", FALSE, TRUE },
+#ifndef TC_WINDOWS_BOOT
+ { SHA512, "SHA-512", FALSE, FALSE },
+ { WHIRLPOOL, "Whirlpool", FALSE, FALSE },
+ { SHA1, "SHA-1", TRUE, FALSE }, // Deprecated/legacy
+#endif
+ { 0, 0, 0 }
+};
+
+/* Return values: 0 = success, ERR_CIPHER_INIT_FAILURE (fatal), ERR_CIPHER_INIT_WEAK_KEY (non-fatal) */
+int CipherInit (int cipher, unsigned char *key, unsigned __int8 *ks)
+{
+ int retVal = ERR_SUCCESS;
+
+ switch (cipher)
+ {
+ case AES:
+#ifndef TC_WINDOWS_BOOT
+ if (aes_encrypt_key256 (key, (aes_encrypt_ctx *) ks) != EXIT_SUCCESS)
+ return ERR_CIPHER_INIT_FAILURE;
+
+ if (aes_decrypt_key256 (key, (aes_decrypt_ctx *) (ks + sizeof(aes_encrypt_ctx))) != EXIT_SUCCESS)
+ return ERR_CIPHER_INIT_FAILURE;
+#else
+ if (aes_set_key (key, (length_type) CipherGetKeySize(AES), (aes_context *) ks) != 0)
+ return ERR_CIPHER_INIT_FAILURE;
+#endif
+ break;
+
+ case SERPENT:
+ serpent_set_key (key, CipherGetKeySize(SERPENT) * 8, ks);
+ break;
+
+ case TWOFISH:
+ twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key, CipherGetKeySize(TWOFISH) * 8);
+ break;
+
+#ifndef TC_WINDOWS_BOOT
+
+ case BLOWFISH:
+ /* Deprecated/legacy */
+ BlowfishSetKey ((BF_KEY *)ks, CipherGetKeySize(BLOWFISH), key);
+ break;
+
+ case CAST:
+ /* Deprecated/legacy */
+ Cast5SetKey ((CAST_KEY *) ks, CipherGetKeySize(CAST), key);
+ break;
+
+ case TRIPLEDES:
+ /* Deprecated/legacy */
+ TripleDesSetKey (key, CipherGetKeySize (TRIPLEDES), (TDES_KEY *) ks);
+
+ // Verify whether all three DES keys are mutually different
+ if (((*((__int64 *) key) ^ *((__int64 *) key+1)) & 0xFEFEFEFEFEFEFEFEULL) == 0
+ || ((*((__int64 *) key+1) ^ *((__int64 *) key+2)) & 0xFEFEFEFEFEFEFEFEULL) == 0
+ || ((*((__int64 *) key) ^ *((__int64 *) key+2)) & 0xFEFEFEFEFEFEFEFEULL) == 0)
+ retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error
+
+ break;
+
+#endif // TC_WINDOWS_BOOT
+
+ default:
+ // Unknown/wrong cipher ID
+ return ERR_CIPHER_INIT_FAILURE;
+ }
+
+ return retVal;
+}
+
+void EncipherBlock(int cipher, void *data, void *ks)
+{
+ switch (cipher)
+ {
+ case AES:
+ // In 32-bit kernel mode, due to KeSaveFloatingPointState() overhead, AES instructions can be used only when processing the whole data unit.
+#if (defined (_WIN64) || !defined (TC_WINDOWS_DRIVER)) && !defined (TC_WINDOWS_BOOT)
+ if (IsAesHwCpuSupported())
+ aes_hw_cpu_encrypt (ks, data);
+ else
+#endif
+ aes_encrypt (data, data, ks);
+ break;
+
+ case TWOFISH: twofish_encrypt (ks, data, data); break;
+ case SERPENT: serpent_encrypt (data, data, ks); break;
+#ifndef TC_WINDOWS_BOOT
+ case BLOWFISH: BlowfishEncryptLE (data, data, ks, 1); break; // Deprecated/legacy
+ case CAST: Cast5Encrypt (data, data, ks); break; // Deprecated/legacy
+ case TRIPLEDES: TripleDesEncrypt (data, data, ks, 1); break; // Deprecated/legacy
+#endif
+ default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID
+ }
+}
+
+#ifndef TC_WINDOWS_BOOT
+
+void EncipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount)
+{
+ byte *data = dataPtr;
+#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
+ KFLOATING_SAVE floatingPointState;
+#endif
+
+ if (cipher == AES
+ && (blockCount & (32 - 1)) == 0
+ && IsAesHwCpuSupported()
+#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
+ && NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState))
+#endif
+ )
+ {
+ while (blockCount > 0)
+ {
+ aes_hw_cpu_encrypt_32_blocks (ks, data);
+
+ data += 32 * 16;
+ blockCount -= 32;
+ }
+
+#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
+ KeRestoreFloatingPointState (&floatingPointState);
+#endif
+ }
+ else
+ {
+ size_t blockSize = CipherGetBlockSize (cipher);
+ while (blockCount-- > 0)
+ {
+ EncipherBlock (cipher, data, ks);
+ data += blockSize;
+ }
+ }
+}
+
+#endif // !TC_WINDOWS_BOOT
+
+void DecipherBlock(int cipher, void *data, void *ks)
+{
+ switch (cipher)
+ {
+ case SERPENT: serpent_decrypt (data, data, ks); break;
+ case TWOFISH: twofish_decrypt (ks, data, data); break;
+#ifndef TC_WINDOWS_BOOT
+
+ case AES:
+#if defined (_WIN64) || !defined (TC_WINDOWS_DRIVER)
+ if (IsAesHwCpuSupported())
+ aes_hw_cpu_decrypt ((byte *) ks + sizeof (aes_encrypt_ctx), data);
+ else
+#endif
+ aes_decrypt (data, data, (void *) ((char *) ks + sizeof(aes_encrypt_ctx)));
+ break;
+
+ case BLOWFISH: BlowfishEncryptLE (data, data, ks, 0); break; // Deprecated/legacy
+ case CAST: Cast5Decrypt (data, data, ks); break; // Deprecated/legacy
+ case TRIPLEDES: TripleDesEncrypt (data, data, ks, 0); break; // Deprecated/legacy
+#else
+ case AES: aes_decrypt (data, data, ks); break;
+#endif
+ default: TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID
+ }
+}
+
+#ifndef TC_WINDOWS_BOOT
+
+void DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount)
+{
+ byte *data = dataPtr;
+#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
+ KFLOATING_SAVE floatingPointState;
+#endif
+
+ if (cipher == AES
+ && (blockCount & (32 - 1)) == 0
+ && IsAesHwCpuSupported()
+#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
+ && NT_SUCCESS (KeSaveFloatingPointState (&floatingPointState))
+#endif
+ )
+ {
+ while (blockCount > 0)
+ {
+ aes_hw_cpu_decrypt_32_blocks ((byte *) ks + sizeof (aes_encrypt_ctx), data);
+
+ data += 32 * 16;
+ blockCount -= 32;
+ }
+
+#if defined (TC_WINDOWS_DRIVER) && !defined (_WIN64)
+ KeRestoreFloatingPointState (&floatingPointState);
+#endif
+ }
+ else
+ {
+ size_t blockSize = CipherGetBlockSize (cipher);
+ while (blockCount-- > 0)
+ {
+ DecipherBlock (cipher, data, ks);
+ data += blockSize;
+ }
+ }
+}
+
+#endif // !TC_WINDOWS_BOOT
+
+
+// Ciphers support
+
+Cipher *CipherGet (int id)
+{
+ int i;
+ for (i = 0; Ciphers[i].Id != 0; i++)
+ if (Ciphers[i].Id == id)
+ return &Ciphers[i];
+
+ return NULL;
+}
+
+char *CipherGetName (int cipherId)
+{
+ return CipherGet (cipherId) -> Name;
+}
+
+int CipherGetBlockSize (int cipherId)
+{
+ return CipherGet (cipherId) -> BlockSize;
+}
+
+int CipherGetKeySize (int cipherId)
+{
+ return CipherGet (cipherId) -> KeySize;
+}
+
+int CipherGetKeyScheduleSize (int cipherId)
+{
+ return CipherGet (cipherId) -> KeyScheduleSize;
+}
+
+#ifndef TC_WINDOWS_BOOT
+
+BOOL CipherSupportsIntraDataUnitParallelization (int cipher)
+{
+ return cipher == AES && IsAesHwCpuSupported();
+}
+
+#endif
+
+
+// Encryption algorithms support
+
+int EAGetFirst ()
+{
+ return 1;
+}
+
+// Returns number of EAs
+int EAGetCount (void)
+{
+ int ea, count = 0;
+
+ for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea))
+ {
+ count++;
+ }
+ return count;
+}
+
+int EAGetNext (int previousEA)
+{
+ int id = previousEA + 1;
+ if (EncryptionAlgorithms[id].Ciphers[0] != 0) return id;
+ return 0;
+}
+
+
+// Return values: 0 = success, ERR_CIPHER_INIT_FAILURE (fatal), ERR_CIPHER_INIT_WEAK_KEY (non-fatal)
+int EAInit (int ea, unsigned char *key, unsigned __int8 *ks)
+{
+ int c, retVal = ERR_SUCCESS;
+
+ if (ea == 0)
+ return ERR_CIPHER_INIT_FAILURE;
+
+ for (c = EAGetFirstCipher (ea); c != 0; c = EAGetNextCipher (ea, c))
+ {
+ switch (CipherInit (c, key, ks))
+ {
+ case ERR_CIPHER_INIT_FAILURE:
+ return ERR_CIPHER_INIT_FAILURE;
+
+ case ERR_CIPHER_INIT_WEAK_KEY:
+ retVal = ERR_CIPHER_INIT_WEAK_KEY; // Non-fatal error
+ break;
+ }
+
+ key += CipherGetKeySize (c);
+ ks += CipherGetKeyScheduleSize (c);
+ }
+ return retVal;
+}
+
+
+#ifndef TC_WINDOWS_BOOT
+
+BOOL EAInitMode (PCRYPTO_INFO ci)
+{
+ switch (ci->mode)
+ {
+ case XTS:
+ // Secondary key schedule
+ if (EAInit (ci->ea, ci->k2, ci->ks2) != ERR_SUCCESS)
+ return FALSE;
+
+ /* Note: XTS mode could potentially be initialized with a weak key causing all blocks in one data unit
+ on the volume to be tweaked with zero tweaks (i.e. 512 bytes of the volume would be encrypted in ECB
+ mode). However, to create a TrueCrypt volume with such a weak key, each human being on Earth would have
+ to create approximately 11,378,125,361,078,862 (about eleven quadrillion) TrueCrypt volumes (provided
+ that the size of each of the volumes is 1024 terabytes). */
+ break;
+
+ case LRW:
+ switch (CipherGetBlockSize (EAGetFirstCipher (ci->ea)))
+ {
+ case 8:
+ /* Deprecated/legacy */
+ return Gf64TabInit (ci->k2, &ci->gf_ctx);
+
+ case 16:
+ return Gf128Tab64Init (ci->k2, &ci->gf_ctx);
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+
+ break;
+
+ case CBC:
+ case INNER_CBC:
+ case OUTER_CBC:
+ // The mode does not need to be initialized or is initialized elsewhere
+ return TRUE;
+
+ default:
+ // Unknown/wrong ID
+ TC_THROW_FATAL_EXCEPTION;
+ }
+ return TRUE;
+}
+
+
+// Returns name of EA, cascaded cipher names are separated by hyphens
+char *EAGetName (char *buf, int ea)
+{
+ int i = EAGetLastCipher(ea);
+ strcpy (buf, (i != 0) ? CipherGetName (i) : "?");
+
+ while (i = EAGetPreviousCipher(ea, i))
+ {
+ strcat (buf, "-");
+ strcat (buf, CipherGetName (i));
+ }
+
+ return buf;
+}
+
+
+int EAGetByName (char *name)
+{
+ int ea = EAGetFirst ();
+ char n[128];
+
+ do
+ {
+ EAGetName (n, ea);
+ if (strcmp (n, name) == 0)
+ return ea;
+ }
+ while (ea = EAGetNext (ea));
+
+ return 0;
+}
+
+#endif // TC_WINDOWS_BOOT
+
+// Returns sum of key sizes of all ciphers of the EA (in bytes)
+int EAGetKeySize (int ea)
+{
+ int i = EAGetFirstCipher (ea);
+ int size = CipherGetKeySize (i);
+
+ while (i = EAGetNextCipher (ea, i))
+ {
+ size += CipherGetKeySize (i);
+ }
+
+ return size;
+}
+
+
+// Returns the first mode of operation of EA
+int EAGetFirstMode (int ea)
+{
+ return (EncryptionAlgorithms[ea].Modes[0]);
+}
+
+
+int EAGetNextMode (int ea, int previousModeId)
+{
+ int c, i = 0;
+ while (c = EncryptionAlgorithms[ea].Modes[i++])
+ {
+ if (c == previousModeId)
+ return EncryptionAlgorithms[ea].Modes[i];
+ }
+
+ return 0;
+}
+
+
+#ifndef TC_WINDOWS_BOOT
+
+// Returns the name of the mode of operation of the whole EA
+char *EAGetModeName (int ea, int mode, BOOL capitalLetters)
+{
+ switch (mode)
+ {
+ case XTS:
+
+ return "XTS";
+
+ case LRW:
+
+ /* Deprecated/legacy */
+
+ return "LRW";
+
+ case CBC:
+ {
+ /* Deprecated/legacy */
+
+ char eaName[100];
+ EAGetName (eaName, ea);
+
+ if (strcmp (eaName, "Triple DES") == 0)
+ return capitalLetters ? "Outer-CBC" : "outer-CBC";
+
+ return "CBC";
+ }
+
+ case OUTER_CBC:
+
+ /* Deprecated/legacy */
+
+ return capitalLetters ? "Outer-CBC" : "outer-CBC";
+
+ case INNER_CBC:
+
+ /* Deprecated/legacy */
+
+ return capitalLetters ? "Inner-CBC" : "inner-CBC";
+
+ }
+ return "[unknown]";
+}
+
+#endif // TC_WINDOWS_BOOT
+
+
+// Returns sum of key schedule sizes of all ciphers of the EA
+int EAGetKeyScheduleSize (int ea)
+{
+ int i = EAGetFirstCipher(ea);
+ int size = CipherGetKeyScheduleSize (i);
+
+ while (i = EAGetNextCipher(ea, i))
+ {
+ size += CipherGetKeyScheduleSize (i);
+ }
+
+ return size;
+}
+
+
+// Returns the largest key size needed by an EA for the specified mode of operation
+int EAGetLargestKeyForMode (int mode)
+{
+ int ea, key = 0;
+
+ for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea))
+ {
+ if (!EAIsModeSupported (ea, mode))
+ continue;
+
+ if (EAGetKeySize (ea) >= key)
+ key = EAGetKeySize (ea);
+ }
+ return key;
+}
+
+
+// Returns the largest key needed by any EA for any mode
+int EAGetLargestKey ()
+{
+ int ea, key = 0;
+
+ for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea))
+ {
+ if (EAGetKeySize (ea) >= key)
+ key = EAGetKeySize (ea);
+ }
+
+ return key;
+}
+
+
+// Returns number of ciphers in EA
+int EAGetCipherCount (int ea)
+{
+ int i = 0;
+ while (EncryptionAlgorithms[ea].Ciphers[i++]);
+
+ return i - 1;
+}
+
+
+int EAGetFirstCipher (int ea)
+{
+ return EncryptionAlgorithms[ea].Ciphers[0];
+}
+
+
+int EAGetLastCipher (int ea)
+{
+ int c, i = 0;
+ while (c = EncryptionAlgorithms[ea].Ciphers[i++]);
+
+ return EncryptionAlgorithms[ea].Ciphers[i - 2];
+}
+
+
+int EAGetNextCipher (int ea, int previousCipherId)
+{
+ int c, i = 0;
+ while (c = EncryptionAlgorithms[ea].Ciphers[i++])
+ {
+ if (c == previousCipherId)
+ return EncryptionAlgorithms[ea].Ciphers[i];
+ }
+
+ return 0;
+}
+
+
+int EAGetPreviousCipher (int ea, int previousCipherId)
+{
+ int c, i = 0;
+
+ if (EncryptionAlgorithms[ea].Ciphers[i++] == previousCipherId)
+ return 0;
+
+ while (c = EncryptionAlgorithms[ea].Ciphers[i++])
+ {
+ if (c == previousCipherId)
+ return EncryptionAlgorithms[ea].Ciphers[i - 2];
+ }
+
+ return 0;
+}
+
+
+int EAIsFormatEnabled (int ea)
+{
+ return EncryptionAlgorithms[ea].FormatEnabled;
+}
+
+
+// Returns TRUE if the mode of operation is supported for the encryption algorithm
+BOOL EAIsModeSupported (int ea, int testedMode)
+{
+ int mode;
+
+ for (mode = EAGetFirstMode (ea); mode != 0; mode = EAGetNextMode (ea, mode))
+ {
+ if (mode == testedMode)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+Hash *HashGet (int id)
+{
+ int i;
+ for (i = 0; Hashes[i].Id != 0; i++)
+ if (Hashes[i].Id == id)
+ return &Hashes[i];
+
+ return 0;
+}
+
+
+int HashGetIdByName (char *name)
+{
+ int i;
+ for (i = 0; Hashes[i].Id != 0; i++)
+ if (strcmp (Hashes[i].Name, name) == 0)
+ return Hashes[i].Id;
+
+ return 0;
+}
+
+
+char *HashGetName (int hashId)
+{
+ return HashGet (hashId) -> Name;
+}
+
+
+BOOL HashIsDeprecated (int hashId)
+{
+ return HashGet (hashId) -> Deprecated;
+}
+
+
+#endif // TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
+
+
+#ifdef TC_WINDOWS_BOOT
+
+static byte CryptoInfoBufferInUse = 0;
+CRYPTO_INFO CryptoInfoBuffer;
+
+#endif
+
+PCRYPTO_INFO crypto_open ()
+{
+#ifndef TC_WINDOWS_BOOT
+
+ /* Do the crt allocation */
+ PCRYPTO_INFO cryptoInfo = (PCRYPTO_INFO) TCalloc (sizeof (CRYPTO_INFO));
+ if (cryptoInfo == NULL)
+ return NULL;
+
+ memset (cryptoInfo, 0, sizeof (CRYPTO_INFO));
+
+#ifndef DEVICE_DRIVER
+ VirtualLock (cryptoInfo, sizeof (CRYPTO_INFO));
+#endif
+
+ cryptoInfo->ea = -1;
+ return cryptoInfo;
+
+#else // TC_WINDOWS_BOOT
+
+#if 0
+ if (CryptoInfoBufferInUse)
+ TC_THROW_FATAL_EXCEPTION;
+#endif
+ CryptoInfoBufferInUse = 1;
+ return &CryptoInfoBuffer;
+
+#endif // TC_WINDOWS_BOOT
+}
+
+void crypto_loadkey (PKEY_INFO keyInfo, char *lpszUserKey, int nUserKeyLen)
+{
+ keyInfo->keyLength = nUserKeyLen;
+ burn (keyInfo->userKey, sizeof (keyInfo->userKey));
+ memcpy (keyInfo->userKey, lpszUserKey, nUserKeyLen);
+}
+
+void crypto_close (PCRYPTO_INFO cryptoInfo)
+{
+#ifndef TC_WINDOWS_BOOT
+
+ if (cryptoInfo != NULL)
+ {
+ burn (cryptoInfo, sizeof (CRYPTO_INFO));
+#ifndef DEVICE_DRIVER
+ VirtualUnlock (cryptoInfo, sizeof (CRYPTO_INFO));
+#endif
+ TCfree (cryptoInfo);
+ }
+
+#else // TC_WINDOWS_BOOT
+
+ burn (&CryptoInfoBuffer, sizeof (CryptoInfoBuffer));
+ CryptoInfoBufferInUse = FALSE;
+
+#endif // TC_WINDOWS_BOOT
+}
+
+
+#ifndef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
+
+
+#ifndef TC_NO_COMPILER_INT64
+void Xor128 (unsigned __int64 *a, unsigned __int64 *b)
+{
+ *a++ ^= *b++;
+ *a ^= *b;
+}
+
+
+void Xor64 (unsigned __int64 *a, unsigned __int64 *b)
+{
+ *a ^= *b;
+}
+
+
+void EncryptBufferLRW128 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo)
+{
+ /* Deprecated/legacy */
+
+ int cipher = EAGetFirstCipher (cryptoInfo->ea);
+ int cipherCount = EAGetCipherCount (cryptoInfo->ea);
+ unsigned __int8 *p = buffer;
+ unsigned __int8 *ks = cryptoInfo->ks;
+ unsigned __int8 i[8];
+ unsigned __int8 t[16];
+ unsigned __int64 b;
+
+ *(unsigned __int64 *)i = BE64(blockIndex);
+
+ if (length % 16)
+ TC_THROW_FATAL_EXCEPTION;
+
+ // Note that the maximum supported volume size is 8589934592 GB (i.e., 2^63 bytes).
+
+ for (b = 0; b < length >> 4; b++)
+ {
+ Gf128MulBy64Tab (i, t, &cryptoInfo->gf_ctx);
+ Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t);
+
+ if (cipherCount > 1)
+ {
+ // Cipher cascade
+ for (cipher = EAGetFirstCipher (cryptoInfo->ea);
+ cipher != 0;
+ cipher = EAGetNextCipher (cryptoInfo->ea, cipher))
+ {
+ EncipherBlock (cipher, p, ks);
+ ks += CipherGetKeyScheduleSize (cipher);
+ }
+ ks = cryptoInfo->ks;
+ }
+ else
+ {
+ EncipherBlock (cipher, p, ks);
+ }
+
+ Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t);
+
+ p += 16;
+
+ if (i[7] != 0xff)
+ i[7]++;
+ else
+ *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 );
+ }
+
+ FAST_ERASE64 (t, sizeof(t));
+}
+
+
+void EncryptBufferLRW64 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo)
+{
+ /* Deprecated/legacy */
+
+ int cipher = EAGetFirstCipher (cryptoInfo->ea);
+ unsigned __int8 *p = buffer;
+ unsigned __int8 *ks = cryptoInfo->ks;
+ unsigned __int8 i[8];
+ unsigned __int8 t[8];
+ unsigned __int64 b;
+
+ *(unsigned __int64 *)i = BE64(blockIndex);
+
+ if (length % 8)
+ TC_THROW_FATAL_EXCEPTION;
+
+ for (b = 0; b < length >> 3; b++)
+ {
+ Gf64MulTab (i, t, &cryptoInfo->gf_ctx);
+ Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t);
+
+ EncipherBlock (cipher, p, ks);
+
+ Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t);
+
+ p += 8;
+
+ if (i[7] != 0xff)
+ i[7]++;
+ else
+ *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 );
+ }
+
+ FAST_ERASE64 (t, sizeof(t));
+}
+
+
+void DecryptBufferLRW128 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo)
+{
+ /* Deprecated/legacy */
+
+ int cipher = EAGetFirstCipher (cryptoInfo->ea);
+ int cipherCount = EAGetCipherCount (cryptoInfo->ea);
+ unsigned __int8 *p = buffer;
+ unsigned __int8 *ks = cryptoInfo->ks;
+ unsigned __int8 i[8];
+ unsigned __int8 t[16];
+ unsigned __int64 b;
+
+ *(unsigned __int64 *)i = BE64(blockIndex);
+
+ if (length % 16)
+ TC_THROW_FATAL_EXCEPTION;
+
+ // Note that the maximum supported volume size is 8589934592 GB (i.e., 2^63 bytes).
+
+ for (b = 0; b < length >> 4; b++)
+ {
+ Gf128MulBy64Tab (i, t, &cryptoInfo->gf_ctx);
+ Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t);
+
+ if (cipherCount > 1)
+ {
+ // Cipher cascade
+ ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea);
+
+ for (cipher = EAGetLastCipher (cryptoInfo->ea);
+ cipher != 0;
+ cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher))
+ {
+ ks -= CipherGetKeyScheduleSize (cipher);
+ DecipherBlock (cipher, p, ks);
+ }
+ }
+ else
+ {
+ DecipherBlock (cipher, p, ks);
+ }
+
+ Xor128 ((unsigned __int64 *)p, (unsigned __int64 *)t);
+
+ p += 16;
+
+ if (i[7] != 0xff)
+ i[7]++;
+ else
+ *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 );
+ }
+
+ FAST_ERASE64 (t, sizeof(t));
+}
+
+
+
+void DecryptBufferLRW64 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo)
+{
+ /* Deprecated/legacy */
+
+ int cipher = EAGetFirstCipher (cryptoInfo->ea);
+ unsigned __int8 *p = buffer;
+ unsigned __int8 *ks = cryptoInfo->ks;
+ unsigned __int8 i[8];
+ unsigned __int8 t[8];
+ unsigned __int64 b;
+
+ *(unsigned __int64 *)i = BE64(blockIndex);
+
+ if (length % 8)
+ TC_THROW_FATAL_EXCEPTION;
+
+ for (b = 0; b < length >> 3; b++)
+ {
+ Gf64MulTab (i, t, &cryptoInfo->gf_ctx);
+ Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t);
+
+ DecipherBlock (cipher, p, ks);
+
+ Xor64 ((unsigned __int64 *)p, (unsigned __int64 *)t);
+
+ p += 8;
+
+ if (i[7] != 0xff)
+ i[7]++;
+ else
+ *(unsigned __int64 *)i = BE64 ( BE64(*(unsigned __int64 *)i) + 1 );
+ }
+
+ FAST_ERASE64 (t, sizeof(t));
+}
+
+
+// Initializes IV and whitening values for sector encryption/decryption in CBC mode.
+// IMPORTANT: This function has been deprecated (legacy).
+static void
+InitSectorIVAndWhitening (unsigned __int64 unitNo,
+ int blockSize,
+ unsigned __int32 *iv,
+ unsigned __int64 *ivSeed,
+ unsigned __int32 *whitening)
+{
+
+ /* IMPORTANT: This function has been deprecated (legacy) */
+
+ unsigned __int64 iv64[4];
+ unsigned __int32 *iv32 = (unsigned __int32 *) iv64;
+
+ iv64[0] = ivSeed[0] ^ LE64(unitNo);
+ iv64[1] = ivSeed[1] ^ LE64(unitNo);
+ iv64[2] = ivSeed[2] ^ LE64(unitNo);
+ if (blockSize == 16)
+ {
+ iv64[3] = ivSeed[3] ^ LE64(unitNo);
+ }
+
+ iv[0] = iv32[0];
+ iv[1] = iv32[1];
+
+ switch (blockSize)
+ {
+ case 16:
+
+ // 128-bit block
+
+ iv[2] = iv32[2];
+ iv[3] = iv32[3];
+
+ whitening[0] = LE32( crc32int ( &iv32[4] ) ^ crc32int ( &iv32[7] ) );
+ whitening[1] = LE32( crc32int ( &iv32[5] ) ^ crc32int ( &iv32[6] ) );
+ break;
+
+ case 8:
+
+ // 64-bit block
+
+ whitening[0] = LE32( crc32int ( &iv32[2] ) ^ crc32int ( &iv32[5] ) );
+ whitening[1] = LE32( crc32int ( &iv32[3] ) ^ crc32int ( &iv32[4] ) );
+ break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+}
+
+
+// EncryptBufferCBC (deprecated/legacy)
+//
+// data: data to be encrypted
+// len: number of bytes to encrypt (must be divisible by the largest cipher block size)
+// ks: scheduled key
+// iv: IV
+// whitening: whitening constants
+// ea: outer-CBC cascade ID (0 = CBC/inner-CBC)
+// cipher: CBC/inner-CBC cipher ID (0 = outer-CBC)
+
+static void
+EncryptBufferCBC (unsigned __int32 *data,
+ unsigned int len,
+ unsigned __int8 *ks,
+ unsigned __int32 *iv,
+ unsigned __int32 *whitening,
+ int ea,
+ int cipher)
+{
+ /* IMPORTANT: This function has been deprecated (legacy) */
+
+ unsigned __int32 bufIV[4];
+ unsigned __int64 i;
+ int blockSize = CipherGetBlockSize (ea != 0 ? EAGetFirstCipher (ea) : cipher);
+
+ if (len % blockSize)
+ TC_THROW_FATAL_EXCEPTION;
+
+ // IV
+ bufIV[0] = iv[0];
+ bufIV[1] = iv[1];
+ if (blockSize == 16)
+ {
+ bufIV[2] = iv[2];
+ bufIV[3] = iv[3];
+ }
+
+ // Encrypt each block
+ for (i = 0; i < len/blockSize; i++)
+ {
+ // CBC
+ data[0] ^= bufIV[0];
+ data[1] ^= bufIV[1];
+ if (blockSize == 16)
+ {
+ data[2] ^= bufIV[2];
+ data[3] ^= bufIV[3];
+ }
+
+ if (ea != 0)
+ {
+ // Outer-CBC
+ for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher))
+ {
+ EncipherBlock (cipher, data, ks);
+ ks += CipherGetKeyScheduleSize (cipher);
+ }
+ ks -= EAGetKeyScheduleSize (ea);
+ }
+ else
+ {
+ // CBC/inner-CBC
+ EncipherBlock (cipher, data, ks);
+ }
+
+ // CBC
+ bufIV[0] = data[0];
+ bufIV[1] = data[1];
+ if (blockSize == 16)
+ {
+ bufIV[2] = data[2];
+ bufIV[3] = data[3];
+ }
+
+ // Whitening
+ data[0] ^= whitening[0];
+ data[1] ^= whitening[1];
+ if (blockSize == 16)
+ {
+ data[2] ^= whitening[0];
+ data[3] ^= whitening[1];
+ }
+
+ data += blockSize / sizeof(*data);
+ }
+}
+
+
+// DecryptBufferCBC (deprecated/legacy)
+//
+// data: data to be decrypted
+// len: number of bytes to decrypt (must be divisible by the largest cipher block size)
+// ks: scheduled key
+// iv: IV
+// whitening: whitening constants
+// ea: outer-CBC cascade ID (0 = CBC/inner-CBC)
+// cipher: CBC/inner-CBC cipher ID (0 = outer-CBC)
+
+static void
+DecryptBufferCBC (unsigned __int32 *data,
+ unsigned int len,
+ unsigned __int8 *ks,
+ unsigned __int32 *iv,
+ unsigned __int32 *whitening,
+ int ea,
+ int cipher)
+{
+
+ /* IMPORTANT: This function has been deprecated (legacy) */
+
+ unsigned __int32 bufIV[4];
+ unsigned __int64 i;
+ unsigned __int32 ct[4];
+ int blockSize = CipherGetBlockSize (ea != 0 ? EAGetFirstCipher (ea) : cipher);
+
+ if (len % blockSize)
+ TC_THROW_FATAL_EXCEPTION;
+
+ // IV
+ bufIV[0] = iv[0];
+ bufIV[1] = iv[1];
+ if (blockSize == 16)
+ {
+ bufIV[2] = iv[2];
+ bufIV[3] = iv[3];
+ }
+
+ // Decrypt each block
+ for (i = 0; i < len/blockSize; i++)
+ {
+ // Dewhitening
+ data[0] ^= whitening[0];
+ data[1] ^= whitening[1];
+ if (blockSize == 16)
+ {
+ data[2] ^= whitening[0];
+ data[3] ^= whitening[1];
+ }
+
+ // CBC
+ ct[0] = data[0];
+ ct[1] = data[1];
+ if (blockSize == 16)
+ {
+ ct[2] = data[2];
+ ct[3] = data[3];
+ }
+
+ if (ea != 0)
+ {
+ // Outer-CBC
+ ks += EAGetKeyScheduleSize (ea);
+ for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher))
+ {
+ ks -= CipherGetKeyScheduleSize (cipher);
+ DecipherBlock (cipher, data, ks);
+ }
+ }
+ else
+ {
+ // CBC/inner-CBC
+ DecipherBlock (cipher, data, ks);
+ }
+
+ // CBC
+ data[0] ^= bufIV[0];
+ data[1] ^= bufIV[1];
+ bufIV[0] = ct[0];
+ bufIV[1] = ct[1];
+ if (blockSize == 16)
+ {
+ data[2] ^= bufIV[2];
+ data[3] ^= bufIV[3];
+ bufIV[2] = ct[2];
+ bufIV[3] = ct[3];
+ }
+
+ data += blockSize / sizeof(*data);
+ }
+}
+#endif // #ifndef TC_NO_COMPILER_INT64
+
+
+// EncryptBuffer
+//
+// buf: data to be encrypted; the start of the buffer is assumed to be aligned with the start of a data unit.
+// len: number of bytes to encrypt; must be divisible by the block size (for cascaded ciphers, divisible
+// by the largest block size used within the cascade)
+void EncryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo)
+{
+ switch (cryptoInfo->mode)
+ {
+ case XTS:
+ {
+ unsigned __int8 *ks = cryptoInfo->ks;
+ unsigned __int8 *ks2 = cryptoInfo->ks2;
+ UINT64_STRUCT dataUnitNo;
+ int cipher;
+
+ // When encrypting/decrypting a buffer (typically a volume header) the sequential number
+ // of the first XTS data unit in the buffer is always 0 and the start of the buffer is
+ // always assumed to be aligned with the start of a data unit.
+ dataUnitNo.LowPart = 0;
+ dataUnitNo.HighPart = 0;
+
+ for (cipher = EAGetFirstCipher (cryptoInfo->ea);
+ cipher != 0;
+ cipher = EAGetNextCipher (cryptoInfo->ea, cipher))
+ {
+ EncryptBufferXTS (buf, len, &dataUnitNo, 0, ks, ks2, cipher);
+
+ ks += CipherGetKeyScheduleSize (cipher);
+ ks2 += CipherGetKeyScheduleSize (cipher);
+ }
+ }
+ break;
+
+#ifndef TC_NO_COMPILER_INT64
+ case LRW:
+
+ /* Deprecated/legacy */
+
+ switch (CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea)))
+ {
+ case 8:
+ EncryptBufferLRW64 ((unsigned __int8 *)buf, (unsigned __int64) len, 1, cryptoInfo);
+ break;
+
+ case 16:
+ EncryptBufferLRW128 ((unsigned __int8 *)buf, (unsigned __int64) len, 1, cryptoInfo);
+ break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+ break;
+
+ case CBC:
+ case INNER_CBC:
+ {
+ /* Deprecated/legacy */
+
+ unsigned __int8 *ks = cryptoInfo->ks;
+ int cipher;
+
+ for (cipher = EAGetFirstCipher (cryptoInfo->ea);
+ cipher != 0;
+ cipher = EAGetNextCipher (cryptoInfo->ea, cipher))
+ {
+ EncryptBufferCBC ((unsigned __int32 *) buf,
+ (unsigned int) len,
+ ks,
+ (unsigned __int32 *) cryptoInfo->k2,
+ (unsigned __int32 *) &cryptoInfo->k2[8],
+ 0,
+ cipher);
+
+ ks += CipherGetKeyScheduleSize (cipher);
+ }
+ }
+ break;
+
+ case OUTER_CBC:
+
+ /* Deprecated/legacy */
+
+ EncryptBufferCBC ((unsigned __int32 *) buf,
+ (unsigned int) len,
+ cryptoInfo->ks,
+ (unsigned __int32 *) cryptoInfo->k2,
+ (unsigned __int32 *) &cryptoInfo->k2[8],
+ cryptoInfo->ea,
+ 0);
+
+ break;
+#endif // #ifndef TC_NO_COMPILER_INT64
+
+ default:
+ // Unknown/wrong ID
+ TC_THROW_FATAL_EXCEPTION;
+ }
+}
+
+#ifndef TC_NO_COMPILER_INT64
+// Converts a data unit number to the index of the first LRW block in the data unit.
+// Note that the maximum supported volume size is 8589934592 GB (i.e., 2^63 bytes).
+uint64 DataUnit2LRWIndex (uint64 dataUnit, int blockSize, PCRYPTO_INFO ci)
+{
+ /* Deprecated/legacy */
+
+ if (ci->hiddenVolume)
+ dataUnit -= ci->hiddenVolumeOffset / ENCRYPTION_DATA_UNIT_SIZE;
+ else
+ dataUnit -= TC_VOLUME_HEADER_SIZE_LEGACY / ENCRYPTION_DATA_UNIT_SIZE; // Compensate for the volume header size
+
+ switch (blockSize)
+ {
+ case 8:
+ return (dataUnit << 6) | 1;
+
+ case 16:
+ return (dataUnit << 5) | 1;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+
+ return 0;
+}
+#endif // #ifndef TC_NO_COMPILER_INT64
+
+
+// buf: data to be encrypted
+// unitNo: sequential number of the data unit with which the buffer starts
+// nbrUnits: number of data units in the buffer
+void EncryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, uint32 nbrUnits, PCRYPTO_INFO ci)
+#ifndef TC_WINDOWS_BOOT
+{
+ EncryptionThreadPoolDoWork (EncryptDataUnitsWork, buf, structUnitNo, nbrUnits, ci);
+}
+
+void EncryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci)
+#endif // !TC_WINDOWS_BOOT
+{
+ int ea = ci->ea;
+ unsigned __int8 *ks = ci->ks;
+ unsigned __int8 *ks2 = ci->ks2;
+ int cipher;
+
+#ifndef TC_NO_COMPILER_INT64
+ void *iv = ci->k2; // Deprecated/legacy
+ unsigned __int64 unitNo = structUnitNo->Value;
+ unsigned __int64 *iv64 = (unsigned __int64 *) iv; // Deprecated/legacy
+ unsigned __int32 sectorIV[4]; // Deprecated/legacy
+ unsigned __int32 secWhitening[2]; // Deprecated/legacy
+#endif
+
+ switch (ci->mode)
+ {
+ case XTS:
+ for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher))
+ {
+ EncryptBufferXTS (buf,
+ nbrUnits * ENCRYPTION_DATA_UNIT_SIZE,
+ structUnitNo,
+ 0,
+ ks,
+ ks2,
+ cipher);
+
+ ks += CipherGetKeyScheduleSize (cipher);
+ ks2 += CipherGetKeyScheduleSize (cipher);
+ }
+ break;
+
+#ifndef TC_NO_COMPILER_INT64
+ case LRW:
+
+ /* Deprecated/legacy */
+
+ switch (CipherGetBlockSize (EAGetFirstCipher (ea)))
+ {
+ case 8:
+ EncryptBufferLRW64 (buf,
+ (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE,
+ DataUnit2LRWIndex (unitNo, 8, ci),
+ ci);
+ break;
+
+ case 16:
+ EncryptBufferLRW128 (buf,
+ (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE,
+ DataUnit2LRWIndex (unitNo, 16, ci),
+ ci);
+ break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+ break;
+
+ case CBC:
+ case INNER_CBC:
+
+ /* Deprecated/legacy */
+
+ while (nbrUnits--)
+ {
+ for (cipher = EAGetFirstCipher (ea); cipher != 0; cipher = EAGetNextCipher (ea, cipher))
+ {
+ InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening);
+
+ EncryptBufferCBC ((unsigned __int32 *) buf,
+ ENCRYPTION_DATA_UNIT_SIZE,
+ ks,
+ sectorIV,
+ secWhitening,
+ 0,
+ cipher);
+
+ ks += CipherGetKeyScheduleSize (cipher);
+ }
+ ks -= EAGetKeyScheduleSize (ea);
+ buf += ENCRYPTION_DATA_UNIT_SIZE;
+ unitNo++;
+ }
+ break;
+
+ case OUTER_CBC:
+
+ /* Deprecated/legacy */
+
+ while (nbrUnits--)
+ {
+ InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening);
+
+ EncryptBufferCBC ((unsigned __int32 *) buf,
+ ENCRYPTION_DATA_UNIT_SIZE,
+ ks,
+ sectorIV,
+ secWhitening,
+ ea,
+ 0);
+
+ buf += ENCRYPTION_DATA_UNIT_SIZE;
+ unitNo++;
+ }
+ break;
+#endif // #ifndef TC_NO_COMPILER_INT64
+
+ default:
+ // Unknown/wrong ID
+ TC_THROW_FATAL_EXCEPTION;
+ }
+}
+
+// DecryptBuffer
+//
+// buf: data to be decrypted; the start of the buffer is assumed to be aligned with the start of a data unit.
+// len: number of bytes to decrypt; must be divisible by the block size (for cascaded ciphers, divisible
+// by the largest block size used within the cascade)
+void DecryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo)
+{
+ switch (cryptoInfo->mode)
+ {
+ case XTS:
+ {
+ unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea);
+ unsigned __int8 *ks2 = cryptoInfo->ks2 + EAGetKeyScheduleSize (cryptoInfo->ea);
+ UINT64_STRUCT dataUnitNo;
+ int cipher;
+
+ // When encrypting/decrypting a buffer (typically a volume header) the sequential number
+ // of the first XTS data unit in the buffer is always 0 and the start of the buffer is
+ // always assumed to be aligned with the start of the data unit 0.
+ dataUnitNo.LowPart = 0;
+ dataUnitNo.HighPart = 0;
+
+ for (cipher = EAGetLastCipher (cryptoInfo->ea);
+ cipher != 0;
+ cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher))
+ {
+ ks -= CipherGetKeyScheduleSize (cipher);
+ ks2 -= CipherGetKeyScheduleSize (cipher);
+
+ DecryptBufferXTS (buf, len, &dataUnitNo, 0, ks, ks2, cipher);
+ }
+ }
+ break;
+
+#ifndef TC_NO_COMPILER_INT64
+ case LRW:
+
+ /* Deprecated/legacy */
+
+ switch (CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea)))
+ {
+ case 8:
+ DecryptBufferLRW64 (buf, (unsigned __int64) len, 1, cryptoInfo);
+ break;
+
+ case 16:
+ DecryptBufferLRW128 (buf, (unsigned __int64) len, 1, cryptoInfo);
+ break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+ break;
+
+ case CBC:
+ case INNER_CBC:
+ {
+ /* Deprecated/legacy */
+
+ unsigned __int8 *ks = cryptoInfo->ks + EAGetKeyScheduleSize (cryptoInfo->ea);
+ int cipher;
+ for (cipher = EAGetLastCipher (cryptoInfo->ea);
+ cipher != 0;
+ cipher = EAGetPreviousCipher (cryptoInfo->ea, cipher))
+ {
+ ks -= CipherGetKeyScheduleSize (cipher);
+
+ DecryptBufferCBC ((unsigned __int32 *) buf,
+ (unsigned int) len,
+ ks,
+ (unsigned __int32 *) cryptoInfo->k2,
+ (unsigned __int32 *) &cryptoInfo->k2[8],
+ 0,
+ cipher);
+ }
+ }
+ break;
+
+ case OUTER_CBC:
+
+ /* Deprecated/legacy */
+
+ DecryptBufferCBC ((unsigned __int32 *) buf,
+ (unsigned int) len,
+ cryptoInfo->ks,
+ (unsigned __int32 *) cryptoInfo->k2,
+ (unsigned __int32 *) &cryptoInfo->k2[8],
+ cryptoInfo->ea,
+ 0);
+
+ break;
+#endif // #ifndef TC_NO_COMPILER_INT64
+
+ default:
+ // Unknown/wrong ID
+ TC_THROW_FATAL_EXCEPTION;
+ }
+}
+
+// buf: data to be decrypted
+// unitNo: sequential number of the data unit with which the buffer starts
+// nbrUnits: number of data units in the buffer
+void DecryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, uint32 nbrUnits, PCRYPTO_INFO ci)
+#ifndef TC_WINDOWS_BOOT
+{
+ EncryptionThreadPoolDoWork (DecryptDataUnitsWork, buf, structUnitNo, nbrUnits, ci);
+}
+
+void DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci)
+#endif // !TC_WINDOWS_BOOT
+{
+ int ea = ci->ea;
+ unsigned __int8 *ks = ci->ks;
+ unsigned __int8 *ks2 = ci->ks2;
+ int cipher;
+
+#ifndef TC_NO_COMPILER_INT64
+ void *iv = ci->k2; // Deprecated/legacy
+ unsigned __int64 unitNo = structUnitNo->Value;
+ unsigned __int64 *iv64 = (unsigned __int64 *) iv; // Deprecated/legacy
+ unsigned __int32 sectorIV[4]; // Deprecated/legacy
+ unsigned __int32 secWhitening[2]; // Deprecated/legacy
+#endif // #ifndef TC_NO_COMPILER_INT64
+
+
+ switch (ci->mode)
+ {
+ case XTS:
+ ks += EAGetKeyScheduleSize (ea);
+ ks2 += EAGetKeyScheduleSize (ea);
+
+ for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher))
+ {
+ ks -= CipherGetKeyScheduleSize (cipher);
+ ks2 -= CipherGetKeyScheduleSize (cipher);
+
+ DecryptBufferXTS (buf,
+ nbrUnits * ENCRYPTION_DATA_UNIT_SIZE,
+ structUnitNo,
+ 0,
+ ks,
+ ks2,
+ cipher);
+ }
+ break;
+
+#ifndef TC_NO_COMPILER_INT64
+ case LRW:
+
+ /* Deprecated/legacy */
+
+ switch (CipherGetBlockSize (EAGetFirstCipher (ea)))
+ {
+ case 8:
+ DecryptBufferLRW64 (buf,
+ (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE,
+ DataUnit2LRWIndex (unitNo, 8, ci),
+ ci);
+ break;
+
+ case 16:
+ DecryptBufferLRW128 (buf,
+ (unsigned __int64) nbrUnits * ENCRYPTION_DATA_UNIT_SIZE,
+ DataUnit2LRWIndex (unitNo, 16, ci),
+ ci);
+ break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+ break;
+
+ case CBC:
+ case INNER_CBC:
+
+ /* Deprecated/legacy */
+
+ while (nbrUnits--)
+ {
+ ks += EAGetKeyScheduleSize (ea);
+ for (cipher = EAGetLastCipher (ea); cipher != 0; cipher = EAGetPreviousCipher (ea, cipher))
+ {
+ InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (cipher), sectorIV, iv64, secWhitening);
+
+ ks -= CipherGetKeyScheduleSize (cipher);
+
+ DecryptBufferCBC ((unsigned __int32 *) buf,
+ ENCRYPTION_DATA_UNIT_SIZE,
+ ks,
+ sectorIV,
+ secWhitening,
+ 0,
+ cipher);
+ }
+ buf += ENCRYPTION_DATA_UNIT_SIZE;
+ unitNo++;
+ }
+ break;
+
+ case OUTER_CBC:
+
+ /* Deprecated/legacy */
+
+ while (nbrUnits--)
+ {
+ InitSectorIVAndWhitening (unitNo, CipherGetBlockSize (EAGetFirstCipher (ea)), sectorIV, iv64, secWhitening);
+
+ DecryptBufferCBC ((unsigned __int32 *) buf,
+ ENCRYPTION_DATA_UNIT_SIZE,
+ ks,
+ sectorIV,
+ secWhitening,
+ ea,
+ 0);
+
+ buf += ENCRYPTION_DATA_UNIT_SIZE;
+ unitNo++;
+ }
+ break;
+#endif // #ifndef TC_NO_COMPILER_INT64
+
+ default:
+ // Unknown/wrong ID
+ TC_THROW_FATAL_EXCEPTION;
+ }
+}
+
+
+// Returns the maximum number of bytes necessary to be generated by the PBKDF2 (PKCS #5)
+int GetMaxPkcs5OutSize (void)
+{
+ int size = 32;
+
+ size = max (size, EAGetLargestKeyForMode (XTS) * 2); // Sizes of primary + secondary keys
+
+#ifndef TC_WINDOWS_BOOT
+ size = max (size, LEGACY_VOL_IV_SIZE + EAGetLargestKeyForMode (LRW)); // Deprecated/legacy
+ size = max (size, LEGACY_VOL_IV_SIZE + EAGetLargestKeyForMode (CBC)); // Deprecated/legacy
+ size = max (size, LEGACY_VOL_IV_SIZE + EAGetLargestKeyForMode (OUTER_CBC)); // Deprecated/legacy
+ size = max (size, LEGACY_VOL_IV_SIZE + EAGetLargestKeyForMode (INNER_CBC)); // Deprecated/legacy
+#endif
+
+ return size;
+}
+
+
+#else // TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
+
+
+#if !defined (TC_WINDOWS_BOOT_AES) && !defined (TC_WINDOWS_BOOT_SERPENT) && !defined (TC_WINDOWS_BOOT_TWOFISH)
+#error No cipher defined
+#endif
+
+void EncipherBlock(int cipher, void *data, void *ks)
+{
+#ifdef TC_WINDOWS_BOOT_AES
+ if (IsAesHwCpuSupported())
+ aes_hw_cpu_encrypt ((byte *) ks, data);
+ else
+ aes_encrypt (data, data, ks);
+#elif defined (TC_WINDOWS_BOOT_SERPENT)
+ serpent_encrypt (data, data, ks);
+#elif defined (TC_WINDOWS_BOOT_TWOFISH)
+ twofish_encrypt (ks, data, data);
+#endif
+}
+
+void DecipherBlock(int cipher, void *data, void *ks)
+{
+#ifdef TC_WINDOWS_BOOT_AES
+ if (IsAesHwCpuSupported())
+ aes_hw_cpu_decrypt ((byte *) ks + sizeof (aes_encrypt_ctx) + 14 * 16, data);
+ else
+ aes_decrypt (data, data, (aes_decrypt_ctx *) ((byte *) ks + sizeof(aes_encrypt_ctx)));
+#elif defined (TC_WINDOWS_BOOT_SERPENT)
+ serpent_decrypt (data, data, ks);
+#elif defined (TC_WINDOWS_BOOT_TWOFISH)
+ twofish_decrypt (ks, data, data);
+#endif
+}
+
+int EAGetFirst ()
+{
+ return 1;
+}
+
+int EAGetNext (int previousEA)
+{
+ return 0;
+}
+
+int EAInit (int ea, unsigned char *key, unsigned __int8 *ks)
+{
+#ifdef TC_WINDOWS_BOOT_AES
+
+ aes_init();
+
+ if (aes_encrypt_key256 (key, (aes_encrypt_ctx *) ks) != EXIT_SUCCESS)
+ return ERR_CIPHER_INIT_FAILURE;
+ if (aes_decrypt_key256 (key, (aes_decrypt_ctx *) (ks + sizeof (aes_encrypt_ctx))) != EXIT_SUCCESS)
+ return ERR_CIPHER_INIT_FAILURE;
+
+#elif defined (TC_WINDOWS_BOOT_SERPENT)
+ serpent_set_key (key, 32 * 8, ks);
+#elif defined (TC_WINDOWS_BOOT_TWOFISH)
+ twofish_set_key ((TwofishInstance *)ks, (const u4byte *)key, 32 * 8);
+#endif
+ return ERR_SUCCESS;
+}
+
+int EAGetKeySize (int ea)
+{
+ return 32;
+}
+
+int EAGetFirstCipher (int ea)
+{
+ return 1;
+}
+
+void EncryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo)
+{
+ UINT64_STRUCT dataUnitNo;
+ dataUnitNo.LowPart = 0; dataUnitNo.HighPart = 0;
+ EncryptBufferXTS (buf, len, &dataUnitNo, 0, cryptoInfo->ks, cryptoInfo->ks2, 1);
+}
+
+void EncryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci)
+{
+ EncryptBufferXTS (buf, nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, structUnitNo, 0, ci->ks, ci->ks2, 1);
+}
+
+void DecryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo)
+{
+ UINT64_STRUCT dataUnitNo;
+ dataUnitNo.LowPart = 0; dataUnitNo.HighPart = 0;
+ DecryptBufferXTS (buf, len, &dataUnitNo, 0, cryptoInfo->ks, cryptoInfo->ks2, 1);
+}
+
+void DecryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci)
+{
+ DecryptBufferXTS (buf, nbrUnits * ENCRYPTION_DATA_UNIT_SIZE, structUnitNo, 0, ci->ks, ci->ks2, 1);
+}
+
+#endif // TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
+
+
+#if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_AES)
+
+static BOOL HwEncryptionDisabled = FALSE;
+
+BOOL IsAesHwCpuSupported ()
+{
+ static BOOL state = FALSE;
+ static BOOL stateValid = FALSE;
+
+ if (!stateValid)
+ {
+ state = is_aes_hw_cpu_supported() ? TRUE : FALSE;
+ stateValid = TRUE;
+ }
+
+ return state && !HwEncryptionDisabled;
+}
+
+void EnableHwEncryption (BOOL enable)
+{
+#if defined (TC_WINDOWS_BOOT)
+ if (enable)
+ aes_hw_cpu_enable_sse();
+#endif
+
+ HwEncryptionDisabled = !enable;
+}
+
+BOOL IsHwEncryptionEnabled ()
+{
+ return !HwEncryptionDisabled;
+}
+
+#endif // !TC_WINDOWS_BOOT
diff --git a/src/Common/Crypto.h b/src/Common/Crypto.h
new file mode 100644
index 00000000..dd35eeca
--- /dev/null
+++ b/src/Common/Crypto.h
@@ -0,0 +1,332 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2010 TrueCrypt Developers Association
+ and are 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. */
+
+/* Update the following when adding a new cipher or EA:
+
+ Crypto.h:
+ ID #define
+ MAX_EXPANDED_KEY #define
+
+ Crypto.c:
+ Ciphers[]
+ EncryptionAlgorithms[]
+ CipherInit()
+ EncipherBlock()
+ DecipherBlock()
+
+*/
+
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+#include "Tcdefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Encryption data unit size, which may differ from the sector size and must always be 512
+#define ENCRYPTION_DATA_UNIT_SIZE 512
+
+// Size of the salt (in bytes)
+#define PKCS5_SALT_SIZE 64
+
+// Size of the volume header area containing concatenated master key(s) and secondary key(s) (XTS mode)
+#define MASTER_KEYDATA_SIZE 256
+
+// Size of the deprecated volume header item containing either an IV seed (CBC mode) or tweak key (LRW mode)
+#define LEGACY_VOL_IV_SIZE 32
+
+// The first PRF to try when mounting
+#define FIRST_PRF_ID 1
+
+// Hash algorithms (pseudorandom functions).
+enum
+{
+ RIPEMD160 = FIRST_PRF_ID,
+#ifndef TC_WINDOWS_BOOT
+ SHA512,
+ WHIRLPOOL,
+ SHA1, // Deprecated/legacy
+#endif
+ HASH_ENUM_END_ID
+};
+
+// The last PRF to try when mounting and also the number of implemented PRFs
+#define LAST_PRF_ID (HASH_ENUM_END_ID - 1)
+
+#define RIPEMD160_BLOCKSIZE 64
+#define RIPEMD160_DIGESTSIZE 20
+
+#define SHA1_BLOCKSIZE 64
+#define SHA1_DIGESTSIZE 20
+
+#define SHA512_BLOCKSIZE 128
+#define SHA512_DIGESTSIZE 64
+
+#define WHIRLPOOL_BLOCKSIZE 64
+#define WHIRLPOOL_DIGESTSIZE 64
+
+#define MAX_DIGESTSIZE WHIRLPOOL_DIGESTSIZE
+
+#define DEFAULT_HASH_ALGORITHM FIRST_PRF_ID
+#define DEFAULT_HASH_ALGORITHM_BOOT RIPEMD160
+
+// The mode of operation used for newly created volumes and first to try when mounting
+#define FIRST_MODE_OF_OPERATION_ID 1
+
+// Modes of operation
+enum
+{
+ /* If you add/remove a mode, update the following: GetMaxPkcs5OutSize(), EAInitMode() */
+
+ XTS = FIRST_MODE_OF_OPERATION_ID,
+#ifndef TC_WINDOWS_BOOT
+ LRW, // Deprecated/legacy
+ CBC, // Deprecated/legacy
+ OUTER_CBC, // Deprecated/legacy
+ INNER_CBC, // Deprecated/legacy
+#endif
+ MODE_ENUM_END_ID
+};
+
+
+// The last mode of operation to try when mounting and also the number of implemented modes
+#define LAST_MODE_OF_OPERATION (MODE_ENUM_END_ID - 1)
+
+// Ciphertext/plaintext block size for XTS mode (in bytes)
+#define BYTES_PER_XTS_BLOCK 16
+
+// Number of ciphertext/plaintext blocks per XTS data unit
+#define BLOCKS_PER_XTS_DATA_UNIT (ENCRYPTION_DATA_UNIT_SIZE / BYTES_PER_XTS_BLOCK)
+
+
+// Cipher IDs
+enum
+{
+ NONE = 0,
+ AES,
+ SERPENT,
+ TWOFISH,
+#ifndef TC_WINDOWS_BOOT
+ BLOWFISH, // Deprecated/legacy
+ CAST, // Deprecated/legacy
+ TRIPLEDES // Deprecated/legacy
+#endif
+};
+
+typedef struct
+{
+ int Id; // Cipher ID
+ char *Name; // Name
+ int BlockSize; // Block size (bytes)
+ int KeySize; // Key size (bytes)
+ int KeyScheduleSize; // Scheduled key size (bytes)
+} Cipher;
+
+typedef struct
+{
+ int Ciphers[4]; // Null terminated array of ciphers used by encryption algorithm
+ int Modes[LAST_MODE_OF_OPERATION + 1]; // Null terminated array of modes of operation
+ int FormatEnabled;
+} EncryptionAlgorithm;
+
+typedef struct
+{
+ int Id; // Hash ID
+ char *Name; // Name
+ BOOL Deprecated;
+ BOOL SystemEncryption; // Available for system encryption
+} Hash;
+
+// Maxium length of scheduled key
+#if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_AES)
+# define AES_KS (sizeof(aes_encrypt_ctx) + sizeof(aes_decrypt_ctx))
+#else
+# define AES_KS (sizeof(aes_context))
+#endif
+#define SERPENT_KS (140 * 4)
+
+#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE
+
+# ifdef TC_WINDOWS_BOOT_AES
+# define MAX_EXPANDED_KEY AES_KS
+# elif defined (TC_WINDOWS_BOOT_SERPENT)
+# define MAX_EXPANDED_KEY SERPENT_KS
+# elif defined (TC_WINDOWS_BOOT_TWOFISH)
+# define MAX_EXPANDED_KEY TWOFISH_KS
+# endif
+
+#else
+
+#define MAX_EXPANDED_KEY (AES_KS + SERPENT_KS + TWOFISH_KS)
+
+#endif
+
+#ifdef DEBUG
+# define PRAND_DISK_WIPE_PASSES 3
+#else
+# define PRAND_DISK_WIPE_PASSES 256
+#endif
+
+#if !defined (TC_WINDOWS_BOOT) || defined (TC_WINDOWS_BOOT_AES)
+# include "Aes.h"
+#else
+# include "AesSmall.h"
+#endif
+
+#include "Aes_hw_cpu.h"
+#include "Blowfish.h"
+#include "Cast.h"
+#include "Des.h"
+#include "Serpent.h"
+#include "Twofish.h"
+
+#include "Rmd160.h"
+#ifndef TC_WINDOWS_BOOT
+# include "Sha1.h"
+# include "Sha2.h"
+# include "Whirlpool.h"
+#endif
+
+#include "GfMul.h"
+#include "Password.h"
+
+typedef struct keyInfo_t
+{
+ int noIterations; /* Number of times to iterate (PKCS-5) */
+ int keyLength; /* Length of the key */
+ __int8 userKey[MAX_PASSWORD]; /* Password (to which keyfiles may have been applied). WITHOUT +1 for the null terminator. */
+ __int8 salt[PKCS5_SALT_SIZE]; /* PKCS-5 salt */
+ __int8 master_keydata[MASTER_KEYDATA_SIZE]; /* Concatenated master primary and secondary key(s) (XTS mode). For LRW (deprecated/legacy), it contains the tweak key before the master key(s). For CBC (deprecated/legacy), it contains the IV seed before the master key(s). */
+} KEY_INFO, *PKEY_INFO;
+
+typedef struct CRYPTO_INFO_t
+{
+ int ea; /* Encryption algorithm ID */
+ int mode; /* Mode of operation (e.g., XTS) */
+ unsigned __int8 ks[MAX_EXPANDED_KEY]; /* Primary key schedule (if it is a cascade, it conatins multiple concatenated keys) */
+ unsigned __int8 ks2[MAX_EXPANDED_KEY]; /* Secondary key schedule (if cascade, multiple concatenated) for XTS mode. */
+
+ BOOL hiddenVolume; // Indicates whether the volume is mounted/mountable as hidden volume
+
+#ifndef TC_WINDOWS_BOOT
+ uint16 HeaderVersion;
+
+ GfCtx gf_ctx;
+
+ unsigned __int8 master_keydata[MASTER_KEYDATA_SIZE]; /* This holds the volume header area containing concatenated master key(s) and secondary key(s) (XTS mode). For LRW (deprecated/legacy), it contains the tweak key before the master key(s). For CBC (deprecated/legacy), it contains the IV seed before the master key(s). */
+ unsigned __int8 k2[MASTER_KEYDATA_SIZE]; /* For XTS, this contains the secondary key (if cascade, multiple concatenated). For LRW (deprecated/legacy), it contains the tweak key. For CBC (deprecated/legacy), it contains the IV seed. */
+ unsigned __int8 salt[PKCS5_SALT_SIZE];
+ int noIterations;
+ int pkcs5;
+
+ uint64 volume_creation_time; // Legacy
+ uint64 header_creation_time; // Legacy
+
+ BOOL bProtectHiddenVolume; // Indicates whether the volume contains a hidden volume to be protected against overwriting
+ BOOL bHiddenVolProtectionAction; // TRUE if a write operation has been denied by the driver in order to prevent the hidden volume from being overwritten (set to FALSE upon volume mount).
+
+ uint64 volDataAreaOffset; // Absolute position, in bytes, of the first data sector of the volume.
+
+ uint64 hiddenVolumeSize; // Size of the hidden volume excluding the header (in bytes). Set to 0 for standard volumes.
+ uint64 hiddenVolumeOffset; // Absolute position, in bytes, of the first hidden volume data sector within the host volume (provided that there is a hidden volume within). This must be set for all hidden volumes; in case of a normal volume, this variable is only used when protecting a hidden volume within it.
+ uint64 hiddenVolumeProtectedSize;
+
+ BOOL bPartitionInInactiveSysEncScope; // If TRUE, the volume is a partition located on an encrypted system drive and mounted without pre-boot authentication.
+
+ UINT64_STRUCT FirstDataUnitNo; // First data unit number of the volume. This is 0 for file-hosted and non-system partition-hosted volumes. For partitions within key scope of system encryption this reflects real physical offset within the device (this is used e.g. when such a partition is mounted as a regular volume without pre-boot authentication).
+
+ uint16 RequiredProgramVersion;
+ BOOL LegacyVolume;
+
+ uint32 SectorSize;
+
+#endif // !TC_WINDOWS_BOOT
+
+ UINT64_STRUCT VolumeSize;
+
+ UINT64_STRUCT EncryptedAreaStart;
+ UINT64_STRUCT EncryptedAreaLength;
+
+ uint32 HeaderFlags;
+
+} CRYPTO_INFO, *PCRYPTO_INFO;
+
+PCRYPTO_INFO crypto_open (void);
+void crypto_loadkey (PKEY_INFO keyInfo, char *lpszUserKey, int nUserKeyLen);
+void crypto_close (PCRYPTO_INFO cryptoInfo);
+
+int CipherGetBlockSize (int cipher);
+int CipherGetKeySize (int cipher);
+int CipherGetKeyScheduleSize (int cipher);
+BOOL CipherSupportsIntraDataUnitParallelization (int cipher);
+char * CipherGetName (int cipher);
+
+int CipherInit (int cipher, unsigned char *key, unsigned char *ks);
+int EAInit (int ea, unsigned char *key, unsigned char *ks);
+BOOL EAInitMode (PCRYPTO_INFO ci);
+void EncipherBlock(int cipher, void *data, void *ks);
+void DecipherBlock(int cipher, void *data, void *ks);
+#ifndef TC_WINDOWS_BOOT
+void EncipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount);
+void DecipherBlocks (int cipher, void *dataPtr, void *ks, size_t blockCount);
+#endif
+
+int EAGetFirst ();
+int EAGetCount (void);
+int EAGetNext (int previousEA);
+char * EAGetName (char *buf, int ea);
+int EAGetByName (char *name);
+int EAGetKeySize (int ea);
+int EAGetFirstMode (int ea);
+int EAGetNextMode (int ea, int previousModeId);
+char * EAGetModeName (int ea, int mode, BOOL capitalLetters);
+int EAGetKeyScheduleSize (int ea);
+int EAGetLargestKey ();
+int EAGetLargestKeyForMode (int mode);
+
+int EAGetCipherCount (int ea);
+int EAGetFirstCipher (int ea);
+int EAGetLastCipher (int ea);
+int EAGetNextCipher (int ea, int previousCipherId);
+int EAGetPreviousCipher (int ea, int previousCipherId);
+int EAIsFormatEnabled (int ea);
+BOOL EAIsModeSupported (int ea, int testedMode);
+
+char *HashGetName (int hash_algo_id);
+BOOL HashIsDeprecated (int hashId);
+
+int GetMaxPkcs5OutSize (void);
+
+void EncryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, uint32 nbrUnits, PCRYPTO_INFO ci);
+void EncryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci);
+void DecryptDataUnits (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, uint32 nbrUnits, PCRYPTO_INFO ci);
+void DecryptDataUnitsCurrentThread (unsigned __int8 *buf, const UINT64_STRUCT *structUnitNo, TC_LARGEST_COMPILER_UINT nbrUnits, PCRYPTO_INFO ci);
+void EncryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo);
+void DecryptBuffer (unsigned __int8 *buf, TC_LARGEST_COMPILER_UINT len, PCRYPTO_INFO cryptoInfo);
+#ifndef TC_NO_COMPILER_INT64
+void EncryptBufferLRW128 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo);
+void DecryptBufferLRW128 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo);
+void EncryptBufferLRW64 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo);
+void DecryptBufferLRW64 (byte *buffer, uint64 length, uint64 blockIndex, PCRYPTO_INFO cryptoInfo);
+uint64 DataUnit2LRWIndex (uint64 dataUnit, int blockSize, PCRYPTO_INFO ci);
+#endif // #ifndef TC_NO_COMPILER_INT64
+
+BOOL IsAesHwCpuSupported ();
+void EnableHwEncryption (BOOL enable);
+BOOL IsHwEncryptionEnabled ();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CRYPTO_H */
diff --git a/src/Common/Dictionary.c b/src/Common/Dictionary.c
new file mode 100644
index 00000000..382e6b70
--- /dev/null
+++ b/src/Common/Dictionary.c
@@ -0,0 +1,80 @@
+/*
+ Copyright (c) 2005-2009 TrueCrypt Developers Association. All rights reserved.
+
+ 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 "../Common/Dictionary.h"
+#include <windows.h>
+#include <map>
+#include <string>
+
+using namespace std;
+
+static map <string, void *> StringKeyMap;
+static map <int, void *> IntKeyMap;
+
+static void *DataPool = NULL;
+static size_t DataPoolSize = 0;
+
+
+void AddDictionaryEntry (char *key, int intKey, void *value)
+{
+ if (key)
+ StringKeyMap[key] = value;
+
+ if (intKey != 0)
+ IntKeyMap[intKey] = value;
+}
+
+
+void *GetDictionaryValue (const char *key)
+{
+ map <string, void *>::const_iterator i = StringKeyMap.find (key);
+
+ if (i == StringKeyMap.end())
+ return NULL;
+
+ return i->second;
+}
+
+
+void *GetDictionaryValueByInt (int intKey)
+{
+ map <int, void *>::const_iterator i = IntKeyMap.find (intKey);
+
+ if (i == IntKeyMap.end())
+ return NULL;
+
+ return i->second;
+}
+
+
+void *AddPoolData (void *data, size_t dataSize)
+{
+ if (DataPoolSize + dataSize > DATA_POOL_CAPACITY) return NULL;
+
+ if (DataPool == NULL)
+ {
+ DataPool = malloc (DATA_POOL_CAPACITY);
+ if (DataPool == NULL) return NULL;
+ }
+
+ memcpy ((BYTE *)DataPool + DataPoolSize, data, dataSize);
+
+ // Ensure 32-bit alignment for next entries
+ dataSize = (dataSize + 3) & (~(size_t)3);
+
+ DataPoolSize += dataSize;
+ return (BYTE *)DataPool + DataPoolSize - dataSize;
+}
+
+
+void ClearDictionaryPool ()
+{
+ DataPoolSize = 0;
+ StringKeyMap.clear();
+ IntKeyMap.clear();
+} \ No newline at end of file
diff --git a/src/Common/Dictionary.h b/src/Common/Dictionary.h
new file mode 100644
index 00000000..a3ae4d6b
--- /dev/null
+++ b/src/Common/Dictionary.h
@@ -0,0 +1,30 @@
+/*
+ Copyright (c) 2005-2009 TrueCrypt Developers Association. All rights reserved.
+
+ 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.
+*/
+
+#ifndef DICTIONARY_H
+#define DICTIONARY_H
+
+#include <windows.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DATA_POOL_CAPACITY 1000000
+
+void AddDictionaryEntry (char *key, int intKey, void *value);
+void *GetDictionaryValue (const char *key);
+void *GetDictionaryValueByInt (int intKey);
+void *AddPoolData (void *data, size_t dataSize);
+void ClearDictionaryPool ();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c
new file mode 100644
index 00000000..50059882
--- /dev/null
+++ b/src/Common/Dlgcode.c
@@ -0,0 +1,9848 @@
+/*
+ Legal Notice: Some portions of the source code contained in this file were
+ derived from the source code of Encryption for the Masses 2.02a, which is
+ Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
+ Agreement for Encryption for the Masses'. Modifications and additions to
+ the original source code (contained in this file) and all other portions
+ of this file are Copyright (c) 2003-2012 TrueCrypt Developers Association
+ and are 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 "Tcdefs.h"
+
+#include <windowsx.h>
+#include <dbghelp.h>
+#include <dbt.h>
+#include <fcntl.h>
+#include <io.h>
+#include <math.h>
+#include <shlobj.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "Resource.h"
+
+#include "Platform/Finally.h"
+#include "Platform/ForEach.h"
+#include "Apidrvr.h"
+#include "BootEncryption.h"
+#include "Combo.h"
+#include "Crc.h"
+#include "Crypto.h"
+#include "Dictionary.h"
+#include "Dlgcode.h"
+#include "EncryptionThreadPool.h"
+#include "Endian.h"
+#include "Format/Inplace.h"
+#include "Language.h"
+#include "Keyfiles.h"
+#include "Pkcs5.h"
+#include "Random.h"
+#include "Registry.h"
+#include "SecurityToken.h"
+#include "Tests.h"
+#include "Volumes.h"
+#include "Wipe.h"
+#include "Xml.h"
+#include "Xts.h"
+#include "Boot/Windows/BootCommon.h"
+
+#ifdef TCMOUNT
+#include "Mount/Mount.h"
+#endif
+
+#ifdef VOLFORMAT
+#include "Format/Tcformat.h"
+#endif
+
+#ifdef SETUP
+#include "Setup/Setup.h"
+#endif
+
+using namespace TrueCrypt;
+
+LONG DriverVersion;
+
+char *LastDialogId;
+char szHelpFile[TC_MAX_PATH];
+char szHelpFile2[TC_MAX_PATH];
+char SecurityTokenLibraryPath[TC_MAX_PATH];
+
+HFONT hFixedDigitFont = NULL;
+HFONT hBoldFont = NULL;
+HFONT hTitleFont = NULL;
+HFONT hFixedFont = NULL;
+
+HFONT hUserFont = NULL;
+HFONT hUserUnderlineFont = NULL;
+HFONT hUserBoldFont = NULL;
+HFONT hUserUnderlineBoldFont = NULL;
+
+HFONT WindowTitleBarFont;
+
+int ScreenDPI = USER_DEFAULT_SCREEN_DPI;
+double DPIScaleFactorX = 1;
+double DPIScaleFactorY = 1;
+double DlgAspectRatio = 1;
+
+HWND MainDlg = NULL;
+wchar_t *lpszTitle = NULL;
+
+BOOL Silent = FALSE;
+BOOL bPreserveTimestamp = TRUE;
+BOOL bStartOnLogon = FALSE;
+BOOL bMountDevicesOnLogon = FALSE;
+BOOL bMountFavoritesOnLogon = FALSE;
+
+BOOL bHistory = FALSE;
+
+// Status of detection of hidden sectors (whole-system-drive encryption).
+// 0 - Unknown/undetermined/completed, 1: Detection is or was in progress (but did not complete e.g. due to system crash).
+int HiddenSectorDetectionStatus = 0;
+
+OSVersionEnum nCurrentOS = WIN_UNKNOWN;
+int CurrentOSMajor = 0;
+int CurrentOSMinor = 0;
+int CurrentOSServicePack = 0;
+BOOL RemoteSession = FALSE;
+BOOL UacElevated = FALSE;
+
+BOOL bPortableModeConfirmed = FALSE; // TRUE if it is certain that the instance is running in portable mode
+
+BOOL bInPlaceEncNonSysPending = FALSE; // TRUE if the non-system in-place encryption config file indicates that one or more partitions are scheduled to be encrypted. This flag is set only when config files are loaded during app startup.
+
+/* Globals used by Mount and Format (separately per instance) */
+BOOL KeyFilesEnable = FALSE;
+KeyFile *FirstKeyFile = NULL;
+KeyFilesDlgParam defaultKeyFilesParam;
+
+BOOL IgnoreWmDeviceChange = FALSE;
+BOOL DeviceChangeBroadcastDisabled = FALSE;
+BOOL LastMountedVolumeDirty;
+BOOL MountVolumesAsSystemFavorite = FALSE;
+BOOL FavoriteMountOnArrivalInProgress = FALSE;
+BOOL MultipleMountOperationInProgress = FALSE;
+
+/* Handle to the device driver */
+HANDLE hDriver = INVALID_HANDLE_VALUE;
+
+/* This mutex is used to prevent multiple instances of the wizard or main app from dealing with system encryption */
+volatile HANDLE hSysEncMutex = NULL;
+
+/* This mutex is used for non-system in-place encryption but only for informative (non-blocking) purposes,
+such as whether an app should prompt the user whether to resume scheduled process. */
+volatile HANDLE hNonSysInplaceEncMutex = NULL;
+
+/* This mutex is used to prevent multiple instances of the wizard or main app from trying to install or
+register the driver or from trying to launch it in portable mode at the same time. */
+volatile HANDLE hDriverSetupMutex = NULL;
+
+/* This mutex is used to prevent users from running the main TrueCrypt app or the wizard while an instance
+of the TrueCrypt installer is running (which is also useful for enforcing restart before the apps can be used). */
+volatile HANDLE hAppSetupMutex = NULL;
+
+HINSTANCE hInst = NULL;
+HCURSOR hCursor = NULL;
+
+ATOM hDlgClass, hSplashClass;
+
+/* This value may changed only by calling ChangeSystemEncryptionStatus(). Only the wizard can change it
+(others may still read it though). */
+int SystemEncryptionStatus = SYSENC_STATUS_NONE;
+
+/* Only the wizard can change this value (others may only read it). */
+WipeAlgorithmId nWipeMode = TC_WIPE_NONE;
+
+BOOL bSysPartitionSelected = FALSE; /* TRUE if the user selected the system partition via the Select Device dialog */
+BOOL bSysDriveSelected = FALSE; /* TRUE if the user selected the system drive via the Select Device dialog */
+
+/* To populate these arrays, call GetSysDevicePaths(). If they contain valid paths, bCachedSysDevicePathsValid is TRUE. */
+char SysPartitionDevicePath [TC_MAX_PATH];
+char SysDriveDevicePath [TC_MAX_PATH];
+string ExtraBootPartitionDevicePath;
+char bCachedSysDevicePathsValid = FALSE;
+
+BOOL bHyperLinkBeingTracked = FALSE;
+
+int WrongPwdRetryCounter = 0;
+
+static FILE *ConfigFileHandle;
+char *ConfigBuffer;
+
+BOOL SystemFileSelectorCallPending = FALSE;
+DWORD SystemFileSelectorCallerThreadId;
+
+#define RANDPOOL_DISPLAY_REFRESH_INTERVAL 30
+#define RANDPOOL_DISPLAY_ROWS 16
+#define RANDPOOL_DISPLAY_COLUMNS 20
+
+/* Windows dialog class */
+#define WINDOWS_DIALOG_CLASS "#32770"
+
+/* Custom class names */
+#define TC_DLG_CLASS "CustomDlg"
+#define TC_SPLASH_CLASS "SplashDlg"
+
+/* Benchmarks */
+
+#ifndef SETUP
+
+#define BENCHMARK_MAX_ITEMS 100
+#define BENCHMARK_DEFAULT_BUF_SIZE BYTES_PER_MB
+#define HASH_FNC_BENCHMARKS FALSE // For development purposes only. Must be FALSE when building a public release.
+#define PKCS5_BENCHMARKS FALSE // For development purposes only. Must be FALSE when building a public release.
+#if PKCS5_BENCHMARKS && HASH_FNC_BENCHMARKS
+#error PKCS5_BENCHMARKS and HASH_FNC_BENCHMARKS are both TRUE (at least one of them should be FALSE).
+#endif
+
+enum
+{
+ BENCHMARK_SORT_BY_NAME = 0,
+ BENCHMARK_SORT_BY_SPEED
+};
+
+typedef struct
+{
+ int id;
+ char name[100];
+ unsigned __int64 encSpeed;
+ unsigned __int64 decSpeed;
+ unsigned __int64 meanBytesPerSec;
+} BENCHMARK_REC;
+
+BENCHMARK_REC benchmarkTable [BENCHMARK_MAX_ITEMS];
+int benchmarkTotalItems = 0;
+int benchmarkBufferSize = BENCHMARK_DEFAULT_BUF_SIZE;
+int benchmarkLastBufferSize = BENCHMARK_DEFAULT_BUF_SIZE;
+int benchmarkSortMethod = BENCHMARK_SORT_BY_SPEED;
+LARGE_INTEGER benchmarkPerformanceFrequency;
+
+#endif // #ifndef SETUP
+
+
+typedef struct
+{
+ void *strings;
+ BOOL bold;
+
+} MULTI_CHOICE_DLGPROC_PARAMS;
+
+
+void cleanup ()
+{
+ /* Cleanup the GDI fonts */
+ if (hFixedFont != NULL)
+ DeleteObject (hFixedFont);
+ if (hFixedDigitFont != NULL)
+ DeleteObject (hFixedDigitFont);
+ if (hBoldFont != NULL)
+ DeleteObject (hBoldFont);
+ if (hTitleFont != NULL)
+ DeleteObject (hTitleFont);
+ if (hUserFont != NULL)
+ DeleteObject (hUserFont);
+ if (hUserUnderlineFont != NULL)
+ DeleteObject (hUserUnderlineFont);
+ if (hUserBoldFont != NULL)
+ DeleteObject (hUserBoldFont);
+ if (hUserUnderlineBoldFont != NULL)
+ DeleteObject (hUserUnderlineBoldFont);
+
+ /* Cleanup our dialog class */
+ if (hDlgClass)
+ UnregisterClass (TC_DLG_CLASS, hInst);
+ if (hSplashClass)
+ UnregisterClass (TC_SPLASH_CLASS, hInst);
+
+ /* Close the device driver handle */
+ if (hDriver != INVALID_HANDLE_VALUE)
+ {
+ // Unload driver mode if possible (non-install mode)
+ if (IsNonInstallMode ())
+ {
+ // If a dismount was forced in the lifetime of the driver, Windows may later prevent it to be loaded again from
+ // the same path. Therefore, the driver will not be unloaded even though it was loaded in non-install mode.
+ int driverUnloadDisabled;
+ DWORD dwResult;
+
+ if (!DeviceIoControl (hDriver, TC_IOCTL_IS_DRIVER_UNLOAD_DISABLED, NULL, 0, &driverUnloadDisabled, sizeof (driverUnloadDisabled), &dwResult, NULL))
+ driverUnloadDisabled = 0;
+
+ if (!driverUnloadDisabled)
+ DriverUnload ();
+ else
+ {
+ CloseHandle (hDriver);
+ hDriver = INVALID_HANDLE_VALUE;
+ }
+ }
+ else
+ {
+ CloseHandle (hDriver);
+ hDriver = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ if (ConfigBuffer != NULL)
+ {
+ free (ConfigBuffer);
+ ConfigBuffer = NULL;
+ }
+
+ CoUninitialize ();
+
+ CloseSysEncMutex ();
+
+#ifndef SETUP
+ try
+ {
+ if (SecurityToken::IsInitialized())
+ SecurityToken::CloseLibrary();
+ }
+ catch (...) { }
+
+ EncryptionThreadPoolStop();
+#endif
+}
+
+
+void LowerCaseCopy (char *lpszDest, const char *lpszSource)
+{
+ int i = strlen (lpszSource);
+
+ lpszDest[i] = 0;
+ while (--i >= 0)
+ {
+ lpszDest[i] = (char) tolower (lpszSource[i]);
+ }
+
+}
+
+void UpperCaseCopy (char *lpszDest, const char *lpszSource)
+{
+ int i = strlen (lpszSource);
+
+ lpszDest[i] = 0;
+ while (--i >= 0)
+ {
+ lpszDest[i] = (char) toupper (lpszSource[i]);
+ }
+}
+
+
+std::string ToUpperCase (const std::string &str)
+{
+ string u;
+ foreach (char c, str)
+ {
+ u += (char) toupper (c);
+ }
+
+ return u;
+}
+
+
+BOOL IsVolumeDeviceHosted (const char *lpszDiskFile)
+{
+ return strstr (lpszDiskFile, "\\Device\\") == lpszDiskFile
+ || strstr (lpszDiskFile, "\\DEVICE\\") == lpszDiskFile;
+}
+
+
+void CreateFullVolumePath (char *lpszDiskFile, const char *lpszFileName, BOOL * bDevice)
+{
+ UpperCaseCopy (lpszDiskFile, lpszFileName);
+
+ *bDevice = FALSE;
+
+ if (memcmp (lpszDiskFile, "\\DEVICE", sizeof (char) * 7) == 0)
+ {
+ *bDevice = TRUE;
+ }
+
+ strcpy (lpszDiskFile, lpszFileName);
+
+#if _DEBUG
+ OutputDebugString ("CreateFullVolumePath: ");
+ OutputDebugString (lpszDiskFile);
+ OutputDebugString ("\n");
+#endif
+
+}
+
+int FakeDosNameForDevice (const char *lpszDiskFile, char *lpszDosDevice, char *lpszCFDevice, BOOL bNameOnly)
+{
+ BOOL bDosLinkCreated = TRUE;
+ sprintf (lpszDosDevice, "truecrypt%lu", GetCurrentProcessId ());
+
+ if (bNameOnly == FALSE)
+ bDosLinkCreated = DefineDosDevice (DDD_RAW_TARGET_PATH, lpszDosDevice, lpszDiskFile);
+
+ if (bDosLinkCreated == FALSE)
+ return ERR_OS_ERROR;
+ else
+ sprintf (lpszCFDevice, "\\\\.\\%s", lpszDosDevice);
+
+ return 0;
+}
+
+int RemoveFakeDosName (char *lpszDiskFile, char *lpszDosDevice)
+{
+ BOOL bDosLinkRemoved = DefineDosDevice (DDD_RAW_TARGET_PATH | DDD_EXACT_MATCH_ON_REMOVE |
+ DDD_REMOVE_DEFINITION, lpszDosDevice, lpszDiskFile);
+ if (bDosLinkRemoved == FALSE)
+ {
+ return ERR_OS_ERROR;
+ }
+
+ return 0;
+}
+
+
+void AbortProcess (char *stringId)
+{
+ // Note that this function also causes localcleanup() to be called (see atexit())
+ MessageBeep (MB_ICONEXCLAMATION);
+ MessageBoxW (NULL, GetString (stringId), lpszTitle, ICON_HAND);
+ exit (1);
+}
+
+void AbortProcessSilent (void)
+{
+ // Note that this function also causes localcleanup() to be called (see atexit())
+ exit (1);
+}
+
+
+#pragma warning(push)
+#pragma warning(disable:4702)
+
+void *err_malloc (size_t size)
+{
+ void *z = (void *) TCalloc (size);
+ if (z)
+ return z;
+ AbortProcess ("OUTOFMEMORY");
+ return 0;
+}
+
+#pragma warning(pop)
+
+
+char *err_strdup (char *lpszText)
+{
+ int j = (strlen (lpszText) + 1) * sizeof (char);
+ char *z = (char *) err_malloc (j);
+ memmove (z, lpszText, j);
+ return z;
+}
+
+
+BOOL IsDiskReadError (DWORD error)
+{
+ return (error == ERROR_CRC
+ || error == ERROR_IO_DEVICE
+ || error == ERROR_BAD_CLUSTERS
+ || error == ERROR_SECTOR_NOT_FOUND
+ || error == ERROR_READ_FAULT
+ || error == ERROR_INVALID_FUNCTION // I/O error may be reported as ERROR_INVALID_FUNCTION by buggy chipset drivers
+ || error == ERROR_SEM_TIMEOUT); // I/O operation timeout may be reported as ERROR_SEM_TIMEOUT
+}
+
+
+BOOL IsDiskWriteError (DWORD error)
+{
+ return (error == ERROR_IO_DEVICE
+ || error == ERROR_BAD_CLUSTERS
+ || error == ERROR_SECTOR_NOT_FOUND
+ || error == ERROR_WRITE_FAULT
+ || error == ERROR_INVALID_FUNCTION // I/O error may be reported as ERROR_INVALID_FUNCTION by buggy chipset drivers
+ || error == ERROR_SEM_TIMEOUT); // I/O operation timeout may be reported as ERROR_SEM_TIMEOUT
+}
+
+
+BOOL IsDiskError (DWORD error)
+{
+ return IsDiskReadError (error) || IsDiskWriteError (error);
+}
+
+
+DWORD handleWin32Error (HWND hwndDlg)
+{
+ PWSTR lpMsgBuf;
+ DWORD dwError = GetLastError ();
+
+ if (Silent || dwError == 0 || dwError == ERROR_INVALID_WINDOW_HANDLE)
+ return dwError;
+
+ // Access denied
+ if (dwError == ERROR_ACCESS_DENIED && !IsAdmin ())
+ {
+ Error ("ERR_ACCESS_DENIED");
+ SetLastError (dwError); // Preserve the original error code
+ return dwError;
+ }
+
+ FormatMessageW (
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dwError,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ (PWSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ MessageBoxW (hwndDlg, lpMsgBuf, lpszTitle, ICON_HAND);
+ LocalFree (lpMsgBuf);
+
+ // User-friendly hardware error explanation
+ if (IsDiskError (dwError))
+ Error ("ERR_HARDWARE_ERROR");
+
+ // Device not ready
+ if (dwError == ERROR_NOT_READY)
+ HandleDriveNotReadyError();
+
+ SetLastError (dwError); // Preserve the original error code
+
+ return dwError;
+}
+
+BOOL translateWin32Error (wchar_t *lpszMsgBuf, int nWSizeOfBuf)
+{
+ DWORD dwError = GetLastError ();
+
+ if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError,
+ MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ lpszMsgBuf, nWSizeOfBuf, NULL))
+ {
+ SetLastError (dwError); // Preserve the original error code
+ return TRUE;
+ }
+
+ SetLastError (dwError); // Preserve the original error code
+ return FALSE;
+}
+
+// If the user has a non-default screen DPI, all absolute font sizes must be
+// converted using this function.
+int CompensateDPIFont (int val)
+{
+ if (ScreenDPI == USER_DEFAULT_SCREEN_DPI)
+ return val;
+ else
+ {
+ double tmpVal = (double) val * DPIScaleFactorY * DlgAspectRatio * 0.999;
+
+ if (tmpVal > 0)
+ return (int) floor(tmpVal);
+ else
+ return (int) ceil(tmpVal);
+ }
+}
+
+
+// If the user has a non-default screen DPI, some screen coordinates and sizes must
+// be converted using this function
+int CompensateXDPI (int val)
+{
+ if (ScreenDPI == USER_DEFAULT_SCREEN_DPI)
+ return val;
+ else
+ {
+ double tmpVal = (double) val * DPIScaleFactorX;
+
+ if (tmpVal > 0)
+ return (int) floor(tmpVal);
+ else
+ return (int) ceil(tmpVal);
+ }
+}
+
+
+// If the user has a non-default screen DPI, some screen coordinates and sizes must
+// be converted using this function
+int CompensateYDPI (int val)
+{
+ if (ScreenDPI == USER_DEFAULT_SCREEN_DPI)
+ return val;
+ else
+ {
+ double tmpVal = (double) val * DPIScaleFactorY;
+
+ if (tmpVal > 0)
+ return (int) floor(tmpVal);
+ else
+ return (int) ceil(tmpVal);
+ }
+}
+
+
+int GetTextGfxWidth (HWND hwndDlgItem, const wchar_t *text, HFONT hFont)
+{
+ SIZE sizes;
+ TEXTMETRIC textMetrics;
+ HDC hdc = GetDC (hwndDlgItem);
+
+ SelectObject(hdc, (HGDIOBJ) hFont);
+
+ GetTextExtentPoint32W (hdc, text, wcslen (text), &sizes);
+
+ GetTextMetrics(hdc, &textMetrics); // Necessary for non-TrueType raster fonts (tmOverhang)
+
+ ReleaseDC (hwndDlgItem, hdc);
+
+ return ((int) sizes.cx - (int) textMetrics.tmOverhang);
+}
+
+
+int GetTextGfxHeight (HWND hwndDlgItem, const wchar_t *text, HFONT hFont)
+{
+ SIZE sizes;
+ HDC hdc = GetDC (hwndDlgItem);
+
+ SelectObject(hdc, (HGDIOBJ) hFont);
+
+ GetTextExtentPoint32W (hdc, text, wcslen (text), &sizes);
+
+ ReleaseDC (hwndDlgItem, hdc);
+
+ return ((int) sizes.cy);
+}
+
+
+std::string FitPathInGfxWidth (HWND hwnd, HFONT hFont, LONG width, const std::string &path)
+{
+ string newPath;
+
+ RECT rect;
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = width;
+ rect.bottom = LONG_MAX;
+
+ HDC hdc = GetDC (hwnd);
+ SelectObject (hdc, (HGDIOBJ) hFont);
+
+ char pathBuf[TC_MAX_PATH];
+ strcpy_s (pathBuf, sizeof (pathBuf), path.c_str());
+
+ if (DrawText (hdc, pathBuf, path.size(), &rect, DT_CALCRECT | DT_MODIFYSTRING | DT_PATH_ELLIPSIS | DT_SINGLELINE) != 0)
+ newPath = pathBuf;
+
+ ReleaseDC (hwnd, hdc);
+ return newPath;
+}
+
+
+static LRESULT CALLBACK HyperlinkProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC wp = (WNDPROC) GetWindowLongPtr (hwnd, GWLP_USERDATA);
+
+ switch (message)
+ {
+ case WM_SETCURSOR:
+ if (!bHyperLinkBeingTracked)
+ {
+ TRACKMOUSEEVENT trackMouseEvent;
+
+ trackMouseEvent.cbSize = sizeof(trackMouseEvent);
+ trackMouseEvent.dwFlags = TME_LEAVE;
+ trackMouseEvent.hwndTrack = hwnd;
+
+ bHyperLinkBeingTracked = TrackMouseEvent(&trackMouseEvent);
+
+ HandCursor();
+ }
+ return 0;
+
+ case WM_MOUSELEAVE:
+ bHyperLinkBeingTracked = FALSE;
+ NormalCursor();
+ return 0;
+ }
+
+ return CallWindowProc (wp, hwnd, message, wParam, lParam);
+}
+
+
+BOOL ToHyperlink (HWND hwndDlg, UINT ctrlId)
+{
+ return ToCustHyperlink (hwndDlg, ctrlId, hUserUnderlineFont);
+}
+
+
+BOOL ToCustHyperlink (HWND hwndDlg, UINT ctrlId, HFONT hFont)
+{
+ HWND hwndCtrl = GetDlgItem (hwndDlg, ctrlId);
+
+ SendMessage (hwndCtrl, WM_SETFONT, (WPARAM) hFont, 0);
+
+ SetWindowLongPtr (hwndCtrl, GWLP_USERDATA, (LONG_PTR) GetWindowLongPtr (hwndCtrl, GWLP_WNDPROC));
+ SetWindowLongPtr (hwndCtrl, GWLP_WNDPROC, (LONG_PTR) HyperlinkProc);
+
+ // Resize the field according to its actual size in pixels and move it if centered or right-aligned.
+ // This should be done again if the link text changes.
+ AccommodateTextField (hwndDlg, ctrlId, TRUE, hFont);
+
+ return TRUE;
+}
+
+
+// Resizes a text field according to its actual width and height in pixels (font size is taken into account) and moves
+// it accordingly if the field is centered or right-aligned. Should be used on all hyperlinks upon dialog init
+// after localization (bFirstUpdate should be TRUE) and later whenever a hyperlink text changes (bFirstUpdate
+// must be FALSE).
+void AccommodateTextField (HWND hwndDlg, UINT ctrlId, BOOL bFirstUpdate, HFONT hFont)
+{
+ RECT rec, wrec, trec;
+ HWND hwndCtrl = GetDlgItem (hwndDlg, ctrlId);
+ int width, origWidth, height, origHeight;
+ int horizSubOffset, vertSubOffset, vertOffset, alignPosDiff = 0;
+ wchar_t text [MAX_URL_LENGTH];
+ WINDOWINFO windowInfo;
+ BOOL bBorderlessWindow = !(GetWindowLongPtr (hwndDlg, GWL_STYLE) & (WS_BORDER | WS_DLGFRAME));
+
+ // Resize the field according to its length and font size and move if centered or right-aligned
+
+ GetWindowTextW (hwndCtrl, text, sizeof (text) / sizeof (wchar_t));
+
+ width = GetTextGfxWidth (hwndCtrl, text, hFont);
+ height = GetTextGfxHeight (hwndCtrl, text, hFont);
+
+ GetClientRect (hwndCtrl, &rec);
+ origWidth = rec.right;
+ origHeight = rec.bottom;
+
+ if (width >= 0
+ && (!bFirstUpdate || origWidth > width)) // The original width of the field is the maximum allowed size
+ {
+ horizSubOffset = origWidth - width;
+ vertSubOffset = origHeight - height;
+
+ // Window coords
+ GetWindowRect(hwndDlg, &wrec);
+ GetClientRect(hwndDlg, &trec);
+
+ // Vertical "title bar" offset
+ vertOffset = wrec.bottom - wrec.top - trec.bottom - (bBorderlessWindow ? 0 : GetSystemMetrics(SM_CYFIXEDFRAME));
+
+ // Text field coords
+ GetWindowRect(hwndCtrl, &rec);
+
+ // Alignment offset
+ windowInfo.cbSize = sizeof(windowInfo);
+ GetWindowInfo (hwndCtrl, &windowInfo);
+
+ if (windowInfo.dwStyle & SS_CENTER)
+ alignPosDiff = horizSubOffset / 2;
+ else if (windowInfo.dwStyle & SS_RIGHT)
+ alignPosDiff = horizSubOffset;
+
+ // Resize/move
+ if (alignPosDiff > 0)
+ {
+ // Resize and move the text field
+ MoveWindow (hwndCtrl,
+ rec.left - wrec.left - (bBorderlessWindow ? 0 : GetSystemMetrics(SM_CXFIXEDFRAME)) + alignPosDiff,
+ rec.top - wrec.top - vertOffset,
+ origWidth - horizSubOffset,
+ origHeight - vertSubOffset,
+ TRUE);
+ }
+ else
+ {
+ // Resize the text field
+ SetWindowPos (hwndCtrl, 0, 0, 0,
+ origWidth - horizSubOffset,
+ origHeight - vertSubOffset,
+ SWP_NOMOVE | SWP_NOZORDER);
+ }
+
+ SetWindowPos (hwndCtrl, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+
+ InvalidateRect (hwndCtrl, NULL, TRUE);
+ }
+}
+
+
+// Protects an input field from having its content updated by a Paste action (call ToBootPwdField() to use this).
+static LRESULT CALLBACK BootPwdFieldProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ WNDPROC wp = (WNDPROC) GetWindowLongPtr (hwnd, GWLP_USERDATA);
+
+ switch (message)
+ {
+ case WM_PASTE:
+ return 1;
+ }
+
+ return CallWindowProc (wp, hwnd, message, wParam, lParam);
+}
+
+
+// Protects an input field from having its content updated by a Paste action. Used for pre-boot password
+// input fields (only the US keyboard layout is supported in pre-boot environment so we must prevent the
+// user from pasting a password typed using a non-US keyboard layout).
+void ToBootPwdField (HWND hwndDlg, UINT ctrlId)
+{
+ HWND hwndCtrl = GetDlgItem (hwndDlg, ctrlId);
+
+ SetWindowLongPtr (hwndCtrl, GWLP_USERDATA, (LONG_PTR) GetWindowLongPtr (hwndCtrl, GWLP_WNDPROC));
+ SetWindowLongPtr (hwndCtrl, GWLP_WNDPROC, (LONG_PTR) BootPwdFieldProc);
+}
+
+
+
+// This function currently serves the following purposes:
+// - Determines scaling factors for current screen DPI and GUI aspect ratio.
+// - Determines how Windows skews the GUI aspect ratio (which happens when the user has a non-default DPI).
+// The determined values must be used when performing some GUI operations and calculations.
+BOOL CALLBACK AuxiliaryDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ HDC hDC = GetDC (hwndDlg);
+
+ ScreenDPI = GetDeviceCaps (hDC, LOGPIXELSY);
+ ReleaseDC (hwndDlg, hDC);
+
+ DPIScaleFactorX = 1;
+ DPIScaleFactorY = 1;
+ DlgAspectRatio = 1;
+
+ if (ScreenDPI != USER_DEFAULT_SCREEN_DPI)
+ {
+ // Windows skews the GUI aspect ratio if the user has a non-default DPI. Hence, working with
+ // actual screen DPI is redundant and leads to incorrect results. What really matters here is
+ // how Windows actually renders our GUI. This is determined by comparing the expected and current
+ // sizes of a hidden calibration text field.
+
+ RECT trec;
+
+ trec.right = 0;
+ trec.bottom = 0;
+
+ GetClientRect (GetDlgItem (hwndDlg, IDC_ASPECT_RATIO_CALIBRATION_BOX), &trec);
+
+ if (trec.right != 0 && trec.bottom != 0)
+ {
+ // The size of the 282x282 IDC_ASPECT_RATIO_CALIBRATION_BOX rendered at the default DPI (96) is 423x458
+ DPIScaleFactorX = (double) trec.right / 423;
+ DPIScaleFactorY = (double) trec.bottom / 458;
+ DlgAspectRatio = DPIScaleFactorX / DPIScaleFactorY;
+ }
+ }
+
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ case WM_CLOSE:
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/* Except in response to the WM_INITDIALOG message, the dialog box procedure
+ should return nonzero if it processes the message, and zero if it does
+ not. - see DialogProc */
+BOOL CALLBACK AboutDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD lw = LOWORD (wParam);
+ static HBITMAP hbmTextualLogoBitmapRescaled = NULL;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ char szTmp[100];
+ RECT rec;
+
+ LocalizeDialog (hwndDlg, "IDD_ABOUT_DLG");
+
+ // Hyperlink
+ SetWindowText (GetDlgItem (hwndDlg, IDC_HOMEPAGE), "www.truecrypt.org");
+ ToHyperlink (hwndDlg, IDC_HOMEPAGE);
+
+ // Logo area background (must not keep aspect ratio; must retain Windows-imposed distortion)
+ GetClientRect (GetDlgItem (hwndDlg, IDC_ABOUT_LOGO_AREA), &rec);
+ SetWindowPos (GetDlgItem (hwndDlg, IDC_ABOUT_BKG), HWND_TOP, 0, 0, rec.right, rec.bottom, SWP_NOMOVE);
+
+ // Resize the logo bitmap if the user has a non-default DPI
+ if (ScreenDPI != USER_DEFAULT_SCREEN_DPI)
+ {
+ // Logo (must recreate and keep the original aspect ratio as Windows distorts it)
+ hbmTextualLogoBitmapRescaled = RenderBitmap (MAKEINTRESOURCE (IDB_TEXTUAL_LOGO_288DPI),
+ GetDlgItem (hwndDlg, IDC_TEXTUAL_LOGO_IMG),
+ 0, 0, 0, 0, FALSE, TRUE);
+
+ SetWindowPos (GetDlgItem (hwndDlg, IDC_ABOUT_BKG), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ }
+
+ // Version
+ SendMessage (GetDlgItem (hwndDlg, IDT_ABOUT_VERSION), WM_SETFONT, (WPARAM) hUserBoldFont, 0);
+ sprintf (szTmp, "TrueCrypt %s", VERSION_STRING);
+#if (defined(_DEBUG) || defined(DEBUG))
+ strcat (szTmp, " (debug)");
+#endif
+ SetDlgItemText (hwndDlg, IDT_ABOUT_VERSION, szTmp);
+ SetDlgItemText (hwndDlg, IDT_ABOUT_RELEASE, TC_STR_RELEASED_BY);
+
+ // Credits
+ SendMessage (GetDlgItem (hwndDlg, IDC_ABOUT_CREDITS), WM_SETFONT, (WPARAM) hUserFont, (LPARAM) 0);
+ SendMessage (hwndDlg, WM_APP, 0, 0);
+ return 1;
+ }
+
+ case WM_APP:
+ SetWindowText (GetDlgItem (hwndDlg, IDC_ABOUT_CREDITS),
+ "Portions of this software are based in part on the works of the following people: "
+ "Paul Le Roux, "
+ "Bruce Schneier, John Kelsey, Doug Whiting, David Wagner, Chris Hall, Niels Ferguson, "
+ "Lars Knudsen, Ross Anderson, Eli Biham, "
+ "Joan Daemen, Vincent Rijmen, "
+ "Phillip Rogaway, "
+ "Hans Dobbertin, Antoon Bosselaers, Bart Preneel, "
+ "Paulo Barreto, Brian Gladman, Wei Dai, Peter Gutmann, and many others.\r\n\r\n"
+
+ "Portions of this software:\r\n"
+ "Copyright \xA9 2003-2012 TrueCrypt Developers Association. All Rights Reserved.\r\n"
+ "Copyright \xA9 1998-2000 Paul Le Roux. All Rights Reserved.\r\n"
+ "Copyright \xA9 1998-2008 Brian Gladman. All Rights Reserved.\r\n"
+ "Copyright \xA9 2002-2004 Mark Adler. All Rights Reserved.\r\n\r\n"
+
+ "This software as a whole:\r\n"
+ "Copyright \xA9 2012 TrueCrypt Developers Association. All rights reserved.\r\n\r\n"
+
+ "A TrueCrypt Foundation Release");
+
+ return 1;
+
+ case WM_COMMAND:
+ if (lw == IDOK || lw == IDCANCEL)
+ {
+ PostMessage (hwndDlg, WM_CLOSE, 0, 0);
+ return 1;
+ }
+
+ if (lw == IDC_HOMEPAGE)
+ {
+ Applink ("main", TRUE, "");
+ return 1;
+ }
+
+ // Disallow modification of credits
+ if (HIWORD (wParam) == EN_UPDATE)
+ {
+ SendMessage (hwndDlg, WM_APP, 0, 0);
+ return 1;
+ }
+
+ return 0;
+
+ case WM_CLOSE:
+ /* Delete buffered bitmaps (if any) */
+ if (hbmTextualLogoBitmapRescaled != NULL)
+ {
+ DeleteObject ((HGDIOBJ) hbmTextualLogoBitmapRescaled);
+ hbmTextualLogoBitmapRescaled = NULL;
+ }
+
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static HWND StaticModelessWaitDlgHandle = NULL;
+
+// Call DisplayStaticModelessWaitDlg() to open this dialog and CloseStaticModelessWaitDlg() to close it.
+static BOOL CALLBACK StaticModelessWaitDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD lw = LOWORD (wParam);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ LocalizeDialog (hwndDlg, NULL);
+
+ return 0;
+ }
+
+ case WM_COMMAND:
+
+ if (lw == IDOK || lw == IDCANCEL)
+ return 1;
+
+ return 0;
+
+
+ case WM_CLOSE:
+ StaticModelessWaitDlgHandle = NULL;
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+// Opens a dialog window saying "Please wait..." which is not modal and does not need any GUI refresh after initialization.
+void DisplayStaticModelessWaitDlg (HWND parent)
+{
+ if (StaticModelessWaitDlgHandle != NULL)
+ return; // Already shown
+
+ StaticModelessWaitDlgHandle = CreateDialogParamW (hInst, MAKEINTRESOURCEW (IDD_STATIC_MODELESS_WAIT_DLG), parent, (DLGPROC) StaticModelessWaitDlgProc, (LPARAM) 0);
+
+ ShowWindow (StaticModelessWaitDlgHandle, SW_SHOWNORMAL);
+
+ // Allow synchronous use with the GUI being instantly and fully rendered
+ ProcessPaintMessages (StaticModelessWaitDlgHandle, 500);
+}
+
+
+void CloseStaticModelessWaitDlg (void)
+{
+ if (StaticModelessWaitDlgHandle == NULL)
+ return; // Not shown
+
+ DestroyWindow (StaticModelessWaitDlgHandle);
+}
+
+
+BOOL IsButtonChecked (HWND hButton)
+{
+ if (SendMessage (hButton, BM_GETCHECK, 0, 0) == BST_CHECKED)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+void CheckButton (HWND hButton)
+{
+ SendMessage (hButton, BM_SETCHECK, BST_CHECKED, 0);
+}
+
+
+void LeftPadString (char *szTmp, int len, int targetLen, char filler)
+{
+ int i;
+
+ if (targetLen <= len)
+ return;
+
+ for (i = targetLen-1; i >= (targetLen-len); i--)
+ szTmp [i] = szTmp [i-(targetLen-len)];
+
+ memset (szTmp, filler, targetLen-len);
+ szTmp [targetLen] = 0;
+}
+
+
+/*****************************************************************************
+ ToSBCS: converts a unicode string to Single Byte Character String (SBCS).
+ ***************************************************************************/
+
+void ToSBCS (LPWSTR lpszText)
+{
+ int j = wcslen (lpszText);
+ if (j == 0)
+ {
+ strcpy ((char *) lpszText, "");
+ return;
+ }
+ else
+ {
+ char *lpszNewText = (char *) err_malloc (j + 1);
+ j = WideCharToMultiByte (CP_ACP, 0L, lpszText, -1, lpszNewText, j + 1, NULL, NULL);
+ if (j > 0)
+ strcpy ((char *) lpszText, lpszNewText);
+ else
+ strcpy ((char *) lpszText, "");
+ free (lpszNewText);
+ }
+}
+
+/*****************************************************************************
+ ToUNICODE: converts a SBCS string to a UNICODE string.
+ ***************************************************************************/
+
+void ToUNICODE (char *lpszText)
+{
+ int j = strlen (lpszText);
+ if (j == 0)
+ {
+ wcscpy ((LPWSTR) lpszText, (LPWSTR) WIDE (""));
+ return;
+ }
+ else
+ {
+ LPWSTR lpszNewText = (LPWSTR) err_malloc ((j + 1) * 2);
+ j = MultiByteToWideChar (CP_ACP, 0L, lpszText, -1, lpszNewText, j + 1);
+ if (j > 0)
+ wcscpy ((LPWSTR) lpszText, lpszNewText);
+ else
+ wcscpy ((LPWSTR) lpszText, (LPWSTR) WIDE (""));
+ free (lpszNewText);
+ }
+}
+
+/* InitDialog - initialize the applications main dialog, this function should
+ be called only once in the dialogs WM_INITDIALOG message handler */
+void InitDialog (HWND hwndDlg)
+{
+ NONCLIENTMETRICSW metric;
+ static BOOL aboutMenuAppended = FALSE;
+
+ int nHeight;
+ LOGFONTW lf;
+ HMENU hMenu;
+ Font *font;
+
+ /* Fonts */
+
+ memset (&lf, 0, sizeof(lf));
+
+ // Normal
+ font = GetFont ("font_normal");
+
+ metric.cbSize = sizeof (metric);
+ SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, sizeof(metric), &metric, 0);
+
+ WindowTitleBarFont = CreateFontIndirectW (&metric.lfCaptionFont);
+
+ metric.lfMessageFont.lfHeight = CompensateDPIFont (!font ? -11 : -font->Size);
+ metric.lfMessageFont.lfWidth = 0;
+
+ if (font && wcscmp (font->FaceName, L"default") != 0)
+ {
+ wcsncpy ((WCHAR *)metric.lfMessageFont.lfFaceName, font->FaceName, sizeof (metric.lfMessageFont.lfFaceName)/2);
+ }
+ else if (IsOSAtLeast (WIN_VISTA))
+ {
+ // Vista's new default font (size and spacing) breaks compatibility with Windows 2k/XP applications.
+ // Force use of Tahoma (as Microsoft does in many dialogs) until a native Vista look is implemented.
+ wcsncpy ((WCHAR *)metric.lfMessageFont.lfFaceName, L"Tahoma", sizeof (metric.lfMessageFont.lfFaceName)/2);
+ }
+
+ hUserFont = CreateFontIndirectW (&metric.lfMessageFont);
+
+ metric.lfMessageFont.lfUnderline = TRUE;
+ hUserUnderlineFont = CreateFontIndirectW (&metric.lfMessageFont);
+
+ metric.lfMessageFont.lfUnderline = FALSE;
+ metric.lfMessageFont.lfWeight = FW_BOLD;
+ hUserBoldFont = CreateFontIndirectW (&metric.lfMessageFont);
+
+ metric.lfMessageFont.lfUnderline = TRUE;
+ metric.lfMessageFont.lfWeight = FW_BOLD;
+ hUserUnderlineBoldFont = CreateFontIndirectW (&metric.lfMessageFont);
+
+ // Fixed-size (hexadecimal digits)
+ nHeight = CompensateDPIFont (-12);
+ lf.lfHeight = nHeight;
+ lf.lfWidth = 0;
+ lf.lfEscapement = 0;
+ lf.lfOrientation = 0;
+ lf.lfWeight = FW_NORMAL;
+ lf.lfItalic = FALSE;
+ lf.lfUnderline = FALSE;
+ lf.lfStrikeOut = FALSE;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = PROOF_QUALITY;
+ lf.lfPitchAndFamily = FF_DONTCARE;
+ wcscpy (lf.lfFaceName, L"Courier New");
+ hFixedDigitFont = CreateFontIndirectW (&lf);
+ if (hFixedDigitFont == NULL)
+ {
+ handleWin32Error (hwndDlg);
+ AbortProcess ("NOFONT");
+ }
+
+ // Bold
+ font = GetFont ("font_bold");
+
+ nHeight = CompensateDPIFont (!font ? -13 : -font->Size);
+ lf.lfHeight = nHeight;
+ lf.lfWeight = FW_BLACK;
+ wcsncpy (lf.lfFaceName, !font ? L"Arial" : font->FaceName, sizeof (lf.lfFaceName)/2);
+ hBoldFont = CreateFontIndirectW (&lf);
+ if (hBoldFont == NULL)
+ {
+ handleWin32Error (hwndDlg);
+ AbortProcess ("NOFONT");
+ }
+
+ // Title
+ font = GetFont ("font_title");
+
+ nHeight = CompensateDPIFont (!font ? -21 : -font->Size);
+ lf.lfHeight = nHeight;
+ lf.lfWeight = FW_REGULAR;
+ wcsncpy (lf.lfFaceName, !font ? L"Times New Roman" : font->FaceName, sizeof (lf.lfFaceName)/2);
+ hTitleFont = CreateFontIndirectW (&lf);
+ if (hTitleFont == NULL)
+ {
+ handleWin32Error (hwndDlg);
+ AbortProcess ("NOFONT");
+ }
+
+ // Fixed-size
+ font = GetFont ("font_fixed");
+
+ nHeight = CompensateDPIFont (!font ? -12 : -font->Size);
+ lf.lfHeight = nHeight;
+ lf.lfWidth = 0;
+ lf.lfEscapement = 0;
+ lf.lfOrientation = 0;
+ lf.lfWeight = FW_NORMAL;
+ lf.lfItalic = FALSE;
+ lf.lfUnderline = FALSE;
+ lf.lfStrikeOut = FALSE;
+ lf.lfCharSet = DEFAULT_CHARSET;
+ lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = PROOF_QUALITY;
+ lf.lfPitchAndFamily = FF_DONTCARE;
+ wcsncpy (lf.lfFaceName, !font ? L"Lucida Console" : font->FaceName, sizeof (lf.lfFaceName)/2);
+ hFixedFont = CreateFontIndirectW (&lf);
+ if (hFixedFont == NULL)
+ {
+ handleWin32Error (hwndDlg);
+ AbortProcess ("NOFONT");
+ }
+
+ if (!aboutMenuAppended)
+ {
+ hMenu = GetSystemMenu (hwndDlg, FALSE);
+ AppendMenu (hMenu, MF_SEPARATOR, 0, NULL);
+ AppendMenuW (hMenu, MF_ENABLED | MF_STRING, IDC_ABOUT, GetString ("ABOUTBOX"));
+
+ aboutMenuAppended = TRUE;
+ }
+}
+
+
+// The parameter maxMessagesToProcess prevents endless processing of paint messages
+void ProcessPaintMessages (HWND hwnd, int maxMessagesToProcess)
+{
+ MSG paintMsg;
+ int msgCounter = maxMessagesToProcess;
+
+ while (PeekMessage (&paintMsg, hwnd, 0, 0, PM_REMOVE | PM_QS_PAINT) != 0 && msgCounter-- > 0)
+ {
+ DispatchMessage (&paintMsg);
+ }
+}
+
+
+HDC CreateMemBitmap (HINSTANCE hInstance, HWND hwnd, char *resource)
+{
+ HBITMAP picture = LoadBitmap (hInstance, resource);
+ HDC viewDC = GetDC (hwnd), dcMem;
+
+ dcMem = CreateCompatibleDC (viewDC);
+
+ SetMapMode (dcMem, MM_TEXT);
+
+ SelectObject (dcMem, picture);
+
+ DeleteObject (picture);
+
+ ReleaseDC (hwnd, viewDC);
+
+ return dcMem;
+}
+
+
+/* Renders the specified bitmap at the specified location and stretches it to fit (anti-aliasing is applied).
+If bDirectRender is FALSE and both nWidth and nHeight are zero, the width and height of hwndDest are
+retrieved and adjusted according to screen DPI (the width and height of the resultant image are adjusted the
+same way); furthermore, if bKeepAspectRatio is TRUE, the smaller DPI factor of the two (i.e. horiz. or vert.)
+is used both for horiz. and vert. scaling (note that the overall GUI aspect ratio changes irregularly in
+both directions depending on the DPI). If bDirectRender is TRUE, bKeepAspectRatio is ignored.
+This function returns a handle to the scaled bitmap. When the bitmap is no longer needed, it should be
+deleted by calling DeleteObject() with the handle passed as the parameter.
+Known Windows issues:
+- For some reason, anti-aliasing is not applied if the source bitmap contains less than 16K pixels.
+- Windows 2000 may produce slightly inaccurate colors even when source, buffer, and target are 24-bit true color. */
+HBITMAP RenderBitmap (char *resource, HWND hwndDest, int x, int y, int nWidth, int nHeight, BOOL bDirectRender, BOOL bKeepAspectRatio)
+{
+ LRESULT lResult = 0;
+
+ HDC hdcSrc = CreateMemBitmap (hInst, hwndDest, resource);
+
+ HGDIOBJ picture = GetCurrentObject (hdcSrc, OBJ_BITMAP);
+
+ HBITMAP hbmpRescaled;
+ BITMAP bitmap;
+
+ HDC hdcRescaled;
+
+ if (!bDirectRender && nWidth == 0 && nHeight == 0)
+ {
+ RECT rec;
+
+ GetClientRect (hwndDest, &rec);
+
+ if (bKeepAspectRatio)
+ {
+ if (DlgAspectRatio > 1)
+ {
+ // Do not fix this, it's correct. We use the Y scale factor intentionally for both
+ // directions to maintain aspect ratio (see above for more info).
+ nWidth = CompensateYDPI (rec.right);
+ nHeight = CompensateYDPI (rec.bottom);
+ }
+ else
+ {
+ // Do not fix this, it's correct. We use the X scale factor intentionally for both
+ // directions to maintain aspect ratio (see above for more info).
+ nWidth = CompensateXDPI (rec.right);
+ nHeight = CompensateXDPI (rec.bottom);
+ }
+ }
+ else
+ {
+ nWidth = CompensateXDPI (rec.right);
+ nHeight = CompensateYDPI (rec.bottom);
+ }
+ }
+
+ GetObject (picture, sizeof (BITMAP), &bitmap);
+
+ hdcRescaled = CreateCompatibleDC (hdcSrc);
+
+ hbmpRescaled = CreateCompatibleBitmap (hdcSrc, nWidth, nHeight);
+
+ SelectObject (hdcRescaled, hbmpRescaled);
+
+ /* Anti-aliasing mode (HALFTONE is the only anti-aliasing algorithm natively supported by Windows 2000.
+ TODO: GDI+ offers higher quality -- InterpolationModeHighQualityBicubic) */
+ SetStretchBltMode (hdcRescaled, HALFTONE);
+
+ StretchBlt (hdcRescaled,
+ 0,
+ 0,
+ nWidth,
+ nHeight,
+ hdcSrc,
+ 0,
+ 0,
+ bitmap.bmWidth,
+ bitmap.bmHeight,
+ SRCCOPY);
+
+ DeleteDC (hdcSrc);
+
+ if (bDirectRender)
+ {
+ HDC hdcDest = GetDC (hwndDest);
+
+ BitBlt (hdcDest, x, y, nWidth, nHeight, hdcRescaled, 0, 0, SRCCOPY);
+ DeleteDC (hdcDest);
+ }
+ else
+ {
+ lResult = SendMessage (hwndDest, (UINT) STM_SETIMAGE, (WPARAM) IMAGE_BITMAP, (LPARAM) (HANDLE) hbmpRescaled);
+ }
+
+ if ((HGDIOBJ) lResult != NULL && (HGDIOBJ) lResult != (HGDIOBJ) hbmpRescaled)
+ DeleteObject ((HGDIOBJ) lResult);
+
+ DeleteDC (hdcRescaled);
+
+ return hbmpRescaled;
+}
+
+
+LRESULT CALLBACK
+RedTick (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg == WM_CREATE)
+ {
+ }
+ else if (uMsg == WM_DESTROY)
+ {
+ }
+ else if (uMsg == WM_TIMER)
+ {
+ }
+ else if (uMsg == WM_PAINT)
+ {
+ PAINTSTRUCT tmp;
+ HPEN hPen;
+ HDC hDC;
+ BOOL bEndPaint;
+ RECT Rect;
+
+ if (GetUpdateRect (hwnd, NULL, FALSE))
+ {
+ hDC = BeginPaint (hwnd, &tmp);
+ bEndPaint = TRUE;
+ if (hDC == NULL)
+ return DefWindowProc (hwnd, uMsg, wParam, lParam);
+ }
+ else
+ {
+ hDC = GetDC (hwnd);
+ bEndPaint = FALSE;
+ }
+
+ GetClientRect (hwnd, &Rect);
+
+ hPen = CreatePen (PS_SOLID, 2, RGB (0, 255, 0));
+ if (hPen != NULL)
+ {
+ HGDIOBJ hObj = SelectObject (hDC, hPen);
+ WORD bx = LOWORD (GetDialogBaseUnits ());
+ WORD by = HIWORD (GetDialogBaseUnits ());
+
+ MoveToEx (hDC, (Rect.right - Rect.left) / 2, Rect.bottom, NULL);
+ LineTo (hDC, Rect.right, Rect.top);
+ MoveToEx (hDC, (Rect.right - Rect.left) / 2, Rect.bottom, NULL);
+
+ LineTo (hDC, (3 * bx) / 4, (2 * by) / 8);
+
+ SelectObject (hDC, hObj);
+ DeleteObject (hPen);
+ }
+
+ if (bEndPaint)
+ EndPaint (hwnd, &tmp);
+ else
+ ReleaseDC (hwnd, hDC);
+
+ return TRUE;
+ }
+
+ return DefWindowProc (hwnd, uMsg, wParam, lParam);
+}
+
+BOOL
+RegisterRedTick (HINSTANCE hInstance)
+{
+ WNDCLASS wc;
+ ULONG rc;
+
+ memset(&wc, 0 , sizeof wc);
+
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 4;
+ wc.hInstance = hInstance;
+ wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
+ wc.hCursor = NULL;
+ wc.hbrBackground = (HBRUSH) GetStockObject (LTGRAY_BRUSH);
+ wc.lpszClassName = "REDTICK";
+ wc.lpfnWndProc = &RedTick;
+
+ rc = (ULONG) RegisterClass (&wc);
+
+ return rc == 0 ? FALSE : TRUE;
+}
+
+BOOL
+UnregisterRedTick (HINSTANCE hInstance)
+{
+ return UnregisterClass ("REDTICK", hInstance);
+}
+
+LRESULT CALLBACK
+SplashDlgProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return DefDlgProc (hwnd, uMsg, wParam, lParam);
+}
+
+void
+WaitCursor ()
+{
+ static HCURSOR hcWait;
+ if (hcWait == NULL)
+ hcWait = LoadCursor (NULL, IDC_WAIT);
+ SetCursor (hcWait);
+ hCursor = hcWait;
+}
+
+void
+NormalCursor ()
+{
+ static HCURSOR hcArrow;
+ if (hcArrow == NULL)
+ hcArrow = LoadCursor (NULL, IDC_ARROW);
+ SetCursor (hcArrow);
+ hCursor = NULL;
+}
+
+void
+ArrowWaitCursor ()
+{
+ static HCURSOR hcArrowWait;
+ if (hcArrowWait == NULL)
+ hcArrowWait = LoadCursor (NULL, IDC_APPSTARTING);
+ SetCursor (hcArrowWait);
+ hCursor = hcArrowWait;
+}
+
+void HandCursor ()
+{
+ static HCURSOR hcHand;
+ if (hcHand == NULL)
+ hcHand = LoadCursor (NULL, IDC_HAND);
+ SetCursor (hcHand);
+ hCursor = hcHand;
+}
+
+void
+AddComboPair (HWND hComboBox, const char *lpszItem, int value)
+{
+ LPARAM nIndex;
+
+ nIndex = SendMessage (hComboBox, CB_ADDSTRING, 0, (LPARAM) lpszItem);
+ nIndex = SendMessage (hComboBox, CB_SETITEMDATA, nIndex, (LPARAM) value);
+}
+
+void
+AddComboPairW (HWND hComboBox, const wchar_t *lpszItem, int value)
+{
+ LPARAM nIndex;
+
+ nIndex = SendMessageW (hComboBox, CB_ADDSTRING, 0, (LPARAM) lpszItem);
+ nIndex = SendMessage (hComboBox, CB_SETITEMDATA, nIndex, (LPARAM) value);
+}
+
+void
+SelectAlgo (HWND hComboBox, int *algo_id)
+{
+ LPARAM nCount = SendMessage (hComboBox, CB_GETCOUNT, 0, 0);
+ LPARAM x, i;
+
+ for (i = 0; i < nCount; i++)
+ {
+ x = SendMessage (hComboBox, CB_GETITEMDATA, i, 0);
+ if (x == (LPARAM) *algo_id)
+ {
+ SendMessage (hComboBox, CB_SETCURSEL, i, 0);
+ return;
+ }
+ }
+
+ /* Something went wrong ; couldn't find the requested algo id so we drop
+ back to a default */
+
+ *algo_id = SendMessage (hComboBox, CB_GETITEMDATA, 0, 0);
+
+ SendMessage (hComboBox, CB_SETCURSEL, 0, 0);
+
+}
+
+void PopulateWipeModeCombo (HWND hComboBox, BOOL bNA, BOOL bInPlaceEncryption)
+{
+ if (bNA)
+ {
+ AddComboPairW (hComboBox, GetString ("NOT_APPLICABLE_OR_NOT_AVAILABLE"), TC_WIPE_NONE);
+ }
+ else
+ {
+ if (bInPlaceEncryption)
+ AddComboPairW (hComboBox, GetString ("WIPE_MODE_NONE"), TC_WIPE_NONE);
+ else
+ AddComboPairW (hComboBox, GetString ("WIPE_MODE_1_RAND"), TC_WIPE_1_RAND);
+
+ AddComboPairW (hComboBox, GetString ("WIPE_MODE_3_DOD_5220"), TC_WIPE_3_DOD_5220);
+ AddComboPairW (hComboBox, GetString ("WIPE_MODE_7_DOD_5220"), TC_WIPE_7_DOD_5220);
+ AddComboPairW (hComboBox, GetString ("WIPE_MODE_35_GUTMANN"), TC_WIPE_35_GUTMANN);
+ }
+}
+
+wchar_t *GetWipeModeName (WipeAlgorithmId modeId)
+{
+ switch (modeId)
+ {
+ case TC_WIPE_NONE:
+ return GetString ("WIPE_MODE_NONE");
+
+ case TC_WIPE_1_RAND:
+ return GetString ("WIPE_MODE_1_RAND");
+
+ case TC_WIPE_3_DOD_5220:
+ return GetString ("WIPE_MODE_3_DOD_5220");
+
+ case TC_WIPE_7_DOD_5220:
+ return GetString ("WIPE_MODE_7_DOD_5220");
+
+ case TC_WIPE_35_GUTMANN:
+ return GetString ("WIPE_MODE_35_GUTMANN");
+
+ default:
+ return GetString ("NOT_APPLICABLE_OR_NOT_AVAILABLE");
+ }
+}
+
+wchar_t *GetPathType (const char *path, BOOL bUpperCase, BOOL *bIsPartition)
+{
+ if (strstr (path, "Partition")
+ && strstr (path, "Partition0") == NULL)
+ {
+ *bIsPartition = TRUE;
+ return GetString (bUpperCase ? "PARTITION_UPPER_CASE" : "PARTITION_LOWER_CASE");
+ }
+ else if (strstr (path, "HarddiskVolume"))
+ {
+ *bIsPartition = TRUE;
+ return GetString (bUpperCase ? "VOLUME_UPPER_CASE" : "VOLUME_LOWER_CASE");
+ }
+
+ *bIsPartition = FALSE;
+ return GetString (bUpperCase ? "DEVICE_UPPER_CASE" : "DEVICE_LOWER_CASE");
+}
+
+LRESULT CALLBACK CustomDlgProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg == WM_SETCURSOR && hCursor != NULL)
+ {
+ SetCursor (hCursor);
+ return TRUE;
+ }
+
+ return DefDlgProc (hwnd, uMsg, wParam, lParam);
+}
+
+
+static BOOL IsReturnAddress (DWORD64 address)
+{
+ static size_t codeEnd = 0;
+ byte *sp = (byte *) address;
+
+ if (codeEnd == 0)
+ {
+ MEMORY_BASIC_INFORMATION mi;
+ if (VirtualQuery ((LPCVOID) 0x401000, &mi, sizeof (mi)) >= sizeof (mi))
+ codeEnd = (size_t) mi.BaseAddress + mi.RegionSize;
+ }
+
+ if (address < 0x401000 + 8 || address > codeEnd)
+ return FALSE;
+
+ return sp[-5] == 0xe8 // call ADDR
+ || (sp[-6] == 0xff && sp[-5] == 0x15) // call [ADDR]
+ || (sp[-2] == 0xff && (sp[-1] & 0xf0) == 0xd0); // call REG
+}
+
+
+typedef struct
+{
+ EXCEPTION_POINTERS *ExceptionPointers;
+ HANDLE ExceptionThread;
+
+} ExceptionHandlerThreadArgs;
+
+
+void ExceptionHandlerThread (void *threadArg)
+{
+ ExceptionHandlerThreadArgs *args = (ExceptionHandlerThreadArgs *) threadArg;
+
+ EXCEPTION_POINTERS *ep = args->ExceptionPointers;
+ DWORD addr;
+ DWORD exCode = ep->ExceptionRecord->ExceptionCode;
+ SYSTEM_INFO si;
+ wchar_t msg[8192];
+ char modPath[MAX_PATH];
+ int crc = 0;
+ char url[MAX_URL_LENGTH];
+ char lpack[128];
+ stringstream callStack;
+ addr = (DWORD) ep->ExceptionRecord->ExceptionAddress;
+ PDWORD sp = (PDWORD) ep->ContextRecord->Esp;
+ int frameNumber = 0;
+
+ switch (exCode)
+ {
+ case STATUS_IN_PAGE_ERROR:
+ case 0xeedfade:
+ // Exception not caused by TrueCrypt
+ MessageBoxW (0, GetString ("EXCEPTION_REPORT_EXT"),
+ GetString ("EXCEPTION_REPORT_TITLE"),
+ MB_ICONERROR | MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
+ return;
+ }
+
+ // Call stack
+ HMODULE dbgDll = LoadLibrary ("dbghelp.dll");
+ if (dbgDll)
+ {
+ typedef DWORD (__stdcall *SymGetOptions_t) ();
+ typedef DWORD (__stdcall *SymSetOptions_t) (DWORD SymOptions);
+ typedef BOOL (__stdcall *SymInitialize_t) (HANDLE hProcess, PCSTR UserSearchPath, BOOL fInvadeProcess);
+ typedef BOOL (__stdcall *StackWalk64_t) (DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
+ typedef BOOL (__stdcall * SymFromAddr_t) (HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol);
+
+ SymGetOptions_t DbgHelpSymGetOptions = (SymGetOptions_t) GetProcAddress (dbgDll, "SymGetOptions");
+ SymSetOptions_t DbgHelpSymSetOptions = (SymSetOptions_t) GetProcAddress (dbgDll, "SymSetOptions");
+ SymInitialize_t DbgHelpSymInitialize = (SymInitialize_t) GetProcAddress (dbgDll, "SymInitialize");
+ PFUNCTION_TABLE_ACCESS_ROUTINE64 DbgHelpSymFunctionTableAccess64 = (PFUNCTION_TABLE_ACCESS_ROUTINE64) GetProcAddress (dbgDll, "SymFunctionTableAccess64");
+ PGET_MODULE_BASE_ROUTINE64 DbgHelpSymGetModuleBase64 = (PGET_MODULE_BASE_ROUTINE64) GetProcAddress (dbgDll, "SymGetModuleBase64");
+ StackWalk64_t DbgHelpStackWalk64 = (StackWalk64_t) GetProcAddress (dbgDll, "StackWalk64");
+ SymFromAddr_t DbgHelpSymFromAddr = (SymFromAddr_t) GetProcAddress (dbgDll, "SymFromAddr");
+
+ if (DbgHelpSymGetOptions && DbgHelpSymSetOptions && DbgHelpSymInitialize && DbgHelpSymFunctionTableAccess64 && DbgHelpSymGetModuleBase64 && DbgHelpStackWalk64 && DbgHelpSymFromAddr)
+ {
+ DbgHelpSymSetOptions (DbgHelpSymGetOptions() | SYMOPT_DEFERRED_LOADS | SYMOPT_ALLOW_ABSOLUTE_SYMBOLS | SYMOPT_NO_CPP);
+
+ if (DbgHelpSymInitialize (GetCurrentProcess(), NULL, TRUE))
+ {
+ STACKFRAME64 frame;
+ memset (&frame, 0, sizeof (frame));
+
+ frame.AddrPC.Offset = ep->ContextRecord->Eip;
+ frame.AddrPC.Mode = AddrModeFlat;
+ frame.AddrStack.Offset = ep->ContextRecord->Esp;
+ frame.AddrStack.Mode = AddrModeFlat;
+ frame.AddrFrame.Offset = ep->ContextRecord->Ebp;
+ frame.AddrFrame.Mode = AddrModeFlat;
+
+ string lastSymbol;
+
+ while (frameNumber < 32 && DbgHelpStackWalk64 (IMAGE_FILE_MACHINE_I386, GetCurrentProcess(), args->ExceptionThread, &frame, ep->ContextRecord, NULL, DbgHelpSymFunctionTableAccess64, DbgHelpSymGetModuleBase64, NULL))
+ {
+ if (!frame.AddrPC.Offset)
+ continue;
+
+ ULONG64 symbolBuffer[(sizeof (SYMBOL_INFO) + MAX_SYM_NAME * sizeof (TCHAR) + sizeof (ULONG64) - 1) / sizeof (ULONG64)];
+ memset (symbolBuffer, 0, sizeof (symbolBuffer));
+
+ PSYMBOL_INFO symbol = (PSYMBOL_INFO) symbolBuffer;
+ symbol->SizeOfStruct = sizeof (SYMBOL_INFO);
+ symbol->MaxNameLen = MAX_SYM_NAME;
+
+ if (DbgHelpSymFromAddr (GetCurrentProcess(), frame.AddrPC.Offset, NULL, symbol) && symbol->NameLen > 0)
+ {
+ for (size_t i = 0; i < symbol->NameLen; ++i)
+ {
+ if (!isalnum (symbol->Name[i]))
+ symbol->Name[i] = '_';
+ }
+
+ if (symbol->Name != lastSymbol)
+ callStack << "&st" << frameNumber++ << "=" << symbol->Name;
+
+ lastSymbol = symbol->Name;
+ }
+ else if (frameNumber == 0 || IsReturnAddress (frame.AddrPC.Offset))
+ {
+ callStack << "&st" << frameNumber++ << "=0x" << hex << frame.AddrPC.Offset << dec;
+ }
+ }
+ }
+ }
+ }
+
+ // StackWalk64() may fail due to missing frame pointers
+ list <DWORD> retAddrs;
+ if (frameNumber == 0)
+ retAddrs.push_back (ep->ContextRecord->Eip);
+
+ retAddrs.push_back (0);
+
+ MEMORY_BASIC_INFORMATION mi;
+ VirtualQuery (sp, &mi, sizeof (mi));
+ PDWORD stackTop = (PDWORD)((byte *) mi.BaseAddress + mi.RegionSize);
+ int i = 0;
+
+ while (retAddrs.size() < 16 && &sp[i] < stackTop)
+ {
+ if (IsReturnAddress (sp[i]))
+ {
+ bool duplicate = false;
+ foreach (DWORD prevAddr, retAddrs)
+ {
+ if (sp[i] == prevAddr)
+ {
+ duplicate = true;
+ break;
+ }
+ }
+
+ if (!duplicate)
+ retAddrs.push_back (sp[i]);
+ }
+ i++;
+ }
+
+ if (retAddrs.size() > 1)
+ {
+ foreach (DWORD addr, retAddrs)
+ {
+ callStack << "&st" << frameNumber++ << "=0x" << hex << addr << dec;
+ }
+ }
+
+ // Checksum of the module
+ if (GetModuleFileName (NULL, modPath, sizeof (modPath)))
+ {
+ HANDLE h = CreateFile (modPath, FILE_READ_DATA | FILE_READ_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ BY_HANDLE_FILE_INFORMATION fi;
+ if (GetFileInformationByHandle (h, &fi))
+ {
+ char *buf = (char *) malloc (fi.nFileSizeLow);
+ if (buf)
+ {
+ DWORD bytesRead;
+ if (ReadFile (h, buf, fi.nFileSizeLow, &bytesRead, NULL) && bytesRead == fi.nFileSizeLow)
+ crc = GetCrc32 ((unsigned char *) buf, fi.nFileSizeLow);
+ free (buf);
+ }
+ }
+ CloseHandle (h);
+ }
+ }
+
+ GetSystemInfo (&si);
+
+ if (LocalizationActive)
+ sprintf_s (lpack, sizeof (lpack), "&langpack=%s_%s", GetPreferredLangId (), GetActiveLangPackVersion ());
+ else
+ lpack[0] = 0;
+
+ sprintf (url, TC_APPLINK_SECURE "&dest=err-report%s&os=%s&osver=%d.%d.%d&arch=%s&cpus=%d&app=%s&cksum=%x&dlg=%s&err=%x&addr=%x"
+ , lpack
+ , GetWindowsEdition().c_str()
+ , CurrentOSMajor
+ , CurrentOSMinor
+ , CurrentOSServicePack
+ , Is64BitOs () ? "x64" : "x86"
+ , si.dwNumberOfProcessors
+#ifdef TCMOUNT
+ ,"main"
+#endif
+#ifdef VOLFORMAT
+ ,"format"
+#endif
+#ifdef SETUP
+ ,"setup"
+#endif
+ , crc
+ , LastDialogId ? LastDialogId : "-"
+ , exCode
+ , addr);
+
+ string urlStr = url + callStack.str();
+
+ _snwprintf (msg, array_capacity (msg), GetString ("EXCEPTION_REPORT"), urlStr.c_str());
+
+ if (IDYES == MessageBoxW (0, msg, GetString ("EXCEPTION_REPORT_TITLE"), MB_ICONERROR | MB_YESNO | MB_DEFBUTTON1))
+ ShellExecute (NULL, "open", urlStr.c_str(), NULL, NULL, SW_SHOWNORMAL);
+ else
+ UnhandledExceptionFilter (ep);
+}
+
+
+LONG __stdcall ExceptionHandler (EXCEPTION_POINTERS *ep)
+{
+ SetUnhandledExceptionFilter (NULL);
+
+ if (SystemFileSelectorCallPending && SystemFileSelectorCallerThreadId == GetCurrentThreadId())
+ {
+ MessageBoxW (NULL, GetString ("EXCEPTION_REPORT_EXT_FILESEL"), GetString ("EXCEPTION_REPORT_TITLE"), MB_ICONERROR | MB_OK | MB_SETFOREGROUND | MB_TOPMOST);
+
+ UnhandledExceptionFilter (ep);
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+
+ ExceptionHandlerThreadArgs args;
+ args.ExceptionPointers = ep;
+ args.ExceptionThread = GetCurrentThread();
+
+ WaitForSingleObject ((HANDLE) _beginthread (ExceptionHandlerThread, 0, &args), INFINITE);
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+
+void InvalidParameterHandler (const wchar_t *expression, const wchar_t *function, const wchar_t *file, unsigned int line, uintptr_t reserved)
+{
+ TC_THROW_FATAL_EXCEPTION;
+}
+
+
+static LRESULT CALLBACK NonInstallUacWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return DefWindowProc (hWnd, message, wParam, lParam);
+}
+
+
+// Mutex handling to prevent multiple instances of the wizard or main app from dealing with system encryption.
+// Returns TRUE if the mutex is (or had been) successfully acquired (otherwise FALSE).
+BOOL CreateSysEncMutex (void)
+{
+ return TCCreateMutex (&hSysEncMutex, TC_MUTEX_NAME_SYSENC);
+}
+
+
+BOOL InstanceHasSysEncMutex (void)
+{
+ return (hSysEncMutex != NULL);
+}
+
+
+// Mutex handling to prevent multiple instances of the wizard from dealing with system encryption
+void CloseSysEncMutex (void)
+{
+ TCCloseMutex (&hSysEncMutex);
+}
+
+
+// Returns TRUE if the mutex is (or had been) successfully acquired (otherwise FALSE).
+BOOL CreateNonSysInplaceEncMutex (void)
+{
+ return TCCreateMutex (&hNonSysInplaceEncMutex, TC_MUTEX_NAME_NONSYS_INPLACE_ENC);
+}
+
+
+BOOL InstanceHasNonSysInplaceEncMutex (void)
+{
+ return (hNonSysInplaceEncMutex != NULL);
+}
+
+
+void CloseNonSysInplaceEncMutex (void)
+{
+ TCCloseMutex (&hNonSysInplaceEncMutex);
+}
+
+
+// Returns TRUE if another instance of the wizard is preparing, resuming or performing non-system in-place encryption
+BOOL NonSysInplaceEncInProgressElsewhere (void)
+{
+ return (!InstanceHasNonSysInplaceEncMutex ()
+ && MutexExistsOnSystem (TC_MUTEX_NAME_NONSYS_INPLACE_ENC));
+}
+
+
+// Mutex handling to prevent multiple instances of the wizard or main app from trying to install
+// or register the driver or from trying to launch it in portable mode at the same time.
+// Returns TRUE if the mutex is (or had been) successfully acquired (otherwise FALSE).
+BOOL CreateDriverSetupMutex (void)
+{
+ return TCCreateMutex (&hDriverSetupMutex, TC_MUTEX_NAME_DRIVER_SETUP);
+}
+
+
+void CloseDriverSetupMutex (void)
+{
+ TCCloseMutex (&hDriverSetupMutex);
+}
+
+
+BOOL CreateAppSetupMutex (void)
+{
+ return TCCreateMutex (&hAppSetupMutex, TC_MUTEX_NAME_APP_SETUP);
+}
+
+
+void CloseAppSetupMutex (void)
+{
+ TCCloseMutex (&hAppSetupMutex);
+}
+
+
+BOOL IsTrueCryptInstallerRunning (void)
+{
+ return (MutexExistsOnSystem (TC_MUTEX_NAME_APP_SETUP));
+}
+
+
+// Returns TRUE if the mutex is (or had been) successfully acquired (otherwise FALSE).
+BOOL TCCreateMutex (volatile HANDLE *hMutex, char *name)
+{
+ if (*hMutex != NULL)
+ return TRUE; // This instance already has the mutex
+
+ *hMutex = CreateMutex (NULL, TRUE, name);
+ if (*hMutex == NULL)
+ {
+ // In multi-user configurations, the OS returns "Access is denied" here when a user attempts
+ // to acquire the mutex if another user already has. However, on Vista, "Access is denied" is
+ // returned also if the mutex is owned by a process with admin rights while we have none.
+
+ return FALSE;
+ }
+
+ if (GetLastError () == ERROR_ALREADY_EXISTS)
+ {
+ ReleaseMutex (*hMutex);
+ CloseHandle (*hMutex);
+
+ *hMutex = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+void TCCloseMutex (volatile HANDLE *hMutex)
+{
+ if (*hMutex != NULL)
+ {
+ if (ReleaseMutex (*hMutex)
+ && CloseHandle (*hMutex))
+ *hMutex = NULL;
+ }
+}
+
+
+// Returns TRUE if a process running on the system has the specified mutex (otherwise FALSE).
+BOOL MutexExistsOnSystem (char *name)
+{
+ if (name[0] == 0)
+ return FALSE;
+
+ HANDLE hMutex = OpenMutex (MUTEX_ALL_ACCESS, FALSE, name);
+
+ if (hMutex == NULL)
+ {
+ if (GetLastError () == ERROR_FILE_NOT_FOUND)
+ return FALSE;
+
+ if (GetLastError () == ERROR_ACCESS_DENIED) // On Vista, this is returned if the owner of the mutex is elevated while we are not
+ return TRUE;
+
+ // The call failed and it is not certain whether the mutex exists or not
+ return FALSE;
+ }
+
+ CloseHandle (hMutex);
+ return TRUE;
+}
+
+
+uint32 ReadDriverConfigurationFlags ()
+{
+ DWORD configMap;
+
+ if (!ReadLocalMachineRegistryDword ("SYSTEM\\CurrentControlSet\\Services\\truecrypt", TC_DRIVER_CONFIG_REG_VALUE_NAME, &configMap))
+ configMap = 0;
+
+ return configMap;
+}
+
+
+uint32 ReadEncryptionThreadPoolFreeCpuCountLimit ()
+{
+ DWORD count;
+
+ if (!ReadLocalMachineRegistryDword ("SYSTEM\\CurrentControlSet\\Services\\truecrypt", TC_ENCRYPTION_FREE_CPU_COUNT_REG_VALUE_NAME, &count))
+ count = 0;
+
+ return count;
+}
+
+
+BOOL LoadSysEncSettings (HWND hwndDlg)
+{
+ BOOL status = TRUE;
+ DWORD size = 0;
+ char *sysEncCfgFileBuf = LoadFile (GetConfigPath (TC_APPD_FILENAME_SYSTEM_ENCRYPTION), &size);
+ char *xml = sysEncCfgFileBuf;
+ char paramName[100], paramVal[MAX_PATH];
+
+ // Defaults
+ int newSystemEncryptionStatus = SYSENC_STATUS_NONE;
+ WipeAlgorithmId newnWipeMode = TC_WIPE_NONE;
+
+ if (!FileExists (GetConfigPath (TC_APPD_FILENAME_SYSTEM_ENCRYPTION)))
+ {
+ SystemEncryptionStatus = newSystemEncryptionStatus;
+ nWipeMode = newnWipeMode;
+ }
+
+ if (xml == NULL)
+ {
+ return FALSE;
+ }
+
+ while (xml = XmlFindElement (xml, "config"))
+ {
+ XmlGetAttributeText (xml, "key", paramName, sizeof (paramName));
+ XmlGetNodeText (xml, paramVal, sizeof (paramVal));
+
+ if (strcmp (paramName, "SystemEncryptionStatus") == 0)
+ {
+ newSystemEncryptionStatus = atoi (paramVal);
+ }
+ else if (strcmp (paramName, "WipeMode") == 0)
+ {
+ newnWipeMode = (WipeAlgorithmId) atoi (paramVal);
+ }
+
+ xml++;
+ }
+
+ SystemEncryptionStatus = newSystemEncryptionStatus;
+ nWipeMode = newnWipeMode;
+
+ free (sysEncCfgFileBuf);
+ return status;
+}
+
+
+// Returns the number of partitions where non-system in-place encryption is progress or had been in progress
+// but was interrupted. In addition, via the passed pointer, returns the last selected wipe algorithm ID.
+int LoadNonSysInPlaceEncSettings (WipeAlgorithmId *wipeAlgorithm)
+{
+ char *fileBuf = NULL;
+ char *fileBuf2 = NULL;
+ DWORD size, size2;
+ int count;
+
+ *wipeAlgorithm = TC_WIPE_NONE;
+
+ if (!FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC)))
+ return 0;
+
+ if ((fileBuf = LoadFile (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), &size)) == NULL)
+ return 0;
+
+ if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)))
+ {
+ if ((fileBuf2 = LoadFile (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE), &size2)) != NULL)
+ *wipeAlgorithm = (WipeAlgorithmId) atoi (fileBuf2);
+ }
+
+ count = atoi (fileBuf);
+
+ if (fileBuf != NULL)
+ TCfree (fileBuf);
+
+ if (fileBuf2 != NULL)
+ TCfree (fileBuf2);
+
+ return (count);
+}
+
+
+void RemoveNonSysInPlaceEncNotifications (void)
+{
+ if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC)))
+ remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC));
+
+ if (FileExists (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)))
+ remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE));
+
+ if (!IsNonInstallMode () && SystemEncryptionStatus == SYSENC_STATUS_NONE)
+ ManageStartupSeqWiz (TRUE, "");
+}
+
+
+void SavePostInstallTasksSettings (int command)
+{
+ FILE *f = NULL;
+
+ if (IsNonInstallMode() && command != TC_POST_INSTALL_CFG_REMOVE_ALL)
+ return;
+
+ switch (command)
+ {
+ case TC_POST_INSTALL_CFG_REMOVE_ALL:
+ remove (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_TUTORIAL));
+ remove (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RELEASE_NOTES));
+ break;
+
+ case TC_POST_INSTALL_CFG_TUTORIAL:
+ f = fopen (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_TUTORIAL), "w");
+ break;
+
+ case TC_POST_INSTALL_CFG_RELEASE_NOTES:
+ f = fopen (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RELEASE_NOTES), "w");
+ break;
+
+ default:
+ return;
+ }
+
+ if (f == NULL)
+ return;
+
+ if (fputs ("1", f) < 0)
+ {
+ // Error
+ fclose (f);
+ return;
+ }
+
+ TCFlushFile (f);
+
+ fclose (f);
+}
+
+
+void DoPostInstallTasks (void)
+{
+ BOOL bDone = FALSE;
+
+ if (FileExists (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_TUTORIAL)))
+ {
+ if (AskYesNo ("AFTER_INSTALL_TUTORIAL") == IDYES)
+ Applink ("beginnerstutorial", TRUE, "");
+
+ bDone = TRUE;
+ }
+
+ if (FileExists (GetConfigPath (TC_APPD_FILENAME_POST_INSTALL_TASK_RELEASE_NOTES)))
+ {
+ if (AskYesNo ("AFTER_UPGRADE_RELEASE_NOTES") == IDYES)
+ Applink ("releasenotes", TRUE, "");
+
+ bDone = TRUE;
+ }
+
+ if (bDone)
+ SavePostInstallTasksSettings (TC_POST_INSTALL_CFG_REMOVE_ALL);
+}
+
+
+void InitOSVersionInfo ()
+{
+ OSVERSIONINFO os;
+ os.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+
+ if (GetVersionEx (&os) == FALSE)
+ AbortProcess ("NO_OS_VER");
+
+ CurrentOSMajor = os.dwMajorVersion;
+ CurrentOSMinor = os.dwMinorVersion;
+
+ if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 0)
+ nCurrentOS = WIN_2000;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 1)
+ nCurrentOS = WIN_XP;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 5 && CurrentOSMinor == 2)
+ {
+ OSVERSIONINFOEX osEx;
+
+ osEx.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
+ GetVersionEx ((LPOSVERSIONINFOA) &osEx);
+
+ if (osEx.wProductType == VER_NT_SERVER || osEx.wProductType == VER_NT_DOMAIN_CONTROLLER)
+ nCurrentOS = WIN_SERVER_2003;
+ else
+ nCurrentOS = WIN_XP64;
+ }
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 0)
+ {
+ OSVERSIONINFOEX osEx;
+
+ osEx.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
+ GetVersionEx ((LPOSVERSIONINFOA) &osEx);
+
+ if (osEx.wProductType == VER_NT_SERVER || osEx.wProductType == VER_NT_DOMAIN_CONTROLLER)
+ nCurrentOS = WIN_SERVER_2008;
+ else
+ nCurrentOS = WIN_VISTA;
+ }
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 6 && CurrentOSMinor == 1)
+ nCurrentOS = (IsServerOS() ? WIN_SERVER_2008_R2 : WIN_7);
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_NT && CurrentOSMajor == 4)
+ nCurrentOS = WIN_NT4;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 0)
+ nCurrentOS = WIN_95;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 10)
+ nCurrentOS = WIN_98;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && os.dwMajorVersion == 4 && os.dwMinorVersion == 90)
+ nCurrentOS = WIN_ME;
+ else if (os.dwPlatformId == VER_PLATFORM_WIN32s)
+ nCurrentOS = WIN_31;
+ else
+ nCurrentOS = WIN_UNKNOWN;
+}
+
+
+/* InitApp - initialize the application, this function is called once in the
+ applications WinMain function, but before the main dialog has been created */
+void InitApp (HINSTANCE hInstance, char *lpszCommandLine)
+{
+ WNDCLASS wc;
+ char langId[6];
+
+ /* Save the instance handle for later */
+ hInst = hInstance;
+
+ InitOSVersionInfo();
+
+ SetErrorMode (SetErrorMode (0) | SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
+ CoInitialize (NULL);
+
+#ifndef SETUP
+ // Application ID
+ typedef HRESULT (WINAPI *SetAppId_t) (PCWSTR appID);
+ SetAppId_t setAppId = (SetAppId_t) GetProcAddress (GetModuleHandle ("shell32.dll"), "SetCurrentProcessExplicitAppUserModelID");
+
+ if (setAppId)
+ setAppId (TC_APPLICATION_ID);
+#endif
+
+ // Language
+ langId[0] = 0;
+ SetPreferredLangId (ConfigReadString ("Language", "", langId, sizeof (langId)));
+
+ if (langId[0] == 0)
+ DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_LANGUAGE), NULL,
+ (DLGPROC) LanguageDlgProc, (LPARAM) 1);
+
+ LoadLanguageFile ();
+
+#ifndef SETUP
+ // UAC elevation moniker cannot be used in portable mode.
+ // A new instance of the application must be created with elevated privileges.
+ if (IsNonInstallMode () && !IsAdmin () && IsUacSupported ())
+ {
+ char modPath[MAX_PATH], newCmdLine[4096];
+ WNDCLASSEX wcex;
+ HWND hWnd;
+
+ if (strstr (lpszCommandLine, "/q UAC ") == lpszCommandLine)
+ {
+ Error ("UAC_INIT_ERROR");
+ exit (1);
+ }
+
+ memset (&wcex, 0, sizeof (wcex));
+ wcex.cbSize = sizeof(WNDCLASSEX);
+ wcex.lpfnWndProc = (WNDPROC) NonInstallUacWndProc;
+ wcex.hInstance = hInstance;
+ wcex.lpszClassName = "TrueCrypt";
+ RegisterClassEx (&wcex);
+
+ // A small transparent window is necessary to bring the new instance to foreground
+ hWnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_LAYERED,
+ "TrueCrypt", "TrueCrypt", 0,
+ GetSystemMetrics (SM_CXSCREEN)/2,
+ GetSystemMetrics (SM_CYSCREEN)/2,
+ 1, 1, NULL, NULL, hInstance, NULL);
+
+ SetLayeredWindowAttributes (hWnd, 0, 0, LWA_ALPHA);
+ ShowWindow (hWnd, SW_SHOWNORMAL);
+
+ GetModuleFileName (NULL, modPath, sizeof (modPath));
+
+ strcpy (newCmdLine, "/q UAC ");
+ strcat_s (newCmdLine, sizeof (newCmdLine), lpszCommandLine);
+
+ if ((int)ShellExecute (hWnd, "runas", modPath, newCmdLine, NULL, SW_SHOWNORMAL) <= 32)
+ exit (1);
+
+ Sleep (2000);
+ exit (0);
+ }
+#endif
+
+ SetUnhandledExceptionFilter (ExceptionHandler);
+ _set_invalid_parameter_handler (InvalidParameterHandler);
+
+ RemoteSession = GetSystemMetrics (SM_REMOTESESSION) != 0;
+
+ // OS version check
+ if (CurrentOSMajor < 5)
+ {
+ MessageBoxW (NULL, GetString ("UNSUPPORTED_OS"), lpszTitle, MB_ICONSTOP);
+ exit (1);
+ }
+ else
+ {
+ OSVERSIONINFOEX osEx;
+
+ // Service pack check & warnings about critical MS issues
+ osEx.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEX);
+ if (GetVersionEx ((LPOSVERSIONINFOA) &osEx) != 0)
+ {
+ CurrentOSServicePack = osEx.wServicePackMajor;
+ switch (nCurrentOS)
+ {
+ case WIN_2000:
+ if (osEx.wServicePackMajor < 3)
+ Warning ("LARGE_IDE_WARNING_2K");
+ else
+ {
+ DWORD val = 0, size = sizeof(val);
+ HKEY hkey;
+
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\Atapi\\Parameters", 0, KEY_READ, &hkey) == ERROR_SUCCESS
+ && (RegQueryValueEx (hkey, "EnableBigLba", 0, 0, (LPBYTE) &val, &size) != ERROR_SUCCESS
+ || val != 1))
+
+ {
+ Warning ("LARGE_IDE_WARNING_2K_REGISTRY");
+ }
+ RegCloseKey (hkey);
+ }
+ break;
+
+ case WIN_XP:
+ if (osEx.wServicePackMajor < 1)
+ {
+ HKEY k;
+ // PE environment does not report version of SP
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\minint", 0, KEY_READ, &k) != ERROR_SUCCESS)
+ Warning ("LARGE_IDE_WARNING_XP");
+ else
+ RegCloseKey (k);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Get the attributes for the standard dialog class */
+ if ((GetClassInfo (hInst, WINDOWS_DIALOG_CLASS, &wc)) == 0)
+ {
+ handleWin32Error (NULL);
+ AbortProcess ("INIT_REGISTER");
+ }
+
+#ifndef SETUP
+ wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_TRUECRYPT_ICON));
+#else
+#include "../setup/resource.h"
+ wc.hIcon = LoadIcon (hInstance, MAKEINTRESOURCE (IDI_SETUP));
+#endif
+ wc.lpszClassName = TC_DLG_CLASS;
+ wc.lpfnWndProc = &CustomDlgProc;
+ wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+
+ hDlgClass = RegisterClass (&wc);
+ if (hDlgClass == 0)
+ {
+ handleWin32Error (NULL);
+ AbortProcess ("INIT_REGISTER");
+ }
+
+ wc.lpszClassName = TC_SPLASH_CLASS;
+ wc.lpfnWndProc = &SplashDlgProc;
+ wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+
+ hSplashClass = RegisterClass (&wc);
+ if (hSplashClass == 0)
+ {
+ handleWin32Error (NULL);
+ AbortProcess ("INIT_REGISTER");
+ }
+
+ // Required for RichEdit text fields to work
+ if (LoadLibrary("Riched20.dll") == NULL)
+ {
+ // This error is fatal e.g. because legal notices could not be displayed
+ handleWin32Error (NULL);
+ AbortProcess ("INIT_RICHEDIT");
+ }
+
+ // DPI and GUI aspect ratio
+ DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_AUXILIARY_DLG), NULL,
+ (DLGPROC) AuxiliaryDlgProc, (LPARAM) 1);
+
+ InitHelpFileName ();
+
+#ifndef SETUP
+ if (!EncryptionThreadPoolStart (ReadEncryptionThreadPoolFreeCpuCountLimit()))
+ {
+ handleWin32Error (NULL);
+ exit (1);
+ }
+#endif
+}
+
+void InitHelpFileName (void)
+{
+ char *lpszTmp;
+
+ GetModuleFileName (NULL, szHelpFile, sizeof (szHelpFile));
+ lpszTmp = strrchr (szHelpFile, '\\');
+ if (lpszTmp)
+ {
+ char szTemp[TC_MAX_PATH];
+
+ // Primary file name
+ if (strcmp (GetPreferredLangId(), "en") == 0
+ || GetPreferredLangId() == NULL)
+ {
+ strcpy (++lpszTmp, "TrueCrypt User Guide.pdf");
+ }
+ else
+ {
+ sprintf (szTemp, "TrueCrypt User Guide.%s.pdf", GetPreferredLangId());
+ strcpy (++lpszTmp, szTemp);
+ }
+
+ // Secondary file name (used when localized documentation is not found).
+ GetModuleFileName (NULL, szHelpFile2, sizeof (szHelpFile2));
+ lpszTmp = strrchr (szHelpFile2, '\\');
+ if (lpszTmp)
+ {
+ strcpy (++lpszTmp, "TrueCrypt User Guide.pdf");
+ }
+ }
+}
+
+BOOL OpenDevice (const char *lpszPath, OPEN_TEST_STRUCT *driver, BOOL detectFilesystem)
+{
+ DWORD dwResult;
+ BOOL bResult;
+
+ strcpy ((char *) &driver->wszFileName[0], lpszPath);
+ ToUNICODE ((char *) &driver->wszFileName[0]);
+
+ driver->bDetectTCBootLoader = FALSE;
+ driver->DetectFilesystem = detectFilesystem;
+
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_OPEN_TEST,
+ driver, sizeof (OPEN_TEST_STRUCT),
+ driver, sizeof (OPEN_TEST_STRUCT),
+ &dwResult, NULL);
+
+ if (bResult == FALSE)
+ {
+ dwResult = GetLastError ();
+
+ if (dwResult == ERROR_SHARING_VIOLATION || dwResult == ERROR_NOT_READY)
+ {
+ driver->TCBootLoaderDetected = FALSE;
+ driver->FilesystemDetected = FALSE;
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+// Tells the driver that it's running in portable mode
+void NotifyDriverOfPortableMode (void)
+{
+ if (hDriver != INVALID_HANDLE_VALUE)
+ {
+ DWORD dwResult;
+
+ DeviceIoControl (hDriver, TC_IOCTL_SET_PORTABLE_MODE_STATUS, NULL, 0, NULL, 0, &dwResult, NULL);
+ }
+}
+
+
+BOOL GetDriveLabel (int driveNo, wchar_t *label, int labelSize)
+{
+ DWORD fileSystemFlags;
+ wchar_t root[] = { L'A' + (wchar_t) driveNo, L':', L'\\', 0 };
+
+ return GetVolumeInformationW (root, label, labelSize / 2, NULL, NULL, &fileSystemFlags, NULL, 0);
+}
+
+
+/* Stores the device path of the system partition in SysPartitionDevicePath and the device path of the system drive
+in SysDriveDevicePath.
+IMPORTANT: As this may take a very long time if called for the first time, it should be called only before performing
+ a dangerous operation (such as header backup restore or formatting a supposedly non-system device) never
+ at WM_INITDIALOG or any other GUI events -- instead call IsSystemDevicePath (path, hwndDlg, FALSE) for
+ very fast preliminary GUI checks; also note that right after the "Select Device" dialog exits with an OK
+ return code, you can use the global flags bSysPartitionSelected and bSysDriveSelected to see if the user
+ selected the system partition/device.
+After this function completes successfully, the results are cached for the rest of the session and repeated
+executions complete very fast. Returns TRUE if successful (otherwise FALSE). */
+BOOL GetSysDevicePaths (HWND hwndDlg)
+{
+ if (!bCachedSysDevicePathsValid
+ || strlen (SysPartitionDevicePath) <= 1
+ || strlen (SysDriveDevicePath) <= 1)
+ {
+ foreach (const HostDevice &device, GetAvailableHostDevices (false, true))
+ {
+ if (device.ContainsSystem)
+ strcpy_s (device.IsPartition ? SysPartitionDevicePath : SysDriveDevicePath, TC_MAX_PATH, device.Path.c_str());
+ }
+
+ if (IsOSAtLeast (WIN_7))
+ {
+ // Find extra boot partition
+ foreach (const HostDevice &drive, GetAvailableHostDevices (false, false))
+ {
+ if (drive.ContainsSystem)
+ {
+ foreach (const HostDevice &sysDrivePartition, drive.Partitions)
+ {
+ if (sysDrivePartition.Bootable)
+ {
+ if (sysDrivePartition.Size <= TC_MAX_EXTRA_BOOT_PARTITION_SIZE)
+ ExtraBootPartitionDevicePath = sysDrivePartition.Path;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ bCachedSysDevicePathsValid = 1;
+ }
+
+ return (bCachedSysDevicePathsValid
+ && strlen (SysPartitionDevicePath) > 1
+ && strlen (SysDriveDevicePath) > 1);
+}
+
+/* Determines whether the device path is the path of the system partition or of the system drive (or neither).
+If bReliableRequired is TRUE, very fast execution is guaranteed, but the results cannot be relied upon.
+If it's FALSE and the function is called for the first time, execution may take up to one minute but the
+results are reliable.
+IMPORTANT: As the execution may take a very long time if called for the first time with bReliableRequired set
+ to TRUE, it should be called with bReliableRequired set to TRUE only before performing a dangerous
+ operation (such as header backup restore or formatting a supposedly non-system device) never at
+ WM_INITDIALOG or any other GUI events (use IsSystemDevicePath(path, hwndDlg, FALSE) for fast
+ preliminary GUI checks; also note that right after the "Select Device" dialog exits with an OK
+ return code, you can use the global flags bSysPartitionSelected and bSysDriveSelected to see if the
+ user selected the system partition/device).
+After this function completes successfully, the results are cached for the rest of the session, bReliableRequired
+is ignored (TRUE implied), repeated executions complete very fast, and the results are always reliable.
+Return codes:
+1 - it is the system partition path (e.g. \Device\Harddisk0\Partition1)
+2 - it is the system drive path (e.g. \Device\Harddisk0\Partition0)
+3 - it is the extra boot partition path
+0 - it's not the system partition/drive path
+-1 - the result can't be determined, isn't reliable, or there was an error. */
+int IsSystemDevicePath (char *path, HWND hwndDlg, BOOL bReliableRequired)
+{
+ if (!bCachedSysDevicePathsValid
+ && bReliableRequired)
+ {
+ if (!GetSysDevicePaths (hwndDlg))
+ return -1;
+ }
+
+ if (strlen (SysPartitionDevicePath) <= 1 || strlen (SysDriveDevicePath) <= 1)
+ return -1;
+
+ if (strncmp (path, SysPartitionDevicePath, max (strlen(path), strlen(SysPartitionDevicePath))) == 0)
+ return 1;
+ else if (strncmp (path, SysDriveDevicePath, max (strlen(path), strlen(SysDriveDevicePath))) == 0)
+ return 2;
+ else if (ExtraBootPartitionDevicePath == path)
+ return 3;
+
+ return 0;
+}
+
+
+wstring GetSysEncryptionPretestInfo2String (void)
+{
+ // This huge string is divided into smaller portions to make it easier for translators to
+ // re-translate it when a minor modification is made to it (the whole huge string will not be
+ // reverted to English, so they will have to translate only a small portion of it).
+ return (wstring (L"\n")
+ + GetString ("SYS_ENCRYPTION_PRETEST_INFO2_PORTION_1")
+ + GetString ("SYS_ENCRYPTION_PRETEST_INFO2_PORTION_2")
+ + GetString ("SYS_ENCRYPTION_PRETEST_INFO2_PORTION_3")
+ + GetString ("SYS_ENCRYPTION_PRETEST_INFO2_PORTION_4"));
+}
+
+
+wstring GetRescueDiskHelpString (void)
+{
+ // This huge string is divided into smaller portions to make it easier for translators to
+ // re-translate it when a minor modification is made to it (the whole huge string will not be
+ // reverted to English, so they will have to translate only a small portion of it).
+ return (wstring (
+ GetString ("RESCUE_DISK_HELP_PORTION_1"))
+ + GetString ("RESCUE_DISK_HELP_PORTION_2")
+ + GetString ("RESCUE_DISK_HELP_PORTION_3")
+ + GetString ("RESCUE_DISK_HELP_PORTION_4")
+ + GetString ("RESCUE_DISK_HELP_PORTION_5")
+ + GetString ("RESCUE_DISK_HELP_PORTION_6")
+ + GetString ("RESCUE_DISK_HELP_PORTION_7")
+ + GetString ("RESCUE_DISK_HELP_PORTION_8")
+ + GetString ("RESCUE_DISK_HELP_PORTION_9"));
+}
+
+
+wstring GetDecoyOsInstructionsString (void)
+{
+ // This huge string is divided into smaller portions to make it easier for translators to
+ // re-translate it when a minor modification is made to it (the whole huge string will not be
+ // reverted to English, so they will have to translate only a small portion of it).
+ return (wstring (
+ GetString ("DECOY_OS_INSTRUCTIONS_PORTION_1"))
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_2")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_3")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_4")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_5")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_6")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_7")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_8")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_9")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_10")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_11")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_12")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_13")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_14")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_15")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_16")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_17")
+ + GetString ("DECOY_OS_INSTRUCTIONS_PORTION_18"));
+}
+
+
+BOOL TextInfoDialogBox (int nID)
+{
+ return DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TEXT_INFO_DIALOG_BOX_DLG), MainDlg, (DLGPROC) TextInfoDialogBoxDlgProc, (LPARAM) nID);
+}
+
+BOOL CALLBACK TextInfoDialogBoxDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD lw = LOWORD (wParam);
+ static int nID = 0;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ nID = (int) lParam;
+
+ // Left margin for rich edit text field
+ SendMessage (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), EM_SETMARGINS, (WPARAM) EC_LEFTMARGIN, (LPARAM) CompensateXDPI (4));
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_HIDE);
+
+ switch (nID)
+ {
+ case TC_TBXID_LEGAL_NOTICES:
+ LocalizeDialog (hwndDlg, "LEGAL_NOTICES_DLG_TITLE");
+ break;
+
+ case TC_TBXID_SYS_ENCRYPTION_PRETEST:
+ LocalizeDialog (hwndDlg, NULL);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_SHOW);
+ break;
+
+ case TC_TBXID_SYS_ENC_RESCUE_DISK:
+ LocalizeDialog (hwndDlg, NULL);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_SHOW);
+ break;
+
+ case TC_TBXID_DECOY_OS_INSTRUCTIONS:
+ LocalizeDialog (hwndDlg, NULL);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_SHOW);
+ break;
+
+ case TC_TBXID_EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS:
+ LocalizeDialog (hwndDlg, NULL);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_PRINT), SW_SHOW);
+ break;
+ }
+
+ SendMessage (hwndDlg, TC_APPMSG_LOAD_TEXT_BOX_CONTENT, 0, 0);
+ }
+ return 0;
+
+ case WM_COMMAND:
+ if (lw == IDOK || lw == IDCANCEL)
+ {
+ NormalCursor ();
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ if (lw == IDC_PRINT)
+ {
+ switch (nID)
+ {
+ case TC_TBXID_SYS_ENCRYPTION_PRETEST:
+ PrintHardCopyTextUTF16 ((wchar_t *) GetSysEncryptionPretestInfo2String ().c_str(), "Pre-Boot Troubleshooting", GetSysEncryptionPretestInfo2String ().length () * 2);
+ break;
+
+ case TC_TBXID_SYS_ENC_RESCUE_DISK:
+ PrintHardCopyTextUTF16 ((wchar_t *) GetRescueDiskHelpString ().c_str(), "TrueCrypt Rescue Disk Help", GetRescueDiskHelpString ().length () * 2);
+ break;
+
+ case TC_TBXID_DECOY_OS_INSTRUCTIONS:
+ PrintHardCopyTextUTF16 ((wchar_t *) GetDecoyOsInstructionsString ().c_str(), "How to Create Decoy OS", GetDecoyOsInstructionsString ().length () * 2);
+ break;
+
+ case TC_TBXID_EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS:
+ PrintHardCopyTextUTF16 (GetString ("EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS"), "How to Remove Extra Boot Partition", wcslen (GetString ("EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS")) * 2);
+ break;
+ }
+ return 1;
+ }
+
+ return 0;
+
+ case TC_APPMSG_LOAD_TEXT_BOX_CONTENT:
+ {
+ char *r = NULL;
+
+ switch (nID)
+ {
+ case TC_TBXID_LEGAL_NOTICES:
+ LocalizeDialog (hwndDlg, "LEGAL_NOTICES_DLG_TITLE");
+ r = GetLegalNotices ();
+ if (r != NULL)
+ {
+ SetWindowText (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), r);
+ free (r);
+ }
+ break;
+
+ case TC_TBXID_SYS_ENCRYPTION_PRETEST:
+ LocalizeDialog (hwndDlg, NULL);
+ SetWindowTextW (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), (wchar_t *) GetSysEncryptionPretestInfo2String ().c_str());
+ break;
+
+ case TC_TBXID_SYS_ENC_RESCUE_DISK:
+ LocalizeDialog (hwndDlg, NULL);
+ SetWindowTextW (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), (wchar_t *) GetRescueDiskHelpString ().c_str());
+ break;
+
+ case TC_TBXID_DECOY_OS_INSTRUCTIONS:
+ LocalizeDialog (hwndDlg, NULL);
+ SetWindowTextW (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), (wchar_t *) GetDecoyOsInstructionsString ().c_str());
+ break;
+
+ case TC_TBXID_EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS:
+ LocalizeDialog (hwndDlg, NULL);
+ SetWindowTextW (GetDlgItem (hwndDlg, IDC_INFO_BOX_TEXT), GetString ("EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS"));
+ break;
+ }
+ }
+ return 1;
+
+ case WM_CLOSE:
+ NormalCursor ();
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+char * GetLegalNotices ()
+{
+ static char *resource;
+ static DWORD size;
+ char *buf = NULL;
+
+ if (resource == NULL)
+ resource = (char *) MapResource ("Text", IDR_LICENSE, &size);
+
+ if (resource != NULL)
+ {
+ buf = (char *) malloc (size + 1);
+ if (buf != NULL)
+ {
+ memcpy (buf, resource, size);
+ buf[size] = 0;
+ }
+ }
+
+ return buf;
+}
+
+
+BOOL CALLBACK RawDevicesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static char *lpszFileName; // This is actually a pointer to a GLOBAL array
+ static vector <HostDevice> devices;
+ static map <int, HostDevice> itemToDeviceMap;
+
+ WORD lw = LOWORD (wParam);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ LVCOLUMNW LvCol;
+ HWND hList = GetDlgItem (hwndDlg, IDC_DEVICELIST);
+
+ LocalizeDialog (hwndDlg, "IDD_RAWDEVICES_DLG");
+
+ SendMessage (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0,
+ LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_TWOCLICKACTIVATE|LVS_EX_LABELTIP
+ );
+
+ memset (&LvCol,0,sizeof(LvCol));
+ LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
+ LvCol.pszText = GetString ("DEVICE");
+ LvCol.cx = CompensateXDPI (186);
+ LvCol.fmt = LVCFMT_LEFT;
+ SendMessage (hList,LVM_INSERTCOLUMNW,0,(LPARAM)&LvCol);
+
+ LvCol.pszText = GetString ("DRIVE");
+ LvCol.cx = CompensateXDPI (38);
+ LvCol.fmt = LVCFMT_LEFT;
+ SendMessage (hList,LVM_INSERTCOLUMNW,1,(LPARAM)&LvCol);
+
+ LvCol.pszText = GetString ("SIZE");
+ LvCol.cx = CompensateXDPI (64);
+ LvCol.fmt = LVCFMT_RIGHT;
+ SendMessage (hList,LVM_INSERTCOLUMNW,2,(LPARAM)&LvCol);
+
+ LvCol.pszText = GetString ("LABEL");
+ LvCol.cx = CompensateXDPI (128);
+ LvCol.fmt = LVCFMT_LEFT;
+ SendMessage (hList,LVM_INSERTCOLUMNW,3,(LPARAM)&LvCol);
+
+ devices.clear();
+ itemToDeviceMap.clear();
+
+ WaitCursor();
+ devices = GetAvailableHostDevices (false, true, false);
+ NormalCursor();
+
+ if (devices.empty())
+ {
+ MessageBoxW (hwndDlg, GetString ("RAWDEVICES"), lpszTitle, ICON_HAND);
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+
+ int line = 1;
+ LVITEM item;
+ memset (&item, 0, sizeof (item));
+ item.mask = LVIF_TEXT;
+
+ foreach (const HostDevice &device, devices)
+ {
+ item.iSubItem = 1;
+
+ if (device.ContainsSystem)
+ {
+ if (device.IsPartition)
+ strcpy_s (SysPartitionDevicePath, sizeof (SysPartitionDevicePath), device.Path.c_str());
+ else
+ strcpy_s (SysDriveDevicePath, sizeof (SysDriveDevicePath), device.Path.c_str());
+ }
+
+ // Path
+ if (!device.IsPartition || device.DynamicVolume)
+ {
+ if (!device.Floppy && device.Size == 0)
+ continue;
+
+ if (line > 1)
+ {
+ ListItemAdd (hList, item.iItem, "");
+ item.iItem = line++;
+ }
+
+ if (device.Floppy || device.DynamicVolume)
+ {
+ ListItemAdd (hList, item.iItem, (char *) device.Path.c_str());
+ }
+ else
+ {
+ wchar_t s[1024];
+ if (device.Removable)
+ wsprintfW (s, L"%s %d", GetString ("REMOVABLE_DISK"), device.SystemNumber);
+ else
+ wsprintfW (s, L"%s %d", GetString ("HARDDISK"), device.SystemNumber);
+
+ if (!device.Partitions.empty())
+ wcscat (s, L":");
+
+ ListItemAddW (hList, item.iItem, s);
+ }
+ }
+ else
+ {
+ ListItemAdd (hList, item.iItem, (char *) device.Path.c_str());
+ }
+
+ itemToDeviceMap[item.iItem] = device;
+
+ // Size
+ if (device.Size != 0)
+ {
+ wchar_t size[100] = { 0 };
+ GetSizeString (device.Size, size);
+ ListSubItemSetW (hList, item.iItem, 2, size);
+ }
+
+ // Mount point
+ if (!device.MountPoint.empty())
+ ListSubItemSet (hList, item.iItem, 1, (char *) device.MountPoint.c_str());
+
+ // Label
+ if (!device.Name.empty())
+ ListSubItemSetW (hList, item.iItem, 3, (wchar_t *) device.Name.c_str());
+#ifdef TCMOUNT
+ else
+ {
+ wstring favoriteLabel = GetFavoriteVolumeLabel (device.Path);
+ if (!favoriteLabel.empty())
+ ListSubItemSetW (hList, item.iItem, 3, (wchar_t *) favoriteLabel.c_str());
+ }
+#endif
+
+ item.iItem = line++;
+ }
+
+ lpszFileName = (char *) lParam;
+
+#ifdef VOLFORMAT
+ EnableWindow (GetDlgItem (hwndDlg, IDOK), FALSE);
+#endif
+ return 1;
+ }
+
+ case WM_COMMAND:
+ case WM_NOTIFY:
+ // catch non-device line selected
+ if (msg == WM_NOTIFY && ((LPNMHDR) lParam)->code == LVN_ITEMCHANGED && (((LPNMLISTVIEW) lParam)->uNewState & LVIS_FOCUSED ))
+ {
+ LVITEM LvItem;
+ memset(&LvItem,0,sizeof(LvItem));
+ LvItem.mask = LVIF_TEXT | LVIF_PARAM;
+ LvItem.iItem = ((LPNMLISTVIEW) lParam)->iItem;
+ LvItem.pszText = lpszFileName;
+ LvItem.cchTextMax = TC_MAX_PATH;
+
+ SendMessage (GetDlgItem (hwndDlg, IDC_DEVICELIST), LVM_GETITEM, LvItem.iItem, (LPARAM) &LvItem);
+ EnableWindow (GetDlgItem ((HWND) hwndDlg, IDOK), lpszFileName[0] != 0 && lpszFileName[0] != ' ');
+
+ return 1;
+ }
+
+ if (msg == WM_COMMAND && lw == IDOK || msg == WM_NOTIFY && ((NMHDR *)lParam)->code == LVN_ITEMACTIVATE)
+ {
+ int selectedItem = ListView_GetSelectionMark (GetDlgItem (hwndDlg, IDC_DEVICELIST));
+
+ if (selectedItem == -1 || itemToDeviceMap.find (selectedItem) == itemToDeviceMap.end())
+ return 1; // non-device line selected
+
+ const HostDevice selectedDevice = itemToDeviceMap[selectedItem];
+ strcpy_s (lpszFileName, TC_MAX_PATH, selectedDevice.Path.c_str());
+
+#ifdef VOLFORMAT
+ if (selectedDevice.ContainsSystem && selectedDevice.IsPartition)
+ {
+ if (WizardMode != WIZARD_MODE_SYS_DEVICE)
+ {
+ if (AskYesNo ("CONFIRM_SYSTEM_ENCRYPTION_MODE") == IDNO)
+ {
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+
+ bSysPartitionSelected = TRUE;
+ bSysDriveSelected = FALSE;
+ lpszFileName[0] = 0;
+ SwitchWizardToSysEncMode ();
+
+ NormalCursor ();
+ EndDialog (hwndDlg, IDOK);
+ return 1;
+ }
+ else
+ {
+ // This should never be the case because the Select Device dialog is not available in this wizard mode
+ bSysPartitionSelected = TRUE;
+ bSysDriveSelected = FALSE;
+ lpszFileName[0] = 0;
+ SwitchWizardToSysEncMode ();
+ NormalCursor ();
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+ }
+
+ if (!(selectedDevice.ContainsSystem && !selectedDevice.IsPartition))
+ {
+ if (bWarnDeviceFormatAdvanced
+ && !bHiddenVolDirect
+ && AskWarnNoYes("FORMAT_DEVICE_FOR_ADVANCED_ONLY") == IDNO)
+ {
+ if (AskNoYes("CONFIRM_CHANGE_WIZARD_MODE_TO_FILE_CONTAINER") == IDYES)
+ {
+ SwitchWizardToFileContainerMode ();
+ }
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+
+ if (!bHiddenVolDirect)
+ bWarnDeviceFormatAdvanced = FALSE;
+ }
+
+#else // #ifdef VOLFORMAT
+
+ bSysPartitionSelected = (selectedDevice.ContainsSystem && selectedDevice.IsPartition);
+ bSysDriveSelected = FALSE;
+
+#endif // #ifdef VOLFORMAT
+
+ if (!selectedDevice.IsPartition && !selectedDevice.Floppy)
+ {
+ // Whole device selected
+
+#ifdef VOLFORMAT
+ if (selectedDevice.ContainsSystem && !selectedDevice.IsPartition)
+ {
+ if (WizardMode != WIZARD_MODE_SYS_DEVICE)
+ {
+ if (AskYesNo ("CONFIRM_SYSTEM_ENCRYPTION_MODE") == IDNO)
+ {
+ NormalCursor ();
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+
+ bSysDriveSelected = TRUE;
+ bSysPartitionSelected = FALSE;
+ lpszFileName[0] = 0;
+ SwitchWizardToSysEncMode ();
+
+ NormalCursor ();
+ EndDialog (hwndDlg, IDOK);
+ return 1;
+ }
+ else
+ {
+ // This should never be the case because the Select Device dialog is not available in this wizard mode
+ bSysDriveSelected = TRUE;
+ bSysPartitionSelected = FALSE;
+ lpszFileName[0] = 0;
+ SwitchWizardToSysEncMode ();
+ NormalCursor ();
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+ }
+
+ // Disallow format if the device contains partitions, but not if the partition is virtual or system
+ if (!selectedDevice.IsVirtualPartition
+ && !bHiddenVolDirect)
+ {
+ if (!selectedDevice.Partitions.empty())
+ {
+ EnableWindow (GetDlgItem (hwndDlg, IDOK), FALSE);
+ Error ("DEVICE_PARTITIONS_ERR_W_INPLACE_ENC_NOTE");
+ return 1;
+ }
+
+ if (AskWarnNoYes ("WHOLE_NONSYS_DEVICE_ENC_CONFIRM") == IDNO)
+ return 1;
+ }
+#else // #ifdef VOLFORMAT
+
+ bSysDriveSelected = (selectedDevice.ContainsSystem && !selectedDevice.IsPartition);
+ bSysPartitionSelected = FALSE;
+
+#endif // #ifdef VOLFORMAT
+ }
+ else
+ bSysDriveSelected = FALSE;
+
+#ifdef VOLFORMAT
+ bRemovableHostDevice = selectedDevice.Removable;
+#endif
+ NormalCursor ();
+ EndDialog (hwndDlg, IDOK);
+ return 1;
+ }
+
+ if (lw == IDCANCEL)
+ {
+ NormalCursor ();
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+
+BOOL DoDriverInstall (HWND hwndDlg)
+{
+#ifdef SETUP
+ if (SystemEncryptionUpdate)
+ return TRUE;
+#endif
+
+ SC_HANDLE hManager, hService = NULL;
+ BOOL bOK = FALSE, bRet;
+
+ hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (hManager == NULL)
+ goto error;
+
+#ifdef SETUP
+ StatusMessage (hwndDlg, "INSTALLING_DRIVER");
+#endif
+
+ hService = CreateService (hManager, "truecrypt", "truecrypt",
+ SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_SYSTEM_START, SERVICE_ERROR_NORMAL,
+ "System32\\drivers\\truecrypt.sys",
+ NULL, NULL, NULL, NULL, NULL);
+
+ if (hService == NULL)
+ goto error;
+ else
+ CloseServiceHandle (hService);
+
+ hService = OpenService (hManager, "truecrypt", SERVICE_ALL_ACCESS);
+ if (hService == NULL)
+ goto error;
+
+#ifdef SETUP
+ StatusMessage (hwndDlg, "STARTING_DRIVER");
+#endif
+
+ bRet = StartService (hService, 0, NULL);
+ if (bRet == FALSE)
+ goto error;
+
+ bOK = TRUE;
+
+error:
+ if (bOK == FALSE && GetLastError () != ERROR_SERVICE_ALREADY_RUNNING)
+ {
+ handleWin32Error (hwndDlg);
+ MessageBoxW (hwndDlg, GetString ("DRIVER_INSTALL_FAILED"), lpszTitle, MB_ICONHAND);
+ }
+ else
+ bOK = TRUE;
+
+ if (hService != NULL)
+ CloseServiceHandle (hService);
+
+ if (hManager != NULL)
+ CloseServiceHandle (hManager);
+
+ return bOK;
+}
+
+
+// Install and start driver service and mark it for removal (non-install mode)
+static int DriverLoad ()
+{
+ HANDLE file;
+ WIN32_FIND_DATA find;
+ SC_HANDLE hManager, hService = NULL;
+ char driverPath[TC_MAX_PATH*2];
+ BOOL res;
+ char *tmp;
+ DWORD startType;
+
+ if (ReadLocalMachineRegistryDword ("SYSTEM\\CurrentControlSet\\Services\\truecrypt", "Start", &startType) && startType == SERVICE_BOOT_START)
+ return ERR_PARAMETER_INCORRECT;
+
+ GetModuleFileName (NULL, driverPath, sizeof (driverPath));
+ tmp = strrchr (driverPath, '\\');
+ if (!tmp)
+ {
+ strcpy (driverPath, ".");
+ tmp = driverPath + 1;
+ }
+
+ strcpy (tmp, !Is64BitOs () ? "\\truecrypt.sys" : "\\truecrypt-x64.sys");
+
+ file = FindFirstFile (driverPath, &find);
+
+ if (file == INVALID_HANDLE_VALUE)
+ {
+ MessageBoxW (0, GetString ("DRIVER_NOT_FOUND"), lpszTitle, ICON_HAND);
+ return ERR_DONT_REPORT;
+ }
+
+ FindClose (file);
+
+ hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (hManager == NULL)
+ {
+ if (GetLastError () == ERROR_ACCESS_DENIED)
+ {
+ MessageBoxW (0, GetString ("ADMIN_PRIVILEGES_DRIVER"), lpszTitle, ICON_HAND);
+ return ERR_DONT_REPORT;
+ }
+
+ return ERR_OS_ERROR;
+ }
+
+ hService = OpenService (hManager, "truecrypt", SERVICE_ALL_ACCESS);
+ if (hService != NULL)
+ {
+ // Remove stale service (driver is not loaded but service exists)
+ DeleteService (hService);
+ CloseServiceHandle (hService);
+ Sleep (500);
+ }
+
+ hService = CreateService (hManager, "truecrypt", "truecrypt",
+ SERVICE_ALL_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
+ driverPath, NULL, NULL, NULL, NULL, NULL);
+
+ if (hService == NULL)
+ {
+ CloseServiceHandle (hManager);
+ return ERR_OS_ERROR;
+ }
+
+ res = StartService (hService, 0, NULL);
+ DeleteService (hService);
+
+ CloseServiceHandle (hManager);
+ CloseServiceHandle (hService);
+
+ return !res ? ERR_OS_ERROR : ERROR_SUCCESS;
+}
+
+
+BOOL DriverUnload ()
+{
+ MOUNT_LIST_STRUCT driver;
+ int refCount;
+ int volumesMounted;
+ DWORD dwResult;
+ BOOL bResult;
+
+ SC_HANDLE hManager, hService = NULL;
+ BOOL bRet;
+ SERVICE_STATUS status;
+ int x;
+ BOOL driverUnloaded = FALSE;
+
+ if (hDriver == INVALID_HANDLE_VALUE)
+ return TRUE;
+
+ try
+ {
+ if (BootEncryption (NULL).GetStatus().DeviceFilterActive)
+ return FALSE;
+ }
+ catch (...) { }
+
+ // Test for mounted volumes
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_IS_ANY_VOLUME_MOUNTED, NULL, 0, &volumesMounted, sizeof (volumesMounted), &dwResult, NULL);
+
+ if (!bResult)
+ {
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_LEGACY_GET_MOUNTED_VOLUMES, NULL, 0, &driver, sizeof (driver), &dwResult, NULL);
+ if (bResult)
+ volumesMounted = driver.ulMountedDrives;
+ }
+
+ if (bResult)
+ {
+ if (volumesMounted != 0)
+ return FALSE;
+ }
+ else
+ return TRUE;
+
+ // Test for any applications attached to driver
+ refCount = GetDriverRefCount ();
+
+ if (refCount > 1)
+ return FALSE;
+
+ CloseHandle (hDriver);
+ hDriver = INVALID_HANDLE_VALUE;
+
+ // Stop driver service
+
+ hManager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);
+ if (hManager == NULL)
+ goto error;
+
+ hService = OpenService (hManager, "truecrypt", SERVICE_ALL_ACCESS);
+ if (hService == NULL)
+ goto error;
+
+ bRet = QueryServiceStatus (hService, &status);
+ if (bRet != TRUE)
+ goto error;
+
+ if (status.dwCurrentState != SERVICE_STOPPED)
+ {
+ ControlService (hService, SERVICE_CONTROL_STOP, &status);
+
+ for (x = 0; x < 10; x++)
+ {
+ bRet = QueryServiceStatus (hService, &status);
+ if (bRet != TRUE)
+ goto error;
+
+ if (status.dwCurrentState == SERVICE_STOPPED)
+ {
+ driverUnloaded = TRUE;
+ break;
+ }
+
+ Sleep (200);
+ }
+ }
+ else
+ driverUnloaded = TRUE;
+
+error:
+ if (hService != NULL)
+ CloseServiceHandle (hService);
+
+ if (hManager != NULL)
+ CloseServiceHandle (hManager);
+
+ if (driverUnloaded)
+ {
+ hDriver = INVALID_HANDLE_VALUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+int DriverAttach (void)
+{
+ /* Try to open a handle to the device driver. It will be closed later. */
+
+#ifndef SETUP
+
+ int nLoadRetryCount = 0;
+start:
+
+#endif
+
+ hDriver = CreateFile (WIN32_ROOT_PREFIX, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (hDriver == INVALID_HANDLE_VALUE)
+ {
+#ifndef SETUP
+
+ LoadSysEncSettings (NULL);
+
+ if (!CreateDriverSetupMutex ())
+ {
+ // Another instance is already attempting to install, register or start the driver
+
+ while (!CreateDriverSetupMutex ())
+ {
+ Sleep (100); // Wait until the other instance finishes
+ }
+
+ // Try to open a handle to the driver again (keep the mutex in case the other instance failed)
+ goto start;
+ }
+ else
+ {
+ // No other instance is currently attempting to install, register or start the driver
+
+ if (SystemEncryptionStatus != SYSENC_STATUS_NONE)
+ {
+ // This is an inconsistent state. The config file indicates system encryption should be
+ // active, but the driver is not running. This may happen e.g. when the pretest fails and
+ // the user selects "Last Known Good Configuration" from the Windows boot menu.
+ // To fix this, we're going to reinstall the driver, start it, and register it for boot.
+
+ if (DoDriverInstall (NULL))
+ {
+ Sleep (1000);
+ hDriver = CreateFile (WIN32_ROOT_PREFIX, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ try
+ {
+ BootEncryption bootEnc (NULL);
+ bootEnc.RegisterBootDriver (bootEnc.GetHiddenOSCreationPhase() != TC_HIDDEN_OS_CREATION_PHASE_NONE ? true : false);
+ }
+ catch (Exception &e)
+ {
+ e.Show (NULL);
+ }
+ }
+
+ CloseDriverSetupMutex ();
+ }
+ else
+ {
+ // Attempt to load the driver (non-install/portable mode)
+load:
+ BOOL res = DriverLoad ();
+
+ CloseDriverSetupMutex ();
+
+ if (res != ERROR_SUCCESS)
+ return res;
+
+ bPortableModeConfirmed = TRUE;
+
+ hDriver = CreateFile (WIN32_ROOT_PREFIX, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ }
+
+ if (bPortableModeConfirmed)
+ NotifyDriverOfPortableMode ();
+ }
+
+#endif // #ifndef SETUP
+
+ if (hDriver == INVALID_HANDLE_VALUE)
+ return ERR_OS_ERROR;
+ }
+
+ CloseDriverSetupMutex ();
+
+ if (hDriver != INVALID_HANDLE_VALUE)
+ {
+ DWORD dwResult;
+
+ BOOL bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_DRIVER_VERSION, NULL, 0, &DriverVersion, sizeof (DriverVersion), &dwResult, NULL);
+
+ if (!bResult)
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_LEGACY_GET_DRIVER_VERSION, NULL, 0, &DriverVersion, sizeof (DriverVersion), &dwResult, NULL);
+
+#ifndef SETUP // Don't check version during setup to allow removal of another version
+ if (bResult == FALSE)
+ {
+ return ERR_OS_ERROR;
+ }
+ else if (DriverVersion != VERSION_NUM)
+ {
+ // Unload an incompatbile version of the driver loaded in non-install mode and load the required version
+ if (IsNonInstallMode () && CreateDriverSetupMutex () && DriverUnload () && nLoadRetryCount++ < 3)
+ goto load;
+
+ CloseDriverSetupMutex ();
+ CloseHandle (hDriver);
+ hDriver = INVALID_HANDLE_VALUE;
+ return ERR_DRIVER_VERSION;
+ }
+#else
+ if (!bResult)
+ DriverVersion = 0;
+#endif
+ }
+
+ return 0;
+}
+
+
+void ResetCurrentDirectory ()
+{
+ char p[MAX_PATH];
+ if (!IsNonInstallMode () && SHGetFolderPath (NULL, CSIDL_PROFILE, NULL, 0, p) == ERROR_SUCCESS)
+ {
+ SetCurrentDirectory (p);
+ }
+ else
+ {
+ GetModPath (p, sizeof (p));
+ SetCurrentDirectory (p);
+ }
+}
+
+
+BOOL BrowseFiles (HWND hwndDlg, char *stringId, char *lpszFileName, BOOL keepHistory, BOOL saveMode, wchar_t *browseFilter)
+{
+ return BrowseFilesInDir (hwndDlg, stringId, NULL, lpszFileName, keepHistory, saveMode, browseFilter);
+}
+
+
+BOOL BrowseFilesInDir (HWND hwndDlg, char *stringId, char *initialDir, char *lpszFileName, BOOL keepHistory, BOOL saveMode, wchar_t *browseFilter, const wchar_t *initialFileName, const wchar_t *defaultExtension)
+{
+ OPENFILENAMEW ofn;
+ wchar_t file[TC_MAX_PATH] = { 0 };
+ wchar_t wInitialDir[TC_MAX_PATH] = { 0 };
+ wchar_t filter[1024];
+ BOOL status = FALSE;
+
+ CoInitialize (NULL);
+
+ ZeroMemory (&ofn, sizeof (ofn));
+ *lpszFileName = 0;
+
+ if (initialDir)
+ {
+ swprintf_s (wInitialDir, sizeof (wInitialDir) / 2, L"%hs", initialDir);
+ ofn.lpstrInitialDir = wInitialDir;
+ }
+
+ if (initialFileName)
+ wcscpy_s (file, array_capacity (file), initialFileName);
+
+ ofn.lStructSize = sizeof (ofn);
+ ofn.hwndOwner = hwndDlg;
+
+ wsprintfW (filter, L"%ls (*.*)%c*.*%c%ls (*.tc)%c*.tc%c%c",
+ GetString ("ALL_FILES"), 0, 0, GetString ("TC_VOLUMES"), 0, 0, 0);
+ ofn.lpstrFilter = browseFilter ? browseFilter : filter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = file;
+ ofn.nMaxFile = sizeof (file) / sizeof (file[0]);
+ ofn.lpstrTitle = GetString (stringId);
+ ofn.lpstrDefExt = defaultExtension;
+ ofn.Flags = OFN_HIDEREADONLY
+ | OFN_PATHMUSTEXIST
+ | (keepHistory ? 0 : OFN_DONTADDTORECENT)
+ | (saveMode ? OFN_OVERWRITEPROMPT : 0);
+
+ if (!keepHistory)
+ CleanLastVisitedMRU ();
+
+ SystemFileSelectorCallerThreadId = GetCurrentThreadId();
+ SystemFileSelectorCallPending = TRUE;
+
+ if (!saveMode)
+ {
+ if (!GetOpenFileNameW (&ofn))
+ goto ret;
+ }
+ else
+ {
+ if (!GetSaveFileNameW (&ofn))
+ goto ret;
+ }
+
+ SystemFileSelectorCallPending = FALSE;
+
+ WideCharToMultiByte (CP_ACP, 0, file, -1, lpszFileName, MAX_PATH, NULL, NULL);
+
+ if (!keepHistory)
+ CleanLastVisitedMRU ();
+
+ status = TRUE;
+
+ret:
+ SystemFileSelectorCallPending = FALSE;
+ ResetCurrentDirectory();
+ CoUninitialize();
+
+ return status;
+}
+
+
+static char SelectMultipleFilesPath[131072];
+static int SelectMultipleFilesOffset;
+
+BOOL SelectMultipleFiles (HWND hwndDlg, char *stringId, char *lpszFileName, BOOL keepHistory)
+{
+ OPENFILENAMEW ofn;
+ wchar_t file[0xffff * 2] = { 0 }; // The size must not exceed 0xffff*2 due to a bug in Windows 2000 and XP SP1
+ wchar_t filter[1024];
+ BOOL status = FALSE;
+
+ CoInitialize (NULL);
+
+ ZeroMemory (&ofn, sizeof (ofn));
+
+ *lpszFileName = 0;
+ ofn.lStructSize = sizeof (ofn);
+ ofn.hwndOwner = hwndDlg;
+ wsprintfW (filter, L"%ls (*.*)%c*.*%c%ls (*.tc)%c*.tc%c%c",
+ GetString ("ALL_FILES"), 0, 0, GetString ("TC_VOLUMES"), 0, 0, 0);
+ ofn.lpstrFilter = filter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = file;
+ ofn.nMaxFile = sizeof (file) / sizeof (file[0]);
+ ofn.lpstrTitle = GetString (stringId);
+ ofn.Flags = OFN_HIDEREADONLY
+ | OFN_EXPLORER
+ | OFN_PATHMUSTEXIST
+ | OFN_ALLOWMULTISELECT
+ | (keepHistory ? 0 : OFN_DONTADDTORECENT);
+
+ if (!keepHistory)
+ CleanLastVisitedMRU ();
+
+ SystemFileSelectorCallerThreadId = GetCurrentThreadId();
+ SystemFileSelectorCallPending = TRUE;
+
+ if (!GetOpenFileNameW (&ofn))
+ goto ret;
+
+ SystemFileSelectorCallPending = FALSE;
+
+ if (file[ofn.nFileOffset - 1] != 0)
+ {
+ // Single file selected
+ WideCharToMultiByte (CP_ACP, 0, file, -1, lpszFileName, MAX_PATH, NULL, NULL);
+ SelectMultipleFilesOffset = 0;
+ }
+ else
+ {
+ // Multiple files selected
+ int n;
+ wchar_t *f = file;
+ char *s = SelectMultipleFilesPath;
+ while ((n = WideCharToMultiByte (CP_ACP, 0, f, -1, s, MAX_PATH, NULL, NULL)) > 1)
+ {
+ f += n;
+ s += n;
+ }
+
+ SelectMultipleFilesOffset = ofn.nFileOffset;
+ SelectMultipleFilesNext (lpszFileName);
+ }
+
+ if (!keepHistory)
+ CleanLastVisitedMRU ();
+
+ status = TRUE;
+
+ret:
+ SystemFileSelectorCallPending = FALSE;
+ ResetCurrentDirectory();
+ CoUninitialize();
+
+ return status;
+}
+
+
+BOOL SelectMultipleFilesNext (char *lpszFileName)
+{
+ if (SelectMultipleFilesOffset == 0)
+ return FALSE;
+
+ strncpy (lpszFileName, SelectMultipleFilesPath, TC_MAX_PATH);
+ lpszFileName[TC_MAX_PATH - 1] = 0;
+
+ if (lpszFileName[strlen (lpszFileName) - 1] != '\\')
+ strcat (lpszFileName, "\\");
+
+ strcat (lpszFileName, SelectMultipleFilesPath + SelectMultipleFilesOffset);
+
+ SelectMultipleFilesOffset += strlen (SelectMultipleFilesPath + SelectMultipleFilesOffset) + 1;
+ if (SelectMultipleFilesPath[SelectMultipleFilesOffset] == 0)
+ SelectMultipleFilesOffset = 0;
+
+ return TRUE;
+}
+
+
+static int CALLBACK BrowseCallbackProc(HWND hwnd,UINT uMsg,LPARAM lp, LPARAM pData)
+{
+ switch(uMsg) {
+ case BFFM_INITIALIZED:
+ {
+ /* WParam is TRUE since we are passing a path.
+ It would be FALSE if we were passing a pidl. */
+ SendMessage (hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)pData);
+ break;
+ }
+
+ case BFFM_SELCHANGED:
+ {
+ char szDir[TC_MAX_PATH];
+
+ /* Set the status window to the currently selected path. */
+ if (SHGetPathFromIDList((LPITEMIDLIST) lp ,szDir))
+ {
+ SendMessage (hwnd,BFFM_SETSTATUSTEXT,0,(LPARAM)szDir);
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+BOOL BrowseDirectories (HWND hwndDlg, char *lpszTitle, char *dirName)
+{
+ BROWSEINFOW bi;
+ LPITEMIDLIST pidl;
+ LPMALLOC pMalloc;
+ BOOL bOK = FALSE;
+
+ CoInitialize (NULL);
+
+ if (SUCCEEDED (SHGetMalloc (&pMalloc)))
+ {
+ ZeroMemory (&bi, sizeof(bi));
+ bi.hwndOwner = hwndDlg;
+ bi.pszDisplayName = 0;
+ bi.lpszTitle = GetString (lpszTitle);
+ bi.pidlRoot = 0;
+ bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT;
+ bi.lpfn = BrowseCallbackProc;
+ bi.lParam = (LPARAM)dirName;
+
+ pidl = SHBrowseForFolderW (&bi);
+ if (pidl != NULL)
+ {
+ if (SHGetPathFromIDList(pidl, dirName))
+ {
+ bOK = TRUE;
+ }
+
+ pMalloc->Free (pidl);
+ pMalloc->Release();
+ }
+ }
+
+ CoUninitialize();
+
+ return bOK;
+}
+
+
+std::wstring GetWrongPasswordErrorMessage (HWND hwndDlg)
+{
+ WCHAR szTmp[8192];
+
+ swprintf (szTmp, GetString (KeyFilesEnable ? "PASSWORD_OR_KEYFILE_WRONG" : "PASSWORD_WRONG"));
+ if (CheckCapsLock (hwndDlg, TRUE))
+ wcscat (szTmp, GetString ("PASSWORD_WRONG_CAPSLOCK_ON"));
+
+#ifdef TCMOUNT
+ if (TCBootLoaderOnInactiveSysEncDrive ())
+ {
+ swprintf (szTmp, GetString (KeyFilesEnable ? "PASSWORD_OR_KEYFILE_OR_MODE_WRONG" : "PASSWORD_OR_MODE_WRONG"));
+
+ if (CheckCapsLock (hwndDlg, TRUE))
+ wcscat (szTmp, GetString ("PASSWORD_WRONG_CAPSLOCK_ON"));
+
+ wcscat (szTmp, GetString ("SYSENC_MOUNT_WITHOUT_PBA_NOTE"));
+ }
+#endif
+
+ wstring msg = szTmp;
+
+#ifdef TCMOUNT
+ if (KeyFilesEnable && HiddenFilesPresentInKeyfilePath)
+ {
+ msg += GetString ("HIDDEN_FILES_PRESENT_IN_KEYFILE_PATH");
+ HiddenFilesPresentInKeyfilePath = FALSE;
+ }
+#endif
+
+ return msg;
+}
+
+
+void handleError (HWND hwndDlg, int code)
+{
+ WCHAR szTmp[4096];
+
+ if (Silent) return;
+
+ switch (code)
+ {
+ case ERR_OS_ERROR:
+ handleWin32Error (hwndDlg);
+ break;
+ case ERR_OUTOFMEMORY:
+ MessageBoxW (hwndDlg, GetString ("OUTOFMEMORY"), lpszTitle, ICON_HAND);
+ break;
+
+ case ERR_PASSWORD_WRONG:
+ MessageBoxW (hwndDlg, GetWrongPasswordErrorMessage (hwndDlg).c_str(), lpszTitle, MB_ICONWARNING);
+ break;
+
+ case ERR_DRIVE_NOT_FOUND:
+ MessageBoxW (hwndDlg, GetString ("NOT_FOUND"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_FILES_OPEN:
+ MessageBoxW (hwndDlg, GetString ("OPENFILES_DRIVER"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_FILES_OPEN_LOCK:
+ MessageBoxW (hwndDlg, GetString ("OPENFILES_LOCK"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_VOL_SIZE_WRONG:
+ MessageBoxW (hwndDlg, GetString ("VOL_SIZE_WRONG"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_COMPRESSION_NOT_SUPPORTED:
+ MessageBoxW (hwndDlg, GetString ("COMPRESSION_NOT_SUPPORTED"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_PASSWORD_CHANGE_VOL_TYPE:
+ MessageBoxW (hwndDlg, GetString ("WRONG_VOL_TYPE"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_VOL_SEEKING:
+ MessageBoxW (hwndDlg, GetString ("VOL_SEEKING"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_CIPHER_INIT_FAILURE:
+ MessageBoxW (hwndDlg, GetString ("ERR_CIPHER_INIT_FAILURE"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_CIPHER_INIT_WEAK_KEY:
+ MessageBoxW (hwndDlg, GetString ("ERR_CIPHER_INIT_WEAK_KEY"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_VOL_ALREADY_MOUNTED:
+ MessageBoxW (hwndDlg, GetString ("VOL_ALREADY_MOUNTED"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_FILE_OPEN_FAILED:
+ MessageBoxW (hwndDlg, GetString ("FILE_OPEN_FAILED"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_VOL_MOUNT_FAILED:
+ MessageBoxW (hwndDlg, GetString ("VOL_MOUNT_FAILED"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_NO_FREE_DRIVES:
+ MessageBoxW (hwndDlg, GetString ("NO_FREE_DRIVES"), lpszTitle, ICON_HAND);
+ break;
+ case ERR_ACCESS_DENIED:
+ MessageBoxW (hwndDlg, GetString ("ACCESS_DENIED"), lpszTitle, ICON_HAND);
+ break;
+
+ case ERR_DRIVER_VERSION:
+ Error ("DRIVER_VERSION");
+ break;
+
+ case ERR_NEW_VERSION_REQUIRED:
+ MessageBoxW (hwndDlg, GetString ("NEW_VERSION_REQUIRED"), lpszTitle, ICON_HAND);
+ break;
+
+ case ERR_SELF_TESTS_FAILED:
+ Error ("ERR_SELF_TESTS_FAILED");
+ break;
+
+ case ERR_VOL_FORMAT_BAD:
+ Error ("ERR_VOL_FORMAT_BAD");
+ break;
+
+ case ERR_ENCRYPTION_NOT_COMPLETED:
+ Error ("ERR_ENCRYPTION_NOT_COMPLETED");
+ break;
+
+ case ERR_NONSYS_INPLACE_ENC_INCOMPLETE:
+ Error ("ERR_NONSYS_INPLACE_ENC_INCOMPLETE");
+ break;
+
+ case ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG:
+ Error ("ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG");
+ break;
+
+ case ERR_PARAMETER_INCORRECT:
+ Error ("ERR_PARAMETER_INCORRECT");
+ break;
+
+ case ERR_USER_ABORT:
+ case ERR_DONT_REPORT:
+ // A non-error
+ break;
+
+ default:
+ wsprintfW (szTmp, GetString ("ERR_UNKNOWN"), code);
+ MessageBoxW (hwndDlg, szTmp, lpszTitle, ICON_HAND);
+ }
+}
+
+
+BOOL CheckFileStreamWriteErrors (FILE *file, const char *fileName)
+{
+ if (ferror (file))
+ {
+ wchar_t s[TC_MAX_PATH];
+ swprintf_s (s, ARRAYSIZE (s), GetString ("CANNOT_WRITE_FILE_X"), fileName);
+ ErrorDirect (s);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+static BOOL CALLBACK LocalizeDialogEnum( HWND hwnd, LPARAM font)
+{
+ // Localization of controls
+
+ if (LocalizationActive)
+ {
+ int ctrlId = GetDlgCtrlID (hwnd);
+ if (ctrlId != 0)
+ {
+ char name[10] = { 0 };
+ GetClassName (hwnd, name, sizeof (name));
+
+ if (_stricmp (name, "Button") == 0 || _stricmp (name, "Static") == 0)
+ {
+ wchar_t *str = (wchar_t *) GetDictionaryValueByInt (ctrlId);
+ if (str != NULL)
+ SetWindowTextW (hwnd, str);
+ }
+ }
+ }
+
+ // Font
+ SendMessage (hwnd, WM_SETFONT, (WPARAM) font, 0);
+
+ return TRUE;
+}
+
+void LocalizeDialog (HWND hwnd, char *stringId)
+{
+ LastDialogId = stringId;
+ SetWindowLongPtr (hwnd, GWLP_USERDATA, (LONG_PTR) 'TRUE');
+ SendMessage (hwnd, WM_SETFONT, (WPARAM) hUserFont, 0);
+
+ if (stringId == NULL)
+ SetWindowText (hwnd, "TrueCrypt");
+ else
+ SetWindowTextW (hwnd, GetString (stringId));
+
+ if (hUserFont != 0)
+ EnumChildWindows (hwnd, LocalizeDialogEnum, (LPARAM) hUserFont);
+}
+
+void OpenVolumeExplorerWindow (int driveNo)
+{
+ char dosName[5];
+ SHFILEINFO fInfo;
+
+ sprintf (dosName, "%c:\\", (char) driveNo + 'A');
+
+ // Force explorer to discover the drive
+ SHGetFileInfo (dosName, 0, &fInfo, sizeof (fInfo), 0);
+
+ ShellExecute (NULL, "open", dosName, NULL, NULL, SW_SHOWNORMAL);
+}
+
+static BOOL explorerCloseSent;
+static HWND explorerTopLevelWindow;
+
+static BOOL CALLBACK CloseVolumeExplorerWindowsChildEnum (HWND hwnd, LPARAM driveStr)
+{
+ char s[MAX_PATH];
+ SendMessage (hwnd, WM_GETTEXT, sizeof (s), (LPARAM) s);
+
+ if (strstr (s, (char *) driveStr) != NULL)
+ {
+ PostMessage (explorerTopLevelWindow, WM_CLOSE, 0, 0);
+ explorerCloseSent = TRUE;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static BOOL CALLBACK CloseVolumeExplorerWindowsEnum (HWND hwnd, LPARAM driveNo)
+{
+ char driveStr[10];
+ char s[MAX_PATH];
+
+ sprintf (driveStr, "%c:\\", driveNo + 'A');
+
+ GetClassName (hwnd, s, sizeof s);
+ if (strcmp (s, "CabinetWClass") == 0)
+ {
+ GetWindowText (hwnd, s, sizeof s);
+ if (strstr (s, driveStr) != NULL)
+ {
+ PostMessage (hwnd, WM_CLOSE, 0, 0);
+ explorerCloseSent = TRUE;
+ return TRUE;
+ }
+
+ explorerTopLevelWindow = hwnd;
+ EnumChildWindows (hwnd, CloseVolumeExplorerWindowsChildEnum, (LPARAM) driveStr);
+ }
+
+ return TRUE;
+}
+
+BOOL CloseVolumeExplorerWindows (HWND hwnd, int driveNo)
+{
+ if (driveNo >= 0)
+ {
+ explorerCloseSent = FALSE;
+ EnumWindows (CloseVolumeExplorerWindowsEnum, (LPARAM) driveNo);
+ }
+
+ return explorerCloseSent;
+}
+
+string GetUserFriendlyVersionString (int version)
+{
+ char szTmp [64];
+ sprintf (szTmp, "%x", version);
+
+ string versionString (szTmp);
+
+ versionString.insert (version > 0xfff ? 2 : 1,".");
+
+ if (versionString[versionString.length()-1] == '0')
+ versionString.erase (versionString.length()-1, 1);
+
+ return (versionString);
+}
+
+void GetSizeString (unsigned __int64 size, wchar_t *str)
+{
+ static wchar_t *b, *kb, *mb, *gb, *tb, *pb;
+ static int serNo;
+
+ if (b == NULL || serNo != LocalizationSerialNo)
+ {
+ serNo = LocalizationSerialNo;
+ kb = GetString ("KB");
+ mb = GetString ("MB");
+ gb = GetString ("GB");
+ tb = GetString ("TB");
+ pb = GetString ("PB");
+ b = GetString ("BYTE");
+ }
+
+ if (size > 1024I64*1024*1024*1024*1024*99)
+ swprintf (str, L"%I64d %s", size/1024/1024/1024/1024/1024, pb);
+ else if (size > 1024I64*1024*1024*1024*1024)
+ swprintf (str, L"%.1f %s",(double)(size/1024.0/1024/1024/1024/1024), pb);
+ else if (size > 1024I64*1024*1024*1024*99)
+ swprintf (str, L"%I64d %s",size/1024/1024/1024/1024, tb);
+ else if (size > 1024I64*1024*1024*1024)
+ swprintf (str, L"%.1f %s",(double)(size/1024.0/1024/1024/1024), tb);
+ else if (size > 1024I64*1024*1024*99)
+ swprintf (str, L"%I64d %s",size/1024/1024/1024, gb);
+ else if (size > 1024I64*1024*1024)
+ swprintf (str, L"%.1f %s",(double)(size/1024.0/1024/1024), gb);
+ else if (size > 1024I64*1024*99)
+ swprintf (str, L"%I64d %s", size/1024/1024, mb);
+ else if (size > 1024I64*1024)
+ swprintf (str, L"%.1f %s",(double)(size/1024.0/1024), mb);
+ else if (size >= 1024I64)
+ swprintf (str, L"%I64d %s", size/1024, kb);
+ else
+ swprintf (str, L"%I64d %s", size, b);
+}
+
+#ifndef SETUP
+void GetSpeedString (unsigned __int64 speed, wchar_t *str)
+{
+ static wchar_t *b, *kb, *mb, *gb, *tb, *pb;
+ static int serNo;
+
+ if (b == NULL || serNo != LocalizationSerialNo)
+ {
+ serNo = LocalizationSerialNo;
+ kb = GetString ("KB_PER_SEC");
+ mb = GetString ("MB_PER_SEC");
+ gb = GetString ("GB_PER_SEC");
+ tb = GetString ("TB_PER_SEC");
+ pb = GetString ("PB_PER_SEC");
+ b = GetString ("B_PER_SEC");
+ }
+
+ if (speed > 1024I64*1024*1024*1024*1024*99)
+ swprintf (str, L"%I64d %s", speed/1024/1024/1024/1024/1024, pb);
+ else if (speed > 1024I64*1024*1024*1024*1024)
+ swprintf (str, L"%.1f %s",(double)(speed/1024.0/1024/1024/1024/1024), pb);
+ else if (speed > 1024I64*1024*1024*1024*99)
+ swprintf (str, L"%I64d %s",speed/1024/1024/1024/1024, tb);
+ else if (speed > 1024I64*1024*1024*1024)
+ swprintf (str, L"%.1f %s",(double)(speed/1024.0/1024/1024/1024), tb);
+ else if (speed > 1024I64*1024*1024*99)
+ swprintf (str, L"%I64d %s",speed/1024/1024/1024, gb);
+ else if (speed > 1024I64*1024*1024)
+ swprintf (str, L"%.1f %s",(double)(speed/1024.0/1024/1024), gb);
+ else if (speed > 1024I64*1024*99)
+ swprintf (str, L"%I64d %s", speed/1024/1024, mb);
+ else if (speed > 1024I64*1024)
+ swprintf (str, L"%.1f %s",(double)(speed/1024.0/1024), mb);
+ else if (speed > 1024I64)
+ swprintf (str, L"%I64d %s", speed/1024, kb);
+ else
+ swprintf (str, L"%I64d %s", speed, b);
+}
+
+static void DisplayBenchmarkResults (HWND hwndDlg)
+{
+ wchar_t item1[100]={0};
+ LVITEMW LvItem;
+ HWND hList = GetDlgItem (hwndDlg, IDC_RESULTS);
+ int ea, i;
+ BOOL unsorted = TRUE;
+ BENCHMARK_REC tmp_line;
+
+ /* Sort the list */
+
+ switch (benchmarkSortMethod)
+ {
+ case BENCHMARK_SORT_BY_SPEED:
+
+ while (unsorted)
+ {
+ unsorted = FALSE;
+ for (i = 0; i < benchmarkTotalItems - 1; i++)
+ {
+ if (benchmarkTable[i].meanBytesPerSec < benchmarkTable[i+1].meanBytesPerSec)
+ {
+ unsorted = TRUE;
+ memcpy (&tmp_line, &benchmarkTable[i], sizeof(BENCHMARK_REC));
+ memcpy (&benchmarkTable[i], &benchmarkTable[i+1], sizeof(BENCHMARK_REC));
+ memcpy (&benchmarkTable[i+1], &tmp_line, sizeof(BENCHMARK_REC));
+ }
+ }
+ }
+ break;
+
+ case BENCHMARK_SORT_BY_NAME:
+
+ while (unsorted)
+ {
+ unsorted = FALSE;
+ for (i = 0; i < benchmarkTotalItems - 1; i++)
+ {
+ if (benchmarkTable[i].id > benchmarkTable[i+1].id)
+ {
+ unsorted = TRUE;
+ memcpy (&tmp_line, &benchmarkTable[i], sizeof(BENCHMARK_REC));
+ memcpy (&benchmarkTable[i], &benchmarkTable[i+1], sizeof(BENCHMARK_REC));
+ memcpy (&benchmarkTable[i+1], &tmp_line, sizeof(BENCHMARK_REC));
+ }
+ }
+ }
+ break;
+ }
+
+ /* Render the results */
+
+ SendMessage (hList,LVM_DELETEALLITEMS,0,(LPARAM)&LvItem);
+
+ for (i = 0; i < benchmarkTotalItems; i++)
+ {
+ ea = benchmarkTable[i].id;
+
+ memset (&LvItem,0,sizeof(LvItem));
+ LvItem.mask = LVIF_TEXT;
+ LvItem.iItem = i;
+ LvItem.iSubItem = 0;
+ LvItem.pszText = (LPWSTR) benchmarkTable[i].name;
+ SendMessageW (hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
+
+#if PKCS5_BENCHMARKS
+ wcscpy (item1, L"-");
+#else
+ GetSpeedString ((unsigned __int64) (benchmarkLastBufferSize / ((float) benchmarkTable[i].encSpeed / benchmarkPerformanceFrequency.QuadPart)), item1);
+#endif
+ LvItem.iSubItem = 1;
+ LvItem.pszText = item1;
+
+ SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem);
+
+#if PKCS5_BENCHMARKS
+ wcscpy (item1, L"-");
+#else
+ GetSpeedString ((unsigned __int64) (benchmarkLastBufferSize / ((float) benchmarkTable[i].decSpeed / benchmarkPerformanceFrequency.QuadPart)), item1);
+#endif
+ LvItem.iSubItem = 2;
+ LvItem.pszText = item1;
+
+ SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem);
+
+#if PKCS5_BENCHMARKS
+ swprintf (item1, L"%d t", benchmarkTable[i].encSpeed);
+#else
+ GetSpeedString (benchmarkTable[i].meanBytesPerSec, item1);
+#endif
+ LvItem.iSubItem = 3;
+ LvItem.pszText = item1;
+
+ SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem);
+ }
+}
+
+static BOOL PerformBenchmark(HWND hwndDlg)
+{
+ LARGE_INTEGER performanceCountStart, performanceCountEnd;
+ BYTE *lpTestBuffer;
+ PCRYPTO_INFO ci = NULL;
+ UINT64_STRUCT startDataUnitNo;
+
+ startDataUnitNo.Value = 0;
+
+#if !(PKCS5_BENCHMARKS || HASH_FNC_BENCHMARKS)
+ ci = crypto_open ();
+ if (!ci)
+ return FALSE;
+#endif
+
+ if (QueryPerformanceFrequency (&benchmarkPerformanceFrequency) == 0)
+ {
+ MessageBoxW (hwndDlg, GetString ("ERR_PERF_COUNTER"), lpszTitle, ICON_HAND);
+ return FALSE;
+ }
+
+ lpTestBuffer = (BYTE *) malloc(benchmarkBufferSize - (benchmarkBufferSize % 16));
+ if (lpTestBuffer == NULL)
+ {
+ MessageBoxW (hwndDlg, GetString ("ERR_MEM_ALLOC"), lpszTitle, ICON_HAND);
+ return FALSE;
+ }
+ VirtualLock (lpTestBuffer, benchmarkBufferSize - (benchmarkBufferSize % 16));
+
+ WaitCursor ();
+ benchmarkTotalItems = 0;
+
+#if !(PKCS5_BENCHMARKS || HASH_FNC_BENCHMARKS)
+ // CPU "warm up" (an attempt to prevent skewed results on systems where CPU frequency
+ // gradually changes depending on CPU load).
+ ci->ea = EAGetFirst();
+ if (!EAInit (ci->ea, ci->master_keydata, ci->ks))
+ {
+ ci->mode = FIRST_MODE_OF_OPERATION_ID;
+ if (EAInitMode (ci))
+ {
+ int i;
+
+ for (i = 0; i < 10; i++)
+ {
+ EncryptDataUnits (lpTestBuffer, &startDataUnitNo, (TC_LARGEST_COMPILER_UINT) benchmarkBufferSize / ENCRYPTION_DATA_UNIT_SIZE, ci);
+ DecryptDataUnits (lpTestBuffer, &startDataUnitNo, (TC_LARGEST_COMPILER_UINT) benchmarkBufferSize / ENCRYPTION_DATA_UNIT_SIZE, ci);
+ }
+ }
+ }
+#endif
+
+#if HASH_FNC_BENCHMARKS
+
+ /* Measures the speed at which each of the hash algorithms processes the message to produce
+ a single digest.
+
+ The hash algorithm benchmarks are included here for development purposes only. Do not enable
+ them when building a public release (the benchmark GUI strings wouldn't make sense). */
+
+ {
+ BYTE *digest [MAX_DIGESTSIZE];
+ WHIRLPOOL_CTX wctx;
+ RMD160_CTX rctx;
+ sha1_ctx sctx;
+ sha512_ctx s2ctx;
+ int hid;
+
+ for (hid = FIRST_PRF_ID; hid <= LAST_PRF_ID; hid++)
+ {
+ if (QueryPerformanceCounter (&performanceCountStart) == 0)
+ goto counter_error;
+
+ switch (hid)
+ {
+ case SHA1:
+ sha1_begin (&sctx);
+ sha1_hash (lpTestBuffer, benchmarkBufferSize, &sctx);
+ sha1_end ((unsigned char *) digest, &sctx);
+ break;
+
+ case SHA512:
+ sha512_begin (&s2ctx);
+ sha512_hash (lpTestBuffer, benchmarkBufferSize, &s2ctx);
+ sha512_end ((unsigned char *) digest, &s2ctx);
+ break;
+
+ case RIPEMD160:
+ RMD160Init(&rctx);
+ RMD160Update(&rctx, lpTestBuffer, benchmarkBufferSize);
+ RMD160Final((unsigned char *) digest, &rctx);
+ break;
+
+ case WHIRLPOOL:
+ WHIRLPOOL_init (&wctx);
+ WHIRLPOOL_add (lpTestBuffer, benchmarkBufferSize * 8, &wctx);
+ WHIRLPOOL_finalize (&wctx, (unsigned char *) digest);
+ break;
+ }
+
+ if (QueryPerformanceCounter (&performanceCountEnd) == 0)
+ goto counter_error;
+
+ benchmarkTable[benchmarkTotalItems].encSpeed = performanceCountEnd.QuadPart - performanceCountStart.QuadPart;
+
+ benchmarkTable[benchmarkTotalItems].decSpeed = benchmarkTable[benchmarkTotalItems].encSpeed;
+ benchmarkTable[benchmarkTotalItems].id = hid;
+ benchmarkTable[benchmarkTotalItems].meanBytesPerSec = ((unsigned __int64) (benchmarkBufferSize / ((float) benchmarkTable[benchmarkTotalItems].encSpeed / benchmarkPerformanceFrequency.QuadPart)) + (unsigned __int64) (benchmarkBufferSize / ((float) benchmarkTable[benchmarkTotalItems].decSpeed / benchmarkPerformanceFrequency.QuadPart))) / 2;
+ sprintf (benchmarkTable[benchmarkTotalItems].name, "%s", HashGetName(hid));
+
+ benchmarkTotalItems++;
+ }
+ }
+
+#elif PKCS5_BENCHMARKS // #if HASH_FNC_BENCHMARKS
+
+ /* Measures the time that it takes for the PKCS-5 routine to derive a header key using
+ each of the implemented PRF algorithms.
+
+ The PKCS-5 benchmarks are included here for development purposes only. Do not enable
+ them when building a public release (the benchmark GUI strings wouldn't make sense). */
+ {
+ int thid, i;
+ char dk[MASTER_KEYDATA_SIZE];
+ char *tmp_salt = {"\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x01\x23\x45\x67\x89\xAB\xCD\xEF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF\x01\x23\x45\x67\x89\xAB\xCD\xEF\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xAA\xBB\xCC\xDD\xEE\xFF"};
+
+ for (thid = FIRST_PRF_ID; thid <= LAST_PRF_ID; thid++)
+ {
+ if (QueryPerformanceCounter (&performanceCountStart) == 0)
+ goto counter_error;
+
+ for (i = 1; i <= 5; i++)
+ {
+ switch (thid)
+ {
+ case SHA1:
+ /* PKCS-5 test with HMAC-SHA-1 used as the PRF */
+ derive_key_sha1 ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, FALSE), dk, MASTER_KEYDATA_SIZE);
+ break;
+
+ case SHA512:
+ /* PKCS-5 test with HMAC-SHA-512 used as the PRF */
+ derive_key_sha512 ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, FALSE), dk, MASTER_KEYDATA_SIZE);
+ break;
+
+ case RIPEMD160:
+ /* PKCS-5 test with HMAC-RIPEMD-160 used as the PRF */
+ derive_key_ripemd160 ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, FALSE), dk, MASTER_KEYDATA_SIZE);
+ break;
+
+ case WHIRLPOOL:
+ /* PKCS-5 test with HMAC-Whirlpool used as the PRF */
+ derive_key_whirlpool ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, FALSE), dk, MASTER_KEYDATA_SIZE);
+ break;
+ }
+ }
+
+ if (QueryPerformanceCounter (&performanceCountEnd) == 0)
+ goto counter_error;
+
+ benchmarkTable[benchmarkTotalItems].encSpeed = performanceCountEnd.QuadPart - performanceCountStart.QuadPart;
+ benchmarkTable[benchmarkTotalItems].id = thid;
+ sprintf (benchmarkTable[benchmarkTotalItems].name, "%s", get_pkcs5_prf_name (thid));
+
+ benchmarkTotalItems++;
+ }
+ }
+
+#else // #elif PKCS5_BENCHMARKS
+
+ /* Encryption algorithm benchmarks */
+
+ for (ci->ea = EAGetFirst(); ci->ea != 0; ci->ea = EAGetNext(ci->ea))
+ {
+ if (!EAIsFormatEnabled (ci->ea))
+ continue;
+
+ EAInit (ci->ea, ci->master_keydata, ci->ks);
+
+ ci->mode = FIRST_MODE_OF_OPERATION_ID;
+ EAInitMode (ci);
+
+ if (QueryPerformanceCounter (&performanceCountStart) == 0)
+ goto counter_error;
+
+ EncryptDataUnits (lpTestBuffer, &startDataUnitNo, (TC_LARGEST_COMPILER_UINT) benchmarkBufferSize / ENCRYPTION_DATA_UNIT_SIZE, ci);
+
+ if (QueryPerformanceCounter (&performanceCountEnd) == 0)
+ goto counter_error;
+
+ benchmarkTable[benchmarkTotalItems].encSpeed = performanceCountEnd.QuadPart - performanceCountStart.QuadPart;
+
+ if (QueryPerformanceCounter (&performanceCountStart) == 0)
+ goto counter_error;
+
+ DecryptDataUnits (lpTestBuffer, &startDataUnitNo, (TC_LARGEST_COMPILER_UINT) benchmarkBufferSize / ENCRYPTION_DATA_UNIT_SIZE, ci);
+
+ if (QueryPerformanceCounter (&performanceCountEnd) == 0)
+ goto counter_error;
+
+ benchmarkTable[benchmarkTotalItems].decSpeed = performanceCountEnd.QuadPart - performanceCountStart.QuadPart;
+ benchmarkTable[benchmarkTotalItems].id = ci->ea;
+ benchmarkTable[benchmarkTotalItems].meanBytesPerSec = ((unsigned __int64) (benchmarkBufferSize / ((float) benchmarkTable[benchmarkTotalItems].encSpeed / benchmarkPerformanceFrequency.QuadPart)) + (unsigned __int64) (benchmarkBufferSize / ((float) benchmarkTable[benchmarkTotalItems].decSpeed / benchmarkPerformanceFrequency.QuadPart))) / 2;
+ EAGetName (benchmarkTable[benchmarkTotalItems].name, ci->ea);
+
+ benchmarkTotalItems++;
+ }
+
+#endif // #elif PKCS5_BENCHMARKS (#else)
+
+ if (ci)
+ crypto_close (ci);
+
+ VirtualUnlock (lpTestBuffer, benchmarkBufferSize - (benchmarkBufferSize % 16));
+
+ free(lpTestBuffer);
+
+ benchmarkLastBufferSize = benchmarkBufferSize;
+
+ DisplayBenchmarkResults(hwndDlg);
+
+ EnableWindow (GetDlgItem (hwndDlg, IDC_PERFORM_BENCHMARK), TRUE);
+ EnableWindow (GetDlgItem (hwndDlg, IDCLOSE), TRUE);
+
+ NormalCursor ();
+ return TRUE;
+
+counter_error:
+
+ if (ci)
+ crypto_close (ci);
+
+ VirtualUnlock (lpTestBuffer, benchmarkBufferSize - (benchmarkBufferSize % 16));
+
+ free(lpTestBuffer);
+
+ NormalCursor ();
+
+ EnableWindow (GetDlgItem (hwndDlg, IDC_PERFORM_BENCHMARK), TRUE);
+ EnableWindow (GetDlgItem (hwndDlg, IDCLOSE), TRUE);
+
+ MessageBoxW (hwndDlg, GetString ("ERR_PERF_COUNTER"), lpszTitle, ICON_HAND);
+ return FALSE;
+}
+
+
+BOOL CALLBACK BenchmarkDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD lw = LOWORD (wParam);
+ LPARAM nIndex;
+ HWND hCboxSortMethod = GetDlgItem (hwndDlg, IDC_BENCHMARK_SORT_METHOD);
+ HWND hCboxBufferSize = GetDlgItem (hwndDlg, IDC_BENCHMARK_BUFFER_SIZE);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ LVCOLUMNW LvCol;
+ wchar_t s[128];
+ HWND hList = GetDlgItem (hwndDlg, IDC_RESULTS);
+
+ LocalizeDialog (hwndDlg, "IDD_BENCHMARK_DLG");
+
+ benchmarkBufferSize = BENCHMARK_DEFAULT_BUF_SIZE;
+ benchmarkSortMethod = BENCHMARK_SORT_BY_SPEED;
+
+ SendMessage (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0,
+ LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP|LVS_EX_LABELTIP
+ );
+
+ memset (&LvCol,0,sizeof(LvCol));
+ LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
+ LvCol.pszText = GetString ("ALGORITHM");
+ LvCol.cx = CompensateXDPI (114);
+ LvCol.fmt = LVCFMT_LEFT;
+ SendMessage (hList,LVM_INSERTCOLUMNW,0,(LPARAM)&LvCol);
+
+ LvCol.pszText = GetString ("ENCRYPTION");
+ LvCol.cx = CompensateXDPI (80);
+ LvCol.fmt = LVCFMT_RIGHT;
+ SendMessageW (hList,LVM_INSERTCOLUMNW,1,(LPARAM)&LvCol);
+
+ LvCol.pszText = GetString ("DECRYPTION");
+ LvCol.cx = CompensateXDPI (80);
+ LvCol.fmt = LVCFMT_RIGHT;
+ SendMessageW (hList,LVM_INSERTCOLUMNW,2,(LPARAM)&LvCol);
+
+ LvCol.pszText = GetString ("MEAN");
+ LvCol.cx = CompensateXDPI (80);
+ LvCol.fmt = LVCFMT_RIGHT;
+ SendMessageW (hList,LVM_INSERTCOLUMNW,3,(LPARAM)&LvCol);
+
+ /* Combo boxes */
+
+ // Sort method
+
+ SendMessage (hCboxSortMethod, CB_RESETCONTENT, 0, 0);
+
+ nIndex = SendMessageW (hCboxSortMethod, CB_ADDSTRING, 0, (LPARAM) GetString ("ALPHABETICAL_CATEGORIZED"));
+ SendMessage (hCboxSortMethod, CB_SETITEMDATA, nIndex, (LPARAM) 0);
+
+ nIndex = SendMessageW (hCboxSortMethod, CB_ADDSTRING, 0, (LPARAM) GetString ("MEAN_SPEED"));
+ SendMessage (hCboxSortMethod, CB_SETITEMDATA, nIndex, (LPARAM) 0);
+
+ SendMessage (hCboxSortMethod, CB_SETCURSEL, 1, 0); // Default sort method
+
+ // Buffer size
+
+ SendMessage (hCboxBufferSize, CB_RESETCONTENT, 0, 0);
+
+ swprintf (s, L"100 %s", GetString ("KB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 100 * BYTES_PER_KB);
+
+ swprintf (s, L"500 %s", GetString ("KB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 500 * BYTES_PER_KB);
+
+ swprintf (s, L"1 %s", GetString ("MB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 1 * BYTES_PER_MB);
+
+ swprintf (s, L"5 %s", GetString ("MB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 5 * BYTES_PER_MB);
+
+ swprintf (s, L"10 %s", GetString ("MB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 10 * BYTES_PER_MB);
+
+ swprintf (s, L"50 %s", GetString ("MB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 50 * BYTES_PER_MB);
+
+ swprintf (s, L"100 %s", GetString ("MB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 100 * BYTES_PER_MB);
+
+ swprintf (s, L"200 %s", GetString ("MB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 200 * BYTES_PER_MB);
+
+ swprintf (s, L"500 %s", GetString ("MB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 500 * BYTES_PER_MB);
+
+ swprintf (s, L"1 %s", GetString ("GB"));
+ nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s);
+ SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 1 * BYTES_PER_GB);
+
+ SendMessage (hCboxBufferSize, CB_SETCURSEL, 5, 0); // Default buffer size
+
+
+ uint32 driverConfig = ReadDriverConfigurationFlags();
+
+ SetDlgItemTextW (hwndDlg, IDC_HW_AES, (wstring (L" ") + (GetString (is_aes_hw_cpu_supported() ? ((driverConfig & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? "UISTR_DISABLED" : "UISTR_YES") : "NOT_APPLICABLE_OR_NOT_AVAILABLE"))).c_str());
+
+ ToHyperlink (hwndDlg, IDC_HW_AES_LABEL_LINK);
+
+ if (is_aes_hw_cpu_supported() && (driverConfig & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION))
+ {
+ Warning ("DISABLED_HW_AES_AFFECTS_PERFORMANCE");
+ }
+
+ SYSTEM_INFO sysInfo;
+ GetSystemInfo (&sysInfo);
+
+ size_t nbrThreads = GetEncryptionThreadCount();
+
+ wchar_t nbrThreadsStr [300];
+ if (sysInfo.dwNumberOfProcessors < 2)
+ {
+ wcscpy (nbrThreadsStr, GetString ("NOT_APPLICABLE_OR_NOT_AVAILABLE"));
+ }
+ else if (nbrThreads < 2)
+ {
+ wcscpy (nbrThreadsStr, GetString ("UISTR_DISABLED"));
+ }
+ else
+ {
+ wsprintfW (nbrThreadsStr, GetString ("NUMBER_OF_THREADS"), nbrThreads);
+ }
+
+ SetDlgItemTextW (hwndDlg, IDC_PARALLELIZATION, (wstring (L" ") + nbrThreadsStr).c_str());
+
+ ToHyperlink (hwndDlg, IDC_PARALLELIZATION_LABEL_LINK);
+
+ if (nbrThreads < min (sysInfo.dwNumberOfProcessors, GetMaxEncryptionThreadCount())
+ && sysInfo.dwNumberOfProcessors > 1)
+ {
+ Warning ("LIMITED_THREAD_COUNT_AFFECTS_PERFORMANCE");
+ }
+
+ return 1;
+ }
+ break;
+
+ case WM_COMMAND:
+ case WM_NOTIFY:
+
+ switch (lw)
+ {
+ case IDC_BENCHMARK_SORT_METHOD:
+
+ nIndex = SendMessage (hCboxSortMethod, CB_GETCURSEL, 0, 0);
+ if (nIndex != benchmarkSortMethod)
+ {
+ benchmarkSortMethod = nIndex;
+ DisplayBenchmarkResults (hwndDlg);
+ }
+ return 1;
+
+ case IDC_PERFORM_BENCHMARK:
+
+ nIndex = SendMessage (hCboxBufferSize, CB_GETCURSEL, 0, 0);
+ benchmarkBufferSize = SendMessage (hCboxBufferSize, CB_GETITEMDATA, nIndex, 0);
+
+ if (PerformBenchmark (hwndDlg) == FALSE)
+ {
+ EndDialog (hwndDlg, IDCLOSE);
+ }
+ return 1;
+
+ case IDC_HW_AES_LABEL_LINK:
+
+ Applink ("hwacceleration", TRUE, "");
+ return 1;
+
+ case IDC_PARALLELIZATION_LABEL_LINK:
+
+ Applink ("parallelization", TRUE, "");
+ return 1;
+
+ case IDCLOSE:
+ case IDCANCEL:
+
+ EndDialog (hwndDlg, IDCLOSE);
+ return 1;
+ }
+ return 0;
+
+ break;
+
+ case WM_CLOSE:
+ EndDialog (hwndDlg, IDCLOSE);
+ return 1;
+
+ break;
+
+ }
+ return 0;
+}
+
+
+static BOOL CALLBACK RandomPoolEnrichementDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD lw = LOWORD (wParam);
+ WORD hw = HIWORD (wParam);
+ static unsigned char randPool [RNG_POOL_SIZE];
+ static unsigned char lastRandPool [RNG_POOL_SIZE];
+ static char outputDispBuffer [RNG_POOL_SIZE * 3 + RANDPOOL_DISPLAY_ROWS + 2];
+ static BOOL bDisplayPoolContents = TRUE;
+ static BOOL bRandPoolDispAscii = FALSE;
+ int hash_algo = RandGetHashFunction();
+ int hid;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND hComboBox = GetDlgItem (hwndDlg, IDC_PRF_ID);
+
+ VirtualLock (randPool, sizeof(randPool));
+ VirtualLock (lastRandPool, sizeof(lastRandPool));
+ VirtualLock (outputDispBuffer, sizeof(outputDispBuffer));
+
+ LocalizeDialog (hwndDlg, "IDD_RANDOM_POOL_ENRICHMENT");
+
+ SendMessage (hComboBox, CB_RESETCONTENT, 0, 0);
+ for (hid = FIRST_PRF_ID; hid <= LAST_PRF_ID; hid++)
+ {
+ if (!HashIsDeprecated (hid))
+ AddComboPair (hComboBox, HashGetName(hid), hid);
+ }
+ SelectAlgo (hComboBox, &hash_algo);
+
+ SetCheckBox (hwndDlg, IDC_DISPLAY_POOL_CONTENTS, bDisplayPoolContents);
+
+ SetTimer (hwndDlg, 0xfd, RANDPOOL_DISPLAY_REFRESH_INTERVAL, NULL);
+ SendMessage (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), WM_SETFONT, (WPARAM) hFixedDigitFont, (LPARAM) TRUE);
+ return 1;
+ }
+
+ case WM_TIMER:
+ {
+ char tmp[4];
+ unsigned char tmpByte;
+ int col, row;
+
+ if (bDisplayPoolContents)
+ {
+ RandpeekBytes (randPool, sizeof (randPool));
+
+ if (memcmp (lastRandPool, randPool, sizeof(lastRandPool)) != 0)
+ {
+ outputDispBuffer[0] = 0;
+
+ for (row = 0; row < RANDPOOL_DISPLAY_ROWS; row++)
+ {
+ for (col = 0; col < RANDPOOL_DISPLAY_COLUMNS; col++)
+ {
+ tmpByte = randPool[row * RANDPOOL_DISPLAY_COLUMNS + col];
+
+ sprintf (tmp, bRandPoolDispAscii ? ((tmpByte >= 32 && tmpByte < 255 && tmpByte != '&') ? " %c " : " . ") : "%02X ", tmpByte);
+ strcat (outputDispBuffer, tmp);
+ }
+ strcat (outputDispBuffer, "\n");
+ }
+ SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), outputDispBuffer);
+
+ memcpy (lastRandPool, randPool, sizeof(lastRandPool));
+ }
+ }
+ return 1;
+ }
+
+ case WM_COMMAND:
+ if (lw == IDC_CONTINUE)
+ lw = IDOK;
+
+ if (lw == IDOK || lw == IDCLOSE || lw == IDCANCEL)
+ {
+ goto exit;
+ }
+
+ if (lw == IDC_PRF_ID && hw == CBN_SELCHANGE)
+ {
+ hid = (int) SendMessage (GetDlgItem (hwndDlg, IDC_PRF_ID), CB_GETCURSEL, 0, 0);
+ hash_algo = (int) SendMessage (GetDlgItem (hwndDlg, IDC_PRF_ID), CB_GETITEMDATA, hid, 0);
+ RandSetHashFunction (hash_algo);
+ return 1;
+ }
+
+ if (lw == IDC_DISPLAY_POOL_CONTENTS)
+ {
+ if (!(bDisplayPoolContents = GetCheckBox (hwndDlg, IDC_DISPLAY_POOL_CONTENTS)))
+ {
+ char tmp[RNG_POOL_SIZE+1];
+
+ memset (tmp, ' ', sizeof(tmp));
+ tmp [RNG_POOL_SIZE] = 0;
+ SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp);
+ }
+
+ return 1;
+ }
+
+ return 0;
+
+ case WM_CLOSE:
+ {
+ char tmp[RNG_POOL_SIZE+1];
+exit:
+ KillTimer (hwndDlg, 0xfd);
+
+ burn (randPool, sizeof(randPool));
+ burn (lastRandPool, sizeof(lastRandPool));
+ burn (outputDispBuffer, sizeof(outputDispBuffer));
+
+ // Attempt to wipe the pool contents in the GUI text area
+ memset (tmp, ' ', RNG_POOL_SIZE);
+ tmp [RNG_POOL_SIZE] = 0;
+ SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp);
+
+ if (msg == WM_COMMAND && lw == IDOK)
+ EndDialog (hwndDlg, IDOK);
+ else
+ EndDialog (hwndDlg, IDCLOSE);
+
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+void UserEnrichRandomPool (HWND hwndDlg)
+{
+ Randinit();
+
+ if (!IsRandomPoolEnrichedByUser())
+ {
+ INT_PTR result = DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_RANDOM_POOL_ENRICHMENT), hwndDlg ? hwndDlg : MainDlg, (DLGPROC) RandomPoolEnrichementDlgProc, (LPARAM) 0);
+ SetRandomPoolEnrichedByUserStatus (result == IDOK);
+ }
+}
+
+
+/* Except in response to the WM_INITDIALOG message, the dialog box procedure
+ should return nonzero if it processes the message, and zero if it does
+ not. - see DialogProc */
+BOOL CALLBACK KeyfileGeneratorDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD lw = LOWORD (wParam);
+ WORD hw = HIWORD (wParam);
+ static unsigned char randPool [RNG_POOL_SIZE];
+ static unsigned char lastRandPool [RNG_POOL_SIZE];
+ static char outputDispBuffer [RNG_POOL_SIZE * 3 + RANDPOOL_DISPLAY_ROWS + 2];
+ static BOOL bDisplayPoolContents = TRUE;
+ static BOOL bRandPoolDispAscii = FALSE;
+ int hash_algo = RandGetHashFunction();
+ int hid;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ HWND hComboBox = GetDlgItem (hwndDlg, IDC_PRF_ID);
+
+ VirtualLock (randPool, sizeof(randPool));
+ VirtualLock (lastRandPool, sizeof(lastRandPool));
+ VirtualLock (outputDispBuffer, sizeof(outputDispBuffer));
+
+ LocalizeDialog (hwndDlg, "IDD_KEYFILE_GENERATOR");
+
+ SendMessage (hComboBox, CB_RESETCONTENT, 0, 0);
+ for (hid = FIRST_PRF_ID; hid <= LAST_PRF_ID; hid++)
+ {
+ if (!HashIsDeprecated (hid))
+ AddComboPair (hComboBox, HashGetName(hid), hid);
+ }
+ SelectAlgo (hComboBox, &hash_algo);
+
+ SetCheckBox (hwndDlg, IDC_DISPLAY_POOL_CONTENTS, bDisplayPoolContents);
+
+#ifndef VOLFORMAT
+ if (Randinit ())
+ {
+ Error ("INIT_RAND");
+ EndDialog (hwndDlg, IDCLOSE);
+ }
+#endif
+ SetTimer (hwndDlg, 0xfd, RANDPOOL_DISPLAY_REFRESH_INTERVAL, NULL);
+ SendMessage (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), WM_SETFONT, (WPARAM) hFixedDigitFont, (LPARAM) TRUE);
+ return 1;
+ }
+
+ case WM_TIMER:
+ {
+ char tmp[4];
+ unsigned char tmpByte;
+ int col, row;
+
+ if (bDisplayPoolContents)
+ {
+ RandpeekBytes (randPool, sizeof (randPool));
+
+ if (memcmp (lastRandPool, randPool, sizeof(lastRandPool)) != 0)
+ {
+ outputDispBuffer[0] = 0;
+
+ for (row = 0; row < RANDPOOL_DISPLAY_ROWS; row++)
+ {
+ for (col = 0; col < RANDPOOL_DISPLAY_COLUMNS; col++)
+ {
+ tmpByte = randPool[row * RANDPOOL_DISPLAY_COLUMNS + col];
+
+ sprintf (tmp, bRandPoolDispAscii ? ((tmpByte >= 32 && tmpByte < 255 && tmpByte != '&') ? " %c " : " . ") : "%02X ", tmpByte);
+ strcat (outputDispBuffer, tmp);
+ }
+ strcat (outputDispBuffer, "\n");
+ }
+ SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), outputDispBuffer);
+
+ memcpy (lastRandPool, randPool, sizeof(lastRandPool));
+ }
+ }
+ return 1;
+ }
+
+ case WM_COMMAND:
+
+ if (lw == IDCLOSE || lw == IDCANCEL)
+ {
+ goto exit;
+ }
+
+ if (lw == IDC_PRF_ID && hw == CBN_SELCHANGE)
+ {
+ hid = (int) SendMessage (GetDlgItem (hwndDlg, IDC_PRF_ID), CB_GETCURSEL, 0, 0);
+ hash_algo = (int) SendMessage (GetDlgItem (hwndDlg, IDC_PRF_ID), CB_GETITEMDATA, hid, 0);
+ RandSetHashFunction (hash_algo);
+ return 1;
+ }
+
+ if (lw == IDC_DISPLAY_POOL_CONTENTS)
+ {
+ if (!(bDisplayPoolContents = GetCheckBox (hwndDlg, IDC_DISPLAY_POOL_CONTENTS)))
+ {
+ char tmp[RNG_POOL_SIZE+1];
+
+ memset (tmp, ' ', sizeof(tmp));
+ tmp [RNG_POOL_SIZE] = 0;
+ SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp);
+ }
+ return 1;
+ }
+
+ if (lw == IDC_GENERATE_AND_SAVE_KEYFILE)
+ {
+ char szFileName [TC_MAX_PATH];
+ unsigned char keyfile [MAX_PASSWORD];
+ int fhKeyfile = -1;
+
+ /* Select filename */
+ if (!BrowseFiles (hwndDlg, "OPEN_TITLE", szFileName, bHistory, TRUE, NULL))
+ return 1;
+
+ /* Conceive the file */
+ if ((fhKeyfile = _open(szFileName, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_BINARY, _S_IREAD|_S_IWRITE)) == -1)
+ {
+ handleWin32Error (hwndDlg);
+ return 1;
+ }
+
+ /* Generate the keyfile */
+ WaitCursor();
+ if (!RandgetBytes (keyfile, sizeof(keyfile), TRUE))
+ {
+ _close (fhKeyfile);
+ DeleteFile (szFileName);
+ NormalCursor();
+ return 1;
+ }
+ NormalCursor();
+
+ /* Write the keyfile */
+ if (_write (fhKeyfile, keyfile, sizeof(keyfile)) == -1)
+ handleWin32Error (hwndDlg);
+ else
+ Info("KEYFILE_CREATED");
+
+ burn (keyfile, sizeof(keyfile));
+ _close (fhKeyfile);
+ return 1;
+ }
+ return 0;
+
+ case WM_CLOSE:
+ {
+ char tmp[RNG_POOL_SIZE+1];
+exit:
+ WaitCursor();
+ KillTimer (hwndDlg, 0xfd);
+
+#ifndef VOLFORMAT
+ RandStop (FALSE);
+#endif
+ /* Cleanup */
+
+ burn (randPool, sizeof(randPool));
+ burn (lastRandPool, sizeof(lastRandPool));
+ burn (outputDispBuffer, sizeof(outputDispBuffer));
+
+ // Attempt to wipe the pool contents in the GUI text area
+ memset (tmp, ' ', RNG_POOL_SIZE);
+ tmp [RNG_POOL_SIZE] = 0;
+ SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp);
+
+ EndDialog (hwndDlg, IDCLOSE);
+ NormalCursor ();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+/* Except in response to the WM_INITDIALOG message, the dialog box procedure
+should return nonzero if it processes the message, and zero if it does
+not. - see DialogProc */
+BOOL CALLBACK
+CipherTestDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ static int idTestCipher = -1; /* Currently selected cipher for the test vector facility (none = -1). */
+ static BOOL bXTSTestEnabled = FALSE;
+
+ PCRYPTO_INFO ci;
+ WORD lw = LOWORD (wParam);
+ WORD hw = HIWORD (wParam);
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ int ea;
+ char buf[100];
+
+ LocalizeDialog (hwndDlg, "IDD_CIPHER_TEST_DLG");
+
+ SendMessage(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), WM_SETFONT, (WPARAM)hBoldFont, MAKELPARAM(TRUE,0));
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY), EM_LIMITTEXT, 128,0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
+ SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT), EM_LIMITTEXT,64,0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
+ SendMessage(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), EM_LIMITTEXT,64,0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
+ SendMessage(GetDlgItem(hwndDlg, IDC_SECONDARY_KEY), EM_LIMITTEXT, 128,0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_SECONDARY_KEY), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
+ SendMessage(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), EM_LIMITTEXT,32,0);
+ SendMessage(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), WM_SETFONT, (WPARAM)hFixedDigitFont, MAKELPARAM(1,0));
+ SetCheckBox (hwndDlg, IDC_XTS_MODE_ENABLED, bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_SECONDARY_KEY), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDT_SECONDARY_KEY), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_TEST_BLOCK_NUMBER), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDT_TEST_BLOCK_NUMBER), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDT_TEST_DATA_UNIT_NUMBER), bXTSTestEnabled);
+
+ if (idTestCipher == -1)
+ idTestCipher = (int) lParam;
+
+ SendMessage (GetDlgItem (hwndDlg, IDC_CIPHER), CB_RESETCONTENT, 0, 0);
+ for (ea = EAGetFirst (); ea != 0; ea = EAGetNext (ea))
+ {
+ if (EAGetCipherCount (ea) == 1 && EAIsFormatEnabled (ea))
+ AddComboPair (GetDlgItem (hwndDlg, IDC_CIPHER), EAGetName (buf, ea), EAGetFirstCipher (ea));
+ }
+
+ ResetCipherTest(hwndDlg, idTestCipher);
+
+ SelectAlgo (GetDlgItem (hwndDlg, IDC_CIPHER), &idTestCipher);
+
+ return 1;
+ }
+
+ case WM_COMMAND:
+
+ if (hw == CBN_SELCHANGE && lw == IDC_CIPHER)
+ {
+ idTestCipher = (int) SendMessage (GetDlgItem (hwndDlg, IDC_CIPHER), CB_GETITEMDATA, SendMessage (GetDlgItem (hwndDlg, IDC_CIPHER), CB_GETCURSEL, 0, 0), 0);
+ ResetCipherTest(hwndDlg, idTestCipher);
+ SendMessage (hwndDlg, WM_INITDIALOG, 0, 0);
+ return 1;
+ }
+
+ if (hw == CBN_SELCHANGE && lw == IDC_KEY_SIZE)
+ {
+ // NOP
+ return 1;
+ }
+
+ if (lw == IDC_RESET)
+ {
+ ResetCipherTest(hwndDlg, idTestCipher);
+
+ return 1;
+ }
+
+ if (lw == IDC_AUTO)
+ {
+ WaitCursor ();
+ if (!AutoTestAlgorithms())
+ {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), SW_SHOWNORMAL);
+ SetWindowTextW(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), GetString ("TESTS_FAILED"));
+ }
+ else
+ {
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), SW_SHOWNORMAL);
+ SetWindowTextW(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), GetString ("TESTS_PASSED"));
+ ShowWindow(GetDlgItem(hwndDlg, IDC_REDTICK), SW_SHOWNORMAL);
+ }
+ NormalCursor ();
+
+ return 1;
+
+ }
+
+ if (lw == IDC_XTS_MODE_ENABLED)
+ {
+ bXTSTestEnabled = GetCheckBox (hwndDlg, IDC_XTS_MODE_ENABLED);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_SECONDARY_KEY), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDT_SECONDARY_KEY), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_TEST_BLOCK_NUMBER), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDT_TEST_BLOCK_NUMBER), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDT_TEST_DATA_UNIT_NUMBER), bXTSTestEnabled);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), bXTSTestEnabled);
+ if (bXTSTestEnabled)
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETCURSEL, 0,0);
+ }
+
+ if (lw == IDOK || lw == IDC_ENCRYPT || lw == IDC_DECRYPT)
+ {
+ char key[128+1], inputtext[128+1], secondaryKey[64+1], dataUnitNo[16+1], szTmp[128+1];
+ int ks, pt, n, tlen, blockNo = 0;
+ BOOL bEncrypt;
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_REDTICK), SW_HIDE);
+
+ ks = (int) SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_GETCURSEL, 0,0);
+ ks = (int) SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_GETITEMDATA, ks,0);
+ pt = (int) SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_GETITEMDATA, 0,0);
+
+ bEncrypt = lw == IDC_ENCRYPT;
+
+ memset(key,0,sizeof(key));
+ memset(szTmp,0,sizeof(szTmp));
+ n = GetWindowText(GetDlgItem(hwndDlg, IDC_KEY), szTmp, sizeof(szTmp));
+ if (n != ks * 2)
+ {
+ Warning ("TEST_KEY_SIZE");
+ return 1;
+ }
+
+ for (n = 0; n < ks; n ++)
+ {
+ char szTmp2[3], *ptr;
+ long x;
+
+ szTmp2[2] = 0;
+ szTmp2[0] = szTmp[n * 2];
+ szTmp2[1] = szTmp[n * 2 + 1];
+
+ x = strtol(szTmp2, &ptr, 16);
+
+ key[n] = (char) x;
+ }
+
+ memset(inputtext, 0, sizeof(inputtext));
+ memset(secondaryKey, 0, sizeof(secondaryKey));
+ memset(dataUnitNo, 0, sizeof(dataUnitNo));
+ memset(szTmp, 0, sizeof(szTmp));
+
+ if (bEncrypt)
+ {
+ n = GetWindowText(GetDlgItem(hwndDlg, IDC_PLAINTEXT), szTmp, sizeof(szTmp));
+ }
+ else
+ {
+ n = GetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), szTmp, sizeof(szTmp));
+ }
+
+ if (n != pt * 2)
+ {
+ if (bEncrypt)
+ {
+ Warning ("TEST_PLAINTEXT_SIZE");
+ return 1;
+ }
+ else
+ {
+ Warning ("TEST_CIPHERTEXT_SIZE");
+ return 1;
+ }
+ }
+
+ for (n = 0; n < pt; n ++)
+ {
+ char szTmp2[3], *ptr;
+ long x;
+
+ szTmp2[2] = 0;
+ szTmp2[0] = szTmp[n * 2];
+ szTmp2[1] = szTmp[n * 2 + 1];
+
+ x = strtol(szTmp2, &ptr, 16);
+
+ inputtext[n] = (char) x;
+ }
+
+ // XTS
+ if (bXTSTestEnabled)
+ {
+ // Secondary key
+
+ if (GetWindowText(GetDlgItem(hwndDlg, IDC_SECONDARY_KEY), szTmp, sizeof(szTmp)) != 64)
+ {
+ Warning ("TEST_INCORRECT_SECONDARY_KEY_SIZE");
+ return 1;
+ }
+
+ for (n = 0; n < 64; n ++)
+ {
+ char szTmp2[3], *ptr;
+ long x;
+
+ szTmp2[2] = 0;
+ szTmp2[0] = szTmp[n * 2];
+ szTmp2[1] = szTmp[n * 2 + 1];
+
+ x = strtol(szTmp2, &ptr, 16);
+
+ secondaryKey[n] = (char) x;
+ }
+
+ // Data unit number
+
+ tlen = GetWindowText(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), szTmp, sizeof(szTmp));
+
+ if (tlen > 16 || tlen < 1)
+ {
+ Warning ("TEST_INCORRECT_TEST_DATA_UNIT_SIZE");
+ return 1;
+ }
+
+ LeftPadString (szTmp, tlen, 16, '0');
+
+ for (n = 0; n < 16; n ++)
+ {
+ char szTmp2[3], *ptr;
+ long x;
+
+ szTmp2[2] = 0;
+ szTmp2[0] = szTmp[n * 2];
+ szTmp2[1] = szTmp[n * 2 + 1];
+
+ x = strtol(szTmp2, &ptr, 16);
+
+ dataUnitNo[n] = (char) x;
+ }
+
+ // Block number
+
+ blockNo = (int) SendMessage (GetDlgItem (hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_GETITEMDATA, SendMessage (GetDlgItem (hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_GETCURSEL, 0, 0), 0);
+ } // if (bXTSTestEnabled)
+
+
+ /* Perform the actual tests */
+
+ if (ks != CB_ERR && pt != CB_ERR)
+ {
+ char tmp[128];
+ int tmpRetVal;
+
+ /* Copy the plain/ciphertext */
+ memcpy(tmp,inputtext, pt);
+
+ if (bXTSTestEnabled)
+ {
+ UINT64_STRUCT structDataUnitNo;
+
+ /* XTS mode */
+
+ ci = crypto_open ();
+ if (!ci)
+ return 1;
+
+ ci->mode = XTS;
+
+ for (ci->ea = EAGetFirst (); ci->ea != 0 ; ci->ea = EAGetNext (ci->ea))
+ if (EAGetCipherCount (ci->ea) == 1 && EAGetFirstCipher (ci->ea) == idTestCipher)
+ break;
+
+ if ((tmpRetVal = EAInit (ci->ea, (unsigned char *) key, ci->ks)) != ERR_SUCCESS)
+ {
+ handleError (hwndDlg, tmpRetVal);
+ return 1;
+ }
+
+ memcpy (&ci->k2, secondaryKey, sizeof (secondaryKey));
+ if (!EAInitMode (ci))
+ return 1;
+
+ structDataUnitNo.Value = BE64(((unsigned __int64 *)dataUnitNo)[0]);
+
+ if (bEncrypt)
+ EncryptBufferXTS ((unsigned char *) tmp, pt, &structDataUnitNo, blockNo, (unsigned char *) (ci->ks), (unsigned char *) ci->ks2, idTestCipher);
+ else
+ DecryptBufferXTS ((unsigned char *) tmp, pt, &structDataUnitNo, blockNo, (unsigned char *) (ci->ks), (unsigned char *) ci->ks2, idTestCipher);
+
+ crypto_close (ci);
+ }
+ else
+ {
+ if (idTestCipher == BLOWFISH)
+ {
+ /* Deprecated/legacy */
+
+ /* Convert to little-endian, this is needed here and not in
+ above auto-tests because BF_ecb_encrypt above correctly converts
+ from big to little endian, and EncipherBlock does not! */
+ LongReverse((unsigned int *) tmp, pt);
+ }
+
+ CipherInit2(idTestCipher, key, ks_tmp, ks);
+
+ if (bEncrypt)
+ {
+ EncipherBlock(idTestCipher, tmp, ks_tmp);
+ }
+ else
+ {
+ DecipherBlock(idTestCipher, tmp, ks_tmp);
+ }
+
+ if (idTestCipher == BLOWFISH)
+ {
+ /* Deprecated/legacy */
+
+ /* Convert back to big-endian */
+ LongReverse((unsigned int *) tmp, pt);
+ }
+ }
+ *szTmp = 0;
+
+ for (n = 0; n < pt; n ++)
+ {
+ char szTmp2[3];
+ sprintf(szTmp2, "%02x", (int)((unsigned char)tmp[n]));
+ strcat(szTmp, szTmp2);
+ }
+
+ if (bEncrypt)
+ SetWindowText(GetDlgItem(hwndDlg,IDC_CIPHERTEXT), szTmp);
+ else
+ SetWindowText(GetDlgItem(hwndDlg,IDC_PLAINTEXT), szTmp);
+ }
+
+ return 1;
+ }
+
+ if (lw == IDCLOSE || lw == IDCANCEL)
+ {
+ idTestCipher = -1;
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+ break;
+
+ case WM_CLOSE:
+ idTestCipher = -1;
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+ResetCipherTest(HWND hwndDlg, int idTestCipher)
+{
+ int ndx;
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_TESTS_MESSAGE), SW_HIDE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_REDTICK), SW_HIDE);
+
+ EnableWindow(GetDlgItem(hwndDlg,IDC_KEY_SIZE), FALSE);
+
+ /* Setup the keysize and plaintext sizes for the selected cipher */
+
+ SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_RESETCONTENT, 0,0);
+ SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_RESETCONTENT, 0,0);
+ SendMessage (GetDlgItem(hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_RESETCONTENT, 0,0);
+
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_ADDSTRING, 0,(LPARAM) "64");
+ SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 8);
+ SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_SETCURSEL, ndx,0);
+
+ for (ndx = 0; ndx < BLOCKS_PER_XTS_DATA_UNIT; ndx++)
+ {
+ char tmpStr [16];
+
+ sprintf (tmpStr, "%d", ndx);
+
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_ADDSTRING, 0,(LPARAM) tmpStr);
+ SendMessage(GetDlgItem(hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_SETITEMDATA, ndx,(LPARAM) ndx);
+ }
+
+ SendMessage(GetDlgItem(hwndDlg, IDC_TEST_BLOCK_NUMBER), CB_SETCURSEL, 0, 0);
+
+ SetWindowText(GetDlgItem(hwndDlg, IDC_SECONDARY_KEY), "0000000000000000000000000000000000000000000000000000000000000000");
+ SetWindowText(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), "0");
+
+ if (idTestCipher == BLOWFISH)
+ {
+ /* Deprecated/legacy */
+
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) "448");
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 56);
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) "256");
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 32);
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) "128");
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 16);
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) "64");
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 8);
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETCURSEL, 0,0);
+ SetWindowText(GetDlgIt