/* 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-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 "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_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; } 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 ("DISMOUNT_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; }