From e14526c5b57a6d339c8cee19380ae14bc590266c Mon Sep 17 00:00:00 2001 From: Rainer Kottenhoff Date: Tue, 17 Apr 2018 16:26:32 +0200 Subject: [PATCH] + fix: minor fixes + enh: suggested pass-phrase handling --- crypto/crypto.c | 207 ++++++++++++++++++++++++++---------------------- crypto/crypto.h | 13 ++- src/Dialogs.c | 81 +++++++++++++------ src/Dialogs.h | 7 -- src/Edit.c | 14 +++- src/Helpers.c | 1 - src/Notepad3.c | 11 +-- src/Notepad3.rc | 8 +- src/TypeDefs.h | 1 + 9 files changed, 203 insertions(+), 140 deletions(-) diff --git a/crypto/crypto.c b/crypto/crypto.c index 419f47eda..08009b7e1 100644 --- a/crypto/crypto.c +++ b/crypto/crypto.c @@ -315,121 +315,142 @@ bool ReadFileKey(HWND hwnd, bool master) } - -// read the file data, decrypt if necessary, return the result as a new allocation -bool ReadAndDecryptFile(HWND hwnd, HANDLE hFile, DWORD size, void** result, DWORD *resultlen) +// //////////////////////////////////////////////////////////////////////////// +// +// read the file data, decrypt if necessary, +// return the result as a new allocation +// +int ReadAndDecryptFile(HWND hwnd, HANDLE hFile, DWORD size, void** result, DWORD *resultlen) { - bool usedEncryption = false; - HANDLE rawhandle = *result; - BYTE* rawdata = (BYTE*)GlobalLock(rawhandle); - unsigned long readsize = 0; + HANDLE rawhandle = *result; + BYTE* rawdata = (BYTE*)GlobalLock(rawhandle); + + int returnFlag = DECRYPT_SUCCESS; + bool usedEncryption = false; + unsigned long readsize = 0; + bool bRetryPassPhrase = true; + + while (bRetryPassPhrase) { + + SetFilePointer(hFile, 0L, NULL, FILE_BEGIN); + returnFlag = DECRYPT_SUCCESS; + usedEncryption = false; + readsize = 0; + bRetryPassPhrase = false; + bool bReadSuccess = ReadFile(hFile, rawdata, size, &readsize, NULL); + returnFlag = bReadSuccess ? DECRYPT_SUCCESS : DECRYPT_FREAD_FAILED; // we read the file, check if it looks like our encryption format if (bReadSuccess && (readsize > (PREAMBLE_SIZE + AES_MAX_IV_SIZE))) { - long *ldata = (long*)rawdata; - if (ldata && (ldata[0] == PREAMBLE)) { - long scheme = ldata[1]; - unsigned long code_offset = PREAMBLE_SIZE + AES_MAX_IV_SIZE; + long *ldata = (long*)rawdata; - switch (scheme) { - case MASTERKEY_FORMAT: - code_offset += sizeof(masterFileKey) + sizeof(masterFileIV); - // save the encrypted file key and IV. They can be reused if the - // passphrases are not changed. - memcpy(masterFileIV, &rawdata[MASTER_KEY_OFFSET], sizeof(masterFileIV)); - memcpy(masterFileKey, &rawdata[MASTER_KEY_OFFSET + sizeof(masterFileIV)], sizeof(masterFileKey)); - hasMasterFileKey = true; + if (ldata && (ldata[0] == PREAMBLE)) { + long scheme = ldata[1]; + unsigned long code_offset = PREAMBLE_SIZE + AES_MAX_IV_SIZE; - // fall through - case FILEKEY_FORMAT: - { - bool haveFileKey = ReadFileKey(hwnd, scheme == MASTERKEY_FORMAT); + switch (scheme) { - if (useFileKey) { - // use the file key to decode - /*@@@ - char ansiKey[KEY_LEN+1]; - int len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, fileKey, -1, ansiKey, KEY_LEN, NULL, NULL ); - ansiKey[len] = '\0'; - AES_keygen( ansiKey, binFileKey ); // generate the encryption key from the passphrase - */ - AES_keygen(fileKey, binFileKey); // generate the encryption key from the passphrase - hasBinFileKey = true; + case MASTERKEY_FORMAT: + code_offset += sizeof(masterFileKey) + sizeof(masterFileIV); + // save the encrypted file key and IV. They can be reused if the + // passphrases are not changed. + memcpy(masterFileIV, &rawdata[MASTER_KEY_OFFSET], sizeof(masterFileIV)); + memcpy(masterFileKey, &rawdata[MASTER_KEY_OFFSET + sizeof(masterFileIV)], sizeof(masterFileKey)); + hasMasterFileKey = true; + + // fall through + case FILEKEY_FORMAT: + { + bool haveFileKey = ReadFileKey(hwnd, scheme == MASTERKEY_FORMAT); + + if (useFileKey) { + // use the file key to decode + /*@@@ + char ansiKey[KEY_LEN+1]; + int len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, fileKey, -1, ansiKey, KEY_LEN, NULL, NULL ); + ansiKey[len] = '\0'; + AES_keygen( ansiKey, binFileKey ); // generate the encryption key from the passphrase + */ + AES_keygen(fileKey, binFileKey); // generate the encryption key from the passphrase + hasBinFileKey = true; + } + else if ((scheme == MASTERKEY_FORMAT) && useMasterKey) { // use the master key to recover the file key + BYTE binMasterKey[KEY_BYTES]; + AES_keyInstance masterdecode; + AES_cipherInstance mastercypher; + /*@@@ + char ansiKey[KEY_LEN+1]; + int len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, masterKey, -1, ansiKey, KEY_LEN, NULL, NULL ); + AES_keygen( ansiKey, binMasterKey ); + */ + AES_keygen(masterKey, binMasterKey); + AES_bin_setup(&masterdecode, AES_DIR_DECRYPT, KEY_BYTES * 8, binMasterKey); + AES_bin_cipherInit(&mastercypher, AES_MODE_CBC, masterFileIV); + AES_blockDecrypt(&mastercypher, &masterdecode, masterFileKey, sizeof(binFileKey), binFileKey); + hasBinFileKey = true; + haveFileKey = true; + useMasterKey = false; + } + + if (haveFileKey) { + usedEncryption = true; + AES_keyInstance fileDecode; + AES_cipherInstance fileCypher; + AES_bin_setup(&fileDecode, AES_DIR_DECRYPT, KEY_BYTES * 8, binFileKey); + AES_bin_cipherInit(&fileCypher, AES_MODE_CBC, &rawdata[PREAMBLE_SIZE]); // IV is next + { // finally, decrypt the actual data + int nbb = BAD_CIPHER_STATE; + int nbp = BAD_CIPHER_STATE; + if ((readsize - code_offset) >= PAD_SLOP) { + nbb = AES_blockDecrypt(&fileCypher, &fileDecode, &rawdata[code_offset], readsize - code_offset - PAD_SLOP, rawdata); } - else if ((scheme == MASTERKEY_FORMAT) && useMasterKey) { // use the master key to recover the file key - BYTE binMasterKey[KEY_BYTES]; - AES_keyInstance masterdecode; - AES_cipherInstance mastercypher; - /*@@@ - char ansiKey[KEY_LEN+1]; - int len = WideCharToMultiByte( CP_ACP, WC_NO_BEST_FIT_CHARS, masterKey, -1, ansiKey, KEY_LEN, NULL, NULL ); - AES_keygen( ansiKey, binMasterKey ); - */ - AES_keygen(masterKey, binMasterKey); - AES_bin_setup(&masterdecode, AES_DIR_DECRYPT, KEY_BYTES * 8, binMasterKey); - AES_bin_cipherInit(&mastercypher, AES_MODE_CBC, masterFileIV); - AES_blockDecrypt(&mastercypher, &masterdecode, masterFileKey, sizeof(binFileKey), binFileKey); - hasBinFileKey = true; - haveFileKey = true; - useMasterKey = false; + if (nbb >= 0) { + nbp = AES_padDecrypt(&fileCypher, &fileDecode, &rawdata[code_offset + nbb], readsize - code_offset - nbb, rawdata + nbb); } - - if (haveFileKey) { - AES_keyInstance fileDecode; - AES_cipherInstance fileCypher; - AES_bin_setup(&fileDecode, AES_DIR_DECRYPT, KEY_BYTES * 8, binFileKey); - AES_bin_cipherInit(&fileCypher, AES_MODE_CBC, &rawdata[PREAMBLE_SIZE]); // IV is next - { // finally, decrypt the actual data - int nbb = BAD_CIPHER_STATE; - int nbp = BAD_CIPHER_STATE; - if ((readsize - code_offset) >= PAD_SLOP) { - nbb = AES_blockDecrypt(&fileCypher, &fileDecode, &rawdata[code_offset], readsize - code_offset - PAD_SLOP, rawdata); - } - if (nbb >= 0) { - nbp = AES_padDecrypt(&fileCypher, &fileDecode, &rawdata[code_offset + nbb], readsize - code_offset - nbb, rawdata + nbb); - } - if (nbp >= 0) { - int nb = nbb + nbp; - rawdata[nb] = (char)0; - rawdata[nb + 1] = (char)0; // two zeros in case it's multi-byte - *resultlen = (DWORD)nb; - bReadSuccess = true; - } - else { - MsgBox(MBWARN, IDS_PASS_FAILURE); - *resultlen = 0; - bReadSuccess = false; - } - } - usedEncryption = true; + if (nbp >= 0) { + int nb = nbb + nbp; + rawdata[nb] = (char)0; + rawdata[nb + 1] = (char)0; // two zeros in case it's multi-byte + *resultlen = (DWORD)nb; } else { - // simulate read failure - MsgBox(MBWARN, IDS_NOPASS); - *resultlen = 0; - bReadSuccess = false; - usedEncryption = false; + bRetryPassPhrase = (MsgBox(MBRETRYCANCEL, IDS_PASS_FAILURE) == IDRETRY); + if (!bRetryPassPhrase) { + // enable raw encryption read + *resultlen = readsize; + returnFlag |= DECRYPT_WRONG_PASS; + } } + } } - - break; - - default: BUG1("format %d not understood", scheme); + else { + // enable raw encryption read + returnFlag |= DECRYPT_CANCELED_NO_PASS; } + } + break; + + default: + BUG1("format %d not understood", scheme); + returnFlag |= DECRYPT_FATAL_ERROR; + break; } + } } + } // while bRetryPassPhrase - if (!usedEncryption) { // here, the file is believed to be a straight text file - ResetEncryption(); - *resultlen = readsize; - } + if (!usedEncryption) { // here, the file is believed to be a straight text file + ResetEncryption(); + *resultlen = readsize; + returnFlag |= DECRYPT_NO_ENCRYPTION; + } - GlobalUnlock(rawhandle); + GlobalUnlock(rawhandle); - return(bReadSuccess); + return returnFlag; } bool EncryptAndWriteFile(HWND hwnd, HANDLE hFile, BYTE *data, DWORD size, DWORD *written) diff --git a/crypto/crypto.h b/crypto/crypto.h index ff2553fda..37d0333b4 100644 --- a/crypto/crypto.h +++ b/crypto/crypto.h @@ -1,20 +1,29 @@ #ifndef __CRYPTO_H__ #define __CRYPTO_H__ + #include #define BUG1(a,b) { perror("a"); } #define BUG(a) { perror("a"); } #define PREAMBLE_SIZE 8 // 4 byte signature + 4 byte subfile type -#define KEY_BYTES 32 // 32 byts = 256 bits of key +#define KEY_BYTES 32 // 32 bytes = 256 bits of key #define PREAMBLE 0x01020304 // first 4 bytes of the file #define FILEKEY_FORMAT 1 // next 4 bytes determine version/format #define MASTERKEY_FORMAT 2 // format with master key #define MASTER_KEY_OFFSET (PREAMBLE_SIZE+AES_MAX_IV_SIZE) #define UNUSED(expr) (void)(expr) +#define DECRYPT_SUCCESS 0x00 +#define DECRYPT_FREAD_FAILED 0x01 +#define DECRYPT_WRONG_PASS 0x02 +#define DECRYPT_NO_ENCRYPTION 0x04 +#define DECRYPT_CANCELED_NO_PASS 0x08 +#define DECRYPT_FATAL_ERROR 0x10 +int ReadAndDecryptFile(HWND hwnd, HANDLE hFile, DWORD size, void** result, DWORD *resultlen); + bool EncryptAndWriteFile(HWND hwnd, HANDLE hFile, BYTE *data, DWORD size, DWORD *written); -bool ReadAndDecryptFile(HWND hwnd, HANDLE hFile, DWORD size, void** result, DWORD *resultlen); bool GetFileKey(HWND hwnd); void ResetEncryption(); + #endif diff --git a/src/Dialogs.c b/src/Dialogs.c index b381b8ff0..aa3e8efc7 100644 --- a/src/Dialogs.c +++ b/src/Dialogs.c @@ -70,18 +70,50 @@ extern int flagNoFileVariables; extern int flagUseSystemMRU; + //============================================================================= // // MsgBox() // +static HHOOK hhkMsgBox = NULL; + +static LRESULT CALLBACK _MsgBoxProc(INT nCode, WPARAM wParam, LPARAM lParam) +{ + HWND hParentWnd, hChildWnd; // msgbox is "child" + RECT rParent, rChild, rDesktop; + + // notification that a window is about to be activated + if (nCode == HCBT_ACTIVATE) { + // set window handles + hParentWnd = GetForegroundWindow(); + hChildWnd = (HWND)wParam; // window handle is wParam + + if ((hParentWnd != NULL) && (hChildWnd != NULL) && + (GetWindowRect(GetDesktopWindow(), &rDesktop) != 0) && + (GetWindowRect(hParentWnd, &rParent) != 0) && + (GetWindowRect(hChildWnd, &rChild) != 0)) { + + CenterDlgInParent(hChildWnd); + } + // exit _MsgBoxProc hook + UnhookWindowsHookEx(hhkMsgBox); + + + } + else // otherwise, continue with any possible chained hooks + { + CallNextHookEx(hhkMsgBox, nCode, wParam, lParam); + } + return 0; +} +// ----------------------------------------------------------------------------- + + int MsgBox(int iType,UINT uIdMsg,...) { - WCHAR szText [HUGE_BUFFER] = { L'\0' }; WCHAR szBuf [HUGE_BUFFER] = { L'\0' }; WCHAR szTitle[64] = { L'\0' }; - int iIcon = 0; - HWND hwnd; if (!GetString(uIdMsg,szBuf,COUNTOF(szBuf))) return(0); @@ -112,22 +144,24 @@ int MsgBox(int iType,UINT uIdMsg,...) GetString(IDS_APPTITLE,szTitle,COUNTOF(szTitle)); + int iIcon = MB_ICONHAND; switch (iType) { case MBINFO: iIcon = MB_ICONINFORMATION; break; - case MBWARN: iIcon = MB_ICONEXCLAMATION; break; - case MBYESNO: iIcon = MB_ICONEXCLAMATION | MB_YESNO; break; - case MBYESNOCANCEL: iIcon = MB_ICONEXCLAMATION | MB_YESNOCANCEL; break; - case MBYESNOWARN: iIcon = MB_ICONEXCLAMATION | MB_YESNO; break; + case MBWARN: iIcon = MB_ICONWARNING; break; + case MBYESNO: iIcon = MB_ICONQUESTION | MB_YESNO; break; + case MBYESNOCANCEL: iIcon = MB_ICONINFORMATION | MB_YESNOCANCEL; break; + case MBYESNOWARN: iIcon = MB_ICONWARNING | MB_YESNO | MB_DEFBUTTON1; break; case MBOKCANCEL: iIcon = MB_ICONEXCLAMATION | MB_OKCANCEL; break; + case MBRETRYCANCEL: iIcon = MB_ICONQUESTION | MB_RETRYCANCEL; break; + default: iIcon = MB_ICONSTOP | MB_TOPMOST | MB_OK; break; } HWND focus = GetFocus(); - hwnd = focus ? focus : g_hwndMain; + HWND hwnd = focus ? focus : g_hwndMain; - return MessageBoxEx(hwnd, - szText,szTitle, - MB_SETFOREGROUND | iIcon, - MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT)); + hhkMsgBox = SetWindowsHookEx(WH_CBT, &_MsgBoxProc, 0, GetCurrentThreadId()); + + return MessageBoxEx(hwnd, szText, szTitle, MB_SETFOREGROUND | iIcon, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)); } @@ -1513,7 +1547,7 @@ INT_PTR CALLBACK FileMRUDlgProc(HWND hwnd,UINT umsg,WPARAM wParam,LPARAM lParam) } // Ask... - int answ = (LOWORD(wParam) == IDOK) ? MsgBox(MBYESNO, IDS_ERR_MRUDLG) + int answ = (LOWORD(wParam) == IDOK) ? MsgBox(MBYESNOWARN, IDS_ERR_MRUDLG) : ((iCur == lvi.iItem) ? IDNO : IDYES); if (IDYES == answ) { @@ -2759,24 +2793,25 @@ INT_PTR InfoBox(int iType,LPCWSTR lpstrSetting,int uidMessage,...) ib.lpstrSetting = (LPWSTR)lpstrSetting; ib.bDisableCheckBox = (StringCchLenW(g_wchIniFile,COUNTOF(g_wchIniFile)) == 0 || lstrlen(lpstrSetting) == 0 || iMode == 2) ? true : false; - int idDlg = IDD_INFOBOX; - if (iType == MBYESNO) + int idDlg; + switch (iType) { + case MBYESNO: idDlg = IDD_INFOBOX2; - else if (iType == MBOKCANCEL) + break; + case MBOKCANCEL: idDlg = IDD_INFOBOX3; + break; + default: + idDlg = IDD_INFOBOX; + break; + } HWND focus = GetFocus(); HWND hwnd = focus ? focus : g_hwndMain; MessageBeep(MB_ICONEXCLAMATION); - return ThemedDialogBoxParam( - g_hInstance, - MAKEINTRESOURCE(idDlg), - hwnd, - InfoBoxDlgProc, - (LPARAM)&ib); - + return ThemedDialogBoxParam(g_hInstance, MAKEINTRESOURCE(idDlg), hwnd, InfoBoxDlgProc, (LPARAM)&ib); } // End of Dialogs.c diff --git a/src/Dialogs.h b/src/Dialogs.h index 056821a03..e3c379478 100644 --- a/src/Dialogs.h +++ b/src/Dialogs.h @@ -18,13 +18,6 @@ #include "TypeDefs.h" -#define MBINFO 0 -#define MBWARN 1 -#define MBYESNO 2 -#define MBYESNOWARN 3 -#define MBYESNOCANCEL 4 -#define MBOKCANCEL 8 - int MsgBox(int,UINT,...); void DisplayCmdLineHelp(HWND); bool GetDirectory(HWND,int,LPWSTR,LPCWSTR,bool); diff --git a/src/Edit.c b/src/Edit.c index 26f5f6950..711491c08 100644 --- a/src/Edit.c +++ b/src/Edit.c @@ -1061,10 +1061,22 @@ bool EditLoadFile( } DWORD cbData = 0L; - bool bReadSuccess = ReadAndDecryptFile(hwnd, hFile, dwBufSize - 2, &lpData, &cbData); + int const readFlag = ReadAndDecryptFile(hwnd, hFile, dwBufSize - 2, &lpData, &cbData); dwLastIOError = GetLastError(); CloseHandle(hFile); + bool bReadSuccess = ((readFlag & DECRYPT_FATAL_ERROR) || (readFlag & DECRYPT_FREAD_FAILED)) ? false : true; + // ((readFlag == DECRYPT_SUCCESS) || (readFlag & DECRYPT_NO_ENCRYPTION)) => true; + + if ((readFlag & DECRYPT_CANCELED_NO_PASS) || (readFlag & DECRYPT_WRONG_PASS)) + { + bReadSuccess = (InfoBox(MBOKCANCEL, L"MsgNoOrWrongPassphrase", IDS_NOPASS) == IDOK); + if (!bReadSuccess) { + FreeMem(lpData); + return true; + } + } + if (!bReadSuccess) { FreeMem(lpData); Encoding_SrcCmdLn(CPI_NONE); diff --git a/src/Helpers.c b/src/Helpers.c index f96b5392d..c29ccd009 100644 --- a/src/Helpers.c +++ b/src/Helpers.c @@ -608,7 +608,6 @@ void SetWindowTransparentMode(HWND hwnd,bool bTransparentMode) // void CenterDlgInParent(HWND hDlg) { - RECT rcDlg; HWND hParent; RECT rcParent; diff --git a/src/Notepad3.c b/src/Notepad3.c index 87a87acfd..ce3e1204e 100644 --- a/src/Notepad3.c +++ b/src/Notepad3.c @@ -2213,13 +2213,13 @@ void MsgChangeNotify(HWND hwnd, WPARAM wParam, LPARAM lParam) if (PathFileExists(g_wchCurFile)) { if ((iFileWatchingMode == 2 && !IsDocumentModified && !Encoding_HasChanged(CPI_GET)) || - MsgBox(MBYESNO,IDS_FILECHANGENOTIFY) == IDYES) { + MsgBox(MBYESNOWARN,IDS_FILECHANGENOTIFY) == IDYES) { FileRevert(g_wchCurFile); } } else { - if (MsgBox(MBYESNO,IDS_FILECHANGENOTIFY2) == IDYES) + if (MsgBox(MBYESNOWARN,IDS_FILECHANGENOTIFY2) == IDYES) FileSave(true,false,false,false); } @@ -8452,7 +8452,7 @@ bool ActivatePrevInst() else // IsWindowEnabled() { // Ask... - if (IDYES == MsgBox(MBYESNO,IDS_ERR_PREVWINDISABLED)) + if (IDYES == MsgBox(MBYESNOWARN,IDS_ERR_PREVWINDISABLED)) return(false); else return(true); @@ -8557,10 +8557,7 @@ bool ActivatePrevInst() else // IsWindowEnabled() { // Ask... - if (IDYES == MsgBox(MBYESNO,IDS_ERR_PREVWINDISABLED)) - return(false); - else - return(true); + return ((IDYES == MsgBox(MBYESNOWARN, IDS_ERR_PREVWINDISABLED)) ? false : true); } } else diff --git a/src/Notepad3.rc b/src/Notepad3.rc index b6cb1e4d6..74d2b846e 100644 --- a/src/Notepad3.rc +++ b/src/Notepad3.rc @@ -1450,12 +1450,8 @@ END STRINGTABLE BEGIN - IDS_PASS_FAILURE "The passphrase is incorrect." -END - -STRINGTABLE -BEGIN - IDS_NOPASS "Cancelled - no passphrase." + IDS_PASS_FAILURE "The Passphrase is incorrect.\nRetry another Passphrase?" + IDS_NOPASS "Decryption Cancelled!\nRead encrypted raw data?" END STRINGTABLE diff --git a/src/TypeDefs.h b/src/TypeDefs.h index 7bd055e9c..06466ecc0 100644 --- a/src/TypeDefs.h +++ b/src/TypeDefs.h @@ -72,6 +72,7 @@ typedef enum BufferSizes typedef enum { FND_NOP = 0, NXT_NOT_FND, NXT_FND, NXT_WRP_FND, PRV_NOT_FND, PRV_FND, PRV_WRP_FND } FR_STATES; typedef enum { FRMOD_IGNORE = 0, FRMOD_NORM, FRMOD_WRAPED } FR_UPD_MODES; +typedef enum { MBINFO = 0, MBWARN, MBYESNO, MBYESNOWARN, MBYESNOCANCEL, MBOKCANCEL, MBRETRYCANCEL } MBTYPES; // --------------------------------------------------------------------------