www.pudn.com > truecrypt-4.2-source-code.zip > Keyfiles.c
/* Copyright (c) 2004-2006 TrueCrypt Foundation. All rights reserved. Covered by TrueCrypt License 2.0 the full text of which is contained in the file License.txt included in TrueCrypt binary and source code distribution archives. */ #include#include #include "Tcdefs.h" #include "Keyfiles.h" #include "Crc.h" #ifdef _WIN32 #include #include "Dlgcode.h" #include "Language.h" #include "../common/resource.h" #define stat _stat #define S_IFDIR _S_IFDIR #define snprintf _snprintf #else #include #include #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; memset (keyFile, 0, 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; if (keyFile == NULL) return NULL; clone = malloc (sizeof (KeyFile)); strcpy (clone->FileName, keyFile->FileName); clone->Next = NULL; return clone; } KeyFile *KeyFileCloneAll (KeyFile *firstKeyFile) { KeyFile *cloneFirstKeyFile = KeyFileClone (firstKeyFile); KeyFile *kf; if (firstKeyFile == NULL) return NULL; kf = firstKeyFile->Next; while (kf != NULL) { KeyFileAdd (cloneFirstKeyFile, KeyFileClone (kf)); kf = kf->Next; } return cloneFirstKeyFile; } static BOOL KeyFileProcess (unsigned __int8 *keyPool, KeyFile *keyFile, BOOL preserveTimestamp) { FILE *f; unsigned __int8 buffer[64 * 1024]; unsigned __int32 crc = 0xffffffff; int writePos = 0; size_t bytesRead, totalRead = 0; #ifdef _WIN32 HANDLE src; FILETIME ftCreationTime; FILETIME ftLastWriteTime; FILETIME ftLastAccessTime; #else struct stat kfStat; #endif BOOL bTimeStampValid = FALSE; if (preserveTimestamp) { /* 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. */ #ifdef _WIN32 src = CreateFile (keyFile->FileName, preserveTimestamp ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ, 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; else Warning ("GETFILETIME_FAILED_KEYFILE"); } #else bTimeStampValid = stat (keyFile->FileName, &kfStat) == 0; #endif } f = fopen (keyFile->FileName, "rb"); if (f == NULL) return FALSE; while ((bytesRead = fread (buffer, 1, sizeof (buffer), f)) > 0) { size_t i; 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; } } close: fclose (f); if (bTimeStampValid) { // Restore the keyfile timestamp #ifdef _WIN32 if (!SetFileTime (src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime)) Warning ("SETFILETIME_FAILED_KEYFILE"); CloseHandle (src); #else struct utimbuf u; u.actime = kfStat.st_atime; u.modtime = kfStat.st_atime; utime (keyFile->FileName, &u); #endif } return TRUE; } BOOL KeyFilesApply (Password *password, KeyFile *firstKeyFile, BOOL preserveTimestamp) { BOOL status = TRUE; KeyFile kfSubStruct; KeyFile *kf; KeyFile *kfSub = &kfSubStruct; static unsigned __int8 keyPool [KEYFILE_POOL_SIZE]; int i; struct stat statStruct; char searchPath [TC_MAX_PATH*2]; #ifdef _WIN32 struct _finddata_t fBuf; intptr_t searchHandle; #else struct dirent *fBuf; DIR *searchHandle; #endif if (firstKeyFile == NULL) return TRUE; #ifdef _WIN32 VirtualLock (keyPool, sizeof (keyPool)); #endif memset (keyPool, 0, sizeof (keyPool)); for (kf = firstKeyFile; kf != NULL; kf = kf->Next) { // Determine whether it's a path or a file if (stat (kf->FileName, &statStruct) != 0) { #ifdef _WIN32 Error ("ERR_PROCESS_KEYFILE"); #else perror ("stat"); #endif status = FALSE; continue; } if (statStruct.st_mode & S_IFDIR) // If it's a directory { /* Find and process all keyfiles in the directory */ #ifdef _WIN32 snprintf (searchPath, sizeof (searchPath), "%s\\*.*", kf->FileName); if ((searchHandle = _findfirst (searchPath, &fBuf)) == -1) #else if ((searchHandle = opendir (kf->FileName)) == NULL) #endif { #ifdef _WIN32 Error ("ERR_PROCESS_KEYFILE_PATH"); #endif status = FALSE; continue; } #ifdef _WIN32 do #else while ((fBuf = readdir (searchHandle)) != NULL) #endif { snprintf (kfSub->FileName, sizeof(kfSub->FileName), "%s%c%s", kf->FileName, #ifdef _WIN32 '\\', fBuf.name #else '/', fBuf->d_name #endif ); // Determine whether it's a path or a file if (stat (kfSub->FileName, &statStruct) != 0) { #ifdef _WIN32 Error ("ERR_PROCESS_KEYFILE"); #endif status = FALSE; continue; } else if (statStruct.st_mode & S_IFDIR) // If it's a directory { // Prevent recursive folder scanning continue; } // Apply keyfile to the pool if (!KeyFileProcess (keyPool, kfSub, preserveTimestamp)) { #ifdef _WIN32 handleWin32Error (NULL); Error ("ERR_PROCESS_KEYFILE"); #endif status = FALSE; } #ifdef _WIN32 } while (_findnext (searchHandle, &fBuf) != -1); _findclose (searchHandle); #else } closedir (searchHandle); #endif burn (&kfSubStruct, sizeof (kfSubStruct)); } // Apply keyfile to the pool else if (!KeyFileProcess (keyPool, kf, preserveTimestamp)) { #ifdef _WIN32 handleWin32Error (NULL); Error ("ERR_PROCESS_KEYFILE"); #endif status = FALSE; } } /* Mix the keyfile pool contents into the password */ for (i = 0; i < (int)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; } #ifdef _WIN32 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 WINAPI 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; param->FirstKeyFile = KeyFileCloneAll (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 = 366; LvCol.fmt = LVCFMT_LEFT; SendMessageW (hList, LVM_INSERTCOLUMNW, 0, (LPARAM)&LvCol); LoadKeyList (hwndDlg, param->FirstKeyFile); SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, param->EnableKeyFiles); SetWindowTextW(GetDlgItem(hwndDlg, IDT_KEYFILES_NOTE), GetString ("IDT_KEYFILES_NOTE")); } return 1; case WM_COMMAND: if (lw == IDC_KEYADD) { KeyFile *kf = malloc (sizeof (KeyFile)); if (SelectMultipleFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, FALSE)) { do { param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); LoadKeyList (hwndDlg, param->FirstKeyFile); kf = malloc (sizeof (KeyFile)); } while (SelectMultipleFilesNext (kf->FileName)); } free (kf); return 1; } if (lw == IDC_ADD_KEYFILE_PATH) { KeyFile *kf = 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_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 (¶m->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 == IDOK) { param->EnableKeyFiles = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_ENABLE)); EndDialog (hwndDlg, IDOK); return 1; } if (lw == IDCANCEL) { KeyFileRemoveAll (¶m->FirstKeyFile); *param = origParam; EndDialog (hwndDlg, IDCLOSE); return 1; } case WM_DROPFILES: { HDROP hdrop = (HDROP) wParam; int i = 0, count = DragQueryFile (hdrop, -1, NULL, 0); while (count-- > 0) { KeyFile *kf = malloc (sizeof (KeyFile)); DragQueryFile (hdrop, i++, kf->FileName, sizeof (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 (¶m->FirstKeyFile); *param = origParam; EndDialog (hwndDlg, IDCLOSE); return 1; break; } return 0; } #endif /* #ifdef _WIN32 */