Files
VeraCrypt/src/ExpandVolume/DlgExpandVolume.cpp
Mounir IDRASSI 9ea5ccc4aa Windows: Enable screen protection by default to block screenshots, recordings & Windows Recall. Add configurable setting in Preferences, Installer, and MSI.
This update introduces a screen protection mechanism that leverages the Windows Display Affinity API to prevent screen capture, screen recording, and inclusion in the Windows 11 Recall feature. By default, all VeraCrypt windows, menus, and tooltips are protected. Users can enable or disable this feature through a new setting available in the application Preferences, as well as in the installer and MSI configurations.

This enhances user privacy by mitigating potential leaks of sensitive interface content.

Note: Due to a regression in Windows 11 affecting layered windows, ComboBox dropdowns cannot currently be protected by this mechanism.
2025-05-24 15:28:39 +09:00

852 lines
25 KiB
C++

/*
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'
and also from the source code of extcv, which is Copyright (c) 2009-2010 Kih-Oskh
or Copyright (c) 2012-2013 Josef Schneider <josef@netpage.dk>
Modifications and additions to the original source code (contained in this file)
and all other portions of this file are Copyright (c) 2013-2025 AM Crypto
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 <time.h>
#include <math.h>
#include <dbt.h>
#include <fcntl.h>
#include <io.h>
#include <sys/stat.h>
#include <windowsx.h>
#include <stdio.h>
#include "Apidrvr.h"
#include "Volumes.h"
#include "Crypto.h"
#include "Dlgcode.h"
#include "Language.h"
#include "Pkcs5.h"
#include "Random.h"
// #include "../Mount/Mount.h"
#include "../Common/Dictionary.h"
#include "../Common/Common.h"
#include "../Common/Resource.h"
#include "../Common/SecurityToken.h"
#include "../Common/Progress.h"
#include "ExpandVolume.h"
#include "Resource.h"
// TO DO: display sector sizes different than 512 bytes
#define SECTOR_SIZE_MSG 512
#define TIMER_ID_RANDVIEW 0xff
#define TIMER_INTERVAL_RANDVIEW 50
BOOL bSeManageVolumeNameSet = FALSE;
// see definition of enum EV_FileSystem
const wchar_t * szFileSystemStr[4] = {L"RAW",L"FAT",L"NTFS",L"EXFAT"};
// prototypes for internal functions
BOOL CALLBACK ExpandVolSizeDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
BOOL CALLBACK ExpandVolProgressDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
namespace VeraCryptExpander
{
/* defined in WinMain.c, referenced by ExpandVolumeWizard() */
int ExtcvAskVolumePassword (HWND hwndDlg, const wchar_t* fileName, Password *password, int *pkcs5, int *pim, char *titleStringId, BOOL enableMountOptions);
}
int GetSpaceString(wchar_t *dest, size_t cbDest, uint64 size, BOOL bDevice)
{
const wchar_t * szFmtBytes = L"%.0lf %s";
const wchar_t * szFmtOther = L"%.2lf %s";
const wchar_t * SuffixStr[] = {GetString("BYTE"), GetString("KB"), GetString("MB"), GetString("GB"), GetString("TB")};
const uint64 Muliplier[] = {1, BYTES_PER_KB, BYTES_PER_MB, BYTES_PER_GB, BYTES_PER_TB};
const int nMaxSuffix = sizeof(Muliplier)/sizeof(uint64) - 1;
int i;
for (i=1; i<=nMaxSuffix && size>Muliplier[i]; i++) ;
--i;
if (bDevice) {
wchar_t szTemp[512];
if (StringCbPrintfW(szTemp, sizeof(szTemp),i?szFmtOther:szFmtBytes, size/(double)Muliplier[i], SuffixStr[i]) < 0 )
return -1;
return StringCbPrintfW(dest, cbDest, L"%I64u sectors (%s)", size/SECTOR_SIZE_MSG , szTemp);
}
return StringCbPrintfW(dest, cbDest,i?szFmtOther:szFmtBytes, size/(double)Muliplier[i], SuffixStr[i]);
}
void SetCurrentVolSize(HWND hwndDlg, uint64 size)
{
const uint64 Muliplier[] = {BYTES_PER_KB, BYTES_PER_MB, BYTES_PER_GB, BYTES_PER_TB};
const int IdRadioBtn[] = {IDC_KB, IDC_MB, IDC_GB, IDC_TB};
const int nMaxSuffix = sizeof(Muliplier)/sizeof(uint64) - 1;
int i;
wchar_t szTemp[256];
for (i=1; i<=nMaxSuffix && size>Muliplier[i]; i++) ;
--i;
SendDlgItemMessage (hwndDlg, IdRadioBtn[i], BM_SETCHECK, BST_CHECKED, 0);
StringCbPrintfW(szTemp,sizeof(szTemp),L"%I64u",size/Muliplier[i]);
SetWindowText (GetDlgItem (hwndDlg, IDC_SIZEBOX), szTemp);
}
uint64 GetSizeBoxMultiplier(HWND hwndDlg)
{
const uint64 Muliplier[] = {BYTES_PER_KB, BYTES_PER_MB, BYTES_PER_GB, BYTES_PER_TB};
const int IdRadioBtn[] = {IDC_KB, IDC_MB, IDC_GB, IDC_TB};
const int nMaxSuffix = sizeof(Muliplier)/sizeof(uint64) - 1;
int i;
for (i=nMaxSuffix; i>0 && !IsButtonChecked (GetDlgItem (hwndDlg, IdRadioBtn[i])); --i) ;
return Muliplier[i];
}
void HandleQuickExpanddCheckBox (HWND hwndDlg)
{
if (IsButtonChecked (GetDlgItem (hwndDlg, IDC_INIT_NEWSPACE)))
{
EnableWindow (GetDlgItem (hwndDlg, IDC_QUICKEXPAND), FALSE);
SendDlgItemMessage (hwndDlg, IDC_QUICKEXPAND, BM_SETCHECK, BST_UNCHECKED, 0);
}
else
{
EnableWindow (GetDlgItem (hwndDlg, IDC_QUICKEXPAND), TRUE);
}
}
BOOL CALLBACK ExpandVolSizeDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static EXPAND_VOL_THREAD_PARAMS *pVolExpandParam;
WORD lw = LOWORD (wParam);
switch (msg)
{
case WM_INITDIALOG:
{
wchar_t szTemp[4096];
pVolExpandParam = (EXPAND_VOL_THREAD_PARAMS*)lParam;
LocalizeDialog (hwndDlg, NULL);
EnableWindow (GetDlgItem (hwndDlg, IDC_SIZEBOX), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_KB), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_MB), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_GB), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_TB), !pVolExpandParam->bIsDevice);
EnableWindow (GetDlgItem (hwndDlg, IDC_INIT_NEWSPACE),
!(pVolExpandParam->bIsLegacy && pVolExpandParam->bIsDevice));
SendDlgItemMessage (hwndDlg, IDC_INIT_NEWSPACE, BM_SETCHECK,
pVolExpandParam->bInitFreeSpace ? BST_CHECKED : BST_UNCHECKED, 0);
if (!pVolExpandParam->bIsDevice)
SetCurrentVolSize(hwndDlg,pVolExpandParam->oldSize);
SendMessage (GetDlgItem (hwndDlg, IDC_BOX_HELP), WM_SETFONT, (WPARAM) hBoldFont, (LPARAM) TRUE);
GetSpaceString(szTemp,sizeof(szTemp),pVolExpandParam->oldSize,pVolExpandParam->bIsDevice);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_OLDSIZE), szTemp);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_NAME), pVolExpandParam->szVolumeName);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_FILE_SYSTEM), szFileSystemStr[pVolExpandParam->FileSystem]);
if (pVolExpandParam->bIsDevice)
{
GetSpaceString(szTemp,sizeof(szTemp),pVolExpandParam->newSize,TRUE);
}
else
{
wchar_t szHostFreeStr[256];
SetWindowText (GetDlgItem (hwndDlg, IDT_NEW_SIZE), L"");
GetSpaceString(szHostFreeStr,sizeof(szHostFreeStr),pVolExpandParam->hostSizeFree,FALSE);
StringCbPrintfW (szTemp,sizeof(szTemp),GetString("EXPANDER_FREE_SPACE"), szHostFreeStr);
if (!pVolExpandParam->bDisableQuickExpand)
{
ShowWindow (GetDlgItem (hwndDlg, IDC_QUICKEXPAND), SW_SHOW);
HandleQuickExpanddCheckBox (hwndDlg);
}
}
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_NEWSIZE), szTemp);
// set help text
if (pVolExpandParam->bIsDevice)
{
StringCbPrintfW (szTemp,sizeof(szTemp),GetString("EXPANDER_HELP_DEVICE"));
if (pVolExpandParam->bIsLegacy)
StringCbCatW(szTemp,sizeof(szTemp),L" Note: filling the new space with random data is not supported for legacy volumes.");
}
else
{
StringCbPrintfW (szTemp, sizeof(szTemp),GetString("EXPANDER_HELP_FILE"),TC_MINVAL_FS_EXPAND/1024);
}
SetWindowText (GetDlgItem (hwndDlg, IDC_BOX_HELP), szTemp);
}
return 0;
case WM_DESTROY:
DetachProtectionFromCurrentThread();
break;
case WM_COMMAND:
if (lw == IDCANCEL)
{
EndDialog (hwndDlg, lw);
return 1;
}
if (lw == IDC_CONTINUE)
{
wchar_t szTemp[4096];
pVolExpandParam->bInitFreeSpace = IsButtonChecked (GetDlgItem (hwndDlg, IDC_INIT_NEWSPACE));
pVolExpandParam->bQuickExpand = IsButtonChecked (GetDlgItem (hwndDlg, IDC_QUICKEXPAND));
if (!pVolExpandParam->bIsDevice) // for devices new size is set by calling function
{
GetWindowText (GetDlgItem (hwndDlg, IDC_SIZEBOX), szTemp, ARRAYSIZE (szTemp));
pVolExpandParam->newSize = _wtoi64(szTemp) * GetSizeBoxMultiplier(hwndDlg);
}
EndDialog (hwndDlg, lw);
return 1;
}
if (lw == IDC_INIT_NEWSPACE && !pVolExpandParam->bDisableQuickExpand)
{
HandleQuickExpanddCheckBox (hwndDlg);
return 1;
}
if (lw == IDC_QUICKEXPAND && IsButtonChecked (GetDlgItem (hwndDlg, IDC_QUICKEXPAND)))
{
// If quick expand selected, then we warn about security issue
if (MessageBoxW (hwndDlg, GetString ("QUICK_EXPAND_WARNING"),
lpszTitle, YES_NO|MB_ICONWARNING|MB_DEFBUTTON2) == IDNO)
{
SendDlgItemMessage (hwndDlg, IDC_QUICKEXPAND, BM_SETCHECK, BST_UNCHECKED, 0);
return 1;
}
}
return 0;
}
return 0;
}
extern "C" void AddProgressDlgStatus(HWND hwndDlg, const wchar_t* szText)
{
HWND hwndCtrl;
hwndCtrl = GetDlgItem (hwndDlg,IDC_BOX_STATUS);
SendMessage(hwndCtrl,EM_REPLACESEL,FALSE,(LPARAM)szText);
SendMessage(hwndCtrl,EM_SCROLLCARET,0,0);
}
extern "C" void SetProgressDlgStatus(HWND hwndDlg, const wchar_t* szText)
{
HWND hwndCtrl;
hwndCtrl = GetDlgItem (hwndDlg,IDC_BOX_STATUS);
SendMessage(hwndCtrl,EM_SETSEL,0,-1);
SendMessage(hwndCtrl,EM_REPLACESEL,FALSE,(LPARAM)szText);
SendMessage(hwndCtrl,EM_SCROLLCARET,0,0);
}
BOOL CALLBACK ExpandVolProgressDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
static EXPAND_VOL_THREAD_PARAMS *pProgressDlgParam;
static BOOL bVolTransformStarted = FALSE;
static BOOL showRandPool = TRUE;
static unsigned char randPool[16];
static unsigned char maskRandPool [16];
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;
WORD lw = LOWORD (wParam);
switch (msg)
{
case WM_INITDIALOG:
{
wchar_t szOldHostSize[512], szNewHostSize[512];
HCRYPTPROV hRngProv;
pProgressDlgParam = (EXPAND_VOL_THREAD_PARAMS*)lParam;
bVolTransformStarted = FALSE;
showRandPool = FALSE;
hCurPage = hwndDlg;
nPbar = IDC_PROGRESS_BAR;
VirtualLock (randPool, sizeof(randPool));
VirtualLock (&mouseEntropyGathered, sizeof(mouseEntropyGathered));
VirtualLock (maskRandPool, sizeof(maskRandPool));
LocalizeDialog (hwndDlg, NULL);
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);
}
GetSpaceString(szOldHostSize,sizeof(szOldHostSize),pProgressDlgParam->oldSize,pProgressDlgParam->bIsDevice);
GetSpaceString(szNewHostSize,sizeof(szNewHostSize),pProgressDlgParam->newSize,pProgressDlgParam->bIsDevice);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_OLDSIZE), szOldHostSize);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_NEWSIZE), szNewHostSize);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_NAME), pProgressDlgParam->szVolumeName);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_FILE_SYSTEM), szFileSystemStr[pProgressDlgParam->FileSystem]);
SetWindowText (GetDlgItem (hwndDlg, IDC_EXPAND_VOLUME_INITSPACE), pProgressDlgParam->bInitFreeSpace?GetString("UISTR_YES"):GetString("UISTR_NO"));
SendMessage (GetDlgItem (hwndDlg, IDC_BOX_STATUS), WM_SETFONT, (WPARAM) hBoldFont, (LPARAM) TRUE);
SendMessage (GetDlgItem (hwndDlg, IDC_RANDOM_BYTES), WM_SETFONT, (WPARAM) hFixedDigitFont, (LPARAM) TRUE);
// set status text
if ( !pProgressDlgParam->bInitFreeSpace && pProgressDlgParam->bIsLegacy )
{
showRandPool = FALSE;
EnableWindow (GetDlgItem (hwndDlg, IDC_DISPLAY_POOL_CONTENTS), FALSE);
EnableWindow (GetDlgItem (hwndDlg, IDC_RANDOM_BYTES), FALSE);
SetDlgItemText(hwndDlg, IDC_BOX_STATUS, GetString("EXPANDER_STATUS_TEXT_LEGACY"));
}
else
{
SetDlgItemText(hwndDlg, IDC_BOX_STATUS, GetString("EXPANDER_STATUS_TEXT"));
}
SendMessage (GetDlgItem (hwndDlg, IDC_DISPLAY_POOL_CONTENTS), BM_SETCHECK, BST_UNCHECKED, 0);
hEntropyBar = GetDlgItem (hwndDlg, IDC_ENTROPY_BAR);
SendMessage (hEntropyBar, PBM_SETRANGE32, 0, maxEntropyLevel);
SendMessage (hEntropyBar, PBM_SETSTEP, 1, 0);
SetTimer (hwndDlg, TIMER_ID_RANDVIEW, TIMER_INTERVAL_RANDVIEW, NULL);
}
return 0;
case TC_APPMSG_VOL_TRANSFORM_THREAD_ENDED:
{
int nStatus = (int)lParam;
NormalCursor ();
if (nStatus != 0)
{
if ( nStatus != ERR_USER_ABORT )
AddProgressDlgStatus (hwndDlg, GetString("EXPANDER_FINISH_ERROR"));
else
AddProgressDlgStatus (hwndDlg, GetString("EXPANDER_FINISH_ABORT"));
}
else
{
AddProgressDlgStatus (hwndDlg, GetString("EXPANDER_FINISH_OK"));
}
SetWindowText (GetDlgItem (hwndDlg, IDC_CONTINUE), GetString("EXIT"));
EnableWindow (GetDlgItem (hwndDlg, IDC_CONTINUE), TRUE);
EnableWindow (GetDlgItem (hwndDlg, IDCANCEL), FALSE);
}
return 1;
case WM_TIMER:
switch (wParam)
{
case TIMER_ID_RANDVIEW:
{
wchar_t szRndPool[64] = {0};
DWORD mouseEventsCounter;
RandpeekBytes (hwndDlg, randPool, sizeof (randPool),&mouseEventsCounter);
ProcessEntropyEstimate (hEntropyBar, &mouseEventsInitialCount, mouseEventsCounter, maxEntropyLevel, &mouseEntropyGathered);
if (showRandPool)
StringCbPrintfW (szRndPool, sizeof(szRndPool), L"%08X%08X%08X%08X",
*((DWORD*) (randPool + 12)), *((DWORD*) (randPool + 8)), *((DWORD*) (randPool + 4)), *((DWORD*) (randPool)));
else if (bUseMask)
{
for (int i = 0; i < 16; i++)
{
wchar_t tmp2[3];
unsigned char tmpByte = randPool[i] ^ maskRandPool[i];
tmp2[0] = (wchar_t) (((tmpByte >> 4) % 6) + L'*');
tmp2[1] = (wchar_t) (((tmpByte & 0x0F) % 6) + L'*');
tmp2[2] = 0;
StringCbCatW (szRndPool, sizeof(szRndPool), tmp2);
}
}
else
{
wmemset (szRndPool, L'*', 32);
}
SetWindowText (GetDlgItem (hwndDlg, IDC_RANDOM_BYTES), szRndPool);
burn (randPool, sizeof(randPool));
burn (szRndPool, sizeof(szRndPool));
}
return 1;
}
return 0;
case WM_COMMAND:
if (lw == IDC_DISPLAY_POOL_CONTENTS)
{
showRandPool = IsButtonChecked (GetDlgItem (hwndDlg, IDC_DISPLAY_POOL_CONTENTS));
return 1;
}
if (lw == IDCANCEL)
{
if (bVolTransformStarted)
{
if (MessageBoxW (hwndDlg, GetString("EXPANDER_CANCEL_WARNING"), lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
return 1;
// tell the volume transform thread to terminate
bVolTransformThreadCancel = TRUE;
}
NormalCursor ();
EndDialog (hwndDlg, lw);
return 1;
}
if (lw == IDC_CONTINUE)
{
if (bVolTransformStarted)
{
// TransformThreadFunction finished -> OK button is now exit
NormalCursor ();
EndDialog (hwndDlg, lw);
}
else
{
showRandPool = FALSE;
KillTimer (hwndDlg, TIMER_ID_RANDVIEW);
EnableWindow (GetDlgItem (hwndDlg, IDC_DISPLAY_POOL_CONTENTS), FALSE);
EnableWindow (GetDlgItem (hwndDlg, IDC_CONTINUE), FALSE);
SetProgressDlgStatus (hwndDlg, GetString("EXPANDER_STARTING_STATUS"));
bVolTransformStarted = TRUE;
pProgressDlgParam->hwndDlg = hwndDlg;
if ( _beginthread (volTransformThreadFunction, 0, pProgressDlgParam) == -1L )
{
handleError (hwndDlg, ERR_OS_ERROR, SRC_POS);
EndDialog (hwndDlg, lw);
}
WaitCursor();
}
return 1;
}
return 0;
case WM_NCDESTROY:
burn (randPool, sizeof (randPool));
burn (&mouseEventsInitialCount, sizeof(mouseEventsInitialCount));
burn (&mouseEntropyGathered, sizeof(mouseEntropyGathered));
burn (maskRandPool, sizeof(maskRandPool));
return 0;
case WM_DESTROY:
DetachProtectionFromCurrentThread();
break;
}
return 0;
}
typedef struct
{
OpenVolumeContext *context;
const wchar_t *volumePath;
Password *password;
int pkcs5_prf;
int pim;
BOOL write;
BOOL preserveTimestamps;
BOOL useBackupHeader;
int* nStatus;
} OpenVolumeThreadParam;
void CALLBACK OpenVolumeWaitThreadProc(void* pArg, HWND hwndDlg)
{
OpenVolumeThreadParam* pThreadParam = (OpenVolumeThreadParam*) pArg;
*(pThreadParam)->nStatus = OpenVolume(pThreadParam->context, pThreadParam->volumePath, pThreadParam->password, pThreadParam->pkcs5_prf,
pThreadParam->pim, pThreadParam->write, pThreadParam->preserveTimestamps, pThreadParam->useBackupHeader);
}
/*
ExpandVolumeWizard
Expands a trucrypt volume (wizard for user interface)
Parameters:
hwndDlg : HWND
[in] handle to parent window (if any)
szVolume : char *
[in] Pointer to a string with the volume name (e.g. '\Device\Harddisk0\Partition1' or 'C:\topsecret.tc')
Return value:
none
*/
void ExpandVolumeWizard (HWND hwndDlg, wchar_t *lpszVolume)
{
int nStatus = ERR_OS_ERROR;
wchar_t szTmp[4096];
Password VolumePassword;
int VolumePkcs5 = 0, VolumePim = -1;
uint64 hostSize, volSize, hostSizeFree, maxSizeFS;
BOOL bIsDevice, bIsLegacy;
DWORD dwError;
int driveNo;
enum EV_FileSystem volFSType;
wchar_t rootPath[] = L"A:\\";
switch (IsSystemDevicePath (lpszVolume, hwndDlg, TRUE))
{
case 1:
case 2:
MessageBoxW (hwndDlg, GetString("EXPANDER_SYSTEM_VOLUME_ERROR"), lpszTitle, MB_OK|MB_ICONEXCLAMATION);
goto ret;
}
EnableElevatedCursorChange (hwndDlg);
WaitCursor();
if (IsMountedVolume (lpszVolume))
{
Warning ("UNMOUNT_FIRST", hwndDlg);
goto ret;
}
if (Randinit() != ERR_SUCCESS) {
if (CryptoAPILastError == ERROR_SUCCESS)
nStatus = ERR_RAND_INIT_FAILED;
else
nStatus = ERR_CAPI_INIT_FAILED;
goto error;
}
NormalCursor();
// Ask the user if there is a hidden volume
char *volTypeChoices[] = {0, "DOES_VOLUME_CONTAIN_HIDDEN", "VOLUME_CONTAINS_HIDDEN", "VOLUME_DOES_NOT_CONTAIN_HIDDEN", "IDCANCEL", 0};
switch (AskMultiChoice ((void **) volTypeChoices, FALSE, hwndDlg))
{
case 1:
MessageBoxW (hwndDlg, GetString("EXPANDER_HIDDEN_VOLUME_ERROR"), lpszTitle, MB_OK|MB_ICONEXCLAMATION);
goto ret;
case 2:
break;
default:
nStatus = ERR_SUCCESS;
goto ret;
}
WaitCursor();
nStatus = QueryVolumeInfo(hwndDlg,lpszVolume,&hostSizeFree,&maxSizeFS);
if (nStatus!=ERR_SUCCESS)
{
nStatus = ERR_OS_ERROR;
goto error;
}
NormalCursor();
while (TRUE)
{
OpenVolumeContext expandVol;
if (!VeraCryptExpander::ExtcvAskVolumePassword (hwndDlg, lpszVolume, &VolumePassword, &VolumePkcs5, &VolumePim, "ENTER_NORMAL_VOL_PASSWORD", FALSE))
{
goto ret;
}
EnableElevatedCursorChange (hwndDlg);
WaitCursor();
if (KeyFilesEnable && FirstKeyFile)
KeyFilesApply (hwndDlg, &VolumePassword, FirstKeyFile, lpszVolume);
OpenVolumeThreadParam threadParam;
threadParam.context = &expandVol;
threadParam.volumePath = lpszVolume;
threadParam.password = &VolumePassword;
threadParam.pkcs5_prf = VolumePkcs5;
threadParam.pim = VolumePim;
threadParam.write = FALSE;
threadParam.preserveTimestamps = bPreserveTimestamp;
threadParam.useBackupHeader = FALSE;
threadParam.nStatus = &nStatus;
ShowWaitDialog (hwndDlg, TRUE, OpenVolumeWaitThreadProc, &threadParam);
NormalCursor ();
dwError = GetLastError();
if (nStatus == ERR_SUCCESS)
{
bIsDevice = expandVol.IsDevice;
bIsLegacy = expandVol.CryptoInfo->LegacyVolume;
hostSize = expandVol.HostSize;
VolumePkcs5 = expandVol.CryptoInfo->pkcs5;
if ( bIsLegacy )
{
if ( bIsDevice )
volSize = 0; // updated later
else
volSize = hostSize;
}
else
{
volSize = GetVolumeSizeByDataAreaSize (expandVol.CryptoInfo->VolumeSize.Value, bIsLegacy);
}
CloseVolume (&expandVol);
break;
}
else if (nStatus != ERR_PASSWORD_WRONG)
{
SetLastError (dwError);
goto error;
}
NormalCursor();
handleError (hwndDlg, nStatus, SRC_POS);
}
WaitCursor();
// auto mount the volume to check the file system type
nStatus=MountVolTemp(hwndDlg, lpszVolume, &driveNo, &VolumePassword, VolumePkcs5, VolumePim);
if (nStatus != ERR_SUCCESS)
goto error;
rootPath[0] += driveNo;
if ( !GetFileSystemType(rootPath,&volFSType) )
volFSType = EV_FS_TYPE_RAW;
if ( bIsLegacy && bIsDevice && volFSType == EV_FS_TYPE_NTFS )
{
uint64 NumberOfSectors;
DWORD BytesPerSector;
if ( !GetNtfsNumberOfSectors(rootPath, &NumberOfSectors, &BytesPerSector) )
nStatus = ERR_OS_ERROR;
// NTFS reported size does not include boot sector copy at volume end
volSize = ( NumberOfSectors + 1 ) * BytesPerSector;
}
UnmountVolume (hwndDlg, driveNo, TRUE);
NormalCursor();
if (nStatus != ERR_SUCCESS)
goto error;
if ( bIsDevice && bIsLegacy && volFSType != EV_FS_TYPE_NTFS )
{
MessageBoxW (hwndDlg,
L"Expanding a device hosted legacy volume with no NTFS file system\n"
L"is unsupported.\n"
L"Note that expanding the VeraCrypt volume itself is not neccessary\n"
L"for legacy volumes.\n",
lpszTitle, MB_OK|MB_ICONEXCLAMATION);
goto ret;
}
// check if there is enough free space on host device/drive to expand the volume
if ( (bIsDevice && hostSize < volSize + TC_MINVAL_FS_EXPAND) || (!bIsDevice && hostSizeFree < TC_MINVAL_FS_EXPAND) )
{
MessageBoxW (hwndDlg, GetString("EXPANDER_NO_FREE_SPACE"), lpszTitle, MB_OK|MB_ICONEXCLAMATION);
goto ret;
}
if (!bIsDevice && hostSize != volSize ) {
// there is some junk data at the end of the volume
if (MessageBoxW (hwndDlg, GetString("EXPANDER_WARNING_FILE_CONTAINER_JUNK"), lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
goto ret;
}
switch (volFSType)
{
case EV_FS_TYPE_NTFS:
break;
case EV_FS_TYPE_FAT:
if (MessageBoxW (hwndDlg, GetString("EXPANDER_WARNING_FAT"),
lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
goto ret;
break;
case EV_FS_TYPE_EXFAT:
if (MessageBoxW (hwndDlg, GetString("EXPANDER_WARNING_EXFAT"),
lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
goto ret;
break;
default:
if (MessageBoxW (hwndDlg, GetString("EXPANDER_WARNING_UNKNOWN_FS"),
lpszTitle, YES_NO|MB_ICONQUESTION|MB_DEFBUTTON2) == IDNO)
goto ret;
}
EXPAND_VOL_THREAD_PARAMS VolExpandParam;
VolExpandParam.bInitFreeSpace = (bIsLegacy && bIsDevice) ? FALSE:TRUE;
VolExpandParam.bQuickExpand = FALSE;
VolExpandParam.bDisableQuickExpand = bIsDevice;
VolExpandParam.szVolumeName = lpszVolume;
VolExpandParam.FileSystem = volFSType;
VolExpandParam.pVolumePassword = &VolumePassword;
VolExpandParam.VolumePkcs5 = VolumePkcs5;
VolExpandParam.VolumePim = VolumePim;
VolExpandParam.bIsDevice = bIsDevice;
VolExpandParam.bIsLegacy = bIsLegacy;
VolExpandParam.oldSize = bIsDevice ? volSize : hostSize;
VolExpandParam.newSize = hostSize;
VolExpandParam.hostSizeFree = hostSizeFree;
// disable Quick Expand if the file is sparse or compressed
if (!bIsDevice)
{
DWORD dwFileAttrib = GetFileAttributesW (lpszVolume);
if (INVALID_FILE_ATTRIBUTES != dwFileAttrib)
{
if (dwFileAttrib & (FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_SPARSE_FILE))
VolExpandParam.bDisableQuickExpand = TRUE;
}
}
while (1)
{
uint64 newVolumeSize;
if (IDCANCEL == DialogBoxParamW (hInst,
MAKEINTRESOURCEW (IDD_SIZE_DIALOG), hwndDlg,
(DLGPROC) ExpandVolSizeDlgProc, (LPARAM) &VolExpandParam))
{
goto ret;
}
newVolumeSize = VolExpandParam.newSize;
if ( !bIsDevice )
{
if ( (newVolumeSize < hostSize + TC_MINVAL_FS_EXPAND) && ((hostSize == volSize) || (newVolumeSize != hostSize) || ((hostSize - volSize) < TC_MINVAL_FS_EXPAND)))
{
StringCbPrintfW(szTmp,sizeof(szTmp),GetString("EXPANDER_ERROR_VOLUME_SIZE_TOO_SMALL"),TC_MINVAL_FS_EXPAND/BYTES_PER_KB);
MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_OK | MB_ICONEXCLAMATION );
continue;
}
if ( newVolumeSize - hostSize > hostSizeFree )
{
StringCbPrintfW(szTmp,sizeof(szTmp), GetString("EXPANDER_ERROR_VOLUME_SIZE_TOO_LARGE"));
MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_OK | MB_ICONEXCLAMATION );
continue;
}
if ( newVolumeSize>maxSizeFS )
{
StringCbPrintfW(szTmp,sizeof(szTmp), GetString("EXPANDER_ERROR_MAX_FILE_SIZE_EXCEEDED"),maxSizeFS/BYTES_PER_MB);
MessageBoxW (hwndDlg, L"!\n",lpszTitle, MB_OK | MB_ICONEXCLAMATION );
continue;
}
if (VolExpandParam.bQuickExpand && !bSeManageVolumeNameSet)
{
if (!SetPrivilege (SE_MANAGE_VOLUME_NAME, TRUE))
{
MessageBoxW (hwndDlg, GetString("EXPANDER_ERROR_QUICKEXPAND_PRIVILEGES"),lpszTitle, MB_OK | MB_ICONEXCLAMATION );
VolExpandParam.bQuickExpand = FALSE;
continue;
}
bSeManageVolumeNameSet = TRUE;
}
}
if ( newVolumeSize > TC_MAX_VOLUME_SIZE )
{
// note: current limit TC_MAX_VOLUME_SIZE is 1 PetaByte
StringCbPrintfW(szTmp,sizeof(szTmp), GetString("EXPANDER_ERROR_MAX_VC_VOLUME_SIZE_EXCEEDED"),TC_MAX_VOLUME_SIZE/BYTES_PER_TB);
MessageBoxW (hwndDlg, szTmp,lpszTitle, MB_OK | MB_ICONEXCLAMATION );
if (bIsDevice)
break; // TODO: ask to limit volume size to TC_MAX_VOLUME_SIZE
continue;
}
break;
}
VolExpandParam.oldSize = volSize;
// start progress dialog
DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_EXPAND_PROGRESS_DLG), hwndDlg,
(DLGPROC) ExpandVolProgressDlgProc, (LPARAM) &VolExpandParam );
ret:
nStatus = ERR_SUCCESS;
error:
if (nStatus != 0)
handleError (hwndDlg, nStatus, SRC_POS);
burn (&VolumePassword, sizeof (VolumePassword));
RestoreDefaultKeyFilesParam();
RandStop (FALSE);
NormalCursor();
return;
}