+ fix: minor fixes

+ enh: suggested pass-phrase handling
This commit is contained in:
Rainer Kottenhoff 2018-04-17 16:26:32 +02:00
parent ead46c880c
commit e14526c5b5
9 changed files with 203 additions and 140 deletions

View File

@ -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)

View File

@ -1,20 +1,29 @@
#ifndef __CRYPTO_H__
#define __CRYPTO_H__
#include <stdbool.h>
#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

View File

@ -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

View File

@ -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);

View File

@ -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);

View File

@ -608,7 +608,6 @@ void SetWindowTransparentMode(HWND hwnd,bool bTransparentMode)
//
void CenterDlgInParent(HWND hDlg)
{
RECT rcDlg;
HWND hParent;
RECT rcParent;

View File

@ -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

View File

@ -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

View File

@ -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;
// --------------------------------------------------------------------------