Notepad3/src/crypto/crypto.c

730 lines
26 KiB
C

// encoding: UTF-8
/**
*
* Distributed under the terms of the GNU General Public License,
* see License.txt for details.
*
* Author: Dave Dyer ddyer@real-me.net Oct/2005
*
adds the option to encrypt and decrypt files, using stong AES encryption,
optionally with master key
see ecryption-doc.txt for details
*/
#if !defined(WINVER)
#define WINVER 0x601 /*_WIN32_WINNT_WIN7*/
#endif
#if !defined(_WIN32_WINNT)
#define _WIN32_WINNT 0x601 /*_WIN32_WINNT_WIN7*/
#endif
#if !defined(NTDDI_VERSION)
#define NTDDI_VERSION 0x06010000 /*NTDDI_WIN7*/
#endif
#define VC_EXTRALEAN 1
#define WIN32_LEAN_AND_MEAN 1
#define NOMINMAX 1
#include <windows.h>
#include <shellapi.h>
#include <time.h>
#include "../src/Dialogs.h"
#include "../src/Helpers.h"
#include "../src/resource.h"
#include "../src/DarkMode/DarkMode.h"
#include "rijndael-api-fst.h"
#include "crypto.h"
#define WKEY_LEN 256
#define KEY_LEN 512
static bool useFileKey = false; // file should be encrypted
static char fileKey[KEY_LEN] = { 0 }; // ascii passphrase for the file key
static WCHAR unicodeFileKey[WKEY_LEN] = { 0 }; // unicode file passphrase
static bool useMasterKey = false; // file should have a master key
static char masterKey[KEY_LEN] = { 0 }; // ascii passphrase for the master key
static WCHAR unicodeMasterKey[WKEY_LEN] = { 0 }; // unicode master passphrase
static BYTE binFileKey[KEY_BYTES]; // the encryption key in for the file
static bool hasBinFileKey = false;
static BYTE masterFileKey[KEY_BYTES]; // file key encrypted with the master key
static BYTE masterFileIV[AES_MAX_IV_SIZE]; // the iv for the master key
static bool hasMasterFileKey = false;
static bool masterKeyAvailable = false; // information for the passphrase dialog box
bool IsEncryptionRequired()
{
return (useFileKey || hasMasterFileKey);
}
void ResetEncryption()
{
masterKeyAvailable = false;
hasMasterFileKey = false;
hasBinFileKey = false;
useMasterKey = false;
useFileKey = false;
memset(fileKey, 0, sizeof(fileKey));
memset(masterKey, 0, sizeof(masterKey));
memset(binFileKey, 0, sizeof(binFileKey));
memset(unicodeFileKey, 0, sizeof(unicodeFileKey));
memset(unicodeMasterKey, 0, sizeof(unicodeMasterKey));
memset(masterFileKey, 0, sizeof(masterFileKey));
memset(masterFileIV, 0, sizeof(masterFileIV));
}
//=============================================================================
//
// copy a unicode string to a regular string, but keep the same
// result string for simple, non-unicode characters.
// this is used to convert a unicode password to a byte stream compatible with an ascii password
//
void unicodeStringCpy(char *dest, WCHAR *src, int destSize)
{
int sidx = 0;
int didx = 0;
int destLim = destSize - 1;
while ((src[sidx] != 0) && (didx < destLim))
{
WCHAR c = src[sidx++];
char clow = (char)(c & 0xff);
if (clow != 0)
{
dest[didx++] = clow; // ignore zeros in the low order part
}
if (((c & 0xff00) != 0) && (didx < destLim)) // ignore zeros in the high order part
{
dest[didx++] = (char)((c >> 8) & 0xff);
}
}
dest[didx++] = (char)0;
}
//=============================================================================
// helper function for set focus to editbox
void SetDialogFocus(HWND hDlg, HWND hwndControl)
{
PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)hwndControl, true);
}
//=============================================================================
// helper function for the "set passphrase" dialog before output
// the complication in this version is that the incoming text is unicode. We deal
// with it by converting the unicode to an ascii compatible byte stream, so the
// caller (and hence the rest of the encryption) doesn't know unicode was involved.
INT_PTR CALLBACK SetKeysDlgProc(HWND hDlg, UINT umsg, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
const WCHAR wDot = (WCHAR)0x25CF;
switch (umsg)
{
case WM_INITDIALOG:
{
SetDialogIconNP3(hDlg);
InitWindowCommon(hDlg, true);
#ifdef D_NP3_WIN10_DARK_MODE
if (UseDarkMode())
{
SetExplorerTheme(GetDlgItem(hDlg, IDOK));
SetExplorerTheme(GetDlgItem(hDlg, IDCANCEL));
//SetExplorerTheme(GetDlgItem(hwnd, IDC_RESIZEGRIP));
int const ctl[] = { IDC_PWD_EDIT1, IDC_PWD_EDIT2, IDC_PWD_CHECK1,
IDC_PWD_CHECK2, IDC_PWD_CHECK3, IDC_PWD_CHECK4, IDC_STATIC, IDC_STATIC2
};
for (int i = 0; i < COUNTOF(ctl); ++i)
{
SetWindowTheme(GetDlgItem(hDlg, ctl[i]), L"", L""); // remove theme for BS_AUTORADIOBUTTON
}
}
#endif
SetDlgItemText(hDlg, IDC_PWD_EDIT1, unicodeFileKey);
SetDlgItemText(hDlg, IDC_PWD_EDIT2, unicodeMasterKey);
ShowWindow(GetDlgItem(hDlg, IDC_PWD_CHECK3), hasMasterFileKey);
CheckDlgButton(hDlg, IDC_PWD_CHECK3, SetBtn(hasMasterFileKey));
CheckDlgButton(hDlg, IDC_PWD_CHECK2, SetBtn(hasBinFileKey || useFileKey));
CheckDlgButton(hDlg, IDC_PWD_CHECK1, SetBtn(useMasterKey));
CenterDlgInParent(hDlg, NULL, true);
// Don't use: SetFocus( GetDlgItem( hDlg, IDC_PWD_EDIT1 ) );
SetDialogFocus(hDlg, GetDlgItem(hDlg, IDC_PWD_EDIT1));
}
return TRUE;
case WM_DPICHANGED:
UpdateWindowLayoutForDPI(hDlg, (RECT*)lParam, (UINT)HIWORD(wParam));
return TRUE;
//#define WM_CTLCOLORMSGBOX 0x0132
//#define WM_CTLCOLOREDIT 0x0133
//#define WM_CTLCOLORLISTBOX 0x0134
//#define WM_CTLCOLORBTN 0x0135
//#define WM_CTLCOLORDLG 0x0136
//#define WM_CTLCOLORSCROLLBAR 0x0137
//#define WM_CTLCOLORSTATIC 0x0138
//#define MN_GETHMENU 0x01E1
#ifdef D_NP3_WIN10_DARK_MODE
CASE_WM_CTLCOLOR_SET :
return SetDarkModeCtlColors((HDC)wParam, UseDarkMode());
break;
case WM_SETTINGCHANGE:
if (IsDarkModeSupported() && IsColorSchemeChangeMessage(lParam))
{
SendMessage(hDlg, WM_THEMECHANGED, 0, 0);
}
break;
case WM_THEMECHANGED:
if (IsDarkModeSupported())
{
bool const darkModeEnabled = CheckDarkModeEnabled();
AllowDarkModeForWindowEx(hDlg, darkModeEnabled);
RefreshTitleBarThemeColor(hDlg);
int const buttons[] = { IDOK, IDCANCEL };
for (int id = 0; id < COUNTOF(buttons); ++id)
{
HWND const hBtn = GetDlgItem(hDlg, buttons[id]);
AllowDarkModeForWindowEx(hBtn, darkModeEnabled);
SendMessage(hBtn, WM_THEMECHANGED, 0, 0);
}
UpdateWindowEx(hDlg);
}
break;
#endif
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_PWD_CHECK4:
{
if (IsButtonChecked(hDlg, IDC_PWD_CHECK4))
{
SendDlgItemMessage(hDlg, IDC_PWD_EDIT1, EM_SETPASSWORDCHAR, 0, 0);
SendDlgItemMessage(hDlg, IDC_PWD_EDIT2, EM_SETPASSWORDCHAR, 0, 0);
}
else
{
SendDlgItemMessage(hDlg, IDC_PWD_EDIT1, EM_SETPASSWORDCHAR, (WPARAM)wDot, 0);
SendDlgItemMessage(hDlg, IDC_PWD_EDIT2, EM_SETPASSWORDCHAR, (WPARAM)wDot, 0);
}
InvalidateRect(hDlg, NULL, TRUE);
}
return !0;
break;
case IDOK:
{
bool const useMas = IsButtonChecked(hDlg, IDC_PWD_CHECK1);
bool const useFil = IsButtonChecked(hDlg, IDC_PWD_CHECK2);
bool const reuseMas = IsButtonChecked(hDlg, IDC_PWD_CHECK3);
WCHAR newFileKey[WKEY_LEN] = { 0 };
WCHAR newMasKey[WKEY_LEN] = { 0 };
hasMasterFileKey &= reuseMas;
GetDlgItemText(hDlg, IDC_PWD_EDIT1, newFileKey, COUNTOF(newFileKey));
GetDlgItemText(hDlg, IDC_PWD_EDIT2, newMasKey, COUNTOF(newMasKey));
useFileKey = !((newFileKey[0] <= ' ') || !useFil);
useMasterKey = !((newMasKey[0] <= ' ') || !useMas);
memcpy(unicodeFileKey, newFileKey, sizeof(unicodeFileKey));
memcpy(unicodeMasterKey, newMasKey, sizeof(unicodeMasterKey));
unicodeStringCpy(fileKey, unicodeFileKey, sizeof(fileKey));
unicodeStringCpy(masterKey, unicodeMasterKey, sizeof(masterKey));
EndDialog(hDlg, IDOK);
return true;
}
break;
case IDC_PWD_EDIT1:
{
WCHAR newFileKey[WKEY_LEN] = { 0 };
GetDlgItemText(hDlg, IDC_PWD_EDIT1, newFileKey, COUNTOF(newFileKey));
CheckDlgButton(hDlg, IDC_PWD_CHECK2, SetBtn(newFileKey[0] > ' '));
}
break;
case IDC_PWD_EDIT2:
{
WCHAR newMasKey[WKEY_LEN] = { 0 };
GetDlgItemText(hDlg, IDC_PWD_EDIT2, newMasKey, COUNTOF(newMasKey));
{
bool newuse = (newMasKey[0] > ' '); // no leading whitespace or empty passwords
CheckDlgButton(hDlg, IDC_PWD_CHECK1, SetBtn(newuse));
if (newuse)
{
CheckDlgButton(hDlg, IDC_PWD_CHECK3, BST_UNCHECKED);
}
}
}
break;
case IDC_PWD_CHECK3: // check reuse, uncheck set new and inverse
{
bool const reuseMas = IsButtonChecked(hDlg, IDC_PWD_CHECK3);
if (reuseMas)
{
CheckDlgButton(hDlg, IDC_PWD_CHECK1, SetBtn(!reuseMas));
}
}
break;
case IDC_PWD_CHECK1:
{
bool const useMas = IsButtonChecked(hDlg, IDC_PWD_CHECK1);
if (useMas)
{
CheckDlgButton(hDlg, IDC_PWD_CHECK3, SetBtn(!useMas));
}
}
break;
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
break;
}
break;
}
return 0;
}
//
// helper for setting password when reading a file
// the complication in this version is that the incoming text is unicode. We deal
// with it by converting the unicode to an ascii compatible byte stream, so the
// caller (and hence the rest of the encryption) doesn't know unicode was involved.
//
INT_PTR CALLBACK GetKeysDlgProc(HWND hDlg, UINT umsg, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
const WCHAR wDot = (WCHAR)0x25CF;
switch (umsg)
{
case WM_INITDIALOG:
{
SetDialogIconNP3(hDlg);
InitWindowCommon(hDlg, true);
#ifdef D_NP3_WIN10_DARK_MODE
if (UseDarkMode())
{
SetExplorerTheme(GetDlgItem(hDlg, IDOK));
SetExplorerTheme(GetDlgItem(hDlg, IDCANCEL));
//SetExplorerTheme(GetDlgItem(hwnd, IDC_RESIZEGRIP));
int const ctl[] = { IDC_PWD_STATMPW, IDC_PWD_EDIT3, IDC_PWD_CHECK3, IDC_PWD_CHECK4, IDC_STATIC };
for (int i = 0; i < COUNTOF(ctl); ++i)
{
SetWindowTheme(GetDlgItem(hDlg, ctl[i]), L"", L""); // remove theme for static controls
}
}
#endif
int const vis = masterKeyAvailable ? SW_SHOW : SW_HIDE;
ShowWindow(GetDlgItem(hDlg, IDC_PWD_STATMPW), vis);
ShowWindow(GetDlgItem(hDlg, IDC_PWD_CHECK3), vis);
//~SetDlgItemText( hDlg, IDC_PWD_EDIT3, fileKey );
SetDlgItemText(hDlg, IDC_PWD_EDIT3, unicodeFileKey);
CheckDlgButton(hDlg, IDC_PWD_CHECK3, BST_UNCHECKED);
CenterDlgInParent(hDlg, NULL, true);
// Don't use: SetFocus( GetDlgItem( hDlg, IDC_PWD_EDIT3 ) );
SetDialogFocus(hDlg, GetDlgItem(hDlg, IDC_PWD_EDIT3));
}
return !0;
case WM_DPICHANGED:
UpdateWindowLayoutForDPI(hDlg, (RECT*)lParam, (UINT)HIWORD(wParam));
return !0;
#ifdef D_NP3_WIN10_DARK_MODE
CASE_WM_CTLCOLOR_SET:
return SetDarkModeCtlColors((HDC)wParam, UseDarkMode());
break;
case WM_SETTINGCHANGE:
if (IsDarkModeSupported() && IsColorSchemeChangeMessage(lParam))
{
SendMessage(hDlg, WM_THEMECHANGED, 0, 0);
}
break;
case WM_THEMECHANGED:
if (IsDarkModeSupported())
{
bool const darkModeEnabled = CheckDarkModeEnabled();
AllowDarkModeForWindowEx(hDlg, darkModeEnabled);
RefreshTitleBarThemeColor(hDlg);
int const buttons[] = { IDOK, IDCANCEL };
for (int id = 0; id < COUNTOF(buttons); ++id)
{
HWND const hBtn = GetDlgItem(hDlg, buttons[id]);
AllowDarkModeForWindowEx(hBtn, darkModeEnabled);
SendMessage(hBtn, WM_THEMECHANGED, 0, 0);
}
UpdateWindowEx(hDlg);
}
break;
#endif
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_PWD_CHECK4:
{
if (IsButtonChecked(hDlg, IDC_PWD_CHECK4))
{
SendDlgItemMessage(hDlg, IDC_PWD_EDIT3, EM_SETPASSWORDCHAR, 0, 0);
}
else
{
SendDlgItemMessage(hDlg, IDC_PWD_EDIT3, EM_SETPASSWORDCHAR, (WPARAM)wDot, 0);
}
InvalidateRect(hDlg, NULL, TRUE);
}
return !0;
case IDOK:
{
bool const useMas = IsButtonChecked(hDlg, IDC_PWD_CHECK3);
WCHAR newKey[WKEY_LEN] = { L'\0' };
GetDlgItemText(hDlg, IDC_PWD_EDIT3, newKey, COUNTOF(newKey));
if (useMas)
{
memcpy(unicodeMasterKey, newKey, sizeof(unicodeMasterKey));
unicodeStringCpy(masterKey, unicodeMasterKey, sizeof(masterKey));
useFileKey = false;
useMasterKey = true;
}
else
{
memcpy(unicodeFileKey, newKey, sizeof(unicodeFileKey));
unicodeStringCpy(fileKey, unicodeFileKey, sizeof(fileKey));
useFileKey = true;
useMasterKey = false;
}
EndDialog(hDlg, IDOK);
}
return !0;
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
break;
}
break;
}
return 0;
}
// set passphrases for output
bool GetFileKey(HWND hwnd)
{
return (IsYesOkay(ThemedDialogBoxParam(Globals.hLngResContainer, MAKEINTRESOURCE(IDD_MUI_PASSWORDS),
GetParent(hwnd), SetKeysDlgProc, (LPARAM)hwnd)));
}
// set passphrases for file being input
bool ReadFileKey(HWND hwnd, bool master)
{
masterKeyAvailable = master;
return (IsYesOkay(ThemedDialogBoxParam(Globals.hLngResContainer, MAKEINTRESOURCE(IDD_MUI_READPW),
GetParent(hwnd), GetKeysDlgProc, (LPARAM)hwnd)));
}
// ////////////////////////////////////////////////////////////////////////////
//
// read the file data, decrypt if necessary,
// return the result as a new allocation
//
int ReadAndDecryptFile(HWND hwnd, HANDLE hFile, size_t fileSize, void** result, size_t *resultlen)
{
HANDLE rawhandle = *result;
BYTE* rawdata = (BYTE*)GlobalLock(rawhandle);
int returnFlag = DECRYPT_SUCCESS;
bool usedEncryption = false;
bool bRetryPassPhrase = true;
size_t bytesRead = 0ULL;
while (bRetryPassPhrase)
{
SetFilePointer(hFile, 0L, NULL, FILE_BEGIN);
returnFlag = DECRYPT_SUCCESS;
usedEncryption = false;
bRetryPassPhrase = false;
bool const bReadOk = ReadFileXL(hFile, (char* const)rawdata, fileSize, &bytesRead);
returnFlag = bReadOk ? DECRYPT_SUCCESS : DECRYPT_FREAD_FAILED;
// we read the file, check if it looks like our encryption format
if (bReadOk && (bytesRead > (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;
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;
// 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];
ptrdiff_t len = WideCharToMultiByteEx( 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 ptrdiff_t = WideCharToMultiByteEx( 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
ptrdiff_t nbb = BAD_CIPHER_STATE;
ptrdiff_t nbp = BAD_CIPHER_STATE;
if ((bytesRead - code_offset) >= PAD_SLOP)
{
nbb = AES_blockDecrypt(&fileCypher, &fileDecode, &rawdata[code_offset], bytesRead - code_offset - PAD_SLOP, rawdata);
}
if (nbb >= 0)
{
nbp = AES_padDecrypt(&fileCypher, &fileDecode, &rawdata[code_offset + nbb], bytesRead - code_offset - nbb, rawdata + nbb);
}
if (nbp >= 0)
{
size_t const nb = nbb + nbp;
rawdata[nb] = '\0';
rawdata[nb + 1] = '\0'; // two zeros in case it's multi-byte
*resultlen = nb;
}
else
{
bRetryPassPhrase = IsRetryContinue(InfoBoxLng(MB_RETRYCANCEL | MB_ICONWARNING, NULL, IDS_MUI_PASS_FAILURE));
if (!bRetryPassPhrase)
{
// enable raw encryption read
*resultlen = bytesRead;
returnFlag |= DECRYPT_WRONG_PASS;
}
}
}
}
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 = bytesRead;
returnFlag |= DECRYPT_NO_ENCRYPTION;
}
GlobalUnlock(rawhandle);
return returnFlag;
}
bool EncryptAndWriteFile(HWND hwnd, HANDLE hFile, BYTE *data, size_t size, size_t*written)
{
UNREFERENCED_PARAMETER(hwnd);
if (IsEncryptionRequired())
{
AES_keyInstance fileEncode; // encryption key for the file
AES_cipherInstance fileCypher; // cypher for the file, including the IV
DWORD PREAMBLE_written = 0;
BYTE precodedata[AES_MAX_IV_SIZE * 2 + KEY_BYTES * 2 + PREAMBLE_SIZE] = { 0 };
long precode_size = AES_MAX_IV_SIZE + PREAMBLE_SIZE; //precode in standard file format
long *PREAMBLE_data = (long *)precodedata;
PREAMBLE_data[0] = PREAMBLE;
PREAMBLE_data[1] = FILEKEY_FORMAT;
static int sequence = 1; // sequence counter so each time is unique
srand(sequence++ ^ (unsigned int)time(NULL));
{
for (int i = 0; i < AES_MAX_IV_SIZE; i++)
{
precodedata[PREAMBLE_SIZE + i] = ((i % 2) == 0) ? HIBYTE(rand()) : LOBYTE(rand());
}
}
{
if (useFileKey)
{
// generate the encryption key from the passphrase
/* §§§
char ansiKey[KEY_LEN+1];
int ptrdiff_t = WideCharToMultiByteEx( CP_ACP, WC_NO_BEST_FIT_CHARS, fileKey, -1, ansiKey, KEY_LEN, NULL, NULL );
ansiKey[len] = '\0';
AES_keygen( ansiKey, binFileKey );
*/
AES_keygen(fileKey, binFileKey);
hasBinFileKey = true;
};
AES_bin_setup(&fileEncode, AES_DIR_ENCRYPT, KEY_BYTES * 8, binFileKey);
AES_bin_cipherInit(&fileCypher, AES_MODE_CBC, &precodedata[PREAMBLE_SIZE]);
if (useMasterKey && *masterKey) //setup with the master key and encrypt the file key.
{
//append the encrypted file key to the end of the PREAMBLE block
BYTE binMasterKey[KEY_BYTES];
AES_keyInstance masterencode;
AES_cipherInstance mastercypher;
/* §§§
char ansiKey[KEY_LEN+1];
ptrdiff_t len = WideCharToMultiByteEx( CP_ACP, WC_NO_BEST_FIT_CHARS, masterKey, -1, ansiKey, KEY_LEN, NULL, NULL );
ansiKey[len] = '\0';
AES_keygen( ansiKey, binMasterKey );
*/
AES_keygen(masterKey, binMasterKey);
AES_bin_setup(&masterencode, AES_DIR_ENCRYPT, KEY_BYTES * 8, binMasterKey);
{
// generate another IV for the master key
for (int i = 0; i < sizeof(masterFileIV); i++)
{
masterFileIV[i] = ((i % 2) == 0) ? HIBYTE(rand()) : LOBYTE(rand());
}
}
AES_bin_cipherInit(&mastercypher, AES_MODE_CBC, masterFileIV);
AES_blockEncrypt(&mastercypher, &masterencode, binFileKey, sizeof(binFileKey), masterFileKey);
hasMasterFileKey = true;
}
if (hasMasterFileKey) // copy the encrypted (new or recycled) into the output
{
memcpy(&precodedata[precode_size], masterFileIV, sizeof(masterFileIV));
memcpy(&precodedata[precode_size + sizeof(masterFileIV)], masterFileKey, sizeof(masterFileKey));
precode_size += sizeof(masterFileKey) + sizeof(masterFileIV);
PREAMBLE_data[1] = MASTERKEY_FORMAT;
}
// write the PREAMBLE, punt if that failed
if (!WriteFile(hFile, precodedata, precode_size, &PREAMBLE_written, NULL))
{
*written = PREAMBLE_written;
return false;
}
}
// now encrypt the main file
{
bool bWriteRes = false;
BYTE* encdata = (BYTE*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size + PAD_SLOP); // add slop to the end for padding
if (!encdata)
{
return bWriteRes;
}
size_t enclen = 0;
if (size > PAD_SLOP)
{
enclen += AES_blockEncrypt(&fileCypher, &fileEncode, data, size - PAD_SLOP, encdata);
}
enclen += AES_padEncrypt(&fileCypher, &fileEncode, data + enclen, size - enclen, encdata + enclen);
size_t enclen_written = 0;
bWriteRes = WriteFileXL(hFile, (const char* const)encdata, enclen, &enclen_written);
HeapFree(GetProcessHeap(), 0, encdata); // clean-up
*written = (size_t)PREAMBLE_written + enclen_written; // return the file size written
return bWriteRes; // and the file ok status
}
}
else
{
// not an encrypted file, write normally
return WriteFileXL(hFile, (const char* const)data, size, written);
}
}