VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Common/Keyfiles.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Common/Keyfiles.c')
-rw-r--r--src/Common/Keyfiles.c1556
1 files changed, 778 insertions, 778 deletions
diff --git a/src/Common/Keyfiles.c b/src/Common/Keyfiles.c
index 8b3825d5..c59ab374 100644
--- a/src/Common/Keyfiles.c
+++ b/src/Common/Keyfiles.c
@@ -1,778 +1,778 @@
-/*
- Derived from source code of TrueCrypt 7.1a, which is
- Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
- by the TrueCrypt License 3.0.
-
- Modifications and additions to the original source code (contained in this file)
- and all other portions of this file are Copyright (c) 2013-2016 IDRIX
- and are governed by the Apache License 2.0 the full text of which is
- contained in the file License.txt included in VeraCrypt binary and source
- code distribution packages.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include "Tcdefs.h"
-#include "Keyfiles.h"
-#include "Crc.h"
-
-#include <io.h>
-#include "Dlgcode.h"
-#include "Language.h"
-#include "SecurityToken.h"
-#include "Common/resource.h"
-#include "Platform/Finally.h"
-#include "Platform/ForEach.h"
-#ifdef TCMOUNT
-#include "Mount/Mount.h"
-#endif
-
-#include <Strsafe.h>
-
-using namespace VeraCrypt;
-
-#define stat _stat
-#define S_IFDIR _S_IFDIR
-
-
-BOOL HiddenFilesPresentInKeyfilePath = FALSE;
-
-#ifdef TCMOUNT
-extern BOOL UsePreferences;
-#endif
-
-KeyFile *KeyFileAdd (KeyFile *firstKeyFile, KeyFile *keyFile)
-{
- KeyFile *kf = firstKeyFile;
-
- if (firstKeyFile != NULL)
- {
- while (kf->Next)
- kf = kf->Next;
-
- kf->Next = keyFile;
- }
- else
- firstKeyFile = keyFile;
-
- keyFile->Next = NULL;
-
- return firstKeyFile;
-}
-
-
-// Returns first keyfile, NULL if last keyfile was removed
-static KeyFile *KeyFileRemove (KeyFile *firstKeyFile, KeyFile *keyFile)
-{
- KeyFile *prevkf = NULL, *kf = firstKeyFile;
-
- if (firstKeyFile == NULL) return NULL;
- do
- {
- if (kf == keyFile)
- {
- if (prevkf == NULL)
- firstKeyFile = kf->Next;
- else
- prevkf->Next = kf->Next;
-
- burn (keyFile, sizeof(*keyFile)); // wipe
- free (keyFile);
- break;
- }
- prevkf = kf;
- }
- while (kf = kf->Next);
-
- return firstKeyFile;
-}
-
-
-void KeyFileRemoveAll (KeyFile **firstKeyFile)
-{
- KeyFile *kf = *firstKeyFile;
- while (kf != NULL)
- {
- KeyFile *d = kf;
- kf = kf->Next;
- burn (d, sizeof(*d)); // wipe
- free (d);
- }
-
- *firstKeyFile = NULL;
-}
-
-
-KeyFile *KeyFileClone (KeyFile *keyFile)
-{
- KeyFile *clone = NULL;
-
- if (keyFile == NULL) return NULL;
-
- clone = (KeyFile *) malloc (sizeof (KeyFile));
- if (clone)
- {
- StringCbCopyW (clone->FileName, sizeof(clone->FileName), keyFile->FileName);
- clone->Next = NULL;
- }
- return clone;
-}
-
-
-void KeyFileCloneAll (KeyFile *firstKeyFile, KeyFile **outputKeyFile)
-{
- if (outputKeyFile)
- {
- KeyFile *cloneFirstKeyFile = KeyFileClone (firstKeyFile);
- KeyFile *kf;
-
- // free output only if different from input
- if (*outputKeyFile != firstKeyFile)
- KeyFileRemoveAll (outputKeyFile);
- if (firstKeyFile)
- {
- kf = firstKeyFile->Next;
- while (kf != NULL)
- {
- KeyFileAdd (cloneFirstKeyFile, KeyFileClone (kf));
- kf = kf->Next;
- }
-
- *outputKeyFile = cloneFirstKeyFile;
- }
- }
-}
-
-
-static BOOL KeyFileProcess (unsigned __int8 *keyPool, KeyFile *keyFile)
-{
- FILE *f;
- unsigned __int8 buffer[64 * 1024];
- unsigned __int32 crc = 0xffffffff;
- int writePos = 0;
- size_t bytesRead, totalRead = 0;
- int status = TRUE;
-
- HANDLE src;
- FILETIME ftCreationTime;
- FILETIME ftLastWriteTime;
- FILETIME ftLastAccessTime;
-
- BOOL bTimeStampValid = FALSE;
-
- /* Remember the last access time of the keyfile. It will be preserved in order to prevent
- an adversary from determining which file may have been used as keyfile. */
- src = CreateFile (keyFile->FileName,
- GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
-
- if (src != INVALID_HANDLE_VALUE)
- {
- if (GetFileTime ((HANDLE) src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime))
- bTimeStampValid = TRUE;
- }
-
- finally_do_arg (HANDLE, src,
- {
- if (finally_arg != INVALID_HANDLE_VALUE)
- CloseHandle (finally_arg);
- });
-
- f = _wfopen (keyFile->FileName, L"rb");
- if (f == NULL) return FALSE;
-
- while ((bytesRead = fread (buffer, 1, sizeof (buffer), f)) > 0)
- {
- size_t i;
-
- if (ferror (f))
- {
- status = FALSE;
- goto close;
- }
-
- for (i = 0; i < bytesRead; i++)
- {
- crc = UPDC32 (buffer[i], crc);
-
- keyPool[writePos++] += (unsigned __int8) (crc >> 24);
- keyPool[writePos++] += (unsigned __int8) (crc >> 16);
- keyPool[writePos++] += (unsigned __int8) (crc >> 8);
- keyPool[writePos++] += (unsigned __int8) crc;
-
- if (writePos >= KEYFILE_POOL_SIZE)
- writePos = 0;
-
- if (++totalRead >= KEYFILE_MAX_READ_LEN)
- goto close;
- }
- }
-
- if (ferror (f))
- {
- status = FALSE;
- }
- else if (totalRead == 0)
- {
- status = FALSE;
- SetLastError (ERROR_HANDLE_EOF);
- }
-
-close:
- DWORD err = GetLastError();
- fclose (f);
-
- if (bTimeStampValid && !IsFileOnReadOnlyFilesystem (keyFile->FileName))
- {
- // Restore the keyfile timestamp
- SetFileTime (src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime);
- }
-
- SetLastError (err);
- return status;
-}
-
-
-BOOL KeyFilesApply (HWND hwndDlg, Password *password, KeyFile *firstKeyFile, const wchar_t* volumeFileName)
-{
- return KeyFilesApplyWithPin (hwndDlg, password, nullptr, firstKeyFile, volumeFileName);
-}
-
-BOOL KeyFilesApplyWithPin (HWND hwndDlg, Password *password, char* pin, KeyFile *firstKeyFile, const wchar_t* volumeFileName)
-{
- BOOL status = TRUE;
- KeyFile kfSubStruct;
- KeyFile *kf;
- KeyFile *kfSub = &kfSubStruct;
- static unsigned __int8 keyPool [KEYFILE_POOL_SIZE];
- size_t i;
- struct stat statStruct;
- wchar_t searchPath [TC_MAX_PATH*2];
- struct _wfinddata_t fBuf;
- intptr_t searchHandle;
-
- HiddenFilesPresentInKeyfilePath = FALSE;
-
- if (firstKeyFile == NULL) return TRUE;
-
- VirtualLock (keyPool, sizeof (keyPool));
- memset (keyPool, 0, sizeof (keyPool));
-
- for (kf = firstKeyFile; kf != NULL; kf = kf->Next)
- {
- // Determine whether it's a security token path
- try
- {
- if (SecurityToken::IsKeyfilePathValid (kf->FileName))
- {
- // Apply security token keyfile
- vector <byte> keyfileData;
- SecurityTokenKeyfilePath secPath (kf->FileName);
- SecurityToken::GetKeyfileData (SecurityTokenKeyfile (secPath, pin), pin, keyfileData);
-
- if (keyfileData.empty())
- {
- SetLastError (ERROR_HANDLE_EOF);
- handleWin32Error (hwndDlg, SRC_POS);
- Error ("ERR_PROCESS_KEYFILE", hwndDlg);
- status = FALSE;
- continue;
- }
-
- unsigned __int32 crc = 0xffffffff;
- int writePos = 0;
- size_t totalRead = 0;
-
- for (size_t i = 0; i < keyfileData.size(); i++)
- {
- crc = UPDC32 (keyfileData[i], crc);
-
- keyPool[writePos++] += (unsigned __int8) (crc >> 24);
- keyPool[writePos++] += (unsigned __int8) (crc >> 16);
- keyPool[writePos++] += (unsigned __int8) (crc >> 8);
- keyPool[writePos++] += (unsigned __int8) crc;
-
- if (writePos >= KEYFILE_POOL_SIZE)
- writePos = 0;
-
- if (++totalRead >= KEYFILE_MAX_READ_LEN)
- break;
- }
-
- burn (&keyfileData.front(), keyfileData.size());
- continue;
- }
- }
- catch (Exception &e)
- {
- e.Show (NULL);
- return FALSE;
- }
-
- // Determine whether it's a path or a file
- if (_wstat (kf->FileName, &statStruct) != 0)
- {
- handleWin32Error (hwndDlg, SRC_POS);
- Error ("ERR_PROCESS_KEYFILE", hwndDlg);
- status = FALSE;
- continue;
- }
-
- if (statStruct.st_mode & S_IFDIR) // If it's a directory
- {
- /* Find and process all keyfiles in the directory */
- int keyfileCount = 0;
-
- StringCbPrintfW (searchPath, sizeof (searchPath), L"%s\\*.*", kf->FileName);
- if ((searchHandle = _wfindfirst (searchPath, &fBuf)) == -1)
- {
- handleWin32Error (hwndDlg, SRC_POS);
- Error ("ERR_PROCESS_KEYFILE_PATH", hwndDlg);
- status = FALSE;
- continue;
- }
-
- do
- {
- WIN32_FILE_ATTRIBUTE_DATA fileAttributes;
-
- StringCbPrintfW (kfSub->FileName, sizeof(kfSub->FileName), L"%s%c%s", kf->FileName,
- L'\\',
- fBuf.name
- );
-
- // Determine whether it's a path or a file
- if (_wstat (kfSub->FileName, &statStruct) != 0)
- {
- handleWin32Error (hwndDlg, SRC_POS);
- Error ("ERR_PROCESS_KEYFILE", hwndDlg);
- status = FALSE;
- continue;
- }
- else if (statStruct.st_mode & S_IFDIR) // If it's a directory
- {
- // Prevent recursive folder scanning
- continue;
- }
-
- // Skip hidden files
- if (GetFileAttributesExW (kfSub->FileName, GetFileExInfoStandard, &fileAttributes)
- && (fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)
- {
- HiddenFilesPresentInKeyfilePath = TRUE;
- continue;
- }
-
- CorrectFileName (kfSub->FileName);
- if (volumeFileName && (_wcsicmp (volumeFileName, kfSub->FileName) == 0))
- {
- // skip if it is the current container file name
- continue;
- }
-
- ++keyfileCount;
-
- // Apply keyfile to the pool
- if (!KeyFileProcess (keyPool, kfSub))
- {
- handleWin32Error (hwndDlg, SRC_POS);
- Error ("ERR_PROCESS_KEYFILE", hwndDlg);
- status = FALSE;
- }
-
- } while (_wfindnext (searchHandle, &fBuf) != -1);
- _findclose (searchHandle);
-
- burn (&kfSubStruct, sizeof (kfSubStruct));
-
- if (keyfileCount == 0)
- {
- ErrorDirect ((wstring (GetString ("ERR_KEYFILE_PATH_EMPTY")) + L"\n\n" + wstring (kf->FileName)).c_str(), hwndDlg);
- status = FALSE;
- }
- }
- // Apply keyfile to the pool
- else if (!KeyFileProcess (keyPool, kf))
- {
- handleWin32Error (hwndDlg, SRC_POS);
- Error ("ERR_PROCESS_KEYFILE", hwndDlg);
- status = FALSE;
- }
- }
-
- /* Mix the keyfile pool contents into the password */
-
- for (i = 0; i < sizeof (keyPool); i++)
- {
- if (i < password->Length)
- password->Text[i] += keyPool[i];
- else
- password->Text[i] = keyPool[i];
- }
-
- if (password->Length < (int)sizeof (keyPool))
- password->Length = sizeof (keyPool);
-
- burn (keyPool, sizeof (keyPool));
-
- return status;
-}
-
-
-static void LoadKeyList (HWND hwndDlg, KeyFile *firstKeyFile)
-{
- KeyFile *kf;
- LVITEM LvItem;
- int line = 0;
- HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST);
-
- ListView_DeleteAllItems (hList);
- EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE), FALSE);
- EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVEALL), firstKeyFile != NULL);
- SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, firstKeyFile != NULL);
-
- for (kf = firstKeyFile; kf != NULL; kf = kf->Next)
- {
- memset (&LvItem,0,sizeof(LvItem));
- LvItem.mask = LVIF_TEXT|LVIF_PARAM;
- LvItem.iItem = line++;
- LvItem.iSubItem = 0;
- LvItem.pszText = kf->FileName;
- LvItem.lParam = (LPARAM) kf;
- SendMessage (hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
- }
-}
-
-#if KEYFILE_POOL_SIZE % 4 != 0
-#error KEYFILE_POOL_SIZE must be a multiple of 4
-#endif
-
-BOOL CALLBACK KeyFilesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
-{
- static KeyFilesDlgParam *param;
- static KeyFilesDlgParam origParam;
-
- WORD lw = LOWORD (wParam);
-
- switch (msg)
- {
- case WM_INITDIALOG:
- {
- LVCOLUMNW LvCol;
- HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST);
-
- param = (KeyFilesDlgParam *) lParam;
- origParam = *(KeyFilesDlgParam *) lParam;
-
- KeyFileCloneAll (param->FirstKeyFile, &param->FirstKeyFile);
-
- LocalizeDialog (hwndDlg, "IDD_KEYFILES");
- DragAcceptFiles (hwndDlg, TRUE);
-
- SendMessageW (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0,
- LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP
- );
-
- memset (&LvCol,0,sizeof(LvCol));
- LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
- LvCol.pszText = GetString ("KEYFILE");
- LvCol.cx = CompensateXDPI (374);
- LvCol.fmt = LVCFMT_LEFT;
- SendMessageW (hList, LVM_INSERTCOLUMNW, 0, (LPARAM)&LvCol);
-
- LoadKeyList (hwndDlg, param->FirstKeyFile);
- SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, param->EnableKeyFiles);
-
-#ifdef TCMOUNT
- if ( (origParam.EnableKeyFiles == defaultKeyFilesParam.EnableKeyFiles)
- && (origParam.FirstKeyFile == defaultKeyFilesParam.FirstKeyFile)
- )
- {
- /* default keyfile dialog case */
- SetCheckBox (hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD, bTryEmptyPasswordWhenKeyfileUsed);
- ShowWindow(GetDlgItem(hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD), SW_SHOW);
- }
-#endif
-
- SetWindowTextW(GetDlgItem(hwndDlg, IDT_KEYFILES_NOTE), GetString ("KEYFILES_NOTE"));
-
- ToHyperlink (hwndDlg, IDC_LINK_KEYFILES_INFO);
- }
- return 1;
-
- case WM_COMMAND:
-
- if (lw == IDC_KEYADD)
- {
- KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
- if (kf)
- {
- if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, sizeof(kf->FileName),bHistory))
- {
- bool containerFileSkipped = false;
- do
- {
- CorrectFileName (kf->FileName);
- if (_wcsicmp (param->VolumeFileName, kf->FileName) == 0)
- containerFileSkipped = true;
- else
- {
- param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
- LoadKeyList (hwndDlg, param->FirstKeyFile);
-
- kf = (KeyFile *) malloc (sizeof (KeyFile));
- }
- } while (SelectMultipleFilesNext (kf->FileName, sizeof(kf->FileName)));
-
- if (containerFileSkipped)
- {
- Warning ("SELECTED_KEYFILE_IS_CONTAINER_FILE", hwndDlg);
- }
- }
-
- free (kf);
- }
- return 1;
- }
-
- if (lw == IDC_ADD_KEYFILE_PATH)
- {
- KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
-
- if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName))
- {
- param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
- LoadKeyList (hwndDlg, param->FirstKeyFile);
- }
- else
- {
- free (kf);
- }
- return 1;
- }
-
- if (lw == IDC_TOKEN_FILES_ADD)
- {
- list <SecurityTokenKeyfilePath> selectedTokenKeyfiles;
- if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK)
- {
- foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles)
- {
- KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
- if (kf)
- {
- StringCbCopyW (kf->FileName, sizeof (kf->FileName), wstring(keyPath).c_str ());
-
- param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
- LoadKeyList (hwndDlg, param->FirstKeyFile);
- }
- }
- }
-
- return 1;
- }
-
- if (lw == IDC_KEYREMOVE)
- {
- HWND list = GetDlgItem (hwndDlg, IDC_KEYLIST);
- LVITEM LvItem;
- memset (&LvItem, 0, sizeof(LvItem));
- LvItem.mask = LVIF_PARAM;
- LvItem.iItem = -1;
-
- while (-1 != (LvItem.iItem = ListView_GetNextItem (list, LvItem.iItem, LVIS_SELECTED)))
- {
- ListView_GetItem (list, &LvItem);
- param->FirstKeyFile = KeyFileRemove (param->FirstKeyFile, (KeyFile *) LvItem.lParam);
- }
-
- LoadKeyList (hwndDlg, param->FirstKeyFile);
- return 1;
- }
-
- if (lw == IDC_KEYREMOVEALL)
- {
- KeyFileRemoveAll (&param->FirstKeyFile);
- LoadKeyList (hwndDlg, NULL);
- return 1;
- }
-
- if (lw == IDC_GENERATE_KEYFILE)
- {
- DialogBoxParamW (hInst,
- MAKEINTRESOURCEW (IDD_KEYFILE_GENERATOR), hwndDlg,
- (DLGPROC) KeyfileGeneratorDlgProc, (LPARAM) 0);
- return 1;
- }
-
- if (lw == IDC_LINK_KEYFILES_INFO)
- {
- Applink ("keyfiles", TRUE, "");
- return 1;
- }
-
- if (lw == IDOK)
- {
- param->EnableKeyFiles = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_ENABLE));
-
-#ifdef TCMOUNT
- if (IsWindowVisible (GetDlgItem (hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD)))
- {
- bTryEmptyPasswordWhenKeyfileUsed = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD));
-
- if (UsePreferences)
- {
- WaitCursor ();
- SaveSettings (hwndDlg);
- NormalCursor ();
- }
- }
-#endif
- EndDialog (hwndDlg, IDOK);
- return 1;
- }
-
- if (lw == IDCANCEL)
- {
- KeyFileRemoveAll (&param->FirstKeyFile);
- *param = origParam;
-
- EndDialog (hwndDlg, IDCLOSE);
- return 1;
- }
- break;
-
- case WM_DROPFILES:
- {
- HDROP hdrop = (HDROP) wParam;
-
- int i = 0, count = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
-
- while (count-- > 0)
- {
- KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
- if (kf)
- {
- DragQueryFile (hdrop, i++, kf->FileName, ARRAYSIZE (kf->FileName));
- param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
- LoadKeyList (hwndDlg, param->FirstKeyFile);
- }
- }
-
- DragFinish (hdrop);
- }
- return 1;
-
- case WM_NOTIFY:
- if (((LPNMHDR) lParam)->code == LVN_ITEMCHANGED)
- {
- EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE),
- ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_KEYLIST), -1, LVIS_SELECTED) != -1);
- return 1;
- }
- break;
-
- case WM_CLOSE:
- KeyFileRemoveAll (&param->FirstKeyFile);
- *param = origParam;
-
- EndDialog (hwndDlg, IDCLOSE);
- return 1;
-
- break;
-
- }
-
- return 0;
-}
-
-
-#define IDM_KEYFILES_POPUP_ADD_FILES 9001
-#define IDM_KEYFILES_POPUP_ADD_DIR 9002
-#define IDM_KEYFILES_POPUP_ADD_TOKEN_FILES 9003
-
-BOOL KeyfilesPopupMenu (HWND hwndDlg, POINT popupPosition, KeyFilesDlgParam *param)
-{
- HMENU popup = CreatePopupMenu ();
- if (!popup)
- return FALSE;
- int sel;
- BOOL status = FALSE;
-
- AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_FILES, GetString ("IDC_KEYADD"));
- AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_DIR, GetString ("IDC_ADD_KEYFILE_PATH"));
- AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_TOKEN_FILES, GetString ("IDC_TOKEN_FILES_ADD"));
-
- sel = TrackPopupMenu (popup, TPM_RETURNCMD | TPM_LEFTBUTTON, popupPosition.x, popupPosition.y, 0, hwndDlg, NULL);
-
- switch (sel)
- {
- case IDM_KEYFILES_POPUP_ADD_FILES:
- {
- KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
- if (kf)
- {
- if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, sizeof(kf->FileName),bHistory))
- {
- do
- {
- param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
- kf = (KeyFile *) malloc (sizeof (KeyFile));
- } while (SelectMultipleFilesNext (kf->FileName, sizeof(kf->FileName)));
-
- param->EnableKeyFiles = TRUE;
- status = TRUE;
- }
-
- free (kf);
- }
- }
- break;
-
- case IDM_KEYFILES_POPUP_ADD_DIR:
- {
- KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
- if (kf)
- {
- if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName))
- {
- param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
- param->EnableKeyFiles = TRUE;
- status = TRUE;
- }
- else
- {
- free (kf);
- }
- }
- }
- break;
-
- case IDM_KEYFILES_POPUP_ADD_TOKEN_FILES:
- {
- list <SecurityTokenKeyfilePath> selectedTokenKeyfiles;
- if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK)
- {
- foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles)
- {
- KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
- if (kf)
- {
- StringCbCopyW (kf->FileName, sizeof (kf->FileName), wstring (keyPath).c_str());
-
- param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
- param->EnableKeyFiles = TRUE;
- status = TRUE;
- }
- }
- }
- }
- break;
- }
-
- DestroyMenu (popup);
- return status;
-}
+/*
+ Derived from source code of TrueCrypt 7.1a, which is
+ Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
+ by the TrueCrypt License 3.0.
+
+ Modifications and additions to the original source code (contained in this file)
+ and all other portions of this file are Copyright (c) 2013-2016 IDRIX
+ and are governed by the Apache License 2.0 the full text of which is
+ contained in the file License.txt included in VeraCrypt binary and source
+ code distribution packages.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "Tcdefs.h"
+#include "Keyfiles.h"
+#include "Crc.h"
+
+#include <io.h>
+#include "Dlgcode.h"
+#include "Language.h"
+#include "SecurityToken.h"
+#include "Common/resource.h"
+#include "Platform/Finally.h"
+#include "Platform/ForEach.h"
+#ifdef TCMOUNT
+#include "Mount/Mount.h"
+#endif
+
+#include <Strsafe.h>
+
+using namespace VeraCrypt;
+
+#define stat _stat
+#define S_IFDIR _S_IFDIR
+
+
+BOOL HiddenFilesPresentInKeyfilePath = FALSE;
+
+#ifdef TCMOUNT
+extern BOOL UsePreferences;
+#endif
+
+KeyFile *KeyFileAdd (KeyFile *firstKeyFile, KeyFile *keyFile)
+{
+ KeyFile *kf = firstKeyFile;
+
+ if (firstKeyFile != NULL)
+ {
+ while (kf->Next)
+ kf = kf->Next;
+
+ kf->Next = keyFile;
+ }
+ else
+ firstKeyFile = keyFile;
+
+ keyFile->Next = NULL;
+
+ return firstKeyFile;
+}
+
+
+// Returns first keyfile, NULL if last keyfile was removed
+static KeyFile *KeyFileRemove (KeyFile *firstKeyFile, KeyFile *keyFile)
+{
+ KeyFile *prevkf = NULL, *kf = firstKeyFile;
+
+ if (firstKeyFile == NULL) return NULL;
+ do
+ {
+ if (kf == keyFile)
+ {
+ if (prevkf == NULL)
+ firstKeyFile = kf->Next;
+ else
+ prevkf->Next = kf->Next;
+
+ burn (keyFile, sizeof(*keyFile)); // wipe
+ free (keyFile);
+ break;
+ }
+ prevkf = kf;
+ }
+ while (kf = kf->Next);
+
+ return firstKeyFile;
+}
+
+
+void KeyFileRemoveAll (KeyFile **firstKeyFile)
+{
+ KeyFile *kf = *firstKeyFile;
+ while (kf != NULL)
+ {
+ KeyFile *d = kf;
+ kf = kf->Next;
+ burn (d, sizeof(*d)); // wipe
+ free (d);
+ }
+
+ *firstKeyFile = NULL;
+}
+
+
+KeyFile *KeyFileClone (KeyFile *keyFile)
+{
+ KeyFile *clone = NULL;
+
+ if (keyFile == NULL) return NULL;
+
+ clone = (KeyFile *) malloc (sizeof (KeyFile));
+ if (clone)
+ {
+ StringCbCopyW (clone->FileName, sizeof(clone->FileName), keyFile->FileName);
+ clone->Next = NULL;
+ }
+ return clone;
+}
+
+
+void KeyFileCloneAll (KeyFile *firstKeyFile, KeyFile **outputKeyFile)
+{
+ if (outputKeyFile)
+ {
+ KeyFile *cloneFirstKeyFile = KeyFileClone (firstKeyFile);
+ KeyFile *kf;
+
+ // free output only if different from input
+ if (*outputKeyFile != firstKeyFile)
+ KeyFileRemoveAll (outputKeyFile);
+ if (firstKeyFile)
+ {
+ kf = firstKeyFile->Next;
+ while (kf != NULL)
+ {
+ KeyFileAdd (cloneFirstKeyFile, KeyFileClone (kf));
+ kf = kf->Next;
+ }
+
+ *outputKeyFile = cloneFirstKeyFile;
+ }
+ }
+}
+
+
+static BOOL KeyFileProcess (unsigned __int8 *keyPool, KeyFile *keyFile)
+{
+ FILE *f;
+ unsigned __int8 buffer[64 * 1024];
+ unsigned __int32 crc = 0xffffffff;
+ int writePos = 0;
+ size_t bytesRead, totalRead = 0;
+ int status = TRUE;
+
+ HANDLE src;
+ FILETIME ftCreationTime;
+ FILETIME ftLastWriteTime;
+ FILETIME ftLastAccessTime;
+
+ BOOL bTimeStampValid = FALSE;
+
+ /* Remember the last access time of the keyfile. It will be preserved in order to prevent
+ an adversary from determining which file may have been used as keyfile. */
+ src = CreateFile (keyFile->FileName,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (src != INVALID_HANDLE_VALUE)
+ {
+ if (GetFileTime ((HANDLE) src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime))
+ bTimeStampValid = TRUE;
+ }
+
+ finally_do_arg (HANDLE, src,
+ {
+ if (finally_arg != INVALID_HANDLE_VALUE)
+ CloseHandle (finally_arg);
+ });
+
+ f = _wfopen (keyFile->FileName, L"rb");
+ if (f == NULL) return FALSE;
+
+ while ((bytesRead = fread (buffer, 1, sizeof (buffer), f)) > 0)
+ {
+ size_t i;
+
+ if (ferror (f))
+ {
+ status = FALSE;
+ goto close;
+ }
+
+ for (i = 0; i < bytesRead; i++)
+ {
+ crc = UPDC32 (buffer[i], crc);
+
+ keyPool[writePos++] += (unsigned __int8) (crc >> 24);
+ keyPool[writePos++] += (unsigned __int8) (crc >> 16);
+ keyPool[writePos++] += (unsigned __int8) (crc >> 8);
+ keyPool[writePos++] += (unsigned __int8) crc;
+
+ if (writePos >= KEYFILE_POOL_SIZE)
+ writePos = 0;
+
+ if (++totalRead >= KEYFILE_MAX_READ_LEN)
+ goto close;
+ }
+ }
+
+ if (ferror (f))
+ {
+ status = FALSE;
+ }
+ else if (totalRead == 0)
+ {
+ status = FALSE;
+ SetLastError (ERROR_HANDLE_EOF);
+ }
+
+close:
+ DWORD err = GetLastError();
+ fclose (f);
+
+ if (bTimeStampValid && !IsFileOnReadOnlyFilesystem (keyFile->FileName))
+ {
+ // Restore the keyfile timestamp
+ SetFileTime (src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime);
+ }
+
+ SetLastError (err);
+ return status;
+}
+
+
+BOOL KeyFilesApply (HWND hwndDlg, Password *password, KeyFile *firstKeyFile, const wchar_t* volumeFileName)
+{
+ return KeyFilesApplyWithPin (hwndDlg, password, nullptr, firstKeyFile, volumeFileName);
+}
+
+BOOL KeyFilesApplyWithPin (HWND hwndDlg, Password *password, char* pin, KeyFile *firstKeyFile, const wchar_t* volumeFileName)
+{
+ BOOL status = TRUE;
+ KeyFile kfSubStruct;
+ KeyFile *kf;
+ KeyFile *kfSub = &kfSubStruct;
+ static unsigned __int8 keyPool [KEYFILE_POOL_SIZE];
+ size_t i;
+ struct stat statStruct;
+ wchar_t searchPath [TC_MAX_PATH*2];
+ struct _wfinddata_t fBuf;
+ intptr_t searchHandle;
+
+ HiddenFilesPresentInKeyfilePath = FALSE;
+
+ if (firstKeyFile == NULL) return TRUE;
+
+ VirtualLock (keyPool, sizeof (keyPool));
+ memset (keyPool, 0, sizeof (keyPool));
+
+ for (kf = firstKeyFile; kf != NULL; kf = kf->Next)
+ {
+ // Determine whether it's a security token path
+ try
+ {
+ if (SecurityToken::IsKeyfilePathValid (kf->FileName))
+ {
+ // Apply security token keyfile
+ vector <byte> keyfileData;
+ SecurityTokenKeyfilePath secPath (kf->FileName);
+ SecurityToken::GetKeyfileData (SecurityTokenKeyfile (secPath, pin), pin, keyfileData);
+
+ if (keyfileData.empty())
+ {
+ SetLastError (ERROR_HANDLE_EOF);
+ handleWin32Error (hwndDlg, SRC_POS);
+ Error ("ERR_PROCESS_KEYFILE", hwndDlg);
+ status = FALSE;
+ continue;
+ }
+
+ unsigned __int32 crc = 0xffffffff;
+ int writePos = 0;
+ size_t totalRead = 0;
+
+ for (size_t i = 0; i < keyfileData.size(); i++)
+ {
+ crc = UPDC32 (keyfileData[i], crc);
+
+ keyPool[writePos++] += (unsigned __int8) (crc >> 24);
+ keyPool[writePos++] += (unsigned __int8) (crc >> 16);
+ keyPool[writePos++] += (unsigned __int8) (crc >> 8);
+ keyPool[writePos++] += (unsigned __int8) crc;
+
+ if (writePos >= KEYFILE_POOL_SIZE)
+ writePos = 0;
+
+ if (++totalRead >= KEYFILE_MAX_READ_LEN)
+ break;
+ }
+
+ burn (&keyfileData.front(), keyfileData.size());
+ continue;
+ }
+ }
+ catch (Exception &e)
+ {
+ e.Show (NULL);
+ return FALSE;
+ }
+
+ // Determine whether it's a path or a file
+ if (_wstat (kf->FileName, &statStruct) != 0)
+ {
+ handleWin32Error (hwndDlg, SRC_POS);
+ Error ("ERR_PROCESS_KEYFILE", hwndDlg);
+ status = FALSE;
+ continue;
+ }
+
+ if (statStruct.st_mode & S_IFDIR) // If it's a directory
+ {
+ /* Find and process all keyfiles in the directory */
+ int keyfileCount = 0;
+
+ StringCbPrintfW (searchPath, sizeof (searchPath), L"%s\\*.*", kf->FileName);
+ if ((searchHandle = _wfindfirst (searchPath, &fBuf)) == -1)
+ {
+ handleWin32Error (hwndDlg, SRC_POS);
+ Error ("ERR_PROCESS_KEYFILE_PATH", hwndDlg);
+ status = FALSE;
+ continue;
+ }
+
+ do
+ {
+ WIN32_FILE_ATTRIBUTE_DATA fileAttributes;
+
+ StringCbPrintfW (kfSub->FileName, sizeof(kfSub->FileName), L"%s%c%s", kf->FileName,
+ L'\\',
+ fBuf.name
+ );
+
+ // Determine whether it's a path or a file
+ if (_wstat (kfSub->FileName, &statStruct) != 0)
+ {
+ handleWin32Error (hwndDlg, SRC_POS);
+ Error ("ERR_PROCESS_KEYFILE", hwndDlg);
+ status = FALSE;
+ continue;
+ }
+ else if (statStruct.st_mode & S_IFDIR) // If it's a directory
+ {
+ // Prevent recursive folder scanning
+ continue;
+ }
+
+ // Skip hidden files
+ if (GetFileAttributesExW (kfSub->FileName, GetFileExInfoStandard, &fileAttributes)
+ && (fileAttributes.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) != 0)
+ {
+ HiddenFilesPresentInKeyfilePath = TRUE;
+ continue;
+ }
+
+ CorrectFileName (kfSub->FileName);
+ if (volumeFileName && (_wcsicmp (volumeFileName, kfSub->FileName) == 0))
+ {
+ // skip if it is the current container file name
+ continue;
+ }
+
+ ++keyfileCount;
+
+ // Apply keyfile to the pool
+ if (!KeyFileProcess (keyPool, kfSub))
+ {
+ handleWin32Error (hwndDlg, SRC_POS);
+ Error ("ERR_PROCESS_KEYFILE", hwndDlg);
+ status = FALSE;
+ }
+
+ } while (_wfindnext (searchHandle, &fBuf) != -1);
+ _findclose (searchHandle);
+
+ burn (&kfSubStruct, sizeof (kfSubStruct));
+
+ if (keyfileCount == 0)
+ {
+ ErrorDirect ((wstring (GetString ("ERR_KEYFILE_PATH_EMPTY")) + L"\n\n" + wstring (kf->FileName)).c_str(), hwndDlg);
+ status = FALSE;
+ }
+ }
+ // Apply keyfile to the pool
+ else if (!KeyFileProcess (keyPool, kf))
+ {
+ handleWin32Error (hwndDlg, SRC_POS);
+ Error ("ERR_PROCESS_KEYFILE", hwndDlg);
+ status = FALSE;
+ }
+ }
+
+ /* Mix the keyfile pool contents into the password */
+
+ for (i = 0; i < sizeof (keyPool); i++)
+ {
+ if (i < password->Length)
+ password->Text[i] += keyPool[i];
+ else
+ password->Text[i] = keyPool[i];
+ }
+
+ if (password->Length < (int)sizeof (keyPool))
+ password->Length = sizeof (keyPool);
+
+ burn (keyPool, sizeof (keyPool));
+
+ return status;
+}
+
+
+static void LoadKeyList (HWND hwndDlg, KeyFile *firstKeyFile)
+{
+ KeyFile *kf;
+ LVITEM LvItem;
+ int line = 0;
+ HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST);
+
+ ListView_DeleteAllItems (hList);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE), FALSE);
+ EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVEALL), firstKeyFile != NULL);
+ SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, firstKeyFile != NULL);
+
+ for (kf = firstKeyFile; kf != NULL; kf = kf->Next)
+ {
+ memset (&LvItem,0,sizeof(LvItem));
+ LvItem.mask = LVIF_TEXT|LVIF_PARAM;
+ LvItem.iItem = line++;
+ LvItem.iSubItem = 0;
+ LvItem.pszText = kf->FileName;
+ LvItem.lParam = (LPARAM) kf;
+ SendMessage (hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem);
+ }
+}
+
+#if KEYFILE_POOL_SIZE % 4 != 0
+#error KEYFILE_POOL_SIZE must be a multiple of 4
+#endif
+
+BOOL CALLBACK KeyFilesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static KeyFilesDlgParam *param;
+ static KeyFilesDlgParam origParam;
+
+ WORD lw = LOWORD (wParam);
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ LVCOLUMNW LvCol;
+ HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST);
+
+ param = (KeyFilesDlgParam *) lParam;
+ origParam = *(KeyFilesDlgParam *) lParam;
+
+ KeyFileCloneAll (param->FirstKeyFile, &param->FirstKeyFile);
+
+ LocalizeDialog (hwndDlg, "IDD_KEYFILES");
+ DragAcceptFiles (hwndDlg, TRUE);
+
+ SendMessageW (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0,
+ LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP
+ );
+
+ memset (&LvCol,0,sizeof(LvCol));
+ LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT;
+ LvCol.pszText = GetString ("KEYFILE");
+ LvCol.cx = CompensateXDPI (374);
+ LvCol.fmt = LVCFMT_LEFT;
+ SendMessageW (hList, LVM_INSERTCOLUMNW, 0, (LPARAM)&LvCol);
+
+ LoadKeyList (hwndDlg, param->FirstKeyFile);
+ SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, param->EnableKeyFiles);
+
+#ifdef TCMOUNT
+ if ( (origParam.EnableKeyFiles == defaultKeyFilesParam.EnableKeyFiles)
+ && (origParam.FirstKeyFile == defaultKeyFilesParam.FirstKeyFile)
+ )
+ {
+ /* default keyfile dialog case */
+ SetCheckBox (hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD, bTryEmptyPasswordWhenKeyfileUsed);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD), SW_SHOW);
+ }
+#endif
+
+ SetWindowTextW(GetDlgItem(hwndDlg, IDT_KEYFILES_NOTE), GetString ("KEYFILES_NOTE"));
+
+ ToHyperlink (hwndDlg, IDC_LINK_KEYFILES_INFO);
+ }
+ return 1;
+
+ case WM_COMMAND:
+
+ if (lw == IDC_KEYADD)
+ {
+ KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
+ if (kf)
+ {
+ if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, sizeof(kf->FileName),bHistory))
+ {
+ bool containerFileSkipped = false;
+ do
+ {
+ CorrectFileName (kf->FileName);
+ if (_wcsicmp (param->VolumeFileName, kf->FileName) == 0)
+ containerFileSkipped = true;
+ else
+ {
+ param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
+ LoadKeyList (hwndDlg, param->FirstKeyFile);
+
+ kf = (KeyFile *) malloc (sizeof (KeyFile));
+ }
+ } while (SelectMultipleFilesNext (kf->FileName, sizeof(kf->FileName)));
+
+ if (containerFileSkipped)
+ {
+ Warning ("SELECTED_KEYFILE_IS_CONTAINER_FILE", hwndDlg);
+ }
+ }
+
+ free (kf);
+ }
+ return 1;
+ }
+
+ if (lw == IDC_ADD_KEYFILE_PATH)
+ {
+ KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
+
+ if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName))
+ {
+ param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
+ LoadKeyList (hwndDlg, param->FirstKeyFile);
+ }
+ else
+ {
+ free (kf);
+ }
+ return 1;
+ }
+
+ if (lw == IDC_TOKEN_FILES_ADD)
+ {
+ list <SecurityTokenKeyfilePath> selectedTokenKeyfiles;
+ if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK)
+ {
+ foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles)
+ {
+ KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
+ if (kf)
+ {
+ StringCbCopyW (kf->FileName, sizeof (kf->FileName), wstring(keyPath).c_str ());
+
+ param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
+ LoadKeyList (hwndDlg, param->FirstKeyFile);
+ }
+ }
+ }
+
+ return 1;
+ }
+
+ if (lw == IDC_KEYREMOVE)
+ {
+ HWND list = GetDlgItem (hwndDlg, IDC_KEYLIST);
+ LVITEM LvItem;
+ memset (&LvItem, 0, sizeof(LvItem));
+ LvItem.mask = LVIF_PARAM;
+ LvItem.iItem = -1;
+
+ while (-1 != (LvItem.iItem = ListView_GetNextItem (list, LvItem.iItem, LVIS_SELECTED)))
+ {
+ ListView_GetItem (list, &LvItem);
+ param->FirstKeyFile = KeyFileRemove (param->FirstKeyFile, (KeyFile *) LvItem.lParam);
+ }
+
+ LoadKeyList (hwndDlg, param->FirstKeyFile);
+ return 1;
+ }
+
+ if (lw == IDC_KEYREMOVEALL)
+ {
+ KeyFileRemoveAll (&param->FirstKeyFile);
+ LoadKeyList (hwndDlg, NULL);
+ return 1;
+ }
+
+ if (lw == IDC_GENERATE_KEYFILE)
+ {
+ DialogBoxParamW (hInst,
+ MAKEINTRESOURCEW (IDD_KEYFILE_GENERATOR), hwndDlg,
+ (DLGPROC) KeyfileGeneratorDlgProc, (LPARAM) 0);
+ return 1;
+ }
+
+ if (lw == IDC_LINK_KEYFILES_INFO)
+ {
+ Applink ("keyfiles", TRUE, "");
+ return 1;
+ }
+
+ if (lw == IDOK)
+ {
+ param->EnableKeyFiles = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_ENABLE));
+
+#ifdef TCMOUNT
+ if (IsWindowVisible (GetDlgItem (hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD)))
+ {
+ bTryEmptyPasswordWhenKeyfileUsed = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_TRY_EMPTY_PASSWORD));
+
+ if (UsePreferences)
+ {
+ WaitCursor ();
+ SaveSettings (hwndDlg);
+ NormalCursor ();
+ }
+ }
+#endif
+ EndDialog (hwndDlg, IDOK);
+ return 1;
+ }
+
+ if (lw == IDCANCEL)
+ {
+ KeyFileRemoveAll (&param->FirstKeyFile);
+ *param = origParam;
+
+ EndDialog (hwndDlg, IDCLOSE);
+ return 1;
+ }
+ break;
+
+ case WM_DROPFILES:
+ {
+ HDROP hdrop = (HDROP) wParam;
+
+ int i = 0, count = DragQueryFile (hdrop, 0xFFFFFFFF, NULL, 0);
+
+ while (count-- > 0)
+ {
+ KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
+ if (kf)
+ {
+ DragQueryFile (hdrop, i++, kf->FileName, ARRAYSIZE (kf->FileName));
+ param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
+ LoadKeyList (hwndDlg, param->FirstKeyFile);
+ }
+ }
+
+ DragFinish (hdrop);
+ }
+ return 1;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR) lParam)->code == LVN_ITEMCHANGED)
+ {
+ EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE),
+ ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_KEYLIST), -1, LVIS_SELECTED) != -1);
+ return 1;
+ }
+ break;
+
+ case WM_CLOSE:
+ KeyFileRemoveAll (&param->FirstKeyFile);
+ *param = origParam;
+
+ EndDialog (hwndDlg, IDCLOSE);
+ return 1;
+
+ break;
+
+ }
+
+ return 0;
+}
+
+
+#define IDM_KEYFILES_POPUP_ADD_FILES 9001
+#define IDM_KEYFILES_POPUP_ADD_DIR 9002
+#define IDM_KEYFILES_POPUP_ADD_TOKEN_FILES 9003
+
+BOOL KeyfilesPopupMenu (HWND hwndDlg, POINT popupPosition, KeyFilesDlgParam *param)
+{
+ HMENU popup = CreatePopupMenu ();
+ if (!popup)
+ return FALSE;
+ int sel;
+ BOOL status = FALSE;
+
+ AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_FILES, GetString ("IDC_KEYADD"));
+ AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_DIR, GetString ("IDC_ADD_KEYFILE_PATH"));
+ AppendMenuW (popup, MF_STRING, IDM_KEYFILES_POPUP_ADD_TOKEN_FILES, GetString ("IDC_TOKEN_FILES_ADD"));
+
+ sel = TrackPopupMenu (popup, TPM_RETURNCMD | TPM_LEFTBUTTON, popupPosition.x, popupPosition.y, 0, hwndDlg, NULL);
+
+ switch (sel)
+ {
+ case IDM_KEYFILES_POPUP_ADD_FILES:
+ {
+ KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
+ if (kf)
+ {
+ if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, sizeof(kf->FileName),bHistory))
+ {
+ do
+ {
+ param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
+ kf = (KeyFile *) malloc (sizeof (KeyFile));
+ } while (SelectMultipleFilesNext (kf->FileName, sizeof(kf->FileName)));
+
+ param->EnableKeyFiles = TRUE;
+ status = TRUE;
+ }
+
+ free (kf);
+ }
+ }
+ break;
+
+ case IDM_KEYFILES_POPUP_ADD_DIR:
+ {
+ KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
+ if (kf)
+ {
+ if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName))
+ {
+ param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
+ param->EnableKeyFiles = TRUE;
+ status = TRUE;
+ }
+ else
+ {
+ free (kf);
+ }
+ }
+ }
+ break;
+
+ case IDM_KEYFILES_POPUP_ADD_TOKEN_FILES:
+ {
+ list <SecurityTokenKeyfilePath> selectedTokenKeyfiles;
+ if (DialogBoxParamW (hInst, MAKEINTRESOURCEW (IDD_TOKEN_KEYFILES), hwndDlg, (DLGPROC) SecurityTokenKeyfileDlgProc, (LPARAM) &selectedTokenKeyfiles) == IDOK)
+ {
+ foreach (const SecurityTokenKeyfilePath &keyPath, selectedTokenKeyfiles)
+ {
+ KeyFile *kf = (KeyFile *) malloc (sizeof (KeyFile));
+ if (kf)
+ {
+ StringCbCopyW (kf->FileName, sizeof (kf->FileName), wstring (keyPath).c_str());
+
+ param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf);
+ param->EnableKeyFiles = TRUE;
+ status = TRUE;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ DestroyMenu (popup);
+ return status;
+}