/* 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 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 #include #include #include #include #include #include #include #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; }