diff options
author | Mounir IDRASSI <mounir.idrassi@idrix.fr> | 2013-06-22 16:16:13 +0200 |
---|---|---|
committer | Mounir IDRASSI <mounir.idrassi@idrix.fr> | 2014-11-08 23:18:07 +0100 |
commit | c606f0866c3a2a5db3ef9bc41738ef33eb9612a9 (patch) | |
tree | 5847c644cdfff3c1dd55b88b565448087ae89f11 /src/Common | |
download | VeraCrypt-c606f0866c3a2a5db3ef9bc41738ef33eb9612a9.tar.gz VeraCrypt-c606f0866c3a2a5db3ef9bc41738ef33eb9612a9.zip |
Add original TrueCrypt 7.1a sources
Diffstat (limited to 'src/Common')
71 files changed, 33185 insertions, 0 deletions
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, ®Key));
+ 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(GetDlgItem(hwndDlg, IDC_KEY), "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+ }
+
+
+ if (idTestCipher == CAST)
+ {
+ /* Deprecated/legacy */
+
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) "128");
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 16);
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETCURSEL, ndx,0);
+ SetWindowText(GetDlgItem(hwndDlg, IDC_KEY), "00000000000000000000000000000000");
+ }
+
+ if (idTestCipher == TRIPLEDES)
+ {
+ /* Deprecated/legacy */
+
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) "168");
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 24);
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETCURSEL, ndx,0);
+ SetWindowText(GetDlgItem(hwndDlg, IDC_KEY), "000000000000000000000000000000000000000000000000");
+ }
+
+ SetWindowText(GetDlgItem(hwndDlg, IDC_PLAINTEXT), "0000000000000000");
+ SetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), "0000000000000000");
+
+ if (idTestCipher == AES || idTestCipher == SERPENT || idTestCipher == TWOFISH)
+ {
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) "256");
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 32);
+ SendMessage(GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_SETCURSEL, ndx,0);
+
+ SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_RESETCONTENT, 0,0);
+ ndx = SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_ADDSTRING, 0,(LPARAM) "128");
+ SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_SETITEMDATA, ndx,(LPARAM) 16);
+ SendMessage(GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_SETCURSEL, ndx,0);
+
+ SetWindowText(GetDlgItem(hwndDlg, IDC_KEY), "0000000000000000000000000000000000000000000000000000000000000000");
+ SetWindowText(GetDlgItem(hwndDlg, IDC_PLAINTEXT), "00000000000000000000000000000000");
+ SetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), "00000000000000000000000000000000");
+ }
+}
+
+#endif // #ifndef SETUP
+
+
+BOOL CALLBACK MultiChoiceDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ int nChoiceIDs [MAX_MULTI_CHOICES+1] = { IDC_MULTI_CHOICE_MSG, IDC_CHOICE1, IDC_CHOICE2, IDC_CHOICE3,
+ IDC_CHOICE4, IDC_CHOICE5, IDC_CHOICE6, IDC_CHOICE7, IDC_CHOICE8, IDC_CHOICE9, IDC_CHOICE10 };
+ int nBaseButtonWidth = 0;
+ int nBaseButtonHeight = 0;
+ int nActiveChoices = -1;
+ int nStr = 0;
+ int vertSubOffset, horizSubOffset, vertMsgHeightOffset;
+ int vertOffset = 0;
+ int nLongestButtonCaptionWidth = 6;
+ int nLongestButtonCaptionCharLen = 1;
+ int nTextGfxLineHeight = 0;
+ int nMainTextLenInChars = 0;
+ int newLineSeqCount = 0;
+ RECT rec, wrec, wtrec, trec;
+ BOOL bResolve;
+
+ WORD lw = LOWORD (wParam);
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ char **pStr = (char **) ((MULTI_CHOICE_DLGPROC_PARAMS *) lParam)->strings;
+ char **pStrOrig = pStr;
+ wchar_t **pwStr = (wchar_t **) ((MULTI_CHOICE_DLGPROC_PARAMS *) lParam)->strings;
+ wchar_t **pwStrOrig = pwStr;
+
+ LocalizeDialog (hwndDlg, NULL);
+
+ SetWindowPos (hwndDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+ SetWindowPos (hwndDlg, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
+
+ bResolve = (*pStr == NULL);
+
+ // Style
+ if (((MULTI_CHOICE_DLGPROC_PARAMS *) lParam)->bold)
+ {
+ SendMessage (GetDlgItem (hwndDlg, IDC_MULTI_CHOICE_MSG), WM_SETFONT, (WPARAM) hUserBoldFont, (LPARAM) TRUE);
+ }
+
+ // Process the strings
+ pStr++;
+ pwStr++;
+
+ do
+ {
+ if (*pStr != 0)
+ {
+ SetWindowTextW (GetDlgItem(hwndDlg, nChoiceIDs[nStr]), bResolve ? GetString(*pStr) : *pwStr);
+
+ if (nStr > 0)
+ {
+ nLongestButtonCaptionWidth = max (
+ GetTextGfxWidth (GetDlgItem(hwndDlg, IDC_CHOICE1),
+ bResolve ? GetString(*pStr) : *pwStr,
+ hUserFont),
+ nLongestButtonCaptionWidth);
+
+ nLongestButtonCaptionCharLen = max (nLongestButtonCaptionCharLen,
+ (int) wcslen ((const wchar_t *) (bResolve ? GetString(*pStr) : *pwStr)));
+ }
+
+ nActiveChoices++;
+ pStr++;
+ pwStr++;
+ }
+ else
+ {
+ ShowWindow(GetDlgItem(hwndDlg, nChoiceIDs[nStr]), SW_HIDE);
+ }
+ nStr++;
+
+ } while (nStr < MAX_MULTI_CHOICES+1);
+
+ // Length of main message in characters (not bytes)
+ nMainTextLenInChars = wcslen ((const wchar_t *) (bResolve ? GetString(*(pStrOrig+1)) : *(pwStrOrig+1)));
+
+ if (nMainTextLenInChars > 200
+ && nMainTextLenInChars / nLongestButtonCaptionCharLen >= 10)
+ {
+ // As the main text is longer than 200 characters, we will "pad" the widest button caption with
+ // spaces (if it is not wide enough) so as to increase the width of the whole dialog window.
+ // Otherwise, it would look too tall (dialog boxes look better when they are more wide than tall).
+ nLongestButtonCaptionWidth = CompensateXDPI (max (
+ nLongestButtonCaptionWidth,
+ min (350, nMainTextLenInChars)));
+ }
+
+ // Get the window coords
+ GetWindowRect(hwndDlg, &wrec);
+
+ // Get the base button size
+ GetClientRect(GetDlgItem(hwndDlg, IDC_CHOICE1), &rec);
+ nBaseButtonWidth = rec.right + 2;
+ nBaseButtonHeight = rec.bottom + 2;
+
+ // Increase in width based on the gfx length of the widest button caption
+ horizSubOffset = min (CompensateXDPI (500), max (0, nLongestButtonCaptionWidth + CompensateXDPI (50) - nBaseButtonWidth));
+
+ // Vertical "title bar" offset
+ GetClientRect(hwndDlg, &wtrec);
+ vertOffset = wrec.bottom - wrec.top - wtrec.bottom - GetSystemMetrics(SM_CYFIXEDFRAME);
+
+ // Height/width of the message text
+ GetClientRect(GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG), &trec);
+
+ // Determine the number of newlines contained in the message text
+ {
+ int64 offset = -1;
+
+ do
+ {
+ offset = FindString ((char *) (bResolve ? GetString(*(pStrOrig+1)) : *(pwStrOrig+1)),
+ (char *) L"\n",
+ nMainTextLenInChars * 2,
+ wcslen (L"\n") * 2,
+ offset + 1);
+
+ newLineSeqCount++;
+
+ } while (offset != -1);
+ }
+
+ nTextGfxLineHeight = GetTextGfxHeight (GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG),
+ bResolve ? GetString(*(pStrOrig+1)) : *(pwStrOrig+1),
+ hUserFont);
+
+ vertMsgHeightOffset = ((GetTextGfxWidth (GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG),
+ bResolve ? GetString(*(pStrOrig+1)) : *(pwStrOrig+1),
+ hUserFont) / (trec.right + horizSubOffset) + 1) * nTextGfxLineHeight) - trec.bottom;
+
+ vertMsgHeightOffset = min (CompensateYDPI (350), vertMsgHeightOffset + newLineSeqCount * nTextGfxLineHeight + (trec.bottom + vertMsgHeightOffset) / 10); // As reserve, we are adding 10% and the number of lines equal to the number of newlines in the message
+
+ // Reduction in height according to the number of shown buttons
+ vertSubOffset = ((MAX_MULTI_CHOICES - nActiveChoices) * nBaseButtonHeight);
+
+ if (horizSubOffset > 0
+ || vertMsgHeightOffset > 0
+ || vertOffset > 0)
+ {
+ // Resize/move each button if necessary
+ for (nStr = 1; nStr < MAX_MULTI_CHOICES+1; nStr++)
+ {
+ GetWindowRect(GetDlgItem(hwndDlg, nChoiceIDs[nStr]), &rec);
+
+ MoveWindow (GetDlgItem(hwndDlg, nChoiceIDs[nStr]),
+ rec.left - wrec.left - GetSystemMetrics(SM_CXFIXEDFRAME),
+ rec.top - wrec.top - vertOffset + vertMsgHeightOffset,
+ nBaseButtonWidth + horizSubOffset,
+ nBaseButtonHeight,
+ TRUE);
+ }
+
+ // Resize/move the remaining GUI elements
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG), &rec);
+ GetClientRect(GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG), &trec);
+ MoveWindow (GetDlgItem(hwndDlg, IDC_MULTI_CHOICE_MSG),
+ rec.left - wrec.left - GetSystemMetrics(SM_CXFIXEDFRAME),
+ rec.top - wrec.top - vertOffset,
+ trec.right + 2 + horizSubOffset,
+ trec.bottom + 2 + vertMsgHeightOffset,
+ TRUE);
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_MC_DLG_HR1), &rec);
+ GetClientRect(GetDlgItem(hwndDlg, IDC_MC_DLG_HR1), &trec);
+ MoveWindow (GetDlgItem(hwndDlg, IDC_MC_DLG_HR1),
+ rec.left - wrec.left - GetSystemMetrics(SM_CXFIXEDFRAME),
+ rec.top - wrec.top - vertOffset,
+ trec.right + 2 + horizSubOffset,
+ trec.bottom + 2,
+ TRUE);
+
+ GetWindowRect(GetDlgItem(hwndDlg, IDC_MC_DLG_HR2), &rec);
+ GetClientRect(GetDlgItem(hwndDlg, IDC_MC_DLG_HR2), &trec);
+ MoveWindow (GetDlgItem(hwndDlg, IDC_MC_DLG_HR2),
+ rec.left - wrec.left - GetSystemMetrics(SM_CXFIXEDFRAME),
+ rec.top - wrec.top - vertOffset + vertMsgHeightOffset,
+ trec.right + 2 + horizSubOffset,
+ trec.bottom + 2,
+ TRUE);
+ }
+
+ // Resize the window according to number of shown buttons and the longest button caption
+ MoveWindow (hwndDlg,
+ wrec.left - horizSubOffset / 2,
+ wrec.top + vertSubOffset / 2 - vertMsgHeightOffset / 2,
+ wrec.right - wrec.left + horizSubOffset,
+ wrec.bottom - wrec.top - vertSubOffset + 1 + vertMsgHeightOffset,
+ TRUE);
+
+ return 1;
+ }
+
+ case WM_COMMAND:
+
+ if (lw == IDCLOSE || lw == IDCANCEL)
+ {
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ for (nStr = 1; nStr < MAX_MULTI_CHOICES+1; nStr++)
+ {
+ if (lw == nChoiceIDs[nStr])
+ {
+ EndDialog (hwndDlg, nStr);
+ return 1;
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog (hwndDlg, 0);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+BOOL CheckCapsLock (HWND hwnd, BOOL quiet)
+{
+ if ((GetKeyState(VK_CAPITAL) & 1) != 0)
+ {
+ if (!quiet)
+ {
+ MessageBoxW (hwnd, GetString ("CAPSLOCK_ON"), lpszTitle, MB_ICONEXCLAMATION);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+// Checks whether the file extension is not used for executable files or similarly problematic, which often
+// causes Windows and antivirus software to interfere with the container.
+BOOL CheckFileExtension (char *fileName)
+{
+ int i = 0;
+ char *ext = strrchr (fileName, '.');
+ static char *problemFileExt[] = {
+ // These are protected by the Windows Resource Protection
+ ".asa", ".asp", ".aspx", ".ax", ".bas", ".bat", ".bin", ".cer", ".chm", ".clb", ".cmd", ".cnt", ".cnv",
+ ".com", ".cpl", ".cpx", ".crt", ".csh", ".dll", ".drv", ".dtd", ".exe", ".fxp", ".grp", ".h1s", ".hlp",
+ ".hta", ".ime", ".inf", ".ins", ".isp", ".its", ".js", ".jse", ".ksh", ".lnk", ".mad", ".maf", ".mag",
+ ".mam", ".man", ".maq", ".mar", ".mas", ".mat", ".mau", ".mav", ".maw", ".mda", ".mdb", ".mde", ".mdt",
+ ".mdw", ".mdz", ".msc", ".msi", ".msp", ".mst", ".mui", ".nls", ".ocx", ".ops", ".pal", ".pcd", ".pif",
+ ".prf", ".prg", ".pst", ".reg", ".scf", ".scr", ".sct", ".shb", ".shs", ".sys", ".tlb", ".tsp", ".url",
+ ".vb", ".vbe", ".vbs", ".vsmacros", ".vss", ".vst", ".vsw", ".ws", ".wsc", ".wsf", ".wsh", ".xsd", ".xsl",
+ // These additional file extensions are usually watched by antivirus programs
+ ".386", ".acm", ".ade", ".adp", ".ani", ".app", ".asd", ".asf", ".asx", ".awx", ".ax", ".boo", ".bz2", ".cdf",
+ ".class", ".dhtm", ".dhtml",".dlo", ".emf", ".eml", ".flt", ".fot", ".gz", ".hlp", ".htm", ".html", ".ini",
+ ".j2k", ".jar", ".jff", ".jif", ".jmh", ".jng", ".jp2", ".jpe", ".jpeg", ".jpg", ".lsp", ".mod", ".nws",
+ ".obj", ".olb", ".osd", ".ov1", ".ov2", ".ov3", ".ovl", ".ovl", ".ovr", ".pdr", ".pgm", ".php", ".pkg",
+ ".pl", ".png", ".pot", ".pps", ".ppt", ".ps1", ".ps1xml", ".psc1", ".rar", ".rpl", ".rtf", ".sbf", ".script", ".sh", ".sha", ".shtm",
+ ".shtml", ".spl", ".swf", ".tar", ".tgz", ".tmp", ".ttf", ".vcs", ".vlm", ".vxd", ".vxo", ".wiz", ".wll", ".wmd",
+ ".wmf", ".wms", ".wmz", ".wpc", ".wsc", ".wsh", ".wwk", ".xhtm", ".xhtml", ".xl", ".xml", ".zip", ".7z", 0};
+
+ if (!ext)
+ return FALSE;
+
+ while (problemFileExt[i])
+ {
+ if (!_stricmp (ext, problemFileExt[i++]))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+void IncreaseWrongPwdRetryCount (int count)
+{
+ WrongPwdRetryCounter += count;
+}
+
+
+void ResetWrongPwdRetryCount (void)
+{
+ WrongPwdRetryCounter = 0;
+}
+
+
+BOOL WrongPwdRetryCountOverLimit (void)
+{
+ return (WrongPwdRetryCounter > TC_TRY_HEADER_BAK_AFTER_NBR_WRONG_PWD_TRIES);
+}
+
+
+int GetFirstAvailableDrive ()
+{
+ DWORD dwUsedDrives = GetLogicalDrives();
+ int i;
+
+ for (i = 3; i < 26; i++)
+ {
+ if (!(dwUsedDrives & 1 << i))
+ return i;
+ }
+
+ return -1;
+}
+
+
+int GetLastAvailableDrive ()
+{
+ DWORD dwUsedDrives = GetLogicalDrives();
+ int i;
+
+ for (i = 25; i > 2; i--)
+ {
+ if (!(dwUsedDrives & 1 << i))
+ return i;
+ }
+
+ return -1;
+}
+
+
+BOOL IsDriveAvailable (int driveNo)
+{
+ return (GetLogicalDrives() & (1 << driveNo)) == 0;
+}
+
+
+BOOL IsDeviceMounted (char *deviceName)
+{
+ BOOL bResult = FALSE;
+ DWORD dwResult;
+ HANDLE dev = INVALID_HANDLE_VALUE;
+
+ if ((dev = CreateFile (deviceName,
+ GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL)) != INVALID_HANDLE_VALUE)
+ {
+ bResult = DeviceIoControl (dev, FSCTL_IS_VOLUME_MOUNTED, NULL, 0, NULL, 0, &dwResult, NULL);
+ CloseHandle (dev);
+ }
+
+ return bResult;
+}
+
+
+int DriverUnmountVolume (HWND hwndDlg, int nDosDriveNo, BOOL forced)
+{
+ UNMOUNT_STRUCT unmount;
+ DWORD dwResult;
+
+ BOOL bResult;
+
+ unmount.nDosDriveNo = nDosDriveNo;
+ unmount.ignoreOpenFiles = forced;
+
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_DISMOUNT_VOLUME, &unmount,
+ sizeof (unmount), &unmount, sizeof (unmount), &dwResult, NULL);
+
+ if (bResult == FALSE)
+ {
+ handleWin32Error (hwndDlg);
+ return 1;
+ }
+
+#ifdef TCMOUNT
+
+ if (unmount.nReturnCode == ERR_SUCCESS
+ && unmount.HiddenVolumeProtectionTriggered
+ && !VolumeNotificationsList.bHidVolDamagePrevReported [nDosDriveNo])
+ {
+ wchar_t msg[4096];
+
+ VolumeNotificationsList.bHidVolDamagePrevReported [nDosDriveNo] = TRUE;
+ swprintf (msg, GetString ("DAMAGE_TO_HIDDEN_VOLUME_PREVENTED"), nDosDriveNo + 'A');
+ SetForegroundWindow (hwndDlg);
+ MessageBoxW (hwndDlg, msg, lpszTitle, MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST);
+ }
+
+#endif // #ifdef TCMOUNT
+
+ return unmount.nReturnCode;
+}
+
+
+void BroadcastDeviceChange (WPARAM message, int nDosDriveNo, DWORD driveMap)
+{
+ DEV_BROADCAST_VOLUME dbv;
+ DWORD_PTR dwResult;
+ LONG eventId = 0;
+ int i;
+
+ if (DeviceChangeBroadcastDisabled)
+ return;
+
+ if (message == DBT_DEVICEARRIVAL)
+ eventId = SHCNE_DRIVEADD;
+ else if (message == DBT_DEVICEREMOVECOMPLETE)
+ eventId = SHCNE_DRIVEREMOVED;
+ else if (IsOSAtLeast (WIN_7) && message == DBT_DEVICEREMOVEPENDING) // Explorer on Windows 7 holds open handles of all drives when 'Computer' is expanded in navigation pane. SHCNE_DRIVEREMOVED must be used as DBT_DEVICEREMOVEPENDING is ignored.
+ eventId = SHCNE_DRIVEREMOVED;
+
+ if (driveMap == 0)
+ driveMap = (1 << nDosDriveNo);
+
+ if (eventId != 0)
+ {
+ for (i = 0; i < 26; i++)
+ {
+ if (driveMap & (1 << i))
+ {
+ char root[] = { (char) i + 'A', ':', '\\', 0 };
+ SHChangeNotify (eventId, SHCNF_PATH, root, NULL);
+
+ if (nCurrentOS == WIN_2000 && RemoteSession)
+ {
+ char target[32];
+ wsprintf (target, "%ls%c", TC_MOUNT_PREFIX, i + 'A');
+ root[2] = 0;
+
+ if (message == DBT_DEVICEARRIVAL)
+ DefineDosDevice (DDD_RAW_TARGET_PATH, root, target);
+ else if (message == DBT_DEVICEREMOVECOMPLETE)
+ DefineDosDevice (DDD_RAW_TARGET_PATH| DDD_REMOVE_DEFINITION
+ | DDD_EXACT_MATCH_ON_REMOVE, root, target);
+ }
+ }
+ }
+ }
+
+ dbv.dbcv_size = sizeof (dbv);
+ dbv.dbcv_devicetype = DBT_DEVTYP_VOLUME;
+ dbv.dbcv_reserved = 0;
+ dbv.dbcv_unitmask = driveMap;
+ dbv.dbcv_flags = 0;
+
+ UINT timeOut = 1000;
+
+ // SHChangeNotify() works on Vista, so the Explorer does not require WM_DEVICECHANGE
+ if (CurrentOSMajor >= 6)
+ timeOut = 100;
+
+ IgnoreWmDeviceChange = TRUE;
+ SendMessageTimeout (HWND_BROADCAST, WM_DEVICECHANGE, message, (LPARAM)(&dbv), SMTO_ABORTIFHUNG, timeOut, &dwResult);
+
+ // Explorer prior Vista sometimes fails to register a new drive
+ if (CurrentOSMajor < 6 && message == DBT_DEVICEARRIVAL)
+ SendMessageTimeout (HWND_BROADCAST, WM_DEVICECHANGE, message, (LPARAM)(&dbv), SMTO_ABORTIFHUNG, 200, &dwResult);
+
+ IgnoreWmDeviceChange = FALSE;
+}
+
+
+// Use only cached passwords if password = NULL
+//
+// Returns:
+// -1 = user aborted mount / error
+// 0 = mount failed
+// 1 = mount OK
+// 2 = mount OK in shared mode
+//
+// Note that some code calling this relies on the content of the mountOptions struct
+// to remain unmodified (don't remove the 'const' without proper revision).
+
+int MountVolume (HWND hwndDlg,
+ int driveNo,
+ char *volumePath,
+ Password *password,
+ BOOL cachePassword,
+ BOOL sharedAccess,
+ const MountOptions* const mountOptions,
+ BOOL quiet,
+ BOOL bReportWrongPassword)
+{
+ MOUNT_STRUCT mount;
+ DWORD dwResult;
+ BOOL bResult, bDevice;
+ char root[MAX_PATH];
+ int favoriteMountOnArrivalRetryCount = 0;
+
+#ifdef TCMOUNT
+ if (mountOptions->PartitionInInactiveSysEncScope)
+ {
+ if (!CheckSysEncMountWithoutPBA (volumePath, quiet))
+ return -1;
+ }
+#endif
+
+ if (IsMountedVolume (volumePath))
+ {
+ if (!quiet)
+ Error ("VOL_ALREADY_MOUNTED");
+ return -1;
+ }
+
+ if (!IsDriveAvailable (driveNo))
+ {
+ if (!quiet)
+ Error ("DRIVE_LETTER_UNAVAILABLE");
+
+ return -1;
+ }
+
+ // If using cached passwords, check cache status first
+ if (password == NULL && IsPasswordCacheEmpty ())
+ return 0;
+
+ ZeroMemory (&mount, sizeof (mount));
+ mount.bExclusiveAccess = sharedAccess ? FALSE : TRUE;
+ mount.SystemFavorite = MountVolumesAsSystemFavorite;
+ mount.UseBackupHeader = mountOptions->UseBackupHeader;
+ mount.RecoveryMode = mountOptions->RecoveryMode;
+
+retry:
+ mount.nDosDriveNo = driveNo;
+ mount.bCache = cachePassword;
+
+ mount.bPartitionInInactiveSysEncScope = FALSE;
+
+ if (password != NULL)
+ mount.VolumePassword = *password;
+ else
+ mount.VolumePassword.Length = 0;
+
+ if (!mountOptions->ReadOnly && mountOptions->ProtectHiddenVolume)
+ {
+ mount.ProtectedHidVolPassword = mountOptions->ProtectedHidVolPassword;
+ mount.bProtectHiddenVolume = TRUE;
+ }
+ else
+ mount.bProtectHiddenVolume = FALSE;
+
+ mount.bMountReadOnly = mountOptions->ReadOnly;
+ mount.bMountRemovable = mountOptions->Removable;
+ mount.bPreserveTimestamp = mountOptions->PreserveTimestamp;
+
+ mount.bMountManager = TRUE;
+
+ // Windows 2000 mount manager causes problems with remounted volumes
+ if (CurrentOSMajor == 5 && CurrentOSMinor == 0)
+ mount.bMountManager = FALSE;
+
+ string path = volumePath;
+ if (path.find ("\\\\?\\") == 0)
+ {
+ // Remove \\?\ prefix
+ path = path.substr (4);
+ strcpy_s (volumePath, TC_MAX_PATH, path.c_str());
+ }
+
+ if (path.find ("Volume{") == 0 && path.rfind ("}\\") == path.size() - 2)
+ {
+ string resolvedPath = VolumeGuidPathToDevicePath (path);
+
+ if (!resolvedPath.empty())
+ strcpy_s (volumePath, TC_MAX_PATH, resolvedPath.c_str());
+ }
+
+ CreateFullVolumePath ((char *) mount.wszVolume, volumePath, &bDevice);
+
+ if (!bDevice)
+ {
+ // UNC path
+ if (path.find ("\\\\") == 0)
+ {
+ strcpy_s ((char *)mount.wszVolume, array_capacity (mount.wszVolume), ("UNC" + path.substr (1)).c_str());
+ }
+
+ if (GetVolumePathName (volumePath, root, sizeof (root) - 1))
+ {
+ DWORD bps, flags, d;
+ if (GetDiskFreeSpace (root, &d, &bps, &d, &d))
+ mount.BytesPerSector = bps;
+
+ // Read-only host filesystem
+ if (!mount.bMountReadOnly && GetVolumeInformation (root, NULL, 0, NULL, &d, &flags, NULL, 0))
+ mount.bMountReadOnly = (flags & FILE_READ_ONLY_VOLUME) != 0;
+ }
+ }
+
+ ToUNICODE ((char *) mount.wszVolume);
+
+ if (mountOptions->PartitionInInactiveSysEncScope)
+ {
+ if (mount.wszVolume == NULL || swscanf_s ((const wchar_t *) mount.wszVolume,
+ WIDE("\\Device\\Harddisk%d\\Partition"),
+ &mount.nPartitionInInactiveSysEncScopeDriveNo,
+ sizeof(mount.nPartitionInInactiveSysEncScopeDriveNo)) != 1)
+ {
+ return -1;
+ }
+
+ mount.bPartitionInInactiveSysEncScope = TRUE;
+ }
+
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_MOUNT_VOLUME, &mount,
+ sizeof (mount), &mount, sizeof (mount), &dwResult, NULL);
+
+ burn (&mount.VolumePassword, sizeof (mount.VolumePassword));
+ burn (&mount.ProtectedHidVolPassword, sizeof (mount.ProtectedHidVolPassword));
+
+ if (bResult == FALSE)
+ {
+ // Volume already open by another process
+ if (GetLastError () == ERROR_SHARING_VIOLATION)
+ {
+ if (FavoriteMountOnArrivalInProgress && ++favoriteMountOnArrivalRetryCount < 10)
+ {
+ Sleep (500);
+ goto retry;
+ }
+
+ if (mount.bExclusiveAccess == FALSE)
+ {
+ if (!quiet)
+ Error ("FILE_IN_USE_FAILED");
+
+ return -1;
+ }
+ else
+ {
+ if (quiet)
+ {
+ mount.bExclusiveAccess = FALSE;
+ goto retry;
+ }
+
+ // Ask user
+ if (IDYES == AskWarnNoYes ("FILE_IN_USE"))
+ {
+ mount.bExclusiveAccess = FALSE;
+ goto retry;
+ }
+ }
+
+ return -1;
+ }
+
+ if (!quiet && (!MultipleMountOperationInProgress || GetLastError() != ERROR_NOT_READY))
+ handleWin32Error (hwndDlg);
+
+ return -1;
+ }
+
+ if (mount.nReturnCode != 0)
+ {
+ if (mount.nReturnCode == ERR_PASSWORD_WRONG)
+ {
+ // Do not report wrong password, if not instructed to
+ if (bReportWrongPassword)
+ {
+ IncreaseWrongPwdRetryCount (1); // We increase the count here only if bReportWrongPassword is TRUE, because "Auto-Mount All Devices" and other callers do it separately
+
+ if (WrongPwdRetryCountOverLimit ()
+ && !mount.UseBackupHeader)
+ {
+ // Retry using embedded header backup (if any)
+ mount.UseBackupHeader = TRUE;
+ goto retry;
+ }
+
+ if (bDevice && mount.bProtectHiddenVolume)
+ {
+ int driveNo;
+
+ if (sscanf (volumePath, "\\Device\\Harddisk%d\\Partition", &driveNo) == 1)
+ {
+ OPEN_TEST_STRUCT openTestStruct;
+ memset (&openTestStruct, 0, sizeof (openTestStruct));
+
+ openTestStruct.bDetectTCBootLoader = TRUE;
+ _snwprintf ((wchar_t *) openTestStruct.wszFileName, array_capacity (openTestStruct.wszFileName), L"\\Device\\Harddisk%d\\Partition0", driveNo);
+
+ DWORD dwResult;
+ if (DeviceIoControl (hDriver, TC_IOCTL_OPEN_TEST, &openTestStruct, sizeof (OPEN_TEST_STRUCT), &openTestStruct, sizeof (OPEN_TEST_STRUCT), &dwResult, NULL) && openTestStruct.TCBootLoaderDetected)
+ WarningDirect ((GetWrongPasswordErrorMessage (hwndDlg) + L"\n\n" + GetString ("HIDDEN_VOL_PROT_PASSWORD_US_KEYB_LAYOUT")).c_str());
+ else
+ handleError (hwndDlg, mount.nReturnCode);
+ }
+ }
+ else
+ handleError (hwndDlg, mount.nReturnCode);
+ }
+
+ return 0;
+ }
+
+ if (!quiet)
+ handleError (hwndDlg, mount.nReturnCode);
+
+ return 0;
+ }
+
+ // Mount successful
+
+ if (mount.UseBackupHeader != mountOptions->UseBackupHeader
+ && mount.UseBackupHeader)
+ {
+ if (bReportWrongPassword && !Silent)
+ Warning ("HEADER_DAMAGED_AUTO_USED_HEADER_BAK");
+ }
+
+ LastMountedVolumeDirty = mount.FilesystemDirty;
+
+ if (mount.FilesystemDirty)
+ {
+ wchar_t msg[1024];
+ wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 };
+ wsprintfW (msg, GetString ("MOUNTED_VOLUME_DIRTY"), mountPoint);
+
+ if (AskWarnYesNoStringTopmost (msg) == IDYES)
+ CheckFilesystem (driveNo, TRUE);
+ }
+
+ if (mount.VolumeMountedReadOnlyAfterAccessDenied
+ && !Silent
+ && !bDevice
+ && !FileHasReadOnlyAttribute (volumePath)
+ && !IsFileOnReadOnlyFilesystem (volumePath))
+ {
+ wchar_t msg[1024];
+ wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 };
+ wsprintfW (msg, GetString ("MOUNTED_CONTAINER_FORCED_READ_ONLY"), mountPoint);
+
+ WarningDirect (msg);
+ }
+
+ if (mount.VolumeMountedReadOnlyAfterAccessDenied
+ && !Silent
+ && bDevice)
+ {
+ wchar_t msg[1024];
+ wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 };
+ wsprintfW (msg, GetString ("MOUNTED_DEVICE_FORCED_READ_ONLY"), mountPoint);
+
+ WarningDirect (msg);
+ }
+
+ if (mount.VolumeMountedReadOnlyAfterDeviceWriteProtected
+ && !Silent
+ && strstr (volumePath, "\\Device\\Harddisk") == volumePath)
+ {
+ wchar_t msg[1024];
+ wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 };
+ wsprintfW (msg, GetString ("MOUNTED_DEVICE_FORCED_READ_ONLY_WRITE_PROTECTION"), mountPoint);
+
+ WarningDirect (msg);
+
+ if (CurrentOSMajor >= 6
+ && strstr (volumePath, "\\Device\\HarddiskVolume") != volumePath
+ && AskNoYes ("ASK_REMOVE_DEVICE_WRITE_PROTECTION") == IDYES)
+ {
+ RemoveDeviceWriteProtection (hwndDlg, volumePath);
+ }
+ }
+
+ ResetWrongPwdRetryCount ();
+
+ BroadcastDeviceChange (DBT_DEVICEARRIVAL, driveNo, 0);
+
+ if (mount.bExclusiveAccess == FALSE)
+ return 2;
+
+ return 1;
+}
+
+
+BOOL UnmountVolume (HWND hwndDlg, int nDosDriveNo, BOOL forceUnmount)
+{
+ int result;
+ BOOL forced = forceUnmount;
+ int dismountMaxRetries = UNMOUNT_MAX_AUTO_RETRIES;
+
+retry:
+ BroadcastDeviceChange (DBT_DEVICEREMOVEPENDING, nDosDriveNo, 0);
+
+ do
+ {
+ result = DriverUnmountVolume (hwndDlg, nDosDriveNo, forced);
+
+ if (result == ERR_FILES_OPEN)
+ Sleep (UNMOUNT_AUTO_RETRY_DELAY);
+ else
+ break;
+
+ } while (--dismountMaxRetries > 0);
+
+ if (result != 0)
+ {
+ if (result == ERR_FILES_OPEN && !Silent)
+ {
+ if (IDYES == AskWarnYesNoTopmost ("UNMOUNT_LOCK_FAILED"))
+ {
+ forced = TRUE;
+ goto retry;
+ }
+
+ if (IsOSAtLeast (WIN_7))
+ {
+ // Undo SHCNE_DRIVEREMOVED
+ char root[] = { (char) nDosDriveNo + 'A', ':', '\\', 0 };
+ SHChangeNotify (SHCNE_DRIVEADD, SHCNF_PATH, root, NULL);
+ }
+
+ return FALSE;
+ }
+
+ Error ("UNMOUNT_FAILED");
+
+ return FALSE;
+ }
+
+ BroadcastDeviceChange (DBT_DEVICEREMOVECOMPLETE, nDosDriveNo, 0);
+
+ return TRUE;
+}
+
+
+BOOL IsPasswordCacheEmpty (void)
+{
+ DWORD dw;
+ return !DeviceIoControl (hDriver, TC_IOCTL_GET_PASSWORD_CACHE_STATUS, 0, 0, 0, 0, &dw, 0);
+}
+
+
+BOOL IsMountedVolume (const char *volname)
+{
+ MOUNT_LIST_STRUCT mlist;
+ DWORD dwResult;
+ int i;
+ char volume[TC_MAX_PATH*2+16];
+
+ strcpy (volume, volname);
+
+ if (strstr (volname, "\\Device\\") != volname)
+ sprintf(volume, "\\??\\%s", volname);
+
+ string resolvedPath = VolumeGuidPathToDevicePath (volname);
+ if (!resolvedPath.empty())
+ strcpy_s (volume, sizeof (volume), resolvedPath.c_str());
+
+ ToUNICODE (volume);
+
+ memset (&mlist, 0, sizeof (mlist));
+ DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist,
+ sizeof (mlist), &mlist, sizeof (mlist), &dwResult,
+ NULL);
+
+ for (i=0 ; i<26; i++)
+ if (0 == _wcsicmp ((wchar_t *) mlist.wszVolume[i], (WCHAR *)volume))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+int GetMountedVolumeDriveNo (char *volname)
+{
+ MOUNT_LIST_STRUCT mlist;
+ DWORD dwResult;
+ int i;
+ char volume[TC_MAX_PATH*2+16];
+
+ if (volname == NULL)
+ return -1;
+
+ strcpy (volume, volname);
+
+ if (strstr (volname, "\\Device\\") != volname)
+ sprintf(volume, "\\??\\%s", volname);
+
+ string resolvedPath = VolumeGuidPathToDevicePath (volname);
+ if (!resolvedPath.empty())
+ strcpy_s (volume, sizeof (volume), resolvedPath.c_str());
+
+ ToUNICODE (volume);
+
+ memset (&mlist, 0, sizeof (mlist));
+ DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist,
+ sizeof (mlist), &mlist, sizeof (mlist), &dwResult,
+ NULL);
+
+ for (i=0 ; i<26; i++)
+ if (0 == _wcsicmp ((wchar_t *) mlist.wszVolume[i], (WCHAR *)volume))
+ return i;
+
+ return -1;
+}
+
+
+BOOL IsAdmin (void)
+{
+ return IsUserAnAdmin ();
+}
+
+
+BOOL IsBuiltInAdmin ()
+{
+ HANDLE procToken;
+ DWORD size;
+
+ if (!IsAdmin() || !OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &procToken))
+ return FALSE;
+
+ finally_do_arg (HANDLE, procToken, { CloseHandle (finally_arg); });
+
+ if (GetTokenInformation (procToken, TokenUser, NULL, 0, &size) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ return FALSE;
+
+ TOKEN_USER *tokenUser = (TOKEN_USER *) malloc (size);
+ if (!tokenUser)
+ return FALSE;
+
+ finally_do_arg (void *, tokenUser, { free (finally_arg); });
+
+ if (!GetTokenInformation (procToken, TokenUser, tokenUser, size, &size))
+ return FALSE;
+
+ return IsWellKnownSid (tokenUser->User.Sid, WinAccountAdministratorSid);
+}
+
+
+BOOL IsUacSupported ()
+{
+ HKEY hkey;
+ DWORD value = 1, size = sizeof (DWORD);
+
+ if (!IsOSAtLeast (WIN_VISTA))
+ return FALSE;
+
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", 0, KEY_READ, &hkey) == ERROR_SUCCESS)
+ {
+ if (RegQueryValueEx (hkey, "EnableLUA", 0, 0, (LPBYTE) &value, &size) != ERROR_SUCCESS)
+ value = 1;
+
+ RegCloseKey (hkey);
+ }
+
+ return value != 0;
+}
+
+
+BOOL ResolveSymbolicLink (const wchar_t *symLinkName, PWSTR targetName)
+{
+ BOOL bResult;
+ DWORD dwResult;
+ RESOLVE_SYMLINK_STRUCT resolve;
+
+ memset (&resolve, 0, sizeof(resolve));
+ wcscpy ((PWSTR) &resolve.symLinkName, symLinkName);
+
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_RESOLVED_SYMLINK, &resolve,
+ sizeof (resolve), &resolve, sizeof (resolve), &dwResult,
+ NULL);
+
+ wcscpy (targetName, (PWSTR) &resolve.targetName);
+
+ return bResult;
+}
+
+
+BOOL GetPartitionInfo (const char *deviceName, PPARTITION_INFORMATION rpartInfo)
+{
+ BOOL bResult;
+ DWORD dwResult;
+ DISK_PARTITION_INFO_STRUCT dpi;
+
+ memset (&dpi, 0, sizeof(dpi));
+ wsprintfW ((PWSTR) &dpi.deviceName, L"%hs", deviceName);
+
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_DRIVE_PARTITION_INFO, &dpi,
+ sizeof (dpi), &dpi, sizeof (dpi), &dwResult, NULL);
+
+ memcpy (rpartInfo, &dpi.partInfo, sizeof (PARTITION_INFORMATION));
+ return bResult;
+}
+
+
+BOOL GetDeviceInfo (const char *deviceName, DISK_PARTITION_INFO_STRUCT *info)
+{
+ DWORD dwResult;
+
+ memset (info, 0, sizeof(*info));
+ wsprintfW ((PWSTR) &info->deviceName, L"%hs", deviceName);
+
+ return DeviceIoControl (hDriver, TC_IOCTL_GET_DRIVE_PARTITION_INFO, info, sizeof (*info), info, sizeof (*info), &dwResult, NULL);
+}
+
+
+BOOL GetDriveGeometry (const char *deviceName, PDISK_GEOMETRY diskGeometry)
+{
+ BOOL bResult;
+ DWORD dwResult;
+ DISK_GEOMETRY_STRUCT dg;
+
+ memset (&dg, 0, sizeof(dg));
+ wsprintfW ((PWSTR) &dg.deviceName, L"%hs", deviceName);
+
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_DRIVE_GEOMETRY, &dg,
+ sizeof (dg), &dg, sizeof (dg), &dwResult, NULL);
+
+ memcpy (diskGeometry, &dg.diskGeometry, sizeof (DISK_GEOMETRY));
+ return bResult;
+}
+
+
+// Returns drive letter number assigned to device (-1 if none)
+int GetDiskDeviceDriveLetter (PWSTR deviceName)
+{
+ int i;
+ WCHAR link[MAX_PATH];
+ WCHAR target[MAX_PATH];
+ WCHAR device[MAX_PATH];
+
+ if (!ResolveSymbolicLink (deviceName, device))
+ wcscpy (device, deviceName);
+
+ for (i = 0; i < 26; i++)
+ {
+ WCHAR drive[] = { (WCHAR) i + 'A', ':', 0 };
+
+ wcscpy (link, L"\\DosDevices\\");
+ wcscat (link, drive);
+
+ ResolveSymbolicLink (link, target);
+
+ if (wcscmp (device, target) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+
+// WARNING: This function does NOT provide 100% reliable results -- do NOT use it for critical/dangerous operations!
+// Return values: 0 - filesystem does not appear empty, 1 - filesystem appears empty, -1 - an error occurred
+int FileSystemAppearsEmpty (const char *devicePath)
+{
+ float percentFreeSpace = 0.0;
+ __int64 occupiedBytes = 0;
+
+ if (GetStatsFreeSpaceOnPartition (devicePath, &percentFreeSpace, &occupiedBytes, TRUE) != -1)
+ {
+ if (occupiedBytes > BYTES_PER_GB && percentFreeSpace < 99.99 // "percentFreeSpace < 99.99" is needed because an NTFS filesystem larger than several terabytes can have more than 1GB of data in use, even if there are no files stored on it.
+ || percentFreeSpace < 88) // A 24-MB NTFS filesystem has 11.5% of space in use even if there are no files stored on it.
+ {
+ return 0;
+ }
+ else
+ return 1;
+ }
+ else
+ return -1;
+}
+
+
+// Returns the free space on the specified partition (volume) in bytes. If the 'occupiedBytes' pointer
+// is not NULL, size of occupied space (in bytes) is written to the pointed location. In addition, if the
+// 'percent' pointer is not NULL, % of free space is stored in the pointed location. If there's an error,
+// returns -1.
+__int64 GetStatsFreeSpaceOnPartition (const char *devicePath, float *percentFree, __int64 *occupiedBytes, BOOL silent)
+{
+ WCHAR devPath [MAX_PATH];
+ int driveLetterNo = -1;
+ char szRootPath[4] = {0, ':', '\\', 0};
+ ULARGE_INTEGER freeSpaceSize;
+ ULARGE_INTEGER totalNumberOfBytes;
+ ULARGE_INTEGER totalNumberOfFreeBytes;
+
+ strcpy ((char *) devPath, devicePath);
+ ToUNICODE ((char *) devPath);
+
+ driveLetterNo = GetDiskDeviceDriveLetter (devPath);
+ szRootPath[0] = (char) driveLetterNo + 'A';
+
+
+ if (!GetDiskFreeSpaceEx (szRootPath, &freeSpaceSize, &totalNumberOfBytes, &totalNumberOfFreeBytes))
+ {
+ if (!silent)
+ {
+ handleWin32Error (MainDlg);
+ Error ("CANNOT_CALC_SPACE");
+ }
+
+ return -1;
+ }
+
+
+ if (percentFree != NULL || occupiedBytes != NULL)
+ {
+ // Determine occupied space and % of free space
+
+ PARTITION_INFORMATION partitionInfo;
+
+ if (!GetPartitionInfo (devicePath, &partitionInfo))
+ {
+ if (!silent)
+ {
+ handleWin32Error (MainDlg);
+ Error ("CANT_GET_VOLSIZE");
+ }
+ return -1;
+ }
+
+ if (occupiedBytes != NULL)
+ *occupiedBytes = partitionInfo.PartitionLength.QuadPart - freeSpaceSize.QuadPart;
+
+ if (percentFree != NULL)
+ *percentFree = (float) ((double) freeSpaceSize.QuadPart / (double) partitionInfo.PartitionLength.QuadPart * 100.0);
+ }
+
+ return freeSpaceSize.QuadPart;
+}
+
+
+// Returns -1 if there's an error.
+__int64 GetDeviceSize (const char *devicePath)
+{
+ PARTITION_INFORMATION partitionInfo;
+
+ if (!GetPartitionInfo (devicePath, &partitionInfo))
+ return -1;
+
+ return partitionInfo.PartitionLength.QuadPart;
+}
+
+
+HANDLE DismountDrive (char *devName, char *devicePath)
+{
+ DWORD dwResult;
+ HANDLE hVolume;
+ BOOL bResult = FALSE;
+ int attempt = UNMOUNT_MAX_AUTO_RETRIES;
+ int driveLetterNo = -1;
+ WCHAR devPath [MAX_PATH];
+
+ strcpy ((char *) devPath, devicePath);
+ ToUNICODE ((char *) devPath);
+ driveLetterNo = GetDiskDeviceDriveLetter (devPath);
+
+
+ hVolume = CreateFile (devName, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (hVolume == INVALID_HANDLE_VALUE)
+ return INVALID_HANDLE_VALUE;
+
+
+ // Try to lock the volume first so that dismount is not forced.
+ // If we fail, we will dismount anyway even if it needs to be forced.
+
+ CloseVolumeExplorerWindows (MainDlg, driveLetterNo);
+
+ while (!(bResult = DeviceIoControl (hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
+ && attempt > 0)
+ {
+ Sleep (UNMOUNT_AUTO_RETRY_DELAY);
+ attempt--;
+ }
+
+
+ // Try to dismount the volume
+
+ attempt = UNMOUNT_MAX_AUTO_RETRIES;
+
+ while (!(bResult = DeviceIoControl (hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwResult, NULL))
+ && attempt > 0)
+ {
+ Sleep (UNMOUNT_AUTO_RETRY_DELAY);
+ attempt--;
+ }
+
+ if (!bResult)
+ CloseHandle (hVolume);
+
+ return (bResult ? hVolume : INVALID_HANDLE_VALUE);
+}
+
+// Returns -1 if the specified string is not found in the buffer. Otherwise, returns the
+// offset of the first occurrence of the string. The string and the buffer may contain zeroes,
+// which do NOT terminate them.
+int64 FindString (const char *buf, const char *str, int64 bufLen, size_t strLen, int64 startOffset)
+{
+ if (buf == NULL
+ || str == NULL
+ || strLen > bufLen
+ || bufLen < 1
+ || strLen < 1
+ || startOffset > bufLen - strLen)
+ {
+ return -1;
+ }
+
+ for (int64 i = startOffset; i <= bufLen - strLen; i++)
+ {
+ if (memcmp (buf + i, str, strLen) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+// Returns TRUE if the file or directory exists (both may be enclosed in quotation marks).
+BOOL FileExists (const char *filePathPtr)
+{
+ char filePath [TC_MAX_PATH];
+
+ // Strip quotation marks (if any)
+ if (filePathPtr [0] == '"')
+ {
+ strcpy (filePath, filePathPtr + 1);
+ }
+ else
+ {
+ strcpy (filePath, filePathPtr);
+ }
+
+ // Strip quotation marks (if any)
+ if (filePath [strlen (filePath) - 1] == '"')
+ filePath [strlen (filePath) - 1] = 0;
+
+ return (_access (filePath, 0) != -1);
+}
+
+// Searches the file from its end for the LAST occurrence of the string str.
+// The string may contain zeroes, which do NOT terminate the string.
+// If the string is found, its offset from the start of the file is returned.
+// If the string isn't found or if any error occurs, -1 is returned.
+__int64 FindStringInFile (const char *filePath, const char* str, int strLen)
+{
+ int bufSize = 64 * BYTES_PER_KB;
+ char *buffer = (char *) err_malloc (bufSize);
+ HANDLE src = NULL;
+ DWORD bytesRead;
+ BOOL readRetVal;
+ __int64 filePos = GetFileSize64 (filePath);
+ int bufPos = 0;
+ LARGE_INTEGER seekOffset, seekOffsetNew;
+ BOOL bExit = FALSE;
+ int filePosStep;
+ __int64 retVal = -1;
+
+ if (filePos <= 0
+ || buffer == NULL
+ || strLen > bufSize
+ || strLen < 1)
+ return -1;
+
+ src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (src == INVALID_HANDLE_VALUE)
+ {
+ free (buffer);
+ return -1;
+ }
+
+ filePosStep = bufSize - strLen + 1;
+
+ do
+ {
+ filePos -= filePosStep;
+
+ if (filePos < 0)
+ {
+ filePos = 0;
+ bExit = TRUE;
+ }
+
+ seekOffset.QuadPart = filePos;
+
+ if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
+ goto fsif_end;
+
+ if ((readRetVal = ReadFile (src, buffer, bufSize, &bytesRead, NULL)) == 0
+ || bytesRead == 0)
+ goto fsif_end;
+
+ bufPos = bytesRead - strLen;
+
+ while (bufPos > 0)
+ {
+ if (memcmp (buffer + bufPos, str, strLen) == 0)
+ {
+ // String found
+ retVal = filePos + bufPos;
+ goto fsif_end;
+ }
+ bufPos--;
+ }
+
+ } while (!bExit);
+
+fsif_end:
+ CloseHandle (src);
+ free (buffer);
+
+ return retVal;
+}
+
+// System CopyFile() copies source file attributes (like FILE_ATTRIBUTE_ENCRYPTED)
+// so we need to use our own copy function
+BOOL TCCopyFile (char *sourceFileName, char *destinationFile)
+{
+ __int8 *buffer;
+ HANDLE src, dst;
+ FILETIME fileTime;
+ DWORD bytesRead, bytesWritten;
+ BOOL res;
+
+ src = CreateFile (sourceFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (src == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ dst = CreateFile (destinationFile,
+ GENERIC_WRITE,
+ 0, NULL, CREATE_ALWAYS, 0, NULL);
+
+ if (dst == INVALID_HANDLE_VALUE)
+ {
+ CloseHandle (src);
+ return FALSE;
+ }
+
+ buffer = (char *) malloc (64 * 1024);
+ if (!buffer)
+ {
+ CloseHandle (src);
+ CloseHandle (dst);
+ return FALSE;
+ }
+
+ while (res = ReadFile (src, buffer, 64 * 1024, &bytesRead, NULL))
+ {
+ if (bytesRead == 0)
+ {
+ res = 1;
+ break;
+ }
+
+ if (!WriteFile (dst, buffer, bytesRead, &bytesWritten, NULL)
+ || bytesRead != bytesWritten)
+ {
+ res = 0;
+ break;
+ }
+ }
+
+ GetFileTime (src, NULL, NULL, &fileTime);
+ SetFileTime (dst, NULL, NULL, &fileTime);
+
+ CloseHandle (src);
+ CloseHandle (dst);
+
+ free (buffer);
+ return res != 0;
+}
+
+// If bAppend is TRUE, the buffer is appended to an existing file. If bAppend is FALSE, any existing file
+// is replaced. If an error occurs, the incomplete file is deleted (provided that bAppend is FALSE).
+BOOL SaveBufferToFile (const char *inputBuffer, const char *destinationFile, DWORD inputLength, BOOL bAppend)
+{
+ HANDLE dst;
+ DWORD bytesWritten;
+ BOOL res = TRUE;
+
+ dst = CreateFile (destinationFile,
+ GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, bAppend ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
+
+ if (dst == INVALID_HANDLE_VALUE)
+ {
+ handleWin32Error (MainDlg);
+ return FALSE;
+ }
+
+ if (bAppend)
+ SetFilePointer (dst, 0, NULL, FILE_END);
+
+ if (!WriteFile (dst, inputBuffer, inputLength, &bytesWritten, NULL)
+ || inputLength != bytesWritten)
+ {
+ res = FALSE;
+ }
+
+ if (!res)
+ {
+ // If CREATE_ALWAYS is used, ERROR_ALREADY_EXISTS is returned after successful overwrite
+ // of an existing file (it's not an error)
+ if (! (GetLastError() == ERROR_ALREADY_EXISTS && !bAppend) )
+ handleWin32Error (MainDlg);
+ }
+
+ CloseHandle (dst);
+
+ if (!res && !bAppend)
+ remove (destinationFile);
+
+ return res;
+}
+
+
+// Proper flush for Windows systems. Returns TRUE if successful.
+BOOL TCFlushFile (FILE *f)
+{
+ HANDLE hf = (HANDLE) _get_osfhandle (_fileno (f));
+
+ fflush (f);
+
+ if (hf == INVALID_HANDLE_VALUE)
+ return FALSE;
+
+ return FlushFileBuffers (hf) != 0;
+}
+
+
+// Prints a UTF-16 text (note that this involves a real printer, not a screen).
+// textByteLen - length of the text in bytes
+// title - printed as part of the page header and used as the filename for a temporary file
+BOOL PrintHardCopyTextUTF16 (wchar_t *text, char *title, int textByteLen)
+{
+ char cl [MAX_PATH*3] = {"/p \""};
+ char path [MAX_PATH * 2] = { 0 };
+ char filename [MAX_PATH + 1] = { 0 };
+
+ strcpy (filename, title);
+ //strcat (filename, ".txt");
+
+ GetTempPath (sizeof (path), path);
+
+ if (!FileExists (path))
+ {
+ strcpy (path, GetConfigPath (filename));
+
+ if (strlen(path) < 2)
+ return FALSE;
+ }
+ else
+ {
+ strcat (path, filename);
+ }
+
+ // Write the Unicode signature
+ if (!SaveBufferToFile ("\xFF\xFE", path, 2, FALSE))
+ {
+ remove (path);
+ return FALSE;
+ }
+
+ // Write the actual text
+ if (!SaveBufferToFile ((char *) text, path, textByteLen, TRUE))
+ {
+ remove (path);
+ return FALSE;
+ }
+
+ strcat (cl, path);
+ strcat (cl, "\"");
+
+ WaitCursor ();
+ ShellExecute (NULL, "open", PRINT_TOOL, cl, NULL, SW_HIDE);
+ Sleep (6000);
+ NormalCursor();
+
+ remove (path);
+
+ return TRUE;
+}
+
+
+BOOL IsNonInstallMode ()
+{
+ HKEY hkey;
+ DWORD dw;
+
+ if (bPortableModeConfirmed)
+ return TRUE;
+
+ if (hDriver != INVALID_HANDLE_VALUE)
+ {
+ // The driver is running
+ if (DeviceIoControl (hDriver, TC_IOCTL_GET_PORTABLE_MODE_STATUS, NULL, 0, NULL, 0, &dw, 0))
+ {
+ bPortableModeConfirmed = TRUE;
+ return TRUE;
+ }
+ else
+ {
+ // This is also returned if we fail to determine the status (it does not mean that portable mode is disproved).
+ return FALSE;
+ }
+ }
+ else
+ {
+ // The tests in this block are necessary because this function is in some cases called before DriverAttach().
+
+ HANDLE hDriverTmp = CreateFile (WIN32_ROOT_PREFIX, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (hDriverTmp == INVALID_HANDLE_VALUE)
+ {
+ // The driver was not found in the system path
+
+ char path[MAX_PATH * 2] = { 0 };
+
+ // We can't use GetConfigPath() here because it would call us back (indirect recursion)
+ if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_APPDATA, NULL, 0, path)))
+ {
+ strcat (path, "\\TrueCrypt\\");
+ strcat (path, TC_APPD_FILENAME_SYSTEM_ENCRYPTION);
+
+ if (FileExists (path))
+ {
+ // To maintain consistency and safety, if the system encryption config file exits, we cannot
+ // allow portable mode. (This happens e.g. when the pretest fails and the user selects
+ // "Last Known Good Configuration" from the Windows boot menu.)
+
+ // However, if UAC elevation is needed, we have to confirm portable mode first (after we are elevated, we won't).
+ if (!IsAdmin () && IsUacSupported ())
+ return TRUE;
+
+ return FALSE;
+ }
+ }
+
+ // As the driver was not found in the system path, we can predict that we will run in portable mode
+ return TRUE;
+ }
+ else
+ CloseHandle (hDriverTmp);
+ }
+
+ // The following test may be unreliable in some cases (e.g. after the user selects restore "Last Known Good
+ // Configuration" from the Windows boot menu).
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\TrueCrypt", 0, KEY_READ, &hkey) == ERROR_SUCCESS)
+ {
+ RegCloseKey (hkey);
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+
+LRESULT SetCheckBox (HWND hwndDlg, int dlgItem, BOOL state)
+{
+ return SendDlgItemMessage (hwndDlg, dlgItem, BM_SETCHECK, state ? BST_CHECKED : BST_UNCHECKED, 0);
+}
+
+
+BOOL GetCheckBox (HWND hwndDlg, int dlgItem)
+{
+ return IsButtonChecked (GetDlgItem (hwndDlg, dlgItem));
+}
+
+
+// Scroll the listview vertically so that the item with index of topMostVisibleItem is the topmost visible item.
+void SetListScrollHPos (HWND hList, int topMostVisibleItem)
+{
+ int testedPos = 0;
+
+ do
+ {
+ SendMessage (hList, LVM_SCROLL, 0, testedPos);
+
+ } while (ListView_GetTopIndex (hList) < topMostVisibleItem && ++testedPos < 10000);
+}
+
+
+// Adds or removes TrueCrypt.exe to/from the system startup sequence (with appropriate command line arguments)
+void ManageStartupSeq (void)
+{
+ if (!IsNonInstallMode ())
+ {
+ char regk [64];
+
+ GetStartupRegKeyName (regk);
+
+ if (bStartOnLogon || bMountDevicesOnLogon || bMountFavoritesOnLogon)
+ {
+ char exe[MAX_PATH * 2] = { '"' };
+
+ GetModuleFileName (NULL, exe + 1, sizeof (exe) - 1);
+
+#ifdef VOLFORMAT
+ {
+ char *tmp = NULL;
+
+ if (tmp = strrchr (exe, '\\'))
+ strcpy (++tmp, "TrueCrypt.exe");
+ }
+#endif
+ strcat (exe, "\" /q preferences /a logon");
+
+ if (bMountDevicesOnLogon) strcat (exe, " /a devices");
+ if (bMountFavoritesOnLogon) strcat (exe, " /a favorites");
+
+ WriteRegistryString (regk, "TrueCrypt", exe);
+ }
+ else
+ DeleteRegistryValue (regk, "TrueCrypt");
+ }
+}
+
+
+// Adds or removes the TrueCrypt Volume Creation Wizard to/from the system startup sequence
+void ManageStartupSeqWiz (BOOL bRemove, const char *arg)
+{
+ char regk [64];
+
+ GetStartupRegKeyName (regk);
+
+ if (!bRemove)
+ {
+ char exe[MAX_PATH * 2] = { '"' };
+ GetModuleFileName (NULL, exe + 1, sizeof (exe) - 1);
+
+#ifndef VOLFORMAT
+ {
+ char *tmp = NULL;
+
+ if (tmp = strrchr (exe, '\\'))
+ strcpy (++tmp, "TrueCrypt Format.exe");
+ }
+#endif
+
+ if (strlen (arg) > 0)
+ {
+ strcat (exe, "\" ");
+ strcat (exe, arg);
+ }
+
+ WriteRegistryString (regk, "TrueCrypt Format", exe);
+ }
+ else
+ DeleteRegistryValue (regk, "TrueCrypt Format");
+}
+
+
+// Delete the last used Windows file selector path for TrueCrypt from the registry
+void CleanLastVisitedMRU (void)
+{
+ WCHAR exeFilename[MAX_PATH];
+ WCHAR *strToMatch;
+
+ WCHAR strTmp[4096];
+ char regPath[128];
+ char key[64];
+ int id, len;
+
+ GetModuleFileNameW (NULL, exeFilename, sizeof (exeFilename) / sizeof(exeFilename[0]));
+ strToMatch = wcsrchr (exeFilename, '\\') + 1;
+
+ sprintf (regPath, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisited%sMRU", IsOSAtLeast (WIN_VISTA) ? "Pidl" : "");
+
+ for (id = (IsOSAtLeast (WIN_VISTA) ? 0 : 'a'); id <= (IsOSAtLeast (WIN_VISTA) ? 1000 : 'z'); id++)
+ {
+ *strTmp = 0;
+ sprintf (key, (IsOSAtLeast (WIN_VISTA) ? "%d" : "%c"), id);
+
+ if ((len = ReadRegistryBytes (regPath, key, (char *) strTmp, sizeof (strTmp))) > 0)
+ {
+ if (_wcsicmp (strTmp, strToMatch) == 0)
+ {
+ char buf[65536], bufout[sizeof (buf)];
+
+ // Overwrite the entry with zeroes while keeping its original size
+ memset (strTmp, 0, len);
+ if (!WriteRegistryBytes (regPath, key, (char *) strTmp, len))
+ MessageBoxW (NULL, GetString ("CLEAN_WINMRU_FAILED"), lpszTitle, ICON_HAND);
+
+ DeleteRegistryValue (regPath, key);
+
+ // Remove ID from MRUList
+ if (IsOSAtLeast (WIN_VISTA))
+ {
+ int *p = (int *)buf;
+ int *pout = (int *)bufout;
+ int l;
+
+ l = len = ReadRegistryBytes ("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRU", "MRUListEx", buf, sizeof (buf));
+ while (l > 0)
+ {
+ l -= sizeof (int);
+
+ if (*p == id)
+ {
+ p++;
+ len -= sizeof (int);
+ continue;
+ }
+ *pout++ = *p++;
+ }
+
+ WriteRegistryBytes ("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRU", "MRUListEx", bufout, len);
+ }
+ else
+ {
+ char *p = buf;
+ char *pout = bufout;
+
+ ReadRegistryString ("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", "MRUList", "", buf, sizeof (buf));
+ while (*p)
+ {
+ if (*p == id)
+ {
+ p++;
+ continue;
+ }
+ *pout++ = *p++;
+ }
+ *pout++ = 0;
+
+ WriteRegistryString ("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", "MRUList", bufout);
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+
+#ifndef SETUP
+void ClearHistory (HWND hwndDlgItem)
+{
+ ArrowWaitCursor ();
+
+ ClearCombo (hwndDlgItem);
+ DumpCombo (hwndDlgItem, TRUE);
+
+ CleanLastVisitedMRU ();
+
+ NormalCursor ();
+}
+#endif // #ifndef SETUP
+
+
+LRESULT ListItemAdd (HWND list, int index, char *string)
+{
+ LVITEM li;
+ memset (&li, 0, sizeof(li));
+
+ li.mask = LVIF_TEXT;
+ li.pszText = string;
+ li.iItem = index;
+ li.iSubItem = 0;
+ return ListView_InsertItem (list, &li);
+}
+
+
+LRESULT ListItemAddW (HWND list, int index, wchar_t *string)
+{
+ LVITEMW li;
+ memset (&li, 0, sizeof(li));
+
+ li.mask = LVIF_TEXT;
+ li.pszText = string;
+ li.iItem = index;
+ li.iSubItem = 0;
+ return SendMessageW (list, LVM_INSERTITEMW, 0, (LPARAM)(&li));
+}
+
+
+LRESULT ListSubItemSet (HWND list, int index, int subIndex, char *string)
+{
+ LVITEM li;
+ memset (&li, 0, sizeof(li));
+
+ li.mask = LVIF_TEXT;
+ li.pszText = string;
+ li.iItem = index;
+ li.iSubItem = subIndex;
+ return ListView_SetItem (list, &li);
+}
+
+
+LRESULT ListSubItemSetW (HWND list, int index, int subIndex, wchar_t *string)
+{
+ LVITEMW li;
+ memset (&li, 0, sizeof(li));
+
+ li.mask = LVIF_TEXT;
+ li.pszText = string;
+ li.iItem = index;
+ li.iSubItem = subIndex;
+ return SendMessageW (list, LVM_SETITEMW, 0, (LPARAM)(&li));
+}
+
+
+BOOL GetMountList (MOUNT_LIST_STRUCT *list)
+{
+ DWORD dwResult;
+
+ memset (list, 0, sizeof (*list));
+ return DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, list,
+ sizeof (*list), list, sizeof (*list), &dwResult,
+ NULL);
+}
+
+
+int GetDriverRefCount ()
+{
+ DWORD dwResult;
+ BOOL bResult;
+ int refCount;
+
+ bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_DEVICE_REFCOUNT, &refCount, sizeof (refCount), &refCount,
+ sizeof (refCount), &dwResult, NULL);
+
+ if (bResult)
+ return refCount;
+ else
+ return -1;
+}
+
+// Loads a 32-bit integer from the file at the specified file offset. The saved value is assumed to have been
+// processed by mputLong(). The result is stored in *result. Returns TRUE if successful (otherwise FALSE).
+BOOL LoadInt32 (char *filePath, unsigned __int32 *result, __int64 fileOffset)
+{
+ size_t bufSize = sizeof(__int32);
+ unsigned char *buffer = (unsigned char *) malloc (bufSize);
+ unsigned char *bufferPtr = buffer;
+ HANDLE src = NULL;
+ DWORD bytesRead;
+ LARGE_INTEGER seekOffset, seekOffsetNew;
+ BOOL retVal = FALSE;
+
+ if (buffer == NULL)
+ return -1;
+
+ src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (src == INVALID_HANDLE_VALUE)
+ {
+ free (buffer);
+ return FALSE;
+ }
+
+ seekOffset.QuadPart = fileOffset;
+
+ if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
+ goto fsif_end;
+
+ if (ReadFile (src, buffer, bufSize, &bytesRead, NULL) == 0
+ || bytesRead != bufSize)
+ goto fsif_end;
+
+
+ retVal = TRUE;
+
+ *result = mgetLong(bufferPtr);
+
+fsif_end:
+ CloseHandle (src);
+ free (buffer);
+
+ return retVal;
+}
+
+// Loads a 16-bit integer from the file at the specified file offset. The saved value is assumed to have been
+// processed by mputWord(). The result is stored in *result. Returns TRUE if successful (otherwise FALSE).
+BOOL LoadInt16 (char *filePath, int *result, __int64 fileOffset)
+{
+ size_t bufSize = sizeof(__int16);
+ unsigned char *buffer = (unsigned char *) malloc (bufSize);
+ unsigned char *bufferPtr = buffer;
+ HANDLE src = NULL;
+ DWORD bytesRead;
+ LARGE_INTEGER seekOffset, seekOffsetNew;
+ BOOL retVal = FALSE;
+
+ if (buffer == NULL)
+ return -1;
+
+ src = CreateFile (filePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (src == INVALID_HANDLE_VALUE)
+ {
+ free (buffer);
+ return FALSE;
+ }
+
+ seekOffset.QuadPart = fileOffset;
+
+ if (SetFilePointerEx (src, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
+ goto fsif_end;
+
+ if (ReadFile (src, buffer, bufSize, &bytesRead, NULL) == 0
+ || bytesRead != bufSize)
+ goto fsif_end;
+
+
+ retVal = TRUE;
+
+ *result = mgetWord(bufferPtr);
+
+fsif_end:
+ CloseHandle (src);
+ free (buffer);
+
+ return retVal;
+}
+
+// Returns NULL if there's any error. Although the buffer can contain binary data, it is always null-terminated.
+char *LoadFile (const char *fileName, DWORD *size)
+{
+ char *buf;
+ HANDLE h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ *size = GetFileSize (h, NULL);
+ buf = (char *) malloc (*size + 1);
+
+ if (buf == NULL)
+ {
+ CloseHandle (h);
+ return NULL;
+ }
+
+ ZeroMemory (buf, *size + 1);
+
+ if (!ReadFile (h, buf, *size, size, NULL))
+ {
+ free (buf);
+ buf = NULL;
+ }
+
+ CloseHandle (h);
+ return buf;
+}
+
+
+// Returns NULL if there's any error.
+char *LoadFileBlock (char *fileName, __int64 fileOffset, size_t count)
+{
+ char *buf;
+ DWORD bytesRead = 0;
+ LARGE_INTEGER seekOffset, seekOffsetNew;
+
+ HANDLE h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ return NULL;
+
+ seekOffset.QuadPart = fileOffset;
+
+ if (SetFilePointerEx (h, seekOffset, &seekOffsetNew, FILE_BEGIN) == 0)
+ {
+ CloseHandle (h);
+ return NULL;
+ }
+
+ buf = (char *) malloc (count);
+
+ if (buf == NULL)
+ {
+ CloseHandle (h);
+ return NULL;
+ }
+
+ ZeroMemory (buf, count);
+
+ if (buf != NULL)
+ ReadFile (h, buf, count, &bytesRead, NULL);
+
+ CloseHandle (h);
+
+ if (bytesRead != count)
+ {
+ free (buf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+
+// Returns -1 if there is an error, or the size of the file.
+__int64 GetFileSize64 (const char *path)
+{
+ HANDLE h = CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ LARGE_INTEGER size;
+
+ if (h == INVALID_HANDLE_VALUE)
+ return -1;
+
+ if (GetFileSizeEx (h, &size) == 0)
+ return -1;
+
+ CloseHandle (h);
+
+ return size.QuadPart;
+}
+
+
+char *GetModPath (char *path, int maxSize)
+{
+ GetModuleFileName (NULL, path, maxSize);
+ strrchr (path, '\\')[1] = 0;
+ return path;
+}
+
+
+char *GetConfigPath (char *fileName)
+{
+ static char path[MAX_PATH * 2] = { 0 };
+
+ if (IsNonInstallMode ())
+ {
+ GetModPath (path, sizeof (path));
+ strcat (path, fileName);
+
+ return path;
+ }
+
+ if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path)))
+ {
+ strcat (path, "\\TrueCrypt\\");
+ CreateDirectory (path, NULL);
+ strcat (path, fileName);
+ }
+ else
+ path[0] = 0;
+
+ return path;
+}
+
+
+char *GetProgramConfigPath (char *fileName)
+{
+ static char path[MAX_PATH * 2] = { 0 };
+
+ if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path)))
+ {
+ strcat (path, "\\TrueCrypt\\");
+ CreateDirectory (path, NULL);
+ strcat (path, fileName);
+ }
+ else
+ path[0] = 0;
+
+ return path;
+}
+
+
+std::string GetServiceConfigPath (const char *fileName)
+{
+ char sysPath[TC_MAX_PATH];
+
+ if (Is64BitOs())
+ {
+ typedef UINT (WINAPI *GetSystemWow64Directory_t) (LPTSTR lpBuffer, UINT uSize);
+
+ GetSystemWow64Directory_t getSystemWow64Directory = (GetSystemWow64Directory_t) GetProcAddress (GetModuleHandle ("kernel32"), "GetSystemWow64DirectoryA");
+ getSystemWow64Directory (sysPath, sizeof (sysPath));
+ }
+ else
+ GetSystemDirectory (sysPath, sizeof (sysPath));
+
+ return string (sysPath) + "\\" + fileName;
+}
+
+
+// Returns 0 if an error occurs or the drive letter (as an upper-case char) of the system partition (e.g. 'C');
+char GetSystemDriveLetter (void)
+{
+ char systemDir [MAX_PATH];
+
+ if (GetSystemDirectory (systemDir, sizeof (systemDir)))
+ return (char) (toupper (systemDir [0]));
+ else
+ return 0;
+}
+
+
+void TaskBarIconDisplayBalloonTooltip (HWND hwnd, wchar_t *headline, wchar_t *text, BOOL warning)
+{
+ if (nCurrentOS == WIN_2000)
+ {
+ MessageBoxW (MainDlg, text, headline, warning ? MB_ICONWARNING : MB_ICONINFORMATION);
+ return;
+ }
+
+ NOTIFYICONDATAW tnid;
+
+ ZeroMemory (&tnid, sizeof (tnid));
+
+ tnid.cbSize = sizeof (tnid);
+ tnid.hWnd = hwnd;
+ tnid.uID = IDI_TRUECRYPT_ICON;
+ //tnid.uVersion = (IsOSAtLeast (WIN_VISTA) ? NOTIFYICON_VERSION_4 : NOTIFYICON_VERSION);
+
+ //Shell_NotifyIconW (NIM_SETVERSION, &tnid);
+
+ tnid.uFlags = NIF_INFO;
+ tnid.dwInfoFlags = (warning ? NIIF_WARNING : NIIF_INFO);
+ tnid.uTimeout = (IsOSAtLeast (WIN_VISTA) ? 1000 : 5000); // in ms
+
+ wcsncpy (tnid.szInfoTitle, headline, ARRAYSIZE (tnid.szInfoTitle) - 1);
+ wcsncpy (tnid.szInfo, text, ARRAYSIZE (tnid.szInfo) - 1);
+
+ // Display the balloon tooltip quickly twice in a row to avoid the slow and unwanted "fade-in" phase
+ Shell_NotifyIconW (NIM_MODIFY, &tnid);
+ Shell_NotifyIconW (NIM_MODIFY, &tnid);
+}
+
+
+// Either of the pointers may be NULL
+void InfoBalloon (char *headingStringId, char *textStringId)
+{
+ if (Silent)
+ return;
+
+ TaskBarIconDisplayBalloonTooltip (MainDlg,
+ headingStringId == NULL ? L"TrueCrypt" : GetString (headingStringId),
+ textStringId == NULL ? L" " : GetString (textStringId),
+ FALSE);
+}
+
+
+// Either of the pointers may be NULL
+void InfoBalloonDirect (wchar_t *headingString, wchar_t *textString)
+{
+ if (Silent)
+ return;
+
+ TaskBarIconDisplayBalloonTooltip (MainDlg,
+ headingString == NULL ? L"TrueCrypt" : headingString,
+ textString == NULL ? L" " : textString,
+ FALSE);
+}
+
+
+// Either of the pointers may be NULL
+void WarningBalloon (char *headingStringId, char *textStringId)
+{
+ if (Silent)
+ return;
+
+ TaskBarIconDisplayBalloonTooltip (MainDlg,
+ headingStringId == NULL ? L"TrueCrypt" : GetString (headingStringId),
+ textStringId == NULL ? L" " : GetString (textStringId),
+ TRUE);
+}
+
+
+// Either of the pointers may be NULL
+void WarningBalloonDirect (wchar_t *headingString, wchar_t *textString)
+{
+ if (Silent)
+ return;
+
+ TaskBarIconDisplayBalloonTooltip (MainDlg,
+ headingString == NULL ? L"TrueCrypt" : headingString,
+ textString == NULL ? L" " : textString,
+ TRUE);
+}
+
+
+int Info (char *stringId)
+{
+ if (Silent) return 0;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONINFORMATION);
+}
+
+
+int InfoTopMost (char *stringId)
+{
+ if (Silent) return 0;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+int InfoDirect (const wchar_t *msg)
+{
+ if (Silent) return 0;
+ return MessageBoxW (MainDlg, msg, lpszTitle, MB_ICONINFORMATION);
+}
+
+
+int Warning (char *stringId)
+{
+ if (Silent) return 0;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONWARNING);
+}
+
+
+int WarningTopMost (char *stringId)
+{
+ if (Silent) return 0;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+int WarningDirect (const wchar_t *warnMsg)
+{
+ if (Silent) return 0;
+ return MessageBoxW (MainDlg, warnMsg, lpszTitle, MB_ICONWARNING);
+}
+
+
+int Error (char *stringId)
+{
+ if (Silent) return 0;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONERROR);
+}
+
+
+int ErrorTopMost (char *stringId)
+{
+ if (Silent) return 0;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+int ErrorDirect (const wchar_t *errMsg)
+{
+ if (Silent) return 0;
+ return MessageBoxW (MainDlg, errMsg, lpszTitle, MB_ICONERROR);
+}
+
+
+int AskYesNo (char *stringId)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1);
+}
+
+
+int AskYesNoString (const wchar_t *str)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, str, lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1);
+}
+
+
+int AskYesNoTopmost (char *stringId)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+int AskNoYes (char *stringId)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
+}
+
+
+int AskOkCancel (char *stringId)
+{
+ if (Silent) return IDCANCEL;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_OKCANCEL | MB_DEFBUTTON1);
+}
+
+
+int AskWarnYesNo (char *stringId)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1);
+}
+
+
+int AskWarnYesNoString (const wchar_t *string)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, string, lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1);
+}
+
+
+int AskWarnYesNoTopmost (char *stringId)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+int AskWarnYesNoStringTopmost (const wchar_t *string)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, string, lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+int AskWarnNoYes (char *stringId)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2);
+}
+
+
+int AskWarnNoYesString (const wchar_t *string)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, string, lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2);
+}
+
+
+int AskWarnNoYesTopmost (char *stringId)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+int AskWarnOkCancel (char *stringId)
+{
+ if (Silent) return IDCANCEL;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1);
+}
+
+
+int AskWarnCancelOk (char *stringId)
+{
+ if (Silent) return IDCANCEL;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2);
+}
+
+
+int AskErrYesNo (char *stringId)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONERROR | MB_YESNO | MB_DEFBUTTON1);
+}
+
+
+int AskErrNoYes (char *stringId)
+{
+ if (Silent) return IDNO;
+ return MessageBoxW (MainDlg, GetString (stringId), lpszTitle, MB_ICONERROR | MB_YESNO | MB_DEFBUTTON2);
+}
+
+
+// The function accepts two input formats:
+// Input format 1: {0, "MESSAGE_STRING_ID", "BUTTON_1_STRING_ID", ... "LAST_BUTTON_STRING_ID", 0};
+// Input format 2: {L"", L"Message text", L"Button caption 1", ... L"Last button caption", 0};
+// The second format is to be used if any of the strings contains format specification (e.g. %s, %d) or
+// in any other cases where a string needs to be resolved before calling this function.
+// If the returned value is 0, the user closed the dialog window without making a choice.
+// If the user made a choice, the returned value is the ordinal number of the choice (1..MAX_MULTI_CHOICES)
+int AskMultiChoice (void *strings[], BOOL bBold)
+{
+ MULTI_CHOICE_DLGPROC_PARAMS params;
+
+ params.strings = &strings[0];
+ params.bold = bBold;
+
+ return DialogBoxParamW (hInst,
+ MAKEINTRESOURCEW (IDD_MULTI_CHOICE_DLG), MainDlg,
+ (DLGPROC) MultiChoiceDialogProc, (LPARAM) ¶ms);
+}
+
+
+BOOL ConfigWriteBegin ()
+{
+ DWORD size;
+ if (ConfigFileHandle != NULL)
+ return FALSE;
+
+ if (ConfigBuffer == NULL)
+ ConfigBuffer = LoadFile (GetConfigPath (TC_APPD_FILENAME_CONFIGURATION), &size);
+
+ ConfigFileHandle = fopen (GetConfigPath (TC_APPD_FILENAME_CONFIGURATION), "w");
+ if (ConfigFileHandle == NULL)
+ {
+ free (ConfigBuffer);
+ ConfigBuffer = NULL;
+ return FALSE;
+ }
+ XmlWriteHeader (ConfigFileHandle);
+ fputs ("\n\t<configuration>", ConfigFileHandle);
+
+ return TRUE;
+}
+
+
+BOOL ConfigWriteEnd ()
+{
+ char *xml = ConfigBuffer;
+ char key[128], value[2048];
+
+ if (ConfigFileHandle == NULL) return FALSE;
+
+ // Write unmodified values
+ while (xml && (xml = XmlFindElement (xml, "config")))
+ {
+ XmlGetAttributeText (xml, "key", key, sizeof (key));
+ XmlGetNodeText (xml, value, sizeof (value));
+
+ fprintf (ConfigFileHandle, "\n\t\t<config key=\"%s\">%s</config>", key, value);
+ xml++;
+ }
+
+ fputs ("\n\t</configuration>", ConfigFileHandle);
+ XmlWriteFooter (ConfigFileHandle);
+
+ TCFlushFile (ConfigFileHandle);
+
+ CheckFileStreamWriteErrors (ConfigFileHandle, TC_APPD_FILENAME_CONFIGURATION);
+
+ fclose (ConfigFileHandle);
+ ConfigFileHandle = NULL;
+
+ if (ConfigBuffer != NULL)
+ {
+ DWORD size;
+ free (ConfigBuffer);
+ ConfigBuffer = LoadFile (GetConfigPath (TC_APPD_FILENAME_CONFIGURATION), &size);
+ }
+
+ return TRUE;
+}
+
+
+BOOL ConfigWriteString (char *configKey, char *configValue)
+{
+ char *c;
+ if (ConfigFileHandle == NULL)
+ return FALSE;
+
+ // Mark previous config value as updated
+ if (ConfigBuffer != NULL)
+ {
+ c = XmlFindElementByAttributeValue (ConfigBuffer, "config", "key", configKey);
+ if (c != NULL)
+ c[1] = '!';
+ }
+
+ return 0 != fprintf (
+ ConfigFileHandle, "\n\t\t<config key=\"%s\">%s</config>",
+ configKey, configValue);
+}
+
+
+BOOL ConfigWriteInt (char *configKey, int configValue)
+{
+ char val[32];
+ sprintf (val, "%d", configValue);
+ return ConfigWriteString (configKey, val);
+}
+
+
+static BOOL ConfigRead (char *configKey, char *configValue, int maxValueSize)
+{
+ DWORD size;
+ char *xml;
+
+ if (ConfigBuffer == NULL)
+ ConfigBuffer = LoadFile (GetConfigPath (TC_APPD_FILENAME_CONFIGURATION), &size);
+
+ xml = ConfigBuffer;
+ if (xml != NULL)
+ {
+ xml = XmlFindElementByAttributeValue (xml, "config", "key", configKey);
+ if (xml != NULL)
+ {
+ XmlGetNodeText (xml, configValue, maxValueSize);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+int ConfigReadInt (char *configKey, int defaultValue)
+{
+ char s[32];
+
+ if (ConfigRead (configKey, s, sizeof (s)))
+ return atoi (s);
+ else
+ return defaultValue;
+}
+
+
+char *ConfigReadString (char *configKey, char *defaultValue, char *str, int maxLen)
+{
+ if (ConfigRead (configKey, str, maxLen))
+ return str;
+ else
+ return defaultValue;
+}
+
+
+void OpenPageHelp (HWND hwndDlg, int nPage)
+{
+ int r = (int)ShellExecute (NULL, "open", szHelpFile, NULL, NULL, SW_SHOWNORMAL);
+
+ if (r == ERROR_FILE_NOT_FOUND)
+ {
+ // Try the secondary help file
+ r = (int)ShellExecute (NULL, "open", szHelpFile2, NULL, NULL, SW_SHOWNORMAL);
+
+ if (r == ERROR_FILE_NOT_FOUND)
+ {
+ OpenOnlineHelp ();
+ return;
+ }
+ }
+
+ if (r == SE_ERR_NOASSOC)
+ {
+ if (AskYesNo ("HELP_READER_ERROR") == IDYES)
+ OpenOnlineHelp ();
+ }
+}
+
+
+void OpenOnlineHelp ()
+{
+ Applink ("help", TRUE, "");
+}
+
+
+#ifndef SETUP
+
+void RestoreDefaultKeyFilesParam (void)
+{
+ KeyFileRemoveAll (&FirstKeyFile);
+ if (defaultKeyFilesParam.FirstKeyFile != NULL)
+ {
+ FirstKeyFile = KeyFileCloneAll (defaultKeyFilesParam.FirstKeyFile);
+ KeyFilesEnable = defaultKeyFilesParam.EnableKeyFiles;
+ }
+ else
+ KeyFilesEnable = FALSE;
+}
+
+
+BOOL LoadDefaultKeyFilesParam (void)
+{
+ BOOL status = TRUE;
+ DWORD size;
+ char *defaultKeyfilesFile = LoadFile (GetConfigPath (TC_APPD_FILENAME_DEFAULT_KEYFILES), &size);
+ char *xml = defaultKeyfilesFile;
+ KeyFile *kf;
+
+ if (xml == NULL)
+ return FALSE;
+
+ KeyFileRemoveAll (&defaultKeyFilesParam.FirstKeyFile);
+
+ while (xml = XmlFindElement (xml, "keyfile"))
+ {
+ kf = (KeyFile *) malloc (sizeof (KeyFile));
+
+ if (XmlGetNodeText (xml, kf->FileName, sizeof (kf->FileName)) != NULL)
+ defaultKeyFilesParam.FirstKeyFile = KeyFileAdd (defaultKeyFilesParam.FirstKeyFile, kf);
+ else
+ free (kf);
+
+ xml++;
+ }
+
+ free (defaultKeyfilesFile);
+ KeyFilesEnable = defaultKeyFilesParam.EnableKeyFiles;
+
+ return status;
+}
+
+#endif /* #ifndef SETUP */
+
+
+void Debug (char *format, ...)
+{
+ char buf[1024];
+ va_list val;
+
+ va_start(val, format);
+ _vsnprintf (buf, sizeof (buf), format, val);
+ va_end(val);
+
+ OutputDebugString (buf);
+}
+
+
+void DebugMsgBox (char *format, ...)
+{
+ char buf[1024];
+ va_list val;
+
+ va_start(val, format);
+ _vsnprintf (buf, sizeof (buf), format, val);
+ va_end(val);
+
+ MessageBox (MainDlg, buf, "TrueCrypt debug", 0);
+}
+
+
+BOOL IsOSAtLeast (OSVersionEnum reqMinOS)
+{
+ return IsOSVersionAtLeast (reqMinOS, 0);
+}
+
+
+// Returns TRUE if the operating system is at least reqMinOS and service pack at least reqMinServicePack.
+// Example 1: IsOSVersionAtLeast (WIN_VISTA, 1) called under Windows 2008, returns TRUE.
+// Example 2: IsOSVersionAtLeast (WIN_XP, 3) called under Windows XP SP1, returns FALSE.
+// Example 3: IsOSVersionAtLeast (WIN_XP, 3) called under Windows Vista SP1, returns TRUE.
+BOOL IsOSVersionAtLeast (OSVersionEnum reqMinOS, int reqMinServicePack)
+{
+ /* When updating this function, update IsOSAtLeast() in Ntdriver.c too. */
+
+ if (CurrentOSMajor <= 0)
+ TC_THROW_FATAL_EXCEPTION;
+
+ int major = 0, minor = 0;
+
+ switch (reqMinOS)
+ {
+ case WIN_2000: major = 5; minor = 0; break;
+ case WIN_XP: major = 5; minor = 1; break;
+ case WIN_SERVER_2003: major = 5; minor = 2; break;
+ case WIN_VISTA: major = 6; minor = 0; break;
+ case WIN_7: major = 6; minor = 1; break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ break;
+ }
+
+ return ((CurrentOSMajor << 16 | CurrentOSMinor << 8 | CurrentOSServicePack)
+ >= (major << 16 | minor << 8 | reqMinServicePack));
+}
+
+
+BOOL Is64BitOs ()
+{
+ static BOOL isWow64 = FALSE;
+ static BOOL valid = FALSE;
+ typedef BOOL (__stdcall *LPFN_ISWOW64PROCESS ) (HANDLE hProcess,PBOOL Wow64Process);
+ LPFN_ISWOW64PROCESS fnIsWow64Process;
+
+ if (valid)
+ return isWow64;
+
+ fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress (GetModuleHandle("kernel32"), "IsWow64Process");
+
+ if (fnIsWow64Process != NULL)
+ if (!fnIsWow64Process (GetCurrentProcess(), &isWow64))
+ isWow64 = FALSE;
+
+ valid = TRUE;
+ return isWow64;
+}
+
+
+BOOL IsServerOS ()
+{
+ OSVERSIONINFOEXA osVer;
+ osVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXA);
+ GetVersionExA ((LPOSVERSIONINFOA) &osVer);
+
+ return (osVer.wProductType == VER_NT_SERVER || osVer.wProductType == VER_NT_DOMAIN_CONTROLLER);
+}
+
+
+// Returns TRUE, if the currently running operating system is installed in a hidden volume. If it's not, or if
+// there's an error, returns FALSE.
+BOOL IsHiddenOSRunning (void)
+{
+ static BOOL statusCached = FALSE;
+ static BOOL hiddenOSRunning;
+
+ if (!statusCached)
+ {
+ try
+ {
+ hiddenOSRunning = BootEncryption (MainDlg).IsHiddenSystemRunning();
+ }
+ catch (...)
+ {
+ hiddenOSRunning = FALSE;
+ }
+
+ statusCached = TRUE;
+ }
+
+ return hiddenOSRunning;
+}
+
+
+BOOL EnableWow64FsRedirection (BOOL enable)
+{
+ typedef BOOLEAN (__stdcall *Wow64EnableWow64FsRedirection_t) (BOOL enable);
+ Wow64EnableWow64FsRedirection_t wow64EnableWow64FsRedirection = (Wow64EnableWow64FsRedirection_t) GetProcAddress (GetModuleHandle ("kernel32"), "Wow64EnableWow64FsRedirection");
+
+ if (!wow64EnableWow64FsRedirection)
+ return FALSE;
+
+ return wow64EnableWow64FsRedirection (enable);
+}
+
+
+BOOL RestartComputer (void)
+{
+ TOKEN_PRIVILEGES tokenPrivil;
+ HANDLE hTkn;
+
+ if (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hTkn))
+ {
+ return false;
+ }
+
+ LookupPrivilegeValue (NULL, SE_SHUTDOWN_NAME, &tokenPrivil.Privileges[0].Luid);
+ tokenPrivil.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ tokenPrivil.PrivilegeCount = 1;
+
+ AdjustTokenPrivileges (hTkn, false, &tokenPrivil, 0, (PTOKEN_PRIVILEGES) NULL, 0);
+ if (GetLastError() != ERROR_SUCCESS)
+ return false;
+
+ if (!ExitWindowsEx (EWX_REBOOT,
+ SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED))
+ return false;
+
+ return true;
+}
+
+
+std::string GetWindowsEdition ()
+{
+ string osname = "win";
+
+ OSVERSIONINFOEXA osVer;
+ osVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXA);
+ GetVersionExA ((LPOSVERSIONINFOA) &osVer);
+
+ BOOL home = (osVer.wSuiteMask & VER_SUITE_PERSONAL);
+ BOOL server = (osVer.wProductType == VER_NT_SERVER || osVer.wProductType == VER_NT_DOMAIN_CONTROLLER);
+
+ HKEY hkey;
+ char productName[300] = {0};
+ DWORD productNameSize = sizeof (productName);
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS)
+ {
+ if (RegQueryValueEx (hkey, "ProductName", 0, 0, (LPBYTE) &productName, &productNameSize) != ERROR_SUCCESS || productNameSize < 1)
+ productName[0] = 0;
+
+ RegCloseKey (hkey);
+ }
+
+ switch (nCurrentOS)
+ {
+ case WIN_2000:
+ osname += "2000";
+ break;
+
+ case WIN_XP:
+ case WIN_XP64:
+ osname += "xp";
+ osname += home ? "-home" : "-pro";
+ break;
+
+ case WIN_SERVER_2003:
+ osname += "2003";
+ break;
+
+ case WIN_VISTA:
+ osname += "vista";
+ break;
+
+ case WIN_SERVER_2008:
+ osname += "2008";
+ break;
+
+ case WIN_7:
+ osname += "7";
+ break;
+
+ case WIN_SERVER_2008_R2:
+ osname += "2008r2";
+ break;
+
+ default:
+ stringstream s;
+ s << CurrentOSMajor << "." << CurrentOSMinor;
+ osname += s.str();
+ break;
+ }
+
+ if (server)
+ osname += "-server";
+
+ if (IsOSAtLeast (WIN_VISTA))
+ {
+ if (home)
+ osname += "-home";
+ else if (strstr (productName, "Standard") != 0)
+ osname += "-standard";
+ else if (strstr (productName, "Professional") != 0)
+ osname += "-pro";
+ else if (strstr (productName, "Business") != 0)
+ osname += "-business";
+ else if (strstr (productName, "Enterprise") != 0)
+ osname += "-enterprise";
+ else if (strstr (productName, "Datacenter") != 0)
+ osname += "-datacenter";
+ else if (strstr (productName, "Ultimate") != 0)
+ osname += "-ultimate";
+ }
+
+ if (GetSystemMetrics (SM_STARTER))
+ osname += "-starter";
+ else if (strstr (productName, "Basic") != 0)
+ osname += "-basic";
+
+ if (Is64BitOs())
+ osname += "-x64";
+
+ if (CurrentOSServicePack > 0)
+ {
+ stringstream s;
+ s << "-sp" << CurrentOSServicePack;
+ osname += s.str();
+ }
+
+ return osname;
+}
+
+
+void Applink (char *dest, BOOL bSendOS, char *extraOutput)
+{
+ char url [MAX_URL_LENGTH];
+
+ ArrowWaitCursor ();
+
+ sprintf_s (url, sizeof (url), TC_APPLINK "%s%s&dest=%s", bSendOS ? ("&os=" + GetWindowsEdition()).c_str() : "", extraOutput, dest);
+ ShellExecute (NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
+
+ Sleep (200);
+ NormalCursor ();
+}
+
+
+char *RelativePath2Absolute (char *szFileName)
+{
+ if (szFileName[0] != '\\'
+ && strchr (szFileName, ':') == 0
+ && strstr (szFileName, "Volume{") != szFileName)
+ {
+ char path[MAX_PATH*2];
+ GetCurrentDirectory (MAX_PATH, path);
+
+ if (path[strlen (path) - 1] != '\\')
+ strcat (path, "\\");
+
+ strcat (path, szFileName);
+ strncpy (szFileName, path, MAX_PATH-1);
+ }
+
+ return szFileName;
+}
+
+
+void HandleDriveNotReadyError ()
+{
+ HKEY hkey = 0;
+ DWORD value = 0, size = sizeof (DWORD);
+
+ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\MountMgr",
+ 0, KEY_READ, &hkey) != ERROR_SUCCESS)
+ return;
+
+ if (RegQueryValueEx (hkey, "NoAutoMount", 0, 0, (LPBYTE) &value, &size) == ERROR_SUCCESS
+ && value != 0)
+ {
+ Warning ("SYS_AUTOMOUNT_DISABLED");
+ }
+ else if (nCurrentOS == WIN_VISTA && CurrentOSServicePack < 1)
+ Warning ("SYS_ASSIGN_DRIVE_LETTER");
+ else
+ Warning ("DEVICE_NOT_READY_ERROR");
+
+ RegCloseKey (hkey);
+}
+
+
+BOOL CALLBACK CloseTCWindowsEnum (HWND hwnd, LPARAM lParam)
+{
+ if (GetWindowLongPtr (hwnd, GWLP_USERDATA) == (LONG_PTR) 'TRUE')
+ {
+ char name[1024] = { 0 };
+ GetWindowText (hwnd, name, sizeof (name) - 1);
+ if (hwnd != MainDlg && strstr (name, "TrueCrypt"))
+ {
+ PostMessage (hwnd, TC_APPMSG_CLOSE_BKG_TASK, 0, 0);
+
+ if (DriverVersion < 0x0430)
+ PostMessage (hwnd, WM_ENDSESSION, 0, 0);
+
+ PostMessage (hwnd, WM_CLOSE, 0, 0);
+
+ if (lParam != 0)
+ *((BOOL *)lParam) = TRUE;
+ }
+ }
+ return TRUE;
+}
+
+BOOL CALLBACK FindTCWindowEnum (HWND hwnd, LPARAM lParam)
+{
+ if (*(HWND *)lParam == hwnd)
+ return TRUE;
+
+ if (GetWindowLongPtr (hwnd, GWLP_USERDATA) == (LONG_PTR) 'TRUE')
+ {
+ char name[32] = { 0 };
+ GetWindowText (hwnd, name, sizeof (name) - 1);
+ if (hwnd != MainDlg && strcmp (name, "TrueCrypt") == 0)
+ {
+ if (lParam != 0)
+ *((HWND *)lParam) = hwnd;
+ }
+ }
+ return TRUE;
+}
+
+
+BYTE *MapResource (char *resourceType, int resourceId, PDWORD size)
+{
+ HGLOBAL hResL;
+ HRSRC hRes;
+
+ hRes = FindResource (NULL, MAKEINTRESOURCE(resourceId), resourceType);
+ hResL = LoadResource (NULL, hRes);
+
+ if (size != NULL)
+ *size = SizeofResource (NULL, hRes);
+
+ return (BYTE *) LockResource (hResL);
+}
+
+
+void InconsistencyResolved (char *techInfo)
+{
+ wchar_t finalMsg[8024];
+
+ wsprintfW (finalMsg, GetString ("INCONSISTENCY_RESOLVED"), techInfo);
+ MessageBoxW (MainDlg, finalMsg, lpszTitle, MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+void ReportUnexpectedState (char *techInfo)
+{
+ wchar_t finalMsg[8024];
+
+ wsprintfW (finalMsg, GetString ("UNEXPECTED_STATE"), techInfo);
+ MessageBoxW (MainDlg, finalMsg, lpszTitle, MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+#ifndef SETUP
+
+int OpenVolume (OpenVolumeContext *context, const char *volumePath, Password *password, BOOL write, BOOL preserveTimestamps, BOOL useBackupHeader)
+{
+ int status = ERR_PARAMETER_INCORRECT;
+ int volumeType;
+ char szDiskFile[TC_MAX_PATH], szCFDevice[TC_MAX_PATH];
+ char szDosDevice[TC_MAX_PATH];
+ char buffer[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
+ LARGE_INTEGER headerOffset;
+ DWORD dwResult;
+ DISK_GEOMETRY deviceGeometry;
+
+ context->VolumeIsOpen = FALSE;
+ context->CryptoInfo = NULL;
+ context->HostFileHandle = INVALID_HANDLE_VALUE;
+ context->TimestampsValid = FALSE;
+
+ CreateFullVolumePath (szDiskFile, volumePath, &context->IsDevice);
+
+ if (context->IsDevice)
+ {
+ status = FakeDosNameForDevice (szDiskFile, szDosDevice, szCFDevice, FALSE);
+ if (status != 0)
+ return status;
+
+ preserveTimestamps = FALSE;
+
+ if (!GetDriveGeometry (volumePath, &deviceGeometry))
+ {
+ status = ERR_OS_ERROR;
+ goto error;
+ }
+ }
+ else
+ strcpy (szCFDevice, szDiskFile);
+
+ if (preserveTimestamps)
+ write = TRUE;
+
+ context->HostFileHandle = CreateFile (szCFDevice, GENERIC_READ | (write ? GENERIC_WRITE : 0), FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (context->HostFileHandle == INVALID_HANDLE_VALUE)
+ {
+ status = ERR_OS_ERROR;
+ goto error;
+ }
+
+ if (context->IsDevice)
+ {
+ // Try to gain "raw" access to the partition in case there is a live filesystem on it (otherwise,
+ // the NTFS driver guards hidden sectors and prevents e.g. header backup restore after the user
+ // accidentally quick-formats a dismounted partition-hosted TrueCrypt volume as NTFS, etc.)
+
+ DeviceIoControl (context->HostFileHandle, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0, &dwResult, NULL);
+ }
+
+ context->VolumeIsOpen = TRUE;
+
+ // Remember the container modification/creation date and time
+ if (!context->IsDevice && preserveTimestamps)
+ {
+ if (GetFileTime (context->HostFileHandle, &context->CreationTime, &context->LastAccessTime, &context->LastWriteTime) == 0)
+ context->TimestampsValid = FALSE;
+ else
+ context->TimestampsValid = TRUE;
+ }
+
+ // Determine host size
+ if (context->IsDevice)
+ {
+ PARTITION_INFORMATION diskInfo;
+
+ if (GetPartitionInfo (volumePath, &diskInfo))
+ {
+ context->HostSize = diskInfo.PartitionLength.QuadPart;
+ }
+ else
+ {
+ DISK_GEOMETRY driveInfo;
+
+ if (!DeviceIoControl (context->HostFileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveInfo, sizeof (driveInfo), &dwResult, NULL))
+ {
+ status = ERR_OS_ERROR;
+ goto error;
+ }
+
+ context->HostSize = driveInfo.Cylinders.QuadPart * driveInfo.BytesPerSector * driveInfo.SectorsPerTrack * driveInfo.TracksPerCylinder;
+ }
+
+ if (context->HostSize == 0)
+ {
+ status = ERR_VOL_SIZE_WRONG;
+ goto error;
+ }
+ }
+ else
+ {
+ LARGE_INTEGER fileSize;
+ if (!GetFileSizeEx (context->HostFileHandle, &fileSize))
+ {
+ status = ERR_OS_ERROR;
+ goto error;
+ }
+
+ context->HostSize = fileSize.QuadPart;
+ }
+
+ for (volumeType = TC_VOLUME_TYPE_NORMAL; volumeType < TC_VOLUME_TYPE_COUNT; volumeType++)
+ {
+ // Seek the volume header
+ switch (volumeType)
+ {
+ case TC_VOLUME_TYPE_NORMAL:
+ headerOffset.QuadPart = useBackupHeader ? context->HostSize - TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET;
+ break;
+
+ case TC_VOLUME_TYPE_HIDDEN:
+ if (TC_HIDDEN_VOLUME_HEADER_OFFSET + TC_VOLUME_HEADER_SIZE > context->HostSize)
+ continue;
+
+ headerOffset.QuadPart = useBackupHeader ? context->HostSize - TC_VOLUME_HEADER_SIZE : TC_HIDDEN_VOLUME_HEADER_OFFSET;
+ break;
+
+ case TC_VOLUME_TYPE_HIDDEN_LEGACY:
+ if (useBackupHeader)
+ {
+ status = ERR_PASSWORD_WRONG;
+ goto error;
+ }
+
+ if (context->IsDevice && deviceGeometry.BytesPerSector != TC_SECTOR_SIZE_LEGACY)
+ continue;
+
+ headerOffset.QuadPart = context->HostSize - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY;
+ break;
+ }
+
+ if (!SetFilePointerEx ((HANDLE) context->HostFileHandle, headerOffset, NULL, FILE_BEGIN))
+ {
+ status = ERR_OS_ERROR;
+ goto error;
+ }
+
+ // Read volume header
+ DWORD bytesRead;
+ if (!ReadEffectiveVolumeHeader (context->IsDevice, context->HostFileHandle, (byte *) buffer, &bytesRead))
+ {
+ status = ERR_OS_ERROR;
+ goto error;
+ }
+
+ if (bytesRead != sizeof (buffer)
+ && context->IsDevice)
+ {
+ // If FSCTL_ALLOW_EXTENDED_DASD_IO failed and there is a live filesystem on the partition, then the
+ // filesystem driver may report EOF when we are reading hidden sectors (when the filesystem is
+ // shorter than the partition). This can happen for example after the user quick-formats a dismounted
+ // partition-hosted TrueCrypt volume and then tries to read the embedded backup header.
+
+ memset (buffer, 0, sizeof (buffer));
+ }
+
+ // Decrypt volume header
+ status = ReadVolumeHeader (FALSE, buffer, password, &context->CryptoInfo, NULL);
+
+ if (status == ERR_PASSWORD_WRONG)
+ continue; // Try next volume type
+
+ break;
+ }
+
+ if (status == ERR_SUCCESS)
+ return status;
+
+error:
+ DWORD sysError = GetLastError ();
+
+ CloseVolume (context);
+
+ SetLastError (sysError);
+ return status;
+}
+
+
+void CloseVolume (OpenVolumeContext *context)
+{
+ if (!context->VolumeIsOpen)
+ return;
+
+ if (context->HostFileHandle != INVALID_HANDLE_VALUE)
+ {
+ if (context->TimestampsValid)
+ SetFileTime (context->HostFileHandle, &context->CreationTime, &context->LastAccessTime, &context->LastWriteTime);
+
+ CloseHandle (context->HostFileHandle);
+ context->HostFileHandle = INVALID_HANDLE_VALUE;
+ }
+
+ if (context->CryptoInfo)
+ {
+ crypto_close (context->CryptoInfo);
+ context->CryptoInfo = NULL;
+ }
+
+ context->VolumeIsOpen = FALSE;
+}
+
+
+int ReEncryptVolumeHeader (char *buffer, BOOL bBoot, CRYPTO_INFO *cryptoInfo, Password *password, BOOL wipeMode)
+{
+ CRYPTO_INFO *newCryptoInfo = NULL;
+
+ RandSetHashFunction (cryptoInfo->pkcs5);
+
+ if (Randinit() != ERR_SUCCESS)
+ return ERR_PARAMETER_INCORRECT;
+
+ UserEnrichRandomPool (NULL);
+
+ int status = CreateVolumeHeaderInMemory (bBoot,
+ buffer,
+ cryptoInfo->ea,
+ cryptoInfo->mode,
+ password,
+ cryptoInfo->pkcs5,
+ (char *) cryptoInfo->master_keydata,
+ &newCryptoInfo,
+ cryptoInfo->VolumeSize.Value,
+ cryptoInfo->hiddenVolume ? cryptoInfo->hiddenVolumeSize : 0,
+ cryptoInfo->EncryptedAreaStart.Value,
+ cryptoInfo->EncryptedAreaLength.Value,
+ cryptoInfo->RequiredProgramVersion,
+ cryptoInfo->HeaderFlags,
+ cryptoInfo->SectorSize,
+ wipeMode);
+
+ if (newCryptoInfo != NULL)
+ crypto_close (newCryptoInfo);
+
+ return status;
+}
+
+#endif // !SETUP
+
+
+BOOL IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly)
+{
+ // GlobalMemoryStatusEx() cannot be used to determine if a paging file is active
+
+ char data[65536];
+ DWORD size = sizeof (data);
+
+ if (IsPagingFileWildcardActive())
+ return TRUE;
+
+ if (ReadLocalMachineRegistryMultiString ("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", "PagingFiles", data, &size)
+ && size > 12 && !checkNonWindowsPartitionsOnly)
+ return TRUE;
+
+ if (!IsAdmin())
+ AbortProcess ("UAC_INIT_ERROR");
+
+ for (char drive = 'C'; drive <= 'Z'; ++drive)
+ {
+ // Query geometry of the drive first to prevent "no medium" pop-ups
+ string drivePath = "\\\\.\\X:";
+ drivePath[4] = drive;
+
+ if (checkNonWindowsPartitionsOnly)
+ {
+ char sysDir[MAX_PATH];
+ if (GetSystemDirectory (sysDir, sizeof (sysDir)) != 0 && toupper (sysDir[0]) == drive)
+ continue;
+ }
+
+ HANDLE handle = CreateFile (drivePath.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ continue;
+
+ DISK_GEOMETRY driveInfo;
+ DWORD dwResult;
+
+ if (!DeviceIoControl (handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveInfo, sizeof (driveInfo), &dwResult, NULL))
+ {
+ CloseHandle (handle);
+ continue;
+ }
+
+ CloseHandle (handle);
+
+ // Test if a paging file exists and is locked by another process
+ string path = "X:\\pagefile.sys";
+ path[0] = drive;
+
+ handle = CreateFile (path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (handle != INVALID_HANDLE_VALUE)
+ CloseHandle (handle);
+ else if (GetLastError() == ERROR_SHARING_VIOLATION)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+BOOL IsPagingFileWildcardActive ()
+{
+ char pagingFiles[65536];
+ DWORD size = sizeof (pagingFiles);
+ char *mmKey = "System\\CurrentControlSet\\Control\\Session Manager\\Memory Management";
+
+ if (!ReadLocalMachineRegistryString (mmKey, "PagingFiles", pagingFiles, &size))
+ {
+ size = sizeof (pagingFiles);
+ if (!ReadLocalMachineRegistryMultiString (mmKey, "PagingFiles", pagingFiles, &size))
+ size = 0;
+ }
+
+ return size > 0 && strstr (pagingFiles, "?:\\") == pagingFiles;
+}
+
+
+BOOL DisablePagingFile ()
+{
+ char empty[] = { 0, 0 };
+ return WriteLocalMachineRegistryMultiString ("System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", "PagingFiles", empty, sizeof (empty));
+}
+
+
+std::wstring SingleStringToWide (const std::string &singleString)
+{
+ if (singleString.empty())
+ return std::wstring();
+
+ WCHAR wbuf[65536];
+ int wideLen = MultiByteToWideChar (CP_ACP, 0, singleString.c_str(), -1, wbuf, array_capacity (wbuf) - 1);
+ throw_sys_if (wideLen == 0);
+
+ wbuf[wideLen] = 0;
+ return wbuf;
+}
+
+
+std::wstring Utf8StringToWide (const std::string &utf8String)
+{
+ if (utf8String.empty())
+ return std::wstring();
+
+ WCHAR wbuf[65536];
+ int wideLen = MultiByteToWideChar (CP_UTF8, 0, utf8String.c_str(), -1, wbuf, array_capacity (wbuf) - 1);
+ throw_sys_if (wideLen == 0);
+
+ wbuf[wideLen] = 0;
+ return wbuf;
+}
+
+
+std::string WideToUtf8String (const std::wstring &wideString)
+{
+ if (wideString.empty())
+ return std::string();
+
+ char buf[65536];
+ int len = WideCharToMultiByte (CP_UTF8, 0, wideString.c_str(), -1, buf, array_capacity (buf) - 1, NULL, NULL);
+ throw_sys_if (len == 0);
+
+ buf[len] = 0;
+ return buf;
+}
+
+
+std::string WideToSingleString (const std::wstring &wideString)
+{
+ if (wideString.empty())
+ return std::string();
+
+ char buf[65536];
+ int len = WideCharToMultiByte (CP_ACP, 0, wideString.c_str(), -1, buf, array_capacity (buf) - 1, NULL, NULL);
+ throw_sys_if (len == 0);
+
+ buf[len] = 0;
+ return buf;
+}
+
+
+std::string StringToUpperCase (const std::string &str)
+{
+ string upperCase (str);
+ _strupr ((char *) upperCase.c_str());
+ return upperCase;
+}
+
+
+#ifndef SETUP
+
+BOOL CALLBACK SecurityTokenPasswordDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ WORD lw = LOWORD (wParam);
+ static string *password;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ password = (string *) lParam;
+ LocalizeDialog (hwndDlg, "IDD_TOKEN_PASSWORD");
+
+ wchar_t s[1024];
+ wsprintfW (s, GetString ("ENTER_TOKEN_PASSWORD"), Utf8StringToWide (password->c_str()).c_str());
+ SetWindowTextW (GetDlgItem (hwndDlg, IDT_TOKEN_PASSWORD_INFO), s);
+
+ SendMessage (GetDlgItem (hwndDlg, IDC_TOKEN_PASSWORD), EM_LIMITTEXT, SecurityToken::MaxPasswordLength, 0);
+
+ SetForegroundWindow (hwndDlg);
+ SetFocus (GetDlgItem (hwndDlg, IDC_TOKEN_PASSWORD));
+ }
+ return 0;
+
+ case WM_COMMAND:
+ if (lw == IDCANCEL || lw == IDOK)
+ {
+ if (lw == IDOK)
+ {
+ wchar_t passwordWide[SecurityToken::MaxPasswordLength + 1];
+
+ if (GetWindowTextW (GetDlgItem (hwndDlg, IDC_TOKEN_PASSWORD), passwordWide, SecurityToken::MaxPasswordLength + 1) == 0)
+ {
+ handleWin32Error (hwndDlg);
+ break;
+ }
+
+ char passwordUtf8[SecurityToken::MaxPasswordLength + 1];
+
+ int len = WideCharToMultiByte (CP_UTF8, 0, passwordWide, -1, passwordUtf8, array_capacity (passwordUtf8) - 1, nullptr, nullptr);
+ passwordUtf8[len] = 0;
+ *password = passwordUtf8;
+
+ burn (passwordWide, sizeof (passwordWide));
+ burn (passwordUtf8, sizeof (passwordUtf8));
+ }
+
+ // Attempt to wipe password stored in the input field buffer
+ char tmp[SecurityToken::MaxPasswordLength+1];
+ memset (tmp, 'X', SecurityToken::MaxPasswordLength);
+ tmp[SecurityToken::MaxPasswordLength] = 0;
+ SetWindowText (GetDlgItem (hwndDlg, IDC_TOKEN_PASSWORD), tmp);
+
+ EndDialog (hwndDlg, lw);
+ }
+ return 1;
+ }
+
+ return 0;
+}
+
+
+struct NewSecurityTokenKeyfileDlgProcParams
+{
+ CK_SLOT_ID SlotId;
+ string Name;
+};
+
+static BOOL CALLBACK NewSecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static NewSecurityTokenKeyfileDlgProcParams *newParams;
+
+ WORD lw = LOWORD (wParam);
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ LocalizeDialog (hwndDlg, "IDD_NEW_TOKEN_KEYFILE");
+
+ newParams = (NewSecurityTokenKeyfileDlgProcParams *) lParam;
+
+ WaitCursor();
+ finally_do ({ NormalCursor(); });
+
+ list <SecurityTokenInfo> tokens;
+
+ try
+ {
+ tokens = SecurityToken::GetAvailableTokens();
+ }
+ catch (Exception &e)
+ {
+ e.Show (hwndDlg);
+ }
+
+ if (tokens.empty())
+ {
+ Error ("NO_TOKENS_FOUND");
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+
+ foreach (const SecurityTokenInfo &token, tokens)
+ {
+ wstringstream tokenLabel;
+ tokenLabel << L"[" << token.SlotId << L"] " << token.Label;
+
+ AddComboPairW (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN), tokenLabel.str().c_str(), token.SlotId);
+ }
+
+ ComboBox_SetCurSel (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN), 0);
+
+ SetWindowTextW (GetDlgItem (hwndDlg, IDC_TOKEN_KEYFILE_NAME), Utf8StringToWide (newParams->Name).c_str());
+ return 1;
+ }
+
+ case WM_COMMAND:
+ switch (lw)
+ {
+ case IDOK:
+ {
+ int selectedToken = ComboBox_GetCurSel (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN));
+ if (selectedToken == CB_ERR)
+ {
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+
+ newParams->SlotId = ComboBox_GetItemData (GetDlgItem (hwndDlg, IDC_SELECTED_TOKEN), selectedToken);
+
+ wchar_t name[1024];
+ if (GetWindowTextW (GetDlgItem (hwndDlg, IDC_TOKEN_KEYFILE_NAME), name, array_capacity (name)) != 0)
+ {
+ try
+ {
+ newParams->Name = WideToUtf8String (name);
+ }
+ catch (...) { }
+ }
+
+ EndDialog (hwndDlg, IDOK);
+ return 1;
+ }
+
+ case IDCANCEL:
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+
+ if (HIWORD (wParam) == EN_CHANGE)
+ {
+ wchar_t name[2];
+ EnableWindow (GetDlgItem (hwndDlg, IDOK), (GetWindowTextW (GetDlgItem (hwndDlg, IDC_TOKEN_KEYFILE_NAME), name, array_capacity (name)) != 0));
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void SecurityTokenKeyfileDlgFillList (HWND hwndDlg, const vector <SecurityTokenKeyfile> &keyfiles)
+{
+ HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST);
+ LVITEMW lvItem;
+ int line = 0;
+
+ ListView_DeleteAllItems (tokenListControl);
+
+ foreach (const SecurityTokenKeyfile &keyfile, keyfiles)
+ {
+ memset (&lvItem, 0, sizeof(lvItem));
+ lvItem.mask = LVIF_TEXT;
+ lvItem.iItem = line++;
+
+ stringstream s;
+ s << keyfile.SlotId;
+
+ ListItemAdd (tokenListControl, lvItem.iItem, (char *) s.str().c_str());
+ ListSubItemSetW (tokenListControl, lvItem.iItem, 1, (wchar_t *) keyfile.Token.Label.c_str());
+ ListSubItemSetW (tokenListControl, lvItem.iItem, 2, (wchar_t *) keyfile.Id.c_str());
+ }
+
+ BOOL selected = (ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST), -1, LVIS_SELECTED) != -1);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_EXPORT), selected);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_DELETE), selected);
+}
+
+
+static list <SecurityTokenKeyfile> SecurityTokenKeyfileDlgGetSelected (HWND hwndDlg, const vector <SecurityTokenKeyfile> &keyfiles)
+{
+ HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST);
+ list <SecurityTokenKeyfile> selectedKeyfiles;
+
+ int itemId = -1;
+ while ((itemId = ListView_GetNextItem (tokenListControl, itemId, LVIS_SELECTED)) != -1)
+ {
+ selectedKeyfiles.push_back (keyfiles[itemId]);
+ }
+
+ return selectedKeyfiles;
+}
+
+
+BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static list <SecurityTokenKeyfilePath> *selectedTokenKeyfiles;
+ static vector <SecurityTokenKeyfile> keyfiles;
+
+ WORD lw = LOWORD (wParam);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ selectedTokenKeyfiles = (list <SecurityTokenKeyfilePath> *) lParam;
+
+ LVCOLUMNW LvCol;
+ HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST);
+
+ LocalizeDialog (hwndDlg, selectedTokenKeyfiles ? "SELECT_TOKEN_KEYFILES" : "IDD_TOKEN_KEYFILES");
+
+ SendMessage (tokenListControl,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 ("TOKEN_SLOT_ID");
+ LvCol.cx = CompensateXDPI (40);
+ LvCol.fmt = LVCFMT_CENTER;
+ SendMessage (tokenListControl, LVM_INSERTCOLUMNW, 1, (LPARAM)&LvCol);
+
+ LvCol.pszText = GetString ("TOKEN_NAME");
+ LvCol.cx = CompensateXDPI (128);
+ LvCol.fmt = LVCFMT_LEFT;
+ SendMessage (tokenListControl, LVM_INSERTCOLUMNW, 2, (LPARAM)&LvCol);
+
+ LvCol.pszText = GetString ("TOKEN_DATA_OBJECT_LABEL");
+ LvCol.cx = CompensateXDPI (195);
+ LvCol.fmt = LVCFMT_LEFT;
+ SendMessage (tokenListControl, LVM_INSERTCOLUMNW, 3, (LPARAM)&LvCol);
+
+ keyfiles.clear();
+
+ try
+ {
+ WaitCursor();
+ finally_do ({ NormalCursor(); });
+
+ keyfiles = SecurityToken::GetAvailableKeyfiles();
+ }
+ catch (UserAbort&)
+ {
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+ catch (Exception &e)
+ {
+ e.Show (hwndDlg);
+
+ if (keyfiles.empty())
+ {
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+ }
+ }
+
+ SecurityTokenKeyfileDlgFillList (hwndDlg, keyfiles);
+ return 1;
+ }
+
+ case WM_COMMAND:
+ case WM_NOTIFY:
+ if (msg == WM_COMMAND && lw == IDOK || msg == WM_NOTIFY && ((NMHDR *)lParam)->code == LVN_ITEMACTIVATE)
+ {
+ if (selectedTokenKeyfiles)
+ {
+ foreach (const SecurityTokenKeyfile &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles))
+ {
+ selectedTokenKeyfiles->push_back (SecurityTokenKeyfilePath (keyfile));
+ }
+ }
+
+ EndDialog (hwndDlg, IDOK);
+ return 1;
+ }
+
+ if (msg == WM_NOTIFY && ((LPNMHDR) lParam)->code == LVN_ITEMCHANGED)
+ {
+ BOOL selected = (ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST), -1, LVIS_SELECTED) != -1);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_EXPORT), selected);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_DELETE), selected);
+ return 1;
+ }
+
+ switch (lw)
+ {
+ case IDCANCEL:
+ EndDialog (hwndDlg, IDCANCEL);
+ return 1;
+
+ case IDC_IMPORT_KEYFILE:
+ {
+ char keyfilePath[TC_MAX_PATH];
+
+ if (BrowseFiles (hwndDlg, "SELECT_KEYFILE", keyfilePath, bHistory, FALSE, NULL))
+ {
+ DWORD keyfileSize;
+ byte *keyfileData = (byte *) LoadFile (keyfilePath, &keyfileSize);
+ if (!keyfileData)
+ {
+ handleWin32Error (hwndDlg);
+ return 1;
+ }
+
+ if (keyfileSize != 0)
+ {
+ NewSecurityTokenKeyfileDlgProcParams newParams;
+ newParams.Name = WideToUtf8String (SingleStringToWide (keyfilePath));
+
+ size_t lastBackSlash = newParams.Name.find_last_of ('\\');
+ if (lastBackSlash != string::npos)
+ newParams.Name = newParams.Name.substr (lastBackSlash + 1);
+
+ if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_NEW_TOKEN_KEYFILE), hwndDlg, (DLGPROC) NewSecurityTokenKeyfileDlgProc, (LPARAM) &newParams) == IDOK)
+ {
+ vector <byte> keyfileDataVector (keyfileSize);
+ memcpy (&keyfileDataVector.front(), keyfileData, keyfileSize);
+
+ try
+ {
+ WaitCursor();
+ finally_do ({ NormalCursor(); });
+
+ SecurityToken::CreateKeyfile (newParams.SlotId, keyfileDataVector, newParams.Name);
+
+ keyfiles = SecurityToken::GetAvailableKeyfiles();
+ SecurityTokenKeyfileDlgFillList (hwndDlg, keyfiles);
+ }
+ catch (Exception &e)
+ {
+ e.Show (hwndDlg);
+ }
+
+ burn (&keyfileDataVector.front(), keyfileSize);
+ }
+ }
+ else
+ {
+ SetLastError (ERROR_HANDLE_EOF);
+ handleWin32Error (hwndDlg);
+ }
+
+ burn (keyfileData, keyfileSize);
+ TCfree (keyfileData);
+ }
+
+ return 1;
+ }
+
+ case IDC_EXPORT:
+ {
+ try
+ {
+ foreach (const SecurityTokenKeyfile &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles))
+ {
+ char keyfilePath[TC_MAX_PATH];
+
+ if (!BrowseFiles (hwndDlg, "OPEN_TITLE", keyfilePath, bHistory, TRUE, NULL))
+ break;
+
+ {
+ WaitCursor();
+ finally_do ({ NormalCursor(); });
+
+ vector <byte> keyfileData;
+
+ SecurityToken::GetKeyfileData (keyfile, keyfileData);
+
+ if (keyfileData.empty())
+ {
+ SetLastError (ERROR_HANDLE_EOF);
+ handleWin32Error (hwndDlg);
+ return 1;
+ }
+
+ finally_do_arg (vector <byte> *, &keyfileData, { burn (&finally_arg->front(), finally_arg->size()); });
+
+ if (!SaveBufferToFile ((char *) &keyfileData.front(), keyfilePath, keyfileData.size(), FALSE))
+ throw SystemException ();
+ }
+
+ Info ("KEYFILE_EXPORTED");
+ }
+ }
+ catch (Exception &e)
+ {
+ e.Show (hwndDlg);
+ }
+
+ return 1;
+ }
+
+ case IDC_DELETE:
+ {
+ if (AskNoYes ("CONFIRM_SEL_FILES_DELETE") == IDNO)
+ return 1;
+
+ try
+ {
+ WaitCursor();
+ finally_do ({ NormalCursor(); });
+
+ foreach (const SecurityTokenKeyfile &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles))
+ {
+ SecurityToken::DeleteKeyfile (keyfile);
+ }
+
+ keyfiles = SecurityToken::GetAvailableKeyfiles();
+ SecurityTokenKeyfileDlgFillList (hwndDlg, keyfiles);
+ }
+ catch (Exception &e)
+ {
+ e.Show (hwndDlg);
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+ return 0;
+}
+
+
+BOOL InitSecurityTokenLibrary ()
+{
+ if (SecurityTokenLibraryPath[0] == 0)
+ {
+ Error ("NO_PKCS11_MODULE_SPECIFIED");
+ return FALSE;
+ }
+
+ struct PinRequestHandler : public GetPinFunctor
+ {
+ virtual void operator() (string &str)
+ {
+ if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_PASSWORD), MainDlg, (DLGPROC) SecurityTokenPasswordDlgProc, (LPARAM) &str) == IDCANCEL)
+ throw UserAbort (SRC_POS);
+
+ if (hCursor != NULL)
+ SetCursor (hCursor);
+ }
+ };
+
+ struct WarningHandler : public SendExceptionFunctor
+ {
+ virtual void operator() (const Exception &e)
+ {
+ e.Show (NULL);
+ }
+ };
+
+ try
+ {
+ SecurityToken::InitLibrary (SecurityTokenLibraryPath, auto_ptr <GetPinFunctor> (new PinRequestHandler), auto_ptr <SendExceptionFunctor> (new WarningHandler));
+ }
+ catch (Exception &e)
+ {
+ e.Show (NULL);
+ Error ("PKCS11_MODULE_INIT_FAILED");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif // !SETUP
+
+std::vector <HostDevice> GetAvailableHostDevices (bool noDeviceProperties, bool singleList, bool noFloppy, bool detectUnencryptedFilesystems)
+{
+ vector <HostDevice> devices;
+ size_t dev0;
+
+ for (int devNumber = 0; devNumber < MAX_HOST_DRIVE_NUMBER; devNumber++)
+ {
+ for (int partNumber = 0; partNumber < MAX_HOST_PARTITION_NUMBER; partNumber++)
+ {
+ stringstream strm;
+ strm << "\\Device\\Harddisk" << devNumber << "\\Partition" << partNumber;
+ string devPathStr (strm.str());
+ const char *devPath = devPathStr.c_str();
+
+ OPEN_TEST_STRUCT openTest;
+ if (!OpenDevice (devPath, &openTest, detectUnencryptedFilesystems && partNumber != 0))
+ {
+ if (partNumber == 0)
+ break;
+
+ continue;
+ }
+
+ HostDevice device;
+ device.SystemNumber = devNumber;
+ device.Path = devPath;
+
+ PARTITION_INFORMATION partInfo;
+
+ if (GetPartitionInfo (devPath, &partInfo))
+ {
+ device.Bootable = partInfo.BootIndicator ? true : false;
+ device.Size = partInfo.PartitionLength.QuadPart;
+ }
+
+ device.HasUnencryptedFilesystem = (detectUnencryptedFilesystems && openTest.FilesystemDetected) ? true : false;
+
+ if (!noDeviceProperties)
+ {
+ DISK_GEOMETRY geometry;
+
+ wstringstream ws;
+ ws << devPathStr.c_str();
+ int driveNumber = GetDiskDeviceDriveLetter ((wchar_t *) ws.str().c_str());
+
+ if (driveNumber >= 0)
+ {
+ device.MountPoint += (char) (driveNumber + 'A');
+ device.MountPoint += ":";
+
+ wchar_t name[64];
+ if (GetDriveLabel (driveNumber, name, sizeof (name)))
+ device.Name = name;
+
+ if (GetSystemDriveLetter() == 'A' + driveNumber)
+ device.ContainsSystem = true;
+ }
+
+ if (partNumber == 0 && GetDriveGeometry (devPath, &geometry))
+ device.Removable = (geometry.MediaType == RemovableMedia);
+ }
+
+ if (partNumber == 0)
+ {
+ devices.push_back (device);
+ dev0 = devices.size() - 1;
+ }
+ else
+ {
+ // System creates a virtual partition1 for some storage devices without
+ // partition table. We try to detect this case by comparing sizes of
+ // partition0 and partition1. If they match, no partition of the device
+ // is displayed to the user to avoid confusion. Drive letter assigned by
+ // system to partition1 is assigned partition0
+ if (partNumber == 1 && devices[dev0].Size == device.Size)
+ {
+ devices[dev0].IsVirtualPartition = true;
+ devices[dev0].MountPoint = device.MountPoint;
+ devices[dev0].Name = device.Name;
+ devices[dev0].Path = device.Path;
+ devices[dev0].HasUnencryptedFilesystem = device.HasUnencryptedFilesystem;
+ break;
+ }
+
+ device.IsPartition = true;
+ device.SystemNumber = partNumber;
+ device.Removable = devices[dev0].Removable;
+
+ if (device.ContainsSystem)
+ devices[dev0].ContainsSystem = true;
+
+ if (singleList)
+ devices.push_back (device);
+
+ devices[dev0].Partitions.push_back (device);
+ }
+ }
+ }
+
+ // Vista does not create partition links for dynamic volumes so it is necessary to scan \\Device\\HarddiskVolumeX devices
+ if (CurrentOSMajor >= 6)
+ {
+ for (int devNumber = 0; devNumber < 256; devNumber++)
+ {
+ stringstream strm;
+ strm << "\\Device\\HarddiskVolume" << devNumber;
+ string devPathStr (strm.str());
+ const char *devPath = devPathStr.c_str();
+
+ OPEN_TEST_STRUCT openTest;
+ if (!OpenDevice (devPath, &openTest, detectUnencryptedFilesystems))
+ continue;
+
+ DISK_PARTITION_INFO_STRUCT info;
+ if (GetDeviceInfo (devPath, &info) && info.IsDynamic)
+ {
+ HostDevice device;
+ device.DynamicVolume = true;
+ device.IsPartition = true;
+ device.SystemNumber = devNumber;
+ device.Path = devPath;
+ device.Size = info.partInfo.PartitionLength.QuadPart;
+ device.HasUnencryptedFilesystem = (detectUnencryptedFilesystems && openTest.FilesystemDetected) ? true : false;
+
+ if (!noDeviceProperties)
+ {
+ wstringstream ws;
+ ws << devPathStr.c_str();
+ int driveNumber = GetDiskDeviceDriveLetter ((wchar_t *) ws.str().c_str());
+
+ if (driveNumber >= 0)
+ {
+ device.MountPoint += (char) (driveNumber + 'A');
+ device.MountPoint += ":";
+
+ wchar_t name[64];
+ if (GetDriveLabel (driveNumber, name, sizeof (name)))
+ device.Name = name;
+
+ if (GetSystemDriveLetter() == 'A' + driveNumber)
+ device.ContainsSystem = true;
+ }
+ }
+
+ devices.push_back (device);
+ }
+ }
+ }
+
+ return devices;
+}
+
+
+BOOL FileHasReadOnlyAttribute (const char *path)
+{
+ DWORD attributes = GetFileAttributes (path);
+ return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_READONLY) != 0;
+}
+
+
+BOOL IsFileOnReadOnlyFilesystem (const char *path)
+{
+ char root[MAX_PATH];
+ if (!GetVolumePathName (path, root, sizeof (root)))
+ return FALSE;
+
+ DWORD flags, d;
+ if (!GetVolumeInformation (root, NULL, 0, NULL, &d, &flags, NULL, 0))
+ return FALSE;
+
+ return (flags & FILE_READ_ONLY_VOLUME) ? TRUE : FALSE;
+}
+
+
+void CheckFilesystem (int driveNo, BOOL fixErrors)
+{
+ wchar_t msg[1024], param[1024];
+ char driveRoot[] = { 'A' + (char) driveNo, ':', 0 };
+
+ if (fixErrors && AskWarnYesNo ("FILESYS_REPAIR_CONFIRM_BACKUP") == IDNO)
+ return;
+
+ wsprintfW (msg, GetString (fixErrors ? "REPAIRING_FS" : "CHECKING_FS"), driveRoot);
+ wsprintfW (param, fixErrors ? L"/C echo %s & chkdsk %hs /F /X & pause" : L"/C echo %s & chkdsk %hs & pause", msg, driveRoot);
+
+ ShellExecuteW (NULL, (!IsAdmin() && IsUacSupported()) ? L"runas" : L"open", L"cmd.exe", param, NULL, SW_SHOW);
+}
+
+
+BOOL BufferContainsString (const byte *buffer, size_t bufferSize, const char *str)
+{
+ size_t strLen = strlen (str);
+
+ if (bufferSize < strLen)
+ return FALSE;
+
+ bufferSize -= strLen;
+
+ for (size_t i = 0; i < bufferSize; ++i)
+ {
+ if (memcmp (buffer + i, str, strLen) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+#ifndef SETUP
+
+int AskNonSysInPlaceEncryptionResume ()
+{
+ if (AskWarnYesNo ("NONSYS_INPLACE_ENC_RESUME_PROMPT") == IDYES)
+ return IDYES;
+
+ char *multiChoiceStr[] = { 0, "ASK_NONSYS_INPLACE_ENC_NOTIFICATION_REMOVAL", "DO_NOT_PROMPT_ME", "KEEP_PROMPTING_ME", 0 };
+
+ switch (AskMultiChoice ((void **) multiChoiceStr, FALSE))
+ {
+ case 1:
+ RemoveNonSysInPlaceEncNotifications();
+ Warning ("NONSYS_INPLACE_ENC_NOTIFICATION_REMOVAL_NOTE");
+ break;
+
+ default:
+ // NOP
+ break;
+ }
+
+ return IDNO;
+}
+
+#endif // !SETUP
+
+
+BOOL RemoveDeviceWriteProtection (HWND hwndDlg, char *devicePath)
+{
+ int driveNumber;
+ int partitionNumber;
+
+ char temp[MAX_PATH*2];
+ char cmdBatch[MAX_PATH*2];
+ char diskpartScript[MAX_PATH*2];
+
+ if (sscanf (devicePath, "\\Device\\Harddisk%d\\Partition%d", &driveNumber, &partitionNumber) != 2)
+ return FALSE;
+
+ if (GetTempPath (sizeof (temp), temp) == 0)
+ return FALSE;
+
+ _snprintf (cmdBatch, sizeof (cmdBatch), "%s\\TrueCrypt_Write_Protection_Removal.cmd", temp);
+ _snprintf (diskpartScript, sizeof (diskpartScript), "%s\\TrueCrypt_Write_Protection_Removal.diskpart", temp);
+
+ FILE *f = fopen (cmdBatch, "w");
+ if (!f)
+ {
+ handleWin32Error (hwndDlg);
+ return FALSE;
+ }
+
+ fprintf (f, "@diskpart /s \"%s\"\n@pause\n@del \"%s\" \"%s\"", diskpartScript, diskpartScript, cmdBatch);
+
+ CheckFileStreamWriteErrors (f, cmdBatch);
+ fclose (f);
+
+ f = fopen (diskpartScript, "w");
+ if (!f)
+ {
+ handleWin32Error (hwndDlg);
+ DeleteFile (cmdBatch);
+ return FALSE;
+ }
+
+ fprintf (f, "select disk %d\nattributes disk clear readonly\n", driveNumber);
+
+ if (partitionNumber != 0)
+ fprintf (f, "select partition %d\nattributes volume clear readonly\n", partitionNumber);
+
+ fprintf (f, "exit\n");
+
+ CheckFileStreamWriteErrors (f, diskpartScript);
+ fclose (f);
+
+ ShellExecute (NULL, (!IsAdmin() && IsUacSupported()) ? "runas" : "open", cmdBatch, NULL, NULL, SW_SHOW);
+
+ return TRUE;
+}
+
+
+static LRESULT CALLBACK EnableElevatedCursorChangeWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return DefWindowProc (hWnd, message, wParam, lParam);
+}
+
+
+void EnableElevatedCursorChange (HWND parent)
+{
+ // Create a transparent window to work around a UAC issue preventing change of the cursor
+ if (UacElevated)
+ {
+ const char *className = "TrueCryptEnableElevatedCursorChange";
+ WNDCLASSEX winClass;
+ HWND hWnd;
+
+ memset (&winClass, 0, sizeof (winClass));
+ winClass.cbSize = sizeof (WNDCLASSEX);
+ winClass.lpfnWndProc = (WNDPROC) EnableElevatedCursorChangeWndProc;
+ winClass.hInstance = hInst;
+ winClass.lpszClassName = className;
+ RegisterClassEx (&winClass);
+
+ hWnd = CreateWindowEx (WS_EX_TOOLWINDOW | WS_EX_LAYERED, className, "TrueCrypt UAC", 0, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), parent, NULL, hInst, NULL);
+ SetLayeredWindowAttributes (hWnd, 0, 1, LWA_ALPHA);
+ ShowWindow (hWnd, SW_SHOWNORMAL);
+
+ DestroyWindow (hWnd);
+ UnregisterClass (className, hInst);
+ }
+}
+
+
+BOOL DisableFileCompression (HANDLE file)
+{
+ USHORT format;
+ DWORD bytesOut;
+
+ if (!DeviceIoControl (file, FSCTL_GET_COMPRESSION, NULL, 0, &format, sizeof (format), &bytesOut, NULL))
+ return FALSE;
+
+ if (format == COMPRESSION_FORMAT_NONE)
+ return TRUE;
+
+ format = COMPRESSION_FORMAT_NONE;
+ return DeviceIoControl (file, FSCTL_SET_COMPRESSION, &format, sizeof (format), NULL, 0, &bytesOut, NULL);
+}
+
+
+BOOL VolumePathExists (char *volumePath)
+{
+ OPEN_TEST_STRUCT openTest;
+ char upperCasePath[TC_MAX_PATH];
+
+ UpperCaseCopy (upperCasePath, volumePath);
+
+ if (strstr (upperCasePath, "\\DEVICE\\") == upperCasePath)
+ return OpenDevice (volumePath, &openTest, FALSE);
+
+ string path = volumePath;
+ if (path.find ("\\\\?\\Volume{") == 0 && path.rfind ("}\\") == path.size() - 2)
+ {
+ char devicePath[TC_MAX_PATH];
+ if (QueryDosDevice (path.substr (4, path.size() - 5).c_str(), devicePath, TC_MAX_PATH) != 0)
+ return TRUE;
+ }
+
+ return _access (volumePath, 0) == 0;
+}
+
+
+BOOL IsWindowsIsoBurnerAvailable ()
+{
+ char path[MAX_PATH*2] = { 0 };
+
+ if (!IsOSAtLeast (WIN_7))
+ {
+ return FALSE;
+ }
+
+ if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_SYSTEM, NULL, 0, path)))
+ {
+ strcat (path, "\\" ISO_BURNER_TOOL);
+
+ return (FileExists (path));
+ }
+
+ return FALSE;
+}
+
+
+BOOL LaunchWindowsIsoBurner (HWND hwnd, const char *isoPath)
+{
+ int r = (int) ShellExecute (hwnd, "open", ISO_BURNER_TOOL, (string ("\"") + isoPath + "\"").c_str(), NULL, SW_SHOWNORMAL);
+
+ if (r <= 32)
+ {
+ SetLastError (r);
+ handleWin32Error (hwnd);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+std::string VolumeGuidPathToDevicePath (std::string volumeGuidPath)
+{
+ if (volumeGuidPath.find ("\\\\?\\") == 0)
+ volumeGuidPath = volumeGuidPath.substr (4);
+
+ if (volumeGuidPath.find ("Volume{") != 0 || volumeGuidPath.rfind ("}\\") != volumeGuidPath.size() - 2)
+ return string();
+
+ char volDevPath[TC_MAX_PATH];
+ if (QueryDosDevice (volumeGuidPath.substr (0, volumeGuidPath.size() - 1).c_str(), volDevPath, TC_MAX_PATH) == 0)
+ return string();
+
+ string partitionPath = HarddiskVolumePathToPartitionPath (volDevPath);
+
+ return partitionPath.empty() ? volDevPath : partitionPath;
+}
+
+
+std::string HarddiskVolumePathToPartitionPath (const std::string &harddiskVolumePath)
+{
+ wstring volPath = SingleStringToWide (harddiskVolumePath);
+
+ for (int driveNumber = 0; driveNumber < MAX_HOST_DRIVE_NUMBER; driveNumber++)
+ {
+ for (int partNumber = 0; partNumber < MAX_HOST_PARTITION_NUMBER; partNumber++)
+ {
+ wchar_t partitionPath[TC_MAX_PATH];
+ swprintf_s (partitionPath, ARRAYSIZE (partitionPath), L"\\Device\\Harddisk%d\\Partition%d", driveNumber, partNumber);
+
+ wchar_t resolvedPath[TC_MAX_PATH];
+ if (ResolveSymbolicLink (partitionPath, resolvedPath))
+ {
+ if (volPath == resolvedPath)
+ return WideToSingleString (partitionPath);
+ }
+ else if (partNumber == 0)
+ break;
+ }
+ }
+
+ return string();
+}
+
+
+BOOL IsApplicationInstalled (const char *appName)
+{
+ const char *uninstallRegName = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
+ BOOL installed = FALSE;
+ HKEY unistallKey;
+ LONG res = RegOpenKeyEx (HKEY_LOCAL_MACHINE, uninstallRegName, 0, KEY_READ | KEY_WOW64_64KEY, &unistallKey);
+ if (res != ERROR_SUCCESS)
+ {
+ SetLastError (res);
+ return FALSE;
+ }
+
+ char regName[1024];
+ DWORD regNameSize = sizeof (regName);
+ DWORD index = 0;
+ while (RegEnumKeyEx (unistallKey, index++, regName, ®NameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
+ {
+ if (strstr (regName, "{") == regName)
+ {
+ regNameSize = sizeof (regName);
+ if (!ReadLocalMachineRegistryStringNonReflected ((string (uninstallRegName) + "\\" + regName).c_str(), "DisplayName", regName, ®NameSize))
+ regName[0] = 0;
+ }
+
+ if (_stricmp (regName, appName) == 0)
+ {
+ installed = TRUE;
+ break;
+ }
+
+ regNameSize = sizeof (regName);
+ }
+
+ RegCloseKey (unistallKey);
+ return installed;
+}
+
+
+std::string FindLatestFileOrDirectory (const std::string &directory, const char *namePattern, bool findDirectory, bool findFile)
+{
+ string name;
+ ULARGE_INTEGER latestTime;
+ latestTime.QuadPart = 0;
+ WIN32_FIND_DATA findData;
+
+ HANDLE find = FindFirstFile ((directory + "\\" + namePattern).c_str(), &findData);
+ if (find != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ if (strcmp (findData.cFileName, ".") == 0 || strcmp (findData.cFileName, "..") == 0)
+ continue;
+
+ ULARGE_INTEGER writeTime;
+ writeTime.LowPart = findData.ftLastWriteTime.dwLowDateTime;
+ writeTime.HighPart = findData.ftLastWriteTime.dwHighDateTime;
+
+ if ((!findFile && !(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ || (!findDirectory && (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))
+ continue;
+
+ if (latestTime.QuadPart < writeTime.QuadPart)
+ {
+ latestTime = writeTime;
+ name = findData.cFileName;
+ }
+ }
+ while (FindNextFile (find, &findData));
+
+ FindClose (find);
+ }
+
+ if (name.empty())
+ return name;
+
+ return string (directory) + "\\" + name;
+}
diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h new file mode 100644 index 00000000..9999494d --- /dev/null +++ b/src/Common/Dlgcode.h @@ -0,0 +1,532 @@ +/*
+ 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. */
+
+#ifndef TC_HEADER_DLGCODE
+#define TC_HEADER_DLGCODE
+
+#include "Common.h"
+#include "Apidrvr.h"
+#include "Keyfiles.h"
+#include "Wipe.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* IDs for dynamically generated GUI elements */
+enum dynamic_gui_element_ids
+{
+ IDPM_CHECK_FILESYS = 500001,
+ IDPM_REPAIR_FILESYS,
+ IDPM_OPEN_VOLUME,
+ IDPM_SELECT_FILE_AND_MOUNT,
+ IDPM_SELECT_DEVICE_AND_MOUNT,
+ IDPM_ADD_TO_FAVORITES,
+ IDPM_ADD_TO_SYSTEM_FAVORITES,
+ IDM_SHOW_HIDE,
+ IDM_HOMEPAGE_SYSTRAY
+};
+
+enum
+{
+ TC_TBXID_LEGAL_NOTICES,
+ TC_TBXID_SYS_ENCRYPTION_PRETEST,
+ TC_TBXID_SYS_ENC_RESCUE_DISK,
+ TC_TBXID_DECOY_OS_INSTRUCTIONS,
+ TC_TBXID_EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS
+};
+
+#define TC_APPLICATION_ID L"TrueCryptFoundation.TrueCrypt"
+
+#define TC_MUTEX_NAME_SYSENC "Global\\TrueCrypt System Encryption Wizard"
+#define TC_MUTEX_NAME_NONSYS_INPLACE_ENC "Global\\TrueCrypt In-Place Encryption Wizard"
+#define TC_MUTEX_NAME_APP_SETUP "Global\\TrueCrypt Setup"
+#define TC_MUTEX_NAME_DRIVER_SETUP "Global\\TrueCrypt Driver Setup"
+
+#define IDC_ABOUT 0x7fff /* ID for AboutBox on system menu in wm_user range */
+
+#define EXCL_ACCESS_MAX_AUTO_RETRIES 500
+#define EXCL_ACCESS_AUTO_RETRY_DELAY 10
+
+#define UNMOUNT_MAX_AUTO_RETRIES 30
+#define UNMOUNT_AUTO_RETRY_DELAY 50
+
+// After the user receives the "Incorrect password" error this number of times in a row, we should automatically
+// try using the embedded header backup (if any). This ensures that the "Incorrect password" message is reported faster
+// initially (most such errors are really caused by supplying an incorrect password, not by header corruption).
+#define TC_TRY_HEADER_BAK_AFTER_NBR_WRONG_PWD_TRIES 2
+
+#define MAX_MULTI_CHOICES 10 /* Maximum number of options for mutliple-choice dialog */
+
+#define TC_APPD_FILENAME_CONFIGURATION "Configuration.xml"
+#define TC_APPD_FILENAME_SYSTEM_ENCRYPTION "System Encryption.xml"
+#define TC_APPD_FILENAME_DEFAULT_KEYFILES "Default Keyfiles.xml"
+#define TC_APPD_FILENAME_HISTORY "History.xml"
+#define TC_APPD_FILENAME_FAVORITE_VOLUMES "Favorite Volumes.xml"
+#define TC_APPD_FILENAME_SYSTEM_FAVORITE_VOLUMES TC_APP_NAME " System Favorite Volumes.xml"
+#define TC_APPD_FILENAME_NONSYS_INPLACE_ENC "In-Place Encryption"
+#define TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE "In-Place Encryption Wipe Algo"
+#define TC_APPD_FILENAME_POST_INSTALL_TASK_TUTORIAL "Post-Install Task - Tutorial"
+#define TC_APPD_FILENAME_POST_INSTALL_TASK_RELEASE_NOTES "Post-Install Task - Release Notes"
+
+#ifndef USER_DEFAULT_SCREEN_DPI
+#define USER_DEFAULT_SCREEN_DPI 96
+#endif
+
+#if (USER_DEFAULT_SCREEN_DPI != 96)
+# error Revision of GUI and graphics necessary, since everything assumes default screen DPI as 96 (note that 96 is the default on Windows 2000, XP, and Vista).
+#endif
+
+enum
+{
+ TC_POST_INSTALL_CFG_REMOVE_ALL = 0,
+ TC_POST_INSTALL_CFG_TUTORIAL,
+ TC_POST_INSTALL_CFG_RELEASE_NOTES
+};
+
+extern char *LastDialogId;
+extern char *ConfigBuffer;
+extern char szHelpFile[TC_MAX_PATH];
+extern char szHelpFile2[TC_MAX_PATH];
+extern char SecurityTokenLibraryPath[TC_MAX_PATH];
+extern HFONT hFixedDigitFont;
+extern HFONT hBoldFont;
+extern HFONT hTitleFont;
+extern HFONT hFixedFont;
+extern HFONT hUserFont;
+extern HFONT hUserUnderlineFont;
+extern HFONT hUserBoldFont;
+extern HFONT WindowTitleBarFont;
+extern int ScreenDPI;
+extern double DlgAspectRatio;
+extern HWND MainDlg;
+extern BOOL Silent;
+extern BOOL bHistory;
+extern BOOL bPreserveTimestamp;
+extern BOOL bStartOnLogon;
+extern BOOL bMountDevicesOnLogon;
+extern BOOL bMountFavoritesOnLogon;
+extern int HiddenSectorDetectionStatus;
+extern wchar_t *lpszTitle;
+extern OSVersionEnum nCurrentOS;
+extern int CurrentOSMajor;
+extern int CurrentOSMinor;
+extern int CurrentOSServicePack;
+extern BOOL RemoteSession;
+extern HANDLE hDriver;
+extern HINSTANCE hInst;
+extern int SystemEncryptionStatus;
+extern WipeAlgorithmId nWipeMode;
+extern BOOL bSysPartitionSelected;
+extern BOOL bSysDriveSelected;
+
+extern BOOL bHyperLinkBeingTracked;
+extern BOOL bInPlaceEncNonSysPending;
+
+extern BOOL KeyFilesEnable;
+extern KeyFile *FirstKeyFile;
+extern KeyFilesDlgParam defaultKeyFilesParam;
+extern BOOL UacElevated;
+extern BOOL IgnoreWmDeviceChange;
+extern BOOL DeviceChangeBroadcastDisabled;
+extern BOOL LastMountedVolumeDirty;
+extern BOOL MountVolumesAsSystemFavorite;
+extern BOOL FavoriteMountOnArrivalInProgress;
+extern BOOL MultipleMountOperationInProgress;
+
+
+enum tc_app_msg_ids
+{
+ /* WARNING: Changing these values or their meanings may cause incompatibility with other versions
+ (for example, if a new version of the TrueCrypt installer needed to shut down this version of
+ TrueCrypt during upgrade, it could fail or do something unwanted because the signal value would
+ be incorrect). When adding a new constant, verify that the value is unique within this block and
+ that it is less than WM_APP+16383. */
+
+ // Common (inter-app)
+ TC_APPMSG_CLOSE_BKG_TASK = WM_APP + 4, // Changing this value will prevent smooth upgrades from pre-5.x versions
+ TC_APPMSG_SYSENC_CONFIG_UPDATE = WM_APP + 101,
+ TC_APPMSG_TASKBAR_ICON = WM_APP + 102,
+ TC_APPMSG_LOAD_TEXT_BOX_CONTENT = WM_APP + 103,
+ // Mount
+ TC_APPMSG_MOUNT_ENABLE_DISABLE_CONTROLS = WM_APP + 201,
+ TC_APPMSG_MOUNT_SHOW_WINDOW = WM_APP + 202,
+ TC_APPMSG_PREBOOT_PASSWORD_MODE = WM_APP + 203,
+ // Format
+ TC_APPMSG_VOL_TRANSFORM_THREAD_ENDED = WM_APP + 301,
+ TC_APPMSG_FORMAT_FINISHED = WM_APP + 302,
+ TC_APPMSG_FORMAT_USER_QUIT = WM_APP + 303,
+ TC_APPMSG_PERFORM_POST_WMINIT_TASKS = WM_APP + 304,
+ TC_APPMSG_PERFORM_POST_SYSENC_WMINIT_TASKS = WM_APP + 305,
+ TC_APPMSG_NONSYS_INPLACE_ENC_FINISHED = WM_APP + 306,
+ // Setup
+ TC_APPMSG_INSTALL_SUCCESS = WM_APP + 401,
+ TC_APPMSG_UNINSTALL_SUCCESS = WM_APP + 402,
+ TC_APPMSG_EXTRACTION_SUCCESS = WM_APP + 403,
+ TC_APPMSG_INSTALL_FAILURE = WM_APP + 404,
+ TC_APPMSG_UNINSTALL_FAILURE = WM_APP + 405,
+ TC_APPMSG_EXTRACTION_FAILURE = WM_APP + 406
+};
+
+enum system_encryption_status
+{
+ /* WARNING: As these values are written to config files, if they or their meanings
+ are changed, incompatiblity with other versions may arise (upgrade, downgrade, etc.).
+ When adding a new constant, verify that the value is unique within this block. */
+ SYSENC_STATUS_NONE = 0,
+ SYSENC_STATUS_PRETEST = 200, // This may also mean that the OS is to be (or has been) copied to a hidden volume (to create a hidden OS).
+ SYSENC_STATUS_ENCRYPTING = 400,
+ SYSENC_STATUS_DECRYPTING = 600
+};
+
+enum vol_creation_wizard_modes
+{
+ WIZARD_MODE_FILE_CONTAINER = 0,
+ WIZARD_MODE_NONSYS_DEVICE,
+ WIZARD_MODE_SYS_DEVICE
+};
+
+
+typedef struct
+{
+ BOOL VolumeIsOpen;
+
+ CRYPTO_INFO *CryptoInfo;
+ BOOL IsDevice;
+ HANDLE HostFileHandle;
+ uint64 HostSize;
+
+ BOOL TimestampsValid;
+ FILETIME CreationTime;
+ FILETIME LastWriteTime;
+ FILETIME LastAccessTime;
+
+} OpenVolumeContext;
+
+
+#define DEFAULT_VOL_CREATION_WIZARD_MODE WIZARD_MODE_FILE_CONTAINER
+
+#define ICON_HAND MB_ICONHAND
+#define YES_NO MB_YESNO
+
+#define ISO_BURNER_TOOL "isoburn.exe"
+#define PRINT_TOOL "notepad"
+
+void cleanup ( void );
+void LowerCaseCopy ( char *lpszDest , const char *lpszSource );
+void UpperCaseCopy ( char *lpszDest , const char *lpszSource );
+void CreateFullVolumePath ( char *lpszDiskFile , const char *lpszFileName , BOOL *bDevice );
+int FakeDosNameForDevice ( const char *lpszDiskFile , char *lpszDosDevice , char *lpszCFDevice , BOOL bNameOnly );
+int RemoveFakeDosName ( char *lpszDiskFile , char *lpszDosDevice );
+void AbortProcess ( char *stringId );
+void AbortProcessSilent ( void );
+void *err_malloc ( size_t size );
+char *err_strdup ( char *lpszText );
+DWORD handleWin32Error ( HWND hwndDlg );
+BOOL IsDiskReadError (DWORD error);
+BOOL IsDiskWriteError (DWORD error);
+BOOL IsDiskError (DWORD error);
+BOOL translateWin32Error ( wchar_t *lpszMsgBuf , int nWSizeOfBuf );
+BOOL CALLBACK AboutDlgProc ( HWND hwndDlg , UINT msg , WPARAM wParam , LPARAM lParam );
+static BOOL CALLBACK StaticModelessWaitDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+void DisplayStaticModelessWaitDlg (HWND parent);
+void CloseStaticModelessWaitDlg (void);
+BOOL IsButtonChecked ( HWND hButton );
+void CheckButton ( HWND hButton );
+void LeftPadString (char *szTmp, int len, int targetLen, char filler);
+void ToSBCS ( LPWSTR lpszText );
+void ToUNICODE ( char *lpszText );
+void InitDialog ( HWND hwndDlg );
+void ProcessPaintMessages (HWND hwnd, int maxMessagesToProcess);
+HDC CreateMemBitmap ( HINSTANCE hInstance , HWND hwnd , char *resource );
+HBITMAP RenderBitmap ( char *resource , HWND hwndDest , int x , int y , int nWidth , int nHeight , BOOL bDirectRender , BOOL bKeepAspectRatio);
+LRESULT CALLBACK RedTick ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam );
+BOOL RegisterRedTick ( HINSTANCE hInstance );
+BOOL UnregisterRedTick ( HINSTANCE hInstance );
+LRESULT CALLBACK SplashDlgProc ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam );
+void WaitCursor ( void );
+void NormalCursor ( void );
+void ArrowWaitCursor ( void );
+void HandCursor ();
+void AddComboPair (HWND hComboBox, const char *lpszItem, int value);
+void AddComboPairW (HWND hComboBox, const wchar_t *lpszItem, int value);
+void SelectAlgo ( HWND hComboBox , int *nCipher );
+void PopulateWipeModeCombo (HWND hComboBox, BOOL bNA, BOOL bInPlaceEncryption);
+wchar_t *GetWipeModeName (WipeAlgorithmId modeId);
+wchar_t *GetPathType (const char *path, BOOL bUpperCase, BOOL *bIsPartition);
+LRESULT CALLBACK CustomDlgProc ( HWND hwnd , UINT uMsg , WPARAM wParam , LPARAM lParam );
+BOOL TCCreateMutex (volatile HANDLE *hMutex, char *name);
+void TCCloseMutex (volatile HANDLE *hMutex);
+BOOL MutexExistsOnSystem (char *name);
+BOOL CreateSysEncMutex (void);
+BOOL InstanceHasSysEncMutex (void);
+void CloseSysEncMutex (void);
+BOOL CreateNonSysInplaceEncMutex (void);
+BOOL InstanceHasNonSysInplaceEncMutex (void);
+void CloseNonSysInplaceEncMutex (void);
+BOOL NonSysInplaceEncInProgressElsewhere (void);
+BOOL CreateDriverSetupMutex (void);
+void CloseDriverSetupMutex (void);
+BOOL CreateAppSetupMutex (void);
+BOOL InstanceHasAppSetupMutex (void);
+void CloseAppSetupMutex (void);
+BOOL IsTrueCryptInstallerRunning (void);
+uint32 ReadDriverConfigurationFlags ();
+uint32 ReadEncryptionThreadPoolFreeCpuCountLimit ();
+BOOL LoadSysEncSettings (HWND hwndDlg);
+int LoadNonSysInPlaceEncSettings (WipeAlgorithmId *wipeAlgorithm);
+void RemoveNonSysInPlaceEncNotifications (void);
+void SavePostInstallTasksSettings (int command);
+void DoPostInstallTasks (void);
+void InitOSVersionInfo ();
+void InitApp ( HINSTANCE hInstance, char *lpszCommandLine );
+void InitHelpFileName (void);
+BOOL OpenDevice (const char *lpszPath, OPEN_TEST_STRUCT *driver, BOOL detectFilesystem);
+void NotifyDriverOfPortableMode (void);
+int GetAvailableFixedDisks ( HWND hComboBox , char *lpszRootPath );
+int GetAvailableRemovables ( HWND hComboBox , char *lpszRootPath );
+int IsSystemDevicePath (char *path, HWND hwndDlg, BOOL bReliableRequired);
+BOOL CALLBACK RawDevicesDlgProc ( HWND hwndDlg , UINT msg , WPARAM wParam , LPARAM lParam );
+BOOL TextInfoDialogBox (int nID);
+BOOL CALLBACK TextInfoDialogBoxDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+char * GetLegalNotices ();
+BOOL CALLBACK BenchmarkDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+void UserEnrichRandomPool (HWND hwndDlg);
+BOOL CALLBACK KeyfileGeneratorDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK MultiChoiceDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
+int DriverAttach ( void );
+BOOL CALLBACK CipherTestDialogProc ( HWND hwndDlg , UINT uMsg , WPARAM wParam , LPARAM lParam );
+void ResetCipherTest ( HWND hwndDlg , int idTestCipher );
+void ResetCurrentDirectory ();
+BOOL BrowseFiles (HWND hwndDlg, char *stringId, char *lpszFileName, BOOL keepHistory, BOOL saveMode, wchar_t *browseFilter);
+BOOL BrowseDirectories (HWND hWnd, char *lpszTitle, char *dirName);
+void handleError ( HWND hwndDlg , int code );
+BOOL CheckFileStreamWriteErrors (FILE *file, const char *fileName);
+void LocalizeDialog ( HWND hwnd, char *stringId );
+void OpenVolumeExplorerWindow (int driveNo);
+static BOOL CALLBACK CloseVolumeExplorerWindowsEnum( HWND hwnd, LPARAM driveNo);
+BOOL CloseVolumeExplorerWindows (HWND hwnd, int driveNo);
+BOOL CheckCapsLock (HWND hwnd, BOOL quiet);
+BOOL CheckFileExtension (char *fileName);
+void IncreaseWrongPwdRetryCount (int count);
+void ResetWrongPwdRetryCount (void);
+BOOL WrongPwdRetryCountOverLimit (void);
+int GetFirstAvailableDrive ();
+int GetLastAvailableDrive ();
+BOOL IsDriveAvailable (int driveNo);
+BOOL IsDeviceMounted (char *deviceName);
+int DriverUnmountVolume (HWND hwndDlg, int nDosDriveNo, BOOL forced);
+void BroadcastDeviceChange (WPARAM message, int nDosDriveNo, DWORD driveMap);
+int MountVolume (HWND hwndDlg, int driveNo, char *volumePath, Password *password, BOOL cachePassword, BOOL sharedAccess, const MountOptions* const mountOptions, BOOL quiet, BOOL bReportWrongPassword);
+BOOL UnmountVolume (HWND hwndDlg , int nDosDriveNo, BOOL forceUnmount);
+BOOL IsPasswordCacheEmpty (void);
+BOOL IsMountedVolume (const char *volname);
+int GetMountedVolumeDriveNo (char *volname);
+BOOL IsAdmin (void);
+BOOL IsBuiltInAdmin ();
+BOOL IsUacSupported ();
+BOOL ResolveSymbolicLink (const wchar_t *symLinkName, PWSTR targetName);
+int GetDiskDeviceDriveLetter (PWSTR deviceName);
+int FileSystemAppearsEmpty (const char *devicePath);
+__int64 GetStatsFreeSpaceOnPartition (const char *devicePath, float *percent, __int64 *occupiedBytes, BOOL silent);
+__int64 GetDeviceSize (const char *devicePath);
+HANDLE DismountDrive (char *devName, char *devicePath);
+int64 FindString (const char *buf, const char *str, int64 bufLen, size_t strLen, int64 startOffset);
+BOOL FileExists (const char *filePathPtr);
+__int64 FindStringInFile (const char *filePath, const char *str, int strLen);
+BOOL TCCopyFile (char *sourceFileName, char *destinationFile);
+BOOL SaveBufferToFile (const char *inputBuffer, const char *destinationFile, DWORD inputLength, BOOL bAppend);
+BOOL TCFlushFile (FILE *f);
+BOOL PrintHardCopyTextUTF16 (wchar_t *text, char *title, int byteLen);
+void GetSpeedString (unsigned __int64 speed, wchar_t *str);
+BOOL IsNonInstallMode ();
+BOOL DriverUnload ();
+LRESULT SetCheckBox (HWND hwndDlg, int dlgItem, BOOL state);
+BOOL GetCheckBox (HWND hwndDlg, int dlgItem);
+void SetListScrollHPos (HWND hList, int topMostVisibleItem);
+void ManageStartupSeq (void);
+void ManageStartupSeqWiz (BOOL bRemove, const char *arg);
+void CleanLastVisitedMRU (void);
+void ClearHistory (HWND hwndDlgItem);
+LRESULT ListItemAdd (HWND list, int index, char *string);
+LRESULT ListItemAddW (HWND list, int index, wchar_t *string);
+LRESULT ListSubItemSet (HWND list, int index, int subIndex, char *string);
+LRESULT ListSubItemSetW (HWND list, int index, int subIndex, wchar_t *string);
+BOOL GetMountList (MOUNT_LIST_STRUCT *list);
+int GetDriverRefCount ();
+void GetSizeString (unsigned __int64 size, wchar_t *str);
+__int64 GetFileSize64 (const char *path);
+BOOL LoadInt16 (char *filePath, int *result, __int64 fileOffset);
+BOOL LoadInt32 (char *filePath, unsigned __int32 *result, __int64 fileOffset);
+char *LoadFile (const char *fileName, DWORD *size);
+char *LoadFileBlock (char *fileName, __int64 fileOffset, size_t count);
+char *GetModPath (char *path, int maxSize);
+char *GetConfigPath (char *fileName);
+char *GetProgramConfigPath (char *fileName);
+char GetSystemDriveLetter (void);
+void OpenPageHelp (HWND hwndDlg, int nPage);
+void TaskBarIconDisplayBalloonTooltip (HWND hwnd, wchar_t *headline, wchar_t *text, BOOL warning);
+void InfoBalloon (char *headingStringId, char *textStringId);
+void InfoBalloonDirect (wchar_t *headingString, wchar_t *textString);
+void WarningBalloon (char *headingStringId, char *textStringId);
+void WarningBalloonDirect (wchar_t *headingString, wchar_t *textString);
+int Info (char *stringId);
+int InfoTopMost (char *stringId);
+int InfoDirect (const wchar_t *msg);
+int Warning (char *stringId);
+int WarningTopMost (char *stringId);
+int WarningDirect (const wchar_t *warnMsg);
+int Error (char *stringId);
+int ErrorDirect (const wchar_t *errMsg);
+int ErrorTopMost (char *stringId);
+int AskYesNo (char *stringId);
+int AskYesNoString (const wchar_t *str);
+int AskYesNoTopmost (char *stringId);
+int AskNoYes (char *stringId);
+int AskOkCancel (char *stringId);
+int AskWarnYesNo (char *stringId);
+int AskWarnYesNoString (const wchar_t *string);
+int AskWarnYesNoTopmost (char *stringId);
+int AskWarnYesNoStringTopmost (const wchar_t *string);
+int AskWarnNoYes (char *stringId);
+int AskWarnNoYesString (const wchar_t *string);
+int AskWarnNoYesTopmost (char *stringId);
+int AskWarnOkCancel (char *stringId);
+int AskWarnCancelOk (char *stringId);
+int AskErrYesNo (char *stringId);
+int AskErrNoYes (char *stringId);
+int AskMultiChoice (void *strings[], BOOL bBold);
+BOOL ConfigWriteBegin ();
+BOOL ConfigWriteEnd ();
+BOOL ConfigWriteString (char *configKey, char *configValue);
+BOOL ConfigWriteInt (char *configKey, int configValue);
+int ConfigReadInt (char *configKey, int defaultValue);
+char *ConfigReadString (char *configKey, char *defaultValue, char *str, int maxLen);
+void RestoreDefaultKeyFilesParam (void);
+BOOL LoadDefaultKeyFilesParam (void);
+void Debug (char *format, ...);
+void DebugMsgBox (char *format, ...);
+BOOL IsOSAtLeast (OSVersionEnum reqMinOS);
+BOOL IsOSVersionAtLeast (OSVersionEnum reqMinOS, int reqMinServicePack);
+BOOL Is64BitOs ();
+BOOL IsServerOS ();
+BOOL IsHiddenOSRunning (void);
+BOOL EnableWow64FsRedirection (BOOL enable);
+BOOL RestartComputer (void);
+void Applink (char *dest, BOOL bSendOS, char *extraOutput);
+char *RelativePath2Absolute (char *szFileName);
+void HandleDriveNotReadyError ();
+BOOL CALLBACK CloseTCWindowsEnum( HWND hwnd, LPARAM lParam);
+BOOL CALLBACK FindTCWindowEnum (HWND hwnd, LPARAM lParam);
+BYTE *MapResource (char *resourceType, int resourceId, PDWORD size);
+void InconsistencyResolved (char *msg);
+void ReportUnexpectedState (char *techInfo);
+BOOL SelectMultipleFiles (HWND hwndDlg, char *stringId, char *lpszFileName, BOOL keepHistory);
+BOOL SelectMultipleFilesNext (char *lpszFileName);
+void OpenOnlineHelp ();
+BOOL GetPartitionInfo (const char *deviceName, PPARTITION_INFORMATION rpartInfo);
+BOOL GetDeviceInfo (const char *deviceName, DISK_PARTITION_INFO_STRUCT *info);
+BOOL GetDriveGeometry (const char *deviceName, PDISK_GEOMETRY diskGeometry);
+BOOL IsVolumeDeviceHosted (const char *lpszDiskFile);
+int CompensateXDPI (int val);
+int CompensateYDPI (int val);
+int CompensateDPIFont (int val);
+int GetTextGfxWidth (HWND hwndDlgItem, const wchar_t *text, HFONT hFont);
+int GetTextGfxHeight (HWND hwndDlgItem, const wchar_t *text, HFONT hFont);
+BOOL ToHyperlink (HWND hwndDlg, UINT ctrlId);
+BOOL ToCustHyperlink (HWND hwndDlg, UINT ctrlId, HFONT hFont);
+void ToBootPwdField (HWND hwndDlg, UINT ctrlId);
+void AccommodateTextField (HWND hwndDlg, UINT ctrlId, BOOL bFirstUpdate, HFONT hFont);
+BOOL GetDriveLabel (int driveNo, wchar_t *label, int labelSize);
+BOOL DoDriverInstall (HWND hwndDlg);
+int OpenVolume (OpenVolumeContext *context, const char *volumePath, Password *password, BOOL write, BOOL preserveTimestamps, BOOL useBackupHeader);
+void CloseVolume (OpenVolumeContext *context);
+int ReEncryptVolumeHeader (char *buffer, BOOL bBoot, CRYPTO_INFO *cryptoInfo, Password *password, BOOL wipeMode);
+BOOL IsPagingFileActive (BOOL checkNonWindowsPartitionsOnly);
+BOOL IsPagingFileWildcardActive ();
+BOOL DisablePagingFile ();
+BOOL CALLBACK SecurityTokenPasswordDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK SecurityTokenKeyfileDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+BOOL InitSecurityTokenLibrary ();
+BOOL FileHasReadOnlyAttribute (const char *path);
+BOOL IsFileOnReadOnlyFilesystem (const char *path);
+void CheckFilesystem (int driveNo, BOOL fixErrors);
+BOOL BufferContainsString (const byte *buffer, size_t bufferSize, const char *str);
+int AskNonSysInPlaceEncryptionResume ();
+BOOL RemoveDeviceWriteProtection (HWND hwndDlg, char *devicePath);
+void EnableElevatedCursorChange (HWND parent);
+BOOL DisableFileCompression (HANDLE file);
+BOOL VolumePathExists (char *volumePath);
+BOOL IsWindowsIsoBurnerAvailable ();
+BOOL LaunchWindowsIsoBurner (HWND hwnd, const char *isoPath);
+BOOL IsApplicationInstalled (const char *appName);
+
+#ifdef __cplusplus
+}
+
+#include <vector>
+#include <string>
+
+struct HostDevice
+{
+ HostDevice ()
+ :
+ Bootable (false),
+ ContainsSystem (false),
+ DynamicVolume (false),
+ Floppy (false),
+ IsPartition (false),
+ IsVirtualPartition (false),
+ HasUnencryptedFilesystem (false),
+ Removable (false),
+ Size (0)
+ {
+ }
+
+ ~HostDevice () { }
+
+ bool Bootable;
+ bool ContainsSystem;
+ bool DynamicVolume;
+ bool Floppy;
+ bool IsPartition;
+ bool IsVirtualPartition;
+ bool HasUnencryptedFilesystem;
+ std::string MountPoint;
+ std::wstring Name;
+ std::string Path;
+ bool Removable;
+ uint64 Size;
+ uint32 SystemNumber;
+
+ std::vector <HostDevice> Partitions;
+};
+
+BOOL BrowseFilesInDir (HWND hwndDlg, char *stringId, char *initialDir, char *lpszFileName, BOOL keepHistory, BOOL saveMode, wchar_t *browseFilter, const wchar_t *initialFileName = NULL, const wchar_t *defaultExtension = NULL);
+std::wstring SingleStringToWide (const std::string &singleString);
+std::wstring Utf8StringToWide (const std::string &utf8String);
+std::string WideToSingleString (const std::wstring &wideString);
+std::string WideToUtf8String (const std::wstring &wideString);
+std::string StringToUpperCase (const std::string &str);
+std::vector <HostDevice> GetAvailableHostDevices (bool noDeviceProperties = false, bool singleList = false, bool noFloppy = true, bool detectUnencryptedFilesystems = false);
+std::string ToUpperCase (const std::string &str);
+std::wstring GetWrongPasswordErrorMessage (HWND hwndDlg);
+std::string GetWindowsEdition ();
+std::string FitPathInGfxWidth (HWND hwnd, HFONT hFont, LONG width, const std::string &path);
+std::string GetServiceConfigPath (const char *fileName);
+std::string VolumeGuidPathToDevicePath (std::string volumeGuidPath);
+std::string HarddiskVolumePathToPartitionPath (const std::string &harddiskVolumePath);
+std::string FindLatestFileOrDirectory (const std::string &directory, const char *namePattern, bool findDirectory, bool findFile);
+std::string GetUserFriendlyVersionString (int version);
+
+#endif // __cplusplus
+
+#endif // TC_HEADER_DLGCODE
diff --git a/src/Common/EncryptionThreadPool.c b/src/Common/EncryptionThreadPool.c new file mode 100644 index 00000000..bd6b7b1b --- /dev/null +++ b/src/Common/EncryptionThreadPool.c @@ -0,0 +1,507 @@ +/*
+ 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 "EncryptionThreadPool.h"
+#include "Pkcs5.h"
+#ifdef DEVICE_DRIVER
+#include "Driver/Ntdriver.h"
+#endif
+
+#define TC_ENC_THREAD_POOL_MAX_THREAD_COUNT 64
+#define TC_ENC_THREAD_POOL_QUEUE_SIZE (TC_ENC_THREAD_POOL_MAX_THREAD_COUNT * 2)
+
+#ifdef DEVICE_DRIVER
+
+#define TC_THREAD_HANDLE PKTHREAD
+#define TC_THREAD_PROC VOID
+
+#define TC_SET_EVENT(EVENT) KeSetEvent (&EVENT, IO_DISK_INCREMENT, FALSE)
+#define TC_CLEAR_EVENT(EVENT) KeClearEvent (&EVENT)
+
+#define TC_MUTEX FAST_MUTEX
+#define TC_ACQUIRE_MUTEX(MUTEX) ExAcquireFastMutex (MUTEX)
+#define TC_RELEASE_MUTEX(MUTEX) ExReleaseFastMutex (MUTEX)
+
+#else // !DEVICE_DRIVER
+
+#define TC_THREAD_HANDLE HANDLE
+#define TC_THREAD_PROC unsigned __stdcall
+
+#define TC_SET_EVENT(EVENT) SetEvent (EVENT)
+#define TC_CLEAR_EVENT(EVENT) ResetEvent (EVENT)
+
+#define TC_MUTEX HANDLE
+#define TC_ACQUIRE_MUTEX(MUTEX) WaitForSingleObject (*(MUTEX), INFINITE)
+#define TC_RELEASE_MUTEX(MUTEX) ReleaseMutex (*(MUTEX))
+
+#endif // !DEVICE_DRIVER
+
+
+typedef enum
+{
+ WorkItemFree,
+ WorkItemReady,
+ WorkItemBusy
+} WorkItemState;
+
+
+typedef struct EncryptionThreadPoolWorkItemStruct
+{
+ WorkItemState State;
+ EncryptionThreadPoolWorkType Type;
+
+ TC_EVENT ItemCompletedEvent;
+
+ struct EncryptionThreadPoolWorkItemStruct *FirstFragment;
+ LONG OutstandingFragmentCount;
+
+ union
+ {
+ struct
+ {
+ PCRYPTO_INFO CryptoInfo;
+ byte *Data;
+ UINT64_STRUCT StartUnitNo;
+ uint32 UnitCount;
+
+ } Encryption;
+
+ struct
+ {
+ TC_EVENT *CompletionEvent;
+ LONG *CompletionFlag;
+ char *DerivedKey;
+ int IterationCount;
+ TC_EVENT *NoOutstandingWorkItemEvent;
+ LONG *OutstandingWorkItemCount;
+ char *Password;
+ int PasswordLength;
+ int Pkcs5Prf;
+ char *Salt;
+
+ } KeyDerivation;
+ };
+
+} EncryptionThreadPoolWorkItem;
+
+
+static volatile BOOL ThreadPoolRunning = FALSE;
+static volatile BOOL StopPending = FALSE;
+
+static uint32 ThreadCount;
+static TC_THREAD_HANDLE ThreadHandles[TC_ENC_THREAD_POOL_MAX_THREAD_COUNT];
+
+static EncryptionThreadPoolWorkItem WorkItemQueue[TC_ENC_THREAD_POOL_QUEUE_SIZE];
+
+static volatile int EnqueuePosition;
+static volatile int DequeuePosition;
+
+static TC_MUTEX EnqueueMutex;
+static TC_MUTEX DequeueMutex;
+
+static TC_EVENT WorkItemReadyEvent;
+static TC_EVENT WorkItemCompletedEvent;
+
+
+static WorkItemState GetWorkItemState (EncryptionThreadPoolWorkItem *workItem)
+{
+ return InterlockedExchangeAdd ((LONG *) &workItem->State, 0);
+}
+
+
+static void SetWorkItemState (EncryptionThreadPoolWorkItem *workItem, WorkItemState newState)
+{
+ InterlockedExchange ((LONG *) &workItem->State, (LONG) newState);
+}
+
+
+static TC_THREAD_PROC EncryptionThreadProc (void *threadArg)
+{
+ EncryptionThreadPoolWorkItem *workItem;
+
+ while (!StopPending)
+ {
+ TC_ACQUIRE_MUTEX (&DequeueMutex);
+
+ workItem = &WorkItemQueue[DequeuePosition++];
+
+ if (DequeuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE)
+ DequeuePosition = 0;
+
+ while (!StopPending && GetWorkItemState (workItem) != WorkItemReady)
+ {
+ TC_WAIT_EVENT (WorkItemReadyEvent);
+ }
+
+ SetWorkItemState (workItem, WorkItemBusy);
+
+ TC_RELEASE_MUTEX (&DequeueMutex);
+
+ if (StopPending)
+ break;
+
+ switch (workItem->Type)
+ {
+ case DecryptDataUnitsWork:
+ DecryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
+ break;
+
+ case EncryptDataUnitsWork:
+ EncryptDataUnitsCurrentThread (workItem->Encryption.Data, &workItem->Encryption.StartUnitNo, workItem->Encryption.UnitCount, workItem->Encryption.CryptoInfo);
+ break;
+
+ case DeriveKeyWork:
+ switch (workItem->KeyDerivation.Pkcs5Prf)
+ {
+ case RIPEMD160:
+ derive_key_ripemd160 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
+ workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
+ break;
+
+ case SHA512:
+ derive_key_sha512 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
+ workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
+ break;
+
+ case WHIRLPOOL:
+ derive_key_whirlpool (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
+ workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
+ break;
+
+ case SHA1:
+ derive_key_sha1 (workItem->KeyDerivation.Password, workItem->KeyDerivation.PasswordLength, workItem->KeyDerivation.Salt, PKCS5_SALT_SIZE,
+ workItem->KeyDerivation.IterationCount, workItem->KeyDerivation.DerivedKey, GetMaxPkcs5OutSize());
+ break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+
+ InterlockedExchange (workItem->KeyDerivation.CompletionFlag, TRUE);
+ TC_SET_EVENT (*workItem->KeyDerivation.CompletionEvent);
+
+ if (InterlockedDecrement (workItem->KeyDerivation.OutstandingWorkItemCount) == 0)
+ TC_SET_EVENT (*workItem->KeyDerivation.NoOutstandingWorkItemEvent);
+
+ SetWorkItemState (workItem, WorkItemFree);
+ TC_SET_EVENT (WorkItemCompletedEvent);
+ continue;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+
+ if (workItem != workItem->FirstFragment)
+ {
+ SetWorkItemState (workItem, WorkItemFree);
+ TC_SET_EVENT (WorkItemCompletedEvent);
+ }
+
+ if (InterlockedDecrement (&workItem->FirstFragment->OutstandingFragmentCount) == 0)
+ TC_SET_EVENT (workItem->FirstFragment->ItemCompletedEvent);
+ }
+
+#ifdef DEVICE_DRIVER
+ PsTerminateSystemThread (STATUS_SUCCESS);
+#else
+ _endthreadex (0);
+ return 0;
+#endif
+}
+
+
+BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount)
+{
+ size_t cpuCount, i;
+
+ if (ThreadPoolRunning)
+ return TRUE;
+
+#ifdef DEVICE_DRIVER
+ cpuCount = GetCpuCount();
+#else
+ {
+ SYSTEM_INFO sysInfo;
+ GetSystemInfo (&sysInfo);
+ cpuCount = sysInfo.dwNumberOfProcessors;
+ }
+#endif
+
+ if (cpuCount > encryptionFreeCpuCount)
+ cpuCount -= encryptionFreeCpuCount;
+
+ if (cpuCount < 2)
+ return TRUE;
+
+ if (cpuCount > TC_ENC_THREAD_POOL_MAX_THREAD_COUNT)
+ cpuCount = TC_ENC_THREAD_POOL_MAX_THREAD_COUNT;
+
+ StopPending = FALSE;
+ DequeuePosition = 0;
+ EnqueuePosition = 0;
+
+#ifdef DEVICE_DRIVER
+ KeInitializeEvent (&WorkItemReadyEvent, SynchronizationEvent, FALSE);
+ KeInitializeEvent (&WorkItemCompletedEvent, SynchronizationEvent, FALSE);
+#else
+ WorkItemReadyEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+ if (!WorkItemReadyEvent)
+ return FALSE;
+
+ WorkItemCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+ if (!WorkItemCompletedEvent)
+ return FALSE;
+#endif
+
+#ifdef DEVICE_DRIVER
+ ExInitializeFastMutex (&DequeueMutex);
+ ExInitializeFastMutex (&EnqueueMutex);
+#else
+ DequeueMutex = CreateMutex (NULL, FALSE, NULL);
+ if (!DequeueMutex)
+ return FALSE;
+
+ EnqueueMutex = CreateMutex (NULL, FALSE, NULL);
+ if (!EnqueueMutex)
+ return FALSE;
+#endif
+
+ memset (WorkItemQueue, 0, sizeof (WorkItemQueue));
+
+ for (i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i)
+ {
+ WorkItemQueue[i].State = WorkItemFree;
+
+#ifdef DEVICE_DRIVER
+ KeInitializeEvent (&WorkItemQueue[i].ItemCompletedEvent, SynchronizationEvent, FALSE);
+#else
+ WorkItemQueue[i].ItemCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
+ if (!WorkItemQueue[i].ItemCompletedEvent)
+ {
+ EncryptionThreadPoolStop();
+ return FALSE;
+ }
+#endif
+ }
+
+ for (ThreadCount = 0; ThreadCount < cpuCount; ++ThreadCount)
+ {
+#ifdef DEVICE_DRIVER
+ if (!NT_SUCCESS (TCStartThread (EncryptionThreadProc, NULL, &ThreadHandles[ThreadCount])))
+#else
+ if (!(ThreadHandles[ThreadCount] = (HANDLE) _beginthreadex (NULL, 0, EncryptionThreadProc, NULL, 0, NULL)))
+#endif
+ {
+ EncryptionThreadPoolStop();
+ return FALSE;
+ }
+ }
+
+ ThreadPoolRunning = TRUE;
+ return TRUE;
+}
+
+
+void EncryptionThreadPoolStop ()
+{
+ size_t i;
+
+ if (!ThreadPoolRunning)
+ return;
+
+ StopPending = TRUE;
+ TC_SET_EVENT (WorkItemReadyEvent);
+
+ for (i = 0; i < ThreadCount; ++i)
+ {
+#ifdef DEVICE_DRIVER
+ TCStopThread (ThreadHandles[i], &WorkItemReadyEvent);
+#else
+ TC_WAIT_EVENT (ThreadHandles[i]);
+#endif
+ }
+
+ ThreadCount = 0;
+
+#ifndef DEVICE_DRIVER
+ CloseHandle (DequeueMutex);
+ CloseHandle (EnqueueMutex);
+
+ CloseHandle (WorkItemReadyEvent);
+ CloseHandle (WorkItemCompletedEvent);
+
+ for (i = 0; i < sizeof (WorkItemQueue) / sizeof (WorkItemQueue[0]); ++i)
+ {
+ if (WorkItemQueue[i].ItemCompletedEvent)
+ CloseHandle (WorkItemQueue[i].ItemCompletedEvent);
+ }
+#endif
+
+ ThreadPoolRunning = FALSE;
+}
+
+
+void EncryptionThreadPoolBeginKeyDerivation (TC_EVENT *completionEvent, TC_EVENT *noOutstandingWorkItemEvent, LONG *completionFlag, LONG *outstandingWorkItemCount, int pkcs5Prf, char *password, int passwordLength, char *salt, int iterationCount, char *derivedKey)
+{
+ EncryptionThreadPoolWorkItem *workItem;
+
+ if (!ThreadPoolRunning)
+ TC_THROW_FATAL_EXCEPTION;
+
+ TC_ACQUIRE_MUTEX (&EnqueueMutex);
+
+ workItem = &WorkItemQueue[EnqueuePosition++];
+ if (EnqueuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE)
+ EnqueuePosition = 0;
+
+ while (GetWorkItemState (workItem) != WorkItemFree)
+ {
+ TC_WAIT_EVENT (WorkItemCompletedEvent);
+ }
+
+ workItem->Type = DeriveKeyWork;
+ workItem->KeyDerivation.CompletionEvent = completionEvent;
+ workItem->KeyDerivation.CompletionFlag = completionFlag;
+ workItem->KeyDerivation.DerivedKey = derivedKey;
+ workItem->KeyDerivation.IterationCount = iterationCount;
+ workItem->KeyDerivation.NoOutstandingWorkItemEvent = noOutstandingWorkItemEvent;
+ workItem->KeyDerivation.OutstandingWorkItemCount = outstandingWorkItemCount;
+ workItem->KeyDerivation.Password = password;
+ workItem->KeyDerivation.PasswordLength = passwordLength;
+ workItem->KeyDerivation.Pkcs5Prf = pkcs5Prf;
+ workItem->KeyDerivation.Salt = salt;
+
+ InterlockedIncrement (outstandingWorkItemCount);
+ TC_CLEAR_EVENT (*noOutstandingWorkItemEvent);
+
+ SetWorkItemState (workItem, WorkItemReady);
+ TC_SET_EVENT (WorkItemReadyEvent);
+ TC_RELEASE_MUTEX (&EnqueueMutex);
+}
+
+
+void EncryptionThreadPoolDoWork (EncryptionThreadPoolWorkType type, byte *data, const UINT64_STRUCT *startUnitNo, uint32 unitCount, PCRYPTO_INFO cryptoInfo)
+{
+ uint32 fragmentCount;
+ uint32 unitsPerFragment;
+ uint32 remainder;
+
+ byte *fragmentData;
+ uint64 fragmentStartUnitNo;
+
+ EncryptionThreadPoolWorkItem *workItem;
+ EncryptionThreadPoolWorkItem *firstFragmentWorkItem;
+
+ if (unitCount == 0)
+ return;
+
+ if (!ThreadPoolRunning || unitCount == 1)
+ {
+ switch (type)
+ {
+ case DecryptDataUnitsWork:
+ DecryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo);
+ break;
+
+ case EncryptDataUnitsWork:
+ EncryptDataUnitsCurrentThread (data, startUnitNo, unitCount, cryptoInfo);
+ break;
+
+ default:
+ TC_THROW_FATAL_EXCEPTION;
+ }
+
+ return;
+ }
+
+ if (unitCount <= ThreadCount)
+ {
+ fragmentCount = unitCount;
+ unitsPerFragment = 1;
+ remainder = 0;
+ }
+ else
+ {
+ /* Note that it is not efficient to divide the data into fragments smaller than a few hundred bytes.
+ The reason is that the overhead associated with thread handling would in most cases make a multi-threaded
+ process actually slower than a single-threaded process. */
+
+ fragmentCount = ThreadCount;
+ unitsPerFragment = unitCount / ThreadCount;
+ remainder = unitCount % ThreadCount;
+
+ if (remainder > 0)
+ ++unitsPerFragment;
+ }
+
+ fragmentData = data;
+ fragmentStartUnitNo = startUnitNo->Value;
+
+ TC_ACQUIRE_MUTEX (&EnqueueMutex);
+ firstFragmentWorkItem = &WorkItemQueue[EnqueuePosition];
+
+ while (GetWorkItemState (firstFragmentWorkItem) != WorkItemFree)
+ {
+ TC_WAIT_EVENT (WorkItemCompletedEvent);
+ }
+
+ firstFragmentWorkItem->OutstandingFragmentCount = fragmentCount;
+
+ while (fragmentCount-- > 0)
+ {
+ workItem = &WorkItemQueue[EnqueuePosition++];
+ if (EnqueuePosition >= TC_ENC_THREAD_POOL_QUEUE_SIZE)
+ EnqueuePosition = 0;
+
+ while (GetWorkItemState (workItem) != WorkItemFree)
+ {
+ TC_WAIT_EVENT (WorkItemCompletedEvent);
+ }
+
+ workItem->Type = type;
+ workItem->FirstFragment = firstFragmentWorkItem;
+
+ workItem->Encryption.CryptoInfo = cryptoInfo;
+ workItem->Encryption.Data = fragmentData;
+ workItem->Encryption.UnitCount = unitsPerFragment;
+ workItem->Encryption.StartUnitNo.Value = fragmentStartUnitNo;
+
+ fragmentData += unitsPerFragment * ENCRYPTION_DATA_UNIT_SIZE;
+ fragmentStartUnitNo += unitsPerFragment;
+
+ if (remainder > 0 && --remainder == 0)
+ --unitsPerFragment;
+
+ SetWorkItemState (workItem, WorkItemReady);
+ TC_SET_EVENT (WorkItemReadyEvent);
+ }
+
+ TC_RELEASE_MUTEX (&EnqueueMutex);
+
+ TC_WAIT_EVENT (firstFragmentWorkItem->ItemCompletedEvent);
+ SetWorkItemState (firstFragmentWorkItem, WorkItemFree);
+ TC_SET_EVENT (WorkItemCompletedEvent);
+}
+
+
+size_t GetEncryptionThreadCount ()
+{
+ return ThreadPoolRunning ? ThreadCount : 0;
+}
+
+
+size_t GetMaxEncryptionThreadCount ()
+{
+ return TC_ENC_THREAD_POOL_MAX_THREAD_COUNT;
+}
+
+
+BOOL IsEncryptionThreadPoolRunning ()
+{
+ return ThreadPoolRunning;
+}
diff --git a/src/Common/EncryptionThreadPool.h b/src/Common/EncryptionThreadPool.h new file mode 100644 index 00000000..7b6d19fd --- /dev/null +++ b/src/Common/EncryptionThreadPool.h @@ -0,0 +1,38 @@ +/*
+ 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_ENCRYPTION_THREAD_POOL
+#define TC_HEADER_ENCRYPTION_THREAD_POOL
+
+#include "Tcdefs.h"
+#include "Crypto.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+ EncryptDataUnitsWork,
+ DecryptDataUnitsWork,
+ DeriveKeyWork
+} EncryptionThreadPoolWorkType;
+
+void EncryptionThreadPoolBeginKeyDerivation (TC_EVENT *completionEvent, TC_EVENT *noOutstandingWorkItemEvent, LONG *completionFlag, LONG *outstandingWorkItemCount, int pkcs5Prf, char *password, int passwordLength, char *salt, int iterationCount, char *derivedKey);
+void EncryptionThreadPoolDoWork (EncryptionThreadPoolWorkType type, byte *data, const UINT64_STRUCT *startUnitNo, uint32 unitCount, PCRYPTO_INFO cryptoInfo);
+BOOL EncryptionThreadPoolStart (size_t encryptionFreeCpuCount);
+void EncryptionThreadPoolStop ();
+size_t GetEncryptionThreadCount ();
+size_t GetMaxEncryptionThreadCount ();
+BOOL IsEncryptionThreadPoolRunning ();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // TC_HEADER_ENCRYPTION_THREAD_POOL
diff --git a/src/Common/Endian.c b/src/Common/Endian.c new file mode 100644 index 00000000..75f595e0 --- /dev/null +++ b/src/Common/Endian.c @@ -0,0 +1,57 @@ +/*
+ 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 "Common/Endian.h"
+
+
+unsigned __int16 MirrorBytes16 (unsigned __int16 x)
+{
+ return (x << 8) | (x >> 8);
+}
+
+
+unsigned __int32 MirrorBytes32 (unsigned __int32 x)
+{
+ unsigned __int32 n = (unsigned __int8) x;
+ n <<= 8; n |= (unsigned __int8) (x >> 8);
+ n <<= 8; n |= (unsigned __int8) (x >> 16);
+ return (n << 8) | (unsigned __int8) (x >> 24);
+}
+
+#ifndef TC_NO_COMPILER_INT64
+uint64 MirrorBytes64 (uint64 x)
+{
+ uint64 n = (unsigned __int8) x;
+ n <<= 8; n |= (unsigned __int8) (x >> 8);
+ n <<= 8; n |= (unsigned __int8) (x >> 16);
+ n <<= 8; n |= (unsigned __int8) (x >> 24);
+ n <<= 8; n |= (unsigned __int8) (x >> 32);
+ n <<= 8; n |= (unsigned __int8) (x >> 40);
+ n <<= 8; n |= (unsigned __int8) (x >> 48);
+ return (n << 8) | (unsigned __int8) (x >> 56);
+}
+#endif
+
+void
+LongReverse (unsigned __int32 *buffer, unsigned byteCount)
+{
+ unsigned __int32 value;
+
+ byteCount /= sizeof (unsigned __int32);
+ while (byteCount--)
+ {
+ value = *buffer;
+ value = ((value & 0xFF00FF00L) >> 8) | \
+ ((value & 0x00FF00FFL) << 8);
+ *buffer++ = (value << 16) | (value >> 16);
+ }
+}
diff --git a/src/Common/Endian.h b/src/Common/Endian.h new file mode 100644 index 00000000..38af8cfb --- /dev/null +++ b/src/Common/Endian.h @@ -0,0 +1,147 @@ +/*
+ 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. */
+
+#ifndef TC_ENDIAN_H
+#define TC_ENDIAN_H
+
+#include "Common/Tcdefs.h"
+
+#if defined(__cplusplus)
+extern "C"
+{
+#endif
+
+#ifdef _WIN32
+
+# ifndef LITTLE_ENDIAN
+# define LITTLE_ENDIAN 1234
+# endif
+# ifndef BYTE_ORDER
+# define BYTE_ORDER LITTLE_ENDIAN
+# endif
+
+#elif !defined(BYTE_ORDER)
+
+# ifdef TC_MACOSX
+# include <machine/endian.h>
+# elif defined (TC_BSD)
+# include <sys/endian.h>
+# elif defined (TC_SOLARIS)
+# include <sys/types.h>
+# define LITTLE_ENDIAN 1234
+# define BIG_ENDIAN 4321
+# ifdef _BIG_ENDIAN
+# define BYTE_ORDER BIG_ENDIAN
+# else
+# define BYTE_ORDER LITTLE_ENDIAN
+# endif
+# else
+# include <endian.h>
+# endif
+
+# ifndef BYTE_ORDER
+# ifndef __BYTE_ORDER
+# error Byte order cannot be determined (BYTE_ORDER undefined)
+# endif
+
+# define BYTE_ORDER __BYTE_ORDER
+# endif
+
+# ifndef LITTLE_ENDIAN
+# define LITTLE_ENDIAN __LITTLE_ENDIAN
+# endif
+
+# ifndef BIG_ENDIAN
+# define BIG_ENDIAN __BIG_ENDIAN
+# endif
+
+#endif // !BYTE_ORDER
+
+/* Macros to read and write 16, 32, and 64-bit quantities in a portable manner.
+ These functions are implemented as macros rather than true functions as
+ the need to adjust the memory pointers makes them somewhat painful to call
+ in user code */
+
+#define mputInt64(memPtr,data) \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 56 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 48 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 40 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 32 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 24 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 16 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 8 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( data ) & 0xFF )
+
+#define mputLong(memPtr,data) \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 24 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 16 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 8 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( data ) & 0xFF )
+
+#define mputWord(memPtr,data) \
+ *memPtr++ = ( unsigned char ) ( ( ( data ) >> 8 ) & 0xFF ), \
+ *memPtr++ = ( unsigned char ) ( ( data ) & 0xFF )
+
+#define mputByte(memPtr,data) \
+ *memPtr++ = ( unsigned char ) data
+
+#define mputBytes(memPtr,data,len) \
+ memcpy (memPtr,data,len); \
+ memPtr += len;
+
+#define mgetInt64(memPtr) \
+ ( memPtr += 8, ( ( unsigned __int64 ) memPtr[ -8 ] << 56 ) | ( ( unsigned __int64 ) memPtr[ -7 ] << 48 ) | \
+ ( ( unsigned __int64 ) memPtr[ -6 ] << 40 ) | ( ( unsigned __int64 ) memPtr[ -5 ] << 32 ) | \
+ ( ( unsigned __int64 ) memPtr[ -4 ] << 24 ) | ( ( unsigned __int64 ) memPtr[ -3 ] << 16 ) | \
+ ( ( unsigned __int64 ) memPtr[ -2 ] << 8 ) | ( unsigned __int64 ) memPtr[ -1 ] )
+
+#define mgetLong(memPtr) \
+ ( memPtr += 4, ( ( unsigned __int32 ) memPtr[ -4 ] << 24 ) | ( ( unsigned __int32 ) memPtr[ -3 ] << 16 ) | \
+ ( ( unsigned __int32 ) memPtr[ -2 ] << 8 ) | ( unsigned __int32 ) memPtr[ -1 ] )
+
+#define mgetWord(memPtr) \
+ ( memPtr += 2, ( unsigned short ) memPtr[ -2 ] << 8 ) | ( ( unsigned short ) memPtr[ -1 ] )
+
+#define mgetByte(memPtr) \
+ ( ( unsigned char ) *memPtr++ )
+
+#if BYTE_ORDER == BIG_ENDIAN
+# define LE16(x) MirrorBytes16(x)
+# define LE32(x) MirrorBytes32(x)
+# define LE64(x) MirrorBytes64(x)
+#else
+# define LE16(x) (x)
+# define LE32(x) (x)
+# define LE64(x) (x)
+#endif
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define BE16(x) MirrorBytes16(x)
+# define BE32(x) MirrorBytes32(x)
+# define BE64(x) MirrorBytes64(x)
+#else
+# define BE16(x) (x)
+# define BE32(x) (x)
+# define BE64(x) (x)
+#endif
+
+unsigned __int16 MirrorBytes16 (unsigned __int16 x);
+unsigned __int32 MirrorBytes32 (unsigned __int32 x);
+#ifndef TC_NO_COMPILER_INT64
+uint64 MirrorBytes64 (uint64 x);
+#endif
+void LongReverse ( unsigned __int32 *buffer , unsigned byteCount );
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* TC_ENDIAN_H */
diff --git a/src/Common/Exception.h b/src/Common/Exception.h new file mode 100644 index 00000000..8e084742 --- /dev/null +++ b/src/Common/Exception.h @@ -0,0 +1,81 @@ +/*
+ 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_Common_Exception
+#define TC_HEADER_Common_Exception
+
+#include "Platform/PlatformBase.h"
+#include "Dlgcode.h"
+
+namespace TrueCrypt
+{
+ struct Exception
+ {
+ virtual void Show (HWND parent) const = 0;
+ };
+
+ struct SystemException : public Exception
+ {
+ SystemException () : ErrorCode (GetLastError()) { }
+
+ void Show (HWND parent) const
+ {
+ SetLastError (ErrorCode);
+ handleWin32Error (parent);
+ }
+
+ DWORD ErrorCode;
+ };
+
+ struct ErrorException : public Exception
+ {
+ ErrorException (char *langId) : ErrLangId (langId) { }
+ ErrorException (const wstring &errMsg) : ErrMsg (errMsg) { }
+
+ void Show (HWND parent) const
+ {
+ if (ErrMsg.empty())
+ ::Error (ErrLangId);
+ else
+ ::ErrorDirect (ErrMsg.c_str());
+ }
+
+ char *ErrLangId;
+ wstring ErrMsg;
+ };
+
+ struct ParameterIncorrect : public Exception
+ {
+ ParameterIncorrect (const char *srcPos) : SrcPos (srcPos) { }
+
+ void Show (HWND parent) const
+ {
+ string msgBody = "Parameter incorrect.\n\n\n(If you report a bug in connection with this, please include the following technical information in the bug report:\n" + string (SrcPos) + ")";
+ MessageBox (parent, msgBody.c_str(), "TrueCrypt", MB_ICONERROR | MB_SETFOREGROUND);
+ }
+
+ const char *SrcPos;
+ };
+
+ struct TimeOut : public Exception
+ {
+ TimeOut (const char *srcPos) { }
+ void Show (HWND parent) const { ErrorDirect (L"Timeout"); }
+ };
+
+ struct UserAbort : public Exception
+ {
+ UserAbort (const char *srcPos) { }
+ void Show (HWND parent) const { }
+ };
+}
+
+#define throw_sys_if(condition) do { if (condition) throw SystemException(); } while (false)
+
+
+#endif // TC_HEADER_Common_Exception
diff --git a/src/Common/Fat.c b/src/Common/Fat.c new file mode 100644 index 00000000..6a2c77db --- /dev/null +++ b/src/Common/Fat.c @@ -0,0 +1,445 @@ +/*
+ 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 <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "Tcdefs.h"
+
+#include "Crypto.h"
+#include "Common/Endian.h"
+#include "Format.h"
+#include "Fat.h"
+#include "Progress.h"
+#include "Random.h"
+#include "Volumes.h"
+
+void
+GetFatParams (fatparams * ft)
+{
+ uint64 volumeSize = (uint64) ft->num_sectors * ft->sector_size;
+ unsigned int fatsecs;
+
+ if(ft->cluster_size == 0) // 'Default' cluster size
+ {
+ uint32 clusterSize;
+
+ // Determine optimal cluster size to minimize FAT size (mounting delay), maximize number of files, keep 4 KB alignment, etc.
+ if (volumeSize >= 2 * BYTES_PER_TB)
+ clusterSize = 256 * BYTES_PER_KB;
+ else if (volumeSize >= 512 * BYTES_PER_GB)
+ clusterSize = 128 * BYTES_PER_KB;
+ else if (volumeSize >= 128 * BYTES_PER_GB)
+ clusterSize = 64 * BYTES_PER_KB;
+ else if (volumeSize >= 64 * BYTES_PER_GB)
+ clusterSize = 32 * BYTES_PER_KB;
+ else if (volumeSize >= 32 * BYTES_PER_GB)
+ clusterSize = 16 * BYTES_PER_KB;
+ else if (volumeSize >= 16 * BYTES_PER_GB)
+ clusterSize = 8 * BYTES_PER_KB;
+ else if (volumeSize >= 512 * BYTES_PER_MB)
+ clusterSize = 4 * BYTES_PER_KB;
+ else if (volumeSize >= 256 * BYTES_PER_MB)
+ clusterSize = 2 * BYTES_PER_KB;
+ else if (volumeSize >= 1 * BYTES_PER_MB)
+ clusterSize = 1 * BYTES_PER_KB;
+ else
+ clusterSize = 512;
+
+ ft->cluster_size = clusterSize / ft->sector_size;
+
+ if (ft->cluster_size == 0)
+ ft->cluster_size = 1;
+
+ if (ft->cluster_size * ft->sector_size > TC_MAX_FAT_CLUSTER_SIZE)
+ ft->cluster_size = TC_MAX_FAT_CLUSTER_SIZE / ft->sector_size;
+
+ if (ft->cluster_size > 128)
+ ft->cluster_size = 128;
+ }
+
+ if (volumeSize <= TC_MAX_FAT_CLUSTER_SIZE * 4)
+ ft->cluster_size = 1;
+
+ // Geometry always set to SECTORS/1/1
+ ft->secs_track = 1;
+ ft->heads = 1;
+
+ ft->dir_entries = 512;
+ ft->fats = 2;
+ ft->media = 0xf8;
+ ft->hidden = 0;
+
+ ft->size_root_dir = ft->dir_entries * 32;
+
+ // FAT12
+ ft->size_fat = 12;
+ ft->reserved = 2;
+ fatsecs = ft->num_sectors - (ft->size_root_dir + ft->sector_size - 1) / ft->sector_size - ft->reserved;
+ ft->cluster_count = (int) (((__int64) fatsecs * ft->sector_size) / (ft->cluster_size * ft->sector_size));
+ ft->fat_length = (((ft->cluster_count * 3 + 1) >> 1) + ft->sector_size - 1) / ft->sector_size;
+
+ if (ft->cluster_count >= 4085) // FAT16
+ {
+ ft->size_fat = 16;
+ ft->reserved = 2;
+ fatsecs = ft->num_sectors - (ft->size_root_dir + ft->sector_size - 1) / ft->sector_size - ft->reserved;
+ ft->cluster_count = (int) (((__int64) fatsecs * ft->sector_size) / (ft->cluster_size * ft->sector_size));
+ ft->fat_length = (ft->cluster_count * 2 + ft->sector_size - 1) / ft->sector_size;
+ }
+
+ if(ft->cluster_count >= 65525) // FAT32
+ {
+ ft->size_fat = 32;
+ ft->reserved = 32 - 1;
+
+ do
+ {
+ ft->reserved++;
+
+ fatsecs = ft->num_sectors - ft->reserved;
+ ft->size_root_dir = ft->cluster_size * ft->sector_size;
+ ft->cluster_count = (int) (((__int64) fatsecs * ft->sector_size) / (ft->cluster_size * ft->sector_size));
+ ft->fat_length = (ft->cluster_count * 4 + ft->sector_size - 1) / ft->sector_size;
+
+ // Align data area on TC_MAX_VOLUME_SECTOR_SIZE
+
+ } while (ft->sector_size == TC_SECTOR_SIZE_LEGACY
+ && (ft->reserved * ft->sector_size + ft->fat_length * ft->fats * ft->sector_size) % TC_MAX_VOLUME_SECTOR_SIZE != 0);
+ }
+
+ ft->cluster_count -= ft->fat_length * ft->fats / ft->cluster_size;
+
+ if (ft->num_sectors >= 65536 || ft->size_fat == 32)
+ {
+ ft->sectors = 0;
+ ft->total_sect = ft->num_sectors;
+ }
+ else
+ {
+ ft->sectors = (uint16) ft->num_sectors;
+ ft->total_sect = 0;
+ }
+}
+
+void
+PutBoot (fatparams * ft, unsigned char *boot)
+{
+ int cnt = 0;
+
+ boot[cnt++] = 0xeb; /* boot jump */
+ boot[cnt++] = 0x3c;
+ boot[cnt++] = 0x90;
+ memcpy (boot + cnt, "MSDOS5.0", 8); /* system id */
+ cnt += 8;
+ *(__int16 *)(boot + cnt) = LE16(ft->sector_size); /* bytes per sector */
+ cnt += 2;
+ boot[cnt++] = (__int8) ft->cluster_size; /* sectors per cluster */
+ *(__int16 *)(boot + cnt) = LE16(ft->reserved); /* reserved sectors */
+ cnt += 2;
+ boot[cnt++] = (__int8) ft->fats; /* 2 fats */
+
+ if(ft->size_fat == 32)
+ {
+ boot[cnt++] = 0x00;
+ boot[cnt++] = 0x00;
+ }
+ else
+ {
+ *(__int16 *)(boot + cnt) = LE16(ft->dir_entries); /* 512 root entries */
+ cnt += 2;
+ }
+
+ *(__int16 *)(boot + cnt) = LE16(ft->sectors); /* # sectors */
+ cnt += 2;
+ boot[cnt++] = (__int8) ft->media; /* media byte */
+
+ if(ft->size_fat == 32)
+ {
+ boot[cnt++] = 0x00;
+ boot[cnt++] = 0x00;
+ }
+ else
+ {
+ *(__int16 *)(boot + cnt) = LE16((uint16) ft->fat_length); /* fat size */
+ cnt += 2;
+ }
+
+ *(__int16 *)(boot + cnt) = LE16(ft->secs_track); /* # sectors per track */
+ cnt += 2;
+ *(__int16 *)(boot + cnt) = LE16(ft->heads); /* # heads */
+ cnt += 2;
+ *(__int32 *)(boot + cnt) = LE32(ft->hidden); /* # hidden sectors */
+ cnt += 4;
+ *(__int32 *)(boot + cnt) = LE32(ft->total_sect); /* # huge sectors */
+ cnt += 4;
+
+ if(ft->size_fat == 32)
+ {
+ *(__int32 *)(boot + cnt) = LE32(ft->fat_length); cnt += 4; /* fat size 32 */
+ boot[cnt++] = 0x00; /* ExtFlags */
+ boot[cnt++] = 0x00;
+ boot[cnt++] = 0x00; /* FSVer */
+ boot[cnt++] = 0x00;
+ boot[cnt++] = 0x02; /* RootClus */
+ boot[cnt++] = 0x00;
+ boot[cnt++] = 0x00;
+ boot[cnt++] = 0x00;
+ boot[cnt++] = 0x01; /* FSInfo */
+ boot[cnt++] = 0x00;
+ boot[cnt++] = 0x06; /* BkBootSec */
+ boot[cnt++] = 0x00;
+ memset(boot+cnt, 0, 12); cnt+=12; /* Reserved */
+ }
+
+ boot[cnt++] = 0x00; /* drive number */ // FIXED 80 > 00
+ boot[cnt++] = 0x00; /* reserved */
+ boot[cnt++] = 0x29; /* boot sig */
+
+ memcpy (boot + cnt, ft->volume_id, 4); /* vol id */
+ cnt += 4;
+
+ memcpy (boot + cnt, ft->volume_name, 11); /* vol title */
+ cnt += 11;
+
+ switch(ft->size_fat) /* filesystem type */
+ {
+ case 12: memcpy (boot + cnt, "FAT12 ", 8); break;
+ case 16: memcpy (boot + cnt, "FAT16 ", 8); break;
+ case 32: memcpy (boot + cnt, "FAT32 ", 8); break;
+ }
+ cnt += 8;
+
+ memset (boot + cnt, 0, ft->size_fat==32 ? 420:448); /* boot code */
+ cnt += ft->size_fat==32 ? 420:448;
+ boot[cnt++] = 0x55;
+ boot[cnt++] = 0xaa; /* boot sig */
+}
+
+
+/* FAT32 FSInfo */
+static void PutFSInfo (unsigned char *sector, fatparams *ft)
+{
+ memset (sector, 0, ft->sector_size);
+ sector[3]=0x41; /* LeadSig */
+ sector[2]=0x61;
+ sector[1]=0x52;
+ sector[0]=0x52;
+ sector[484+3]=0x61; /* StrucSig */
+ sector[484+2]=0x41;
+ sector[484+1]=0x72;
+ sector[484+0]=0x72;
+
+ // Free cluster count
+ *(uint32 *)(sector + 488) = LE32 (ft->cluster_count - ft->size_root_dir / ft->sector_size / ft->cluster_size);
+
+ // Next free cluster
+ *(uint32 *)(sector + 492) = LE32 (2);
+
+ sector[508+3]=0xaa; /* TrailSig */
+ sector[508+2]=0x55;
+ sector[508+1]=0x00;
+ sector[508+0]=0x00;
+}
+
+
+int
+FormatFat (unsigned __int64 startSector, fatparams * ft, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat)
+{
+ int write_buf_cnt = 0;
+ char sector[TC_MAX_VOLUME_SECTOR_SIZE], *write_buf;
+ unsigned __int64 nSecNo = startSector;
+ int x, n;
+ int retVal;
+ char temporaryKey[MASTER_KEYDATA_SIZE];
+
+ LARGE_INTEGER startOffset;
+ LARGE_INTEGER newOffset;
+
+ // Seek to start sector
+ startOffset.QuadPart = startSector * ft->sector_size;
+ if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN)
+ || newOffset.QuadPart != startOffset.QuadPart)
+ {
+ return ERR_VOL_SEEKING;
+ }
+
+ /* Write the data area */
+
+ write_buf = (char *)TCalloc (FormatWriteBufferSize);
+ if (!write_buf)
+ return ERR_OUTOFMEMORY;
+
+ memset (sector, 0, ft->sector_size);
+
+ RandgetBytes (ft->volume_id, sizeof (ft->volume_id), FALSE);
+
+ PutBoot (ft, (unsigned char *) sector);
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ cryptoInfo) == FALSE)
+ goto fail;
+
+ /* fat32 boot area */
+ if (ft->size_fat == 32)
+ {
+ /* fsinfo */
+ PutFSInfo((unsigned char *) sector, ft);
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ cryptoInfo) == FALSE)
+ goto fail;
+
+ /* reserved */
+ while (nSecNo - startSector < 6)
+ {
+ memset (sector, 0, ft->sector_size);
+ sector[508+3]=0xaa; /* TrailSig */
+ sector[508+2]=0x55;
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ cryptoInfo) == FALSE)
+ goto fail;
+ }
+
+ /* bootsector backup */
+ memset (sector, 0, ft->sector_size);
+ PutBoot (ft, (unsigned char *) sector);
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ cryptoInfo) == FALSE)
+ goto fail;
+
+ PutFSInfo((unsigned char *) sector, ft);
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ cryptoInfo) == FALSE)
+ goto fail;
+ }
+
+ /* reserved */
+ while (nSecNo - startSector < (unsigned int)ft->reserved)
+ {
+ memset (sector, 0, ft->sector_size);
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ cryptoInfo) == FALSE)
+ goto fail;
+ }
+
+ /* write fat */
+ for (x = 1; x <= ft->fats; x++)
+ {
+ for (n = 0; n < ft->fat_length; n++)
+ {
+ memset (sector, 0, ft->sector_size);
+
+ if (n == 0)
+ {
+ unsigned char fat_sig[12];
+ if (ft->size_fat == 32)
+ {
+ fat_sig[0] = (unsigned char) ft->media;
+ fat_sig[1] = fat_sig[2] = 0xff;
+ fat_sig[3] = 0x0f;
+ fat_sig[4] = fat_sig[5] = fat_sig[6] = 0xff;
+ fat_sig[7] = 0x0f;
+ fat_sig[8] = fat_sig[9] = fat_sig[10] = 0xff;
+ fat_sig[11] = 0x0f;
+ memcpy (sector, fat_sig, 12);
+ }
+ else if (ft->size_fat == 16)
+ {
+ fat_sig[0] = (unsigned char) ft->media;
+ fat_sig[1] = 0xff;
+ fat_sig[2] = 0xff;
+ fat_sig[3] = 0xff;
+ memcpy (sector, fat_sig, 4);
+ }
+ else if (ft->size_fat == 12)
+ {
+ fat_sig[0] = (unsigned char) ft->media;
+ fat_sig[1] = 0xff;
+ fat_sig[2] = 0xff;
+ fat_sig[3] = 0x00;
+ memcpy (sector, fat_sig, 4);
+ }
+ }
+
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ cryptoInfo) == FALSE)
+ goto fail;
+ }
+ }
+
+
+ /* write rootdir */
+ for (x = 0; x < ft->size_root_dir / ft->sector_size; x++)
+ {
+ memset (sector, 0, ft->sector_size);
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ cryptoInfo) == FALSE)
+ goto fail;
+
+ }
+
+ /* Fill the rest of the data area with random data */
+
+ if(!quickFormat)
+ {
+ if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo))
+ goto fail;
+
+ /* Generate a random temporary key set to be used for "dummy" encryption that will fill
+ the free disk space (data area) with random data. This is necessary for plausible
+ deniability of hidden volumes (and also reduces the amount of predictable plaintext
+ within the volume). */
+
+ // Temporary master key
+ if (!RandgetBytes (temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE))
+ goto fail;
+
+ // Temporary secondary key (XTS mode)
+ if (!RandgetBytes (cryptoInfo->k2, sizeof cryptoInfo->k2, FALSE))
+ goto fail;
+
+ retVal = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks);
+ if (retVal != ERR_SUCCESS)
+ {
+ burn (temporaryKey, sizeof(temporaryKey));
+ return retVal;
+ }
+ if (!EAInitMode (cryptoInfo))
+ {
+ burn (temporaryKey, sizeof(temporaryKey));
+ return ERR_MODE_INIT_FAILED;
+ }
+
+ x = ft->num_sectors - ft->reserved - ft->size_root_dir / ft->sector_size - ft->fat_length * 2;
+ while (x--)
+ {
+ if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo,
+ cryptoInfo) == FALSE)
+ goto fail;
+ }
+ UpdateProgressBar (nSecNo * ft->sector_size);
+ }
+ else
+ UpdateProgressBar ((uint64) ft->num_sectors * ft->sector_size);
+
+ if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo))
+ goto fail;
+
+ TCfree (write_buf);
+ burn (temporaryKey, sizeof(temporaryKey));
+ return 0;
+
+fail:
+
+ TCfree (write_buf);
+ burn (temporaryKey, sizeof(temporaryKey));
+ return ERR_OS_ERROR;
+}
diff --git a/src/Common/Fat.h b/src/Common/Fat.h new file mode 100644 index 00000000..164fe855 --- /dev/null +++ b/src/Common/Fat.h @@ -0,0 +1,67 @@ +/*
+ 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. */
+
+typedef struct fatparams_t
+{
+ char volume_name[11];
+ byte volume_id[4];
+ unsigned int num_sectors; /* total number of sectors */
+ int cluster_count; /* number of clusters */
+ int size_root_dir; /* size of the root directory in bytes */
+ int size_fat; /* size of FAT */
+ int fats;
+ int media;
+ int cluster_size;
+ int fat_length;
+ uint16 dir_entries;
+ uint16 sector_size;
+ int hidden;
+ __int16 reserved;
+ uint16 sectors;
+ unsigned int total_sect;
+
+ uint16 heads;
+ uint16 secs_track;
+
+} fatparams;
+
+
+struct msdos_boot_sector
+{
+ unsigned char boot_jump[3]; /* Boot strap short or near jump */
+ char system_id[8]; /* Name - can be used to special case
+ partition manager volumes */
+ unsigned char sector_size[2]; /* bytes per logical sector */
+ unsigned char cluster_size; /* sectors/cluster */
+ unsigned short reserved;/* reserved sectors */
+ unsigned char fats; /* number of FATs */
+ unsigned char dir_entries[2]; /* root directory entries */
+ unsigned char sectors[2]; /* number of sectors */
+ unsigned char media; /* media code */
+ unsigned short fat_length; /* sectors/FAT */
+ unsigned short secs_track; /* sectors per track */
+ unsigned short heads; /* number of heads */
+ unsigned __int32 hidden; /* hidden sectors */
+ unsigned __int32 total_sect; /* number of sectors (if sectors == 0) */
+ unsigned char drive_number; /* BIOS drive number */
+ unsigned char RESERVED; /* Unused */
+ unsigned char ext_boot_sign; /* 0x29 if fields below exist (DOS 3.3+) */
+ unsigned char volume_id[4]; /* Volume ID number */
+ char volume_label[11]; /* Volume label */
+ char fs_type[8]; /* Typically FAT12, FAT16, or FAT32 */
+ unsigned char boot_code[448]; /* Boot code (or message) */
+ unsigned short boot_sign; /* 0xAA55 */
+};
+
+
+void GetFatParams ( fatparams *ft );
+void PutBoot ( fatparams *ft , unsigned char *boot );
+int FormatFat (unsigned __int64 startSector, fatparams * ft, void * dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat);
diff --git a/src/Common/Format.c b/src/Common/Format.c new file mode 100644 index 00000000..49365a1b --- /dev/null +++ b/src/Common/Format.c @@ -0,0 +1,1010 @@ +/*
+ 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 <stdlib.h>
+#include <string.h>
+
+#include "Tcdefs.h"
+
+#include "Common.h"
+#include "Crypto.h"
+#include "Fat.h"
+#include "Format.h"
+#include "Random.h"
+#include "Volumes.h"
+
+#include "Apidrvr.h"
+#include "Dlgcode.h"
+#include "Language.h"
+#include "Progress.h"
+#include "Resource.h"
+#include "Format/FormatCom.h"
+#include "Format/Tcformat.h"
+
+int FormatWriteBufferSize = 1024 * 1024;
+static uint32 FormatSectorSize = 0;
+
+
+uint64 GetVolumeDataAreaSize (BOOL hiddenVolume, uint64 volumeSize)
+{
+ uint64 reservedSize;
+
+ if (hiddenVolume)
+ {
+ // Reserve free space at the end of the host filesystem. FAT file system fills the last sector with
+ // zeroes (marked as free; observed when quick format was performed using the OS format tool).
+ // Therefore, when the outer volume is mounted with hidden volume protection, such write operations
+ // (e.g. quick formatting the outer volume filesystem as FAT) would needlessly trigger hidden volume
+ // protection.
+
+#if TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE > 4096
+# error TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE too large for very small volumes. Revise the code.
+#endif
+
+#if TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH < TC_MAX_VOLUME_SECTOR_SIZE
+# error TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH too small.
+#endif
+
+ if (volumeSize < TC_VOLUME_SMALL_SIZE_THRESHOLD)
+ reservedSize = TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE;
+ else
+ reservedSize = TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH; // Ensure size of a hidden volume larger than TC_VOLUME_SMALL_SIZE_THRESHOLD is a multiple of the maximum supported sector size
+ }
+ else
+ {
+ reservedSize = TC_TOTAL_VOLUME_HEADERS_SIZE;
+ }
+
+ if (volumeSize < reservedSize)
+ return 0;
+
+ return volumeSize - reservedSize;
+}
+
+
+int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams)
+{
+ int nStatus;
+ PCRYPTO_INFO cryptoInfo = NULL;
+ HANDLE dev = INVALID_HANDLE_VALUE;
+ DWORD dwError;
+ char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE];
+ unsigned __int64 num_sectors, startSector;
+ fatparams ft;
+ FILETIME ftCreationTime;
+ FILETIME ftLastWriteTime;
+ FILETIME ftLastAccessTime;
+ BOOL bTimeStampValid = FALSE;
+ BOOL bInstantRetryOtherFilesys = FALSE;
+ char dosDev[TC_MAX_PATH] = { 0 };
+ char devName[MAX_PATH] = { 0 };
+ int driveLetter = -1;
+ WCHAR deviceName[MAX_PATH];
+ uint64 dataOffset, dataAreaSize;
+ LARGE_INTEGER offset;
+ BOOL bFailedRequiredDASD = FALSE;
+
+ FormatSectorSize = volParams->sectorSize;
+
+ if (FormatSectorSize < TC_MIN_VOLUME_SECTOR_SIZE
+ || FormatSectorSize > TC_MAX_VOLUME_SECTOR_SIZE
+ || FormatSectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0)
+ {
+ Error ("SECTOR_SIZE_UNSUPPORTED");
+ return ERR_DONT_REPORT;
+ }
+
+ /* WARNING: Note that if Windows fails to format the volume as NTFS and the volume size is
+ less than the maximum FAT size, the user is asked within this function whether he wants to instantly
+ retry FAT format instead (to avoid having to re-create the whole container again). If the user
+ answers yes, some of the input parameters are modified, the code below 'begin_format' is re-executed
+ and some destructive operations that were performed during the first attempt must be (and are) skipped.
+ Therefore, whenever adding or modifying any potentially destructive operations below 'begin_format',
+ determine whether they (or their portions) need to be skipped during such a second attempt; if so,
+ use the 'bInstantRetryOtherFilesys' flag to skip them. */
+
+ if (volParams->hiddenVol)
+ {
+ dataOffset = volParams->hiddenVolHostSize - TC_VOLUME_HEADER_GROUP_SIZE - volParams->size;
+ }
+ else
+ {
+ if (volParams->size <= TC_TOTAL_VOLUME_HEADERS_SIZE)
+ return ERR_VOL_SIZE_WRONG;
+
+ dataOffset = TC_VOLUME_DATA_OFFSET;
+ }
+
+ dataAreaSize = GetVolumeDataAreaSize (volParams->hiddenVol, volParams->size);
+
+ num_sectors = dataAreaSize / FormatSectorSize;
+
+ if (volParams->bDevice)
+ {
+ strcpy ((char *)deviceName, volParams->volumePath);
+ ToUNICODE ((char *)deviceName);
+
+ driveLetter = GetDiskDeviceDriveLetter (deviceName);
+ }
+
+ VirtualLock (header, sizeof (header));
+
+ nStatus = CreateVolumeHeaderInMemory (FALSE,
+ header,
+ volParams->ea,
+ FIRST_MODE_OF_OPERATION_ID,
+ volParams->password,
+ volParams->pkcs5,
+ NULL,
+ &cryptoInfo,
+ dataAreaSize,
+ volParams->hiddenVol ? dataAreaSize : 0,
+ dataOffset,
+ dataAreaSize,
+ 0,
+ volParams->headerFlags,
+ FormatSectorSize,
+ FALSE);
+
+ if (nStatus != 0)
+ {
+ burn (header, sizeof (header));
+ VirtualUnlock (header, sizeof (header));
+ return nStatus;
+ }
+
+begin_format:
+
+ if (volParams->bDevice)
+ {
+ /* Device-hosted volume */
+
+ DWORD dwResult;
+ int nPass;
+
+ if (FakeDosNameForDevice (volParams->volumePath, dosDev, devName, FALSE) != 0)
+ return ERR_OS_ERROR;
+
+ if (IsDeviceMounted (devName))
+ {
+ if ((dev = DismountDrive (devName, volParams->volumePath)) == INVALID_HANDLE_VALUE)
+ {
+ Error ("FORMAT_CANT_DISMOUNT_FILESYS");
+ nStatus = ERR_DONT_REPORT;
+ goto error;
+ }
+
+ /* Gain "raw" access to the partition (it contains a live filesystem and the filesystem driver
+ would otherwise prevent us from writing to hidden sectors). */
+
+ if (!DeviceIoControl (dev,
+ FSCTL_ALLOW_EXTENDED_DASD_IO,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &dwResult,
+ NULL))
+ {
+ bFailedRequiredDASD = TRUE;
+ }
+ }
+ else if (IsOSAtLeast (WIN_VISTA) && driveLetter == -1)
+ {
+ // Windows Vista doesn't allow overwriting sectors belonging to an unformatted partition
+ // to which no drive letter has been assigned under the system. This problem can be worked
+ // around by assigning a drive letter to the partition temporarily.
+
+ char szDriveLetter[] = { 'A', ':', 0 };
+ char rootPath[] = { 'A', ':', '\\', 0 };
+ char uniqVolName[MAX_PATH+1] = { 0 };
+ int tmpDriveLetter = -1;
+ BOOL bResult = FALSE;
+
+ tmpDriveLetter = GetFirstAvailableDrive ();
+
+ if (tmpDriveLetter != -1)
+ {
+ rootPath[0] += (char) tmpDriveLetter;
+ szDriveLetter[0] += (char) tmpDriveLetter;
+
+ if (DefineDosDevice (DDD_RAW_TARGET_PATH, szDriveLetter, volParams->volumePath))
+ {
+ bResult = GetVolumeNameForVolumeMountPoint (rootPath, uniqVolName, MAX_PATH);
+
+ DefineDosDevice (DDD_RAW_TARGET_PATH|DDD_REMOVE_DEFINITION|DDD_EXACT_MATCH_ON_REMOVE,
+ szDriveLetter,
+ volParams->volumePath);
+
+ if (bResult
+ && SetVolumeMountPoint (rootPath, uniqVolName))
+ {
+ // The drive letter can be removed now
+ DeleteVolumeMountPoint (rootPath);
+ }
+ }
+ }
+ }
+
+ // For extra safety, we will try to gain "raw" access to the partition. Note that this should actually be
+ // redundant because if the filesystem was mounted, we already tried to obtain DASD above. If we failed,
+ // bFailedRequiredDASD was set to TRUE and therefore we will perform pseudo "quick format" below. However,
+ // for extra safety, in case IsDeviceMounted() failed to detect a live filesystem, we will blindly
+ // send FSCTL_ALLOW_EXTENDED_DASD_IO (possibly for a second time) without checking the result.
+
+ DeviceIoControl (dev,
+ FSCTL_ALLOW_EXTENDED_DASD_IO,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &dwResult,
+ NULL);
+
+
+ // If DASD is needed but we failed to obtain it, perform open - 'quick format' - close - open
+ // so that the filesystem driver does not prevent us from formatting hidden sectors.
+ for (nPass = (bFailedRequiredDASD ? 0 : 1); nPass < 2; nPass++)
+ {
+ int retryCount;
+
+ retryCount = 0;
+
+ // Try exclusive access mode first
+ // Note that when exclusive access is denied, it is worth retrying (usually succeeds after a few tries).
+ while (dev == INVALID_HANDLE_VALUE && retryCount++ < EXCL_ACCESS_MAX_AUTO_RETRIES)
+ {
+ dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (retryCount > 1)
+ Sleep (EXCL_ACCESS_AUTO_RETRY_DELAY);
+ }
+
+ if (dev == INVALID_HANDLE_VALUE)
+ {
+ // Exclusive access denied -- retry in shared mode
+ dev = CreateFile (devName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+ if (dev != INVALID_HANDLE_VALUE)
+ {
+ if (IDNO == MessageBoxW (volParams->hwndDlg, GetString ("DEVICE_IN_USE_FORMAT"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2))
+ {
+ nStatus = ERR_DONT_REPORT;
+ goto error;
+ }
+ }
+ else
+ {
+ handleWin32Error (volParams->hwndDlg);
+ Error ("CANT_ACCESS_VOL");
+ nStatus = ERR_DONT_REPORT;
+ goto error;
+ }
+ }
+
+ if (volParams->hiddenVol || bInstantRetryOtherFilesys)
+ break; // The following "quick format" operation would damage the outer volume
+
+ if (nPass == 0)
+ {
+ char buf [2 * TC_MAX_VOLUME_SECTOR_SIZE];
+ DWORD bw;
+
+ // Perform pseudo "quick format" so that the filesystem driver does not prevent us from
+ // formatting hidden sectors
+ memset (buf, 0, sizeof (buf));
+
+ if (!WriteFile (dev, buf, sizeof (buf), &bw, NULL))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ FlushFileBuffers (dev);
+ CloseHandle (dev);
+ dev = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ if (DeviceIoControl (dev, FSCTL_IS_VOLUME_MOUNTED, NULL, 0, NULL, 0, &dwResult, NULL))
+ {
+ Error ("FORMAT_CANT_DISMOUNT_FILESYS");
+ nStatus = ERR_DONT_REPORT;
+ goto error;
+ }
+ }
+ else
+ {
+ /* File-hosted volume */
+
+ dev = CreateFile (volParams->volumePath, GENERIC_READ | GENERIC_WRITE,
+ (volParams->hiddenVol || bInstantRetryOtherFilesys) ? (FILE_SHARE_READ | FILE_SHARE_WRITE) : 0,
+ NULL, (volParams->hiddenVol || bInstantRetryOtherFilesys) ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL);
+
+ if (dev == INVALID_HANDLE_VALUE)
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ DisableFileCompression (dev);
+
+ if (!volParams->hiddenVol && !bInstantRetryOtherFilesys)
+ {
+ LARGE_INTEGER volumeSize;
+ volumeSize.QuadPart = dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE;
+
+ if (volParams->sparseFileSwitch && volParams->quickFormat)
+ {
+ // Create as sparse file container
+ DWORD tmp;
+ if (!DeviceIoControl (dev, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &tmp, NULL))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+ }
+
+ // Preallocate the file
+ if (!SetFilePointerEx (dev, volumeSize, NULL, FILE_BEGIN)
+ || !SetEndOfFile (dev)
+ || SetFilePointer (dev, 0, NULL, FILE_BEGIN) != 0)
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+ }
+ }
+
+ if (volParams->hiddenVol && !volParams->bDevice && bPreserveTimestamp)
+ {
+ if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0)
+ bTimeStampValid = FALSE;
+ else
+ bTimeStampValid = TRUE;
+ }
+
+ KillTimer (volParams->hwndDlg, TIMER_ID_RANDVIEW);
+
+ /* Volume header */
+
+ // Hidden volume setup
+ if (volParams->hiddenVol)
+ {
+ LARGE_INTEGER headerOffset;
+
+ // Check hidden volume size
+ if (volParams->hiddenVolHostSize < TC_MIN_HIDDEN_VOLUME_HOST_SIZE || volParams->hiddenVolHostSize > TC_MAX_HIDDEN_VOLUME_HOST_SIZE)
+ {
+ nStatus = ERR_VOL_SIZE_WRONG;
+ goto error;
+ }
+
+ // Seek to hidden volume header location
+
+ headerOffset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET;
+
+ if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+ }
+ else if (bInstantRetryOtherFilesys)
+ {
+ // The previous file system format failed and the user wants to try again with a different file system.
+ // The volume header had been written successfully so we need to seek to the byte after the header.
+
+ LARGE_INTEGER offset;
+ offset.QuadPart = TC_VOLUME_DATA_OFFSET;
+ if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+ }
+
+ if (!bInstantRetryOtherFilesys)
+ {
+ // Write the volume header
+ if (!WriteEffectiveVolumeHeader (volParams->bDevice, dev, header))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ // To prevent fragmentation, write zeroes to reserved header sectors which are going to be filled with random data
+ if (!volParams->bDevice && !volParams->hiddenVol)
+ {
+ byte buf[TC_VOLUME_HEADER_GROUP_SIZE - TC_VOLUME_HEADER_EFFECTIVE_SIZE];
+ DWORD bytesWritten;
+ ZeroMemory (buf, sizeof (buf));
+
+ if (!WriteFile (dev, buf, sizeof (buf), &bytesWritten, NULL))
+ {
+ nStatus = ERR_OS_ERROR;
+ goto error;
+ }
+
+ if (bytesWritten != sizeof (buf))
+ {
+ nStatus = ERR_PARAMETER_INCORRECT;
|