diff options
Diffstat (limited to 'Common')
71 files changed, 33185 insertions, 0 deletions
diff --git a/Common/Apidrvr.h b/Common/Apidrvr.h new file mode 100644 index 0000000..1740919 --- /dev/null +++ b/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/Common/BaseCom.cpp b/Common/BaseCom.cpp new file mode 100644 index 0000000..767a475 --- /dev/null +++ b/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/Common/BaseCom.h b/Common/BaseCom.h new file mode 100644 index 0000000..60ad0f9 --- /dev/null +++ b/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/Common/BootEncryption.cpp b/Common/BootEncryption.cpp new file mode 100644 index 0000000..51221ff --- /dev/null +++ b/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/Common/BootEncryption.h b/Common/BootEncryption.h new file mode 100644 index 0000000..036f75a --- /dev/null +++ b/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/Common/Cache.c b/Common/Cache.c new file mode 100644 index 0000000..5b4b754 --- /dev/null +++ b/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/Common/Cache.h b/Common/Cache.h new file mode 100644 index 0000000..8a56940 --- /dev/null +++ b/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/Common/Cmdline.c b/Common/Cmdline.c new file mode 100644 index 0000000..ebeae8f --- /dev/null +++ b/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/Common/Cmdline.h b/Common/Cmdline.h new file mode 100644 index 0000000..ed639f3 --- /dev/null +++ b/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/Common/Combo.c b/Common/Combo.c new file mode 100644 index 0000000..bd0f409 --- /dev/null +++ b/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/Common/Combo.h b/Common/Combo.h new file mode 100644 index 0000000..6a1b384 --- /dev/null +++ b/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/Common/Common.h b/Common/Common.h new file mode 100644 index 0000000..1ef0189 --- /dev/null +++ b/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/Common/Common.rc b/Common/Common.rc new file mode 100644 index 0000000..e579fe1 --- /dev/null +++ b/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/Common/Crc.c b/Common/Crc.c new file mode 100644 index 0000000..b2e5bd2 --- /dev/null +++ b/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/Common/Crc.h b/Common/Crc.h new file mode 100644 index 0000000..599cbcc --- /dev/null +++ b/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/Common/Crypto.c b/Common/Crypto.c new file mode 100644 index 0000000..a3d3cca --- /dev/null +++ b/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/Common/Crypto.h b/Common/Crypto.h new file mode 100644 index 0000000..f3b9f14 --- /dev/null +++ b/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/Common/Dictionary.c b/Common/Dictionary.c new file mode 100644 index 0000000..c9501d8 --- /dev/null +++ b/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/Common/Dictionary.h b/Common/Dictionary.h new file mode 100644 index 0000000..c393869 --- /dev/null +++ b/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/Common/Dlgcode.c b/Common/Dlgcode.c new file mode 100644 index 0000000..8293d06 --- /dev/null +++ b/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/Common/Dlgcode.h b/Common/Dlgcode.h new file mode 100644 index 0000000..fccfbc7 --- /dev/null +++ b/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/Common/EncryptionThreadPool.c b/Common/EncryptionThreadPool.c new file mode 100644 index 0000000..cb5b1ab --- /dev/null +++ b/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/Common/EncryptionThreadPool.h b/Common/EncryptionThreadPool.h new file mode 100644 index 0000000..a5eef57 --- /dev/null +++ b/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/Common/Endian.c b/Common/Endian.c new file mode 100644 index 0000000..f2b7a27 --- /dev/null +++ b/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/Common/Endian.h b/Common/Endian.h new file mode 100644 index 0000000..337e51c --- /dev/null +++ b/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/Common/Exception.h b/Common/Exception.h new file mode 100644 index 0000000..0f689ea --- /dev/null +++ b/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/Common/Fat.c b/Common/Fat.c new file mode 100644 index 0000000..168e471 --- /dev/null +++ b/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/Common/Fat.h b/Common/Fat.h new file mode 100644 index 0000000..661aba4 --- /dev/null +++ b/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/Common/Format.c b/Common/Format.c new file mode 100644 index 0000000..7e9418b --- /dev/null +++ b/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; + goto error; + } + } + } + + if (volParams->hiddenVol) + { + // Calculate data area position of hidden volume + cryptoInfo->hiddenVolumeOffset = dataOffset; + + // Validate the offset + if (dataOffset % FormatSectorSize != 0) + { + nStatus = ERR_VOL_SIZE_WRONG; + goto error; + } + + volParams->quickFormat = TRUE; // To entirely format a hidden volume would be redundant + } + + /* Data area */ + startSector = dataOffset / FormatSectorSize; + + // Format filesystem + + switch (volParams->fileSystem) + { + case FILESYS_NONE: + case FILESYS_NTFS: + + if (volParams->bDevice && !StartFormatWriteThread()) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + nStatus = FormatNoFs (startSector, num_sectors, dev, cryptoInfo, volParams->quickFormat); + + if (volParams->bDevice) + StopFormatWriteThread(); + + break; + + case FILESYS_FAT: + if (num_sectors > 0xFFFFffff) + { + nStatus = ERR_VOL_SIZE_WRONG; + goto error; + } + + // Calculate the fats, root dir etc + ft.num_sectors = (unsigned int) (num_sectors); + +#if TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF +#error TC_MAX_VOLUME_SECTOR_SIZE > 0xFFFF +#endif + + ft.sector_size = (uint16) FormatSectorSize; + ft.cluster_size = volParams->clusterSize; + memcpy (ft.volume_name, "NO NAME ", 11); + GetFatParams (&ft); + *(volParams->realClusterSize) = ft.cluster_size * FormatSectorSize; + + if (volParams->bDevice && !StartFormatWriteThread()) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + nStatus = FormatFat (startSector, &ft, (void *) dev, cryptoInfo, volParams->quickFormat); + + if (volParams->bDevice) + StopFormatWriteThread(); + + break; + + default: + nStatus = ERR_PARAMETER_INCORRECT; + goto error; + } + + if (nStatus != ERR_SUCCESS) + goto error; + + // Write header backup + offset.QuadPart = volParams->hiddenVol ? volParams->hiddenVolHostSize - TC_HIDDEN_VOLUME_HEADER_OFFSET : dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE; + + if (!SetFilePointerEx ((HANDLE) dev, offset, NULL, FILE_BEGIN)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + nStatus = CreateVolumeHeaderInMemory (FALSE, + header, + volParams->ea, + FIRST_MODE_OF_OPERATION_ID, + volParams->password, + volParams->pkcs5, + cryptoInfo->master_keydata, + &cryptoInfo, + dataAreaSize, + volParams->hiddenVol ? dataAreaSize : 0, + dataOffset, + dataAreaSize, + 0, + volParams->headerFlags, + FormatSectorSize, + FALSE); + + if (!WriteEffectiveVolumeHeader (volParams->bDevice, dev, header)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + // Fill reserved header sectors (including the backup header area) with random data + if (!volParams->hiddenVol) + { + nStatus = WriteRandomDataToReservedHeaderAreas (dev, cryptoInfo, dataAreaSize, FALSE, FALSE); + + if (nStatus != ERR_SUCCESS) + goto error; + } + +#ifndef DEBUG + if (volParams->quickFormat && volParams->fileSystem != FILESYS_NTFS) + Sleep (500); // User-friendly GUI +#endif + +error: + dwError = GetLastError(); + + burn (header, sizeof (header)); + VirtualUnlock (header, sizeof (header)); + + if (dev != INVALID_HANDLE_VALUE) + { + if (!volParams->bDevice && !volParams->hiddenVol && nStatus != 0) + { + // Remove preallocated part before closing file handle if format failed + if (SetFilePointer (dev, 0, NULL, FILE_BEGIN) == 0) + SetEndOfFile (dev); + } + + FlushFileBuffers (dev); + + if (bTimeStampValid) + SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime); + + CloseHandle (dev); + dev = INVALID_HANDLE_VALUE; + } + + if (nStatus != 0) + { + SetLastError(dwError); + goto fv_end; + } + + if (volParams->fileSystem == FILESYS_NTFS) + { + // Quick-format volume as NTFS + int driveNo = GetLastAvailableDrive (); + MountOptions mountOptions; + int retCode; + + ZeroMemory (&mountOptions, sizeof (mountOptions)); + + if (driveNo == -1) + { + MessageBoxW (volParams->hwndDlg, GetString ("NO_FREE_DRIVES"), lpszTitle, ICON_HAND); + MessageBoxW (volParams->hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND); + + nStatus = ERR_NO_FREE_DRIVES; + goto fv_end; + } + + mountOptions.ReadOnly = FALSE; + mountOptions.Removable = FALSE; + mountOptions.ProtectHiddenVolume = FALSE; + mountOptions.PreserveTimestamp = bPreserveTimestamp; + mountOptions.PartitionInInactiveSysEncScope = FALSE; + mountOptions.UseBackupHeader = FALSE; + + if (MountVolume (volParams->hwndDlg, driveNo, volParams->volumePath, volParams->password, FALSE, TRUE, &mountOptions, FALSE, TRUE) < 1) + { + MessageBoxW (volParams->hwndDlg, GetString ("CANT_MOUNT_VOLUME"), lpszTitle, ICON_HAND); + MessageBoxW (volParams->hwndDlg, GetString ("FORMAT_NTFS_STOP"), lpszTitle, ICON_HAND); + nStatus = ERR_VOL_MOUNT_FAILED; + goto fv_end; + } + + if (!IsAdmin () && IsUacSupported ()) + retCode = UacFormatNtfs (volParams->hwndDlg, driveNo, volParams->clusterSize); + else + retCode = FormatNtfs (driveNo, volParams->clusterSize); + + if (retCode != TRUE) + { + if (!UnmountVolume (volParams->hwndDlg, driveNo, FALSE)) + MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND); + + if (dataAreaSize <= TC_MAX_FAT_SECTOR_COUNT * FormatSectorSize) + { + if (AskErrYesNo ("FORMAT_NTFS_FAILED_ASK_FAT") == IDYES) + { + // NTFS format failed and the user wants to try FAT format immediately + volParams->fileSystem = FILESYS_FAT; + bInstantRetryOtherFilesys = TRUE; + volParams->quickFormat = TRUE; // Volume has already been successfully TC-formatted + volParams->clusterSize = 0; // Default cluster size + goto begin_format; + } + } + else + Error ("FORMAT_NTFS_FAILED"); + + nStatus = ERR_DONT_REPORT; + goto fv_end; + } + + if (!UnmountVolume (volParams->hwndDlg, driveNo, FALSE)) + MessageBoxW (volParams->hwndDlg, GetString ("CANT_DISMOUNT_VOLUME"), lpszTitle, ICON_HAND); + } + +fv_end: + dwError = GetLastError(); + + if (dosDev[0]) + RemoveFakeDosName (volParams->volumePath, dosDev); + + crypto_close (cryptoInfo); + + SetLastError (dwError); + return nStatus; +} + + +int FormatNoFs (unsigned __int64 startSector, __int64 num_sectors, 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 retVal = 0; + DWORD err; + char temporaryKey[MASTER_KEYDATA_SIZE]; + char originalK2[MASTER_KEYDATA_SIZE]; + + LARGE_INTEGER startOffset; + LARGE_INTEGER newOffset; + + // Seek to start sector + startOffset.QuadPart = startSector * FormatSectorSize; + if (!SetFilePointerEx ((HANDLE) dev, startOffset, &newOffset, FILE_BEGIN) + || newOffset.QuadPart != startOffset.QuadPart) + { + return ERR_OS_ERROR; + } + + write_buf = (char *)TCalloc (FormatWriteBufferSize); + if (!write_buf) + return ERR_OUTOFMEMORY; + + VirtualLock (temporaryKey, sizeof (temporaryKey)); + VirtualLock (originalK2, sizeof (originalK2)); + + memset (sector, 0, sizeof (sector)); + + // Remember the original secondary key (XTS mode) before generating a temporary one + memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2)); + + /* Fill the rest of the data area with random data */ + + if(!quickFormat) + { + /* 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. */ + + // 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) + goto fail; + + if (!EAInitMode (cryptoInfo)) + { + retVal = ERR_MODE_INIT_FAILED; + goto fail; + } + + while (num_sectors--) + { + if (WriteSector (dev, sector, write_buf, &write_buf_cnt, &nSecNo, + cryptoInfo) == FALSE) + goto fail; + } + + if (!FlushFormatWriteBuffer (dev, write_buf, &write_buf_cnt, &nSecNo, cryptoInfo)) + goto fail; + } + else + nSecNo = num_sectors; + + UpdateProgressBar (nSecNo * FormatSectorSize); + + // Restore the original secondary key (XTS mode) in case NTFS format fails and the user wants to try FAT immediately + memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2)); + + // Reinitialize the encryption algorithm and mode in case NTFS format fails and the user wants to try FAT immediately + retVal = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks); + if (retVal != ERR_SUCCESS) + goto fail; + if (!EAInitMode (cryptoInfo)) + { + retVal = ERR_MODE_INIT_FAILED; + goto fail; + } + + burn (temporaryKey, sizeof(temporaryKey)); + burn (originalK2, sizeof(originalK2)); + VirtualUnlock (temporaryKey, sizeof (temporaryKey)); + VirtualUnlock (originalK2, sizeof (originalK2)); + TCfree (write_buf); + + return 0; + +fail: + err = GetLastError(); + + burn (temporaryKey, sizeof(temporaryKey)); + burn (originalK2, sizeof(originalK2)); + VirtualUnlock (temporaryKey, sizeof (temporaryKey)); + VirtualUnlock (originalK2, sizeof (originalK2)); + TCfree (write_buf); + + SetLastError (err); + return (retVal ? retVal : ERR_OS_ERROR); +} + + +volatile BOOLEAN FormatExResult; + +BOOLEAN __stdcall FormatExCallback (int command, DWORD subCommand, PVOID parameter) +{ + if (command == FMIFS_DONE) + FormatExResult = *(BOOLEAN *) parameter; + return TRUE; +} + +BOOL FormatNtfs (int driveNo, int clusterSize) +{ + WCHAR dir[8] = { (WCHAR) driveNo + 'A', 0 }; + PFORMATEX FormatEx; + HMODULE hModule = LoadLibrary ("fmifs.dll"); + int i; + + if (hModule == NULL) + return FALSE; + + if (!(FormatEx = (PFORMATEX) GetProcAddress (GetModuleHandle ("fmifs.dll"), "FormatEx"))) + { + FreeLibrary (hModule); + return FALSE; + } + + wcscat (dir, L":\\"); + + FormatExResult = FALSE; + + // Windows sometimes fails to format a volume (hosted on a removable medium) as NTFS. + // It often helps to retry several times. + for (i = 0; i < 50 && FormatExResult != TRUE; i++) + { + FormatEx (dir, FMIFS_HARDDISK, L"NTFS", L"", TRUE, clusterSize * FormatSectorSize, FormatExCallback); + } + + // The device may be referenced for some time after FormatEx() returns + Sleep (2000); + + FreeLibrary (hModule); + return FormatExResult; +} + + +BOOL WriteSector (void *dev, char *sector, + char *write_buf, int *write_buf_cnt, + __int64 *nSecNo, PCRYPTO_INFO cryptoInfo) +{ + static __int32 updateTime = 0; + + (*nSecNo)++; + + memcpy (write_buf + *write_buf_cnt, sector, FormatSectorSize); + (*write_buf_cnt) += FormatSectorSize; + + if (*write_buf_cnt == FormatWriteBufferSize && !FlushFormatWriteBuffer (dev, write_buf, write_buf_cnt, nSecNo, cryptoInfo)) + return FALSE; + + if (GetTickCount () - updateTime > 25) + { + if (UpdateProgressBar (*nSecNo * FormatSectorSize)) + return FALSE; + + updateTime = GetTickCount (); + } + + return TRUE; + +} + + +static volatile BOOL WriteThreadRunning; +static volatile BOOL WriteThreadExitRequested; +static HANDLE WriteThreadHandle; + +static byte *WriteThreadBuffer; +static HANDLE WriteBufferEmptyEvent; +static HANDLE WriteBufferFullEvent; + +static volatile HANDLE WriteRequestHandle; +static volatile int WriteRequestSize; +static volatile DWORD WriteRequestResult; + + +static void __cdecl FormatWriteThreadProc (void *arg) +{ + DWORD bytesWritten; + + SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_HIGHEST); + + while (!WriteThreadExitRequested) + { + if (WaitForSingleObject (WriteBufferFullEvent, INFINITE) == WAIT_FAILED) + { + handleWin32Error (NULL); + break; + } + + if (WriteThreadExitRequested) + break; + + if (!WriteFile (WriteRequestHandle, WriteThreadBuffer, WriteRequestSize, &bytesWritten, NULL)) + WriteRequestResult = GetLastError(); + else + WriteRequestResult = ERROR_SUCCESS; + + if (!SetEvent (WriteBufferEmptyEvent)) + { + handleWin32Error (NULL); + break; + } + } + + WriteThreadRunning = FALSE; + _endthread(); +} + + +static BOOL StartFormatWriteThread () +{ + DWORD sysErr; + + WriteBufferEmptyEvent = NULL; + WriteBufferFullEvent = NULL; + WriteThreadBuffer = NULL; + + WriteBufferEmptyEvent = CreateEvent (NULL, FALSE, TRUE, NULL); + if (!WriteBufferEmptyEvent) + goto err; + + WriteBufferFullEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + if (!WriteBufferFullEvent) + goto err; + + WriteThreadBuffer = TCalloc (FormatWriteBufferSize); + if (!WriteThreadBuffer) + { + SetLastError (ERROR_OUTOFMEMORY); + goto err; + } + + WriteThreadExitRequested = FALSE; + WriteRequestResult = ERROR_SUCCESS; + + WriteThreadHandle = (HANDLE) _beginthread (FormatWriteThreadProc, 0, NULL); + if ((uintptr_t) WriteThreadHandle == -1L) + goto err; + + WriteThreadRunning = TRUE; + return TRUE; + +err: + sysErr = GetLastError(); + + if (WriteBufferEmptyEvent) + CloseHandle (WriteBufferEmptyEvent); + if (WriteBufferFullEvent) + CloseHandle (WriteBufferFullEvent); + if (WriteThreadBuffer) + TCfree (WriteThreadBuffer); + + SetLastError (sysErr); + return FALSE; +} + + +static void StopFormatWriteThread () +{ + if (WriteThreadRunning) + { + WaitForSingleObject (WriteBufferEmptyEvent, INFINITE); + + WriteThreadExitRequested = TRUE; + SetEvent (WriteBufferFullEvent); + + WaitForSingleObject (WriteThreadHandle, INFINITE); + } + + CloseHandle (WriteBufferEmptyEvent); + CloseHandle (WriteBufferFullEvent); + TCfree (WriteThreadBuffer); +} + + +BOOL FlushFormatWriteBuffer (void *dev, char *write_buf, int *write_buf_cnt, __int64 *nSecNo, PCRYPTO_INFO cryptoInfo) +{ + UINT64_STRUCT unitNo; + DWORD bytesWritten; + + if (*write_buf_cnt == 0) + return TRUE; + + unitNo.Value = (*nSecNo * FormatSectorSize - *write_buf_cnt) / ENCRYPTION_DATA_UNIT_SIZE; + + EncryptDataUnits (write_buf, &unitNo, *write_buf_cnt / ENCRYPTION_DATA_UNIT_SIZE, cryptoInfo); + + if (WriteThreadRunning) + { + if (WaitForSingleObject (WriteBufferEmptyEvent, INFINITE) == WAIT_FAILED) + return FALSE; + + if (WriteRequestResult != ERROR_SUCCESS) + { + SetEvent (WriteBufferEmptyEvent); + SetLastError (WriteRequestResult); + return FALSE; + } + + memcpy (WriteThreadBuffer, write_buf, *write_buf_cnt); + WriteRequestHandle = dev; + WriteRequestSize = *write_buf_cnt; + + if (!SetEvent (WriteBufferFullEvent)) + return FALSE; + } + else + { + if (!WriteFile ((HANDLE) dev, write_buf, *write_buf_cnt, &bytesWritten, NULL)) + return FALSE; + } + + *write_buf_cnt = 0; + return TRUE; +} diff --git a/Common/Format.h b/Common/Format.h new file mode 100644 index 0000000..b971613 --- /dev/null +++ b/Common/Format.h @@ -0,0 +1,68 @@ +/* + 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_Format +#define TC_HEADER_Format + +#include "Password.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// FMIFS +typedef BOOLEAN (__stdcall *PFMIFSCALLBACK)( int command, DWORD subCommand, PVOID parameter ); +typedef VOID (__stdcall *PFORMATEX)( PWCHAR DriveRoot, DWORD MediaFlag, PWCHAR Format, PWCHAR Label, BOOL QuickFormat, DWORD ClusterSize, PFMIFSCALLBACK Callback ); + +typedef struct +{ + BOOL bDevice; + BOOL hiddenVol; + char *volumePath; + unsigned __int64 size; + unsigned __int64 hiddenVolHostSize; + int ea; + int pkcs5; + uint32 headerFlags; + int fileSystem; + int clusterSize; + BOOL sparseFileSwitch; + BOOL quickFormat; + int sectorSize; + int *realClusterSize; + Password *password; + HWND hwndDlg; +} +FORMAT_VOL_PARAMETERS; + +#define FMIFS_DONE 0xB +#define FMIFS_HARDDISK 0xC + +extern int FormatWriteBufferSize; + +int TCFormatVolume (volatile FORMAT_VOL_PARAMETERS *volParams); +BOOL FormatNtfs (int driveNo, int clusterSize); +uint64 GetVolumeDataAreaSize (BOOL hiddenVolume, uint64 volumeSize); +int FormatNoFs (unsigned __int64 startSector, __int64 num_sectors, void *dev, PCRYPTO_INFO cryptoInfo, BOOL quickFormat); +BOOL WriteSector ( void *dev , char *sector , char *write_buf , int *write_buf_cnt , __int64 *nSecNo , PCRYPTO_INFO cryptoInfo ); +BOOL FlushFormatWriteBuffer (void *dev, char *write_buf, int *write_buf_cnt, __int64 *nSecNo, PCRYPTO_INFO cryptoInfo); +static BOOL StartFormatWriteThread (); +static void StopFormatWriteThread (); + +#define FILESYS_NONE 0 +#define FILESYS_FAT 1 +#define FILESYS_NTFS 2 + +#ifdef __cplusplus +} +#endif + +#endif // TC_HEADER_Format diff --git a/Common/GfMul.c b/Common/GfMul.c new file mode 100644 index 0000000..4cb86b6 --- /dev/null +++ b/Common/GfMul.c @@ -0,0 +1,894 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2003, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 31/01/2004 + + My thanks to John Viega and David McGrew for their support in developing + this code and to David for testing it on a big-endain system. +*/ + +/* + --------------------------------------------------------------------------- + Portions Copyright (c) 2005 TrueCrypt Developers Association + + Changes: + + - Added multiplication in the finite field GF(2^128) optimized for + cases involving a 64-bit operand. + + - Added multiplication in the finite field GF(2^64). + + - Added MSB-first mode. + + - Added basic test algorithms. + + - Removed GCM. + --------------------------------------------------------------------------- +*/ + +#include <memory.h> +#include <stdlib.h> +#include "GfMul.h" +#include "Tcdefs.h" +#include "Common/Endian.h" + +/* BUFFER_ALIGN32 or BUFFER_ALIGN64 must be defined at this point to */ +/* enable faster operation by taking advantage of memory aligned values */ +/* NOTE: the BUFFER_ALIGN64 option has not been tested extensively */ + +#define BUFFER_ALIGN32 +#define UNROLL_LOOPS /* define to unroll some loops */ +#define IN_LINES /* define to use inline functions */ + /* in place of macros */ + +#define mode(x) GM_##x + +#if defined(__cplusplus) +extern "C" +{ +#endif + +typedef unsigned __int32 mode(32t); +typedef uint64 mode(64t); + +#define BRG_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ +#define BRG_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ + +#if BYTE_ORDER == LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER BRG_LITTLE_ENDIAN +#endif + +#if BYTE_ORDER == BIG_ENDIAN +# define PLATFORM_BYTE_ORDER BRG_BIG_ENDIAN +#endif + +#ifdef _MSC_VER +#pragma intrinsic(memcpy) +#define in_line __inline +#else +#define in_line +#endif + +#if 0 && defined(_MSC_VER) +#define rotl32 _lrotl +#define rotr32 _lrotr +#else +#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) +#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) +#endif + +#if !defined(bswap_32) +#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00)) +#endif + +#if (PLATFORM_BYTE_ORDER == BRG_LITTLE_ENDIAN) +#define SWAP_BYTES +#else +#undef SWAP_BYTES +#endif + +#if defined(SWAP_BYTES) + +#if defined ( IN_LINES ) + +in_line void bsw_32(void * p, unsigned int n) +{ unsigned int i = n; + while(i--) + ((mode(32t)*)p)[i] = bswap_32(((mode(32t)*)p)[i]); +} + +#else + +#define bsw_32(p,n) \ + { int _i = (n); while(_i--) ((mode(32t)*)p)[_i] = bswap_32(((mode(32t)*)p)[_i]); } + +#endif + +#else +#define bsw_32(p,n) +#endif + +/* These values are used to detect long word alignment in order */ +/* to speed up some GCM buffer operations. This facility may */ +/* not work on some machines */ + +#define lp08(x) ((unsigned char*)(x)) +#define lp32(x) ((mode(32t)*)(x)) +#define lp64(x) ((mode(64t)*)(x)) + +#define A32_MASK 3 +#define A64_MASK 7 +#define aligned32(x) (!(((mode(32t))(x)) & A32_MASK)) +#define aligned64(x) (!(((mode(32t))(x)) & A64_MASK)) + +#if defined( BUFFER_ALIGN32 ) + +#define ADR_MASK A32_MASK +#define aligned aligned32 +#define lp lp32 +#define lp_inc 4 + +#if defined( IN_LINES ) + +in_line void move_block_aligned( void *p, const void *q) +{ + lp32(p)[0] = lp32(q)[0], lp32(p)[1] = lp32(q)[1], + lp32(p)[2] = lp32(q)[2], lp32(p)[3] = lp32(q)[3]; +} + +in_line void move_block_aligned64( void *p, const void *q) +{ + lp32(p)[0] = lp32(q)[0], lp32(p)[1] = lp32(q)[1]; +} + +in_line void xor_block_aligned( void *p, const void *q) +{ + lp32(p)[0] ^= lp32(q)[0], lp32(p)[1] ^= lp32(q)[1], + lp32(p)[2] ^= lp32(q)[2], lp32(p)[3] ^= lp32(q)[3]; +} + +in_line void xor_block_aligned64( void *p, const void *q) +{ + lp32(p)[0] ^= lp32(q)[0], lp32(p)[1] ^= lp32(q)[1]; +} + +#else + +#define move_block_aligned(p,q) \ + lp32(p)[0] = lp32(q)[0], lp32(p)[1] = lp32(q)[1], \ + lp32(p)[2] = lp32(q)[2], lp32(p)[3] = lp32(q)[3] + +#define xor_block_aligned(p,q) \ + lp32(p)[0] ^= lp32(q)[0], lp32(p)[1] ^= lp32(q)[1], \ + lp32(p)[2] ^= lp32(q)[2], lp32(p)[3] ^= lp32(q)[3] + +#endif + +#elif defined( BUFFER_ALIGN64 ) + +#define ADR_MASK A64_MASK +#define aligned aligned64 +#define lp lp64 +#define lp_inc 8 + +#define move_block_aligned(p,q) \ + lp64(p)[0] = lp64(q)[0], lp64(p)[1] = lp64(q)[1] + +#define xor_block_aligned(p,q) \ + lp64(p)[0] ^= lp64(q)[0], lp64(p)[1] ^= lp64(q)[1] + +#else +#define aligned(x) 0 +#endif + +#define move_block(p,q) memcpy((p), (q), BLOCK_LEN) + +#define xor_block(p,q) \ + lp08(p)[ 0] ^= lp08(q)[ 0], lp08(p)[ 1] ^= lp08(q)[ 1], \ + lp08(p)[ 2] ^= lp08(q)[ 2], lp08(p)[ 3] ^= lp08(q)[ 3], \ + lp08(p)[ 4] ^= lp08(q)[ 4], lp08(p)[ 5] ^= lp08(q)[ 5], \ + lp08(p)[ 6] ^= lp08(q)[ 6], lp08(p)[ 7] ^= lp08(q)[ 7], \ + lp08(p)[ 8] ^= lp08(q)[ 8], lp08(p)[ 9] ^= lp08(q)[ 9], \ + lp08(p)[10] ^= lp08(q)[10], lp08(p)[11] ^= lp08(q)[11], \ + lp08(p)[12] ^= lp08(q)[12], lp08(p)[13] ^= lp08(q)[13], \ + lp08(p)[14] ^= lp08(q)[14], lp08(p)[15] ^= lp08(q)[15] + + +#define gf_dat(q) {\ + q(0x00), q(0x01), q(0x02), q(0x03), q(0x04), q(0x05), q(0x06), q(0x07),\ + q(0x08), q(0x09), q(0x0a), q(0x0b), q(0x0c), q(0x0d), q(0x0e), q(0x0f),\ + q(0x10), q(0x11), q(0x12), q(0x13), q(0x14), q(0x15), q(0x16), q(0x17),\ + q(0x18), q(0x19), q(0x1a), q(0x1b), q(0x1c), q(0x1d), q(0x1e), q(0x1f),\ + q(0x20), q(0x21), q(0x22), q(0x23), q(0x24), q(0x25), q(0x26), q(0x27),\ + q(0x28), q(0x29), q(0x2a), q(0x2b), q(0x2c), q(0x2d), q(0x2e), q(0x2f),\ + q(0x30), q(0x31), q(0x32), q(0x33), q(0x34), q(0x35), q(0x36), q(0x37),\ + q(0x38), q(0x39), q(0x3a), q(0x3b), q(0x3c), q(0x3d), q(0x3e), q(0x3f),\ + q(0x40), q(0x41), q(0x42), q(0x43), q(0x44), q(0x45), q(0x46), q(0x47),\ + q(0x48), q(0x49), q(0x4a), q(0x4b), q(0x4c), q(0x4d), q(0x4e), q(0x4f),\ + q(0x50), q(0x51), q(0x52), q(0x53), q(0x54), q(0x55), q(0x56), q(0x57),\ + q(0x58), q(0x59), q(0x5a), q(0x5b), q(0x5c), q(0x5d), q(0x5e), q(0x5f),\ + q(0x60), q(0x61), q(0x62), q(0x63), q(0x64), q(0x65), q(0x66), q(0x67),\ + q(0x68), q(0x69), q(0x6a), q(0x6b), q(0x6c), q(0x6d), q(0x6e), q(0x6f),\ + q(0x70), q(0x71), q(0x72), q(0x73), q(0x74), q(0x75), q(0x76), q(0x77),\ + q(0x78), q(0x79), q(0x7a), q(0x7b), q(0x7c), q(0x7d), q(0x7e), q(0x7f),\ + q(0x80), q(0x81), q(0x82), q(0x83), q(0x84), q(0x85), q(0x86), q(0x87),\ + q(0x88), q(0x89), q(0x8a), q(0x8b), q(0x8c), q(0x8d), q(0x8e), q(0x8f),\ + q(0x90), q(0x91), q(0x92), q(0x93), q(0x94), q(0x95), q(0x96), q(0x97),\ + q(0x98), q(0x99), q(0x9a), q(0x9b), q(0x9c), q(0x9d), q(0x9e), q(0x9f),\ + q(0xa0), q(0xa1), q(0xa2), q(0xa3), q(0xa4), q(0xa5), q(0xa6), q(0xa7),\ + q(0xa8), q(0xa9), q(0xaa), q(0xab), q(0xac), q(0xad), q(0xae), q(0xaf),\ + q(0xb0), q(0xb1), q(0xb2), q(0xb3), q(0xb4), q(0xb5), q(0xb6), q(0xb7),\ + q(0xb8), q(0xb9), q(0xba), q(0xbb), q(0xbc), q(0xbd), q(0xbe), q(0xbf),\ + q(0xc0), q(0xc1), q(0xc2), q(0xc3), q(0xc4), q(0xc5), q(0xc6), q(0xc7),\ + q(0xc8), q(0xc9), q(0xca), q(0xcb), q(0xcc), q(0xcd), q(0xce), q(0xcf),\ + q(0xd0), q(0xd1), q(0xd2), q(0xd3), q(0xd4), q(0xd5), q(0xd6), q(0xd7),\ + q(0xd8), q(0xd9), q(0xda), q(0xdb), q(0xdc), q(0xdd), q(0xde), q(0xdf),\ + q(0xe0), q(0xe1), q(0xe2), q(0xe3), q(0xe4), q(0xe5), q(0xe6), q(0xe7),\ + q(0xe8), q(0xe9), q(0xea), q(0xeb), q(0xec), q(0xed), q(0xee), q(0xef),\ + q(0xf0), q(0xf1), q(0xf2), q(0xf3), q(0xf4), q(0xf5), q(0xf6), q(0xf7),\ + q(0xf8), q(0xf9), q(0xfa), q(0xfb), q(0xfc), q(0xfd), q(0xfe), q(0xff) } + +/* given the value i in 0..255 as the byte overflow when a a field */ +/* element in GHASH is multipled by x^8, this function will return */ +/* the values that are generated in the lo 16-bit word of the field */ +/* value by applying the modular polynomial. The values lo_byte and */ +/* hi_byte are returned via the macro xp_fun(lo_byte, hi_byte) so */ +/* that the values can be assembled into memory as required by a */ +/* suitable definition of this macro operating on the table above */ + +#define xp(i) xp_fun( \ + (i & 0x80 ? 0xe1 : 0) ^ (i & 0x40 ? 0x70 : 0) ^ \ + (i & 0x20 ? 0x38 : 0) ^ (i & 0x10 ? 0x1c : 0) ^ \ + (i & 0x08 ? 0x0e : 0) ^ (i & 0x04 ? 0x07 : 0) ^ \ + (i & 0x02 ? 0x03 : 0) ^ (i & 0x01 ? 0x01 : 0), \ + (i & 0x80 ? 0x00 : 0) ^ (i & 0x40 ? 0x80 : 0) ^ \ + (i & 0x20 ? 0x40 : 0) ^ (i & 0x10 ? 0x20 : 0) ^ \ + (i & 0x08 ? 0x10 : 0) ^ (i & 0x04 ? 0x08 : 0) ^ \ + (i & 0x02 ? 0x84 : 0) ^ (i & 0x01 ? 0xc2 : 0) ) + +#define xp64(i) xp_fun( \ + (i & 0x80 ? 0xd8 : 0) ^ (i & 0x40 ? 0x6c : 0) ^ \ + (i & 0x20 ? 0x36 : 0) ^ (i & 0x10 ? 0x1b : 0) ^ \ + (i & 0x08 ? 0x0d : 0) ^ (i & 0x04 ? 0x06 : 0) ^ \ + (i & 0x02 ? 0x03 : 0) ^ (i & 0x01 ? 0x01 : 0), \ + (i & 0x80 ? 0x00 : 0) ^ (i & 0x40 ? 0x00 : 0) ^ \ + (i & 0x20 ? 0x00 : 0) ^ (i & 0x10 ? 0x00 : 0) ^ \ + (i & 0x08 ? 0x80 : 0) ^ (i & 0x04 ? 0xc0 : 0) ^ \ + (i & 0x02 ? 0x60 : 0) ^ (i & 0x01 ? 0xb0 : 0) ) + +static mode(32t) gf_poly[2] = { 0, 0xe1000000 }; +static mode(32t) gf_poly64[2] = { 0, 0xd8000000 }; + +/* Multiply of a GF128 field element by x. The field element */ +/* is held in an array of bytes in which field bits 8n..8n + 7 */ +/* are held in byte[n], with lower indexed bits placed in the */ +/* more numerically significant bit positions in bytes. */ + +/* This function multiples a field element x, in the polynomial */ +/* field representation. It uses 32-bit word operations to gain */ +/* speed but compensates for machine endianess and hence works */ +/* correctly on both styles of machine */ + +in_line void mul_x(mode(32t) x[4]) +{ mode(32t) t; + + bsw_32(x, 4); + + /* at this point the filed element bits 0..127 are set out */ + /* as follows in 32-bit words (where the most significant */ + /* (ms) numeric bits are to the left) */ + /* */ + /* x[0] x[1] x[2] x[3] */ + /* ms ls ms ls ms ls ms ls */ + /* field: 0 ... 31 32 .. 63 64 .. 95 96 .. 127 */ + + t = gf_poly[x[3] & 1]; /* bit 127 of the element */ + x[3] = (x[3] >> 1) | (x[2] << 31); /* shift bits up by one */ + x[2] = (x[2] >> 1) | (x[1] << 31); /* position */ + x[1] = (x[1] >> 1) | (x[0] << 31); /* if bit 7 is 1 xor in */ + x[0] = (x[0] >> 1) ^ t; /* the field polynomial */ + bsw_32(x, 4); +} + +in_line void mul_x64(mode(32t) x[2]) +{ mode(32t) t; + + bsw_32(x, 2); + + /* at this point the filed element bits 0..127 are set out */ + /* as follows in 32-bit words (where the most significant */ + /* (ms) numeric bits are to the left) */ + /* */ + /* x[0] x[1] x[2] x[3] */ + /* ms ls ms ls ms ls ms ls */ + /* field: 0 ... 31 32 .. 63 64 .. 95 96 .. 127 */ + + t = gf_poly64[x[1] & 1]; /* bit 127 of the element */ + /* shift bits up by one */ + /* position */ + x[1] = (x[1] >> 1) | (x[0] << 31); /* if bit 7 is 1 xor in */ + x[0] = (x[0] >> 1) ^ t; /* the field polynomial */ + bsw_32(x, 2); +} + +/* Multiply of a GF128 field element by x^8 using 32-bit words */ +/* for speed - machine endianess matters here */ + +#if (PLATFORM_BYTE_ORDER == BRG_LITTLE_ENDIAN) + +#define xp_fun(x,y) ((mode(32t))(x)) | (((mode(32t))(y)) << 8) +static const unsigned __int16 gft_le[256] = gf_dat(xp); +static const unsigned __int16 gft_le64[256] = gf_dat(xp64); + +in_line void mul_lex8(mode(32t) x[4]) /* mutiply with long words */ +{ mode(32t) t = (x[3] >> 24); /* in little endian format */ + x[3] = (x[3] << 8) | (x[2] >> 24); + x[2] = (x[2] << 8) | (x[1] >> 24); + x[1] = (x[1] << 8) | (x[0] >> 24); + x[0] = (x[0] << 8) ^ gft_le[t]; +} + +in_line void mul_lex8_64(mode(32t) x[2]) /* mutiply with long words */ +{ mode(32t) t = (x[1] >> 24); /* in little endian format */ + x[1] = (x[1] << 8) | (x[0] >> 24); + x[0] = (x[0] << 8) ^ gft_le64[t]; +} + +#endif + +#if 1 || (PLATFORM_BYTE_ORDER == BRG_LITTLE_ENDIAN) + +#undef xp_fun +#define xp_fun(x,y) ((mode(32t))(y)) | (((mode(32t))(x)) << 8) +static const unsigned __int16 gft_be[256] = gf_dat(xp); +static const unsigned __int16 gft_be64[256] = gf_dat(xp64); + +in_line void mul_bex8(mode(32t) x[4]) /* mutiply with long words */ +{ mode(32t) t = (x[3] & 0xff); /* in big endian format */ + x[3] = (x[3] >> 8) | (x[2] << 24); + x[2] = (x[2] >> 8) | (x[1] << 24); + x[1] = (x[1] >> 8) | (x[0] << 24); + x[0] = (x[0] >> 8) ^ (((mode(32t))gft_be[t]) << 16); +} + +in_line void mul_bex8_64(mode(32t) x[2]) /* mutiply with long words */ +{ mode(32t) t = (x[1] & 0xff); /* in big endian format */ + x[1] = (x[1] >> 8) | (x[0] << 24); + x[0] = (x[0] >> 8) ^ (((mode(32t))gft_be64[t]) << 16); +} + +#endif + +/* hence choose the correct version for the machine endianess */ + +#if PLATFORM_BYTE_ORDER == BRG_BIG_ENDIAN +#define mul_x8 mul_bex8 +#define mul_x8_64 mul_bex8_64 +#else +#define mul_x8 mul_lex8 +#define mul_x8_64 mul_lex8_64 +#endif + +/* different versions of the general gf_mul function are provided */ +/* here. Sadly none are very fast :-( */ + +void GfMul128 (void *a, const void* b) +{ mode(32t) r[CBLK_LEN >> 2], p[8][CBLK_LEN >> 2]; + int i; + + move_block_aligned(p[0], b); + bsw_32(p[0], 4); + for(i = 0; i < 7; ++i) + { + p[i + 1][3] = (p[i][3] >> 1) | (p[i][2] << 31); + p[i + 1][2] = (p[i][2] >> 1) | (p[i][1] << 31); + p[i + 1][1] = (p[i][1] >> 1) | (p[i][0] << 31); + p[i + 1][0] = (p[i][0] >> 1) ^ gf_poly[p[i][3] & 1]; + } + + memset(r, 0, CBLK_LEN); + for(i = 0; i < 16; ++i) + { + if(i) mul_bex8(r); /* order is always big endian here */ + + if(((unsigned char*)a)[15 - i] & 0x80) + xor_block_aligned(r, p[0]); + if(((unsigned char*)a)[15 - i] & 0x40) + xor_block_aligned(r, p[1]); + if(((unsigned char*)a)[15 - i] & 0x20) + xor_block_aligned(r, p[2]); + if(((unsigned char*)a)[15 - i] & 0x10) + xor_block_aligned(r, p[3]); + if(((unsigned char*)a)[15 - i] & 0x08) + xor_block_aligned(r, p[4]); + if(((unsigned char*)a)[15 - i] & 0x04) + xor_block_aligned(r, p[5]); + if(((unsigned char*)a)[15 - i] & 0x02) + xor_block_aligned(r, p[6]); + if(((unsigned char*)a)[15 - i] & 0x01) + xor_block_aligned(r, p[7]); + } + bsw_32(r, 4); + move_block_aligned(a, r); +} + +#if defined( UNROLL_LOOPS ) + +#define xor_8k(i) \ + xor_block_aligned(r, ctx->gf_t8k[i + i][a[i] & 15]); \ + xor_block_aligned(r, ctx->gf_t8k[i + i + 1][a[i] >> 4]) + + +void GfMul128Tab (unsigned char a[CBLK_LEN], GfCtx8k *ctx) +{ unsigned __int32 r[CBLK_LEN >> 2]; + + move_block_aligned(r, ctx->gf_t8k[0][a[0] & 15]); + xor_block_aligned(r, ctx->gf_t8k[1][a[0] >> 4]); + xor_8k( 1); xor_8k( 2); xor_8k( 3); + xor_8k( 4); xor_8k( 5); xor_8k( 6); xor_8k( 7); + xor_8k( 8); xor_8k( 9); xor_8k(10); xor_8k(11); + xor_8k(12); xor_8k(13); xor_8k(14); xor_8k(15); + move_block_aligned(a, r); +} + +#else + +void GfMul128Tab (unsigned char a[CBLK_LEN], GfCtx8k *ctx) +{ unsigned __int32 r[CBLK_LEN >> 2], *p; + int i; + + p = ctx->gf_t8k[0][a[0] & 15]; + memcpy(r, p, CBLK_LEN); + p = ctx->gf_t8k[1][a[0] >> 4]; + xor_block_aligned(r, p); + for(i = 1; i < CBLK_LEN; ++i) + { + xor_block_aligned(r, ctx->gf_t8k[i + i][a[i] & 15]); + xor_block_aligned(r, ctx->gf_t8k[i + i + 1][a[i] >> 4]); + } + memcpy(a, r, CBLK_LEN); +} + +#endif + +void compile_8k_table(unsigned __int8 *a, GfCtx8k *ctx) +{ int i, j, k; + + memset(ctx->gf_t8k, 0, 32 * 16 * 16); + for(i = 0; i < 2 * CBLK_LEN; ++i) + { + if(i == 0) + { + memcpy(ctx->gf_t8k[1][8], a, CBLK_LEN); + for(j = 4; j > 0; j >>= 1) + { + memcpy(ctx->gf_t8k[1][j], ctx->gf_t8k[1][j + j], CBLK_LEN); + mul_x(ctx->gf_t8k[1][j]); + } + memcpy(ctx->gf_t8k[0][8], ctx->gf_t8k[1][1], CBLK_LEN); + mul_x(ctx->gf_t8k[0][8]); + for(j = 4; j > 0; j >>= 1) + { + memcpy(ctx->gf_t8k[0][j], ctx->gf_t8k[0][j + j], CBLK_LEN); + mul_x(ctx->gf_t8k[0][j]); + } + } + else if(i > 1) + for(j = 8; j > 0; j >>= 1) + { + memcpy(ctx->gf_t8k[i][j], ctx->gf_t8k[i - 2][j], CBLK_LEN); + mul_x8(ctx->gf_t8k[i][j]); + } + + for(j = 2; j < 16; j += j) + { + mode(32t) *pj = ctx->gf_t8k[i][j]; + mode(32t) *pk = ctx->gf_t8k[i][1]; + mode(32t) *pl = ctx->gf_t8k[i][j + 1]; + + for(k = 1; k < j; ++k) + { + *pl++ = pj[0] ^ *pk++; + *pl++ = pj[1] ^ *pk++; + *pl++ = pj[2] ^ *pk++; + *pl++ = pj[3] ^ *pk++; + } + } + } +} + + +void compile_4k_table64(unsigned __int8 *a, GfCtx4k64 *ctx) +{ int i, j, k; + + memset(ctx->gf_t4k, 0, sizeof(ctx->gf_t4k)); + for(i = 0; i < 2 * CBLK_LEN8; ++i) + { + if(i == 0) + { + memcpy(ctx->gf_t4k[1][8], a, CBLK_LEN8); + for(j = 4; j > 0; j >>= 1) + { + memcpy(ctx->gf_t4k[1][j], ctx->gf_t4k[1][j + j], CBLK_LEN8); + mul_x64(ctx->gf_t4k[1][j]); + } + memcpy(ctx->gf_t4k[0][8], ctx->gf_t4k[1][1], CBLK_LEN8); + mul_x64(ctx->gf_t4k[0][8]); + for(j = 4; j > 0; j >>= 1) + { + memcpy(ctx->gf_t4k[0][j], ctx->gf_t4k[0][j + j], CBLK_LEN8); + mul_x64(ctx->gf_t4k[0][j]); + } + } + else if(i > 1) + for(j = 8; j > 0; j >>= 1) + { + memcpy(ctx->gf_t4k[i][j], ctx->gf_t4k[i - 2][j], CBLK_LEN8); + mul_x8_64(ctx->gf_t4k[i][j]); + } + + for(j = 2; j < 16; j += j) + { + mode(32t) *pj = ctx->gf_t4k[i][j]; + mode(32t) *pk = ctx->gf_t4k[i][1]; + mode(32t) *pl = ctx->gf_t4k[i][j + 1]; + + for(k = 1; k < j; ++k) + { + *pl++ = pj[0] ^ *pk++; + *pl++ = pj[1] ^ *pk++; + *pl++ = pj[2] ^ *pk++; + *pl++ = pj[3] ^ *pk++; + } + } + } +} + +static int IsBitSet128 (unsigned int bit, unsigned __int8 *a) +{ + return a[(127 - bit) / 8] & (0x80 >> ((127 - bit) % 8)); +} + +static int IsBitSet64 (unsigned int bit, unsigned __int8 *a) +{ + return a[(63 - bit) / 8] & (0x80 >> ((63 - bit) % 8)); +} + +static void SetBit128 (unsigned int bit, unsigned __int8 *a) +{ + a[(127 - bit) / 8] |= 0x80 >> ((127 - bit) % 8); +} + +static void SetBit64 (unsigned int bit, unsigned __int8 *a) +{ + a[(63 - bit) / 8] |= 0x80 >> ((63 - bit) % 8); +} + +void MirrorBits128 (unsigned __int8 *a) +{ + unsigned __int8 t[128 / 8]; + int i; + memset (t,0,16); + for (i = 0; i < 128; i++) + { + if (IsBitSet128(i, a)) + SetBit128 (127 - i, t); + } + memcpy (a, t, sizeof (t)); + burn (t,sizeof (t)); +} + +void MirrorBits64 (unsigned __int8 *a) +{ + unsigned __int8 t[64 / 8]; + int i; + memset (t,0,8); + for (i = 0; i < 64; i++) + { + if (IsBitSet64(i, a)) + SetBit64 (63 - i, t); + } + memcpy (a, t, sizeof (t)); + burn (t,sizeof (t)); +} + +/* Allocate and initialize speed optimization table + for multiplication by 64-bit operand in MSB-first mode */ +int Gf128Tab64Init (unsigned __int8 *a, GfCtx *ctx) +{ + GfCtx8k *ctx8k; + unsigned __int8 am[16]; + int i, j; + + ctx8k = (GfCtx8k *) TCalloc (sizeof (GfCtx8k)); + if (!ctx8k) + return FALSE; + + memcpy (am, a, 16); + MirrorBits128 (am); + compile_8k_table (am, ctx8k); + + /* Convert 8k LSB-first table to 4k MSB-first */ + for (i = 16; i < 32; i++) + { + for (j = 0; j < 16; j++) + { + int jm = 0; + jm |= (j & 0x1) << 3; + jm |= (j & 0x2) << 1; + jm |= (j & 0x4) >> 1; + jm |= (j & 0x8) >> 3; + + memcpy (&ctx->gf_t128[i-16][jm], (unsigned char *)&ctx8k->gf_t8k[31-i][j], 16); + MirrorBits128 ((unsigned char *)&ctx->gf_t128[i-16][jm]); + } + } + + burn (ctx8k ,sizeof (*ctx8k)); + burn (am, sizeof (am)); + TCfree (ctx8k); + return TRUE; +} + +int Gf64TabInit (unsigned __int8 *a, GfCtx *ctx) +{ + /* Deprecated/legacy */ + + GfCtx4k64 *ctx4k; + unsigned __int8 am[8]; + int i, j; + + ctx4k = (GfCtx4k64 *) TCalloc (sizeof (GfCtx4k64)); + if (!ctx4k) + return FALSE; + + memcpy (am, a, 8); + MirrorBits64 (am); + compile_4k_table64 (am, ctx4k); + + /* Convert LSB-first table to MSB-first */ + for (i = 0; i < 16; i++) + { + for (j = 0; j < 16; j++) + { + int jm = 0; + jm |= (j & 0x1) << 3; + jm |= (j & 0x2) << 1; + jm |= (j & 0x4) >> 1; + jm |= (j & 0x8) >> 3; + + memcpy (&ctx->gf_t64[i][jm], (unsigned char *)&ctx4k->gf_t4k[15-i][j], 8); + MirrorBits64 ((unsigned char *)&ctx->gf_t64[i][jm]); + } + } + + burn (ctx4k,sizeof (*ctx4k)); + burn (am, sizeof (am)); + TCfree (ctx4k); + return TRUE; +} + +#define xor_8kt64(i) \ + xor_block_aligned(r, ctx->gf_t128[i + i][a[i] & 15]); \ + xor_block_aligned(r, ctx->gf_t128[i + i + 1][a[i] >> 4]) + +/* Multiply a 128-bit number by a 64-bit number in the finite field GF(2^128) */ +void Gf128MulBy64Tab (unsigned __int8 a[8], unsigned __int8 p[16], GfCtx *ctx) +{ + unsigned __int32 r[CBLK_LEN >> 2]; + + move_block_aligned(r, ctx->gf_t128[7*2][a[7] & 15]); + xor_block_aligned(r, ctx->gf_t128[7*2+1][a[7] >> 4]); + + if (*(unsigned __int16 *)a) + { + xor_8kt64(0); + xor_8kt64(1); + } + if (a[2]) + { + xor_8kt64(2); + } + xor_8kt64(3); + xor_8kt64(4); + xor_8kt64(5); + xor_8kt64(6); + + move_block_aligned(p, r); +} + +#define xor_8k64(i) \ + xor_block_aligned64(r, ctx->gf_t64[i + i][a[i] & 15]); \ + xor_block_aligned64(r, ctx->gf_t64[i + i + 1][a[i] >> 4]) + +/* Multiply two 64-bit numbers in the finite field GF(2^64) */ +void Gf64MulTab (unsigned char a[8], unsigned char p[8], GfCtx *ctx) +{ + /* Deprecated/legacy */ + + unsigned __int32 r[CBLK_LEN8 >> 2]; + + move_block_aligned64(r, ctx->gf_t64[7*2][a[7] & 15]); + xor_block_aligned64(r, ctx->gf_t64[7*2+1][a[7] >> 4]); + + if (*(unsigned __int16 *)a) + { + xor_8k64(0); + xor_8k64(1); + } + if (a[2]) + { + xor_8k64(2); + } + xor_8k64(3); + xor_8k64(4); + xor_8k64(5); + xor_8k64(6); + + move_block_aligned64(p, r); +} + + +/* Basic algorithms for testing of optimized algorithms */ + +static void xor128 (uint64 *a, uint64 *b) +{ + *a++ ^= *b++; + *a ^= *b; +} + +static void shl128 (unsigned __int8 *a) +{ + int i, x = 0, xx; + for (i = 15; i >= 0; i--) + { + xx = (a[i] & 0x80) >> 7; + a[i] = (char) ((a[i] << 1) | x); + x = xx; + } +} + +static void GfMul128Basic (unsigned __int8 *a, unsigned __int8 *b, unsigned __int8 *p) +{ + int i; + unsigned __int8 la[16]; + memcpy (la, a, 16); + memset (p, 0, 16); + + for (i = 0; i < 128; i++) + { + if (IsBitSet128 (i, b)) + xor128 ((uint64 *)p, (uint64 *)la); + + if (la[0] & 0x80) + { + shl128 (la); + la[15] ^= 0x87; + } + else + { + shl128 (la); + } + } +} + +static void xor64 (uint64 *a, uint64 *b) +{ + *a ^= *b; +} + +static void shl64 (unsigned __int8 *a) +{ + int i, x = 0, xx; + for (i = 7; i >= 0; i--) + { + xx = (a[i] & 0x80) >> 7; + a[i] = (char) ((a[i] << 1) | x); + x = xx; + } +} + +static void GfMul64Basic (unsigned __int8 *a, unsigned __int8 *b, unsigned __int8* p) +{ + /* Deprecated/legacy */ + + int i; + unsigned __int8 la[8]; + memcpy (la, a, 8); + memset (p, 0, 8); + + for (i = 0; i < 64; i++) + { + if (IsBitSet64 (i, b)) + xor64 ((uint64 *)p, (uint64 *)la); + + if (la[0] & 0x80) + { + shl64 (la); + la[7] ^= 0x1b; + } + else + { + shl64 (la); + } + } +} + + +BOOL GfMulSelfTest () +{ + BOOL result = TRUE; + unsigned __int8 a[16]; + unsigned __int8 b[16]; + unsigned __int8 p1[16]; + unsigned __int8 p2[16]; + GfCtx *gfCtx = (GfCtx *) TCalloc (sizeof (GfCtx)); + int i, j; + + if (!gfCtx) + return FALSE; + + /* GF(2^64) - deprecated/legacy */ + for (i = 0; i < 0x100; i++) + { + for (j = 0; j < 8; j++) + { + a[j] = (unsigned __int8) i; + b[j] = a[j] ^ 0xff; + } + + GfMul64Basic (a, b, p1); + + Gf64TabInit (a, gfCtx); + Gf64MulTab (b, p2, gfCtx); + + if (memcmp (p1, p2, 8) != 0) + result = FALSE; + } + + /* GF(2^128) */ + for (i = 0; i < 0x100; i++) + { + for (j = 0; j < 16; j++) + { + a[j] = (unsigned __int8) i; + b[j] = j < 8 ? 0 : a[j] ^ 0xff; + } + + GfMul128Basic (a, b, p1); + + Gf128Tab64Init (a, gfCtx); + Gf128MulBy64Tab (b + 8, p2, gfCtx); + + if (memcmp (p1, p2, 16) != 0) + result = FALSE; + } + + TCfree (gfCtx); + return result; +} + +#if defined(__cplusplus) +} +#endif diff --git a/Common/GfMul.h b/Common/GfMul.h new file mode 100644 index 0000000..d8c274e --- /dev/null +++ b/Common/GfMul.h @@ -0,0 +1,76 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 2003, Dr Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 31/01/2004 +*/ + +/* Adapted for TrueCrypt */ + +#ifndef _GCM_H +#define _GCM_H + +#include "Tcdefs.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#define CBLK_LEN 16 /* encryption block length */ +#define CBLK_LEN8 8 + +typedef struct +{ + unsigned __int32 gf_t8k[CBLK_LEN * 2][16][CBLK_LEN / 4]; +} GfCtx8k; + +typedef struct +{ + unsigned __int32 gf_t4k[CBLK_LEN8 * 2][16][CBLK_LEN / 4]; +} GfCtx4k64; + +typedef struct +{ + /* union not used to support faster mounting */ + unsigned __int32 gf_t128[CBLK_LEN * 2 / 2][16][CBLK_LEN / 4]; + unsigned __int32 gf_t64[CBLK_LEN8 * 2][16][CBLK_LEN8 / 4]; +} GfCtx; + +typedef int ret_type; + +void GfMul128 (void *a, const void* b); +void GfMul128Tab(unsigned char a[16], GfCtx8k *ctx); +int Gf128Tab64Init (unsigned __int8 *a, GfCtx *ctx); +void Gf128MulBy64Tab (unsigned __int8 a[8], unsigned __int8 p[16], GfCtx *ctx); +int Gf64TabInit (unsigned __int8 *a, GfCtx *ctx); +void Gf64MulTab (unsigned char a[8], unsigned char p[8], GfCtx *ctx); +void MirrorBits128 (unsigned __int8 *a); +void MirrorBits64 (unsigned __int8 *a); +BOOL GfMulSelfTest (); + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/Common/Inflate.c b/Common/Inflate.c new file mode 100644 index 0000000..ab2f4a3 --- /dev/null +++ b/Common/Inflate.c @@ -0,0 +1,1308 @@ +/* inflate.c -- put in the public domain by Mark Adler */ + +/* Decompresses raw data compressed using the DEFLATE algorithm (RFC 1951) */ + +/* You can do whatever you like with this source file, though I would + prefer that if you modify it and redistribute it that you include + comments to that effect with your name and the date. Thank you. + + History: + vers date who what + ---- --------- -------------- ------------------------------------ + a ~~ Feb 92 M. Adler used full (large, one-step) lookup table + b1 21 Mar 92 M. Adler first version with partial lookup tables + b2 21 Mar 92 M. Adler fixed bug in fixed-code blocks + b3 22 Mar 92 M. Adler sped up match copies, cleaned up some + b4 25 Mar 92 M. Adler added prototypes; removed window[] (now + is the responsibility of unzip.h--also + changed name to slide[]), so needs diffs + for unzip.c and unzip.h (this allows + compiling in the small model on MSDOS); + fixed cast of q in huft_build(); + b5 26 Mar 92 M. Adler got rid of unintended macro recursion. + b6 27 Mar 92 M. Adler got rid of nextbyte() routine. fixed + bug in inflate_fixed(). + c1 30 Mar 92 M. Adler removed lbits, dbits environment variables. + changed BMAX to 16 for explode. Removed + OUTB usage, and replaced it with flush()-- + this was a 20% speed improvement! Added + an explode.c (to replace unimplod.c) that + uses the huft routines here. Removed + register union. + c2 4 Apr 92 M. Adler fixed bug for file sizes a multiple of 32k. + c3 10 Apr 92 M. Adler reduced memory of code tables made by + huft_build significantly (factor of two to + three). + c4 15 Apr 92 M. Adler added NOMEMCPY do kill use of memcpy(). + worked around a Turbo C optimization bug. + c5 21 Apr 92 M. Adler added the WSIZE #define to allow reducing + the 32K window size for specialized + applications. + c6 31 May 92 M. Adler added some typecasts to eliminate warnings + c7 27 Jun 92 G. Roelofs added some more typecasts (444: MSC bug). + c8 5 Oct 92 J-l. Gailly added ifdef'd code to deal with PKZIP bug. + c9 9 Oct 92 M. Adler removed a memory error message (~line 416). + c10 17 Oct 92 G. Roelofs changed ULONG/UWORD/byte to ulg/ush/uch, + removed old inflate, renamed inflate_entry + to inflate, added Mark's fix to a comment. + c10.5 14 Dec 92 M. Adler fix up error messages for incomplete trees. + c11 2 Jan 93 M. Adler fixed bug in detection of incomplete + tables, and removed assumption that EOB is + the longest code (bad assumption). + c12 3 Jan 93 M. Adler make tables for fixed blocks only once. + c13 5 Jan 93 M. Adler allow all zero length codes (pkzip 2.04c + outputs one zero length code for an empty + distance tree). + c14 12 Mar 93 M. Adler made inflate.c standalone with the + introduction of inflate.h. + c14b 16 Jul 93 G. Roelofs added (unsigned) typecast to w at 470. + c14c 19 Jul 93 J. Bush changed v[N_MAX], l[288], ll[28x+3x] arrays + to static for Amiga. + c14d 13 Aug 93 J-l. Gailly de-complicatified Mark's c[*p++]++ thing. + c14e 8 Oct 93 G. Roelofs changed memset() to memzero(). + c14f 22 Oct 93 G. Roelofs renamed quietflg to qflag; made Trace() + conditional; added inflate_free(). + c14g 28 Oct 93 G. Roelofs changed l/(lx+1) macro to pointer (Cray bug) + c14h 7 Dec 93 C. Ghisler huft_build() optimizations. + c14i 9 Jan 94 A. Verheijen set fixed_t{d,l} to NULL after freeing; + G. Roelofs check NEXTBYTE macro for EOF. + c14j 23 Jan 94 G. Roelofs removed Ghisler "optimizations"; ifdef'd + EOF check. + c14k 27 Feb 94 G. Roelofs added some typecasts to avoid warnings. + c14l 9 Apr 94 G. Roelofs fixed split comments on preprocessor lines + to avoid bug in Encore compiler. + c14m 7 Jul 94 P. Kienitz modified to allow assembler version of + inflate_codes() (define ASM_INFLATECODES) + c14n 22 Jul 94 G. Roelofs changed fprintf to macro for DLL versions + c14o 23 Aug 94 C. Spieler added a newline to a debug statement; + G. Roelofs added another typecast to avoid MSC warning + c14p 4 Oct 94 G. Roelofs added (voidp *) cast to free() argument + c14q 30 Oct 94 G. Roelofs changed fprintf macro to MESSAGE() + c14r 1 Nov 94 G. Roelofs fixed possible redefinition of CHECK_EOF + c14s 7 May 95 S. Maxwell OS/2 DLL globals stuff incorporated; + P. Kienitz "fixed" ASM_INFLATECODES macro/prototype + c14t 18 Aug 95 G. Roelofs added inflate() to use zlib functions; + changed voidp to zvoid; moved huft_build() + and huft_free() to end of file + c14u 1 Oct 95 G. Roelofs moved G into definition of MESSAGE macro + c14v 8 Nov 95 P. Kienitz changed ASM_INFLATECODES to use a regular + call with __G__ instead of a macro + c15 3 Aug 96 M. Adler fixed bomb-bug on random input data (Adobe) + c15b 24 Aug 96 M. Adler more fixes for random input data + c15c 28 Mar 97 G. Roelofs changed USE_ZLIB fatal exit code from + PK_MEM2 to PK_MEM3 + c16 20 Apr 97 J. Altman added memzero(v[]) in huft_build() + c16b 29 Mar 98 C. Spieler modified DLL code for slide redirection + + fork 12 Dec 07 Adapted for TrueCrypt + */ + + +/* + Inflate deflated (PKZIP's method 8 compressed) data. The compression + method searches for as much of the current string of bytes (up to a + length of 258) in the previous 32K bytes. If it doesn't find any + matches (of at least length 3), it codes the next byte. Otherwise, it + codes the length of the matched string and its distance backwards from + the current position. There is a single Huffman code that codes both + single bytes (called "literals") and match lengths. A second Huffman + code codes the distance information, which follows a length code. Each + length or distance code actually represents a base value and a number + of "extra" (sometimes zero) bits to get to add to the base value. At + the end of each deflated block is a special end-of-block (EOB) literal/ + length code. The decoding process is basically: get a literal/length + code; if EOB then done; if a literal, emit the decoded byte; if a + length then get the distance and emit the referred-to bytes from the + sliding window of previously emitted data. + + There are (currently) three kinds of inflate blocks: stored, fixed, and + dynamic. The compressor outputs a chunk of data at a time and decides + which method to use on a chunk-by-chunk basis. A chunk might typically + be 32K to 64K, uncompressed. If the chunk is uncompressible, then the + "stored" method is used. In this case, the bytes are simply stored as + is, eight bits per byte, with none of the above coding. The bytes are + preceded by a count, since there is no longer an EOB code. + + If the data are compressible, then either the fixed or dynamic methods + are used. In the dynamic method, the compressed data are preceded by + an encoding of the literal/length and distance Huffman codes that are + to be used to decode this block. The representation is itself Huffman + coded, and so is preceded by a description of that code. These code + descriptions take up a little space, and so for small blocks, there is + a predefined set of codes, called the fixed codes. The fixed method is + used if the block ends up smaller that way (usually for quite small + chunks); otherwise the dynamic method is used. In the latter case, the + codes are customized to the probabilities in the current block and so + can code it much better than the pre-determined fixed codes can. + + The Huffman codes themselves are decoded using a multi-level table + lookup, in order to maximize the speed of decoding plus the speed of + building the decoding tables. See the comments below that precede the + lbits and dbits tuning parameters. + + GRR: return values(?) + 0 OK + 1 incomplete table + 2 bad input + 3 not enough memory + */ + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +/* #define DEBUG */ +#define INFMOD /* tell inflate.h to include code to be compiled */ +#include "inflate.h" + + +#ifndef WSIZE /* default is 32K */ +# define WSIZE 0x8000 /* window size--must be a power of two, and at least */ +#endif /* 32K for zip's deflate method */ + +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) +# define wsize G._wsize /* wsize is a variable */ +#else +# define wsize WSIZE /* wsize is a constant */ +#endif + + +#ifndef NEXTBYTE /* default is to simply get a byte from stdin */ +# define NEXTBYTE getchar() +#endif + +#ifndef MESSAGE /* only used twice, for fixed strings--NOT general-purpose */ +# define MESSAGE(str,len,flag) fprintf(stderr,(char *)(str)) +#endif + +#ifndef FLUSH /* default is to simply write the buffer to stdout */ +# define FLUSH(n) fwrite(redirSlide, 1, n, stdout) /* return value not used */ +#endif +/* Warning: the fwrite above might not work on 16-bit compilers, since + 0x8000 might be interpreted as -32,768 by the library function. */ + +#ifndef Trace +# ifdef DEBUG +# define Trace(x) fprintf x +# else +# define Trace(x) +# endif +#endif + +G_struct G; +uch redirSlide [WSIZE]; + +/*---------------------------------------------------------------------------*/ +#ifdef USE_ZLIB + + +/* + GRR: return values for both original inflate() and inflate() + 0 OK + 1 incomplete table(?) + 2 bad input + 3 not enough memory + */ + +/**************************/ +/* Function inflate() */ +/**************************/ + +int inflate(__G) /* decompress an inflated entry using the zlib routines */ + __GDEF +{ + int err=Z_OK; + +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) + wsize = G.redirect_size, redirSlide = G.redirect_buffer; + else + wsize = WSIZE, redirSlide = slide; +#endif + + G.dstrm.next_out = redirSlide; + G.dstrm.avail_out = wsize; + + G.dstrm.next_in = G.inptr; + G.dstrm.avail_in = G.incnt; + + if (!G.inflInit) { + unsigned i; + int windowBits; + + /* only need to test this stuff once */ + if (zlib_version[0] != ZLIB_VERSION[0]) { + Info(slide, 0x21, ((char *)slide, + "error: incompatible zlib version (expected %s, found %s)\n", + ZLIB_VERSION, zlib_version)); + return 3; + } else if (strcmp(zlib_version, ZLIB_VERSION) != 0) + Info(slide, 0x21, ((char *)slide, + "warning: different zlib version (expected %s, using %s)\n", + ZLIB_VERSION, zlib_version)); + + /* windowBits = log2(wsize) */ + for (i = ((unsigned)wsize * 2 - 1), windowBits = 0; + !(i & 1); i >>= 1, ++windowBits); + if ((unsigned)windowBits > (unsigned)15) + windowBits = 15; + else if (windowBits < 8) + windowBits = 8; + + G.dstrm.zalloc = (alloc_func)Z_NULL; + G.dstrm.zfree = (free_func)Z_NULL; + + Trace((stderr, "initializing inflate()\n")); + err = inflateInit2(&G.dstrm, -windowBits); + + if (err == Z_MEM_ERROR) + return 3; + else if (err != Z_OK) + Trace((stderr, "oops! (inflateInit2() err = %d)\n", err)); + G.inflInit = 1; + } + +#ifdef FUNZIP + while (err != Z_STREAM_END) { +#else /* !FUNZIP */ + while (G.csize > 0) { + Trace((stderr, "first loop: G.csize = %ld\n", G.csize)); +#endif /* ?FUNZIP */ + while (G.dstrm.avail_out > 0) { + err = inflate(&G.dstrm, Z_PARTIAL_FLUSH); + + if (err == Z_DATA_ERROR) + return 2; + else if (err == Z_MEM_ERROR) + return 3; + else if (err != Z_OK && err != Z_STREAM_END) + Trace((stderr, "oops! (inflate(first loop) err = %d)\n", err)); + +#ifdef FUNZIP + if (err == Z_STREAM_END) /* "END-of-entry-condition" ? */ +#else /* !FUNZIP */ + if (G.csize <= 0L) /* "END-of-entry-condition" ? */ +#endif /* ?FUNZIP */ + break; + + if (G.dstrm.avail_in <= 0) { + if (fillinbuf(__G) == 0) + return 2; /* no "END-condition" yet, but no more data */ + + G.dstrm.next_in = G.inptr; + G.dstrm.avail_in = G.incnt; + } + Trace((stderr, " avail_in = %d\n", G.dstrm.avail_in)); + } + FLUSH(wsize - G.dstrm.avail_out); /* flush slide[] */ + Trace((stderr, "inside loop: flushing %ld bytes (ptr diff = %ld)\n", + (long)(wsize - G.dstrm.avail_out), + (long)(G.dstrm.next_out-(Bytef *)redirSlide))); + G.dstrm.next_out = redirSlide; + G.dstrm.avail_out = wsize; + } + + /* no more input, so loop until we have all output */ + Trace((stderr, "beginning final loop: err = %d\n", err)); + while (err != Z_STREAM_END) { + err = inflate(&G.dstrm, Z_PARTIAL_FLUSH); + if (err == Z_DATA_ERROR) + return 2; + else if (err == Z_MEM_ERROR) + return 3; + else if (err == Z_BUF_ERROR) { /* DEBUG */ + Trace((stderr, "zlib inflate() did not detect stream end (%s, %s)\n" + , G.zipfn, G.filename)); + break; + } else if (err != Z_OK && err != Z_STREAM_END) { + Trace((stderr, "oops! (inflate(final loop) err = %d)\n", err)); + DESTROYGLOBALS() + EXIT(PK_MEM3); + } + FLUSH(wsize - G.dstrm.avail_out); /* final flush of slide[] */ + Trace((stderr, "final loop: flushing %ld bytes (ptr diff = %ld)\n", + (long)(wsize - G.dstrm.avail_out), + (long)(G.dstrm.next_out-(Bytef *)redirSlide))); + G.dstrm.next_out = redirSlide; + G.dstrm.avail_out = wsize; + } + Trace((stderr, "total in = %ld, total out = %ld\n", G.dstrm.total_in, + G.dstrm.total_out)); + + G.inptr = (uch *)G.dstrm.next_in; + G.incnt = (G.inbuf + INBUFSIZ) - G.inptr; /* reset for other routines */ + + err = inflateReset(&G.dstrm); + if (err != Z_OK) + Trace((stderr, "oops! (inflateReset() err = %d)\n", err)); + + return 0; +} + + +/*---------------------------------------------------------------------------*/ +#else /* !USE_ZLIB */ + + +/* Function prototypes */ +#ifndef OF +# ifdef __STDC__ +# define OF(a) a +# else +# define OF(a) () +# endif +#endif /* !OF */ +int inflate_codes OF((__GPRO__ struct huft *tl, struct huft *td, + int bl, int bd)); +static int inflate_stored OF((__GPRO)); +static int inflate_fixed OF((__GPRO)); +static int inflate_dynamic OF((__GPRO)); +static int inflate_block OF((__GPRO__ int *e)); + + +/* The inflate algorithm uses a sliding 32K byte window on the uncompressed + stream to find repeated byte strings. This is implemented here as a + circular buffer. The index is updated simply by incrementing and then + and'ing with 0x7fff (32K-1). */ +/* It is left to other modules to supply the 32K area. It is assumed + to be usable as if it were declared "uch slide[32768];" or as just + "uch *slide;" and then malloc'ed in the latter case. The definition + must be in unzip.h, included above. */ + + +/* unsigned wp; moved to globals.h */ /* current position in slide */ + + +/* Tables for deflate from PKZIP's appnote.txt. */ +static ZCONST unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +static ZCONST ush cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +static ZCONST ush cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +static ZCONST ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static ZCONST ush cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + +/* moved to consts.h (included in unzip.c), resp. funzip.c */ +#if 1 +/* And'ing with mask_bits[n] masks the lower n bits */ +ZCONST ush near mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; +#endif /* 0 */ + + +/* Macros for inflate() bit peeking and grabbing. + The usage is: + + NEEDBITS(j) + x = b & mask_bits[j]; + DUMPBITS(j) + + where NEEDBITS makes sure that b has at least j bits in it, and + DUMPBITS removes the bits from b. The macros use the variable k + for the number of bits in b. Normally, b and k are register + variables for speed and are initialized at the begining of a + routine that uses these macros from a global bit buffer and count. + + In order to not ask for more bits than there are in the compressed + stream, the Huffman tables are constructed to only ask for just + enough bits to make up the end-of-block code (value 256). Then no + bytes need to be "returned" to the buffer at the end of the last + block. See the huft_build() routine. + */ + +/* These have been moved to globals.h */ +#if 0 +ulg bb; /* bit buffer */ +unsigned bk; /* bits in bit buffer */ +#endif + +#ifndef CHECK_EOF +# define CHECK_EOF /* default as of 5.13/5.2 */ +#endif + +#ifndef CHECK_EOF +# define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE)<<k;k+=8;}} +#else +# define NEEDBITS(n) {while(k<(n)){int c=NEXTBYTE;if(c==EOF)return 1;\ + b|=((ulg)c)<<k;k+=8;}} +#endif /* Piet Plomp: change "return 1" to "break" */ + +#define DUMPBITS(n) {b>>=(n);k-=(n);} + + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + are not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + +static ZCONST int lbits = 9; /* bits in base literal/length lookup table */ +static ZCONST int dbits = 6; /* bits in base distance lookup table */ + + +#ifndef ASM_INFLATECODES + +#pragma warning(disable:4131) + +int inflate_codes(__G__ tl, td, bl, bd) + __GDEF +struct huft *tl, *td; /* literal/length and distance decoder tables */ +int bl, bd; /* number of bits decoded by tl[] and td[] */ +/* inflate (decompress) the codes in a deflated (compressed) block. + Return an error code or zero if it all goes ok. */ +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = G.bb; /* initialize bit buffer */ + k = G.bk; + w = G.wp; /* initialize window position */ + + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + while (1) /* do until end of block */ + { + NEEDBITS((unsigned)bl) + if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + { + redirSlide[w++] = (uch)t->v.n; + if (w == wsize) + { + FLUSH(w); + w = 0; + } + } + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + break; + + /* get length of block to copy */ + NEEDBITS(e) + n = t->v.n + ((unsigned)b & mask_bits[e]); + DUMPBITS(e); + + /* decode distance of block to copy */ + NEEDBITS((unsigned)bd) + if ((e = (t = td + ((unsigned)b & md))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + NEEDBITS(e) + d = w - t->v.n - ((unsigned)b & mask_bits[e]); + DUMPBITS(e) + + /* do the copy */ + do { +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) {/* &= w/ wsize unnecessary & wrong if redirect */ + if (d >= wsize) + return 1; /* invalid compressed data */ + n -= (e = (e = wsize - (d > w ? d : w)) > n ? n : e); + } + else +#endif + n -= (e = (e = wsize - ((d &= wsize-1) > w ? d : w)) > n ? n : e); +#ifndef NOMEMCPY + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(redirSlide + w, redirSlide + d, e); + w += e; + d += e; + } + else /* do it slowly to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + redirSlide[w++] = redirSlide[d++]; + } while (--e); + if (w == wsize) + { + FLUSH(w); + w = 0; + } + } while (n); + } + } + + + /* restore the globals from the locals */ + G.wp = w; /* restore global window pointer */ + G.bb = b; /* restore global bit buffer */ + G.bk = k; + + + /* done */ + return 0; +} + +#endif /* ASM_INFLATECODES */ + + + +static int inflate_stored(__G) + __GDEF +/* "decompress" an inflated type 0 (stored) block. */ +{ + unsigned n; /* number of bytes in block */ + unsigned w; /* current window position */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + Trace((stderr, "\nstored block")); + b = G.bb; /* initialize bit buffer */ + k = G.bk; + w = G.wp; /* initialize window position */ + + + /* go to byte boundary */ + n = k & 7; + DUMPBITS(n); + + + /* get the length and its complement */ + NEEDBITS(16) + n = ((unsigned)b & 0xffff); + DUMPBITS(16) + NEEDBITS(16) + if (n != (unsigned)((~b) & 0xffff)) + return 1; /* error in compressed data */ + DUMPBITS(16) + + + /* read and output the compressed data */ + while (n--) + { + NEEDBITS(8) + redirSlide[w++] = (uch)b; + if (w == wsize) + { + FLUSH(w); + w = 0; + } + DUMPBITS(8) + } + + + /* restore the globals from the locals */ + G.wp = w; /* restore global window pointer */ + G.bb = b; /* restore global bit buffer */ + G.bk = k; + return 0; +} + + +/* Globals for literal tables (built once) */ +/* Moved to globals.h */ +#if 0 +struct huft *fixed_tl = (struct huft *)NULL; +struct huft *fixed_td; +int fixed_bl, fixed_bd; +#endif + +static int inflate_fixed(__G) + __GDEF +/* decompress an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ +{ + /* if first time, set up tables for fixed blocks */ + Trace((stderr, "\nliteral block")); + if (G.fixed_tl == (struct huft *)NULL) + { + int i; /* temporary variable */ + unsigned l[288]; /* length list for huft_build */ + + /* literal table */ + for (i = 0; i < 144; i++) + l[i] = 8; + for (; i < 256; i++) + l[i] = 9; + for (; i < 280; i++) + l[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + l[i] = 8; + G.fixed_bl = 7; + if ((i = huft_build(__G__ l, 288, 257, cplens, cplext, + &G.fixed_tl, &G.fixed_bl)) != 0) + { + G.fixed_tl = (struct huft *)NULL; + return i; + } + + /* distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + l[i] = 5; + G.fixed_bd = 5; + if ((i = huft_build(__G__ l, 30, 0, cpdist, cpdext, + &G.fixed_td, &G.fixed_bd)) > 1) + { + huft_free(G.fixed_tl); + G.fixed_tl = (struct huft *)NULL; + return i; + } + } + + /* decompress until an end-of-block code */ + return inflate_codes(__G__ G.fixed_tl, G.fixed_td, + G.fixed_bl, G.fixed_bd) != 0; +} + + + +static int inflate_dynamic(__G) + __GDEF +/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ +#ifdef PKZIP_BUG_WORKAROUND + unsigned ll[288+32]; /* literal/length and distance code lengths */ +#else + unsigned ll[286+30]; /* literal/length and distance code lengths */ +#endif + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local bit buffer */ + Trace((stderr, "\ndynamic block")); + b = G.bb; + k = G.bk; + + + /* read in table lengths */ + NEEDBITS(5) + nl = 257 + ((unsigned)b & 0x1f); /* number of literal/length codes */ + DUMPBITS(5) + NEEDBITS(5) + nd = 1 + ((unsigned)b & 0x1f); /* number of distance codes */ + DUMPBITS(5) + NEEDBITS(4) + nb = 4 + ((unsigned)b & 0xf); /* number of bit length codes */ + DUMPBITS(4) +#ifdef PKZIP_BUG_WORKAROUND + if (nl > 288 || nd > 32) +#else + if (nl > 286 || nd > 30) +#endif + return 1; /* bad lengths */ + + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3) + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3) + } + for (; j < 19; j++) + ll[border[j]] = 0; + + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + i = huft_build(__G__ ll, 19, 19, NULL, NULL, &tl, &bl); + if (bl == 0) /* no bit lengths */ + i = 1; + if (i) + { + if (i == 1) + huft_free(tl); + return i; /* incomplete code set */ + } + + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned)i < n) + { + NEEDBITS((unsigned)bl) + j = (td = tl + ((unsigned)b & m))->b; + DUMPBITS(j) + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2) + j = 3 + ((unsigned)b & 3); + DUMPBITS(2) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3) + j = 3 + ((unsigned)b & 7); + DUMPBITS(3) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7) + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + + + /* free decoding table for trees */ + huft_free(tl); + + + /* restore the global bit buffer */ + G.bb = b; + G.bk = k; + + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + i = huft_build(__G__ ll, nl, 257, cplens, cplext, &tl, &bl); + if (bl == 0) /* no literals or lengths */ + i = 1; + if (i) + { + if (i == 1) { + //if (!uO.qflag) + MESSAGE((uch *)"(incomplete l-tree) ", 21L, 1); + huft_free(tl); + } + return i; /* incomplete code set */ + } + bd = dbits; + i = huft_build(__G__ ll + nl, nd, 0, cpdist, cpdext, &td, &bd); + if (bd == 0 && nl > 257) /* lengths but no distances */ + { + //if (!uO.qflag) + MESSAGE((uch *)"(incomplete d-tree) ", 21L, 1); + huft_free(tl); + return 1; + } + if (i == 1) { +#ifdef PKZIP_BUG_WORKAROUND + i = 0; +#else + //if (!uO.qflag) + MESSAGE((uch *)"(incomplete d-tree) ", 21L, 1); + huft_free(td); +#endif + } + if (i) + { + huft_free(tl); + return i; + } + + + /* decompress until an end-of-block code */ + if (inflate_codes(__G__ tl, td, bl, bd)) + return 1; + + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; +} + + + +static int inflate_block(__G__ e) + __GDEF + int *e; /* last block flag */ +/* decompress an inflated block */ +{ + unsigned t; /* block type */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local bit buffer */ + b = G.bb; + k = G.bk; + + + /* read in last block bit */ + NEEDBITS(1) + *e = (int)b & 1; + DUMPBITS(1) + + + /* read in block type */ + NEEDBITS(2) + t = (unsigned)b & 3; + DUMPBITS(2) + + + /* restore the global bit buffer */ + G.bb = b; + G.bk = k; + + + /* inflate that block type */ + if (t == 2) + return inflate_dynamic(__G); + if (t == 0) + return inflate_stored(__G); + if (t == 1) + return inflate_fixed(__G); + + + /* bad block type */ + return 2; +} + + + +int inflate(__G) + __GDEF +/* decompress an inflated entry */ +{ + int e; /* last block flag */ + int r; /* result code */ +//#ifdef DEBUG +// unsigned h = 0; /* maximum struct huft's malloc'ed */ +//#endif + +#if (defined(DLL) && !defined(NO_SLIDE_REDIR)) + if (G.redirect_slide) + wsize = G.redirect_size, redirSlide = G.redirect_buffer; + else + wsize = WSIZE, redirSlide = slide; /* how they're #defined if !DLL */ +#endif + + /* initialize window, bit buffer */ + G.wp = 0; + G.bk = 0; + G.bb = 0; + + + /* decompress until the last block */ + do { +//#ifdef DEBUG +// G.hufts = 0; +//#endif + if ((r = inflate_block(__G__ &e)) != 0) + return r; +//#ifdef DEBUG +// if (G.hufts > h) +// h = G.hufts; +//#endif + } while (!e); + + + /* flush out redirSlide */ + FLUSH(G.wp); + + + /* return success */ + //Trace((stderr, "\n%u bytes in Huffman tables (%d/entry)\n", + // h * sizeof(struct huft), sizeof(struct huft))); + return 0; +} + + + +int inflate_free(__G) + __GDEF +{ + if (G.fixed_tl != (struct huft *)NULL) + { + huft_free(G.fixed_td); + huft_free(G.fixed_tl); + G.fixed_td = G.fixed_tl = (struct huft *)NULL; + } + return 0; +} + +#endif /* ?USE_ZLIB */ + + +/* + * GRR: moved huft_build() and huft_free() down here; used by explode() + * and fUnZip regardless of whether USE_ZLIB defined or not + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +int huft_build( + __GDEF + ZCONST unsigned *b, /* code lengths in bits (all assumed <= BMAX) */ + unsigned n, /* number of codes (assumed <= N_MAX) */ + unsigned s, /* number of simple-valued codes (0..s-1) */ + ZCONST ush *d, /* list of base values for non-simple codes */ + ZCONST ush *e, /* list of extra bits for non-simple codes */ + struct huft **t, /* result: starting table */ + int *m /* maximum lookup bits, returns actual */ + ) +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. + The code with value 256 is special, and the tables are constructed + so that no bits beyond that code are fetched when that code is + decoded. */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned el; /* length of EOB code (value 256) */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int lx[BMAX+1]; /* memory for l[-1..BMAX-1] */ + int *l = lx+1; /* stack of bits per table */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + el = n > 256 ? b[256] : BMAX; /* set length of EOB code, if any */ + memset(c, 0, sizeof(c)); + p = (unsigned *)b; i = n; + do { + c[*p]++; p++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *)NULL; + *m = 0; + return 0; + } + + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned)*m < j) + *m = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned)*m > i) + *m = i; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + memset(v, 0, sizeof(v)); + p = (unsigned *)b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = l[-1] = 0; /* no bits decoded yet */ + u[0] = (struct huft *)NULL; /* just to keep compilers happy */ + q = (struct huft *)NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l[h]) + { + w += l[h++]; /* add bits already decoded */ + + /* compute minimum size table less than or equal to *m bits */ + z = (z = g - w) > (unsigned)*m ? *m : z; /* upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + if ((unsigned)w + j > el && (unsigned)w < el) + j = el - w; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + l[h] = j; /* set table size in stack */ + + /* allocate and link in new table */ + if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) == + (struct huft *)NULL) + { + if (h) + huft_free(u[0]); + return 3; /* not enough memory */ + } +//#ifdef DEBUG +// G.hufts += z + 1; /* track memory usage */ +//#endif + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *)NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l[h-1]; /* bits to dump before this table */ + r.e = (uch)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = (i & ((1 << w) - 1)) >> (w - l[h-1]); + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = (ush)*p++; /* simple code is just the value */ + } + else + { + r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + w -= l[--h]; /* don't need to update q */ + } + } + + + /* return actual size of base table */ + *m = l[0]; + + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + + +int huft_free (struct huft *t) + /* table to free */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (struct huft *)NULL) + { + q = (--p)->v.t; + free((zvoid *)p); + p = q; + } + return 0; +} + + +// Main public function. Decompresses raw data compressed using the DEFLATE algorithm (RFC 1951 - e.g. zlib, gzip). +// Returns 0 if decompression fails or, if successful, returns the size of the decompressed data. +int DecompressDeflatedData (char *out, char *in, int inLength) +{ + G.outbufptr = out; + G.inptr = in; + G.incnt = inLength; + G.outCounter = 0; + + if (inflate(__G) != 0) + { + // Error decompressing + return 0; + } + return G.outCounter; +} + diff --git a/Common/Inflate.h b/Common/Inflate.h new file mode 100644 index 0000000..c2810c8 --- /dev/null +++ b/Common/Inflate.h @@ -0,0 +1,51 @@ +#include <stdio.h> +#include <windows.h> + +#define WSIZE 0x8000 // Window size +#define ZCONST const +#define OF(p) p + +typedef unsigned long ulg; +typedef unsigned char uch; +typedef unsigned short ush; +typedef void zvoid; + +typedef struct huft +{ + uch b, e; + union + { + ush n; + struct huft *t; + }v; +}; + +typedef struct +{ + uch *inptr, *outbufptr; + int incnt; + int outCounter; + + struct huft *fixed_tl; + struct huft *fixed_td; + int fixed_bl, fixed_bd; + + unsigned bk, wp; + ulg bb; +} G_struct; + +#define __GPRO void +#define __GPRO__ +#define __G +#define __G__ +#define __GDEF + + +#define FLUSH(cnt) { memcpy (G.outbufptr, redirSlide, cnt); G.outbufptr += cnt; G.outCounter += cnt; } +#define NEXTBYTE (((G.incnt--) >= 0) ? (*G.inptr++) : EOF) + + +int huft_free(struct huft *t); +int huft_build(__GDEF ZCONST unsigned *b, unsigned n, unsigned s, ZCONST ush *d, ZCONST ush *e, struct huft **t, int *m); + +int DecompressDeflatedData (char *out, char *in, int inLength); diff --git a/Common/Keyfiles.c b/Common/Keyfiles.c new file mode 100644 index 0000000..f11ba41 --- /dev/null +++ b/Common/Keyfiles.c @@ -0,0 +1,685 @@ +/* + 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 <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "Tcdefs.h" +#include "Keyfiles.h" +#include "Crc.h" + +#include <io.h> +#include "Dlgcode.h" +#include "Language.h" +#include "SecurityToken.h" +#include "Common/resource.h" +#include "Platform/Finally.h" +#include "Platform/ForEach.h" + +using namespace TrueCrypt; + +#define stat _stat +#define S_IFDIR _S_IFDIR +#define snprintf _snprintf + + +BOOL HiddenFilesPresentInKeyfilePath = FALSE; + + +KeyFile *KeyFileAdd (KeyFile *firstKeyFile, KeyFile *keyFile) +{ + KeyFile *kf = firstKeyFile; + + if (firstKeyFile != NULL) + { + while (kf->Next) + kf = kf->Next; + + kf->Next = keyFile; + } + else + firstKeyFile = keyFile; + + keyFile->Next = NULL; + + return firstKeyFile; +} + + +// Returns first keyfile, NULL if last keyfile was removed +static KeyFile *KeyFileRemove (KeyFile *firstKeyFile, KeyFile *keyFile) +{ + KeyFile *prevkf = NULL, *kf = firstKeyFile; + + if (firstKeyFile == NULL) return NULL; + do + { + if (kf == keyFile) + { + if (prevkf == NULL) + firstKeyFile = kf->Next; + else + prevkf->Next = kf->Next; + + burn (keyFile, sizeof(*keyFile)); // wipe + free (keyFile); + break; + } + prevkf = kf; + } + while (kf = kf->Next); + + return firstKeyFile; +} + + +void KeyFileRemoveAll (KeyFile **firstKeyFile) +{ + KeyFile *kf = *firstKeyFile; + while (kf != NULL) + { + KeyFile *d = kf; + kf = kf->Next; + burn (d, sizeof(*d)); // wipe + free (d); + } + + *firstKeyFile = NULL; +} + + +KeyFile *KeyFileClone (KeyFile *keyFile) +{ + KeyFile *clone; + + if (keyFile == NULL) return NULL; + + clone = (KeyFile *) malloc (sizeof (KeyFile)); + strcpy (clone->FileName, keyFile->FileName); + clone->Next = NULL; + return clone; +} + + +KeyFile *KeyFileCloneAll (KeyFile *firstKeyFile) +{ + KeyFile *cloneFirstKeyFile = KeyFileClone (firstKeyFile); + KeyFile *kf; + + if (firstKeyFile == NULL) return NULL; + kf = firstKeyFile->Next; + while (kf != NULL) + { + KeyFileAdd (cloneFirstKeyFile, KeyFileClone (kf)); + kf = kf->Next; + } + + return cloneFirstKeyFile; +} + + +static BOOL KeyFileProcess (unsigned __int8 *keyPool, KeyFile *keyFile) +{ + FILE *f; + unsigned __int8 buffer[64 * 1024]; + unsigned __int32 crc = 0xffffffff; + int writePos = 0; + size_t bytesRead, totalRead = 0; + int status = TRUE; + + HANDLE src; + FILETIME ftCreationTime; + FILETIME ftLastWriteTime; + FILETIME ftLastAccessTime; + + BOOL bTimeStampValid = FALSE; + + /* Remember the last access time of the keyfile. It will be preserved in order to prevent + an adversary from determining which file may have been used as keyfile. */ + src = CreateFile (keyFile->FileName, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + + if (src != INVALID_HANDLE_VALUE) + { + if (GetFileTime ((HANDLE) src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime)) + bTimeStampValid = TRUE; + } + + finally_do_arg (HANDLE, src, + { + if (finally_arg != INVALID_HANDLE_VALUE) + CloseHandle (finally_arg); + }); + + f = fopen (keyFile->FileName, "rb"); + if (f == NULL) return FALSE; + + while ((bytesRead = fread (buffer, 1, sizeof (buffer), f)) > 0) + { + size_t i; + + if (ferror (f)) + { + status = FALSE; + goto close; + } + + for (i = 0; i < bytesRead; i++) + { + crc = UPDC32 (buffer[i], crc); + + keyPool[writePos++] += (unsigned __int8) (crc >> 24); + keyPool[writePos++] += (unsigned __int8) (crc >> 16); + keyPool[writePos++] += (unsigned __int8) (crc >> 8); + keyPool[writePos++] += (unsigned __int8) crc; + + if (writePos >= KEYFILE_POOL_SIZE) + writePos = 0; + + if (++totalRead >= KEYFILE_MAX_READ_LEN) + goto close; + } + } + + if (ferror (f)) + { + status = FALSE; + } + else if (totalRead == 0) + { + status = FALSE; + SetLastError (ERROR_HANDLE_EOF); + } + +close: + DWORD err = GetLastError(); + fclose (f); + + if (bTimeStampValid && !IsFileOnReadOnlyFilesystem (keyFile->FileName)) + { + // Restore the keyfile timestamp + SetFileTime (src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime); + } + + SetLastError (err); + return status; +} + + +BOOL KeyFilesApply (Password *password, KeyFile *firstKeyFile) +{ + BOOL status = TRUE; + KeyFile kfSubStruct; + KeyFile *kf; + KeyFile *kfSub = &kfSubStruct; + static unsigned __int8 keyPool [KEYFILE_POOL_SIZE]; + size_t i; + struct stat statStruct; + char searchPath [TC_MAX_PATH*2]; + struct _finddata_t fBuf; + intptr_t searchHandle; + + HiddenFilesPresentInKeyfilePath = FALSE; + + if (firstKeyFile == NULL) return TRUE; + + VirtualLock (keyPool, sizeof (keyPool)); + memset (keyPool, 0, sizeof (keyPool)); + + for (kf = firstKeyFile; kf != NULL; kf = kf->Next) + { + // Determine whether it's a security token path + try + { + if (SecurityToken::IsKeyfilePathValid (SingleStringToWide (kf->FileName))) + { + // Apply security token keyfile + vector <byte> keyfileData; + SecurityToken::GetKeyfileData (SecurityTokenKeyfile (SingleStringToWide (kf->FileName)), keyfileData); + + if (keyfileData.empty()) + { + SetLastError (ERROR_HANDLE_EOF); + handleWin32Error (MainDlg); + Error ("ERR_PROCESS_KEYFILE"); + status = FALSE; + continue; + } + + unsigned __int32 crc = 0xffffffff; + int writePos = 0; + size_t totalRead = 0; + + for (size_t i = 0; i < keyfileData.size(); i++) + { + crc = UPDC32 (keyfileData[i], crc); + + keyPool[writePos++] += (unsigned __int8) (crc >> 24); + keyPool[writePos++] += (unsigned __int8) (crc >> 16); + keyPool[writePos++] += (unsigned __int8) (crc >> 8); + keyPool[writePos++] += (unsigned __int8) crc; + + if (writePos >= KEYFILE_POOL_SIZE) + writePos = 0; + + if (++totalRead >= KEYFILE_MAX_READ_LEN) + break; + } + + burn (&keyfileData.front(), keyfileData.size()); + continue; + } + } + catch (Exception &e) + { + e.Show (NULL); + return FALSE; + } + + // Determine whether it's a path or a file + if (stat (kf->FileName, &statStruct) != 0) + { + handleWin32Error (MainDlg); + Error ("ERR_PROCESS_KEYFILE"); + status = FALSE; + continue; + } + + if (statStruct.st_mode & S_IFDIR) // If it's a directory + { + /* Find and process all keyfiles in the directory */ + int keyfileCount = 0; + + snprintf (searchPath, sizeof (searchPath), "%s\\*.*", kf->FileName); + if ((searchHandle = _findfirst (searchPath, &fBuf)) == -1) + { + handleWin32Error (MainDlg); + Error ("ERR_PROCESS_KEYFILE_PATH"); + status = FALSE; + continue; + } + + do + { + WIN32_FILE_ATTRIBUTE_DATA fileAttributes; + + snprintf (kfSub->FileName, sizeof(kfSub->FileName), "%s%c%s", kf->FileName, + '\\', + fBuf.name + ); + + // Determine whether it's a path or a file + if (stat (kfSub->FileName, &statStruct) != 0) + { + handleWin32Error (MainDlg); + Error ("ERR_PROCESS_KEYFILE"); + status = FALSE; + continue; + } + else if (statStruct.st_mode & S_IFDIR) // If it's a directory + { + // Prevent recursive folder scanning + continue; + } + + // Skip hidden files + if (GetFileAttributesEx (kfSub->FileName, GetFileExInfoStandard, &fileAttributes) + && (fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0) + { + HiddenFilesPresentInKeyfilePath = TRUE; + continue; + } + + ++keyfileCount; + + // Apply keyfile to the pool + if (!KeyFileProcess (keyPool, kfSub)) + { + handleWin32Error (MainDlg); + Error ("ERR_PROCESS_KEYFILE"); + status = FALSE; + } + + } while (_findnext (searchHandle, &fBuf) != -1); + _findclose (searchHandle); + + burn (&kfSubStruct, sizeof (kfSubStruct)); + + if (keyfileCount == 0) + { + ErrorDirect ((wstring (GetString ("ERR_KEYFILE_PATH_EMPTY")) + L"\n\n" + SingleStringToWide (kf->FileName)).c_str()); + status = FALSE; + } + } + // Apply keyfile to the pool + else if (!KeyFileProcess (keyPool, kf)) + { + handleWin32Error (MainDlg); + Error ("ERR_PROCESS_KEYFILE"); + status = FALSE; + } + } + + /* Mix the keyfile pool contents into the password */ + + for (i = 0; i < sizeof (keyPool); i++) + { + if (i < password->Length) + password->Text[i] += keyPool[i]; + else + password->Text[i] = keyPool[i]; + } + + if (password->Length < (int)sizeof (keyPool)) + password->Length = sizeof (keyPool); + + burn (keyPool, sizeof (keyPool)); + + return status; +} + + +static void LoadKeyList (HWND hwndDlg, KeyFile *firstKeyFile) +{ + KeyFile *kf; + LVITEM LvItem; + int line = 0; + HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST); + + ListView_DeleteAllItems (hList); + EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE), FALSE); + EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVEALL), firstKeyFile != NULL); + SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, firstKeyFile != NULL); + + for (kf = firstKeyFile; kf != NULL; kf = kf->Next) + { + memset (&LvItem,0,sizeof(LvItem)); + LvItem.mask = LVIF_TEXT|LVIF_PARAM; + LvItem.iItem = line++; + LvItem.iSubItem = 0; + LvItem.pszText = kf->FileName; + LvItem.lParam = (LPARAM) kf; + SendMessage (hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem); + } +} + +#if KEYFILE_POOL_SIZE % 4 != 0 +#error KEYFILE_POOL_SIZE must be a multiple of 4 +#endif + +BOOL CALLBACK KeyFilesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static KeyFilesDlgParam *param; + static KeyFilesDlgParam origParam; + + WORD lw = LOWORD (wParam); + + switch (msg) + { + case WM_INITDIALOG: + { + LVCOLUMNW LvCol; + HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST); + + param = (KeyFilesDlgParam *) lParam; + origParam = *(KeyFilesDlgParam *) lParam; + + param->FirstKeyFile = KeyFileCloneAll (param->FirstKeyFile); + + LocalizeDialog (hwndDlg, "IDD_KEYFILES"); + DragAcceptFiles (hwndDlg, TRUE); + + SendMessageW (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0, + LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP + ); + + memset (&LvCol,0,sizeof(LvCol)); + LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT; + LvCol.pszText = GetString ("KEYFILE"); + LvCol.cx = CompensateXDPI (374); + LvCol.fmt = LVCFMT_LEFT; + SendMessageW (hList, LVM_INSERTCOLUMNW, 0, (LPARAM)&LvCol); + + LoadKeyList (hwndDlg, param->FirstKeyFile); + SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, param->EnableKeyFiles); + + SetWindowTextW(GetDlgItem(hwndDlg, IDT_KEYFILES_NOTE), GetString ("KEYFILES_NOTE")); + + ToHyperlink (hwndDlg, IDC_LINK_KEYFILES_INFO); + } + return 1; + + case WM_COMMAND: + + if (lw == IDC_KEYADD) + { + KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile)); + if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, bHistory)) + { + do + { + param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); + LoadKeyList (hwndDlg, param->FirstKeyFile); + + kf = (KeyFile *) malloc (sizeof (KeyFile)); + } while (SelectMultipleFilesNext (kf->FileName)); + } + + free (kf); + return 1; + } + + if (lw == IDC_ADD_KEYFILE_PATH) + { + KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile)); + + if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName)) + { + param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); + LoadKeyList (hwndDlg, param->FirstKeyFile); + } + else + { + free (kf); + } + return 1; + } + + if (lw == IDC_TOKEN_FILES_ADD) + { + list <SecurityTokenKeyfilePath> selectedTokenKeyfiles; + if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK) + { + foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles) + { + KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile)); + strcpy_s (kf->FileName, sizeof (kf->FileName), WideToSingleString (keyPath).c_str()); + + param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); + LoadKeyList (hwndDlg, param->FirstKeyFile); + } + } + + return 1; + } + + if (lw == IDC_KEYREMOVE) + { + HWND list = GetDlgItem (hwndDlg, IDC_KEYLIST); + LVITEM LvItem; + memset (&LvItem, 0, sizeof(LvItem)); + LvItem.mask = LVIF_PARAM; + LvItem.iItem = -1; + + while (-1 != (LvItem.iItem = ListView_GetNextItem (list, LvItem.iItem, LVIS_SELECTED))) + { + ListView_GetItem (list, &LvItem); + param->FirstKeyFile = KeyFileRemove (param->FirstKeyFile, (KeyFile *) LvItem.lParam); + } + + LoadKeyList (hwndDlg, param->FirstKeyFile); + return 1; + } + + if (lw == IDC_KEYREMOVEALL) + { + KeyFileRemoveAll (¶m->FirstKeyFile); + LoadKeyList (hwndDlg, NULL); + return 1; + } + + if (lw == IDC_GENERATE_KEYFILE) + { + DialogBoxParamW (hInst, + MAKEINTRESOURCEW (IDD_KEYFILE_GENERATOR), hwndDlg, + (DLGPROC) KeyfileGeneratorDlgProc, (LPARAM) 0); + return 1; + } + + if (lw == IDC_LINK_KEYFILES_INFO) + { + Applink ("keyfiles", TRUE, ""); + } + + if (lw == IDOK) + { + param->EnableKeyFiles = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_ENABLE)); + EndDialog (hwndDlg, IDOK); + return 1; + } + + if (lw == IDCANCEL) + { + KeyFileRemoveAll (¶m->FirstKeyFile); + *param = origParam; + + EndDialog (hwndDlg, IDCLOSE); + return 1; + } + + case WM_DROPFILES: + { + HDROP hdrop = (HDROP) wParam; + + int i = 0, count = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0); + + while (count-- > 0) + { + KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile)); + DragQueryFile (hdrop, i++, kf->FileName, sizeof (kf->FileName)); + param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); + LoadKeyList (hwndDlg, param->FirstKeyFile); + } + + DragFinish (hdrop); + } + return 1; + + case WM_NOTIFY: + if (((LPNMHDR) lParam)->code == LVN_ITEMCHANGED) + { + EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE), + ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_KEYLIST), -1, LVIS_SELECTED) != -1); + return 1; + } + break; + + case WM_CLOSE: + KeyFileRemoveAll (¶m->FirstKeyFile); + *param = origParam; + + EndDialog (hwndDlg, IDCLOSE); + return 1; + + break; + + } + + return 0; +} + + +#define IDM_KEYFILES_POPUP_ADD_FILES 9001 +#define IDM_KEYFILES_POPUP_ADD_DIR 9002 +#define IDM_KEYFILES_POPUP_ADD_TOKEN_FILES 9003 + +BOOL KeyfilesPopupMenu (HWND hwndDlg, POINT popupPosition, KeyFilesDlgParam *param) +{ + HMENU popup = CreatePopupMenu (); + int sel; + BOOL status = FALSE; + + AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_FILES, GetString ("IDC_KEYADD")); + AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_DIR, GetString ("IDC_ADD_KEYFILE_PATH")); + AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_TOKEN_FILES, GetString ("IDC_TOKEN_FILES_ADD")); + + sel = TrackPopupMenu (popup, TPM_RETURNCMD | TPM_LEFTBUTTON, popupPosition.x, popupPosition.y, 0, hwndDlg, NULL); + + switch (sel) + { + case IDM_KEYFILES_POPUP_ADD_FILES: + { + KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile)); + if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, bHistory)) + { + do + { + param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); + kf = (KeyFile *) malloc (sizeof (KeyFile)); + } while (SelectMultipleFilesNext (kf->FileName)); + + param->EnableKeyFiles = TRUE; + status = TRUE; + } + + free (kf); + } + break; + + case IDM_KEYFILES_POPUP_ADD_DIR: + { + KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile)); + + if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName)) + { + param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); + param->EnableKeyFiles = TRUE; + status = TRUE; + } + else + { + free (kf); + } + } + break; + + case IDM_KEYFILES_POPUP_ADD_TOKEN_FILES: + { + list <SecurityTokenKeyfilePath> selectedTokenKeyfiles; + if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK) + { + foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles) + { + KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile)); + strcpy_s (kf->FileName, sizeof (kf->FileName), WideToSingleString (keyPath).c_str()); + + param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); + param->EnableKeyFiles = TRUE; + status = TRUE; + } + } + } + break; + } + + DestroyMenu (popup); + return status; +} diff --git a/Common/Keyfiles.h b/Common/Keyfiles.h new file mode 100644 index 0000000..c19a846 --- /dev/null +++ b/Common/Keyfiles.h @@ -0,0 +1,48 @@ +/* + Copyright (c) 2005 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 KEYFILES_H +#define KEYFILES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "Common.h" + +#define KEYFILE_POOL_SIZE 64 +#define KEYFILE_MAX_READ_LEN (1024*1024) + +typedef struct KeyFileStruct +{ + char FileName[MAX_PATH]; + struct KeyFileStruct *Next; +} KeyFile; + +typedef struct +{ + BOOL EnableKeyFiles; + KeyFile *FirstKeyFile; +} KeyFilesDlgParam; + +KeyFile *KeyFileAdd (KeyFile *firstKeyFile, KeyFile *keyFile); +void KeyFileRemoveAll (KeyFile **firstKeyFile); +KeyFile *KeyFileClone (KeyFile *keyFile); +KeyFile *KeyFileCloneAll (KeyFile *firstKeyFile); +BOOL KeyFilesApply (Password *password, KeyFile *firstKeyFile); + +BOOL CALLBACK KeyFilesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +BOOL KeyfilesPopupMenu (HWND hwndDlg, POINT popupPosition, KeyFilesDlgParam *dialogParam); + +extern BOOL HiddenFilesPresentInKeyfilePath; + +#ifdef __cplusplus +} +#endif + +#endif /* #ifndef KEYFILES_H */ diff --git a/Common/Language.c b/Common/Language.c new file mode 100644 index 0000000..e7737ca --- /dev/null +++ b/Common/Language.c @@ -0,0 +1,515 @@ +/* + 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 "Language.h" +#include "Dlgcode.h" +#include "Dictionary.h" +#include "Tcdefs.h" +#include "Xml.h" + +#include "../Common/Resource.h" + +#ifdef TCMOUNT +#include "../Mount/Resource.h" +#endif + +#ifdef VOLFORMAT +#include "../Format/Resource.h" +#endif + +#ifdef SETUP +#include "../Setup/Resource.h" +#endif + +BOOL LocalizationActive; +int LocalizationSerialNo; + +wchar_t UnknownString[1024]; +static char *LanguageFileBuffer; +static HANDLE LanguageFileFindHandle = INVALID_HANDLE_VALUE; +static char PreferredLangId[6]; +static char *LanguageResource; +static char *HeaderResource[2]; +static char ActiveLangPackVersion[6]; + +static char *MapFirstLanguageFile () +{ + if (LanguageFileFindHandle != INVALID_HANDLE_VALUE) + { + FindClose (LanguageFileFindHandle); + LanguageFileFindHandle = INVALID_HANDLE_VALUE; + } + + if (LanguageResource == NULL) + { + DWORD size; + LanguageResource = MapResource ("Xml", IDR_LANGUAGE, &size); + LanguageResource[size - 1] = 0; + } + + return LanguageResource; +} + + +static char *MapNextLanguageFile () +{ + wchar_t f[TC_MAX_PATH*2], *t; + WIN32_FIND_DATAW find; + HANDLE file; + DWORD read; + + if (LanguageFileFindHandle == INVALID_HANDLE_VALUE) + { + GetModuleFileNameW (NULL, f, sizeof (f) / sizeof (f[0])); + t = wcsrchr (f, L'\\'); + if (t == NULL) return NULL; + + wcscpy (t, L"\\Language*.xml"); + + LanguageFileFindHandle = FindFirstFileW (f, &find); + } + else if (!FindNextFileW (LanguageFileFindHandle, &find)) + { + FindClose (LanguageFileFindHandle); + LanguageFileFindHandle = INVALID_HANDLE_VALUE; + return NULL; + } + + if (find.nFileSizeHigh != 0) return NULL; + + if (LanguageFileBuffer != NULL) free (LanguageFileBuffer); + LanguageFileBuffer = malloc(find.nFileSizeLow); + if (LanguageFileBuffer == NULL) return NULL; + + GetModuleFileNameW (NULL, f, sizeof (f) / sizeof(f[0])); + t = wcsrchr (f, L'\\'); + wcscpy (t + 1, find.cFileName); + + file = CreateFileW (f, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + if (file == INVALID_HANDLE_VALUE) return NULL; + + ReadFile (file, LanguageFileBuffer, find.nFileSizeLow, &read, NULL); + CloseHandle (file); + if (read != find.nFileSizeLow) return NULL; + + return LanguageFileBuffer; +} + + +BOOL LoadLanguageFile () +{ + DWORD size; + BYTE *res; + char *xml, *header; + char langId[6] = "en", attr[32768], key[128]; + BOOL defaultLangParsed = FALSE, langFound = FALSE; + WCHAR wattr[32768]; + int i, intKey, len; + + char *xmlElements[] = {"control", "string", 0}; + +#ifdef TCMOUNT + int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_MOUNT_RSRC_HEADER, 0 }; +#endif + +#ifdef VOLFORMAT + int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_FORMAT_RSRC_HEADER, 0 }; +#endif + +#ifdef SETUP + int headers[] = { IDR_COMMON_RSRC_HEADER, IDR_SETUP_RSRC_HEADER, 0 }; +#endif + + LocalizationActive = FALSE; + ActiveLangPackVersion[0] = 0; + ClearDictionaryPool (); + + if (PreferredLangId[0] != 0) + strcpy (langId, PreferredLangId); + + // Parse all available language files until preferred language is found + for (res = MapFirstLanguageFile (); res != NULL; res = MapNextLanguageFile ()) + { + xml = (char *) res; + xml = XmlFindElement (xml, "localization"); + if (!xml) + continue; + + // Required TrueCrypt version + XmlGetAttributeText (xml, "prog-version", attr, sizeof (attr)); + + // Check version of external language file + if (defaultLangParsed && strcmp (attr, VERSION_STRING) && strcmp (attr, "DEBUG")) + { + wchar_t m[2048]; + swprintf (m, L"The installed language pack is incompatible with this version of TrueCrypt (the language pack is for TrueCrypt %hs). A newer version may be available at www.truecrypt.org.\n\nTo prevent this message from being displayed, do any of the following:\n\n- Select 'Settings' > 'Language'; then select 'English' and click 'OK'.\n\n- Remove or replace the language pack with a compatible version (the language pack may reside e.g. in 'C:\\Program Files\\TrueCrypt' or '%%LOCALAPPDATA%%\\VirtualStore\\Program Files\\TrueCrypt', etc.)", attr); + MessageBoxW (NULL, m, L"TrueCrypt", MB_ICONERROR); + continue; + } + + // Search language id in language file + if (defaultLangParsed) + { + while (xml = XmlFindElement (xml, "language")) + { + XmlGetAttributeText (xml, "langid", attr, sizeof (attr)); + if (strcmp (attr, langId) == 0) + { + XmlGetAttributeText (xml++, "version", ActiveLangPackVersion, sizeof (ActiveLangPackVersion)); + langFound = TRUE; + break; + } + xml++; + } + + if (!langFound) continue; + } + + // Create font dictionary + xml = (char *) res; + while (xml = XmlFindElement (xml, "font")) + { + XmlGetAttributeText (xml, "lang", attr, sizeof (attr)); + if (!defaultLangParsed + || strcmp (attr, langId) == 0) + { + Font font; + memset (&font, 0, sizeof (font)); + + XmlGetAttributeText (xml, "face", attr, sizeof (attr)); + + len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0])); + font.FaceName = AddPoolData ((void *) wattr, len * 2); + + XmlGetAttributeText (xml, "size", attr, sizeof (attr)); + sscanf (attr, "%d", &font.Size); + + strcpy (attr, "font_"); + XmlGetAttributeText (xml, "class", attr + 5, sizeof (attr) - 5); + AddDictionaryEntry ( + AddPoolData ((void *) attr, strlen (attr) + 1), 0, + AddPoolData ((void *) &font, sizeof(font))); + } + + xml++; + } + + // Create string and control dictionaries + for (i = 0; xmlElements[i] != 0; i++) + { + xml = (char *) res; + while (xml = XmlFindElement (xml, xmlElements[i])) + { + void *key; + void *text; + + XmlGetAttributeText (xml, "lang", attr, sizeof (attr)); + if (!defaultLangParsed + || strcmp (attr, langId) == 0) + { + if (XmlGetAttributeText (xml, "key", attr, sizeof (attr))) + { + key = AddPoolData (attr, strlen (attr) + 1); + if (key == NULL) return FALSE; + + XmlGetNodeText (xml, attr, sizeof (attr)); + + // Parse \ escape sequences + { + char *in = attr, *out = attr; + while (*in) + { + if (*in == '\\') + { + in++; + switch (*in++) + { + case '\\': *out++ = '\\'; break; + case 't': *out++ = '\t'; break; + case 'n': *out++ = 13; *out++ = 10; break; + default: + MessageBox (0, key, "TrueCrypt: Unknown '\\' escape sequence in string", MB_ICONERROR); + return FALSE; + } + } + else + *out++ = *in++; + } + *out = 0; + } + + // UTF8 => wide char + len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0])); + if (len == 0 || len == ERROR_NO_UNICODE_TRANSLATION) + { + MessageBox (0, key, "TrueCrypt: Error while decoding UTF-8 string", MB_ICONERROR); + return FALSE; + } + + // Add to dictionary + text = AddPoolData ((void *) wattr, len * 2); + if (text == NULL) return FALSE; + + AddDictionaryEntry ((char *) key, 0, text); + } + } + + xml++; + } + } + + if (langFound) + break; + + if (!defaultLangParsed) + { + defaultLangParsed = TRUE; + if (langId[0] == 0 || strcmp (langId, "en") == 0) + break; + } + } + + LocalizationActive = langFound && strcmp (langId, "en") != 0; + LocalizationSerialNo++; + + // Create control ID dictionary + + // Default controls + AddDictionaryEntry (NULL, 1, GetString ("IDOK")); + AddDictionaryEntry (NULL, 2, GetString ("IDCANCEL")); + AddDictionaryEntry (NULL, 8, GetString ("IDCLOSE")); + AddDictionaryEntry (NULL, 9, GetString ("IDHELP")); + + for (i = 0; headers[i] != 0; i++) + { + if (HeaderResource[i] == NULL) + { + HeaderResource[i] = MapResource ("Header", headers[i], &size); + *(HeaderResource[i] + size - 1) = 0; + } + + header = HeaderResource[i]; + if (header == NULL) return FALSE; + + do + { + if (sscanf (header, "#define %s %d", key, &intKey) == 2) + { + WCHAR *str = GetString (key); + + if (str != UnknownString) + AddDictionaryEntry (NULL, intKey, str); + } + + } while ((header = strchr (header, '\n') + 1) != (char *) 1); + } + + return TRUE; +} + + +// lParam = 1: auto mode +BOOL CALLBACK LanguageDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WORD lw = LOWORD (wParam); + WORD hw = HIWORD (wParam); + + switch (msg) + { + case WM_INITDIALOG: + { + char *xml; + char attr[2048], lastLangId[10]; + WCHAR wattr[2048]; + int len; + int langCount = 0; + BOOL defaultLangFound = FALSE; + + LocalizeDialog (hwndDlg, "IDD_LANGUAGE"); + ToHyperlink (hwndDlg, IDC_GET_LANG_PACKS); + + for (xml = MapFirstLanguageFile (); xml != NULL; xml = MapNextLanguageFile ()) + { + while (xml = XmlFindElement (xml, "language")) + { + XmlGetAttributeText (xml, "name", attr, sizeof (attr)); + len = MultiByteToWideChar (CP_UTF8, 0, attr, -1, wattr, sizeof (wattr) / sizeof(wattr[0])); + + if (len != 0 && len != ERROR_NO_UNICODE_TRANSLATION + && (!defaultLangFound || wcscmp (wattr, L"English") != 0)) + { + int i = SendDlgItemMessageW (hwndDlg, IDC_LANGLIST, LB_ADDSTRING, 0, (LPARAM)wattr); + if (i >= 0) + { + int id; + + // Encode language id in LPARAM + XmlGetAttributeText (xml, "langid", attr, sizeof (attr)); + switch (strlen (attr)) + { + case 2: id = attr[0] | attr[1] << 8; break; + case 5: id = attr[0] | attr[1] << 8 | attr[3] << 16 | attr[4] << 24; break; + default: continue; + } + + if (!defaultLangFound) + defaultLangFound = TRUE; + + SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_SETITEMDATA, i, (LPARAM) id); + + if (strcmp (attr, PreferredLangId) == 0) + { + char credits [10000]; + WCHAR wcredits [10000]; + WCHAR wversion [20]; + wchar_t szVers [200]; + int nLen; + + SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_SETCURSEL, i, 0); + + // Language pack version + if (!ActiveLangPackVersion[0] || memcmp (ActiveLangPackVersion, "0.0.0", 5) == 0) + { + swprintf (szVers, GetString("LANG_PACK_VERSION"), L"--"); + } + else + { + nLen = MultiByteToWideChar (CP_UTF8, 0, ActiveLangPackVersion, -1, wversion, sizeof (wversion) / sizeof(wversion[0])); + if (nLen != 0 && nLen != ERROR_NO_UNICODE_TRANSLATION) + swprintf (szVers, GetString("LANG_PACK_VERSION"), wversion); + } + SetWindowTextW (GetDlgItem (hwndDlg, IDC_LANGPACK_VERSION), szVers); + + // Translator credits + XmlGetAttributeText (xml, "translators", credits, sizeof (credits)); + nLen = MultiByteToWideChar (CP_UTF8, 0, credits, -1, wcredits, sizeof (wcredits) / sizeof(wcredits[0])); + if (nLen != 0 && nLen != ERROR_NO_UNICODE_TRANSLATION) + { + SetWindowTextW (GetDlgItem (hwndDlg, IDC_LANGPACK_CREDITS), wcredits); + } + } + + strcpy (lastLangId, attr); + langCount++; + } + } + + xml++; + } + } + + if (lParam == 1) + { + // Auto mode + if (langCount < 2) + EndDialog (hwndDlg, IDCANCEL); + + if (langCount == 2) + strcpy (PreferredLangId, lastLangId); + + EndDialog (hwndDlg, IDOK); + } + + return 1; + } + + case WM_COMMAND: + + if (lw == IDOK || hw == LBN_DBLCLK) + { + int i = SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETCURSEL, 0, 0); + + if (i >= 0) + { + int id = SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETITEMDATA, i, 0); + + if (id != LB_ERR) + { + char l[6]; + + // Decode language id from LPARAM + l[0] = (char) id; + l[1] = (char) (id >> 8); + l[2] = 0; + + if ((id & 0xffff0000) != 0) + { + l[2] = '-'; + l[3] = (char) (id >> 16); + l[4] = id >> 24; + l[5] = 0; + } + + if (SendDlgItemMessage (hwndDlg, IDC_LANGLIST, LB_GETCOUNT, 0, 0) > 1) + strcpy (PreferredLangId, l); + } + } + + EndDialog (hwndDlg, IDOK); + return 1; + } + + if (lw == IDCANCEL) + { + EndDialog (hwndDlg, lw); + return 1; + } + + if (lw == IDC_GET_LANG_PACKS) + { + char tmpstr [256]; + + if (strlen (ActiveLangPackVersion) > 0 && strlen (GetPreferredLangId()) > 0) + sprintf (tmpstr, "&langpackversion=%s&lang=%s", ActiveLangPackVersion, GetPreferredLangId()); + else + tmpstr[0] = 0; + + Applink ("localizations", TRUE, tmpstr); + + return 1; + } + return 0; + } + + return 0; +} + + +char *GetPreferredLangId () +{ + return PreferredLangId; +} + + +void SetPreferredLangId (char *langId) +{ + strncpy (PreferredLangId, langId, 5); +} + + +char *GetActiveLangPackVersion () +{ + return ActiveLangPackVersion; +} + + +wchar_t *GetString (const char *stringId) +{ + WCHAR *str = (WCHAR *) GetDictionaryValue (stringId); + if (str != NULL) return str; + + wsprintfW (UnknownString, UNKNOWN_STRING_ID L"%hs" UNKNOWN_STRING_ID, stringId); + return UnknownString; +} + + +Font *GetFont (char *fontType) +{ + return (Font *) GetDictionaryValue (fontType); + +} diff --git a/Common/Language.h b/Common/Language.h new file mode 100644 index 0000000..a87e513 --- /dev/null +++ b/Common/Language.h @@ -0,0 +1,37 @@ +/* + Copyright (c) 2008 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include <windows.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define UNKNOWN_STRING_ID L"[?]" + +extern BOOL LocalizationActive; +extern int LocalizationSerialNo; +extern wchar_t UnknownString[1024]; + +typedef struct +{ + wchar_t *FaceName; + int Size; +} Font; + +BOOL CALLBACK LanguageDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); +wchar_t *GetString (const char *stringId); +Font *GetFont (char *fontType); +BOOL LoadLanguageFile (); +char *GetPreferredLangId (); +void SetPreferredLangId (char *langId); +char *GetActiveLangPackVersion (); + +#ifdef __cplusplus +} +#endif diff --git a/Common/Language.xml b/Common/Language.xml new file mode 100644 index 0000000..f6394e1 --- /dev/null +++ b/Common/Language.xml @@ -0,0 +1,1341 @@ +<?xml version="1.0" encoding="utf-8"?> +<TrueCrypt> + <localization prog-version="7.1a"> + <!-- Languages --> + <language langid="en" name="English" en-name="English" version="0.0.0" translators="" /> + <!-- Fonts --> + <font lang="en" class="normal" size="11" face="default" /> + <font lang="en" class="bold" size="13" face="Arial" /> + <font lang="en" class="fixed" size="12" face="Lucida Console" /> + <font lang="en" class="title" size="21" face="Times New Roman" /> + <!-- Controls --> + <control lang="en" key="IDCANCEL">Cancel</control> + <control lang="en" key="IDC_ALL_USERS">Install &for all users</control> + <control lang="en" key="IDC_BROWSE">Bro&wse...</control> + <control lang="en" key="IDC_DESKTOP_ICON">Add TrueCrypt icon to &desktop</control> + <control lang="en" key="IDC_DONATE">Donate now...</control> + <control lang="en" key="IDC_FILE_TYPE">Associate the .tc file &extension with TrueCrypt</control> + <control lang="en" key="IDC_OPEN_CONTAINING_FOLDER">&Open the destination location when finished</control> + <control lang="en" key="IDC_PROG_GROUP">Add TrueCrypt to &Start menu</control> + <control lang="en" key="IDC_SYSTEM_RESTORE">Create System &Restore point</control> + <control lang="en" key="IDC_UNINSTALL">&Uninstall</control> + <control lang="en" key="IDC_WIZARD_MODE_EXTRACT_ONLY">&Extract</control> + <control lang="en" key="IDC_WIZARD_MODE_INSTALL">&Install</control> + <control lang="en" key="IDD_INSTL_DLG">TrueCrypt Setup Wizard</control> + <control lang="en" key="IDD_UNINSTALL">Uninstall TrueCrypt</control> + <control lang="en" key="IDHELP">&Help</control> + <control lang="en" key="IDT_EXTRACT_DESTINATION">Please select or type the location where you want to place the extracted files:</control> + <control lang="en" key="IDT_INSTALL_DESTINATION">Please select or type the location where you want to install the TrueCrypt program files. If the specified folder does not exist, it will be automatically created.</control> + <control lang="en" key="IDT_UNINSTALL_DIR">Click Uninstall to remove TrueCrypt from this system.</control> + <control lang="en" key="IDC_ABORT_BUTTON">Abort</control> + <control lang="en" key="IDC_BENCHMARK">&Benchmark</control> + <control lang="en" key="IDC_CIPHER_TEST">&Test</control> + <control lang="en" key="IDC_DEVICE_TRANSFORM_MODE_FORMAT">Create encrypted volume and format it</control> + <control lang="en" key="IDC_DEVICE_TRANSFORM_MODE_INPLACE">Encrypt partition in place</control> + <control lang="en" key="IDC_DISPLAY_KEYS">Display generated keys (their portions)</control> + <control lang="en" key="IDC_DISPLAY_POOL_CONTENTS">Display pool content</control> + <control lang="en" key="IDC_DOWNLOAD_CD_BURN_SOFTWARE">Download CD/DVD recording software</control> + <control lang="en" key="IDC_FILE_CONTAINER">Create an encrypted file container</control> + <control lang="en" key="IDC_GB">&GB</control> + <control lang="en" key="IDC_HIDDEN_SYSENC_INFO_LINK">More information</control> + <control lang="en" key="IDC_HIDDEN_VOL">Hi&dden TrueCrypt volume </control> + <control lang="en" key="IDC_HIDDEN_VOL_HELP">More information about hidden volumes</control> + <control lang="en" key="IDC_HIDVOL_WIZ_MODE_DIRECT">Direct mode</control> + <control lang="en" key="IDC_HIDVOL_WIZ_MODE_FULL">Normal mode</control> + <control lang="en" key="IDC_KB">&KB</control> + <control lang="en" key="IDC_KEYFILES_ENABLE">U&se keyfiles</control> + <control lang="en" key="IDC_KEY_FILES">&Keyfiles...</control> + <control lang="en" key="IDC_LINK_HASH_INFO">Information on hash algorithms</control> + <control lang="en" key="IDC_LINK_MORE_INFO_ABOUT_CIPHER">More information</control> + <control lang="en" key="IDC_MB">&MB</control> + <control lang="en" key="IDC_MORE_INFO_ON_CONTAINERS">More information</control> + <control lang="en" key="IDC_MORE_INFO_ON_SYS_ENCRYPTION">More information about system encryption</control> + <control lang="en" key="IDC_MORE_INFO_SYS_ENCRYPTION">More information</control> + <control lang="en" key="IDC_MULTI_BOOT">Multi-boot</control> + <control lang="en" key="IDC_NONSYS_DEVICE">Encrypt a non-system partition/drive</control> + <control lang="en" key="IDC_NO_HISTORY">&Never save history</control> + <control lang="en" key="IDC_OPEN_OUTER_VOLUME">Open Outer Volume</control> + <control lang="en" key="IDC_PAUSE">&Pause</control> + <control lang="en" key="IDC_QUICKFORMAT">Quick Format</control> + <control lang="en" key="IDC_SHOW_PASSWORD">&Display password</control> + <control lang="en" key="IDC_SHOW_PASSWORD_SINGLE">&Display password</control> + <control lang="en" key="IDC_SINGLE_BOOT">Single-boot</control> + <control lang="en" key="IDC_STD_VOL">Standard TrueCrypt volume</control> + <control lang="en" key="IDC_SYSENC_HIDDEN">Hi&dden</control> + <control lang="en" key="IDC_SYSENC_NORMAL">Normal</control> + <control lang="en" key="IDC_SYS_DEVICE">Encrypt the system partition or entire system drive</control> + <control lang="en" key="IDC_SYS_PARTITION">Encrypt the Windows system partition</control> + <control lang="en" key="IDC_WHOLE_SYS_DRIVE">Encrypt the whole drive</control> + <control lang="en" key="IDD_VOL_CREATION_WIZARD_DLG">TrueCrypt Volume Creation Wizard</control> + <control lang="en" key="IDT_CLUSTER">Cluster </control> + <control lang="en" key="IDT_COLLECTING_RANDOM_DATA_NOTE">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 encryption keys. Then click Next to continue.</control> + <control lang="en" key="IDT_CONFIRM">&Confirm:</control> + <control lang="en" key="IDT_DONE">Done</control> + <control lang="en" key="IDT_ENCRYPTION_ALGO">Encryption Algorithm</control> + <control lang="en" key="IDT_FILESYSTEM">Filesystem </control> + <control lang="en" key="IDT_FILE_CONTAINER">Creates a virtual encrypted disk within a file. Recommended for inexperienced users.</control> + <control lang="en" key="IDT_FORMAT_OPTIONS">Options</control> + <control lang="en" key="IDT_HASH_ALGO">Hash Algorithm</control> + <control lang="en" key="IDT_HEADER_KEY">Header Key: </control> + <control lang="en" key="IDT_LEFT">Left</control> + <control lang="en" key="IDT_MASTER_KEY">Master Key: </control> + <control lang="en" key="IDT_MULTI_BOOT">Select this option if there are two or more operating systems installed on this computer.\n\nFor example:\n- Windows XP and Windows XP\n- Windows XP and Windows Vista\n- Windows and Mac OS X\n- Windows and Linux\n- Windows, Linux and Mac OS X</control> + <control lang="en" key="IDT_NON_SYS_DEVICE">Encrypts a non-system partition on any internal or external drive (e.g. a flash drive). Optionally, creates a hidden volume.</control> + <control lang="en" key="IDT_PARTIAL_POOL_CONTENTS">Current pool content (partial)</control> + <control lang="en" key="IDT_PASS">Pass</control> + <control lang="en" key="IDT_PASSWORD">Password:</control> + <control lang="en" key="IDT_PROGRESS">Progress:</control> + <control lang="en" key="IDT_RANDOM_POOL">Random Pool: </control> + <control lang="en" key="IDT_SINGLE_BOOT">Select this option if there is only one operating system installed on this computer (even if it has multiple users).</control> + <control lang="en" key="IDT_SPEED">Speed</control> + <control lang="en" key="IDT_STATUS">Status</control> + <control lang="en" key="IDT_SYSENC_KEYS_GEN_INFO">The keys, salt, and other data have been successfully generated. If you want to generate new keys, click Back and then Next. Otherwise, click Next to continue.</control> + <control lang="en" key="IDT_SYS_DEVICE">Encrypts the partition/drive where Windows is installed. Anyone who wants to gain access and use the system, read and write files, etc., will need to enter the correct password each time before Windows boots. Optionally, creates a hidden system.</control> + <control lang="en" key="IDT_SYS_PARTITION">Select this option to encrypt the partition where the currently running Windows operating system is installed.</control> + <control lang="en" key="IDT_WIPE_MODE">Wipe mode:</control> + <control lang="en" key="IDCLOSE">Close</control> + <control lang="en" key="IDC_ALLOW_ESC_PBA_BYPASS">Allow pre-boot &authentication to be bypassed by pressing the Esc key (enables boot manager)</control> + <control lang="en" key="IDC_AUTORUN_DISABLE">Do nothing</control> + <control lang="en" key="IDC_AUTORUN_MOUNT">&Auto-mount TrueCrypt volume (specified below)</control> + <control lang="en" key="IDC_AUTORUN_START">&Start TrueCrypt</control> + <control lang="en" key="IDC_AUTO_DETECT_PKCS11_MODULE">Auto-&Detect Library</control> + <control lang="en" key="IDC_BOOT_LOADER_CACHE_PASSWORD">&Cache pre-boot authentication password in driver memory (for mounting of non-system volumes)</control> + <control lang="en" key="IDC_BROWSE_DIRS">Browse...</control> + <control lang="en" key="IDC_BROWSE_FILES">Browse...</control> + <control lang="en" key="IDC_CACHE">Cache passwords and keyfil&es in memory</control> + <control lang="en" key="IDC_CLOSE_BKG_TASK_WHEN_NOVOL">Exit when there are no mounted volumes</control> + <control lang="en" key="IDC_CLOSE_TOKEN_SESSION_AFTER_MOUNT">&Close token session (log out) after a volume is successfully mounted</control> + <control lang="en" key="IDC_COPY_WIZARD">Include TrueCrypt Volume Creation Wizard</control> + <control lang="en" key="IDC_CREATE">Create</control> + <control lang="en" key="IDC_CREATE_VOLUME">&Create Volume</control> + <control lang="en" key="IDC_DISABLE_BOOT_LOADER_OUTPUT">Do not &show any texts in the pre-boot authentication screen (except the below custom message)</control> + <control lang="en" key="IDC_ENABLE_HARDWARE_ENCRYPTION">Accelerate AES encryption/decryption by using the AES instructions of the processor (if available)</control> + <control lang="en" key="IDC_ENABLE_KEYFILES">Use keyfiles</control> + <control lang="en" key="IDC_ENABLE_NEW_KEYFILES">Use keyfiles</control> + <control lang="en" key="IDC_EXIT">E&xit</control> + <control lang="en" key="IDC_FAVORITES_HELP_LINK">Help on favorite volumes</control> + <control lang="en" key="IDC_FAVORITE_DISABLE_HOTKEY">Do not mount selected volume when 'Mount Favorite Volumes' &hot key is pressed</control> + <control lang="en" key="IDC_FAVORITE_MOUNT_ON_ARRIVAL">Mount selected volume when its host device gets &connected</control> + <control lang="en" key="IDC_FAVORITE_MOUNT_ON_LOGON">Mount selected volume upon log&on</control> + <control lang="en" key="IDC_FAVORITE_MOUNT_READONLY">Mount selected volume as read-o&nly</control> + <control lang="en" key="IDC_FAVORITE_MOUNT_REMOVABLE">Mount selected volume as remo&vable medium</control> + <control lang="en" key="IDC_FAVORITE_MOVE_DOWN">Move &Down</control> + <control lang="en" key="IDC_FAVORITE_MOVE_UP">Move &Up</control> + <control lang="en" key="IDC_FAVORITE_OPEN_EXPLORER_WIN_ON_MOUNT">Open &Explorer window for selected volume when successfully mounted</control> + <control lang="en" key="IDC_FAVORITE_REMOVE">&Remove</control> + <control lang="en" key="IDC_FAV_VOL_OPTIONS_GLOBAL_SETTINGS_BOX">Global Settings</control> + <control lang="en" key="IDC_HK_DISMOUNT_BALLOON_TOOLTIP">Display balloon tooltip after successful hot-key dismount</control> + <control lang="en" key="IDC_HK_DISMOUNT_PLAY_SOUND">Play system notification sound after successful hot-key dismount</control> + <control lang="en" key="IDC_HK_MOD_ALT">Alt</control> + <control lang="en" key="IDC_HK_MOD_CTRL">Ctrl</control> + <control lang="en" key="IDC_HK_MOD_SHIFT">Shift</control> + <control lang="en" key="IDC_HK_MOD_WIN">Win</control> + <control lang="en" key="IDC_HOTKEY_ASSIGN">Assign</control> + <control lang="en" key="IDC_HOTKEY_REMOVE">Remove</control> + <control lang="en" key="IDC_KEYFILES">Keyfiles...</control> + <control lang="en" key="IDC_LIMIT_ENC_THREAD_POOL">Do not use the following number of processors for encryption/decryption:</control> + <control lang="en" key="IDC_MORE_INFO_ON_HW_ACCELERATION">More information</control> + <control lang="en" key="IDC_MORE_INFO_ON_THREAD_BASED_PARALLELIZATION">More information</control> + <control lang="en" key="IDC_MORE_SETTINGS">More Settings...</control> + <control lang="en" key="IDC_MOUNTALL">&Auto-Mount Devices</control> + <control lang="en" key="IDC_MOUNT_OPTIONS">Mount Opti&ons...</control> + <control lang="en" key="IDC_MOUNT_READONLY">Mount volume as read-&only</control> + <control lang="en" key="IDC_NEW_KEYFILES">Keyfiles...</control> + <control lang="en" key="IDC_PREF_BKG_TASK_ENABLE">Enabled</control> + <control lang="en" key="IDC_PREF_CACHE_PASSWORDS">Cache passwords in driver memory</control> + <control lang="en" key="IDC_PREF_DISMOUNT_INACTIVE">Auto-dismount volume after no data has been read/written to it for</control> + <control lang="en" key="IDC_PREF_DISMOUNT_LOGOFF">User logs off</control> + <control lang="en" key="IDC_PREF_DISMOUNT_POWERSAVING">Entering power saving mode</control> + <control lang="en" key="IDC_PREF_DISMOUNT_SCREENSAVER">Screen saver is launched</control> + <control lang="en" key="IDC_PREF_FORCE_AUTO_DISMOUNT">Force auto-dismount even if volume contains open files or directories</control> + <control lang="en" key="IDC_PREF_LOGON_MOUNT_DEVICES">Mount all device-hosted TrueCrypt volumes</control> + <control lang="en" key="IDC_PREF_LOGON_START">Start TrueCrypt Background Task</control> + <control lang="en" key="IDC_PREF_MOUNT_READONLY">Mount volumes as read-only</control> + <control lang="en" key="IDC_PREF_MOUNT_REMOVABLE">Mount volumes as removable media</control> + <control lang="en" key="IDC_PREF_OPEN_EXPLORER">Open Explorer window for successfully mounted volume</control> + <control lang="en" key="IDC_PREF_USE_DIFF_TRAY_ICON_IF_VOL_MOUNTED">Use a different taskbar icon when there are mounted volumes</control> + <control lang="en" key="IDC_PREF_WIPE_CACHE_ON_AUTODISMOUNT">Wipe cached passwords on auto-dismount</control> + <control lang="en" key="IDC_PREF_WIPE_CACHE_ON_EXIT">Wipe cached passwords on exit</control> + <control lang="en" key="IDC_PRESERVE_TIMESTAMPS">Preserve modification timestamp of file containers</control> + <control lang="en" key="IDC_RESET_HOTKEYS">Reset</control> + <control lang="en" key="IDC_SELECT_DEVICE">Select D&evice...</control> + <control lang="en" key="IDC_SELECT_FILE">Select &File...</control> + <control lang="en" key="IDC_SELECT_PKCS11_MODULE">Select &Library...</control> + <control lang="en" key="IDC_SHOW_PASSWORD_CHPWD_NEW">Display password</control> + <control lang="en" key="IDC_SHOW_PASSWORD_CHPWD_ORI">Display password</control> + <control lang="en" key="IDC_TRAVEL_OPEN_EXPLORER">Open &Explorer window for mounted volume</control> + <control lang="en" key="IDC_TRAV_CACHE_PASSWORDS">&Cache password in driver memory</control> + <control lang="en" key="IDC_UNMOUNTALL">Di&smount All</control> + <control lang="en" key="IDC_VOLUME_PROPERTIES">&Volume Properties...</control> + <control lang="en" key="IDC_VOLUME_TOOLS">Volume &Tools...</control> + <control lang="en" key="IDC_WIPE_CACHE">&Wipe Cache</control> + <control lang="en" key="IDD_FAVORITE_VOLUMES">TrueCrypt - Favorite Volumes</control> + <control lang="en" key="IDD_HOTKEYS_DLG">TrueCrypt - System-Wide Hot Keys</control> + <control lang="en" key="IDD_MOUNT_DLG">TrueCrypt</control> + <control lang="en" key="IDD_PASSWORDCHANGE_DLG">Change Password or Keyfiles</control> + <control lang="en" key="IDD_PASSWORD_DLG">Enter TrueCrypt Volume Password</control> + <control lang="en" key="IDD_PERFORMANCE_SETTINGS">TrueCrypt - Performance Options</control> + <control lang="en" key="IDD_PREFERENCES_DLG">TrueCrypt - Preferences</control> + <control lang="en" key="IDD_SYSENC_SETTINGS">TrueCrypt - System Encryption Settings</control> + <control lang="en" key="IDD_TOKEN_PREFERENCES">TrueCrypt - Security Token Preferences</control> + <control lang="en" key="IDD_TRAVELER_DLG">TrueCrypt Traveler Disk Setup</control> + <control lang="en" key="IDD_VOLUME_PROPERTIES">TrueCrypt Volume Properties</control> + <control lang="en" key="IDM_ABOUT">About</control> + <control lang="en" key="IDM_ADD_REMOVE_VOL_KEYFILES">Add/Remove Keyfiles to/from Volume...</control> + <control lang="en" key="IDM_ADD_VOLUME_TO_FAVORITES">Add Mounted Volume to Favorites...</control> + <control lang="en" key="IDM_ADD_VOLUME_TO_SYSTEM_FAVORITES">Add Mounted Volume to System Favorites...</control> + <control lang="en" key="IDM_ANALYZE_SYSTEM_CRASH">Analyze a System Crash...</control> + <control lang="en" key="IDM_BACKUP_VOL_HEADER">Backup Volume Header...</control> + <control lang="en" key="IDM_BENCHMARK">Benchmark...</control> + <control lang="en" key="IDM_CHANGE_HEADER_KEY_DERIV_ALGO">Set Header Key Derivation Algorithm...</control> + <control lang="en" key="IDM_CHANGE_PASSWORD">Change Volume Password...</control> + <control lang="en" key="IDM_CHANGE_SYS_HEADER_KEY_DERIV_ALGO">Set Header Key Derivation Algorithm...</control> + <control lang="en" key="IDM_CHANGE_SYS_PASSWORD">Change Password...</control> + <control lang="en" key="IDM_CLEAR_HISTORY">Clear Volume History</control> + <control lang="en" key="IDM_CLOSE_ALL_TOKEN_SESSIONS">Close All Security Token Sessions</control> + <control lang="en" key="IDM_CONTACT">Contact</control> + <control lang="en" key="IDM_CREATE_HIDDEN_OS">Create Hidden Operating System...</control> + <control lang="en" key="IDM_CREATE_RESCUE_DISK">Create Rescue Disk...</control> + <control lang="en" key="IDM_CREATE_VOLUME">Create New Volume...</control> + <control lang="en" key="IDM_DEFAULT_KEYFILES">Default Keyfiles...</control> + <control lang="en" key="IDM_ENCRYPT_SYSTEM_DEVICE">Encrypt System Partition/Drive...</control> + <control lang="en" key="IDM_FAQ">Frequently Asked Questions</control> + <control lang="en" key="IDM_HELP">User's Guide</control> + <control lang="en" key="IDM_HOMEPAGE">&Homepage </control> + <control lang="en" key="IDM_HOTKEY_SETTINGS">Hot Keys...</control> + <control lang="en" key="IDM_KEYFILE_GENERATOR">Keyfile Generator</control> + <control lang="en" key="IDM_LANGUAGE">Language...</control> + <control lang="en" key="IDM_LICENSE">Legal Notices</control> + <control lang="en" key="IDM_MANAGE_TOKEN_KEYFILES">Manage Security Token Keyfiles...</control> + <control lang="en" key="IDM_MOUNTALL">Auto-Mount All Device-Hosted Volumes</control> + <control lang="en" key="IDM_MOUNT_FAVORITE_VOLUMES">Mount Favorite Volumes</control> + <control lang="en" key="IDM_MOUNT_SYSENC_PART_WITHOUT_PBA">Mount Without Pre-Boot &Authentication...</control> + <control lang="en" key="IDM_MOUNT_VOLUME">Mount Volume</control> + <control lang="en" key="IDM_MOUNT_VOLUME_OPTIONS">Mount Volume with Options</control> + <control lang="en" key="IDM_NEWS">News</control> + <control lang="en" key="IDM_ONLINE_HELP">Online Help</control> + <control lang="en" key="IDM_ONLINE_TUTORIAL">Beginner's Tutorial</control> + <control lang="en" key="IDM_ORGANIZE_FAVORITES">Organize Favorite Volumes...</control> + <control lang="en" key="IDM_ORGANIZE_SYSTEM_FAVORITES">Organize System Favorite Volumes...</control> + <control lang="en" key="IDM_PERFORMANCE_SETTINGS">Performance...</control> + <control lang="en" key="IDM_PERMANENTLY_DECRYPT_SYS">Permanently Decrypt System Partition/Drive</control> + <control lang="en" key="IDM_PREFERENCES">Preferences...</control> + <control lang="en" key="IDM_REFRESH_DRIVE_LETTERS">Refresh Drive Letters</control> + <control lang="en" key="IDM_REMOVE_ALL_KEYFILES_FROM_VOL">Remove All Keyfiles from Volume...</control> + <control lang="en" key="IDM_RESTORE_VOL_HEADER">Restore Volume Header...</control> + <control lang="en" key="IDM_RESUME_INTERRUPTED_PROC">Resume Interrupted Process</control> + <control lang="en" key="IDM_SELECT_DEVICE">Select Device...</control> + <control lang="en" key="IDM_SELECT_FILE">Select File...</control> + <control lang="en" key="IDM_SYSENC_RESUME">Resume Interrupted Process</control> + <control lang="en" key="IDM_SYSENC_SETTINGS">System Encryption...</control> + <control lang="en" key="IDM_SYSTEM_ENCRYPTION_STATUS">Properties...</control> + <control lang="en" key="IDM_SYS_ENC_SETTINGS">Settings...</control> + <control lang="en" key="IDM_SYS_FAVORITES_SETTINGS">System Favorite Volumes...</control> + <control lang="en" key="IDM_TC_DOWNLOADS">Downloads</control> + <control lang="en" key="IDM_TEST_VECTORS">Test Vectors...</control> + <control lang="en" key="IDM_TOKEN_PREFERENCES">Security Tokens...</control> + <control lang="en" key="IDM_TRAVELER">Traveler Disk Setup...</control> + <control lang="en" key="IDM_UNMOUNTALL">Dismount All Mounted Volumes</control> + <control lang="en" key="IDM_UNMOUNT_VOLUME">Dismount Volume</control> + <control lang="en" key="IDM_VERIFY_RESCUE_DISK">Verify Rescue Disk</control> + <control lang="en" key="IDM_VERSION_HISTORY">Version History</control> + <control lang="en" key="IDM_VOLUME_PROPERTIES">Volume Properties</control> + <control lang="en" key="IDM_VOLUME_WIZARD">Volume Creation Wizard</control> + <control lang="en" key="IDM_WEBSITE">TrueCrypt Website</control> + <control lang="en" key="IDM_WIPE_CACHE">Wipe Cached Passwords</control> + <control lang="en" key="IDOK">OK</control> + <control lang="en" key="IDT_ACCELERATION_OPTIONS">Hardware Acceleration</control> + <control lang="en" key="IDT_ASSIGN_HOTKEY">Shortcut</control> + <control lang="en" key="IDT_AUTORUN">AutoRun Configuration (autorun.inf)</control> + <control lang="en" key="IDT_AUTO_DISMOUNT">Auto-Dismount</control> + <control lang="en" key="IDT_AUTO_DISMOUNT_ON">Dismount all when:</control> + <control lang="en" key="IDT_BOOT_LOADER_SCREEN_OPTIONS">Boot Loader Screen Options</control> + <control lang="en" key="IDT_CONFIRM_PASSWORD">Confirm Password:</control> + <control lang="en" key="IDT_CURRENT">Current</control> + <control lang="en" key="IDT_CUSTOM_BOOT_LOADER_MESSAGE">Display this custom message in the pre-boot authentication screen (24 characters maximum):</control> + <control lang="en" key="IDT_DEFAULT_MOUNT_OPTIONS">Default Mount Options</control> + <control lang="en" key="IDT_DISMOUNT_ACTION">Hot Key Options</control> + <control lang="en" key="IDT_FAVORITE_LABEL">Label of selected favorite volume:</control> + <control lang="en" key="IDT_FILE_SETTINGS">File Settings</control> + <control lang="en" key="IDT_HOTKEY_KEY">Key to assign:</control> + <control lang="en" key="IDT_HW_AES_SUPPORTED_BY_CPU">Processor (CPU) in this computer supports hardware acceleration for AES:</control> + <control lang="en" key="IDT_LOGON">Actions to perform upon logon to Windows</control> + <control lang="en" key="IDT_MINUTES">minutes</control> + <control lang="en" key="IDT_MOUNT_LETTER">Mount volume as drive letter:</control> + <control lang="en" key="IDT_MOUNT_SETTINGS">Mount Settings</control> + <control lang="en" key="IDT_NEW">New</control> + <control lang="en" key="IDT_NEW_PASSWORD">Password:</control> + <control lang="en" key="IDT_PARALLELIZATION_OPTIONS">Thread-Based Parallelization</control> + <control lang="en" key="IDT_PKCS11_LIB_PATH">PKCS #11 Library Path</control> + <control lang="en" key="IDT_PKCS5_PRF">PKCS-5 PRF:</control> + <control lang="en" key="IDT_PW_CACHE_OPTIONS">Password Cache</control> + <control lang="en" key="IDT_SECURITY_OPTIONS">Security Options</control> + <control lang="en" key="IDT_TASKBAR_ICON">TrueCrypt Background Task</control> + <control lang="en" key="IDT_TRAVELER_MOUNT">TrueCrypt volume to mount (relative to traveler disk root):</control> + <control lang="en" key="IDT_TRAVEL_INSERTION">Upon insertion of traveler disk: </control> + <control lang="en" key="IDT_TRAVEL_ROOT">Create traveler disk files at (traveler disk root directory):</control> + <control lang="en" key="IDT_VOLUME">Volume</control> + <control lang="en" key="IDT_WINDOWS_RELATED_SETTING">Windows</control> + <control lang="en" key="IDC_ADD_KEYFILE_PATH">Add &Path...</control> + <control lang="en" key="IDC_AUTO">&Auto-Test All</control> + <control lang="en" key="IDC_CONTINUE">&Continue</control> + <control lang="en" key="IDC_DECRYPT">&Decrypt</control> + <control lang="en" key="IDC_DELETE">&Delete</control> + <control lang="en" key="IDC_ENCRYPT">&Encrypt</control> + <control lang="en" key="IDC_EXPORT">&Export...</control> + <control lang="en" key="IDC_GENERATE_AND_SAVE_KEYFILE">Generate and Save Keyfile...</control> + <control lang="en" key="IDC_GENERATE_KEYFILE">&Generate Random Keyfile...</control> + <control lang="en" key="IDC_GET_LANG_PACKS">Download language pack</control> + <control lang="en" key="IDC_HW_AES_LABEL_LINK">Hardware-accelerated AES:</control> + <control lang="en" key="IDC_IMPORT_KEYFILE">&Import Keyfile to Token...</control> + <control lang="en" key="IDC_KEYADD">Add &Files...</control> + <control lang="en" key="IDC_KEYFILES_ENABLE_HIDVOL_PROT">U&se keyfiles</control> + <control lang="en" key="IDC_KEYFILES_HIDVOL_PROT">&Keyfiles...</control> + <control lang="en" key="IDC_KEYREMOVE">&Remove</control> + <control lang="en" key="IDC_KEYREMOVEALL">Remove &All</control> + <control lang="en" key="IDC_LINK_HIDVOL_PROTECTION_INFO">What is hidden volume protection?</control> + <control lang="en" key="IDC_LINK_KEYFILES_INFO">More information on keyfiles</control> + <control lang="en" key="IDC_MOUNT_REMOVABLE">Mount volume as removable &medium</control> + <control lang="en" key="IDC_MOUNT_SYSENC_PART_WITHOUT_PBA">Mount partition &using system encryption without pre-boot authentication</control> + <control lang="en" key="IDC_PARALLELIZATION_LABEL_LINK">Parallelization:</control> + <control lang="en" key="IDC_PERFORM_BENCHMARK">Benchmark</control> + <control lang="en" key="IDC_PRINT">&Print</control> + <control lang="en" key="IDC_PROTECT_HIDDEN_VOL">&Protect hidden volume against damage caused by writing to outer volume</control> + <control lang="en" key="IDC_RESET">&Reset</control> + <control lang="en" key="IDC_SHOW_PASSWORD_MO">&Display password</control> + <control lang="en" key="IDC_TOKEN_FILES_ADD">Add &Token Files...</control> + <control lang="en" key="IDC_USE_EMBEDDED_HEADER_BAK">Use backup header embedded in &volume if available</control> + <control lang="en" key="IDC_XTS_MODE_ENABLED">XTS mode</control> + <control lang="en" key="IDD_ABOUT_DLG">About TrueCrypt</control> + <control lang="en" key="IDD_BENCHMARK_DLG">TrueCrypt - Encryption Algorithm Benchmark</control> + <control lang="en" key="IDD_CIPHER_TEST_DLG">TrueCrypt - Test Vectors</control> + <control lang="en" key="IDD_COMMANDHELP_DLG">Command Line Help</control> + <control lang="en" key="IDD_KEYFILES">TrueCrypt - Keyfiles</control> + <control lang="en" key="IDD_KEYFILE_GENERATOR">TrueCrypt - Keyfile Generator</control> + <control lang="en" key="IDD_LANGUAGE">TrueCrypt - Language</control> + <control lang="en" key="IDD_MOUNT_OPTIONS">TrueCrypt - Mount Options</control> + <control lang="en" key="IDD_NEW_TOKEN_KEYFILE">New Security Token Keyfile Properties</control> + <control lang="en" key="IDD_RANDOM_POOL_ENRICHMENT">TrueCrypt - Random Pool Enrichment</control> + <control lang="en" key="IDD_RAWDEVICES_DLG">Select a Partition or Device</control> + <control lang="en" key="IDD_STATIC_MODELESS_WAIT_DLG">TrueCrypt</control> + <control lang="en" key="IDD_TOKEN_KEYFILES">Security Token Keyfiles</control> + <control lang="en" key="IDD_TOKEN_PASSWORD">Security token password/PIN required</control> + <control lang="en" key="IDT_ACTIVE_LANG_PACK">Active language pack</control> + <control lang="en" key="IDT_BOX_BENCHMARK_INFO">Speed is affected by CPU load and storage device characteristics.\n\nThese tests take place in RAM.</control> + <control lang="en" key="IDT_BUFFER_SIZE">Buffer Size:</control> + <control lang="en" key="IDT_CIPHER">Cipher:</control> + <control lang="en" key="IDT_HIDDEN_PROT_PASSWD">P&assword to hidden volume:\n(if empty, cache is used)</control> + <control lang="en" key="IDT_HIDDEN_VOL_PROTECTION">Hidden Volume Protection</control> + <control lang="en" key="IDT_KEY">Key size:</control> + <control lang="en" key="IDT_KEYFILE_GENERATOR_NOTE">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.</control> + <control lang="en" key="IDT_KEYFILE_WARNING">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!</control> + <control lang="en" key="IDT_KEY_UNIT">bits</control> + <control lang="en" key="IDT_LANGPACK_AUTHORS">Translated by:</control> + <control lang="en" key="IDT_PLAINTEXT">Plaintext size:</control> + <control lang="en" key="IDT_PLAINTEXT_SIZE_UNIT">bits</control> + <control lang="en" key="IDT_POOL_CONTENTS">Current Pool Content</control> + <control lang="en" key="IDT_PRF">Mixing PRF:</control> + <control lang="en" key="IDT_RANDOM_POOL_ENRICHMENT_NOTE">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'.</control> + <control lang="en" key="IDT_SECONDARY_KEY">Secondary key (hexadecimal)</control> + <control lang="en" key="IDT_SECURITY_TOKEN">Security token:</control> + <control lang="en" key="IDT_SORT_METHOD">Sort Method:</control> + <control lang="en" key="IDT_STATIC_MODELESS_WAIT_DLG_INFO">Please wait. This process may take a long time...</control> + <control lang="en" key="IDT_TEST_BLOCK_NUMBER">Block number:</control> + <control lang="en" key="IDT_TEST_CIPHERTEXT">Ciphertext (hexadecimal)</control> + <control lang="en" key="IDT_TEST_DATA_UNIT_NUMBER">Data unit number (64-bit hexadecimal, data unit size is 512 bytes)</control> + <control lang="en" key="IDT_TEST_KEY">Key (hexadecimal)</control> + <control lang="en" key="IDT_TEST_PLAINTEXT">Plaintext (hexadecimal)</control> + <control lang="en" key="IDT_TOKEN_KEYFILE_NAME">Keyfile name:</control> + <control lang="en" key="IDT_XTS_MODE">XTS mode</control> + <control lang="en" key="MENU_SYSTEM_ENCRYPTION">S&ystem</control> + <control lang="en" key="MENU_VOLUMES">&Volumes</control> + <control lang="en" key="MENU_FAVORITES">Favor&ites</control> + <control lang="en" key="MENU_TOOLS">T&ools</control> + <control lang="en" key="MENU_SETTINGS">Settin&gs</control> + <control lang="en" key="MENU_HELP">&Help</control> + <control lang="en" key="MENU_WEBSITE"> Home&page </control> + <!-- Strings --> + <string lang="en" key="ABOUTBOX">&About...</string> + <string lang="en" key="ACCESSMODEFAIL">The read-only attribute on your old volume could not be changed. Please check the file access permissions.</string> + <string lang="en" key="ACCESS_DENIED">Error: Access denied.\n\nThe partition you are trying to access is either 0 sectors long, or it is the boot device.</string> + <string lang="en" key="ADMINISTRATOR">Administrator</string> + <string lang="en" key="ADMIN_PRIVILEGES_DRIVER">In order to load the TrueCrypt driver, you need to be logged into an account with administrator privileges.</string> + <string lang="en" key="ADMIN_PRIVILEGES_WARN_DEVICES">Please note that in order to encrypt/format a partition/device you need to be logged into an account with administrator privileges.\n\nThis does not apply to file-hosted volumes.</string> + <string lang="en" key="ADMIN_PRIVILEGES_WARN_HIDVOL">In order to create a hidden volume you need to be logged into an account with administrator privileges.\n\nContinue?</string> + <string lang="en" key="ADMIN_PRIVILEGES_WARN_NTFS">Please note that in order to format the volume as NTFS you need to be logged into an account with administrator privileges.\n\nWithout administrator privileges, you can format the volume as FAT.</string> + <string lang="en" key="AES_HELP">FIPS-approved cipher (Rijndael, published in 1998) that may be used by U.S. government departments and agencies to protect classified information up to the Top Secret level. 256-bit key, 128-bit block, 14 rounds (AES-256). Mode of operation is XTS.</string> + <string lang="en" key="ALREADY_MOUNTED">Volume is already mounted.</string> + <string lang="en" key="ERR_SELF_TESTS_FAILED">CAUTION: At least one encryption or hash algorithm failed the built-in automatic self-tests!\n\nTrueCrypt installation may be corrupted.</string> + <string lang="en" key="ERR_NOT_ENOUGH_RANDOM_DATA">CAUTION: There is not enough data in the Random Number Generator pool to provide the requested amount of random data.\n\nYou should not proceed any further. Please select 'Report a Bug' from the Help menu, and report this error.</string> + <string lang="en" key="ERR_HARDWARE_ERROR">The drive is damaged (there is a physical defect on it) or a cable is damaged, or the memory is malfunctioning.\n\nPlease note that this is a problem with your hardware, not with TrueCrypt. Therefore, please do NOT report this as a bug/problem in TrueCrypt and please do NOT ask for help with this in the TrueCrypt Forums. Please contact your computer vendor's technical support team for assistance. Thank you.\n\nNote: If the error occurs repeatedly at the same place, it is very likely caused by a bad disk block, which should be possible to correct using third-party software (note that, in many cases, the 'chkdsk /r' command cannot correct it because it works only at the filesystem level; in some cases, the 'chkdsk' tool cannot even detect it).</string> + <string lang="en" key="DEVICE_NOT_READY_ERROR">If you are accessing a drive for removable media, please make sure that a medium is inserted in the drive. The drive/medium may also be damaged (there may be a physical defect on it) or a cable may be damaged/disconnected.</string> + <string lang="en" key="WHOLE_DRIVE_ENCRYPTION_PREVENTED_BY_DRIVERS">Your system appears to be using custom chipset drivers containing a bug that prevents encryption of the whole system drive.\n\nPlease try updating or uninstalling any custom (non-Microsoft) chipset drivers before proceeding. If it does not help, try encrypting the system partition only.</string> + <string lang="en" key="BAD_DRIVE_LETTER">Invalid drive letter.</string> + <string lang="en" key="INVALID_PATH">Invalid path.</string> + <string lang="en" key="CANCEL">Cancel</string> + <string lang="en" key="CANNOT_CALC_SPACE">Cannot access device. Make sure the selected device exists and is not used by system.</string> + <string lang="en" key="CAPSLOCK_ON">Warning: Caps Lock is on. This may cause you to enter your password incorrectly.</string> + <string lang="en" key="VOLUME_TYPE_TITLE">Volume Type</string> + <string lang="en" key="HIDDEN_VOLUME_TYPE_HELP">It may happen that you are forced by somebody to reveal the password to an encrypted volume. There are many situations where you cannot refuse to reveal the password (for example, due to extortion). Using a so-called hidden volume allows you to solve such situations without revealing the password to your volume.</string> + <string lang="en" key="NORMAL_VOLUME_TYPE_HELP">Select this option if you want to create a normal TrueCrypt volume.</string> + <string lang="en" key="HIDDEN_OS_PRECLUDES_SINGLE_KEY_WDE">Please note that if you wish an operating system to be installed in a hidden partition-hosted volume, then the entire system drive cannot be encrypted using a single key.</string> + <string lang="en" key="CIPHER_HIDVOL_HOST_TITLE">Outer Volume Encryption Options</string> + <string lang="en" key="CIPHER_HIDVOL_TITLE">Hidden Volume Encryption Options</string> + <string lang="en" key="CIPHER_TITLE">Encryption Options</string> + <string lang="en" key="CLEAN_WINMRU_FAILED">WARNING: Failed to clear the path of the last selected volume/keyfile (remembered by file selector)!</string> + <string lang="en" key="COMPRESSION_NOT_SUPPORTED">Error: The container has been compressed at the filesystem level. TrueCrypt does not support compressed containers (note that compression of encrypted data is ineffective and redundant).\n\nPlease disable compression for the container by following these steps:\n1) Right-click the container in Windows Explorer (not in TrueCrypt).\n2) Select 'Properties'.\n3) In the 'Properties' dialog box, click 'Advanced'.\n4) In the 'Advanced Attributes' dialog box, disable the option 'Compress contents to save disk space' and click 'OK'.\n5) In the 'Properties' dialog box, click 'OK'.</string> + <string lang="en" key="CREATE_FAILED">Failed to create volume %hs</string> + <string lang="en" key="DEVICE_FREE_BYTES">Size of %hs is %.2f bytes</string> + <string lang="en" key="DEVICE_FREE_KB">Size of %hs is %.2f KB</string> + <string lang="en" key="DEVICE_FREE_MB">Size of %hs is %.2f MB</string> + <string lang="en" key="DEVICE_FREE_GB">Size of %hs is %.2f GB</string> + <string lang="en" key="DEVICE_FREE_TB">Size of %hs is %.2f TB</string> + <string lang="en" key="DEVICE_FREE_PB">Size of %hs is %.2f PB</string> + <string lang="en" key="DEVICE_IN_USE_FORMAT">WARNING: The device/partition is in use by the operating system or applications. Formatting the device/partition might cause data corruption and system instability.\n\nContinue?</string> + <string lang="en" key="DEVICE_IN_USE_INPLACE_ENC">Warning: The partition is in use by the operating system or applications. You should close any applications that might be using the partition (including antivirus software).\n\nContinue?</string> + <string lang="en" key="FORMAT_CANT_DISMOUNT_FILESYS">Error: The device/partition contains a file system that could not be dismounted. The file system may be in use by the operating system. Formatting the device/partition would very likely cause data corruption and system instability.\n\nTo solve this issue, we recommend that you first delete the partition and then recreate it without formatting. To do so, follow these steps:\n1) Right-click the 'Computer' (or 'My Computer') icon in the 'Start Menu' and select 'Manage'. The 'Computer Management' window should appear.\n2) In the 'Computer Management' window, select 'Storage' > 'Disk Management'.\n3) Right-click the partition you want to encrypt and select either 'Delete Partition', or 'Delete Volume', or 'Delete Logical Drive'.\n4) Click 'Yes'. If Windows asks you to restart the computer, do so. Then repeat the steps 1 and 2 and continue from the step 5.\n5) Right-click the unallocated/free space area and select either 'New Partition', or 'New Simple Volume', or 'New Logical Drive'.\n6) The 'New Partition Wizard' or 'New Simple Volume Wizard' window should appear now; follow its instructions. On the wizard page entitled 'Format Partition', select either 'Do not format this partition' or 'Do not format this volume'. In the same wizard, click 'Next' and then 'Finish'.\n7) Note that the device path you have selected in TrueCrypt may be wrong now. Therefore, exit the TrueCrypt Volume Creation Wizard (if it is still running) and then start it again.\n8) Try encrypting the device/partition again.\n\nIf TrueCrypt repeatedly fails to encrypt the device/partition, you may want to consider creating a file container instead.</string> + <string lang="en" key="INPLACE_ENC_CANT_LOCK_OR_DISMOUNT_FILESYS">Error: The filesystem could not be locked and/or dismounted. It may be in use by the operating system or applications (for example, antivirus software). Encrypting the partition might cause data corruption and system instability.\n\nPlease close any applications that might be using the filesystem (including antivirus software) and try again. If it does not help, please follow the below steps.</string> + <string lang="en" key="DEVICE_IN_USE_INFO">WARNING: Some of the mounted devices/partitions were already in use!\n\nIgnoring this can cause undesired results including system instability.\n\nWe strongly recommend that you close any application that might be using the devices/partitions.</string> + <string lang="en" key="DEVICE_PARTITIONS_ERR">The selected device contains partitions.\n\nFormatting the device might cause system instability and/or data corruption. Please either select a partition on the device, or remove all partitions on the device to enable TrueCrypt to format it safely.</string> + <string lang="en" key="DEVICE_PARTITIONS_ERR_W_INPLACE_ENC_NOTE">The selected non-system device contains partitions.\n\nEncrypted device-hosted TrueCrypt volumes can be created within devices that do not contain any partitions (including hard disks and solid-state drives). A device that contains partitions can be entirely encrypted in place (using a single master key) only if it is the drive where Windows is installed and from which it boots.\n\nIf you want to encrypt the selected non-system device using a single master key, you will need to remove all partitions on the device first to enable TrueCrypt to format it safely (formatting a device that contains partitions might cause system instability and/or data corruption). Alternatively, you can encrypt each partition on the drive individually (each partition will be encrypted using a different master key).\n\nNote: If you want to remove all partitions from a GPT disk, you may need to convert it to a MBR disk (using e.g. the Computer Management tool) in order to remove hidden partitions.</string> + <string lang="en" key="WHOLE_NONSYS_DEVICE_ENC_CONFIRM">Warning: If you encrypt the entire device (as opposed to encrypting only a partition on it), operating systems will consider the device as new, empty, and unformatted (as it will contain no partition table) and may spontaneously initialize the device (or ask you if you want to do so), which may damage the volume. Furthermore, it will not be possible to consistently mount the volume as favorite (e.g. when the drive number changes) or to assign a favorite-volume label to it.\n\nTo avoid that you may want to consider creating a partition on the device and encrypting the partition instead.\n\nAre you sure want to encrypt the entire device?</string> + <string lang="en" key="AFTER_FORMAT_DRIVE_LETTER_WARN">IMPORTANT: Please keep in mind that this volume can NOT be mounted/accessed using the drive letter %c:, which is currently assigned to it!\n\nTo mount this volume, click 'Auto-Mount Devices' in the main TrueCrypt window (alternatively, in the main TrueCrypt window, click 'Select Device', then select this partition/device, and click 'Mount'). The volume will be mounted to a different drive letter, which you select from the list in the main TrueCrypt window.\n\nThe original drive letter %c: should be used only in case you need to remove encryption from the partition/device (e.g., if you no longer need encryption). In such a case, right-click the drive letter %c: in the 'Computer' (or 'My Computer') list and select 'Format'. Otherwise, the drive letter %c: should never be used (unless you remove it, as described e.g. in the TrueCrypt FAQ, and assign it to another partition/device).</string> + <string lang="en" key="OS_NOT_SUPPORTED_FOR_NONSYS_INPLACE_ENC">In-place encryption of non-system volumes is not supported on the version of the operating system you are currently using (it is supported only on Windows Vista and later versions of Windows).\n\nThe reason is that this version of Windows does not support shrinking of a filesystem (the filesystem needs to be shrunk to make space for the volume header and backup header).</string> + <string lang="en" key="ONLY_NTFS_SUPPORTED_FOR_NONSYS_INPLACE_ENC">The selected partition does not appear to contain an NTFS filesystem. Only partitions that contain an NTFS filesystem can be encrypted in place.\n\nNote: The reason is that Windows does not support shrinking of other types of filesystems (the filesystem needs to be shrunk to make space for the volume header and backup header).</string> + <string lang="en" key="ONLY_MOUNTED_VOL_SUPPORTED_FOR_NONSYS_INPLACE_ENC">The selected partition does not appear to contain an NTFS filesystem. Only partitions that contain an NTFS filesystem can be encrypted in place.\n\nIf you want to create an encrypted TrueCrypt volume within this partition, choose the option "Create encrypted volume and format it" (instead of the option "Encrypt partition in place").</string> + <string lang="en" key="PARTITION_TOO_SMALL_FOR_NONSYS_INPLACE_ENC">Error: The partition is too small. TrueCrypt cannot encrypt it in place.</string> + <string lang="en" key="INPLACE_ENC_ALTERNATIVE_STEPS">To encrypt the data on this partition, please follow these steps:\n\n1) Create a TrueCrypt volume on an empty partition/device and then mount it.\n\n2) Copy all files from the partition that you originally wanted to encrypt to the mounted TrueCrypt volume (that has been created and mounted in step 1). That way, you will create a TrueCrypt-encrypted backup of the data.\n\n3) Create a TrueCrypt volume on the partition that you originally wanted to encrypt and make sure that (in the TrueCrypt wizard) you choose the option "Create encrypted volume and format it" (instead of the option "Encrypt partition in place"). Note that all data stored on the partition will be erased. After the volume is created, mount it.\n\n4) Copy all files from the mounted backup TrueCrypt volume (created and mounted in step 1) to the mounted TrueCrypt volume that has been created (and mounted) in step 3.\n\nAfter you complete these steps, the data will be encrypted and, in addition, there will be an encrypted backup of the data.</string> + <string lang="en" key="RAW_DEV_NOT_SUPPORTED_FOR_INPLACE_ENC">TrueCrypt can in-place encrypt only a partition, a dynamic volume, or an entire system drive.\n\nIf you want to create an encrypted TrueCrypt volume within the selected non-system device, choose the option "Create encrypted volume and format it" (instead of the option "Encrypt partition in place").</string> + <string lang="en" key="INPLACE_ENC_INVALID_PATH">Error: TrueCrypt can in-place encrypt only a partition, a dynamic volume, or an entire system drive. Please make sure the specified path is valid.</string> + <string lang="en" key="CANNOT_RESIZE_FILESYS">Error: Cannot shrink the filesystem (the filesystem needs to be shrunk to make space for the volume header and backup header).\n\nPossible causes and solutions:\n\n- Not enough free space on the volume. Please make sure no other application is writing to the filesystem.\n\n- Corrupted file system. Try to check it and fix any errors (right-click the corresponding drive letter in the 'Computer' list, then select Properties > Tools > 'Check Now', make sure the option 'Automatically fix file system errors' is enabled and click Start).\n\nIf the above steps do not help, please follow the below steps.</string> + <string lang="en" key="NOT_ENOUGH_FREE_FILESYS_SPACE_FOR_SHRINK">Error: There is not enough free space on the volume and so the filesystem cannot be shrunk (the filesystem needs to be shrunk to make space for the volume header and backup header).\n\nPlease delete any redundant files and empty the Recycle Bin so as to free at least 256 KB of space and then try again. Note that due to a Windows issue, the amount of free space reported by the Windows Explorer may be incorrect until the operating system is restarted. If restarting the system does not help, the file system may be corrupted. Try to check it and fix any errors (right-click the corresponding drive letter in the 'Computer' list, then select Properties > Tools > 'Check Now', make sure the option 'Automatically fix file system errors' is enabled and click Start).\n\nIf the above steps do not help, please follow the below steps.</string> + <string lang="en" key="DISK_FREE_BYTES">Free space on drive %hs is %.2f bytes.</string> + <string lang="en" key="DISK_FREE_KB">Free space on drive %hs is %.2f KB</string> + <string lang="en" key="DISK_FREE_MB">Free space on drive %hs is %.2f MB</string> + <string lang="en" key="DISK_FREE_GB">Free space on drive %hs is %.2f GB</string> + <string lang="en" key="DISK_FREE_TB">Free space on drive %hs is %.2f TB</string> + <string lang="en" key="DISK_FREE_PB">Free space on drive %hs is %.2f PB</string> + <string lang="en" key="DRIVELETTERS">Could not get available drive letters.</string> + <string lang="en" key="DRIVER_NOT_FOUND">Error: TrueCrypt driver not found.\n\nPlease copy the files 'truecrypt.sys' and 'truecrypt-x64.sys' to the directory where the main TrueCrypt application (TrueCrypt.exe) is located.</string> + <string lang="en" key="DRIVER_VERSION">Error: An incompatible version of the TrueCrypt driver is currently running.\n\nIf you are trying to run TrueCrypt in portable mode (i.e. without installing it) and a different version of TrueCrypt is already installed, you must uninstall it first (or upgrade it using the TrueCrypt installer). To uninstall it, follow these steps: On Windows Vista or later, select 'Start Menu' > Computer > 'Uninstall or change a program' > TrueCrypt > Uninstall; on Windows XP, select 'Start Menu' > Settings > 'Control Panel' > 'Add Or Remove Programs' > TrueCrypt > Remove.\n\nSimilarly, if you are trying to run TrueCrypt in portable mode (i.e. without installing it) and a different version of TrueCrypt is already running in portable mode, you must restart the system first and then run only this new version.</string> + <string lang="en" key="ERR_CIPHER_INIT_FAILURE">Error: Cipher initialization failure.</string> + <string lang="en" key="ERR_CIPHER_INIT_WEAK_KEY">Error: A weak or a potentially weak key has been detected. The key will be discarded. Please try again.</string> + <string lang="en" key="EXCEPTION_REPORT">A critical error has occurred and TrueCrypt must be terminated. If this is caused by a bug in TrueCrypt, we would like to fix it. To help us, you can send us an automatically generated error report containing the following items:\n\n- Program version\n- Operating system version\n- Type of CPU\n- TrueCrypt component name\n- Checksum of TrueCrypt executable\n- Symbolic name of dialog window\n- Error category\n- Error address\n- TrueCrypt call stack\n\nIf you select 'Yes', the following URL (which contains the entire error report) will be opened in your default Internet browser.\n\n%hs\n\nDo you want to send us the above error report?</string> + <string lang="en" key="EXCEPTION_REPORT_EXT">A critical error has occurred in your system, which requires TrueCrypt to be terminated.\n\nNote that this error has not been caused by TrueCrypt (so the TrueCrypt developers cannot fix it). Please, check your system for possible problems (e.g., system configuration, network connection, failing hardware components).</string> + <string lang="en" key="EXCEPTION_REPORT_EXT_FILESEL">A critical error has occurred in your system, which requires TrueCrypt to be terminated.\n\nIf this problem persists, you may want to try disabling or uninstalling applications that could potentially be causing this issue, such as antivirus or Internet security software, system "enhancers", "optimizers" or "tweakers", etc. If it does not help, you may want to try reinstalling your operating system (this problem may also be caused by malware).</string> + <string lang="en" key="EXCEPTION_REPORT_TITLE">TrueCrypt Critical Error</string> + <string lang="en" key="SYSTEM_CRASHED_ASK_REPORT">TrueCrypt detected that the operating system recently crashed. There are many potential reasons why the system could have crashed (for example, a failing hardware component, a bug in a device driver, etc.)\n\nDo you want TrueCrypt to check whether a bug in TrueCrypt could have caused the system crash?</string> + <string lang="en" key="ASK_KEEP_DETECTING_SYSTEM_CRASH">Do you want TrueCrypt to continue detecting system crashes?</string> + <string lang="en" key="NO_MINIDUMP_FOUND">TrueCrypt found no system crash minidump file.</string> + <string lang="en" key="ASK_DELETE_KERNEL_CRASH_DUMP">Do you want to delete the Windows crash dump file to free up disk space?</string> + <string lang="en" key="ASK_DEBUGGER_INSTALL">In order to analyze the system crash, TrueCrypt needs to install Microsoft Debugging Tools for Windows first.\n\nAfter you click OK, the Windows installer will download the Microsoft Debugging Tools installation package (16 MB) from a Microsoft server and install it (the Windows installer will be forwarded to the Microsoft server URL from the truecrypt.org server, which ensures that this feature works even if Microsoft changes the location of the installation package).</string> + <string lang="en" key="SYSTEM_CRASH_ANALYSIS_INFO">After you click OK, TrueCrypt will analyze the system crash. This may take up to several minutes.</string> + <string lang="en" key="DEBUGGER_NOT_FOUND">Please make sure the environment variable 'PATH' includes the path to 'kd.exe' (Kernel Debugger).</string> + <string lang="en" key="SYSTEM_CRASH_NO_TRUECRYPT">It appears that TrueCrypt most likely did not cause the system crash. There are many potential reasons why the system could have crashed (for example, a failing hardware component, a bug in a device driver, etc.)</string> + <string lang="en" key="SYSTEM_CRASH_UPDATE_DRIVER">Results of the analysis indicate that updating the following driver might solve this issue: </string> + <string lang="en" key="SYSTEM_CRASH_REPORT">To help us determine whether there is a bug in TrueCrypt, you can send us an automatically generated error report containing the following items:\n- Program version\n- Operating system version\n- Type of CPU\n- Error category\n- Driver name and version\n- System call stack\n\nIf you select 'Yes', the following URL (which contains the entire error report) will be opened in your default Internet browser.</string> + <string lang="en" key="ASK_SEND_ERROR_REPORT">Do you want to send us the above error report?</string> + <string lang="en" key="ENCRYPT">&Encrypt</string> + <string lang="en" key="DECRYPT">&Decrypt</string> + <string lang="en" key="PERMANENTLY_DECRYPT">&Permanently Decrypt</string> + <string lang="en" key="EXIT">Exit</string> + <string lang="en" key="EXT_PARTITION">Please create a logical drive for this extended partition, and then try again.</string> + <string lang="en" key="FILE_HELP">A TrueCrypt volume can reside in a file (called TrueCrypt container), which can reside on a hard disk, on a USB flash drive, etc. A TrueCrypt container is just like any normal file (it can be, for example, moved or deleted as any normal file). Click 'Select File' to choose a filename for the container and to select the location where you wish the container to be created.\n\nWARNING: If you select an existing file, TrueCrypt will NOT encrypt it; the file will be deleted and replaced with the newly created TrueCrypt container. You will be able to encrypt existing files (later on) by moving them to the TrueCrypt container that you are about to create now.</string> + <string lang="en" key="FILE_HELP_HIDDEN_HOST_VOL">Select the location of the outer volume to be created (within this volume the hidden volume will be created later on).\n\nA TrueCrypt volume can reside in a file (called TrueCrypt container), which can reside on a hard disk, on a USB flash drive, etc. A TrueCrypt container can be moved or deleted as any normal file. Click 'Select File' to choose a filename for the container and to select the location where you wish the container to be created. If you select an existing file, TrueCrypt will NOT encrypt it; it will be deleted and replaced with the newly created container. You will be able to encrypt existing files (later on) by moving them to the TrueCrypt container you are about to create now.</string> + <string lang="en" key="DEVICE_HELP">Encrypted device-hosted TrueCrypt volumes can be created within partitions on hard disks, solid-state drives, USB memory sticks, and on any other supported storage devices. Partitions can also be encrypted in place.\n\nIn addition, encrypted device-hosted TrueCrypt volumes can be created within devices that do not contain any partitions (including hard disks and solid-state drives).\n\nNote: A device that contains partitions can be entirely encrypted in place (using a single key) only if it is the drive where Windows is installed and from which it boots.</string> + <string lang="en" key="DEVICE_HELP_NO_INPLACE">A device-hosted TrueCrypt volume can be created within a hard disk partition, solid-state drive, USB memory stick, and other storage devices.\n\nWARNING: Note that the partition/device will be formatted and all data currently stored on it will be lost.</string> + <string lang="en" key="DEVICE_HELP_HIDDEN_HOST_VOL">\nSelect the location of the outer volume to be created (within this volume the hidden volume will be created later on).\n\nOuter volumes can be created within partitions on hard disks, solid-state drives, USB memory sticks, and on any other supported storage devices. Outer volumes can also be created within devices that do not contain any partitions (including hard disks and solid-state drives).\n\nWARNING: Note that the partition/device will be formatted and all data currently stored on it will be lost.</string> + <string lang="en" key="FILE_HELP_HIDDEN_HOST_VOL_DIRECT">\nSelect the location of the TrueCrypt volume within which you wish to create a hidden volume.</string> + <string lang="en" key="FILE_IN_USE">WARNING: The host file/device is already in use!\n\nIgnoring this can cause undesired results including system instability. All applications that might be using the host file/device (for example, antivirus or backup applications) should be closed before mounting the volume.\n\nContinue mounting?</string> + <string lang="en" key="FILE_IN_USE_FAILED">Error: Cannot mount volume. The host file/device is already in use. Attempt to mount without exclusive access failed as well.</string> + <string lang="en" key="FILE_OPEN_FAILED">The file could not be opened.</string> + <string lang="en" key="FILE_TITLE">Volume Location</string> + <string lang="en" key="FILESYS_PAGE_TITLE">Large Files</string> + <string lang="en" key="FILESYS_PAGE_HELP_QUESTION">Do you intend to store files larger than 4 GB in this TrueCrypt volume?</string> + <string lang="en" key="FILESYS_PAGE_HELP_EXPLANATION">Depending on your choice above, TrueCrypt will choose a suitable default file system for the TrueCrypt volume (you will be able to select a file system in the next step).</string> + <string lang="en" key="FILESYS_PAGE_HELP_EXPLANATION_HIDVOL">As you are creating an outer volume, you should consider choosing 'No'. If you choose 'Yes', the default filesystem will be NTFS, which is not as suitable for outer volumes as FAT (for example, the maximum possible size of the hidden volume will be significantly greater if the outer volume is formatted as FAT). Normally, FAT is the default for both hidden and normal volumes (so FAT volumes are not suspicious). However, if the user indicates intent to store files larger than 4 GB (which the FAT file system does not allow), then FAT is not the default.</string> + <string lang="en" key="FILESYS_PAGE_HELP_EXPLANATION_HIDVOL_CONFIRM">Are you sure you want to choose 'Yes'?</string> + <string lang="en" key="DEVICE_TRANSFORM_MODE_PAGE_TITLE">Volume Creation Mode</string> + <string lang="en" key="DEVICE_TRANSFORM_MODE_PAGE_FORMAT_HELP">This is the fastest way to create a partition-hosted or device-hosted TrueCrypt volume (in-place encryption, which is the other option, is slower because content of each sector has to be first read, encrypted, and then written). Any data currently stored on the selected partition/device will be lost (the data will NOT be encrypted; it will be overwritten with random data). If you want to encrypt existing data on a partition, choose the other option.</string> + <string lang="en" key="DEVICE_TRANSFORM_MODE_PAGE_INPLACE_HELP">The entire selected partition and all data stored on it will be encrypted in place. If the partition is empty, you should choose the other option (the volume will be created much faster).</string> + <string lang="en" key="NOTE_BEGINNING">Note: </string> + <string lang="en" key="RESUME">&Resume</string> + <string lang="en" key="DEFER">&Defer</string> + <string lang="en" key="START">&Start</string> + <string lang="en" key="CONTINUE">&Continue</string> + <string lang="en" key="FORMAT">&Format</string> + <string lang="en" key="WIPE">&Wipe</string> + <string lang="en" key="FORMAT_ABORT">Abort format?</string> + <string lang="en" key="SHOW_MORE_INFORMATION">Show more information</string> + <string lang="en" key="DO_NOT_SHOW_THIS_AGAIN">Do not show this again</string> + <string lang="en" key="WIPE_FINISHED">The content of the partition/device has been successfully erased.</string> + <string lang="en" key="WIPE_FINISHED_DECOY_SYSTEM_PARTITION">The content of the partition where the original system (of which the hidden system is a clone) resided has been successfully erased.</string> + <string lang="en" key="DECOY_OS_VERSION_WARNING">Please make sure the version of Windows you are going to install (on the wiped partition) is the same as the version of Windows you are currently running. This is required due to the fact that both systems will share a common boot partition.</string> + <string lang="en" key="SYSTEM_ENCRYPTION_FINISHED">The system partition/drive has been successfully encrypted.\n\nNote: If there are non-system TrueCrypt volumes that you need to have mounted automatically every time Windows starts, you can set it up by mounting each of them and selecting 'Favorites' > 'Add Mounted Volume to System Favorites').</string> + <string lang="en" key="SYSTEM_DECRYPTION_FINISHED">The system partition/drive has been successfully decrypted.</string> + <string lang="en" key="FORMAT_FINISHED_HELP">\n\nThe TrueCrypt volume has been created and is ready for use. If you wish to create another TrueCrypt volume, click Next. Otherwise, click Exit.</string> + <string lang="en" key="SYSENC_HIDDEN_VOL_FORMAT_FINISHED_HELP">\n\nThe hidden TrueCrypt volume has been successfully created (the hidden operating system will reside within this hidden volume).\n\nClick Next to continue.</string> + <string lang="en" key="NONSYS_INPLACE_ENC_FINISHED_TITLE">Volume Fully Encrypted</string> + <string lang="en" key="NONSYS_INPLACE_ENC_FINISHED_INFO">IMPORTANT: TO MOUNT THIS NEWLY CREATED TRUECRYPT VOLUME AND TO ACCESS DATA STORED IN IT, CLICK 'Auto-Mount Devices' IN THE MAIN TRUECRYPT WINDOW. After you enter the correct password (and/or supply correct keyfiles), the volume will be mounted to the drive letter you select from the list in the main TrueCrypt window (and you will be able to access the encrypted data via the selected drive letter).\n\nPLEASE REMEMBER OR WRITE DOWN THE ABOVE STEPS. YOU MUST FOLLOW THEM WHENEVER YOU WANT TO MOUNT THE VOLUME AND ACCESS DATA STORED IN IT. Alternatively, in the main TrueCrypt window, click 'Select Device', then select this partition/volume, and click 'Mount'.\n\nThe partition/volume has been successfully encrypted (it contains a fully encrypted TrueCrypt volume now) and is ready for use.</string> + <string lang="en" key="FORMAT_FINISHED_INFO">The TrueCrypt volume has been successfully created.</string> + <string lang="en" key="FORMAT_FINISHED_TITLE">Volume Created</string> + <string lang="en" key="FORMAT_HELP">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 encryption keys. Then click Format to create the volume.</string> + <string lang="en" key="FORMAT_HIDVOL_HOST_HELP">Click Format to create the outer volume. For more information, please refer to the documentation.</string> + <string lang="en" key="FORMAT_HIDVOL_HOST_TITLE">Outer Volume Format</string> + <string lang="en" key="FORMAT_HIDVOL_TITLE">Hidden Volume Format</string> + <string lang="en" key="FORMAT_TITLE">Volume Format</string> + <string lang="en" key="HELP_READER_ERROR">Adobe Reader (or a compatible tool) is necessary to view or print the TrueCrypt User's Guide. Adobe Reader (freeware) can be downloaded at: www.adobe.com\n\nDo you want to view the online documentation instead?</string> + <string lang="en" key="HIDDEN_VOL_WIZARD_MODE_NORMAL_HELP">If you select this option, the wizard will first help you create a normal TrueCrypt volume and then a hidden TrueCrypt volume within it. Inexperienced users should always select this option.</string> + <string lang="en" key="HIDDEN_VOL_WIZARD_MODE_DIRECT_HELP">If you select this option, you will create a hidden volume within an existing TrueCrypt volume. It will be assumed that you have already created a TrueCrypt volume that is suitable to host the hidden volume.</string> + <string lang="en" key="HIDDEN_VOL_WIZARD_MODE_TITLE">Volume Creation Mode</string> + <string lang="en" key="HIDVOL_FORMAT_FINISHED_TITLE">Hidden Volume Created</string> + <string lang="en" key="HIDVOL_FORMAT_FINISHED_HELP">The hidden TrueCrypt volume has been successfully created and is ready for use. If all the instructions have been followed and if the precautions and requirements listed in the section "Security Requirements and Precautions Pertaining to Hidden Volumes" in the TrueCrypt User's Guide are followed, it should be impossible to prove that the hidden volume exists, even when the outer volume is mounted.\n\nWARNING: IF YOU DO NOT PROTECT THE HIDDEN VOLUME (FOR INFORMATION ON HOW TO DO SO, REFER TO THE SECTION "PROTECTION OF HIDDEN VOLUMES AGAINST DAMAGE" IN THE TRUECRYPT USER'S GUIDE), DO NOT WRITE TO THE OUTER VOLUME. OTHERWISE, YOU MAY OVERWRITE AND DAMAGE THE HIDDEN VOLUME!</string> + <string lang="en" key="FIRST_HIDDEN_OS_BOOT_INFO">You have started the hidden operating system. As you may have noticed, the hidden operating system appears to be installed on the same partition as the original operating system. However, in reality, it is installed within the partition behind it (in the hidden volume). All read and write operations are being transparently redirected from the original system partition to the hidden volume.\n\nNeither the operating system nor applications will know that data written to and read from the system partition are actually written to and read from the partition behind it (from/to a hidden volume). Any such data is encrypted and decrypted on the fly as usual (with an encryption key different from the one that will be used for the decoy operating system).\n\n\nPlease click Next to continue.</string> + <string lang="en" key="HIDVOL_HOST_FILLING_HELP_SYSENC">The outer volume has been created and mounted as drive %hc:. To this outer volume you should now copy some sensitive-looking files that you actually do NOT want to hide. They will be there for anyone forcing you to disclose the password for the first partition behind the system partition, where both the outer volume and the hidden volume (containing the hidden operating system) will reside. You will be able to reveal the password for this outer volume, and the existence of the hidden volume (and of the hidden operating system) will remain secret.\n\nIMPORTANT: The files you copy to the outer volume should not occupy more than %s. Otherwise, there may not be enough free space on the outer volume for the hidden volume (and you will not be able to continue). After you finish copying, click Next (do not dismount the volume).</string> + <string lang="en" key="HIDVOL_HOST_FILLING_HELP">Outer volume has been successfully created and mounted as drive %hc:. To this volume you should now copy some sensitive-looking files that you actually do NOT want to hide. The files will be there for anyone forcing you to disclose your password. You will reveal only the password for this outer volume, not for the hidden one. The files that you really care about will be stored in the hidden volume, which will be created later on. When you finish copying, click Next. Do not dismount the volume.\n\nNote: After you click Next, cluster bitmap of the outer volume will be scanned to determine the size of uninterrupted area of free space whose end is aligned with the end of the volume. This area will accommodate the hidden volume, so it will limit its maximum possible size. Cluster bitmap scanning ensures that no data on the outer volume are overwritten by the hidden volume.</string> + <string lang="en" key="HIDVOL_HOST_FILLING_TITLE">Outer Volume Contents</string> + <string lang="en" key="HIDVOL_HOST_PRE_CIPHER_HELP">\n\nIn the next steps, you will set the options for the outer volume (within which the hidden volume will be created later on). </string> + <string lang="en" key="HIDVOL_HOST_PRE_CIPHER_HELP_SYSENC">\n\nIn the next steps, you will create a so-called outer TrueCrypt volume within the first partition behind the system partition (as was explained in one of the previous steps).</string> + <string lang="en" key="HIDVOL_HOST_PRE_CIPHER_TITLE">Outer Volume</string> + <string lang="en" key="HIDDEN_OS_PRE_CIPHER_HELP">In the following steps, you will set the options and password for the hidden volume, which will contain the hidden operating system.\n\nRemark: The cluster bitmap of the outer volume has been scanned in order to determine the size of uninterrupted area of free space whose end is aligned with the end of the outer volume. This area will accommodate the hidden volume, so it limits its maximum possible size. The maximum possible size of the hidden volume has been determined and confirmed to be greater than the size of the system partition (which is required, because the entire content of the system partition will need to be copied to the hidden volume). This ensures that no data currently stored on the outer volume will be overwritten by data written to the area of the hidden volume.</string> + <string lang="en" key="HIDDEN_OS_PRE_CIPHER_WARNING">IMPORTANT: Please remember the algorithms that you select in this step. You will have to select the same algorithms for the decoy system. Otherwise, the hidden system will be inaccessible! (The decoy system must be encrypted with the same encryption algorithm as the hidden system.)\n\nNote: The reason is that the decoy system and the hidden system will share a single boot loader, which supports only a single algorithm, selected by the user (for each algorithm, there is a special version of the TrueCrypt Boot Loader).</string> + <string lang="en" key="HIDVOL_PRE_CIPHER_HELP">\n\nThe volume cluster bitmap has been scanned and the maximum possible size of the hidden volume has been determined. In the next steps you will set the options, the size, and the password for the hidden volume.</string> + <string lang="en" key="HIDVOL_PRE_CIPHER_TITLE">Hidden Volume</string> + <string lang="en" key="HIDVOL_PROT_WARN_AFTER_MOUNT">The hidden volume is now protected against damage until the outer volume is dismounted.\n\nWARNING: If any data is attempted to be saved to the hidden volume area, TrueCrypt will start write-protecting the entire volume (both the outer and the hidden part) until it is dismounted. This may cause filesystem corruption on the outer volume, which (if repeated) might adversely affect plausible deniability of the hidden volume. Therefore, you should make every effort to avoid writing to the hidden volume area. Any data being saved to the hidden volume area will not be saved and will be lost. Windows may report this as a write error ("Delayed Write Failed" or "The parameter is incorrect").</string> + <string lang="en" key="HIDVOL_PROT_WARN_AFTER_MOUNT_PLURAL">Each of the hidden volumes within the newly mounted volumes is now protected against damage until dismounted.\n\nWARNING: If any data is attempted to be saved to protected hidden volume area of any of these volumes, TrueCrypt will start write-protecting the entire volume (both the outer and the hidden part) until it is dismounted. This may cause filesystem corruption on the outer volume, which (if repeated) might adversely affect plausible deniability of the hidden volume. Therefore, you should make every effort to avoid writing to the hidden volume area. Any data being saved to protected hidden volume areas will not be saved and will be lost. Windows may report this as a write error ("Delayed Write Failed" or "The parameter is incorrect").</string> + <string lang="en" key="DAMAGE_TO_HIDDEN_VOLUME_PREVENTED">WARNING: Data were attempted to be saved to the hidden volume area of the volume mounted as %c:! TrueCrypt prevented these data from being saved in order to protect the hidden volume. This may have caused filesystem corruption on the outer volume and Windows may have reported a write error ("Delayed Write Failed" or "The parameter is incorrect"). The entire volume (both the outer and the hidden part) will be write-protected until it is dismounted. If this is not the first time TrueCrypt has prevented data from being saved to the hidden volume area of this volume, plausible deniability of this hidden volume might be adversely affected (due to possible unusual correlated inconsistencies within the outer volume file system). Therefore, you should consider creating a new TrueCrypt volume (with Quick Format disabled) and moving files from this volume to the new volume; this volume should be securely erased (both the outer and the hidden part). We strongly recommend that you restart the operating system now.</string> + <string lang="en" key="CANNOT_SATISFY_OVER_4G_FILE_SIZE_REQ">You have indicated intent to store files larger than 4 GB on the volume. This requires the volume to be formatted as NTFS, which, however, will not be possible.</string> + <string lang="en" key="CANNOT_CREATE_NON_HIDDEN_NTFS_VOLUMES_UNDER_HIDDEN_OS">Please note that when a hidden operating system is running, non-hidden TrueCrypt volumes cannot be formatted as NTFS. The reason is that the volume would need to be temporarily mounted without write protection in order to allow the operating system to format it as NTFS (whereas formatting as FAT is performed by TrueCrypt, not by the operating system, and without mounting the volume). For further technical details, see below. You can create a non-hidden NTFS volume from within the decoy operating system.</string> + <string lang="en" key="HIDDEN_VOL_CREATION_UNDER_HIDDEN_OS_HOWTO">For security reasons, when a hidden operating system is running, hidden volumes can be created only in the 'direct' mode (because outer volumes must always be mounted as read-only). To create a hidden volume securely, follow these steps:\n\n1) Boot the decoy system.\n\n2) Create a normal TrueCrypt volume and, to this volume, copy some sensitive-looking files that you actually do NOT want to hide (the volume will become the outer volume).\n\n3) Boot the hidden system and start the TrueCrypt Volume Creation Wizard. If the volume is file-hosted, move it to the system partition or to another hidden volume (otherwise, the newly created hidden volume would be mounted as read-only and could not be formatted). Follow the instructions in the wizard so as to select the 'direct' hidden volume creation mode.\n\n4) In the wizard, select the volume you created in step 2 and then follow the instructions to create a hidden volume within it.</string> + <string lang="en" key="HIDDEN_OS_WRITE_PROTECTION_BRIEF_INFO">For security reasons, when a hidden operating system is running, local unencrypted filesystems and non-hidden TrueCrypt volumes are mounted as read-only (no data can be written to such filesystems or TrueCrypt volumes).\n\nData is allowed to be written to any filesystem that resides within a hidden TrueCrypt volume (provided that the hidden volume is not located in a container stored on an unencrypted filesystem or on any other read-only filesystem).</string> + <string lang="en" key="HIDDEN_OS_WRITE_PROTECTION_EXPLANATION">There are three main reasons why such countermeasures have been implemented:\n\n- It enables the creation of a secure platform for mounting of hidden TrueCrypt volumes. Note that we officially recommend that hidden volumes are mounted only when a hidden operating system is running. (For more information, see the subsection 'Security Requirements and Precautions Pertaining to Hidden Volumes' in the documentation.)\n\n- In some cases, it is possible to determine that, at a certain time, a particular filesystem was not mounted under (or that a particular file on the filesystem was not saved or accessed from within) a particular instance of an operating system (e.g. by analyzing and comparing filesystem journals, file timestamps, application logs, error logs, etc). This might indicate that a hidden operating system is installed on the computer. The countermeasures prevent these issues.\n\n- It prevents data corruption and allows safe hibernation. When Windows resumes from hibernation, it assumes that all mounted filesystems are in the same state as when the system entered hibernation. TrueCrypt ensures this by write-protecting any filesystem accessible both from within the decoy and hidden systems. Without such protection, the filesystem could become corrupted when mounted by one system while the other system is hibernated.</string> + <string lang="en" key="DECOY_TO_HIDDEN_OS_DATA_TRANSFER_HOWTO">Note: If you need to securely transfer files from the decoy system to the hidden system, follow these steps:\n1) Start the decoy system.\n2) Save the files to an unencrypted volume or to an outer/normal TrueCrypt volume.\n3) Start the hidden system.\n4) If you saved the files to a TrueCrypt volume, mount it (it will be automatically mounted as read-only).\n5) Copy the files to the hidden system partition or to another hidden volume.</string> + <string lang="en" key="CONFIRM_RESTART">Your computer must be restarted.\n\nDo you want to restart it now?</string> + <string lang="en" key="ERR_GETTING_SYSTEM_ENCRYPTION_STATUS">An error occurred when obtaining the system encryption status.</string> + <string lang="en" key="INIT_SYS_ENC">Cannot initialize application components for system encryption.</string> + <string lang="en" key="INIT_RAND">Failed to initialize the random number generator!</string> + <string lang="en" key="INIT_REGISTER">Unable to initialize the application. Failed to register the Dialog class.</string> + <string lang="en" key="INIT_RICHEDIT">Error: Failed to load the Rich Edit system library.</string> + <string lang="en" key="INTRO_TITLE">TrueCrypt Volume Creation Wizard</string> + <string lang="en" key="MAX_HIDVOL_SIZE_BYTES">Maximum possible hidden volume size for this volume is %.2f bytes.</string> + <string lang="en" key="MAX_HIDVOL_SIZE_KB">Maximum possible hidden volume size for this volume is %.2f KB.</string> + <string lang="en" key="MAX_HIDVOL_SIZE_MB">Maximum possible hidden volume size for this volume is %.2f MB.</string> + <string lang="en" key="MAX_HIDVOL_SIZE_GB">Maximum possible hidden volume size for this volume is %.2f GB.</string> + <string lang="en" key="MOUNTED_NOPWCHANGE">Volume password/keyfiles cannot be changed while the volume is mounted. Please dismount the volume first.</string> + <string lang="en" key="MOUNTED_NO_PKCS5_PRF_CHANGE">The header key derivation algorithm cannot be changed while the volume is mounted. Please dismount the volume first.</string> + <string lang="en" key="MOUNT_BUTTON">&Mount</string> + <string lang="en" key="NEW_VERSION_REQUIRED">A newer version of TrueCrypt is required to mount this volume.</string> + <string lang="en" key="VOL_CREATION_WIZARD_NOT_FOUND">Error: Volume Creation Wizard not found.\n\nPlease make sure that the file 'TrueCrypt Format.exe' is in the folder from which 'TrueCrypt.exe' was launched. If it is not, please reinstall TrueCrypt, or locate 'TrueCrypt Format.exe' on your disk and run it.</string> + <string lang="en" key="NEXT">&Next ></string> + <string lang="en" key="FINALIZE">&Finish</string> + <string lang="en" key="INSTALL">&Install</string> + <string lang="en" key="EXTRACT">E&xtract</string> + <string lang="en" key="NODRIVER">Unable to connect to the TrueCrypt device driver. TrueCrypt cannot work if the device driver is not running.\n\nPlease note that, due to a Windows issue, it may be necessary to log off or restart the system before the device driver can be loaded.</string> + <string lang="en" key="NOFONT">Error occurred when loading/preparing fonts.</string> + <string lang="en" key="NOT_FOUND">The drive letter was not found or no drive letter was specified.</string> + <string lang="en" key="DRIVE_LETTER_UNAVAILABLE">Drive letter not available.</string> + <string lang="en" key="NO_FILE_SELECTED">No file selected!</string> + <string lang="en" key="NO_FREE_DRIVES">No drive letters available.</string> + <string lang="en" key="NO_FREE_DRIVE_FOR_OUTER_VOL">No free drive letter for the outer volume! Volume creation cannot continue.</string> + <string lang="en" key="NO_OS_VER">Could not determine your operating system version or you are using an unsupported operating system.</string> + <string lang="en" key="NO_PATH_SELECTED">No path selected!</string> + <string lang="en" key="NO_SPACE_FOR_HIDDEN_VOL">Not enough free space for the hidden volume! Volume creation cannot continue.</string> + <string lang="en" key="HIDDEN_VOLUME_TOO_SMALL_FOR_OS_CLONE">Error: The files you copied to the outer volume occupy too much space. Therefore, there is not enough free space on the outer volume for the hidden volume.\n\nNote that the hidden volume must be as large as the system partition (the partition where the currently running operating system is installed). The reason is that the hidden operating system needs to be created by copying the content of the system partition to the hidden volume.\n\n\nThe process of creation of the hidden operating system cannot continue.</string> + <string lang="en" key="OPENFILES_DRIVER">The driver is unable to dismount the volume. Some files located on the volume are probably still open.</string> + <string lang="en" key="OPENFILES_LOCK">Unable to lock the volume. There are still open files on the volume. Therefore, it cannot be dismounted.</string> + <string lang="en" key="VOL_LOCK_FAILED_OFFER_FORCED_DISMOUNT">TrueCrypt cannot lock the volume because it is in use by the system or applications (there may be open files on the volume).\n\nDo you want to force dismount on the volume?</string> + <string lang="en" key="OPEN_VOL_TITLE">Select a TrueCrypt Volume</string> + <string lang="en" key="OPEN_TITLE">Specify Path and File Name</string> + <string lang="en" key="SELECT_PKCS11_MODULE">Select PKCS #11 Library</string> + <string lang="en" key="OUTOFMEMORY">Out of Memory</string> + <string lang="en" key="FORMAT_DEVICE_FOR_ADVANCED_ONLY">IMPORTANT: We strongly recommend that inexperienced users create a TrueCrypt file container on the selected device/partition, instead of attempting to encrypt the entire device/partition.\n\nWhen you create a TrueCrypt file container (as opposed to encrypting a device or partition) there is, for example, no risk of destroying a large number of files. Note that a TrueCrypt file container (even though it contains a virtual encrypted disk) is actually just like any normal file. For more information, see the chapter Beginner's Tutorial in the TrueCrypt User Guide.\n\nAre you sure you want to encrypt the entire device/partition?</string> + <string lang="en" key="OVERWRITEPROMPT">WARNING: The file '%hs' already exists!\n\nIMPORTANT: TRUECRYPT WILL NOT ENCRYPT THE FILE, BUT IT WILL DELETE IT. Are you sure you want to delete the file and replace it with a new TrueCrypt container?</string> + <string lang="en" key="OVERWRITEPROMPT_DEVICE">CAUTION: ALL FILES CURRENTLY STORED ON THE SELECTED %s '%hs'%s WILL BE ERASED AND LOST (THEY WILL NOT BE ENCRYPTED)!\n\nAre you sure you want to proceed with format?</string> + <string lang="en" key="NONSYS_INPLACE_ENC_CONFIRM">WARNING: You will not be able to mount the volume or access any files stored on it until it has been fully encrypted.\n\nAre you sure you want to start encrypting the selected %s '%hs'%s?</string> + <string lang="en" key="NONSYS_INPLACE_ENC_CONFIRM_BACKUP">WARNING: Please note that if power supply is suddenly interrupted while encrypting existing data in place, or when the operating system crashes due to a software error or hardware malfunction while TrueCrypt is encrypting existing data in place, portions of the data will be corrupted or lost. Therefore, before you start encrypting, please make sure that you have backup copies of the files you want to encrypt.\n\nDo you have such a backup?</string> + <string lang="en" key="OVERWRITEPROMPT_DEVICE_HIDDEN_OS_PARTITION">CAUTION: ANY FILES CURRENTLY STORED ON THE PARTITION '%hs'%s (I.E. ON THE FIRST PARTITION BEHIND THE SYSTEM PARTITION) WILL BE ERASED AND LOST (THEY WILL NOT BE ENCRYPTED)!\n\nAre you sure you want to proceed with format?</string> + <string lang="en" key="OVERWRITEPROMPT_DEVICE_SECOND_WARNING_LOTS_OF_DATA">WARNING: THE SELECTED PARTITION CONTAINS A LARGE AMOUNT OF DATA! Any files stored on the partition will be erased and lost (they will NOT be encrypted)!</string> + <string lang="en" key="ERASE_FILES_BY_CREATING_VOLUME">Erase any files stored on the partition by creating a TrueCrypt volume within it</string> + <string lang="en" key="PASSWORD">Password</string> + <string lang="en" key="IDD_PCDM_CHANGE_PKCS5_PRF">Set Header Key Derivation Algorithm</string> + <string lang="en" key="IDD_PCDM_ADD_REMOVE_VOL_KEYFILES">Add/Remove Keyfiles to/from Volume</string> + <string lang="en" key="IDD_PCDM_REMOVE_ALL_KEYFILES_FROM_VOL">Remove All Keyfiles from Volume</string> + <string lang="en" key="PASSWORD_CHANGED">Password and/or keyfile(s) successfully changed.\n\nIMPORTANT: Please make sure you have read the section 'Changing Passwords and Keyfiles' in the chapter 'Security Requirements and Precautions' in the TrueCrypt User Guide.</string> + <string lang="en" key="SYS_PASSWORD_CHANGED_ASK_RESCUE_DISK">IMPORTANT: If you did not destroy your TrueCrypt Rescue Disk, your system partition/drive can still be decrypted using the old password (by booting the TrueCrypt Rescue Disk and entering the old password). You should create a new TrueCrypt Rescue Disk and then destroy the old one.\n\nDo you want to create a new TrueCrypt Rescue Disk?</string> + <string lang="en" key="SYS_HKD_ALGO_CHANGED_ASK_RESCUE_DISK">Note that your TrueCrypt Rescue Disk still uses the previous algorithm. If you consider the previous algorithm insecure, you should create a new TrueCrypt Rescue Disk and then destroy the old one.\n\nDo you want to create a new TrueCrypt Rescue Disk?</string> + <string lang="en" key="KEYFILES_NOTE">Any kind of file (for example, .mp3, .jpg, .zip, .avi) may be used as a TrueCrypt keyfile. Note that TrueCrypt never modifies the keyfile contents. You can select more than one keyfile (the order does not matter). If you add a folder, all non-hidden files found in it will be used as keyfiles. Click 'Add Token Files' to select keyfiles stored on security tokens or smart cards (or to import keyfiles to security tokens or smart cards).</string> + <string lang="en" key="KEYFILE_CHANGED">Keyfile(s) successfully added/removed.</string> + <string lang="en" key="KEYFILE_EXPORTED">Keyfile exported.</string> + <string lang="en" key="PKCS5_PRF_CHANGED">Header key derivation algorithm successfully set.</string> + <string lang="en" key="NONSYS_INPLACE_ENC_RESUME_PASSWORD_PAGE_HELP">Please enter the password and/or keyfile(s) for the non-system volume where you want to resume the process of in-place encryption.\n\n\nRemark: After you click Next, TrueCrypt will attempt to find all non-system volumes where the process of encryption has been interrupted and where the TrueCrypt volume header can be decrypted using the supplied password and/or keyfile(s). If more than one such volume is found, you will need to select one of them in the next step.</string> + <string lang="en" key="NONSYS_INPLACE_ENC_RESUME_VOL_SELECT_HELP">Please select one of the listed volumes. The list contains every accessible non-system volume where the process of encryption has been interrupted and whose header could be decrypted using the supplied password and/or keyfile(s).</string> + <string lang="en" key="PASSWORD_HELP">It is very important that you choose a good password. You should avoid choosing one that contains only a single word that can be found in a dictionary (or a combination of 2, 3, or 4 such words). It should not contain any names or dates of birth. It should not be easy to guess. A good password is a random combination of upper and lower case letters, numbers, and special characters, such as @ ^ = $ * + etc. We recommend choosing a password consisting of more than 20 characters (the longer, the better). The maximum possible length is 64 characters.</string> + <string lang="en" key="PASSWORD_HIDDENVOL_HELP">Please choose a password for the hidden volume. </string> + <string lang="en" key="PASSWORD_HIDDEN_OS_HELP">Please choose a password for the hidden operating system (i.e. for the hidden volume). </string> + <string lang="en" key="PASSWORD_HIDDEN_OS_NOTE">IMPORTANT: The password that you choose for the hidden operating system in this step must be substantially different from the other two passwords (i.e. from the password for the outer volume and from the password for the decoy operating system).</string> + <string lang="en" key="PASSWORD_HIDDENVOL_HOST_DIRECT_HELP">Please enter the password for the volume within which you wish to create a hidden volume.\n\nAfter you click Next, TrueCrypt will attempt to mount the volume. As soon as the volume is mounted, its cluster bitmap will be scanned to determine the size of the uninterrupted area of free space (if there is any) whose end is aligned with the end of the volume. This area will accommodate the hidden volume and therefore will limit its maximum possible size. Cluster map scanning is necessary to ensure that no data on the outer volume will be overwritten by the hidden volume.</string> + <string lang="en" key="PASSWORD_HIDDENVOL_HOST_HELP">\nPlease choose a password for the outer volume. This will be the password that you will be able to reveal to an adversary if you are asked or forced to do so.\n\nIMPORTANT: The password must be substantially different from the one you will choose for the hidden volume.\n\nNote: The maximum possible password length is 64 characters.</string> + <string lang="en" key="PASSWORD_SYSENC_OUTERVOL_HELP">Please choose a password for the outer volume. This will be the password you will be able to reveal to anyone forcing you to disclose the password for the first partition behind the system partition, where both the outer volume and the hidden volume (containing the hidden operating system) will reside. The existence of the hidden volume (and of the hidden operating system) will remain secret. Note that this password is not for the decoy operating system.\n\nIMPORTANT: The password must be substantially different from the one you will choose for the hidden volume (i.e. for the hidden operating system).</string> + <string lang="en" key="PASSWORD_HIDVOL_HOST_TITLE">Outer Volume Password</string> + <string lang="en" key="PASSWORD_HIDVOL_TITLE">Hidden Volume Password</string> + <string lang="en" key="PASSWORD_HIDDEN_OS_TITLE">Password for Hidden Operating System</string> + <string lang="en" key="PASSWORD_LENGTH_WARNING">WARNING: Short passwords are easy to crack using brute force techniques!\n\nWe recommend choosing a password consisting of more than 20 characters. Are you sure you want to use a short password?</string> + <string lang="en" key="PASSWORD_TITLE">Volume Password</string> + <string lang="en" key="PASSWORD_WRONG">Incorrect password or not a TrueCrypt volume.</string> + <string lang="en" key="PASSWORD_OR_KEYFILE_WRONG">Incorrect keyfile(s) and/or password or not a TrueCrypt volume.</string> + <string lang="en" key="PASSWORD_OR_MODE_WRONG">Wrong mount mode, incorrect password, or not a TrueCrypt volume.</string> + <string lang="en" key="PASSWORD_OR_KEYFILE_OR_MODE_WRONG">Wrong mount mode, incorrect keyfile(s) and/or password, or not a TrueCrypt volume.</string> + <string lang="en" key="PASSWORD_WRONG_AUTOMOUNT">Incorrect password or no TrueCrypt volume found.</string> + <string lang="en" key="PASSWORD_OR_KEYFILE_WRONG_AUTOMOUNT">Incorrect keyfile(s)/password or no TrueCrypt volume found.</string> + <string lang="en" key="PASSWORD_WRONG_CAPSLOCK_ON">\n\nWarning: Caps Lock is on. This may cause you to enter your password incorrectly.</string> + <string lang="en" key="HIDDEN_FILES_PRESENT_IN_KEYFILE_PATH">\n\nWARNING: Hidden file(s) have been found in a keyfile search path. Such hidden files cannot be used as keyfiles. If you need to use them as keyfiles, remove their 'Hidden' attribute (right-click each of them, select 'Properties', uncheck 'Hidden' and click OK). Note: Hidden files are visible only if the corresponding option is enabled (Computer > Organize > 'Folder and search options' > View).</string> + <string lang="en" key="HIDDEN_VOL_PROT_PASSWORD_US_KEYB_LAYOUT">If you are attempting to protect a hidden volume containing a hidden system, please make sure you are using the standard US keyboard layout when typing the password for the hidden volume. This is required due to the fact that the password needs to be typed in the pre-boot environment (before Windows starts) where non-US Windows keyboard layouts are not available.</string> + <string lang="en" key="FOUND_NO_PARTITION_W_DEFERRED_INPLACE_ENC">TrueCrypt has not found any volume where non-system encryption has been interrupted and where the volume header can be decrypted using the supplied password and/or keyfile(s).\n\nPlease make sure the password and/or keyfile(s) are correct and that the partition/volume is not being used by the system or applications (including antivirus software).</string> + <string lang="en" key="SYSENC_MOUNT_WITHOUT_PBA_NOTE">\n\nNote: If you are attempting to mount a partition located on an encrypted system drive without pre-boot authentication or to mount the encrypted system partition of an operating system that is not running, you can do so by selecting 'System' > 'Mount Without Pre-Boot Authentication'.</string> + <string lang="en" key="MOUNT_WITHOUT_PBA_VOL_ON_ACTIVE_SYSENC_DRIVE">In this mode, you cannot mount a partition located on a drive whose portion is within the key scope of active system encryption.\n\nBefore you can mount this partition in this mode, you need to either boot an operating system installed on a different drive (encrypted or unencrypted) or boot an unencrypted operating system.</string> + <string lang="en" key="PREV">< &Back</string> + <string lang="en" key="RAWDEVICES">Unable to list raw devices installed on your system!</string> + <string lang="en" key="READONLYPROMPT">The volume '%hs' exists, and is read-only. Are you sure you want to replace it?</string> + <string lang="en" key="SELECT_DEST_DIR">Select destination directory</string> + <string lang="en" key="SELECT_KEYFILE">Select Keyfile</string> + <string lang="en" key="SELECT_KEYFILE_PATH">Select a keyfile search path. WARNING: Note that only the path will be remembered, not the filenames!</string> + <string lang="en" key="SERPENT_HELP">Designed by Ross Anderson, Eli Biham, and Lars Knudsen. Published in 1998. 256-bit key, 128-bit block. Mode of operation is XTS. Serpent was one of the AES finalists.</string> + <string lang="en" key="SIZE_HELP">Please specify the size of the container you want to create.\n\nIf you create a dynamic (sparse-file) container, this parameter will specify its maximum possible size.\n\nNote that the minimum possible size of a FAT volume is 292 KB. The minimum possible size of an NTFS volume is 3792 KB.</string> + <string lang="en" key="SIZE_HELP_HIDDEN_HOST_VOL">Please specify the size of the outer volume to be created (you will first create the outer volume and then a hidden volume within it). The minimum possible size of a volume within which a hidden volume is intended to be created is 340 KB.</string> + <string lang="en" key="SIZE_HELP_HIDDEN_VOL">Please specify the size of the hidden volume to create. The minimum possible size of a hidden volume is 40 KB (or 3664 KB if it is formatted as NTFS). The maximum possible size you can specify for the hidden volume is displayed above.</string> + <string lang="en" key="SIZE_HIDVOL_HOST_TITLE">Outer Volume Size</string> + <string lang="en" key="SIZE_HIDVOL_TITLE">Hidden Volume Size</string> + <string lang="en" key="SIZE_PARTITION_HELP">Please verify that the size of the selected device/partition shown above is correct and click Next.</string> + <string lang="en" key="SIZE_PARTITION_HIDDEN_SYSENC_HELP">The outer volume and the hidden volume (containing the hidden operating system) will reside within the above partition. It should be the first partition behind the system partition.\n\nPlease verify that the size of the partition and its number shown above are correct, and if they are, click Next.</string> + <string lang="en" key="SIZE_PARTITION_HIDDEN_VOL_HELP">\n\nNote that the minimum possible size of a volume within which a hidden volume is intended to be created is 340 KB.</string> + <string lang="en" key="SIZE_TITLE">Volume Size</string> + <string lang="en" key="SPARSE_FILE">Dynamic</string> + <string lang="en" key="TESTS_FAILED">CAUTION: SELF-TEST FAILED!</string> + <string lang="en" key="TESTS_PASSED">Self-tests of all algorithms passed</string> + <string lang="en" key="TEST_INCORRECT_TEST_DATA_UNIT_SIZE">The data unit number that you supplied is too long or short.</string> + <string lang="en" key="TEST_INCORRECT_SECONDARY_KEY_SIZE">The secondary key that you supplied is too long or short.</string> + <string lang="en" key="TEST_CIPHERTEXT_SIZE">The test ciphertext you have supplied is too long or short.</string> + <string lang="en" key="TEST_KEY_SIZE">The test key you have supplied is too long or short.</string> + <string lang="en" key="TEST_PLAINTEXT_SIZE">The test plaintext you have supplied is too long or short.</string> + <string lang="en" key="TWO_LAYER_CASCADE_HELP">Two ciphers in a cascade operating in XTS mode. Each block is first encrypted with %hs (%d-bit key) and then with %hs (%d-bit key). Each cipher uses its own key. All keys are mutually independent.</string> + <string lang="en" key="THREE_LAYER_CASCADE_HELP">Three ciphers in a cascade operating in XTS mode. Each block is first encrypted with %hs (%d-bit key), then with %hs (%d-bit key), and finally with %hs (%d-bit key). Each cipher uses its own key. All keys are mutually independent.</string> + <string lang="en" key="AUTORUN_MAY_NOT_ALWAYS_WORK">Note that, depending on the operating system configuration, these auto-run and auto-mount features may work only when the traveler disk files are created on a non-writable CD/DVD-like medium. Also note that this is not a bug in TrueCrypt (it is a limitation of Windows).</string> + <string lang="en" key="TRAVELER_DISK_CREATED">TrueCrypt traveler disk has been successfully created.\n\nNote that you need administrator privileges to run TrueCrypt in portable mode. Also note that, after examining the registry file, it may be possible to tell that TrueCrypt was run on a Windows system even if it is run in portable mode.</string> + <string lang="en" key="TC_TRAVELER_DISK">TrueCrypt Traveler Disk</string> + <string lang="en" key="TWOFISH_HELP">Designed by Bruce Schneier, John Kelsey, Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson. Published in 1998. 256-bit key, 128-bit block. Mode of operation is XTS. Twofish was one of the AES finalists.</string> + <string lang="en" key="MORE_INFO_ABOUT">More information on %hs</string> + <string lang="en" key="UNKNOWN">Unknown</string> + <string lang="en" key="ERR_UNKNOWN">An unspecified or unknown error occurred (%d).</string> + <string lang="en" key="UNMOUNTALL_LOCK_FAILED">Some volumes contain files or folders being used by applications or system.\n\nForce dismount?</string> + <string lang="en" key="UNMOUNT_BUTTON">&Dismount</string> + <string lang="en" key="UNMOUNT_FAILED">Dismount failed!</string> + <string lang="en" key="UNMOUNT_LOCK_FAILED">Volume contains files or folders being used by applications or system.\n\nForce dismount?</string> + <string lang="en" key="NO_VOLUME_MOUNTED_TO_DRIVE">No volume is mounted to the specified drive letter.</string> + <string lang="en" key="VOL_ALREADY_MOUNTED">The volume you are trying to mount is already mounted. </string> + <string lang="en" key="VOL_MOUNT_FAILED">An error occurred when attempting to mount volume.</string> + <string lang="en" key="VOL_SEEKING">Error seeking location within volume.</string> + <string lang="en" key="VOL_SIZE_WRONG">Error: Incorrect volume size.</string> + <string lang="en" key="WARN_QUICK_FORMAT">WARNING: You should use Quick Format only in the following cases:\n\n1) The device contains no sensitive data and you do not need plausible deniability.\n2) The device has already been securely and fully encrypted.\n\nAre you sure you want to use Quick Format?</string> + <string lang="en" key="CONFIRM_SPARSE_FILE">Dynamic container is a pre-allocated NTFS sparse file whose physical size (actual disk space used) grows as new data is added to it.\n\nWARNING: Performance of sparse-file-hosted volumes is significantly worse than performance of regular volumes. Sparse-file-hosted volumes are also less secure, because it is possible to tell which volume sectors are unused. Furthermore, sparse-file-hosted volumes cannot provide plausible deniability (host a hidden volume). Also note that if data is written to a sparse file container when there is not enough free space in the host file system, the encrypted file system may get corrupted.\n\nAre you sure you want to create a sparse-file-hosted volume?</string> + <string lang="en" key="SPARSE_FILE_SIZE_NOTE">Note that the size of the dynamic container reported by Windows and by TrueCrypt will always be equal to its maximum size. To find out current physical size of the container (actual disk space it uses), right-click the container file (in a Windows Explorer window, not in TrueCrypt), then select 'Properties' and see the 'Size on disk' value.\n\nAlso note that if you move a dynamic container to another volume or drive, the physical size of the container will be extended to the maximum. (You can prevent that by creating a new dynamic container in the destination location, mounting it and then moving the files from the old container to the new one.)</string> + <string lang="en" key="PASSWORD_CACHE_WIPED_SHORT">Password cache wiped</string> + <string lang="en" key="PASSWORD_CACHE_WIPED">Passwords (and/or processed keyfile contents) stored in the TrueCrypt driver cache have been wiped.</string> + <string lang="en" key="WRONG_VOL_TYPE">TrueCrypt cannot change the password for a foreign volume.</string> + <string lang="en" key="SELECT_FREE_DRIVE">Please select a free drive letter from the list.</string> + <string lang="en" key="SELECT_A_MOUNTED_VOLUME">Please select a mounted volume in the drive letter list.</string> + <string lang="en" key="AMBIGUOUS_VOL_SELECTION">Two different mounted volumes are currently selected (one in the drive letter list and the other in the input field below the list).\n\nPlease choose the volume you wanted to select:</string> + <string lang="en" key="CANT_CREATE_AUTORUN">Error: Cannot create autorun.inf</string> + <string lang="en" key="ERR_PROCESS_KEYFILE">Error while processing keyfile!</string> + <string lang="en" key="ERR_PROCESS_KEYFILE_PATH">Error processing keyfile path!</string> + <string lang="en" key="ERR_KEYFILE_PATH_EMPTY">The keyfile path contains no files.\n\nPlease note that folders (and files they contain) found in keyfile search paths are ignored.</string> + <string lang="en" key="UNSUPPORTED_OS">TrueCrypt does not support this operating system.</string> + <string lang="en" key="UNSUPPORTED_BETA_OS">Error: TrueCrypt supports only stable versions of this operating system (beta/RC versions are not supported).</string> + <string lang="en" key="ERR_MEM_ALLOC">Error: Cannot allocate memory.</string> + <string lang="en" key="ERR_PERF_COUNTER">Error: Could not retrieve value of performance counter.</string> + <string lang="en" key="ERR_VOL_FORMAT_BAD">Error: Bad volume format.</string> + <string lang="en" key="ERR_HIDDEN_NOT_NORMAL_VOLUME">Error: You supplied a password for a hidden volume (not for a normal volume).</string> + <string lang="en" key="ERR_HIDDEN_VOL_HOST_ENCRYPTED_INPLACE">For security reasons, a hidden volume cannot be created within a TrueCrypt volume containing a filesystem that has been encrypted in place (because the free space on the volume has not been filled with random data).</string> + <string lang="en" key="LEGAL_NOTICES_DLG_TITLE">TrueCrypt - Legal Notices</string> + <string lang="en" key="ALL_FILES">All Files</string> + <string lang="en" key="TC_VOLUMES">TrueCrypt Volumes</string> + <string lang="en" key="DLL_FILES">Library Modules</string> + <string lang="en" key="FORMAT_NTFS_STOP">NTFS formatting cannot continue.</string> + <string lang="en" key="CANT_MOUNT_VOLUME">Cannot mount volume.</string> + <string lang="en" key="CANT_DISMOUNT_VOLUME">Cannot dismount volume.</string> + <string lang="en" key="FORMAT_NTFS_FAILED">Windows failed to format the volume as NTFS.\n\nPlease select a different type of file system (if possible) and try again. Alternatively, you could leave the volume unformatted (select 'None' as the filesystem), exit this wizard, mount the volume, and then use either a system or a third-party tool to format the mounted volume (the volume will remain encrypted).</string> + <string lang="en" key="FORMAT_NTFS_FAILED_ASK_FAT">Windows failed to format the volume as NTFS.\n\nDo you want to format the volume as FAT instead?</string> + <string lang="en" key="DEFAULT">Default</string> + <string lang="en" key="PARTITION_LOWER_CASE">partition</string> + <string lang="en" key="PARTITION_UPPER_CASE">PARTITION</string> + <string lang="en" key="DEVICE">Device</string> + <string lang="en" key="DEVICE_LOWER_CASE">device</string> + <string lang="en" key="DEVICE_UPPER_CASE">DEVICE</string> + <string lang="en" key="VOLUME">Volume</string> + <string lang="en" key="VOLUME_LOWER_CASE">volume</string> + <string lang="en" key="VOLUME_UPPER_CASE">VOLUME</string> + <string lang="en" key="LABEL">Label</string> + <string lang="en" key="CLUSTER_TOO_SMALL">The selected cluster size is too small for this volume size. A greater cluster size will be used instead.</string> + <string lang="en" key="CANT_GET_VOLSIZE">Error: Cannot get volume size!\n\nMake sure the selected volume is not being used by the system or an application.</string> + <string lang="en" key="HIDDEN_VOL_HOST_SPARSE">Hidden volumes must not be created within dynamic (sparse file) containers. To achieve plausible deniability, the hidden volume needs to be created within a non-dynamic container.</string> + <string lang="en" key="HIDDEN_VOL_HOST_UNSUPPORTED_FILESYS">The TrueCrypt Volume Creation Wizard can create a hidden volume only within a FAT or NTFS volume.</string> + <string lang="en" key="HIDDEN_VOL_HOST_UNSUPPORTED_FILESYS_WIN2000">Under Windows 2000, the TrueCrypt Volume Creation Wizard can create a hidden volume only within a FAT volume.</string> + <string lang="en" key="HIDDEN_VOL_HOST_NTFS">Note: The FAT file system is more suitable for outer volumes than the NTFS file system (for example, the maximum possible size of the hidden volume would very likely have been significantly greater if the outer volume had been formatted as FAT).</string> + <string lang="en" key="HIDDEN_VOL_HOST_NTFS_ASK">Note that the FAT file system is more suitable for outer volumes than the NTFS file system. For example, the maximum possible size of the hidden volume will very likely be significantly greater if the outer volume is formatted as FAT (the reason is that the NTFS file system always stores internal data exactly in the middle of the volume and, therefore, the hidden volume can reside only in the second half of the outer volume).\n\nAre you sure you want to format the outer volume as NTFS?</string> + <string lang="en" key="OFFER_FAT_FORMAT_ALTERNATIVE">Do you want to format the volume as FAT instead?</string> + <string lang="en" key="FAT_NOT_AVAILABLE_FOR_SO_LARGE_VOLUME">Note: This volume cannot be formatted as FAT, because it exceeds the maximum volume size supported by the FAT32 filesystem for the applicable sector size (2 TB for 512-byte sectors and 16 TB for 4096-byte sectors).</string> + <string lang="en" key="PARTITION_TOO_SMALL_FOR_HIDDEN_OS">Error: The partition for the hidden operating system (i.e. the first partition behind the system partition) must be at least 5% larger than the system partition (the system partition is the one where the currently running operating system is installed).</string> + <string lang="en" key="PARTITION_TOO_SMALL_FOR_HIDDEN_OS_NTFS">Error: The partition for the hidden operating system (i.e. the first partition behind the system partition) must be at least 110% (2.1 times) larger than the system partition (the system partition is the one where the currently running operating system is installed). The reason is that the NTFS file system always stores internal data exactly in the middle of the volume and, therefore, the hidden volume (which is to contain a clone of the system partition) can reside only in the second half of the partition.</string> + <string lang="en" key="OUTER_VOLUME_TOO_SMALL_FOR_HIDDEN_OS_NTFS">Error: If the outer volume is formatted as NTFS, it must be at least 110% (2.1 times) larger than the system partition. The reason is that the NTFS file system always stores internal data exactly in the middle of the volume and, therefore, the hidden volume (which is to contain a clone of the system partition) can reside only in the second half of the outer volume.\n\nNote: The outer volume needs to reside within the same partition as the hidden operating system (i.e. within the first partition behind the system partition).</string> + <string lang="en" key="NO_PARTITION_FOLLOWS_BOOT_PARTITION">Error: There is no partition behind the system partition.\n\nNote that before you can create a hidden operating system, you need to create a partition for it on the system drive. It must be the first partition behind the system partition and it must be at least 5% larger than the system partition (the system partition is the one where the currently running operating system is installed). However, if the outer volume (not to be confused with the system partition) is formatted as NTFS, the partition for the hidden operating system must be at least 110% (2.1 times) larger than the system partition (the reason is that the NTFS file system always stores internal data exactly in the middle of the volume and, therefore, the hidden volume, which is to contain a clone of the system partition, can reside only in the second half of the partition).</string> + <string lang="en" key="TWO_SYSTEMS_IN_ONE_PARTITION_REMARK">Remark: It is not practical (and therefore is not supported) to install operating systems in two TrueCrypt volumes that are embedded within a single partition, because using the outer operating system would often require data to be written to the area of the hidden operating system (and if such write operations were prevented using the hidden volume protection feature, it would inherently cause system crashes, i.e. 'Blue Screen' errors).</string> + <string lang="en" key="FOR_MORE_INFO_ON_PARTITIONS">For information on how to create and manage partitions, please refer to the documentation supplied with your operating system or contact your computer vendor's technical support team for assistance.</string> + <string lang="en" key="SYSTEM_PARTITION_NOT_ACTIVE">Error: The currently running operating system is not installed on the boot partition (first Active partition). This is not supported.</string> + <string lang="en" key="CONFIRM_FAT_FOR_FILES_OVER_4GB">You indicated that you intend to store files larger than 4 GB in this TrueCrypt volume. However, you chose the FAT file system, on which files larger than 4 GB cannot be stored.\n\nAre you sure you want to format the volume as FAT?</string> + <string lang="en" key="CANT_ACCESS_VOL">Error: Cannot access the volume!\n\nMake sure that the selected volume exists, that it is not mounted or being used by the system or an application, that you have read/write permission for the volume, and that it is not write-protected.</string> + <string lang="en" key="INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL">Error: Cannot access the volume and/or obtain information about the volume.\n\nMake sure that the selected volume exists, that it is not being used by the system or applications, that you have read/write permission for the volume, and that it is not write-protected.</string> + <string lang="en" key="INPLACE_ENC_CANT_ACCESS_OR_GET_INFO_ON_VOL_ALT">Error: Cannot access the volume and/or obtain information about the volume. Make sure that the selected volume exists, that it is not being used by the system or applications, that you have read/write permission for the volume, and that it is not write-protected.\n\nIf the problem persists, it might help to follow the below steps.</string> + <string lang="en" key="INPLACE_ENC_GENERIC_ERR_ALT_STEPS">An error prevented TrueCrypt from encrypting the partition. Please try fixing any previously reported problems and then try again. If the problems persist, it might help to follow the below steps.</string> + <string lang="en" key="INPLACE_ENC_GENERIC_ERR_RESUME">An error prevented TrueCrypt from resuming the process of encryption of the partition.\n\nPlease try fixing any previously reported problems and then try resuming the process again. Note that the volume cannot be mounted until it has been fully encrypted.</string> + <string lang="en" key="CANT_DISMOUNT_OUTER_VOL">Error: Cannot dismount the outer volume!\n\nVolume cannot be dismounted if it contains files or folders being used by a program or the system.\n\nPlease close any program that might be using files or directories on the volume and click Retry.</string> + <string lang="en" key="CANT_GET_OUTER_VOL_INFO">Error: Cannot obtain information about the outer volume!\nVolume creation cannot continue.</string> + <string lang="en" key="CANT_ACCESS_OUTER_VOL">Error: Cannot access the outer volume! Volume creation cannot continue.</string> + <string lang="en" key="CANT_MOUNT_OUTER_VOL">Error: Cannot mount the outer volume! Volume creation cannot continue.</string> + <string lang="en" key="CANT_GET_CLUSTER_BITMAP">Error: Cannot get volume cluster bitmap! Volume creation cannot continue.</string> + <string lang="en" key="ALPHABETICAL_CATEGORIZED">Alphabetical/Categorized</string> + <string lang="en" key="MEAN_SPEED">Mean Speed (Descending)</string> + <string lang="en" key="ALGORITHM">Algorithm</string> + <string lang="en" key="ENCRYPTION">Encryption</string> + <string lang="en" key="DECRYPTION">Decryption</string> + <string lang="en" key="MEAN">Mean</string> + <string lang="en" key="DRIVE">Drive</string> + <string lang="en" key="SIZE">Size</string> + <string lang="en" key="ENCRYPTION_ALGORITHM">Encryption Algorithm</string> + <string lang="en" key="ENCRYPTION_ALGORITHM_LV">Encryption algorithm</string> + <string lang="en" key="TYPE">Type</string> + <string lang="en" key="VALUE">Value</string> + <string lang="en" key="PROPERTY">Property</string> + <string lang="en" key="LOCATION">Location</string> + <string lang="en" key="BYTES">bytes</string> + <string lang="en" key="HIDDEN">Hidden</string> + <string lang="en" key="OUTER">Outer</string> + <string lang="en" key="NORMAL">Normal</string> + <string lang="en" key="SYSTEM_VOLUME_TYPE_ADJECTIVE">System</string> + <string lang="en" key="TYPE_HIDDEN_SYSTEM_ADJECTIVE">Hidden (system)</string> + <string lang="en" key="READ_ONLY">Read-Only</string> + <string lang="en" key="SYSTEM_DRIVE">System drive</string> + <string lang="en" key="SYSTEM_DRIVE_ENCRYPTING">System drive (encrypting - %.2f%% done)</string> + <string lang="en" key="SYSTEM_DRIVE_DECRYPTING">System drive (decrypting - %.2f%% done)</string> + <string lang="en" key="SYSTEM_DRIVE_PARTIALLY_ENCRYPTED">System drive (%.2f%% encrypted)</string> + <string lang="en" key="SYSTEM_PARTITION">System partition</string> + <string lang="en" key="HIDDEN_SYSTEM_PARTITION">Hidden system partition</string> + <string lang="en" key="SYSTEM_PARTITION_ENCRYPTING">System partition (encrypting - %.2f%% done)</string> + <string lang="en" key="SYSTEM_PARTITION_DECRYPTING">System partition (decrypting - %.2f%% done)</string> + <string lang="en" key="SYSTEM_PARTITION_PARTIALLY_ENCRYPTED">System partition (%.2f%% encrypted)</string> + <string lang="en" key="HID_VOL_DAMAGE_PREVENTED">Yes (damage prevented!)</string> + <string lang="en" key="NONE">None</string> + <string lang="en" key="KEY_SIZE">Primary Key Size</string> + <string lang="en" key="SECONDARY_KEY_SIZE_XTS">Secondary Key Size (XTS Mode)</string> + <string lang="en" key="SECONDARY_KEY_SIZE_LRW">Tweak Key Size (LRW Mode)</string> + <string lang="en" key="BITS">bits</string> + <string lang="en" key="BLOCK_SIZE">Block Size</string> + <string lang="en" key="PKCS5_PRF">PKCS-5 PRF</string> + <string lang="en" key="PKCS5_ITERATIONS">PKCS-5 Iteration Count</string> + <string lang="en" key="VOLUME_CREATE_DATE">Volume Created</string> + <string lang="en" key="VOLUME_HEADER_DATE">Header Last Modified</string> + <string lang="en" key="VOLUME_HEADER_DAYS"> (%I64d days ago)</string> + <string lang="en" key="VOLUME_FORMAT_VERSION">Volume Format Version</string> + <string lang="en" key="BACKUP_HEADER">Embedded Backup Header</string> + <string lang="en" key="TC_BOOT_LOADER_VERSION">TrueCrypt Boot Loader Version</string> + <string lang="en" key="FIRST_AVAILABLE">First available</string> + <string lang="en" key="REMOVABLE_DISK">Removable Disk</string> + <string lang="en" key="HARDDISK">Harddisk</string> + <string lang="en" key="UNCHANGED">Unchanged</string> + <string lang="en" key="SETUP_MODE_TITLE">Wizard Mode</string> + <string lang="en" key="SETUP_MODE_INFO">Select one of the modes. If you are not sure which to select, use the default mode.</string> + <string lang="en" key="SETUP_MODE_HELP_INSTALL">Select this option if you want to install TrueCrypt on this system.</string> + <string lang="en" key="SETUP_MODE_HELP_UPGRADE">Note: You can upgrade without decrypting even if the system partition/drive is encrypted or you use a hidden operating system.</string> + <string lang="en" key="SETUP_MODE_HELP_EXTRACT">If you select this option, all files will be extracted from this package but nothing will be installed on the system. Do not select it if you intend to encrypt the system partition or system drive. Selecting this option can be useful, for example, if you want to run TrueCrypt in so-called portable mode. TrueCrypt does not have to be installed on the operating system under which it is run. After all files are extracted, you can directly run the extracted file 'TrueCrypt.exe' (then TrueCrypt will run in portable mode).</string> + <string lang="en" key="SETUP_OPTIONS_TITLE">Setup Options</string> + <string lang="en" key="SETUP_OPTIONS_INFO">Here you can set various options to control the installation process.</string> + <string lang="en" key="SETUP_PROGRESS_TITLE">Installing</string> + <string lang="en" key="SETUP_PROGRESS_INFO">Please wait while TrueCrypt is being installed.</string> + <string lang="en" key="SETUP_FINISHED_TITLE_DON">TrueCrypt has been successfully installed</string> + <string lang="en" key="SETUP_FINISHED_UPGRADE_TITLE_DON">TrueCrypt has been successfully upgraded</string> + <string lang="en" key="SETUP_FINISHED_INFO_DON">Please consider making a donation. You can click Finish anytime to close the installer.</string> + <string lang="en" key="EXTRACTION_OPTIONS_TITLE">Extraction Options</string> + <string lang="en" key="EXTRACTION_OPTIONS_INFO">Here you can set various options to control the extraction process.</string> + <string lang="en" key="EXTRACTION_PROGRESS_INFO">Please wait while files are being extracted.</string> + <string lang="en" key="EXTRACTION_FINISHED_TITLE_DON">Files successfully extracted</string> + <string lang="en" key="EXTRACTION_FINISHED_INFO">All files have been successfully extracted to the destination location.</string> + <string lang="en" key="AUTO_FOLDER_CREATION">If the specified folder does not exist, it will be automatically created.</string> + <string lang="en" key="SETUP_UPGRADE_DESTINATION">The TrueCrypt program files will be upgraded in the location where TrueCrypt is installed. If you need to select a different location, please uninstall TrueCrypt first.</string> + <string lang="en" key="AFTER_UPGRADE_RELEASE_NOTES">Do you want to view release notes for the current (latest stable) version of TrueCrypt?</string> + <string lang="en" key="AFTER_INSTALL_TUTORIAL">If you have never used TrueCrypt before, we recommend that you read the chapter Beginner's Tutorial in the TrueCrypt User Guide. Do you want to view the tutorial?</string> + <string lang="en" key="SELECT_AN_ACTION">Please select an action to perform from the following:</string> + <string lang="en" key="REPAIR_REINSTALL">Repair/Reinstall</string> + <string lang="en" key="UPGRADE">Upgrade</string> + <string lang="en" key="UNINSTALL">Uninstall</string> + <string lang="en" key="SETUP_ADMIN">To successfully install/uninstall TrueCrypt, you must have administrator privileges. Do you want to continue?</string> + <string lang="en" key="TC_INSTALLER_IS_RUNNING">TrueCrypt Installer is currently running on this system and performing or preparing installation or update of TrueCrypt. Before you proceed, please wait for it to finish or close it. If you cannot close it, please restart your computer before proceeding.</string> + <string lang="en" key="INSTALL_FAILED">Installation failed.</string> + <string lang="en" key="UNINSTALL_FAILED">Uninstallation failed.</string> + <string lang="en" key="DIST_PACKAGE_CORRUPTED">This distribution package is damaged. Please try downloading it again (preferably from the official TrueCrypt website at www.truecrypt.org).</string> + <string lang="en" key="CANNOT_WRITE_FILE_X">Cannot write file %hs</string> + <string lang="en" key="EXTRACTING_VERB">Extracting</string> + <string lang="en" key="CANNOT_READ_FROM_PACKAGE">Cannot read data from the package.</string> + <string lang="en" key="CANT_VERIFY_PACKAGE_INTEGRITY">Cannot verify the integrity of this distribution package.</string> + <string lang="en" key="EXTRACTION_FAILED">Extraction failed.</string> + <string lang="en" key="ROLLBACK">The installation has been rolled back.</string> + <string lang="en" key="INSTALL_OK">TrueCrypt has been successfully installed.</string> + <string lang="en" key="SETUP_UPDATE_OK">TrueCrypt has been successfully updated.</string> + <string lang="en" key="UPGRADE_OK_REBOOT_REQUIRED">TrueCrypt has been successfully upgraded. However, before you can start using it, the computer must be restarted.\n\nDo you want to restart it now?</string> + <string lang="en" key="SYS_ENC_UPGRADE_FAILED">Failed to upgrade TrueCrypt!\n\nIMPORTANT: Before you shut down or restart the system, we strongly recommend that you use System Restore (Windows Start menu > All programs > Accessories > System Tools > System Restore) to restore your system to the restore point named 'TrueCrypt installation'. If System Restore is not available, you should try installing the original or the new version of TrueCrypt again before you shut down or restart the system.</string> + <string lang="en" key="UNINSTALL_OK">TrueCrypt has been successfully uninstalled.\n\nClick 'Finish' to remove the TrueCrypt installer and the folder %hs. Note that the folder will not be removed if it contains any files that were not installed by the TrueCrypt installer or created by TrueCrypt.</string> + <string lang="en" key="REMOVING_REG">Removing TrueCrypt registry entries</string> + <string lang="en" key="ADDING_REG">Adding registry entry</string> + <string lang="en" key="REMOVING_APPDATA">Removing application-specific data</string> + <string lang="en" key="INSTALLING">Installing</string> + <string lang="en" key="STOPPING">Stopping</string> + <string lang="en" key="REMOVING">Removing</string> + <string lang="en" key="ADDING_ICON">Adding icon</string> + <string lang="en" key="CREATING_SYS_RESTORE">Creating System Restore point</string> + <string lang="en" key="FAILED_SYS_RESTORE">Failed to create System Restore point!</string> + <string lang="en" key="INSTALLER_UPDATING_BOOT_LOADER">Updating boot loader</string> + <string lang="en" key="INSTALL_OF_FAILED">Failed to install '%hs'. %hs\nDo you want to continue installing?</string> + <string lang="en" key="UNINSTALL_OF_FAILED">Failed to uninstall '%hs'. %hs\nDo you want to continue uninstalling?</string> + <string lang="en" key="INSTALL_COMPLETED">Installation completed.</string> + <string lang="en" key="CANT_CREATE_FOLDER">The folder '%hs' could not be created</string> + <string lang="en" key="CLOSE_TC_FIRST">The TrueCrypt device driver cannot be unloaded.\n\nPlease close all open TrueCrypt windows first. If it does not help, please restart Windows and then try again.</string> + <string lang="en" key="DISMOUNT_ALL_FIRST">All TrueCrypt volumes must be dismounted before installing or uninstalling TrueCrypt.</string> + <string lang="en" key="UNINSTALL_OLD_VERSION_FIRST">An obsolete version of TrueCrypt is currently installed on this system. It needs to be uninstalled before you can install this new version of TrueCrypt.\n\nAs soon as you close this message box, the uninstaller of the old version will be launched. Note that no volume will be decrypted when you uninstall TrueCrypt. After you uninstall the old version of TrueCrypt, run the installer of the new version of TrueCrypt again.</string> + <string lang="en" key="REG_INSTALL_FAILED">The installation of the registry entries has failed</string> + <string lang="en" key="DRIVER_INSTALL_FAILED">The installation of the device driver has failed. Please restart Windows and then try installing TrueCrypt again.</string> + <string lang="en" key="STARTING_DRIVER">Starting TrueCrypt device driver</string> + <string lang="en" key="DRIVER_UINSTALL_FAILED">Uninstallation of the device driver has failed. Please note that, due to a Windows issue, it may be necessary to log off or restart the system before the device driver can be uninstalled (or reinstalled).</string> + <string lang="en" key="INSTALLING_DRIVER">Installing TrueCrypt device driver</string> + <string lang="en" key="STOPPING_DRIVER">Stopping TrueCrypt device driver</string> + <string lang="en" key="REMOVING_DRIVER">Uninstalling TrueCrypt device driver</string> + <string lang="en" key="COM_REG_FAILED">Registration of the User Account Control support library failed.</string> + <string lang="en" key="COM_DEREG_FAILED">Unregistration of the User Account Control support library failed.</string> + <string lang="en" key="TRAVELER_LIMITATIONS_NOTE">Note about portable mode:\n\nPlease note that the operating system requires drivers to be registered with it before they can be started. Hence, the TrueCrypt driver is not (and cannot be) fully portable (whereas the TrueCrypt applications are fully portable, i.e. they do not have to be installed or registered with the operating system). Also note that TrueCrypt needs a driver to provide transparent on-the-fly encryption/decryption.</string> + <string lang="en" key="TRAVELER_UAC_NOTE">Note that if you decide to run TrueCrypt in portable mode (as opposed to running an installed copy of TrueCrypt), the system will ask you for permission to run TrueCrypt (UAC prompt) every time you attempt to run it.\n\nThe reason is that when you run TrueCrypt in portable mode, TrueCrypt needs to load and start the TrueCrypt device driver. TrueCrypt needs a device driver to provide transparent on-the-fly encryption/decryption, and users without administrator privileges cannot start device drivers in Windows. Therefore, the system will ask you for permission to run TrueCrypt with administrator privileges (UAC prompt).\n\nNote that if you install TrueCrypt on the system (as opposed to running TrueCrypt in portable mode), the system will NOT ask you for permission to run TrueCrypt (UAC prompt) every time you attempt to run it.\n\nAre you sure you want to extract the files?</string> + <string lang="en" key="CONTAINER_ADMIN_WARNING">Warning: This instance of the Volume Creation Wizard has administrator privileges.\n\nYour new volume may be created with permissions that will not allow you to write to the volume when it is mounted. If you want to avoid that, close this instance of the Volume Creation Wizard and launch a new one without administrator privileges.\n\nDo you want to close this instance of the Volume Creation Wizard?</string> + <string lang="en" key="CANNOT_DISPLAY_LICENSE">Error: Cannot display license.</string> + <string lang="en" key="OUTER_VOL_WRITE_PREVENTED">Outer(!)</string> + <string lang="en" key="DAYS">days</string> + <string lang="en" key="HOURS">hours</string> + <string lang="en" key="MINUTES">minutes</string> + <string lang="en" key="SECONDS">s</string> + <string lang="en" key="OPEN">Open</string> + <string lang="en" key="DISMOUNT">Dismount</string> + <string lang="en" key="SHOW_TC">Show TrueCrypt</string> + <string lang="en" key="HIDE_TC">Hide TrueCrypt</string> + <string lang="en" key="TOTAL_DATA_READ">Data Read since Mount</string> + <string lang="en" key="TOTAL_DATA_WRITTEN">Data Written since Mount</string> + <string lang="en" key="ENCRYPTED_PORTION">Encrypted Portion</string> + <string lang="en" key="ENCRYPTED_PORTION_FULLY_ENCRYPTED">100% (fully encrypted)</string> + <string lang="en" key="ENCRYPTED_PORTION_NOT_ENCRYPTED">0% (not encrypted)</string> + <string lang="en" key="PROCESSED_PORTION_X_PERCENT">%.3f%%</string> + <string lang="en" key="PROCESSED_PORTION_100_PERCENT">100%</string> + <string lang="en" key="PROGRESS_STATUS_WAITING">Waiting</string> + <string lang="en" key="PROGRESS_STATUS_PREPARING">Preparing</string> + <string lang="en" key="PROGRESS_STATUS_RESIZING">Resizing</string> + <string lang="en" key="PROGRESS_STATUS_ENCRYPTING">Encrypting</string> + <string lang="en" key="PROGRESS_STATUS_DECRYPTING">Decrypting</string> + <string lang="en" key="PROGRESS_STATUS_FINALIZING">Finalizing</string> + <string lang="en" key="PROGRESS_STATUS_PAUSED">Paused</string> + <string lang="en" key="PROGRESS_STATUS_FINISHED">Finished</string> + <string lang="en" key="PROGRESS_STATUS_ERROR">Error</string> + <string lang="en" key="FAVORITE_DISCONNECTED_DEV">Device disconnected</string> + <string lang="en" key="SYS_FAVORITE_VOLUMES_SAVED">System favorite volumes saved.\n\nTo enable mounting of system favorite volumes when the system starts, please select 'Settings' > 'System Favorite Volumes' > 'Mount system favorite volumes when Windows starts'.</string> + <string lang="en" key="FAVORITE_ADD_DRIVE_DEV_WARNING">The volume you are adding to favorites is neither a partition nor a dynamic volume. Therefore, TrueCrypt will be unable to mount this favorite volume if the device number changes.</string> + <string lang="en" key="FAVORITE_ADD_PARTITION_TYPE_WARNING">The volume you are adding to favorites is a partition not recognized by Windows.\n\nTrueCrypt will be unable to mount this favorite volume if the device number changes. Please set the type of the partition to a type recognized by Windows (use the SETID command of the Windows 'diskpart' tool). Then add the partition to favorites again.</string> + <string lang="en" key="FAVORITE_ARRIVAL_MOUNT_BACKGROUND_TASK_ERR">TrueCrypt Background Task is disabled or it is configured to exit when there are no mounted volumes (or TrueCrypt is running in portable mode). This may prevent your favorite volumes from being automatically mounted when devices hosting them get connected.\n\nNote: To enable the TrueCrypt Background Task, select Settings > Preferences and check the 'Enabled' checkbox in the section 'TrueCrypt Background Task'.</string> + <string lang="en" key="FAVORITE_ARRIVAL_MOUNT_NETWORK_PATH_ERR">A container stored in a remote filesystem shared over a network cannot be automatically mounted when its host device gets connected.</string> + <string lang="en" key="FAVORITE_ARRIVAL_MOUNT_DEVICE_PATH_ERR">The device displayed below is neither a partition nor a dynamic volume. Therefore, the volume hosted on the device cannot be automatically mounted when the device gets connected.</string> + <string lang="en" key="FAVORITE_ARRIVAL_MOUNT_PARTITION_TYPE_ERR">Please set the type of the partition displayed below to a type recognized by Windows (use the SETID command of the Windows 'diskpart' tool). Then remove the partition from favorites and add it again. This will enable the volume hosted on the device to be automatically mounted when the device gets connected.</string> + <string lang="en" key="FAVORITE_LABEL_DEVICE_PATH_ERR">The device displayed below is neither a partition nor a dynamic volume. Therefore, no label can be assigned to it.</string> + <string lang="en" key="FAVORITE_LABEL_PARTITION_TYPE_ERR">Please set the type of the partition displayed below to a type recognized by Windows (use the SETID command of the Windows 'diskpart' tool). Then remove the partition from favorites and add it again. This will enable TrueCrypt to assign a label to the partition.</string> + <string lang="en" key="SYSTEM_FAVORITE_NETWORK_PATH_ERR">Due to a Windows limitation, a container stored in a remote filesystem shared over a network cannot be mounted as a system favorite volume (however, it can be mounted as a non-system favorite volume when a user logs on).</string> + <string lang="en" key="ENTER_PASSWORD_FOR">Enter password for %hs</string> + <string lang="en" key="ENTER_PASSWORD_FOR_LABEL">Enter password for '%s'</string> + <string lang="en" key="ENTER_NORMAL_VOL_PASSWORD">Enter password for the normal/outer volume</string> + <string lang="en" key="ENTER_HIDDEN_VOL_PASSWORD">Enter password for the hidden volume</string> + <string lang="en" key="ENTER_HEADER_BACKUP_PASSWORD">Enter password for the header stored in backup file</string> + <string lang="en" key="KEYFILE_CREATED">Keyfile has been successfully created.</string> + <string lang="en" key="HEADER_DAMAGED_AUTO_USED_HEADER_BAK">WARNING: The header of this volume is damaged! TrueCrypt automatically used the backup of the volume header embedded in the volume.\n\nYou should repair the volume header by selecting 'Tools' > 'Restore Volume Header'.</string> + <string lang="en" key="VOL_HEADER_BACKED_UP">Volume header backup has been successfully created.\n\nIMPORTANT: Restoring the volume header using this backup will also restore the current volume password. Moreover, if keyfile(s) are/is necessary to mount the volume, the same keyfile(s) will be necessary to mount the volume again when the volume header is restored.\n\nWARNING: This volume header backup may be used to restore the header ONLY of this particular volume. If you use this header backup to restore a header of a different volume, you will be able to mount the volume, but you will NOT be able to decrypt any data stored in the volume (because you will change its master key).</string> + <string lang="en" key="VOL_HEADER_RESTORED">The volume header has been successfully restored.\n\nIMPORTANT: Please note that an old password may have been restored as well. Moreover, if keyfile(s) were/was necessary to mount the volume when the backup was created, the same keyfile(s) are now necessary to mount the volume again.</string> + <string lang="en" key="EXTERNAL_VOL_HEADER_BAK_FIRST_INFO">For security reasons, you will have to enter the correct password (and/or supply the correct keyfiles) for the volume.\n\nNote: If the volume contains a hidden volume, you will have to enter the correct password (and/or supply the correct keyfiles) for the outer volume first. Afterwards, if you choose to back up the header of the hidden volume, you will have to enter the correct password (and/or supply the correct keyfiles) for the hidden volume.</string> + <string lang="en" key="CONFIRM_VOL_HEADER_BAK">Are you sure you want to create volume header backup for %hs?\n\nAfter you click Yes, you will prompted for a filename for the header backup.\n\nNote: Both the standard and the hidden volume headers will be re-encrypted using a new salt and stored in the backup file. If there is no hidden volume within this volume, the area reserved for the hidden volume header in the backup file will be filled with random data (to preserve plausible deniability). When restoring a volume header from the backup file, you will need to enter the correct password (and/or to supply the correct keyfiles) that was/were valid when the volume header backup was created. The password (and/or keyfiles) will also automatically determine the type of the volume header to restore, i.e. standard or hidden (note that TrueCrypt determines the type through the process of trial and error).</string> + <string lang="en" key="CONFIRM_VOL_HEADER_RESTORE">Are you sure you want to restore volume header of %hs?\n\nWARNING: Restoring a volume header also restores the volume password that was valid when the backup was created. Moreover, if keyfile(s) were/was necessary to mount the volume when the backup was created, the same keyfile(s) will be necessary to mount the volume again after the volume header is restored.\n\nAfter you click Yes, you will select the header backup file.</string> + <string lang="en" key="DOES_VOLUME_CONTAIN_HIDDEN">Does the volume contain a hidden volume?</string> + <string lang="en" key="VOLUME_CONTAINS_HIDDEN">The volume contains a hidden volume</string> + <string lang="en" key="VOLUME_DOES_NOT_CONTAIN_HIDDEN">The volume does not contain a hidden volume</string> + <string lang="en" key="HEADER_RESTORE_EXTERNAL_INTERNAL">Please select the type of volume header backup you want to use:</string> + <string lang="en" key="HEADER_RESTORE_INTERNAL">Restore the volume header from the backup embedded in the volume</string> + <string lang="en" key="HEADER_RESTORE_EXTERNAL">Restore the volume header from an external backup file</string> + <string lang="en" key="HEADER_BACKUP_SIZE_INCORRECT">The size of the volume header backup file is incorrect.</string> + <string lang="en" key="VOLUME_HAS_NO_BACKUP_HEADER">There is no backup header embedded in this volume (note that only volumes created by TrueCrypt 6.0 or later contain embedded backup headers).</string> + <string lang="en" key="BACKUP_HEADER_NOT_FOR_SYS_DEVICE">You are attempting to back up the header of the system partition/drive. This is not allowed. Backup/restore operations pertaining to the system partition/drive can be performed only using the TrueCrypt Rescue Disk.\n\nDo you want to create a TrueCrypt Rescue Disk?</string> + <string lang="en" key="RESTORE_HEADER_NOT_FOR_SYS_DEVICE">You are attempting to restore the header of a virtual TrueCrypt volume but you selected the system partition/drive. This is not allowed. Backup/restore operations pertaining to the system partition/drive can be performed only using the TrueCrypt Rescue Disk.\n\nDo you want to create a TrueCrypt Rescue Disk?</string> + <string lang="en" key="RESCUE_DISK_NON_WIZARD_CREATION_SELECT_PATH">After you click OK, you will select a filename for the new TrueCrypt Rescue Disk ISO image and the location where you wish to place it.</string> + <string lang="en" key="RESCUE_DISK_NON_WIZARD_CREATION_BURN">The Rescue Disk image has been created and stored in this file:\n%hs\n\nNow you need to burn the Rescue Disk image to a CD or DVD.\n\nIMPORTANT: Note that the file must be written to the CD/DVD as an ISO disk image (not as an individual file). For information on how to do so, please refer to the documentation of your CD/DVD recording software.\n\nAfter you burn the Rescue Disk, select 'System' > 'Verify Rescue Disk' to verify that it has been correctly burned.</string> + <string lang="en" key="RESCUE_DISK_NON_WIZARD_CREATION_WIN_ISOBURN">The Rescue Disk image has been created and stored in this file:\n%hs\n\nNow you need to burn the Rescue Disk image to a CD or DVD.\n\nDo you want to launch the Microsoft Windows Disc Image Burner now?\n\nNote: After you burn the Rescue Disk, select 'System' > 'Verify Rescue Disk' to verify that it has been correctly burned.</string> + <string lang="en" key="RESCUE_DISK_NON_WIZARD_CHECK_INSERT">Please insert your TrueCrypt Rescue Disk into your CD/DVD drive and click OK to verify it.</string> + <string lang="en" key="RESCUE_DISK_NON_WIZARD_CHECK_PASSED">The TrueCrypt Rescue Disk has been successfully verified.</string> + <string lang="en" key="RESCUE_DISK_NON_WIZARD_CHECK_FAILED">Cannot verify that the Rescue Disk has been correctly burned.\n\nIf you have burned the Rescue Disk, please eject and reinsert the CD/DVD; then try again. If this does not help, please try other CD/DVD recording software and/or medium.\n\nIf you attempted to verify a TrueCrypt Rescue Disk created for a different master key, password, salt, etc., please note that such Rescue Disk will always fail this verification. To create a new Rescue Disk fully compatible with your current configuration, select 'System' > 'Create Rescue Disk'.</string> + <string lang="en" key="ERROR_CREATING_RESCUE_DISK">Error creating TrueCrypt Rescue Disk.</string> + <string lang="en" key="CANNOT_CREATE_RESCUE_DISK_ON_HIDDEN_OS">TrueCrypt Rescue Disk cannot be created when a hidden operating system is running.\n\nTo create a TrueCrypt Rescue Disk, boot the decoy operating system and then select 'System' > 'Create Rescue Disk'.</string> + <string lang="en" key="RESCUE_DISK_CHECK_FAILED">Cannot verify that the Rescue Disk has been correctly burned.\n\nIf you have burned the Rescue Disk, please eject and reinsert the CD/DVD; then click Next to try again. If this does not help, please try another medium%s.\n\nIf you have not burned the Rescue Disk yet, please do so, and then click Next.\n\nIf you attempted to verify a TrueCrypt Rescue Disk created before you started this wizard, please note that such Rescue Disk cannot be used, because it was created for a different master key. You need to burn the newly generated Rescue Disk.</string> + <string lang="en" key="RESCUE_DISK_CHECK_FAILED_SENTENCE_APPENDIX"> and/or other CD/DVD recording software</string> + <string lang="en" key="SYSTEM_FAVORITES_DLG_TITLE">TrueCrypt - System Favorite Volumes</string> + <string lang="en" key="SYS_FAVORITES_HELP_LINK">What are system favorite volumes?</string> + <string lang="en" key="SYS_FAVORITES_REQUIRE_PBA">The system partition/drive does not appear to be encrypted.\n\nSystem favorite volumes can be mounted using only a pre-boot authentication password. Therefore, to enable use of system favorite volumes, you need to encrypt the system partition/drive first.</string> + <string lang="en" key="DISMOUNT_FIRST">Please dismount the volume before proceeding.</string> + <string lang="en" key="CANNOT_SET_TIMER">Error: Cannot set timer.</string> + <string lang="en" key="IDPM_CHECK_FILESYS">Check Filesystem</string> + <string lang="en" key="IDPM_REPAIR_FILESYS">Repair Filesystem</string> + <string lang="en" key="IDPM_ADD_TO_FAVORITES">Add to Favorites...</string> + <string lang="en" key="IDPM_ADD_TO_SYSTEM_FAVORITES">Add to System Favorites...</string> + <string lang="en" key="IDPM_PROPERTIES">P&roperties...</string> + <string lang="en" key="HIDDEN_VOL_PROTECTION">Hidden Volume Protected</string> + <string lang="en" key="NOT_APPLICABLE_OR_NOT_AVAILABLE">N/A</string> + <string lang="en" key="UISTR_YES">Yes</string> + <string lang="en" key="UISTR_NO">No</string> + <string lang="en" key="UISTR_DISABLED">Disabled</string> + <string lang="en" key="DIGIT_ONE">1</string> + <string lang="en" key="TWO_OR_MORE">2 or more</string> + <string lang="en" key="MODE_OF_OPERATION">Mode of Operation</string> + <string lang="en" key="LABEL_ITEM">Label: </string> + <string lang="en" key="SIZE_ITEM">Size: </string> + <string lang="en" key="PATH_ITEM">Path: </string> + <string lang="en" key="DRIVE_LETTER_ITEM">Drive Letter: </string> + <string lang="en" key="UNSUPPORTED_CHARS_IN_PWD">Error: Password must contain only ASCII characters.\n\nNon-ASCII characters in password might cause the volume to be impossible to mount when your system configuration changes.\n\nThe following characters are allowed:\n\n ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \\ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w k y z { | } ~</string> + <string lang="en" key="UNSUPPORTED_CHARS_IN_PWD_RECOM">Warning: Password contains non-ASCII characters. This may cause the volume to be impossible to mount when your system configuration changes.\n\nYou should replace all non-ASCII characters in the password with ASCII characters. To do so, click 'Volumes' -> 'Change Volume Password'.\n\nThe following are ASCII characters:\n\n ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \\ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w k y z { | } ~</string> + <string lang="en" key="EXE_FILE_EXTENSION_CONFIRM">WARNING: We strongly recommend that you avoid file extensions that are used for executable files (such as .exe, .sys, or .dll) and other similarly problematic file extensions. Using such file extensions causes Windows and antivirus software to interfere with the container, which adversely affects the performance of the volume and may also cause other serious problems.\n\nWe strongly recommend that you remove the file extension or change it (e.g., to '.tc').\n\nAre you sure you want to use the problematic file extension?</string> + <string lang="en" key="EXE_FILE_EXTENSION_MOUNT_WARNING">WARNING: This container has a file extension that is used for executable files (such as .exe, .sys, or .dll) or some other file extension that is similarly problematic. It will very likely cause Windows and antivirus software to interfere with the container, which will adversely affect the performance of the volume and may also cause other serious problems.\n\nWe strongly recommend that you remove the file extension of the container or change it (e.g., to '.tc') after you dismount the volume.</string> + <string lang="en" key="HOMEPAGE">Homepage</string> + <string lang="en" key="LARGE_IDE_WARNING_XP">WARNING: It appears that you have not applied any Service Pack to your Windows installation. You should not write to IDE disks larger than 128 GB under Windows XP to which you did not apply Service Pack 1 or later! If you do, data on the disk (no matter if it is a TrueCrypt volume or not) may get corrupted. Note that this is a limitation of Windows, not a bug in TrueCrypt.</string> + <string lang="en" key="LARGE_IDE_WARNING_2K">WARNING: It appears that you have not applied Service Pack 3 or later to your Windows installation. You should not write to IDE disks larger than 128 GB under Windows 2000 to which you did not apply Service Pack 3 or later! If you do, data on the disk (no matter if it is a TrueCrypt volume or not) may get corrupted. Note that this is a limitation of Windows, not a bug in TrueCrypt.\n\nNote: You may also need to enable the 48-bit LBA support in the registry; for more information, see http://support.microsoft.com/kb/305098/EN-US</string> + <string lang="en" key="LARGE_IDE_WARNING_2K_REGISTRY">WARNING: 48-bit LBA ATAPI support is disabled on your system. Therefore, you should not write to IDE disks larger than 128 GB! If you do, data on the disk (no matter if it is a TrueCrypt volume or not) may get corrupted. Note that this is a limitation of Windows, not a limitation of TrueCrypt.\n\nTo enable the 48-bit LBA support, add the 'EnableBigLba' registry value in the registry key HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\atapi\\Parameters and set it to 1.\n\nFor more information, see http://support.microsoft.com/kb/305098</string> + <string lang="en" key="VOLUME_TOO_LARGE_FOR_FAT32">Error: Files larger than 4 GB cannot be stored on a FAT32 file system. Therefore, file-hosted TrueCrypt volumes (containers) stored on a FAT32 file system cannot be larger than 4 GB.\n\nIf you need a larger volume, create it on an NTFS file system (or, if you use Windows Vista SP1 or later, on an exFAT file system) or, instead of creating a file-hosted volume, encrypt an entire partition or device.</string> + <string lang="en" key="VOLUME_TOO_LARGE_FOR_WINXP">Warning: Windows XP does not support files larger than 2048 GB (it will report that "Not enough storage is available"). Therefore, you cannot create a file-hosted TrueCrypt volume (container) larger than 2048 GB under Windows XP.\n\nNote that it is still possible to encrypt the entire drive or create a partition-hosted TrueCrypt volume larger than 2048 GB under Windows XP.</string> + <string lang="en" key="FREE_SPACE_FOR_WRITING_TO_OUTER_VOLUME">WARNING: If you want to be able to add more data/files to the outer volume in future, you should consider choosing a smaller size for the hidden volume.\n\nAre you sure you want to continue with the size you specified?</string> + <string lang="en" key="NO_VOLUME_SELECTED">No volume selected.\n\nClick 'Select Device' or 'Select File' to select a TrueCrypt volume.</string> + <string lang="en" key="NO_SYSENC_PARTITION_SELECTED">No partition selected.\n\nClick 'Select Device' to select a dismounted partition that normally requires pre-boot authentication (for example, a partition located on the encrypted system drive of another operating system, which is not running, or the encrypted system partition of another operating system).\n\nNote: The selected partition will be mounted as a regular TrueCrypt volume without pre-boot authentication. This is useful e.g. for backup or repair operations.</string> + <string lang="en" key="CONFIRM_SAVE_DEFAULT_KEYFILES">WARNING: If default keyfiles are set and enabled, volumes that are not using these keyfiles will be impossible to mount. Therefore, after you enable default keyfiles, keep in mind to uncheck the 'Use keyfiles' checkbox (below a password input field) whenever mounting such volumes.\n\nAre you sure you want to save the selected keyfiles/paths as default?</string> + <string lang="en" key="HK_AUTOMOUNT_DEVICES">Auto-Mount Devices</string> + <string lang="en" key="HK_DISMOUNT_ALL">Dismount All</string> + <string lang="en" key="HK_WIPE_CACHE">Wipe Cache</string> + <string lang="en" key="HK_DISMOUNT_ALL_AND_WIPE">Dismount All & Wipe Cache</string> + <string lang="en" key="HK_FORCE_DISMOUNT_ALL_AND_WIPE">Force Dismount All & Wipe Cache</string> + <string lang="en" key="HK_FORCE_DISMOUNT_ALL_AND_WIPE_AND_EXIT">Force Dismount All, Wipe Cache & Exit</string> + <string lang="en" key="HK_MOUNT_FAVORITE_VOLUMES">Mount Favorite Volumes</string> + <string lang="en" key="HK_SHOW_HIDE_MAIN_WINDOW">Show/Hide Main TrueCrypt Window</string> + <string lang="en" key="PRESS_A_KEY_TO_ASSIGN">(Click here and press a key)</string> + <string lang="en" key="ACTION">Action</string> + <string lang="en" key="SHORTCUT">Shortcut</string> + <string lang="en" key="CANNOT_USE_RESERVED_KEY">Error: This shortcut is reserved. Please choose a different shortcut.</string> + <string lang="en" key="SHORTCUT_ALREADY_IN_USE">Error: Shortcut already in use.</string> + <string lang="en" key="HOTKEY_REGISTRATION_ERROR">WARNING: One or more TrueCrypt system-wide hot keys will not work!\n\nPlease make sure that other applications and the operating system do not use the same shortcut(s) as TrueCrypt.</string> + <string lang="en" key="PAGING_FILE_CREATION_PREVENTED">Paging file creation has been prevented.\n\nPlease note that, due to Windows issues, paging files cannot be located on non-system TrueCrypt volumes (including system favorite volumes). TrueCrypt supports creation of paging files only on an encrypted system partition/drive.</string> + <string lang="en" key="SYS_ENC_HIBERNATION_PREVENTED">An error or incompatibility prevents TrueCrypt from encrypting the hibernation file. Therefore, hibernation has been prevented.\n\nNote: When a computer hibernates (or enters a power-saving mode), the content of its system memory is written to a hibernation storage file residing on the system drive. TrueCrypt would not be able to prevent encryption keys and the contents of sensitive files opened in RAM from being saved unencrypted to the hibernation storage file.</string> + <string lang="en" key="HIDDEN_OS_HIBERNATION_PREVENTED">Hibernation has been prevented.\n\nTrueCrypt does not support hibernation on hidden operating systems that use an extra boot partition. Please note that the boot partition is shared by both the decoy and the hidden system. Therefore, in order to prevent data leaks and problems while resuming from hibernation, TrueCrypt has to prevent the hidden system from writing to the shared boot partition and from hibernating.</string> + <string lang="en" key="VOLUME_MOUNTED_AS_DRIVE_LETTER_X_DISMOUNTED">TrueCrypt volume mounted as %c: has been dismounted.</string> + <string lang="en" key="MOUNTED_VOLUMES_DISMOUNTED">TrueCrypt volumes have been dismounted.</string> + <string lang="en" key="VOLUMES_DISMOUNTED_CACHE_WIPED">TrueCrypt volumes have been dismounted and password cache has been wiped.</string> + <string lang="en" key="SUCCESSFULLY_DISMOUNTED">Successfully dismounted</string> + <string lang="en" key="CONFIRM_BACKGROUND_TASK_DISABLED">WARNING: If the TrueCrypt Background Task is disabled, the following functions will be disabled:\n\n1) Hot keys\n2) Auto-dismount (e.g., upon logoff, inadvertent host device removal, time-out, etc.)\n3) Auto-mount of favorite volumes\n4) Notifications (e.g., when damage to hidden volume is prevented)\n5) Tray icon\n\nNote: You can shut down the Background Task anytime by right-clicking the TrueCrypt tray icon and selecting 'Exit'.\n\nAre you sure you want to permanently disable the TrueCrypt Background Task?</string> + <string lang="en" key="CONFIRM_NO_FORCED_AUTODISMOUNT">WARNING: If this option is disabled, volumes containing open files/directories will not be possible to auto-dismount.\n\nAre you sure you want to disable this option?</string> + <string lang="en" key="WARN_PREF_AUTO_DISMOUNT">WARNING: Volumes containing open files/directories will NOT be auto-dismounted.\n\nTo prevent this, enable the following option in this dialog window: 'Force auto-dismount even if volume contains open files or directories'</string> + <string lang="en" key="WARN_PREF_AUTO_DISMOUNT_ON_POWER">WARNING: When the notebook battery power is low, Windows may omit sending the appropriate messages to running applications when the computer is entering power saving mode. Therefore, TrueCrypt may fail to auto-dismount volumes in such cases.</string> + <string lang="en" key="NONSYS_INPLACE_ENC_RESUME_PROMPT">You have scheduled the process of encryption of a partition/volume. The process has not been completed yet.\n\nDo you want to resume the process now?</string> + <string lang="en" key="SYSTEM_ENCRYPTION_RESUME_PROMPT">You have scheduled the process of encryption or decryption of the system partition/drive. The process has not been completed yet.\n\nDo you want to start (resume) the process now?</string> + <string lang="en" key="ASK_NONSYS_INPLACE_ENC_NOTIFICATION_REMOVAL">Do you want to be prompted about whether you want to resume the currently scheduled processes of encryption of non-system partitions/volumes?</string> + <string lang="en" key="KEEP_PROMPTING_ME">Yes, keep prompting me</string> + <string lang="en" key="DO_NOT_PROMPT_ME">No, do not prompt me</string> + <string lang="en" key="NONSYS_INPLACE_ENC_NOTIFICATION_REMOVAL_NOTE">IMPORTANT: Keep in mind that you can resume the process of encryption of any non-system partition/volume by selecting 'Volumes' > 'Resume Interrupted Process' from the menu bar of the main TrueCrypt window.</string> + <string lang="en" key="SYSTEM_ENCRYPTION_SCHEDULED_BUT_PBA_FAILED">You have scheduled the process of encryption or decryption of the system partition/drive. However, pre-boot authentication failed (or was bypassed).\n\nNote: If you decrypted the system partition/drive in the pre-boot environment, you may need to finalize the process by selecting 'System' > 'Permanently Decrypt System Partition/Drive' from the menu bar of the main TrueCrypt window.</string> + <string lang="en" key="CONFIRM_EXIT">WARNING: If TrueCrypt exits now, the following functions will be disabled:\n\n1) Hot keys\n2) Auto-dismount (e.g., upon logoff, inadvertent host device removal, time-out, etc.)\n3) Auto-mount of favorite volumes\n4) Notifications (e.g., when damage to hidden volume is prevented)\n\nNote: If you do not wish TrueCrypt to run in the background, disable the TrueCrypt Background Task in the Preferences (and, if necessary, disable the automatic start of TrueCrypt in the Preferences).\n\nAre you sure you want TrueCrypt to exit?</string> + <string lang="en" key="CONFIRM_EXIT_UNIVERSAL">Exit?</string> + <string lang="en" key="CHOOSE_ENCRYPT_OR_DECRYPT">TrueCrypt does not have sufficient information to determine whether to encrypt or decrypt.</string> + <string lang="en" key="CHOOSE_ENCRYPT_OR_DECRYPT_FINALIZE_DECRYPT_NOTE">TrueCrypt does not have sufficient information to determine whether to encrypt or decrypt.\n\nNote: If you decrypted the system partition/drive in the pre-boot environment, you may need to finalize the process by clicking Decrypt.</string> + <string lang="en" key="NONSYS_INPLACE_ENC_DEFER_CONFIRM">Do you want to interrupt and postpone the process of encryption of the partition/volume?\n\nNote: Keep in mind that the volume cannot be mounted until it has been fully encrypted. You will be able to resume the process of encryption and it will continue from the point it was stopped. You can do so, for example, by selecting 'Volumes' > 'Resume Interrupted Process' from the menu bar of the main TrueCrypt window.</string> + <string lang="en" key="SYSTEM_ENCRYPTION_DEFER_CONFIRM">Do you want to interrupt and postpone the process of encryption of the system partition/drive?\n\nNote: You will be able to resume the process and it will continue from the point it was stopped. You can do so, for example, by selecting 'System' > 'Resume Interrupted Process' from the menu bar of the main TrueCrypt window. If you want to permanently terminate or reverse the encryption process, select 'System' > 'Permanently Decrypt System Partition/Drive'.</string> + <string lang="en" key="SYSTEM_DECRYPTION_DEFER_CONFIRM">Do you want to interrupt and postpone the process of decryption of the system partition/drive?\n\nNote: You will be able to resume the process and it will continue from the point it was stopped. You can do so, for example, by selecting 'System' > 'Resume Interrupted Process' from the menu bar of the main TrueCrypt window. If you want to reverse the decryption process (and start encrypting), select 'System' > 'Encrypt System Partition/Drive'.</string> + <string lang="en" key="FAILED_TO_INTERRUPT_SYSTEM_ENCRYPTION">Error: Failed to interrupt the process of encryption/decryption of the system partition/drive.</string> + <string lang="en" key="FAILED_TO_INTERRUPT_WIPING">Error: Failed to interrupt the process of wiping.</string> + <string lang="en" key="FAILED_TO_RESUME_SYSTEM_ENCRYPTION">Error: Failed to resume the process of encryption/decryption of the system partition/drive.</string> + <string lang="en" key="FAILED_TO_START_WIPING">Error: Failed to start the process of wiping.</string> + <string lang="en" key="INCONSISTENCY_RESOLVED">Inconsistency resolved.\n\n\n(If you report a bug in connection with this, please include the following technical information in the bug report:\n%hs)</string> + <string lang="en" key="UNEXPECTED_STATE">Error: Unexpected state.\n\n\n(If you report a bug in connection with this, please include the following technical information in the bug report:\n%hs)</string> + <string lang="en" key="NOTHING_TO_RESUME">There is no process/task to resume.</string> + <string lang="en" key="HIDVOL_PROT_BKG_TASK_WARNING">WARNING: TrueCrypt Background Task is disabled. After you exit TrueCrypt, you will not be notified if damage to hidden volume is prevented.\n\nNote: You may shut down the Background Task anytime by right-clicking the TrueCrypt tray icon and selecting 'Exit'.\n\nEnable TrueCrypt Background Task?</string> + <string lang="en" key="LANG_PACK_VERSION">Language pack version: %s</string> + <string lang="en" key="CHECKING_FS">Checking the file system on the TrueCrypt volume mounted as %hs...</string> + <string lang="en" key="REPAIRING_FS">Attempting to repair the file system on the TrueCrypt volume mounted as %hs...</string> + <string lang="en" key="WARN_CBC_MODE">Warning: This volume is encrypted in CBC mode. Due to security issues, CBC mode has been deprecated since TrueCrypt 4.1.\n\nWe strongly recommend that you move data from this TrueCrypt volume to a new volume created by this version of TrueCrypt. After you do so, you should securely erase or destroy the old volume. For more information, please see the Version History in the documentation or the release notices distributed with TrueCrypt 4.1 or later.</string> + <string lang="en" key="WARN_64_BIT_BLOCK_CIPHER">Warning: This volume is encrypted with a legacy encryption algorithm.\n\nAll 64-bit-block encryption algorithms (e.g., Blowfish, CAST-128, or Triple DES) are deprecated. It will be possible to mount this volume using future versions of TrueCrypt. However, there will be no further enhancements to the implementations of these legacy encryption algorithms. We recommend that you create a new TrueCrypt volume encrypted with a 128-bit-block encryption algorithm (e.g., AES, Serpent, Twofish, etc.) and that you move all files from this volume to the new volume.</string> + <string lang="en" key="SYS_AUTOMOUNT_DISABLED">Your system is not configured to auto-mount new volumes. It may be impossible to mount device-hosted TrueCrypt volumes. Auto-mounting can be enabled by executing the following command and restarting the system.\n\nmountvol.exe /E</string> + <string lang="en" key="SYS_ASSIGN_DRIVE_LETTER">Please assign a drive letter to the partition/device before proceeding ('Control Panel' > 'System and Maintenance' > 'Administrative Tools' - 'Create and format hard disk partitions').\n\nNote that this is a requirement of the operating system.</string> + <string lang="en" key="MOUNT_TC_VOLUME">Mount TrueCrypt volume</string> + <string lang="en" key="DISMOUNT_ALL_TC_VOLUMES">Dismount all TrueCrypt volumes</string> + <string lang="en" key="UAC_INIT_ERROR">TrueCrypt failed to obtain Administrator privileges.</string> + <string lang="en" key="ERR_ACCESS_DENIED">Access was denied by the operating system.\n\nPossible cause: The operating system requires that you have read/write permission (or administrator privileges) for certain folders, files, and devices, in order for you to be allowed to read and write data to/from them. Normally, a user without administrator privileges is allowed to create, read and modify files in his or her Documents folder.</string> + <string lang="en" key="SECTOR_SIZE_UNSUPPORTED">Error: The drive uses an unsupported sector size.\n\nIt is currently not possible to create partition/device-hosted volumes on drives that use sectors larger than 4096 bytes. However, note that you can create file-hosted volumes (containers) on such drives.</string> + <string lang="en" key="SYSENC_UNSUPPORTED_SECTOR_SIZE_BIOS">It is currently not possible to encrypt a system installed on a disk that uses a sector size other than 512 bytes.</string> + <string lang="en" key="NO_SPACE_FOR_BOOT_LOADER">The TrueCrypt Boot Loader requires at least 32 KBytes of free space at the beginning of the system drive (the TrueCrypt Boot Loader needs to be stored in that area). Unfortunately, your drive does not meet this condition.\n\nPlease do NOT report this as a bug/problem in TrueCrypt. To solve this problem, you will need to repartition your disk and leave the first 32 KBytes of the disk free (in most cases, you will need to delete and recreate the first partition). We recommend that you use the Microsoft partition manager that is available e.g. when you are installing Windows.</string> + <string lang="en" key="FEATURE_UNSUPPORTED_ON_CURRENT_OS">The feature is not supported on the version of the operating system you are currently using.</string> + <string lang="en" key="SYS_ENCRYPTION_UNSUPPORTED_ON_CURRENT_OS">TrueCrypt does not support encryption of a system partition/drive on the version of the operating system you are currently using.</string> + <string lang="en" key="SYS_ENCRYPTION_UNSUPPORTED_ON_VISTA_SP0">Before you can encrypt the system partition/drive on Windows Vista, you need to install Service Pack 1 or higher for Windows Vista (no such Service Pack has been installed on this system yet).\n\nNote: Service Pack 1 for Windows Vista resolved an issue causing a shortage of free base memory during system boot.</string> + <string lang="en" key="SYS_ENCRYPTION_UPGRADE_UNSUPPORTED_ON_VISTA_SP0">TrueCrypt no longer supports encryption of the system partition/drive on Windows Vista with no Service Pack installed. Before upgrading TrueCrypt, please install Service Pack 1 or higher for Windows Vista.</string> + <string lang="en" key="FEATURE_REQUIRES_INSTALLATION">Error: This feature requires TrueCrypt to be installed on the system (you are running TrueCrypt in portable mode).\n\nPlease install TrueCrypt and then try again.</string> + <string lang="en" key="WINDOWS_NOT_ON_BOOT_DRIVE_ERROR">WARNING: Windows does not appear to be installed on the drive from which it boots. This is not supported.\n\nYou should continue only if you are sure that Windows is installed on the drive from which it boots.\n\nDo you want to continue?</string> + <string lang="en" key="GPT_BOOT_DRIVE_UNSUPPORTED">Your system drive has a GUID partition table (GPT). Currently, only drives with a MBR partition table are supported.</string> + <string lang="en" key="TC_BOOT_LOADER_ALREADY_INSTALLED">CAUTION: The TrueCrypt Boot Loader is already installed on your system drive!\n\nIt is possible that another system on your computer is already encrypted.\n\nWARNING: PROCEEDING WITH ENCRYPTION OF THE CURRENTLY RUNNING SYSTEM MAY MAKE OTHER SYSTEM(S) IMPOSSIBLE TO START AND RELATED DATA INACCESSIBLE.\n\nAre you sure you want to continue?</string> + <string lang="en" key="SYS_LOADER_RESTORE_FAILED">Failed to restore the original system loader.\n\nPlease use your TrueCrypt Rescue Disk ('Repair Options' > 'Restore original system loader') or Windows installation medium to replace the TrueCrypt Boot Loader with the Windows system loader.</string> + <string lang="en" key="SYS_LOADER_UNAVAILABLE_FOR_RESCUE_DISK">The original system loader will not be stored on the Rescue Disk (probable cause: missing backup file).</string> + <string lang="en" key="ERROR_MBR_PROTECTED">Failed to write the MBR sector.\n\nYour BIOS may be configured to protect the MBR sector. Check your BIOS settings (press F2, Delete, or Esc, after powering on your computer) for MBR/antivirus protection.</string> + <string lang="en" key="BOOT_LOADER_VERSION_INCORRECT_PREFERENCES">The required version of the TrueCrypt Boot Loader is currently not installed. This may prevent some of the settings from being saved.</string> + <string lang="en" key="CUSTOM_BOOT_LOADER_MESSAGE_HELP">Note: In some situations, you may wish to prevent a person (adversary) that is watching you start the computer from knowing that you use TrueCrypt. The above options allow you to do that by customizing the TrueCrypt boot loader screen. If you enable the first option, no texts will be displayed by the boot loader (not even when you enter the wrong password). The computer will appear to be "frozen" while you can type your password. In addition, a custom message can be displayed to mislead the adversary. For example, fake error messages such as "Missing operating system" (which is normally displayed by the Windows boot loader if it finds no Windows boot partition). It is, however, important to note that if the adversary can analyze the content of the hard drive, he can still find out that it contains the TrueCrypt boot loader.</string> + <string lang="en" key="CUSTOM_BOOT_LOADER_MESSAGE_PROMPT">WARNING: Please keep in mind that if you enable this option, the TrueCrypt boot loader will not display any texts (not even when you enter the wrong password). The computer will appear to be "frozen" (unresponsive) while you can type your password (the cursor will NOT move and no asterisk will be displayed when you press a key).\n\nAre you sure you want to enable this option?</string> + <string lang="en" key="SYS_PARTITION_OR_DRIVE_APPEARS_FULLY_ENCRYPTED">Your system partition/drive appears to be fully encrypted.</string> + <string lang="en" key="SYSENC_UNSUPPORTED_FOR_DYNAMIC_DISK">TrueCrypt does not support encrypting a system drive that has been converted to a dynamic disk.</string> + <string lang="en" key="WDE_UNSUPPORTED_FOR_EXTENDED_PARTITIONS">The system drive contains extended (logical) partitions.\n\nYou can encrypt an entire system drive containing extended (logical) partitions only on Windows Vista and later versions of Windows. On Windows XP, you can encrypt an entire system drive provided that it contains only primary partitions.\n\nNote: You can still encrypt the system partition instead of the entire system drive (and, in addition to that, you can create partition-hosted TrueCrypt volumes within any non-system partitions on the drive).</string> + <string lang="en" key="WDE_EXTENDED_PARTITIONS_WARNING">WARNING: As you are running Windows XP/2003, after you start encrypting the drive, you must NOT create any extended (logical) partitions on it (you may create only primary partitions). Any extended (logical) partition on the drive would be inaccessible after you start encrypting (the drive currently does not contain any such partition).\n\nNote: If this limitation is not acceptable, you can go back and choose to encrypt only the system partition instead of the entire drive (and, in addition to that, you can create partition-hosted TrueCrypt volumes within any non-system partitions on the drive).\n\nAlternatively, if this limitation is not acceptable, you may want to consider upgrading to Windows Vista or a later version of Windows (you can encrypt an entire system drive containing extended/logical partitions only on Windows Vista or later).</string> + <string lang="en" key="SYSDRIVE_NON_STANDARD_PARTITIONS">Your system drive contains a non-standard partition.\n\nIf you are using a notebook, your system drive probably contains a special recovery partition. After the whole system drive is encrypted (including any recovery partition), your system might become unbootable if your computer is using an inappropriately designed BIOS. It would also be impossible to use any recovery partition until the system drive is decrypted. Therefore, we recommend that you encrypt only the system partition.</string> + <string lang="en" key="ASK_ENCRYPT_PARTITION_INSTEAD_OF_DRIVE">Do you want to encrypt the system partition instead of the entire drive?\n\nNote that you can create partition-hosted TrueCrypt volumes within any non-system partitions on the drive (in addition to encrypting the system partition).</string> + <string lang="en" key="WHOLE_SYC_DEVICE_RECOM">As your system drive contains only a single partition that occupies the whole drive, it is preferable (more secure) to encrypt the entire drive including the free "slack" space that typically surrounds such a partition.\n\nDo you want to encrypt the entire system drive?</string> + <string lang="en" key="TEMP_NOT_ON_SYS_PARTITION">Your system is configured to store temporary files on a non-system partition.\n\nTemporary files may be stored only on the system partition.</string> + <string lang="en" key="USER_PROFILE_NOT_ON_SYS_PARTITION">Your user profile files are not stored on the system partition.\n\nUser profile files may be stored only on the system partition.</string> + <string lang="en" key="PAGING_FILE_NOT_ON_SYS_PARTITION">There is/are paging file(s) on non-system partitions.\n\nPaging files may be located only on the system partition.</string> + <string lang="en" key="RESTRICT_PAGING_FILES_TO_SYS_PARTITION">Do you want to configure Windows to create paging files only on the Windows partition now?\n\nNote that if you click 'Yes', the computer will be restarted. Then start TrueCrypt and try creating the hidden OS again.</string> + <string lang="en" key="LEAKS_OUTSIDE_SYSPART_UNIVERSAL_EXPLANATION"> Otherwise, plausible deniability of the hidden operating system might be adversely affected.\n\nNote: If an adversary analyzed the content of such files (residing on a non-system partition), he might find out that you used this wizard in the hidden-system-creation mode (which might indicate the existence of a hidden operating system on your computer). Also note that any such files stored on the system partition will be securely erased by TrueCrypt during the process of creation of the hidden operating system.</string> + <string lang="en" key="DECOY_OS_REINSTALL_WARNING">WARNING: During the process of creation of the hidden operating system, you will be required to fully reinstall the currently running system (in order to create a decoy system securely).\n\nNote: The currently running operating system and the entire content of the system partition will be copied to the hidden volume (in order to create the hidden system).\n\n\nAre you sure you will be able to install Windows using a Windows Setup medium (or using a service partition)?</string> + <string lang="en" key="DECOY_OS_REQUIREMENTS">For security reasons, if the currently running operating system requires activation, it must be activated before proceeding. Note that the hidden operating system will be created by copying the content of the system partition to a hidden volume (so if this operating system is not activated, the hidden operating system will not be activated either). For more information, see the section "Security Requirements and Precautions Pertaining to Hidden Volumes" in the TrueCrypt User's Guide.\n\nImportant: Before proceeding, please make sure you have read the section "Security Requirements and Precautions Pertaining to Hidden Volumes" in the TrueCrypt User's Guide.\n\n\nDoes the currently running operating system meet the above condition?</string> + <string lang="en" key="CONFIRM_HIDDEN_OS_EXTRA_BOOT_PARTITION">Your system uses an extra boot partition. TrueCrypt does not support hibernation on hidden operating systems that use an extra boot partition (decoy systems can be hibernated without any problems).\n\nPlease note that the boot partition would be shared by both the decoy and the hidden system. Therefore, in order to prevent data leaks and problems while resuming from hibernation, TrueCrypt has to prevent the hidden system from writing to the shared boot partition and from hibernating.\n\n\nDo you want to continue? If you select 'No', instructions for removing the extra boot partition will be displayed.</string> + <string lang="en" key="EXTRA_BOOT_PARTITION_REMOVAL_INSTRUCTIONS">\nThe extra boot partition can be removed before installing Windows. To do so, follow these steps:\n\n1) Boot your Windows installation disc.\n\n2) In the Windows installer screen, click 'Install now' > 'Custom (advanced)'.\n\n3) Click 'Drive Options'.\n\n4) Select the main system partition and delete it by clicking 'Delete' and 'OK'.\n\n5) Select the 'System Reserved' partition, click 'Extend', and increase its size so that the operating system can be installed to it.\n\n6) Click 'Apply' and 'OK'.\n\n7) Install Windows on the 'System Reserved' partition.\n\n\nShould an attacker ask why you removed the extra boot partition, you can answer that you wanted to prevent any possible data leaks to the unencrypted boot partition.\n\nNote: You can print this text by clicking the 'Print' button below. If you save a copy of this text or print it (strongly recommended, unless your printer stores copies of documents it prints on its internal drive), you should destroy any copies of it after removing the extra boot partition (otherwise, if such a copy was found, it might indicate that there is a hidden operating system on this computer).</string> + <string lang="en" key="GAP_BETWEEN_SYS_AND_HIDDEN_OS_PARTITION">Warning: There is unallocated space between the system partition and the first partition behind it. After you create the hidden operating system, you must not create any new partitions in that unallocated space. Otherwise, the hidden operating system will be impossible to boot (until you delete such newly created partitions).</string> + <string lang="en" key="ALGO_NOT_SUPPORTED_FOR_SYS_ENCRYPTION">This algorithm is currently not supported for system encryption.</string> + <string lang="en" key="KEYFILES_NOT_SUPPORTED_FOR_SYS_ENCRYPTION">Keyfiles are currently not supported for system encryption.</string> + <string lang="en" key="CANNOT_RESTORE_KEYBOARD_LAYOUT">Warning: TrueCrypt could not restore the original keyboard layout. This may cause you to enter a password incorrectly.</string> + <string lang="en" key="CANT_CHANGE_KEYB_LAYOUT_FOR_SYS_ENCRYPTION">Error: Cannot set the keyboard layout for TrueCrypt to the standard US keyboard layout.\n\nNote that the password needs to be typed in the pre-boot environment (before Windows starts) where non-US Windows keyboard layouts are not available. Therefore, the password must always be typed using the standard US keyboard layout.</string> + <string lang="en" key="ALT_KEY_CHARS_NOT_FOR_SYS_ENCRYPTION">As TrueCrypt temporarily changed the keyboard layout to the standard US keyboard layout, it is not possible to type characters by pressing keys while the right Alt key is held down. However, you can type most of such characters by pressing appropriate keys while the Shift key is held down.</string> + <string lang="en" key="KEYB_LAYOUT_CHANGE_PREVENTED">TrueCrypt prevented change of keyboard layout.</string> + <string lang="en" key="KEYB_LAYOUT_SYS_ENC_EXPLANATION">Note: The password will need to be typed in the pre-boot environment (before Windows starts) where non-US Windows keyboard layouts are not available. Therefore, the password must always be typed using the standard US keyboard layout. However, it is important to note that you do NOT need a real US keyboard. TrueCrypt automatically ensures that you can safely type the password (right now and in the pre-boot environment) even if you do NOT have a real US keyboard.</string> + <string lang="en" key="RESCUE_DISK_INFO">Before you can encrypt the partition/drive, you must create a TrueCrypt Rescue Disk (TRD), which serves the following purposes:\n\n- If the TrueCrypt Boot Loader, master key, or other critical data gets damaged, the TRD allows you to restore it (note, however, that you will still have to enter the correct password then).\n\n- If Windows gets damaged and cannot start, the TRD allows you to permanently decrypt the partition/drive before Windows starts.\n\n- The TRD will contain a backup of the present content of the first drive track (which typically contains a system loader or boot manager) and will allow you to restore it if necessary.\n\nThe TrueCrypt Rescue Disk ISO image will be created in the location specified below.</string> + <string lang="en" key="RESCUE_DISK_WIN_ISOBURN_PRELAUNCH_NOTE">After you click OK, Microsoft Windows Disc Image Burner will be launched. Please use it to burn the TrueCrypt Rescue Disk ISO image to a CD or DVD.\n\nAfter you do so, return to the TrueCrypt Volume Creation Wizard and follow its instructions.</string> + <string lang="en" key="RESCUE_DISK_BURN_INFO">The Rescue Disk image has been created and stored in this file:\n%hs\n\nNow you need to burn it to a CD or DVD.\n\n%lsAfter you burn the Rescue Disk, click Next to verify that it has been correctly burned.</string> + <string lang="en" key="RESCUE_DISK_BURN_INFO_NO_CHECK">The Rescue Disk image has been created and stored in this file:\n%hs\n\nNow you should either burn the image to a CD/DVD or move it to a safe location for later use.\n\n%lsClick Next to continue.</string> + <string lang="en" key="RESCUE_DISK_BURN_INFO_NONWIN_ISO_BURNER">IMPORTANT: Note that the file must be written to the CD/DVD as an ISO disk image (not as an individual file). For information on how to do so, please refer to the documentation of your CD/DVD recording software. If you do not have any CD/DVD recording software that can write the ISO disk image to a CD/DVD, click the link below to download such free software.\n\n</string> + <string lang="en" key="LAUNCH_WIN_ISOBURN">Launch Microsoft Windows Disc Image Burner</string> + <string lang="en" key="RESCUE_DISK_BURN_NO_CHECK_WARN">WARNING: If you already created a TrueCrypt Rescue Disk in the past, it cannot be reused for this system partition/drive because it was created for a different master key! Every time you encrypt a system partition/drive, you must create a new TrueCrypt Rescue Disk for it even if you use the same password.</string> + <string lang="en" key="CANNOT_SAVE_SYS_ENCRYPTION_SETTINGS">Error: Cannot save system encryption settings.</string> + <string lang="en" key="CANNOT_INITIATE_SYS_ENCRYPTION_PRETEST">Cannot initiate the system encryption pretest.</string> + <string lang="en" key="CANNOT_INITIATE_HIDDEN_OS_CREATION">Cannot initiate the process of creation of the hidden operating system.</string> + <string lang="en" key="WIPE_MODE_TITLE">Wipe Mode</string> + <string lang="en" key="INPLACE_ENC_WIPE_MODE_INFO">On some types of storage media, when data is overwritten with other data, it may be possible to recover the overwritten data using techniques such as magnetic force microscopy. This also applies to data that are overwritten with their encrypted form (which happens when TrueCrypt initially encrypts an unencrypted partition or drive). According to some studies and governmental publications, recovery of overwritten data can be prevented (or made very difficult) by overwritting the data with pseudorandom and certain non-random data a certain number of times. Therefore, if you believe that an adversary might be able to use such techniques to recover the data you intend encrypt, you may want to select one of the wipe modes (existing data will NOT be lost). Note that wiping will NOT be performed after the partition/drive is encrypted. When the partition/drive is fully encrypted, no unencrypted data is written to it. Any data being written to it is first encrypted on the fly in memory and only then is the (encrypted) data written to the disk.</string> + <string lang="en" key="WIPE_MODE_INFO">On some types of storage media, when data is overwritten with other data (e.g. when the data is erased), it may be possible to recover the overwritten data using techniques such as magnetic force microscopy. According to some studies and governmental publications, recovery of overwritten data can be prevented (or made very difficult) by overwritting the data with pseudorandom and certain non-random data a certain number of times. Therefore, if you believe that an adversary might be able to use such techniques to recover the data that is to be erased, you may want to select one of the multi-pass wipe modes.\n\nNote: The more wipe passes you use, the longer it takes to erase the data.</string> + <string lang="en" key="DEVICE_WIPE_PAGE_TITLE">Wiping</string> + <string lang="en" key="DEVICE_WIPE_PAGE_INFO_HIDDEN_OS">\nNote: You can interrupt the process of wiping, shut down your computer, start the hidden system again and then resume the process (this wizard will be launched automatically). However, if you interrupt it, the entire process of wiping will have to start from the beginning.</string> + <string lang="en" key="DEVICE_WIPE_PAGE_INFO">\n\nNote: If you interrupt the process of wiping and then attempt to resume it, the entire process will have to start from the beginning.</string> + <string lang="en" key="CONFIRM_WIPE_ABORT">Do you want to abort the process of wiping?</string> + <string lang="en" key="CONFIRM_WIPE_START">Warning: The entire content of the selected partition/device will be erased and lost.</string> + <string lang="en" key="CONFIRM_WIPE_START_DECOY_SYS_PARTITION">The entire content of the partition where the original system resides will be erased.\n\nNote: The entire content of the partition that is to be erased has been copied to this hidden system partition.</string> + <string lang="en" key="WIPE_MODE_WARN">WARNING: Note that when you choose e.g. the 3-pass wipe mode, the time necessary to encrypt the partition/drive will be up to 4 times longer. Likewise, if you choose the 35-pass wipe mode, it will be up to 36 times longer (it might even take several weeks).\n\nHowever, please note that wiping will NOT be performed after the partition/drive is fully encrypted. When the partition/drive is fully encrypted, no unencrypted data is written to it. Any data being written to it is first encrypted on the fly in memory and only then is the (encrypted) data written to the disk (so the performance will NOT be affected).\n\nAre you sure you want to use the wipe mode?</string> + <string lang="en" key="WIPE_MODE_NONE">None (fastest)</string> + <string lang="en" key="WIPE_MODE_1_RAND">1-pass (random data)</string> + <string lang="en" key="WIPE_MODE_3_DOD_5220">3-pass (US DoD 5220.22-M)</string> + <string lang="en" key="WIPE_MODE_7_DOD_5220">7-pass (US DoD 5220.22-M)</string> + <string lang="en" key="WIPE_MODE_35_GUTMANN">35-pass ("Gutmann")</string> + <string lang="en" key="SYS_MULTI_BOOT_MODE_TITLE">Number of Operating Systems</string> + <string lang="en" key="MULTI_BOOT_FOR_ADVANCED_ONLY">WARNING: Inexperienced users should never attempt to encrypt Windows in multi-boot configurations.\n\nContinue?</string> + <string lang="en" key="HIDDEN_OS_MULTI_BOOT">When creating/using a hidden operating system, TrueCrypt supports multi-boot configurations only when the following conditions are met:\n\n- The currently running operating system must be installed on the boot drive, which must not contain any other operating systems.\n\n- Operating systems installed on other drives must not use any boot loader residing on the drive on which the currently running operating system is installed.\n\nAre the above conditions met?</string> + <string lang="en" key="UNSUPPORTED_HIDDEN_OS_MULTI_BOOT_CFG">TrueCrypt does not support this multi-boot configuration when creating/using a hidden operating system.</string> + <string lang="en" key="SYSENC_MULTI_BOOT_SYS_EQ_BOOT_TITLE">Boot Drive</string> + <string lang="en" key="SYSENC_MULTI_BOOT_SYS_EQ_BOOT_HELP">Is the currently running operating system installed on the boot drive?\n\nNote: Sometimes, Windows is not installed on the same drive as the Windows boot loader (boot partition). If that is the case, select 'No'.</string> + <string lang="en" key="SYS_PARTITION_MUST_BE_ON_BOOT_DRIVE">TrueCrypt currently does not support encrypting an operating system that does not boot from the drive on which it is installed.</string> + <string lang="en" key="SYSENC_MULTI_BOOT_NBR_SYS_DRIVES_TITLE">Number of System Drives</string> + <string lang="en" key="SYSENC_MULTI_BOOT_NBR_SYS_DRIVES_HELP">How many drives contain an operating system?\n\nNote: For example, if you have any operating system (e.g. Windows, Mac OS X, Linux, etc.) installed on your primary drive and any additional operating system installed on your secondary drive, select '2 or more'.</string> + <string lang="en" key="WDE_UNSUPPORTED_FOR_MULTIPLE_SYSTEMS_ON_ONE_DRIVE">TrueCrypt currently does not support encrypting a whole drive that contains multiple operating systems.\n\nPossible Solutions:\n\n- You can still encrypt one of the systems if you go back and choose to encrypt only a single system partition (as opposed to choosing to encrypt the entire system drive).\n\n- Alternatively, you will be able to encrypt the entire drive if you move some of the systems to other drives leaving only one system on the drive you want to encrypt.</string> + <string lang="en" key="SYSENC_MULTI_BOOT_ADJACENT_SYS_TITLE">Multiple Systems on Single Drive</string> + <string lang="en" key="SYSENC_MULTI_BOOT_ADJACENT_SYS_HELP">Are there any other operating systems installed on the drive on which the currently running operating system is installed?\n\nNote: For example, if the currently running operating system is installed on the drive #0, which contains several partitions, and if one of the partitions contains Windows and another partition contains any additional operating system (e.g. Windows, Mac OS X, Linux, etc.), select 'Yes'.</string> + <string lang="en" key="SYSENC_MULTI_BOOT_NONWIN_BOOT_LOADER_TITLE">Non-Windows Boot Loader</string> + <string lang="en" key="SYSENC_MULTI_BOOT_NONWIN_BOOT_LOADER_HELP">Is a non-Windows boot loader (or boot manager) installed in the master boot record (MBR)?\n\nNote: For example, if the first track of the boot drive contains GRUB, LILO, XOSL, or some other non-Windows boot manager (or boot loader), select 'Yes'.</string> + <string lang="en" key="SYSENC_MULTI_BOOT_OUTCOME_TITLE">Multi-Boot</string> + <string lang="en" key="CUSTOM_BOOT_MANAGERS_IN_MBR_UNSUPPORTED">TrueCrypt currently does not support multi-boot configurations where a non-Windows boot loader is installed in the Master Boot Record.\n\nPossible Solutions:\n\n- If you use a boot manager to boot Windows and Linux, move the boot manager (typically, GRUB) from the Master Boot Record to a partition. Then start this wizard again and encrypt the system partition/drive. Note that the TrueCrypt Boot Loader will become your primary boot manager and it will allow you to launch the original boot manager (e.g. GRUB) as your secondary boot manager (by pressing Esc in the TrueCrypt Boot Loader screen) and thus you will be able boot Linux.</string> + <string lang="en" key="WINDOWS_BOOT_LOADER_HINTS">If the currently running operating system is installed on the boot partition, then, after you encrypt it, you will need to enter the correct password even if you want to start any other unencrypted Windows system(s) (as they will share a single encrypted Windows boot loader/manager).\n\nIn contrast, if the currently running operating system is not installed on the boot partition (or if the Windows boot loader/manager is not used by any other system), then, after you encrypt this system, you will not need to enter the correct password to boot the other unencrypted system(s) -- you will only need to press the Esc key to start the unencrypted system (if there are multiple unencrypted systems, you will also need to choose which system to start in the TrueCrypt Boot Manager menu).\n\nNote: Typically, the earliest installed Windows system is installed on the boot partition.</string> + <string lang="en" key="SYSENC_PRE_DRIVE_ANALYSIS_TITLE">Encryption of Host Protected Area</string> + <string lang="en" key="SYSENC_PRE_DRIVE_ANALYSIS_HELP">At the end of many drives, there is an area that is normally hidden from the operating system (such areas are usually referred to as Host Protected Areas). However, some programs can read and write data from/to such areas.\n\nWARNING: Some computer manufacturers may use such areas to store tools and data for RAID, system recovery, system setup, diagnostic, or other purposes. If such tools or data must be accessible before booting, the hidden area should NOT be encrypted (choose 'No' above).\n\nDo you want TrueCrypt to detect and encrypt such a hidden area (if any) at the end of the system drive?</string> + <string lang="en" key="SYSENC_TYPE_PAGE_TITLE">Type of System Encryption</string> + <string lang="en" key="SYSENC_NORMAL_TYPE_HELP">Select this option if you merely want to encrypt the system partition or the entire system drive.</string> + <string lang="en" key="SYSENC_HIDDEN_TYPE_HELP">It may happen that you are forced by somebody to decrypt the operating system. There are many situations where you cannot refuse to do so (for example, due to extortion). If you select this option, you will create a hidden operating system whose existence should be impossible to prove (provided that certain guidelines are followed). Thus, you will not have to decrypt or reveal the password to the hidden operating system. For a detailed explanation, please click the link below.</string> + <string lang="en" key="HIDDEN_OS_PREINFO">It may happen that you are forced by somebody to decrypt the operating system. There are many situations where you cannot refuse to do so (for example, due to extortion).\n\nUsing this wizard, you can create a hidden operating system whose existence should be impossible to prove (provided that certain guidelines are followed). Thus, you will not have to decrypt or reveal the password for the hidden operating system.</string> + <string lang="en" key="SYSENC_HIDDEN_OS_REQ_CHECK_PAGE_TITLE">Hidden Operating System</string> + <string lang="en" key="SYSENC_HIDDEN_OS_REQ_CHECK_PAGE_HELP">In the following steps, you will create two TrueCrypt volumes (outer and hidden) within the first partition behind the system partition. The hidden volume will contain the hidden operating system (OS). TrueCrypt will create the hidden OS by copying the content of the system partition (where the currently running OS is installed) to the hidden volume. To the outer volume, you will copy some sensitive looking files that you actually do NOT want to hide. They will be there for anyone forcing you to disclose the password for the hidden OS partition. You can reveal the password for the outer volume within the hidden OS partition (the existence of the hidden OS remains secret).\n\nFinally, on the system partition of the currently running OS, you will install a new OS, so-called decoy OS, and encrypt it. It must not contain sensitive data and will be there for anyone forcing you to reveal your pre-boot authentication password. In total, there will be three passwords. Two of them can be disclosed (for the decoy OS and outer volume). If you use the third one, the hidden OS will start.</string> + <string lang="en" key="SYSENC_DRIVE_ANALYSIS_TITLE">Detecting Hidden Sectors</string> + <string lang="en" key="SYSENC_DRIVE_ANALYSIS_INFO">Please wait while TrueCrypt is detecting possible hidden sectors at the end of the system drive. Note that it may take a long time to complete.\n\nNote: In very rare cases, on some computers, the system may become unresponsive during this detection process. If it happens, restart the computer, start TrueCrypt, repeat the previous steps but skip this detection process. Note that this issue is not caused by a bug in TrueCrypt.</string> + <string lang="en" key="SYS_ENCRYPTION_SPAN_TITLE">Area to Encrypt</string> + <string lang="en" key="SYS_ENCRYPTION_SPAN_WHOLE_SYS_DRIVE_HELP">Select this option if you want to encrypt the entire drive on which the currently running Windows system is installed. The whole drive, including all its partitions, will be encrypted except the first track where the TrueCrypt Boot Loader will reside. Anyone who wants to access a system installed on the drive, or files stored on the drive, will need to enter the correct password each time before the system starts. This option cannot be used to encrypt a secondary or external drive if Windows is not installed on it and does not boot from it.</string> + <string lang="en" key="COLLECTING_RANDOM_DATA_TITLE">Collecting Random Data</string> + <string lang="en" key="KEYS_GEN_TITLE">Keys Generated</string> + <string lang="en" key="CD_BURNER_NOT_PRESENT">TrueCrypt has found no CD/DVD burner connected to your computer. TrueCrypt needs a CD/DVD burner to burn a bootable TrueCrypt Rescue Disk containing a backup of the encryption keys, TrueCrypt boot loader, original system loader, etc.\n\nWe strongly recommend that you burn the TrueCrypt Rescue Disk.</string> + <string lang="en" key="CD_BURNER_NOT_PRESENT_WILL_STORE_ISO">I have no CD/DVD burner but I will store the Rescue Disk ISO image on a removable drive (e.g. USB flash drive).</string> + <string lang="en" key="CD_BURNER_NOT_PRESENT_WILL_CONNECT_LATER">I will connect a CD/DVD burner to my computer later. Terminate the process now.</string> + <string lang="en" key="CD_BURNER_NOT_PRESENT_CONNECTED_NOW">A CD/DVD burner is connected to my computer now. Continue and write the Rescue Disk.</string> + <string lang="en" key="CD_BURNER_NOT_PRESENT_WILL_STORE_ISO_INFO">Please follow these steps:\n\n1) Connect a removable drive, such as a USB flash drive, to your computer now.\n\n2) Copy the TrueCrypt Rescue Disk image file (%s) to the removable drive.\n\nIn case you need to use the TrueCrypt Rescue Disk in the future, you will be able to connect your removable drive (containing the TrueCrypt Rescue Disk image) to a computer with a CD/DVD burner and create a bootable TrueCrypt Rescue Disk by burning the image to a CD or DVD. IMPORTANT: Note that the TrueCrypt Rescue Disk image file must be written to the CD/DVD as an ISO disk image (not as an individual file).</string> + <string lang="en" key="RESCUE_DISK_RECORDING_TITLE">Rescue Disk Recording</string> + <string lang="en" key="RESCUE_DISK_CREATED_TITLE">Rescue Disk Created</string> + <string lang="en" key="SYS_ENCRYPTION_PRETEST_TITLE">System Encryption Pretest</string> + <string lang="en" key="RESCUE_DISK_DISK_VERIFIED_TITLE">Rescue Disk Verified</string> + <string lang="en" key="RESCUE_DISK_VERIFIED_INFO">\nThe TrueCrypt Rescue Disk has been successfully verified. Please remove it from the drive now and store it in a safe place.\n\nClick Next to continue.</string> + <string lang="en" key="REMOVE_RESCUE_DISK_FROM_DRIVE">WARNING: During the next steps, the TrueCrypt Rescue Disk must not be in the drive. Otherwise, it will not be possible to complete the steps correctly.\n\nPlease remove it from the drive now and store it in a safe place. Then click OK.</string> + <string lang="en" key="PREBOOT_NOT_LOCALIZED">Warning: Due to technical limitations of the pre-boot environment, texts displayed by TrueCrypt in the pre-boot environment (i.e. before Windows starts) cannot be localized. The TrueCrypt Boot Loader user interface is completely in English.\n\nContinue?</string> + <string lang="en" key="SYS_ENCRYPTION_PRETEST_INFO">Before encrypting your system partition or drive, TrueCrypt needs to verify that everything works correctly.\n\nAfter you click Test, all the necessary components (for example, the pre-boot authentication component, i.e. the TrueCrypt Boot Loader) will be installed and your computer will be restarted. Then you will have to enter your password in the TrueCrypt Boot Loader screen that will appear before Windows starts. After Windows starts, you will be automatically informed about the result of this pretest.\n\nThe following device will be modified: Drive #%d\n\n\nIf you click Cancel now, nothing will be installed and the pretest will not be performed.</string> + <string lang="en" key="SYS_ENCRYPTION_PRETEST_INFO2_PORTION_1">IMPORTANT NOTES -- PLEASE READ OR PRINT (click 'Print'):\n\nNote that none of your files will be encrypted before you successfully restart your computer and start Windows. Thus, if anything fails, your data will NOT be lost. However, if something does go wrong, you might encounter difficulties in starting Windows. Therefore, please read (and, if possible, print) the following guidelines on what to do if Windows cannot start after you restart the computer.\n\n</string> + <string lang="en" key="SYS_ENCRYPTION_PRETEST_INFO2_PORTION_2">What to Do If Windows Cannot Start\n------------------------------------------------\n\nNote: These instructions are valid only if you have not started encrypting.\n\n- If Windows does not start after you enter the correct password (or if you repeatedly enter the correct password but TrueCrypt says that the password is incorrect), do not panic. Restart (power off and on) the computer, and in the TrueCrypt Boot Loader screen, press the Esc key on your keyboard (and if you have multiple systems, choose which to start). Then Windows should start (provided that it is not encrypted) and TrueCrypt will automatically ask whether you want to uninstall the pre-boot authentication component. Note that the previous steps do NOT work if the system partition/drive is encrypted (nobody can start Windows or access encrypted data on the drive without the correct password even if he or she follows the previous steps).\n\n</string> + <string lang="en" key="SYS_ENCRYPTION_PRETEST_INFO2_PORTION_3">- If the previous steps do not help or if the TrueCrypt Boot Loader screen does not appear (before Windows starts), insert the TrueCrypt Rescue Disk into your CD/DVD drive and restart your computer. If the TrueCrypt Rescue Disk screen does not appear (or if you do not see the 'Repair Options' item in the 'Keyboard Controls' section of the TrueCrypt Rescue Disk screen), it is possible that your BIOS is configured to attempt to boot from hard drives before CD/DVD drives. If that is the case, restart your computer, press F2 or Delete (as soon as you see a BIOS start-up screen), and wait until a BIOS configuration screen appears. If no BIOS configuration screen appears, restart (reset) the computer again and start pressing F2 or Delete repeatedly as soon as you restart (reset) the computer. When a BIOS configuration screen appears, configure your BIOS to boot from the CD/DVD drive first (for information on how to do so, please refer to the documentation for your BIOS/motherboard or contact your computer vendor's technical support team for assistance). Then restart your computer. The TrueCrypt Rescue Disk screen should appear now. In the TrueCrypt Rescue Disk screen, select 'Repair Options' by pressing F8 on your keyboard. From the 'Repair Options' menu, select 'Restore original system loader'. Then remove the Rescue Disk from your CD/DVD drive and restart your computer. Windows should start normally (provided that it is not encrypted).\n\n</string> + <string lang="en" key="SYS_ENCRYPTION_PRETEST_INFO2_PORTION_4">Note that the previous steps do NOT work if the system partition/drive is encrypted (nobody can start Windows or access encrypted data on the drive without the correct password even if he or she follows the previous steps).\n\n\nNote that even if you lose your TrueCrypt Rescue Disk and an attacker finds it, he or she will NOT be able to decrypt the system partition or drive without the correct password.</string> + <string lang="en" key="SYS_ENCRYPTION_PRETEST_RESULT_TITLE">Pretest Completed</string> + <string lang="en" key="SYS_ENCRYPTION_PRETEST_RESULT_INFO">The pretest has been successfully completed.\n\nWARNING: Please note that if power supply is suddenly interrupted while encrypting existing data in place, or when the operating system crashes due to a software error or hardware malfunction while TrueCrypt is encrypting existing data in place, portions of the data will be corrupted or lost. Therefore, before you start encrypting, please make sure that you have backup copies of the files you want to encrypt. If you do not, please back up the files now (you can click Defer, back up the files, then run TrueCrypt again anytime, and select 'System' > 'Resume Interrupted Process' to start encrypting).\n\nWhen ready, click Encrypt to start encrypting.</string> + <string lang="en" key="SYSENC_ENCRYPTION_PAGE_INFO">You can click Pause or Defer anytime to interrupt the process of encryption or decryption, exit this wizard, restart or shut down your computer, and then resume the process, which will continue from the point it was stopped. To prevent slowdown when the system or applications write or read data from the system drive, TrueCrypt automatically waits until the data is written or read (see Status above) and then automatically continues encrypting or decrypting.</string> + <string lang="en" key="NONSYS_INPLACE_ENC_ENCRYPTION_PAGE_INFO">\n\nYou can click Pause or Defer anytime to interrupt the process of encryption, exit this wizard, restart or shut down your computer, and then resume the process, which will continue from the point it was stopped. Note that the volume cannot be mounted until it has been fully encrypted.</string> + <string lang="en" key="SYSENC_HIDDEN_OS_INITIAL_INFO_TITLE">Hidden System Started</string> + <string lang="en" key="SYSENC_HIDDEN_OS_WIPE_INFO_TITLE">Original System</string> + <string lang="en" key="SYSENC_HIDDEN_OS_WIPE_INFO">Windows creates (typically, without your knowledge or consent) various log files, temporary files, etc., on the system partition. It also saves the content of RAM to hibernation and paging files located on the system partition. Therefore, if an adversary analyzed files stored on the partition where the original system (of which the hidden system is a clone) resides, he might find out, for example, that you used the TrueCrypt wizard in the hidden-system-creation mode (which might indicate the existence of a hidden operating system on your computer).\n\nTo prevent such issues, TrueCrypt will, in the next steps, securely erase the entire content of the partition where the original system resides. Afterwards, in order to achieve plausible deniability, you will need to install a new system on the partition and encrypt it. Thus you will create the decoy system and the whole process of creation of the hidden operating system will be completed.</string> + <string lang="en" key="OS_WIPING_NOT_FINISHED_ASK">The hidden operating system has been successfully created. However, before you can start using it (and achieve plausible deniability), you need to securely erase (using TrueCrypt) the entire content of the partition where the currently running operating system is installed. Before you can do that, you need to restart the computer and, in the TrueCrypt Boot Loader screen (which appears before Windows starts), enter the pre-boot authentication password for the hidden operating system. Then, after the hidden system starts, the TrueCrypt wizard will be launched automatically.\n\nNote: If you choose to terminate the process of creation of the hidden operating system now, you will NOT be able to resume the process and the hidden system will NOT be accessible (because the TrueCrypt Boot Loader will be removed).</string> + <string lang="en" key="HIDDEN_OS_CREATION_NOT_FINISHED_ASK">You have scheduled the process of creation of a hidden operating system. The process has not been completed yet. To complete it, you need to restart the computer and, in the TrueCrypt Boot Loader screen (which appears before Windows starts), enter the password for the hidden operating system.\n\nNote: If you choose to terminate the process of creation of the hidden operating system now, you will NOT be able to resume the process.</string> + <string lang="en" key="HIDDEN_OS_CREATION_NOT_FINISHED_CHOICE_RETRY">Restart the computer and proceed</string> + <string lang="en" key="HIDDEN_OS_CREATION_NOT_FINISHED_CHOICE_TERMINATE">Permanently terminate the process of creation of the hidden operating system</string> + <string lang="en" key="HIDDEN_OS_CREATION_NOT_FINISHED_CHOICE_ASK_LATER">Do nothing now and ask again later</string> + <string lang="en" key="RESCUE_DISK_HELP_PORTION_1">\nIF POSSIBLE, PLEASE PRINT THIS TEXT (click 'Print' below).\n\n\nHow and When to Use TrueCrypt Rescue Disk (After Encrypting)\n-----------------------------------------------------------------------------------\n\n</string> + <string lang="en" key="RESCUE_DISK_HELP_PORTION_2">I. How to Boot TrueCrypt Rescue Disk\n\nTo boot a TrueCrypt Rescue Disk, insert it into your CD/DVD drive and restart your computer. If the TrueCrypt Rescue Disk screen does not appear (or if you do not see the 'Repair Options' item in the 'Keyboard Controls' section of the screen), it is possible that your BIOS is configured to attempt to boot from hard drives before CD/DVD drives. If that is the case, restart your computer, press F2 or Delete (as soon as you see a BIOS start-up screen), and wait until a BIOS configuration screen appears. If no BIOS configuration screen appears, restart (reset) the computer again and start pressing F2 or Delete repeatedly as soon as you restart (reset) the computer. When a BIOS configuration screen appears, configure your BIOS to boot from the CD/DVD drive first (for information on how to do so, please refer to the documentation for your BIOS/motherboard or contact your computer vendor's technical support team for assistance). Then restart your computer. The TrueCrypt Rescue Disk screen should appear now. Note: In the TrueCrypt Rescue Disk screen, you can select 'Repair Options' by pressing F8 on your keyboard.\n\n\n</string> + <string lang="en" key="RESCUE_DISK_HELP_PORTION_3">II. When and How to Use TrueCrypt Rescue Disk (After Encrypting)\n\n</string> + <string lang="en" key="RESCUE_DISK_HELP_PORTION_4">1) If the TrueCrypt Boot Loader screen does not appear after you start your computer (or if Windows does not boot), the TrueCrypt Boot Loader may be damaged. The TrueCrypt Rescue Disk allows you to restore it and thus to regain access to your encrypted system and data (however, note that you will still have to enter the correct password then). In the Rescue Disk screen, select 'Repair Options' > 'Restore TrueCrypt Boot Loader'. Then press 'Y' to confirm the action, remove the Rescue Disk from your CD/DVD drive and restart your computer.\n\n</string> + <string lang="en" key="RESCUE_DISK_HELP_PORTION_5">2) If you repeatedly enter the correct password but TrueCrypt says that the password is incorrect, the master key or other critical data may be damaged. The TrueCrypt Rescue Disk allows you to restore them and thus to regain access to your encrypted system and data (however, note that you will still have to enter the correct password then). In the Rescue Disk screen, select 'Repair Options' > 'Restore key data'. Then enter your password, press 'Y' to confirm the action, remove the Rescue Disk from your CD/DVD drive, and restart your computer.\n\n</string> + <string lang="en" key="RESCUE_DISK_HELP_PORTION_6">3) If the TrueCrypt Boot Loader is damaged, you can avoid running it by booting directly from the TrueCrypt Rescue Disk. Insert your Rescue Disk into your CD/DVD drive and then enter your password in the Rescue Disk screen.\n\n</string> + <string lang="en" key="RESCUE_DISK_HELP_PORTION_7">4) If Windows is damaged and cannot start, the TrueCrypt Rescue Disk allows you to permanently decrypt the partition/drive before Windows starts. In the Rescue Disk screen, select 'Repair Options' > 'Permanently decrypt system partition/drive'. Enter the correct password and wait until decryption is complete. Then you can e.g. boot your MS Windows setup CD/DVD to repair your Windows installation.\n\n</string> + <string lang="en" key="RESCUE_DISK_HELP_PORTION_8">Note: Alternatively, if Windows is damaged (cannot start) and you need to repair it (or access files on it), you can avoid decrypting the system partition/drive by following these steps: If you have multiple operating systems installed on your computer, boot the one that does not require pre-boot authentication. If you do not have multiple operating systems installed on your computer, you can boot a WinPE or BartPE CD/DVD or you can connect your system drive as a secondary or external drive to another computer and then boot the operating system installed on the computer. After you boot a system, run TrueCrypt, click 'Select Device', select the affected system partition, click 'OK', select 'System' > 'Mount Without Pre-Boot Authentication', enter your pre-boot authentication password and click 'OK'. The partition will be mounted as a regular TrueCrypt volume (data will be on-the-fly decrypted/encrypted in RAM on access, as usual).\n\n\n</string> + <string lang="en" key="RESCUE_DISK_HELP_PORTION_9">Note that even if you lose your TrueCrypt Rescue Disk and an attacker finds it, he or she will NOT be able to decrypt the system partition or drive without the correct password.</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_1">\n\nI M P O R T A N T -- PLEASE PRINT THIS TEXT IF POSSIBLE (click 'Print' below).\n\n\nNote: This text will be automatically displayed each time you start the hidden system until you start creating the decoy system.\n\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_2">How to Create Decoy System Safely and Securely\n----------------------------------------------------------------------------\n\nIn order to achieve plausible deniability, you need to create the decoy operating system now. To do so, follow these steps:\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_3">1) For security reasons, shut down your computer and leave it powered off for at least several minutes (the longer, the better). This is required to clear the memory, which contains sensitive data. Then turn on the computer but do not boot the hidden system.\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_4">2) Install Windows on the partition whose content has been erased (i.e. on the partition where the original system, of which the hidden system is a clone, was installed).\n\nIMPORTANT: WHEN YOU START INSTALLING THE DECOY SYSTEM, THE HIDDEN SYSTEM WILL *NOT* BE POSSIBLE TO BOOT (because the TrueCrypt Boot Loader will be erased by the Windows system installer). THIS IS NORMAL AND EXPECTED. PLEASE DO NOT PANIC. YOU WILL BE ABLE TO BOOT THE HIDDEN SYSTEM AGAIN AS SOON AS YOU START ENCRYPTING THE DECOY SYSTEM (because TrueCrypt will then automatically install the TrueCrypt Boot Loader on the system drive).\n\nImportant: The size of the decoy system partition must remain the same as the size of the hidden volume (this condition is now met). Moreover, you must not create any partition between the decoy system partition and the partition where the hidden system resides.\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_5">3) Boot the decoy system (which you installed in step 2 and install TrueCrypt on it).\n\nKeep in mind that the decoy system must never contain any sensitive data.\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_6">4) On the decoy system, run TrueCrypt and select 'System' > 'Encrypt System Partition/Drive'. The TrueCrypt Volume Creation Wizard window should appear.\n\nThe following steps apply to the TrueCrypt Volume Creation Wizard.\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_7">5) In the TrueCrypt Volume Creation Wizard, do NOT select the 'Hidden' option. Leave the 'Normal' option selected and click 'Next'.\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_8">6) Select the option 'Encrypt the Windows system partition' and then click 'Next'.\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_9">7) If there are only the hidden system and the decoy system installed on the computer, select the option 'Single-boot' (if there are more than these two systems installed on the computer, select 'Multi-boot'). Then click 'Next'.\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_10">8) IMPORTANT: In this step, FOR THE DECOY SYSTEM, YOU MUST SELECT THE SAME ENCRYPTION ALGORITHM AND HASH ALGORITHM THAT YOU SELECTED FOR THE HIDDEN SYSTEM! OTHERWISE, THE HIDDEN SYSTEM WILL BE INACCESSIBLE! In other words, the decoy system must be encrypted with the same encryption algorithm as the hidden system. Note: The reason is that the decoy system and the hidden system will share a single boot loader, which supports only a single algorithm, selected by the user (for each algorithm, there is a special version of the TrueCrypt Boot Loader).\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_11">9) In this step, choose a password for the decoy operating system. This will be the password that you will be able to reveal to an adversary if you are asked or forced to disclose your pre-boot authentication password (the other password you can reveal is the one for the outer volume). The existence of the third password (i.e. of the pre-boot authentication password for the hidden operating system) will remain secret.\n\nImportant: The password you choose for the decoy system must be substantially different from the one you chose for the hidden volume (i.e. for the hidden operating system).\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_12">10) Follow the remaining instructions in the wizard so as to encrypt the decoy operating system.\n\n\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_13">After Decoy System Is Created\n------------------------------------------------\n\nAfter you encrypt the decoy system, the whole process of creation of the hidden operating system will be completed and you will be able to use these three passwords:\n\n1) Pre-boot authentication password for the hidden operating system.\n\n2) Pre-boot authentication password for the decoy operating system.\n\n3) Password for the outer volume.\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_14">If you want to start the hidden operating system, you will just need to enter the password for the hidden operating system in the TrueCrypt Boot Loader screen (which appears after you turn on or restart your computer).\n\nIf you want to start the decoy operating system, you will just need to enter the password for the decoy operating system in the TrueCrypt Boot Loader screen.\n\nThe password for the decoy system can be disclosed to anyone forcing you to reveal your pre-boot authentication password. The existence of the hidden volume (and of the hidden operating system) will remain secret.\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_15">The third password (for the outer volume) can be disclosed to anyone forcing you to reveal the password for the first partition behind the system partition, where both the outer volume and the hidden volume (containing the hidden operating system) reside. The existence of the hidden volume (and of the hidden operating system) will remain secret.\n\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_16">If you revealed the password for the decoy system to an adversary and he asked you why the free space of the (decoy) system partition contains random data, you could answer, for example: "The partition previously contained a system encrypted by TrueCrypt, but I forgot the pre-boot authentication password (or the system was damaged and stopped booting), so I had to reinstall Windows and encrypt the partition again."\n\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_17">If all the instructions are followed and if the precautions and requirements listed in the section "Security Requirements and Precautions Pertaining to Hidden Volumes" in the TrueCrypt User's Guide are followed, it should be impossible to prove that the hidden volume and hidden operating system exist, even when the outer volume is mounted or when the decoy operating system is decrypted or started.\n\nIf you save a copy of this text or print it (strongly recommended, unless your printer stores copies of documents it prints on its internal drive), you should destroy any copies of it after you have created the decoy system and after you have understood all the information contained in the text (otherwise, if such a copy was found, it might indicate that there is a hidden operating system on this computer).\n\n</string> + <string lang="en" key="DECOY_OS_INSTRUCTIONS_PORTION_18">WARNING: IF YOU DO NOT PROTECT THE HIDDEN VOLUME (for information on how to do so, refer to the section "Protection of Hidden Volumes Against Damage" in the TrueCrypt User's Guide), DO NOT WRITE TO THE OUTER VOLUME (note that the decoy operating system is NOT installed in the outer volume). OTHERWISE, YOU MAY OVERWRITE AND DAMAGE THE HIDDEN VOLUME (AND THE HIDDEN OPERATING SYSTEM WITHIN IT)!</string> + <string lang="en" key="HIDDEN_OS_CREATION_PREINFO_TITLE">Operating System Cloning</string> + <string lang="en" key="HIDDEN_OS_CREATION_PREINFO_HELP">In the next steps, TrueCrypt will create the hidden operating system by copying the content of the system partition to the hidden volume (data being copied will be encrypted on the fly with an encryption key different from the one that will be used for the decoy operating system).\n\nPlease note that the process will be performed in the pre-boot environment (before Windows starts) and it may take a long time to complete; several hours or even several days (depending on the size of the system partition and on the performance of your computer).\n\nYou will be able to interrupt the process, shut down your computer, start the operating system and then resume the process. However, if you interrupt it, the entire process of copying the system will have to start from the beginning (because the content of the system partition must not change during cloning).</string> + <string lang="en" key="CONFIRM_CANCEL_HIDDEN_OS_CREATION">Do you want to cancel the entire process of creation of the hidden operating system?\n\nNote: You will NOT be able to resume the process if you cancel it now.</string> + <string lang="en" key="CONFIRM_CANCEL_SYS_ENC_PRETEST">Do you want to cancel the system encryption pretest?</string> + <string lang="en" key="BOOT_PRETEST_FAILED_RETRY">The TrueCrypt system encryption pretest failed. Do you want to try again?\n\nIf you select 'No', the pre-boot authentication component will be uninstalled.\n\nNotes:\n\n- If the TrueCrypt Boot Loader did not ask you to enter the password before Windows started, it is possible that your operating system does not boot from the drive on which it is installed. This is not supported.\n\n- If you used an encryption algorithm other than AES and the pretest failed (and you entered the password), it may have been caused by an inappropriately designed driver. Select 'No', and try encrypting the system partition/drive again, but use the AES encryption algorithm (which has the lowest memory requirements).\n\n- For more possible causes and solutions, see: http://www.truecrypt.org/docs/?s=troubleshooting</string> + <string lang="en" key="SYS_DRIVE_NOT_ENCRYPTED">The system partition/drive does not appear to be encrypted (neither partially nor fully).</string> + <string lang="en" key="SETUP_FAILED_BOOT_DRIVE_ENCRYPTED">Your system partition/drive is encrypted (partially or fully).\n\nPlease decrypt your system partition/drive entirely before proceeding. To do so, select 'System' > 'Permanently Decrypt System Partition/Drive' from the menu bar of the main TrueCrypt window.</string> + <string lang="en" key="SETUP_FAILED_BOOT_DRIVE_ENCRYPTED_DOWNGRADE">When the system partition/drive is encrypted (partially or fully), you cannot downgrade TrueCrypt (but you can upgrade it or reinstall the same version).</string> + <string lang="en" key="SYS_ENCRYPTION_OR_DECRYPTION_IN_PROGRESS">Your system partition/drive is currently being encrypted, decrypted, or otherwise modified. Please interrupt the encryption/decryption/modification process (or wait until it is complete) before proceeding.</string> + <string lang="en" key="SYSTEM_ENCRYPTION_IN_PROGRESS_ELSEWHERE">An instance of the TrueCrypt Volume Creation Wizard is currently running on this system and performing or preparing encryption/decryption of the system partition/drive. Before you proceed, please wait for it to finish or close it. If you cannot close it, please restart your computer before proceeding.</string> + <string lang="en" key="SYSTEM_ENCRYPTION_NOT_COMPLETED">The process of encryption or decryption of the system partition/drive has not been completed. Please wait until it is complete before proceeding.</string> + <string lang="en" key="ERR_ENCRYPTION_NOT_COMPLETED">Error: The process of encryption of the partition/drive has not been completed. It must be completed first.</string> + <string lang="en" key="ERR_NONSYS_INPLACE_ENC_INCOMPLETE">Error: The process of encryption of the partition/volume has not been completed. It must be completed first.\n\nNote: To resume the process, select 'Volumes' > 'Resume Interrupted Process' from the menu bar of the main TrueCrypt window.</string> + <string lang="en" key="ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG">The password is correct, TrueCrypt has successfully decrypted the volume header and detected that this volume is a hidden system volume. However, you cannot modify the header of a hidden system volume this way.\n\nTo change the password for a hidden system volume, boot the operating system residing in the hidden volume, and then select 'System' > 'Change Password' from the menu bar of the main TrueCrypt window.\n\nTo set the header key derivation algorithm, boot the hidden operating system and then select 'System' > 'Set Header Key Derivation Algorithm'.</string> + <string lang="en" key="CANNOT_DECRYPT_HIDDEN_OS">TrueCrypt does not support in-place decryption of a hidden system partition.\n\nNote: If you want to decrypt the decoy system partition, boot the decoy system, and then select 'System' > 'Permanently Decrypt System Partition/Drive' from the menu bar of the main TrueCrypt window.</string> + <string lang="en" key="ERR_PARAMETER_INCORRECT">Error: Incorrect/invalid parameter.</string> + <string lang="en" key="DEVICE_SELECTED_IN_NON_DEVICE_MODE">You have selected a partition or a device but the wizard mode you selected is suitable only for file containers.\n\nDo you want to change the wizard mode?</string> + <string lang="en" key="CONFIRM_CHANGE_WIZARD_MODE_TO_FILE_CONTAINER">Do you want to create a TrueCrypt file container instead?</string> + <string lang="en" key="CONFIRM_SYSTEM_ENCRYPTION_MODE">You have selected the system partition/drive (or the boot partition), but the wizard mode you selected is suitable only for non-system partitions/drives.\n\nDo you want to set up pre-boot authentication (which means that you will need to enter your password each time before Windows boots/starts) and encrypt the system partition/drive?</string> + <string lang="en" key="CONFIRM_DECRYPT_SYS_DEVICE">Are you sure you want to permanently decrypt the system partition/drive?</string> + <string lang="en" key="CONFIRM_DECRYPT_SYS_DEVICE_CAUTION">CAUTION: If you permanently decrypt the system partition/drive, unencrypted data will be written to it.\n\nAre you really sure you want to permanently decrypt the system partition/drive?</string> + <string lang="en" key="CONFIRM_CASCADE_FOR_SYS_ENCRYPTION">Warning: If you use a cascade of ciphers for system encryption, you may encounter the following issues:\n\n1) The TrueCrypt Boot Loader is larger than normal and, therefore, there is not enough space in the first drive track for a backup of the TrueCrypt Boot Loader. Hence, whenever it gets damaged (which often happens, for example, during inappropriately designed anti-piracy activation procedures of certain programs), you will need to use the TrueCrypt Rescue Disk to boot or to repair the TrueCrypt Boot Loader.\n\n2) On some computers, resuming from hibernation takes longer.\n\nThese potential issues can be prevented by choosing a non-cascade encryption algorithm (e.g. AES).\n\nAre you sure you want to use a cascade of ciphers?</string> + <string lang="en" key="NOTE_CASCADE_FOR_SYS_ENCRYPTION">If you encounter any of the previously described problems, decrypt the partition/drive (if it is encrypted) and then try encrypting it again using a non-cascade encryption algorithm (e.g. AES).</string> + <string lang="en" key="UPDATE_TC_IN_DECOY_OS_FIRST">WARNING: For safety and security reasons, you should update TrueCrypt on the decoy operating system before you update it on the hidden operating system.\n\nTo do so, boot the decoy system and run the TrueCrypt installer from within it. Then boot the hidden system and run the installer from within it as well.\n\nNote: The decoy system and the hidden system share a single boot loader. If you upgraded TrueCrypt only on the hidden system (but not on the decoy system), the decoy system would contain a TrueCrypt driver and TrueCrypt applications whose version numbers are different from the version number of the TrueCrypt Boot Loader. Such a discrepancy might indicate that there is a hidden operating system on this computer.\n\n\nDo you want to continue?</string> + <string lang="en" key="UPDATE_TC_IN_HIDDEN_OS_TOO">The version number of the TrueCrypt Boot Loader that booted this operating system is different from the version number of the TrueCrypt driver (and of the TrueCrypt applications) installed on this system.\n\nYou should run the TrueCrypt installer (whose version number is the same as the one of the TrueCrypt Boot Loader) to update TrueCrypt on this operating system.</string> + <string lang="en" key="BOOT_LOADER_VERSION_DIFFERENT_FROM_DRIVER_VERSION">The version number of the TrueCrypt Boot Loader that booted this operating system is different from the version number of the TrueCrypt driver (and of the TrueCrypt applications) installed on this system. Note that older versions may contain bugs fixed in later versions.\n\nIf you did not boot from the TrueCrypt Rescue Disk, you should reinstall TrueCrypt or upgrade it to the latest stable version (the boot loader will be updated too).\n\nIf you booted from the TrueCrypt Rescue Disk, you should update it ('System' > 'Create Rescue Disk').</string> + <string lang="en" key="BOOT_LOADER_UPGRADE_OK">The TrueCrypt Boot Loader has been upgraded.\n\nIt is strongly recommended that you create a new TrueCrypt Rescue Disk (which will contain the new version of the TrueCrypt Boot Loader) by selecting 'System' > 'Create Rescue Disk' after you restart your computer.</string> + <string lang="en" key="BOOT_LOADER_UPGRADE_OK_HIDDEN_OS">The TrueCrypt Boot Loader has been upgraded.\n\nIt is strongly recommended that you boot the decoy operating system and then create a new TrueCrypt Rescue Disk (which will contain the new version of the TrueCrypt Boot Loader) by selecting 'System' > 'Create Rescue Disk'.</string> + <string lang="en" key="BOOT_LOADER_UPGRADE_FAILED">Failed to upgrade the TrueCrypt Boot Loader.</string> + <string lang="en" key="SYS_DRIVE_SIZE_PROBE_TIMEOUT">TrueCrypt failed to detect the real size of the system drive and, therefore, the size reported by the operating system (which may be smaller than the real size) will be used. Also note that this is not a bug in TrueCrypt.</string> + <string lang="en" key="HIDDEN_SECTOR_DETECTION_FAILED_PREVIOUSLY">WARNING: It appears that TrueCrypt has already tried to detect hidden sectors on this system drive. If you encountered any problems during the previous detection process, you can avoid the problems by skipping the detection of hidden sectors now. Note that if you do so, TrueCrypt will use the size reported by the operating system (which may be smaller than the real size of the drive).\n\nNote that this issue is not caused by a bug in TrueCrypt.</string> + <string lang="en" key="SKIP_HIDDEN_SECTOR_DETECTION">Skip detection of hidden sectors (use the size reported by the operating system)</string> + <string lang="en" key="RETRY_HIDDEN_SECTOR_DETECTION">Try to detect hidden sectors again</string> + <string lang="en" key="ENABLE_BAD_SECTOR_ZEROING">Error: Content of one or more sectors on the disk cannot be read (probably due to a physical defect).\n\nThe process of in-place encryption can continue only when the sectors have been made readable again. TrueCrypt can attempt to make these sectors readable by writing zeros to the sectors (subsequently such all-zero blocks would be encrypted). However, note that any data stored in the unreadable sectors will be lost. If you want to avoid that, you can attempt to recover portions of the corrupted data using appropriate third-party tools.\n\nNote: In case of physically damaged sectors (as opposed to mere data corruption and checksum errors) most types of storage devices internally reallocate the sectors when data is attempted to be written to them (so the existing data in the damaged sectors may remain unencrypted on the drive).\n\nDo you want TrueCrypt to write zeroes to unreadable sectors?</string> + <string lang="en" key="DISCARD_UNREADABLE_ENCRYPTED_SECTORS">Error: Content of one or more sectors on the disk cannot be read (probably due to a physical defect).\n\nTo be able to proceed with decryption, TrueCrypt will have to discard the content of the unreadable sectors (the content will be replaced with pseudorandom data). Please note that, before proceeding, you can attempt to recover portions of any corrupted data using appropriate third-party tools.\n\nDo you want TrueCrypt to discard data in the unreadable sectors now?</string> + <string lang="en" key="ZEROED_BAD_SECTOR_COUNT">Note: TrueCrypt has replaced the content of %I64d unreadable sectors (%s) with encrypted all-zero plaintext blocks.</string> + <string lang="en" key="ENTER_TOKEN_PASSWORD">Enter password/PIN for token '%s':</string> + <string lang="en" key="PKCS11_LIB_LOCATION_HELP">In order to allow TrueCrypt to access a security token or smart card, you need to install a PKCS #11 software library for the token or smart card first. Such a library may be supplied with the device or it may be available for download from the website of the vendor or other third parties.\n\nAfter you install the library, you can either select it manually by clicking 'Select Library' or you can let TrueCrypt find and select it automatically by clicking 'Auto-Detect Library' (only the Windows system directory will be searched).</string> + <string lang="en" key="SELECT_PKCS11_MODULE_HELP">Note: For the filename and location of the PKCS #11 library installed for your security token or smart card, please refer to the documentation supplied with the token, card, or third-party software.\n\nClick 'OK' to select the path and filename.</string> + <string lang="en" key="NO_PKCS11_MODULE_SPECIFIED">In order to allow TrueCrypt to access a security token or smart card, you need to select a PKCS #11 software library for the token/card first. To do so, select 'Settings' > 'Security Tokens'.</string> + <string lang="en" key="PKCS11_MODULE_INIT_FAILED">Failed to initialize PKCS #11 security token library.\n\nPlease make sure the specified path and filename refer to a valid PKCS #11 library. To specify a PKCS #11 library path and filename, select 'Settings' > 'Security Tokens'.</string> + <string lang="en" key="PKCS11_MODULE_AUTO_DETECTION_FAILED">No PKCS #11 library has been found in the Windows system directory.\n\nPlease make sure that a PKCS #11 library for your security token (or for your smart card) is installed (such a library may be supplied with the token/card or it may be available for download from the website of the vendor or other third parties). If it is installed in a directory other than the Windows system directory, click 'Select Library' to locate the library (e.g. in the folder where the software for the token/card is installed).</string> + <string lang="en" key="NO_TOKENS_FOUND">No security token found.\n\nPlease make sure your security token is connected to your computer and the correct device driver for your token is installed.</string> + <string lang="en" key="TOKEN_KEYFILE_NOT_FOUND">Security token keyfile not found.</string> + <string lang="en" key="TOKEN_KEYFILE_ALREADY_EXISTS">A security token keyfile with the same name already exists.</string> + <string lang="en" key="CONFIRM_SEL_FILES_DELETE">Do you want to delete the selected files?</string> + <string lang="en" key="INVALID_TOKEN_KEYFILE_PATH">Security token keyfile path is invalid.</string> + <string lang="en" key="SECURITY_TOKEN_ERROR">Security token error</string> + <string lang="en" key="CKR_PIN_INCORRECT">Password for security token is incorrect.</string> + <string lang="en" key="CKR_DEVICE_MEMORY">The security token does not have enough memory/space to perform the requested operation.\n\nIf you are attempting to import a keyfile, you should select a smaller file or use a keyfile generated by TrueCrypt (select 'Tools' > 'Keyfile Generator').</string> + <string lang="en" key="ALL_TOKEN_SESSIONS_CLOSED">All open security token sessions have been closed.</string> + <string lang="en" key="SELECT_TOKEN_KEYFILES">Select Security Token Keyfiles</string> + <string lang="en" key="TOKEN_SLOT_ID">Slot</string> + <string lang="en" key="TOKEN_NAME">Token name</string> + <string lang="en" key="TOKEN_DATA_OBJECT_LABEL">File name</string> + <string lang="en" key="BOOT_PASSWORD_CACHE_KEYBOARD_WARNING">IMPORTANT: Please note that pre-boot authentication passwords are always typed using the standard US keyboard layout. Therefore, a volume that uses a password typed using any other keyboard layout may be impossible to mount using a pre-boot authentication password (note that this is not a bug in TrueCrypt). To allow such a volume to be mounted using a pre-boot authentication password, follow these steps:\n\n1) Click 'Select File' or 'Select Device' and select the volume.\n2) Select 'Volumes' > 'Change Volume Password'.\n3) Enter the current password for the volume.\n4) Change the keyboard layout to English (US) by clicking the Language bar icon in the Windows taskbar and selecting 'EN English (United States)'.\n5) In TrueCrypt, in the field for the new password, type the pre-boot authentication password.\n6) Confirm the new password by retyping it in the confirmation field and click 'OK'.\nWARNING: Please keep in mind that if you follow these steps, the volume password will always have to be typed using the US keyboard layout (which is automatically ensured only in the pre-boot environment).</string> + <string lang="en" key="SYS_FAVORITES_KEYBOARD_WARNING">System favorite volumes will be mounted using the pre-boot authentication password. If any system favorite volume uses a different password, it will not be mounted.</string> + <string lang="en" key="SYS_FAVORITES_ADMIN_ONLY_INFO">Please note that if you need to prevent normal TrueCrypt volume actions (such as 'Dismount All', auto-dismount, etc.) from affecting system favorite volumes, you should enable the option 'Allow only administrators to view and dismount system favorite volumes in TrueCrypt'. In addition, when TrueCrypt is run without administrator privileges (the default on Windows Vista and later), system favorite volumes will not be displayed in the drive letter list in the main TrueCrypt application window.</string> + <string lang="en" key="SYS_FAVORITES_ADMIN_ONLY_WARNING">IMPORTANT: Please keep in mind that if this option is enabled and TrueCrypt does not have administrator privileges, mounted system favorite volumes are NOT displayed in the TrueCrypt application window and they cannot be dismounted. Therefore, if you need e.g. to dismount a system favorite volume, please right-click the TrueCrypt icon (in the Start menu) and select 'Run as administrator' first. The same limitation applies to the 'Dismount All' function, 'Auto-Dismount' functions, 'Dismount All' hot keys, etc.</string> + <string lang="en" key="SETTING_REQUIRES_REBOOT">Note that this setting takes effect only after the operating system is restarted.</string> + <string lang="en" key="COMMAND_LINE_ERROR">Error while parsing command line.</string> + <string lang="en" key="RESCUE_DISK">Rescue Disk</string> + <string lang="en" key="SELECT_FILE_AND_MOUNT">Select &File and Mount...</string> + <string lang="en" key="SELECT_DEVICE_AND_MOUNT">Select &Device and Mount...</string> + <string lang="en" key="DISABLE_NONADMIN_SYS_FAVORITES_ACCESS">Allow only administrators to view and dismount system favorite volumes in TrueCrypt</string> + <string lang="en" key="MOUNT_SYSTEM_FAVORITES_ON_BOOT">Mount system favorite volumes when Windows starts (in the initial phase of the startup procedure)</string> + <string lang="en" key="MOUNTED_VOLUME_DIRTY">Warning: The filesystem on the volume mounted as '%s' was not cleanly dismounted and thus may contain errors. Using a corrupted filesystem can cause data loss or data corruption.\n\nNote: Before you physically remove or switch off a device (such as a USB flash drive or an external hard drive) where a mounted TrueCrypt volume resides, you should always dismount the TrueCrypt volume in TrueCrypt first.\n\n\nDo you want Windows to attempt to detect and fix errors (if any) on the filesystem?</string> + <string lang="en" key="SYS_FAVORITE_VOLUME_DIRTY">Warning: One or more system favorite volumes were not cleanly dismounted and thus may contain filesystem errors. Please see the system event log for further details.\n\nUsing a corrupted filesystem can cause data loss or data corruption. You should check the affected system favorite volume(s) for errors (right-click each of them in TrueCrypt and select 'Repair Filesystem').</string> + <string lang="en" key="FILESYS_REPAIR_CONFIRM_BACKUP">Warning: Repairing a damaged filesystem using the Microsoft 'chkdsk' tool might cause loss of files in damaged areas. Therefore, it is recommended that you first back up the files stored on the TrueCrypt volume to another, healthy, TrueCrypt volume.\n\nDo you want to repair the filesystem now?</string> + <string lang="en" key="MOUNTED_CONTAINER_FORCED_READ_ONLY">Volume '%s' has been mounted as read-only because write access was denied.\n\nPlease make sure the security permissions of the file container allow you to write to it (right-click the container and select Properties > Security).\n\nNote that, due to a Windows issue, you may see this warning even after setting the appropriate security permissions. This is not caused by a bug in TrueCrypt. A possible solution is to move your container to, e.g., your 'Documents' folder.\n\nIf you intend to keep your volume read-only, set the read-only attribute of the container (right-click the container and select Properties > Read-only), which will suppress this warning.</string> + <string lang="en" key="MOUNTED_DEVICE_FORCED_READ_ONLY">Volume '%s' had to be mounted as read-only because write access was denied.\n\nPlease make sure no other application (e.g. antivirus software) is accessing the partition/device on which the volume is hosted.</string> + <string lang="en" key="MOUNTED_DEVICE_FORCED_READ_ONLY_WRITE_PROTECTION">Volume '%s' has been mounted as read-only because the operating system reported the host device to be write-protected.\n\nPlease note that some custom chipset drivers have been reported to cause writable media to falsely appear write-protected. This problem is not caused by TrueCrypt. It may be solved by updating or uninstalling any custom (non-Microsoft) chipset drivers that are currently installed on this system.</string> + <string lang="en" key="LIMIT_ENC_THREAD_POOL_NOTE">Note that the Hyper-Threading technology provides multiple logical cores per a single physical core. When Hyper Threading is enabled, the number selected above represents the number of logical processors/cores.</string> + <string lang="en" key="NUMBER_OF_THREADS">%d threads</string> + <string lang="en" key="DISABLED_HW_AES_AFFECTS_PERFORMANCE">Note that hardware-accelerated AES is disabled, which will affect benchmark results (worse performance).\n\nTo enable hardware acceleration, select 'Settings' > 'Performance' and enable the corresponding option.</string> + <string lang="en" key="LIMITED_THREAD_COUNT_AFFECTS_PERFORMANCE">Note that the number of threads is currently limited, which will affect benchmark results (worse performance).\n\nTo utilize the full potential of the processor(s), select 'Settings' > 'Performance' and disable the corresponding option.</string> + <string lang="en" key="ASK_REMOVE_DEVICE_WRITE_PROTECTION">Do you want TrueCrypt to attempt to disable write protection of the partition/drive?</string> + <string lang="en" key="CONFIRM_SETTING_DEGRADES_PERFORMANCE">WARNING: This setting may degrade performance.\n\nAre you sure you want to use this setting?</string> + <string lang="en" key="HOST_DEVICE_REMOVAL_DISMOUNT_WARN_TITLE">Warning: TrueCrypt volume auto-dismounted</string> + <string lang="en" key="HOST_DEVICE_REMOVAL_DISMOUNT_WARN">Before you physically remove or turn off a device containing a mounted volume, you should always dismount the volume in TrueCrypt first.\n\nUnexpected spontaneous dismount is usually caused by an intermittently failing cable, drive (enclosure), etc.</string> + <string lang="en" key="TEST">Test</string> + <string lang="en" key="KEYFILE">Keyfile</string> + <string lang="en" key="VKEY_08">Backspace</string> + <string lang="en" key="VKEY_09">Tab</string> + <string lang="en" key="VKEY_0C">Clear</string> + <string lang="en" key="VKEY_0D">Enter</string> + <string lang="en" key="VKEY_13">Pause</string> + <string lang="en" key="VKEY_14">Caps Lock</string> + <string lang="en" key="VKEY_20">Spacebar</string> + <string lang="en" key="VKEY_21">Page Up</string> + <string lang="en" key="VKEY_22">Page Down</string> + <string lang="en" key="VKEY_23">End</string> + <string lang="en" key="VKEY_24">Home</string> + <string lang="en" key="VKEY_25">Left Arrow</string> + <string lang="en" key="VKEY_26">Up Arrow</string> + <string lang="en" key="VKEY_27">Right Arrow</string> + <string lang="en" key="VKEY_28">Down Arrow</string> + <string lang="en" key="VKEY_29">Select Key</string> + <string lang="en" key="VKEY_2A">Print Key</string> + <string lang="en" key="VKEY_2B">Execute Key</string> + <string lang="en" key="VKEY_2C">Print Screen</string> + <string lang="en" key="VKEY_2D">Insert</string> + <string lang="en" key="VKEY_2E">Delete</string> + <string lang="en" key="VKEY_5D">Applications Key</string> + <string lang="en" key="VKEY_5F">Sleep</string> + <string lang="en" key="VKEY_90">Num Lock</string> + <string lang="en" key="VKEY_91">Scroll Lock</string> + <string lang="en" key="VKEY_A6">Browser Back</string> + <string lang="en" key="VKEY_A7">Browser Forward</string> + <string lang="en" key="VKEY_A8">Browser Refresh</string> + <string lang="en" key="VKEY_A9">Browser Stop</string> + <string lang="en" key="VKEY_AA">Browser Search</string> + <string lang="en" key="VKEY_AB">Browser Favorites</string> + <string lang="en" key="VKEY_AC">Browser Home</string> + <string lang="en" key="VKEY_AD">Mute</string> + <string lang="en" key="VKEY_AE">Volume Down</string> + <string lang="en" key="VKEY_AF">Volume Up</string> + <string lang="en" key="VKEY_B0">Next Track</string> + <string lang="en" key="VKEY_B1">Previous Track</string> + <string lang="en" key="VKEY_B2">Stop Media</string> + <string lang="en" key="VKEY_B3">Play/Pause Media</string> + <string lang="en" key="VKEY_B4">Start Mail Key</string> + <string lang="en" key="VKEY_B5">Select Media Key</string> + <string lang="en" key="VKEY_B6">Application 1</string> + <string lang="en" key="VKEY_B7">Application 2</string> + <string lang="en" key="VKEY_F6">Attn</string> + <string lang="en" key="VKEY_F7">CrSel</string> + <string lang="en" key="VKEY_F8">ExSel</string> + <string lang="en" key="VKEY_FA">Play</string> + <string lang="en" key="VKEY_FB">Zoom</string> + <string lang="en" key="VK_NUMPAD">NumPad</string> + <string lang="en" key="VK_SHIFT">Shift</string> + <string lang="en" key="VK_CONTROL">Control</string> + <string lang="en" key="VK_ALT">Alt</string> + <string lang="en" key="VK_WIN">Win</string> + <string lang="en" key="BYTE">B</string> + <string lang="en" key="KB">KB</string> + <string lang="en" key="MB">MB</string> + <string lang="en" key="GB">GB</string> + <string lang="en" key="TB">TB</string> + <string lang="en" key="PB">PB</string> + <string lang="en" key="B_PER_SEC">B/s</string> + <string lang="en" key="KB_PER_SEC">KB/s</string> + <string lang="en" key="MB_PER_SEC">MB/s</string> + <string lang="en" key="GB_PER_SEC">GB/s</string> + <string lang="en" key="TB_PER_SEC">TB/s</string> + <string lang="en" key="PB_PER_SEC">PB/s</string> + <string lang="en" key="TRIPLE_DOT_GLYPH_ELLIPSIS">…</string> + </localization> + <!-- XML Schema --> + <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema"> + <xs:element name="TrueCrypt"> + <xs:complexType> + <xs:sequence> + <xs:element name="localization"> + <xs:complexType> + <xs:sequence> + <xs:element name="language"> + <xs:complexType> + <xs:attribute name="langid" type="xs:string" use="required" /> + <xs:attribute name="name" type="xs:string" use="required" /> + <xs:attribute name="en-name" type="xs:string" use="required" /> + <xs:attribute name="version" type="xs:string" use="required" /> + <xs:attribute name="translators" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element minOccurs="4" maxOccurs="4" name="font"> + <xs:complexType> + <xs:attribute name="lang" type="xs:string" use="required" /> + <xs:attribute name="class" type="xs:string" use="required" /> + <xs:attribute name="size" type="xs:unsignedByte" use="required" /> + <xs:attribute name="face" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + <xs:element maxOccurs="unbounded" name="control"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="lang" type="xs:string" use="required" /> + <xs:attribute name="key" type="xs:string" use="required" /> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + <xs:element maxOccurs="unbounded" name="string"> + <xs:complexType> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="lang" type="xs:string" use="required" /> + <xs:attribute name="key" type="xs:string" use="required" /> + </xs:extension> + </xs:simpleContent> + </xs:complexType> + </xs:element> + </xs:sequence> + <xs:attribute name="prog-version" type="xs:string" use="required" /> + </xs:complexType> + </xs:element> + </xs:sequence> + </xs:complexType> + </xs:element> + </xs:schema> +</TrueCrypt> diff --git a/Common/Makefile b/Common/Makefile new file mode 100644 index 0000000..5acbbd2 --- /dev/null +++ b/Common/Makefile @@ -0,0 +1 @@ +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/Common/Password.c b/Common/Password.c new file mode 100644 index 0000000..739e2f2 --- /dev/null +++ b/Common/Password.c @@ -0,0 +1,422 @@ +/* + 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 "Volumes.h" +#include "Password.h" +#include "Dlgcode.h" +#include "Language.h" +#include "Pkcs5.h" +#include "Endian.h" +#include "Random.h" + +#include <io.h> + +void VerifyPasswordAndUpdate (HWND hwndDlg, HWND hButton, HWND hPassword, + HWND hVerify, unsigned char *szPassword, + char *szVerify, + BOOL keyFilesEnabled) +{ + char szTmp1[MAX_PASSWORD + 1]; + char szTmp2[MAX_PASSWORD + 1]; + int k = GetWindowTextLength (hPassword); + BOOL bEnable = FALSE; + + if (hwndDlg); /* Remove warning */ + + GetWindowText (hPassword, szTmp1, sizeof (szTmp1)); + GetWindowText (hVerify, szTmp2, sizeof (szTmp2)); + + if (strcmp (szTmp1, szTmp2) != 0) + bEnable = FALSE; + else + { + if (k >= MIN_PASSWORD || keyFilesEnabled) + bEnable = TRUE; + else + bEnable = FALSE; + } + + if (szPassword != NULL) + memcpy (szPassword, szTmp1, sizeof (szTmp1)); + + if (szVerify != NULL) + memcpy (szVerify, szTmp2, sizeof (szTmp2)); + + burn (szTmp1, sizeof (szTmp1)); + burn (szTmp2, sizeof (szTmp2)); + + EnableWindow (hButton, bEnable); +} + + +BOOL CheckPasswordCharEncoding (HWND hPassword, Password *ptrPw) +{ + int i, len; + + if (hPassword == NULL) + { + unsigned char *pw; + len = ptrPw->Length; + pw = (unsigned char *) ptrPw->Text; + + for (i = 0; i < len; i++) + { + if (pw[i] >= 0x7f || pw[i] < 0x20) // A non-ASCII or non-printable character? + return FALSE; + } + } + else + { + wchar_t s[MAX_PASSWORD + 1]; + len = GetWindowTextLength (hPassword); + + if (len > MAX_PASSWORD) + return FALSE; + + GetWindowTextW (hPassword, s, sizeof (s) / sizeof (wchar_t)); + + for (i = 0; i < len; i++) + { + if (s[i] >= 0x7f || s[i] < 0x20) // A non-ASCII or non-printable character? + break; + } + + burn (s, sizeof(s)); + + if (i < len) + return FALSE; + } + + return TRUE; +} + + +BOOL CheckPasswordLength (HWND hwndDlg, HWND hwndItem) +{ + if (GetWindowTextLength (hwndItem) < PASSWORD_LEN_WARNING) + { +#ifndef _DEBUG + if (MessageBoxW (hwndDlg, GetString ("PASSWORD_LENGTH_WARNING"), lpszTitle, MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2) != IDYES) + return FALSE; +#endif + } + return TRUE; +} + +int ChangePwd (char *lpszVolume, Password *oldPassword, Password *newPassword, int pkcs5, HWND hwndDlg) +{ + int nDosLinkCreated = 1, nStatus = ERR_OS_ERROR; + char szDiskFile[TC_MAX_PATH], szCFDevice[TC_MAX_PATH]; + char szDosDevice[TC_MAX_PATH]; + char buffer[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; + PCRYPTO_INFO cryptoInfo = NULL, ci = NULL; + void *dev = INVALID_HANDLE_VALUE; + DWORD dwError; + DWORD bytesRead; + BOOL bDevice; + unsigned __int64 hostSize = 0; + int volumeType; + int wipePass; + FILETIME ftCreationTime; + FILETIME ftLastWriteTime; + FILETIME ftLastAccessTime; + BOOL bTimeStampValid = FALSE; + LARGE_INTEGER headerOffset; + BOOL backupHeader; + DISK_GEOMETRY driveInfo; + + if (oldPassword->Length == 0 || newPassword->Length == 0) return -1; + + WaitCursor (); + + CreateFullVolumePath (szDiskFile, lpszVolume, &bDevice); + + if (bDevice == FALSE) + { + strcpy (szCFDevice, szDiskFile); + } + else + { + nDosLinkCreated = FakeDosNameForDevice (szDiskFile, szDosDevice, szCFDevice, FALSE); + + if (nDosLinkCreated != 0) + goto error; + } + + dev = CreateFile (szCFDevice, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); + + if (dev == INVALID_HANDLE_VALUE) + goto error; + + if (bDevice) + { + /* This is necessary to determine the hidden volume header offset */ + + if (dev == INVALID_HANDLE_VALUE) + { + goto error; + } + else + { + PARTITION_INFORMATION diskInfo; + DWORD dwResult; + BOOL bResult; + + bResult = DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, + &driveInfo, sizeof (driveInfo), &dwResult, NULL); + + if (!bResult) + goto error; + + bResult = GetPartitionInfo (lpszVolume, &diskInfo); + + if (bResult) + { + hostSize = diskInfo.PartitionLength.QuadPart; + } + else + { + hostSize = driveInfo.Cylinders.QuadPart * driveInfo.BytesPerSector * + driveInfo.SectorsPerTrack * driveInfo.TracksPerCylinder; + } + + if (hostSize == 0) + { + nStatus = ERR_VOL_SIZE_WRONG; + goto error; + } + } + } + else + { + LARGE_INTEGER fileSize; + if (!GetFileSizeEx (dev, &fileSize)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + hostSize = fileSize.QuadPart; + } + + if (Randinit ()) + goto error; + + if (!bDevice && bPreserveTimestamp) + { + if (GetFileTime ((HANDLE) dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime) == 0) + bTimeStampValid = FALSE; + else + bTimeStampValid = TRUE; + } + + 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 = TC_VOLUME_HEADER_OFFSET; + break; + + case TC_VOLUME_TYPE_HIDDEN: + if (TC_HIDDEN_VOLUME_HEADER_OFFSET + TC_VOLUME_HEADER_SIZE > hostSize) + continue; + + headerOffset.QuadPart = TC_HIDDEN_VOLUME_HEADER_OFFSET; + break; + + case TC_VOLUME_TYPE_HIDDEN_LEGACY: + if (bDevice && driveInfo.BytesPerSector != TC_SECTOR_SIZE_LEGACY) + continue; + + headerOffset.QuadPart = hostSize - TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY; + break; + } + + if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + /* Read in volume header */ + if (!ReadEffectiveVolumeHeader (bDevice, dev, buffer, &bytesRead)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + if (bytesRead != sizeof (buffer)) + { + // Windows may report EOF when reading sectors from the last cluster of a device formatted as NTFS + memset (buffer, 0, sizeof (buffer)); + } + + /* Try to decrypt the header */ + + nStatus = ReadVolumeHeader (FALSE, buffer, oldPassword, &cryptoInfo, NULL); + if (nStatus == ERR_CIPHER_INIT_WEAK_KEY) + nStatus = 0; // We can ignore this error here + + if (nStatus == ERR_PASSWORD_WRONG) + { + continue; // Try next volume type + } + else if (nStatus != 0) + { + cryptoInfo = NULL; + goto error; + } + else + break; + } + + if (nStatus != 0) + { + cryptoInfo = NULL; + goto error; + } + + if (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_ENCRYPTED_SYSTEM) + { + nStatus = ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG; + goto error; + } + + // Change the PKCS-5 PRF if requested by user + if (pkcs5 != 0) + cryptoInfo->pkcs5 = pkcs5; + + RandSetHashFunction (cryptoInfo->pkcs5); + + NormalCursor(); + UserEnrichRandomPool (hwndDlg); + EnableElevatedCursorChange (hwndDlg); + WaitCursor(); + + /* Re-encrypt the volume header */ + backupHeader = FALSE; + + while (TRUE) + { + /* 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. */ + + for (wipePass = 0; wipePass < PRAND_DISK_WIPE_PASSES; wipePass++) + { + // Prepare new volume header + nStatus = CreateVolumeHeaderInMemory (FALSE, + buffer, + cryptoInfo->ea, + cryptoInfo->mode, + newPassword, + cryptoInfo->pkcs5, + cryptoInfo->master_keydata, + &ci, + cryptoInfo->VolumeSize.Value, + (volumeType == TC_VOLUME_TYPE_HIDDEN || volumeType == TC_VOLUME_TYPE_HIDDEN_LEGACY) ? cryptoInfo->hiddenVolumeSize : 0, + cryptoInfo->EncryptedAreaStart.Value, + cryptoInfo->EncryptedAreaLength.Value, + cryptoInfo->RequiredProgramVersion, + cryptoInfo->HeaderFlags, + cryptoInfo->SectorSize, + wipePass < PRAND_DISK_WIPE_PASSES - 1); + + if (ci != NULL) + crypto_close (ci); + + if (nStatus != 0) + goto error; + + if (!SetFilePointerEx ((HANDLE) dev, headerOffset, NULL, FILE_BEGIN)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + if (!WriteEffectiveVolumeHeader (bDevice, dev, buffer)) + { + nStatus = ERR_OS_ERROR; + goto error; + } + + if (bDevice + && !cryptoInfo->LegacyVolume + && !cryptoInfo->hiddenVolume + && cryptoInfo->HeaderVersion == 4 + && (cryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC) != 0 + && (cryptoInfo->HeaderFlags & ~TC_HEADER_FLAG_NONSYS_INPLACE_ENC) == 0) + { + nStatus = WriteRandomDataToReservedHeaderAreas (dev, cryptoInfo, cryptoInfo->VolumeSize.Value, !backupHeader, backupHeader); + if (nStatus != ERR_SUCCESS) + goto error; + } + + FlushFileBuffers (dev); + } + + if (backupHeader || cryptoInfo->LegacyVolume) + break; + + backupHeader = TRUE; + headerOffset.QuadPart += hostSize - TC_VOLUME_HEADER_GROUP_SIZE; + } + + /* Password successfully changed */ + nStatus = 0; + +error: + dwError = GetLastError (); + + burn (buffer, sizeof (buffer)); + + if (cryptoInfo != NULL) + crypto_close (cryptoInfo); + + if (bTimeStampValid) + SetFileTime (dev, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime); + + if (dev != INVALID_HANDLE_VALUE) + CloseHandle ((HANDLE) dev); + + if (nDosLinkCreated == 0) + RemoveFakeDosName (szDiskFile, szDosDevice); + + RandStop (FALSE); + NormalCursor (); + + SetLastError (dwError); + + if (nStatus == ERR_OS_ERROR && dwError == ERROR_ACCESS_DENIED + && bDevice + && !UacElevated + && IsUacSupported ()) + return nStatus; + + if (nStatus != 0) + handleError (hwndDlg, nStatus); + + return nStatus; +} + diff --git a/Common/Password.h b/Common/Password.h new file mode 100644 index 0000000..2e7960b --- /dev/null +++ b/Common/Password.h @@ -0,0 +1,46 @@ +/* + 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 PASSWORD_H +#define PASSWORD_H + +// User text input limits +#define MIN_PASSWORD 1 // Minimum possible password length +#define MAX_PASSWORD 64 // Maximum possible password length + +#define PASSWORD_LEN_WARNING 20 // Display a warning when a password is shorter than this + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + // Modifying this structure can introduce incompatibility with previous versions + unsigned __int32 Length; + unsigned char Text[MAX_PASSWORD + 1]; + char Pad[3]; // keep 64-bit alignment +} Password; + +#if defined(_WIN32) && !defined(TC_WINDOWS_DRIVER) + +void VerifyPasswordAndUpdate ( HWND hwndDlg , HWND hButton , HWND hPassword , HWND hVerify , unsigned char *szPassword , char *szVerify, BOOL keyFilesEnabled ); +BOOL CheckPasswordLength (HWND hwndDlg, HWND hwndItem); +BOOL CheckPasswordCharEncoding (HWND hPassword, Password *ptrPw); +int ChangePwd (char *lpszVolume, Password *oldPassword, Password *newPassword, int pkcs5, HWND hwndDlg); + +#endif // defined(_WIN32) && !defined(TC_WINDOWS_DRIVER) + +#ifdef __cplusplus +} +#endif + +#endif // PASSWORD_H diff --git a/Common/Pkcs5.c b/Common/Pkcs5.c new file mode 100644 index 0000000..2888940 --- /dev/null +++ b/Common/Pkcs5.c @@ -0,0 +1,642 @@ +/* + 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 <memory.h> +#include "Rmd160.h" +#ifndef TC_WINDOWS_BOOT +#include "Sha1.h" +#include "Sha2.h" +#include "Whirlpool.h" +#endif +#include "Pkcs5.h" +#include "Crypto.h" + +void hmac_truncate + ( + char *d1, /* data to be truncated */ + char *d2, /* truncated data */ + int len /* length in bytes to keep */ +) +{ + int i; + for (i = 0; i < len; i++) + d2[i] = d1[i]; +} + +#ifndef TC_WINDOWS_BOOT + +void hmac_sha512 +( + char *k, /* secret key */ + int lk, /* length of the key in bytes */ + char *d, /* data */ + int ld, /* length of data in bytes */ + char *out, /* output buffer, at least "t" bytes */ + int t +) +{ + sha512_ctx ictx, octx; + char isha[SHA512_DIGESTSIZE], osha[SHA512_DIGESTSIZE]; + char key[SHA512_DIGESTSIZE]; + char buf[SHA512_BLOCKSIZE]; + int i; + + /* If the key is longer than the hash algorithm block size, + let key = sha512(key), as per HMAC specifications. */ + if (lk > SHA512_BLOCKSIZE) + { + sha512_ctx tctx; + + sha512_begin (&tctx); + sha512_hash ((unsigned char *) k, lk, &tctx); + sha512_end ((unsigned char *) key, &tctx); + + k = key; + lk = SHA512_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + + /**** Inner Digest ****/ + + sha512_begin (&ictx); + + /* Pad the key for inner digest */ + for (i = 0; i < lk; ++i) + buf[i] = (char) (k[i] ^ 0x36); + for (i = lk; i < SHA512_BLOCKSIZE; ++i) + buf[i] = 0x36; + + sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, &ictx); + sha512_hash ((unsigned char *) d, ld, &ictx); + + sha512_end ((unsigned char *) isha, &ictx); + + /**** Outer Digest ****/ + + sha512_begin (&octx); + + for (i = 0; i < lk; ++i) + buf[i] = (char) (k[i] ^ 0x5C); + for (i = lk; i < SHA512_BLOCKSIZE; ++i) + buf[i] = 0x5C; + + sha512_hash ((unsigned char *) buf, SHA512_BLOCKSIZE, &octx); + sha512_hash ((unsigned char *) isha, SHA512_DIGESTSIZE, &octx); + + sha512_end ((unsigned char *) osha, &octx); + + /* truncate and print the results */ + t = t > SHA512_DIGESTSIZE ? SHA512_DIGESTSIZE : t; + hmac_truncate (osha, out, t); + + /* Prevent leaks */ + burn (&ictx, sizeof(ictx)); + burn (&octx, sizeof(octx)); + burn (isha, sizeof(isha)); + burn (osha, sizeof(osha)); + burn (buf, sizeof(buf)); + burn (key, sizeof(key)); +} + + +void derive_u_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) +{ + char j[SHA512_DIGESTSIZE], k[SHA512_DIGESTSIZE]; + char init[128]; + char counter[4]; + int c, i; + + /* iteration 1 */ + memset (counter, 0, 4); + counter[3] = (char) b; + memcpy (init, salt, salt_len); /* salt */ + memcpy (&init[salt_len], counter, 4); /* big-endian block number */ + hmac_sha512 (pwd, pwd_len, init, salt_len + 4, j, SHA512_DIGESTSIZE); + memcpy (u, j, SHA512_DIGESTSIZE); + + /* remaining iterations */ + for (c = 1; c < iterations; c++) + { + hmac_sha512 (pwd, pwd_len, j, SHA512_DIGESTSIZE, k, SHA512_DIGESTSIZE); + for (i = 0; i < SHA512_DIGESTSIZE; i++) + { + u[i] ^= k[i]; + j[i] = k[i]; + } + } + + /* Prevent possible leaks. */ + burn (j, sizeof(j)); + burn (k, sizeof(k)); +} + + +void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) +{ + char u[SHA512_DIGESTSIZE]; + int b, l, r; + + if (dklen % SHA512_DIGESTSIZE) + { + l = 1 + dklen / SHA512_DIGESTSIZE; + } + else + { + l = dklen / SHA512_DIGESTSIZE; + } + + r = dklen - (l - 1) * SHA512_DIGESTSIZE; + + /* first l - 1 blocks */ + for (b = 1; b < l; b++) + { + derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, u, b); + memcpy (dk, u, SHA512_DIGESTSIZE); + dk += SHA512_DIGESTSIZE; + } + + /* last block */ + derive_u_sha512 (pwd, pwd_len, salt, salt_len, iterations, u, b); + memcpy (dk, u, r); + + + /* Prevent possible leaks. */ + burn (u, sizeof(u)); +} + + +/* Deprecated/legacy */ +void hmac_sha1 +( + char *k, /* secret key */ + int lk, /* length of the key in bytes */ + char *d, /* data */ + int ld, /* length of data in bytes */ + char *out, /* output buffer, at least "t" bytes */ + int t +) +{ + sha1_ctx ictx, octx; + char isha[SHA1_DIGESTSIZE], osha[SHA1_DIGESTSIZE]; + char key[SHA1_DIGESTSIZE]; + char buf[SHA1_BLOCKSIZE]; + int i; + + /* If the key is longer than the hash algorithm block size, + let key = sha1(key), as per HMAC specifications. */ + if (lk > SHA1_BLOCKSIZE) + { + sha1_ctx tctx; + + sha1_begin (&tctx); + sha1_hash ((unsigned char *) k, lk, &tctx); + sha1_end ((unsigned char *) key, &tctx); + + k = key; + lk = SHA1_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + + /**** Inner Digest ****/ + + sha1_begin (&ictx); + + /* Pad the key for inner digest */ + for (i = 0; i < lk; ++i) + buf[i] = (char) (k[i] ^ 0x36); + for (i = lk; i < SHA1_BLOCKSIZE; ++i) + buf[i] = 0x36; + + sha1_hash ((unsigned char *) buf, SHA1_BLOCKSIZE, &ictx); + sha1_hash ((unsigned char *) d, ld, &ictx); + + sha1_end ((unsigned char *) isha, &ictx); + + /**** Outer Digest ****/ + + sha1_begin (&octx); + + for (i = 0; i < lk; ++i) + buf[i] = (char) (k[i] ^ 0x5C); + for (i = lk; i < SHA1_BLOCKSIZE; ++i) + buf[i] = 0x5C; + + sha1_hash ((unsigned char *) buf, SHA1_BLOCKSIZE, &octx); + sha1_hash ((unsigned char *) isha, SHA1_DIGESTSIZE, &octx); + + sha1_end ((unsigned char *) osha, &octx); + + /* truncate and print the results */ + t = t > SHA1_DIGESTSIZE ? SHA1_DIGESTSIZE : t; + hmac_truncate (osha, out, t); + + /* Prevent leaks */ + burn (&ictx, sizeof(ictx)); + burn (&octx, sizeof(octx)); + burn (isha, sizeof(isha)); + burn (osha, sizeof(osha)); + burn (buf, sizeof(buf)); + burn (key, sizeof(key)); +} + + +/* Deprecated/legacy */ +void derive_u_sha1 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) +{ + char j[SHA1_DIGESTSIZE], k[SHA1_DIGESTSIZE]; + char init[128]; + char counter[4]; + int c, i; + + /* iteration 1 */ + memset (counter, 0, 4); + counter[3] = (char) b; + memcpy (init, salt, salt_len); /* salt */ + memcpy (&init[salt_len], counter, 4); /* big-endian block number */ + hmac_sha1 (pwd, pwd_len, init, salt_len + 4, j, SHA1_DIGESTSIZE); + memcpy (u, j, SHA1_DIGESTSIZE); + + /* remaining iterations */ + for (c = 1; c < iterations; c++) + { + hmac_sha1 (pwd, pwd_len, j, SHA1_DIGESTSIZE, k, SHA1_DIGESTSIZE); + for (i = 0; i < SHA1_DIGESTSIZE; i++) + { + u[i] ^= k[i]; + j[i] = k[i]; + } + } + + /* Prevent possible leaks. */ + burn (j, sizeof(j)); + burn (k, sizeof(k)); +} + + +/* Deprecated/legacy */ +void derive_key_sha1 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) +{ + char u[SHA1_DIGESTSIZE]; + int b, l, r; + + if (dklen % SHA1_DIGESTSIZE) + { + l = 1 + dklen / SHA1_DIGESTSIZE; + } + else + { + l = dklen / SHA1_DIGESTSIZE; + } + + r = dklen - (l - 1) * SHA1_DIGESTSIZE; + + /* first l - 1 blocks */ + for (b = 1; b < l; b++) + { + derive_u_sha1 (pwd, pwd_len, salt, salt_len, iterations, u, b); + memcpy (dk, u, SHA1_DIGESTSIZE); + dk += SHA1_DIGESTSIZE; + } + + /* last block */ + derive_u_sha1 (pwd, pwd_len, salt, salt_len, iterations, u, b); + memcpy (dk, u, r); + + + /* Prevent possible leaks. */ + burn (u, sizeof(u)); +} + +#endif // TC_WINDOWS_BOOT + +void hmac_ripemd160 (char *key, int keylen, char *input, int len, char *digest) +{ + RMD160_CTX context; + unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */ + unsigned char k_opad[65]; /* outer padding - key XORd with opad */ + unsigned char tk[RIPEMD160_DIGESTSIZE]; + int i; + + /* If the key is longer than the hash algorithm block size, + let key = ripemd160(key), as per HMAC specifications. */ + if (keylen > RIPEMD160_BLOCKSIZE) + { + RMD160_CTX tctx; + + RMD160Init(&tctx); + RMD160Update(&tctx, (const unsigned char *) key, keylen); + RMD160Final(tk, &tctx); + + key = (char *) tk; + keylen = RIPEMD160_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + + /* + + RMD160(K XOR opad, RMD160(K XOR ipad, text)) + + where K is an n byte key + ipad is the byte 0x36 repeated RIPEMD160_BLOCKSIZE times + opad is the byte 0x5c repeated RIPEMD160_BLOCKSIZE times + and text is the data being protected */ + + + /* start out by storing key in pads */ + memset(k_ipad, 0x36, sizeof(k_ipad)); + memset(k_opad, 0x5c, sizeof(k_opad)); + + /* XOR key with ipad and opad values */ + for (i=0; i<keylen; i++) + { + k_ipad[i] ^= key[i]; + k_opad[i] ^= key[i]; + } + + /* perform inner RIPEMD-160 */ + + RMD160Init(&context); /* init context for 1st pass */ + RMD160Update(&context, k_ipad, RIPEMD160_BLOCKSIZE); /* start with inner pad */ + RMD160Update(&context, (const unsigned char *) input, len); /* then text of datagram */ + RMD160Final((unsigned char *) digest, &context); /* finish up 1st pass */ + + /* perform outer RIPEMD-160 */ + RMD160Init(&context); /* init context for 2nd pass */ + RMD160Update(&context, k_opad, RIPEMD160_BLOCKSIZE); /* start with outer pad */ + /* results of 1st hash */ + RMD160Update(&context, (const unsigned char *) digest, RIPEMD160_DIGESTSIZE); + RMD160Final((unsigned char *) digest, &context); /* finish up 2nd pass */ + + /* Prevent possible leaks. */ + burn (k_ipad, sizeof(k_ipad)); + burn (k_opad, sizeof(k_opad)); + burn (tk, sizeof(tk)); + burn (&context, sizeof(context)); +} + +void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) +{ + char j[RIPEMD160_DIGESTSIZE], k[RIPEMD160_DIGESTSIZE]; + char init[128]; + char counter[4]; + int c, i; + + /* iteration 1 */ + memset (counter, 0, 4); + counter[3] = (char) b; + memcpy (init, salt, salt_len); /* salt */ + memcpy (&init[salt_len], counter, 4); /* big-endian block number */ + hmac_ripemd160 (pwd, pwd_len, init, salt_len + 4, j); + memcpy (u, j, RIPEMD160_DIGESTSIZE); + + /* remaining iterations */ + for (c = 1; c < iterations; c++) + { + hmac_ripemd160 (pwd, pwd_len, j, RIPEMD160_DIGESTSIZE, k); + for (i = 0; i < RIPEMD160_DIGESTSIZE; i++) + { + u[i] ^= k[i]; + j[i] = k[i]; + } + } + + /* Prevent possible leaks. */ + burn (j, sizeof(j)); + burn (k, sizeof(k)); +} + +void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) +{ + char u[RIPEMD160_DIGESTSIZE]; + int b, l, r; + + if (dklen % RIPEMD160_DIGESTSIZE) + { + l = 1 + dklen / RIPEMD160_DIGESTSIZE; + } + else + { + l = dklen / RIPEMD160_DIGESTSIZE; + } + + r = dklen - (l - 1) * RIPEMD160_DIGESTSIZE; + + /* first l - 1 blocks */ + for (b = 1; b < l; b++) + { + derive_u_ripemd160 (pwd, pwd_len, salt, salt_len, iterations, u, b); + memcpy (dk, u, RIPEMD160_DIGESTSIZE); + dk += RIPEMD160_DIGESTSIZE; + } + + /* last block */ + derive_u_ripemd160 (pwd, pwd_len, salt, salt_len, iterations, u, b); + memcpy (dk, u, r); + + + /* Prevent possible leaks. */ + burn (u, sizeof(u)); +} + +#ifndef TC_WINDOWS_BOOT + +void hmac_whirlpool +( + char *k, /* secret key */ + int lk, /* length of the key in bytes */ + char *d, /* data */ + int ld, /* length of data in bytes */ + char *out, /* output buffer, at least "t" bytes */ + int t +) +{ + WHIRLPOOL_CTX ictx, octx; + char iwhi[WHIRLPOOL_DIGESTSIZE], owhi[WHIRLPOOL_DIGESTSIZE]; + char key[WHIRLPOOL_DIGESTSIZE]; + char buf[WHIRLPOOL_BLOCKSIZE]; + int i; + + /* If the key is longer than the hash algorithm block size, + let key = whirlpool(key), as per HMAC specifications. */ + if (lk > WHIRLPOOL_BLOCKSIZE) + { + WHIRLPOOL_CTX tctx; + + WHIRLPOOL_init (&tctx); + WHIRLPOOL_add ((unsigned char *) k, lk * 8, &tctx); + WHIRLPOOL_finalize (&tctx, (unsigned char *) key); + + k = key; + lk = WHIRLPOOL_DIGESTSIZE; + + burn (&tctx, sizeof(tctx)); // Prevent leaks + } + + /**** Inner Digest ****/ + + WHIRLPOOL_init (&ictx); + + /* Pad the key for inner digest */ + for (i = 0; i < lk; ++i) + buf[i] = (char) (k[i] ^ 0x36); + for (i = lk; i < WHIRLPOOL_BLOCKSIZE; ++i) + buf[i] = 0x36; + + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, &ictx); + WHIRLPOOL_add ((unsigned char *) d, ld * 8, &ictx); + + WHIRLPOOL_finalize (&ictx, (unsigned char *) iwhi); + + /**** Outer Digest ****/ + + WHIRLPOOL_init (&octx); + + for (i = 0; i < lk; ++i) + buf[i] = (char) (k[i] ^ 0x5C); + for (i = lk; i < WHIRLPOOL_BLOCKSIZE; ++i) + buf[i] = 0x5C; + + WHIRLPOOL_add ((unsigned char *) buf, WHIRLPOOL_BLOCKSIZE * 8, &octx); + WHIRLPOOL_add ((unsigned char *) iwhi, WHIRLPOOL_DIGESTSIZE * 8, &octx); + + WHIRLPOOL_finalize (&octx, (unsigned char *) owhi); + + /* truncate and print the results */ + t = t > WHIRLPOOL_DIGESTSIZE ? WHIRLPOOL_DIGESTSIZE : t; + hmac_truncate (owhi, out, t); + + /* Prevent possible leaks. */ + burn (&ictx, sizeof(ictx)); + burn (&octx, sizeof(octx)); + burn (owhi, sizeof(owhi)); + burn (iwhi, sizeof(iwhi)); + burn (buf, sizeof(buf)); + burn (key, sizeof(key)); +} + +void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b) +{ + char j[WHIRLPOOL_DIGESTSIZE], k[WHIRLPOOL_DIGESTSIZE]; + char init[128]; + char counter[4]; + int c, i; + + /* iteration 1 */ + memset (counter, 0, 4); + counter[3] = (char) b; + memcpy (init, salt, salt_len); /* salt */ + memcpy (&init[salt_len], counter, 4); /* big-endian block number */ + hmac_whirlpool (pwd, pwd_len, init, salt_len + 4, j, WHIRLPOOL_DIGESTSIZE); + memcpy (u, j, WHIRLPOOL_DIGESTSIZE); + + /* remaining iterations */ + for (c = 1; c < iterations; c++) + { + hmac_whirlpool (pwd, pwd_len, j, WHIRLPOOL_DIGESTSIZE, k, WHIRLPOOL_DIGESTSIZE); + for (i = 0; i < WHIRLPOOL_DIGESTSIZE; i++) + { + u[i] ^= k[i]; + j[i] = k[i]; + } + } + + /* Prevent possible leaks. */ + burn (j, sizeof(j)); + burn (k, sizeof(k)); +} + +void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen) +{ + char u[WHIRLPOOL_DIGESTSIZE]; + int b, l, r; + + if (dklen % WHIRLPOOL_DIGESTSIZE) + { + l = 1 + dklen / WHIRLPOOL_DIGESTSIZE; + } + else + { + l = dklen / WHIRLPOOL_DIGESTSIZE; + } + + r = dklen - (l - 1) * WHIRLPOOL_DIGESTSIZE; + + /* first l - 1 blocks */ + for (b = 1; b < l; b++) + { + derive_u_whirlpool (pwd, pwd_len, salt, salt_len, iterations, u, b); + memcpy (dk, u, WHIRLPOOL_DIGESTSIZE); + dk += WHIRLPOOL_DIGESTSIZE; + } + + /* last block */ + derive_u_whirlpool (pwd, pwd_len, salt, salt_len, iterations, u, b); + memcpy (dk, u, r); + + + /* Prevent possible leaks. */ + burn (u, sizeof(u)); +} + + +char *get_pkcs5_prf_name (int pkcs5_prf_id) +{ + switch (pkcs5_prf_id) + { + case SHA512: + return "HMAC-SHA-512"; + + case SHA1: // Deprecated/legacy + return "HMAC-SHA-1"; + + case RIPEMD160: + return "HMAC-RIPEMD-160"; + + case WHIRLPOOL: + return "HMAC-Whirlpool"; + + default: + return "(Unknown)"; + } +} + +#endif //!TC_WINDOWS_BOOT + + +int get_pkcs5_iteration_count (int pkcs5_prf_id, BOOL bBoot) +{ + switch (pkcs5_prf_id) + { + case RIPEMD160: + return (bBoot ? 1000 : 2000); + +#ifndef TC_WINDOWS_BOOT + + case SHA512: + return 1000; + + case SHA1: // Deprecated/legacy + return 2000; + + case WHIRLPOOL: + return 1000; +#endif + + default: + TC_THROW_FATAL_EXCEPTION; // Unknown/wrong ID + } + return 0; +} diff --git a/Common/Pkcs5.h b/Common/Pkcs5.h new file mode 100644 index 0000000..34fe3ad --- /dev/null +++ b/Common/Pkcs5.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. */ + +#ifndef TC_HEADER_PKCS5 +#define TC_HEADER_PKCS5 + +#include "Tcdefs.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +void hmac_sha512 (char *k, int lk, char *d, int ld, char *out, int t); +void derive_u_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b); +void derive_key_sha512 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen); +void hmac_sha1 (char *k, int lk, char *d, int ld, char *out, int t); +void derive_u_sha1 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b); +void derive_key_sha1 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen); +void hmac_ripemd160 (char *key, int keylen, char *input, int len, char *digest); +void derive_u_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b); +void derive_key_ripemd160 (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen); +void hmac_whirlpool (char *k, int lk, char *d, int ld, char *out, int t); +void derive_u_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *u, int b); +void derive_key_whirlpool (char *pwd, int pwd_len, char *salt, int salt_len, int iterations, char *dk, int dklen); +int get_pkcs5_iteration_count (int pkcs5_prf_id, BOOL bBoot); +char *get_pkcs5_prf_name (int pkcs5_prf_id); + +#if defined(__cplusplus) +} +#endif + +#endif // TC_HEADER_PKCS5 diff --git a/Common/Progress.c b/Common/Progress.c new file mode 100644 index 0000000..cfbfb4d --- /dev/null +++ b/Common/Progress.c @@ -0,0 +1,130 @@ +/* + 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 "Language.h" +#include "Dlgcode.h" +#include "Progress.h" +#include "../Format/Tcformat.h" +#include "../Format/FormatCom.h" +#include "../Format/resource.h" + +static ULONG prevTime, startTime; +static __int64 TotalSize; +static __int64 resumedPointBytesDone; +static BOOL bProgressBarReverse = FALSE; +static BOOL bRWThroughput = FALSE; +static BOOL bShowStatus = FALSE; +static BOOL bPercentMode = FALSE; + +static wchar_t *seconds, *minutes, *hours, *days; + + +// If bIOThroughput is TRUE, the speed reflects the amount of data read AND written per second (rather than +// the speed of the "transform cursor"). +void InitProgressBar (__int64 totalBytes, __int64 bytesDone, BOOL bReverse, BOOL bIOThroughput, BOOL bDisplayStatus, BOOL bShowPercent) +{ + HWND hProgressBar = GetDlgItem (hCurPage, nPbar); + SendMessage (hProgressBar, PBM_SETRANGE32, 0, 10000); + SendMessage (hProgressBar, PBM_SETSTEP, 1, 0); + + bProgressBarReverse = bReverse; + bRWThroughput = bIOThroughput; + bShowStatus = bDisplayStatus; + bPercentMode = bShowPercent; + + seconds = GetString ("SECONDS"); + minutes = GetString ("MINUTES"); + hours = GetString ("HOURS"); + days = GetString ("DAYS"); + + prevTime = startTime = GetTickCount (); + TotalSize = totalBytes; + resumedPointBytesDone = bytesDone; +} + + +BOOL UpdateProgressBar (__int64 byteOffset) +{ + return UpdateProgressBarProc (byteOffset); +} + + +BOOL UpdateProgressBarProc (__int64 byteOffset) +{ + wchar_t text[100]; + wchar_t speed[100]; + HWND hProgressBar = GetDlgItem (hCurPage, nPbar); + int time = GetTickCount (); + int elapsed = (time - startTime) / 1000; + + uint64 bytesDone = (bProgressBarReverse ? (TotalSize - byteOffset) : byteOffset); + uint64 bytesPerSec = (bProgressBarReverse ? (resumedPointBytesDone - byteOffset) : (bytesDone - resumedPointBytesDone)) / (elapsed + 1); + + if (bPercentMode) + { + double perc = (double) (100.0 * (bProgressBarReverse ? ((double) (TotalSize - byteOffset)) : ((double) byteOffset)) / (TotalSize == 0 ? 0.0001 : ((double) TotalSize))); + + if (perc > 99.999999999) + wcscpy (text, GetString ("PROCESSED_PORTION_100_PERCENT")); + else + _snwprintf (text, sizeof text/2, GetString ("PROCESSED_PORTION_X_PERCENT"), perc); + + wcscat (speed, L" "); + } + else + { + GetSizeString (bytesDone, text); + if (bytesDone < (unsigned __int64) BYTES_PER_MB * 1000000) + swprintf(text, L"%I64d %s ", bytesDone / BYTES_PER_MB, GetString ("MB")); + else if (bytesDone < (unsigned __int64) BYTES_PER_GB * 1000000) + swprintf(text, L"%I64d %s ", bytesDone / BYTES_PER_GB, GetString ("GB")); + else if (bytesDone < (unsigned __int64) BYTES_PER_TB * 1000000) + swprintf(text, L"%I64d %s ", bytesDone / BYTES_PER_TB, GetString ("TB")); + else + swprintf(text, L"%I64d %s ", bytesDone / BYTES_PER_PB, GetString ("PB")); + } + + SetWindowTextW (GetDlgItem (hCurPage, IDC_BYTESWRITTEN), text); + + if (!bShowStatus) + { + GetSpeedString (bRWThroughput ? bytesPerSec*2 : bytesPerSec, speed); + wcscat (speed, L" "); + SetWindowTextW (GetDlgItem (hCurPage, IDC_WRITESPEED), speed); + } + + if (byteOffset < TotalSize) + { + int64 sec = (int64) ((bProgressBarReverse ? byteOffset : (TotalSize - byteOffset)) / (bytesPerSec == 0 ? 0.001 : bytesPerSec)); + + if (bytesPerSec == 0 || sec > 60 * 60 * 24 * 999) + swprintf (text, L"%s ", GetString ("NOT_APPLICABLE_OR_NOT_AVAILABLE")); + else if (sec >= 60 * 60 * 24 * 2) + swprintf (text, L"%I64d %s ", sec / (60 * 24 * 60), days); + else if (sec >= 120 * 60) + swprintf (text, L"%I64d %s ", sec / (60 * 60), hours); + else if (sec >= 120) + swprintf (text, L"%I64d %s ", sec / 60, minutes); + else + swprintf (text, L"%I64d %s ", sec, seconds); + + SetWindowTextW (GetDlgItem (hCurPage, IDC_TIMEREMAIN), text); + } + + prevTime = time; + + SendMessage (hProgressBar, PBM_SETPOS, + (int) (10000.0 * (bProgressBarReverse ? (TotalSize - byteOffset) : byteOffset) / (TotalSize == 0 ? 1 : TotalSize)), + 0); + + return bVolTransformThreadCancel; +} diff --git a/Common/Progress.h b/Common/Progress.h new file mode 100644 index 0000000..3c8f5ff --- /dev/null +++ b/Common/Progress.h @@ -0,0 +1,22 @@ +/* + 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. */ + +#ifdef __cplusplus +extern "C" { +#endif + +void InitProgressBar (__int64 totalBytes, __int64 bytesDone, BOOL bReverse, BOOL bIOThroughput, BOOL bDisplayStatus, BOOL bShowPercent); +BOOL UpdateProgressBar (__int64 byteOffset); +BOOL UpdateProgressBarProc (__int64 byteOffset); + +#ifdef __cplusplus +} +#endif diff --git a/Common/Random.c b/Common/Random.c new file mode 100644 index 0000000..d0372ed --- /dev/null +++ b/Common/Random.c @@ -0,0 +1,772 @@ +/* + 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 "Crc.h" +#include "Random.h" + +static unsigned __int8 buffer[RNG_POOL_SIZE]; +static unsigned char *pRandPool = NULL; +static BOOL bRandDidInit = FALSE; +static int nRandIndex = 0, randPoolReadIndex = 0; +static int HashFunction = DEFAULT_HASH_ALGORITHM; +static BOOL bDidSlowPoll = FALSE; +BOOL volatile bFastPollEnabled = TRUE; /* Used to reduce CPU load when performing benchmarks */ +BOOL volatile bRandmixEnabled = TRUE; /* Used to reduce CPU load when performing benchmarks */ +static BOOL RandomPoolEnrichedByUser = FALSE; +static HANDLE PeriodicFastPollThreadHandle = NULL; + +/* Macro to add a single byte to the pool */ +#define RandaddByte(x) {\ + if (nRandIndex == RNG_POOL_SIZE) nRandIndex = 0;\ + pRandPool[nRandIndex] = (unsigned char) ((unsigned char)x + pRandPool[nRandIndex]); \ + if (nRandIndex % RANDMIX_BYTE_INTERVAL == 0) Randmix();\ + nRandIndex++; \ + } + +/* Macro to add four bytes to the pool */ +#define RandaddInt32(x) RandAddInt((unsigned __int32)x); + +void RandAddInt (unsigned __int32 x) +{ + RandaddByte(x); + RandaddByte((x >> 8)); + RandaddByte((x >> 16)); + RandaddByte((x >> 24)); +} + +#include <tlhelp32.h> +#include "Dlgcode.h" + +HHOOK hMouse = NULL; /* Mouse hook for the random number generator */ +HHOOK hKeyboard = NULL; /* Keyboard hook for the random number generator */ + +/* Variables for thread control, the thread is used to gather up info about + the system in in the background */ +CRITICAL_SECTION critRandProt; /* The critical section */ +BOOL volatile bThreadTerminate = FALSE; /* This variable is shared among thread's so its made volatile */ + +/* Network library handle for the SlowPoll function */ +HANDLE hNetAPI32 = NULL; + +// CryptoAPI +BOOL CryptoAPIAvailable = FALSE; +HCRYPTPROV hCryptProv; + + +/* Init the random number generator, setup the hooks, and start the thread */ +int Randinit () +{ + if (GetMaxPkcs5OutSize() > RNG_POOL_SIZE) + TC_THROW_FATAL_EXCEPTION; + + if(bRandDidInit) + return 0; + + InitializeCriticalSection (&critRandProt); + + bRandDidInit = TRUE; + + if (pRandPool == NULL) + { + pRandPool = (unsigned char *) TCalloc (RANDOMPOOL_ALLOCSIZE); + if (pRandPool == NULL) + goto error; + + bDidSlowPoll = FALSE; + RandomPoolEnrichedByUser = FALSE; + + memset (pRandPool, 0, RANDOMPOOL_ALLOCSIZE); + VirtualLock (pRandPool, RANDOMPOOL_ALLOCSIZE); + } + + hKeyboard = SetWindowsHookEx (WH_KEYBOARD, (HOOKPROC)&KeyboardProc, NULL, GetCurrentThreadId ()); + if (hKeyboard == 0) handleWin32Error (0); + + hMouse = SetWindowsHookEx (WH_MOUSE, (HOOKPROC)&MouseProc, NULL, GetCurrentThreadId ()); + if (hMouse == 0) + { + handleWin32Error (0); + goto error; + } + + if (!CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0) + && !CryptAcquireContext (&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) + CryptoAPIAvailable = FALSE; + else + CryptoAPIAvailable = TRUE; + + if (!(PeriodicFastPollThreadHandle = (HANDLE) _beginthreadex (NULL, 0, PeriodicFastPollThreadProc, NULL, 0, NULL))) + goto error; + + return 0; + +error: + RandStop (TRUE); + return 1; +} + +/* Close everything down, including the thread which is closed down by + setting a flag which eventually causes the thread function to exit */ +void RandStop (BOOL freePool) +{ + if (!bRandDidInit && freePool && pRandPool) + goto freePool; + + if (bRandDidInit == FALSE) + return; + + EnterCriticalSection (&critRandProt); + + if (hMouse != 0) + UnhookWindowsHookEx (hMouse); + if (hKeyboard != 0) + UnhookWindowsHookEx (hKeyboard); + + bThreadTerminate = TRUE; + + LeaveCriticalSection (&critRandProt); + + if (PeriodicFastPollThreadHandle) + WaitForSingleObject (PeriodicFastPollThreadHandle, INFINITE); + + if (hNetAPI32 != 0) + { + FreeLibrary (hNetAPI32); + hNetAPI32 = NULL; + } + + if (CryptoAPIAvailable) + { + CryptReleaseContext (hCryptProv, 0); + CryptoAPIAvailable = FALSE; + } + + hMouse = NULL; + hKeyboard = NULL; + bThreadTerminate = FALSE; + DeleteCriticalSection (&critRandProt); + + bRandDidInit = FALSE; + +freePool: + if (freePool) + { + bDidSlowPoll = FALSE; + RandomPoolEnrichedByUser = FALSE; + + if (pRandPool != NULL) + { + burn (pRandPool, RANDOMPOOL_ALLOCSIZE); + TCfree (pRandPool); + pRandPool = NULL; + } + } +} + +BOOL IsRandomNumberGeneratorStarted () +{ + return bRandDidInit; +} + +void RandSetHashFunction (int hash_algo_id) +{ + if (HashIsDeprecated (hash_algo_id)) + hash_algo_id = DEFAULT_HASH_ALGORITHM; + + HashFunction = hash_algo_id; +} + +int RandGetHashFunction (void) +{ + return HashFunction; +} + +void SetRandomPoolEnrichedByUserStatus (BOOL enriched) +{ + RandomPoolEnrichedByUser = enriched; +} + +BOOL IsRandomPoolEnrichedByUser () +{ + return RandomPoolEnrichedByUser; +} + +/* The random pool mixing function */ +BOOL Randmix () +{ + if (bRandmixEnabled) + { + unsigned char hashOutputBuffer [MAX_DIGESTSIZE]; + WHIRLPOOL_CTX wctx; + RMD160_CTX rctx; + sha512_ctx sctx; + int poolIndex, digestIndex, digestSize; + + switch (HashFunction) + { + case RIPEMD160: + digestSize = RIPEMD160_DIGESTSIZE; + break; + + case SHA512: + digestSize = SHA512_DIGESTSIZE; + break; + + case WHIRLPOOL: + digestSize = WHIRLPOOL_DIGESTSIZE; + break; + + default: + TC_THROW_FATAL_EXCEPTION; + } + + if (RNG_POOL_SIZE % digestSize) + TC_THROW_FATAL_EXCEPTION; + + for (poolIndex = 0; poolIndex < RNG_POOL_SIZE; poolIndex += digestSize) + { + /* Compute the message digest of the entire pool using the selected hash function. */ + switch (HashFunction) + { + case RIPEMD160: + RMD160Init(&rctx); + RMD160Update(&rctx, pRandPool, RNG_POOL_SIZE); + RMD160Final(hashOutputBuffer, &rctx); + break; + + case SHA512: + sha512_begin (&sctx); + sha512_hash (pRandPool, RNG_POOL_SIZE, &sctx); + sha512_end (hashOutputBuffer, &sctx); + break; + + case WHIRLPOOL: + WHIRLPOOL_init (&wctx); + WHIRLPOOL_add (pRandPool, RNG_POOL_SIZE * 8, &wctx); + WHIRLPOOL_finalize (&wctx, hashOutputBuffer); + break; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } + + /* XOR the resultant message digest to the pool at the poolIndex position. */ + for (digestIndex = 0; digestIndex < digestSize; digestIndex++) + { + pRandPool [poolIndex + digestIndex] ^= hashOutputBuffer [digestIndex]; + } + } + + /* Prevent leaks */ + burn (hashOutputBuffer, MAX_DIGESTSIZE); + switch (HashFunction) + { + case RIPEMD160: + burn (&rctx, sizeof(rctx)); + break; + + case SHA512: + burn (&sctx, sizeof(sctx)); + break; + + case WHIRLPOOL: + burn (&wctx, sizeof(wctx)); + break; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } + } + return TRUE; +} + +/* Add a buffer to the pool */ +void RandaddBuf (void *buf, int len) +{ + int i; + for (i = 0; i < len; i++) + { + RandaddByte (((unsigned char *) buf)[i]); + } +} + +BOOL RandpeekBytes (unsigned char *buf, int len) +{ + if (!bRandDidInit) + return FALSE; + + if (len > RNG_POOL_SIZE) + { + Error ("ERR_NOT_ENOUGH_RANDOM_DATA"); + len = RNG_POOL_SIZE; + } + + EnterCriticalSection (&critRandProt); + memcpy (buf, pRandPool, len); + LeaveCriticalSection (&critRandProt); + + return TRUE; +} + + +/* Get len random bytes from the pool (max. RNG_POOL_SIZE bytes per a single call) */ +BOOL RandgetBytes (unsigned char *buf, int len, BOOL forceSlowPoll) +{ + int i; + BOOL ret = TRUE; + + if (!bRandDidInit || HashFunction == 0) + TC_THROW_FATAL_EXCEPTION; + + EnterCriticalSection (&critRandProt); + + if (bDidSlowPoll == FALSE || forceSlowPoll) + { + if (!SlowPoll ()) + ret = FALSE; + else + bDidSlowPoll = TRUE; + } + + if (!FastPoll ()) + ret = FALSE; + + /* There's never more than RNG_POOL_SIZE worth of randomess */ + if (len > RNG_POOL_SIZE) + { + Error ("ERR_NOT_ENOUGH_RANDOM_DATA"); + len = RNG_POOL_SIZE; + return FALSE; + } + + // Requested number of bytes is copied from pool to output buffer, + // pool is rehashed, and output buffer is XORed with new data from pool + for (i = 0; i < len; i++) + { + buf[i] = pRandPool[randPoolReadIndex++]; + if (randPoolReadIndex == RNG_POOL_SIZE) randPoolReadIndex = 0; + } + + /* Invert the pool */ + for (i = 0; i < RNG_POOL_SIZE / 4; i++) + { + ((unsigned __int32 *) pRandPool)[i] = ~((unsigned __int32 *) pRandPool)[i]; + } + + // Mix the pool + if (!FastPoll ()) + ret = FALSE; + + // XOR the current pool content into the output buffer to prevent pool state leaks + for (i = 0; i < len; i++) + { + buf[i] ^= pRandPool[randPoolReadIndex++]; + if (randPoolReadIndex == RNG_POOL_SIZE) randPoolReadIndex = 0; + } + + LeaveCriticalSection (&critRandProt); + + if (!ret) + TC_THROW_FATAL_EXCEPTION; + + return ret; +} + +/* Capture the mouse, and as long as the event is not the same as the last + two events, add the crc of the event, and the crc of the time difference + between this event and the last + the current time to the pool. + The role of CRC-32 is merely to perform diffusion. Note that the output + of CRC-32 is subsequently processed using a cryptographically secure hash + algorithm. */ +LRESULT CALLBACK MouseProc (int nCode, WPARAM wParam, LPARAM lParam) +{ + static DWORD dwLastTimer; + static unsigned __int32 lastCrc, lastCrc2; + MOUSEHOOKSTRUCT *lpMouse = (MOUSEHOOKSTRUCT *) lParam; + + if (nCode < 0) + return CallNextHookEx (hMouse, nCode, wParam, lParam); + else + { + DWORD dwTimer = GetTickCount (); + DWORD j = dwLastTimer - dwTimer; + unsigned __int32 crc = 0L; + int i; + + dwLastTimer = dwTimer; + + for (i = 0; i < sizeof (MOUSEHOOKSTRUCT); i++) + { + crc = UPDC32 (((unsigned char *) lpMouse)[i], crc); + } + + if (crc != lastCrc && crc != lastCrc2) + { + unsigned __int32 timeCrc = 0L; + + for (i = 0; i < 4; i++) + { + timeCrc = UPDC32 (((unsigned char *) &j)[i], timeCrc); + } + + for (i = 0; i < 4; i++) + { + timeCrc = UPDC32 (((unsigned char *) &dwTimer)[i], timeCrc); + } + + EnterCriticalSection (&critRandProt); + RandaddInt32 ((unsigned __int32) (crc + timeCrc)); + LeaveCriticalSection (&critRandProt); + } + lastCrc2 = lastCrc; + lastCrc = crc; + + } + return 0; +} + +/* Capture the keyboard, as long as the event is not the same as the last two + events, add the crc of the event to the pool along with the crc of the time + difference between this event and the last. The role of CRC-32 is merely to + perform diffusion. Note that the output of CRC-32 is subsequently processed + using a cryptographically secure hash algorithm. */ +LRESULT CALLBACK KeyboardProc (int nCode, WPARAM wParam, LPARAM lParam) +{ + static int lLastKey, lLastKey2; + static DWORD dwLastTimer; + int nKey = (lParam & 0x00ff0000) >> 16; + int nCapture = 0; + + if (nCode < 0) + return CallNextHookEx (hMouse, nCode, wParam, lParam); + + if ((lParam & 0x0000ffff) == 1 && !(lParam & 0x20000000) && + (lParam & 0x80000000)) + { + if (nKey != lLastKey) + nCapture = 1; /* Capture this key */ + else if (nKey != lLastKey2) + nCapture = 1; /* Allow for one repeat */ + } + if (nCapture) + { + DWORD dwTimer = GetTickCount (); + DWORD j = dwLastTimer - dwTimer; + unsigned __int32 timeCrc = 0L; + int i; + + dwLastTimer = dwTimer; + lLastKey2 = lLastKey; + lLastKey = nKey; + + for (i = 0; i < 4; i++) + { + timeCrc = UPDC32 (((unsigned char *) &j)[i], timeCrc); + } + + for (i = 0; i < 4; i++) + { + timeCrc = UPDC32 (((unsigned char *) &dwTimer)[i], timeCrc); + } + + EnterCriticalSection (&critRandProt); + RandaddInt32 ((unsigned __int32) (crc32int(&lParam) + timeCrc)); + LeaveCriticalSection (&critRandProt); + } + + return CallNextHookEx (hMouse, nCode, wParam, lParam); +} + +/* This is the thread function which will poll the system for randomness */ +static unsigned __stdcall PeriodicFastPollThreadProc (void *dummy) +{ + if (dummy); /* Remove unused parameter warning */ + + for (;;) + { + EnterCriticalSection (&critRandProt); + + if (bThreadTerminate) + { + bThreadTerminate = FALSE; + LeaveCriticalSection (&critRandProt); + _endthreadex (0); + } + else if (bFastPollEnabled) + { + FastPoll (); + } + + LeaveCriticalSection (&critRandProt); + + Sleep (FASTPOLL_INTERVAL); + } +} + +/* Type definitions for function pointers to call NetAPI32 functions */ + +typedef + DWORD (WINAPI * NETSTATISTICSGET) (LPWSTR szServer, LPWSTR szService, + DWORD dwLevel, DWORD dwOptions, + LPBYTE * lpBuffer); +typedef + DWORD (WINAPI * NETAPIBUFFERSIZE) (LPVOID lpBuffer, LPDWORD cbBuffer); +typedef + DWORD (WINAPI * NETAPIBUFFERFREE) (LPVOID lpBuffer); + +NETSTATISTICSGET pNetStatisticsGet = NULL; +NETAPIBUFFERSIZE pNetApiBufferSize = NULL; +NETAPIBUFFERFREE pNetApiBufferFree = NULL; + + +/* This is the slowpoll function which gathers up network/hard drive + performance data for the random pool */ +BOOL SlowPoll (void) +{ + static int isWorkstation = -1; + static int cbPerfData = 0x10000; + HANDLE hDevice; + LPBYTE lpBuffer; + DWORD dwSize, status; + LPWSTR lpszLanW, lpszLanS; + int nDrive; + + /* Find out whether this is an NT server or workstation if necessary */ + if (isWorkstation == -1) + { + HKEY hKey; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, + "SYSTEM\\CurrentControlSet\\Control\\ProductOptions", + 0, KEY_READ, &hKey) == ERROR_SUCCESS) + { + unsigned char szValue[32]; + dwSize = sizeof (szValue); + + isWorkstation = TRUE; + status = RegQueryValueEx (hKey, "ProductType", 0, NULL, + szValue, &dwSize); + + if (status == ERROR_SUCCESS && _stricmp ((char *) szValue, "WinNT")) + /* Note: There are (at least) three cases for + ProductType: WinNT = NT Workstation, + ServerNT = NT Server, LanmanNT = NT Server + acting as a Domain Controller */ + isWorkstation = FALSE; + + RegCloseKey (hKey); + } + } + /* Initialize the NetAPI32 function pointers if necessary */ + if (hNetAPI32 == NULL) + { + /* Obtain a handle to the module containing the Lan Manager + functions */ + hNetAPI32 = LoadLibrary ("NETAPI32.DLL"); + if (hNetAPI32 != NULL) + { + /* Now get pointers to the functions */ + pNetStatisticsGet = (NETSTATISTICSGET) GetProcAddress (hNetAPI32, + "NetStatisticsGet"); + pNetApiBufferSize = (NETAPIBUFFERSIZE) GetProcAddress (hNetAPI32, + "NetApiBufferSize"); + pNetApiBufferFree = (NETAPIBUFFERFREE) GetProcAddress (hNetAPI32, + "NetApiBufferFree"); + + /* Make sure we got valid pointers for every NetAPI32 + function */ + if (pNetStatisticsGet == NULL || + pNetApiBufferSize == NULL || + pNetApiBufferFree == NULL) + { + /* Free the library reference and reset the + static handle */ + FreeLibrary (hNetAPI32); + hNetAPI32 = NULL; + } + } + } + + /* Get network statistics. Note: Both NT Workstation and NT Server + by default will be running both the workstation and server + services. The heuristic below is probably useful though on the + assumption that the majority of the network traffic will be via + the appropriate service */ + lpszLanW = (LPWSTR) WIDE ("LanmanWorkstation"); + lpszLanS = (LPWSTR) WIDE ("LanmanServer"); + if (hNetAPI32 && + pNetStatisticsGet (NULL, + isWorkstation ? lpszLanW : lpszLanS, + 0, 0, &lpBuffer) == 0) + { + pNetApiBufferSize (lpBuffer, &dwSize); + RandaddBuf ((unsigned char *) lpBuffer, dwSize); + pNetApiBufferFree (lpBuffer); + } + + /* Get disk I/O statistics for all the hard drives */ + for (nDrive = 0;; nDrive++) + { + DISK_PERFORMANCE diskPerformance; + char szDevice[24]; + + /* Check whether we can access this device */ + sprintf (szDevice, "\\\\.\\PhysicalDrive%d", nDrive); + hDevice = CreateFile (szDevice, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + if (hDevice == INVALID_HANDLE_VALUE) + break; + + + /* Note: This only works if you have turned on the disk + performance counters with 'diskperf -y'. These counters + are off by default */ + if (DeviceIoControl (hDevice, IOCTL_DISK_PERFORMANCE, NULL, 0, + &diskPerformance, sizeof (DISK_PERFORMANCE), + &dwSize, NULL)) + { + RandaddBuf ((unsigned char *) &diskPerformance, dwSize); + } + CloseHandle (hDevice); + } + + // CryptoAPI + if (CryptoAPIAvailable && CryptGenRandom (hCryptProv, sizeof (buffer), buffer)) + RandaddBuf (buffer, sizeof (buffer)); + + burn(buffer, sizeof (buffer)); + Randmix(); + return TRUE; +} + + +/* This is the fastpoll function which gathers up info by calling various api's */ +BOOL FastPoll (void) +{ + int nOriginalRandIndex = nRandIndex; + static BOOL addedFixedItems = FALSE; + FILETIME creationTime, exitTime, kernelTime, userTime; + DWORD minimumWorkingSetSize, maximumWorkingSetSize; + LARGE_INTEGER performanceCount; + MEMORYSTATUS memoryStatus; + HANDLE handle; + POINT point; + + /* Get various basic pieces of system information */ + RandaddInt32 (GetActiveWindow ()); /* Handle of active window */ + RandaddInt32 (GetCapture ()); /* Handle of window with mouse + capture */ + RandaddInt32 (GetClipboardOwner ()); /* Handle of clipboard owner */ + RandaddInt32 (GetClipboardViewer ()); /* Handle of start of + clpbd.viewer list */ + RandaddInt32 (GetCurrentProcess ()); /* Pseudohandle of current + process */ + RandaddInt32 (GetCurrentProcessId ()); /* Current process ID */ + RandaddInt32 (GetCurrentThread ()); /* Pseudohandle of current + thread */ + RandaddInt32 (GetCurrentThreadId ()); /* Current thread ID */ + RandaddInt32 (GetCurrentTime ()); /* Milliseconds since Windows + started */ + RandaddInt32 (GetDesktopWindow ()); /* Handle of desktop window */ + RandaddInt32 (GetFocus ()); /* Handle of window with kb.focus */ + RandaddInt32 (GetInputState ()); /* Whether sys.queue has any events */ + RandaddInt32 (GetMessagePos ()); /* Cursor pos.for last message */ + RandaddInt32 (GetMessageTime ()); /* 1 ms time for last message */ + RandaddInt32 (GetOpenClipboardWindow ()); /* Handle of window with + clpbd.open */ + RandaddInt32 (GetProcessHeap ()); /* Handle of process heap */ + RandaddInt32 (GetProcessWindowStation ()); /* Handle of procs + window station */ + RandaddInt32 (GetQueueStatus (QS_ALLEVENTS)); /* Types of events in + input queue */ + + /* Get multiword system information */ + GetCaretPos (&point); /* Current caret position */ + RandaddBuf ((unsigned char *) &point, sizeof (POINT)); + GetCursorPos (&point); /* Current mouse cursor position */ + RandaddBuf ((unsigned char *) &point, sizeof (POINT)); + + /* Get percent of memory in use, bytes of physical memory, bytes of + free physical memory, bytes in paging file, free bytes in paging + file, user bytes of address space, and free user bytes */ + memoryStatus.dwLength = sizeof (MEMORYSTATUS); + GlobalMemoryStatus (&memoryStatus); + RandaddBuf ((unsigned char *) &memoryStatus, sizeof (MEMORYSTATUS)); + + /* Get thread and process creation time, exit time, time in kernel + mode, and time in user mode in 100ns intervals */ + handle = GetCurrentThread (); + GetThreadTimes (handle, &creationTime, &exitTime, &kernelTime, &userTime); + RandaddBuf ((unsigned char *) &creationTime, sizeof (FILETIME)); + RandaddBuf ((unsigned char *) &exitTime, sizeof (FILETIME)); + RandaddBuf ((unsigned char *) &kernelTime, sizeof (FILETIME)); + RandaddBuf ((unsigned char *) &userTime, sizeof (FILETIME)); + handle = GetCurrentProcess (); + GetProcessTimes (handle, &creationTime, &exitTime, &kernelTime, &userTime); + RandaddBuf ((unsigned char *) &creationTime, sizeof (FILETIME)); + RandaddBuf ((unsigned char *) &exitTime, sizeof (FILETIME)); + RandaddBuf ((unsigned char *) &kernelTime, sizeof (FILETIME)); + RandaddBuf ((unsigned char *) &userTime, sizeof (FILETIME)); + + /* Get the minimum and maximum working set size for the current + process */ + GetProcessWorkingSetSize (handle, &minimumWorkingSetSize, + &maximumWorkingSetSize); + RandaddInt32 (minimumWorkingSetSize); + RandaddInt32 (maximumWorkingSetSize); + + /* The following are fixed for the lifetime of the process so we only + add them once */ + if (addedFixedItems == 0) + { + STARTUPINFO startupInfo; + + /* Get name of desktop, console window title, new window + position and size, window flags, and handles for stdin, + stdout, and stderr */ + startupInfo.cb = sizeof (STARTUPINFO); + GetStartupInfo (&startupInfo); + RandaddBuf ((unsigned char *) &startupInfo, sizeof (STARTUPINFO)); + addedFixedItems = TRUE; + } + /* The docs say QPC can fail if appropriate hardware is not + available. It works on 486 & Pentium boxes, but hasn't been tested + for 386 or RISC boxes */ + if (QueryPerformanceCounter (&performanceCount)) + RandaddBuf ((unsigned char *) &performanceCount, sizeof (LARGE_INTEGER)); + else + { + /* Millisecond accuracy at best... */ + DWORD dwTicks = GetTickCount (); + RandaddBuf ((unsigned char *) &dwTicks, sizeof (dwTicks)); + } + + // CryptoAPI + if (CryptoAPIAvailable && CryptGenRandom (hCryptProv, sizeof (buffer), buffer)) + RandaddBuf (buffer, sizeof (buffer)); + + /* Apply the pool mixing function */ + Randmix(); + + /* Restore the original pool cursor position. If this wasn't done, mouse coordinates + could be written to a limited area of the pool, especially when moving the mouse + uninterruptedly. The severity of the problem would depend on the length of data + written by FastPoll (if it was equal to the size of the pool, mouse coordinates + would be written only to a particular 4-byte area, whenever moving the mouse + uninterruptedly). */ + nRandIndex = nOriginalRandIndex; + + return TRUE; +} + diff --git a/Common/Random.h b/Common/Random.h new file mode 100644 index 0000000..5ec16bd --- /dev/null +++ b/Common/Random.h @@ -0,0 +1,62 @@ +/* + 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 "Crypto.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* RNG defines & pool pointers */ +#define RNG_POOL_SIZE 320 // Must be divisible by the size of the output of each of the implemented hash functions. (in bytes) + +#if RNG_POOL_SIZE % SHA512_DIGESTSIZE || RNG_POOL_SIZE % WHIRLPOOL_DIGESTSIZE || RNG_POOL_SIZE % RIPEMD160_DIGESTSIZE +#error RNG_POOL_SIZE must be divisible by the size of the output of each of the implemented hash functions. +#endif + +#define RANDOMPOOL_ALLOCSIZE RNG_POOL_SIZE + +// After every RANDMIX_BYTE_INTERVAL-th byte written to the pool, the pool mixing function is applied to the entire pool +#define RANDMIX_BYTE_INTERVAL 16 + +// FastPoll interval (in milliseconds) +#define FASTPOLL_INTERVAL 500 + +void RandAddInt ( unsigned __int32 x ); +int Randinit ( void ); +void RandStop (BOOL freePool); +BOOL IsRandomNumberGeneratorStarted (); +void RandSetHashFunction ( int hash_algo_id ); +int RandGetHashFunction (void); +void SetRandomPoolEnrichedByUserStatus (BOOL enriched); +BOOL IsRandomPoolEnrichedByUser (); +BOOL Randmix ( void ); +void RandaddBuf ( void *buf , int len ); +BOOL FastPoll ( void ); +BOOL SlowPoll ( void ); +BOOL RandpeekBytes ( unsigned char *buf , int len ); +BOOL RandgetBytes ( unsigned char *buf , int len, BOOL forceSlowPoll ); + +#ifdef _WIN32 + +extern BOOL volatile bFastPollEnabled; +extern BOOL volatile bRandmixEnabled; + +LRESULT CALLBACK MouseProc ( int nCode , WPARAM wParam , LPARAM lParam ); +LRESULT CALLBACK KeyboardProc ( int nCode , WPARAM wParam , LPARAM lParam ); +static unsigned __stdcall PeriodicFastPollThreadProc (void *dummy); + +#endif + +#ifdef __cplusplus +} +#endif diff --git a/Common/Registry.c b/Common/Registry.c new file mode 100644 index 0000000..a309d93 --- /dev/null +++ b/Common/Registry.c @@ -0,0 +1,286 @@ +/* + Copyright (c) 2004-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 "Registry.h" + +BOOL ReadLocalMachineRegistryDword (char *subKey, char *name, DWORD *value) +{ + HKEY hkey = 0; + DWORD size = sizeof (*value); + DWORD type; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hkey) != ERROR_SUCCESS) + return FALSE; + + if (RegQueryValueEx (hkey, name, NULL, &type, (BYTE *) value, &size) != ERROR_SUCCESS) + { + RegCloseKey (hkey); + return FALSE; + } + + RegCloseKey (hkey); + return type == REG_DWORD; +} + +BOOL ReadLocalMachineRegistryMultiString (char *subKey, char *name, char *value, DWORD *size) +{ + HKEY hkey = 0; + DWORD type; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hkey) != ERROR_SUCCESS) + return FALSE; + + if (RegQueryValueEx (hkey, name, NULL, &type, (BYTE *) value, size) != ERROR_SUCCESS) + { + RegCloseKey (hkey); + return FALSE; + } + + RegCloseKey (hkey); + return type == REG_MULTI_SZ; +} + +BOOL ReadLocalMachineRegistryString (const char *subKey, char *name, char *str, DWORD *size) +{ + HKEY hkey = 0; + DWORD type; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hkey) != ERROR_SUCCESS) + return FALSE; + + if (RegQueryValueEx (hkey, name, NULL, &type, (BYTE *) str, size) != ERROR_SUCCESS) + { + RegCloseKey (hkey); + return FALSE; + } + + RegCloseKey (hkey); + return type == REG_SZ; +} + +BOOL ReadLocalMachineRegistryStringNonReflected (const char *subKey, char *name, char *str, DWORD *size) +{ + HKEY hkey = 0; + DWORD type; + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ | KEY_WOW64_64KEY, &hkey) != ERROR_SUCCESS) + return FALSE; + + if (RegQueryValueEx (hkey, name, NULL, &type, (BYTE *) str, size) != ERROR_SUCCESS) + { + RegCloseKey (hkey); + return FALSE; + } + + RegCloseKey (hkey); + return type == REG_SZ; +} + +int ReadRegistryInt (char *subKey, char *name, int defaultValue) +{ + HKEY hkey = 0; + DWORD value, size = sizeof (DWORD); + + if (RegOpenKeyEx (HKEY_CURRENT_USER, subKey, + 0, KEY_READ, &hkey) != ERROR_SUCCESS) + return defaultValue; + + if (RegQueryValueEx (hkey, name, 0, 0, (LPBYTE) &value, &size) != ERROR_SUCCESS) + value = defaultValue; + + RegCloseKey (hkey); + return value; +} + +char *ReadRegistryString (char *subKey, char *name, char *defaultValue, char *str, int maxLen) +{ + HKEY hkey = 0; + char value[MAX_PATH*4]; + DWORD size = sizeof (value); + + strncpy (str, defaultValue, maxLen-1); + + ZeroMemory (value, sizeof value); + if (RegOpenKeyEx (HKEY_CURRENT_USER, subKey, + 0, KEY_READ, &hkey) == ERROR_SUCCESS) + if (RegQueryValueEx (hkey, name, 0, 0, (LPBYTE) &value, &size) == ERROR_SUCCESS) + strncpy (str, value, maxLen-1); + + RegCloseKey (hkey); + return str; +} + +DWORD ReadRegistryBytes (char *path, char *name, char *value, int maxLen) +{ + HKEY hkey = 0; + DWORD size = maxLen; + BOOL success = FALSE; + + if (RegOpenKeyEx (HKEY_CURRENT_USER, path, 0, KEY_READ, &hkey) != ERROR_SUCCESS) + return 0; + + success = (RegQueryValueEx (hkey, name, 0, 0, (LPBYTE) value, &size) == ERROR_SUCCESS); + RegCloseKey (hkey); + + return success ? size : 0; +} + +void WriteRegistryInt (char *subKey, char *name, int value) +{ + HKEY hkey = 0; + DWORD disp; + + if (RegCreateKeyEx (HKEY_CURRENT_USER, subKey, + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &disp) != ERROR_SUCCESS) + return; + + RegSetValueEx (hkey, name, 0, REG_DWORD, (BYTE *) &value, sizeof value); + RegCloseKey (hkey); +} + +BOOL WriteLocalMachineRegistryDword (char *subKey, char *name, DWORD value) +{ + HKEY hkey = 0; + DWORD disp; + LONG status; + + if ((status = RegCreateKeyEx (HKEY_LOCAL_MACHINE, subKey, + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &disp)) != ERROR_SUCCESS) + { + SetLastError (status); + return FALSE; + } + + if ((status = RegSetValueEx (hkey, name, 0, REG_DWORD, (BYTE *) &value, sizeof value)) != ERROR_SUCCESS) + { + RegCloseKey (hkey); + SetLastError (status); + return FALSE; + } + + RegCloseKey (hkey); + return TRUE; +} + +BOOL WriteLocalMachineRegistryMultiString (char *subKey, char *name, char *multiString, DWORD size) +{ + HKEY hkey = 0; + DWORD disp; + LONG status; + + if ((status = RegCreateKeyEx (HKEY_LOCAL_MACHINE, subKey, + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &disp)) != ERROR_SUCCESS) + { + SetLastError (status); + return FALSE; + } + + if ((status = RegSetValueEx (hkey, name, 0, REG_MULTI_SZ, (BYTE *) multiString, size)) != ERROR_SUCCESS) + { + RegCloseKey (hkey); + SetLastError (status); + return FALSE; + } + + RegCloseKey (hkey); + return TRUE; +} + +BOOL WriteLocalMachineRegistryString (char *subKey, char *name, char *str, BOOL expandable) +{ + HKEY hkey = 0; + DWORD disp; + LONG status; + + if ((status = RegCreateKeyEx (HKEY_LOCAL_MACHINE, subKey, + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &disp)) != ERROR_SUCCESS) + { + SetLastError (status); + return FALSE; + } + + if ((status = RegSetValueEx (hkey, name, 0, expandable ? REG_EXPAND_SZ : REG_SZ, (BYTE *) str, strlen (str) + 1)) != ERROR_SUCCESS) + { + RegCloseKey (hkey); + SetLastError (status); + return FALSE; + } + + RegCloseKey (hkey); + return TRUE; +} + +void WriteRegistryString (char *subKey, char *name, char *str) +{ + HKEY hkey = 0; + DWORD disp; + + if (RegCreateKeyEx (HKEY_CURRENT_USER, subKey, + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &disp) != ERROR_SUCCESS) + return; + + RegSetValueEx (hkey, name, 0, REG_SZ, (BYTE *) str, strlen (str) + 1); + RegCloseKey (hkey); +} + +BOOL WriteRegistryBytes (char *path, char *name, char *str, DWORD size) +{ + HKEY hkey = 0; + DWORD disp; + BOOL res; + + if (RegCreateKeyEx (HKEY_CURRENT_USER, path, + 0, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hkey, &disp) != ERROR_SUCCESS) + return FALSE; + + res = RegSetValueEx (hkey, name, 0, REG_BINARY, (BYTE *) str, size); + RegCloseKey (hkey); + return res == ERROR_SUCCESS; +} + +BOOL DeleteLocalMachineRegistryKey (char *parentKey, char *subKeyToDelete) +{ + LONG status; + HKEY hkey = 0; + + if ((status = RegOpenKeyEx (HKEY_LOCAL_MACHINE, parentKey, 0, KEY_WRITE, &hkey)) != ERROR_SUCCESS) + { + SetLastError (status); + return FALSE; + } + + if ((status = RegDeleteKey (hkey, subKeyToDelete)) != ERROR_SUCCESS) + { + RegCloseKey (hkey); + SetLastError (status); + return FALSE; + } + + RegCloseKey (hkey); + return TRUE; +} + +void DeleteRegistryValue (char *subKey, char *name) +{ + HKEY hkey = 0; + + if (RegOpenKeyEx (HKEY_CURRENT_USER, subKey, 0, KEY_WRITE, &hkey) != ERROR_SUCCESS) + return; + + RegDeleteValue (hkey, name); + RegCloseKey (hkey); +} + + +void GetStartupRegKeyName (char *regk) +{ + // The string is split in order to prevent some antivirus packages from falsely reporting + // TrueCrypt.exe to contain a possible Trojan horse because of this string (heuristic scan). + sprintf (regk, "%s%s", "Software\\Microsoft\\Windows\\Curren", "tVersion\\Run"); +} diff --git a/Common/Registry.h b/Common/Registry.h new file mode 100644 index 0000000..dd05e8d --- /dev/null +++ b/Common/Registry.h @@ -0,0 +1,32 @@ +/* + Copyright (c) 2004-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. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +BOOL ReadLocalMachineRegistryDword (char *subKey, char *name, DWORD *value); +BOOL ReadLocalMachineRegistryMultiString (char *subKey, char *name, char *value, DWORD *size); +BOOL ReadLocalMachineRegistryString (const char *subKey, char *name, char *value, DWORD *size); +BOOL ReadLocalMachineRegistryStringNonReflected (const char *subKey, char *name, char *str, DWORD *size); +int ReadRegistryInt (char *subKey, char *name, int defaultValue); +char *ReadRegistryString (char *subKey, char *name, char *defaultValue, char *str, int maxLen); +DWORD ReadRegistryBytes (char *path, char *name, char *value, int maxLen); +void WriteRegistryInt (char *subKey, char *name, int value); +BOOL WriteLocalMachineRegistryDword (char *subKey, char *name, DWORD value); +BOOL WriteLocalMachineRegistryMultiString (char *subKey, char *name, char *multiString, DWORD size); +BOOL WriteLocalMachineRegistryString (char *subKey, char *name, char *str, BOOL expandable); +void WriteRegistryString (char *subKey, char *name, char *str); +BOOL WriteRegistryBytes (char *path, char *name, char *str, DWORD size); +BOOL DeleteLocalMachineRegistryKey (char *parentKey, char *subKeyToDelete); +void DeleteRegistryValue (char *subKey, char *name); +void GetStartupRegKeyName (char *regk); + +#ifdef __cplusplus +} +#endif diff --git a/Common/Resource.h b/Common/Resource.h new file mode 100644 index 0000000..cb7fb33 --- /dev/null +++ b/Common/Resource.h @@ -0,0 +1,174 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Common.rc +// +#define IDI_TRUECRYPT_ICON 501 +#define IDI_TRUECRYPT_VOL_ICON 502 +#define IDD_BENCHMARK_DLG 503 +#define IDD_MOUNT_OPTIONS 504 +#define IDD_KEYFILES 505 +#define IDR_LANGUAGE 506 +#define IDI_TRUECRYPT 507 +#define IDD_ABOUT_DLG 508 +#define IDD_COMMANDHELP_DLG 509 +#define IDD_RAWDEVICES_DLG 510 +#define IDC_HOMEPAGE 511 +#define IDR_COMMON_RSRC_HEADER 512 +#define IDD_LANGUAGE 513 +#define IDD_CIPHER_TEST_DLG 514 +#define IDR_LICENSE 515 +#define IDD_AUXILIARY_DLG 516 +#define IDB_TEXTUAL_LOGO_BKG 517 +#define IDB_TEXTUAL_LOGO_96DPI 518 +#define IDB_TEXTUAL_LOGO_288DPI 519 +#define IDR_BOOT_SECTOR 520 +#define IDR_BOOT_SECTOR_AES 521 +#define IDR_BOOT_SECTOR_SERPENT 522 +#define IDR_BOOT_SECTOR_TWOFISH 523 +#define IDR_BOOT_LOADER_DECOMPRESSOR 524 +#define IDR_BOOT_LOADER 525 +#define IDR_BOOT_LOADER_AES 526 +#define IDR_BOOT_LOADER_SERPENT 527 +#define IDR_BOOT_LOADER_TWOFISH 528 +#define IDR_RESCUE_BOOT_SECTOR 529 +#define IDR_RESCUE_BOOT_SECTOR_AES 530 +#define IDR_RESCUE_BOOT_SECTOR_SERPENT 531 +#define IDR_RESCUE_BOOT_SECTOR_TWOFISH 532 +#define IDR_RESCUE_LOADER 533 +#define IDR_RESCUE_LOADER_AES 534 +#define IDR_RESCUE_LOADER_SERPENT 535 +#define IDR_RESCUE_LOADER_TWOFISH 536 +#define IDD_TOKEN_PASSWORD 537 +#define IDD_TOKEN_KEYFILES 538 +#define IDD_NEW_TOKEN_KEYFILE 539 +#define IDD_RANDOM_POOL_ENRICHMENT 540 +#define IDI_TRUECRYPT_MOUNTED_ICON 541 +#define IDC_HW_AES_LABEL_LINK 5000 +#define IDC_HW_AES 5001 +#define IDC_PARALLELIZATION_LABEL_LINK 5002 +#define IDC_PARALLELIZATION 5003 +#define IDT_TOKEN_PASSWORD 5004 +#define IDC_PRINT 5005 +#define IDC_KEY 5006 +#define IDC_PLAINTEXT 5007 +#define IDC_CIPHERTEXT 5008 +#define IDC_INFO_BOX_TEXT 5009 +#define IDC_SECONDARY_KEY 5010 +#define IDD_TEXT_INFO_DIALOG_BOX_DLG 5011 +#define IDC_TEST_DATA_UNIT_NUMBER 5012 +#define IDD_KEYFILE_GENERATOR 5013 +#define IDC_CIPHER 5014 +#define IDD_MULTI_CHOICE_DLG 5015 +#define IDC_TEST_BLOCK_NUMBER 5016 +#define IDD_STATIC_MODELESS_WAIT_DLG 5017 +#define IDC_POOL_CONTENTS 5018 +#define IDC_PRF_ID 5019 +#define IDC_KEY_SIZE 5020 +#define IDC_PLAINTEXT_SIZE 5021 +#define IDC_REDTICK 5022 +#define IDC_TESTS_MESSAGE 5023 +#define IDC_RESET 5024 +#define IDC_AUTO 5025 +#define IDC_DECRYPT 5026 +#define IDT_TEST_KEY 5027 +#define IDT_TEST_PLAINTEXT 5028 +#define IDT_PRF 5029 +#define IDT_XTS_MODE 5030 +#define IDT_TEST_CIPHERTEXT 5031 +#define IDT_KEY 5032 +#define IDT_PLAINTEXT 5033 +#define IDC_ENCRYPT 5034 +#define IDT_KEY_UNIT 5035 +#define IDT_CIPHER 5036 +#define IDT_PLAINTEXT_SIZE_UNIT 5037 +#define IDC_DEVICELIST 5038 +#define IDT_TEST_BLOCK_NUMBER 5039 +#define IDT_SECONDARY_KEY 5040 +#define IDC_PERFORM_BENCHMARK 5041 +#define IDT_TEST_DATA_UNIT_NUMBER 5042 +#define IDC_KEYFILES_HIDVOL_PROT 5043 +#define IDC_KEYLIST 5044 +#define IDC_ABOUT_BKG 5045 +#define IDT_ABOUT_VERSION 5046 +#define IDT_BOX_BENCHMARK_INFO 5047 +#define IDC_ABOUT_CREDITS 5048 +#define IDT_SORT_METHOD 5049 +#define IDC_MOUNT_READONLY 5050 +#define IDC_MOUNT_REMOVABLE 5051 +#define IDC_PROTECT_HIDDEN_VOL 5052 +#define IDC_COMMANDHELP_TEXT 5053 +#define IDC_USE_EMBEDDED_HEADER_BAK 5054 +#define IDC_MOUNT_SYSENC_PART_WITHOUT_PBA 5055 +#define IDT_HIDDEN_PROT_PASSWD 5056 +#define IDC_RESULTS 5057 +#define IDC_KEYADD 5058 +#define IDC_KEYREMOVE 5059 +#define IDC_KEYREMOVEALL 5060 +#define IDC_KEYFILES_ENABLE 5061 +#define IDT_HIDDEN_VOL_PROTECTION 5062 +#define IDC_ADD_KEYFILE_PATH 5063 +#define IDC_BENCHMARK_BUFFER_SIZE 5064 +#define IDC_SHOW_PASSWORD_MO 5065 +#define IDC_GENERATE_KEYFILE 5066 +#define IDC_BENCHMARK_SORT_METHOD 5067 +#define IDC_PASSWORD_PROT_HIDVOL 5068 +#define IDT_BUFFER_SIZE 5069 +#define IDC_LANGLIST 5070 +#define IDC_KEYFILES_ENABLE_HIDVOL_PROT 5071 +#define IDT_KEYFILES_NOTE 5072 +#define IDT_KEYFILE_WARNING 5073 +#define IDT_KEYFILE_GENERATOR_NOTE 5074 +#define IDC_GENERATE_AND_SAVE_KEYFILE 5075 +#define IDT_POOL_CONTENTS 5076 +#define IDC_GET_LANG_PACKS 5077 +#define IDT_LANGPACK_AUTHORS 5078 +#define IDC_LANGPACK_CREDITS 5079 +#define IDC_LANGPACK_VERSION 5080 +#define IDT_ACTIVE_LANG_PACK 5081 +#define IDC_DISPLAY_POOL_CONTENTS 5082 +#define IDC_XTS_MODE_ENABLED 5083 +#define IDC_MULTI_CHOICE_MSG 5084 +#define IDC_CHOICE1 5085 +#define IDC_CHOICE5 5086 +#define IDC_CHOICE2 5087 +#define IDC_CHOICE3 5088 +#define IDC_CHOICE4 5089 +#define IDC_CHOICE6 5090 +#define IDC_CHOICE7 5091 +#define IDC_CHOICE8 5092 +#define IDC_CHOICE9 5093 +#define IDC_CHOICE10 5094 +#define IDC_MC_DLG_HR1 5095 +#define IDC_MC_DLG_HR2 5096 +#define IDC_LINK_HIDVOL_PROTECTION_INFO 5097 +#define IDC_LINK_KEYFILES_INFO 5098 +#define IDC_TEXTUAL_LOGO_IMG 5099 +#define IDC_ASPECT_RATIO_CALIBRATION_BOX 5100 +#define IDC_ABOUT_LOGO_AREA 5101 +#define IDC_TOKEN_PASSWORD 5102 +#define IDC_TOKEN_FILE_LIST 5103 +#define IDC_TOKEN_FILES_ADD 5104 +#define IDC_EXPORT 5105 +#define IDC_DELETE 5106 +#define IDC_IMPORT_KEYFILE 5107 +#define IDC_SELECTED_TOKEN 5108 +#define IDT_SECURITY_TOKEN 5109 +#define IDT_TOKEN_KEYFILE_NAME 5110 +#define IDC_TOKEN_KEYFILE_NAME 5111 +#define IDT_TOKEN_PASSWORD_INFO 5112 +#define IDT_RANDOM_POOL_ENRICHMENT_NOTE 5113 +#define IDC_CONTINUE 5114 +#define IDT_ABOUT_RELEASE 5115 +#define IDT_STATIC_MODELESS_WAIT_DLG_INFO 5116 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 542 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 5117 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Common/SecurityToken.cpp b/Common/SecurityToken.cpp new file mode 100644 index 0000000..4788023 --- /dev/null +++ b/Common/SecurityToken.cpp @@ -0,0 +1,761 @@ +/* + 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 "Platform/Finally.h" +#include "Platform/ForEach.h" + +#if !defined (TC_WINDOWS) || defined (TC_PROTOTYPE) +# include "Platform/SerializerFactory.h" +# include "Platform/StringConverter.h" +# include "Platform/SystemException.h" +#else +# include "Dictionary.h" +# include "Language.h" +#endif + +#ifdef TC_UNIX +# include <dlfcn.h> +#endif + +#include "SecurityToken.h" + +#ifndef burn +# define burn Memory::Erase +#endif + +using namespace std; + +namespace TrueCrypt +{ + SecurityTokenKeyfile::SecurityTokenKeyfile (const SecurityTokenKeyfilePath &path) + { + wstring pathStr = path; + unsigned long slotId; + + if (swscanf (pathStr.c_str(), TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX TC_SECURITY_TOKEN_KEYFILE_URL_SLOT L"/%lu", &slotId) != 1) + throw InvalidSecurityTokenKeyfilePath(); + + SlotId = slotId; + + size_t keyIdPos = pathStr.find (L"/" TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"/"); + if (keyIdPos == string::npos) + throw InvalidSecurityTokenKeyfilePath(); + + Id = pathStr.substr (keyIdPos + wstring (L"/" TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"/").size()); + + vector <SecurityTokenKeyfile> keyfiles = SecurityToken::GetAvailableKeyfiles (&SlotId, Id); + + if (keyfiles.empty()) + throw SecurityTokenKeyfileNotFound(); + + *this = keyfiles.front(); + } + + SecurityTokenKeyfile::operator SecurityTokenKeyfilePath () const + { + wstringstream path; + path << TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX TC_SECURITY_TOKEN_KEYFILE_URL_SLOT L"/" << SlotId << L"/" TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"/" << Id; + return path.str(); + } + + void SecurityToken::CheckLibraryStatus () + { + if (!Initialized) + throw SecurityTokenLibraryNotInitialized(); + } + + void SecurityToken::CloseLibrary () + { + if (Initialized) + { + CloseAllSessions(); + Pkcs11Functions->C_Finalize (NULL_PTR); + +#ifdef TC_WINDOWS + FreeLibrary (Pkcs11LibraryHandle); +#else + dlclose (Pkcs11LibraryHandle); +#endif + Initialized = false; + } + } + + void SecurityToken::CloseAllSessions () throw () + { + if (!Initialized) + return; + + typedef pair <CK_SLOT_ID, Pkcs11Session> SessionMapPair; + + foreach (SessionMapPair p, Sessions) + { + try + { + CloseSession (p.first); + } + catch (...) { } + } + } + + void SecurityToken::CloseSession (CK_SLOT_ID slotId) + { + if (Sessions.find (slotId) == Sessions.end()) + throw ParameterIncorrect (SRC_POS); + + Pkcs11Functions->C_CloseSession (Sessions[slotId].Handle); + Sessions.erase (Sessions.find (slotId)); + } + + void SecurityToken::CreateKeyfile (CK_SLOT_ID slotId, vector <byte> &keyfileData, const string &name) + { + if (name.empty()) + throw ParameterIncorrect (SRC_POS); + + LoginUserIfRequired (slotId); + + foreach (const SecurityTokenKeyfile &keyfile, GetAvailableKeyfiles (&slotId)) + { + if (keyfile.IdUtf8 == name) + throw SecurityTokenKeyfileAlreadyExists(); + } + + CK_OBJECT_CLASS dataClass = CKO_DATA; + CK_BBOOL trueVal = CK_TRUE; + + CK_ATTRIBUTE keyfileTemplate[] = + { + { CKA_CLASS, &dataClass, sizeof (dataClass) }, + { CKA_TOKEN, &trueVal, sizeof (trueVal) }, + { CKA_PRIVATE, &trueVal, sizeof (trueVal) }, + { CKA_LABEL, (CK_UTF8CHAR *) name.c_str(), name.size() }, + { CKA_VALUE, &keyfileData.front(), keyfileData.size() } + }; + + CK_OBJECT_HANDLE keyfileHandle; + + CK_RV status = Pkcs11Functions->C_CreateObject (Sessions[slotId].Handle, keyfileTemplate, array_capacity (keyfileTemplate), &keyfileHandle); + + switch (status) + { + case CKR_DATA_LEN_RANGE: + status = CKR_DEVICE_MEMORY; + break; + + case CKR_SESSION_READ_ONLY: + status = CKR_TOKEN_WRITE_PROTECTED; + break; + } + + if (status != CKR_OK) + throw Pkcs11Exception (status); + + // Some tokens report success even if the new object was truncated to fit in the available memory + vector <byte> objectData; + + GetObjectAttribute (slotId, keyfileHandle, CKA_VALUE, objectData); + finally_do_arg (vector <byte> *, &objectData, { if (!finally_arg->empty()) burn (&finally_arg->front(), finally_arg->size()); }); + + if (objectData.size() != keyfileData.size()) + { + Pkcs11Functions->C_DestroyObject (Sessions[slotId].Handle, keyfileHandle); + throw Pkcs11Exception (CKR_DEVICE_MEMORY); + } + } + + void SecurityToken::DeleteKeyfile (const SecurityTokenKeyfile &keyfile) + { + LoginUserIfRequired (keyfile.SlotId); + + CK_RV status = Pkcs11Functions->C_DestroyObject (Sessions[keyfile.SlotId].Handle, keyfile.Handle); + if (status != CKR_OK) + throw Pkcs11Exception (status); + } + + vector <SecurityTokenKeyfile> SecurityToken::GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter, const wstring keyfileIdFilter) + { + bool unrecognizedTokenPresent = false; + vector <SecurityTokenKeyfile> keyfiles; + + foreach (const CK_SLOT_ID &slotId, GetTokenSlots()) + { + SecurityTokenInfo token; + + if (slotIdFilter && *slotIdFilter != slotId) + continue; + + try + { + LoginUserIfRequired (slotId); + token = GetTokenInfo (slotId); + } + catch (UserAbort &) + { + continue; + } + catch (Pkcs11Exception &e) + { + if (e.GetErrorCode() == CKR_TOKEN_NOT_RECOGNIZED) + { + unrecognizedTokenPresent = true; + continue; + } + + throw; + } + + foreach (const CK_OBJECT_HANDLE &dataHandle, GetObjects (slotId, CKO_DATA)) + { + SecurityTokenKeyfile keyfile; + keyfile.Handle = dataHandle; + keyfile.SlotId = slotId; + keyfile.Token = token; + + vector <byte> privateAttrib; + GetObjectAttribute (slotId, dataHandle, CKA_PRIVATE, privateAttrib); + + if (privateAttrib.size() == sizeof (CK_BBOOL) && *(CK_BBOOL *) &privateAttrib.front() != CK_TRUE) + continue; + + vector <byte> label; + GetObjectAttribute (slotId, dataHandle, CKA_LABEL, label); + label.push_back (0); + + keyfile.IdUtf8 = (char *) &label.front(); + +#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) + keyfile.Id = Utf8StringToWide ((const char *) &label.front()); +#else + keyfile.Id = StringConverter::ToWide ((const char *) &label.front()); +#endif + if (keyfile.Id.empty() || (!keyfileIdFilter.empty() && keyfileIdFilter != keyfile.Id)) + continue; + + keyfiles.push_back (keyfile); + + if (!keyfileIdFilter.empty()) + break; + } + } + + if (keyfiles.empty() && unrecognizedTokenPresent) + throw Pkcs11Exception (CKR_TOKEN_NOT_RECOGNIZED); + + return keyfiles; + } + + list <SecurityTokenInfo> SecurityToken::GetAvailableTokens () + { + bool unrecognizedTokenPresent = false; + list <SecurityTokenInfo> tokens; + + foreach (const CK_SLOT_ID &slotId, GetTokenSlots()) + { + try + { + tokens.push_back (GetTokenInfo (slotId)); + } + catch (Pkcs11Exception &e) + { + if (e.GetErrorCode() == CKR_TOKEN_NOT_RECOGNIZED) + { + unrecognizedTokenPresent = true; + continue; + } + + throw; + } + } + + if (tokens.empty() && unrecognizedTokenPresent) + throw Pkcs11Exception (CKR_TOKEN_NOT_RECOGNIZED); + + return tokens; + } + + SecurityTokenInfo SecurityToken::GetTokenInfo (CK_SLOT_ID slotId) + { + CK_TOKEN_INFO info; + CK_RV status = Pkcs11Functions->C_GetTokenInfo (slotId, &info); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + SecurityTokenInfo token; + token.SlotId = slotId; + token.Flags = info.flags; + + char label[sizeof (info.label) + 1]; + memset (label, 0, sizeof (label)); + memcpy (label, info.label, sizeof (info.label)); + + token.LabelUtf8 = label; + + size_t lastSpace = token.LabelUtf8.find_last_not_of (' '); + if (lastSpace == string::npos) + token.LabelUtf8.clear(); + else + token.LabelUtf8 = token.LabelUtf8.substr (0, lastSpace + 1); + +#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) + token.Label = Utf8StringToWide (token.LabelUtf8); +#else + token.Label = StringConverter::ToWide (token.LabelUtf8); +#endif + return token; + } + + void SecurityToken::GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector <byte> &keyfileData) + { + LoginUserIfRequired (keyfile.SlotId); + GetObjectAttribute (keyfile.SlotId, keyfile.Handle, CKA_VALUE, keyfileData); + } + + vector <CK_OBJECT_HANDLE> SecurityToken::GetObjects (CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass) + { + if (Sessions.find (slotId) == Sessions.end()) + throw ParameterIncorrect (SRC_POS); + + CK_ATTRIBUTE findTemplate; + findTemplate.type = CKA_CLASS; + findTemplate.pValue = &objectClass; + findTemplate.ulValueLen = sizeof (objectClass); + + CK_RV status = Pkcs11Functions->C_FindObjectsInit (Sessions[slotId].Handle, &findTemplate, 1); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + finally_do_arg (CK_SLOT_ID, slotId, { Pkcs11Functions->C_FindObjectsFinal (Sessions[finally_arg].Handle); }); + + CK_ULONG objectCount; + vector <CK_OBJECT_HANDLE> objects; + + while (true) + { + CK_OBJECT_HANDLE object; + CK_RV status = Pkcs11Functions->C_FindObjects (Sessions[slotId].Handle, &object, 1, &objectCount); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + if (objectCount != 1) + break; + + objects.push_back (object); + } + + return objects; + } + + void SecurityToken::GetObjectAttribute (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector <byte> &attributeValue) + { + attributeValue.clear(); + + if (Sessions.find (slotId) == Sessions.end()) + throw ParameterIncorrect (SRC_POS); + + CK_ATTRIBUTE attribute; + attribute.type = attributeType; + attribute.pValue = NULL_PTR; + + CK_RV status = Pkcs11Functions->C_GetAttributeValue (Sessions[slotId].Handle, tokenObject, &attribute, 1); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + if (attribute.ulValueLen == 0) + return; + + attributeValue = vector <byte> (attribute.ulValueLen); + attribute.pValue = &attributeValue.front(); + + status = Pkcs11Functions->C_GetAttributeValue (Sessions[slotId].Handle, tokenObject, &attribute, 1); + if (status != CKR_OK) + throw Pkcs11Exception (status); + } + + list <CK_SLOT_ID> SecurityToken::GetTokenSlots () + { + CheckLibraryStatus(); + + list <CK_SLOT_ID> slots; + CK_ULONG slotCount; + + CK_RV status = Pkcs11Functions->C_GetSlotList (TRUE, NULL_PTR, &slotCount); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + if (slotCount > 0) + { + vector <CK_SLOT_ID> slotArray (slotCount); + status = Pkcs11Functions->C_GetSlotList (TRUE, &slotArray.front(), &slotCount); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + for (size_t i = 0; i < slotCount; i++) + { + CK_SLOT_INFO slotInfo; + status = Pkcs11Functions->C_GetSlotInfo (slotArray[i], &slotInfo); + + if (status != CKR_OK || !(slotInfo.flags & CKF_TOKEN_PRESENT)) + continue; + + slots.push_back (slotArray[i]); + } + } + + return slots; + } + + bool SecurityToken::IsKeyfilePathValid (const wstring &securityTokenKeyfilePath) + { + return securityTokenKeyfilePath.find (TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX) == 0; + } + + void SecurityToken::Login (CK_SLOT_ID slotId, const string &pin) + { + if (Sessions.find (slotId) == Sessions.end()) + OpenSession (slotId); + else if (Sessions[slotId].UserLoggedIn) + return; + + CK_RV status = Pkcs11Functions->C_Login (Sessions[slotId].Handle, CKU_USER, (CK_CHAR_PTR) pin.c_str(), pin.size()); + + if (status != CKR_OK) + throw Pkcs11Exception (status); + + Sessions[slotId].UserLoggedIn = true; + } + + void SecurityToken::LoginUserIfRequired (CK_SLOT_ID slotId) + { + CheckLibraryStatus(); + CK_RV status; + + if (Sessions.find (slotId) == Sessions.end()) + { + OpenSession (slotId); + } + else + { + CK_SESSION_INFO sessionInfo; + status = Pkcs11Functions->C_GetSessionInfo (Sessions[slotId].Handle, &sessionInfo); + + if (status == CKR_OK) + { + Sessions[slotId].UserLoggedIn = (sessionInfo.state == CKS_RO_USER_FUNCTIONS || sessionInfo.state == CKS_RW_USER_FUNCTIONS); + } + else + { + try + { + CloseSession (slotId); + } + catch (...) { } + OpenSession (slotId); + } + } + + SecurityTokenInfo tokenInfo = GetTokenInfo (slotId); + + while (!Sessions[slotId].UserLoggedIn && (tokenInfo.Flags & CKF_LOGIN_REQUIRED)) + { + try + { + if (tokenInfo.Flags & CKF_PROTECTED_AUTHENTICATION_PATH) + { + status = Pkcs11Functions->C_Login (Sessions[slotId].Handle, CKU_USER, NULL_PTR, 0); + if (status != CKR_OK) + throw Pkcs11Exception (status); + } + else + { + string pin = tokenInfo.LabelUtf8; + if (tokenInfo.Label.empty()) + { + stringstream s; + s << "#" << slotId; + pin = s.str(); + } + + finally_do_arg (string*, &pin, { burn ((void *) finally_arg->c_str(), finally_arg->size()); }); + + (*PinCallback) (pin); + Login (slotId, pin); + } + + Sessions[slotId].UserLoggedIn = true; + } + catch (Pkcs11Exception &e) + { + CK_RV error = e.GetErrorCode(); + + if (error == CKR_USER_ALREADY_LOGGED_IN) + { + break; + } + else if (error == CKR_PIN_INCORRECT && !(tokenInfo.Flags & CKF_PROTECTED_AUTHENTICATION_PATH)) + { + (*WarningCallback) (Pkcs11Exception (CKR_PIN_INCORRECT)); + continue; + } + + throw; + } + } + } + + void SecurityToken::InitLibrary (const string &pkcs11LibraryPath, auto_ptr <GetPinFunctor> pinCallback, auto_ptr <SendExceptionFunctor> warningCallback) + { + if (Initialized) + CloseLibrary(); + +#ifdef TC_WINDOWS + Pkcs11LibraryHandle = LoadLibraryA (pkcs11LibraryPath.c_str()); +#else + Pkcs11LibraryHandle = dlopen (pkcs11LibraryPath.c_str(), RTLD_NOW | RTLD_LOCAL); +#endif + throw_sys_if (!Pkcs11LibraryHandle); + + typedef CK_RV (*C_GetFunctionList_t) (CK_FUNCTION_LIST_PTR_PTR ppFunctionList); +#ifdef TC_WINDOWS + C_GetFunctionList_t C_GetFunctionList = (C_GetFunctionList_t) GetProcAddress (Pkcs11LibraryHandle, "C_GetFunctionList"); +#else + C_GetFunctionList_t C_GetFunctionList = (C_GetFunctionList_t) dlsym (Pkcs11LibraryHandle, "C_GetFunctionList"); +#endif + + if (!C_GetFunctionList) + throw SecurityTokenLibraryNotInitialized(); + + CK_RV status = C_GetFunctionList (&Pkcs11Functions); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + status = Pkcs11Functions->C_Initialize (NULL_PTR); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + PinCallback = pinCallback; + WarningCallback = warningCallback; + + Initialized = true; + } + + void SecurityToken::OpenSession (CK_SLOT_ID slotId) + { + if (Sessions.find (slotId) != Sessions.end()) + return; + + CK_SESSION_HANDLE session; + + CK_FLAGS flags = CKF_SERIAL_SESSION; + + if (!(GetTokenInfo (slotId).Flags & CKF_WRITE_PROTECTED)) + flags |= CKF_RW_SESSION; + + CK_RV status = Pkcs11Functions->C_OpenSession (slotId, flags, NULL_PTR, NULL_PTR, &session); + if (status != CKR_OK) + throw Pkcs11Exception (status); + + Sessions[slotId].Handle = session; + } + + Pkcs11Exception::operator string () const + { + if (ErrorCode == CKR_OK) + return string(); + + static const struct + { + CK_RV ErrorCode; + const char *ErrorString; + } ErrorStrings[] = + { +# define TC_TOKEN_ERR(CODE) { CODE, #CODE }, + + TC_TOKEN_ERR (CKR_CANCEL) + TC_TOKEN_ERR (CKR_HOST_MEMORY) + TC_TOKEN_ERR (CKR_SLOT_ID_INVALID) + TC_TOKEN_ERR (CKR_GENERAL_ERROR) + TC_TOKEN_ERR (CKR_FUNCTION_FAILED) + TC_TOKEN_ERR (CKR_ARGUMENTS_BAD) + TC_TOKEN_ERR (CKR_NO_EVENT) + TC_TOKEN_ERR (CKR_NEED_TO_CREATE_THREADS) + TC_TOKEN_ERR (CKR_CANT_LOCK) + TC_TOKEN_ERR (CKR_ATTRIBUTE_READ_ONLY) + TC_TOKEN_ERR (CKR_ATTRIBUTE_SENSITIVE) + TC_TOKEN_ERR (CKR_ATTRIBUTE_TYPE_INVALID) + TC_TOKEN_ERR (CKR_ATTRIBUTE_VALUE_INVALID) + TC_TOKEN_ERR (CKR_DATA_INVALID) + TC_TOKEN_ERR (CKR_DATA_LEN_RANGE) + TC_TOKEN_ERR (CKR_DEVICE_ERROR) + TC_TOKEN_ERR (CKR_DEVICE_MEMORY) + TC_TOKEN_ERR (CKR_DEVICE_REMOVED) + TC_TOKEN_ERR (CKR_ENCRYPTED_DATA_INVALID) + TC_TOKEN_ERR (CKR_ENCRYPTED_DATA_LEN_RANGE) + TC_TOKEN_ERR (CKR_FUNCTION_CANCELED) + TC_TOKEN_ERR (CKR_FUNCTION_NOT_PARALLEL) + TC_TOKEN_ERR (CKR_FUNCTION_NOT_SUPPORTED) + TC_TOKEN_ERR (CKR_KEY_HANDLE_INVALID) + TC_TOKEN_ERR (CKR_KEY_SIZE_RANGE) + TC_TOKEN_ERR (CKR_KEY_TYPE_INCONSISTENT) + TC_TOKEN_ERR (CKR_KEY_NOT_NEEDED) + TC_TOKEN_ERR (CKR_KEY_CHANGED) + TC_TOKEN_ERR (CKR_KEY_NEEDED) + TC_TOKEN_ERR (CKR_KEY_INDIGESTIBLE) + TC_TOKEN_ERR (CKR_KEY_FUNCTION_NOT_PERMITTED) + TC_TOKEN_ERR (CKR_KEY_NOT_WRAPPABLE) + TC_TOKEN_ERR (CKR_KEY_UNEXTRACTABLE) + TC_TOKEN_ERR (CKR_MECHANISM_INVALID) + TC_TOKEN_ERR (CKR_MECHANISM_PARAM_INVALID) + TC_TOKEN_ERR (CKR_OBJECT_HANDLE_INVALID) + TC_TOKEN_ERR (CKR_OPERATION_ACTIVE) + TC_TOKEN_ERR (CKR_OPERATION_NOT_INITIALIZED) + TC_TOKEN_ERR (CKR_PIN_INCORRECT) + TC_TOKEN_ERR (CKR_PIN_INVALID) + TC_TOKEN_ERR (CKR_PIN_LEN_RANGE) + TC_TOKEN_ERR (CKR_PIN_EXPIRED) + TC_TOKEN_ERR (CKR_PIN_LOCKED) + TC_TOKEN_ERR (CKR_SESSION_CLOSED) + TC_TOKEN_ERR (CKR_SESSION_COUNT) + TC_TOKEN_ERR (CKR_SESSION_HANDLE_INVALID) + TC_TOKEN_ERR (CKR_SESSION_PARALLEL_NOT_SUPPORTED) + TC_TOKEN_ERR (CKR_SESSION_READ_ONLY) + TC_TOKEN_ERR (CKR_SESSION_EXISTS) + TC_TOKEN_ERR (CKR_SESSION_READ_ONLY_EXISTS) + TC_TOKEN_ERR (CKR_SESSION_READ_WRITE_SO_EXISTS) + TC_TOKEN_ERR (CKR_SIGNATURE_INVALID) + TC_TOKEN_ERR (CKR_SIGNATURE_LEN_RANGE) + TC_TOKEN_ERR (CKR_TEMPLATE_INCOMPLETE) + TC_TOKEN_ERR (CKR_TEMPLATE_INCONSISTENT) + TC_TOKEN_ERR (CKR_TOKEN_NOT_PRESENT) + TC_TOKEN_ERR (CKR_TOKEN_NOT_RECOGNIZED) + TC_TOKEN_ERR (CKR_TOKEN_WRITE_PROTECTED) + TC_TOKEN_ERR (CKR_UNWRAPPING_KEY_HANDLE_INVALID) + TC_TOKEN_ERR (CKR_UNWRAPPING_KEY_SIZE_RANGE) + TC_TOKEN_ERR (CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT) + TC_TOKEN_ERR (CKR_USER_ALREADY_LOGGED_IN) + TC_TOKEN_ERR (CKR_USER_NOT_LOGGED_IN) + TC_TOKEN_ERR (CKR_USER_PIN_NOT_INITIALIZED) + TC_TOKEN_ERR (CKR_USER_TYPE_INVALID) + TC_TOKEN_ERR (CKR_USER_ANOTHER_ALREADY_LOGGED_IN) + TC_TOKEN_ERR (CKR_USER_TOO_MANY_TYPES) + TC_TOKEN_ERR (CKR_WRAPPED_KEY_INVALID) + TC_TOKEN_ERR (CKR_WRAPPED_KEY_LEN_RANGE) + TC_TOKEN_ERR (CKR_WRAPPING_KEY_HANDLE_INVALID) + TC_TOKEN_ERR (CKR_WRAPPING_KEY_SIZE_RANGE) + TC_TOKEN_ERR (CKR_WRAPPING_KEY_TYPE_INCONSISTENT) + TC_TOKEN_ERR (CKR_RANDOM_SEED_NOT_SUPPORTED) + TC_TOKEN_ERR (CKR_RANDOM_NO_RNG) + TC_TOKEN_ERR (CKR_DOMAIN_PARAMS_INVALID) + TC_TOKEN_ERR (CKR_BUFFER_TOO_SMALL) + TC_TOKEN_ERR (CKR_SAVED_STATE_INVALID) + TC_TOKEN_ERR (CKR_INFORMATION_SENSITIVE) + TC_TOKEN_ERR (CKR_STATE_UNSAVEABLE) + TC_TOKEN_ERR (CKR_CRYPTOKI_NOT_INITIALIZED) + TC_TOKEN_ERR (CKR_CRYPTOKI_ALREADY_INITIALIZED) + TC_TOKEN_ERR (CKR_MUTEX_BAD) + TC_TOKEN_ERR (CKR_MUTEX_NOT_LOCKED) + TC_TOKEN_ERR (CKR_NEW_PIN_MODE) + TC_TOKEN_ERR (CKR_NEXT_OTP) + TC_TOKEN_ERR (CKR_FUNCTION_REJECTED) + +#undef TC_TOKEN_ERR + }; + + + for (size_t i = 0; i < array_capacity (ErrorStrings); ++i) + { + if (ErrorStrings[i].ErrorCode == ErrorCode) + return ErrorStrings[i].ErrorString; + } + + stringstream s; + s << "0x" << hex << ErrorCode; + return s.str(); + + } + +#ifdef TC_HEADER_Common_Exception + void Pkcs11Exception::Show (HWND parent) const + { + string errorString = string (*this); + + if (!errorString.empty()) + { + wstringstream subjectErrorCode; + if (SubjectErrorCodeValid) + subjectErrorCode << L": " << SubjectErrorCode; + + if (!GetDictionaryValue (errorString.c_str())) + { + if (errorString.find ("CKR_") == 0) + { + errorString = errorString.substr (4); + for (size_t i = 0; i < errorString.size(); ++i) + { + if (errorString[i] == '_') + errorString[i] = ' '; + } + } + wchar_t err[8192]; + wsprintfW (err, L"%s:\n\n%hs%s", GetString ("SECURITY_TOKEN_ERROR"), errorString.c_str(), subjectErrorCode.str().c_str()); + ErrorDirect (err); + } + else + { + wstring err = GetString (errorString.c_str()); + + if (SubjectErrorCodeValid) + err += L"\n\nError code" + subjectErrorCode.str(); + + ErrorDirect (err.c_str()); + } + } + } +#endif // TC_HEADER_Common_Exception + + auto_ptr <GetPinFunctor> SecurityToken::PinCallback; + auto_ptr <SendExceptionFunctor> SecurityToken::WarningCallback; + + bool SecurityToken::Initialized; + CK_FUNCTION_LIST_PTR SecurityToken::Pkcs11Functions; + map <CK_SLOT_ID, Pkcs11Session> SecurityToken::Sessions; + +#ifdef TC_WINDOWS + HMODULE SecurityToken::Pkcs11LibraryHandle; +#else + void *SecurityToken::Pkcs11LibraryHandle; +#endif + +#ifdef TC_HEADER_Platform_Exception + + void Pkcs11Exception::Deserialize (shared_ptr <Stream> stream) + { + Exception::Deserialize (stream); + Serializer sr (stream); + uint64 code; + sr.Deserialize ("ErrorCode", code); + sr.Deserialize ("SubjectErrorCodeValid", SubjectErrorCodeValid); + sr.Deserialize ("SubjectErrorCode", SubjectErrorCode); + ErrorCode = (CK_RV) code; + } + + void Pkcs11Exception::Serialize (shared_ptr <Stream> stream) const + { + Exception::Serialize (stream); + Serializer sr (stream); + sr.Serialize ("ErrorCode", (uint64) ErrorCode); + sr.Serialize ("SubjectErrorCodeValid", SubjectErrorCodeValid); + sr.Serialize ("SubjectErrorCode", SubjectErrorCode); + } + +# define TC_EXCEPTION(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE) +# undef TC_EXCEPTION_NODECL +# define TC_EXCEPTION_NODECL(TYPE) TC_SERIALIZER_FACTORY_ADD(TYPE) + + TC_SERIALIZER_FACTORY_ADD_EXCEPTION_SET (SecurityTokenException); + +#endif +} diff --git a/Common/SecurityToken.h b/Common/SecurityToken.h new file mode 100644 index 0000000..3ef85c5 --- /dev/null +++ b/Common/SecurityToken.h @@ -0,0 +1,216 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Common_SecurityToken +#define TC_HEADER_Common_SecurityToken + +#include "Platform/PlatformBase.h" +#if defined (TC_WINDOWS) && !defined (TC_PROTOTYPE) +# include "Exception.h" +#else +# include "Platform/Exception.h" +#endif + +#ifndef NULL_PTR +# define NULL_PTR 0 +#endif +#define CK_PTR * +#define CK_CALLBACK_FUNCTION(RET_TYPE, NAME) RET_TYPE (* NAME) + +#ifdef TC_WINDOWS + +# include <windows.h> + +# define CK_DEFINE_FUNCTION(RET_TYPE, NAME) RET_TYPE __declspec(dllexport) NAME +# define CK_DECLARE_FUNCTION(RET_TYPE, NAME) RET_TYPE __declspec(dllimport) NAME +# define CK_DECLARE_FUNCTION_POINTER(RET_TYPE, NAME) RET_TYPE __declspec(dllimport) (* NAME) + +# pragma pack(push, cryptoki, 1) +# include <pkcs11.h> +# pragma pack(pop, cryptoki) + +#else // !TC_WINDOWS + +# define CK_DEFINE_FUNCTION(RET_TYPE, NAME) RET_TYPE NAME +# define CK_DECLARE_FUNCTION(RET_TYPE, NAME) RET_TYPE NAME +# define CK_DECLARE_FUNCTION_POINTER(RET_TYPE, NAME) RET_TYPE (* NAME) + +# include <pkcs11.h> + +#endif // !TC_WINDOWS + + +#define TC_SECURITY_TOKEN_KEYFILE_URL_PREFIX L"token://" +#define TC_SECURITY_TOKEN_KEYFILE_URL_SLOT L"slot" +#define TC_SECURITY_TOKEN_KEYFILE_URL_FILE L"file" + +namespace TrueCrypt +{ + struct SecurityTokenInfo + { + CK_SLOT_ID SlotId; + CK_FLAGS Flags; + wstring Label; + string LabelUtf8; + }; + + struct SecurityTokenKeyfilePath + { + SecurityTokenKeyfilePath () { } + SecurityTokenKeyfilePath (const wstring &path) : Path (path) { } + operator wstring () const { return Path; } + wstring Path; + }; + + struct SecurityTokenKeyfile + { + SecurityTokenKeyfile () { } + SecurityTokenKeyfile (const SecurityTokenKeyfilePath &path); + + operator SecurityTokenKeyfilePath () const; + + CK_OBJECT_HANDLE Handle; + wstring Id; + string IdUtf8; + CK_SLOT_ID SlotId; + SecurityTokenInfo Token; + }; + + struct Pkcs11Exception : public Exception + { + Pkcs11Exception (CK_RV errorCode = (CK_RV) -1) + : ErrorCode (errorCode), + SubjectErrorCodeValid (false) + { + } + + Pkcs11Exception (CK_RV errorCode, uint64 subjectErrorCode) + : ErrorCode (errorCode), + SubjectErrorCodeValid (true), + SubjectErrorCode (subjectErrorCode) + { + } + +#ifdef TC_HEADER_Platform_Exception + virtual ~Pkcs11Exception () throw () { } + TC_SERIALIZABLE_EXCEPTION (Pkcs11Exception); +#else + void Show (HWND parent) const; +#endif + operator string () const; + CK_RV GetErrorCode () const { return ErrorCode; } + + protected: + CK_RV ErrorCode; + bool SubjectErrorCodeValid; + uint64 SubjectErrorCode; + }; + + +#ifdef TC_HEADER_Platform_Exception + +#define TC_EXCEPTION(NAME) TC_EXCEPTION_DECL(NAME,Exception) + +#undef TC_EXCEPTION_SET +#define TC_EXCEPTION_SET \ + TC_EXCEPTION_NODECL (Pkcs11Exception); \ + TC_EXCEPTION (InvalidSecurityTokenKeyfilePath); \ + TC_EXCEPTION (SecurityTokenLibraryNotInitialized); \ + TC_EXCEPTION (SecurityTokenKeyfileAlreadyExists); \ + TC_EXCEPTION (SecurityTokenKeyfileNotFound); + + TC_EXCEPTION_SET; + +#undef TC_EXCEPTION + +#else // !TC_HEADER_Platform_Exception + + struct SecurityTokenLibraryNotInitialized : public Exception + { + void Show (HWND parent) const { Error (SecurityTokenLibraryPath[0] == 0 ? "NO_PKCS11_MODULE_SPECIFIED" : "PKCS11_MODULE_INIT_FAILED"); } + }; + + struct InvalidSecurityTokenKeyfilePath : public Exception + { + void Show (HWND parent) const { Error ("INVALID_TOKEN_KEYFILE_PATH"); } + }; + + struct SecurityTokenKeyfileAlreadyExists : public Exception + { + void Show (HWND parent) const { Error ("TOKEN_KEYFILE_ALREADY_EXISTS"); } + }; + + struct SecurityTokenKeyfileNotFound : public Exception + { + void Show (HWND parent) const { Error ("TOKEN_KEYFILE_NOT_FOUND"); } + }; + +#endif // !TC_HEADER_Platform_Exception + + + struct Pkcs11Session + { + Pkcs11Session () : UserLoggedIn (false) { } + + CK_SESSION_HANDLE Handle; + bool UserLoggedIn; + }; + + struct GetPinFunctor + { + virtual ~GetPinFunctor () { } + virtual void operator() (string &str) = 0; + }; + + struct SendExceptionFunctor + { + virtual ~SendExceptionFunctor () { } + virtual void operator() (const Exception &e) = 0; + }; + + class SecurityToken + { + public: + static void CloseAllSessions () throw (); + static void CloseLibrary (); + static void CreateKeyfile (CK_SLOT_ID slotId, vector <byte> &keyfileData, const string &name); + static void DeleteKeyfile (const SecurityTokenKeyfile &keyfile); + static vector <SecurityTokenKeyfile> GetAvailableKeyfiles (CK_SLOT_ID *slotIdFilter = nullptr, const wstring keyfileIdFilter = wstring()); + static void GetKeyfileData (const SecurityTokenKeyfile &keyfile, vector <byte> &keyfileData); + static list <SecurityTokenInfo> GetAvailableTokens (); + static SecurityTokenInfo GetTokenInfo (CK_SLOT_ID slotId); + static void InitLibrary (const string &pkcs11LibraryPath, auto_ptr <GetPinFunctor> pinCallback, auto_ptr <SendExceptionFunctor> warningCallback); + static bool IsInitialized () { return Initialized; } + static bool IsKeyfilePathValid (const wstring &securityTokenKeyfilePath); + + static const size_t MaxPasswordLength = 128; + + protected: + static void CloseSession (CK_SLOT_ID slotId); + static vector <CK_OBJECT_HANDLE> GetObjects (CK_SLOT_ID slotId, CK_ATTRIBUTE_TYPE objectClass); + static void GetObjectAttribute (CK_SLOT_ID slotId, CK_OBJECT_HANDLE tokenObject, CK_ATTRIBUTE_TYPE attributeType, vector <byte> &attributeValue); + static list <CK_SLOT_ID> GetTokenSlots (); + static void Login (CK_SLOT_ID slotId, const string &pin); + static void LoginUserIfRequired (CK_SLOT_ID slotId); + static void OpenSession (CK_SLOT_ID slotId); + static void CheckLibraryStatus (); + + static bool Initialized; + static auto_ptr <GetPinFunctor> PinCallback; + static CK_FUNCTION_LIST_PTR Pkcs11Functions; +#ifdef TC_WINDOWS + static HMODULE Pkcs11LibraryHandle; +#else + static void *Pkcs11LibraryHandle; +#endif + static map <CK_SLOT_ID, Pkcs11Session> Sessions; + static auto_ptr <SendExceptionFunctor> WarningCallback; + }; +} + +#endif // TC_HEADER_Common_SecurityToken diff --git a/Common/Sources b/Common/Sources new file mode 100644 index 0000000..98dbb93 --- /dev/null +++ b/Common/Sources @@ -0,0 +1,17 @@ +TARGETNAME=Common
+TARGETTYPE=DRIVER_LIBRARY
+
+INCLUDES = ..;../Crypto
+
+SOURCES = \
+ Cache.c \
+ Crc.c \
+ Crypto.c \
+ EncryptionThreadPool.c \
+ Endian.c \
+ GfMul.c \
+ Pkcs5.c \
+ Volumes.c \
+ Xts.c \
+ Tests.c \
+ Wipe.c
diff --git a/Common/Tcdefs.h b/Common/Tcdefs.h new file mode 100644 index 0000000..9ab14a4 --- /dev/null +++ b/Common/Tcdefs.h @@ -0,0 +1,301 @@ +/* + 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 TCDEFS_H +#define TCDEFS_H + +#define TC_APP_NAME "TrueCrypt" + +// Version displayed to user +#define VERSION_STRING "7.1a" + +// Version number to compare against driver +#define VERSION_NUM 0x071a + +// Release date +#define TC_STR_RELEASE_DATE "February 7, 2012" +#define TC_RELEASE_DATE_YEAR 2012 +#define TC_RELEASE_DATE_MONTH 2 + +#define BYTES_PER_KB 1024LL +#define BYTES_PER_MB 1048576LL +#define BYTES_PER_GB 1073741824LL +#define BYTES_PER_TB 1099511627776LL +#define BYTES_PER_PB 1125899906842624LL + +/* GUI/driver errors */ + +#define WIDE(x) (LPWSTR)L##x + +#ifdef _MSC_VER + +typedef __int8 int8; +typedef __int16 int16; +typedef __int32 int32; +typedef unsigned __int8 byte; +typedef unsigned __int16 uint16; +typedef unsigned __int32 uint32; + +#ifdef TC_NO_COMPILER_INT64 +typedef unsigned __int32 TC_LARGEST_COMPILER_UINT; +#else +typedef unsigned __int64 TC_LARGEST_COMPILER_UINT; +typedef __int64 int64; +typedef unsigned __int64 uint64; +#endif + +#else // !_MSC_VER + +#include <inttypes.h> +#include <limits.h> + +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; +typedef uint8_t byte; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; + +#if UCHAR_MAX != 0xffU +#error UCHAR_MAX != 0xff +#endif +#define __int8 char + +#if USHRT_MAX != 0xffffU +#error USHRT_MAX != 0xffff +#endif +#define __int16 short + +#if UINT_MAX != 0xffffffffU +#error UINT_MAX != 0xffffffff +#endif +#define __int32 int + +typedef uint64 TC_LARGEST_COMPILER_UINT; + +#define BOOL int +#ifndef FALSE +#define FALSE 0 +#define TRUE 1 +#endif + +#endif // !_MSC_VER + +#define TC_INT_TYPES_DEFINED + +// Integer types required by Cryptolib +typedef unsigned __int8 uint_8t; +typedef unsigned __int16 uint_16t; +typedef unsigned __int32 uint_32t; +#ifndef TC_NO_COMPILER_INT64 +typedef uint64 uint_64t; +#endif + +typedef union +{ + struct + { + unsigned __int32 LowPart; + unsigned __int32 HighPart; + }; +#ifndef TC_NO_COMPILER_INT64 + uint64 Value; +#endif + +} UINT64_STRUCT; + +#ifdef TC_WINDOWS_BOOT + +# ifdef __cplusplus +extern "C" +# endif +void ThrowFatalException (int line); + +# define TC_THROW_FATAL_EXCEPTION ThrowFatalException (__LINE__) +#elif defined (TC_WINDOWS_DRIVER) +# define TC_THROW_FATAL_EXCEPTION KeBugCheckEx (SECURITY_SYSTEM, __LINE__, 0, 0, 'TC') +#else +# define TC_THROW_FATAL_EXCEPTION *(char *) 0 = 0 +#endif + +#ifdef TC_WINDOWS_DRIVER + +#include <ntifs.h> +#include <ntddk.h> /* Standard header file for nt drivers */ +#include <ntdddisk.h> /* Standard I/O control codes */ + +#define TCalloc(size) ((void *) ExAllocatePoolWithTag( NonPagedPool, size, 'MMCT' )) +#define TCfree(memblock) ExFreePoolWithTag( memblock, 'MMCT' ) + +#define DEVICE_DRIVER + +#ifndef BOOL +typedef int BOOL; +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE !TRUE +#endif + +#else /* !TC_WINDOWS_DRIVER */ + +#define TCalloc malloc +#define TCfree free + +#ifdef _WIN32 + +#ifndef TC_LOCAL_WIN32_WINNT_OVERRIDE +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0501 /* Does not apply to the driver */ +#endif + +#include <windows.h> /* Windows header */ +#include <commctrl.h> /* The common controls */ +#include <process.h> /* Process control */ +#include <winioctl.h> +#include <stdio.h> /* For sprintf */ + +#endif /* _WIN32 */ + +#endif /* !TC_WINDOWS_DRIVER */ + +#ifndef TC_TO_STRING +# define TC_TO_STRING2(n) #n +# define TC_TO_STRING(n) TC_TO_STRING2(n) +#endif + +#ifdef DEVICE_DRIVER +# if defined (DEBUG) || 0 +# if 1 // DbgPrintEx is not available on Windows 2000 +# define Dump DbgPrint +# else +# define Dump(...) DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__) +# endif +# define DumpMem(...) DumpMemory (__VA_ARGS__) +# else +# define Dump(...) +# define DumpMem(...) +# endif +#endif + +#if !defined (trace_msg) && !defined (TC_WINDOWS_BOOT) +# ifdef DEBUG +# ifdef DEVICE_DRIVER +# define trace_msg Dump +# elif defined (_WIN32) +# define trace_msg(...) do { char msg[2048]; _snprintf (msg, sizeof (msg), __VA_ARGS__); OutputDebugString (msg); } while (0) +# endif +# define trace_point trace_msg (__FUNCTION__ ":" TC_TO_STRING(__LINE__) "\n") +# else +# define trace_msg(...) +# define trace_point +# endif +#endif + +#ifdef DEVICE_DRIVER +# define TC_EVENT KEVENT +# define TC_WAIT_EVENT(EVENT) KeWaitForSingleObject (&EVENT, Executive, KernelMode, FALSE, NULL) +#elif defined (_WIN32) +# define TC_EVENT HANDLE +# define TC_WAIT_EVENT(EVENT) WaitForSingleObject (EVENT, INFINITE) +#endif + +#ifdef _WIN32 +#define burn(mem,size) do { volatile char *burnm = (volatile char *)(mem); int burnc = size; RtlSecureZeroMemory (mem, size); while (burnc--) *burnm++ = 0; } while (0) +#else +#define burn(mem,size) do { volatile char *burnm = (volatile char *)(mem); int burnc = size; while (burnc--) *burnm++ = 0; } while (0) +#endif + +// The size of the memory area to wipe is in bytes amd it must be a multiple of 8. +#ifndef TC_NO_COMPILER_INT64 +# define FAST_ERASE64(mem,size) do { volatile uint64 *burnm = (volatile uint64 *)(mem); int burnc = size >> 3; while (burnc--) *burnm++ = 0; } while (0) +#else +# define FAST_ERASE64(mem,size) do { volatile unsigned __int32 *burnm = (volatile unsigned __int32 *)(mem); int burnc = size >> 2; while (burnc--) *burnm++ = 0; } while (0) +#endif + +#ifdef TC_WINDOWS_BOOT +# ifndef max +# define max(a,b) (((a) > (b)) ? (a) : (b)) +# endif + +# ifdef __cplusplus +extern "C" +# endif +void EraseMemory (void *memory, int size); + +# undef burn +# define burn EraseMemory +#endif + +#ifdef MAX_PATH +#define TC_MAX_PATH MAX_PATH +#else +#define TC_MAX_PATH 260 /* Includes the null terminator */ +#endif + +#define TC_STR_RELEASED_BY "Released by TrueCrypt Foundation on " TC_STR_RELEASE_DATE + +#define MAX_URL_LENGTH 2084 /* Internet Explorer limit. Includes the terminating null character. */ + +#define TC_HOMEPAGE "http://www.truecrypt.org/" +#define TC_APPLINK "http://www.truecrypt.org/applink?version=" VERSION_STRING +#define TC_APPLINK_SECURE "https://www.truecrypt.org/applink?version=" VERSION_STRING + +enum +{ + /* WARNING: ADD ANY NEW CODES AT THE END (DO NOT INSERT THEM BETWEEN EXISTING). DO *NOT* DELETE ANY + EXISTING CODES! Changing these values or their meanings may cause incompatibility with other versions + (for example, if a new version of the TrueCrypt installer receives an error code from an installed + driver whose version is lower, it will report and interpret the error incorrectly). */ + + ERR_SUCCESS = 0, + ERR_OS_ERROR = 1, + ERR_OUTOFMEMORY = 2, + ERR_PASSWORD_WRONG = 3, + ERR_VOL_FORMAT_BAD = 4, + ERR_DRIVE_NOT_FOUND = 5, + ERR_FILES_OPEN = 6, + ERR_VOL_SIZE_WRONG = 7, + ERR_COMPRESSION_NOT_SUPPORTED = 8, + ERR_PASSWORD_CHANGE_VOL_TYPE = 9, + ERR_PASSWORD_CHANGE_VOL_VERSION = 10, + ERR_VOL_SEEKING = 11, + ERR_VOL_WRITING = 12, + ERR_FILES_OPEN_LOCK = 13, + ERR_VOL_READING = 14, + ERR_DRIVER_VERSION = 15, + ERR_NEW_VERSION_REQUIRED = 16, + ERR_CIPHER_INIT_FAILURE = 17, + ERR_CIPHER_INIT_WEAK_KEY = 18, + ERR_SELF_TESTS_FAILED = 19, + ERR_SECTOR_SIZE_INCOMPATIBLE = 20, + ERR_VOL_ALREADY_MOUNTED = 21, + ERR_NO_FREE_DRIVES = 22, + ERR_FILE_OPEN_FAILED = 23, + ERR_VOL_MOUNT_FAILED = 24, + DEPRECATED_ERR_INVALID_DEVICE = 25, + ERR_ACCESS_DENIED = 26, + ERR_MODE_INIT_FAILED = 27, + ERR_DONT_REPORT = 28, + ERR_ENCRYPTION_NOT_COMPLETED = 29, + ERR_PARAMETER_INCORRECT = 30, + ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG = 31, + ERR_NONSYS_INPLACE_ENC_INCOMPLETE = 32, + ERR_USER_ABORT = 33 +}; + +#endif // #ifndef TCDEFS_H diff --git a/Common/Tests.c b/Common/Tests.c new file mode 100644 index 0000000..cf17713 --- /dev/null +++ b/Common/Tests.c @@ -0,0 +1,1722 @@ +/* + 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 "Crc.h" +#include "Crypto.h" +#include "Common/Endian.h" +#include "Tests.h" +#include "Xts.h" +#include <string.h> +#include "Pkcs5.h" + +typedef struct { + unsigned __int8 key1[32]; + unsigned __int8 key2[32]; + unsigned __int8 dataUnitNo[8]; + unsigned int blockNo; + unsigned __int8 plaintext[ENCRYPTION_DATA_UNIT_SIZE]; + unsigned __int8 ciphertext[ENCRYPTION_DATA_UNIT_SIZE]; +} XTS_TEST; + +#define XTS_TEST_COUNT 5 + +XTS_TEST XTS_vectors[XTS_TEST_COUNT] = { +/* XTS-AES-256 */ +{ + // IEEE 1619 - Vector 10 + + { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26, 0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69, 0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27 }, + { 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95, 0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37, 0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff }, + 0, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }, + { + 0x1c, 0x3b, 0x3a, 0x10, 0x2f, 0x77, 0x03, 0x86, 0xe4, 0x83, 0x6c, 0x99, 0xe3, 0x70, 0xcf, 0x9b, 0xea, 0x00, 0x80, 0x3f, 0x5e, 0x48, 0x23, 0x57, 0xa4, 0xae, 0x12, 0xd4, 0x14, 0xa3, 0xe6, 0x3b, + 0x5d, 0x31, 0xe2, 0x76, 0xf8, 0xfe, 0x4a, 0x8d, 0x66, 0xb3, 0x17, 0xf9, 0xac, 0x68, 0x3f, 0x44, 0x68, 0x0a, 0x86, 0xac, 0x35, 0xad, 0xfc, 0x33, 0x45, 0xbe, 0xfe, 0xcb, 0x4b, 0xb1, 0x88, 0xfd, + 0x57, 0x76, 0x92, 0x6c, 0x49, 0xa3, 0x09, 0x5e, 0xb1, 0x08, 0xfd, 0x10, 0x98, 0xba, 0xec, 0x70, 0xaa, 0xa6, 0x69, 0x99, 0xa7, 0x2a, 0x82, 0xf2, 0x7d, 0x84, 0x8b, 0x21, 0xd4, 0xa7, 0x41, 0xb0, + 0xc5, 0xcd, 0x4d, 0x5f, 0xff, 0x9d, 0xac, 0x89, 0xae, 0xba, 0x12, 0x29, 0x61, 0xd0, 0x3a, 0x75, 0x71, 0x23, 0xe9, 0x87, 0x0f, 0x8a, 0xcf, 0x10, 0x00, 0x02, 0x08, 0x87, 0x89, 0x14, 0x29, 0xca, + 0x2a, 0x3e, 0x7a, 0x7d, 0x7d, 0xf7, 0xb1, 0x03, 0x55, 0x16, 0x5c, 0x8b, 0x9a, 0x6d, 0x0a, 0x7d, 0xe8, 0xb0, 0x62, 0xc4, 0x50, 0x0d, 0xc4, 0xcd, 0x12, 0x0c, 0x0f, 0x74, 0x18, 0xda, 0xe3, 0xd0, + 0xb5, 0x78, 0x1c, 0x34, 0x80, 0x3f, 0xa7, 0x54, 0x21, 0xc7, 0x90, 0xdf, 0xe1, 0xde, 0x18, 0x34, 0xf2, 0x80, 0xd7, 0x66, 0x7b, 0x32, 0x7f, 0x6c, 0x8c, 0xd7, 0x55, 0x7e, 0x12, 0xac, 0x3a, 0x0f, + 0x93, 0xec, 0x05, 0xc5, 0x2e, 0x04, 0x93, 0xef, 0x31, 0xa1, 0x2d, 0x3d, 0x92, 0x60, 0xf7, 0x9a, 0x28, 0x9d, 0x6a, 0x37, 0x9b, 0xc7, 0x0c, 0x50, 0x84, 0x14, 0x73, 0xd1, 0xa8, 0xcc, 0x81, 0xec, + 0x58, 0x3e, 0x96, 0x45, 0xe0, 0x7b, 0x8d, 0x96, 0x70, 0x65, 0x5b, 0xa5, 0xbb, 0xcf, 0xec, 0xc6, 0xdc, 0x39, 0x66, 0x38, 0x0a, 0xd8, 0xfe, 0xcb, 0x17, 0xb6, 0xba, 0x02, 0x46, 0x9a, 0x02, 0x0a, + 0x84, 0xe1, 0x8e, 0x8f, 0x84, 0x25, 0x20, 0x70, 0xc1, 0x3e, 0x9f, 0x1f, 0x28, 0x9b, 0xe5, 0x4f, 0xbc, 0x48, 0x14, 0x57, 0x77, 0x8f, 0x61, 0x60, 0x15, 0xe1, 0x32, 0x7a, 0x02, 0xb1, 0x40, 0xf1, + 0x50, 0x5e, 0xb3, 0x09, 0x32, 0x6d, 0x68, 0x37, 0x8f, 0x83, 0x74, 0x59, 0x5c, 0x84, 0x9d, 0x84, 0xf4, 0xc3, 0x33, 0xec, 0x44, 0x23, 0x88, 0x51, 0x43, 0xcb, 0x47, 0xbd, 0x71, 0xc5, 0xed, 0xae, + 0x9b, 0xe6, 0x9a, 0x2f, 0xfe, 0xce, 0xb1, 0xbe, 0xc9, 0xde, 0x24, 0x4f, 0xbe, 0x15, 0x99, 0x2b, 0x11, 0xb7, 0x7c, 0x04, 0x0f, 0x12, 0xbd, 0x8f, 0x6a, 0x97, 0x5a, 0x44, 0xa0, 0xf9, 0x0c, 0x29, + 0xa9, 0xab, 0xc3, 0xd4, 0xd8, 0x93, 0x92, 0x72, 0x84, 0xc5, 0x87, 0x54, 0xcc, 0xe2, 0x94, 0x52, 0x9f, 0x86, 0x14, 0xdc, 0xd2, 0xab, 0xa9, 0x91, 0x92, 0x5f, 0xed, 0xc4, 0xae, 0x74, 0xff, 0xac, + 0x6e, 0x33, 0x3b, 0x93, 0xeb, 0x4a, 0xff, 0x04, 0x79, 0xda, 0x9a, 0x41, 0x0e, 0x44, 0x50, 0xe0, 0xdd, 0x7a, 0xe4, 0xc6, 0xe2, 0x91, 0x09, 0x00, 0x57, 0x5d, 0xa4, 0x01, 0xfc, 0x07, 0x05, 0x9f, + 0x64, 0x5e, 0x8b, 0x7e, 0x9b, 0xfd, 0xef, 0x33, 0x94, 0x30, 0x54, 0xff, 0x84, 0x01, 0x14, 0x93, 0xc2, 0x7b, 0x34, 0x29, 0xea, 0xed, 0xb4, 0xed, 0x53, 0x76, 0x44, 0x1a, 0x77, 0xed, 0x43, 0x85, + 0x1a, 0xd7, 0x7f, 0x16, 0xf5, 0x41, 0xdf, 0xd2, 0x69, 0xd5, 0x0d, 0x6a, 0x5f, 0x14, 0xfb, 0x0a, 0xab, 0x1c, 0xbb, 0x4c, 0x15, 0x50, 0xbe, 0x97, 0xf7, 0xab, 0x40, 0x66, 0x19, 0x3c, 0x4c, 0xaa, + 0x77, 0x3d, 0xad, 0x38, 0x01, 0x4b, 0xd2, 0x09, 0x2f, 0xa7, 0x55, 0xc8, 0x24, 0xbb, 0x5e, 0x54, 0xc4, 0xf3, 0x6f, 0xfd, 0xa9, 0xfc, 0xea, 0x70, 0xb9, 0xc6, 0xe6, 0x93, 0xe1, 0x48, 0xc1, 0x51 + } +}, +{ + // IEEE 1619 - Vector 11 + + { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26, 0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69, 0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27 }, + { 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95, 0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37, 0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }, + 0, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }, + { + 0x77, 0xa3, 0x12, 0x51, 0x61, 0x8a, 0x15, 0xe6, 0xb9, 0x2d, 0x1d, 0x66, 0xdf, 0xfe, 0x7b, 0x50, 0xb5, 0x0b, 0xad, 0x55, 0x23, 0x05, 0xba, 0x02, 0x17, 0xa6, 0x10, 0x68, 0x8e, 0xff, 0x7e, 0x11, + 0xe1, 0xd0, 0x22, 0x54, 0x38, 0xe0, 0x93, 0x24, 0x2d, 0x6d, 0xb2, 0x74, 0xfd, 0xe8, 0x01, 0xd4, 0xca, 0xe0, 0x6f, 0x20, 0x92, 0xc7, 0x28, 0xb2, 0x47, 0x85, 0x59, 0xdf, 0x58, 0xe8, 0x37, 0xc2, + 0x46, 0x9e, 0xe4, 0xa4, 0xfa, 0x79, 0x4e, 0x4b, 0xbc, 0x7f, 0x39, 0xbc, 0x02, 0x6e, 0x3c, 0xb7, 0x2c, 0x33, 0xb0, 0x88, 0x8f, 0x25, 0xb4, 0xac, 0xf5, 0x6a, 0x2a, 0x98, 0x04, 0xf1, 0xce, 0x6d, + 0x3d, 0x6e, 0x1d, 0xc6, 0xca, 0x18, 0x1d, 0x4b, 0x54, 0x61, 0x79, 0xd5, 0x55, 0x44, 0xaa, 0x77, 0x60, 0xc4, 0x0d, 0x06, 0x74, 0x15, 0x39, 0xc7, 0xe3, 0xcd, 0x9d, 0x2f, 0x66, 0x50, 0xb2, 0x01, + 0x3f, 0xd0, 0xee, 0xb8, 0xc2, 0xb8, 0xe3, 0xd8, 0xd2, 0x40, 0xcc, 0xae, 0x2d, 0x4c, 0x98, 0x32, 0x0a, 0x74, 0x42, 0xe1, 0xc8, 0xd7, 0x5a, 0x42, 0xd6, 0xe6, 0xcf, 0xa4, 0xc2, 0xec, 0xa1, 0x79, + 0x8d, 0x15, 0x8c, 0x7a, 0xec, 0xdf, 0x82, 0x49, 0x0f, 0x24, 0xbb, 0x9b, 0x38, 0xe1, 0x08, 0xbc, 0xda, 0x12, 0xc3, 0xfa, 0xf9, 0xa2, 0x11, 0x41, 0xc3, 0x61, 0x3b, 0x58, 0x36, 0x7f, 0x92, 0x2a, + 0xaa, 0x26, 0xcd, 0x22, 0xf2, 0x3d, 0x70, 0x8d, 0xae, 0x69, 0x9a, 0xd7, 0xcb, 0x40, 0xa8, 0xad, 0x0b, 0x6e, 0x27, 0x84, 0x97, 0x3d, 0xcb, 0x60, 0x56, 0x84, 0xc0, 0x8b, 0x8d, 0x69, 0x98, 0xc6, + 0x9a, 0xac, 0x04, 0x99, 0x21, 0x87, 0x1e, 0xbb, 0x65, 0x30, 0x1a, 0x46, 0x19, 0xca, 0x80, 0xec, 0xb4, 0x85, 0xa3, 0x1d, 0x74, 0x42, 0x23, 0xce, 0x8d, 0xdc, 0x23, 0x94, 0x82, 0x8d, 0x6a, 0x80, + 0x47, 0x0c, 0x09, 0x2f, 0x5b, 0xa4, 0x13, 0xc3, 0x37, 0x8f, 0xa6, 0x05, 0x42, 0x55, 0xc6, 0xf9, 0xdf, 0x44, 0x95, 0x86, 0x2b, 0xbb, 0x32, 0x87, 0x68, 0x1f, 0x93, 0x1b, 0x68, 0x7c, 0x88, 0x8a, + 0xbf, 0x84, 0x4d, 0xfc, 0x8f, 0xc2, 0x83, 0x31, 0xe5, 0x79, 0x92, 0x8c, 0xd1, 0x2b, 0xd2, 0x39, 0x0a, 0xe1, 0x23, 0xcf, 0x03, 0x81, 0x8d, 0x14, 0xde, 0xdd, 0xe5, 0xc0, 0xc2, 0x4c, 0x8a, 0xb0, + 0x18, 0xbf, 0xca, 0x75, 0xca, 0x09, 0x6f, 0x2d, 0x53, 0x1f, 0x3d, 0x16, 0x19, 0xe7, 0x85, 0xf1, 0xad, 0xa4, 0x37, 0xca, 0xb9, 0x2e, 0x98, 0x05, 0x58, 0xb3, 0xdc, 0xe1, 0x47, 0x4a, 0xfb, 0x75, + 0xbf, 0xed, 0xbf, 0x8f, 0xf5, 0x4c, 0xb2, 0x61, 0x8e, 0x02, 0x44, 0xc9, 0xac, 0x0d, 0x3c, 0x66, 0xfb, 0x51, 0x59, 0x8c, 0xd2, 0xdb, 0x11, 0xf9, 0xbe, 0x39, 0x79, 0x1a, 0xbe, 0x44, 0x7c, 0x63, + 0x09, 0x4f, 0x7c, 0x45, 0x3b, 0x7f, 0xf8, 0x7c, 0xb5, 0xbb, 0x36, 0xb7, 0xc7, 0x9e, 0xfb, 0x08, 0x72, 0xd1, 0x70, 0x58, 0xb8, 0x3b, 0x15, 0xab, 0x08, 0x66, 0xad, 0x8a, 0x58, 0x65, 0x6c, 0x5a, + 0x7e, 0x20, 0xdb, 0xdf, 0x30, 0x8b, 0x24, 0x61, 0xd9, 0x7c, 0x0e, 0xc0, 0x02, 0x4a, 0x27, 0x15, 0x05, 0x52, 0x49, 0xcf, 0x3b, 0x47, 0x8d, 0xdd, 0x47, 0x40, 0xde, 0x65, 0x4f, 0x75, 0xca, 0x68, + 0x6e, 0x0d, 0x73, 0x45, 0xc6, 0x9e, 0xd5, 0x0c, 0xdc, 0x2a, 0x8b, 0x33, 0x2b, 0x1f, 0x88, 0x24, 0x10, 0x8a, 0xc9, 0x37, 0xeb, 0x05, 0x05, 0x85, 0x60, 0x8e, 0xe7, 0x34, 0x09, 0x7f, 0xc0, 0x90, + 0x54, 0xfb, 0xff, 0x89, 0xee, 0xae, 0xea, 0x79, 0x1f, 0x4a, 0x7a, 0xb1, 0xf9, 0x86, 0x82, 0x94, 0xa4, 0xf9, 0xe2, 0x7b, 0x42, 0xaf, 0x81, 0x00, 0xcb, 0x9d, 0x59, 0xce, 0xf9, 0x64, 0x58, 0x03 + } +}, +{ + // IEEE 1619 - Vector 12 + + { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26, 0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69, 0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27 }, + { 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95, 0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37, 0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff }, + 0, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }, + { + 0xe3, 0x87, 0xaa, 0xa5, 0x8b, 0xa4, 0x83, 0xaf, 0xa7, 0xe8, 0xeb, 0x46, 0x97, 0x78, 0x31, 0x7e, 0xcf, 0x4c, 0xf5, 0x73, 0xaa, 0x9d, 0x4e, 0xac, 0x23, 0xf2, 0xcd, 0xf9, 0x14, 0xe4, 0xe2, 0x00, + 0xa8, 0xb4, 0x90, 0xe4, 0x2e, 0xe6, 0x46, 0x80, 0x2d, 0xc6, 0xee, 0x2b, 0x47, 0x1b, 0x27, 0x81, 0x95, 0xd6, 0x09, 0x18, 0xec, 0xec, 0xb4, 0x4b, 0xf7, 0x99, 0x66, 0xf8, 0x3f, 0xab, 0xa0, 0x49, + 0x92, 0x98, 0xeb, 0xc6, 0x99, 0xc0, 0xc8, 0x63, 0x47, 0x15, 0xa3, 0x20, 0xbb, 0x4f, 0x07, 0x5d, 0x62, 0x2e, 0x74, 0xc8, 0xc9, 0x32, 0x00, 0x4f, 0x25, 0xb4, 0x1e, 0x36, 0x10, 0x25, 0xb5, 0xa8, + 0x78, 0x15, 0x39, 0x1f, 0x61, 0x08, 0xfc, 0x4a, 0xfa, 0x6a, 0x05, 0xd9, 0x30, 0x3c, 0x6b, 0xa6, 0x8a, 0x12, 0x8a, 0x55, 0x70, 0x5d, 0x41, 0x59, 0x85, 0x83, 0x2f, 0xde, 0xaa, 0xe6, 0xc8, 0xe1, + 0x91, 0x10, 0xe8, 0x4d, 0x1b, 0x1f, 0x19, 0x9a, 0x26, 0x92, 0x11, 0x9e, 0xdc, 0x96, 0x13, 0x26, 0x58, 0xf0, 0x9d, 0xa7, 0xc6, 0x23, 0xef, 0xce, 0xc7, 0x12, 0x53, 0x7a, 0x3d, 0x94, 0xc0, 0xbf, + 0x5d, 0x7e, 0x35, 0x2e, 0xc9, 0x4a, 0xe5, 0x79, 0x7f, 0xdb, 0x37, 0x7d, 0xc1, 0x55, 0x11, 0x50, 0x72, 0x1a, 0xdf, 0x15, 0xbd, 0x26, 0xa8, 0xef, 0xc2, 0xfc, 0xaa, 0xd5, 0x68, 0x81, 0xfa, 0x9e, + 0x62, 0x46, 0x2c, 0x28, 0xf3, 0x0a, 0xe1, 0xce, 0xac, 0xa9, 0x3c, 0x34, 0x5c, 0xf2, 0x43, 0xb7, 0x3f, 0x54, 0x2e, 0x20, 0x74, 0xa7, 0x05, 0xbd, 0x26, 0x43, 0xbb, 0x9f, 0x7c, 0xc7, 0x9b, 0xb6, + 0xe7, 0x09, 0x1e, 0xa6, 0xe2, 0x32, 0xdf, 0x0f, 0x9a, 0xd0, 0xd6, 0xcf, 0x50, 0x23, 0x27, 0x87, 0x6d, 0x82, 0x20, 0x7a, 0xbf, 0x21, 0x15, 0xcd, 0xac, 0xf6, 0xd5, 0xa4, 0x8f, 0x6c, 0x18, 0x79, + 0xa6, 0x5b, 0x11, 0x5f, 0x0f, 0x8b, 0x3c, 0xb3, 0xc5, 0x9d, 0x15, 0xdd, 0x8c, 0x76, 0x9b, 0xc0, 0x14, 0x79, 0x5a, 0x18, 0x37, 0xf3, 0x90, 0x1b, 0x58, 0x45, 0xeb, 0x49, 0x1a, 0xdf, 0xef, 0xe0, + 0x97, 0xb1, 0xfa, 0x30, 0xa1, 0x2f, 0xc1, 0xf6, 0x5b, 0xa2, 0x29, 0x05, 0x03, 0x15, 0x39, 0x97, 0x1a, 0x10, 0xf2, 0xf3, 0x6c, 0x32, 0x1b, 0xb5, 0x13, 0x31, 0xcd, 0xef, 0xb3, 0x9e, 0x39, 0x64, + 0xc7, 0xef, 0x07, 0x99, 0x94, 0xf5, 0xb6, 0x9b, 0x2e, 0xdd, 0x83, 0xa7, 0x1e, 0xf5, 0x49, 0x97, 0x1e, 0xe9, 0x3f, 0x44, 0xea, 0xc3, 0x93, 0x8f, 0xcd, 0xd6, 0x1d, 0x01, 0xfa, 0x71, 0x79, 0x9d, + 0xa3, 0xa8, 0x09, 0x1c, 0x4c, 0x48, 0xaa, 0x9e, 0xd2, 0x63, 0xff, 0x07, 0x49, 0xdf, 0x95, 0xd4, 0x4f, 0xef, 0x6a, 0x0b, 0xb5, 0x78, 0xec, 0x69, 0x45, 0x6a, 0xa5, 0x40, 0x8a, 0xe3, 0x2c, 0x7a, + 0xf0, 0x8a, 0xd7, 0xba, 0x89, 0x21, 0x28, 0x7e, 0x3b, 0xbe, 0xe3, 0x1b, 0x76, 0x7b, 0xe0, 0x6a, 0x0e, 0x70, 0x5c, 0x86, 0x4a, 0x76, 0x91, 0x37, 0xdf, 0x28, 0x29, 0x22, 0x83, 0xea, 0x81, 0xa2, + 0x48, 0x02, 0x41, 0xb4, 0x4d, 0x99, 0x21, 0xcd, 0xbe, 0xc1, 0xbc, 0x28, 0xdc, 0x1f, 0xda, 0x11, 0x4b, 0xd8, 0xe5, 0x21, 0x7a, 0xc9, 0xd8, 0xeb, 0xaf, 0xa7, 0x20, 0xe9, 0xda, 0x4f, 0x9a, 0xce, + 0x23, 0x1c, 0xc9, 0x49, 0xe5, 0xb9, 0x6f, 0xe7, 0x6f, 0xfc, 0x21, 0x06, 0x3f, 0xdd, 0xc8, 0x3a, 0x6b, 0x86, 0x79, 0xc0, 0x0d, 0x35, 0xe0, 0x95, 0x76, 0xa8, 0x75, 0x30, 0x5b, 0xed, 0x5f, 0x36, + 0xed, 0x24, 0x2c, 0x89, 0x00, 0xdd, 0x1f, 0xa9, 0x65, 0xbc, 0x95, 0x0d, 0xfc, 0xe0, 0x9b, 0x13, 0x22, 0x63, 0xa1, 0xee, 0xf5, 0x2d, 0xd6, 0x88, 0x8c, 0x30, 0x9f, 0x5a, 0x7d, 0x71, 0x28, 0x26 + } +}, +{ + // IEEE 1619 - Vector 13 + + { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26, 0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69, 0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27 }, + { 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95, 0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37, 0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92 }, + { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }, + 0, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }, + { + 0xbf, 0x53, 0xd2, 0xda, 0xde, 0x78, 0xe8, 0x22, 0xa4, 0xd9, 0x49, 0xa9, 0xbc, 0x67, 0x66, 0xb0, 0x1b, 0x06, 0xa8, 0xef, 0x70, 0xd2, 0x67, 0x48, 0xc6, 0xa7, 0xfc, 0x36, 0xd8, 0x0a, 0xe4, 0xc5, + 0x52, 0x0f, 0x7c, 0x4a, 0xb0, 0xac, 0x85, 0x44, 0x42, 0x4f, 0xa4, 0x05, 0x16, 0x2f, 0xef, 0x5a, 0x6b, 0x7f, 0x22, 0x94, 0x98, 0x06, 0x36, 0x18, 0xd3, 0x9f, 0x00, 0x03, 0xcb, 0x5f, 0xb8, 0xd1, + 0xc8, 0x6b, 0x64, 0x34, 0x97, 0xda, 0x1f, 0xf9, 0x45, 0xc8, 0xd3, 0xbe, 0xde, 0xca, 0x4f, 0x47, 0x97, 0x02, 0xa7, 0xa7, 0x35, 0xf0, 0x43, 0xdd, 0xb1, 0xd6, 0xaa, 0xad, 0xe3, 0xc4, 0xa0, 0xac, + 0x7c, 0xa7, 0xf3, 0xfa, 0x52, 0x79, 0xbe, 0xf5, 0x6f, 0x82, 0xcd, 0x7a, 0x2f, 0x38, 0x67, 0x2e, 0x82, 0x48, 0x14, 0xe1, 0x07, 0x00, 0x30, 0x0a, 0x05, 0x5e, 0x16, 0x30, 0xb8, 0xf1, 0xcb, 0x0e, + 0x91, 0x9f, 0x5e, 0x94, 0x20, 0x10, 0xa4, 0x16, 0xe2, 0xbf, 0x48, 0xcb, 0x46, 0x99, 0x3d, 0x3c, 0xb6, 0xa5, 0x1c, 0x19, 0xba, 0xcf, 0x86, 0x47, 0x85, 0xa0, 0x0b, 0xc2, 0xec, 0xff, 0x15, 0xd3, + 0x50, 0x87, 0x5b, 0x24, 0x6e, 0xd5, 0x3e, 0x68, 0xbe, 0x6f, 0x55, 0xbd, 0x7e, 0x05, 0xcf, 0xc2, 0xb2, 0xed, 0x64, 0x32, 0x19, 0x8a, 0x64, 0x44, 0xb6, 0xd8, 0xc2, 0x47, 0xfa, 0xb9, 0x41, 0xf5, + 0x69, 0x76, 0x8b, 0x5c, 0x42, 0x93, 0x66, 0xf1, 0xd3, 0xf0, 0x0f, 0x03, 0x45, 0xb9, 0x61, 0x23, 0xd5, 0x62, 0x04, 0xc0, 0x1c, 0x63, 0xb2, 0x2c, 0xe7, 0x8b, 0xaf, 0x11, 0x6e, 0x52, 0x5e, 0xd9, + 0x0f, 0xde, 0xa3, 0x9f, 0xa4, 0x69, 0x49, 0x4d, 0x38, 0x66, 0xc3, 0x1e, 0x05, 0xf2, 0x95, 0xff, 0x21, 0xfe, 0xa8, 0xd4, 0xe6, 0xe1, 0x3d, 0x67, 0xe4, 0x7c, 0xe7, 0x22, 0xe9, 0x69, 0x8a, 0x1c, + 0x10, 0x48, 0xd6, 0x8e, 0xbc, 0xde, 0x76, 0xb8, 0x6f, 0xcf, 0x97, 0x6e, 0xab, 0x8a, 0xa9, 0x79, 0x02, 0x68, 0xb7, 0x06, 0x8e, 0x01, 0x7a, 0x8b, 0x9b, 0x74, 0x94, 0x09, 0x51, 0x4f, 0x10, 0x53, + 0x02, 0x7f, 0xd1, 0x6c, 0x37, 0x86, 0xea, 0x1b, 0xac, 0x5f, 0x15, 0xcb, 0x79, 0x71, 0x1e, 0xe2, 0xab, 0xe8, 0x2f, 0x5c, 0xf8, 0xb1, 0x3a, 0xe7, 0x30, 0x30, 0xef, 0x5b, 0x9e, 0x44, 0x57, 0xe7, + 0x5d, 0x13, 0x04, 0xf9, 0x88, 0xd6, 0x2d, 0xd6, 0xfc, 0x4b, 0x94, 0xed, 0x38, 0xba, 0x83, 0x1d, 0xa4, 0xb7, 0x63, 0x49, 0x71, 0xb6, 0xcd, 0x8e, 0xc3, 0x25, 0xd9, 0xc6, 0x1c, 0x00, 0xf1, 0xdf, + 0x73, 0x62, 0x7e, 0xd3, 0x74, 0x5a, 0x5e, 0x84, 0x89, 0xf3, 0xa9, 0x5c, 0x69, 0x63, 0x9c, 0x32, 0xcd, 0x6e, 0x1d, 0x53, 0x7a, 0x85, 0xf7, 0x5c, 0xc8, 0x44, 0x72, 0x6e, 0x8a, 0x72, 0xfc, 0x00, + 0x77, 0xad, 0x22, 0x00, 0x0f, 0x1d, 0x50, 0x78, 0xf6, 0xb8, 0x66, 0x31, 0x8c, 0x66, 0x8f, 0x1a, 0xd0, 0x3d, 0x5a, 0x5f, 0xce, 0xd5, 0x21, 0x9f, 0x2e, 0xab, 0xbd, 0x0a, 0xa5, 0xc0, 0xf4, 0x60, + 0xd1, 0x83, 0xf0, 0x44, 0x04, 0xa0, 0xd6, 0xf4, 0x69, 0x55, 0x8e, 0x81, 0xfa, 0xb2, 0x4a, 0x16, 0x79, 0x05, 0xab, 0x4c, 0x78, 0x78, 0x50, 0x2a, 0xd3, 0xe3, 0x8f, 0xdb, 0xe6, 0x2a, 0x41, 0x55, + 0x6c, 0xec, 0x37, 0x32, 0x57, 0x59, 0x53, 0x3c, 0xe8, 0xf2, 0x5f, 0x36, 0x7c, 0x87, 0xbb, 0x55, 0x78, 0xd6, 0x67, 0xae, 0x93, 0xf9, 0xe2, 0xfd, 0x99, 0xbc, 0xbc, 0x5f, 0x2f, 0xbb, 0xa8, 0x8c, + 0xf6, 0x51, 0x61, 0x39, 0x42, 0x0f, 0xcf, 0xf3, 0xb7, 0x36, 0x1d, 0x86, 0x32, 0x2c, 0x4b, 0xd8, 0x4c, 0x82, 0xf3, 0x35, 0xab, 0xb1, 0x52, 0xc4, 0xa9, 0x34, 0x11, 0x37, 0x3a, 0xaa, 0x82, 0x20 + } +}, +{ + // IEEE 1619 - Vector 14 + + /* This vector must always be the last one in XTS_vectors[] because TestSectorBufEncryption() relies on it. */ + + { 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26, 0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69, 0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27 }, + { 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95, 0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37, 0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92 }, + { 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff }, + 0, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }, + { + 0x64, 0x49, 0x7e, 0x5a, 0x83, 0x1e, 0x4a, 0x93, 0x2c, 0x09, 0xbe, 0x3e, 0x53, 0x93, 0x37, 0x6d, 0xaa, 0x59, 0x95, 0x48, 0xb8, 0x16, 0x03, 0x1d, 0x22, 0x4b, 0xbf, 0x50, 0xa8, 0x18, 0xed, 0x23, + 0x50, 0xea, 0xe7, 0xe9, 0x60, 0x87, 0xc8, 0xa0, 0xdb, 0x51, 0xad, 0x29, 0x0b, 0xd0, 0x0c, 0x1a, 0xc1, 0x62, 0x08, 0x57, 0x63, 0x5b, 0xf2, 0x46, 0xc1, 0x76, 0xab, 0x46, 0x3b, 0xe3, 0x0b, 0x80, + 0x8d, 0xa5, 0x48, 0x08, 0x1a, 0xc8, 0x47, 0xb1, 0x58, 0xe1, 0x26, 0x4b, 0xe2, 0x5b, 0xb0, 0x91, 0x0b, 0xbc, 0x92, 0x64, 0x71, 0x08, 0x08, 0x94, 0x15, 0xd4, 0x5f, 0xab, 0x1b, 0x3d, 0x26, 0x04, + 0xe8, 0xa8, 0xef, 0xf1, 0xae, 0x40, 0x20, 0xcf, 0xa3, 0x99, 0x36, 0xb6, 0x68, 0x27, 0xb2, 0x3f, 0x37, 0x1b, 0x92, 0x20, 0x0b, 0xe9, 0x02, 0x51, 0xe6, 0xd7, 0x3c, 0x5f, 0x86, 0xde, 0x5f, 0xd4, + 0xa9, 0x50, 0x78, 0x19, 0x33, 0xd7, 0x9a, 0x28, 0x27, 0x2b, 0x78, 0x2a, 0x2e, 0xc3, 0x13, 0xef, 0xdf, 0xcc, 0x06, 0x28, 0xf4, 0x3d, 0x74, 0x4c, 0x2d, 0xc2, 0xff, 0x3d, 0xcb, 0x66, 0x99, 0x9b, + 0x50, 0xc7, 0xca, 0x89, 0x5b, 0x0c, 0x64, 0x79, 0x1e, 0xea, 0xa5, 0xf2, 0x94, 0x99, 0xfb, 0x1c, 0x02, 0x6f, 0x84, 0xce, 0x5b, 0x5c, 0x72, 0xba, 0x10, 0x83, 0xcd, 0xdb, 0x5c, 0xe4, 0x54, 0x34, + 0x63, 0x16, 0x65, 0xc3, 0x33, 0xb6, 0x0b, 0x11, 0x59, 0x3f, 0xb2, 0x53, 0xc5, 0x17, 0x9a, 0x2c, 0x8d, 0xb8, 0x13, 0x78, 0x2a, 0x00, 0x48, 0x56, 0xa1, 0x65, 0x30, 0x11, 0xe9, 0x3f, 0xb6, 0xd8, + 0x76, 0xc1, 0x83, 0x66, 0xdd, 0x86, 0x83, 0xf5, 0x34, 0x12, 0xc0, 0xc1, 0x80, 0xf9, 0xc8, 0x48, 0x59, 0x2d, 0x59, 0x3f, 0x86, 0x09, 0xca, 0x73, 0x63, 0x17, 0xd3, 0x56, 0xe1, 0x3e, 0x2b, 0xff, + 0x3a, 0x9f, 0x59, 0xcd, 0x9a, 0xeb, 0x19, 0xcd, 0x48, 0x25, 0x93, 0xd8, 0xc4, 0x61, 0x28, 0xbb, 0x32, 0x42, 0x3b, 0x37, 0xa9, 0xad, 0xfb, 0x48, 0x2b, 0x99, 0x45, 0x3f, 0xbe, 0x25, 0xa4, 0x1b, + 0xf6, 0xfe, 0xb4, 0xaa, 0x0b, 0xef, 0x5e, 0xd2, 0x4b, 0xf7, 0x3c, 0x76, 0x29, 0x78, 0x02, 0x54, 0x82, 0xc1, 0x31, 0x15, 0xe4, 0x01, 0x5a, 0xac, 0x99, 0x2e, 0x56, 0x13, 0xa3, 0xb5, 0xc2, 0xf6, + 0x85, 0xb8, 0x47, 0x95, 0xcb, 0x6e, 0x9b, 0x26, 0x56, 0xd8, 0xc8, 0x81, 0x57, 0xe5, 0x2c, 0x42, 0xf9, 0x78, 0xd8, 0x63, 0x4c, 0x43, 0xd0, 0x6f, 0xea, 0x92, 0x8f, 0x28, 0x22, 0xe4, 0x65, 0xaa, + 0x65, 0x76, 0xe9, 0xbf, 0x41, 0x93, 0x84, 0x50, 0x6c, 0xc3, 0xce, 0x3c, 0x54, 0xac, 0x1a, 0x6f, 0x67, 0xdc, 0x66, 0xf3, 0xb3, 0x01, 0x91, 0xe6, 0x98, 0x38, 0x0b, 0xc9, 0x99, 0xb0, 0x5a, 0xbc, + 0xe1, 0x9d, 0xc0, 0xc6, 0xdc, 0xc2, 0xdd, 0x00, 0x1e, 0xc5, 0x35, 0xba, 0x18, 0xde, 0xb2, 0xdf, 0x1a, 0x10, 0x10, 0x23, 0x10, 0x83, 0x18, 0xc7, 0x5d, 0xc9, 0x86, 0x11, 0xa0, 0x9d, 0xc4, 0x8a, + 0x0a, 0xcd, 0xec, 0x67, 0x6f, 0xab, 0xdf, 0x22, 0x2f, 0x07, 0xe0, 0x26, 0xf0, 0x59, 0xb6, 0x72, 0xb5, 0x6e, 0x5c, 0xbc, 0x8e, 0x1d, 0x21, 0xbb, 0xd8, 0x67, 0xdd, 0x92, 0x72, 0x12, 0x05, 0x46, + 0x81, 0xd7, 0x0e, 0xa7, 0x37, 0x13, 0x4c, 0xdf, 0xce, 0x93, 0xb6, 0xf8, 0x2a, 0xe2, 0x24, 0x23, 0x27, 0x4e, 0x58, 0xa0, 0x82, 0x1c, 0xc5, 0x50, 0x2e, 0x2d, 0x0a, 0xb4, 0x58, 0x5e, 0x94, 0xde, + 0x69, 0x75, 0xbe, 0x5e, 0x0b, 0x4e, 0xfc, 0xe5, 0x1c, 0xd3, 0xe7, 0x0c, 0x25, 0xa1, 0xfb, 0xbb, 0xd6, 0x09, 0xd2, 0x73, 0xad, 0x5b, 0x0d, 0x59, 0x63, 0x1c, 0x53, 0x1f, 0x6a, 0x0a, 0x57, 0xb9 + } +} }; // XTS_TEST XTS_vectors[] + + +BOOL XTSAesTest (PCRYPTO_INFO ci) +{ + unsigned __int8 p[ENCRYPTION_DATA_UNIT_SIZE]; + UINT64_STRUCT dataUnitNo; + int i; + + for (i = 0; i < XTS_TEST_COUNT; i++) + { + ci->ea = EAGetByName ("AES"); + if (ci->ea == 0) + return FALSE; + + ci->mode = XTS; + + if (EAInit (ci->ea, XTS_vectors[i].key1, ci->ks) != ERR_SUCCESS) + return FALSE; + + memcpy (&ci->k2, XTS_vectors[i].key2, sizeof (XTS_vectors[i].key2)); + + if (!EAInitMode (ci)) + return FALSE; + + memcpy (p, XTS_vectors[i].plaintext, sizeof (p)); + + dataUnitNo.Value = BE64 (*((unsigned __int64 *) XTS_vectors[i].dataUnitNo)); + + EncryptBufferXTS (p, sizeof (p), &dataUnitNo, XTS_vectors[i].blockNo, (unsigned char *) (ci->ks), (unsigned char *) ci->ks2, AES); + + if (memcmp (XTS_vectors[i].ciphertext, p, sizeof (p)) != 0) + return FALSE; + } + + return TRUE; +} + +/* Blowfish Test Vectors (deprecated/legacy) */ + +/* Blowfish test vectors from www.counterpane.com/blowfish.html */ + +#define BF_TEST_COUNT 34 + +typedef struct { + unsigned char key[8]; + unsigned char plaintext[8]; + unsigned char ciphertext[8]; + } BF_TEST; + +#pragma warning(disable:4295) + +BF_TEST bf_ecb_vectors[BF_TEST_COUNT] = { +"\x00\x00\x00\x00\x00\x00\x00\x00","\x00\x00\x00\x00\x00\x00\x00\x00","\x4E\xF9\x97\x45\x61\x98\xDD\x78", +"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF","\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF","\x51\x86\x6F\xD5\xB8\x5E\xCB\x8A", +"\x30\x00\x00\x00\x00\x00\x00\x00","\x10\x00\x00\x00\x00\x00\x00\x01","\x7D\x85\x6F\x9A\x61\x30\x63\xF2", +"\x11\x11\x11\x11\x11\x11\x11\x11","\x11\x11\x11\x11\x11\x11\x11\x11","\x24\x66\xDD\x87\x8B\x96\x3C\x9D", +"\x01\x23\x45\x67\x89\xAB\xCD\xEF","\x11\x11\x11\x11\x11\x11\x11\x11","\x61\xF9\xC3\x80\x22\x81\xB0\x96", +"\x11\x11\x11\x11\x11\x11\x11\x11","\x01\x23\x45\x67\x89\xAB\xCD\xEF","\x7D\x0C\xC6\x30\xAF\xDA\x1E\xC7", +"\x00\x00\x00\x00\x00\x00\x00\x00","\x00\x00\x00\x00\x00\x00\x00\x00","\x4E\xF9\x97\x45\x61\x98\xDD\x78", +"\xFE\xDC\xBA\x98\x76\x54\x32\x10","\x01\x23\x45\x67\x89\xAB\xCD\xEF","\x0A\xCE\xAB\x0F\xC6\xA0\xA2\x8D", +"\x7C\xA1\x10\x45\x4A\x1A\x6E\x57","\x01\xA1\xD6\xD0\x39\x77\x67\x42","\x59\xC6\x82\x45\xEB\x05\x28\x2B", +"\x01\x31\xD9\x61\x9D\xC1\x37\x6E","\x5C\xD5\x4C\xA8\x3D\xEF\x57\xDA","\xB1\xB8\xCC\x0B\x25\x0F\x09\xA0", +"\x07\xA1\x13\x3E\x4A\x0B\x26\x86","\x02\x48\xD4\x38\x06\xF6\x71\x72","\x17\x30\xE5\x77\x8B\xEA\x1D\xA4", +"\x38\x49\x67\x4C\x26\x02\x31\x9E","\x51\x45\x4B\x58\x2D\xDF\x44\x0A","\xA2\x5E\x78\x56\xCF\x26\x51\xEB", +"\x04\xB9\x15\xBA\x43\xFE\xB5\xB6","\x42\xFD\x44\x30\x59\x57\x7F\xA2","\x35\x38\x82\xB1\x09\xCE\x8F\x1A", +"\x01\x13\xB9\x70\xFD\x34\xF2\xCE","\x05\x9B\x5E\x08\x51\xCF\x14\x3A","\x48\xF4\xD0\x88\x4C\x37\x99\x18", +"\x01\x70\xF1\x75\x46\x8F\xB5\xE6","\x07\x56\xD8\xE0\x77\x47\x61\xD2","\x43\x21\x93\xB7\x89\x51\xFC\x98", +"\x43\x29\x7F\xAD\x38\xE3\x73\xFE","\x76\x25\x14\xB8\x29\xBF\x48\x6A","\x13\xF0\x41\x54\xD6\x9D\x1A\xE5", +"\x07\xA7\x13\x70\x45\xDA\x2A\x16","\x3B\xDD\x11\x90\x49\x37\x28\x02","\x2E\xED\xDA\x93\xFF\xD3\x9C\x79", +"\x04\x68\x91\x04\xC2\xFD\x3B\x2F","\x26\x95\x5F\x68\x35\xAF\x60\x9A","\xD8\x87\xE0\x39\x3C\x2D\xA6\xE3", +"\x37\xD0\x6B\xB5\x16\xCB\x75\x46","\x16\x4D\x5E\x40\x4F\x27\x52\x32","\x5F\x99\xD0\x4F\x5B\x16\x39\x69", +"\x1F\x08\x26\x0D\x1A\xC2\x46\x5E","\x6B\x05\x6E\x18\x75\x9F\x5C\xCA","\x4A\x05\x7A\x3B\x24\xD3\x97\x7B", +"\x58\x40\x23\x64\x1A\xBA\x61\x76","\x00\x4B\xD6\xEF\x09\x17\x60\x62","\x45\x20\x31\xC1\xE4\xFA\xDA\x8E", +"\x02\x58\x16\x16\x46\x29\xB0\x07","\x48\x0D\x39\x00\x6E\xE7\x62\xF2","\x75\x55\xAE\x39\xF5\x9B\x87\xBD", +"\x49\x79\x3E\xBC\x79\xB3\x25\x8F","\x43\x75\x40\xC8\x69\x8F\x3C\xFA","\x53\xC5\x5F\x9C\xB4\x9F\xC0\x19", +"\x4F\xB0\x5E\x15\x15\xAB\x73\xA7","\x07\x2D\x43\xA0\x77\x07\x52\x92","\x7A\x8E\x7B\xFA\x93\x7E\x89\xA3", +"\x49\xE9\x5D\x6D\x4C\xA2\x29\xBF","\x02\xFE\x55\x77\x81\x17\xF1\x2A","\xCF\x9C\x5D\x7A\x49\x86\xAD\xB5", +"\x01\x83\x10\xDC\x40\x9B\x26\xD6","\x1D\x9D\x5C\x50\x18\xF7\x28\xC2","\xD1\xAB\xB2\x90\x65\x8B\xC7\x78", +"\x1C\x58\x7F\x1C\x13\x92\x4F\xEF","\x30\x55\x32\x28\x6D\x6F\x29\x5A","\x55\xCB\x37\x74\xD1\x3E\xF2\x01", +"\x01\x01\x01\x01\x01\x01\x01\x01","\x01\x23\x45\x67\x89\xAB\xCD\xEF","\xFA\x34\xEC\x48\x47\xB2\x68\xB2", +"\x1F\x1F\x1F\x1F\x0E\x0E\x0E\x0E","\x01\x23\x45\x67\x89\xAB\xCD\xEF","\xA7\x90\x79\x51\x08\xEA\x3C\xAE", +"\xE0\xFE\xE0\xFE\xF1\xFE\xF1\xFE","\x01\x23\x45\x67\x89\xAB\xCD\xEF","\xC3\x9E\x07\x2D\x9F\xAC\x63\x1D", +"\x00\x00\x00\x00\x00\x00\x00\x00","\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF","\x01\x49\x33\xE0\xCD\xAF\xF6\xE4", +"\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF","\x00\x00\x00\x00\x00\x00\x00\x00","\xF2\x1E\x9A\x77\xB7\x1C\x49\xBC", +"\x01\x23\x45\x67\x89\xAB\xCD\xEF","\x00\x00\x00\x00\x00\x00\x00\x00","\x24\x59\x46\x88\x57\x54\x36\x9A", +"\xFE\xDC\xBA\x98\x76\x54\x32\x10","\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF","\x6B\x5C\x5A\x9C\x5D\x9E\x0A\x5A" +}; + + +#define TRIPLEDES_TEST_COUNT 1 + +typedef struct { + unsigned char key[24]; + unsigned char plaintext[8]; + unsigned char ciphertext[8]; + } TRIPLEDES_TEST; + +TRIPLEDES_TEST tripledes_vectors[TRIPLEDES_TEST_COUNT] = { +0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xfe, 0xdc, 0xba, 0x98, +0x76, 0x54, 0x32, 0x10, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23, 0x45, 0x67, + +0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xe7, + +0xde, 0x0b, 0x7c, 0x06, 0xae, 0x5e, 0x0e, 0xd5 +}; + +/* CAST-128 Test Vectors from RFC2144 (deprecated/legacy) */ + +#define CAST_TEST_COUNT 1 + +typedef struct { + unsigned char key[16]; + unsigned char plaintext[8]; + unsigned char ciphertext[8]; + } CAST_TEST; + + +CAST_TEST cast_ecb_vectors[CAST_TEST_COUNT] = { + "\x01\x23\x45\x67\x12\x34\x56\x78\x23\x45\x67\x89\x34\x56\x78\x9A", + "\x01\x23\x45\x67\x89\xAB\xCD\xEF", + "\x23\x8B\x4F\xE5\x84\x7E\x44\xB2" + }; + +// AES ECB test vectors FIPS-197 + +#define AES_TEST_COUNT 1 + +typedef struct { + unsigned char key[32]; + unsigned char plaintext[16]; + unsigned char ciphertext[16]; + } AES_TEST; + +AES_TEST aes_ecb_vectors[AES_TEST_COUNT] = { +0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, +0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + +0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff, + +0x8e,0xa2,0xb7,0xca,0x51,0x67,0x45,0xbf,0xea,0xfc,0x49,0x90,0x4b,0x49,0x60,0x89 +}; + +// Serpent ECB test vectors + +#define SERPENT_TEST_COUNT 1 + +typedef struct { + unsigned char key[32]; + unsigned char plaintext[16]; + unsigned char ciphertext[16]; + } SERPENT_TEST; + +SERPENT_TEST serpent_vectors[SERPENT_TEST_COUNT] = { +0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + +0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, +0xde, 0x26, 0x9f, 0xf8, 0x33, 0xe4, 0x32, 0xb8, 0x5b, 0x2e, 0x88, 0xd2, 0x70, 0x1c, 0xe7, 0x5c +}; + +// Twofish ECB test vectors + +#define TWOFISH_TEST_COUNT 1 + +typedef struct { + unsigned char key[32]; + unsigned char plaintext[16]; + unsigned char ciphertext[16]; + } TWOFISH_TEST; + +TWOFISH_TEST twofish_vectors[TWOFISH_TEST_COUNT] = { +0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46, 0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D, +0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B, 0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F, + +0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6, +0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97, 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA +}; + +/* Test vectors from FIPS 198a, RFC 4231, RFC 2104, RFC 2202, and other sources. */ + +char *hmac_sha512_test_keys[] = +{ + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "Jefe", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", + "\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa", +}; + +char *hmac_sha512_test_data[] = +{ + "Hi There", + "what do ya want for nothing?", + "\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd\xdd", + "\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd\xcd", + "Test Using Larger Than Block-Size Key - Hash Key First", + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.", +}; + +char *hmac_sha512_test_vectors[] = +{ + "\x87\xaa\x7c\xde\xa5\xef\x61\x9d\x4f\xf0\xb4\x24\x1a\x1d\x6c\xb0\x23\x79\xf4\xe2\xce\x4e\xc2\x78\x7a\xd0\xb3\x05\x45\xe1\x7c\xde\xda\xa8\x33\xb7\xd6\xb8\xa7\x02\x03\x8b\x27\x4e\xae\xa3\xf4\xe4\xbe\x9d\x91\x4e\xeb\x61\xf1\x70\x2e\x69\x6c\x20\x3a\x12\x68\x54", + "\x16\x4b\x7a\x7b\xfc\xf8\x19\xe2\xe3\x95\xfb\xe7\x3b\x56\xe0\xa3\x87\xbd\x64\x22\x2e\x83\x1f\xd6\x10\x27\x0c\xd7\xea\x25\x05\x54\x97\x58\xbf\x75\xc0\x5a\x99\x4a\x6d\x03\x4f\x65\xf8\xf0\xe6\xfd\xca\xea\xb1\xa3\x4d\x4a\x6b\x4b\x63\x6e\x07\x0a\x38\xbc\xe7\x37", + "\xfa\x73\xb0\x08\x9d\x56\xa2\x84\xef\xb0\xf0\x75\x6c\x89\x0b\xe9\xb1\xb5\xdb\xdd\x8e\xe8\x1a\x36\x55\xf8\x3e\x33\xb2\x27\x9d\x39\xbf\x3e\x84\x82\x79\xa7\x22\xc8\x06\xb4\x85\xa4\x7e\x67\xc8\x07\xb9\x46\xa3\x37\xbe\xe8\x94\x26\x74\x27\x88\x59\xe1\x32\x92\xfb", + "\xb0\xba\x46\x56\x37\x45\x8c\x69\x90\xe5\xa8\xc5\xf6\x1d\x4a\xf7\xe5\x76\xd9\x7f\xf9\x4b\x87\x2d\xe7\x6f\x80\x50\x36\x1e\xe3\xdb\xa9\x1c\xa5\xc1\x1a\xa2\x5e\xb4\xd6\x79\x27\x5c\xc5\x78\x80\x63\xa5\xf1\x97\x41\x12\x0c\x4f\x2d\xe2\xad\xeb\xeb\x10\xa2\x98\xdd", + "\x80\xb2\x42\x63\xc7\xc1\xa3\xeb\xb7\x14\x93\xc1\xdd\x7b\xe8\xb4\x9b\x46\xd1\xf4\x1b\x4a\xee\xc1\x12\x1b\x01\x37\x83\xf8\xf3\x52\x6b\x56\xd0\x37\xe0\x5f\x25\x98\xbd\x0f\xd2\x21\x5d\x6a\x1e\x52\x95\xe6\x4f\x73\xf6\x3f\x0a\xec\x8b\x91\x5a\x98\x5d\x78\x65\x98", + "\xe3\x7b\x6a\x77\x5d\xc8\x7d\xba\xa4\xdf\xa9\xf9\x6e\x5e\x3f\xfd\xde\xbd\x71\xf8\x86\x72\x89\x86\x5d\xf5\xa3\x2d\x20\xcd\xc9\x44\xb6\x02\x2c\xac\x3c\x49\x82\xb1\x0d\x5e\xeb\x55\xc3\xe4\xde\x15\x13\x46\x76\xfb\x6d\xe0\x44\x60\x65\xc9\x74\x40\xfa\x8c\x6a\x58", +}; + +char *hmac_sha1_test_keys[] = +{ + // Deprecated/legacy + "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3", + "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b", + "Jefe", + "\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA" +}; + +char *hmac_sha1_test_data[] = +{ + // Deprecated/legacy + "Sample #3", + "Hi There", + "what do ya want for nothing?", + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" + "\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD\xDD" +}; + +char *hmac_sha1_test_vectors[] = +{ + // Deprecated/legacy + "\xbc\xf4\x1e\xab\x8b\xb2\xd8\x02\xf3\xd0\x5c\xaf\x7c\xb0\x92\xec\xf8\xd1\xa3\xaa", + "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00", + "\xef\xfc\xdf\x6a\xe5\xeb\x2f\xa2\xd2\x74\x16\xd5\xf1\x84\xdf\x9c\x25\x9a\x7c\x79", + "\x12\x5d\x73\x42\xb9\xac\x11\xcd\x91\xa3\x9a\xf4\x8a\xa1\x7b\x4f\x63\xf1\x75\xd3" +}; + +char *hmac_ripemd160_test_keys[] = +{ + "\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x01\x23\x45\x67", + "\x01\x23\x45\x67\x89\xab\xcd\xef\xfe\xdc\xba\x98\x76\x54\x32\x10\x00\x11\x22\x33", +}; + +char *hmac_ripemd160_test_data[] = +{ + "message digest", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890", +}; + +char *hmac_ripemd160_test_vectors[] = +{ + "\xf8\x36\x62\xcc\x8d\x33\x9c\x22\x7e\x60\x0f\xcd\x63\x6c\x57\xd2\x57\x1b\x1c\x34", + "\x85\xf1\x64\x70\x3e\x61\xa6\x31\x31\xbe\x7e\x45\x95\x8e\x07\x94\x12\x39\x04\xf9", +}; + +char *hmac_whirlpool_test_key = +{ + "\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" +}; + +char *hmac_whirlpool_test_data = +{ + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" +}; + +char *hmac_whirlpool_test_vectors = +{ + "\x03\x91\xd2\x80\x00\xb6\x62\xbb\xb8\xe6\x23\x3e\xe8\x6c\xf2\xb2\x84\x74\x4c\x73" + "\x8b\x58\x00\xba\x28\x12\xed\x52\x6f\xe3\x15\x3a\xb1\xba\xe7\xe2\x36\xbe\x96\x54" + "\x49\x3f\x19\xfa\xce\xa6\x44\x1f\x60\xf5\xf0\x18\x93\x09\x11\xa5\xe5\xce\xd8\xf2" + "\x6a\xbf\xa4\x02" +}; + +unsigned char ks_tmp[MAX_EXPANDED_KEY]; + +void CipherInit2(int cipher, void* key, void* ks, int key_len) +{ + switch (cipher) + { + case BLOWFISH: + /* Deprecated/legacy */ + BlowfishSetKey (ks, key_len, key); + break; + + case AES: + CipherInit(cipher,key,ks); + break; + + case CAST: + /* Deprecated/legacy */ + CipherInit(cipher,key,ks); + break; + + case SERPENT: + CipherInit(cipher,key,ks); + break; + + case TRIPLEDES: + /* Deprecated/legacy */ + CipherInit(cipher,key,ks); + break; + + case TWOFISH: + CipherInit(cipher,key,ks); + break; + + default: + /* Unknown/wrong ID */ + TC_THROW_FATAL_EXCEPTION; + } +} + + +/* Deprecated/legacy */ +typedef struct { + unsigned __int8 key1[32]; + unsigned __int8 key2[16]; + unsigned __int8 index[16]; + unsigned __int8 plaintext[16]; + unsigned __int8 ciphertext[16]; +} LRW_TEST; + +#define LRW_TEST_COUNT 2 + +/* Deprecated/legacy */ +LRW_TEST lrw_vectors[LRW_TEST_COUNT] = { + { + { 0xf8, 0xd4, 0x76, 0xff, 0xd6, 0x46, 0xee, 0x6c, 0x23, 0x84, 0xcb, 0x1c, 0x77, 0xd6, 0x19, 0x5d, + 0xfe, 0xf1, 0xa9, 0xf3, 0x7b, 0xbc, 0x8d, 0x21, 0xa7, 0x9c, 0x21, 0xf8, 0xcb, 0x90, 0x02, 0x89 }, + { 0xa8, 0x45, 0x34, 0x8e, 0xc8, 0xc5, 0xb5, 0xf1, 0x26, 0xf5, 0x0e, 0x76, 0xfe, 0xfd, 0x1b, 0x1e }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }, + { 0xbd, 0x06, 0xb8, 0xe1, 0xdb, 0x98, 0x89, 0x9e, 0xc4, 0x98, 0xe4, 0x91, 0xcf, 0x1c, 0x70, 0x2b } + }, + { + { 0xfb, 0x76, 0x15, 0xb2, 0x3d, 0x80, 0x89, 0x1d, 0xd4, 0x70, 0x98, 0x0b, 0xc7, 0x95, 0x84, 0xc8, + 0xb2, 0xfb, 0x64, 0xce, 0x60, 0x97, 0x87, 0x8d, 0x17, 0xfc, 0xe4, 0x5a, 0x49, 0xe8, 0x30, 0xb7 }, + { 0x6e, 0x78, 0x17, 0xe7, 0x2d, 0x5e, 0x12, 0xd4, 0x60, 0x64, 0x04, 0x7a, 0xf1, 0x2f, 0x9e, 0x0c }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00 }, + { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }, + { 0x5b, 0x90, 0x8e, 0xc1, 0xab, 0xdd, 0x67, 0x5f, 0x3d, 0x69, 0x8a, 0x95, 0x53, 0xc8, 0x9c, 0xe5 } + } +}; + + +BOOL LRWAesTest (PCRYPTO_INFO ci) +{ + /* Deprecated/legacy */ + + unsigned __int8 p[16]; + int i; + + for (i = 0; i < LRW_TEST_COUNT; i++) + { + ci->ea = EAGetByName ("AES"); + if (ci->ea == 0) + return FALSE; + + ci->mode = LRW; + + if (EAInit (ci->ea, lrw_vectors[i].key1, ci->ks) != ERR_SUCCESS) + return FALSE; + + memcpy (&ci->k2, lrw_vectors[i].key2, sizeof (lrw_vectors[i].key2)); + if (!EAInitMode (ci)) + return FALSE; + + memcpy (p, lrw_vectors[i].plaintext, sizeof (p)); + + EncryptBufferLRW128 (p, sizeof (p), BE64(((unsigned __int64 *)(lrw_vectors[i].index))[1]), ci); + + if (memcmp (lrw_vectors[i].ciphertext, p, sizeof (p)) != 0) + return FALSE; + } + + return TRUE; +} + + +BOOL TestSectorBufEncryption (PCRYPTO_INFO ci) +{ + unsigned char buf [ENCRYPTION_DATA_UNIT_SIZE * 4]; + unsigned int i; + char name[64]; + unsigned __int32 crc; + UINT64_STRUCT unitNo; + uint32 nbrUnits; + unsigned __int64 writeOffset; + int testCase = 0; + int nTestsPerformed = 0; + + static unsigned char key1[] = + { + 0x27, 0x18, 0x28, 0x18, 0x28, 0x45, 0x90, 0x45, 0x23, 0x53, 0x60, 0x28, 0x74, 0x71, 0x35, 0x26, 0x62, 0x49, 0x77, 0x57, 0x24, 0x70, 0x93, 0x69, 0x99, 0x59, 0x57, 0x49, 0x66, 0x96, 0x76, 0x27, + 0x31, 0x41, 0x59, 0x26, 0x53, 0x58, 0x97, 0x93, 0x23, 0x84, 0x62, 0x64, 0x33, 0x83, 0x27, 0x95, 0x02, 0x88, 0x41, 0x97, 0x16, 0x93, 0x99, 0x37, 0x51, 0x05, 0x82, 0x09, 0x74, 0x94, 0x45, 0x92, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13 + }; + + if (!TestLegacySectorBufEncryption (ci)) + return FALSE; + + + /* Encryption/decryption of data units (typically, volume data sectors) */ + + nbrUnits = sizeof (buf) / ENCRYPTION_DATA_UNIT_SIZE; + + ci->mode = XTS; // Other modes of operation are tested in TestLegacySectorBufEncryption() + + /* The buffer can accommodate 4 data units and we'll test 4 cases by "scrolling". The data unit 0xFFFFFFFFFF + will "move" from the start of the buffer to its end. For a 512-byte data unit, the byte offset 562949953420800 + corresponds to the data unit 0xFFFFFFFFFF. */ + for (writeOffset = 562949953420800ULL; + writeOffset > 562949953420800ULL - nbrUnits * ENCRYPTION_DATA_UNIT_SIZE; + writeOffset -= ENCRYPTION_DATA_UNIT_SIZE) + { + unitNo.Value = writeOffset / ENCRYPTION_DATA_UNIT_SIZE; + + // Test all EAs that support this mode of operation + for (ci->ea = EAGetFirst (); ci->ea != 0; ci->ea = EAGetNext (ci->ea)) + { + if (!EAIsModeSupported (ci->ea, ci->mode)) + continue; + + EAGetName (name, ci->ea); + + if (EAInit (ci->ea, key1, ci->ks) != ERR_SUCCESS) + return FALSE; + + for (i = 0; i < sizeof (ci->k2); i++) + ci->k2[i] = (unsigned char) i; + + memcpy (&ci->k2, XTS_vectors[XTS_TEST_COUNT-1].key2, sizeof (XTS_vectors[XTS_TEST_COUNT-1].key2)); + + if (!EAInitMode (ci)) + return FALSE; + + // Each data unit will contain the same plaintext + for (i = 0; i < nbrUnits; i++) + { + memcpy ((unsigned char *) buf + i * ENCRYPTION_DATA_UNIT_SIZE, + XTS_vectors[XTS_TEST_COUNT-1].plaintext, + ENCRYPTION_DATA_UNIT_SIZE); + } + + EncryptDataUnits (buf, &unitNo, nbrUnits, ci); + + crc = GetCrc32 (buf, sizeof (buf)); + + if (strcmp (name, "AES") == 0) + { + // Verify the ciphertext of the "moving" data unit using the IEEE test vector #14 + if (memcmp (XTS_vectors[XTS_TEST_COUNT-1].ciphertext, + (unsigned char *) buf + testCase * ENCRYPTION_DATA_UNIT_SIZE, + ENCRYPTION_DATA_UNIT_SIZE) != 0) + { + return FALSE; + } + + // CRC of all data units in the buffer for each test case + switch (testCase) + { + case 0: + if (crc != 0x888f2990) + return FALSE; + nTestsPerformed++; + break; + case 1: + if (crc != 0xea28ea34) + return FALSE; + nTestsPerformed++; + break; + case 2: + if (crc != 0xe058f5a2) + return FALSE; + nTestsPerformed++; + break; + case 3: + if (crc != 0x10473dc9) + return FALSE; + nTestsPerformed++; + break; + } + } + else if (strcmp (name, "Serpent") == 0) + { + switch (testCase) + { + case 0: + if (crc != 0x7edfecb3) + return FALSE; + nTestsPerformed++; + break; + case 1: + if (crc != 0x357baaaa) + return FALSE; + nTestsPerformed++; + break; + case 2: + if (crc != 0xc7b9fca5) + return FALSE; + nTestsPerformed++; + break; + case 3: + if (crc != 0xb5263e0c) + return FALSE; + nTestsPerformed++; + break; + } + } + else if (strcmp (name, "Twofish") == 0) + { + switch (testCase) + { + case 0: + if (crc != 0x91525124) + return FALSE; + nTestsPerformed++; + break; + case 1: + if (crc != 0x2895cc47) + return FALSE; + nTestsPerformed++; + break; + case 2: + if (crc != 0x6bee346d) + return FALSE; + nTestsPerformed++; + break; + case 3: + if (crc != 0xb1c45759) + return FALSE; + nTestsPerformed++; + break; + } + } + else if (strcmp (name, "AES-Twofish") == 0) + { + switch (testCase) + { + case 0: + if (crc != 0x6cea7fa2) + return FALSE; + nTestsPerformed++; + break; + case 1: + if (crc != 0x69052c4c) + return FALSE; + nTestsPerformed++; + break; + case 2: + if (crc != 0x88db8de5) + return FALSE; + nTestsPerformed++; + break; + case 3: + if (crc != 0xf16fd8c5) + return FALSE; + nTestsPerformed++; + break; + } + } + else if (strcmp (name, "AES-Twofish-Serpent") == 0) + { + switch (testCase) + { + case 0: + if (crc != 0xa2d7d82a) + return FALSE; + nTestsPerformed++; + break; + case 1: + if (crc != 0xdbf76412) + return FALSE; + nTestsPerformed++; + break; + case 2: + if (crc != 0xdf0ea03e) + return FALSE; + nTestsPerformed++; + break; + case 3: + if (crc != 0xdadedff7) + return FALSE; + nTestsPerformed++; + break; + } + } + else if (strcmp (name, "Serpent-AES") == 0) + { + switch (testCase) + { + case 0: + if (crc != 0x6dd133b3) + return FALSE; + nTestsPerformed++; + break; + case 1: + if (crc != 0x0e5717d2) + return FALSE; + nTestsPerformed++; + break; + case 2: + if (crc != 0x39f83cd9) + return FALSE; + nTestsPerformed++; + break; + case 3: + if (crc != 0x8a79fa2c) + return FALSE; + nTestsPerformed++; + break; + } + } + else if (strcmp (name, "Serpent-Twofish-AES") == 0) + { + switch (testCase) + { + case 0: + if (crc != 0xe536daf8) + return FALSE; + nTestsPerformed++; + break; + case 1: + if (crc != 0x3ae89e7f) + return FALSE; + nTestsPerformed++; + break; + case 2: + if (crc != 0x2cc1301a) + return FALSE; + nTestsPerformed++; + break; + case 3: + if (crc != 0xcac7bdc7) + return FALSE; + nTestsPerformed++; + break; + } + } + else if (strcmp (name, "Twofish-Serpent") == 0) + { + switch (testCase) + { + case 0: + if (crc != 0x2686c859) + return FALSE; + nTestsPerformed++; + break; + case 1: + if (crc != 0x8a201780) + return FALSE; + nTestsPerformed++; + break; + case 2: + if (crc != 0x8dd13796) + return FALSE; + nTestsPerformed++; + break; + case 3: + if (crc != 0xe95196cb) + return FALSE; + nTestsPerformed++; + break; + } + } + + if (crc == 0x9f5edd58) + return FALSE; + + DecryptDataUnits (buf, &unitNo, nbrUnits, ci); + + if (GetCrc32 (buf, sizeof (buf)) != 0x9f5edd58) + return FALSE; + + nTestsPerformed++; + } + testCase++; + } + + /* Encryption/decryption of a buffer (typically, a volume header) */ + + nbrUnits = sizeof (buf) / ENCRYPTION_DATA_UNIT_SIZE; + + // Test all EAs that support this mode of operation + for (ci->ea = EAGetFirst (); ci->ea != 0; ci->ea = EAGetNext (ci->ea)) + { + if (!EAIsModeSupported (ci->ea, ci->mode)) + continue; + + EAGetName (name, ci->ea); + + if (EAInit (ci->ea, key1, ci->ks) != ERR_SUCCESS) + return FALSE; + + memcpy (&ci->k2, XTS_vectors[XTS_TEST_COUNT-1].key2, sizeof (XTS_vectors[XTS_TEST_COUNT-1].key2)); + + if (!EAInitMode (ci)) + return FALSE; + + // Each data unit will contain the same plaintext + for (i = 0; i < nbrUnits; i++) + { + memcpy ((unsigned char *) buf + i * ENCRYPTION_DATA_UNIT_SIZE, + XTS_vectors[XTS_TEST_COUNT-1].plaintext, + ENCRYPTION_DATA_UNIT_SIZE); + } + + EncryptBuffer (buf, sizeof (buf), ci); + + crc = GetCrc32 (buf, sizeof (buf)); + + if (strcmp (name, "AES") == 0) + { + if (crc != 0x33b91fab) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent") == 0) + { + if (crc != 0x3494d480) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Twofish") == 0) + { + if (crc != 0xc4d65b46) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Twofish") == 0) + { + if (crc != 0x14ce7385) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Twofish-Serpent") == 0) + { + if (crc != 0x0ec81bf7) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent-AES") == 0) + { + if (crc != 0x42f919ad) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent-Twofish-AES") == 0) + { + if (crc != 0x208d5c58) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Twofish-Serpent") == 0) + { + if (crc != 0xbe78cec1) + return FALSE; + nTestsPerformed++; + } + + if (crc == 0x9f5edd58) + return FALSE; + + DecryptBuffer (buf, sizeof (buf), ci); + + if (GetCrc32 (buf, sizeof (buf)) != 0x9f5edd58) + return FALSE; + + nTestsPerformed++; + } + + return (nTestsPerformed == 80); +} + + +BOOL TestLegacySectorBufEncryption (PCRYPTO_INFO ci) +{ + unsigned char buf [ENCRYPTION_DATA_UNIT_SIZE * 2]; + unsigned int i; + char name[64]; + unsigned __int32 crc; + UINT64_STRUCT unitNo; + uint32 nbrUnits; + int blockSize; + BOOL lrw64InitDone = FALSE; + BOOL lrw128InitDone = FALSE; + int nTestsPerformed = 0; + + unitNo.Value = 0x0234567890ABCDEFull; + nbrUnits = sizeof (buf) / ENCRYPTION_DATA_UNIT_SIZE; + + for (i = 0; i < sizeof (buf); i++) + buf[i] = (unsigned char) i; + + for (i = 0; i < sizeof (ci->k2); i++) + ci->k2[i] = (unsigned char) i; + + // Test all EAs + for (ci->ea = EAGetFirst (); ci->ea != 0; ci->ea = EAGetNext (ci->ea)) + { + EAGetName (name, ci->ea); + blockSize = CipherGetBlockSize (EAGetFirstCipher (ci->ea)); + + if (EAInit (ci->ea, (unsigned char *)buf, ci->ks) == ERR_CIPHER_INIT_FAILURE) + return FALSE; + + // Test all deprecated modes of operation + for (ci->mode = EAGetFirstMode (ci->ea); + ci->mode != 0; + ci->mode = EAGetNextMode (ci->ea, ci->mode)) + { + // Skip modes that are not deprecated + if (ci->mode == XTS) + continue; + + if (ci->mode == LRW + && (blockSize == 8 && !lrw64InitDone || blockSize == 16 && !lrw128InitDone )) + { + if (!EAInitMode (ci)) + return FALSE; + + if (blockSize == 8) + lrw64InitDone = TRUE; + else if (blockSize == 16) + lrw128InitDone = TRUE; + } + + EncryptDataUnits (buf, &unitNo, nbrUnits, ci); + crc = GetCrc32 (buf, sizeof (buf)); + + switch (ci->mode) + { + case LRW: // Deprecated/legacy + if (strcmp (name, "AES") == 0) + { + if (crc != 0x5237acf9) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Blowfish") == 0) // Deprecated/legacy + { + if (crc != 0xf94d5300) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "CAST5") == 0) // Deprecated/legacy + { + if (crc != 0x33971e82) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent") == 0) + { + if (crc != 0x7fb86805) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Triple DES") == 0) // Deprecated/legacy + { + if (crc != 0x2b20bb84) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Twofish") == 0) + { + if (crc != 0xa9de0f0b) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Twofish") == 0) + { + if (crc != 0x4ed0fd80) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Twofish-Serpent") == 0) + { + if (crc != 0xea04b3cf) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent-AES") == 0) + { + if (crc != 0x0d33596a) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent-Twofish-AES") == 0) + { + if (crc != 0x2845d0e3) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Twofish-Serpent") == 0) + { + if (crc != 0xca65c5cd) + return FALSE; + nTestsPerformed++; + } + break; + + case CBC: // Deprecated/legacy + case INNER_CBC: // Deprecated/legacy + case OUTER_CBC: // Deprecated/legacy + if (strcmp (name, "AES") == 0) + { + if (crc != 0x2274f53d) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Blowfish") == 0) // Deprecated/legacy + { + if (crc != 0x033899a1) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "CAST5") == 0) // Deprecated/legacy + { + if (crc != 0x331cecc7) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent") == 0) + { + if (crc != 0x42dff3d4) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Triple DES") == 0) // Deprecated/legacy + { + if (crc != 0xfe497d0c) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Blowfish") == 0) // Deprecated/legacy + { + if (crc != 0xa7a80c84) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Blowfish-Serpent") == 0) // Deprecated/legacy + { + if (crc != 0xa0584562) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Twofish") == 0) + { + if (crc != 0x3c226444) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Twofish-Serpent") == 0) + { + if (crc != 0x5e5e77fd) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent-AES") == 0) + { + if (crc != 0x57c612d5) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent-Twofish-AES") == 0) + { + if (crc != 0x081e045a) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Twofish-Serpent") == 0) + { + if (crc != 0xa7b659f3) + return FALSE; + nTestsPerformed++; + } + break; + } + + if (crc == 0xb70b4c26) + return FALSE; + + DecryptDataUnits (buf, &unitNo, nbrUnits, ci); + + if (GetCrc32 (buf, sizeof (buf)) != 0xb70b4c26) + return FALSE; + + nTestsPerformed++; + + EncryptBuffer (buf, sizeof (buf), ci); + crc = GetCrc32 (buf, sizeof (buf)); + + switch (ci->mode) + { + case LRW: // Deprecated/legacy + if (strcmp (name, "AES") == 0) + { + if (crc != 0x5ae1e3d8) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Blowfish") == 0) // Deprecated/legacy + { + if (crc != 0x2738426f) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Twofish-Serpent") == 0) + { + if (crc != 0x14f2948a) + return FALSE; + nTestsPerformed++; + } + break; + + case CBC: // Deprecated/legacy + case INNER_CBC: // Deprecated/legacy + case OUTER_CBC: // Deprecated/legacy + if (strcmp (name, "AES") == 0) + { + if (crc != 0x960f740e) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Blowfish") == 0) // Deprecated/legacy + { + if (crc != 0x7e1cfabb) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "CAST5") == 0) // Deprecated/legacy + { + if (crc != 0xeaae21c8) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent") == 0) + { + if (crc != 0xa8139d62) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Triple DES") == 0) // Deprecated/legacy + { + if (crc != 0xecf5d7d0) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Blowfish") == 0) // Deprecated/legacy + { + if (crc != 0xb70171b6) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Blowfish-Serpent") == 0) // Deprecated/legacy + { + if (crc != 0x1e749a87) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Twofish") == 0) + { + if (crc != 0xb4b8bb9b) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "AES-Twofish-Serpent") == 0) + { + if (crc != 0x76b6c1cb) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent-AES") == 0) + { + if (crc != 0x634f12ed) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Serpent-Twofish-AES") == 0) + { + if (crc != 0xe54bc1b9) + return FALSE; + nTestsPerformed++; + } + else if (strcmp (name, "Twofish-Serpent") == 0) + { + if (crc != 0x21cdb382) + return FALSE; + nTestsPerformed++; + } + break; + } + + if (crc == 0xb70b4c26) + return FALSE; + + DecryptBuffer (buf, sizeof (buf), ci); + + if (GetCrc32 (buf, sizeof (buf)) != 0xb70b4c26) + return FALSE; + + nTestsPerformed++; + } + } + return (nTestsPerformed == 86); +} + + +static BOOL DoAutoTestAlgorithms (void) +{ + PCRYPTO_INFO ci; + char key[32]; + unsigned char tmp[16]; + BOOL bFailed = FALSE; + int i; + + ci = crypto_open (); + if (!ci) + return FALSE; + + memset (ci, 0, sizeof (*ci)); + + /* Blowfish (deprecated/legacy) */ + + for (i=0;i<BF_TEST_COUNT;i++) + { + memcpy(key, bf_ecb_vectors[i].key, 8); + memcpy(tmp, bf_ecb_vectors[i].plaintext, 8); + CipherInit2(BLOWFISH, key, ks_tmp, 8); + + ((uint32 *)tmp)[0] = BE32 (((uint32 *)tmp)[0]); + ((uint32 *)tmp)[1] = BE32 (((uint32 *)tmp)[1]); + + BlowfishEncryptLE (tmp,tmp,(BF_KEY *)ks_tmp,1); + BlowfishEncryptLE (tmp,tmp,(BF_KEY *)ks_tmp,0); + BlowfishEncryptLE (tmp,tmp,(BF_KEY *)ks_tmp,1); + + ((uint32 *)tmp)[0] = BE32 (((uint32 *)tmp)[0]); + ((uint32 *)tmp)[1] = BE32 (((uint32 *)tmp)[1]); + + if (memcmp(bf_ecb_vectors[i].ciphertext,tmp,8)!=0) + break; + } + + if (i != BF_TEST_COUNT) + bFailed = TRUE; + + /* CAST5 (deprecated/legacy) */ + + for (i=0;i<CAST_TEST_COUNT;i++) + { + int cipher = CAST; + memcpy(key, cast_ecb_vectors[i].key, 16); + memcpy(tmp, cast_ecb_vectors[i].plaintext, 8); + CipherInit2(cipher, key, ks_tmp, 16); + + EncipherBlock(cipher, tmp, ks_tmp); + DecipherBlock(cipher, tmp, ks_tmp); + EncipherBlock(cipher, tmp, ks_tmp); + + if (memcmp(cast_ecb_vectors[i].ciphertext, tmp,8)!=0) + break; + } + + if (i!=CAST_TEST_COUNT) + bFailed = TRUE; + + + /* Triple DES (TECB, EDE) - deprecated/legacy */ + + for (i = 0; i < TRIPLEDES_TEST_COUNT; i++) + { + int cipher = TRIPLEDES; + memcpy(key, tripledes_vectors[i].key, sizeof(tripledes_vectors->key)); + memcpy(tmp, tripledes_vectors[i].plaintext, sizeof(tripledes_vectors->plaintext)); + + CipherInit(cipher, key, ks_tmp); + + EncipherBlock(cipher, tmp, ks_tmp); + if (memcmp(tripledes_vectors[i].ciphertext, tmp, sizeof(tripledes_vectors->ciphertext)) != 0) + break; + + DecipherBlock(cipher, tmp, ks_tmp); + if (memcmp(tripledes_vectors[i].plaintext, tmp, sizeof(tripledes_vectors->plaintext)) != 0) + break; + } + if (i != TRIPLEDES_TEST_COUNT) + bFailed = TRUE; + + + /* AES */ + + for (i = 0; i < AES_TEST_COUNT; i++) + { + int cipher = AES; + memcpy(key, aes_ecb_vectors[i].key, 32); + memcpy(tmp, aes_ecb_vectors[i].plaintext, 16); + CipherInit(cipher, key, ks_tmp); + + EncipherBlock(cipher, tmp, ks_tmp); + if (memcmp(aes_ecb_vectors[i].ciphertext, tmp, 16) != 0) + break; + + DecipherBlock(cipher, tmp, ks_tmp); + if (memcmp(aes_ecb_vectors[i].plaintext, tmp, 16) != 0) + break; + } + if (i != AES_TEST_COUNT) + bFailed = TRUE; + + // AES EncipherBlocks()/DecipherBlocks() + { + byte testData[1024]; + uint32 origCrc; + size_t i; + + for (i = 0; i < sizeof (testData); ++i) + { + testData[i] = (byte) i; + } + + origCrc = GetCrc32 (testData, sizeof (testData)); + + CipherInit (AES, testData, ks_tmp); + EncipherBlocks (AES, testData, ks_tmp, sizeof (testData) / CipherGetBlockSize (AES)); + + if (GetCrc32 (testData, sizeof (testData)) != 0xb5cd5631) + bFailed = TRUE; + + DecipherBlocks (AES, testData, ks_tmp, sizeof (testData) / CipherGetBlockSize (AES)); + + if (origCrc != GetCrc32 (testData, sizeof (testData))) + bFailed = TRUE; + } + + /* Serpent */ + + for (i = 0; i < SERPENT_TEST_COUNT; i++) + { + int cipher = SERPENT; + memcpy(key, serpent_vectors[i].key, 32); + memcpy(tmp, serpent_vectors[i].plaintext, 16); + CipherInit(cipher, key, ks_tmp); + + EncipherBlock(cipher, tmp, ks_tmp); + if (memcmp(serpent_vectors[i].ciphertext, tmp, 16) != 0) + break; + + DecipherBlock(cipher, tmp, ks_tmp); + if (memcmp(serpent_vectors[i].plaintext, tmp, 16) != 0) + break; + } + if (i != SERPENT_TEST_COUNT) + bFailed = TRUE; + + + /* Twofish */ + + for (i = 0; i < TWOFISH_TEST_COUNT; i++) + { + int cipher = TWOFISH; + memcpy(key, twofish_vectors[i].key, 32); + memcpy(tmp, twofish_vectors[i].plaintext, 16); + CipherInit(cipher, key, ks_tmp); + + EncipherBlock(cipher, tmp, ks_tmp); + if (memcmp(twofish_vectors[i].ciphertext, tmp, 16) != 0) + break; + + DecipherBlock(cipher, tmp, ks_tmp); + if (memcmp(twofish_vectors[i].plaintext, tmp, 16) != 0) + break; + } + if (i != TWOFISH_TEST_COUNT) + bFailed = TRUE; + + + /* PKCS #5 and HMACs */ + if (!test_pkcs5 ()) + bFailed = TRUE; + + /* CRC-32 */ + if (!crc32_selftests ()) + bFailed = TRUE; + + /* GF multiplicator */ +#if 0 + if (!GfMulSelfTest ()) + bFailed = TRUE; +#endif + + /* XTS-AES */ + if (!XTSAesTest (ci)) + bFailed = TRUE; + + /* LRW-AES (deprecated/legacy) */ + if (!LRWAesTest (ci)) + bFailed = TRUE; + + /* Sector and buffer related algorithms */ + if (!TestSectorBufEncryption (ci)) + bFailed = TRUE; + + crypto_close (ci); + return !bFailed; +} + + +BOOL AutoTestAlgorithms (void) +{ + BOOL result = TRUE; + BOOL hwEncryptionEnabled = IsHwEncryptionEnabled(); + + EnableHwEncryption (FALSE); + + if (!DoAutoTestAlgorithms()) + result = FALSE; + + EnableHwEncryption (TRUE); + + if (!DoAutoTestAlgorithms()) + result = FALSE; + + EnableHwEncryption (hwEncryptionEnabled); + return result; +} + + +BOOL test_hmac_sha512 () +{ + unsigned int i; + int nTestsPerformed = 0; + + for (i = 0; i < sizeof (hmac_sha512_test_data) / sizeof(char *); i++) + { + char digest[SHA512_DIGESTSIZE]; + hmac_sha512 (hmac_sha512_test_keys[i], (int) strlen (hmac_sha512_test_keys[i]), hmac_sha512_test_data[i], (int) strlen (hmac_sha512_test_data[i]), digest, SHA512_DIGESTSIZE); + if (memcmp (digest, hmac_sha512_test_vectors[i], SHA512_DIGESTSIZE) != 0) + return FALSE; + else + nTestsPerformed++; + } + + return (nTestsPerformed == 6); +} + +BOOL test_hmac_sha1 () +{ + // Deprecated/legacy + + int nTestsPerformed = 0; + int i; + + for (i = 0; i < 3; i++) + { + char digest[SHA1_DIGESTSIZE]; + hmac_sha1 (hmac_sha1_test_keys[i], (int) strlen (hmac_sha1_test_keys[i]), hmac_sha1_test_data[i], (int) strlen (hmac_sha1_test_data[i]), digest, SHA1_DIGESTSIZE); + if (memcmp (digest, hmac_sha1_test_vectors[i], SHA1_DIGESTSIZE) != 0) + return FALSE; + else + nTestsPerformed++; + } + + return (nTestsPerformed == 3); +} + +BOOL test_hmac_ripemd160 () +{ + int nTestsPerformed = 0; + unsigned int i; + + for (i = 0; i < sizeof (hmac_ripemd160_test_data) / sizeof(char *); i++) + { + char digest[RIPEMD160_DIGESTSIZE]; + hmac_ripemd160 (hmac_ripemd160_test_keys[i], RIPEMD160_DIGESTSIZE, hmac_ripemd160_test_data[i], (int) strlen (hmac_ripemd160_test_data[i]), digest); + if (memcmp (digest, hmac_ripemd160_test_vectors[i], RIPEMD160_DIGESTSIZE) != 0) + return FALSE; + else + nTestsPerformed++; + } + + return (nTestsPerformed == 2); +} + +BOOL test_hmac_whirlpool () +{ + unsigned char digest[WHIRLPOOL_DIGESTSIZE]; + + hmac_whirlpool (hmac_whirlpool_test_key, 64, hmac_whirlpool_test_data, (int) strlen (hmac_whirlpool_test_data), digest, WHIRLPOOL_DIGESTSIZE); + if (memcmp (digest, hmac_whirlpool_test_vectors, WHIRLPOOL_DIGESTSIZE) != 0) + return FALSE; + + return TRUE; +} + +BOOL test_pkcs5 () +{ + char dk[144]; + + /* HMAC-SHA-512 tests */ + if (!test_hmac_sha512()) + return FALSE; + + /* HMAC-SHA-1 tests (deprecated/legacy) */ + if (test_hmac_sha1() == FALSE) + return FALSE; + + /* HMAC-RIPEMD-160 tests */ + if (test_hmac_ripemd160() == FALSE) + return FALSE; + + /* HMAC-Whirlpool tests */ + if (test_hmac_whirlpool() == FALSE) + return FALSE; + + /* PKCS-5 test 1 with HMAC-SHA-512 used as the PRF */ + derive_key_sha512 ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 4); + if (memcmp (dk, "\x13\x64\xae\xf8", 4) != 0) + return FALSE; + + /* PKCS-5 test 2 with HMAC-SHA-512 used as the PRF (derives a key longer than the underlying + hash output size and block size) */ + derive_key_sha512 ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 144); + if (memcmp (dk, "\x13\x64\xae\xf8\x0d\xf5\x57\x6c\x30\xd5\x71\x4c\xa7\x75\x3f\xfd\x00\xe5\x25\x8b\x39\xc7\x44\x7f\xce\x23\x3d\x08\x75\xe0\x2f\x48\xd6\x30\xd7\x00\xb6\x24\xdb\xe0\x5a\xd7\x47\xef\x52\xca\xa6\x34\x83\x47\xe5\xcb\xe9\x87\xf1\x20\x59\x6a\xe6\xa9\xcf\x51\x78\xc6\xb6\x23\xa6\x74\x0d\xe8\x91\xbe\x1a\xd0\x28\xcc\xce\x16\x98\x9a\xbe\xfb\xdc\x78\xc9\xe1\x7d\x72\x67\xce\xe1\x61\x56\x5f\x96\x68\xe6\xe1\xdd\xf4\xbf\x1b\x80\xe0\x19\x1c\xf4\xc4\xd3\xdd\xd5\xd5\x57\x2d\x83\xc7\xa3\x37\x87\xf4\x4e\xe0\xf6\xd8\x6d\x65\xdc\xa0\x52\xa3\x13\xbe\x81\xfc\x30\xbe\x7d\x69\x58\x34\xb6\xdd\x41\xc6", 144) != 0) + return FALSE; + + /* PKCS-5 test 1 with HMAC-SHA-1 (deprecated/legacy) used as the PRF (derives a key longer than the underlying hash) */ + derive_key_sha1 ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 48); + if (memcmp (dk, "\x5c\x75\xce\xf0\x1a\x96\x0d\xf7\x4c\xb6\xb4\x9b\x9e\x38\xe6\xb5\x3b\x11\x80\xe3\x2f\xf7\xe0\xdd\xaa\xca\x8f\x81\x27\xf6\x9f\x4f\x1d\xc8\x2f\x48\x2d\xdb\x1a\x0a\xca\x90\xcb\x80\xb9\x2e\x90\x9e", 48) != 0) + return FALSE; + + /* PKCS-5 test 2 with HMAC-SHA-1 (deprecated/legacy) used as the PRF */ + derive_key_sha1 ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 4); + if (memcmp (dk, "\x5c\x75\xce\xf0", 4) != 0) + return FALSE; + +#if 0 // This test is disabled because it uses 1200 iterations (to prevent startup slowdown) + /* PKCS-5 test 3 with HMAC-SHA-1 (deprecated/legacy) used as the PRF */ + derive_key_sha1 ("password", 8, "ATHENA.MIT.EDUraeburn", 21, 1200, dk, 16); + if (memcmp (dk, "\x5c\x08\xeb\x61\xfd\xf7\x1e\x4e\x4e\xc3\xcf\x6b\xa1\xf5\x51\x2b", 16) != 0) + return FALSE; +#endif + + /* PKCS-5 test 1 with HMAC-RIPEMD-160 used as the PRF */ + derive_key_ripemd160 ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 4); + if (memcmp (dk, "\x7a\x3d\x7c\x03", 4) != 0) + return FALSE; + + /* PKCS-5 test 2 with HMAC-RIPEMD-160 used as the PRF (derives a key longer than the underlying hash) */ + derive_key_ripemd160 ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 48); + if (memcmp (dk, "\x7a\x3d\x7c\x03\xe7\x26\x6b\xf8\x3d\x78\xfb\x29\xd2\x64\x1f\x56\xea\xf0\xe5\xf5\xcc\xc4\x3a\x31\xa8\x84\x70\xbf\xbd\x6f\x8e\x78\x24\x5a\xc0\x0a\xf6\xfa\xf0\xf6\xe9\x00\x47\x5f\x73\xce\xe1\x43", 48) != 0) + return FALSE; + + /* PKCS-5 test 1 with HMAC-Whirlpool used as the PRF */ + derive_key_whirlpool ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 4); + if (memcmp (dk, "\x50\x7c\x36\x6f", 4) != 0) + return FALSE; + + /* PKCS-5 test 2 with HMAC-Whirlpool used as the PRF (derives a key longer than the underlying hash) */ + derive_key_whirlpool ("password", 8, "\x12\x34\x56\x78", 4, 5, dk, 96); + if (memcmp (dk, "\x50\x7c\x36\x6f\xee\x10\x2e\x9a\xe2\x8a\xd5\x82\x72\x7d\x27\x0f\xe8\x4d\x7f\x68\x7a\xcf\xb5\xe7\x43\x67\xaa\x98\x93\x52\x2b\x09\x6e\x42\xdf\x2c\x59\x4a\x91\x6d\x7e\x10\xae\xb2\x1a\x89\x8f\xb9\x8f\xe6\x31\xa9\xd8\x9f\x98\x26\xf4\xda\xcd\x7d\x65\x65\xde\x10\x95\x91\xb4\x84\x26\xae\x43\xa1\x00\x5b\x1e\xb8\x38\x97\xa4\x1e\x4b\xd2\x65\x64\xbc\xfa\x1f\x35\x85\xdb\x4f\x97\x65\x6f\xbd\x24", 96) != 0) + return FALSE; + + return TRUE; +} diff --git a/Common/Tests.h b/Common/Tests.h new file mode 100644 index 0000000..271159a --- /dev/null +++ b/Common/Tests.h @@ -0,0 +1,30 @@ +/* + 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 + +extern unsigned char ks_tmp[MAX_EXPANDED_KEY]; + +void CipherInit2(int cipher, void* key, void* ks, int key_len); +BOOL test_hmac_sha512 (void); +BOOL test_hmac_sha1 (void); +BOOL test_hmac_ripemd160 (void); +BOOL test_hmac_whirlpool (void); +BOOL test_pkcs5 (void); +BOOL TestSectorBufEncryption (); +BOOL TestLegacySectorBufEncryption (); +BOOL AutoTestAlgorithms (void); + +#ifdef __cplusplus +} +#endif diff --git a/Common/Textual_logo_288dpi.bmp b/Common/Textual_logo_288dpi.bmp Binary files differnew file mode 100644 index 0000000..f4a0518 --- /dev/null +++ b/Common/Textual_logo_288dpi.bmp diff --git a/Common/Textual_logo_96dpi.bmp b/Common/Textual_logo_96dpi.bmp Binary files differnew file mode 100644 index 0000000..51c61a6 --- /dev/null +++ b/Common/Textual_logo_96dpi.bmp diff --git a/Common/Textual_logo_background.bmp b/Common/Textual_logo_background.bmp Binary files differnew file mode 100644 index 0000000..458dac5 --- /dev/null +++ b/Common/Textual_logo_background.bmp diff --git a/Common/TrueCrypt.ico b/Common/TrueCrypt.ico Binary files differnew file mode 100644 index 0000000..5c04a5a --- /dev/null +++ b/Common/TrueCrypt.ico diff --git a/Common/TrueCrypt_Volume.ico b/Common/TrueCrypt_Volume.ico Binary files differnew file mode 100644 index 0000000..df08248 --- /dev/null +++ b/Common/TrueCrypt_Volume.ico diff --git a/Common/TrueCrypt_mounted.ico b/Common/TrueCrypt_mounted.ico Binary files differnew file mode 100644 index 0000000..50c215e --- /dev/null +++ b/Common/TrueCrypt_mounted.ico diff --git a/Common/Volumes.c b/Common/Volumes.c new file mode 100644 index 0000000..f9b2642 --- /dev/null +++ b/Common/Volumes.c @@ -0,0 +1,1198 @@ +/* + 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" + +#ifndef TC_WINDOWS_BOOT +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include "EncryptionThreadPool.h" +#endif + +#include <stddef.h> +#include <string.h> +#include <io.h> + +#ifndef DEVICE_DRIVER +#include "Random.h" +#endif + +#include "Crc.h" +#include "Crypto.h" +#include "Endian.h" +#include "Volumes.h" +#include "Pkcs5.h" + + +/* Volume header v5 structure (used since TrueCrypt 7.0): */ +// +// Offset Length Description +// ------------------------------------------ +// Unencrypted: +// 0 64 Salt +// Encrypted: +// 64 4 ASCII string 'TRUE' +// 68 2 Header version +// 70 2 Required program version +// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 +// 76 16 Reserved (must contain zeroes) +// 92 8 Size of hidden volume in bytes (0 = normal volume) +// 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes, valid if field 70 >= 0x600 or flag bit 0 == 1) +// 108 8 Byte offset of the start of the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) +// 116 8 Size of the encrypted area within the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) +// 124 4 Flags: bit 0 set = system encryption; bit 1 set = non-system in-place encryption, bits 2-31 are reserved (set to zero) +// 128 4 Sector size in bytes +// 132 120 Reserved (must contain zeroes) +// 252 4 CRC-32 checksum of the (decrypted) bytes 64-251 +// 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode) + + +/* Deprecated/legacy volume header v4 structure (used by TrueCrypt 6.x): */ +// +// Offset Length Description +// ------------------------------------------ +// Unencrypted: +// 0 64 Salt +// Encrypted: +// 64 4 ASCII string 'TRUE' +// 68 2 Header version +// 70 2 Required program version +// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 +// 76 16 Reserved (must contain zeroes) +// 92 8 Size of hidden volume in bytes (0 = normal volume) +// 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes, valid if field 70 >= 0x600 or flag bit 0 == 1) +// 108 8 Byte offset of the start of the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) +// 116 8 Size of the encrypted area within the master key scope (valid if field 70 >= 0x600 or flag bit 0 == 1) +// 124 4 Flags: bit 0 set = system encryption; bit 1 set = non-system in-place encryption, bits 2-31 are reserved +// 128 124 Reserved (must contain zeroes) +// 252 4 CRC-32 checksum of the (decrypted) bytes 64-251 +// 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode) + + +/* Deprecated/legacy volume header v3 structure (used by TrueCrypt 5.x): */ +// +// Offset Length Description +// ------------------------------------------ +// Unencrypted: +// 0 64 Salt +// Encrypted: +// 64 4 ASCII string 'TRUE' +// 68 2 Header version +// 70 2 Required program version +// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 +// 76 8 Volume creation time +// 84 8 Header creation time +// 92 8 Size of hidden volume in bytes (0 = normal volume) +// 100 8 Size of the volume in bytes (identical with field 92 for hidden volumes) +// 108 8 Start byte offset of the encrypted area of the volume +// 116 8 Size of the encrypted area of the volume in bytes +// 124 132 Reserved (must contain zeroes) +// 256 256 Concatenated primary master key(s) and secondary master key(s) (XTS mode) + + +/* Deprecated/legacy volume header v2 structure (used before TrueCrypt 5.0): */ +// +// Offset Length Description +// ------------------------------------------ +// Unencrypted: +// 0 64 Salt +// Encrypted: +// 64 4 ASCII string 'TRUE' +// 68 2 Header version +// 70 2 Required program version +// 72 4 CRC-32 checksum of the (decrypted) bytes 256-511 +// 76 8 Volume creation time +// 84 8 Header creation time +// 92 8 Size of hidden volume in bytes (0 = normal volume) +// 100 156 Reserved (must contain zeroes) +// 256 32 For LRW (deprecated/legacy), secondary key +// For CBC (deprecated/legacy), data used to generate IV and whitening values +// 288 224 Master key(s) + + + +uint16 GetHeaderField16 (byte *header, int offset) +{ + return BE16 (*(uint16 *) (header + offset)); +} + + +uint32 GetHeaderField32 (byte *header, int offset) +{ + return BE32 (*(uint32 *) (header + offset)); +} + + +UINT64_STRUCT GetHeaderField64 (byte *header, int offset) +{ + UINT64_STRUCT uint64Struct; + +#ifndef TC_NO_COMPILER_INT64 + uint64Struct.Value = BE64 (*(uint64 *) (header + offset)); +#else + uint64Struct.HighPart = BE32 (*(uint32 *) (header + offset)); + uint64Struct.LowPart = BE32 (*(uint32 *) (header + offset + 4)); +#endif + return uint64Struct; +} + + +#ifndef TC_WINDOWS_BOOT + +typedef struct +{ + char DerivedKey[MASTER_KEYDATA_SIZE]; + BOOL Free; + LONG KeyReady; + int Pkcs5Prf; +} KeyDerivationWorkItem; + + +BOOL ReadVolumeHeaderRecoveryMode = FALSE; + +int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo) +{ + char header[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; + KEY_INFO keyInfo; + PCRYPTO_INFO cryptoInfo; + char dk[MASTER_KEYDATA_SIZE]; + int enqPkcs5Prf, pkcs5_prf; + uint16 headerVersion; + int status = ERR_PARAMETER_INCORRECT; + int primaryKeyOffset; + + TC_EVENT keyDerivationCompletedEvent; + TC_EVENT noOutstandingWorkItemEvent; + KeyDerivationWorkItem *keyDerivationWorkItems; + KeyDerivationWorkItem *item; + int pkcs5PrfCount = LAST_PRF_ID - FIRST_PRF_ID + 1; + size_t encryptionThreadCount = GetEncryptionThreadCount(); + size_t queuedWorkItems = 0; + LONG outstandingWorkItemCount = 0; + int i; + + if (retHeaderCryptoInfo != NULL) + { + cryptoInfo = retHeaderCryptoInfo; + } + else + { + cryptoInfo = *retInfo = crypto_open (); + if (cryptoInfo == NULL) + return ERR_OUTOFMEMORY; + } + + if (encryptionThreadCount > 1) + { + keyDerivationWorkItems = TCalloc (sizeof (KeyDerivationWorkItem) * pkcs5PrfCount); + if (!keyDerivationWorkItems) + return ERR_OUTOFMEMORY; + + for (i = 0; i < pkcs5PrfCount; ++i) + keyDerivationWorkItems[i].Free = TRUE; + +#ifdef DEVICE_DRIVER + KeInitializeEvent (&keyDerivationCompletedEvent, SynchronizationEvent, FALSE); + KeInitializeEvent (&noOutstandingWorkItemEvent, SynchronizationEvent, TRUE); +#else + keyDerivationCompletedEvent = CreateEvent (NULL, FALSE, FALSE, NULL); + if (!keyDerivationCompletedEvent) + { + TCfree (keyDerivationWorkItems); + return ERR_OUTOFMEMORY; + } + + noOutstandingWorkItemEvent = CreateEvent (NULL, FALSE, TRUE, NULL); + if (!noOutstandingWorkItemEvent) + { + CloseHandle (keyDerivationCompletedEvent); + TCfree (keyDerivationWorkItems); + return ERR_OUTOFMEMORY; + } +#endif + } + +#ifndef DEVICE_DRIVER + VirtualLock (&keyInfo, sizeof (keyInfo)); + VirtualLock (&dk, sizeof (dk)); +#endif + + crypto_loadkey (&keyInfo, password->Text, (int) password->Length); + + // PKCS5 is used to derive the primary header key(s) and secondary header key(s) (XTS mode) from the password + memcpy (keyInfo.salt, encryptedHeader + HEADER_SALT_OFFSET, PKCS5_SALT_SIZE); + + // Test all available PKCS5 PRFs + for (enqPkcs5Prf = FIRST_PRF_ID; enqPkcs5Prf <= LAST_PRF_ID || queuedWorkItems > 0; ++enqPkcs5Prf) + { + BOOL lrw64InitDone = FALSE; // Deprecated/legacy + BOOL lrw128InitDone = FALSE; // Deprecated/legacy + + if (encryptionThreadCount > 1) + { + // Enqueue key derivation on thread pool + if (queuedWorkItems < encryptionThreadCount && enqPkcs5Prf <= LAST_PRF_ID) + { + for (i = 0; i < pkcs5PrfCount; ++i) + { + item = &keyDerivationWorkItems[i]; + if (item->Free) + { + item->Free = FALSE; + item->KeyReady = FALSE; + item->Pkcs5Prf = enqPkcs5Prf; + + EncryptionThreadPoolBeginKeyDerivation (&keyDerivationCompletedEvent, &noOutstandingWorkItemEvent, + &item->KeyReady, &outstandingWorkItemCount, enqPkcs5Prf, keyInfo.userKey, + keyInfo.keyLength, keyInfo.salt, get_pkcs5_iteration_count (enqPkcs5Prf, bBoot), item->DerivedKey); + + ++queuedWorkItems; + break; + } + } + + if (enqPkcs5Prf < LAST_PRF_ID) + continue; + } + else + --enqPkcs5Prf; + + // Wait for completion of a key derivation + while (queuedWorkItems > 0) + { + for (i = 0; i < pkcs5PrfCount; ++i) + { + item = &keyDerivationWorkItems[i]; + if (!item->Free && InterlockedExchangeAdd (&item->KeyReady, 0) == TRUE) + { + pkcs5_prf = item->Pkcs5Prf; + keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, bBoot); + memcpy (dk, item->DerivedKey, sizeof (dk)); + + item->Free = TRUE; + --queuedWorkItems; + goto KeyReady; + } + } + + if (queuedWorkItems > 0) + TC_WAIT_EVENT (keyDerivationCompletedEvent); + } + continue; +KeyReady: ; + } + else + { + pkcs5_prf = enqPkcs5Prf; + keyInfo.noIterations = get_pkcs5_iteration_count (enqPkcs5Prf, bBoot); + + switch (pkcs5_prf) + { + case RIPEMD160: + derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case SHA512: + derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case SHA1: + // Deprecated/legacy + derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case WHIRLPOOL: + derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } + } + + // Test all available modes of operation + for (cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID; + cryptoInfo->mode <= LAST_MODE_OF_OPERATION; + cryptoInfo->mode++) + { + switch (cryptoInfo->mode) + { + case LRW: + case CBC: + case INNER_CBC: + case OUTER_CBC: + + // For LRW (deprecated/legacy), copy the tweak key + // For CBC (deprecated/legacy), copy the IV/whitening seed + memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE); + primaryKeyOffset = LEGACY_VOL_IV_SIZE; + break; + + default: + primaryKeyOffset = 0; + } + + // Test all available encryption algorithms + for (cryptoInfo->ea = EAGetFirst (); + cryptoInfo->ea != 0; + cryptoInfo->ea = EAGetNext (cryptoInfo->ea)) + { + int blockSize; + + if (!EAIsModeSupported (cryptoInfo->ea, cryptoInfo->mode)) + continue; // This encryption algorithm has never been available with this mode of operation + + blockSize = CipherGetBlockSize (EAGetFirstCipher (cryptoInfo->ea)); + + status = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; + + // Init objects related to the mode of operation + + if (cryptoInfo->mode == XTS) + { + // Copy the secondary key (if cascade, multiple concatenated) + memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); + + // Secondary key schedule + if (!EAInitMode (cryptoInfo)) + { + status = ERR_MODE_INIT_FAILED; + goto err; + } + } + else if (cryptoInfo->mode == LRW + && (blockSize == 8 && !lrw64InitDone || blockSize == 16 && !lrw128InitDone)) + { + // Deprecated/legacy + + if (!EAInitMode (cryptoInfo)) + { + status = ERR_MODE_INIT_FAILED; + goto err; + } + + if (blockSize == 8) + lrw64InitDone = TRUE; + else if (blockSize == 16) + lrw128InitDone = TRUE; + } + + // Copy the header for decryption + memcpy (header, encryptedHeader, sizeof (header)); + + // Try to decrypt header + + DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); + + // Magic 'TRUE' + if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545) + continue; + + // Header version + headerVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION); + + if (headerVersion > VOLUME_HEADER_VERSION) + { + status = ERR_NEW_VERSION_REQUIRED; + goto err; + } + + // Check CRC of the header fields + if (!ReadVolumeHeaderRecoveryMode + && headerVersion >= 4 + && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)) + continue; + + // Required program version + cryptoInfo->RequiredProgramVersion = GetHeaderField16 (header, TC_HEADER_OFFSET_REQUIRED_VERSION); + cryptoInfo->LegacyVolume = cryptoInfo->RequiredProgramVersion < 0x600; + + // Check CRC of the key set + if (!ReadVolumeHeaderRecoveryMode + && GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE)) + continue; + + // Now we have the correct password, cipher, hash algorithm, and volume type + + // Check the version required to handle this volume + if (cryptoInfo->RequiredProgramVersion > VERSION_NUM) + { + status = ERR_NEW_VERSION_REQUIRED; + goto err; + } + + // Header version + cryptoInfo->HeaderVersion = headerVersion; + + // Volume creation time (legacy) + cryptoInfo->volume_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_CREATION_TIME).Value; + + // Header creation time (legacy) + cryptoInfo->header_creation_time = GetHeaderField64 (header, TC_HEADER_OFFSET_MODIFICATION_TIME).Value; + + // Hidden volume size (if any) + cryptoInfo->hiddenVolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE).Value; + + // Hidden volume status + cryptoInfo->hiddenVolume = (cryptoInfo->hiddenVolumeSize != 0); + + // Volume size + cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE); + + // Encrypted area size and length + cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START); + cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH); + + // Flags + cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS); + + // Sector size + if (headerVersion >= 5) + cryptoInfo->SectorSize = GetHeaderField32 (header, TC_HEADER_OFFSET_SECTOR_SIZE); + else + cryptoInfo->SectorSize = TC_SECTOR_SIZE_LEGACY; + + if (cryptoInfo->SectorSize < TC_MIN_VOLUME_SECTOR_SIZE + || cryptoInfo->SectorSize > TC_MAX_VOLUME_SECTOR_SIZE + || cryptoInfo->SectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) + { + status = ERR_PARAMETER_INCORRECT; + goto err; + } + + // Preserve scheduled header keys if requested + if (retHeaderCryptoInfo) + { + if (retInfo == NULL) + { + cryptoInfo->pkcs5 = pkcs5_prf; + cryptoInfo->noIterations = keyInfo.noIterations; + goto ret; + } + + cryptoInfo = *retInfo = crypto_open (); + if (cryptoInfo == NULL) + { + status = ERR_OUTOFMEMORY; + goto err; + } + + memcpy (cryptoInfo, retHeaderCryptoInfo, sizeof (*cryptoInfo)); + } + + // Master key data + memcpy (keyInfo.master_keydata, header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE); + memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); + + // PKCS #5 + memcpy (cryptoInfo->salt, keyInfo.salt, PKCS5_SALT_SIZE); + cryptoInfo->pkcs5 = pkcs5_prf; + cryptoInfo->noIterations = keyInfo.noIterations; + + // Init the cipher with the decrypted master key + status = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; + + switch (cryptoInfo->mode) + { + case LRW: + case CBC: + case INNER_CBC: + case OUTER_CBC: + + // For LRW (deprecated/legacy), the tweak key + // For CBC (deprecated/legacy), the IV/whitening seed + memcpy (cryptoInfo->k2, keyInfo.master_keydata, LEGACY_VOL_IV_SIZE); + break; + + default: + // The secondary master key (if cascade, multiple concatenated) + memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); + + } + + if (!EAInitMode (cryptoInfo)) + { + status = ERR_MODE_INIT_FAILED; + goto err; + } + + status = ERR_SUCCESS; + goto ret; + } + } + } + status = ERR_PASSWORD_WRONG; + +err: + if (cryptoInfo != retHeaderCryptoInfo) + { + crypto_close(cryptoInfo); + *retInfo = NULL; + } + +ret: + burn (&keyInfo, sizeof (keyInfo)); + burn (dk, sizeof(dk)); + +#ifndef DEVICE_DRIVER + VirtualUnlock (&keyInfo, sizeof (keyInfo)); + VirtualUnlock (&dk, sizeof (dk)); +#endif + + if (encryptionThreadCount > 1) + { + TC_WAIT_EVENT (noOutstandingWorkItemEvent); + + burn (keyDerivationWorkItems, sizeof (KeyDerivationWorkItem) * pkcs5PrfCount); + TCfree (keyDerivationWorkItems); + +#ifndef DEVICE_DRIVER + CloseHandle (keyDerivationCompletedEvent); + CloseHandle (noOutstandingWorkItemEvent); +#endif + } + + return status; +} + +#else // TC_WINDOWS_BOOT + +int ReadVolumeHeader (BOOL bBoot, char *header, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo) +{ +#ifdef TC_WINDOWS_BOOT_SINGLE_CIPHER_MODE + char dk[32 * 2]; // 2 * 256-bit key + char masterKey[32 * 2]; +#else + char dk[32 * 2 * 3]; // 6 * 256-bit key + char masterKey[32 * 2 * 3]; +#endif + + PCRYPTO_INFO cryptoInfo; + int status; + + if (retHeaderCryptoInfo != NULL) + cryptoInfo = retHeaderCryptoInfo; + else + cryptoInfo = *retInfo = crypto_open (); + + // PKCS5 PRF + derive_key_ripemd160 (password->Text, (int) password->Length, header + HEADER_SALT_OFFSET, + PKCS5_SALT_SIZE, bBoot ? 1000 : 2000, dk, sizeof (dk)); + + // Mode of operation + cryptoInfo->mode = FIRST_MODE_OF_OPERATION_ID; + + // Test all available encryption algorithms + for (cryptoInfo->ea = EAGetFirst (); cryptoInfo->ea != 0; cryptoInfo->ea = EAGetNext (cryptoInfo->ea)) + { + status = EAInit (cryptoInfo->ea, dk, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; + + // Secondary key schedule + EAInit (cryptoInfo->ea, dk + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2); + + // Try to decrypt header + DecryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); + + // Check magic 'TRUE' and CRC-32 of header fields and master keydata + if (GetHeaderField32 (header, TC_HEADER_OFFSET_MAGIC) != 0x54525545 + || (GetHeaderField16 (header, TC_HEADER_OFFSET_VERSION) >= 4 && GetHeaderField32 (header, TC_HEADER_OFFSET_HEADER_CRC) != GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC)) + || GetHeaderField32 (header, TC_HEADER_OFFSET_KEY_AREA_CRC) != GetCrc32 (header + HEADER_MASTER_KEYDATA_OFFSET, MASTER_KEYDATA_SIZE)) + { + EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); + continue; + } + + // Header decrypted + status = 0; + + // Hidden volume status + cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE); + cryptoInfo->hiddenVolume = (cryptoInfo->VolumeSize.LowPart != 0 || cryptoInfo->VolumeSize.HighPart != 0); + + // Volume size + cryptoInfo->VolumeSize = GetHeaderField64 (header, TC_HEADER_OFFSET_VOLUME_SIZE); + + // Encrypted area size and length + cryptoInfo->EncryptedAreaStart = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_START); + cryptoInfo->EncryptedAreaLength = GetHeaderField64 (header, TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH); + + // Flags + cryptoInfo->HeaderFlags = GetHeaderField32 (header, TC_HEADER_OFFSET_FLAGS); + + memcpy (masterKey, header + HEADER_MASTER_KEYDATA_OFFSET, sizeof (masterKey)); + EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, HEADER_ENCRYPTED_DATA_SIZE, cryptoInfo); + + if (retHeaderCryptoInfo) + goto ret; + + // Init the encryption algorithm with the decrypted master key + status = EAInit (cryptoInfo->ea, masterKey, cryptoInfo->ks); + if (status == ERR_CIPHER_INIT_FAILURE) + goto err; + + // The secondary master key (if cascade, multiple concatenated) + EAInit (cryptoInfo->ea, masterKey + EAGetKeySize (cryptoInfo->ea), cryptoInfo->ks2); + goto ret; + } + + status = ERR_PASSWORD_WRONG; + +err: + if (cryptoInfo != retHeaderCryptoInfo) + { + crypto_close(cryptoInfo); + *retInfo = NULL; + } + +ret: + burn (dk, sizeof(dk)); + burn (masterKey, sizeof(masterKey)); + return status; +} + +#endif // TC_WINDOWS_BOOT + + +#if !defined (DEVICE_DRIVER) && !defined (TC_WINDOWS_BOOT) + +#ifdef VOLFORMAT +# include "../Format/TcFormat.h" +# include "Dlgcode.h" +#endif + +// Creates a volume header in memory +int CreateVolumeHeaderInMemory (BOOL bBoot, char *header, int ea, int mode, Password *password, + int pkcs5_prf, char *masterKeydata, PCRYPTO_INFO *retInfo, + unsigned __int64 volumeSize, unsigned __int64 hiddenVolumeSize, + unsigned __int64 encryptedAreaStart, unsigned __int64 encryptedAreaLength, uint16 requiredProgramVersion, uint32 headerFlags, uint32 sectorSize, BOOL bWipeMode) +{ + unsigned char *p = (unsigned char *) header; + static KEY_INFO keyInfo; + + int nUserKeyLen = password->Length; + PCRYPTO_INFO cryptoInfo = crypto_open (); + static char dk[MASTER_KEYDATA_SIZE]; + int x; + int retVal = 0; + int primaryKeyOffset; + + if (cryptoInfo == NULL) + return ERR_OUTOFMEMORY; + + memset (header, 0, TC_VOLUME_HEADER_EFFECTIVE_SIZE); + + VirtualLock (&keyInfo, sizeof (keyInfo)); + VirtualLock (&dk, sizeof (dk)); + + /* Encryption setup */ + + if (masterKeydata == NULL) + { + // We have no master key data (creating a new volume) so we'll use the TrueCrypt RNG to generate them + + int bytesNeeded; + + switch (mode) + { + case LRW: + case CBC: + case INNER_CBC: + case OUTER_CBC: + + // Deprecated/legacy modes of operation + bytesNeeded = LEGACY_VOL_IV_SIZE + EAGetKeySize (ea); + + // In fact, this should never be the case since volumes being newly created are not + // supposed to use any deprecated mode of operation. + TC_THROW_FATAL_EXCEPTION; + break; + + default: + bytesNeeded = EAGetKeySize (ea) * 2; // Size of primary + secondary key(s) + } + + if (!RandgetBytes (keyInfo.master_keydata, bytesNeeded, TRUE)) + return ERR_CIPHER_INIT_WEAK_KEY; + } + else + { + // We already have existing master key data (the header is being re-encrypted) + memcpy (keyInfo.master_keydata, masterKeydata, MASTER_KEYDATA_SIZE); + } + + // User key + memcpy (keyInfo.userKey, password->Text, nUserKeyLen); + keyInfo.keyLength = nUserKeyLen; + keyInfo.noIterations = get_pkcs5_iteration_count (pkcs5_prf, bBoot); + + // User selected encryption algorithm + cryptoInfo->ea = ea; + + // Mode of operation + cryptoInfo->mode = mode; + + // Salt for header key derivation + if (!RandgetBytes (keyInfo.salt, PKCS5_SALT_SIZE, !bWipeMode)) + return ERR_CIPHER_INIT_WEAK_KEY; + + // PBKDF2 (PKCS5) is used to derive primary header key(s) and secondary header key(s) (XTS) from the password/keyfiles + switch (pkcs5_prf) + { + case SHA512: + derive_key_sha512 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case SHA1: + // Deprecated/legacy + derive_key_sha1 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case RIPEMD160: + derive_key_ripemd160 (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + case WHIRLPOOL: + derive_key_whirlpool (keyInfo.userKey, keyInfo.keyLength, keyInfo.salt, + PKCS5_SALT_SIZE, keyInfo.noIterations, dk, GetMaxPkcs5OutSize()); + break; + + default: + // Unknown/wrong ID + TC_THROW_FATAL_EXCEPTION; + } + + /* Header setup */ + + // Salt + mputBytes (p, keyInfo.salt, PKCS5_SALT_SIZE); + + // Magic + mputLong (p, 0x54525545); + + // Header version + mputWord (p, VOLUME_HEADER_VERSION); + cryptoInfo->HeaderVersion = VOLUME_HEADER_VERSION; + + // Required program version to handle this volume + switch (mode) + { + case LRW: + // Deprecated/legacy + mputWord (p, 0x0410); + break; + case OUTER_CBC: + case INNER_CBC: + // Deprecated/legacy + mputWord (p, 0x0300); + break; + case CBC: + // Deprecated/legacy + mputWord (p, hiddenVolumeSize > 0 ? 0x0300 : 0x0100); + break; + default: + mputWord (p, requiredProgramVersion != 0 ? requiredProgramVersion : TC_VOLUME_MIN_REQUIRED_PROGRAM_VERSION); + } + + // CRC of the master key data + x = GetCrc32(keyInfo.master_keydata, MASTER_KEYDATA_SIZE); + mputLong (p, x); + + // Reserved fields + p += 2 * 8; + + // Size of hidden volume (if any) + cryptoInfo->hiddenVolumeSize = hiddenVolumeSize; + mputInt64 (p, cryptoInfo->hiddenVolumeSize); + + cryptoInfo->hiddenVolume = cryptoInfo->hiddenVolumeSize != 0; + + // Volume size + cryptoInfo->VolumeSize.Value = volumeSize; + mputInt64 (p, volumeSize); + + // Encrypted area start + cryptoInfo->EncryptedAreaStart.Value = encryptedAreaStart; + mputInt64 (p, encryptedAreaStart); + + // Encrypted area size + cryptoInfo->EncryptedAreaLength.Value = encryptedAreaLength; + mputInt64 (p, encryptedAreaLength); + + // Flags + cryptoInfo->HeaderFlags = headerFlags; + mputLong (p, headerFlags); + + // Sector size + if (sectorSize < TC_MIN_VOLUME_SECTOR_SIZE + || sectorSize > TC_MAX_VOLUME_SECTOR_SIZE + || sectorSize % ENCRYPTION_DATA_UNIT_SIZE != 0) + { + TC_THROW_FATAL_EXCEPTION; + } + + cryptoInfo->SectorSize = sectorSize; + mputLong (p, sectorSize); + + // CRC of the header fields + x = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC); + p = header + TC_HEADER_OFFSET_HEADER_CRC; + mputLong (p, x); + + // The master key data + memcpy (header + HEADER_MASTER_KEYDATA_OFFSET, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); + + + /* Header encryption */ + + switch (mode) + { + case LRW: + case CBC: + case INNER_CBC: + case OUTER_CBC: + + // For LRW (deprecated/legacy), the tweak key + // For CBC (deprecated/legacy), the IV/whitening seed + memcpy (cryptoInfo->k2, dk, LEGACY_VOL_IV_SIZE); + primaryKeyOffset = LEGACY_VOL_IV_SIZE; + break; + + default: + // The secondary key (if cascade, multiple concatenated) + memcpy (cryptoInfo->k2, dk + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); + primaryKeyOffset = 0; + } + + retVal = EAInit (cryptoInfo->ea, dk + primaryKeyOffset, cryptoInfo->ks); + if (retVal != ERR_SUCCESS) + return retVal; + + // Mode of operation + if (!EAInitMode (cryptoInfo)) + return ERR_OUTOFMEMORY; + + + // Encrypt the entire header (except the salt) + EncryptBuffer (header + HEADER_ENCRYPTED_DATA_OFFSET, + HEADER_ENCRYPTED_DATA_SIZE, + cryptoInfo); + + + /* cryptoInfo setup for further use (disk format) */ + + // Init with the master key(s) + retVal = EAInit (cryptoInfo->ea, keyInfo.master_keydata + primaryKeyOffset, cryptoInfo->ks); + if (retVal != ERR_SUCCESS) + return retVal; + + memcpy (cryptoInfo->master_keydata, keyInfo.master_keydata, MASTER_KEYDATA_SIZE); + + switch (cryptoInfo->mode) + { + case LRW: + case CBC: + case INNER_CBC: + case OUTER_CBC: + + // For LRW (deprecated/legacy), the tweak key + // For CBC (deprecated/legacy), the IV/whitening seed + memcpy (cryptoInfo->k2, keyInfo.master_keydata, LEGACY_VOL_IV_SIZE); + break; + + default: + // The secondary master key (if cascade, multiple concatenated) + memcpy (cryptoInfo->k2, keyInfo.master_keydata + EAGetKeySize (cryptoInfo->ea), EAGetKeySize (cryptoInfo->ea)); + } + + // Mode of operation + if (!EAInitMode (cryptoInfo)) + return ERR_OUTOFMEMORY; + + +#ifdef VOLFORMAT + if (showKeys && !bInPlaceEncNonSys) + { + BOOL dots3 = FALSE; + int i, j; + + j = EAGetKeySize (ea); + + if (j > NBR_KEY_BYTES_TO_DISPLAY) + { + dots3 = TRUE; + j = NBR_KEY_BYTES_TO_DISPLAY; + } + + MasterKeyGUIView[0] = 0; + for (i = 0; i < j; i++) + { + char tmp2[8] = {0}; + sprintf (tmp2, "%02X", (int) (unsigned char) keyInfo.master_keydata[i + primaryKeyOffset]); + strcat (MasterKeyGUIView, tmp2); + } + + HeaderKeyGUIView[0] = 0; + for (i = 0; i < NBR_KEY_BYTES_TO_DISPLAY; i++) + { + char tmp2[8]; + sprintf (tmp2, "%02X", (int) (unsigned char) dk[primaryKeyOffset + i]); + strcat (HeaderKeyGUIView, tmp2); + } + + if (dots3) + { + DisplayPortionsOfKeys (hHeaderKey, hMasterKey, HeaderKeyGUIView, MasterKeyGUIView, !showKeys); + } + else + { + SendMessage (hMasterKey, WM_SETTEXT, 0, (LPARAM) MasterKeyGUIView); + SendMessage (hHeaderKey, WM_SETTEXT, 0, (LPARAM) HeaderKeyGUIView); + } + } +#endif // #ifdef VOLFORMAT + + burn (dk, sizeof(dk)); + burn (&keyInfo, sizeof (keyInfo)); + + *retInfo = cryptoInfo; + return 0; +} + + +BOOL ReadEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header, DWORD *bytesRead) +{ +#if TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE +#error TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE +#endif + + byte sectorBuffer[TC_MAX_VOLUME_SECTOR_SIZE]; + DISK_GEOMETRY geometry; + + if (!device) + return ReadFile (fileHandle, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, bytesRead, NULL); + + if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry), bytesRead, NULL)) + return FALSE; + + if (geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (!ReadFile (fileHandle, sectorBuffer, max (TC_VOLUME_HEADER_EFFECTIVE_SIZE, geometry.BytesPerSector), bytesRead, NULL)) + return FALSE; + + memcpy (header, sectorBuffer, min (*bytesRead, TC_VOLUME_HEADER_EFFECTIVE_SIZE)); + + if (*bytesRead > TC_VOLUME_HEADER_EFFECTIVE_SIZE) + *bytesRead = TC_VOLUME_HEADER_EFFECTIVE_SIZE; + + return TRUE; +} + + +BOOL WriteEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header) +{ +#if TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE +#error TC_VOLUME_HEADER_EFFECTIVE_SIZE > TC_MAX_VOLUME_SECTOR_SIZE +#endif + + byte sectorBuffer[TC_MAX_VOLUME_SECTOR_SIZE]; + DWORD bytesDone; + DISK_GEOMETRY geometry; + + if (!device) + { + if (!WriteFile (fileHandle, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE, &bytesDone, NULL)) + return FALSE; + + if (bytesDone != TC_VOLUME_HEADER_EFFECTIVE_SIZE) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + return TRUE; + } + + if (!DeviceIoControl (fileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &geometry, sizeof (geometry), &bytesDone, NULL)) + return FALSE; + + if (geometry.BytesPerSector > sizeof (sectorBuffer) || geometry.BytesPerSector < TC_MIN_VOLUME_SECTOR_SIZE) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (geometry.BytesPerSector != TC_VOLUME_HEADER_EFFECTIVE_SIZE) + { + LARGE_INTEGER seekOffset; + + if (!ReadFile (fileHandle, sectorBuffer, geometry.BytesPerSector, &bytesDone, NULL)) + return FALSE; + + if (bytesDone != geometry.BytesPerSector) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + seekOffset.QuadPart = -(int) bytesDone; + if (!SetFilePointerEx (fileHandle, seekOffset, NULL, FILE_CURRENT)) + return FALSE; + } + + memcpy (sectorBuffer, header, TC_VOLUME_HEADER_EFFECTIVE_SIZE); + + if (!WriteFile (fileHandle, sectorBuffer, geometry.BytesPerSector, &bytesDone, NULL)) + return FALSE; + + if (bytesDone != geometry.BytesPerSector) + { + SetLastError (ERROR_INVALID_PARAMETER); + return FALSE; + } + + return TRUE; +} + + +// Writes randomly generated data to unused/reserved header areas. +// When bPrimaryOnly is TRUE, then only the primary header area (not the backup header area) is filled with random data. +// When bBackupOnly is TRUE, only the backup header area (not the primary header area) is filled with random data. +int WriteRandomDataToReservedHeaderAreas (HANDLE dev, CRYPTO_INFO *cryptoInfo, uint64 dataAreaSize, BOOL bPrimaryOnly, BOOL bBackupOnly) +{ + char temporaryKey[MASTER_KEYDATA_SIZE]; + char originalK2[MASTER_KEYDATA_SIZE]; + + byte buf[TC_VOLUME_HEADER_GROUP_SIZE]; + + LARGE_INTEGER offset; + int nStatus = ERR_SUCCESS; + DWORD dwError; + DWORD bytesDone; + BOOL backupHeaders = bBackupOnly; + + if (bPrimaryOnly && bBackupOnly) + TC_THROW_FATAL_EXCEPTION; + + memcpy (originalK2, cryptoInfo->k2, sizeof (cryptoInfo->k2)); + + while (TRUE) + { + // Temporary keys + if (!RandgetBytes (temporaryKey, EAGetKeySize (cryptoInfo->ea), FALSE) + || !RandgetBytes (cryptoInfo->k2, sizeof (cryptoInfo->k2), FALSE)) + { + nStatus = ERR_PARAMETER_INCORRECT; + goto final_seq; + } + + nStatus = EAInit (cryptoInfo->ea, temporaryKey, cryptoInfo->ks); + if (nStatus != ERR_SUCCESS) + goto final_seq; + + if (!EAInitMode (cryptoInfo)) + { + nStatus = ERR_MODE_INIT_FAILED; + goto final_seq; + } + + offset.QuadPart = backupHeaders ? dataAreaSize + TC_VOLUME_HEADER_GROUP_SIZE : TC_VOLUME_HEADER_OFFSET; + + if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) + { + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + if (!ReadFile (dev, buf, sizeof (buf), &bytesDone, NULL)) + { + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + if (bytesDone < TC_VOLUME_HEADER_EFFECTIVE_SIZE) + { + SetLastError (ERROR_INVALID_PARAMETER); + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + EncryptBuffer (buf + TC_VOLUME_HEADER_EFFECTIVE_SIZE, sizeof (buf) - TC_VOLUME_HEADER_EFFECTIVE_SIZE, cryptoInfo); + + if (!SetFilePointerEx (dev, offset, NULL, FILE_BEGIN)) + { + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + if (!WriteFile (dev, buf, sizeof (buf), &bytesDone, NULL)) + { + nStatus = ERR_OS_ERROR; + goto final_seq; + } + + if (bytesDone != sizeof (buf)) + { + nStatus = ERR_PARAMETER_INCORRECT; + goto final_seq; + } + + if (backupHeaders || bPrimaryOnly) + break; + + backupHeaders = TRUE; + } + + memcpy (cryptoInfo->k2, originalK2, sizeof (cryptoInfo->k2)); + + nStatus = EAInit (cryptoInfo->ea, cryptoInfo->master_keydata, cryptoInfo->ks); + if (nStatus != ERR_SUCCESS) + goto final_seq; + + if (!EAInitMode (cryptoInfo)) + { + nStatus = ERR_MODE_INIT_FAILED; + goto final_seq; + } + +final_seq: + + dwError = GetLastError(); + + burn (temporaryKey, sizeof (temporaryKey)); + burn (originalK2, sizeof (originalK2)); + + if (nStatus != ERR_SUCCESS) + SetLastError (dwError); + + return nStatus; +} + +#endif // !defined (DEVICE_DRIVER) && !defined (TC_WINDOWS_BOOT) diff --git a/Common/Volumes.h b/Common/Volumes.h new file mode 100644 index 0000000..33f7d19 --- /dev/null +++ b/Common/Volumes.h @@ -0,0 +1,144 @@ +/* + 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_Common_Volumes +#define TC_HEADER_Common_Volumes + +#ifdef __cplusplus +extern "C" { +#endif + +// Volume header version +#define VOLUME_HEADER_VERSION 0x0005 + +// Version number written to volume header during format; +// specifies the minimum program version required to mount the volume +#define TC_VOLUME_MIN_REQUIRED_PROGRAM_VERSION 0x0700 + +// Version number written (encrypted) to the key data area of an encrypted system partition/drive; +// specifies the minimum program version required to decrypt the system partition/drive +#define TC_SYSENC_KEYSCOPE_MIN_REQ_PROG_VERSION 0x0700 + +// Current volume format version (created by TrueCrypt 6.0+) +#define TC_VOLUME_FORMAT_VERSION 2 + +// Version number of volume format created by TrueCrypt 1.0-5.1a +#define TC_VOLUME_FORMAT_VERSION_PRE_6_0 1 + +// Volume header sizes +#define TC_VOLUME_HEADER_SIZE (64 * 1024L) +#define TC_VOLUME_HEADER_EFFECTIVE_SIZE 512 +#define TC_BOOT_ENCRYPTION_VOLUME_HEADER_SIZE 512 +#define TC_VOLUME_HEADER_SIZE_LEGACY 512 + +#define TC_VOLUME_HEADER_GROUP_SIZE (2 * TC_VOLUME_HEADER_SIZE) +#define TC_TOTAL_VOLUME_HEADERS_SIZE (4 * TC_VOLUME_HEADER_SIZE) + +// Volume offsets +#define TC_VOLUME_HEADER_OFFSET 0 +#define TC_HIDDEN_VOLUME_HEADER_OFFSET TC_VOLUME_HEADER_SIZE + +// Sector sizes +#define TC_MIN_VOLUME_SECTOR_SIZE 512 +#define TC_MAX_VOLUME_SECTOR_SIZE 4096 +#define TC_SECTOR_SIZE_FILE_HOSTED_VOLUME 512 +#define TC_SECTOR_SIZE_LEGACY 512 + +// Sector size which can be safely assumed to be supported by all BIOSes +#define TC_SECTOR_SIZE_BIOS 512 + +#define TC_VOLUME_SMALL_SIZE_THRESHOLD (2 * BYTES_PER_MB) // Volume sizes below this threshold are considered small + +#define TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE TC_MAX_VOLUME_SECTOR_SIZE // FAT file system fills the last sector with zeroes (marked as free; observed when quick format was performed using the OS format tool). +#define TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE_HIGH TC_VOLUME_HEADER_GROUP_SIZE // Reserved area size used for hidden volumes larger than TC_VOLUME_SMALL_SIZE_THRESHOLD + +#define TC_VOLUME_DATA_OFFSET TC_VOLUME_HEADER_GROUP_SIZE + +// The offset, in bytes, of the legacy hidden volume header position from the end of the file (a positive value). +#define TC_HIDDEN_VOLUME_HEADER_OFFSET_LEGACY (TC_VOLUME_HEADER_SIZE_LEGACY + TC_SECTOR_SIZE_LEGACY * 2) + +#define TC_MAX_128BIT_BLOCK_VOLUME_SIZE BYTES_PER_PB // Security bound (128-bit block XTS mode) + +// Filesystem size limits +#define TC_MIN_FAT_FS_SIZE (9 * TC_MAX_VOLUME_SECTOR_SIZE) +#define TC_MAX_FAT_SECTOR_COUNT 0x100000000ULL +#define TC_MIN_NTFS_FS_SIZE (884 * TC_MAX_VOLUME_SECTOR_SIZE) +#define TC_MAX_NTFS_FS_SIZE (128LL * BYTES_PER_TB) // NTFS volume can theoretically be up to 16 exabytes, but Windows XP and 2003 limit the size to that addressable with 32-bit clusters, i.e. max size is 128 TB (if 64-KB clusters are used). +#define TC_MAX_FAT_CLUSTER_SIZE (256 * BYTES_PER_KB) // Windows XP/Vista may crash when writing to a filesystem using clusters larger than 256 KB + +// Volume size limits +#define TC_MIN_VOLUME_SIZE (TC_TOTAL_VOLUME_HEADERS_SIZE + TC_MIN_FAT_FS_SIZE) +#define TC_MIN_VOLUME_SIZE_LEGACY (37 * TC_SECTOR_SIZE_LEGACY) +#define TC_MAX_VOLUME_SIZE_GENERAL 0x7fffFFFFffffFFFFLL // Signed 64-bit integer file offset values +#define TC_MAX_VOLUME_SIZE TC_MAX_128BIT_BLOCK_VOLUME_SIZE + +#define TC_MIN_HIDDEN_VOLUME_SIZE (TC_MIN_FAT_FS_SIZE + TC_HIDDEN_VOLUME_HOST_FS_RESERVED_END_AREA_SIZE) + +#define TC_MIN_HIDDEN_VOLUME_HOST_SIZE (TC_MIN_VOLUME_SIZE + TC_MIN_HIDDEN_VOLUME_SIZE + 2 * TC_MAX_VOLUME_SECTOR_SIZE) +#define TC_MAX_HIDDEN_VOLUME_HOST_SIZE (TC_MAX_NTFS_FS_SIZE - TC_TOTAL_VOLUME_HEADERS_SIZE) + +#ifndef TC_NO_COMPILER_INT64 +# if TC_MAX_VOLUME_SIZE > TC_MAX_VOLUME_SIZE_GENERAL +# error TC_MAX_VOLUME_SIZE > TC_MAX_VOLUME_SIZE_GENERAL +# endif +#endif + +#define HEADER_ENCRYPTED_DATA_SIZE (TC_VOLUME_HEADER_EFFECTIVE_SIZE - HEADER_ENCRYPTED_DATA_OFFSET) + +// Volume header field offsets +#define HEADER_SALT_OFFSET 0 +#define HEADER_ENCRYPTED_DATA_OFFSET PKCS5_SALT_SIZE +#define HEADER_MASTER_KEYDATA_OFFSET 256 + +#define TC_HEADER_OFFSET_MAGIC 64 +#define TC_HEADER_OFFSET_VERSION 68 +#define TC_HEADER_OFFSET_REQUIRED_VERSION 70 +#define TC_HEADER_OFFSET_KEY_AREA_CRC 72 +#define TC_HEADER_OFFSET_VOLUME_CREATION_TIME 76 +#define TC_HEADER_OFFSET_MODIFICATION_TIME 84 +#define TC_HEADER_OFFSET_HIDDEN_VOLUME_SIZE 92 +#define TC_HEADER_OFFSET_VOLUME_SIZE 100 +#define TC_HEADER_OFFSET_ENCRYPTED_AREA_START 108 +#define TC_HEADER_OFFSET_ENCRYPTED_AREA_LENGTH 116 +#define TC_HEADER_OFFSET_FLAGS 124 +#define TC_HEADER_OFFSET_SECTOR_SIZE 128 +#define TC_HEADER_OFFSET_HEADER_CRC 252 + +// Volume header flags +#define TC_HEADER_FLAG_ENCRYPTED_SYSTEM 0x1 +#define TC_HEADER_FLAG_NONSYS_INPLACE_ENC 0x2 // The volume has been created using non-system in-place encryption + + +#ifndef TC_HEADER_Volume_VolumeHeader + +#include "Password.h" + +extern BOOL ReadVolumeHeaderRecoveryMode; + +uint16 GetHeaderField16 (byte *header, int offset); +uint32 GetHeaderField32 (byte *header, int offset); +UINT64_STRUCT GetHeaderField64 (byte *header, int offset); +int ReadVolumeHeader (BOOL bBoot, char *encryptedHeader, Password *password, PCRYPTO_INFO *retInfo, CRYPTO_INFO *retHeaderCryptoInfo); + +#if !defined (DEVICE_DRIVER) && !defined (TC_WINDOWS_BOOT) +int CreateVolumeHeaderInMemory (BOOL bBoot, char *encryptedHeader, int ea, int mode, Password *password, int pkcs5_prf, char *masterKeydata, PCRYPTO_INFO *retInfo, unsigned __int64 volumeSize, unsigned __int64 hiddenVolumeSize, unsigned __int64 encryptedAreaStart, unsigned __int64 encryptedAreaLength, uint16 requiredProgramVersion, uint32 headerFlags, uint32 sectorSize, BOOL bWipeMode); +BOOL ReadEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header, DWORD *bytesRead); +BOOL WriteEffectiveVolumeHeader (BOOL device, HANDLE fileHandle, byte *header); +int WriteRandomDataToReservedHeaderAreas (HANDLE dev, CRYPTO_INFO *cryptoInfo, uint64 dataAreaSize, BOOL bPrimaryOnly, BOOL bBackupOnly); +#endif + +#endif // !TC_HEADER_Volume_VolumeHeader + +#ifdef __cplusplus +} +#endif + +#endif // TC_HEADER_Common_Volumes diff --git a/Common/Wipe.c b/Common/Wipe.c new file mode 100644 index 0000000..e5a09db --- /dev/null +++ b/Common/Wipe.c @@ -0,0 +1,187 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#include "Tcdefs.h" +#include "Wipe.h" + + +static BOOL Wipe1PseudoRandom (int pass, byte *buffer, size_t size) +{ + return FALSE; +} + + +// Fill buffer with wipe patterns defined in "National Industrial Security Program Operating Manual", US DoD 5220.22-M. +// Return: FALSE = buffer must be filled with random data + +static BOOL Wipe3Dod5220 (int pass, byte *buffer, size_t size) +{ + byte wipeChar; + + switch (pass) + { + case 1: + wipeChar = 0; + break; + + case 2: + wipeChar = 0xff; + break; + + default: + return FALSE; + } + + memset (buffer, wipeChar, size); + return TRUE; +} + + +static BOOL Wipe7Dod5220 (int pass, byte randChars[TC_WIPE_RAND_CHAR_COUNT], byte *buffer, size_t size) +{ + byte wipeChar; + + switch (pass) + { + case 1: + wipeChar = randChars[0]; + break; + + case 2: + wipeChar = ~randChars[0]; + break; + + case 4: + wipeChar = randChars[1]; + break; + + case 5: + wipeChar = randChars[2]; + break; + + case 6: + wipeChar = ~randChars[2]; + break; + + default: + return FALSE; + } + + memset (buffer, wipeChar, size); + return TRUE; +} + + +// Fill the buffer with wipe patterns defined in the paper "Secure Deletion of Data from Magnetic and Solid-State Memory" by Peter Gutmann. +// Return: FALSE = buffer must be filled with random data + +static BOOL Wipe35Gutmann (int pass, byte *buffer, size_t size) +{ + byte wipePat3[] = { 0x92, 0x49, 0x24 }; + int wipePat3Pos; + size_t i; + + switch (pass) + { + case 5: + memset (buffer, 0x55, size); + break; + + case 6: + memset (buffer, 0xaa, size); + break; + + case 7: + case 26: + case 29: + wipePat3Pos = 0; + goto wipe3; + + case 8: + case 27: + case 30: + wipePat3Pos = 1; + goto wipe3; + + case 9: + case 28: + case 31: + wipePat3Pos = 2; + goto wipe3; + +wipe3: + if (pass >= 29) + { + wipePat3[0] = ~wipePat3[0]; + wipePat3[1] = ~wipePat3[1]; + wipePat3[2] = ~wipePat3[2]; + } + + for (i = 0; i < size; ++i) + { + buffer[i] = wipePat3[wipePat3Pos++ % 3]; + } + break; + + default: + if (pass >= 10 && pass <= 25) + memset (buffer, (pass - 10) * 0x11, size); + else + return FALSE; + } + + return TRUE; +} + + +int GetWipePassCount (WipeAlgorithmId algorithm) +{ + switch (algorithm) + { + case TC_WIPE_1_RAND: + return 1; + + case TC_WIPE_3_DOD_5220: + return 3; + + case TC_WIPE_7_DOD_5220: + return 7; + + case TC_WIPE_35_GUTMANN: + return 35; + + default: + TC_THROW_FATAL_EXCEPTION; + } + + return 0; // Prevent compiler warnings +} + + +BOOL WipeBuffer (WipeAlgorithmId algorithm, byte randChars[TC_WIPE_RAND_CHAR_COUNT], int pass, byte *buffer, size_t size) +{ + switch (algorithm) + { + case TC_WIPE_1_RAND: + return Wipe1PseudoRandom (pass, buffer, size); + + case TC_WIPE_3_DOD_5220: + return Wipe3Dod5220 (pass, buffer, size); + + case TC_WIPE_7_DOD_5220: + return Wipe7Dod5220 (pass, randChars, buffer, size); + + case TC_WIPE_35_GUTMANN: + return Wipe35Gutmann (pass, buffer, size); + + default: + TC_THROW_FATAL_EXCEPTION; + } + + return FALSE; // Prevent compiler warnings +} diff --git a/Common/Wipe.h b/Common/Wipe.h new file mode 100644 index 0000000..a59c902 --- /dev/null +++ b/Common/Wipe.h @@ -0,0 +1,40 @@ +/* + Copyright (c) 2008-2009 TrueCrypt Developers Association. All rights reserved. + + Governed by the TrueCrypt License 3.0 the full text of which is contained in + the file License.txt included in TrueCrypt binary and source code distribution + packages. +*/ + +#ifndef TC_HEADER_Common_Wipe +#define TC_HEADER_Common_Wipe + +#include "Tcdefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + /* 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. */ + TC_WIPE_NONE = 0, + TC_WIPE_1_RAND = 100, + TC_WIPE_3_DOD_5220 = 300, + TC_WIPE_7_DOD_5220 = 700, + TC_WIPE_35_GUTMANN = 3500 + +} WipeAlgorithmId; + +#define TC_WIPE_RAND_CHAR_COUNT 3 + +int GetWipePassCount (WipeAlgorithmId algorithm); +BOOL WipeBuffer (WipeAlgorithmId algorithm, byte randChars[TC_WIPE_RAND_CHAR_COUNT], int pass, byte *buffer, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif // TC_HEADER_Common_Wipe diff --git a/Common/Xml.c b/Common/Xml.c new file mode 100644 index 0000000..fad64e7 --- /dev/null +++ b/Common/Xml.c @@ -0,0 +1,231 @@ +/* + Copyright (c) 2005-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 <windows.h> +#include <stdio.h> +#include "Xml.h" + + +static BOOL BeginsWith (char *string, char *subString) +{ + while (*string++ == *subString++) + { + if (*subString == 0) return TRUE; + if (*string == 0) return FALSE; + } + + return FALSE; +} + + +char *XmlNextNode (char *xmlNode) +{ + char *t = xmlNode + 1; + while ((t = strchr (t, '<')) != NULL) + { + if (t[1] != '/') + return t; + + t++; + } + + return NULL; +} + + +char *XmlFindElement (char *xmlNode, char *nodeName) +{ + char *t = xmlNode; + size_t nameLen = strlen (nodeName); + + do + { + if (BeginsWith (t + 1, nodeName) + && (t[nameLen + 1] == '>' + || t[nameLen + 1] == ' ')) return t; + + } while (t = XmlNextNode (t)); + + return NULL; +} + + +char *XmlFindElementByAttributeValue (char *xml, char *nodeName, char *attrName, char *attrValue) +{ + char attr[2048]; + + while (xml = XmlFindElement (xml, nodeName)) + { + XmlGetAttributeText (xml, attrName, attr, sizeof (attr)); + if (strcmp (attr, attrValue) == 0) + return xml; + + xml++; + } + + return NULL; +} + + +char *XmlGetAttributeText (char *xmlNode, char *xmlAttrName, char *xmlAttrValue, int xmlAttrValueSize) +{ + char *t = xmlNode; + char *e = xmlNode; + int l = 0; + + xmlAttrValue[0] = 0; + if (t[0] != '<') return NULL; + + e = strchr (e, '>'); + if (e == NULL) return NULL; + + while ((t = strstr (t, xmlAttrName)) && t < e) + { + char *o = t + strlen (xmlAttrName); + if (t[-1] == ' ' + && + (BeginsWith (o, "=\"") + || BeginsWith (o, "= \"") + || BeginsWith (o, " =\"") + || BeginsWith (o, " = \"")) + ) + break; + + t++; + } + + if (t == NULL || t > e) return NULL; + + t = strchr (t, '"') + 1; + e = strchr (t, '"'); + l = (int)(e - t); + if (e == NULL || l > xmlAttrValueSize) return NULL; + + memcpy (xmlAttrValue, t, l); + xmlAttrValue[l] = 0; + + return xmlAttrValue; +} + + +char *XmlGetNodeText (char *xmlNode, char *xmlText, int xmlTextSize) +{ + char *t = xmlNode; + char *e = xmlNode + 1; + int l = 0, i = 0, j = 0; + + xmlText[0] = 0; + + if (t[0] != '<') + return NULL; + + t = strchr (t, '>') + 1; + if (t == (char *)1) return NULL; + + e = strchr (e, '<'); + if (e == NULL) return NULL; + + l = (int)(e - t); + if (e == NULL || l > xmlTextSize) return NULL; + + while (i < l) + { + if (BeginsWith (&t[i], "<")) + { + xmlText[j++] = '<'; + i += 4; + continue; + } + if (BeginsWith (&t[i], ">")) + { + xmlText[j++] = '>'; + i += 4; + continue; + } + if (BeginsWith (&t[i], "&")) + { + xmlText[j++] = '&'; + i += 5; + continue; + } + xmlText[j++] = t[i++]; + } + xmlText[j] = 0; + + return t; +} + + +char *XmlQuoteText (const char *textSrc, char *textDst, int textDstMaxSize) +{ + char *textDstLast = textDst + textDstMaxSize - 1; + + if (textDstMaxSize == 0) + return NULL; + + while (*textSrc != 0 && textDst <= textDstLast) + { + char c = *textSrc++; + switch (c) + { + case '&': + if (textDst + 6 > textDstLast) + return NULL; + strcpy (textDst, "&"); + textDst += 5; + continue; + + case '>': + if (textDst + 5 > textDstLast) + return NULL; + strcpy (textDst, ">"); + textDst += 4; + continue; + + case '<': + if (textDst + 5 > textDstLast) + return NULL; + strcpy (textDst, "<"); + textDst += 4; + continue; + + default: + *textDst++ = c; + } + } + + if (textDst > textDstLast) + return NULL; + + *textDst = 0; + return textDst; +} + + +int XmlWriteHeader (FILE *file) +{ + return fputs ("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TrueCrypt>", file); +} + + +int XmlWriteHeaderW (FILE *file) +{ + return fputws (L"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<TrueCrypt>", file); +} + + +int XmlWriteFooter (FILE *file) +{ + return fputs ("\n</TrueCrypt>", file); +} + + +int XmlWriteFooterW (FILE *file) +{ + return fputws (L"\n</TrueCrypt>", file); +} diff --git a/Common/Xml.h b/Common/Xml.h new file mode 100644 index 0000000..2ec2010 --- /dev/null +++ b/Common/Xml.h @@ -0,0 +1,26 @@ +/* + Copyright (c) 2005-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. +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +char *XmlNextNode (char *xmlNode); +char *XmlFindElement (char *xmlNode, char *nodeName); +char *XmlGetAttributeText (char *xmlNode, char *xmlAttrName, char *xmlAttrValue, int xmlAttrValueSize); +char *XmlGetNodeText (char *xmlNode, char *xmlText, int xmlTextSize); +int XmlWriteHeader (FILE *file); +int XmlWriteHeaderW (FILE *file); +int XmlWriteFooter (FILE *file); +int XmlWriteFooterW (FILE *file); +char *XmlFindElementByAttributeValue (char *xml, char *nodeName, char *attrName, char *attrValue); +char *XmlQuoteText (const char *textSrc, char *textDst, int textDstMaxSize); + +#ifdef __cplusplus +} +#endif diff --git a/Common/Xts.c b/Common/Xts.c new file mode 100644 index 0000000..d7537a1 --- /dev/null +++ b/Common/Xts.c @@ -0,0 +1,746 @@ +/* + 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. +*/ + +/* If native 64-bit data types are not available, define TC_NO_COMPILER_INT64. + +For big-endian platforms define BYTE_ORDER as BIG_ENDIAN. */ + + +#ifdef TC_MINIMIZE_CODE_SIZE +// Preboot/boot version +# ifndef TC_NO_COMPILER_INT64 +# define TC_NO_COMPILER_INT64 +# endif +# pragma optimize ("tl", on) +#endif + +#ifdef TC_NO_COMPILER_INT64 +# include <memory.h> +#endif + +#include "Xts.h" + + +#ifndef TC_NO_COMPILER_INT64 + +// length: number of bytes to encrypt; may be larger than one data unit and must be divisible by the cipher block size +// ks: the primary key schedule +// ks2: the secondary key schedule +// startDataUnitNo: The sequential number of the data unit with which the buffer starts. +// startCipherBlockNo: The sequential number of the first plaintext block to encrypt inside the data unit startDataUnitNo. +// When encrypting the data unit from its first block, startCipherBlockNo is 0. +// The startCipherBlockNo value applies only to the first data unit in the buffer; each successive +// data unit is encrypted from its first block. The start of the buffer does not have to be +// aligned with the start of a data unit. If it is aligned, startCipherBlockNo must be 0; if it +// is not aligned, startCipherBlockNo must reflect the misalignment accordingly. +void EncryptBufferXTS (unsigned __int8 *buffer, + TC_LARGEST_COMPILER_UINT length, + const UINT64_STRUCT *startDataUnitNo, + unsigned int startCipherBlockNo, + unsigned __int8 *ks, + unsigned __int8 *ks2, + int cipher) +{ + if (CipherSupportsIntraDataUnitParallelization (cipher)) + EncryptBufferXTSParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher); + else + EncryptBufferXTSNonParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher); +} + + +// Optimized for encryption algorithms supporting intra-data-unit parallelization +static void EncryptBufferXTSParallel (unsigned __int8 *buffer, + TC_LARGEST_COMPILER_UINT length, + const UINT64_STRUCT *startDataUnitNo, + unsigned int startCipherBlockNo, + unsigned __int8 *ks, + unsigned __int8 *ks2, + int cipher) +{ + unsigned __int8 finalCarry; + unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; + unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; + unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; + unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues; + unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; + unsigned __int64 *bufPtr = (unsigned __int64 *) buffer; + unsigned __int64 *dataUnitBufPtr; + unsigned int startBlock = startCipherBlockNo, endBlock, block; + unsigned __int64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1; + TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; + + /* The encrypted data unit number (i.e. the resultant ciphertext block) is to be multiplied in the + finite field GF(2^128) by j-th power of n, where j is the sequential plaintext/ciphertext block + number and n is 2, a primitive element of GF(2^128). This can be (and is) simplified and implemented + as a left shift of the preceding whitening value by one bit (with carry propagating). In addition, if + the shift of the highest byte results in a carry, 135 is XORed into the lowest byte. The value 135 is + derived from the modulus of the Galois Field (x^128+x^7+x^2+x+1). */ + + // Convert the 64-bit data unit number into a little-endian 16-byte array. + // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. + dataUnitNo = startDataUnitNo->Value; + *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); + *((unsigned __int64 *) byteBufUnitNo + 1) = 0; + + if (length % BYTES_PER_XTS_BLOCK) + TC_THROW_FATAL_EXCEPTION; + + blockCount = length / BYTES_PER_XTS_BLOCK; + + // Process all blocks in the buffer + while (blockCount > 0) + { + if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) + endBlock = startBlock + (unsigned int) blockCount; + else + endBlock = BLOCKS_PER_XTS_DATA_UNIT; + + whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; + whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; + + // Encrypt the data unit number using the secondary key (in order to generate the first + // whitening value for this data unit) + *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo); + *(whiteningValuePtr64 + 1) = 0; + EncipherBlock (cipher, whiteningValue, ks2); + + // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit + // whitening values are stored in memory as a sequence of 64-bit integers in reverse order. + for (block = 0; block < endBlock; block++) + { + if (block >= startBlock) + { + *whiteningValuesPtr64-- = *whiteningValuePtr64++; + *whiteningValuesPtr64-- = *whiteningValuePtr64; + } + else + whiteningValuePtr64++; + + // Derive the next whitening value + +#if BYTE_ORDER == LITTLE_ENDIAN + + // Little-endian platforms + + finalCarry = + (*whiteningValuePtr64 & 0x8000000000000000) ? + 135 : 0; + + *whiteningValuePtr64-- <<= 1; + + if (*whiteningValuePtr64 & 0x8000000000000000) + *(whiteningValuePtr64 + 1) |= 1; + + *whiteningValuePtr64 <<= 1; +#else + + // Big-endian platforms + + finalCarry = + (*whiteningValuePtr64 & 0x80) ? + 135 : 0; + + *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); + + whiteningValuePtr64--; + + if (*whiteningValuePtr64 & 0x80) + *(whiteningValuePtr64 + 1) |= 0x0100000000000000; + + *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); +#endif + + whiteningValue[0] ^= finalCarry; + } + + dataUnitBufPtr = bufPtr; + whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; + + // Encrypt all blocks in this data unit + + for (block = startBlock; block < endBlock; block++) + { + // Pre-whitening + *bufPtr++ ^= *whiteningValuesPtr64--; + *bufPtr++ ^= *whiteningValuesPtr64--; + } + + // Actual encryption + EncipherBlocks (cipher, dataUnitBufPtr, ks, endBlock - startBlock); + + bufPtr = dataUnitBufPtr; + whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; + + for (block = startBlock; block < endBlock; block++) + { + // Post-whitening + *bufPtr++ ^= *whiteningValuesPtr64--; + *bufPtr++ ^= *whiteningValuesPtr64--; + } + + blockCount -= endBlock - startBlock; + startBlock = 0; + dataUnitNo++; + *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); + } + + FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); + FAST_ERASE64 (whiteningValues, sizeof (whiteningValues)); +} + + +// Optimized for encryption algorithms not supporting intra-data-unit parallelization +static void EncryptBufferXTSNonParallel (unsigned __int8 *buffer, + TC_LARGEST_COMPILER_UINT length, + const UINT64_STRUCT *startDataUnitNo, + unsigned int startCipherBlockNo, + unsigned __int8 *ks, + unsigned __int8 *ks2, + int cipher) +{ + unsigned __int8 finalCarry; + unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; + unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; + unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; + unsigned __int64 *bufPtr = (unsigned __int64 *) buffer; + unsigned int startBlock = startCipherBlockNo, endBlock, block; + TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; + + /* The encrypted data unit number (i.e. the resultant ciphertext block) is to be multiplied in the + finite field GF(2^128) by j-th power of n, where j is the sequential plaintext/ciphertext block + number and n is 2, a primitive element of GF(2^128). This can be (and is) simplified and implemented + as a left shift of the preceding whitening value by one bit (with carry propagating). In addition, if + the shift of the highest byte results in a carry, 135 is XORed into the lowest byte. The value 135 is + derived from the modulus of the Galois Field (x^128+x^7+x^2+x+1). */ + + // Convert the 64-bit data unit number into a little-endian 16-byte array. + // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. + dataUnitNo = startDataUnitNo->Value; + *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); + *((unsigned __int64 *) byteBufUnitNo + 1) = 0; + + if (length % BYTES_PER_XTS_BLOCK) + TC_THROW_FATAL_EXCEPTION; + + blockCount = length / BYTES_PER_XTS_BLOCK; + + // Process all blocks in the buffer + while (blockCount > 0) + { + if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) + endBlock = startBlock + (unsigned int) blockCount; + else + endBlock = BLOCKS_PER_XTS_DATA_UNIT; + + whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; + + // Encrypt the data unit number using the secondary key (in order to generate the first + // whitening value for this data unit) + *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo); + *(whiteningValuePtr64 + 1) = 0; + EncipherBlock (cipher, whiteningValue, ks2); + + // Generate (and apply) subsequent whitening values for blocks in this data unit and + // encrypt all relevant blocks in this data unit + for (block = 0; block < endBlock; block++) + { + if (block >= startBlock) + { + // Pre-whitening + *bufPtr++ ^= *whiteningValuePtr64++; + *bufPtr-- ^= *whiteningValuePtr64--; + + // Actual encryption + EncipherBlock (cipher, bufPtr, ks); + + // Post-whitening + *bufPtr++ ^= *whiteningValuePtr64++; + *bufPtr++ ^= *whiteningValuePtr64; + } + else + whiteningValuePtr64++; + + // Derive the next whitening value + +#if BYTE_ORDER == LITTLE_ENDIAN + + // Little-endian platforms + + finalCarry = + (*whiteningValuePtr64 & 0x8000000000000000) ? + 135 : 0; + + *whiteningValuePtr64-- <<= 1; + + if (*whiteningValuePtr64 & 0x8000000000000000) + *(whiteningValuePtr64 + 1) |= 1; + + *whiteningValuePtr64 <<= 1; +#else + + // Big-endian platforms + + finalCarry = + (*whiteningValuePtr64 & 0x80) ? + 135 : 0; + + *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); + + whiteningValuePtr64--; + + if (*whiteningValuePtr64 & 0x80) + *(whiteningValuePtr64 + 1) |= 0x0100000000000000; + + *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); +#endif + + whiteningValue[0] ^= finalCarry; + } + + blockCount -= endBlock - startBlock; + startBlock = 0; + dataUnitNo++; + *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); + } + + FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); +} + + +// For descriptions of the input parameters, see EncryptBufferXTS(). +void DecryptBufferXTS (unsigned __int8 *buffer, + TC_LARGEST_COMPILER_UINT length, + const UINT64_STRUCT *startDataUnitNo, + unsigned int startCipherBlockNo, + unsigned __int8 *ks, + unsigned __int8 *ks2, + int cipher) +{ + if (CipherSupportsIntraDataUnitParallelization (cipher)) + DecryptBufferXTSParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher); + else + DecryptBufferXTSNonParallel (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher); +} + + +// Optimized for encryption algorithms supporting intra-data-unit parallelization +static void DecryptBufferXTSParallel (unsigned __int8 *buffer, + TC_LARGEST_COMPILER_UINT length, + const UINT64_STRUCT *startDataUnitNo, + unsigned int startCipherBlockNo, + unsigned __int8 *ks, + unsigned __int8 *ks2, + int cipher) +{ + unsigned __int8 finalCarry; + unsigned __int8 whiteningValues [ENCRYPTION_DATA_UNIT_SIZE]; + unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; + unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; + unsigned __int64 *whiteningValuesPtr64 = (unsigned __int64 *) whiteningValues; + unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; + unsigned __int64 *bufPtr = (unsigned __int64 *) buffer; + unsigned __int64 *dataUnitBufPtr; + unsigned int startBlock = startCipherBlockNo, endBlock, block; + unsigned __int64 *const finalInt64WhiteningValuesPtr = whiteningValuesPtr64 + sizeof (whiteningValues) / sizeof (*whiteningValuesPtr64) - 1; + TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; + + // Convert the 64-bit data unit number into a little-endian 16-byte array. + // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. + dataUnitNo = startDataUnitNo->Value; + *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); + *((unsigned __int64 *) byteBufUnitNo + 1) = 0; + + if (length % BYTES_PER_XTS_BLOCK) + TC_THROW_FATAL_EXCEPTION; + + blockCount = length / BYTES_PER_XTS_BLOCK; + + // Process all blocks in the buffer + while (blockCount > 0) + { + if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) + endBlock = startBlock + (unsigned int) blockCount; + else + endBlock = BLOCKS_PER_XTS_DATA_UNIT; + + whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; + whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; + + // Encrypt the data unit number using the secondary key (in order to generate the first + // whitening value for this data unit) + *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo); + *(whiteningValuePtr64 + 1) = 0; + EncipherBlock (cipher, whiteningValue, ks2); + + // Generate subsequent whitening values for blocks in this data unit. Note that all generated 128-bit + // whitening values are stored in memory as a sequence of 64-bit integers in reverse order. + for (block = 0; block < endBlock; block++) + { + if (block >= startBlock) + { + *whiteningValuesPtr64-- = *whiteningValuePtr64++; + *whiteningValuesPtr64-- = *whiteningValuePtr64; + } + else + whiteningValuePtr64++; + + // Derive the next whitening value + +#if BYTE_ORDER == LITTLE_ENDIAN + + // Little-endian platforms + + finalCarry = + (*whiteningValuePtr64 & 0x8000000000000000) ? + 135 : 0; + + *whiteningValuePtr64-- <<= 1; + + if (*whiteningValuePtr64 & 0x8000000000000000) + *(whiteningValuePtr64 + 1) |= 1; + + *whiteningValuePtr64 <<= 1; + +#else + // Big-endian platforms + + finalCarry = + (*whiteningValuePtr64 & 0x80) ? + 135 : 0; + + *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); + + whiteningValuePtr64--; + + if (*whiteningValuePtr64 & 0x80) + *(whiteningValuePtr64 + 1) |= 0x0100000000000000; + + *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); +#endif + + whiteningValue[0] ^= finalCarry; + } + + dataUnitBufPtr = bufPtr; + whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; + + // Decrypt blocks in this data unit + + for (block = startBlock; block < endBlock; block++) + { + *bufPtr++ ^= *whiteningValuesPtr64--; + *bufPtr++ ^= *whiteningValuesPtr64--; + } + + DecipherBlocks (cipher, dataUnitBufPtr, ks, endBlock - startBlock); + + bufPtr = dataUnitBufPtr; + whiteningValuesPtr64 = finalInt64WhiteningValuesPtr; + + for (block = startBlock; block < endBlock; block++) + { + *bufPtr++ ^= *whiteningValuesPtr64--; + *bufPtr++ ^= *whiteningValuesPtr64--; + } + + blockCount -= endBlock - startBlock; + startBlock = 0; + dataUnitNo++; + + *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); + } + + FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); + FAST_ERASE64 (whiteningValues, sizeof (whiteningValues)); +} + + +// Optimized for encryption algorithms not supporting intra-data-unit parallelization +static void DecryptBufferXTSNonParallel (unsigned __int8 *buffer, + TC_LARGEST_COMPILER_UINT length, + const UINT64_STRUCT *startDataUnitNo, + unsigned int startCipherBlockNo, + unsigned __int8 *ks, + unsigned __int8 *ks2, + int cipher) +{ + unsigned __int8 finalCarry; + unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; + unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; + unsigned __int64 *whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; + unsigned __int64 *bufPtr = (unsigned __int64 *) buffer; + unsigned int startBlock = startCipherBlockNo, endBlock, block; + TC_LARGEST_COMPILER_UINT blockCount, dataUnitNo; + + // Convert the 64-bit data unit number into a little-endian 16-byte array. + // Note that as we are converting a 64-bit number into a 16-byte array we can always zero the last 8 bytes. + dataUnitNo = startDataUnitNo->Value; + *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); + *((unsigned __int64 *) byteBufUnitNo + 1) = 0; + + if (length % BYTES_PER_XTS_BLOCK) + TC_THROW_FATAL_EXCEPTION; + + blockCount = length / BYTES_PER_XTS_BLOCK; + + // Process all blocks in the buffer + while (blockCount > 0) + { + if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) + endBlock = startBlock + (unsigned int) blockCount; + else + endBlock = BLOCKS_PER_XTS_DATA_UNIT; + + whiteningValuePtr64 = (unsigned __int64 *) whiteningValue; + + // Encrypt the data unit number using the secondary key (in order to generate the first + // whitening value for this data unit) + *whiteningValuePtr64 = *((unsigned __int64 *) byteBufUnitNo); + *(whiteningValuePtr64 + 1) = 0; + EncipherBlock (cipher, whiteningValue, ks2); + + // Generate (and apply) subsequent whitening values for blocks in this data unit and + // decrypt all relevant blocks in this data unit + for (block = 0; block < endBlock; block++) + { + if (block >= startBlock) + { + // Post-whitening + *bufPtr++ ^= *whiteningValuePtr64++; + *bufPtr-- ^= *whiteningValuePtr64--; + + // Actual decryption + DecipherBlock (cipher, bufPtr, ks); + + // Pre-whitening + *bufPtr++ ^= *whiteningValuePtr64++; + *bufPtr++ ^= *whiteningValuePtr64; + } + else + whiteningValuePtr64++; + + // Derive the next whitening value + +#if BYTE_ORDER == LITTLE_ENDIAN + + // Little-endian platforms + + finalCarry = + (*whiteningValuePtr64 & 0x8000000000000000) ? + 135 : 0; + + *whiteningValuePtr64-- <<= 1; + + if (*whiteningValuePtr64 & 0x8000000000000000) + *(whiteningValuePtr64 + 1) |= 1; + + *whiteningValuePtr64 <<= 1; + +#else + // Big-endian platforms + + finalCarry = + (*whiteningValuePtr64 & 0x80) ? + 135 : 0; + + *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); + + whiteningValuePtr64--; + + if (*whiteningValuePtr64 & 0x80) + *(whiteningValuePtr64 + 1) |= 0x0100000000000000; + + *whiteningValuePtr64 = LE64 (LE64 (*whiteningValuePtr64) << 1); +#endif + + whiteningValue[0] ^= finalCarry; + } + + blockCount -= endBlock - startBlock; + startBlock = 0; + dataUnitNo++; + *((unsigned __int64 *) byteBufUnitNo) = LE64 (dataUnitNo); + } + + FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); +} + + +#else // TC_NO_COMPILER_INT64 + +/* ---- The following code is to be used only when native 64-bit data types are not available. ---- */ + +#if BYTE_ORDER == BIG_ENDIAN +#error The TC_NO_COMPILER_INT64 version of the XTS code is not compatible with big-endian platforms +#endif + + +// Converts a 64-bit unsigned integer (passed as two 32-bit integers for compatibility with non-64-bit +// environments/platforms) into a little-endian 16-byte array. +static void Uint64ToLE16ByteArray (unsigned __int8 *byteBuf, unsigned __int32 highInt32, unsigned __int32 lowInt32) +{ + unsigned __int32 *bufPtr32 = (unsigned __int32 *) byteBuf; + + *bufPtr32++ = lowInt32; + *bufPtr32++ = highInt32; + + // We're converting a 64-bit number into a little-endian 16-byte array so we can zero the last 8 bytes + *bufPtr32++ = 0; + *bufPtr32 = 0; +} + + +// Encrypts or decrypts all blocks in the buffer in XTS mode. For descriptions of the input parameters, +// see the 64-bit version of EncryptBufferXTS(). +static void EncryptDecryptBufferXTS32 (const unsigned __int8 *buffer, + TC_LARGEST_COMPILER_UINT length, + const UINT64_STRUCT *startDataUnitNo, + unsigned int startBlock, + unsigned __int8 *ks, + unsigned __int8 *ks2, + int cipher, + BOOL decryption) +{ + TC_LARGEST_COMPILER_UINT blockCount; + UINT64_STRUCT dataUnitNo; + unsigned int block; + unsigned int endBlock; + unsigned __int8 byteBufUnitNo [BYTES_PER_XTS_BLOCK]; + unsigned __int8 whiteningValue [BYTES_PER_XTS_BLOCK]; + unsigned __int32 *bufPtr32 = (unsigned __int32 *) buffer; + unsigned __int32 *whiteningValuePtr32 = (unsigned __int32 *) whiteningValue; + unsigned __int8 finalCarry; + unsigned __int32 *const finalDwordWhiteningValuePtr = whiteningValuePtr32 + sizeof (whiteningValue) / sizeof (*whiteningValuePtr32) - 1; + + // Store the 64-bit data unit number in a way compatible with non-64-bit environments/platforms + dataUnitNo.HighPart = startDataUnitNo->HighPart; + dataUnitNo.LowPart = startDataUnitNo->LowPart; + + blockCount = length / BYTES_PER_XTS_BLOCK; + + // Convert the 64-bit data unit number into a little-endian 16-byte array. + // (Passed as two 32-bit integers for compatibility with non-64-bit environments/platforms.) + Uint64ToLE16ByteArray (byteBufUnitNo, dataUnitNo.HighPart, dataUnitNo.LowPart); + + // Generate whitening values for all blocks in the buffer + while (blockCount > 0) + { + if (blockCount < BLOCKS_PER_XTS_DATA_UNIT) + endBlock = startBlock + (unsigned int) blockCount; + else + endBlock = BLOCKS_PER_XTS_DATA_UNIT; + + // Encrypt the data unit number using the secondary key (in order to generate the first + // whitening value for this data unit) + memcpy (whiteningValue, byteBufUnitNo, BYTES_PER_XTS_BLOCK); + EncipherBlock (cipher, whiteningValue, ks2); + + // Generate (and apply) subsequent whitening values for blocks in this data unit and + // encrypt/decrypt all relevant blocks in this data unit + for (block = 0; block < endBlock; block++) + { + if (block >= startBlock) + { + whiteningValuePtr32 = (unsigned __int32 *) whiteningValue; + + // Whitening + *bufPtr32++ ^= *whiteningValuePtr32++; + *bufPtr32++ ^= *whiteningValuePtr32++; + *bufPtr32++ ^= *whiteningValuePtr32++; + *bufPtr32 ^= *whiteningValuePtr32; + + bufPtr32 -= BYTES_PER_XTS_BLOCK / sizeof (*bufPtr32) - 1; + + // Actual encryption/decryption + if (decryption) + DecipherBlock (cipher, bufPtr32, ks); + else + EncipherBlock (cipher, bufPtr32, ks); + + whiteningValuePtr32 = (unsigned __int32 *) whiteningValue; + + // Whitening + *bufPtr32++ ^= *whiteningValuePtr32++; + *bufPtr32++ ^= *whiteningValuePtr32++; + *bufPtr32++ ^= *whiteningValuePtr32++; + *bufPtr32++ ^= *whiteningValuePtr32; + } + + // Derive the next whitening value + + finalCarry = 0; + + for (whiteningValuePtr32 = finalDwordWhiteningValuePtr; + whiteningValuePtr32 >= (unsigned __int32 *) whiteningValue; + whiteningValuePtr32--) + { + if (*whiteningValuePtr32 & 0x80000000) // If the following shift results in a carry + { + if (whiteningValuePtr32 != finalDwordWhiteningValuePtr) // If not processing the highest double word + { + // A regular carry + *(whiteningValuePtr32 + 1) |= 1; + } + else + { + // The highest byte shift will result in a carry + finalCarry = 135; + } + } + + *whiteningValuePtr32 <<= 1; + } + + whiteningValue[0] ^= finalCarry; + } + + blockCount -= endBlock - startBlock; + startBlock = 0; + + // Increase the data unit number by one + if (!++dataUnitNo.LowPart) + { + dataUnitNo.HighPart++; + } + + // Convert the 64-bit data unit number into a little-endian 16-byte array. + Uint64ToLE16ByteArray (byteBufUnitNo, dataUnitNo.HighPart, dataUnitNo.LowPart); + } + + FAST_ERASE64 (whiteningValue, sizeof (whiteningValue)); +} + + +// For descriptions of the input parameters, see the 64-bit version of EncryptBufferXTS() above. +void EncryptBufferXTS (unsigned __int8 *buffer, + TC_LARGEST_COMPILER_UINT length, + const UINT64_STRUCT *startDataUnitNo, + unsigned int startCipherBlockNo, + unsigned __int8 *ks, + unsigned __int8 *ks2, + int cipher) +{ + // Encrypt all plaintext blocks in the buffer + EncryptDecryptBufferXTS32 (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher, FALSE); +} + + +// For descriptions of the input parameters, see the 64-bit version of EncryptBufferXTS(). +void DecryptBufferXTS (unsigned __int8 *buffer, + TC_LARGEST_COMPILER_UINT length, + const UINT64_STRUCT *startDataUnitNo, + unsigned int startCipherBlockNo, + unsigned __int8 *ks, + unsigned __int8 *ks2, + int cipher) +{ + // Decrypt all ciphertext blocks in the buffer + EncryptDecryptBufferXTS32 (buffer, length, startDataUnitNo, startCipherBlockNo, ks, ks2, cipher, TRUE); +} + +#endif // TC_NO_COMPILER_INT64 diff --git a/Common/Xts.h b/Common/Xts.h new file mode 100644 index 0000000..c6f173d --- /dev/null +++ b/Common/Xts.h @@ -0,0 +1,80 @@ +/* + 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 XTS_H +#define XTS_H + +// Header files (optional) + +#include "Tcdefs.h" +#include "Common/Endian.h" +#include "Crypto.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Macros + +#ifndef LITTLE_ENDIAN +# define LITTLE_ENDIAN 1 +#endif + +#ifndef BIG_ENDIAN +# define BIG_ENDIAN 2 +#endif + +#ifndef BYTE_ORDER +# define BYTE_ORDER LITTLE_ENDIAN +#endif + +#ifndef LE64 +# if BYTE_ORDER == LITTLE_ENDIAN +# define LE64(x) (x) +# endif +#endif + +// Custom data types + +#ifndef TC_LARGEST_COMPILER_UINT +# ifdef TC_NO_COMPILER_INT64 + typedef unsigned __int32 TC_LARGEST_COMPILER_UINT; +# else + typedef unsigned __int64 TC_LARGEST_COMPILER_UINT; +# endif +#endif + +#ifndef TCDEFS_H +typedef union +{ + struct + { + unsigned __int32 LowPart; + unsigned __int32 HighPart; + }; +# ifndef TC_NO_COMPILER_INT64 + unsigned __int64 Value; +# endif + +} UINT64_STRUCT; +#endif + +// Public function prototypes + +void EncryptBufferXTS (unsigned __int8 *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher); +static void EncryptBufferXTSParallel (unsigned __int8 *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher); +static void EncryptBufferXTSNonParallel (unsigned __int8 *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher); +void DecryptBufferXTS (unsigned __int8 *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher); +static void DecryptBufferXTSParallel (unsigned __int8 *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher); +static void DecryptBufferXTSNonParallel (unsigned __int8 *buffer, TC_LARGEST_COMPILER_UINT length, const UINT64_STRUCT *startDataUnitNo, unsigned int startCipherBlockNo, unsigned __int8 *ks, unsigned __int8 *ks2, int cipher); + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef XTS_H |