From f72125ea71f98d0147bb742b48d1097844949c9e Mon Sep 17 00:00:00 2001 From: Mounir IDRASSI Date: Sun, 17 May 2015 12:14:58 +0200 Subject: Windows: First implementation of non-system volumes decryption. --- src/Common/Cmdline.c | 2 + src/Common/Common.rc | 18 +- src/Common/Dlgcode.c | 108 ++++++++- src/Common/Dlgcode.h | 11 +- src/Common/Language.xml | 51 +++-- src/Common/Volumes.h | 2 +- src/Format/Format.rc | 19 +- src/Format/InPlace.c | 578 +++++++++++++++++++++++++++++++++++++++++++++++- src/Format/InPlace.h | 5 +- src/Format/Resource.h | 7 +- src/Format/Tcformat.c | 488 +++++++++++++++++++++++++++++++++++----- src/Format/Tcformat.h | 2 + src/Mount/Mount.c | 376 +++++++++++++++++++++++++++++-- src/Mount/Mount.h | 2 +- src/Mount/Mount.rc | 1 + src/Mount/Resource.h | 3 +- 16 files changed, 1557 insertions(+), 116 deletions(-) diff --git a/src/Common/Cmdline.c b/src/Common/Cmdline.c index 178d938e..842a1e4c 100644 --- a/src/Common/Cmdline.c +++ b/src/Common/Cmdline.c @@ -55,6 +55,8 @@ BOOL CALLBACK CommandHelpDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM } } + StringCbCatA (tmp, 8192, "\nExamples:\n\nMount a volume as X:\tveracrypt.exe /q /v volume.tc /l X\nDismount a volume X:\tveracrypt.exe /q /d X"); + SetWindowText (GetDlgItem (hwndDlg, IDC_COMMANDHELP_TEXT), (char*) tmp); TCfree(tmp); diff --git a/src/Common/Common.rc b/src/Common/Common.rc index 40b09bfc..1fba8899 100644 --- a/src/Common/Common.rc +++ b/src/Common/Common.rc @@ -36,23 +36,23 @@ BEGIN DEFPUSHBUTTON "OK",IDOK,230,178,52,14 LTEXT "",IDC_HOMEPAGE,18,87,117,9,SS_NOTIFY LTEXT "",IDT_ABOUT_RELEASE,18,71,235,8 - CONTROL 517,IDC_ABOUT_BKG,"Static",SS_BITMAP,0,0,12,11,WS_EX_STATICEDGE + CONTROL IDB_TEXTUAL_LOGO_BKG,IDC_ABOUT_BKG,"Static",SS_BITMAP,0,0,12,11,WS_EX_STATICEDGE LTEXT "",IDT_ABOUT_VERSION,18,61,161,8 CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,167,291,1,WS_EX_STATICEDGE CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,169,291,1,WS_EX_STATICEDGE CONTROL "",IDC_STATIC,"Static",SS_ETCHEDHORZ,1,107,291,1,WS_EX_STATICEDGE CONTROL "",IDC_ABOUT_LOGO_AREA,"Static",SS_GRAYRECT | NOT WS_VISIBLE,0,0,293,50,WS_EX_TRANSPARENT | WS_EX_STATICEDGE - CONTROL 518,IDC_TEXTUAL_LOGO_IMG,"Static",SS_BITMAP,12,26,157,16 + CONTROL IDB_TEXTUAL_LOGO_96DPI,IDC_TEXTUAL_LOGO_IMG,"Static",SS_BITMAP,12,26,157,16 END -IDD_COMMANDHELP_DLG DIALOGEX 0, 0, 249, 213 +IDD_COMMANDHELP_DLG DIALOGEX 0, 0, 249, 234 STYLE DS_SETFONT | DS_MODALFRAME | DS_3DLOOK | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Command Line Help" CLASS "VeraCryptCustomDlg" FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN - DEFPUSHBUTTON "OK",IDOK,93,191,59,14 - LTEXT "",IDC_COMMANDHELP_TEXT,20,11,208,174 + DEFPUSHBUTTON "OK",IDOK,93,212,59,14 + LTEXT "",IDC_COMMANDHELP_TEXT,20,11,208,195 END IDD_RAWDEVICES_DLG DIALOGEX 0, 0, 305, 209 @@ -221,7 +221,7 @@ BEGIN END IDD_MULTI_CHOICE_DLG DIALOGEX 0, 0, 167, 322 -STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN PUSHBUTTON "",IDC_CHOICE10,7,292,153,24,BS_CENTER | BS_MULTILINE,WS_EX_STATICEDGE @@ -327,9 +327,13 @@ END #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO BEGIN + IDD_ABOUT_DLG, DIALOG + BEGIN + END + IDD_COMMANDHELP_DLG, DIALOG BEGIN - BOTTOMMARGIN, 205 + BOTTOMMARGIN, 226 END IDD_RAWDEVICES_DLG, DIALOG diff --git a/src/Common/Dlgcode.c b/src/Common/Dlgcode.c index 673da461..b433aa04 100644 --- a/src/Common/Dlgcode.c +++ b/src/Common/Dlgcode.c @@ -52,6 +52,7 @@ #ifdef TCMOUNT #include "Mount/Mount.h" +#include "Mount/resource.h" #endif #ifdef VOLFORMAT @@ -845,6 +846,17 @@ void AccommodateTextField (HWND hwndDlg, UINT ctrlId, BOOL bFirstUpdate, HFONT h } } +// Note that the user can still close the window by right-clicking its taskbar icon and selecting 'Close window', or by pressing Alt-F4, or using the Task Manager. +void DisableCloseButton (HWND hwndDlg) +{ + EnableMenuItem (GetSystemMenu (hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); +} + + +void EnableCloseButton (HWND hwndDlg) +{ + EnableMenuItem (GetSystemMenu (hwndDlg, FALSE), SC_CLOSE, MF_BYCOMMAND | MF_ENABLED); +} // Protects an input field from having its content updated by a Paste action (call ToBootPwdField() to use this). static LRESULT CALLBACK BootPwdFieldProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -2787,6 +2799,61 @@ int IsSystemDevicePath (const char *path, HWND hwndDlg, BOOL bReliableRequired) } +/* Determines whether the path points to a non-system partition on the system drive. +IMPORTANT: As this may take a very long time if called for the first time, it should be called + only before performing a dangerous operation, never at WM_INITDIALOG or any other GUI events. +Return codes: +0 - it isn't a non-system partition on the system drive +1 - it's a non-system partition on the system drive +-1 - the result can't be determined, isn't reliable, or there was an error. */ +int IsNonSysPartitionOnSysDrive (const char *path) +{ + char tmpPath [TC_MAX_PATH + 1]; + int pos; + + if (!GetSysDevicePaths (MainDlg)) + return -1; + + if (strlen (SysPartitionDevicePath) <= 1 || strlen (SysDriveDevicePath) <= 1) + return -1; + + if (strncmp (path, SysPartitionDevicePath, max (strlen(path), strlen(SysPartitionDevicePath))) == 0 + || strncmp (path, SysDriveDevicePath, max (strlen(path), strlen(SysDriveDevicePath))) == 0) + { + // It is the system partition/drive path (it isn't a non-system partition) + return 0; + } + + memset (tmpPath, 0, sizeof (tmpPath)); + strncpy (tmpPath, path, sizeof (tmpPath) - 1); + + + pos = (int) FindString (tmpPath, "Partition", strlen (tmpPath), strlen ("Partition"), 0); + + if (pos < 0) + return -1; + + pos += strlen ("Partition"); + + if (pos + 1 > sizeof (tmpPath) - 1) + return -1; + + tmpPath [pos] = '0'; + tmpPath [pos + 1] = 0; + + if (strncmp (tmpPath, SysDriveDevicePath, max (strlen(tmpPath), strlen(SysDriveDevicePath))) == 0) + { + // It is a non-system partition on the system drive + return 1; + } + else + { + // The partition is not on the system drive + return 0; + } +} + + wstring GetSysEncryptionPretestInfo2String (void) { // This huge string is divided into smaller portions to make it easier for translators to @@ -3990,7 +4057,10 @@ std::wstring GetWrongPasswordErrorMessage (HWND hwndDlg) StringCbCatW (szTmp, sizeof(szTmp), GetString ("PASSWORD_WRONG_CAPSLOCK_ON")); #ifdef TCMOUNT - if (TCBootLoaderOnInactiveSysEncDrive ()) + char szDevicePath [TC_MAX_PATH+1] = {0}; + GetWindowText (GetDlgItem (MainDlg, IDC_VOLUME), szDevicePath, sizeof (szDevicePath)); + + if (TCBootLoaderOnInactiveSysEncDrive (szDevicePath)) { StringCbPrintfW (szTmp, sizeof(szTmp), GetString (KeyFilesEnable ? "PASSWORD_OR_KEYFILE_OR_MODE_WRONG" : "PASSWORD_OR_MODE_WRONG")); @@ -6005,6 +6075,8 @@ BOOL CALLBACK MultiChoiceDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPA wrec.bottom - wrec.top - vertSubOffset + 1 + vertMsgHeightOffset, TRUE); + DisableCloseButton (hwndDlg); + return 1; } @@ -6027,7 +6099,8 @@ BOOL CALLBACK MultiChoiceDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPA break; case WM_CLOSE: - EndDialog (hwndDlg, 0); + // 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; } @@ -8335,6 +8408,11 @@ int AskNoYes (char *stringId, HWND hwnd) 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) { @@ -8425,8 +8503,7 @@ int AskErrNoYes (char *stringId, HWND hwnd) // Input format 2: {L"", L"Message text", L"Button caption 1", ... L"Last button caption", 0}; // The second format is to be used if any of the strings contains format specification (e.g. %s, %d) or // in any other cases where a string needs to be resolved before calling this function. -// If the returned value is 0, the user closed the dialog window without making a choice. -// If the user made a choice, the returned value is the ordinal number of the choice (1..MAX_MULTI_CHOICES) +// 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; @@ -10270,10 +10347,29 @@ BOOL BufferContainsString (const byte *buffer, size_t bufferSize, const char *st #ifndef SETUP -int AskNonSysInPlaceEncryptionResume (HWND hwndDlg) +int AskNonSysInPlaceEncryptionResume (HWND hwndDlg, BOOL *pbDecrypt) { if (AskWarnYesNo ("NONSYS_INPLACE_ENC_RESUME_PROMPT", hwndDlg) == IDYES) - return 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 }; diff --git a/src/Common/Dlgcode.h b/src/Common/Dlgcode.h index 1c792e7c..115a3b85 100644 --- a/src/Common/Dlgcode.h +++ b/src/Common/Dlgcode.h @@ -128,6 +128,10 @@ extern WipeAlgorithmId nWipeMode; extern BOOL bSysPartitionSelected; extern BOOL bSysDriveSelected; +extern char SysPartitionDevicePath [TC_MAX_PATH]; +extern char SysDriveDevicePath [TC_MAX_PATH]; +extern char bCachedSysDevicePathsValid; + extern BOOL bHyperLinkBeingTracked; extern BOOL bInPlaceEncNonSysPending; @@ -296,6 +300,7 @@ void NotifyDriverOfPortableMode (void); int GetAvailableFixedDisks ( HWND hComboBox , char *lpszRootPath ); int GetAvailableRemovables ( HWND hComboBox , char *lpszRootPath ); int IsSystemDevicePath (const char *path, HWND hwndDlg, BOOL bReliableRequired); +int IsNonSysPartitionOnSysDrive (const char *path); BOOL CALLBACK RawDevicesDlgProc ( HWND hwndDlg , UINT msg , WPARAM wParam , LPARAM lParam ); BOOL TextInfoDialogBox (int nID); BOOL CALLBACK TextInfoDialogBoxDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); @@ -394,6 +399,7 @@ int AskYesNo (char *stringId, HWND hwnd); int AskYesNoString (const wchar_t *str, HWND hwnd); int AskYesNoTopmost (char *stringId, HWND hwnd); int AskNoYes (char *stringId, HWND hwnd); +int AskNoYesString (const wchar_t *string, HWND hwnd); int AskOkCancel (char *stringId, HWND hwnd); int AskWarnYesNo (char *stringId, HWND hwnd); int AskWarnYesNoString (const wchar_t *string, HWND hwnd); @@ -446,9 +452,12 @@ int GetTextGfxWidth (HWND hwndDlgItem, const wchar_t *text, HFONT hFont); int GetTextGfxHeight (HWND hwndDlgItem, const wchar_t *text, HFONT hFont); BOOL ToHyperlink (HWND hwndDlg, UINT ctrlId); BOOL ToCustHyperlink (HWND hwndDlg, UINT ctrlId, HFONT hFont); +void DisableCloseButton (HWND hwndDlg); +void EnableCloseButton (HWND hwndDlg); void ToBootPwdField (HWND hwndDlg, UINT ctrlId); void AccommodateTextField (HWND hwndDlg, UINT ctrlId, BOOL bFirstUpdate, HFONT hFont); BOOL GetDriveLabel (int driveNo, wchar_t *label, int labelSize); +BOOL GetSysDevicePaths (HWND hwndDlg); BOOL DoDriverInstall (HWND hwndDlg); int OpenVolume (OpenVolumeContext *context, const char *volumePath, Password *password, int pkcs5_prf, BOOL truecryptMode, BOOL write, BOOL preserveTimestamps, BOOL useBackupHeader); void CloseVolume (OpenVolumeContext *context); @@ -463,7 +472,7 @@ BOOL FileHasReadOnlyAttribute (const char *path); BOOL IsFileOnReadOnlyFilesystem (const char *path); void CheckFilesystem (HWND hwndDlg, int driveNo, BOOL fixErrors); BOOL BufferContainsString (const byte *buffer, size_t bufferSize, const char *str); -int AskNonSysInPlaceEncryptionResume (HWND hwndDlg); +int AskNonSysInPlaceEncryptionResume (HWND hwndDlg, BOOL* pbDecrypt); BOOL RemoveDeviceWriteProtection (HWND hwndDlg, char *devicePath); void EnableElevatedCursorChange (HWND parent); BOOL DisableFileCompression (HANDLE file); diff --git a/src/Common/Language.xml b/src/Common/Language.xml index 4e5fd333..3feb51dd 100644 --- a/src/Common/Language.xml +++ b/src/Common/Language.xml @@ -72,6 +72,7 @@ IMPORTANT: Move your mouse as randomly as possible within this window. The longer you move it, the better. This significantly increases the cryptographic strength of the encryption keys. Then click Next to continue. &Confirm: Done + Drive letter: Encryption Algorithm Filesystem Creates a virtual encrypted disk within a file. Recommended for inexperienced users. @@ -202,6 +203,7 @@ Create Hidden Operating System... Create Rescue Disk... Create New Volume... + Permanently Decrypt... Default Keyfiles... Default Mount Parameters... Donate now... @@ -373,7 +375,7 @@ Error: Access denied.\n\nThe partition you are trying to access is either 0 sectors long, or it is the boot device. Administrator In order to load the VeraCrypt driver, you need to be logged into an account with administrator privileges. - Please note that in order to encrypt/format a partition/device you need to be logged into an account with administrator privileges.\n\nThis does not apply to file-hosted volumes. + Please note that in order to encrypt, decrypt or format a partition/device you need to be logged into an account with administrator privileges.\n\nThis does not apply to file-hosted volumes. In order to create a hidden volume you need to be logged into an account with administrator privileges.\n\nContinue? Please note that in order to format the volume as NTFS you need to be logged into an account with administrator privileges.\n\nWithout administrator privileges, you can format the volume as FAT. FIPS-approved cipher (Rijndael, published in 1998) that may be used by U.S. government departments and agencies to protect classified information up to the Top Secret level. 256-bit key, 128-bit block, 14 rounds (AES-256). Mode of operation is XTS. @@ -489,7 +491,11 @@ \n\nThe VeraCrypt volume has been created and is ready for use. If you wish to create another VeraCrypt volume, click Next. Otherwise, click Exit. \n\nThe hidden VeraCrypt volume has been successfully created (the hidden operating system will reside within this hidden volume).\n\nClick Next to continue. Volume Fully Encrypted + Volume Fully Decrypted IMPORTANT: TO MOUNT THIS NEWLY CREATED VERACRYPT VOLUME AND TO ACCESS DATA STORED IN IT, CLICK 'Auto-Mount Devices' IN THE MAIN VERACRYPT WINDOW. After you enter the correct password (and/or supply correct keyfiles), the volume will be mounted to the drive letter you select from the list in the main VeraCrypt window (and you will be able to access the encrypted data via the selected drive letter).\n\nPLEASE REMEMBER OR WRITE DOWN THE ABOVE STEPS. YOU MUST FOLLOW THEM WHENEVER YOU WANT TO MOUNT THE VOLUME AND ACCESS DATA STORED IN IT. Alternatively, in the main VeraCrypt window, click 'Select Device', then select this partition/volume, and click 'Mount'.\n\nThe partition/volume has been successfully encrypted (it contains a fully encrypted VeraCrypt volume now) and is ready for use. + The VeraCrypt volume has been successfully decrypted. + The VeraCrypt volume has been successfully decrypted.\n\nPlease select a drive letter that you wish to assign to the decrypted volume and then click Finish.\n\nIMPORTANT: Until a drive letter is assigned to the decrypted volume, you will not be able to access data stored on the volume. + Warning: To be able to access the decrypted data, a drive letter needs to be assigned to the decrypted volume. However, no drive letter is currently available.\n\nPlease vacate a drive letter (for example, by disconnecting a USB flash drive or external hard drive, etc.) and then click OK. The VeraCrypt volume has been successfully created. Volume Created IMPORTANT: Move your mouse as randomly as possible within this window. The longer you move it, the better. This significantly increases the cryptographic strength of the encryption keys. Then click Format to create the volume. @@ -548,6 +554,7 @@ Unable to connect to the VeraCrypt device driver. VeraCrypt cannot work if the device driver is not running.\n\nPlease note that, due to a Windows issue, it may be necessary to log off or restart the system before the device driver can be loaded. Error occurred when loading/preparing fonts. The drive letter was not found or no drive letter was specified. + Error: Cannot assign drive letter.\n\nUntil a drive letter is assigned to the decrypted volume, you will not be able to access data stored on the volume.\n\nRetry? Drive letter not available. No file selected! No drive letters available. @@ -567,7 +574,8 @@ WARNING: The file '%hs' already exists!\n\nIMPORTANT: VERACRYPT WILL NOT ENCRYPT THE FILE, BUT IT WILL DELETE IT. Are you sure you want to delete the file and replace it with a new VeraCrypt container? CAUTION: ALL FILES CURRENTLY STORED ON THE SELECTED %s '%hs'%s WILL BE ERASED AND LOST (THEY WILL NOT BE ENCRYPTED)!\n\nAre you sure you want to proceed with format? WARNING: You will not be able to mount the volume or access any files stored on it until it has been fully encrypted.\n\nAre you sure you want to start encrypting the selected %s '%hs'%s? - WARNING: Please note that if power supply is suddenly interrupted while encrypting existing data in place, or when the operating system crashes due to a software error or hardware malfunction while VeraCrypt is encrypting existing data in place, portions of the data will be corrupted or lost. Therefore, before you start encrypting, please make sure that you have backup copies of the files you want to encrypt.\n\nDo you have such a backup? + WARNING: You will not be able to mount the volume or access any files stored on it until it has been fully decrypted.\n\nAre you sure you want to start decrypting the selected %s '%hs'%s? + WARNING: Please note that if power supply is suddenly interrupted while encrypting/decrypting existing data in place, or when the operating system crashes due to a software error or hardware malfunction while VeraCrypt is encrypting/decrypting existing data in place, portions of the data will be corrupted or lost. Therefore, before you start encrypting/decrypting, please make sure that you have backup copies of the files you want to encrypt/decrypt.\n\nDo you have such a backup? CAUTION: ANY FILES CURRENTLY STORED ON THE PARTITION '%hs'%s (I.E. ON THE FIRST PARTITION BEHIND THE SYSTEM PARTITION) WILL BE ERASED AND LOST (THEY WILL NOT BE ENCRYPTED)!\n\nAre you sure you want to proceed with format? WARNING: THE SELECTED PARTITION CONTAINS A LARGE AMOUNT OF DATA! Any files stored on the partition will be erased and lost (they will NOT be encrypted)! Erase any files stored on the partition by creating a VeraCrypt volume within it @@ -582,8 +590,9 @@ Keyfile(s) successfully added/removed. Keyfile exported. Header key derivation algorithm successfully set. - Please enter the password and/or keyfile(s) for the non-system volume where you want to resume the process of in-place encryption.\n\n\nRemark: After you click Next, VeraCrypt will attempt to find all non-system volumes where the process of encryption has been interrupted and where the VeraCrypt volume header can be decrypted using the supplied password and/or keyfile(s). If more than one such volume is found, you will need to select one of them in the next step. - Please select one of the listed volumes. The list contains every accessible non-system volume where the process of encryption has been interrupted and whose header could be decrypted using the supplied password and/or keyfile(s). + Please enter the password and/or keyfile(s) for the non-system volume where you want to resume the process of in-place encryption/decryption.\n\nRemark: After you click Next, VeraCrypt will attempt to find all non-system volumes where the process of encryption/decryption has been interrupted and where the VeraCrypt volume header can be deciphered using the supplied password and/or keyfile(s). If more than one such volume is found, you will need to select one of them in the next step. + Please select one of the listed volumes. The list contains each accessible non-system volume where the process of encryption/decryption has been interrupted and where the volume header was successfully deciphered using the supplied password and/or keyfile(s). + Please enter the password and/or keyfile(s) for the non-system VeraCrypt volume that you want to decrypt. It is very important that you choose a good password. You should avoid choosing one that contains only a single word that can be found in a dictionary (or a combination of 2, 3, or 4 such words). It should not contain any names or dates of birth. It should not be easy to guess. A good password is a random combination of upper and lower case letters, numbers, and special characters, such as @ ^ = $ * + etc. We recommend choosing a password consisting of more than 20 characters (the longer, the better). The maximum possible length is 64 characters. Please choose a password for the hidden volume. Please choose a password for the hidden operating system (i.e. for the hidden volume). @@ -605,11 +614,13 @@ \n\nWarning: Caps Lock is on. This may cause you to enter your password incorrectly. \n\nWARNING: Hidden file(s) have been found in a keyfile search path. Such hidden files cannot be used as keyfiles. If you need to use them as keyfiles, remove their 'Hidden' attribute (right-click each of them, select 'Properties', uncheck 'Hidden' and click OK). Note: Hidden files are visible only if the corresponding option is enabled (Computer > Organize > 'Folder and search options' > View). If you are attempting to protect a hidden volume containing a hidden system, please make sure you are using the standard US keyboard layout when typing the password for the hidden volume. This is required due to the fact that the password needs to be typed in the pre-boot environment (before Windows starts) where non-US Windows keyboard layouts are not available. - VeraCrypt has not found any volume where non-system encryption has been interrupted and where the volume header can be decrypted using the supplied password and/or keyfile(s).\n\nPlease make sure the password and/or keyfile(s) are correct and that the partition/volume is not being used by the system or applications (including antivirus software). + VeraCrypt has not found any volume where the process of encryption/decryption of a non-system volume has been interrupted and where the volume header can be deciphered using the supplied password and/or keyfile(s).\n\nPlease make sure the password and/or keyfile(s) are correct and that the partition/volume is not being used by the system or applications (including antivirus software). The selected partition/device is already fully encrypted.\nHeader Flags = 0x%.8X The selected partition/device is not using in-place encryption.\nHeader Flags = 0x%.8X \n\nNote: If you are attempting to mount a partition located on an encrypted system drive without pre-boot authentication or to mount the encrypted system partition of an operating system that is not running, you can do so by selecting 'System' > 'Mount Without Pre-Boot Authentication'. In this mode, you cannot mount a partition located on a drive whose portion is within the key scope of active system encryption.\n\nBefore you can mount this partition in this mode, you need to either boot an operating system installed on a different drive (encrypted or unencrypted) or boot an unencrypted operating system. + VeraCrypt cannot decrypt an individual partition on an entirely encrypted system drive (you can decrypt only the entire system drive). + Warning: As the drive contains the VeraCrypt Boot Loader, it may be an entirely encrypted system drive. If it is, please note that VeraCrypt cannot decrypt an individual partition on an entirely encrypted system drive (you can decrypt only the entire system drive). If that is the case, you will be able to continue now but you will receive the 'Incorrect password' error message later. < &Back Unable to list raw devices installed on your system! The volume '%hs' exists, and is read-only. Are you sure you want to replace it? @@ -661,7 +672,7 @@ VeraCrypt cannot change the password for a foreign volume. Please select a free drive letter from the list. Please select a mounted volume in the drive letter list. - Two different mounted volumes are currently selected (one in the drive letter list and the other in the input field below the list).\n\nPlease choose the volume you wanted to select: + Warning: Two different volumes/devices are currently selected (the first is selected in the drive letter list and the second is selected in the input field below the drive letter list).\n\nPlease confirm your choice: Error: Cannot create autorun.inf Error while processing keyfile! Error processing keyfile path! @@ -709,11 +720,18 @@ For information on how to create and manage partitions, please refer to the documentation supplied with your operating system or contact your computer vendor's technical support team for assistance. Error: The currently running operating system is not installed on the boot partition (first Active partition). This is not supported. You indicated that you intend to store files larger than 4 GB in this VeraCrypt volume. However, you chose the FAT file system, on which files larger than 4 GB cannot be stored.\n\nAre you sure you want to format the volume as FAT? + Error: VeraCrypt does not support in-place decryption of legacy non-system volumes created by VeraCrypt 1.0b or earlier.\n\nNote: You can still decrypt files stored on the volume by copying/moving them to any unencrypted volume. + Error: VeraCrypt cannot in-place decrypt a hidden VeraCrypt volume.\n\nNote: You can still decrypt files stored on the volume by copying/moving them to any unencrypted volume. + Warning: Note that VeraCrypt cannot in-place decrypt a volume that contains a hidden VeraCrypt volume (the hidden volume would be overwritten with pseudorandom data).\n\nPlease confirm that the volume you are about to decrypt contains no hidden volume.\n\nNote: If the volume contains a hidden volume but you do not mind losing the hidden volume, you can select Proceed (the outer volume will be safely decrypted). + The volume does not contain any hidden volume. Proceed. + The volume contains a hidden volume. Cancel. Error: Cannot access the volume!\n\nMake sure that the selected volume exists, that it is not mounted or being used by the system or an application, that you have read/write permission for the volume, and that it is not write-protected. + Error: Cannot obtain volume properties. Error: Cannot access the volume and/or obtain information about the volume.\n\nMake sure that the selected volume exists, that it is not being used by the system or applications, that you have read/write permission for the volume, and that it is not write-protected. Error: Cannot access the volume and/or obtain information about the volume. Make sure that the selected volume exists, that it is not being used by the system or applications, that you have read/write permission for the volume, and that it is not write-protected.\n\nIf the problem persists, it might help to follow the below steps. An error prevented VeraCrypt from encrypting the partition. Please try fixing any previously reported problems and then try again. If the problems persist, it might help to follow the below steps. - An error prevented VeraCrypt from resuming the process of encryption of the partition.\n\nPlease try fixing any previously reported problems and then try resuming the process again. Note that the volume cannot be mounted until it has been fully encrypted. + An error prevented VeraCrypt from decrypting the volume. Please try fixing any previously reported problems and then try again if possible. + An error prevented VeraCrypt from resuming the process of encryption/decryption of the partition/volume.\n\nPlease try fixing any previously reported problems and then try resuming the process again if possible. Note that the volume cannot be mounted until it has been fully encrypted or fully decrypted. Error: Cannot dismount the outer volume!\n\nVolume cannot be dismounted if it contains files or folders being used by a program or the system.\n\nPlease close any program that might be using files or directories on the volume and click Retry. Error: Cannot obtain information about the outer volume!\nVolume creation cannot continue. Error: Cannot access the outer volume! Volume creation cannot continue. @@ -974,18 +992,19 @@ WARNING: If this option is disabled, volumes containing open files/directories will not be possible to auto-dismount.\n\nAre you sure you want to disable this option? WARNING: Volumes containing open files/directories will NOT be auto-dismounted.\n\nTo prevent this, enable the following option in this dialog window: 'Force auto-dismount even if volume contains open files or directories' WARNING: When the notebook battery power is low, Windows may omit sending the appropriate messages to running applications when the computer is entering power saving mode. Therefore, VeraCrypt may fail to auto-dismount volumes in such cases. - You have scheduled the process of encryption of a partition/volume. The process has not been completed yet.\n\nDo you want to resume the process now? + You have scheduled the process of encryption/decryption of a partition/volume. The process has not been completed yet.\n\nDo you want to resume the process now? You have scheduled the process of encryption or decryption of the system partition/drive. The process has not been completed yet.\n\nDo you want to start (resume) the process now? - Do you want to be prompted about whether you want to resume the currently scheduled processes of encryption of non-system partitions/volumes? + Do you want to be prompted about whether you want to resume the currently scheduled processes of encryption/decryption of non-system partitions/volumes? Yes, keep prompting me No, do not prompt me - IMPORTANT: Keep in mind that you can resume the process of encryption of any non-system partition/volume by selecting 'Volumes' > 'Resume Interrupted Process' from the menu bar of the main VeraCrypt window. + IMPORTANT: Keep in mind that you can resume the process of encryption/decryption of any non-system partition/volume by selecting 'Volumes' > 'Resume Interrupted Process' from the menu bar of the main VeraCrypt window. You have scheduled the process of encryption or decryption of the system partition/drive. However, pre-boot authentication failed (or was bypassed).\n\nNote: If you decrypted the system partition/drive in the pre-boot environment, you may need to finalize the process by selecting 'System' > 'Permanently Decrypt System Partition/Drive' from the menu bar of the main VeraCrypt window. WARNING: If VeraCrypt exits now, the following functions will be disabled:\n\n1) Hot keys\n2) Auto-dismount (e.g., upon logoff, inadvertent host device removal, time-out, etc.)\n3) Auto-mount of favorite volumes\n4) Notifications (e.g., when damage to hidden volume is prevented)\n\nNote: If you do not wish VeraCrypt to run in the background, disable the VeraCrypt Background Task in the Preferences (and, if necessary, disable the automatic start of VeraCrypt in the Preferences).\n\nAre you sure you want VeraCrypt to exit? Exit? VeraCrypt does not have sufficient information to determine whether to encrypt or decrypt. VeraCrypt does not have sufficient information to determine whether to encrypt or decrypt.\n\nNote: If you decrypted the system partition/drive in the pre-boot environment, you may need to finalize the process by clicking Decrypt. - Do you want to interrupt and postpone the process of encryption of the partition/volume?\n\nNote: Keep in mind that the volume cannot be mounted until it has been fully encrypted. You will be able to resume the process of encryption and it will continue from the point it was stopped. You can do so, for example, by selecting 'Volumes' > 'Resume Interrupted Process' from the menu bar of the main VeraCrypt window. + Note: When you are encrypting a non-system partition/volume in place and an error persistently prevents you from finishing the process, you will not be able to mount the volume (and access data stored on it) until you entirely DECRYPT the volume (i.e. reverse the process).\n\nIf you need to do so, follow these steps:\n1) Exit this wizard.\n2) In the main VeraCrypt window, select 'Volumes' > 'Resume Interrupted Process'.\n3) Select 'Decrypt'. + Do you want to interrupt and postpone the process of encryption/decryption of the partition/volume?\n\nNote: Keep in mind that the volume cannot be mounted until it has been fully encrypted or decrypted. You will be able to resume the process of encryption/decryption and it will continue from the point where it was stopped. You can do so, for example, by selecting 'Volumes' > 'Resume Interrupted Process' from the menu bar of the main VeraCrypt window. Do you want to interrupt and postpone the process of encryption of the system partition/drive?\n\nNote: You will be able to resume the process and it will continue from the point it was stopped. You can do so, for example, by selecting 'System' > 'Resume Interrupted Process' from the menu bar of the main VeraCrypt window. If you want to permanently terminate or reverse the encryption process, select 'System' > 'Permanently Decrypt System Partition/Drive'. Do you want to interrupt and postpone the process of decryption of the system partition/drive?\n\nNote: You will be able to resume the process and it will continue from the point it was stopped. You can do so, for example, by selecting 'System' > 'Resume Interrupted Process' from the menu bar of the main VeraCrypt window. If you want to reverse the decryption process (and start encrypting), select 'System' > 'Encrypt System Partition/Drive'. Error: Failed to interrupt the process of encryption/decryption of the system partition/drive. @@ -994,7 +1013,7 @@ Error: Failed to start the process of wiping. Inconsistency resolved.\n\n\n(If you report a bug in connection with this, please include the following technical information in the bug report:\n%hs) Error: Unexpected state.\n\n\n(If you report a bug in connection with this, please include the following technical information in the bug report:\n%hs) - There is no process/task to resume. + There is no interrupted process of encryption/decryption of the system partition/drive to resume.\n\nNote: If you want to resume an interrupted process of encryption/decryption of a non-system partition/volume, select 'Volumes' > 'Resume Interrupted Process'. WARNING: VeraCrypt Background Task is disabled. After you exit VeraCrypt, you will not be notified if damage to hidden volume is prevented.\n\nNote: You may shut down the Background Task anytime by right-clicking the VeraCrypt tray icon and selecting 'Exit'.\n\nEnable VeraCrypt Background Task? Language pack version: %s Checking the file system on the VeraCrypt volume mounted as %hs... @@ -1127,6 +1146,7 @@ The pretest has been successfully completed.\n\nWARNING: Please note that if power supply is suddenly interrupted while encrypting existing data in place, or when the operating system crashes due to a software error or hardware malfunction while VeraCrypt is encrypting existing data in place, portions of the data will be corrupted or lost. Therefore, before you start encrypting, please make sure that you have backup copies of the files you want to encrypt. If you do not, please back up the files now (you can click Defer, back up the files, then run VeraCrypt again anytime, and select 'System' > 'Resume Interrupted Process' to start encrypting).\n\nWhen ready, click Encrypt to start encrypting. You can click Pause or Defer anytime to interrupt the process of encryption or decryption, exit this wizard, restart or shut down your computer, and then resume the process, which will continue from the point it was stopped. To prevent slowdown when the system or applications write or read data from the system drive, VeraCrypt automatically waits until the data is written or read (see Status above) and then automatically continues encrypting or decrypting. \n\nYou can click Pause or Defer anytime to interrupt the process of encryption, exit this wizard, restart or shut down your computer, and then resume the process, which will continue from the point it was stopped. Note that the volume cannot be mounted until it has been fully encrypted. + \n\nYou can click Pause or Defer anytime to interrupt the process of decryption, exit this wizard, restart or shut down the computer, and then resume the process, which will continue from the point where it was stopped. Note that the volume cannot be mounted until it has been fully decrypted. Hidden System Started Original System Windows creates (typically, without your knowledge or consent) various log files, temporary files, etc., on the system partition. It also saves the content of RAM to hibernation and paging files located on the system partition. Therefore, if an adversary analyzed files stored on the partition where the original system (of which the hidden system is a clone) resides, he might find out, for example, that you used the VeraCrypt wizard in the hidden-system-creation mode (which might indicate the existence of a hidden operating system on your computer).\n\nTo prevent such issues, VeraCrypt will, in the next steps, securely erase the entire content of the partition where the original system resides. Afterwards, in order to achieve plausible deniability, you will need to install a new system on the partition and encrypt it. Thus you will create the decoy system and the whole process of creation of the hidden operating system will be completed. @@ -1174,7 +1194,7 @@ An instance of the VeraCrypt Volume Creation Wizard is currently running on this system and performing or preparing encryption/decryption of the system partition/drive. Before you proceed, please wait for it to finish or close it. If you cannot close it, please restart your computer before proceeding. The process of encryption or decryption of the system partition/drive has not been completed. Please wait until it is complete before proceeding. Error: The process of encryption of the partition/drive has not been completed. It must be completed first. - Error: The process of encryption of the partition/volume has not been completed. It must be completed first.\n\nNote: To resume the process, select 'Volumes' > 'Resume Interrupted Process' from the menu bar of the main VeraCrypt window. + Error: The process of encryption or decryption of the partition/volume has not been completed. It must be completed first.\n\nNote: To resume the process, select 'Volumes' > 'Resume Interrupted Process' from the menu bar of the main VeraCrypt window. The password is correct, VeraCrypt has successfully decrypted the volume header and detected that this volume is a hidden system volume. However, you cannot modify the header of a hidden system volume this way.\n\nTo change the password for a hidden system volume, boot the operating system residing in the hidden volume, and then select 'System' > 'Change Password' from the menu bar of the main VeraCrypt window.\n\nTo set the header key derivation algorithm, boot the hidden operating system and then select 'System' > 'Set Header Key Derivation Algorithm'. VeraCrypt does not support in-place decryption of a hidden system partition.\n\nNote: If you want to decrypt the decoy system partition, boot the decoy system, and then select 'System' > 'Permanently Decrypt System Partition/Drive' from the menu bar of the main VeraCrypt window. Error: Incorrect/invalid parameter. @@ -1183,6 +1203,8 @@ You have selected the system partition/drive (or the boot partition), but the wizard mode you selected is suitable only for non-system partitions/drives.\n\nDo you want to set up pre-boot authentication (which means that you will need to enter your password each time before Windows boots/starts) and encrypt the system partition/drive? Are you sure you want to permanently decrypt the system partition/drive? CAUTION: If you permanently decrypt the system partition/drive, unencrypted data will be written to it.\n\nAre you really sure you want to permanently decrypt the system partition/drive? + Are you sure you want to permanently decrypt the following volume? + CAUTION: If you permanently decrypt the VeraCrypt volume, unencrypted data will be written to the disk.\n\nAre you really sure you want to permanently decrypt the selected volume? Warning: If you use a cascade of ciphers for system encryption, you may encounter the following issues:\n\n1) The VeraCrypt Boot Loader is larger than normal and, therefore, there is not enough space in the first drive track for a backup of the VeraCrypt Boot Loader. Hence, whenever it gets damaged (which often happens, for example, during inappropriately designed anti-piracy activation procedures of certain programs), you will need to use the VeraCrypt Rescue Disk to boot or to repair the VeraCrypt Boot Loader.\n\n2) On some computers, resuming from hibernation takes longer.\n\nThese potential issues can be prevented by choosing a non-cascade encryption algorithm (e.g. AES).\n\nAre you sure you want to use a cascade of ciphers? If you encounter any of the previously described problems, decrypt the partition/drive (if it is encrypted) and then try encrypting it again using a non-cascade encryption algorithm (e.g. AES). WARNING: For safety and security reasons, you should update VeraCrypt on the decoy operating system before you update it on the hidden operating system.\n\nTo do so, boot the decoy system and run the VeraCrypt installer from within it. Then boot the hidden system and run the installer from within it as well.\n\nNote: The decoy system and the hidden system share a single boot loader. If you upgraded VeraCrypt only on the hidden system (but not on the decoy system), the decoy system would contain a VeraCrypt driver and VeraCrypt applications whose version numbers are different from the version number of the VeraCrypt Boot Loader. Such a discrepancy might indicate that there is a hidden operating system on this computer.\n\n\nDo you want to continue? @@ -1198,6 +1220,7 @@ Error: Content of one or more sectors on the disk cannot be read (probably due to a physical defect).\n\nThe process of in-place encryption can continue only when the sectors have been made readable again. VeraCrypt can attempt to make these sectors readable by writing zeros to the sectors (subsequently such all-zero blocks would be encrypted). However, note that any data stored in the unreadable sectors will be lost. If you want to avoid that, you can attempt to recover portions of the corrupted data using appropriate third-party tools.\n\nNote: In case of physically damaged sectors (as opposed to mere data corruption and checksum errors) most types of storage devices internally reallocate the sectors when data is attempted to be written to them (so the existing data in the damaged sectors may remain unencrypted on the drive).\n\nDo you want VeraCrypt to write zeroes to unreadable sectors? Error: Content of one or more sectors on the disk cannot be read (probably due to a physical defect).\n\nTo be able to proceed with decryption, VeraCrypt will have to discard the content of the unreadable sectors (the content will be replaced with pseudorandom data). Please note that, before proceeding, you can attempt to recover portions of any corrupted data using appropriate third-party tools.\n\nDo you want VeraCrypt to discard data in the unreadable sectors now? Note: VeraCrypt has replaced the content of %I64d unreadable sectors (%s) with encrypted all-zero plaintext blocks. + Note: VeraCrypt has replaced the content of %I64d unreadable sectors (%s) with pseudorandom data. Enter password/PIN for token '%s': In order to allow VeraCrypt to access a security token or smart card, you need to install a PKCS #11 software library for the token or smart card first. Such a library may be supplied with the device or it may be available for download from the website of the vendor or other third parties.\n\nAfter you install the library, you can either select it manually by clicking 'Select Library' or you can let VeraCrypt find and select it automatically by clicking 'Auto-Detect Library' (only the Windows system directory will be searched). Note: For the filename and location of the PKCS #11 library installed for your security token or smart card, please refer to the documentation supplied with the token, card, or third-party software.\n\nClick 'OK' to select the path and filename. @@ -1243,7 +1266,7 @@ Warning: VeraCrypt volume auto-dismounted Before you physically remove or turn off a device containing a mounted volume, you should always dismount the volume in VeraCrypt first.\n\nUnexpected spontaneous dismount is usually caused by an intermittently failing cable, drive (enclosure), etc. This volume was created with TrueCrypt %x.%x but VeraCrypt supports only TrueCrypt volumes created with TrueCrypt 6.x/7.x series - Test + Test Keyfile Backspace Tab diff --git a/src/Common/Volumes.h b/src/Common/Volumes.h index 96997774..7021ab86 100644 --- a/src/Common/Volumes.h +++ b/src/Common/Volumes.h @@ -114,7 +114,7 @@ extern "C" { // Volume header flags #define TC_HEADER_FLAG_ENCRYPTED_SYSTEM 0x1 -#define TC_HEADER_FLAG_NONSYS_INPLACE_ENC 0x2 // The volume has been created using non-system in-place encryption +#define TC_HEADER_FLAG_NONSYS_INPLACE_ENC 0x2 // The volume has been created (or is being encrypted/decrypted) using non-system in-place encryption #ifndef TC_HEADER_Volume_VolumeHeader diff --git a/src/Format/Format.rc b/src/Format/Format.rc index 44bcc66b..51564a64 100644 --- a/src/Format/Format.rc +++ b/src/Format/Format.rc @@ -223,12 +223,12 @@ STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN EDITTEXT IDC_PASSWORD_DIRECT,50,2,149,14,ES_PASSWORD | ES_AUTOHSCROLL + COMBOBOX IDC_PKCS5_PRF_ID,50,17,91,90,CBS_DROPDOWNLIST | WS_TABSTOP CONTROL "&Display password",IDC_SHOW_PASSWORD_SINGLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,50,31,84,11,WS_EX_TRANSPARENT CONTROL "U&se keyfiles",IDC_KEYFILES_ENABLE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,50,42,82,11 PUSHBUTTON "&Keyfiles...",IDC_KEY_FILES,142,39,64,14 LTEXT "",IDC_BOX_HELP,0,57,225,94 RTEXT "Password:",IDT_PASSWORD,0,6,48,8 - COMBOBOX IDC_PKCS5_PRF_ID,50,17,91,90,CBS_DROPDOWNLIST | WS_TABSTOP RTEXT "PKCS-5 PRF:",IDT_PKCS5_PRF,0,17,48,8 END @@ -419,6 +419,15 @@ BEGIN LISTBOX IDC_LIST_BOX,0,3,222,100,LBS_NOINTEGRALHEIGHT | LBS_DISABLENOSCROLL | WS_VSCROLL END +IDD_DRIVE_LETTER_SELECTION_PAGE DIALOGEX 0, 0, 226, 152 +STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD +FONT 8, "MS Shell Dlg", 400, 0, 0x1 +BEGIN + LTEXT "",IDC_BOX_HELP,0,40,225,95 + COMBOBOX IDC_DRIVE_LETTER_LIST,94,15,38,69,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + RTEXT "Drive letter:",IDT_DRIVE_LETTER,5,17,86,8 +END + #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// @@ -662,6 +671,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 145 END + + IDD_DRIVE_LETTER_SELECTION_PAGE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 219 + TOPMARGIN, 7 + BOTTOMMARGIN, 145 + END END #endif // APSTUDIO_INVOKED diff --git a/src/Format/InPlace.c b/src/Format/InPlace.c index 3998c2a5..408f6252 100644 --- a/src/Format/InPlace.c +++ b/src/Format/InPlace.c @@ -40,6 +40,18 @@ IMPORTANT: Due to this issue, functions in this file must not directly interact using namespace std; using namespace VeraCrypt; +#if TC_VOLUME_DATA_OFFSET != 131072 +# error TC_VOLUME_DATA_OFFSET != 131072 +#endif + +#if TC_VOLUME_HEADER_EFFECTIVE_SIZE != 512 +# error TC_VOLUME_HEADER_EFFECTIVE_SIZE != 512 +#endif + +#if TC_TOTAL_VOLUME_HEADERS_SIZE != 262144 +# error TC_TOTAL_VOLUME_HEADERS_SIZE != 262144 +#endif + #define TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE (2048 * BYTES_PER_KB) #define TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE (2 * TC_MAX_VOLUME_SECTOR_SIZE) #define TC_NTFS_CONCEAL_CONSTANT 0xFF @@ -312,6 +324,42 @@ BOOL CheckRequirementsForNonSysInPlaceEnc (HWND hwndDlg, const char *devicePath, return TRUE; } +BOOL CheckRequirementsForNonSysInPlaceDec (HWND hwndDlg, const char *devicePath, BOOL silent) +{ + int partitionNumber = -1, driveNumber = -1; + + /* ---------- Checks that do not require admin rights ----------- */ + + /* Volume type (must be a partition or a dynamic volume) */ + if ((sscanf (devicePath, "\\Device\\HarddiskVolume%d", &partitionNumber) != 1 + && sscanf (devicePath, "\\Device\\Harddisk%d\\Partition%d", &driveNumber, &partitionNumber) != 2) + || partitionNumber == 0) + { + if (!silent) + Error ("INPLACE_ENC_INVALID_PATH", hwndDlg); + + return FALSE; + } + + + /* Admin rights */ + if (!IsAdmin()) + { + // We rely on the wizard process to call us only when the whole wizard process has been elevated (so UAC + // status can be ignored). In case the IsAdmin() detection somehow fails, we allow the user to continue. + + if (!silent) + Warning ("ADMIN_PRIVILEGES_WARN_DEVICES", hwndDlg); + } + + + /* ---------- Checks that may require admin rights ----------- */ + + // [Currently none] + + return TRUE; +} + int EncryptPartitionInPlaceBegin (volatile FORMAT_VOL_PARAMETERS *volParams, volatile HANDLE *outHandle, WipeAlgorithmId wipeAlgorithm) { @@ -606,7 +654,7 @@ int EncryptPartitionInPlaceBegin (volatile FORMAT_VOL_PARAMETERS *volParams, vol // In the config file, increase the number of partitions where in-place encryption is in progress - SaveNonSysInPlaceEncSettings (1, wipeAlgorithm); + SaveNonSysInPlaceEncSettings (1, wipeAlgorithm, FALSE); // Add the wizard to the system startup sequence if appropriate @@ -1033,7 +1081,7 @@ inplace_enc_read: // Update the configuration files - SaveNonSysInPlaceEncSettings (-1, wipeAlgorithm); + SaveNonSysInPlaceEncSettings (-1, wipeAlgorithm, FALSE); @@ -1126,6 +1174,513 @@ closing_seq: return nStatus; } +int DecryptPartitionInPlace (volatile FORMAT_VOL_PARAMETERS *volParams, volatile BOOL *DiscardUnreadableEncryptedSectors) +{ + HANDLE dev = INVALID_HANDLE_VALUE; + PCRYPTO_INFO masterCryptoInfo = NULL, headerCryptoInfo = NULL; + UINT64_STRUCT unitNo; + char *buf = NULL; + byte *tmpSectorBuf = NULL; + char dosDev[TC_MAX_PATH] = {0}; + char devName[MAX_PATH] = {0}; + WCHAR deviceName[MAX_PATH]; + int nStatus = ERR_SUCCESS; + __int64 deviceSize; + uint64 remainingBytes, workChunkStartByteOffset, lastHeaderUpdateDistance = 0, skippedBadSectorCount = 0; + uint32 workChunkSize; + DWORD dwError, dwResult; + BOOL bPause = FALSE, bEncryptedAreaSizeChanged = FALSE; + LARGE_INTEGER offset; + int sectorSize; + int i; + DWORD n; + char *devicePath = volParams->volumePath; + Password *password = volParams->password; + HWND hwndDlg = volParams->hwndDlg; + int pkcs5_prf = volParams->pkcs5; + DISK_GEOMETRY driveGeometry; + + + buf = (char *) TCalloc (TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE); + if (!buf) + { + nStatus = ERR_OUTOFMEMORY; + goto closing_seq; + } + + headerCryptoInfo = crypto_open(); + + if (headerCryptoInfo == NULL) + { + nStatus = ERR_OUTOFMEMORY; + goto closing_seq; + } + + deviceSize = GetDeviceSize (devicePath); + if (deviceSize < 0) + { + // Cannot determine the size of the partition + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + + + // The wizard should have dismounted the TC volume if it was mounted, but for extra safety we will check this again. + if (IsMountedVolume (devicePath)) + { + int driveLetter = GetMountedVolumeDriveNo (devicePath); + + if (driveLetter == -1 + || !UnmountVolume (hwndDlg, driveLetter, TRUE)) + { + handleWin32Error (hwndDlg); + AbortProcess ("CANT_DISMOUNT_VOLUME"); + } + } + + + StringCbCopyA ((char *)deviceName, sizeof(deviceName), devicePath); + ToUNICODE ((char *)deviceName, sizeof(deviceName)); + + if (FakeDosNameForDevice (devicePath, dosDev, sizeof(dosDev), devName, sizeof(devName), FALSE) != 0) + { + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + + dev = OpenPartitionVolume (hwndDlg, devName, + TRUE, // Require exclusive access + FALSE, // Do not require shared access + TRUE, // Ask the user to confirm shared access (if exclusive fails) + FALSE, // Do not append alternative instructions how to encrypt the data (to applicable error messages) + FALSE); // Non-silent mode + + if (dev == INVALID_HANDLE_VALUE) + { + nStatus = ERR_DONT_REPORT; + goto closing_seq; + } + + + + // This should never be needed, but is still performed for extra safety (without checking the result) + DeviceIoControl (dev, + FSCTL_ALLOW_EXTENDED_DASD_IO, + NULL, + 0, + NULL, + 0, + &dwResult, + NULL); + + + if (!DeviceIoControl (dev, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &driveGeometry, sizeof (driveGeometry), &dwResult, NULL)) + { + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + + sectorSize = driveGeometry.BytesPerSector; + + + tmpSectorBuf = (byte *) TCalloc (sectorSize); + if (!tmpSectorBuf) + { + nStatus = ERR_OUTOFMEMORY; + goto closing_seq; + } + + + nStatus = OpenBackupHeader (dev, devicePath, password, pkcs5_prf, &masterCryptoInfo, headerCryptoInfo, deviceSize); + + if (nStatus != ERR_SUCCESS) + goto closing_seq; + + + if (masterCryptoInfo->LegacyVolume) + { + Error ("NONSYS_INPLACE_DECRYPTION_BAD_VOL_FORMAT", hwndDlg); + nStatus = ERR_DONT_REPORT; + goto closing_seq; + } + + if (masterCryptoInfo->hiddenVolume) + { + Error ("NONSYS_INPLACE_DECRYPTION_CANT_DECRYPT_HID_VOL", hwndDlg); + nStatus = ERR_DONT_REPORT; + goto closing_seq; + } + + if (!bInPlaceEncNonSysResumed + && masterCryptoInfo->VolumeSize.Value == masterCryptoInfo->EncryptedAreaLength.Value) + { + /* Decryption started (not resumed) */ + + if ((masterCryptoInfo->HeaderFlags & TC_HEADER_FLAG_NONSYS_INPLACE_ENC) == 0) + { + // The volume has not been encrypted in-place so it may contain a hidden volume. + // Ask the user to confirm it does not. + + char *tmpStr[] = {0, + "CONFIRM_VOL_CONTAINS_NO_HIDDEN_VOL", + "VOL_CONTAINS_NO_HIDDEN_VOL", + "VOL_CONTAINS_A_HIDDEN_VOL", + 0}; + + switch (AskMultiChoice ((void **) tmpStr, FALSE, hwndDlg)) + { + case 1: + // NOP + break; + case 2: + default: + // Cancel + nStatus = ERR_DONT_REPORT; + goto closing_seq; + } + } + + // Update config files and app data + + // In the config file, increase the number of partitions where in-place decryption is in progress + SaveNonSysInPlaceEncSettings (1, TC_WIPE_NONE, TRUE); + + // Add the wizard to the system startup sequence if appropriate + if (!IsNonInstallMode ()) + ManageStartupSeqWiz (FALSE, "/prinplace"); + } + + + + bInPlaceEncNonSysResumed = TRUE; + bFirstNonSysInPlaceEncResumeDone = TRUE; + + + remainingBytes = masterCryptoInfo->EncryptedAreaLength.Value; + + lastHeaderUpdateDistance = 0; + + + ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value); + + SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_DECRYPTING); + + + + /* The in-place decryption core */ + + while (remainingBytes > 0) + { + workChunkSize = (uint32) min (remainingBytes, TC_MAX_NONSYS_INPLACE_ENC_WORK_CHUNK_SIZE); + + if (workChunkSize % ENCRYPTION_DATA_UNIT_SIZE != 0) + { + nStatus = ERR_PARAMETER_INCORRECT; + goto closing_seq; + } + + workChunkStartByteOffset = masterCryptoInfo->EncryptedAreaStart.Value; + + unitNo.Value = workChunkStartByteOffset / ENCRYPTION_DATA_UNIT_SIZE; + + + // Read the ciphertext into RAM + + offset.QuadPart = workChunkStartByteOffset; + + if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) + { + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + + if (ReadFile (dev, buf, workChunkSize, &n, NULL) == 0) + { + // Read error + + DWORD dwTmpErr = GetLastError (); + + if (IsDiskReadError (dwTmpErr) && !bVolTransformThreadCancel) + { + // Physical defect or data corruption + + if (!*DiscardUnreadableEncryptedSectors) + { + *DiscardUnreadableEncryptedSectors = (AskWarnYesNo ("DISCARD_UNREADABLE_ENCRYPTED_SECTORS", hwndDlg) == IDYES); + } + + if (*DiscardUnreadableEncryptedSectors) + { + // Read the work chunk again, but this time each sector individually and skiping each bad sector + + LARGE_INTEGER tmpSectorOffset; + uint64 tmpSectorCount; + uint64 tmpBufOffset = 0; + DWORD tmpNbrReadBytes = 0; + + tmpSectorOffset.QuadPart = offset.QuadPart; + + for (tmpSectorCount = workChunkSize / sectorSize; tmpSectorCount > 0; --tmpSectorCount) + { + if (SetFilePointerEx (dev, tmpSectorOffset, NULL, FILE_BEGIN) == 0) + { + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + + if (ReadFile (dev, tmpSectorBuf, sectorSize, &tmpNbrReadBytes, NULL) == 0 + || tmpNbrReadBytes != (DWORD) sectorSize) + { + // Read error + + // Clear the buffer so the content of each unreadable sector is replaced with decrypted all-zero blocks (producing pseudorandom data) + memset (tmpSectorBuf, 0, sectorSize); + + skippedBadSectorCount++; + } + + memcpy (buf + tmpBufOffset, tmpSectorBuf, sectorSize); + + tmpSectorOffset.QuadPart += sectorSize; + tmpBufOffset += sectorSize; + } + } + else + { + SetLastError (dwTmpErr); // Preserve the original error code + + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + } + else + { + SetLastError (dwTmpErr); // Preserve the original error code + + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + } + + // Decrypt the ciphertext in RAM + + DecryptDataUnits ((byte *) buf, &unitNo, workChunkSize / ENCRYPTION_DATA_UNIT_SIZE, masterCryptoInfo); + + + + // Conceal initial portion of the filesystem + + if (workChunkStartByteOffset - TC_VOLUME_DATA_OFFSET < TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE) + { + // We are decrypting the initial TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE bytes of the filesystem. We will + // conceal this portion to prevent Windows and applications from interfering with the volume. + + for (i = 0; i < min (TC_INITIAL_NTFS_CONCEAL_PORTION_SIZE, workChunkStartByteOffset - TC_VOLUME_DATA_OFFSET + workChunkSize); i++) + buf[i] ^= TC_NTFS_CONCEAL_CONSTANT; + } + + + // Write the plaintext + + offset.QuadPart = workChunkStartByteOffset - TC_VOLUME_DATA_OFFSET; + + if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) + { + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + + if (WriteFile (dev, buf, workChunkSize, &n, NULL) == 0) + { + // Write error + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + + + masterCryptoInfo->EncryptedAreaStart.Value += workChunkSize; + masterCryptoInfo->EncryptedAreaLength.Value -= workChunkSize; + + remainingBytes -= workChunkSize; + lastHeaderUpdateDistance += workChunkSize; + + bEncryptedAreaSizeChanged = TRUE; + + if (lastHeaderUpdateDistance >= TC_NONSYS_INPLACE_ENC_HEADER_UPDATE_INTERVAL) + { + nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize); + + if (nStatus != ERR_SUCCESS) + { + // Possible write error + goto closing_seq; + } + + lastHeaderUpdateDistance = 0; + } + + ExportProgressStats (masterCryptoInfo->EncryptedAreaLength.Value, masterCryptoInfo->VolumeSize.Value); + + if (bVolTransformThreadCancel) + { + bPause = TRUE; + break; + } + } + + nStatus = FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize); + + + if (nStatus != ERR_SUCCESS) + { + // Possible write error + goto closing_seq; + } + + + if (!bPause) + { + /* Volume has been fully decrypted. */ + + + // Prevent attempts to update volume header during the closing sequence + bEncryptedAreaSizeChanged = FALSE; + + + SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINALIZING); + + + + /* Undo concealing of the filesystem */ + + nStatus = ConcealNTFS (dev); + + if (nStatus != ERR_SUCCESS) + goto closing_seq; + + + + /* Ovewrite the backup header and the remaining ciphertext with all-zero blocks (the primary header was overwritten with the decrypted data). */ + + memset (tmpSectorBuf, 0, sectorSize); + + for (offset.QuadPart = masterCryptoInfo->VolumeSize.Value; + offset.QuadPart <= deviceSize - sectorSize; + offset.QuadPart += sectorSize) + { + if (SetFilePointerEx (dev, offset, NULL, FILE_BEGIN) == 0) + { + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + + if (WriteFile (dev, tmpSectorBuf, sectorSize, &n, NULL) == 0) + { + // Write error + dwError = GetLastError(); + + SetLastError (dwError); + nStatus = ERR_OS_ERROR; + goto closing_seq; + } + } + + + + /* Update the configuration files */ + + SaveNonSysInPlaceEncSettings (-1, TC_WIPE_NONE, TRUE); + + + + SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_FINISHED); + + nStatus = ERR_SUCCESS; + + } + else + { + // The process has been paused by the user or aborted by the wizard (e.g. on app exit) + + nStatus = ERR_USER_ABORT; + + SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PAUSED); + } + + if (dev != INVALID_HANDLE_VALUE) + { + CloseHandle (dev); + dev = INVALID_HANDLE_VALUE; + } + + +closing_seq: + + dwError = GetLastError(); + + if (bEncryptedAreaSizeChanged + && dev != INVALID_HANDLE_VALUE + && masterCryptoInfo != NULL + && headerCryptoInfo != NULL + && deviceSize > 0) + { + // Execution of the core loop may have been interrupted due to an error or user action without updating the header + FastVolumeHeaderUpdate (dev, headerCryptoInfo, masterCryptoInfo, deviceSize); + } + + if (dev != INVALID_HANDLE_VALUE) + { + CloseHandle (dev); + dev = INVALID_HANDLE_VALUE; + } + + if (masterCryptoInfo != NULL) + { + crypto_close (masterCryptoInfo); + masterCryptoInfo = NULL; + } + + if (headerCryptoInfo != NULL) + { + crypto_close (headerCryptoInfo); + headerCryptoInfo = NULL; + } + + if (dosDev[0]) + RemoveFakeDosName (devicePath, dosDev); + + if (buf != NULL) + { + TCfree (buf); + buf = NULL; + } + + if (tmpSectorBuf != NULL) + { + TCfree (tmpSectorBuf); + tmpSectorBuf = NULL; + } + + if (skippedBadSectorCount > 0) + { + wchar_t msg[30000] = {0}; + wchar_t sizeStr[500] = {0}; + + GetSizeString (skippedBadSectorCount * sectorSize, sizeStr, sizeof(sizeStr)); + + StringCbPrintfW (msg, sizeof(msg), + GetString ("SKIPPED_BAD_SECTOR_COUNT"), + skippedBadSectorCount, + sizeStr); + + WarningDirect (msg, hwndDlg); + } + + if (nStatus != ERR_SUCCESS && nStatus != ERR_USER_ABORT) + SetLastError (dwError); + + return nStatus; +} int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_INFO *masterCryptoInfo, __int64 deviceSize) { @@ -1168,6 +1723,13 @@ int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_IN mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaStart.Value)); mputInt64 (fieldPos, (masterCryptoInfo->EncryptedAreaLength.Value)); + // We need to ensure the TC_HEADER_FLAG_NONSYS_INPLACE_ENC flag bit is set, because if volumes created by TC-format + // were decrypted in place, it would be possible to mount them partially encrypted and it wouldn't be possible + // to resume interrupted decryption after the wizard exits. + masterCryptoInfo->HeaderFlags |= TC_HEADER_FLAG_NONSYS_INPLACE_ENC; + fieldPos = (byte *) header + TC_HEADER_OFFSET_FLAGS; + mputLong (fieldPos, (masterCryptoInfo->HeaderFlags)); + headerCrc32 = GetCrc32 (header + TC_HEADER_OFFSET_MAGIC, TC_HEADER_OFFSET_HEADER_CRC - TC_HEADER_OFFSET_MAGIC); fieldPos = (byte *) header + TC_HEADER_OFFSET_HEADER_CRC; @@ -1419,7 +1981,7 @@ void SetNonSysInplaceEncUIStatus (int nonSysInplaceEncStatus) } -BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm) +BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm, BOOL bDecrypt) { int count; char str[32]; @@ -1435,7 +1997,7 @@ BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm) RemoveNonSysInPlaceEncNotifications(); return TRUE; } - else + else if (!bDecrypt) { if (newWipeAlgorithm != TC_WIPE_NONE) { @@ -1447,11 +2009,11 @@ BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId newWipeAlgorithm) { remove (GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC_WIPE)); } - - StringCbPrintfA (str, sizeof(str), "%d", count); - - return SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), strlen(str), FALSE); } + + StringCbPrintfA (str, sizeof(str), "%d", count); + + return SaveBufferToFile (str, GetConfigPath (TC_APPD_FILENAME_NONSYS_INPLACE_ENC), strlen(str), FALSE); } diff --git a/src/Format/InPlace.h b/src/Format/InPlace.h index 90cf5f80..6b59bbd4 100644 --- a/src/Format/InPlace.h +++ b/src/Format/InPlace.h @@ -18,6 +18,7 @@ enum nonsys_inplace_enc_status NONSYS_INPLACE_ENC_STATUS_PREPARING, NONSYS_INPLACE_ENC_STATUS_RESIZING, NONSYS_INPLACE_ENC_STATUS_ENCRYPTING, + NONSYS_INPLACE_ENC_STATUS_DECRYPTING, NONSYS_INPLACE_ENC_STATUS_FINALIZING, NONSYS_INPLACE_ENC_STATUS_PAUSED, NONSYS_INPLACE_ENC_STATUS_FINISHED, @@ -25,8 +26,10 @@ enum nonsys_inplace_enc_status }; BOOL CheckRequirementsForNonSysInPlaceEnc (HWND hwndDlg, const char *devicePath, BOOL silent); +BOOL CheckRequirementsForNonSysInPlaceDec (HWND hwndDlg, const char *devicePath, BOOL silent); int EncryptPartitionInPlaceBegin (volatile FORMAT_VOL_PARAMETERS *volParams, volatile HANDLE *outHandle, WipeAlgorithmId wipeAlgorithm); int EncryptPartitionInPlaceResume (HANDLE dev, volatile FORMAT_VOL_PARAMETERS *volParams, WipeAlgorithmId wipeAlgorithm, volatile BOOL *bTryToCorrectReadErrors); +int DecryptPartitionInPlace (volatile FORMAT_VOL_PARAMETERS *volParams, volatile BOOL *DiscardUnreadableEncryptedSectors); void ShowInPlaceEncErrMsgWAltSteps (HWND hwndDlg, char *iniStrId, BOOL bErr); void SetNonSysInplaceEncUIStatus (int nonSysInplaceEncStatus); int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_INFO *masterCryptoInfo, __int64 deviceSize); @@ -34,7 +37,7 @@ int FastVolumeHeaderUpdate (HANDLE dev, CRYPTO_INFO *headerCryptoInfo, CRYPTO_IN static HANDLE OpenPartitionVolume (HWND hwndDlg, const char *devName, BOOL bExclusiveRequired, BOOL bSharedRequired, BOOL bSharedRequiresConfirmation, BOOL bShowAlternativeSteps, BOOL bSilent); static int DismountFileSystem (HWND hwndDlg, HANDLE dev, int driveLetter, BOOL bForcedAllowed, BOOL bForcedRequiresConfirmation, BOOL bSilent); static int ConcealNTFS (HANDLE dev); -BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId wipeAlgorithm); +BOOL SaveNonSysInPlaceEncSettings (int delta, WipeAlgorithmId wipeAlgorithm, BOOL bDecrypting); static void ExportProgressStats (__int64 bytesDone, __int64 totalSize); int ZeroUnreadableSectors (HANDLE dev, LARGE_INTEGER startOffset, int64 size, int sectorSize, uint64 *zeroedSectorCount); static int OpenBackupHeader (HANDLE dev, const char *devicePath, Password *password, int pkcs5, PCRYPTO_INFO *retCryptoInfo, CRYPTO_INFO *headerCryptoInfo, __int64 deviceSize); diff --git a/src/Format/Resource.h b/src/Format/Resource.h index 61a38332..feba5ec3 100644 --- a/src/Format/Resource.h +++ b/src/Format/Resource.h @@ -34,6 +34,7 @@ #define IDD_DEVICE_WIPE_MODE_PAGE_DLG 129 #define IDD_DEVICE_TRANSFORM_MODE_DLG 130 #define IDD_EXPANDED_LIST_SELECT_PAGE_DLG 131 +#define IDD_DRIVE_LETTER_SELECTION_PAGE 132 #define IDC_BOX_TITLE 1000 #define IDC_RESCUE_DISK_ISO_PATH 1001 #define IDC_COMBO_BOX 1002 @@ -137,15 +138,17 @@ #define IDT_PASS 1100 #define IDC_DEVICE_TRANSFORM_MODE_FORMAT 1101 #define IDC_DEVICE_TRANSFORM_MODE_INPLACE 1102 +#define IDC_DRIVE_LETTER_LIST 1103 +#define IDT_DRIVE_LETTER 1104 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 132 +#define _APS_NEXT_RESOURCE_VALUE 133 #define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1103 +#define _APS_NEXT_CONTROL_VALUE 1105 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif diff --git a/src/Format/Tcformat.c b/src/Format/Tcformat.c index ba35c47e..a0d9b293 100644 --- a/src/Format/Tcformat.c +++ b/src/Format/Tcformat.c @@ -94,8 +94,9 @@ enum wizard_pages NONSYS_INPLACE_ENC_RESUME_PARTITION_SEL_PAGE, NONSYS_INPLACE_ENC_RAND_DATA_PAGE, NONSYS_INPLACE_ENC_WIPE_MODE_PAGE, - NONSYS_INPLACE_ENC_ENCRYPTION_PAGE, - NONSYS_INPLACE_ENC_ENCRYPTION_FINISHED_PAGE, + NONSYS_INPLACE_ENC_TRANSFORM_PAGE, + NONSYS_INPLACE_ENC_TRANSFORM_FINISHED_PAGE, + NONSYS_INPLACE_DEC_TRANSFORM_FINISHED_DRIVE_LETTER_PAGE, FORMAT_PAGE, FORMAT_FINISHED_PAGE, SYSENC_HIDDEN_OS_INITIAL_INFO_PAGE, @@ -148,10 +149,13 @@ volatile BOOL bHiddenOS = FALSE; /* If TRUE, we are performing or (or supposed BOOL bDirectSysEncMode = FALSE; BOOL bDirectSysEncModeCommand = SYSENC_COMMAND_NONE; BOOL DirectDeviceEncMode = FALSE; +BOOL DirectNonSysInplaceDecStartMode = FALSE; BOOL DirectNonSysInplaceEncResumeMode = FALSE; +BOOL DirectNonSysInplaceDecResumeMode = FALSE; BOOL DirectPromptNonSysInplaceEncResumeMode = FALSE; -volatile BOOL bInPlaceEncNonSys = FALSE; /* If TRUE, existing data on a non-system partition/volume are to be encrypted (for system encryption, this flag is ignored) */ -volatile BOOL bInPlaceEncNonSysResumed = FALSE; /* If TRUE, the wizard is supposed to resume (or has resumed) process of non-system in-place encryption. */ +volatile BOOL bInPlaceEncNonSys = FALSE; /* If TRUE, existing data on a non-system partition/volume are to be encrypted (or decrypted if bInPlaceDecNonSys is TRUE) in place (for system encryption, this flag is ignored) */ +volatile BOOL bInPlaceDecNonSys = FALSE; /* If TRUE, existing data on a non-system partition/volume are to be decrypted in place (for system encryption, this flag is ignored) */ +volatile BOOL bInPlaceEncNonSysResumed = FALSE; /* If TRUE, the wizard is supposed to resume (or has resumed) process of non-system in-place encryption/decryption. */ volatile BOOL bFirstNonSysInPlaceEncResumeDone = FALSE; __int64 NonSysInplaceEncBytesDone = 0; __int64 NonSysInplaceEncTotalSize = 0; @@ -657,7 +661,10 @@ static BOOL ChangeWizardMode (int newWizardMode) } if (newWizardMode != WIZARD_MODE_NONSYS_DEVICE) + { bInPlaceEncNonSys = FALSE; + bInPlaceDecNonSys = FALSE; + } if (newWizardMode == WIZARD_MODE_NONSYS_DEVICE && !IsAdmin() && IsUacSupported()) { @@ -666,7 +673,8 @@ static BOOL ChangeWizardMode (int newWizardMode) } // The contents of the following items may be inappropriate after a change of mode - szFileName[0] = 0; + if (! (bInPlaceDecNonSys && !bInPlaceEncNonSysResumed)) // If we are starting (but not resuming) decryption of non-system volume, we actually need szFileName as it contains the command line param. + szFileName[0] = 0; szDiskFile[0] = 0; nUIVolumeSize = 0; nVolumeSize = 0; @@ -1067,6 +1075,7 @@ BOOL SwitchWizardToHiddenOSMode (void) bHiddenVolDirect = FALSE; bWholeSysDrive = FALSE; bInPlaceEncNonSys = FALSE; + bInPlaceDecNonSys = FALSE; if (bDirectSysEncModeCommand == SYSENC_COMMAND_CREATE_HIDDEN_OS_ELEV) { @@ -1102,11 +1111,11 @@ BOOL SwitchWizardToHiddenOSMode (void) return TRUE; } -void SwitchWizardToNonSysInplaceEncResumeMode (void) +void SwitchWizardToNonSysInplaceEncResumeMode (BOOL bDecrypt) { if (!IsAdmin() && IsUacSupported()) { - if (!ElevateWholeWizardProcess ("/zinplace")) + if (!ElevateWholeWizardProcess (bDecrypt ? "/resumeinplacedec" : "/zinplace")) AbortProcessSilent (); } @@ -1116,6 +1125,7 @@ void SwitchWizardToNonSysInplaceEncResumeMode (void) CreateNonSysInplaceEncMutex (); bInPlaceEncNonSys = TRUE; + bInPlaceDecNonSys = bDecrypt; bInPlaceEncNonSysResumed = TRUE; ChangeWizardMode (WIZARD_MODE_NONSYS_DEVICE); @@ -1123,6 +1133,31 @@ void SwitchWizardToNonSysInplaceEncResumeMode (void) LoadPage (MainDlg, NONSYS_INPLACE_ENC_RESUME_PASSWORD_PAGE); } +void SwitchWizardToNonSysInplaceDecStartMode (char *volPath) +{ + if (!IsAdmin() && IsUacSupported()) + { + if (!ElevateWholeWizardProcess ((string ("/inplacedec \"") + volPath + "\"").c_str())) + AbortProcessSilent (); + } + + if (!IsAdmin()) + AbortProcess("ADMIN_PRIVILEGES_WARN_DEVICES"); + + if (!CheckRequirementsForNonSysInPlaceDec (MainDlg, volPath, FALSE)) + AbortProcessSilent (); + + CreateNonSysInplaceEncMutex (); + + bInPlaceEncNonSys = TRUE; + bInPlaceDecNonSys = TRUE; + bInPlaceEncNonSysResumed = FALSE; + + ChangeWizardMode (WIZARD_MODE_NONSYS_DEVICE); + + LoadPage (MainDlg, NONSYS_INPLACE_ENC_RESUME_PASSWORD_PAGE); +} + // Use this function e.g. if the config file with the system encryption settings was lost or not written // correctly, and we don't know whether to encrypt or decrypt (but we know that encryption or decryption // is required). Returns FALSE if failed or cancelled. @@ -1730,6 +1765,7 @@ static void SysEncResume (void) return; } + bVolTransformThreadCancel = FALSE; bSystemEncryptionInProgress = FALSE; WaitCursor (); @@ -1906,6 +1942,9 @@ void ShowNonSysInPlaceEncUIStatus (void) case NONSYS_INPLACE_ENC_STATUS_ENCRYPTING: StringCbCopyW (nonSysInplaceEncUIStatus, sizeof(nonSysInplaceEncUIStatus), GetString ("PROGRESS_STATUS_ENCRYPTING")); break; + case NONSYS_INPLACE_ENC_STATUS_DECRYPTING: + StringCbCopyW (nonSysInplaceEncUIStatus, sizeof(nonSysInplaceEncUIStatus), GetString ("PROGRESS_STATUS_DECRYPTING")); + break; case NONSYS_INPLACE_ENC_STATUS_FINALIZING: StringCbCopyW (nonSysInplaceEncUIStatus, sizeof(nonSysInplaceEncUIStatus), GetString ("PROGRESS_STATUS_FINALIZING")); break; @@ -1925,12 +1964,28 @@ void ShowNonSysInPlaceEncUIStatus (void) void UpdateNonSysInPlaceEncControls (void) { - EnableWindow (GetDlgItem (hCurPage, IDC_WIPE_MODE), !(bVolTransformThreadRunning || bVolTransformThreadToRun)); + // Reduce flickering by updating a GUI element only when a relevant change affects it + static BOOL lastbVolTransformThreadRunning = !bVolTransformThreadRunning; + static BOOL lastbVolTransformThreadToRun = !bVolTransformThreadToRun; + static BOOL lastbInPlaceEncNonSysResumed = !bInPlaceEncNonSysResumed; - SetWindowTextW (GetDlgItem (hCurPage, IDC_PAUSE), - GetString ((bVolTransformThreadRunning || bVolTransformThreadToRun) ? "IDC_PAUSE" : "RESUME")); + EnableWindow (GetDlgItem (hCurPage, IDC_WIPE_MODE), !(bVolTransformThreadRunning || bVolTransformThreadToRun) && !bInPlaceDecNonSys); + + if (lastbVolTransformThreadRunning != bVolTransformThreadRunning + || lastbVolTransformThreadToRun != bVolTransformThreadToRun) + { + SetWindowTextW (GetDlgItem (hCurPage, IDC_PAUSE), + GetString ((bVolTransformThreadRunning || bVolTransformThreadToRun) ? "IDC_PAUSE" : "RESUME")); - SetWindowTextW (GetDlgItem (MainDlg, IDCANCEL), GetString (bInPlaceEncNonSysResumed ? "DEFER" : "CANCEL")); + lastbVolTransformThreadRunning = bVolTransformThreadRunning; + lastbVolTransformThreadToRun = bVolTransformThreadToRun; + } + + if (lastbInPlaceEncNonSysResumed != bInPlaceEncNonSysResumed) + { + SetWindowTextW (GetDlgItem (MainDlg, IDCANCEL), GetString (bInPlaceEncNonSysResumed ? "DEFER" : "CANCEL")); + lastbInPlaceEncNonSysResumed = bInPlaceEncNonSysResumed; + } EnableWindow (GetDlgItem (hCurPage, IDC_PAUSE), bFirstNonSysInPlaceEncResumeDone && NonSysInplaceEncStatus != NONSYS_INPLACE_ENC_STATUS_FINALIZING @@ -1995,11 +2050,12 @@ static void UpdateNonSysInplaceEncProgressBar (void) if (bVolTransformThreadRunning && (nonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_ENCRYPTING + || nonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_DECRYPTING || nonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_FINALIZING || nonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_FINISHED)) { if (lastNonSysInplaceEncStatus != nonSysInplaceEncStatus - && nonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_ENCRYPTING) + && (nonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_ENCRYPTING || nonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_DECRYPTING)) { InitNonSysInplaceEncProgressBar (); } @@ -2033,7 +2089,7 @@ static void InitNonSysInplaceEncProgressBar (void) InitProgressBar (totalSize, NonSysInplaceEncBytesDone, - FALSE, + bInPlaceDecNonSys, TRUE, TRUE, TRUE); @@ -2436,7 +2492,7 @@ static void __cdecl volTransformThreadFunction (void *hwndDlgArg) volParams->hiddenVolHostSize = nHiddenVolHostSize; volParams->ea = nVolumeEA; volParams->pkcs5 = hash_algo; - volParams->headerFlags = CreatingHiddenSysVol() ? TC_HEADER_FLAG_ENCRYPTED_SYSTEM : 0; + volParams->headerFlags = (CreatingHiddenSysVol() ? TC_HEADER_FLAG_ENCRYPTED_SYSTEM : 0); volParams->fileSystem = fileSystem; volParams->clusterSize = clusterSize; volParams->sparseFileSwitch = bSparseFileSwitch; @@ -2446,8 +2502,19 @@ static void __cdecl volTransformThreadFunction (void *hwndDlgArg) volParams->password = &volumePassword; volParams->hwndDlg = hwndDlg; - if (bInPlaceEncNonSys) + if (bInPlaceDecNonSys) { + // In-place decryption of non-system volume + + if (!bInPlaceEncNonSysResumed) + DiscardUnreadableEncryptedSectors = FALSE; + + nStatus = DecryptPartitionInPlace (volParams, &DiscardUnreadableEncryptedSectors); + } + else if (bInPlaceEncNonSys) + { + // In-place encryption of non-system volume + HANDLE hPartition = INVALID_HANDLE_VALUE; SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_PREPARING); @@ -2475,6 +2542,8 @@ static void __cdecl volTransformThreadFunction (void *hwndDlgArg) } else { + // Format-encryption + InitProgressBar (GetVolumeDataAreaSize (bHidden, nVolumeSize), 0, FALSE, FALSE, FALSE, TRUE); nStatus = TCFormatVolume (volParams); @@ -2492,7 +2561,7 @@ static void __cdecl volTransformThreadFunction (void *hwndDlgArg) && nStatus == ERR_USER_ABORT && NonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_FINISHED) { - // Ignore user abort if non-system in-place encryption successfully finished + // Ignore user abort if non-system in-place encryption/decryption successfully finished nStatus = ERR_SUCCESS; } @@ -2519,7 +2588,7 @@ static void __cdecl volTransformThreadFunction (void *hwndDlgArg) SetLastError (dwWin32FormatError); if ((bVolTransformThreadCancel || nStatus == ERR_USER_ABORT) - && !(bInPlaceEncNonSys && NonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_FINISHED)) // Ignore user abort if non-system in-place encryption successfully finished. + && !(bInPlaceEncNonSys && NonSysInplaceEncStatus == NONSYS_INPLACE_ENC_STATUS_FINISHED)) // Ignore user abort if non-system in-place encryption/decryption successfully finished. { if (!bDevice && !(bHiddenVol && !bHiddenVolHost)) // If we're not creating a hidden volume and if it's a file container { @@ -2549,7 +2618,11 @@ static void __cdecl volTransformThreadFunction (void *hwndDlgArg) else { SetNonSysInplaceEncUIStatus (NONSYS_INPLACE_ENC_STATUS_ERROR); - ShowInPlaceEncErrMsgWAltSteps (hwndDlg, "INPLACE_ENC_GENERIC_ERR_ALT_STEPS", TRUE); + + if (bInPlaceDecNonSys) + Error ("INPLACE_DEC_GENERIC_ERR", hwndDlg); + else + ShowInPlaceEncErrMsgWAltSteps (hwndDlg, "INPLACE_ENC_GENERIC_ERR_ALT_STEPS", TRUE); } } else if (!(bHiddenVolHost && hiddenVolHostDriveNo < 0)) // If the error was not that the hidden volume host could not be mounted (this error has already been reported to the user) @@ -2589,9 +2662,16 @@ static void __cdecl volTransformThreadFunction (void *hwndDlgArg) } else if (bInPlaceEncNonSys) { - Warning ("NONSYS_INPLACE_ENC_FINISHED_INFO", hwndDlg); + if (!bInPlaceDecNonSys) + { + Warning ("NONSYS_INPLACE_ENC_FINISHED_INFO", hwndDlg); - HandleOldAssignedDriveLetter (); + HandleOldAssignedDriveLetter (); + } + else + { + // NOP - Final steps for in-place decryption are handled with the TC_APPMSG_NONSYS_INPLACE_ENC_FINISHED message. + } } else { @@ -2868,16 +2948,21 @@ static void LoadPage (HWND hwndDlg, int nPageNo) (DLGPROC) PageDialogProc); break; - case NONSYS_INPLACE_ENC_ENCRYPTION_PAGE: + case NONSYS_INPLACE_ENC_TRANSFORM_PAGE: hCurPage = CreateDialogW (hInst, MAKEINTRESOURCEW (IDD_INPLACE_ENCRYPTION_PAGE_DLG), hwndDlg, (DLGPROC) PageDialogProc); break; - case NONSYS_INPLACE_ENC_ENCRYPTION_FINISHED_PAGE: + case NONSYS_INPLACE_ENC_TRANSFORM_FINISHED_PAGE: hCurPage = CreateDialogW (hInst, MAKEINTRESOURCEW (IDD_INFO_PAGE_DLG), hwndDlg, (DLGPROC) PageDialogProc); break; + case NONSYS_INPLACE_DEC_TRANSFORM_FINISHED_DRIVE_LETTER_PAGE: + hCurPage = CreateDialogW (hInst, MAKEINTRESOURCEW (IDD_DRIVE_LETTER_SELECTION_PAGE), hwndDlg, + (DLGPROC) PageDialogProc); + break; + case FORMAT_PAGE: hCurPage = CreateDialogW (hInst, MAKEINTRESOURCEW (IDD_FORMAT_PAGE_DLG), hwndDlg, (DLGPROC) PageDialogProc); @@ -3272,7 +3357,7 @@ static BOOL FinalPreTransformPrompts (void) if (bHiddenOS && bHiddenVolHost) StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("OVERWRITEPROMPT_DEVICE_HIDDEN_OS_PARTITION"), szFileName, drive); else - StringCbPrintfW (szTmp, sizeof(szTmp), GetString (bInPlaceEncNonSys ? "NONSYS_INPLACE_ENC_CONFIRM" : "OVERWRITEPROMPT_DEVICE"), type, szFileName, drive); + StringCbPrintfW (szTmp, sizeof(szTmp), GetString (bInPlaceEncNonSys ? (bInPlaceDecNonSys ? "NONSYS_INPLACE_DEC_CONFIRM" : "NONSYS_INPLACE_ENC_CONFIRM") : "OVERWRITEPROMPT_DEVICE"), type, szFileName, drive); x = MessageBoxW (MainDlg, szTmp, lpszTitle, YES_NO | MB_ICONWARNING | (bInPlaceEncNonSys ? MB_DEFBUTTON1 : MB_DEFBUTTON2)); @@ -3339,6 +3424,15 @@ static BOOL FinalPreTransformPrompts (void) return TRUE; } +void UpdateLastDialogId (void) +{ + static char PageDebugId[128]; + + StringCbPrintfA (PageDebugId, sizeof(PageDebugId), "FORMAT_PAGE_%d", nCurPageNo); + LastDialogId = PageDebugId; +} + + void HandleOldAssignedDriveLetter (void) { if (bDevice) @@ -3381,7 +3475,6 @@ static BOOL FileSize4GBLimitQuestionNeeded (void) not. - see DialogProc */ BOOL CALLBACK PageDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { - static char PageDebugId[128]; WORD lw = LOWORD (wParam); WORD hw = HIWORD (wParam); @@ -3392,8 +3485,7 @@ BOOL CALLBACK PageDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa case WM_INITDIALOG: LocalizeDialog (hwndDlg, "IDD_VOL_CREATION_WIZARD_DLG"); - StringCbPrintfA (PageDebugId, sizeof(PageDebugId), "FORMAT_PAGE_%d", nCurPageNo); - LastDialogId = PageDebugId; + UpdateLastDialogId (); switch (nCurPageNo) { @@ -3974,7 +4066,7 @@ BOOL CALLBACK PageDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, KeyFilesEnable); - SetWindowTextW (GetDlgItem (hwndDlg, IDC_BOX_HELP), GetString (bInPlaceEncNonSys ? "NONSYS_INPLACE_ENC_RESUME_PASSWORD_PAGE_HELP" : "PASSWORD_HIDDENVOL_HOST_DIRECT_HELP")); + SetWindowTextW (GetDlgItem (hwndDlg, IDC_BOX_HELP), GetString (bInPlaceEncNonSys ? (bInPlaceEncNonSysResumed ? "NONSYS_INPLACE_ENC_RESUME_PASSWORD_PAGE_HELP" : "NONSYS_INPLACE_DEC_PASSWORD_PAGE_HELP") : "PASSWORD_HIDDENVOL_HOST_DIRECT_HELP")); SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_BOX_TITLE), GetString (bInPlaceEncNonSys ? "PASSWORD" : "PASSWORD_HIDVOL_HOST_TITLE")); @@ -4367,7 +4459,7 @@ BOOL CALLBACK PageDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa break; - case NONSYS_INPLACE_ENC_ENCRYPTION_PAGE: + case NONSYS_INPLACE_ENC_TRANSFORM_PAGE: if (bInPlaceEncNonSysResumed) { @@ -4377,19 +4469,19 @@ BOOL CALLBACK PageDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa nWipeMode = savedWipeAlgorithm; } - SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_BOX_TITLE), GetString ("ENCRYPTION")); + SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_BOX_TITLE), GetString (bInPlaceDecNonSys ? "DECRYPTION" : "ENCRYPTION")); - SetWindowTextW (GetDlgItem (hwndDlg, IDC_BOX_HELP), GetString ("NONSYS_INPLACE_ENC_ENCRYPTION_PAGE_INFO")); + SetWindowTextW (GetDlgItem (hwndDlg, IDC_BOX_HELP), GetString (bInPlaceDecNonSys ? "NONSYS_INPLACE_DEC_DECRYPTION_PAGE_INFO" : "NONSYS_INPLACE_ENC_ENCRYPTION_PAGE_INFO")); SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDCANCEL), GetString (bInPlaceEncNonSysResumed ? "DEFER" : "CANCEL")); SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_PREV), GetString ("PREV")); - SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_NEXT), GetString (bInPlaceEncNonSysResumed ? "RESUME" : "ENCRYPT")); + SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_NEXT), GetString (bInPlaceEncNonSysResumed ? "RESUME" : (bInPlaceDecNonSys ? "DECRYPT" : "ENCRYPT"))); SetWindowTextW (GetDlgItem (hwndDlg, IDC_PAUSE), GetString ("IDC_PAUSE")); - EnableWindow (GetDlgItem (GetParent (hwndDlg), IDC_PREV), !bInPlaceEncNonSysResumed); + EnableWindow (GetDlgItem (GetParent (hwndDlg), IDC_PREV), !bInPlaceEncNonSysResumed && !bInPlaceDecNonSys); EnableWindow (GetDlgItem (GetParent (hwndDlg), IDC_NEXT), TRUE); EnableWindow (GetDlgItem (GetParent (hwndDlg), IDCANCEL), TRUE); EnableWindow (GetDlgItem (GetParent (hwndDlg), IDHELP), TRUE); @@ -4397,19 +4489,28 @@ BOOL CALLBACK PageDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa ShowWindow (GetDlgItem (hwndDlg, IDC_MORE_INFO_SYS_ENCRYPTION), SW_HIDE); - EnableWindow (GetDlgItem (hwndDlg, IDC_WIPE_MODE), TRUE); - PopulateWipeModeCombo (GetDlgItem (hwndDlg, IDC_WIPE_MODE), FALSE, TRUE, FALSE); - SelectAlgo (GetDlgItem (hwndDlg, IDC_WIPE_MODE), (int *) &nWipeMode); + if (bInPlaceDecNonSys) + { + ShowWindow(GetDlgItem(hwndDlg, IDT_FORMAT_OPTIONS), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDT_WIPE_MODE), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_WIPE_MODE), SW_HIDE); + } + else + { + EnableWindow (GetDlgItem (hwndDlg, IDC_WIPE_MODE), TRUE); + PopulateWipeModeCombo (GetDlgItem (hwndDlg, IDC_WIPE_MODE), FALSE, TRUE, FALSE); + SelectAlgo (GetDlgItem (hwndDlg, IDC_WIPE_MODE), (int *) &nWipeMode); + } break; - case NONSYS_INPLACE_ENC_ENCRYPTION_FINISHED_PAGE: + case NONSYS_INPLACE_ENC_TRANSFORM_FINISHED_PAGE: bConfirmQuit = FALSE; - SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_BOX_TITLE), GetString ("NONSYS_INPLACE_ENC_FINISHED_TITLE")); + SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_BOX_TITLE), GetString (bInPlaceDecNonSys ? "NONSYS_INPLACE_DEC_FINISHED_TITLE" : "NONSYS_INPLACE_ENC_FINISHED_TITLE")); - SetWindowTextW (GetDlgItem (hwndDlg, IDC_BOX_HELP), GetString ("NONSYS_INPLACE_ENC_FINISHED_INFO")); + SetWindowTextW (GetDlgItem (hwndDlg, IDC_BOX_HELP), GetString (bInPlaceDecNonSys ? "NONSYS_INPLACE_DEC_FINISHED_INFO" : "NONSYS_INPLACE_ENC_FINISHED_INFO")); SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_PREV), GetString ("PREV")); SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_NEXT), GetString ("FINALIZE")); @@ -4421,6 +4522,54 @@ BOOL CALLBACK PageDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa break; + case NONSYS_INPLACE_DEC_TRANSFORM_FINISHED_DRIVE_LETTER_PAGE: + + SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_BOX_TITLE), GetString ("NONSYS_INPLACE_DEC_FINISHED_TITLE")); + + SetWindowTextW (GetDlgItem (hwndDlg, IDC_BOX_HELP), GetString ("NONSYS_INPLACE_DEC_FINISHED_DRIVE_LETTER_SEL_INFO")); + + SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_PREV), GetString ("PREV")); + SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDC_NEXT), GetString ("FINALIZE")); + EnableWindow (GetDlgItem (GetParent (hwndDlg), IDC_PREV), FALSE); + EnableWindow (GetDlgItem (GetParent (hwndDlg), IDC_NEXT), TRUE); + + SetWindowTextW (GetDlgItem (GetParent (hwndDlg), IDCANCEL), GetString ("CANCEL")); + + // The Cancel button and the X button must be disabled to prevent the user from forgetting to assign a drive letter to the partition by closing + // the window accidentally or clicking Cancel. The user is forced to click Finish to assign at least the pre-selected free drive letter. + // This is critical because inexperienced users would not know how to access data on the decrypted volume without a drive letter. + EnableWindow (GetDlgItem (GetParent (hwndDlg), IDCANCEL), FALSE); + DisableCloseButton (MainDlg); + bConfirmQuit = TRUE; // Alt-F4 will still work but the user will be prompted to confirm the action. + + // Decryption of non-system volume finished, no drive letter is assigned to the decrypted volume, and free drive letters are available. + // This is critical because inexperienced users would not know how to access data on the decrypted volume. We cannot allow exit + // until a drive letter is freed up and assigned to the decrypted volume. + + while (GetFirstAvailableDrive () == -1) + { + Error ("NONSYS_INPLACE_DEC_FINISHED_NO_DRIVE_LETTER_AVAILABLE", hwndDlg); + } + + // Populate the combobox with free drive letters + { + DWORD dwUsedDrives = GetLogicalDrives(); + char szDriveLetter[] = {' ', ':', 0 }; + int i; + + for (i = 0; i < 26; i++) + { + if (!(dwUsedDrives & 1 << i)) + { + // Add + szDriveLetter [0] = (char) (i + 'A'); + AddComboPair (GetDlgItem (hCurPage, IDC_DRIVE_LETTER_LIST), szDriveLetter, i); + } + } + } + SendMessage (GetDlgItem (hwndDlg, IDC_DRIVE_LETTER_LIST), CB_SETCURSEL, 0, 0); + break; + case FORMAT_PAGE: { BOOL bNTFSallowed = FALSE; @@ -4967,7 +5116,7 @@ BOOL CALLBACK PageDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa } break; - case NONSYS_INPLACE_ENC_ENCRYPTION_PAGE: + case NONSYS_INPLACE_ENC_TRANSFORM_PAGE: { switch (lw) { @@ -5664,6 +5813,8 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa KillTimer (hwndDlg, TIMER_ID_SYSENC_PROGRESS); + UpdateLastDialogId (); + try { if (BootEncStatus.DriveMounted) // If we had been really encrypting/decrypting (not just proceeding to deinstall) @@ -5788,6 +5939,8 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa if (!bVolTransformThreadRunning && !bVolTransformThreadToRun) { KillTimer (hwndDlg, TIMER_ID_NONSYS_INPLACE_ENC_PROGRESS); + + UpdateLastDialogId (); } UpdateNonSysInPlaceEncControls (); @@ -5927,6 +6080,7 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa // The driver stopped wiping KillTimer (hwndDlg, TIMER_ID_WIPE_PROGRESS); + UpdateLastDialogId (); try { @@ -6010,8 +6164,29 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa KillTimer (hwndDlg, TIMER_ID_NONSYS_INPLACE_ENC_PROGRESS); - LoadPage (hwndDlg, NONSYS_INPLACE_ENC_ENCRYPTION_FINISHED_PAGE); + if (bInPlaceDecNonSys) + { + // Decryption of non-system volume finished and free drive letters are available. Check if a drive letter is assigned to the decrypted volume. + + WCHAR deviceName[MAX_PATH + 1]; + StringCbCopyA ((char *)deviceName, sizeof(deviceName), szDiskFile); + ToUNICODE ((char *)deviceName, sizeof(deviceName)); + + if (GetDiskDeviceDriveLetter (deviceName) < 0) + { + // No drive letter is assigned to the device + MessageBeep (MB_OK); + LoadPage (hwndDlg, NONSYS_INPLACE_DEC_TRANSFORM_FINISHED_DRIVE_LETTER_PAGE); + return 1; + } + else + { + Info ("NONSYS_INPLACE_DEC_FINISHED_INFO", hwndDlg); + } + } + + LoadPage (hwndDlg, NONSYS_INPLACE_ENC_TRANSFORM_FINISHED_PAGE); return 1; case TC_APPMSG_VOL_TRANSFORM_THREAD_ENDED: @@ -6050,7 +6225,7 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa case TC_APPMSG_FORMAT_USER_QUIT: - if (nCurPageNo == NONSYS_INPLACE_ENC_ENCRYPTION_PAGE + if (nCurPageNo == NONSYS_INPLACE_ENC_TRANSFORM_PAGE && (bVolTransformThreadRunning || bVolTransformThreadToRun || bInPlaceEncNonSysResumed)) { // Non-system encryption in progress @@ -6970,10 +7145,10 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa } } } - else + else if (bInPlaceEncNonSysResumed) { /* Scan all available partitions to discover all partitions where non-system in-place - encryption has been interrupted. */ + encryption/decryption has been interrupted. */ BOOL tmpbDevice; @@ -7002,12 +7177,115 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa return 1; } - nNewPageNo = NONSYS_INPLACE_ENC_ENCRYPTION_PAGE - 1; // Skip irrelevant pages + nNewPageNo = NONSYS_INPLACE_ENC_TRANSFORM_PAGE - 1; // Skip irrelevant pages } NormalCursor(); } + else + { + /* Try to mount the non-system volume to decrypt in place (the process has not started yet, we are NOT trying to resume it). + We will try to mount it using the backup header, which we require to work (i.e. be non-damaged) before we start writing + to the volume (the primary header will be overwritten by decrypted data soon after the decryption process begins, so the + backup header will contain the only copy of the master key). */ + + int driveNo = -1; + + // The volume may already be mounted. We need to dismount it first in order to verify the supplied password/keyfile(s) is/are correct. + if (IsMountedVolume (szFileName)) + { + driveNo = GetMountedVolumeDriveNo (szFileName); + + if (driveNo == -1 + || !UnmountVolume (hwndDlg, driveNo, TRUE)) + { + handleWin32Error (MainDlg); + AbortProcess ("CANT_DISMOUNT_VOLUME"); + } + } + + driveNo = GetLastAvailableDrive (); + + if (driveNo < 0) + AbortProcess ("NO_FREE_DRIVES"); + + MountOptions mountOptions; + ZeroMemory (&mountOptions, sizeof (mountOptions)); + + mountOptions.UseBackupHeader = FALSE; // This must be FALSE at this point because otherwise we wouldn't be able to detect a legacy volume + mountOptions.ReadOnly = TRUE; + mountOptions.Removable = ConfigReadInt ("MountVolumesRemovable", FALSE); + + // Check that it is not a hidden or legacy volume + + if (MountVolume (hwndDlg, driveNo, szFileName, &volumePassword, hash_algo, FALSE, FALSE, TRUE, &mountOptions, FALSE, TRUE) < 1) + { + NormalCursor(); + return 1; + } + + { + DWORD dwResult; + VOLUME_PROPERTIES_STRUCT volProp; + + memset (&volProp, 0, sizeof(volProp)); + volProp.driveNo = driveNo; + if (!DeviceIoControl (hDriver, TC_IOCTL_GET_VOLUME_PROPERTIES, &volProp, sizeof (volProp), &volProp, sizeof (volProp), &dwResult, NULL) || dwResult == 0) + { + handleWin32Error (hwndDlg); + UnmountVolume (hwndDlg, driveNo, TRUE); + AbortProcess ("CANT_GET_VOL_INFO"); + } + + if (volProp.volFormatVersion == TC_VOLUME_FORMAT_VERSION_PRE_6_0) + { + UnmountVolume (hwndDlg, driveNo, TRUE); + AbortProcess ("NONSYS_INPLACE_DECRYPTION_BAD_VOL_FORMAT"); + } + + if (volProp.hiddenVolume) + { + UnmountVolume (hwndDlg, driveNo, TRUE); + AbortProcess ("NONSYS_INPLACE_DECRYPTION_CANT_DECRYPT_HID_VOL"); + } + } + + // Remount the volume using the backup header to verify it is working + + if (!UnmountVolume (hwndDlg, driveNo, TRUE)) + { + handleWin32Error (MainDlg); + AbortProcess ("CANT_DISMOUNT_VOLUME"); + } + + mountOptions.UseBackupHeader = TRUE; // This must be TRUE at this point (we won't be using the regular header, which will be lost soon after the decryption process starts) + + if (MountVolume (hwndDlg, driveNo, szFileName, &volumePassword, hash_algo, FALSE, FALSE, TRUE, &mountOptions, FALSE, TRUE) < 1) + { + NormalCursor(); + return 1; + } + + if (!UnmountVolume (hwndDlg, driveNo, TRUE)) + { + handleWin32Error (MainDlg); + AbortProcess ("CANT_DISMOUNT_VOLUME"); + } + + BOOL tmpbDevice; + + CreateFullVolumePath (szDiskFile, sizeof(szDiskFile), szFileName, &tmpbDevice); + + nVolumeSize = GetDeviceSize (szDiskFile); + if (nVolumeSize == -1) + { + handleWin32Error (MainDlg); + AbortProcessSilent (); + } + nNewPageNo = NONSYS_INPLACE_ENC_TRANSFORM_PAGE - 1; // Skip irrelevant pages + NormalCursor(); + } } else if (nCurPageNo == FILESYS_PAGE) @@ -7312,20 +7590,76 @@ retryCDDriveCheck: } else if (nCurPageNo == NONSYS_INPLACE_ENC_RESUME_PARTITION_SEL_PAGE) { - nNewPageNo = NONSYS_INPLACE_ENC_ENCRYPTION_PAGE - 1; // Skip irrelevant pages + nNewPageNo = NONSYS_INPLACE_ENC_TRANSFORM_PAGE - 1; // Skip irrelevant pages } - else if (nCurPageNo == NONSYS_INPLACE_ENC_ENCRYPTION_PAGE) + else if (nCurPageNo == NONSYS_INPLACE_ENC_TRANSFORM_PAGE) { /* In-place encryption start (the 'Next' button has been clicked) */ + if (bInPlaceDecNonSys + && !bInPlaceEncNonSysResumed + && AskWarnYesNo ("NONSYS_INPLACE_ENC_CONFIRM_BACKUP", hwndDlg) == IDNO) + { + // Cancel + return 1; + } NonSysInplaceEncResume (); return 1; } - else if (nCurPageNo == NONSYS_INPLACE_ENC_ENCRYPTION_FINISHED_PAGE) + else if (nCurPageNo == NONSYS_INPLACE_ENC_TRANSFORM_FINISHED_PAGE) { PostMessage (hwndDlg, TC_APPMSG_FORMAT_USER_QUIT, 0, 0); return 1; } + else if (nCurPageNo == NONSYS_INPLACE_DEC_TRANSFORM_FINISHED_DRIVE_LETTER_PAGE) + { + BOOL bDrvLetterAssignResult = FALSE; + + int tmpDriveLetter = (int) SendMessage (GetDlgItem (hCurPage, IDC_DRIVE_LETTER_LIST), + CB_GETITEMDATA, + SendMessage (GetDlgItem (hCurPage, IDC_DRIVE_LETTER_LIST), CB_GETCURSEL, 0, 0), + 0); + + if (tmpDriveLetter < 0) + tmpDriveLetter = GetFirstAvailableDrive (); + + do + { + char szDriveLetter[] = {'A', ':', 0 }; + char rootPath[] = {'A', ':', '\\', 0 }; + char uniqVolName[MAX_PATH+1] = { 0 }; + + rootPath[0] += (char) tmpDriveLetter; + szDriveLetter[0] += (char) tmpDriveLetter; + + if (DefineDosDevice (DDD_RAW_TARGET_PATH, szDriveLetter, szDiskFile)) + { + bDrvLetterAssignResult = GetVolumeNameForVolumeMountPoint (rootPath, uniqVolName, MAX_PATH); + + DefineDosDevice (DDD_RAW_TARGET_PATH|DDD_REMOVE_DEFINITION|DDD_EXACT_MATCH_ON_REMOVE, + szDriveLetter, + szDiskFile); + + if (bDrvLetterAssignResult) + { + if (SetVolumeMountPoint (rootPath, uniqVolName) == 0) + bDrvLetterAssignResult = FALSE; + } + } + + if (!bDrvLetterAssignResult) + { + if (AskErrYesNo ("ERR_CANNOT_ASSIGN_DRIVE_LETTER_NONSYS_DEC", hwndDlg) == IDNO) + break; + } + + } while (bDrvLetterAssignResult == FALSE); + + bConfirmQuit = FALSE; + + PostMessage (hwndDlg, TC_APPMSG_FORMAT_USER_QUIT, 0, 0); + return 1; + } else if (nCurPageNo == FORMAT_PAGE) { /* Format start (the 'Next' button has been clicked on the Format page) */ @@ -7906,26 +8240,33 @@ void ExtractCommandLine (HWND hwndDlg, char *lpszCommandLine) CommandDecryptSysEnc, CommandEncDev, CommandHiddenSys, - CommandResumeInplaceLogOn, + CommandResumeNonSysInplaceLogOn, CommandResumeHiddenSys, CommandSysEnc, + CommandInplaceDec, + CommandResumeInplaceDec, CommandResumeInplace, }; argument args[]= { + // Public { OptionHistory, "/history", "/h", FALSE }, { OptionNoIsoCheck, "/noisocheck", "/n", FALSE }, { OptionTokenLib, "/tokenlib", NULL, FALSE }, { OptionQuit, "/quit", "/q", FALSE }, + + // Internal { CommandResumeSysEncLogOn, "/acsysenc", "/a", TRUE }, { CommandResumeSysEnc, "/csysenc", "/c", TRUE }, { CommandDecryptSysEnc, "/dsysenc", "/d", TRUE }, { CommandEncDev, "/encdev", "/e", TRUE }, { CommandHiddenSys, "/isysenc", "/i", TRUE }, - { CommandResumeInplaceLogOn, "/prinplace", "/p", TRUE }, + { CommandResumeNonSysInplaceLogOn, "/prinplace", "/p", TRUE }, { CommandResumeHiddenSys, "/risysenc", "/r", TRUE }, { CommandSysEnc, "/sysenc", "/s", TRUE }, + { CommandInplaceDec, "/inplacedec", NULL, TRUE }, + { CommandResumeInplaceDec, "/resumeinplacedec",NULL, TRUE }, { CommandResumeInplace, "/zinplace", "/z", TRUE } }; @@ -8053,12 +8394,36 @@ void ExtractCommandLine (HWND hwndDlg, char *lpszCommandLine) DirectDeviceEncMode = TRUE; break; + case CommandInplaceDec: + // Start (not resume) decrypting the specified non-system volume in place + { + char szTmp [TC_MAX_PATH + 8000] = {0}; + + GetArgumentValue (lpszCommandLineArgs, &i, nNoCommandLineArgs, szTmp, sizeof (szTmp)); + + if (strlen (szTmp) < 1) + { + // No valid volume path specified as command-line parameter + AbortProcess ("ERR_PARAMETER_INCORRECT"); + } + + memset (szFileName, 0, sizeof (szFileName)); + StringCbCopyA (szFileName, sizeof (szFileName), szTmp); + DirectNonSysInplaceDecStartMode = TRUE; + } + break; + case CommandResumeInplace: // Resume interrupted process of non-system in-place encryption of a partition DirectNonSysInplaceEncResumeMode = TRUE; break; - case CommandResumeInplaceLogOn: + case CommandResumeInplaceDec: + // Resume interrupted process of non-system in-place decryption of a partition + DirectNonSysInplaceDecResumeMode = TRUE; + break; + + case CommandResumeNonSysInplaceLogOn: // Ask the user whether to resume interrupted process of non-system in-place encryption of a partition // This switch is passed only by the system (from the startup sequence). DirectPromptNonSysInplaceEncResumeMode = TRUE; @@ -8641,7 +9006,7 @@ static void AfterWMInitTasks (HWND hwndDlg) else { // Nothing to resume - Warning ("NOTHING_TO_RESUME", hwndDlg); + Warning ("NO_SYS_ENC_PROCESS_TO_RESUME", hwndDlg); EndMainDlg (MainDlg); return; @@ -8985,7 +9350,7 @@ static void AfterWMInitTasks (HWND hwndDlg) && !bInPlaceEncNonSysPending) { // This instance of the wizard has been launched via the system startup sequence to prompt for resume of - // a non-system in-place encryption process. However, no config file indicates that any such process + // a non-system in-place encryption/decryption process. However, no config file indicates that any such process // has been interrupted. This inconsistency may occur, for example, when the process is finished // but the wizard is not removed from the startup sequence because system encryption is in progress. // Therefore, we remove it from the startup sequence now if possible. @@ -8996,9 +9361,16 @@ static void AfterWMInitTasks (HWND hwndDlg) AbortProcessSilent (); } - if (DirectNonSysInplaceEncResumeMode) + BOOL bDecrypt = FALSE; + + if (DirectNonSysInplaceDecStartMode) + { + SwitchWizardToNonSysInplaceDecStartMode (szFileName); + return; + } + else if (DirectNonSysInplaceEncResumeMode || DirectNonSysInplaceDecResumeMode) { - SwitchWizardToNonSysInplaceEncResumeMode(); + SwitchWizardToNonSysInplaceEncResumeMode (DirectNonSysInplaceDecResumeMode); return; } else if (DirectPromptNonSysInplaceEncResumeMode) @@ -9006,8 +9378,8 @@ static void AfterWMInitTasks (HWND hwndDlg) if (NonSysInplaceEncInProgressElsewhere ()) AbortProcessSilent (); - if (AskNonSysInPlaceEncryptionResume(hwndDlg) == IDYES) - SwitchWizardToNonSysInplaceEncResumeMode(); + if (AskNonSysInPlaceEncryptionResume(hwndDlg, &bDecrypt) == IDYES) + SwitchWizardToNonSysInplaceEncResumeMode(bDecrypt); else AbortProcessSilent (); @@ -9015,9 +9387,9 @@ static void AfterWMInitTasks (HWND hwndDlg) } else if (bInPlaceEncNonSysPending && !NonSysInplaceEncInProgressElsewhere () - && AskNonSysInPlaceEncryptionResume(hwndDlg) == IDYES) + && AskNonSysInPlaceEncryptionResume(hwndDlg, &bDecrypt) == IDYES) { - SwitchWizardToNonSysInplaceEncResumeMode(); + SwitchWizardToNonSysInplaceEncResumeMode(bDecrypt); return; } diff --git a/src/Format/Tcformat.h b/src/Format/Tcformat.h index 77579f54..15a81534 100644 --- a/src/Format/Tcformat.h +++ b/src/Format/Tcformat.h @@ -42,6 +42,7 @@ void DisplaySizingErrorText ( HWND hwndTextBox ); void EnableDisableFileNext ( HWND hComboBox , HWND hMainButton ); BOOL QueryFreeSpace ( HWND hwndDlg , HWND hwndTextBox , BOOL display ); static BOOL FinalPreTransformPrompts (void); +void UpdateLastDialogId (void); void HandleOldAssignedDriveLetter (void); void AddCipher ( HWND hComboBox , char *lpszCipher , int nCipher ); BOOL CALLBACK PageDialogProc ( HWND hwndDlg , UINT uMsg , WPARAM wParam , LPARAM lParam ); @@ -90,6 +91,7 @@ extern volatile BOOL bVolTransformThreadCancel; extern volatile BOOL bInPlaceEncNonSysResumed; extern volatile BOOL bFirstNonSysInPlaceEncResumeDone; extern volatile BOOL bInPlaceEncNonSys; +extern volatile BOOL bInPlaceDecNonSys; extern __int64 NonSysInplaceEncBytesDone; extern __int64 NonSysInplaceEncTotalSize; extern int nPbar; diff --git a/src/Mount/Mount.c b/src/Mount/Mount.c index 716f7926..1288f8df 100644 --- a/src/Mount/Mount.c +++ b/src/Mount/Mount.c @@ -454,6 +454,184 @@ BOOL ActiveSysEncDeviceSelected (void) return FALSE; } +// When a function does not require the affected volume to be dismounted, there may be cases where we have two valid +// paths selected in the main window and we cannot be sure which of them the user really intends to apply the function to. +// This function asks the user to explicitly select either the volume path specified in the input field below the main +// drive list (whether mounted or not), or the path to the volume selected in the main drive list. If, however, both +// of the GUI elements contain the same volume (or one of them does not contain any path), this function does not +// ask the user and returns the volume path directly (no selection ambiguity). +// If driveNoPtr is not NULL, and the volume is mounted, its drive letter is returned in *driveNoPtr (if no valid drive +// letter is resolved, -1 is stored instead). +static string ResolveAmbiguousSelection (HWND hwndDlg, int *driveNoPtr) +{ + LPARAM selectedDrive = GetSelectedLong (GetDlgItem (MainDlg, IDC_DRIVELIST)); + + char volPathInputField [TC_MAX_PATH]; + wchar_t volPathInputFieldW [TC_MAX_PATH]; + + wchar_t volPathDriveListW [TC_MAX_PATH]; + string volPathDriveListStr; + wstring volPathDriveListWStr; + + string retPath; + + VOLUME_PROPERTIES_STRUCT prop; + DWORD dwResult; + + BOOL useInputField = TRUE; + + memset (&prop, 0, sizeof(prop)); + + BOOL ambig = (LOWORD (selectedDrive) != TC_MLIST_ITEM_FREE && LOWORD (selectedDrive) != 0xffff && HIWORD (selectedDrive) != 0xffff + && VolumeSelected (MainDlg)); + + if (VolumeSelected (MainDlg)) + { + // volPathInputField will contain the volume path (if any) from the input field below the drive list + GetWindowText (GetDlgItem (MainDlg, IDC_VOLUME), volPathInputField, sizeof (volPathInputField)); + + if (!ambig) + retPath = (string) volPathInputField; + } + + if (LOWORD (selectedDrive) != TC_MLIST_ITEM_FREE && LOWORD (selectedDrive) != 0xffff && HIWORD (selectedDrive) != 0xffff) + { + // A volume is selected in the main drive list. + + switch (LOWORD (selectedDrive)) + { + case TC_MLIST_ITEM_NONSYS_VOL: + prop.driveNo = HIWORD (selectedDrive) - 'A'; + + if (!DeviceIoControl (hDriver, TC_IOCTL_GET_VOLUME_PROPERTIES, &prop, sizeof (prop), &prop, sizeof (prop), &dwResult, NULL) || dwResult == 0) + { + // The driver did not return any path for this drive letter (the volume may have been dismounted). + + // Return whatever is in the input field below the drive list (even if empty) + return ((string) volPathInputField); + } + + // volPathDriveListWStr will contain the volume path selected in the main drive list + volPathDriveListWStr = (wstring) prop.wszVolume; + volPathDriveListStr = WideToSingleString (volPathDriveListWStr); + break; + + case TC_MLIST_ITEM_SYS_PARTITION: + + GetSysDevicePaths (MainDlg); + + if (bCachedSysDevicePathsValid) + { + volPathDriveListStr = (string) SysPartitionDevicePath; + volPathDriveListWStr = SingleStringToWide (volPathDriveListStr); + } + + break; + + case TC_MLIST_ITEM_SYS_DRIVE: + + GetSysDevicePaths (MainDlg); + + if (bCachedSysDevicePathsValid) + { + volPathDriveListStr = (string) SysDriveDevicePath; + volPathDriveListWStr = SingleStringToWide (volPathDriveListStr); + } + + break; + } + + if (!ambig) + { + useInputField = FALSE; + retPath = volPathDriveListStr; + } + } + + if (ambig) + { + /* We have two paths. Compare them and if they don't match, ask the user to select one of them. Otherwise, return the path without asking. */ + + if (memcmp (volPathDriveListStr.c_str (), "\\??\\", 4) == 0) + { + // The volume path starts with "\\??\\" which is used for file-hosted containers. We're going to strip this prefix. + + volPathDriveListStr = (string) (volPathDriveListStr.c_str () + 4); + volPathDriveListWStr = SingleStringToWide (volPathDriveListStr); + } + + StringCbCopyW (volPathDriveListW, sizeof(volPathDriveListW), SingleStringToWide (volPathDriveListStr).c_str ()); + + ToSBCS (volPathDriveListW, sizeof(volPathDriveListW)); + StringCbCopyA ((char *) volPathInputFieldW, sizeof(volPathInputFieldW), volPathInputField); + ToUNICODE ((char *) volPathInputFieldW, sizeof(volPathInputFieldW)); + + if (strcmp (((memcmp ((char *) volPathDriveListW, "\\??\\", 4) == 0) ? (char *) volPathDriveListW + 4 : (char *) volPathDriveListW), volPathInputField) != 0) + { + // The path selected in the input field is different from the path to the volume selected + // in the drive lettter list. We have to resolve possible ambiguity. + + wchar_t *tmp[] = {L"", L"", L"", L"", L"", 0}; + const int maxVolPathLen = 80; + + if (volPathDriveListWStr.length () > maxVolPathLen) + { + // Ellipsis (path too long) + volPathDriveListWStr = wstring (L"...") + volPathDriveListWStr.substr (volPathDriveListWStr.length () - maxVolPathLen, maxVolPathLen); + } + + wstring volPathInputFieldWStr (volPathInputFieldW); + + if (volPathInputFieldWStr.length () > maxVolPathLen) + { + // Ellipsis (path too long) + volPathInputFieldWStr = wstring (L"...") + volPathInputFieldWStr.substr (volPathInputFieldWStr.length () - maxVolPathLen, maxVolPathLen); + } + + tmp[1] = GetString ("AMBIGUOUS_VOL_SELECTION"); + tmp[2] = (wchar_t *) volPathDriveListWStr.c_str(); + tmp[3] = (wchar_t *) volPathInputFieldWStr.c_str(); + tmp[4] = GetString ("IDCANCEL"); + + switch (AskMultiChoice ((void **) tmp, FALSE, hwndDlg)) + { + case 1: + retPath = volPathDriveListStr; + break; + + case 2: + retPath = (string) volPathInputField; + break; + + default: + if (driveNoPtr != NULL) + *driveNoPtr = -1; + + return string (""); + } + } + else + { + // Both selected paths are the same + retPath = (string) volPathInputField; + } + } + + if (driveNoPtr != NULL) + *driveNoPtr = GetMountedVolumeDriveNo ((char *) retPath.c_str ()); + + + if (memcmp (retPath.c_str (), "\\??\\", 4) == 0) + { + // The selected volume path starts with "\\??\\" which is used for file-hosted containers. We're going to strip this prefix. + + retPath = (string) (retPath.c_str () + 4); + } + + return retPath; +} + + void LoadSettings (HWND hwndDlg) { EnableHwEncryption ((ReadDriverConfigurationFlags() & TC_DRIVER_CONFIG_DISABLE_HARDWARE_ENCRYPTION) ? FALSE : TRUE); @@ -730,7 +908,7 @@ static BOOL SysEncDeviceActive (BOOL bSilent) return (BootEncStatus.DriveMounted); } -// Returns TRUE if the entire system drive (as opposed to the system partition only) is (or is to be) encrypted +// Returns TRUE if the entire system drive (as opposed to the system partition only) of the currently running OS is (or is to be) encrypted BOOL WholeSysDriveEncryption (BOOL bSilent) { try @@ -956,18 +1134,16 @@ BOOL CheckSysEncMountWithoutPBA (HWND hwndDlg, const char *devicePath, BOOL quie // Returns TRUE if the host drive of the specified partition contains a portion of the TrueCrypt Boot Loader // and if the drive is not within key scope of active system encryption (e.g. the system drive of the running OS). // If bPrebootPasswordDlgMode is TRUE, this function returns FALSE (because the check would be redundant). -BOOL TCBootLoaderOnInactiveSysEncDrive (void) +BOOL TCBootLoaderOnInactiveSysEncDrive (char *szDevicePath) { try { int driveNo; - char szDevicePath [TC_MAX_PATH+1]; char parentDrivePath [TC_MAX_PATH+1]; if (bPrebootPasswordDlgMode) return FALSE; - GetWindowText (GetDlgItem (MainDlg, IDC_VOLUME), szDevicePath, sizeof (szDevicePath)); if (sscanf (szDevicePath, "\\Device\\Harddisk%d\\Partition", &driveNo) != 1) return FALSE; @@ -1037,7 +1213,7 @@ BOOL SelectItem (HWND hTree, char nLetter) static void LaunchVolCreationWizard (HWND hwndDlg, const char *arg) { - char t[TC_MAX_PATH] = {'"',0}; + char t[TC_MAX_PATH + 1024] = {'"',0}; char *tmp; GetModuleFileName (NULL, t+1, sizeof(t)-1); @@ -3671,7 +3847,9 @@ LPARAM GetSelectedLong (HWND hTree) item.mask = LVIF_PARAM; item.iItem = hItem; - if (ListView_GetItem (hTree, &item) == FALSE) + if ( (ListView_GetItemCount (hTree) < 1) + || (ListView_GetItem (hTree, &item) == FALSE) + ) return MAKELONG (0xffff, 0xffff); else return item.lParam; @@ -4490,7 +4668,7 @@ static void EncryptSystemDevice (HWND hwndDlg) if (!MutexExistsOnSystem (TC_MUTEX_NAME_SYSENC)) // If no instance of the wizard is currently taking care of system encryption { - LaunchVolCreationWizard (MainDlg, "/sysenc"); + LaunchVolCreationWizard (hwndDlg, "/sysenc"); } else Warning ("SYSTEM_ENCRYPTION_IN_PROGRESS_ELSEWHERE", hwndDlg); @@ -4504,7 +4682,7 @@ static void EncryptSystemDevice (HWND hwndDlg) if (!MutexExistsOnSystem (TC_MUTEX_NAME_SYSENC)) // If no instance of the wizard is currently taking care of system encryption { - LaunchVolCreationWizard (MainDlg, "/sysenc"); + LaunchVolCreationWizard (hwndDlg, "/sysenc"); } else Warning ("SYSTEM_ENCRYPTION_IN_PROGRESS_ELSEWHERE", hwndDlg); @@ -4584,7 +4762,7 @@ static void DecryptSystemDevice (HWND hwndDlg) } CloseSysEncMutex (); - LaunchVolCreationWizard (MainDlg, "/dsysenc"); + LaunchVolCreationWizard (hwndDlg, "/dsysenc"); } else Warning ("SYSTEM_ENCRYPTION_IN_PROGRESS_ELSEWHERE", hwndDlg); @@ -4599,7 +4777,118 @@ static void CreateHiddenOS (HWND hwndDlg) // such information, but will exit (displaying only an error meessage). Info("HIDDEN_OS_PREINFO", hwndDlg); - LaunchVolCreationWizard (MainDlg, "/isysenc"); + LaunchVolCreationWizard (hwndDlg, "/isysenc"); +} + +static void DecryptNonSysDevice (HWND hwndDlg, BOOL bResolveAmbiguousSelection, BOOL bUseDriveListSel) +{ + string scPath; + + if (bResolveAmbiguousSelection) + { + scPath = ResolveAmbiguousSelection (hwndDlg, NULL); + + if (scPath.empty ()) + { + // The user selected Cancel + return; + } + } + else if (bUseDriveListSel) + { + // Decrypt mounted volume selected in the main drive list + + LPARAM lLetter = GetSelectedLong (GetDlgItem (MainDlg, IDC_DRIVELIST)); + + if (LOWORD (lLetter) != 0xffff) + { + VOLUME_PROPERTIES_STRUCT prop; + DWORD bytesReturned; + + memset (&prop, 0, sizeof (prop)); + prop.driveNo = (char) HIWORD (lLetter) - 'A'; + + if (!DeviceIoControl (hDriver, TC_IOCTL_GET_VOLUME_PROPERTIES, &prop, sizeof (prop), &prop, sizeof (prop), &bytesReturned, NULL)) + { + handleWin32Error (MainDlg); + return; + } + + scPath = WideToSingleString ((wchar_t *) prop.wszVolume); + } + else + return; + } + else + { + // Decrypt volume specified in the input field below the main drive list + + char volPath [TC_MAX_PATH]; + + GetWindowText (GetDlgItem (MainDlg, IDC_VOLUME), volPath, sizeof (volPath)); + + scPath = volPath; + } + + if (scPath.empty ()) + { + Warning ("NO_VOLUME_SELECTED", hwndDlg); + return; + } + + WaitCursor(); + + switch (IsSystemDevicePath ((char *) scPath.c_str (), MainDlg, TRUE)) + { + case 1: + case 2: + // The user wants to decrypt the system partition/drive. Divert to the appropriate function. + + NormalCursor (); + + DecryptSystemDevice (hwndDlg); + return; + } + + WaitCursor(); + + // Make sure the user is not attempting to decrypt a partition on an entirely encrypted system drive. + if (IsNonSysPartitionOnSysDrive (scPath.c_str ()) == 1) + { + if (WholeSysDriveEncryption (TRUE)) + { + // The system drive is entirely encrypted and the encrypted OS is running + + NormalCursor (); + + Warning ("CANT_DECRYPT_PARTITION_ON_ENTIRELY_ENCRYPTED_SYS_DRIVE", hwndDlg); + return; + } + } + else if (TCBootLoaderOnInactiveSysEncDrive ((char *) scPath.c_str ())) + { + // The system drive MAY be entirely encrypted (external access without PBA) and the potentially encrypted OS is not running + + NormalCursor (); + + Warning ("CANT_DECRYPT_PARTITION_ON_ENTIRELY_ENCRYPTED_SYS_DRIVE_UNSURE", hwndDlg); + + // We allow the user to continue as we don't know if the drive is really an encrypted system drive. + // If it is, the user has been warned and he will not be able to start decrypting, because the + // format wizard will not enable (nor will it allow the user to enable) the mount option for + // external without-PBA access (the user will receive the 'Incorrect password' error message). + } + + NormalCursor (); + + + if (AskNoYesString ((wstring (GetString ("CONFIRM_DECRYPT_NON_SYS_DEVICE")) + L"\n\n" + SingleStringToWide (scPath)).c_str(), hwndDlg) == IDNO) + return; + + if (AskWarnNoYes ("CONFIRM_DECRYPT_NON_SYS_DEVICE_CAUTION", hwndDlg) == IDNO) + return; + + LaunchVolCreationWizard (hwndDlg, (string ("/inplacedec \"") + scPath + "\"").c_str ()); } // Blindly attempts (without any checks) to instruct the wizard to resume whatever system encryption process @@ -4802,12 +5091,12 @@ static void ShowSystemEncryptionStatus (HWND hwndDlg) } -static void ResumeInterruptedNonSysInplaceEncProcess (void) +static void ResumeInterruptedNonSysInplaceEncProcess (BOOL bDecrypt) { // IMPORTANT: This function must not check any config files! Otherwise, if a config file was lost or corrupt, // the user would not be able resume encryption and the data on the volume would be inaccessible. - LaunchVolCreationWizard (MainDlg, "/zinplace"); + LaunchVolCreationWizard (MainDlg, bDecrypt? "/resumeinplacedec" : "/zinplace"); } BOOL SelectContainer (HWND hwndDlg) @@ -5435,8 +5724,9 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa if (bInPlaceEncNonSysPending && !NonSysInplaceEncInProgressElsewhere()) { - if (AskNonSysInPlaceEncryptionResume(hwndDlg) == IDYES) - ResumeInterruptedNonSysInplaceEncProcess (); + BOOL bDecrypt = FALSE; + if (AskNonSysInPlaceEncryptionResume(hwndDlg, &bDecrypt) == IDYES) + ResumeInterruptedNonSysInplaceEncProcess (bDecrypt); } } @@ -6101,6 +6391,8 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa AppendMenuW (popup, MF_STRING, IDPM_ADD_TO_FAVORITES, GetString ("IDPM_ADD_TO_FAVORITES")); AppendMenuW (popup, MF_STRING, IDPM_ADD_TO_SYSTEM_FAVORITES, GetString ("IDPM_ADD_TO_SYSTEM_FAVORITES")); AppendMenu (popup, MF_SEPARATOR, 0, ""); + AppendMenuW (popup, MF_STRING, IDM_DECRYPT_NONSYS_VOL, GetString ("IDM_DECRYPT_NONSYS_VOL")); + AppendMenu (popup, MF_SEPARATOR, 0, ""); AppendMenuW (popup, MF_STRING, IDM_VOLUME_PROPERTIES, GetString ("IDPM_PROPERTIES")); break; @@ -6152,6 +6444,11 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa Dismount (hwndDlg, -2); break; + case IDM_DECRYPT_NONSYS_VOL: + if (CheckMountList (hwndDlg, FALSE)) + DecryptNonSysDevice (hwndDlg, FALSE, TRUE); + break; + case IDPM_OPEN_VOLUME: { int state = GetItemLong(GetDlgItem (hwndDlg, IDC_DRIVELIST), ((LPNMITEMACTIVATE)lParam)->iItem ); @@ -6351,6 +6648,8 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa AppendMenuW (popup, MF_STRING, IDM_ADD_REMOVE_VOL_KEYFILES, GetString ("IDM_ADD_REMOVE_VOL_KEYFILES")); AppendMenuW (popup, MF_STRING, IDM_REMOVE_ALL_KEYFILES_FROM_VOL, GetString ("IDM_REMOVE_ALL_KEYFILES_FROM_VOL")); AppendMenu (popup, MF_SEPARATOR, 0, ""); + AppendMenuW (popup, MF_STRING, IDM_DECRYPT_NONSYS_VOL, GetString ("IDM_DECRYPT_NONSYS_VOL")); + AppendMenu (popup, MF_SEPARATOR, 0, NULL); AppendMenuW (popup, MF_STRING, IDM_BACKUP_VOL_HEADER, GetString ("IDM_BACKUP_VOL_HEADER")); AppendMenuW (popup, MF_STRING, IDM_RESTORE_VOL_HEADER, GetString ("IDM_RESTORE_VOL_HEADER")); } @@ -6369,6 +6668,17 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa switch (menuItem) { + case IDM_DECRYPT_NONSYS_VOL: + if (!VolumeSelected(hwndDlg)) + { + Warning ("NO_VOLUME_SELECTED", hwndDlg); + } + else + { + DecryptNonSysDevice (hwndDlg, TRUE, FALSE); + } + break; + case IDM_CHANGE_PASSWORD: if (!VolumeSelected(hwndDlg)) { @@ -6469,6 +6779,22 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa return 1; } + if (lw == IDM_DECRYPT_NONSYS_VOL) + { + LPARAM selectedDrive = GetSelectedLong (GetDlgItem (hwndDlg, IDC_DRIVELIST)); + + if (LOWORD (selectedDrive) == TC_MLIST_ITEM_FREE && !VolumeSelected (MainDlg)) + { + Warning ("NO_VOLUME_SELECTED", hwndDlg); + } + else + { + DecryptNonSysDevice (hwndDlg, TRUE, FALSE); + } + + return 1; + } + if (lw == IDM_CHANGE_PASSWORD) { if (!VolumeSelected(hwndDlg)) @@ -6963,7 +7289,27 @@ BOOL CALLBACK MainDialogProc (HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lPa if (lw == IDM_RESUME_INTERRUPTED_PROC) { - ResumeInterruptedNonSysInplaceEncProcess (); + // Ask the user to select encryption, decryption, or cancel + BOOL bDecrypt = FALSE; + char *tmpStr[] = {0, + "CHOOSE_ENCRYPT_OR_DECRYPT", + "ENCRYPT", + "DECRYPT", + "IDCANCEL", + 0}; + + switch (AskMultiChoice ((void **) tmpStr, FALSE, hwndDlg)) + { + case 1: + bDecrypt = FALSE; + break; + case 2: + bDecrypt = TRUE; + break; + default: + return 1; + } + ResumeInterruptedNonSysInplaceEncProcess (bDecrypt); return 1; } diff --git a/src/Mount/Mount.h b/src/Mount/Mount.h index 6c3cf01e..be5585b0 100644 --- a/src/Mount/Mount.h +++ b/src/Mount/Mount.h @@ -98,7 +98,7 @@ void ChangeMainWindowVisibility (); void LaunchVolCreationWizard (HWND hwndDlg); BOOL WholeSysDriveEncryption (BOOL bSilent); BOOL CheckSysEncMountWithoutPBA (HWND hwndDlg, const char *devicePath, BOOL quiet); -BOOL TCBootLoaderOnInactiveSysEncDrive (void); +BOOL TCBootLoaderOnInactiveSysEncDrive (char *szDevicePath); void CreateRescueDisk (HWND hwndDlg); int BackupVolumeHeader (HWND hwndDlg, BOOL bRequireConfirmation, const char *lpszVolume); int RestoreVolumeHeader (HWND hwndDlg, const char *lpszVolume); diff --git a/src/Mount/Mount.rc b/src/Mount/Mount.rc index 145132d5..e52e5095 100644 --- a/src/Mount/Mount.rc +++ b/src/Mount/Mount.rc @@ -538,6 +538,7 @@ BEGIN MENUITEM "Select Device...", IDM_SELECT_DEVICE MENUITEM SEPARATOR MENUITEM "Create New Volume...", IDM_CREATE_VOLUME + MENUITEM "Permanently Decrypt...", IDM_DECRYPT_NONSYS_VOL MENUITEM "Resume Interrupted Process", IDM_RESUME_INTERRUPTED_PROC MENUITEM SEPARATOR MENUITEM "Mount Volume", IDM_MOUNT_VOLUME diff --git a/src/Mount/Resource.h b/src/Mount/Resource.h index 568d6c71..fe57e0d1 100644 --- a/src/Mount/Resource.h +++ b/src/Mount/Resource.h @@ -229,6 +229,7 @@ #define IDM_DONATE 40064 #define IDM_VOLUME_EXPANDER 40065 #define IDM_DEFAULT_MOUNT_PARAMETERS 40066 +#define IDM_DECRYPT_NONSYS_VOL 40067 // Next default values for new objects // @@ -236,7 +237,7 @@ #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NO_MFC 1 #define _APS_NEXT_RESOURCE_VALUE 119 -#define _APS_NEXT_COMMAND_VALUE 40067 +#define _APS_NEXT_COMMAND_VALUE 40068 #define _APS_NEXT_CONTROL_VALUE 1142 #define _APS_NEXT_SYMED_VALUE 101 #endif -- cgit v1.2.3