/* Legal Notice: Some portions of the source code contained in this file were derived from the source code of TrueCrypt 7.1a, which is Copyright (c) 2003-2012 TrueCrypt Developers Association and which is governed by the TrueCrypt License 3.0, also 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) 2013-2017 IDRIX and are governed by the Apache License 2.0 the full text of which is contained in the file License.txt included in VeraCrypt binary and source code distribution packages. */ #include "Tcdefs.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined (TCMOUNT) || defined (VOLFORMAT) #include #include #include #endif #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" #include "Progress.h" #include "zip.h" #ifdef TCMOUNT #include "Mount/Mount.h" #include "Mount/resource.h" #endif #ifdef VOLFORMAT #include "Format/Tcformat.h" #endif #ifdef SETUP #include "Setup/Setup.h" #endif #include #include #include #include #pragma comment( lib, "setupapi.lib" ) #ifndef TTI_INFO_LARGE #define TTI_INFO_LARGE 4 #endif #ifndef TTI_WARNING_LARGE #define TTI_WARNING_LARGE 5 #endif #ifndef TTI_ERROR_LARGE #define TTI_ERROR_LARGE 6 #endif /* GPT Partition Type GUIDs */ #define LOCAL_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) const GUID name = {l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8} LOCAL_DEFINE_GUID(PARTITION_ENTRY_UNUSED_GUID, 0x00000000L, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00); // Entry unused LOCAL_DEFINE_GUID(PARTITION_SYSTEM_GUID, 0xC12A7328L, 0xF81F, 0x11D2, 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B); // EFI system partition LOCAL_DEFINE_GUID(PARTITION_MSFT_RESERVED_GUID, 0xE3C9E316L, 0x0B5C, 0x4DB8, 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE); // Microsoft reserved space LOCAL_DEFINE_GUID(PARTITION_BASIC_DATA_GUID, 0xEBD0A0A2L, 0xB9E5, 0x4433, 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7); // Basic data partition LOCAL_DEFINE_GUID(PARTITION_LDM_METADATA_GUID, 0x5808C8AAL, 0x7E8F, 0x42E0, 0x85, 0xD2, 0xE1, 0xE9, 0x04, 0x34, 0xCF, 0xB3); // Logical Disk Manager metadata partition LOCAL_DEFINE_GUID(PARTITION_LDM_DATA_GUID, 0xAF9B60A0L, 0x1431, 0x4F62, 0xBC, 0x68, 0x33, 0x11, 0x71, 0x4A, 0x69, 0xAD); // Logical Disk Manager data partition LOCAL_DEFINE_GUID(PARTITION_MSFT_RECOVERY_GUID, 0xDE94BBA4L, 0x06D1, 0x4D40, 0xA1, 0x6A, 0xBF, 0xD5, 0x01, 0x79, 0xD6, 0xAC); // Microsoft recovery partition LOCAL_DEFINE_GUID(PARTITION_CLUSTER_GUID, 0xdb97dba9L, 0x0840, 0x4bae, 0x97, 0xf0, 0xff, 0xb9, 0xa3, 0x27, 0xc7, 0xe1); // Cluster metadata partition using namespace VeraCrypt; LONG DriverVersion; char *LastDialogId; wchar_t szHelpFile[TC_MAX_PATH]; wchar_t szHelpFile2[TC_MAX_PATH]; wchar_t SecurityTokenLibraryPath[TC_MAX_PATH]; char CmdTokenPin [TC_MAX_PATH] = {0}; 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; WCHAR EditPasswordChar = 0; 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 bShowDisconnectedNetworkDrives = FALSE; BOOL bHideWaitingDialog = FALSE; BOOL bCmdHideWaitingDialog = FALSE; BOOL bCmdHideWaitingDialogValid = FALSE; BOOL bUseSecureDesktop = FALSE; BOOL bCmdUseSecureDesktop = FALSE; BOOL bCmdUseSecureDesktopValid = FALSE; BOOL bStartOnLogon = FALSE; BOOL bMountDevicesOnLogon = FALSE; BOOL bMountFavoritesOnLogon = FALSE; BOOL bHistory = FALSE; #ifndef SETUP BOOL bLanguageSetInSetup = FALSE; #endif // 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; int CurrentOSBuildNumber = 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 PimEnable = FALSE; 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; BOOL WaitDialogDisplaying = 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; /* Critical section used to protect access to global variables used in WNetGetConnection calls */ CRITICAL_SECTION csWNetCalls; /* Critical section used to protect access to global list of physical drives */ CRITICAL_SECTION csMountableDevices; CRITICAL_SECTION csVolumeIdCandidates; static std::vector mountableDevices; static std::vector rawHostDeviceList; 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. */ wchar_t SysPartitionDevicePath [TC_MAX_PATH]; wchar_t SysDriveDevicePath [TC_MAX_PATH]; wstring 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 HMODULE hRichEditDll = NULL; HMODULE hComctl32Dll = NULL; HMODULE hSetupDll = NULL; HMODULE hShlwapiDll = NULL; HMODULE hProfApiDll = NULL; HMODULE hUsp10Dll = NULL; HMODULE hCryptSpDll = NULL; HMODULE hUXThemeDll = NULL; HMODULE hUserenvDll = NULL; HMODULE hRsaenhDll = NULL; HMODULE himm32dll = NULL; HMODULE hMSCTFdll = NULL; HMODULE hfltlibdll = NULL; HMODULE hframedyndll = NULL; HMODULE hpsapidll = NULL; HMODULE hsecur32dll = NULL; HMODULE hnetapi32dll = NULL; HMODULE hauthzdll = NULL; HMODULE hxmllitedll = NULL; HMODULE hmprdll = NULL; HMODULE hsppdll = NULL; HMODULE vssapidll = NULL; HMODULE hvsstracedll = NULL; HMODULE hcfgmgr32dll = NULL; HMODULE hdevobjdll = NULL; HMODULE hpowrprofdll = NULL; HMODULE hsspiclidll = NULL; HMODULE hcryptbasedll = NULL; HMODULE hdwmapidll = NULL; HMODULE hmsasn1dll = NULL; HMODULE hcrypt32dll = NULL; HMODULE hbcryptdll = NULL; HMODULE hbcryptprimitivesdll = NULL; HMODULE hMsls31 = NULL; HMODULE hntmartadll = NULL; HMODULE hwinscarddll = NULL; HMODULE hmsvcrtdll = NULL; HMODULE hWinTrustLib = NULL; #define FREE_DLL(h) if (h) { FreeLibrary (h); h = NULL;} #ifndef BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE #define BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE 0x00000001 #endif #ifndef BASE_SEARCH_PATH_PERMANENT #define BASE_SEARCH_PATH_PERMANENT 0x00008000 #endif #ifndef LOAD_LIBRARY_SEARCH_SYSTEM32 #define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800 #endif typedef BOOL (WINAPI *SetDllDirectoryPtr)(LPCWSTR lpPathName); typedef BOOL (WINAPI *SetSearchPathModePtr)(DWORD Flags); typedef BOOL (WINAPI *SetDefaultDllDirectoriesPtr)(DWORD DirectoryFlags); typedef void (WINAPI *InitCommonControlsPtr)(void); typedef HIMAGELIST (WINAPI *ImageList_CreatePtr)(int cx, int cy, UINT flags, int cInitial, int cGrow); typedef int (WINAPI *ImageList_AddPtr)(HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask); typedef VOID (WINAPI *SetupCloseInfFilePtr)(HINF InfHandle); typedef HKEY (WINAPI *SetupDiOpenClassRegKeyPtr)(CONST GUID *ClassGuid,REGSAM samDesired); typedef BOOL (WINAPI *SetupInstallFromInfSectionWPtr)(HWND,HINF,PCWSTR,UINT,HKEY,PCWSTR,UINT,PSP_FILE_CALLBACK_W,PVOID,HDEVINFO,PSP_DEVINFO_DATA); typedef HINF (WINAPI *SetupOpenInfFileWPtr)(PCWSTR FileName,PCWSTR InfClass,DWORD InfStyle,PUINT ErrorLine); typedef LSTATUS (STDAPICALLTYPE *SHDeleteKeyWPtr)(HKEY hkey, LPCWSTR pszSubKey); typedef HRESULT (STDAPICALLTYPE *SHStrDupWPtr)(LPCWSTR psz, LPWSTR *ppwsz); // ChangeWindowMessageFilter typedef BOOL (WINAPI *ChangeWindowMessageFilterPtr) (UINT, DWORD); SetDllDirectoryPtr SetDllDirectoryFn = NULL; SetSearchPathModePtr SetSearchPathModeFn = NULL; SetDefaultDllDirectoriesPtr SetDefaultDllDirectoriesFn = NULL; ImageList_CreatePtr ImageList_CreateFn = NULL; ImageList_AddPtr ImageList_AddFn = NULL; SetupCloseInfFilePtr SetupCloseInfFileFn = NULL; SetupDiOpenClassRegKeyPtr SetupDiOpenClassRegKeyFn = NULL; SetupInstallFromInfSectionWPtr SetupInstallFromInfSectionWFn = NULL; SetupOpenInfFileWPtr SetupOpenInfFileWFn = NULL; SHDeleteKeyWPtr SHDeleteKeyWFn = NULL; SHStrDupWPtr SHStrDupWFn = NULL; ChangeWindowMessageFilterPtr ChangeWindowMessageFilterFn = NULL; typedef LONG (WINAPI *WINVERIFYTRUST)(HWND hwnd, GUID *pgActionID, LPVOID pWVTData); typedef CRYPT_PROVIDER_DATA* (WINAPI *WTHELPERPROVDATAFROMSTATEDATA)(HANDLE hStateData); typedef CRYPT_PROVIDER_SGNR* (WINAPI *WTHELPERGETPROVSIGNERFROMCHAIN)(CRYPT_PROVIDER_DATA *pProvData, DWORD idxSigner, BOOL fCounterSigner, DWORD idxCounterSigner); typedef CRYPT_PROVIDER_CERT* (WINAPI *WTHELPERGETPROVCERTFROMCHAIN)(CRYPT_PROVIDER_SGNR *pSgnr, DWORD idxCert); static WINVERIFYTRUST WinVerifyTrustFn = NULL; static WTHELPERPROVDATAFROMSTATEDATA WTHelperProvDataFromStateDataFn = NULL; static WTHELPERGETPROVSIGNERFROMCHAIN WTHelperGetProvSignerFromChainFn = NULL; static WTHELPERGETPROVCERTFROMCHAIN WTHelperGetProvCertFromChainFn = NULL; static unsigned char gpbSha1CodeSignCertFingerprint[64] = { 0xCD, 0xF3, 0x05, 0xAD, 0xAE, 0xD3, 0x91, 0xF2, 0x0D, 0x95, 0x95, 0xAC, 0x76, 0x09, 0x35, 0x53, 0x11, 0x00, 0x4D, 0xDD, 0x56, 0x02, 0xBD, 0x09, 0x76, 0x57, 0xE1, 0xFA, 0xFA, 0xF4, 0x86, 0x09, 0x28, 0xA4, 0x0D, 0x1C, 0x68, 0xE7, 0x68, 0x31, 0xD3, 0xB6, 0x62, 0x9C, 0x75, 0x91, 0xAB, 0xB5, 0x6F, 0x1A, 0x75, 0xE7, 0x13, 0x2F, 0xF1, 0xB1, 0x14, 0xBF, 0x5F, 0x00, 0x40, 0xCE, 0x17, 0x6C }; typedef HRESULT (WINAPI *SHGETKNOWNFOLDERPATH) ( _In_ REFKNOWNFOLDERID rfid, _In_ DWORD dwFlags, _In_opt_ HANDLE hToken, _Out_ PWSTR *ppszPath ); /* Windows dialog class */ #define WINDOWS_DIALOG_CLASS L"#32770" /* Custom class names */ #define TC_DLG_CLASS L"VeraCryptCustomDlg" #define TC_SPLASH_CLASS L"VeraCryptSplashDlg" /* constant used by ChangeWindowMessageFilter calls */ #ifndef MSGFLT_ADD #define MSGFLT_ADD 1 #endif /* undocumented message sent during drag-n-drop */ #ifndef WM_COPYGLOBALDATA #define WM_COPYGLOBALDATA 0x0049 #endif /* 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_TYPE_ENCRYPTION = 0, BENCHMARK_TYPE_PRF, BENCHMARK_TYPE_HASH }; enum { BENCHMARK_SORT_BY_NAME = 0, BENCHMARK_SORT_BY_SPEED }; typedef struct { int id; wchar_t 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; int benchmarkType = BENCHMARK_TYPE_ENCRYPTION; int benchmarkPim = -1; BOOL benchmarkPreBoot = FALSE; BOOL benchmarkGPT = FALSE; #endif // #ifndef SETUP typedef struct { void *strings; BOOL bold; } MULTI_CHOICE_DLGPROC_PARAMS; void InitGlobalLocks () { InitializeCriticalSection (&csWNetCalls); InitializeCriticalSection (&csMountableDevices); InitializeCriticalSection (&csVolumeIdCandidates); } void FinalizeGlobalLocks () { DeleteCriticalSection (&csWNetCalls); DeleteCriticalSection (&csMountableDevices); DeleteCriticalSection (&csVolumeIdCandidates); } void cleanup () { burn (&CmdTokenPin, sizeof (CmdTokenPin)); /* 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) UnregisterClassW (TC_DLG_CLASS, hInst); if (hSplashClass) UnregisterClassW (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 FinalizeGlobalLocks (); } void LowerCaseCopy (wchar_t *lpszDest, const wchar_t *lpszSource) { size_t i = wcslen (lpszSource) + 1; lpszDest[i - 1] = 0; while (--i > 0) { lpszDest[i - 1] = (wchar_t) towlower (lpszSource[i - 1]); } } void UpperCaseCopy (wchar_t *lpszDest, size_t cbDest, const wchar_t *lpszSource) { if (lpszDest && cbDest) { size_t i = wcslen (lpszSource); if (i >= cbDest) i = cbDest - 1; lpszDest[i] = 0; i++; while (--i > 0) { lpszDest[i - 1] = (wchar_t) towupper (lpszSource[i - 1]); } } } std::wstring ToUpperCase (const std::wstring &str) { wstring u; foreach (wchar_t c, str) { u += (wchar_t) towupper (c); } return u; } size_t TrimWhiteSpace(wchar_t *str) { wchar_t *end, *ptr = str; size_t out_size; if(!str || *str == 0) return 0; // Trim leading space while(iswspace(*ptr)) ptr++; if(*ptr == 0) // All spaces? { *str = 0; return 0; } // Trim trailing space end = str + wcslen(str) - 1; while(end > ptr && iswspace(*end)) end--; end++; // Set output size to trimmed string length out_size = (end - ptr); // Copy trimmed string and add null terminator wmemmove(str, ptr, out_size); str[out_size] = 0; return out_size; } BOOL IsNullTerminateString (const wchar_t* str, size_t cbSize) { if (str && cbSize) { for (size_t i = 0; i < cbSize; i++) { if (str[i] == 0) return TRUE; } } return FALSE; } // check the validity of a file name BOOL IsValidFileName(const wchar_t* str) { static wchar_t invalidChars[9] = {L'<', L'>', L':', L'"', L'/', L'\\', L'|', L'?', L'*'}; wchar_t c; int i; BOOL bNotDotOnly = FALSE; while ((c = *str)) { if (c != L'.') bNotDotOnly = TRUE; for (i= 0; i < ARRAYSIZE(invalidChars); i++) if (c == invalidChars[i]) return FALSE; str++; } return bNotDotOnly; } BOOL IsVolumeDeviceHosted (const wchar_t *lpszDiskFile) { return wcsstr (lpszDiskFile, L"\\Device\\") == lpszDiskFile || wcsstr (lpszDiskFile, L"\\DEVICE\\") == lpszDiskFile; } void CreateFullVolumePath (wchar_t *lpszDiskFile, size_t cbDiskFile, const wchar_t *lpszFileName, BOOL * bDevice) { UpperCaseCopy (lpszDiskFile, cbDiskFile, lpszFileName); *bDevice = FALSE; if (wmemcmp (lpszDiskFile, L"\\DEVICE", 7) == 0) { *bDevice = TRUE; } StringCbCopyW (lpszDiskFile, cbDiskFile, lpszFileName); #if _DEBUG OutputDebugString (L"CreateFullVolumePath: "); OutputDebugString (lpszDiskFile); OutputDebugString (L"\n"); #endif } int FakeDosNameForDevice (const wchar_t *lpszDiskFile , wchar_t *lpszDosDevice , size_t cbDosDevice, wchar_t *lpszCFDevice , size_t cbCFDevice, BOOL bNameOnly) { BOOL bDosLinkCreated = TRUE; StringCbPrintfW (lpszDosDevice, cbDosDevice,L"veracrypt%lu", GetCurrentProcessId ()); if (bNameOnly == FALSE) bDosLinkCreated = DefineDosDevice (DDD_RAW_TARGET_PATH, lpszDosDevice, lpszDiskFile); if (bDosLinkCreated == FALSE) return ERR_OS_ERROR; else StringCbPrintfW (lpszCFDevice, cbCFDevice,L"\\\\.\\%s", lpszDosDevice); return 0; } int RemoveFakeDosName (wchar_t *lpszDiskFile, wchar_t *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 AbortProcessDirect (wchar_t *abortMsg) { // Note that this function also causes localcleanup() to be called (see atexit()) MessageBeep (MB_ICONEXCLAMATION); MessageBoxW (NULL, abortMsg, lpszTitle, ICON_HAND); FREE_DLL (hRichEditDll); FREE_DLL (hComctl32Dll); FREE_DLL (hSetupDll); FREE_DLL (hShlwapiDll); FREE_DLL (hProfApiDll); FREE_DLL (hUsp10Dll); FREE_DLL (hCryptSpDll); FREE_DLL (hUXThemeDll); FREE_DLL (hUserenvDll); FREE_DLL (hRsaenhDll); FREE_DLL (himm32dll); FREE_DLL (hMSCTFdll); FREE_DLL (hfltlibdll); FREE_DLL (hframedyndll); FREE_DLL (hpsapidll); FREE_DLL (hsecur32dll); FREE_DLL (hnetapi32dll); FREE_DLL (hauthzdll); FREE_DLL (hxmllitedll); FREE_DLL (hmprdll); FREE_DLL (hsppdll); FREE_DLL (vssapidll); FREE_DLL (hvsstracedll); FREE_DLL (hCryptSpDll); FREE_DLL (hcfgmgr32dll); FREE_DLL (hdevobjdll); FREE_DLL (hpowrprofdll); FREE_DLL (hsspiclidll); FREE_DLL (hcryptbasedll); FREE_DLL (hdwmapidll); FREE_DLL (hmsasn1dll); FREE_DLL (hcrypt32dll); FREE_DLL (hbcryptdll); FREE_DLL (hbcryptprimitivesdll); FREE_DLL (hMsls31); FREE_DLL (hntmartadll); FREE_DLL (hwinscarddll); FREE_DLL (hmsvcrtdll); exit (1); } void AbortProcess (char *stringId) { // Note that this function also causes localcleanup() to be called (see atexit()) AbortProcessDirect (GetString (stringId)); } void AbortProcessSilent (void) { FREE_DLL (hRichEditDll); FREE_DLL (hComctl32Dll); FREE_DLL (hSetupDll); FREE_DLL (hShlwapiDll); FREE_DLL (hProfApiDll); FREE_DLL (hUsp10Dll); FREE_DLL (hCryptSpDll); FREE_DLL (hUXThemeDll); FREE_DLL (hUserenvDll); FREE_DLL (hRsaenhDll); FREE_DLL (himm32dll); FREE_DLL (hMSCTFdll); FREE_DLL (hfltlibdll); FREE_DLL (hframedyndll); FREE_DLL (hpsapidll); FREE_DLL (hsecur32dll); FREE_DLL (hnetapi32dll); FREE_DLL (hauthzdll); FREE_DLL (hxmllitedll); FREE_DLL (hmprdll); FREE_DLL (hsppdll); FREE_DLL (vssapidll); FREE_DLL (hvsstracedll); FREE_DLL (hCryptSpDll); FREE_DLL (hcfgmgr32dll); FREE_DLL (hdevobjdll); FREE_DLL (hpowrprofdll); FREE_DLL (hsspiclidll); FREE_DLL (hcryptbasedll); FREE_DLL (hdwmapidll); FREE_DLL (hmsasn1dll); FREE_DLL (hcrypt32dll); FREE_DLL (hbcryptdll); FREE_DLL (hbcryptprimitivesdll); FREE_DLL (hMsls31); FREE_DLL (hntmartadll); FREE_DLL (hwinscarddll); FREE_DLL (hmsvcrtdll); // 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) { size_t 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, const char* srcPos) { PWSTR lpMsgBuf; DWORD dwError = GetLastError (); wchar_t szErrorValue[32]; wchar_t* pszDesc; if (Silent || dwError == 0 || dwError == ERROR_INVALID_WINDOW_HANDLE) return dwError; // Access denied if (dwError == ERROR_ACCESS_DENIED && !IsAdmin ()) { ErrorDirect ( AppendSrcPos (GetString ("ERR_ACCESS_DENIED"), srcPos).c_str (), hwndDlg); SetLastError (dwError); // Preserve the original error code return dwError; } FormatMessageW ( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dwError, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */ (PWSTR) &lpMsgBuf, 0, NULL ); if (lpMsgBuf) pszDesc = (wchar_t*) lpMsgBuf; else { StringCchPrintfW (szErrorValue, ARRAYSIZE (szErrorValue), L"Error 0x%.8X", dwError); pszDesc = szErrorValue; } MessageBoxW (hwndDlg, AppendSrcPos (pszDesc, srcPos).c_str (), lpszTitle, ICON_HAND); if (lpMsgBuf) LocalFree (lpMsgBuf); // User-friendly hardware error explanation if (IsDiskError (dwError)) Error ("ERR_HARDWARE_ERROR", hwndDlg); // Device not ready if (dwError == ERROR_NOT_READY) HandleDriveNotReadyError(hwndDlg); 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 | FORMAT_MESSAGE_IGNORE_INSERTS, 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, (int) 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, (int) wcslen (text), &sizes); ReleaseDC (hwndDlgItem, hdc); return ((int) sizes.cy); } std::wstring FitPathInGfxWidth (HWND hwnd, HFONT hFont, LONG width, const std::wstring &path) { wstring newPath; RECT rect; rect.left = 0; rect.top = 0; rect.right = width; rect.bottom = LONG_MAX; HDC hdc = GetDC (hwnd); SelectObject (hdc, (HGDIOBJ) hFont); wchar_t pathBuf[TC_MAX_PATH]; StringCchCopyW (pathBuf, ARRAYSIZE (pathBuf), path.c_str()); if (DrawText (hdc, pathBuf, (int) 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) GetWindowLongPtrW (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
/*
 Derived from source code of TrueCrypt 7.1a, which is
 Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
 by the TrueCrypt License 3.0.

 Modifications and additions to the original source code (contained in this file)
 and all other portions of this file are Copyright (c) 2013-2017 IDRIX
 and are governed by the Apache License 2.0 the full text of which is
 contained in the file License.txt included in VeraCrypt 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 VeraCrypt
{
	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 == wstring::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(), (CK_ULONG) name.size() },
			{ CKA_VALUE, &keyfileData.front(), (CK_ULONG) 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 char* pin)
	{
		if (Sessions.find (slotId) == Sessions.end())
			OpenSession (slotId);
		else if (Sessions[slotId].UserLoggedIn)
			return;

		size_t pinLen = pin? strlen (pin) : 0;
		CK_RV status = Pkcs11Functions->C_Login (Sessions[slotId].Handle, CKU_USER, (CK_CHAR_PTR) pin, (CK_ULONG) pinLen);

		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.c_str());
				}

				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))
				{
					PinCallback->notifyIncorrectPin ();
					(*WarningCallback) (Pkcs11Exception (CKR_PIN_INCORRECT));
					continue;
				}

				throw;
			}
		}
	}

#ifdef TC_WINDOWS
	void SecurityToken::InitLibrary (const wstring &pkcs11LibraryPath, auto_ptr <GetPinFunctor> pinCallback, auto_ptr <SendExceptionFunctor> warningCallback)
#else
	void SecurityToken::InitLibrary (const string &pkcs11LibraryPath, auto_ptr <GetPinFunctor> pinCallback, auto_ptr <SendExceptionFunctor> warningCallback)
#endif
	{
		if (Initialized)
			CloseLibrary();

#ifdef TC_WINDOWS
		Pkcs11LibraryHandle = LoadLibraryW (pkcs11LibraryPath.c_str());
		throw_sys_if (!Pkcs11LibraryHandle);
#else
		Pkcs11LibraryHandle = dlopen (pkcs11LibraryPath.c_str(), RTLD_NOW | RTLD_LOCAL);
		throw_sys_sub_if (!Pkcs11LibraryHandle, dlerror());
#endif


		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];
				StringCbPrintfW (err, sizeof(err),L"%s:\n\n%hs%s", GetString ("SECURITY_TOKEN_ERROR"), errorString.c_str(), subjectErrorCode.str().c_str());
				ErrorDirect (err, parent);
			}
			else
			{
				wstring err = GetString (errorString.c_str());

				if (SubjectErrorCodeValid)
					err += L"\n\nError code" + subjectErrorCode.str();

				ErrorDirect (err.c_str(), parent);
			}
		}
	}
#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
}
size_t cbFileName,BOOL keepHistory) { OPENFILENAMEW ofn; wchar_t filter[1024]; BOOL status = FALSE; CoInitialize (NULL); ZeroMemory (&ofn, sizeof (ofn)); SelectMultipleFilesPath[0] = 0; *lpszFileName = 0; ofn.lStructSize = sizeof (ofn); ofn.hwndOwner = hwndDlg; StringCbPrintfW (filter, sizeof(filter), L"%ls (*.*)%c*.*%c%ls (*.hc)%c*.hc%c%c", GetString ("ALL_FILES"), 0, 0, GetString ("TC_VOLUMES"), 0, 0, 0); ofn.lpstrFilter = filter; ofn.nFilterIndex = 1; ofn.lpstrFile = SelectMultipleFilesPath; ofn.nMaxFile = 0xffff * 2; // The size must not exceed 0xffff*2 due to a bug in Windows 2000 and XP SP1 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 (SelectMultipleFilesPath[ofn.nFileOffset - 1] != 0) { // Single file selected StringCbCopyW (lpszFileName, cbFileName, SelectMultipleFilesPath); SelectMultipleFilesOffset = 0; SecureZeroMemory (SelectMultipleFilesPath, sizeof (SelectMultipleFilesPath)); } else { // Multiple files selected SelectMultipleFilesOffset = ofn.nFileOffset; SelectMultipleFilesNext (lpszFileName, cbFileName); } if (!keepHistory) CleanLastVisitedMRU (); status = TRUE; ret: SystemFileSelectorCallPending = FALSE; ResetCurrentDirectory(); CoUninitialize(); return status; } BOOL SelectMultipleFilesNext (wchar_t *lpszFileName, size_t cbFileName) { if (SelectMultipleFilesOffset == 0) return FALSE; StringCbCopyW (lpszFileName, cbFileName,SelectMultipleFilesPath); lpszFileName[TC_MAX_PATH - 1] = 0; if (lpszFileName[wcslen (lpszFileName) - 1] != L'\\') StringCbCatW (lpszFileName, cbFileName,L"\\"); StringCbCatW (lpszFileName, cbFileName,SelectMultipleFilesPath + SelectMultipleFilesOffset); SelectMultipleFilesOffset += (int) wcslen (SelectMultipleFilesPath + SelectMultipleFilesOffset) + 1; if (SelectMultipleFilesPath[SelectMultipleFilesOffset] == 0) { SelectMultipleFilesOffset = 0; SecureZeroMemory (SelectMultipleFilesPath, sizeof (SelectMultipleFilesPath)); } 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. */ SendMessageW (hwnd,BFFM_SETSELECTION,TRUE,(LPARAM)pData); break; } case BFFM_SELCHANGED: { wchar_t 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, wchar_t *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]; StringCbPrintfW (szTmp, sizeof(szTmp), GetString (KeyFilesEnable ? "PASSWORD_OR_KEYFILE_WRONG" : "PASSWORD_WRONG")); if (CheckCapsLock (hwndDlg, TRUE)) StringCbCatW (szTmp, sizeof(szTmp), GetString ("PASSWORD_WRONG_CAPSLOCK_ON")); #ifdef TCMOUNT wchar_t szDevicePath [TC_MAX_PATH+1] = {0}; GetWindowText (GetDlgItem (MainDlg, IDC_VOLUME), szDevicePath, ARRAYSIZE (szDevicePath)); if (TCBootLoaderOnInactiveSysEncDrive (szDevicePath)) { StringCbPrintfW (szTmp, sizeof(szTmp), GetString (KeyFilesEnable ? "PASSWORD_OR_KEYFILE_OR_MODE_WRONG" : "PASSWORD_OR_MODE_WRONG")); if (CheckCapsLock (hwndDlg, TRUE)) StringCbCatW (szTmp, sizeof(szTmp), GetString ("PASSWORD_WRONG_CAPSLOCK_ON")); StringCbCatW (szTmp, sizeof(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, const char* srcPos) { WCHAR szTmp[4096]; if (Silent) return; switch (code & 0x0000FFFF) { case ERR_OS_ERROR: handleWin32Error (hwndDlg, srcPos); break; case ERR_OUTOFMEMORY: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("OUTOFMEMORY"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_PASSWORD_WRONG: MessageBoxW (hwndDlg, AppendSrcPos (GetWrongPasswordErrorMessage (hwndDlg).c_str(), srcPos).c_str(), lpszTitle, MB_ICONWARNING); break; case ERR_DRIVE_NOT_FOUND: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("NOT_FOUND"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_FILES_OPEN: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("OPENFILES_DRIVER"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_FILES_OPEN_LOCK: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("OPENFILES_LOCK"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_VOL_SIZE_WRONG: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("VOL_SIZE_WRONG"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_COMPRESSION_NOT_SUPPORTED: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("COMPRESSION_NOT_SUPPORTED"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_PASSWORD_CHANGE_VOL_TYPE: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("WRONG_VOL_TYPE"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_VOL_SEEKING: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("VOL_SEEKING"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_CIPHER_INIT_FAILURE: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("ERR_CIPHER_INIT_FAILURE"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_CIPHER_INIT_WEAK_KEY: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("ERR_CIPHER_INIT_WEAK_KEY"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_VOL_ALREADY_MOUNTED: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("VOL_ALREADY_MOUNTED"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_FILE_OPEN_FAILED: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("FILE_OPEN_FAILED"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_VOL_MOUNT_FAILED: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("VOL_MOUNT_FAILED"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_NO_FREE_DRIVES: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("NO_FREE_DRIVES"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_ACCESS_DENIED: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("ACCESS_DENIED"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_DRIVER_VERSION: Error ("DRIVER_VERSION", hwndDlg); break; case ERR_NEW_VERSION_REQUIRED: MessageBoxW (hwndDlg, AppendSrcPos (GetString ("NEW_VERSION_REQUIRED"), srcPos).c_str(), lpszTitle, ICON_HAND); break; case ERR_SELF_TESTS_FAILED: Error ("ERR_SELF_TESTS_FAILED", hwndDlg); break; case ERR_VOL_FORMAT_BAD: Error ("ERR_VOL_FORMAT_BAD", hwndDlg); break; case ERR_ENCRYPTION_NOT_COMPLETED: Error ("ERR_ENCRYPTION_NOT_COMPLETED", hwndDlg); break; case ERR_NONSYS_INPLACE_ENC_INCOMPLETE: Error ("ERR_NONSYS_INPLACE_ENC_INCOMPLETE", hwndDlg); break; case ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG: Error ("ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG", hwndDlg); break; case ERR_PARAMETER_INCORRECT: Error ("ERR_PARAMETER_INCORRECT", hwndDlg); break; case ERR_USER_ABORT: case ERR_DONT_REPORT: // A non-error break; case ERR_UNSUPPORTED_TRUECRYPT_FORMAT: StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("UNSUPPORTED_TRUECRYPT_FORMAT"), (code >> 24), (code >> 16) & 0x000000FF); MessageBoxW (hwndDlg, AppendSrcPos (szTmp, srcPos).c_str(), lpszTitle, ICON_HAND); break; #ifndef SETUP case ERR_RAND_INIT_FAILED: StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("INIT_RAND"), SRC_POS, GetLastError ()); MessageBoxW (hwndDlg, AppendSrcPos (szTmp, srcPos).c_str(), lpszTitle, MB_ICONERROR); break; case ERR_CAPI_INIT_FAILED: StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("CAPI_RAND"), SRC_POS, CryptoAPILastError); MessageBoxW (hwndDlg, AppendSrcPos (szTmp, srcPos).c_str(), lpszTitle, MB_ICONERROR); break; #endif default: StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("ERR_UNKNOWN"), code); MessageBoxW (hwndDlg, AppendSrcPos (szTmp, srcPos).c_str(), lpszTitle, ICON_HAND); } } BOOL CheckFileStreamWriteErrors (HWND hwndDlg, FILE *file, const wchar_t *fileName) { if (ferror (file)) { wchar_t s[TC_MAX_PATH]; StringCbPrintfW (s, sizeof (s), GetString ("CANNOT_WRITE_FILE_X"), fileName); ErrorDirect (s, hwndDlg); return FALSE; } return TRUE; } static BOOL CALLBACK LocalizeDialogEnum( HWND hwnd, LPARAM font) { // Localization of controls if (LocalizationActive) { int ctrlId = GetDlgCtrlID (hwnd); if (ctrlId != 0) { WCHAR name[10] = { 0 }; GetClassNameW (hwnd, name, array_capacity (name)); if (_wcsicmp (name, L"Button") == 0 || _wcsicmp (name, L"Static") == 0) { wchar_t *str = (wchar_t *) GetDictionaryValueByInt (ctrlId); if (str != NULL) SetWindowTextW (hwnd, str); } } } // Font SendMessageW (hwnd, WM_SETFONT, (WPARAM) font, 0); return TRUE; } void LocalizeDialog (HWND hwnd, char *stringId) { LastDialogId = stringId; SetWindowLongPtrW (hwnd, GWLP_USERDATA, (LONG_PTR) 'VERA'); SendMessageW (hwnd, WM_SETFONT, (WPARAM) hUserFont, 0); if (stringId == NULL) SetWindowTextW (hwnd, L"VeraCrypt"); else SetWindowTextW (hwnd, GetString (stringId)); if (hUserFont != 0) EnumChildWindows (hwnd, LocalizeDialogEnum, (LPARAM) hUserFont); } void OpenVolumeExplorerWindow (int driveNo) { wchar_t dosName[5]; SHFILEINFO fInfo; StringCbPrintfW (dosName, sizeof(dosName), L"%c:\\", (wchar_t) driveNo + L'A'); // Force explorer to discover the drive SHGetFileInfo (dosName, 0, &fInfo, sizeof (fInfo), 0); ShellExecute (NULL, L"open", dosName, NULL, NULL, SW_SHOWNORMAL); } static BOOL explorerCloseSent; static HWND explorerTopLevelWindow; static BOOL CALLBACK CloseVolumeExplorerWindowsChildEnum (HWND hwnd, LPARAM driveStr) { WCHAR s[MAX_PATH]; SendMessageW (hwnd, WM_GETTEXT, array_capacity (s), (LPARAM) s); if (wcsstr (s, (WCHAR *) driveStr) != NULL) { PostMessageW (explorerTopLevelWindow, WM_CLOSE, 0, 0); explorerCloseSent = TRUE; return FALSE; } return TRUE; } static BOOL CALLBACK CloseVolumeExplorerWindowsEnum (HWND hwnd, LPARAM driveNo) { WCHAR driveStr[10]; WCHAR s[MAX_PATH]; StringCbPrintfW (driveStr, sizeof(driveStr), L"%c:\\", driveNo + L'A'); GetClassNameW (hwnd, s, array_capacity (s)); if (wcscmp (s, L"CabinetWClass") == 0) { GetWindowTextW (hwnd, s, array_capacity (s)); if (wcsstr (s, driveStr) != NULL) { PostMessageW (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; } BOOL UpdateDriveCustomLabel (int driveNo, wchar_t* effectiveLabel, BOOL bSetValue) { wchar_t wszRegPath[MAX_PATH]; wchar_t driveStr[] = {L'A' + (wchar_t) driveNo, 0}; HKEY hKey; LSTATUS lStatus; DWORD cbLabelLen = (DWORD) ((wcslen (effectiveLabel) + 1) * sizeof (wchar_t)); BOOL bToBeDeleted = FALSE; StringCbPrintfW (wszRegPath, sizeof (wszRegPath), L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons\\%s\\DefaultLabel", driveStr); if (bSetValue) lStatus = RegCreateKeyExW (HKEY_CURRENT_USER, wszRegPath, NULL, NULL, 0, KEY_READ | KEY_WRITE | KEY_SET_VALUE, NULL, &hKey, NULL); else lStatus = RegOpenKeyExW (HKEY_CURRENT_USER, wszRegPath, 0, KEY_READ | KEY_WRITE | KEY_SET_VALUE, &hKey); if (ERROR_SUCCESS == lStatus) { if (bSetValue) lStatus = RegSetValueExW (hKey, NULL, NULL, REG_SZ, (LPCBYTE) effectiveLabel, cbLabelLen); else { wchar_t storedLabel[34] = {0}; DWORD cbStoredLen = sizeof (storedLabel) - 1, dwType; lStatus = RegQueryValueExW (hKey, NULL, NULL, &dwType, (LPBYTE) storedLabel, &cbStoredLen); if ((ERROR_SUCCESS == lStatus) && (REG_SZ == dwType) && (0 == wcscmp(storedLabel, effectiveLabel))) { // same label stored. mark key for deletion bToBeDeleted = TRUE; } } RegCloseKey (hKey); } if (bToBeDeleted) { StringCbPrintfW (wszRegPath, sizeof (wszRegPath), L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\DriveIcons\\%s", driveStr); lStatus = RegOpenKeyExW (HKEY_CURRENT_USER, wszRegPath, 0, KEY_READ | KEY_WRITE | KEY_SET_VALUE, &hKey); if (ERROR_SUCCESS == lStatus) { lStatus = RegDeleteKeyW (hKey, L"DefaultLabel"); RegCloseKey (hKey); } // delete drive letter of nothing else is present under it RegDeleteKeyW (HKEY_CURRENT_USER, wszRegPath); } return (ERROR_SUCCESS == lStatus)? TRUE : FALSE; } wstring GetUserFriendlyVersionString (int version) { wchar_t szTmp [64]; StringCbPrintfW (szTmp, sizeof(szTmp), L"%x", version); wstring versionString (szTmp); versionString.insert (version > 0xfff ? 2 : 1,L"."); return (versionString); } wstring IntToWideString (int val) { wchar_t szTmp [64]; StringCbPrintfW (szTmp, sizeof(szTmp), L"%d", val); return szTmp; } wstring ArrayToHexWideString (const unsigned char* pbData, int cbData) { static wchar_t* hexChar = L"0123456789ABCDEF"; wstring result; if (pbData) { for (int i = 0; i < cbData; i++) { result += hexChar[pbData[i] >> 4]; result += hexChar[pbData[i] & 0x0F]; } } return result; } bool HexToByte (wchar_t c, byte& b) { bool bRet = true; if (c >= L'0' && c <= L'9') b = (byte) (c - L'0'); else if (c >= L'a' && c <= L'z') b = (byte) (c - L'a' + 10); else if (c >= L'A' && c <= L'Z') b = (byte) (c - L'A' + 10); else bRet = false; return bRet; } bool HexWideStringToArray (const wchar_t* hexStr, std::vector& arr) { byte b1, b2; size_t i, len = wcslen (hexStr); arr.clear(); if (len %2) return false; for (i = 0; i < len/2; i++) { if (!HexToByte (*hexStr++, b1) || !HexToByte (*hexStr++, b2)) return false; arr.push_back (b1 << 4 | b2); } return true; } wstring GetTempPathString () { wchar_t tempPath[MAX_PATH]; DWORD tempLen = ::GetTempPath (ARRAYSIZE (tempPath), tempPath); if (tempLen == 0 || tempLen > ARRAYSIZE (tempPath)) throw ParameterIncorrect (SRC_POS); return wstring (tempPath); } void GetSizeString (unsigned __int64 size, wchar_t *str, size_t cbStr) { 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) StringCbPrintfW (str, cbStr, L"%I64d %s", size/1024/1024/1024/1024/1024, pb); else if (size > 1024I64*1024*1024*1024*1024) StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(size/1024.0/1024/1024/1024/1024), pb); else if (size > 1024I64*1024*1024*1024*99) StringCbPrintfW (str, cbStr, L"%I64d %s",size/1024/1024/1024/1024, tb); else if (size > 1024I64*1024*1024*1024) StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(size/1024.0/1024/1024/1024), tb); else if (size > 1024I64*1024*1024*99) StringCbPrintfW (str, cbStr, L"%I64d %s",size/1024/1024/1024, gb); else if (size > 1024I64*1024*1024) StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(size/1024.0/1024/1024), gb); else if (size > 1024I64*1024*99) StringCbPrintfW (str, cbStr, L"%I64d %s", size/1024/1024, mb); else if (size > 1024I64*1024) StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(size/1024.0/1024), mb); else if (size >= 1024I64) StringCbPrintfW (str, cbStr, L"%I64d %s", size/1024, kb); else StringCbPrintfW (str, cbStr, L"%I64d %s", size, b); } #ifndef SETUP void GetSpeedString (unsigned __int64 speed, wchar_t *str, size_t cbStr) { 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) StringCbPrintfW (str, cbStr, L"%I64d %s", speed/1024/1024/1024/1024/1024, pb); else if (speed > 1024I64*1024*1024*1024*1024) StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(speed/1024.0/1024/1024/1024/1024), pb); else if (speed > 1024I64*1024*1024*1024*99) StringCbPrintfW (str, cbStr, L"%I64d %s",speed/1024/1024/1024/1024, tb); else if (speed > 1024I64*1024*1024*1024) StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(speed/1024.0/1024/1024/1024), tb); else if (speed > 1024I64*1024*1024*99) StringCbPrintfW (str, cbStr, L"%I64d %s",speed/1024/1024/1024, gb); else if (speed > 1024I64*1024*1024) StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(speed/1024.0/1024/1024), gb); else if (speed > 1024I64*1024*99) StringCbPrintfW (str, cbStr, L"%I64d %s", speed/1024/1024, mb); else if (speed > 1024I64*1024) StringCbPrintfW (str, cbStr, L"%.1f %s",(double)(speed/1024.0/1024), mb); else if (speed > 1024I64) StringCbPrintfW (str, cbStr, L"%I64d %s", speed/1024, kb); else StringCbPrintfW (str, cbStr, L"%I64d %s", speed, b); } static void ResetBenchmarkList (HWND hwndDlg) { LVCOLUMNW LvCol; HWND hList = GetDlgItem (hwndDlg, IDC_RESULTS); /* Render the results */ // delete data SendMessage (hList, LVM_DELETEALLITEMS, 0, 0); // Delete headers SendMessageW (hList, LVM_DELETECOLUMN, 1, 0); SendMessageW (hList, LVM_DELETECOLUMN, 1, 0); SendMessageW (hList, LVM_DELETECOLUMN, 1, 0); memset (&LvCol,0,sizeof(LvCol)); LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT; switch(benchmarkType) { case BENCHMARK_TYPE_ENCRYPTION: // Create headers 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); break; case BENCHMARK_TYPE_HASH: LvCol.pszText = GetString ("MEAN"); LvCol.cx = CompensateXDPI (80); LvCol.fmt = LVCFMT_RIGHT; SendMessageW (hList,LVM_INSERTCOLUMNW,1,(LPARAM)&LvCol); break; case BENCHMARK_TYPE_PRF: LvCol.pszText = GetString ("TIME"); LvCol.cx = CompensateXDPI (80); LvCol.fmt = LVCFMT_RIGHT; SendMessageW (hList,LVM_INSERTCOLUMNW,1,(LPARAM)&LvCol); LvCol.pszText = GetString ("ITERATIONS"); LvCol.cx = CompensateXDPI (80); LvCol.fmt = LVCFMT_RIGHT; SendMessageW (hList,LVM_INSERTCOLUMNW,2,(LPARAM)&LvCol); break; } } 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; ResetBenchmarkList (hwndDlg); /* Sort the list */ switch (benchmarkSortMethod) { case BENCHMARK_SORT_BY_SPEED: while (unsorted) { unsorted = FALSE; for (i = 0; i < benchmarkTotalItems - 1; i++) { if (((benchmarkType == BENCHMARK_TYPE_PRF) && (benchmarkTable[i].meanBytesPerSec > benchmarkTable[i+1].meanBytesPerSec)) || ((benchmarkType != BENCHMARK_TYPE_PRF) && (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; } 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); switch(benchmarkType) { case BENCHMARK_TYPE_ENCRYPTION: GetSpeedString ((unsigned __int64) (benchmarkLastBufferSize / ((float) benchmarkTable[i].encSpeed / benchmarkPerformanceFrequency.QuadPart)), item1, sizeof(item1)); LvItem.iSubItem = 1; LvItem.pszText = item1; SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem); GetSpeedString ((unsigned __int64) (benchmarkLastBufferSize / ((float) benchmarkTable[i].decSpeed / benchmarkPerformanceFrequency.QuadPart)), item1, sizeof(item1)); LvItem.iSubItem = 2; LvItem.pszText = item1; SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem); GetSpeedString (benchmarkTable[i].meanBytesPerSec, item1, sizeof(item1)); LvItem.iSubItem = 3; LvItem.pszText = item1; SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem); break; case BENCHMARK_TYPE_HASH: GetSpeedString (benchmarkTable[i].meanBytesPerSec, item1, sizeof(item1)); LvItem.iSubItem = 1; LvItem.pszText = item1; SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem); break; case BENCHMARK_TYPE_PRF: swprintf_s (item1, sizeof(item1) / sizeof(item1[0]), L"%d ms", benchmarkTable[i].meanBytesPerSec); LvItem.iSubItem = 1; LvItem.pszText = item1; SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem); swprintf_s (item1, sizeof(item1) / sizeof(item1[0]), L"%d", benchmarkTable[i].decSpeed); LvItem.iSubItem = 2; LvItem.pszText = item1; SendMessageW (hList, LVM_SETITEMW, 0, (LPARAM)&LvItem); break; } } SendMessageW(hList, LVM_SETCOLUMNWIDTH, 0, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0)); SendMessageW(hList, LVM_SETCOLUMNWIDTH, 1, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0)); SendMessageW(hList, LVM_SETCOLUMNWIDTH, 2, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0)); SendMessageW(hList, LVM_SETCOLUMNWIDTH, 3, MAKELPARAM(LVSCW_AUTOSIZE_USEHEADER, 0)); } // specific implementation for support of benchmark operation in wait dialog mechanism typedef struct { HWND hBenchDlg; BOOL bStatus; } BenchmarkThreadParam; static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg); void CALLBACK BenchmarkThreadProc(void* pArg, HWND hwndDlg) { BenchmarkThreadParam* pThreadParam = (BenchmarkThreadParam*) pArg; pThreadParam->bStatus = PerformBenchmark (pThreadParam->hBenchDlg, hwndDlg); } static BOOL PerformBenchmark(HWND hBenchDlg, HWND hwndDlg) { LARGE_INTEGER performanceCountStart, performanceCountEnd; BYTE *lpTestBuffer = NULL; PCRYPTO_INFO ci = NULL; UINT64_STRUCT startDataUnitNo; SYSTEM_INFO sysInfo = {0}; GetSystemInfo (&sysInfo); startDataUnitNo.Value = 0; /* set priority to critical only when there are 2 or more CPUs on the system */ if (sysInfo.dwNumberOfProcessors > 1 && (benchmarkType != BENCHMARK_TYPE_ENCRYPTION)) SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL); ci = crypto_open (); if (!ci) return FALSE; if (QueryPerformanceFrequency (&benchmarkPerformanceFrequency) == 0) { if (ci) crypto_close (ci); MessageBoxW (hwndDlg, GetString ("ERR_PERF_COUNTER"), lpszTitle, ICON_HAND); return FALSE; } if (benchmarkType != BENCHMARK_TYPE_PRF) { lpTestBuffer = (BYTE *) _aligned_malloc(benchmarkBufferSize - (benchmarkBufferSize % 16), 16); if (lpTestBuffer == NULL) { if (ci) crypto_close (ci); MessageBoxW (hwndDlg, GetString ("ERR_MEM_ALLOC"), lpszTitle, ICON_HAND); return FALSE; } VirtualLock (lpTestBuffer, benchmarkBufferSize - (benchmarkBufferSize % 16)); } WaitCursor (); benchmarkTotalItems = 0; switch(benchmarkType) { case BENCHMARK_TYPE_HASH: /* Measures the speed at which each of the hash algorithms processes the message to produce a single digest. */ { BYTE digest [MAX_DIGESTSIZE]; WHIRLPOOL_CTX wctx; RMD160_CTX rctx; sha512_ctx s2ctx; sha256_ctx s256ctx; STREEBOG_CTX stctx; int hid, i; for (hid = FIRST_PRF_ID; hid <= LAST_PRF_ID; hid++) { if (QueryPerformanceCounter (&performanceCountStart) == 0) goto counter_error; for (i = 1; i <= 2; i++) { switch (hid) { case SHA512: sha512_begin (&s2ctx); sha512_hash (lpTestBuffer, benchmarkBufferSize, &s2ctx); sha512_end ((unsigned char *) digest, &s2ctx); break; case SHA256: sha256_begin (&s256ctx); sha256_hash (lpTestBuffer, benchmarkBufferSize, &s256ctx); sha256_end ((unsigned char *) digest, &s256ctx); break; case RIPEMD160: RMD160Init(&rctx); RMD160Update(&rctx, lpTestBuffer, benchmarkBufferSize); RMD160Final((unsigned char *) digest, &rctx); break; case WHIRLPOOL: WHIRLPOOL_init (&wctx); WHIRLPOOL_add (lpTestBuffer, benchmarkBufferSize, &wctx); WHIRLPOOL_finalize (&wctx, (unsigned char *) digest); break; case STREEBOG: STREEBOG_init(&stctx); STREEBOG_add(&stctx, lpTestBuffer, benchmarkBufferSize); STREEBOG_finalize(&stctx, (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 / 2)); StringCbPrintfW (benchmarkTable[benchmarkTotalItems].name, sizeof(benchmarkTable[benchmarkTotalItems].name),L"%s", HashGetName(hid)); benchmarkTotalItems++; } } break; case BENCHMARK_TYPE_PRF: /* Measures the time that it takes for the PKCS-5 routine to derive a header key using each of the implemented PRF algorithms. */ { 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 (benchmarkPreBoot && !benchmarkGPT && !HashForSystemEncryption (thid)) continue; if (QueryPerformanceCounter (&performanceCountStart) == 0) goto counter_error; for (i = 1; i <= 2; i++) { switch (thid) { 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, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE); break; case SHA256: /* PKCS-5 test with HMAC-SHA-256 used as the PRF */ derive_key_sha256 ("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), 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, benchmarkPim, FALSE, benchmarkPreBoot), 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, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE); break; case STREEBOG: /* PKCS-5 test with HMAC-STREEBOG used as the PRF */ derive_key_streebog("passphrase-1234567890", 21, tmp_salt, 64, get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot), dk, MASTER_KEYDATA_SIZE); break; } } if (QueryPerformanceCounter (&performanceCountEnd) == 0) goto counter_error; benchmarkTable[benchmarkTotalItems].encSpeed = performanceCountEnd.QuadPart - performanceCountStart.QuadPart; benchmarkTable[benchmarkTotalItems].id = thid; benchmarkTable[benchmarkTotalItems].decSpeed = get_pkcs5_iteration_count(thid, benchmarkPim, FALSE, benchmarkPreBoot); benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (unsigned __int64) (1000 * ((float) benchmarkTable[benchmarkTotalItems].encSpeed / benchmarkPerformanceFrequency.QuadPart / 2)); if (benchmarkPreBoot) { /* heuristics for boot times */ if (benchmarkGPT) { benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 8) / 5; } else { if (thid == SHA256) { #ifdef _WIN64 benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 26); #else benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 24); #endif } else { #ifdef _WIN64 benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 21) / 5; #else benchmarkTable[benchmarkTotalItems].meanBytesPerSec = (benchmarkTable[benchmarkTotalItems].meanBytesPerSec * 18) / 5; #endif } } } StringCbPrintfW (benchmarkTable[benchmarkTotalItems].name, sizeof(benchmarkTable[benchmarkTotalItems].name),L"%s", get_pkcs5_prf_name (thid)); benchmarkTotalItems++; } } break; case BENCHMARK_TYPE_ENCRYPTION: { /* Encryption algorithm 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, ci->k2)) { 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); } } } for (ci->ea = EAGetFirst(); ci->ea != 0; ci->ea = EAGetNext(ci->ea)) { if (!EAIsFormatEnabled (ci->ea)) continue; if (ERR_CIPHER_INIT_FAILURE == EAInit (ci->ea, ci->master_keydata, ci->ks)) goto counter_error; ci->mode = FIRST_MODE_OF_OPERATION_ID; if (!EAInitMode (ci, ci->k2)) goto counter_error; 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, 1); benchmarkTotalItems++; } } break; } if (ci) crypto_close (ci); if (lpTestBuffer) { VirtualUnlock (lpTestBuffer, benchmarkBufferSize - (benchmarkBufferSize % 16)); _aligned_free(lpTestBuffer); } benchmarkLastBufferSize = benchmarkBufferSize; DisplayBenchmarkResults(hBenchDlg); EnableWindow (GetDlgItem (hBenchDlg, IDC_PERFORM_BENCHMARK), TRUE); EnableWindow (GetDlgItem (hBenchDlg, IDCLOSE), TRUE); NormalCursor (); return TRUE; counter_error: if (ci) crypto_close (ci); if (lpTestBuffer) { VirtualUnlock (lpTestBuffer, benchmarkBufferSize - (benchmarkBufferSize % 16)); _aligned_free(lpTestBuffer); } NormalCursor (); EnableWindow (GetDlgItem (hBenchDlg, IDC_PERFORM_BENCHMARK), TRUE); EnableWindow (GetDlgItem (hBenchDlg, 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; static HWND hCboxSortMethod = NULL, hCboxBufferSize = NULL, hCboxList = NULL; switch (msg) { case WM_INITDIALOG: { LVCOLUMNW LvCol; wchar_t s[128]; HWND hList = GetDlgItem (hwndDlg, IDC_RESULTS); hCboxSortMethod = GetDlgItem (hwndDlg, IDC_BENCHMARK_SORT_METHOD); hCboxBufferSize = GetDlgItem (hwndDlg, IDC_BENCHMARK_BUFFER_SIZE); hCboxList = GetDlgItem (hwndDlg, IDC_BENCHMARK_LIST); LocalizeDialog (hwndDlg, "IDD_BENCHMARK_DLG"); benchmarkBufferSize = BENCHMARK_DEFAULT_BUF_SIZE; benchmarkSortMethod = BENCHMARK_SORT_BY_SPEED; benchmarkType = BENCHMARK_TYPE_ENCRYPTION; if (lParam) { benchmarkGPT = TRUE; } else benchmarkGPT = FALSE; 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); ResetBenchmarkList (hwndDlg); /* 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 // benchmark list SendMessage (hCboxList, CB_RESETCONTENT, 0, 0); nIndex = SendMessageW (hCboxList, CB_ADDSTRING, 0, (LPARAM) GetString ("ENCRYPTION_ALGORITHM")); SendMessage (hCboxList, CB_SETITEMDATA, nIndex, (LPARAM) 0); nIndex = SendMessageW (hCboxList, CB_ADDSTRING, 0, (LPARAM) GetString ("PKCS5_PRF")); SendMessage (hCboxList, CB_SETITEMDATA, nIndex, (LPARAM) 0); nIndex = SendMessageW (hCboxList, CB_ADDSTRING, 0, (LPARAM) GetString ("IDT_HASH_ALGO")); SendMessage (hCboxList, CB_SETITEMDATA, nIndex, (LPARAM) 0); SendMessage (hCboxList, CB_SETCURSEL, 0, 0); // Default: benchmark of encryption // Buffer size SendMessage (hCboxBufferSize, CB_RESETCONTENT, 0, 0); StringCbPrintfW (s, sizeof(s), L"100 %s", GetString ("KB")); nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s); SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 100 * BYTES_PER_KB); StringCbPrintfW (s, sizeof(s), L"500 %s", GetString ("KB")); nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s); SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 500 * BYTES_PER_KB); StringCbPrintfW (s, sizeof(s), L"1 %s", GetString ("MB")); nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s); SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 1 * BYTES_PER_MB); StringCbPrintfW (s, sizeof(s), L"5 %s", GetString ("MB")); nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s); SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 5 * BYTES_PER_MB); StringCbPrintfW (s, sizeof(s), L"10 %s", GetString ("MB")); nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s); SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 10 * BYTES_PER_MB); StringCbPrintfW (s, sizeof(s), L"50 %s", GetString ("MB")); nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s); SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 50 * BYTES_PER_MB); StringCbPrintfW (s, sizeof(s), L"100 %s", GetString ("MB")); nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s); SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 100 * BYTES_PER_MB); StringCbPrintfW (s, sizeof(s), L"200 %s", GetString ("MB")); nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s); SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 200 * BYTES_PER_MB); StringCbPrintfW (s, sizeof(s), L"500 %s", GetString ("MB")); nIndex = SendMessageW (hCboxBufferSize, CB_ADDSTRING, 0, (LPARAM) s); SendMessage (hCboxBufferSize, CB_SETITEMDATA, nIndex, (LPARAM) 500 * BYTES_PER_MB); StringCbPrintfW (s, sizeof(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(); int isAesHwSupported = is_aes_hw_cpu_supported(); SetDlgItemTextW (hwndDlg, IDC_HW_AES, (wstring (L" ") + (GetString (isAesHwSupported ? ((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 (isAesHwSupported && (driverConfig & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION)) { Warning ("DISABLED_HW_AES_AFFECTS_PERFORMANCE", hwndDlg); } SYSTEM_INFO sysInfo; GetSystemInfo (&sysInfo); size_t nbrThreads = GetEncryptionThreadCount(); wchar_t nbrThreadsStr [300]; if (sysInfo.dwNumberOfProcessors < 2) { StringCbCopyW (nbrThreadsStr, sizeof(nbrThreadsStr), GetString ("NOT_APPLICABLE_OR_NOT_AVAILABLE")); } else if (nbrThreads < 2) { StringCbCopyW (nbrThreadsStr, sizeof(nbrThreadsStr), GetString ("UISTR_DISABLED")); } else { StringCbPrintfW (nbrThreadsStr, sizeof(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", hwndDlg); } return 1; } break; case WM_COMMAND: switch (lw) { case IDC_BENCHMARK_SORT_METHOD: nIndex = SendMessage (hCboxSortMethod, CB_GETCURSEL, 0, 0); if (nIndex != benchmarkSortMethod) { benchmarkSortMethod = (int) nIndex; DisplayBenchmarkResults (hwndDlg); } return 1; case IDC_BENCHMARK_LIST: nIndex = SendMessage (hCboxList, CB_GETCURSEL, 0, 0); if (nIndex != benchmarkType) { benchmarkType = (int) nIndex; benchmarkTotalItems = 0; ResetBenchmarkList (hwndDlg); } if (benchmarkType == BENCHMARK_TYPE_PRF) { ShowWindow (GetDlgItem (hwndDlg, IDC_BENCHMARK_BUFFER_SIZE), SW_HIDE); ShowWindow (GetDlgItem (hwndDlg, IDT_BUFFER_SIZE), SW_HIDE); ShowWindow (GetDlgItem (hwndDlg, IDC_PIM), SW_SHOW); ShowWindow (GetDlgItem (hwndDlg, IDT_PIM), SW_SHOW); ShowWindow (GetDlgItem (hwndDlg, IDC_BENCHMARK_PREBOOT), SW_SHOW); } else { ShowWindow (GetDlgItem (hwndDlg, IDC_BENCHMARK_BUFFER_SIZE), SW_SHOW); ShowWindow (GetDlgItem (hwndDlg, IDT_BUFFER_SIZE), SW_SHOW); ShowWindow (GetDlgItem (hwndDlg, IDC_PIM), SW_HIDE); ShowWindow (GetDlgItem (hwndDlg, IDT_PIM), SW_HIDE); ShowWindow (GetDlgItem (hwndDlg, IDC_BENCHMARK_PREBOOT), SW_HIDE); } return 1; case IDC_PERFORM_BENCHMARK: if (benchmarkType == BENCHMARK_TYPE_PRF) { benchmarkPim = GetPim (hwndDlg, IDC_PIM, 0); benchmarkPreBoot = GetCheckBox (hwndDlg, IDC_BENCHMARK_PREBOOT); } else { nIndex = SendMessage (hCboxBufferSize, CB_GETCURSEL, 0, 0); benchmarkBufferSize = (int) SendMessage (hCboxBufferSize, CB_GETITEMDATA, nIndex, 0); } BenchmarkThreadParam threadParam; threadParam.hBenchDlg = hwndDlg; threadParam.bStatus = FALSE; WaitCursor (); ShowWaitDialog (hwndDlg, TRUE, BenchmarkThreadProc, &threadParam); NormalCursor (); if (threadParam.bStatus == FALSE) { EndDialog (hwndDlg, IDCLOSE); } return 1; case IDC_HW_AES_LABEL_LINK: Applink ("hwacceleration"); return 1; case IDC_PARALLELIZATION_LABEL_LINK: Applink ("parallelization"); 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 unsigned char maskRandPool [RNG_POOL_SIZE]; static BOOL bUseMask = FALSE; static DWORD mouseEntropyGathered = 0xFFFFFFFF; static DWORD mouseEventsInitialCount = 0; /* max value of entropy needed to fill all random pool = 8 * RNG_POOL_SIZE = 2560 bits */ static const DWORD maxEntropyLevel = RNG_POOL_SIZE * 8; static HWND hEntropyBar = NULL; static wchar_t outputDispBuffer [RNG_POOL_SIZE * 3 + RANDPOOL_DISPLAY_ROWS + 2]; static BOOL bDisplayPoolContents = FALSE; static BOOL bRandPoolDispAscii = FALSE; int hash_algo = RandGetHashFunction(); int hid; switch (msg) { case WM_INITDIALOG: { HWND hComboBox = GetDlgItem (hwndDlg, IDC_PRF_ID); HCRYPTPROV hRngProv = NULL; VirtualLock (randPool, sizeof(randPool)); VirtualLock (lastRandPool, sizeof(lastRandPool)); VirtualLock (outputDispBuffer, sizeof(outputDispBuffer)); VirtualLock (&mouseEntropyGathered, sizeof(mouseEntropyGathered)); VirtualLock (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount)); VirtualLock (maskRandPool, sizeof(maskRandPool)); mouseEntropyGathered = 0xFFFFFFFF; mouseEventsInitialCount = 0; bUseMask = FALSE; if (CryptAcquireContext (&hRngProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { if (CryptGenRandom (hRngProv, sizeof (maskRandPool), maskRandPool)) bUseMask = TRUE; CryptReleaseContext (hRngProv, 0); } 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); hEntropyBar = GetDlgItem (hwndDlg, IDC_ENTROPY_BAR); SendMessage (hEntropyBar, PBM_SETRANGE32, 0, maxEntropyLevel); SendMessage (hEntropyBar, PBM_SETSTEP, 1, 0); SendMessage (hEntropyBar, PBM_SETSTATE, PBST_ERROR, 0); return 1; } case WM_TIMER: { wchar_t tmp[4]; unsigned char tmpByte; int col, row; DWORD mouseEventsCounter; RandpeekBytes (hwndDlg, randPool, sizeof (randPool), &mouseEventsCounter); ProcessEntropyEstimate (hEntropyBar, &mouseEventsInitialCount, mouseEventsCounter, maxEntropyLevel, &mouseEntropyGathered); 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++) { if (bDisplayPoolContents) { tmpByte = randPool[row * RANDPOOL_DISPLAY_COLUMNS + col]; StringCbPrintfW (tmp, sizeof(tmp), bRandPoolDispAscii ? ((tmpByte >= 32 && tmpByte < 255 && tmpByte != L'&') ? L" %c " : L" . ") : L"%02X ", tmpByte); } else if (bUseMask) { /* use mask to compute a randomized ascii representation */ tmpByte = (randPool[row * RANDPOOL_DISPLAY_COLUMNS + col] - lastRandPool[row * RANDPOOL_DISPLAY_COLUMNS + col]) ^ maskRandPool [row * RANDPOOL_DISPLAY_COLUMNS + col]; tmp[0] = (wchar_t) (((tmpByte >> 4) % 6) + L'*'); tmp[1] = (wchar_t) (((tmpByte & 0x0F) % 6) + L'*'); tmp[2] = L' '; tmp[3] = 0; } else { StringCbCopyW (tmp, sizeof(tmp), L"** "); } StringCbCatW (outputDispBuffer, sizeof(outputDispBuffer), tmp); } StringCbCatW (outputDispBuffer, sizeof(outputDispBuffer), L"\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))) { wchar_t tmp[RNG_POOL_SIZE+1]; wmemset (tmp, L' ', ARRAYSIZE(tmp)); tmp [RNG_POOL_SIZE] = 0; SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp); } return 1; } return 0; case WM_CLOSE: { wchar_t tmp[RNG_POOL_SIZE+1]; exit: KillTimer (hwndDlg, 0xfd); burn (randPool, sizeof(randPool)); burn (lastRandPool, sizeof(lastRandPool)); burn (outputDispBuffer, sizeof(outputDispBuffer)); burn (&mouseEntropyGathered, sizeof(mouseEntropyGathered)); burn (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount)); burn (maskRandPool, sizeof(maskRandPool)); // Attempt to wipe the pool contents in the GUI text area wmemset (tmp, L' ', 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; } /* Randinit is always called before UserEnrichRandomPool, so we don't need * the extra Randinit call here since it will always succeed but we keep it * for clarity purposes */ void UserEnrichRandomPool (HWND hwndDlg) { if ((0 == Randinit()) && !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 unsigned char maskRandPool [RNG_POOL_SIZE]; static BOOL bUseMask = FALSE; static DWORD mouseEntropyGathered = 0xFFFFFFFF; static DWORD mouseEventsInitialCount = 0; /* max value of entropy needed to fill all random pool = 8 * RNG_POOL_SIZE = 2560 bits */ static const DWORD maxEntropyLevel = RNG_POOL_SIZE * 8; static HWND hEntropyBar = NULL; static wchar_t outputDispBuffer [RNG_POOL_SIZE * 3 + RANDPOOL_DISPLAY_ROWS + 2]; static BOOL bDisplayPoolContents = FALSE; static BOOL bRandPoolDispAscii = FALSE; int hash_algo = RandGetHashFunction(); int hid; switch (msg) { case WM_INITDIALOG: { HWND hComboBox = GetDlgItem (hwndDlg, IDC_PRF_ID); HCRYPTPROV hRngProv = NULL; VirtualLock (randPool, sizeof(randPool)); VirtualLock (lastRandPool, sizeof(lastRandPool)); VirtualLock (outputDispBuffer, sizeof(outputDispBuffer)); VirtualLock (&mouseEntropyGathered, sizeof(mouseEntropyGathered)); VirtualLock (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount)); VirtualLock (maskRandPool, sizeof(maskRandPool)); mouseEntropyGathered = 0xFFFFFFFF; mouseEventsInitialCount = 0; bUseMask = FALSE; if (CryptAcquireContext (&hRngProv, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { if (CryptGenRandom (hRngProv, sizeof (maskRandPool), maskRandPool)) bUseMask = TRUE; CryptReleaseContext (hRngProv, 0); } 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); hEntropyBar = GetDlgItem (hwndDlg, IDC_ENTROPY_BAR); SendMessage (hEntropyBar, PBM_SETRANGE32, 0, maxEntropyLevel); SendMessage (hEntropyBar, PBM_SETSTEP, 1, 0); SendMessage (hEntropyBar, PBM_SETSTATE, PBST_ERROR, 0); #ifndef VOLFORMAT if (Randinit ()) { handleError (hwndDlg, (CryptoAPILastError == ERROR_SUCCESS)? ERR_RAND_INIT_FAILED : ERR_CAPI_INIT_FAILED, SRC_POS); EndDialog (hwndDlg, IDCLOSE); } #endif SetTimer (hwndDlg, 0xfd, RANDPOOL_DISPLAY_REFRESH_INTERVAL, NULL); SendMessage (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), WM_SETFONT, (WPARAM) hFixedDigitFont, (LPARAM) TRUE); // 9-digit limit for the number of keyfiles (more than enough!) SendMessage (GetDlgItem (hwndDlg, IDC_NUMBER_KEYFILES), EM_SETLIMITTEXT, (WPARAM) 9, 0); SetWindowText(GetDlgItem (hwndDlg, IDC_NUMBER_KEYFILES), L"1"); // maximum keyfile size is 1048576, so limit the edit control to 7 characters SendMessage (GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), EM_SETLIMITTEXT, (WPARAM) 7, 0); SetWindowText(GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), L"64"); // set the maximum length of the keyfile base name to (TC_MAX_PATH - 1) SendMessage (GetDlgItem (hwndDlg, IDC_KEYFILES_BASE_NAME), EM_SETLIMITTEXT, (WPARAM) (TC_MAX_PATH - 1), 0); return 1; } case WM_TIMER: { wchar_t tmp[4]; unsigned char tmpByte; int col, row; DWORD mouseEventsCounter; RandpeekBytes (hwndDlg, randPool, sizeof (randPool), &mouseEventsCounter); ProcessEntropyEstimate (hEntropyBar, &mouseEventsInitialCount, mouseEventsCounter, maxEntropyLevel, &mouseEntropyGathered); 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++) { if (bDisplayPoolContents) { tmpByte = randPool[row * RANDPOOL_DISPLAY_COLUMNS + col]; StringCbPrintfW (tmp, sizeof(tmp), bRandPoolDispAscii ? ((tmpByte >= 32 && tmpByte < 255 && tmpByte != L'&') ? L" %c " : L" . ") : L"%02X ", tmpByte); } else if (bUseMask) { /* use mask to compute a randomized ASCII representation */ tmpByte = (randPool[row * RANDPOOL_DISPLAY_COLUMNS + col] - lastRandPool[row * RANDPOOL_DISPLAY_COLUMNS + col]) ^ maskRandPool [row * RANDPOOL_DISPLAY_COLUMNS + col]; tmp[0] = (wchar_t) (((tmpByte >> 4) % 6) + L'*'); tmp[1] = (wchar_t) (((tmpByte & 0x0F) % 6) + L'*'); tmp[2] = L' '; tmp[3] = 0; } else { StringCbCopyW (tmp, sizeof(tmp), L"** "); } StringCbCatW (outputDispBuffer, sizeof(outputDispBuffer), tmp); } StringCbCatW (outputDispBuffer, sizeof(outputDispBuffer), L"\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))) { wchar_t tmp[RNG_POOL_SIZE+1]; wmemset (tmp, L' ', ARRAYSIZE(tmp)); tmp [RNG_POOL_SIZE] = 0; SetWindowText (GetDlgItem (hwndDlg, IDC_POOL_CONTENTS), tmp); } return 1; } if (lw == IDC_KEYFILES_RANDOM_SIZE) { EnableWindow(GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), !GetCheckBox (hwndDlg, IDC_KEYFILES_RANDOM_SIZE)); } if (lw == IDC_GENERATE_AND_SAVE_KEYFILE) { wchar_t szNumber[16] = {0}; wchar_t szFileBaseName[TC_MAX_PATH]; wchar_t szDirName[TC_MAX_PATH]; wchar_t szFileName [2*TC_MAX_PATH + 16]; unsigned char *keyfile = NULL; int fhKeyfile = -1, status; long keyfilesCount = 0, keyfilesSize = 0, i; wchar_t* fileExtensionPtr = 0; wchar_t szSuffix[32]; BOOL bRandomSize = GetCheckBox (hwndDlg, IDC_KEYFILES_RANDOM_SIZE); if (!GetWindowText(GetDlgItem (hwndDlg, IDC_NUMBER_KEYFILES), szNumber, ARRAYSIZE(szNumber))) szNumber[0] = 0; keyfilesCount = wcstoul(szNumber, NULL, 0); if (keyfilesCount <= 0 || keyfilesCount == LONG_MAX) { Warning("KEYFILE_INCORRECT_NUMBER", hwndDlg); SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hwndDlg, IDC_NUMBER_KEYFILES), TRUE); return 1; } if (!bRandomSize) { if (!GetWindowText(GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), szNumber, ARRAYSIZE(szNumber))) szNumber[0] = 0; keyfilesSize = wcstoul(szNumber, NULL, 0); if (keyfilesSize < 64 || keyfilesSize > 1024*1024) { Warning("KEYFILE_INCORRECT_SIZE", hwndDlg); SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hwndDlg, IDC_KEYFILES_SIZE), TRUE); return 1; } } if (!GetWindowText(GetDlgItem (hwndDlg, IDC_KEYFILES_BASE_NAME), szFileBaseName, TC_MAX_PATH)) szFileBaseName[0] = 0; // Trim trailing space if (TrimWhiteSpace(szFileBaseName) == 0) { Warning("KEYFILE_EMPTY_BASE_NAME", hwndDlg); SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hwndDlg, IDC_KEYFILES_BASE_NAME), TRUE); return 1; } if (!IsValidFileName(szFileBaseName)) { Warning("KEYFILE_INVALID_BASE_NAME", hwndDlg); SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hwndDlg, IDC_KEYFILES_BASE_NAME), TRUE); return 1; } fileExtensionPtr = wcsrchr(szFileBaseName, L'.'); /* Select directory */ if (!BrowseDirectories (hwndDlg, "SELECT_KEYFILE_GENERATION_DIRECTORY", szDirName)) return 1; if (szDirName[wcslen(szDirName) - 1] != L'\\' && szDirName[wcslen(szDirName) - 1] != L'/') StringCbCat(szDirName, sizeof(szDirName), L"\\"); WaitCursor(); keyfile = (unsigned char*) TCalloc( bRandomSize? KEYFILE_MAX_READ_LEN : keyfilesSize ); for (i= 0; i < keyfilesCount; i++) { StringCbCopyW(szFileName, sizeof(szFileName), szDirName); if (i > 0) { StringCbPrintfW(szSuffix, sizeof(szSuffix), L"_%d", i); // Append the counter to the name if (fileExtensionPtr) { StringCchCatN(szFileName, ARRAYSIZE(szFileName), szFileBaseName, (size_t) (fileExtensionPtr - szFileBaseName)); StringCbCat(szFileName, sizeof(szFileName), szSuffix); StringCbCat(szFileName, sizeof(szFileName), fileExtensionPtr); } else { StringCbCat(szFileName, sizeof(szFileName), szFileBaseName); StringCbCat(szFileName, sizeof(szFileName), szSuffix); } } else StringCbCat(szFileName, sizeof(szFileName), szFileBaseName); // check if the file exists if ((fhKeyfile = _wopen(szFileName, _O_RDONLY|_O_BINARY, _S_IREAD|_S_IWRITE)) != -1) { WCHAR s[4*TC_MAX_PATH] = {0}; _close (fhKeyfile); StringCbPrintfW (s, sizeof(s), GetString ("KEYFILE_ALREADY_EXISTS"), szFileName); status = AskWarnNoYesString (s, hwndDlg); if (status == IDNO) { TCfree(keyfile); NormalCursor(); return 1; } } /* Conceive the file */ if ((fhKeyfile = _wopen(szFileName, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_BINARY, _S_IREAD|_S_IWRITE)) == -1) { TCfree(keyfile); NormalCursor(); handleWin32Error (hwndDlg, SRC_POS); return 1; } if (bRandomSize) { /* Generate a random size */ if (!RandgetBytes (hwndDlg, (unsigned char*) &keyfilesSize, sizeof(keyfilesSize), FALSE)) { _close (fhKeyfile); DeleteFile (szFileName); TCfree(keyfile); NormalCursor(); return 1; } /* since keyfilesSize < 1024 * 1024, we mask with 0x000FFFFF */ keyfilesSize = (long) (((unsigned long) keyfilesSize) & 0x000FFFFF); keyfilesSize %= ((KEYFILE_MAX_READ_LEN - 64) + 1); keyfilesSize += 64; } /* Generate the keyfile */ if (!RandgetBytesFull (hwndDlg, keyfile, keyfilesSize, TRUE, TRUE)) { _close (fhKeyfile); DeleteFile (szFileName); TCfree(keyfile); NormalCursor(); return 1; } /* Write the keyfile */ status = _write (fhKeyfile, keyfile, keyfilesSize); burn (keyfile, keyfilesSize); _close (fhKeyfile); if (status == -1) { TCfree(keyfile); NormalCursor(); handleWin32Error (hwndDlg, SRC_POS); return 1; } } TCfree(keyfile); NormalCursor(); Info("KEYFILE_CREATED", hwndDlg); return 1; } return 0; case WM_CLOSE: { wchar_t 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)); burn (&mouseEntropyGathered, sizeof(mouseEntropyGathered)); burn (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount)); burn (maskRandPool, sizeof(maskRandPool)); // Attempt to wipe the pool contents in the GUI text area wmemset (tmp, L' ', 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; wchar_t 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, 1), 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) { CRYPTOPP_ALIGN_DATA(16) char key[128+1], inputtext[128+1], secondaryKey[64+1], dataUnitNo[16+1]; wchar_t 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, ARRAYSIZE(szTmp)); if (n != ks * 2) { Warning ("TEST_KEY_SIZE", hwndDlg); return 1; } for (n = 0; n < ks; n ++) { wchar_t szTmp2[3], *ptr; long x; szTmp2[2] = 0; szTmp2[0] = szTmp[n * 2]; szTmp2[1] = szTmp[n * 2 + 1]; x = wcstol(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, ARRAYSIZE(szTmp)); } else { n = GetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), szTmp, ARRAYSIZE(szTmp)); } if (n != pt * 2) { if (bEncrypt) { Warning ("TEST_PLAINTEXT_SIZE", hwndDlg); return 1; } else { Warning ("TEST_CIPHERTEXT_SIZE", hwndDlg); return 1; } } for (n = 0; n < pt; n ++) { wchar_t szTmp2[3], *ptr; long x; szTmp2[2] = 0; szTmp2[0] = szTmp[n * 2]; szTmp2[1] = szTmp[n * 2 + 1]; x = wcstol(szTmp2, &ptr, 16); inputtext[n] = (char) x; } // XTS if (bXTSTestEnabled) { // Secondary key if (GetWindowText(GetDlgItem(hwndDlg, IDC_SECONDARY_KEY), szTmp, ARRAYSIZE(szTmp)) != 64) { Warning ("TEST_INCORRECT_SECONDARY_KEY_SIZE", hwndDlg); return 1; } for (n = 0; n < 64; n ++) { wchar_t szTmp2[3], *ptr; long x; szTmp2[2] = 0; szTmp2[0] = szTmp[n * 2]; szTmp2[1] = szTmp[n * 2 + 1]; x = wcstol(szTmp2, &ptr, 16); secondaryKey[n] = (char) x; } // Data unit number tlen = GetWindowText(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), szTmp, ARRAYSIZE(szTmp)); if (tlen > 16 || tlen < 1) { Warning ("TEST_INCORRECT_TEST_DATA_UNIT_SIZE", hwndDlg); return 1; } LeftPadString (szTmp, tlen, 16, L'0'); for (n = 0; n < 16; n ++) { wchar_t szTmp2[3], *ptr; long x; szTmp2[2] = 0; szTmp2[0] = szTmp[n * 2]; szTmp2[1] = szTmp[n * 2 + 1]; x = wcstol(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, SRC_POS); crypto_close (ci); return 1; } memcpy (&ci->k2, secondaryKey, sizeof (secondaryKey)); if (!EAInitMode (ci, ci->k2)) { crypto_close (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 { CipherInit2(idTestCipher, key, ks_tmp, ks); if (bEncrypt) { EncipherBlock(idTestCipher, tmp, ks_tmp); } else { DecipherBlock(idTestCipher, tmp, ks_tmp); } } *szTmp = 0; for (n = 0; n < pt; n ++) { wchar_t szTmp2[3]; StringCbPrintfW(szTmp2, sizeof(szTmp2), L"%02x", (int)((unsigned char)tmp[n])); StringCbCatW(szTmp, sizeof(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 = (int) SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_ADDSTRING, 0,(LPARAM) L"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++) { wchar_t tmpStr [16]; StringCbPrintfW (tmpStr, sizeof(tmpStr), L"%d", ndx); ndx = (int) 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), L"0000000000000000000000000000000000000000000000000000000000000000"); SetWindowText(GetDlgItem(hwndDlg, IDC_TEST_DATA_UNIT_NUMBER), L"0"); SetWindowText(GetDlgItem(hwndDlg, IDC_PLAINTEXT), L"0000000000000000"); SetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), L"0000000000000000"); if (idTestCipher == AES || idTestCipher == SERPENT || idTestCipher == TWOFISH || idTestCipher == CAMELLIA #if defined(CIPHER_GOST89) || idTestCipher == GOST89 #endif || idTestCipher == KUZNYECHIK ) { ndx = (int) SendMessage (GetDlgItem(hwndDlg, IDC_KEY_SIZE), CB_ADDSTRING, 0,(LPARAM) L"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 = (int) SendMessage (GetDlgItem(hwndDlg, IDC_PLAINTEXT_SIZE), CB_ADDSTRING, 0,(LPARAM) L"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), L"0000000000000000000000000000000000000000000000000000000000000000"); SetWindowText(GetDlgItem(hwndDlg, IDC_PLAINTEXT), L"00000000000000000000000000000000"); SetWindowText(GetDlgItem(hwndDlg, IDC_CIPHERTEXT), L"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 = (int) 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, (int) 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); DisableCloseButton (hwndDlg); 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: // This prevents the window from being closed by pressing Alt-F4 (the Close button is hidden). // Note that the OS handles modal MessageBox() dialog windows the same way. 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 (wchar_t *fileName) { int i = 0; wchar_t *ext = wcsrchr (fileName, L'.'); static wchar_t *problemFileExt[] = { // These are protected by the Windows Resource Protection L".asa", L".asp", L".aspx", L".ax", L".bas", L".bat", L".bin", L".cer", L".chm", L".clb", L".cmd", L".cnt", L".cnv", L".com", L".cpl", L".cpx", L".crt", L".csh", L".dll", L".drv", L".dtd", L".exe", L".fxp", L".grp", L".h1s", L".hlp", L".hta", L".ime", L".inf", L".ins", L".isp", L".its", L".js", L".jse", L".ksh", L".lnk", L".mad", L".maf", L".mag", L".mam", L".man", L".maq", L".mar", L".mas", L".mat", L".mau", L".mav", L".maw", L".mda", L".mdb", L".mde", L".mdt", L".mdw", L".mdz", L".msc", L".msi", L".msp", L".mst", L".mui", L".nls", L".ocx", L".ops", L".pal", L".pcd", L".pif", L".prf", L".prg", L".pst", L".reg", L".scf", L".scr", L".sct", L".shb", L".shs", L".sys", L".tlb", L".tsp", L".url", L".vb", L".vbe", L".vbs", L".vsmacros", L".vss", L".vst", L".vsw", L".ws", L".wsc", L".wsf", L".wsh", L".xsd", L".xsl", // These additional file extensions are usually watched by antivirus programs L".386", L".acm", L".ade", L".adp", L".ani", L".app", L".asd", L".asf", L".asx", L".awx", L".ax", L".boo", L".bz2", L".cdf", L".class", L".dhtm", L".dhtml",L".dlo", L".emf", L".eml", L".flt", L".fot", L".gz", L".hlp", L".htm", L".html", L".ini", L".j2k", L".jar", L".jff", L".jif", L".jmh", L".jng", L".jp2", L".jpe", L".jpeg", L".jpg", L".lsp", L".mod", L".nws", L".obj", L".olb", L".osd", L".ov1", L".ov2", L".ov3", L".ovl", L".ovl", L".ovr", L".pdr", L".pgm", L".php", L".pkg", L".pl", L".png", L".pot", L".pps", L".ppt", L".ps1", L".ps1xml", L".psc1", L".rar", L".rpl", L".rtf", L".sbf", L".script", L".sh", L".sha", L".shtm", L".shtml", L".spl", L".swf", L".tar", L".tgz", L".tmp", L".ttf", L".vcs", L".vlm", L".vxd", L".vxo", L".wiz", L".wll", L".wmd", L".wmf", L".wms", L".wmz", L".wpc", L".wsc", L".wsh", L".wwk", L".xhtm", L".xhtml", L".xl", L".xml", L".zip", L".7z", 0}; if (!ext) return FALSE; while (problemFileExt[i]) { if (!_wcsicmp (ext, problemFileExt[i++])) return TRUE; } return FALSE; } void CorrectFileName (wchar_t* fileName) { /* replace '/' by '\' */ size_t i, len = wcslen (fileName); for (i = 0; i < len; i++) { if (fileName [i] == L'/') fileName [i] = L'\\'; } } void CorrectFileName (std::wstring& fileName) { /* replace '/' by '\' */ size_t i, len = fileName.length(); for (i = 0; i < len; i++) { if (fileName [i] == L'/') fileName [i] = L'\\'; } } void CorrectURL (wchar_t* fileName) { /* replace '\' by '/' */ size_t i, len = wcslen (fileName); for (i = 0; i < len; i++) { if (fileName [i] == L'\\') fileName [i] = L'/'; } } 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); } DWORD GetUsedLogicalDrives (void) { DWORD dwUsedDrives = GetLogicalDrives(); if (!bShowDisconnectedNetworkDrives) { static DWORD g_dwLastMappedDrives = 0; static time_t g_lastCallTime = 0; EnterCriticalSection (&csWNetCalls); finally_do ({ LeaveCriticalSection (&csWNetCalls); }); /* update values every 1 minute to reduce CPU consumption */ if ((time (NULL) - g_lastCallTime) > 60) { /* detect disconnected mapped network shares and removed * their associated drives from the list */ WCHAR remotePath[512]; WCHAR drive[3] = {L'A', L':', 0}; DWORD dwLen, status; g_dwLastMappedDrives = 0; for (WCHAR i = 0; i <= MAX_MOUNTED_VOLUME_DRIVE_NUMBER; i++) { if ((dwUsedDrives & (1 << i)) == 0) { drive[0] = L'A' + i; dwLen = ARRAYSIZE (remotePath); status = WNetGetConnection (drive, remotePath, &dwLen); if ((NO_ERROR == status) || (status == ERROR_CONNECTION_UNAVAIL)) { /* this is a mapped network share, mark it as used */ g_dwLastMappedDrives |= (1 << i); } } } g_lastCallTime = time (NULL); } dwUsedDrives |= g_dwLastMappedDrives; } return dwUsedDrives; } int GetFirstAvailableDrive () { DWORD dwUsedDrives = GetUsedLogicalDrives(); int i, drive; /* let A: and B: be used as last resort since they can introduce side effects */ for (i = 2; i < 28; i++) { drive = (i < 26) ? i : (i - 26); if (!(dwUsedDrives & 1 << drive)) return i; } return -1; } int GetLastAvailableDrive () { DWORD dwUsedDrives = GetUsedLogicalDrives(); int i; for (i = 25; i >= 0; i--) { if (!(dwUsedDrives & 1 << i)) return i; } return -1; } BOOL IsDriveAvailable (int driveNo) { return (GetUsedLogicalDrives() & (1 << driveNo)) == 0; } BOOL IsDeviceMounted (wchar_t *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; VOLUME_PROPERTIES_STRUCT prop; BOOL bResult; WCHAR wszLabel[33] = {0}; BOOL bDriverSetLabel = FALSE; memset (&prop, 0, sizeof(prop)); prop.driveNo = nDosDriveNo; if ( DeviceIoControl (hDriver, TC_IOCTL_GET_VOLUME_PROPERTIES, &prop, sizeof (prop), &prop, sizeof (prop), &dwResult, NULL) && prop.driveNo == nDosDriveNo ) { memcpy (wszLabel, prop.wszLabel, sizeof (wszLabel)); bDriverSetLabel = prop.bDriverSetLabel; } 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, SRC_POS); return 1; } else if ((unmount.nReturnCode == ERR_SUCCESS) && bDriverSetLabel && wszLabel[0]) UpdateDriveCustomLabel (nDosDriveNo, wszLabel, FALSE); #ifdef TCMOUNT if (unmount.nReturnCode == ERR_SUCCESS && unmount.HiddenVolumeProtectionTriggered && !VolumeNotificationsList.bHidVolDamagePrevReported [nDosDriveNo] && !Silent) { wchar_t msg[4096]; VolumeNotificationsList.bHidVolDamagePrevReported [nDosDriveNo] = TRUE; StringCbPrintfW (msg, sizeof(msg), GetString ("DAMAGE_TO_HIDDEN_VOLUME_PREVENTED"), nDosDriveNo + L'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)) { wchar_t root[] = { (wchar_t) i + L'A', L':', L'\\', 0 }; SHChangeNotify (eventId, SHCNF_PATH, root, NULL); } } } 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; } static BOOL GetDeviceStorageProperty (HANDLE hDevice, STORAGE_PROPERTY_ID propertyId, DWORD dwDescSize, void* pDesc) { DWORD dwRet = NO_ERROR; if (!pDesc) return FALSE; ZeroMemory (pDesc, dwDescSize); // Set the input data structure STORAGE_PROPERTY_QUERY storagePropertyQuery; ZeroMemory(&storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY)); storagePropertyQuery.PropertyId = propertyId; storagePropertyQuery.QueryType = PropertyStandardQuery; // Get the necessary output buffer size STORAGE_DESCRIPTOR_HEADER descHeader = {0}; DWORD dwBytesReturned = 0; BOOL bRet = ::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY), &descHeader, sizeof(STORAGE_DESCRIPTOR_HEADER), &dwBytesReturned, NULL); if (bRet) { if (dwBytesReturned == sizeof(STORAGE_DESCRIPTOR_HEADER)) { unsigned char* outputBuffer = (unsigned char*) TCalloc (descHeader.Size); bRet = ::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, &storagePropertyQuery, sizeof(STORAGE_PROPERTY_QUERY), outputBuffer, descHeader.Size, &dwBytesReturned, NULL); if (bRet) { if (dwBytesReturned >= dwDescSize) { memcpy (pDesc, outputBuffer, dwDescSize); ((STORAGE_DESCRIPTOR_HEADER*)pDesc)->Version = dwDescSize; ((STORAGE_DESCRIPTOR_HEADER*)pDesc)->Size = dwDescSize; } else { bRet = FALSE; dwRet = ERROR_UNHANDLED_ERROR; } } else dwRet = ::GetLastError(); TCfree (outputBuffer); } else { bRet = FALSE; dwRet = ERROR_UNHANDLED_ERROR; } } else dwRet = ::GetLastError(); if (!bRet) { SetLastError (dwRet); return FALSE; } else return TRUE; } BOOL GetPhysicalDriveStorageInformation(UINT nDriveNumber, STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR* pAlignmentDesc, STORAGE_ADAPTER_DESCRIPTOR* pAdapterDesc) { DWORD dwRet = NO_ERROR; if (!pAlignmentDesc || pAdapterDesc) { SetLastError (ERROR_INVALID_PARAMETER); return FALSE; } // Format physical drive path (may be '\\.\PhysicalDrive0', '\\.\PhysicalDrive1' and so on). TCHAR strDrivePath[512]; StringCbPrintf(strDrivePath, sizeof(strDrivePath), _T("\\\\.\\PhysicalDrive%u"), nDriveNumber); // Get a handle to physical drive HANDLE hDevice = ::CreateFile(strDrivePath, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if(INVALID_HANDLE_VALUE == hDevice) return FALSE; BOOL bRet = (GetDeviceStorageProperty (hDevice, StorageAccessAlignmentProperty, sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR), pAlignmentDesc) || GetDeviceStorageProperty (hDevice, StorageAdapterProperty, sizeof (STORAGE_ADAPTER_DESCRIPTOR), pAdapterDesc))? TRUE : FALSE; dwRet = ::GetLastError(); ::CloseHandle(hDevice); if (!bRet) { SetLastError (dwRet); return FALSE; } else return TRUE; } #ifndef SETUP /************************************************************/ // implementation of the generic wait dialog mechanism static UINT g_wmWaitDlg = ::RegisterWindowMessage(L"VeraCryptWaitDlgMessage"); typedef struct { HWND hwnd; void* pArg; WaitThreadProc callback; } WaitThreadParam; static void _cdecl WaitThread (void* pParam) { WaitThreadParam* pThreadParam = (WaitThreadParam*) pParam; pThreadParam->callback(pThreadParam->pArg, pThreadParam->hwnd); /* close the wait dialog */ PostMessage (pThreadParam->hwnd, g_wmWaitDlg, 0, 0); } BOOL CALLBACK WaitDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) { WORD lw = LOWORD (wParam); switch (msg) { case WM_INITDIALOG: { WaitThreadParam* thParam = (WaitThreadParam*) lParam; // set the progress bar type to MARQUEE (indefinite progress) HWND hProgress = GetDlgItem (hwndDlg, IDC_WAIT_PROGRESS_BAR); if (hProgress) { SetWindowLongPtrW (hProgress, GWL_STYLE, PBS_MARQUEE | GetWindowLongPtrW (hProgress, GWL_STYLE)); ::SendMessageW(hProgress, PBM_SETMARQUEE, (WPARAM) TRUE, (LPARAM) 0); } thParam->hwnd = hwndDlg; // For now, we don't have system menu is the resources but we leave this code // if it is enabled in the future HMENU hSysMenu = GetSystemMenu(hwndDlg, FALSE); if (hSysMenu) { //disable the X EnableMenuItem(hSysMenu,SC_CLOSE, MF_BYCOMMAND|MF_GRAYED); // set icons HICON hIcon = (HICON)::LoadImage(hInst, MAKEINTRESOURCE(IDI_TRUECRYPT_ICON), IMAGE_ICON, ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR); ::SendMessage(hwndDlg, WM_SETICON, TRUE, (LPARAM)hIcon); HICON hIconSmall = (HICON)::LoadImage(hInst, MAKEINTRESOURCE(IDI_TRUECRYPT_ICON), IMAGE_ICON, ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR); ::SendMessage(hwndDlg, WM_SETICON, FALSE, (LPARAM)hIconSmall); } LocalizeDialog (hwndDlg, NULL); _beginthread(WaitThread, 0, thParam); return 0; } case WM_COMMAND: if (lw == IDOK || lw == IDCANCEL) return 1; else return 0; default: if (msg == g_wmWaitDlg) { EndDialog (hwndDlg, IDOK); return 1; } return 0; } } // Based on source: https://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with-SetForegroundWindo?msg=5285754#xx5285754xx void BringToForeground (HWND hWnd) { if(!::IsWindow(hWnd)) return; HWND hCurrWnd = ::GetForegroundWindow(); DWORD dwThisTID = ::GetCurrentThreadId(), dwCurrTID = ::GetWindowThreadProcessId(hCurrWnd,0); // This structure will be used to create the keyboard // input event. INPUT ip; if (hCurrWnd != hWnd) { if(dwThisTID != dwCurrTID) { // Set up a generic keyboard event. ip.type = INPUT_KEYBOARD; ip.ki.wScan = 0; // hardware scan code for key ip.ki.time = 0; ip.ki.dwExtraInfo = 0; // Press the "A" key ip.ki.wVk = VK_MENU; // virtual-key code for the "a" key ip.ki.dwFlags = 0; // 0 for key press SendInput(1, &ip, sizeof(INPUT)); ::Sleep(250); //Sometimes SetForegroundWindow will fail and the window will flash instead of it being show. Sleeping for a bit seems to help. } ::SetForegroundWindow(hWnd); if(dwThisTID != dwCurrTID) { // Release the "A" key ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release SendInput(1, &ip, sizeof(INPUT)); } } #ifdef TCMOUNT if (hWnd == MainDlg) { SetFocus (hWnd); ::SendMessage(hWnd, WM_NEXTDLGCTL, (WPARAM) GetDlgItem (hWnd, IDC_DRIVELIST), 1L); } #endif } static LRESULT CALLBACK ShowWaitDialogParentWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return DefWindowProcW (hWnd, message, wParam, lParam); } void ShowWaitDialog(HWND hwnd, BOOL bUseHwndAsParent, WaitThreadProc callback, void* pArg) { BOOL bEffectiveHideWaitingDialog = bCmdHideWaitingDialogValid? bCmdHideWaitingDialog : bHideWaitingDialog; WaitThreadParam threadParam; threadParam.callback = callback; threadParam.pArg = pArg; if (WaitDialogDisplaying || bEffectiveHideWaitingDialog) { if (!WaitDialogDisplaying) WaitCursor (); callback (pArg, hwnd); if (!WaitDialogDisplaying) NormalCursor (); } else { const wchar_t *className = L"VeraCryptShowWaitDialogParent"; BOOL bIsForeground = FALSE; HWND creatorWnd = hwnd? hwnd : MainDlg; WaitDialogDisplaying = TRUE; HWND hParent = NULL; if (creatorWnd) { if (GetForegroundWindow () == creatorWnd) bIsForeground = TRUE; EnableWindow (creatorWnd, FALSE); } if (hwnd && bUseHwndAsParent) hParent = hwnd; else { /* create invisible window and use it as parent */ WNDCLASSEXW winClass; memset (&winClass, 0, sizeof (winClass)); winClass.cbSize = sizeof (WNDCLASSEX); winClass.lpfnWndProc = (WNDPROC) ShowWaitDialogParentWndProc; winClass.hInstance = hInst; winClass.lpszClassName = className; RegisterClassExW (&winClass); hParent = CreateWindowExW (WS_EX_TOOLWINDOW | WS_EX_LAYERED, className, L"VeraCrypt ShowWaitDialog Parent", 0, 0, 0, 1, 1, NULL, NULL, hInst, NULL); if (hParent) { SetLayeredWindowAttributes (hParent, 0, 1, LWA_ALPHA); ShowWindow (hParent, SW_SHOWNORMAL); } } finally_do_arg2 (HWND, creatorWnd, BOOL, bIsForeground, { if (finally_arg) { EnableWindow(finally_arg, TRUE); if (finally_arg2) BringToForeground (finally_arg);}}); DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_STATIC_MODAL_WAIT_DLG), hParent, (DLGPROC) WaitDlgProc, (LPARAM) &threadParam); WaitDialogDisplaying = FALSE; if (!(hwnd && bUseHwndAsParent)) { if (hParent) DestroyWindow (hParent); UnregisterClassW (className, hInst); } } } #ifndef SETUP /************************************************************************/ static BOOL PerformMountIoctl (MOUNT_STRUCT* pmount, LPDWORD pdwResult, BOOL useVolumeID, BYTE volumeID[VOLUME_ID_SIZE]) { if (useVolumeID) { wstring devicePath = FindDeviceByVolumeID (volumeID, FALSE); if (devicePath == L"") { if (pdwResult) *pdwResult = 0; SetLastError (ERROR_PATH_NOT_FOUND); return FALSE; } else { BOOL bDevice = FALSE; CreateFullVolumePath (pmount->wszVolume, sizeof(pmount->wszVolume), devicePath.c_str(), &bDevice); } } return DeviceIoControl (hDriver, TC_IOCTL_MOUNT_VOLUME, pmount, sizeof (MOUNT_STRUCT), pmount, sizeof (MOUNT_STRUCT), pdwResult, NULL); } // specific definitions and implementation for support of mount operation // in wait dialog mechanism typedef struct { MOUNT_STRUCT* pmount; BOOL useVolumeID; BYTE volumeID[VOLUME_ID_SIZE]; BOOL* pbResult; DWORD* pdwResult; DWORD dwLastError; } MountThreadParam; void CALLBACK MountWaitThreadProc(void* pArg, HWND ) { MountThreadParam* pThreadParam = (MountThreadParam*) pArg; *(pThreadParam->pbResult) = PerformMountIoctl (pThreadParam->pmount, pThreadParam->pdwResult, pThreadParam->useVolumeID, pThreadParam->volumeID); pThreadParam->dwLastError = GetLastError (); } /************************************************************************/ // 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, wchar_t *volumePath, Password *password, int pkcs5, int pim, BOOL truecryptMode, BOOL cachePassword, BOOL cachePim, BOOL sharedAccess, const MountOptions* const mountOptions, BOOL quiet, BOOL bReportWrongPassword) { MOUNT_STRUCT mount; DWORD dwResult, dwLastError = ERROR_SUCCESS; BOOL bResult, bDevice; wchar_t root[MAX_PATH]; int favoriteMountOnArrivalRetryCount = 0; BOOL useVolumeID = FALSE; BYTE volumeID[VOLUME_ID_SIZE] = {0}; #ifdef TCMOUNT if (mountOptions->PartitionInInactiveSysEncScope) { if (!CheckSysEncMountWithoutPBA (hwndDlg, volumePath, quiet)) return -1; } #endif if (IsMountedVolume (volumePath)) { if (!quiet) Error ("VOL_ALREADY_MOUNTED", hwndDlg); return -1; } if (!IsDriveAvailable (driveNo)) { if (!quiet) Error ("DRIVE_LETTER_UNAVAILABLE", hwndDlg); 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; StringCbCopyW (mount.wszLabel, sizeof (mount.wszLabel), mountOptions->Label); retry: mount.nDosDriveNo = driveNo; mount.bCache = cachePassword; mount.bCachePim = cachePim; 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; mount.ProtectedHidVolPkcs5Prf = mountOptions->ProtectedHidVolPkcs5Prf; mount.ProtectedHidVolPim = mountOptions->ProtectedHidVolPim; } else mount.bProtectHiddenVolume = FALSE; mount.bMountReadOnly = mountOptions->ReadOnly; mount.bMountRemovable = mountOptions->Removable; mount.bPreserveTimestamp = mountOptions->PreserveTimestamp; if (mountOptions->DisableMountManager) mount.bMountManager = FALSE; else mount.bMountManager = TRUE; mount.pkcs5_prf = pkcs5; mount.bTrueCryptMode = truecryptMode; mount.VolumePim = pim; wstring path = volumePath; if (path.find (L"\\\\?\\") == 0) { // Remove \\?\ prefix path = path.substr (4); StringCchCopyW (volumePath, TC_MAX_PATH, path.c_str()); } if (path.find (L"Volume{") == 0 && path.rfind (L"}\\") == path.size() - 2) { wstring resolvedPath = VolumeGuidPathToDevicePath (path); if (!resolvedPath.empty()) StringCchCopyW (volumePath, TC_MAX_PATH, resolvedPath.c_str()); } if ((path.length () >= 3) && (_wcsnicmp (path.c_str(), L"ID:", 3) == 0)) { std::vector arr; if ( (path.length() == (3 + 2*VOLUME_ID_SIZE)) && HexWideStringToArray (path.c_str() + 3, arr) && (arr.size() == VOLUME_ID_SIZE) ) { useVolumeID = TRUE; bDevice = TRUE; memcpy (volumeID, &arr[0], VOLUME_ID_SIZE); } else { if (!quiet) Error ("VOLUME_ID_INVALID", hwndDlg); SetLastError (ERROR_INVALID_PARAMETER); return -1; } } else CreateFullVolumePath (mount.wszVolume, sizeof(mount.wszVolume), volumePath, &bDevice); if (!bDevice) { // put default values mount.BytesPerSector = 512; mount.BytesPerPhysicalSector = 512; mount.MaximumTransferLength = 65536; mount.MaximumPhysicalPages = 17; mount.AlignmentMask = 0; // UNC path if (path.find (L"\\\\") == 0) { StringCbCopyW (mount.wszVolume, sizeof (mount.wszVolume), (L"UNC" + path.substr (1)).c_str()); } if (GetVolumePathName (volumePath, root, ARRAYSIZE (root) - 1)) { DWORD bps, flags, d; if (GetDiskFreeSpace (root, &d, &bps, &d, &d)) { mount.BytesPerSector = bps; mount.BytesPerPhysicalSector = bps; } if (IsOSAtLeast (WIN_VISTA)) { if ( (wcslen(root) >= 2) && (root[1] == L':') && (towupper(root[0]) >= L'A' && towupper(root[0]) <= L'Z') ) { wstring drivePath = L"\\\\.\\X:"; HANDLE dev = INVALID_HANDLE_VALUE; VOLUME_DISK_EXTENTS extents = {0}; DWORD dwResult = 0; drivePath[4] = root[0]; if ((dev = CreateFile (drivePath.c_str(),0, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) { if (DeviceIoControl (dev, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, 0, &extents, sizeof(extents), &dwResult, NULL)) { if (extents.NumberOfDiskExtents > 0) { STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR accessDesc; STORAGE_ADAPTER_DESCRIPTOR adapterDesc; if (GetPhysicalDriveStorageInformation (extents.Extents[0].DiskNumber, &accessDesc, &adapterDesc)) { if (accessDesc.Size >= sizeof (STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR)) { mount.BytesPerSector = accessDesc.BytesPerLogicalSector; mount.BytesPerPhysicalSector = accessDesc.BytesPerPhysicalSector; } if (adapterDesc.Size >= sizeof (STORAGE_ADAPTER_DESCRIPTOR)) { mount.MaximumTransferLength = adapterDesc.MaximumTransferLength; mount.MaximumPhysicalPages = adapterDesc.MaximumPhysicalPages; mount.AlignmentMask = adapterDesc.AlignmentMask; } } } } CloseHandle (dev); } } } // Read-only host filesystem if (!mount.bMountReadOnly && GetVolumeInformation (root, NULL, 0, NULL, &d, &flags, NULL, 0)) mount.bMountReadOnly = (flags & FILE_READ_ONLY_VOLUME) != 0; } } 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) { if (!quiet) Warning ("NO_SYSENC_PARTITION_SELECTED", hwndDlg); return -1; } mount.bPartitionInInactiveSysEncScope = TRUE; } if (!quiet) { MountThreadParam mountThreadParam; mountThreadParam.pmount = &mount; mountThreadParam.useVolumeID = useVolumeID; memcpy (mountThreadParam.volumeID, volumeID, VOLUME_ID_SIZE); mountThreadParam.pbResult = &bResult; mountThreadParam.pdwResult = &dwResult; mountThreadParam.dwLastError = ERROR_SUCCESS; ShowWaitDialog (hwndDlg, FALSE, MountWaitThreadProc, &mountThreadParam); dwLastError = mountThreadParam.dwLastError; } else { bResult = PerformMountIoctl (&mount, &dwResult, useVolumeID, volumeID); dwLastError = GetLastError (); } burn (&mount.VolumePassword, sizeof (mount.VolumePassword)); burn (&mount.ProtectedHidVolPassword, sizeof (mount.ProtectedHidVolPassword)); burn (&mount.pkcs5_prf, sizeof (mount.pkcs5_prf)); burn (&mount.bTrueCryptMode, sizeof (mount.bTrueCryptMode)); burn (&mount.ProtectedHidVolPkcs5Prf, sizeof (mount.ProtectedHidVolPkcs5Prf)); SetLastError (dwLastError); 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", hwndDlg); return -1; } else { if (quiet) { mount.bExclusiveAccess = FALSE; goto retry; } // Ask user if (IDYES == AskWarnNoYes ("FILE_IN_USE", hwndDlg)) { mount.bExclusiveAccess = FALSE; goto retry; } } return -1; } if (!quiet && (!MultipleMountOperationInProgress || GetLastError() != ERROR_NOT_READY)) handleWin32Error (hwndDlg, SRC_POS); 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 (swscanf (volumePath, L"\\Device\\Harddisk%d\\Partition", &driveNo) == 1) { OPEN_TEST_STRUCT openTestStruct; memset (&openTestStruct, 0, sizeof (openTestStruct)); openTestStruct.bDetectTCBootLoader = TRUE; StringCchPrintfW ((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(), hwndDlg); else handleError (hwndDlg, mount.nReturnCode, SRC_POS); } } else handleError (hwndDlg, mount.nReturnCode, SRC_POS); } return 0; } if (!quiet) handleError (hwndDlg, mount.nReturnCode, SRC_POS); return 0; } // Mount successful if (mount.UseBackupHeader != mountOptions->UseBackupHeader && mount.UseBackupHeader) { if (bReportWrongPassword && !Silent) Warning ("HEADER_DAMAGED_AUTO_USED_HEADER_BAK", hwndDlg); } LastMountedVolumeDirty = mount.FilesystemDirty; if (mount.FilesystemDirty) { wchar_t msg[1024]; wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 }; StringCbPrintfW (msg, sizeof(msg), GetString ("MOUNTED_VOLUME_DIRTY"), mountPoint); if (AskWarnYesNoStringTopmost (msg, hwndDlg) == IDYES) CheckFilesystem (hwndDlg, 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 }; StringCbPrintfW (msg, sizeof(msg), GetString ("MOUNTED_CONTAINER_FORCED_READ_ONLY"), mountPoint); WarningDirect (msg, hwndDlg); } if (mount.VolumeMountedReadOnlyAfterAccessDenied && !Silent && bDevice) { wchar_t msg[1024]; wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 }; StringCbPrintfW (msg, sizeof(msg), GetString ("MOUNTED_DEVICE_FORCED_READ_ONLY"), mountPoint); WarningDirect (msg, hwndDlg); } if (mount.VolumeMountedReadOnlyAfterDeviceWriteProtected && !Silent && wcsstr (volumePath, L"\\Device\\Harddisk") == volumePath) { wchar_t msg[1024]; wchar_t mountPoint[] = { L'A' + (wchar_t) driveNo, L':', 0 }; StringCbPrintfW (msg, sizeof(msg), GetString ("MOUNTED_DEVICE_FORCED_READ_ONLY_WRITE_PROTECTION"), mountPoint); WarningDirect (msg, hwndDlg); if (CurrentOSMajor >= 6 && wcsstr (volumePath, L"\\Device\\HarddiskVolume") != volumePath && AskNoYes ("ASK_REMOVE_DEVICE_WRITE_PROTECTION", hwndDlg) == IDYES) { RemoveDeviceWriteProtection (hwndDlg, volumePath); } } if (mount.wszLabel[0] && !mount.bDriverSetLabel) { // try setting the drive label on user-mode using registry UpdateDriveCustomLabel (driveNo, mount.wszLabel, TRUE); } ResetWrongPwdRetryCount (); BroadcastDeviceChange (DBT_DEVICEARRIVAL, driveNo, 0); if (mount.bExclusiveAccess == FALSE) return 2; return 1; } #endif typedef struct { int nDosDriveNo; BOOL forced; int dismountMaxRetries; DWORD retryDelay; int* presult; DWORD dwLastError; } UnmountThreadParam; void CALLBACK UnmountWaitThreadProc(void* pArg, HWND hwnd) { UnmountThreadParam* pThreadParam = (UnmountThreadParam*) pArg; int dismountMaxRetries = pThreadParam->dismountMaxRetries; DWORD retryDelay = pThreadParam->retryDelay; do { *pThreadParam->presult = DriverUnmountVolume (hwnd, pThreadParam->nDosDriveNo, pThreadParam->forced); if (*pThreadParam->presult == ERR_FILES_OPEN) Sleep (retryDelay); else break; } while (--dismountMaxRetries > 0); pThreadParam->dwLastError = GetLastError (); } static BOOL UnmountVolumeBase (HWND hwndDlg, int nDosDriveNo, BOOL forceUnmount, BOOL ntfsFormatCase) { int result; BOOL forced = forceUnmount; int dismountMaxRetries = ntfsFormatCase? 5 : UNMOUNT_MAX_AUTO_RETRIES; DWORD retryDelay = ntfsFormatCase? 2000: UNMOUNT_AUTO_RETRY_DELAY; UnmountThreadParam param; retry: BroadcastDeviceChange (DBT_DEVICEREMOVEPENDING, nDosDriveNo, 0); param.nDosDriveNo = nDosDriveNo; param.forced = forced; param.dismountMaxRetries = dismountMaxRetries; param.retryDelay = retryDelay; param.presult = &result; if (Silent) { UnmountWaitThreadProc (¶m, hwndDlg); } else { ShowWaitDialog (hwndDlg, FALSE, UnmountWaitThreadProc, ¶m); } SetLastError (param.dwLastError); if (result != 0) { if (result == ERR_FILES_OPEN && !Silent) { if (IDYES == AskWarnYesNoTopmost ("UNMOUNT_LOCK_FAILED", hwndDlg)) { forced = TRUE; goto retry; } if (IsOSAtLeast (WIN_7)) { // Undo SHCNE_DRIVEREMOVED wchar_t root[] = { (wchar_t) nDosDriveNo + L'A', L':', L'\\', 0 }; SHChangeNotify (SHCNE_DRIVEADD, SHCNF_PATH, root, NULL); } return FALSE; } Error ("UNMOUNT_FAILED", hwndDlg); return FALSE; } BroadcastDeviceChange (DBT_DEVICEREMOVECOMPLETE, nDosDriveNo, 0); return TRUE; } BOOL UnmountVolume (HWND hwndDlg, int nDosDriveNo, BOOL forceUnmount) { return UnmountVolumeBase (hwndDlg, nDosDriveNo, forceUnmount, FALSE); } BOOL UnmountVolumeAfterFormatExCall (HWND hwndDlg, int nDosDriveNo) { return UnmountVolumeBase (hwndDlg, nDosDriveNo, FALSE, TRUE); } BOOL IsPasswordCacheEmpty (void) { DWORD dw; return !DeviceIoControl (hDriver, TC_IOCTL_GET_PASSWORD_CACHE_STATUS, 0, 0, 0, 0, &dw, 0); } BOOL IsMountedVolumeID (BYTE volumeID[VOLUME_ID_SIZE]) { MOUNT_LIST_STRUCT mlist; DWORD dwResult; int i; memset (&mlist, 0, sizeof (mlist)); if ( !DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist, sizeof (mlist), &mlist, sizeof (mlist), &dwResult, NULL) || (mlist.ulMountedDrives >= (1 << 26)) ) { return FALSE; } if (mlist.ulMountedDrives) { for (i=0 ; i<26; i++) { if ((mlist.ulMountedDrives & (1 << i)) && (0 == memcmp (mlist.volumeID[i], volumeID, VOLUME_ID_SIZE))) return TRUE; } } return FALSE; } BOOL IsMountedVolume (const wchar_t *volname) { if ((wcslen (volname) == (3 + 2*VOLUME_ID_SIZE)) && _wcsnicmp (volname, L"ID:", 3) == 0) { /* Volume ID specified. Use it for matching mounted volumes. */ std::vector arr; if (HexWideStringToArray (&volname[3], arr) && (arr.size() == VOLUME_ID_SIZE)) { return IsMountedVolumeID (&arr[0]); } } else { MOUNT_LIST_STRUCT mlist; DWORD dwResult; int i; wchar_t volume[TC_MAX_PATH*2+16]; StringCbCopyW (volume, sizeof(volume), volname); if (wcsstr (volname, L"\\Device\\") != volname) StringCbPrintfW(volume, sizeof(volume), L"\\??\\%s", volname); wstring resolvedPath = VolumeGuidPathToDevicePath (volname); if (!resolvedPath.empty()) StringCbCopyW (volume, sizeof (volume), resolvedPath.c_str()); memset (&mlist, 0, sizeof (mlist)); if ( !DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist, sizeof (mlist), &mlist, sizeof (mlist), &dwResult, NULL) || (mlist.ulMountedDrives >= (1 << 26)) ) { return FALSE; } if (mlist.ulMountedDrives) { for (i=0 ; i<26; i++) { if ((mlist.ulMountedDrives & (1 << i)) && IsNullTerminateString (mlist.wszVolume[i], TC_MAX_PATH) && (0 == _wcsicmp ((wchar_t *) mlist.wszVolume[i], volume)) ) { return TRUE; } } } } return FALSE; } int GetMountedVolumeDriveNo (wchar_t *volname) { MOUNT_LIST_STRUCT mlist; DWORD dwResult; int i; wchar_t volume[TC_MAX_PATH*2+16]; if (volname == NULL) return -1; StringCbCopyW (volume, sizeof(volume), volname); if (wcsstr (volname, L"\\Device\\") != volname) StringCbPrintfW (volume, sizeof(volume), L"\\??\\%s", volname); wstring resolvedPath = VolumeGuidPathToDevicePath (volname); if (!resolvedPath.empty()) StringCbCopyW (volume, sizeof (volume), resolvedPath.c_str()); memset (&mlist, 0, sizeof (mlist)); if ( !DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist, sizeof (mlist), &mlist, sizeof (mlist), &dwResult, NULL) || (mlist.ulMountedDrives >= (1 << 26)) ) { return -1; } if (mlist.ulMountedDrives) { for (i=0 ; i<26; i++) { if ((mlist.ulMountedDrives & (1 << i)) && IsNullTerminateString (mlist.wszVolume[i], TC_MAX_PATH) && (0 == _wcsicmp ((wchar_t *) mlist.wszVolume[i], (WCHAR *)volume)) ) { return i; } } } return -1; } #endif //!SETUP 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, L"Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", 0, KEY_READ, &hkey) == ERROR_SUCCESS) { if (RegQueryValueEx (hkey, L"EnableLUA", 0, 0, (LPBYTE) &value, &size) != ERROR_SUCCESS) value = 1; RegCloseKey (hkey); } return value != 0; } BOOL ResolveSymbolicLink (const wchar_t *symLinkName, PWSTR targetName, size_t cbTargetName) { BOOL bResult; DWORD dwResult; RESOLVE_SYMLINK_STRUCT resolve; memset (&resolve, 0, sizeof(resolve)); StringCbCopyW (resolve.symLinkName, sizeof(resolve.symLinkName), symLinkName); bResult = DeviceIoControl (hDriver, TC_IOCTL_GET_RESOLVED_SYMLINK, &resolve, sizeof (resolve), &resolve, sizeof (resolve), &dwResult, NULL); StringCbCopyW (targetName, cbTargetName, resolve.targetName); return bResult; } BOOL GetPartitionInfo (const wchar_t *deviceName, PPARTITION_INFORMATION rpartInfo) { BOOL bResult; DWORD dwResult; DISK_PARTITION_INFO_STRUCT dpi; memset (&dpi, 0, sizeof(dpi)); StringCbCopyW ((PWSTR) &dpi.deviceName, sizeof(dpi.deviceName), 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 wchar_t *deviceName, DISK_PARTITION_INFO_STRUCT *info) { DWORD dwResult; memset (info, 0, sizeof(*info)); StringCbCopyW ((PWSTR) &info->deviceName, sizeof(info->deviceName), deviceName); return DeviceIoControl (hDriver, TC_IOCTL_GET_DRIVE_PARTITION_INFO, info, sizeof (*info), info, sizeof (*info), &dwResult, NULL); } #ifndef SETUP BOOL GetDriveGeometry (const wchar_t *deviceName, PDISK_GEOMETRY_EX diskGeometry) { BOOL bResult; DWORD dwResult; DISK_GEOMETRY_EX_STRUCT dg; memset (&dg, 0, sizeof(dg)); StringCbCopyW ((PWSTR) &dg.deviceName, sizeof(dg.deviceName), deviceName); bResult = DeviceIoControl (hDriver, VC_IOCTL_GET_DRIVE_GEOMETRY_EX, &dg, sizeof (dg), &dg, sizeof (dg), &dwResult, NULL); if (bResult && (dwResult == sizeof (dg)) && dg.diskGeometry.BytesPerSector) { ZeroMemory (diskGeometry, sizeof (DISK_GEOMETRY_EX)); memcpy (&diskGeometry->Geometry, &dg.diskGeometry, sizeof (DISK_GEOMETRY)); diskGeometry->DiskSize.QuadPart = dg.DiskSize.QuadPart; return TRUE; } else return FALSE; } BOOL GetPhysicalDriveGeometry (int driveNumber, PDISK_GEOMETRY_EX diskGeometry) { HANDLE hDev; BOOL bResult = FALSE; TCHAR devicePath[MAX_PATH]; StringCchPrintfW (devicePath, ARRAYSIZE (devicePath), L"\\\\.\\PhysicalDrive%d", driveNumber); if ((hDev = CreateFileW (devicePath, 0, 0, NULL, OPEN_EXISTING, 0, NULL)) != INVALID_HANDLE_VALUE) { DWORD bytesRead = 0; ZeroMemory (diskGeometry, sizeof (DISK_GEOMETRY_EX)); BYTE dgBuffer[256]; if ( DeviceIoControl (hDev, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, dgBuffer, sizeof (dgBuffer), &bytesRead, NULL) && (bytesRead >= (sizeof (DISK_GEOMETRY) + sizeof (LARGE_INTEGER))) && ((PDISK_GEOMETRY_EX) dgBuffer)->Geometry.BytesPerSector) { memcpy (&diskGeometry->Geometry, &((PDISK_GEOMETRY_EX) dgBuffer)->Geometry, sizeof (DISK_GEOMETRY)); diskGeometry->DiskSize.QuadPart = ((PDISK_GEOMETRY_EX) dgBuffer)->DiskSize.QuadPart; bResult = TRUE; } else { DISK_GEOMETRY geo; if ( DeviceIoControl (hDev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, (LPVOID) &geo, sizeof (geo), &bytesRead, NULL) && (bytesRead >= sizeof (DISK_GEOMETRY)) && geo.BytesPerSector) { memcpy (&diskGeometry->Geometry, &geo, sizeof (DISK_GEOMETRY)); diskGeometry->DiskSize.QuadPart = geo.Cylinders.QuadPart * geo.SectorsPerTrack * geo.TracksPerCylinder * geo.BytesPerSector; bResult = TRUE; if (CurrentOSMajor >= 6) { STORAGE_READ_CAPACITY storage = {0}; storage.Version = sizeof (STORAGE_READ_CAPACITY); storage.Size = sizeof (STORAGE_READ_CAPACITY); if (DeviceIoControl (hDev, IOCTL_STORAGE_READ_CAPACITY, NULL, 0, (LPVOID) &storage, sizeof (storage), &bytesRead, NULL) && (bytesRead >= sizeof (storage)) && (storage.Size == sizeof (STORAGE_READ_CAPACITY)) ) { diskGeometry->DiskSize.QuadPart = storage.DiskLength.QuadPart; } } } } CloseHandle (hDev); } return bResult; } #endif // 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, sizeof(device))) StringCchCopyW (device, MAX_PATH, deviceName); for (i = 0; i < 26; i++) { WCHAR drive[] = { (WCHAR) i + L'A', L':', 0 }; StringCchCopyW (link, MAX_PATH, L"\\DosDevices\\"); StringCchCatW (link, MAX_PATH, drive); if ( ResolveSymbolicLink (link, target, sizeof(target)) && (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 wchar_t *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 wchar_t *devicePath, float *percentFree, __int64 *occupiedBytes, BOOL silent) { WCHAR devPath [MAX_PATH]; int driveLetterNo = -1; wchar_t szRootPath[4] = {0, L':', L'\\', 0}; ULARGE_INTEGER freeSpaceSize; ULARGE_INTEGER totalNumberOfBytes; ULARGE_INTEGER totalNumberOfFreeBytes; StringCbCopyW (devPath, sizeof(devPath), devicePath); driveLetterNo = GetDiskDeviceDriveLetter (devPath); szRootPath[0] = (wchar_t) driveLetterNo + L'A'; if (!GetDiskFreeSpaceEx (szRootPath, &freeSpaceSize, &totalNumberOfBytes, &totalNumberOfFreeBytes)) { if (!silent) { handleWin32Error (MainDlg, SRC_POS); Error ("CANNOT_CALC_SPACE", MainDlg); } 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, SRC_POS); Error ("CANT_GET_VOLSIZE", MainDlg); } 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 wchar_t *devicePath) { PARTITION_INFORMATION partitionInfo; if (!GetPartitionInfo (devicePath, &partitionInfo)) return -1; return partitionInfo.PartitionLength.QuadPart; } HANDLE DismountDrive (wchar_t *devName, wchar_t *devicePath) { DWORD dwResult; HANDLE hVolume; BOOL bResult = FALSE; int attempt = UNMOUNT_MAX_AUTO_RETRIES; int driveLetterNo = -1; WCHAR devPath [MAX_PATH]; StringCbCopyW (devPath, sizeof(devPath), devicePath); 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, int64 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, (size_t) strLen) == 0) return i; } return -1; } // Returns TRUE if the file or directory exists (both may be enclosed in quotation marks). BOOL FileExists (const wchar_t *filePathPtr) { wchar_t filePath [TC_MAX_PATH * 2 + 1]; // Strip quotation marks (if any) if (filePathPtr [0] == L'"') { StringCbCopyW (filePath, sizeof(filePath), filePathPtr + 1); } else { StringCbCopyW (filePath, sizeof(filePath), filePathPtr); } // Strip quotation marks (if any) if (filePath [wcslen (filePath) - 1] == L'"') filePath [wcslen (filePath) - 1] = 0; return (_waccess (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 wchar_t *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) { if (buffer) free (buffer); 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 TCCopyFileBase (HANDLE src, HANDLE dst) { __int8 *buffer; FILETIME fileTime; DWORD bytesRead, bytesWritten; BOOL res; 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; } } if (GetFileTime (src, NULL, NULL, &fileTime)) SetFileTime (dst, NULL, NULL, &fileTime); CloseHandle (src); CloseHandle (dst); free (buffer); return res != 0; } BOOL TCCopyFile (wchar_t *sourceFileName, wchar_t *destinationFile) { HANDLE src, dst; src = CreateFileW (sourceFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (src == INVALID_HANDLE_VALUE) return FALSE; dst = CreateFileW (destinationFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); if (dst == INVALID_HANDLE_VALUE) { CloseHandle (src); return FALSE; } return TCCopyFileBase (src, dst); } BOOL DecompressZipToDir (const unsigned char *inputBuffer, DWORD inputLength, const wchar_t *destinationDir, ProgressFn progressFnPtr, HWND hwndDlg) { BOOL res = TRUE; zip_error_t zerr; zip_int64_t numFiles, i; zip_stat_t sb; zip_source_t* zsrc = zip_source_buffer_create (inputBuffer, inputLength, 0, &zerr); if (!zsrc) return FALSE; zip_t* z = zip_open_from_source (zsrc, ZIP_CHECKCONS | ZIP_RDONLY, &zerr); if (!z) { zip_source_free (zsrc); return FALSE; } finally_do_arg (zip_t*, z, { zip_close (finally_arg); }); numFiles = zip_get_num_entries (z, 0); if (numFiles <= 0) return FALSE; for (i = 0; (i < numFiles) && res; i++) { ZeroMemory (&sb, sizeof (sb)); if ((0 == zip_stat_index (z, i, 0, &sb)) && (sb.valid & (ZIP_STAT_NAME | ZIP_STAT_SIZE)) && (sb.size > 0)) { std::wstring wname = Utf8StringToWide (sb.name); CorrectFileName (wname); std::wstring filePath = destinationDir + wname; size_t pos = filePath.find_last_of (L"/\\"); // create the parent directory if it doesn't exist if (pos != std::wstring::npos) { SHCreateDirectoryEx (NULL, filePath.substr (0, pos).c_str(), NULL); } zip_file_t *f = zip_fopen_index (z, i, 0); if (f) { ByteArray buffer((ByteArray::size_type) sb.size); zip_fread (f, buffer.data(), sb.size); zip_fclose (f); if (progressFnPtr) progressFnPtr (hwndDlg, filePath.c_str()); res = SaveBufferToFile ((char *) buffer.data(), filePath.c_str(), (DWORD) buffer.size(), FALSE, TRUE); } } } return res; } // 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 wchar_t *destinationFile, DWORD inputLength, BOOL bAppend, BOOL bRenameIfFailed) { HANDLE dst; DWORD bytesWritten; BOOL res = TRUE; DWORD dwLastError = 0; dst = CreateFile (destinationFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, bAppend ? OPEN_EXISTING : CREATE_ALWAYS, 0, NULL); dwLastError = GetLastError(); if (!bAppend && bRenameIfFailed && (dst == INVALID_HANDLE_VALUE) && (GetLastError () == ERROR_SHARING_VIOLATION)) { wchar_t renamedPath[TC_MAX_PATH + 1]; StringCbCopyW (renamedPath, sizeof(renamedPath), destinationFile); StringCbCatW (renamedPath, sizeof(renamedPath), VC_FILENAME_RENAMED_SUFFIX); /* rename the locked file in order to be able to create a new one */ if (MoveFileEx (destinationFile, renamedPath, MOVEFILE_REPLACE_EXISTING)) { dst = CreateFile (destinationFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); dwLastError = GetLastError(); if (dst == INVALID_HANDLE_VALUE) { /* restore the original file name */ MoveFileEx (renamedPath, destinationFile, MOVEFILE_REPLACE_EXISTING); } else { /* delete the renamed file when the machine reboots */ MoveFileEx (renamedPath, NULL, MOVEFILE_DELAY_UNTIL_REBOOT); } } } if (dst == INVALID_HANDLE_VALUE) { SetLastError (dwLastError); handleWin32Error (MainDlg, SRC_POS); 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, SRC_POS); } CloseHandle (dst); if (!res && !bAppend) _wremove (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, wchar_t *title, size_t textByteLen) { wchar_t cl [MAX_PATH*3] = {L"/p \""}; wchar_t path [MAX_PATH * 2] = { 0 }; wchar_t filename [MAX_PATH + 1] = { 0 }; StringCbCopyW (filename, sizeof(filename), title); //strcat (filename, ".txt"); GetTempPath (ARRAYSIZE (path), path); if (!FileExists (path)) { StringCbCopyW (path, sizeof(path), GetConfigPath (filename)); if (wcslen(path) < 2) return FALSE; } else { StringCbCatW (path, sizeof(path), filename); } // Write the Unicode signature if (!SaveBufferToFile ("\xFF\xFE", path, 2, FALSE, FALSE)) { _wremove (path); return FALSE; } // Write the actual text if (!SaveBufferToFile ((char *) text, path, (DWORD) textByteLen, TRUE, FALSE)) { _wremove (path); return FALSE; } StringCbCatW (cl, sizeof(cl), path); StringCbCatW (cl, sizeof(cl), L"\""); // Get the absolute path for notepad if (GetWindowsDirectory(filename, MAX_PATH)) { if (filename[wcslen (filename) - 1] != L'\\') StringCbCatW (filename, sizeof(filename), L"\\"); StringCbCatW(filename, sizeof(filename), PRINT_TOOL); } else StringCbCopyW(filename, sizeof(filename), L"C:\\Windows\\" PRINT_TOOL); WaitCursor (); ShellExecute (NULL, L"open", filename, cl, NULL, SW_HIDE); Sleep (6000); NormalCursor(); _wremove (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 wchar_t 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))) { StringCbCatW (path, MAX_PATH * 2, L"\\VeraCrypt\\"); StringCbCatW (path, MAX_PATH * 2, 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, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VeraCrypt", 0, KEY_READ | KEY_WOW64_32KEY, &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 ()) { wchar_t regk [64]; GetStartupRegKeyName (regk, sizeof(regk)); if (bStartOnLogon || bMountDevicesOnLogon || bMountFavoritesOnLogon) { wchar_t exe[MAX_PATH * 2] = { L'"' }; GetModuleFileName (NULL, exe + 1, ARRAYSIZE (exe) - 1); #ifdef VOLFORMAT { wchar_t *tmp = NULL; if (tmp = wcsrchr (exe, L'\\')) { *tmp = 0; StringCbCatW (exe, MAX_PATH * 2, L"\\VeraCrypt.exe"); } } #endif StringCbCatW (exe, MAX_PATH * 2, L"\" /q preferences /a logon"); if (bMountDevicesOnLogon) StringCbCatW (exe, MAX_PATH * 2, L" /a devices"); if (bMountFavoritesOnLogon) StringCbCatW (exe, MAX_PATH * 2, L" /a favorites"); WriteRegistryString (regk, L"VeraCrypt", exe); } else DeleteRegistryValue (regk, L"VeraCrypt"); } } // Adds or removes the VeraCrypt Volume Creation Wizard to/from the system startup sequence void ManageStartupSeqWiz (BOOL bRemove, const wchar_t *arg) { wchar_t regk [64]; GetStartupRegKeyName (regk, sizeof(regk)); if (!bRemove) { size_t exeSize = (MAX_PATH * 2) + 3 + 20 + wcslen (arg); // enough room for all concatenation operations wchar_t* exe = (wchar_t*) calloc(1, exeSize * sizeof (wchar_t)); exe[0] = L'"'; GetModuleFileName (NULL, exe + 1, (DWORD) (exeSize - 1)); #ifndef VOLFORMAT { wchar_t *tmp = NULL; if (tmp = wcsrchr (exe, L'\\')) { *tmp = 0; StringCchCatW (exe, exeSize, L"\\VeraCrypt Format.exe"); } } #endif if (wcslen (arg) > 0) { StringCchCatW (exe, exeSize, L"\" "); StringCchCatW (exe, exeSize, arg); } WriteRegistryString (regk, L"VeraCrypt Format", exe); free(exe); } else DeleteRegistryValue (regk, L"VeraCrypt 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]; WCHAR regPath[128]; WCHAR key[64]; int id, len; GetModuleFileNameW (NULL, exeFilename, sizeof (exeFilename) / sizeof(exeFilename[0])); strToMatch = wcsrchr (exeFilename, L'\\') + 1; StringCbPrintfW (regPath, sizeof(regPath), L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisited%sMRU", IsOSAtLeast (WIN_VISTA) ? L"Pidl" : L""); for (id = (IsOSAtLeast (WIN_VISTA) ? 0 : L'a'); id <= (IsOSAtLeast (WIN_VISTA) ? 1000 : L'z'); id++) { *strTmp = 0; StringCbPrintfW (key, sizeof(key), (IsOSAtLeast (WIN_VISTA) ? L"%d" : L"%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 (L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRU", L"MRUListEx", buf, sizeof (buf)); while (l > 0) { l -= sizeof (int); if (*p == id) { p++; len -= sizeof (int); continue; } *pout++ = *p++; } WriteRegistryBytes (L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedPidlMRU", L"MRUListEx", bufout, len); } else { wchar_t *p = (wchar_t*) buf; wchar_t *pout = (wchar_t*) bufout; ReadRegistryString (L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", L"MRUList", L"", (wchar_t*) buf, sizeof (buf)); while (*p) { if (*p == id) { p++; continue; } *pout++ = *p++; } *pout++ = 0; WriteRegistryString (L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ComDlg32\\LastVisitedMRU", L"MRUList", (wchar_t*) 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, const wchar_t *string) { LVITEM li; memset (&li, 0, sizeof(li)); li.mask = LVIF_TEXT; li.pszText = (wchar_t*) string; li.iItem = index; li.iSubItem = 0; return ListView_InsertItem (list, &li); } LRESULT ListSubItemSet (HWND list, int index, int subIndex, const wchar_t *string) { LVITEM li; memset (&li, 0, sizeof(li)); li.mask = LVIF_TEXT; li.pszText = (wchar_t*) string; li.iItem = index; li.iSubItem = subIndex; return ListView_SetItem (list, &li); } BOOL GetMountList (MOUNT_LIST_STRUCT *list) { DWORD dwResult; MOUNT_LIST_STRUCT localList = {0}; if ( list && DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &localList, sizeof (localList), &localList, sizeof (localList), &dwResult, NULL) && (localList.ulMountedDrives < (1 << 26)) ) { memcpy (list, &localList, sizeof (MOUNT_LIST_STRUCT)); return TRUE; } else return FALSE; } 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 (const wchar_t *filePath, unsigned __int32 *result, __int64 fileOffset) { DWORD 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 (const wchar_t *filePath, int *result, __int64 fileOffset) { DWORD 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 wchar_t *fileName, DWORD *size) { char *buf; DWORD fileSize = INVALID_FILE_SIZE; HANDLE h = CreateFile (fileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); if (h == INVALID_HANDLE_VALUE) return NULL; if ((fileSize = GetFileSize (h, NULL)) == INVALID_FILE_SIZE) { CloseHandle (h); return NULL; } *size = fileSize; buf = (char *) calloc (*size + 1, 1); if (buf == NULL) { CloseHandle (h); return NULL; } if (!ReadFile (h, buf, *size, size, NULL)) { free (buf); buf = NULL; } CloseHandle (h); return buf; } // Returns NULL if there's any error. char *LoadFileBlock (const wchar_t *fileName, __int64 fileOffset, DWORD count) { char *buf; DWORD bytesRead = 0; LARGE_INTEGER seekOffset, seekOffsetNew; BOOL bStatus; 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 *) calloc (count, 1); if (buf == NULL) { CloseHandle (h); return NULL; } bStatus = ReadFile (h, buf, count, &bytesRead, NULL); CloseHandle (h); if (!bStatus || (bytesRead != count)) { free (buf); return NULL; } return buf; } // Returns -1 if there is an error, or the size of the file. __int64 GetFileSize64 (const wchar_t *path) { HANDLE h = CreateFile (path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); LARGE_INTEGER size; __int64 retSize = -1; if (h) { if (GetFileSizeEx (h, &size)) { retSize = size.QuadPart; } CloseHandle (h); } return retSize; } wchar_t *GetModPath (wchar_t *path, int maxSize) { GetModuleFileName (NULL, path, maxSize); wchar_t* ptr = wcsrchr (path, L'\\'); if (ptr) ptr[1] = 0; return path; } wchar_t *GetConfigPath (wchar_t *fileName) { static wchar_t path[MAX_PATH * 2] = { 0 }; if (IsNonInstallMode ()) { GetModPath (path, ARRAYSIZE (path)); StringCchCatW (path, (MAX_PATH * 2), fileName); return path; } if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path))) { StringCchCatW (path, (MAX_PATH * 2), L"\\VeraCrypt\\"); CreateDirectory (path, NULL); StringCchCatW (path, (MAX_PATH * 2), fileName); } else path[0] = 0; return path; } wchar_t *GetProgramConfigPath (wchar_t *fileName) { static wchar_t path[MAX_PATH * 2] = { 0 }; if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_COMMON_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, path))) { StringCchCatW (path, (MAX_PATH * 2), L"\\VeraCrypt\\"); CreateDirectory (path, NULL); StringCchCatW (path, (MAX_PATH * 2), fileName); } else path[0] = 0; return path; } std::wstring GetServiceConfigPath (const wchar_t *fileName, bool useLegacy) { wchar_t sysPath[TC_MAX_PATH]; if (Is64BitOs() && useLegacy) { typedef UINT (WINAPI *GetSystemWow64Directory_t) (LPWSTR lpBuffer, UINT uSize); GetSystemWow64Directory_t getSystemWow64Directory = (GetSystemWow64Directory_t) GetProcAddress (GetModuleHandle (L"kernel32"), "GetSystemWow64DirectoryW"); getSystemWow64Directory (sysPath, ARRAYSIZE (sysPath)); } else GetSystemDirectory (sysPath, ARRAYSIZE (sysPath)); return wstring (sysPath) + L"\\" + fileName; } // Returns 0 if an error occurs or the drive letter (as an upper-case char) of the system partition (e.g. 'C'); wchar_t GetSystemDriveLetter (void) { wchar_t systemDir [MAX_PATH]; if (GetSystemDirectory (systemDir, ARRAYSIZE (systemDir))) return (wchar_t) (towupper (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 StringCbCopyW (tnid.szInfoTitle, sizeof(tnid.szInfoTitle), headline); StringCbCopyW (tnid.szInfo, sizeof(tnid.szInfo),text); // 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, HWND hwnd) { if (Silent) return; TaskBarIconDisplayBalloonTooltip (hwnd, headingStringId == NULL ? L"VeraCrypt" : GetString (headingStringId), textStringId == NULL ? L" " : GetString (textStringId), FALSE); } // Either of the pointers may be NULL void InfoBalloonDirect (wchar_t *headingString, wchar_t *textString, HWND hwnd) { if (Silent) return; TaskBarIconDisplayBalloonTooltip (hwnd, headingString == NULL ? L"VeraCrypt" : headingString, textString == NULL ? L" " : textString, FALSE); } // Either of the pointers may be NULL void WarningBalloon (char *headingStringId, char *textStringId, HWND hwnd) { if (Silent) return; TaskBarIconDisplayBalloonTooltip (hwnd, headingStringId == NULL ? L"VeraCrypt" : GetString (headingStringId), textStringId == NULL ? L" " : GetString (textStringId), TRUE); } // Either of the pointers may be NULL void WarningBalloonDirect (wchar_t *headingString, wchar_t *textString, HWND hwnd) { if (Silent) return; TaskBarIconDisplayBalloonTooltip (hwnd, headingString == NULL ? L"VeraCrypt" : headingString, textString == NULL ? L" " : textString, TRUE); } int Info (char *stringId, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONINFORMATION); } int InfoTopMost (char *stringId, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST); } int InfoDirect (const wchar_t *msg, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, msg, lpszTitle, MB_ICONINFORMATION); } int Warning (char *stringId, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING); } int WarningTopMost (char *stringId, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST); } int WarningDirect (const wchar_t *warnMsg, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, warnMsg, lpszTitle, MB_ICONWARNING); } int Error (char *stringId, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR); } int ErrorRetryCancel (char *stringId, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR | MB_RETRYCANCEL); } int ErrorTopMost (char *stringId, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST); } int ErrorDirect (const wchar_t *errMsg, HWND hwnd) { if (Silent) return 0; return MessageBoxW (hwnd, errMsg, lpszTitle, MB_ICONERROR); } int AskYesNo (char *stringId, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1); } int AskYesNoString (const wchar_t *str, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, str, lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1); } int AskYesNoTopmost (char *stringId, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST); } int AskNoYes (char *stringId, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2); } int AskNoYesString (const wchar_t *string, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, string, lpszTitle, MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2); } int AskOkCancel (char *stringId, HWND hwnd) { if (Silent) return IDCANCEL; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONQUESTION | MB_OKCANCEL | MB_DEFBUTTON1); } int AskWarnYesNo (char *stringId, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1); } int AskWarnYesNoString (const wchar_t *string, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, string, lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1); } int AskWarnYesNoTopmost (char *stringId, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST); } int AskWarnYesNoStringTopmost (const wchar_t *string, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, string, lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1 | MB_SETFOREGROUND | MB_TOPMOST); } int AskWarnNoYes (char *stringId, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2); } int AskWarnNoYesString (const wchar_t *string, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, string, lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2); } int AskWarnNoYesTopmost (char *stringId, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON2 | MB_SETFOREGROUND | MB_TOPMOST); } int AskWarnOkCancel (char *stringId, HWND hwnd) { if (Silent) return IDCANCEL; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1); } int AskWarnCancelOk (char *stringId, HWND hwnd) { if (Silent) return IDCANCEL; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON2); } int AskErrYesNo (char *stringId, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, GetString (stringId), lpszTitle, MB_ICONERROR | MB_YESNO | MB_DEFBUTTON1); } int AskErrNoYes (char *stringId, HWND hwnd) { if (Silent) return IDNO; return MessageBoxW (hwnd, 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. // The returned value is the ordinal number of the choice the user selected (1..MAX_MULTI_CHOICES) int AskMultiChoice (void *strings[], BOOL bBold, HWND hwnd) { MULTI_CHOICE_DLGPROC_PARAMS params; params.strings = &strings[0]; params.bold = bBold; return (int) DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_MULTI_CHOICE_DLG), hwnd, (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 = _wfopen (GetConfigPath (TC_APPD_FILENAME_CONFIGURATION), L"w,ccs=UTF-8"); if (ConfigFileHandle == NULL) { free (ConfigBuffer); ConfigBuffer = NULL; return FALSE; } XmlWriteHeader (ConfigFileHandle); fputws (L"\n\t", ConfigFileHandle); return TRUE; } BOOL ConfigWriteEnd (HWND hwnd) { 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)); fwprintf (ConfigFileHandle, L"\n\t\t%hs", key, value); xml++; } fputws (L"\n\t", ConfigFileHandle); XmlWriteFooter (ConfigFileHandle); TCFlushFile (ConfigFileHandle); CheckFileStreamWriteErrors (hwnd, 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 != fwprintf ( ConfigFileHandle, L"\n\t\t%hs", configKey, configValue); } BOOL ConfigWriteStringW (char *configKey, wchar_t *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 != fwprintf ( ConfigFileHandle, L"\n\t\t%ls", configKey, configValue); } BOOL ConfigWriteInt (char *configKey, int configValue) { char val[32]; StringCbPrintfA (val, sizeof(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 { StringCbCopyA (str, maxLen, defaultValue); return defaultValue; } } void ConfigReadCompareInt(char *configKey, int defaultValue, int* pOutputValue, BOOL bOnlyCheckModified, BOOL* pbModified) { int intValue = ConfigReadInt (configKey, defaultValue); if (pOutputValue) { if (pbModified && (*pOutputValue != intValue)) *pbModified = TRUE; if (!bOnlyCheckModified) *pOutputValue = intValue; } } void ConfigReadCompareString (char *configKey, char *defaultValue, char *str, int maxLen, BOOL bOnlyCheckModified, BOOL *pbModified) { char *strValue = (char*) malloc (maxLen); if (strValue) { memcpy (strValue, str, maxLen); ConfigReadString (configKey, defaultValue, strValue, maxLen); if (pbModified && strcmp (str, strValue)) *pbModified = TRUE; if (!bOnlyCheckModified) memcpy(str, strValue, maxLen); free (strValue); } else { /* allocation failed. Suppose that value changed */ if (pbModified) *pbModified = TRUE; if (!bOnlyCheckModified) ConfigReadString (configKey, defaultValue, str, maxLen); } } void OpenPageHelp (HWND hwndDlg, int nPage) { int r = (int)ShellExecuteW (NULL, L"open", szHelpFile, NULL, NULL, SW_SHOWNORMAL); if (r == ERROR_FILE_NOT_FOUND) { // Try the secondary help file r = (int)ShellExecuteW (NULL, L"open", szHelpFile2, NULL, NULL, SW_SHOWNORMAL); if (r == ERROR_FILE_NOT_FOUND) { // Open local HTML help. It will fallback to online help if not found. Applink ("help"); return; } } if (r == SE_ERR_NOASSOC) { if (AskYesNo ("HELP_READER_ERROR", MainDlg) == IDYES) OpenOnlineHelp (); } } void OpenOnlineHelp () { Applink ("onlinehelp"); } #ifndef SETUP void RestoreDefaultKeyFilesParam (void) { KeyFileRemoveAll (&FirstKeyFile); if (defaultKeyFilesParam.FirstKeyFile != NULL) { KeyFileCloneAll (defaultKeyFilesParam.FirstKeyFile, &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 (kf) { char fileName [MAX_PATH + 1]; if (XmlGetNodeText (xml, fileName, sizeof (fileName)) != NULL) { std::wstring wszFileName = Utf8StringToWide(fileName); StringCbCopyW (kf->FileName, sizeof (kf->FileName), wszFileName.c_str ()); defaultKeyFilesParam.FirstKeyFile = KeyFileAdd (defaultKeyFilesParam.FirstKeyFile, kf); } else free (kf); } else { KeyFileRemoveAll (&defaultKeyFilesParam.FirstKeyFile); status = FALSE; break; } xml++; } free (defaultKeyfilesFile); if (status) KeyFilesEnable = defaultKeyFilesParam.EnableKeyFiles; return status; } #endif /* #ifndef SETUP */ void Debug (char *format, ...) { char buf[1024]; va_list val; va_start(val, format); StringCbVPrintfA (buf, sizeof (buf), format, val); va_end(val); OutputDebugStringA (buf); } void DebugMsgBox (char *format, ...) { char buf[1024]; va_list val; va_start(val, format); StringCbVPrintfA (buf, sizeof (buf), format, val); va_end(val); MessageBoxA (MainDlg, buf, "VeraCrypt 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; case WIN_8: major = 6; minor = 2; break; case WIN_8_1: major = 6; minor = 3; break; case WIN_10: major = 10; minor = 0; break; default: TC_THROW_FATAL_EXCEPTION; break; } return ((CurrentOSMajor << 16 | CurrentOSMinor << 8 | CurrentOSServicePack) >= (major << 16 | minor << 8 | reqMinServicePack)); } BOOL Is64BitOs () { #ifdef _WIN64 return TRUE; #else 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(L"kernel32"), "IsWow64Process"); if (fnIsWow64Process != NULL) if (!fnIsWow64Process (GetCurrentProcess(), &isWow64)) isWow64 = FALSE; valid = TRUE; return isWow64; #endif } BOOL IsServerOS () { OSVERSIONINFOEXW osVer; osVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW); GetVersionExW ((LPOSVERSIONINFOW) &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 (L"kernel32"), "Wow64EnableWow64FsRedirection"); if (!wow64EnableWow64FsRedirection) return FALSE; return wow64EnableWow64FsRedirection (enable); } BOOL RestartComputer (BOOL bShutdown) { 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) { CloseHandle(hTkn); return false; } if (!ExitWindowsEx (bShutdown? EWX_POWEROFF: EWX_REBOOT, SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER | SHTDN_REASON_FLAG_PLANNED)) { CloseHandle(hTkn); return false; } CloseHandle(hTkn); return true; } std::wstring GetWindowsEdition () { wstring osname = L"win"; OSVERSIONINFOEXW osVer; osVer.dwOSVersionInfoSize = sizeof (OSVERSIONINFOEXW); GetVersionExW ((LPOSVERSIONINFOW) &osVer); BOOL home = (osVer.wSuiteMask & VER_SUITE_PERSONAL); BOOL server = (osVer.wProductType == VER_NT_SERVER || osVer.wProductType == VER_NT_DOMAIN_CONTROLLER); HKEY hkey; wchar_t productName[300] = {0}; DWORD productNameSize = sizeof (productName); if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_QUERY_VALUE, &hkey) == ERROR_SUCCESS) { if (RegQueryValueEx (hkey, L"ProductName", 0, 0, (LPBYTE) &productName, &productNameSize) != ERROR_SUCCESS || productNameSize < 1) productName[0] = 0; RegCloseKey (hkey); } switch (nCurrentOS) { case WIN_2000: osname += L"2000"; break; case WIN_XP: case WIN_XP64: osname += L"xp"; osname += home ? L"-home" : L"-pro"; break; case WIN_SERVER_2003: osname += L"2003"; break; case WIN_VISTA: osname += L"vista"; break; case WIN_SERVER_2008: osname += L"2008"; break; case WIN_7: osname += L"7"; break; case WIN_SERVER_2008_R2: osname += L"2008r2"; break; default: wstringstream s; s << CurrentOSMajor << L"." << CurrentOSMinor; osname += s.str(); break; } if (server) osname += L"-server"; if (IsOSAtLeast (WIN_VISTA)) { if (home) osname += L"-home"; else if (wcsstr (productName, L"Standard") != 0) osname += L"-standard"; else if (wcsstr (productName, L"Professional") != 0) osname += L"-pro"; else if (wcsstr (productName, L"Business") != 0) osname += L"-business"; else if (wcsstr (productName, L"Enterprise") != 0) osname += L"-enterprise"; else if (wcsstr (productName, L"Datacenter") != 0) osname += L"-datacenter"; else if (wcsstr (productName, L"Ultimate") != 0) osname += L"-ultimate"; } if (GetSystemMetrics (SM_STARTER)) osname += L"-starter"; else if (wcsstr (productName, L"Basic") != 0) osname += L"-basic"; if (Is64BitOs()) osname += L"-x64"; if (CurrentOSServicePack > 0) { wstringstream s; s << L"-sp" << CurrentOSServicePack; osname += s.str(); } return osname; } #ifdef SETUP extern wchar_t InstallationPath[TC_MAX_PATH]; #endif void Applink (const char *dest) { wchar_t url [MAX_URL_LENGTH] = {0}; wchar_t page[TC_MAX_PATH] = {0}; wchar_t installDir[TC_MAX_PATH] = {0}; BOOL buildUrl = TRUE; int r; ArrowWaitCursor (); #ifdef SETUP StringCbCopyW (installDir, sizeof (installDir), InstallationPath); #else GetModPath (installDir, TC_MAX_PATH); #endif if (strcmp(dest, "donate") == 0) { StringCbCopyW (page, sizeof (page),L"Donation.html"); } else if (strcmp(dest, "main") == 0) { StringCbCopyW (url, sizeof (url), TC_HOMEPAGE); buildUrl = FALSE; } else if (strcmp(dest,"localizations") == 0) { StringCbCopyW (page, sizeof (page),L"Language%20Packs.html"); } else if (strcmp(dest, "beginnerstutorial") == 0 || strcmp(dest,"tutorial") == 0) { StringCbCopyW (page, sizeof (page),L"Beginner%27s%20Tutorial.html"); } else if (strcmp(dest, "releasenotes") == 0 || strcmp(dest, "history") == 0) { StringCbCopyW (page, sizeof (page),L"Release%20Notes.html"); } else if (strcmp(dest, "hwacceleration") == 0) { StringCbCopyW (page, sizeof (page),L"Hardware%20Acceleration.html"); } else if (strcmp(dest, "parallelization") == 0) { StringCbCopyW (page, sizeof (page),L"Parallelization.html"); } else if (strcmp(dest, "help") == 0) { StringCbCopyW (page, sizeof (page),L"Documentation.html"); } else if (strcmp(dest, "onlinehelp") == 0) { StringCbCopyW (url, sizeof (url),L"https://www.veracrypt.fr/en/Documentation.html"); buildUrl = FALSE; } else if (strcmp(dest, "keyfiles") == 0) { StringCbCopyW (page, sizeof (page),L"Keyfiles.html"); } else if (strcmp(dest, "introcontainer") == 0) { StringCbCopyW (page, sizeof (page),L"Creating%20New%20Volumes.html"); } else if (strcmp(dest, "introsysenc") == 0) { StringCbCopyW (page, sizeof (page),L"System%20Encryption.html"); } else if (strcmp(dest, "hiddensysenc") == 0) { StringCbCopyW (page, sizeof (page),L"VeraCrypt%20Hidden%20Operating%20System.html"); } else if (strcmp(dest, "sysencprogressinfo") == 0) { StringCbCopyW (page, sizeof (page),L"System%20Encryption.html"); } else if (strcmp(dest, "hiddenvolume") == 0) { StringCbCopyW (page, sizeof (page),L"Hidden%20Volume.html"); } else if (strcmp(dest, "aes") == 0) { StringCbCopyW (page, sizeof (page),L"AES.html"); } else if (strcmp(dest, "serpent") == 0) { StringCbCopyW (page, sizeof (page),L"Serpent.html"); } else if (strcmp(dest, "twofish") == 0) { StringCbCopyW (page, sizeof (page),L"Twofish.html"); } else if (strcmp(dest, "kuznyechik") == 0) { StringCbCopyW (page, sizeof (page),L"Kuznyechik.html"); } else if (strcmp(dest, "camellia") == 0) { StringCbCopyW (page, sizeof (page),L"Camellia.html"); } else if (strcmp(dest, "cascades") == 0) { StringCbCopyW (page, sizeof (page),L"Cascades.html"); } else if (strcmp(dest, "hashalgorithms") == 0) { StringCbCopyW (page, sizeof (page),L"Hash%20Algorithms.html"); } else if (strcmp(dest, "isoburning") == 0) { StringCbCopyW (url, sizeof (url),L"https://cdburnerxp.se/en/home"); buildUrl = FALSE; } else if (strcmp(dest, "sysfavorites") == 0) { StringCbCopyW (page, sizeof (page),L"System%20Favorite%20Volumes.html"); } else if (strcmp(dest, "favorites") == 0) { StringCbCopyW (page, sizeof (page),L"Favorite%20Volumes.html"); } else if (strcmp(dest, "hiddenvolprotection") == 0) { StringCbCopyW (page, sizeof (page),L"Protection%20of%20Hidden%20Volumes.html"); } else if (strcmp(dest, "faq") == 0) { StringCbCopyW (page, sizeof (page),L"FAQ.html"); } else if (strcmp(dest, "downloads") == 0) { StringCbCopyW (page, sizeof (page),L"Downloads.html"); } else if (strcmp(dest, "news") == 0) { StringCbCopyW (page, sizeof (page),L"News.html"); } else if (strcmp(dest, "contact") == 0) { StringCbCopyW (page, sizeof (page),L"Contact.html"); } else if (strcmp(dest, "pim") == 0) { StringCbCopyW (page, sizeof (page),L"Personal%20Iterations%20Multiplier%20%28PIM%29.html"); } else { StringCbCopyW (url, sizeof (url),TC_APPLINK); buildUrl = FALSE; } if (buildUrl) { StringCbPrintfW (url, sizeof (url), L"file:///%sdocs/html/en/%s", installDir, page); CorrectURL (url); } r = (int) ShellExecuteW (NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL); if (((r == ERROR_FILE_NOT_FOUND) || (r == ERROR_PATH_NOT_FOUND)) && buildUrl) { // fallbacl to online resources StringCbPrintfW (url, sizeof (url), L"https://www.veracrypt.fr/en/%s", page); ShellExecuteW (NULL, L"open", url, NULL, NULL, SW_SHOWNORMAL); } Sleep (200); NormalCursor (); } wchar_t *RelativePath2Absolute (wchar_t *szFileName) { if (szFileName[0] != L'\\' && wcschr (szFileName, L':') == 0 && wcsstr (szFileName, L"Volume{") != szFileName) { wchar_t path[MAX_PATH*2]; GetCurrentDirectory (MAX_PATH, path); if (path[wcslen (path) - 1] != L'\\') StringCbCatW (path, (MAX_PATH * 2), L"\\"); StringCbCatW (path, (MAX_PATH * 2), szFileName); StringCbCopyW (szFileName, MAX_PATH + 1, path); // szFileName size is always at least (MAX_PATH + 1) } return szFileName; } void HandleDriveNotReadyError (HWND hwnd) { HKEY hkey = 0; DWORD value = 0, size = sizeof (DWORD); if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Services\\MountMgr", 0, KEY_READ, &hkey) != ERROR_SUCCESS) return; if (RegQueryValueEx (hkey, L"NoAutoMount", 0, 0, (LPBYTE) &value, &size) == ERROR_SUCCESS && value != 0) { Warning ("SYS_AUTOMOUNT_DISABLED", hwnd); } else if (nCurrentOS == WIN_VISTA && CurrentOSServicePack < 1) Warning ("SYS_ASSIGN_DRIVE_LETTER", hwnd); else Warning ("DEVICE_NOT_READY_ERROR", hwnd); RegCloseKey (hkey); } BOOL CALLBACK CloseTCWindowsEnum (HWND hwnd, LPARAM lParam) { LONG_PTR userDataVal = GetWindowLongPtrW (hwnd, GWLP_USERDATA); if ((userDataVal == (LONG_PTR) 'VERA') || (userDataVal == (LONG_PTR) 'TRUE')) // Prior to 1.0e, 'TRUE' was used for VeraCrypt dialogs { wchar_t name[1024] = { 0 }; GetWindowText (hwnd, name, ARRAYSIZE (name) - 1); if (hwnd != MainDlg && wcsstr (name, L"VeraCrypt")) { PostMessage (hwnd, TC_APPMSG_CLOSE_BKG_TASK, 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; LONG_PTR userDataVal = GetWindowLongPtrW (hwnd, GWLP_USERDATA); if ((userDataVal == (LONG_PTR) 'VERA') || (userDataVal == (LONG_PTR) 'TRUE')) // Prior to 1.0e, 'TRUE' was used for VeraCrypt dialogs { wchar_t name[32] = { 0 }; GetWindowText (hwnd, name, ARRAYSIZE (name) - 1); if (hwnd != MainDlg && wcscmp (name, L"VeraCrypt") == 0) { if (lParam != 0) *((HWND *)lParam) = hwnd; } } return TRUE; } BYTE *MapResource (wchar_t *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]; StringCbPrintfW (finalMsg, sizeof(finalMsg), GetString ("INCONSISTENCY_RESOLVED"), techInfo); MessageBoxW (MainDlg, finalMsg, lpszTitle, MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST); } void ReportUnexpectedState (char *techInfo) { wchar_t finalMsg[8024]; StringCbPrintfW (finalMsg, sizeof(finalMsg), GetString ("UNEXPECTED_STATE"), techInfo); MessageBoxW (MainDlg, finalMsg, lpszTitle, MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST); } #ifndef SETUP int OpenVolume (OpenVolumeContext *context, const wchar_t *volumePath, Password *password, int pkcs5_prf, int pim, BOOL truecryptMode, BOOL write, BOOL preserveTimestamps, BOOL useBackupHeader) { int status = ERR_PARAMETER_INCORRECT; int volumeType; wchar_t szDiskFile[TC_MAX_PATH], szCFDevice[TC_MAX_PATH]; wchar_t szDosDevice[TC_MAX_PATH]; char buffer[TC_VOLUME_HEADER_EFFECTIVE_SIZE]; LARGE_INTEGER headerOffset; DWORD dwResult; DISK_GEOMETRY_EX deviceGeometry; context->VolumeIsOpen = FALSE; context->CryptoInfo = NULL; context->HostFileHandle = INVALID_HANDLE_VALUE; context->TimestampsValid = FALSE; CreateFullVolumePath (szDiskFile, sizeof(szDiskFile), volumePath, &context->IsDevice); if (context->IsDevice) { status = FakeDosNameForDevice (szDiskFile, szDosDevice, sizeof(szDosDevice), szCFDevice, sizeof(szCFDevice), FALSE); if (status != 0) return status; preserveTimestamps = FALSE; if (!GetDriveGeometry (volumePath, &deviceGeometry)) { status = ERR_OS_ERROR; goto error; } } else StringCbCopyW (szCFDevice, sizeof(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 { BYTE dgBuffer[256]; if (!DeviceIoControl (context->HostFileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, dgBuffer, sizeof (dgBuffer), &dwResult, NULL)) { DISK_GEOMETRY geo; if (DeviceIoControl (context->HostFileHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, (LPVOID) &geo, sizeof (geo), &dwResult, NULL)) { ((PDISK_GEOMETRY_EX) dgBuffer)->DiskSize.QuadPart = geo.Cylinders.QuadPart * geo.SectorsPerTrack * geo.TracksPerCylinder * geo.BytesPerSector; if (CurrentOSMajor >= 6) { STORAGE_READ_CAPACITY storage = {0}; storage.Version = sizeof (STORAGE_READ_CAPACITY); storage.Size = sizeof (STORAGE_READ_CAPACITY); if (DeviceIoControl (context->HostFileHandle, IOCTL_STORAGE_READ_CAPACITY, NULL, 0, (LPVOID) &storage, sizeof (storage), &dwResult, NULL)) { ((PDISK_GEOMETRY_EX) dgBuffer)->DiskSize.QuadPart = storage.DiskLength.QuadPart; } } } else { status = ERR_OS_ERROR; goto error; } } context->HostSize = ((PDISK_GEOMETRY_EX) dgBuffer)->DiskSize.QuadPart; } 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; } 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, pkcs5_prf, pim, truecryptMode, &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 (HWND hwndDlg, char *buffer, BOOL bBoot, CRYPTO_INFO *cryptoInfo, Password *password, int pim, BOOL wipeMode) { CRYPTO_INFO *newCryptoInfo = NULL; RandSetHashFunction (cryptoInfo->pkcs5); if (Randinit() != ERR_SUCCESS) { if (CryptoAPILastError == ERROR_SUCCESS) return ERR_RAND_INIT_FAILED; else return ERR_CAPI_INIT_FAILED; } UserEnrichRandomPool (NULL); int status = CreateVolumeHeaderInMemory (hwndDlg, bBoot, buffer, cryptoInfo->ea, cryptoInfo->mode, password, cryptoInfo->pkcs5, pim, (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 wchar_t data[65536]; DWORD size = sizeof (data); if (IsPagingFileWildcardActive()) return TRUE; if (ReadLocalMachineRegistryMultiString (L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", L"PagingFiles", data, &size) && size > 24 && !checkNonWindowsPartitionsOnly) return TRUE; if (!IsAdmin()) AbortProcess ("UAC_INIT_ERROR"); for (wchar_t drive = L'C'; drive <= L'Z'; ++drive) { // Query geometry of the drive first to prevent "no medium" pop-ups wstring drivePath = L"\\\\.\\X:"; drivePath[4] = drive; if (checkNonWindowsPartitionsOnly) { wchar_t sysDir[MAX_PATH]; if (GetSystemDirectory (sysDir, ARRAYSIZE (sysDir)) != 0 && towupper (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; BYTE dgBuffer[256]; DWORD dwResult; if (!DeviceIoControl (handle, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, dgBuffer, sizeof (dgBuffer), &dwResult, NULL) && !DeviceIoControl (handle, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, dgBuffer, sizeof (dgBuffer), &dwResult, NULL)) { CloseHandle (handle); continue; } CloseHandle (handle); // Test if a paging file exists and is locked by another process wstring path = L"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 () { wchar_t pagingFiles[65536]; DWORD size = sizeof (pagingFiles); wchar_t *mmKey = L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management"; if (!ReadLocalMachineRegistryString (mmKey, L"PagingFiles", pagingFiles, &size)) { size = sizeof (pagingFiles); if (!ReadLocalMachineRegistryMultiString (mmKey, L"PagingFiles", pagingFiles, &size)) size = 0; } return size > 0 && wcsstr (pagingFiles, L"?:\\") == pagingFiles; } BOOL DisablePagingFile () { wchar_t empty[] = { 0, 0 }; return WriteLocalMachineRegistryMultiString (L"System\\CurrentControlSet\\Control\\Session Manager\\Memory Management", L"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); // We don't throw exception here and only return empty string. // All calls to this function use valid strings. // 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; } #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]; StringCbPrintfW (s, sizeof(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, SRC_POS); 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 wchar_t tmp[SecurityToken::MaxPasswordLength+1]; wmemset (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 tokens; try { tokens = SecurityToken::GetAvailableTokens(); } catch (Exception &e) { e.Show (hwndDlg); } if (tokens.empty()) { Error ("NO_TOKENS_FOUND", hwndDlg); EndDialog (hwndDlg, IDCANCEL); return 1; } foreach (const SecurityTokenInfo &token, tokens) { wstringstream tokenLabel; tokenLabel << L"[" << token.SlotId << L"] " << token.Label; AddComboPair (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 = (CK_SLOT_ID) 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 &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++; wstringstream s; s << keyfile.SlotId; ListItemAdd (tokenListControl, lvItem.iItem, (wchar_t *) s.str().c_str()); ListSubItemSet (tokenListControl, lvItem.iItem, 1, (wchar_t *) keyfile.Token.Label.c_str()); ListSubItemSet (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 SecurityTokenKeyfileDlgGetSelected (HWND hwndDlg, const vector &keyfiles) { HWND tokenListControl = GetDlgItem (hwndDlg, IDC_TOKEN_FILE_LIST); list 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 *selectedTokenKeyfiles; static vector keyfiles; WORD lw = LOWORD (wParam); switch (msg) { case WM_INITDIALOG: { selectedTokenKeyfiles = (list *) 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; } if (msg == WM_COMMAND) { switch (lw) { case IDCANCEL: EndDialog (hwndDlg, IDCANCEL); return 1; case IDC_IMPORT_KEYFILE: { wchar_t 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, SRC_POS); return 1; } if (keyfileSize != 0) { NewSecurityTokenKeyfileDlgProcParams newParams; newParams.Name = WideToUtf8String (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 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, SRC_POS); } burn (keyfileData, keyfileSize); TCfree (keyfileData); } return 1; } case IDC_EXPORT: { try { foreach (const SecurityTokenKeyfile &keyfile, SecurityTokenKeyfileDlgGetSelected (hwndDlg, keyfiles)) { wchar_t keyfilePath[TC_MAX_PATH]; if (!BrowseFiles (hwndDlg, "OPEN_TITLE", keyfilePath, bHistory, TRUE, NULL)) break; { WaitCursor(); finally_do ({ NormalCursor(); }); vector keyfileData; SecurityToken::GetKeyfileData (keyfile, keyfileData); if (keyfileData.empty()) { SetLastError (ERROR_HANDLE_EOF); handleWin32Error (hwndDlg, SRC_POS); return 1; } finally_do_arg (vector *, &keyfileData, { burn (&finally_arg->front(), finally_arg->size()); }); if (!SaveBufferToFile ((char *) &keyfileData.front(), keyfilePath, (DWORD) keyfileData.size(), FALSE, FALSE)) throw SystemException (SRC_POS); } Info ("KEYFILE_EXPORTED", hwndDlg); } } catch (Exception &e) { e.Show (hwndDlg); } return 1; } case IDC_DELETE: { if (AskNoYes ("CONFIRM_SEL_FILES_DELETE", hwndDlg) == 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 (HWND hwndDlg) { if (SecurityTokenLibraryPath[0] == 0) { Error ("NO_PKCS11_MODULE_SPECIFIED", hwndDlg); return FALSE; } struct PinRequestHandler : public GetPinFunctor { HWND m_hwnd; PinRequestHandler(HWND hwnd) : m_hwnd(hwnd) {} virtual void operator() (string &str) { if (CmdTokenPin[0]) { str = CmdTokenPin; } else { HWND hParent = IsWindow (m_hwnd)? m_hwnd : GetActiveWindow(); if (!hParent) hParent = GetForegroundWindow (); if (SecureDesktopDialogBoxParam (hInst, MAKEINTRESOURCEW (IDD_TOKEN_PASSWORD), hParent, (DLGPROC) SecurityTokenPasswordDlgProc, (LPARAM) &str) == IDCANCEL) throw UserAbort (SRC_POS); } if (hCursor != NULL) SetCursor (hCursor); } virtual void notifyIncorrectPin () { // clear wrong PIN burn (&CmdTokenPin, sizeof (CmdTokenPin)); } }; struct WarningHandler : public SendExceptionFunctor { HWND m_hwnd; WarningHandler(HWND hwnd) : m_hwnd(hwnd) {} virtual void operator() (const Exception &e) { HWND hParent = IsWindow (m_hwnd)? m_hwnd : GetActiveWindow(); if (!hParent) hParent = GetForegroundWindow (); e.Show (hParent); } }; try { SecurityToken::InitLibrary (SecurityTokenLibraryPath, auto_ptr (new PinRequestHandler(MainDlg)), auto_ptr (new WarningHandler(MainDlg))); } catch (Exception &e) { e.Show (hwndDlg); Error ("PKCS11_MODULE_INIT_FAILED", hwndDlg); return FALSE; } return TRUE; } std::vector GetAvailableHostDevices (bool noDeviceProperties, bool singleList, bool noFloppy, bool detectUnencryptedFilesystems) { vector devices; size_t dev0; for (int devNumber = 0; devNumber < MAX_HOST_DRIVE_NUMBER; devNumber++) { for (int partNumber = 0; partNumber < MAX_HOST_PARTITION_NUMBER; partNumber++) { WCHAR devPath[32]; StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\Harddisk%d\\Partition%d", devNumber, partNumber); OPEN_TEST_STRUCT openTest = {0}; if (!OpenDevice (devPath, &openTest, detectUnencryptedFilesystems && partNumber != 0, FALSE)) { 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; } else { // retrieve size using DISK_GEOMETRY_EX DISK_GEOMETRY_EX deviceGeometry = {0}; if ( GetDriveGeometry (devPath, &deviceGeometry) || ((partNumber == 0) && GetPhysicalDriveGeometry (devNumber, &deviceGeometry)) ) { device.Size = (uint64) deviceGeometry.DiskSize.QuadPart; } } device.HasUnencryptedFilesystem = (detectUnencryptedFilesystems && openTest.FilesystemDetected) ? true : false; if (!noDeviceProperties) { DISK_GEOMETRY_EX geometry; int driveNumber = GetDiskDeviceDriveLetter (devPath); if (driveNumber >= 0) { device.MountPoint += (wchar_t) (driveNumber + L'A'); device.MountPoint += L":"; wchar_t name[64]; if (GetDriveLabel (driveNumber, name, sizeof (name))) device.Name = name; if (GetSystemDriveLetter() == L'A' + driveNumber) device.ContainsSystem = true; } if (partNumber == 0 && GetDriveGeometry (devPath, &geometry)) device.Removable = (geometry.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++) { WCHAR devPath[32]; StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\HarddiskVolume%d", devNumber); OPEN_TEST_STRUCT openTest = {0}; if (!OpenDevice (devPath, &openTest, detectUnencryptedFilesystems, FALSE)) 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) { int driveNumber = GetDiskDeviceDriveLetter (devPath); if (driveNumber >= 0) { device.MountPoint += (wchar_t) (driveNumber + L'A'); device.MountPoint += L":"; wchar_t name[64]; if (GetDriveLabel (driveNumber, name, sizeof (name))) device.Name = name; if (GetSystemDriveLetter() == L'A' + driveNumber) device.ContainsSystem = true; } } devices.push_back (device); } } } return devices; } void AddDeviceToList (std::vector& devices, int devNumber, int partNumber) { WCHAR devPath[64]; StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\Harddisk%d\\Partition%d", devNumber, partNumber); HostDevice device; device.SystemNumber = devNumber; device.Path = devPath; devices.push_back (device); } std::vector GetHostRawDeviceList () { std::vector list; HDEVINFO diskClassDevices; GUID diskClassDeviceInterfaceGuid = GUID_DEVINTERFACE_DISK; SP_DEVICE_INTERFACE_DATA deviceInterfaceData; PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData; DWORD requiredSize; DWORD deviceIndex; STORAGE_DEVICE_NUMBER diskNumber; DWORD bytesReturned; diskClassDevices = SetupDiGetClassDevs( &diskClassDeviceInterfaceGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ); if ( INVALID_HANDLE_VALUE != diskClassDevices) { ZeroMemory( &deviceInterfaceData, sizeof( SP_DEVICE_INTERFACE_DATA ) ); deviceInterfaceData.cbSize = sizeof( SP_DEVICE_INTERFACE_DATA ); deviceIndex = 0; while ( SetupDiEnumDeviceInterfaces( diskClassDevices, NULL, &diskClassDeviceInterfaceGuid, deviceIndex, &deviceInterfaceData ) ) { ++deviceIndex; if (!SetupDiGetDeviceInterfaceDetail( diskClassDevices, &deviceInterfaceData, NULL, 0, &requiredSize, NULL ) && ( ERROR_INSUFFICIENT_BUFFER == GetLastError())) { deviceInterfaceDetailData = ( PSP_DEVICE_INTERFACE_DETAIL_DATA ) malloc( requiredSize ); if (deviceInterfaceDetailData) { ZeroMemory( deviceInterfaceDetailData, requiredSize ); deviceInterfaceDetailData->cbSize = sizeof( SP_DEVICE_INTERFACE_DETAIL_DATA ); if (SetupDiGetDeviceInterfaceDetail( diskClassDevices, &deviceInterfaceData, deviceInterfaceDetailData, requiredSize, NULL, NULL )) { HANDLE disk = CreateFile( deviceInterfaceDetailData->DevicePath, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if ( INVALID_HANDLE_VALUE != disk) { if (DeviceIoControl( disk, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0, &diskNumber, sizeof( STORAGE_DEVICE_NUMBER ), &bytesReturned, NULL )) { HostDevice device; device.Path = deviceInterfaceDetailData->DevicePath; device.SystemNumber = diskNumber.DeviceNumber; list.push_back (device); } CloseHandle( disk ); } } free (deviceInterfaceDetailData); } } } SetupDiDestroyDeviceInfoList( diskClassDevices ); } return list; } bool CompareDeviceList (const std::vector& list1, const std::vector& list2) { if (list1.size() != list2.size()) return false; for (std::vector::const_iterator It1 = list1.begin(); It1 != list1.end(); It1++) { bool bFound = false; for (std::vector::const_iterator It2 = list2.begin(); It2 != list2.end(); It2++) { if (It1->Path == It2->Path && It1->SystemNumber == It2->SystemNumber) { bFound = true; break; } } if (!bFound) return false; } return true; } void UpdateMountableHostDeviceList () { ByteArray buffer(4096); DWORD bytesReturned; bool dynamicVolumesPresent = false; EnterCriticalSection (&csMountableDevices); finally_do ({ LeaveCriticalSection (&csMountableDevices); }); std::vector newList = GetHostRawDeviceList (); std::map existingDevicesMap; if (CompareDeviceList (newList, rawHostDeviceList)) return; //no change, return // remove raw devices that don't exist anymore for (std::vector::iterator It = rawHostDeviceList.begin(); It != rawHostDeviceList.end();) { for (std::vector::iterator newIt = newList.begin(); newIt != newList.end(); newIt++) { if (newIt->SystemNumber == It->SystemNumber) { existingDevicesMap[It->SystemNumber] = true; break; } } if (existingDevicesMap[It->SystemNumber]) It++; else { It = rawHostDeviceList.erase (It); } } // remove mountable devices that don't exist anymore for (std::vector::iterator It = mountableDevices.begin(); It != mountableDevices.end();) { if (existingDevicesMap[It->SystemNumber]) It++; else It = mountableDevices.erase (It); } // add new devices for (std::vector::iterator It = newList.begin(); It != newList.end(); It++) { if (existingDevicesMap[It->SystemNumber]) continue; HANDLE disk = CreateFile( It->Path.c_str(), 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if ( INVALID_HANDLE_VALUE != disk) { bool bIsDynamic = false; bool bHasPartition = false; if (DeviceIoControl( disk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, (LPVOID) buffer.data(), (DWORD) buffer.size(), (LPDWORD) &bytesReturned, NULL) && (bytesReturned >= sizeof (DRIVE_LAYOUT_INFORMATION_EX))) { PDRIVE_LAYOUT_INFORMATION_EX layout = (PDRIVE_LAYOUT_INFORMATION_EX) buffer.data(); // sanity checks if (layout->PartitionCount <= 256) { for (DWORD i = 0; i < layout->PartitionCount; i++) { if (layout->PartitionEntry[i].PartitionStyle == PARTITION_STYLE_MBR) { if (layout->PartitionEntry[i].Mbr.PartitionType == 0) continue; bHasPartition = true; /* skip dynamic volume */ if (layout->PartitionEntry[i].Mbr.PartitionType == PARTITION_LDM) { bIsDynamic = true; /* remove any partition that may have been added */ while (!mountableDevices.empty() && (mountableDevices.back().SystemNumber == It->SystemNumber)) mountableDevices.pop_back (); break; } } if (layout->PartitionEntry[i].PartitionStyle == PARTITION_STYLE_GPT) { if (IsEqualGUID(layout->PartitionEntry[i].Gpt.PartitionType, PARTITION_ENTRY_UNUSED_GUID)) continue; bHasPartition = true; /* skip dynamic volume */ if ( IsEqualGUID(layout->PartitionEntry[i].Gpt.PartitionType, PARTITION_LDM_METADATA_GUID) || IsEqualGUID(layout->PartitionEntry[i].Gpt.PartitionType, PARTITION_LDM_DATA_GUID) ) { bIsDynamic = true; /* remove any partition that may have been added */ while (!mountableDevices.empty() && (mountableDevices.back().SystemNumber == It->SystemNumber)) mountableDevices.pop_back (); break; } } WCHAR path[MAX_PATH]; StringCbPrintfW (path, sizeof(path), L"\\\\?\\GLOBALROOT\\Device\\Harddisk%d\\Partition%d", It->SystemNumber, layout->PartitionEntry[i].PartitionNumber); HANDLE handle = CreateFile( path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL ); if ((handle != INVALID_HANDLE_VALUE) || (GetLastError () == ERROR_ACCESS_DENIED)) { AddDeviceToList (mountableDevices, It->SystemNumber, layout->PartitionEntry[i].PartitionNumber); if (handle != INVALID_HANDLE_VALUE) CloseHandle (handle); } } } } if (bIsDynamic) dynamicVolumesPresent = true; if (!bHasPartition) AddDeviceToList (mountableDevices, It->SystemNumber, 0); CloseHandle (disk); } } rawHostDeviceList = newList; // Starting from Vista, Windows does not create partition links for dynamic volumes so it is necessary to scan \\Device\\HarddiskVolumeX devices if (dynamicVolumesPresent && (CurrentOSMajor >= 6)) { for (int devNumber = 0; devNumber < 256; devNumber++) { WCHAR devPath[32]; StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\HarddiskVolume%d", devNumber); OPEN_TEST_STRUCT openTest = {0}; if (!OpenDevice (devPath, &openTest, FALSE, FALSE)) continue; DISK_PARTITION_INFO_STRUCT info; if (GetDeviceInfo (devPath, &info) && info.IsDynamic) { HostDevice device; device.SystemNumber = devNumber; device.Path = devPath; mountableDevices.push_back (device); } } } } wstring FindDeviceByVolumeID (const BYTE volumeID [VOLUME_ID_SIZE], BOOL bFromService) { /* if it is already mounted, get the real path name used for mounting */ MOUNT_LIST_STRUCT mlist; DWORD dwResult; memset (&mlist, 0, sizeof (mlist)); if ( !DeviceIoControl (hDriver, TC_IOCTL_GET_MOUNTED_VOLUMES, &mlist, sizeof (mlist), &mlist, sizeof (mlist), &dwResult, NULL) || (mlist.ulMountedDrives >= (1 << 26)) ) { return L""; } if (mlist.ulMountedDrives) { for (int i=0 ; i < 26; i++) { if ((mlist.ulMountedDrives & (1 << i)) && (0 == memcmp (mlist.volumeID[i], volumeID, VOLUME_ID_SIZE))) { if (IsNullTerminateString (mlist.wszVolume[i], TC_MAX_PATH)) return mlist.wszVolume[i]; else return L""; } } } /* not mounted. Look for it in the local drives*/ if (bFromService) { for (int devNumber = 0; devNumber < MAX_HOST_DRIVE_NUMBER; devNumber++) { for (int partNumber = 0; partNumber < MAX_HOST_PARTITION_NUMBER; partNumber++) { WCHAR devPath[32]; StringCbPrintfW (devPath, sizeof (devPath), L"\\Device\\Harddisk%d\\Partition%d", devNumber, partNumber); OPEN_TEST_STRUCT openTest = {0}; if (OpenDevice (devPath, &openTest, TRUE, TRUE) && (openTest.VolumeIDComputed[TC_VOLUME_TYPE_NORMAL] && openTest.VolumeIDComputed[TC_VOLUME_TYPE_HIDDEN]) ) { if ( (0 == memcmp (volumeID, openTest.volumeIDs[TC_VOLUME_TYPE_NORMAL], VOLUME_ID_SIZE)) || (0 == memcmp (volumeID, openTest.volumeIDs[TC_VOLUME_TYPE_HIDDEN], VOLUME_ID_SIZE)) ) { return devPath; } } } } } else { static std::vector volumeIdCandidates; EnterCriticalSection (&csMountableDevices); std::vector newDevices = mountableDevices; LeaveCriticalSection (&csMountableDevices); EnterCriticalSection (&csVolumeIdCandidates); finally_do ({ LeaveCriticalSection (&csVolumeIdCandidates); }); /* remove any devices that don't exist anymore */ for (std::vector::iterator It = volumeIdCandidates.begin(); It != volumeIdCandidates.end();) { bool bFound = false; for (std::vector::iterator newIt = newDevices.begin(); newIt != newDevices.end(); newIt++) { if (It->Path == newIt->Path) { bFound = true; break; } } if (bFound) It++; else It = volumeIdCandidates.erase (It); } /* Add newly inserted devices and compute their VolumeID */ for (std::vector::iterator newIt = newDevices.begin(); newIt != newDevices.end(); newIt++) { bool bFound = false; for (std::vector::iterator It = volumeIdCandidates.begin(); It != volumeIdCandidates.end(); It++) { if (It->Path == newIt->Path) { bFound = true; break; } } if (!bFound) { /* new device/partition. Compute its Volume IDs */ OPEN_TEST_STRUCT openTest = {0}; if (OpenDevice (newIt->Path.c_str(), &openTest, TRUE, TRUE) && (openTest.VolumeIDComputed[TC_VOLUME_TYPE_NORMAL] && openTest.VolumeIDComputed[TC_VOLUME_TYPE_HIDDEN]) ) { memcpy (newIt->VolumeIDs, openTest.volumeIDs, sizeof (newIt->VolumeIDs)); newIt->HasVolumeIDs = true; } else newIt->HasVolumeIDs = false; volumeIdCandidates.push_back (*newIt); } } for (std::vector::iterator It = volumeIdCandidates.begin(); It != volumeIdCandidates.end(); It++) { if ( It->HasVolumeIDs && ( (0 == memcmp (volumeID, It->VolumeIDs[TC_VOLUME_TYPE_NORMAL], VOLUME_ID_SIZE)) || (0 == memcmp (volumeID, It->VolumeIDs[TC_VOLUME_TYPE_HIDDEN], VOLUME_ID_SIZE)) ) ) { return It->Path; } } } return L""; } #endif // !SETUP BOOL FileHasReadOnlyAttribute (const wchar_t *path) { DWORD attributes = GetFileAttributes (path); return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_READONLY) != 0; } BOOL IsFileOnReadOnlyFilesystem (const wchar_t *path) { wchar_t root[MAX_PATH]; if (!GetVolumePathName (path, root, ARRAYSIZE (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 (HWND hwndDlg, int driveNo, BOOL fixErrors) { wchar_t msg[1024], param[1024], cmdPath[MAX_PATH]; wchar_t driveRoot[] = { L'A' + (wchar_t) driveNo, L':', 0 }; if (fixErrors && AskWarnYesNo ("FILESYS_REPAIR_CONFIRM_BACKUP", hwndDlg) == IDNO) return; StringCbPrintfW (msg, sizeof(msg), GetString (fixErrors ? "REPAIRING_FS" : "CHECKING_FS"), driveRoot); StringCbPrintfW (param, sizeof(param), fixErrors ? L"/C echo %s & chkdsk %s /F /X & pause" : L"/C echo %s & chkdsk %s & pause", msg, driveRoot); if (GetSystemDirectoryW(cmdPath, MAX_PATH)) { StringCbCatW(cmdPath, sizeof(cmdPath), L"\\cmd.exe"); } else StringCbCopyW(cmdPath, sizeof(cmdPath), L"C:\\Windows\\System32\\cmd.exe"); ShellExecuteW (NULL, (!IsAdmin() && IsUacSupported()) ? L"runas" : L"open", cmdPath, 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 (HWND hwndDlg, BOOL *pbDecrypt) { if (AskWarnYesNo ("NONSYS_INPLACE_ENC_RESUME_PROMPT", hwndDlg) == IDYES) { char *tmpStr[] = {0, "CHOOSE_ENCRYPT_OR_DECRYPT", "ENCRYPT", "DECRYPT", "IDCANCEL", 0}; switch (AskMultiChoice ((void **) tmpStr, FALSE, hwndDlg)) { case 1: *pbDecrypt = FALSE; return IDYES; case 2: *pbDecrypt = TRUE; return IDYES; default: break; } } char *multiChoiceStr[] = { 0, "ASK_NONSYS_INPLACE_ENC_NOTIFICATION_REMOVAL", "DO_NOT_PROMPT_ME", "KEEP_PROMPTING_ME", 0 }; switch (AskMultiChoice ((void **) multiChoiceStr, FALSE, hwndDlg)) { case 1: RemoveNonSysInPlaceEncNotifications(); Warning ("NONSYS_INPLACE_ENC_NOTIFICATION_REMOVAL_NOTE", hwndDlg); break; default: // NOP break; } return IDNO; } #endif // !SETUP BOOL RemoveDeviceWriteProtection (HWND hwndDlg, wchar_t *devicePath) { int driveNumber; int partitionNumber; wchar_t temp[MAX_PATH*2]; wchar_t cmdBatch[MAX_PATH*2]; wchar_t diskpartScript[MAX_PATH*2]; if (swscanf (devicePath, L"\\Device\\Harddisk%d\\Partition%d", &driveNumber, &partitionNumber) != 2) return FALSE; if (GetTempPath (ARRAYSIZE (temp), temp) == 0) return FALSE; StringCbPrintfW (cmdBatch, sizeof (cmdBatch), L"%s\\VeraCrypt_Write_Protection_Removal.cmd", temp); StringCbPrintfW (diskpartScript, sizeof (diskpartScript), L"%s\\VeraCrypt_Write_Protection_Removal.diskpart", temp); FILE *f = _wfopen (cmdBatch, L"w"); if (!f) { handleWin32Error (hwndDlg, SRC_POS); return FALSE; } fwprintf (f, L"@diskpart /s \"%s\"\n@pause\n@del \"%s\" \"%s\"", diskpartScript, diskpartScript, cmdBatch); CheckFileStreamWriteErrors (hwndDlg, f, cmdBatch); fclose (f); f = _wfopen (diskpartScript, L"w"); if (!f) { handleWin32Error (hwndDlg, SRC_POS); DeleteFile (cmdBatch); return FALSE; } fwprintf (f, L"select disk %d\nattributes disk clear readonly\n", driveNumber); if (partitionNumber != 0) fwprintf (f, L"select partition %d\nattributes volume clear readonly\n", partitionNumber); fwprintf (f, L"exit\n"); CheckFileStreamWriteErrors (hwndDlg, f, diskpartScript); fclose (f); ShellExecute (NULL, (!IsAdmin() && IsUacSupported()) ? L"runas" : L"open", cmdBatch, NULL, NULL, SW_SHOW); return TRUE; } static LRESULT CALLBACK EnableElevatedCursorChangeWndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { return DefWindowProcW (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 wchar_t *className = L"VeraCryptEnableElevatedCursorChange"; WNDCLASSEXW winClass; HWND hWnd; memset (&winClass, 0, sizeof (winClass)); winClass.cbSize = sizeof (WNDCLASSEX); winClass.lpfnWndProc = (WNDPROC) EnableElevatedCursorChangeWndProc; winClass.hInstance = hInst; winClass.lpszClassName = className; RegisterClassExW (&winClass); hWnd = CreateWindowExW (WS_EX_TOOLWINDOW | WS_EX_LAYERED, className, L"VeraCrypt UAC", 0, 0, 0, GetSystemMetrics (SM_CXSCREEN), GetSystemMetrics (SM_CYSCREEN), parent, NULL, hInst, NULL); if (hWnd) { SetLayeredWindowAttributes (hWnd, 0, 1, LWA_ALPHA); ShowWindow (hWnd, SW_SHOWNORMAL); DestroyWindow (hWnd); } UnregisterClassW (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); } #ifndef SETUP BOOL VolumePathExists (const wchar_t *volumePath) { OPEN_TEST_STRUCT openTest = {0}; wchar_t upperCasePath[TC_MAX_PATH + 1]; UpperCaseCopy (upperCasePath, sizeof(upperCasePath), volumePath); if (wcsstr (upperCasePath, L"\\DEVICE\\") == upperCasePath) return OpenDevice (volumePath, &openTest, FALSE, FALSE); wstring path = volumePath; if (path.find (L"\\\\?\\Volume{") == 0 && path.rfind (L"}\\") == path.size() - 2) { wchar_t devicePath[TC_MAX_PATH]; if (QueryDosDevice (path.substr (4, path.size() - 5).c_str(), devicePath, TC_MAX_PATH) != 0) return TRUE; } if (_waccess (volumePath, 0) == 0) return TRUE; else { DWORD dwResult = GetLastError (); if (dwResult == ERROR_SHARING_VIOLATION) return TRUE; else return FALSE; } } BOOL IsWindowsIsoBurnerAvailable () { wchar_t path[MAX_PATH*2] = { 0 }; if (!IsOSAtLeast (WIN_7)) { return FALSE; } if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_SYSTEM, NULL, 0, path))) { StringCbCatW (path, MAX_PATH*2, L"\\" ISO_BURNER_TOOL); return (FileExists (path)); } return FALSE; } BOOL LaunchWindowsIsoBurner (HWND hwnd, const wchar_t *isoPath) { wchar_t path[MAX_PATH*2] = { 0 }; int r; if (SUCCEEDED(SHGetFolderPath (NULL, CSIDL_SYSTEM, NULL, 0, path))) StringCbCatW (path, MAX_PATH*2, L"\\" ISO_BURNER_TOOL); else StringCbCopyW (path, MAX_PATH*2, L"C:\\Windows\\System32\\" ISO_BURNER_TOOL); r = (int) ShellExecute (hwnd, L"open", path, (wstring (L"\"") + isoPath + L"\"").c_str(), NULL, SW_SHOWNORMAL); if (r <= 32) { SetLastError (r); handleWin32Error (hwnd, SRC_POS); return FALSE; } return TRUE; } std::wstring VolumeGuidPathToDevicePath (std::wstring volumeGuidPath) { if (volumeGuidPath.find (L"\\\\?\\") == 0) volumeGuidPath = volumeGuidPath.substr (4); if (volumeGuidPath.find (L"Volume{") != 0 || volumeGuidPath.rfind (L"}\\") != volumeGuidPath.size() - 2) return wstring(); wchar_t volDevPath[TC_MAX_PATH]; if (QueryDosDevice (volumeGuidPath.substr (0, volumeGuidPath.size() - 1).c_str(), volDevPath, TC_MAX_PATH) == 0) return wstring(); wstring partitionPath = HarddiskVolumePathToPartitionPath (volDevPath); return partitionPath.empty() ? volDevPath : partitionPath; } std::wstring HarddiskVolumePathToPartitionPath (const std::wstring &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]; StringCchPrintfW (partitionPath, ARRAYSIZE (partitionPath), L"\\Device\\Harddisk%d\\Partition%d", driveNumber, partNumber); wchar_t resolvedPath[TC_MAX_PATH]; if (ResolveSymbolicLink (partitionPath, resolvedPath, sizeof(resolvedPath))) { if (harddiskVolumePath == resolvedPath) return partitionPath; } else if (partNumber == 0) break; } } return wstring(); } #endif BOOL IsApplicationInstalled (const wchar_t *appName, BOOL b32bitApp) { const wchar_t *uninstallRegName = L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall"; BOOL installed = FALSE; HKEY unistallKey; LONG res = RegOpenKeyEx (HKEY_LOCAL_MACHINE, uninstallRegName, 0, KEY_READ | (b32bitApp? KEY_WOW64_32KEY: KEY_WOW64_64KEY), &unistallKey); if (res != ERROR_SUCCESS) { SetLastError (res); return FALSE; } wchar_t regName[1024]; DWORD regNameSize = sizeof (regName); DWORD index = 0; while (RegEnumKeyEx (unistallKey, index++, regName, ®NameSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { if (wcsstr (regName, L"{") == regName) { regNameSize = sizeof (regName); if (!ReadLocalMachineRegistryStringNonReflected ((wstring (uninstallRegName) + L"\\" + regName).c_str(), L"DisplayName", regName, ®NameSize, b32bitApp)) regName[0] = 0; } if (_wcsicmp (regName, appName) == 0) { installed = TRUE; break; } regNameSize = sizeof (regName); } RegCloseKey (unistallKey); return installed; } std::wstring FindLatestFileOrDirectory (const std::wstring &directory, const wchar_t *namePattern, bool findDirectory, bool findFile) { wstring name; ULARGE_INTEGER latestTime; latestTime.QuadPart = 0; WIN32_FIND_DATA findData; HANDLE find = FindFirstFile ((directory + L"\\" + namePattern).c_str(), &findData); if (find != INVALID_HANDLE_VALUE) { do { if (wcscmp (findData.cFileName, L".") == 0 || wcscmp (findData.cFileName, L"..") == 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 wstring (directory) + L"\\" + name; } int GetPim (HWND hwndDlg, UINT ctrlId, int defaultPim) { int pim = defaultPim; HWND hCtrl = GetDlgItem (hwndDlg, ctrlId); if (IsWindowEnabled (hCtrl) && IsWindowVisible (hCtrl)) { wchar_t szTmp[MAX_PIM + 1] = {0}; if (GetDlgItemText (hwndDlg, ctrlId, szTmp, MAX_PIM + 1) > 0) { wchar_t* endPtr = NULL; pim = wcstol(szTmp, &endPtr, 10); if (pim < 0 || endPtr == szTmp || !endPtr || *endPtr != L'\0') pim = defaultPim; } } return pim; } void SetPim (HWND hwndDlg, UINT ctrlId, int pim) { if (pim > 0) { wchar_t szTmp[MAX_PIM + 1]; StringCbPrintfW (szTmp, sizeof(szTmp), L"%d", pim); SetDlgItemText (hwndDlg, ctrlId, szTmp); } else SetDlgItemText (hwndDlg, ctrlId, L""); } BOOL GetPassword (HWND hwndDlg, UINT ctrlID, char* passValue, int bufSize, BOOL bShowError) { wchar_t tmp [MAX_PASSWORD + 1]; int utf8Len; BOOL bRet = FALSE; GetWindowText (GetDlgItem (hwndDlg, ctrlID), tmp, ARRAYSIZE (tmp)); utf8Len = WideCharToMultiByte (CP_UTF8, 0, tmp, -1, passValue, bufSize, NULL, NULL); burn (tmp, sizeof (tmp)); if (utf8Len > 0) { bRet = TRUE; } else { passValue [0] = 0; if (bShowError) { SetFocus (GetDlgItem(hwndDlg, ctrlID)); if (GetLastError () == ERROR_INSUFFICIENT_BUFFER) Error ("PASSWORD_UTF8_TOO_LONG", hwndDlg); else Error ("PASSWORD_UTF8_INVALID", hwndDlg); } } return bRet; } void SetPassword (HWND hwndDlg, UINT ctrlID, char* passValue) { wchar_t tmp [MAX_PASSWORD + 1] = {0}; MultiByteToWideChar (CP_UTF8, 0, passValue, -1, tmp, MAX_PASSWORD + 1); SetWindowText ( GetDlgItem (hwndDlg, ctrlID), tmp); burn (tmp, sizeof (tmp)); } void HandleShowPasswordFieldAction (HWND hwndDlg, UINT checkBoxId, UINT edit1Id, UINT edit2Id) { if ((EditPasswordChar == 0) && GetCheckBox (hwndDlg, checkBoxId)) { EditPasswordChar = (WCHAR) SendMessageW (GetDlgItem (hwndDlg, edit1Id), EM_GETPASSWORDCHAR, 0, 0); } SendMessageW (GetDlgItem (hwndDlg, edit1Id), EM_SETPASSWORDCHAR, GetCheckBox (hwndDlg, checkBoxId) ? 0 : EditPasswordChar, 0); InvalidateRect (GetDlgItem (hwndDlg, edit1Id), NULL, TRUE); if (edit2Id) { SendMessageW (GetDlgItem (hwndDlg, edit2Id), EM_SETPASSWORDCHAR, GetCheckBox (hwndDlg, checkBoxId) ? 0 : EditPasswordChar, 0); InvalidateRect (GetDlgItem (hwndDlg, edit2Id), NULL, TRUE); } } void RegisterDriverInf (bool registerFilter, const string& filter, const string& filterReg, HWND ParentWindow, HKEY regKey) { wstring infFileName = GetTempPathString() + L"\\veracrypt_driver_setup.inf"; File infFile (infFileName, false, true); finally_do_arg (wstring, infFileName, { DeleteFile (finally_arg.c_str()); }); string infTxt = "[veracrypt]\r\n" + string (registerFilter ? "Add" : "Del") + "Reg=veracrypt_reg\r\n\r\n" "[veracrypt_reg]\r\n" "HKR,,\"" + filterReg + "\",0x0001" + string (registerFilter ? "0008" : "8002") + ",\"" + filter + "\"\r\n"; infFile.Write ((byte *) infTxt.c_str(), (DWORD) infTxt.size()); infFile.Close(); HINF hInf = SetupOpenInfFileWFn (infFileName.c_str(), NULL, INF_STYLE_OLDNT | INF_STYLE_WIN4, NULL); throw_sys_if (hInf == INVALID_HANDLE_VALUE); finally_do_arg (HINF, hInf, { SetupCloseInfFileFn (finally_arg); }); throw_sys_if (!SetupInstallFromInfSectionWFn (ParentWindow, hInf, L"veracrypt", SPINST_REGISTRY, regKey, NULL, 0, NULL, NULL, NULL, NULL)); } HKEY OpenDeviceClassRegKey (const GUID *deviceClassGuid) { return SetupDiOpenClassRegKeyFn (deviceClassGuid, KEY_READ | KEY_WRITE); } LSTATUS DeleteRegistryKey (HKEY hKey, LPCTSTR keyName) { return SHDeleteKeyWFn(hKey, keyName); } HIMAGELIST CreateImageList(int cx, int cy, UINT flags, int cInitial, int cGrow) { return ImageList_CreateFn(cx, cy, flags, cInitial, cGrow); } int AddBitmapToImageList(HIMAGELIST himl, HBITMAP hbmImage, HBITMAP hbmMask) { return ImageList_AddFn(himl, hbmImage, hbmMask); } HRESULT VCStrDupW(LPCWSTR psz, LPWSTR *ppwsz) { return SHStrDupWFn (psz, ppwsz); } void ProcessEntropyEstimate (HWND hProgress, DWORD* pdwInitialValue, DWORD dwCounter, DWORD dwMaxLevel, DWORD* pdwEntropy) { /* conservative estimate: 1 mouse move event brings 1 bit of entropy * https://security.stackexchange.com/questions/32844/for-how-much-time-should-i-randomly-move-the-mouse-for-generating-encryption-key/32848#32848 */ if (*pdwEntropy == 0xFFFFFFFF) { *pdwInitialValue = dwCounter; *pdwEntropy = 0; } else { if ( *pdwEntropy < dwMaxLevel && (dwCounter >= *pdwInitialValue) && (dwCounter - *pdwInitialValue) <= dwMaxLevel) *pdwEntropy = dwCounter - *pdwInitialValue; else *pdwEntropy = dwMaxLevel; if (IsOSAtLeast (WIN_VISTA)) { int state = PBST_ERROR; if (*pdwEntropy >= (dwMaxLevel/2)) state = PBST_NORMAL; else if (*pdwEntropy >= (dwMaxLevel/4)) state = PBST_PAUSED; SendMessage (hProgress, PBM_SETSTATE, state, 0); } SendMessage (hProgress, PBM_SETPOS, (WPARAM) (*pdwEntropy), 0); } } void AllowMessageInUIPI (UINT msg) { if (ChangeWindowMessageFilterFn) { ChangeWindowMessageFilterFn (msg, MSGFLT_ADD); } } BOOL IsRepeatedByteArray (byte value, const byte* buffer, size_t bufferSize) { if (buffer && bufferSize) { size_t i; for (i = 0; i < bufferSize; i++) { if (*buffer++ != value) return FALSE; } return TRUE; } else return FALSE; } #ifndef SETUP BOOL TranslateVolumeID (HWND hwndDlg, wchar_t* pathValue, size_t cchPathValue) { BOOL bRet = TRUE; size_t pathLen = pathValue? wcslen (pathValue) : 0; if ((pathLen >= 3) && (_wcsnicmp (pathValue, L"ID:", 3) == 0)) { std::vector arr; if ( (pathLen == (3 + 2*VOLUME_ID_SIZE)) && HexWideStringToArray (pathValue + 3, arr) && (arr.size() == VOLUME_ID_SIZE) ) { std::wstring devicePath = FindDeviceByVolumeID (&arr[0], FALSE); if (devicePath.length() > 0) StringCchCopyW (pathValue, cchPathValue, devicePath.c_str()); else { if (!Silent && !MultipleMountOperationInProgress) Error ("VOLUME_ID_NOT_FOUND", hwndDlg); SetLastError (ERROR_PATH_NOT_FOUND); bRet = FALSE; } } else { if (!Silent) Error ("VOLUME_ID_INVALID", hwndDlg); SetLastError (ERROR_INVALID_PARAMETER); bRet = FALSE; } } return bRet; } #endif BOOL CopyTextToClipboard (LPCWSTR txtValue) { size_t txtLen = wcslen(txtValue); HGLOBAL hdst; LPWSTR dst; BOOL bRet = FALSE; // Allocate string for cwd hdst = GlobalAlloc(GMEM_MOVEABLE, (txtLen + 1) * sizeof(WCHAR)); if (hdst) { dst = (LPWSTR)GlobalLock(hdst); wmemcpy(dst, txtValue, txtLen + 1); GlobalUnlock(hdst); if (OpenClipboard(NULL)) { EmptyClipboard(); SetClipboardData(CF_UNICODETEXT, hdst); CloseClipboard(); } } return bRet; } BOOL GetFreeDriveLetter(WCHAR* pCh) { DWORD dwUsedDrives = GetLogicalDrives(); WCHAR l; for (l = L'A'; l <= L'Z'; l++) { if ((dwUsedDrives & 1) == 0) { *pCh = l; return TRUE; } dwUsedDrives = dwUsedDrives >> 1; } return FALSE; } BOOL SetPrivilege(LPTSTR szPrivilegeName, BOOL bEnable) { HANDLE hToken; TOKEN_PRIVILEGES tkp; BOOL bRet = FALSE; DWORD dwLastError = 0; if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { if (LookupPrivilegeValue(NULL, szPrivilegeName, &tkp.Privileges[0].Luid)) { tkp.PrivilegeCount = 1; tkp.Privileges[0].Attributes = bEnable? SE_PRIVILEGE_ENABLED : SE_PRIVILEGE_REMOVED; bRet = AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, NULL, NULL); if (!bRet) dwLastError = GetLastError (); } else dwLastError = GetLastError (); CloseHandle(hToken); } else dwLastError = GetLastError (); SetLastError (dwLastError); return bRet; } BOOL DeleteDirectory (const wchar_t* szDirName) { BOOL bStatus = RemoveDirectory (szDirName); if (!bStatus) { /* force removal of the non empty directory */ wchar_t szOpPath[TC_MAX_PATH + 1] = {0}; SHFILEOPSTRUCTW op; StringCchCopyW(szOpPath, ARRAYSIZE(szOpPath)-1, szDirName); ZeroMemory(&op, sizeof(op)); op.wFunc = FO_DELETE; op.pFrom = szOpPath; op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR; if ((0 == SHFileOperation(&op)) && (!op.fAnyOperationsAborted)) bStatus = TRUE; } return bStatus; } #if defined (TCMOUNT) || defined (VOLFORMAT) /*********************************************************************/ static BOOL GenerateRandomString (HWND hwndDlg, LPTSTR szName, DWORD maxCharsCount) { BOOL bRet = FALSE; if (Randinit () != ERR_SUCCESS) { handleError (hwndDlg, (CryptoAPILastError == ERROR_SUCCESS)? ERR_RAND_INIT_FAILED : ERR_CAPI_INIT_FAILED, SRC_POS); } else { BYTE* indexes = (BYTE*) malloc (maxCharsCount + 1); bRet = RandgetBytesFull (hwndDlg, indexes, maxCharsCount + 1, TRUE, TRUE); if (bRet) { static LPCTSTR chars = _T("0123456789@#$%^&_-*abcdefghijklmnopqrstuvwxyz"); DWORD i, charsLen = (DWORD) _tcslen (chars); DWORD effectiveLen = (indexes[0] % (64 - 16)) + 16; // random length between 16 to 64 effectiveLen = (effectiveLen > maxCharsCount)? maxCharsCount : effectiveLen; for (i = 0; i < effectiveLen; i++) { szName[i] = chars[indexes[i + 1] % charsLen]; } szName[effectiveLen] = 0; } burn (indexes, maxCharsCount + 1); free (indexes); } return bRet; } typedef struct { HDESK hDesk; LPCWSTR szDesktopName; HINSTANCE hInstance; LPCWSTR lpTemplateName; DLGPROC lpDialogFunc; LPARAM dwInitParam; INT_PTR retValue; } SecureDesktopThreadParam; typedef struct { LPCWSTR szVCDesktopName; HDESK hVcDesktop; volatile BOOL* pbStopMonitoring; } SecureDesktopMonitoringThreadParam; #define SECUREDESKTOP_MONOTIR_PERIOD 500 // This thread checks if VeraCrypt secure desktop is the one that has user input // and if it is not then it will call SwitchDesktop to make it the input desktop static unsigned int __stdcall SecureDesktopMonitoringThread( LPVOID lpThreadParameter ) { SecureDesktopMonitoringThreadParam* pMonitorParam = (SecureDesktopMonitoringThreadParam*) lpThreadParameter; if (pMonitorParam) { volatile BOOL* pbStopMonitoring = pMonitorParam->pbStopMonitoring; LPCWSTR szVCDesktopName = pMonitorParam->szVCDesktopName; HDESK hVcDesktop = pMonitorParam->hVcDesktop; while (!*pbStopMonitoring) { // check that our secure desktop is still the input desktop // otherwise, switch to it BOOL bPerformSwitch = FALSE; HDESK currentDesk = OpenInputDesktop (0, FALSE, GENERIC_READ); if (currentDesk) { LPWSTR szName = NULL; DWORD dwLen = 0; if (!GetUserObjectInformation (currentDesk, UOI_NAME, NULL, 0, &dwLen)) { szName = (LPWSTR) malloc (dwLen); if (szName) { if (GetUserObjectInformation (currentDesk, UOI_NAME, szName, dwLen, &dwLen)) { if (0 != _wcsicmp (szName, szVCDesktopName)) bPerformSwitch = TRUE; } free (szName); } } CloseDesktop (currentDesk); } if (bPerformSwitch) SwitchDesktop (hVcDesktop); Sleep (SECUREDESKTOP_MONOTIR_PERIOD); } } return 0; } static DWORD WINAPI SecureDesktopThread(LPVOID lpThreadParameter) { volatile BOOL bStopMonitoring = FALSE; HANDLE hMonitoringThread = NULL; unsigned int monitoringThreadID = 0; SecureDesktopThreadParam* pParam = (SecureDesktopThreadParam*) lpThreadParameter; SecureDesktopMonitoringThreadParam monitorParam; HDESK hOriginalDesk = GetThreadDesktop (GetCurrentThreadId ()); BOOL bNewDesktopSet = FALSE; // wait for SwitchDesktop to succeed before using it for current thread while (true) { if (SwitchDesktop (pParam->hDesk)) { bNewDesktopSet = TRUE; break; } Sleep (SECUREDESKTOP_MONOTIR_PERIOD); } if (bNewDesktopSet) { SetThreadDesktop (pParam->hDesk); // create the thread that will ensure that VeraCrypt secure desktop has always user input monitorParam.szVCDesktopName = pParam->szDesktopName; monitorParam.hVcDesktop = pParam->hDesk; monitorParam.pbStopMonitoring = &bStopMonitoring; hMonitoringThread = (HANDLE) _beginthreadex (NULL, 0, SecureDesktopMonitoringThread, (LPVOID) &monitorParam, 0, &monitoringThreadID); } pParam->retValue = DialogBoxParamW (pParam->hInstance, pParam->lpTemplateName, NULL, pParam->lpDialogFunc, pParam->dwInitParam); if (hMonitoringThread) { bStopMonitoring = TRUE; WaitForSingleObject (hMonitoringThread, INFINITE); CloseHandle (hMonitoringThread); } if (bNewDesktopSet) { SetThreadDesktop (hOriginalDesk); SwitchDesktop (hOriginalDesk); } return 0; } static void GetCtfMonProcessIdList (map& processIdList) { HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL); PROCESSENTRY32 pEntry; BOOL hRes; pEntry.dwSize = sizeof (pEntry); processIdList.clear(); hRes = Process32First(hSnapShot, &pEntry); while (hRes) { LPTSTR szFileName = PathFindFileName (pEntry.szExeFile); if (_wcsicmp(szFileName, L"ctfmon.exe") == 0) { processIdList[pEntry.th32ProcessID] = TRUE; } hRes = Process32Next(hSnapShot, &pEntry); } CloseHandle(hSnapShot); } static void KillProcess (DWORD dwProcessId) { HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0, dwProcessId); if (hProcess != NULL) { TerminateProcess(hProcess, (UINT) -1); CloseHandle(hProcess); } } INT_PTR SecureDesktopDialogBoxParam( HINSTANCE hInstance, LPCWSTR lpTemplateName, HWND hWndParent, DLGPROC lpDialogFunc, LPARAM dwInitParam) { TCHAR szDesktopName[65] = {0}; BOOL bSuccess = FALSE; INT_PTR retValue = 0; BOOL bEffectiveUseSecureDesktop = bCmdUseSecureDesktopValid? bCmdUseSecureDesktop : bUseSecureDesktop; if (bEffectiveUseSecureDesktop && GenerateRandomString (hWndParent, szDesktopName, 64)) { map ctfmonBeforeList, ctfmonAfterList; DWORD desktopAccess = DESKTOP_CREATEMENU | DESKTOP_CREATEWINDOW | DESKTOP_READOBJECTS | DESKTOP_SWITCHDESKTOP | DESKTOP_WRITEOBJECTS; HDESK hSecureDesk; HDESK hInputDesk = NULL; // wait for the input desktop to be available before switching to // secure desktop. Under Windows 10, the user session can be started // in the background even before the user has authenticated and in this // case, we wait for the user to be really authenticated before starting // secure desktop mechanism while (!(hInputDesk = OpenInputDesktop (0, TRUE, GENERIC_READ))) { Sleep (SECUREDESKTOP_MONOTIR_PERIOD); } CloseDesktop (hInputDesk); // get the initial list of ctfmon.exe processes before creating new desktop GetCtfMonProcessIdList (ctfmonBeforeList); hSecureDesk = CreateDesktop (szDesktopName, NULL, NULL, 0, desktopAccess, NULL); if (hSecureDesk) { SecureDesktopThreadParam param; param.hDesk = hSecureDesk; param.szDesktopName = szDesktopName; param.hInstance = hInstance; param.lpTemplateName = lpTemplateName; param.lpDialogFunc = lpDialogFunc; param.dwInitParam = dwInitParam; param.retValue = 0; HANDLE hThread = ::CreateThread (NULL, 0, SecureDesktopThread, (LPVOID) ¶m, 0, NULL); if (hThread) { WaitForSingleObject (hThread, INFINITE); CloseHandle (hThread); retValue = param.retValue; bSuccess = TRUE; } CloseDesktop (hSecureDesk); // get the new list of ctfmon.exe processes in order to find the ID of the // ctfmon.exe instance that corresponds to the desktop we create so that // we can kill it, otherwise it would remain running GetCtfMonProcessIdList (ctfmonAfterList); for (map::iterator It = ctfmonAfterList.begin(); It != ctfmonAfterList.end(); It++) { if (ctfmonBeforeList[It->first] != TRUE) { // Kill process KillProcess (It->first); } } } burn (szDesktopName, sizeof (szDesktopName)); } if (!bSuccess) { // fallback to displaying in normal desktop retValue = DialogBoxParamW (hInstance, lpTemplateName, hWndParent, lpDialogFunc, dwInitParam); } return retValue; } #endif #ifdef NDEBUG static BOOL InitializeWintrust() { if (!hWinTrustLib) { wchar_t szPath[MAX_PATH] = {0}; if (GetSystemDirectory(szPath, MAX_PATH)) StringCchCatW (szPath, MAX_PATH, L"\\Wintrust.dll"); else StringCchCopyW (szPath, MAX_PATH, L"C:\\Windows\\System32\\Wintrust.dll"); hWinTrustLib = LoadLibrary (szPath); if (hWinTrustLib) { WinVerifyTrustFn = (WINVERIFYTRUST) GetProcAddress (hWinTrustLib, "WinVerifyTrust"); WTHelperProvDataFromStateDataFn = (WTHELPERPROVDATAFROMSTATEDATA) GetProcAddress (hWinTrustLib, "WTHelperProvDataFromStateData"); WTHelperGetProvSignerFromChainFn = (WTHELPERGETPROVSIGNERFROMCHAIN) GetProcAddress (hWinTrustLib, "WTHelperGetProvSignerFromChain"); WTHelperGetProvCertFromChainFn = (WTHELPERGETPROVCERTFROMCHAIN) GetProcAddress (hWinTrustLib, "WTHelperGetProvCertFromChain"); if ( !WinVerifyTrustFn || !WTHelperProvDataFromStateDataFn || !WTHelperGetProvSignerFromChainFn || !WTHelperGetProvCertFromChainFn) { FreeLibrary (hWinTrustLib); hWinTrustLib = NULL; } } } if (hWinTrustLib) return TRUE; else return FALSE; } static void FinalizeWintrust() { if (hWinTrustLib) { FreeLibrary (hWinTrustLib); hWinTrustLib = NULL; } } #endif BOOL VerifyModuleSignature (const wchar_t* path) { #ifdef NDEBUG BOOL bResult = FALSE; HRESULT hResult; GUID gActionID = WINTRUST_ACTION_GENERIC_VERIFY_V2; WINTRUST_FILE_INFO fileInfo = {0}; WINTRUST_DATA WVTData = {0}; wchar_t filePath [TC_MAX_PATH + 1024]; // Strip quotation marks (if any) if (path [0] == L'"') { StringCbCopyW (filePath, sizeof(filePath), path + 1); } else { StringCbCopyW (filePath, sizeof(filePath), path); } // Strip quotation marks (if any) if (filePath [wcslen (filePath) - 1] == L'"') filePath [wcslen (filePath) - 1] = 0; if (!InitializeWintrust ()) return FALSE; fileInfo.cbStruct = sizeof(WINTRUST_FILE_INFO); fileInfo.pcwszFilePath = filePath; fileInfo.hFile = NULL; WVTData.cbStruct = sizeof(WINTRUST_DATA); WVTData.dwUIChoice = WTD_UI_NONE; WVTData.fdwRevocationChecks = WTD_REVOKE_NONE; WVTData.dwUnionChoice = WTD_CHOICE_FILE; WVTData.pFile = &fileInfo; WVTData.dwStateAction = WTD_STATEACTION_VERIFY; WVTData.dwProvFlags = WTD_REVOCATION_CHECK_NONE | WTD_CACHE_ONLY_URL_RETRIEVAL; hResult = WinVerifyTrustFn(0, &gActionID, &WVTData); if (SUCCEEDED (hResult)) { PCRYPT_PROVIDER_DATA pProviderData = WTHelperProvDataFromStateDataFn (WVTData.hWVTStateData); if (pProviderData) { PCRYPT_PROVIDER_SGNR pProviderSigner = WTHelperGetProvSignerFromChainFn (pProviderData, 0, FALSE, 0); if (pProviderSigner) { PCRYPT_PROVIDER_CERT pProviderCert = WTHelperGetProvCertFromChainFn (pProviderSigner, 0); if (pProviderCert && (pProviderCert->pCert)) { BYTE hashVal[64]; sha512 (hashVal, pProviderCert->pCert->pbCertEncoded, pProviderCert->pCert->cbCertEncoded); if (0 == memcmp (hashVal, gpbSha1CodeSignCertFingerprint, 64)) { bResult = TRUE; } } } } } WVTData.dwUIChoice = WTD_UI_NONE; WVTData.dwStateAction = WTD_STATEACTION_CLOSE; WinVerifyTrustFn(0, &gActionID, &WVTData); FinalizeWintrust (); return bResult; #else return TRUE; #endif } void GetInstallationPath (HWND hwndDlg, wchar_t* szInstallPath, DWORD cchSize, BOOL* pbInstallPathDetermined) { HKEY hkey; BOOL bInstallPathDetermined = FALSE; wchar_t path[MAX_PATH+20]; ITEMIDLIST *itemList; memset (szInstallPath, 0, cchSize * sizeof (wchar_t)); // Determine if VeraCrypt is already installed and try to determine its "Program Files" location if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\VeraCrypt", 0, KEY_READ | KEY_WOW64_32KEY, &hkey) == ERROR_SUCCESS) { /* Default 'UninstallString' registry strings written by VeraCrypt: ------------------------------------------------------------------------------------ 5.0+ "C:\Program Files\VeraCrypt\VeraCrypt Setup.exe" /u */ wchar_t rv[MAX_PATH*4]; DWORD size = sizeof (rv); if (RegQueryValueEx (hkey, L"UninstallString", 0, 0, (LPBYTE) &rv, &size) == ERROR_SUCCESS && wcsrchr (rv, L'/')) { size_t len = 0; // Cut and paste the location (path) where VeraCrypt is installed to InstallationPath if (rv[0] == L'"') { len = wcsrchr (rv, L'/') - rv - 2; StringCchCopyNW (szInstallPath, cchSize, rv + 1, len); szInstallPath [len] = 0; bInstallPathDetermined = TRUE; if (szInstallPath [wcslen (szInstallPath) - 1] != L'\\') { len = wcsrchr (szInstallPath, L'\\') - szInstallPath; szInstallPath [len] = 0; } } } RegCloseKey (hkey); } if (!bInstallPathDetermined) { /* VeraCrypt is not installed or it wasn't possible to determine where it is installed. */ // Default "Program Files" path. SHGetSpecialFolderLocation (hwndDlg, CSIDL_PROGRAM_FILES, &itemList); SHGetPathFromIDList (itemList, path); if (Is64BitOs()) { // Use a unified default installation path (registry redirection of %ProgramFiles% does not work if the installation path is user-selectable) wstring s = path; size_t p = s.find (L" (x86)"); if (p != wstring::npos) { s = s.substr (0, p); if (_waccess (s.c_str(), 0) != -1) StringCbCopyW (path, sizeof (path), s.c_str()); } } StringCbCatW (path, sizeof(path), L"\\VeraCrypt\\"); StringCbCopyW (szInstallPath, cchSize, path); } // Make sure the path ends with a backslash if (szInstallPath [wcslen (szInstallPath) - 1] != L'\\') { StringCbCatW (szInstallPath, cchSize, L"\\"); } if (pbInstallPathDetermined) *pbInstallPathDetermined = bInstallPathDetermined; } BOOL GetSetupconfigLocation (wchar_t* path, DWORD cchSize) { wchar_t szShell32Path[MAX_PATH] = {0}; HMODULE hShell32 = NULL; BOOL bResult = FALSE; path[0] = 0; if (GetSystemDirectory(szShell32Path, MAX_PATH)) StringCchCatW (szShell32Path, MAX_PATH, L"\\Shell32.dll"); else StringCchCopyW (szShell32Path, MAX_PATH, L"C:\\Windows\\System32\\Shell32.dll"); hShell32 = LoadLibrary (szShell32Path); if (hShell32) { SHGETKNOWNFOLDERPATH SHGetKnownFolderPathFn = (SHGETKNOWNFOLDERPATH) GetProcAddress (hShell32, "SHGetKnownFolderPath"); if (SHGetKnownFolderPathFn) { wchar_t* pszUsersPath = NULL; if (S_OK == SHGetKnownFolderPathFn (FOLDERID_UserProfiles, 0, NULL, &pszUsersPath)) { StringCchPrintfW (path, cchSize, L"%s\\Default\\AppData\\Local\\Microsoft\\Windows\\WSUS\\", pszUsersPath); CoTaskMemFree (pszUsersPath); bResult = TRUE; } } FreeLibrary (hShell32); } if (!bResult && CurrentOSMajor >= 10) { StringCchPrintfW (path, cchSize, L"%c:\\Users\\Default\\AppData\\Local\\Microsoft\\Windows\\WSUS\\", szShell32Path[0]); bResult = TRUE; } return bResult; } BOOL BufferHasPattern (const unsigned char* buffer, size_t bufferLen, const void* pattern, size_t patternLen) { BOOL bRet = FALSE; if (patternLen <= bufferLen) { size_t i; for (i = 0; i <= (bufferLen - patternLen); ++i) { if (memcmp (&buffer[i], pattern, patternLen) == 0) { bRet = TRUE; break; } } } return bRet; }