|
|
1.1 ! root 1: /* ! 2: Copyright (c) 2004-2005 TrueCrypt Foundation. All rights reserved. ! 3: ! 4: Covered by TrueCrypt License 2.0 the full text of which is contained in the file ! 5: License.txt included in TrueCrypt binary and source code distribution archives. ! 6: */ ! 7: ! 8: #include <sys/stat.h> ! 9: #include <sys/types.h> ! 10: ! 11: #include "Tcdefs.h" ! 12: #include "Keyfiles.h" ! 13: #include "Crc.h" ! 14: ! 15: #ifdef _WIN32 ! 16: ! 17: #include <io.h> ! 18: #include "Dlgcode.h" ! 19: #include "Language.h" ! 20: #include "../common/resource.h" ! 21: ! 22: #define stat _stat ! 23: #define S_IFDIR _S_IFDIR ! 24: #define snprintf _snprintf ! 25: ! 26: #else ! 27: ! 28: #include <dirent.h> ! 29: #include <utime.h> ! 30: ! 31: #endif ! 32: ! 33: KeyFile *KeyFileAdd (KeyFile *firstKeyFile, KeyFile *keyFile) ! 34: { ! 35: KeyFile *kf = firstKeyFile; ! 36: ! 37: if (firstKeyFile != NULL) ! 38: { ! 39: while (kf->Next) ! 40: kf = kf->Next; ! 41: ! 42: kf->Next = keyFile; ! 43: } ! 44: else ! 45: firstKeyFile = keyFile; ! 46: ! 47: keyFile->Next = NULL; ! 48: ! 49: return firstKeyFile; ! 50: } ! 51: ! 52: ! 53: // Returns first keyfile, NULL if last keyfile was removed ! 54: static KeyFile *KeyFileRemove (KeyFile *firstKeyFile, KeyFile *keyFile) ! 55: { ! 56: KeyFile *prevkf = NULL, *kf = firstKeyFile; ! 57: ! 58: if (firstKeyFile == NULL) return NULL; ! 59: do ! 60: { ! 61: if (kf == keyFile) ! 62: { ! 63: if (prevkf == NULL) ! 64: firstKeyFile = kf->Next; ! 65: else ! 66: prevkf->Next = kf->Next; ! 67: ! 68: memset (keyFile, 0, sizeof(*keyFile)); // wipe ! 69: free (keyFile); ! 70: break; ! 71: } ! 72: prevkf = kf; ! 73: } ! 74: while (kf = kf->Next); ! 75: ! 76: return firstKeyFile; ! 77: } ! 78: ! 79: ! 80: void KeyFileRemoveAll (KeyFile **firstKeyFile) ! 81: { ! 82: KeyFile *kf = *firstKeyFile; ! 83: while (kf != NULL) ! 84: { ! 85: KeyFile *d = kf; ! 86: kf = kf->Next; ! 87: burn (d, sizeof(*d)); // wipe ! 88: free (d); ! 89: } ! 90: ! 91: *firstKeyFile = NULL; ! 92: } ! 93: ! 94: ! 95: KeyFile *KeyFileClone (KeyFile *keyFile) ! 96: { ! 97: KeyFile *clone; ! 98: ! 99: if (keyFile == NULL) return NULL; ! 100: ! 101: clone = malloc (sizeof (KeyFile)); ! 102: strcpy (clone->FileName, keyFile->FileName); ! 103: clone->Next = NULL; ! 104: return clone; ! 105: } ! 106: ! 107: ! 108: KeyFile *KeyFileCloneAll (KeyFile *firstKeyFile) ! 109: { ! 110: KeyFile *cloneFirstKeyFile = KeyFileClone (firstKeyFile); ! 111: KeyFile *kf; ! 112: ! 113: if (firstKeyFile == NULL) return NULL; ! 114: kf = firstKeyFile->Next; ! 115: while (kf != NULL) ! 116: { ! 117: KeyFileAdd (cloneFirstKeyFile, KeyFileClone (kf)); ! 118: kf = kf->Next; ! 119: } ! 120: ! 121: return cloneFirstKeyFile; ! 122: } ! 123: ! 124: ! 125: static BOOL KeyFileProcess (unsigned __int8 *keyPool, KeyFile *keyFile, BOOL preserveTimestamp) ! 126: { ! 127: FILE *f; ! 128: unsigned __int8 buffer[64 * 1024]; ! 129: unsigned __int32 crc = 0xffffffff; ! 130: int writePos = 0; ! 131: size_t bytesRead, totalRead = 0; ! 132: ! 133: #ifdef _WIN32 ! 134: HANDLE src; ! 135: FILETIME ftCreationTime; ! 136: FILETIME ftLastWriteTime; ! 137: FILETIME ftLastAccessTime; ! 138: #else ! 139: struct stat kfStat; ! 140: #endif ! 141: ! 142: BOOL bTimeStampValid = FALSE; ! 143: ! 144: if (preserveTimestamp) ! 145: { ! 146: /* Remember the last access time of the keyfile. It will be preserved in order to prevent ! 147: an adversary from determining which file may have been used as keyfile. */ ! 148: #ifdef _WIN32 ! 149: src = CreateFile (keyFile->FileName, ! 150: preserveTimestamp ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ, ! 151: FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); ! 152: ! 153: if (src != INVALID_HANDLE_VALUE) ! 154: { ! 155: if (GetFileTime ((HANDLE) src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime)) ! 156: bTimeStampValid = TRUE; ! 157: else ! 158: Warning ("GETFILETIME_FAILED_KEYFILE"); ! 159: } ! 160: #else ! 161: bTimeStampValid = stat (keyFile->FileName, &kfStat) == 0; ! 162: #endif ! 163: } ! 164: ! 165: f = fopen (keyFile->FileName, "rb"); ! 166: if (f == NULL) return FALSE; ! 167: ! 168: while ((bytesRead = fread (buffer, 1, sizeof (buffer), f)) > 0) ! 169: { ! 170: size_t i; ! 171: ! 172: for (i = 0; i < bytesRead; i++) ! 173: { ! 174: crc = UPDC32 (buffer[i], crc); ! 175: ! 176: keyPool[writePos++] += (unsigned __int8) (crc >> 24); ! 177: keyPool[writePos++] += (unsigned __int8) (crc >> 16); ! 178: keyPool[writePos++] += (unsigned __int8) (crc >> 8); ! 179: keyPool[writePos++] += (unsigned __int8) crc; ! 180: ! 181: if (writePos >= KEYFILE_POOL_SIZE) ! 182: writePos = 0; ! 183: ! 184: if (++totalRead >= KEYFILE_MAX_READ_LEN) ! 185: goto close; ! 186: } ! 187: } ! 188: ! 189: close: ! 190: fclose (f); ! 191: ! 192: if (bTimeStampValid) ! 193: { ! 194: // Restore the keyfile timestamp ! 195: #ifdef _WIN32 ! 196: if (!SetFileTime (src, &ftCreationTime, &ftLastAccessTime, &ftLastWriteTime)) ! 197: Warning ("SETFILETIME_FAILED_KEYFILE"); ! 198: CloseHandle (src); ! 199: #else ! 200: struct utimbuf u; ! 201: u.actime = kfStat.st_atime; ! 202: u.modtime = kfStat.st_atime; ! 203: utime (keyFile->FileName, &u); ! 204: #endif ! 205: } ! 206: ! 207: return TRUE; ! 208: } ! 209: ! 210: ! 211: BOOL KeyFilesApply (Password *password, KeyFile *firstKeyFile, BOOL preserveTimestamp) ! 212: { ! 213: BOOL status = TRUE; ! 214: KeyFile kfSubStruct; ! 215: KeyFile *kf; ! 216: KeyFile *kfSub = &kfSubStruct; ! 217: static unsigned __int8 keyPool [KEYFILE_POOL_SIZE]; ! 218: int i; ! 219: struct stat statStruct; ! 220: char searchPath [TC_MAX_PATH*2]; ! 221: #ifdef _WIN32 ! 222: struct _finddata_t fBuf; ! 223: intptr_t searchHandle; ! 224: #else ! 225: struct dirent *fBuf; ! 226: DIR *searchHandle; ! 227: #endif ! 228: ! 229: if (firstKeyFile == NULL) return TRUE; ! 230: ! 231: #ifdef _WIN32 ! 232: VirtualLock (keyPool, sizeof (keyPool)); ! 233: #endif ! 234: memset (keyPool, 0, sizeof (keyPool)); ! 235: ! 236: for (kf = firstKeyFile; kf != NULL; kf = kf->Next) ! 237: { ! 238: // Determine whether it's a path or a file ! 239: if (stat (kf->FileName, &statStruct) != 0) ! 240: { ! 241: #ifdef _WIN32 ! 242: Error ("ERR_PROCESS_KEYFILE"); ! 243: #else ! 244: perror ("stat"); ! 245: #endif ! 246: status = FALSE; ! 247: continue; ! 248: } ! 249: ! 250: if (statStruct.st_mode & S_IFDIR) // If it's a directory ! 251: { ! 252: /* Find and process all keyfiles in the directory */ ! 253: ! 254: #ifdef _WIN32 ! 255: snprintf (searchPath, sizeof (searchPath), "%s\\*.*", kf->FileName); ! 256: if ((searchHandle = _findfirst (searchPath, &fBuf)) == -1) ! 257: #else ! 258: if ((searchHandle = opendir (kf->FileName)) == NULL) ! 259: #endif ! 260: { ! 261: #ifdef _WIN32 ! 262: Error ("ERR_PROCESS_KEYFILE_PATH"); ! 263: #endif ! 264: status = FALSE; ! 265: continue; ! 266: } ! 267: ! 268: #ifdef _WIN32 ! 269: do ! 270: #else ! 271: while ((fBuf = readdir (searchHandle)) != NULL) ! 272: #endif ! 273: { ! 274: snprintf (kfSub->FileName, sizeof(kfSub->FileName), "%s%c%s", kf->FileName, ! 275: #ifdef _WIN32 ! 276: '\\', ! 277: fBuf.name ! 278: #else ! 279: '/', ! 280: fBuf->d_name ! 281: #endif ! 282: ); ! 283: ! 284: // Determine whether it's a path or a file ! 285: if (stat (kfSub->FileName, &statStruct) != 0) ! 286: { ! 287: #ifdef _WIN32 ! 288: Error ("ERR_PROCESS_KEYFILE"); ! 289: #endif ! 290: status = FALSE; ! 291: continue; ! 292: } ! 293: else if (statStruct.st_mode & S_IFDIR) // If it's a directory ! 294: { ! 295: // Prevent recursive folder scanning ! 296: continue; ! 297: } ! 298: ! 299: ! 300: // Apply keyfile to the pool ! 301: if (!KeyFileProcess (keyPool, kfSub, preserveTimestamp)) ! 302: { ! 303: #ifdef _WIN32 ! 304: handleWin32Error (NULL); ! 305: Error ("ERR_PROCESS_KEYFILE"); ! 306: #endif ! 307: status = FALSE; ! 308: } ! 309: ! 310: #ifdef _WIN32 ! 311: } while (_findnext (searchHandle, &fBuf) != -1); ! 312: _findclose (searchHandle); ! 313: #else ! 314: } ! 315: closedir (searchHandle); ! 316: #endif ! 317: ! 318: burn (&kfSubStruct, sizeof (kfSubStruct)); ! 319: ! 320: } ! 321: // Apply keyfile to the pool ! 322: else if (!KeyFileProcess (keyPool, kf, preserveTimestamp)) ! 323: { ! 324: #ifdef _WIN32 ! 325: handleWin32Error (NULL); ! 326: Error ("ERR_PROCESS_KEYFILE"); ! 327: #endif ! 328: status = FALSE; ! 329: } ! 330: } ! 331: ! 332: /* Mix the keyfile pool contents into the password */ ! 333: ! 334: for (i = 0; i < (int)sizeof(keyPool); i++) ! 335: { ! 336: if (i < password->Length) ! 337: password->Text[i] += keyPool[i]; ! 338: else ! 339: password->Text[i] = keyPool[i]; ! 340: } ! 341: ! 342: if (password->Length < (int)sizeof (keyPool)) ! 343: password->Length = sizeof (keyPool); ! 344: ! 345: burn (keyPool, sizeof (keyPool)); ! 346: ! 347: return status; ! 348: } ! 349: ! 350: #ifdef _WIN32 ! 351: ! 352: static void LoadKeyList (HWND hwndDlg, KeyFile *firstKeyFile) ! 353: { ! 354: KeyFile *kf; ! 355: LVITEM LvItem; ! 356: int line = 0; ! 357: HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST); ! 358: ! 359: ListView_DeleteAllItems (hList); ! 360: EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE), FALSE); ! 361: EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVEALL), firstKeyFile != NULL); ! 362: SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, firstKeyFile != NULL); ! 363: ! 364: for (kf = firstKeyFile; kf != NULL; kf = kf->Next) ! 365: { ! 366: memset (&LvItem,0,sizeof(LvItem)); ! 367: LvItem.mask = LVIF_TEXT|LVIF_PARAM; ! 368: LvItem.iItem = line++; ! 369: LvItem.iSubItem = 0; ! 370: LvItem.pszText = kf->FileName; ! 371: LvItem.lParam = (LPARAM) kf; ! 372: SendMessage (hList, LVM_INSERTITEM, 0, (LPARAM)&LvItem); ! 373: } ! 374: } ! 375: ! 376: #if KEYFILE_POOL_SIZE % 4 != 0 ! 377: #error KEYFILE_POOL_SIZE must be a multiple of 4 ! 378: #endif ! 379: ! 380: BOOL WINAPI KeyFilesDlgProc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) ! 381: { ! 382: static KeyFilesDlgParam *param; ! 383: static KeyFilesDlgParam origParam; ! 384: ! 385: WORD lw = LOWORD (wParam); ! 386: ! 387: switch (msg) ! 388: { ! 389: case WM_INITDIALOG: ! 390: { ! 391: LVCOLUMN LvCol; ! 392: HWND hList = GetDlgItem (hwndDlg, IDC_KEYLIST); ! 393: ! 394: param = (KeyFilesDlgParam *) lParam; ! 395: origParam = *(KeyFilesDlgParam *) lParam; ! 396: ! 397: param->FirstKeyFile = KeyFileCloneAll (param->FirstKeyFile); ! 398: ! 399: LocalizeDialog (hwndDlg, "IDD_KEYFILES"); ! 400: DragAcceptFiles (hwndDlg, TRUE); ! 401: ! 402: SendMessage (hList,LVM_SETEXTENDEDLISTVIEWSTYLE,0, ! 403: LVS_EX_FULLROWSELECT|LVS_EX_HEADERDRAGDROP ! 404: ); ! 405: ! 406: memset (&LvCol,0,sizeof(LvCol)); ! 407: LvCol.mask = LVCF_TEXT|LVCF_WIDTH|LVCF_SUBITEM|LVCF_FMT; ! 408: LvCol.pszText = "Keyfile"; ! 409: LvCol.cx = 357; ! 410: LvCol.fmt = LVCFMT_LEFT; ! 411: SendMessage (hList, LVM_INSERTCOLUMN, 0, (LPARAM)&LvCol); ! 412: ! 413: LoadKeyList (hwndDlg, param->FirstKeyFile); ! 414: SetCheckBox (hwndDlg, IDC_KEYFILES_ENABLE, param->EnableKeyFiles); ! 415: ! 416: SetWindowTextW(GetDlgItem(hwndDlg, IDT_KEYFILES_NOTE), GetString ("IDT_KEYFILES_NOTE")); ! 417: } ! 418: return 1; ! 419: ! 420: case WM_COMMAND: ! 421: ! 422: if (lw == IDC_KEYADD) ! 423: { ! 424: KeyFile *kf = malloc (sizeof (KeyFile)); ! 425: ! 426: if (BrowseFiles (hwndDlg, "SELECT_KEYFILE", kf->FileName, FALSE)) ! 427: { ! 428: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); ! 429: LoadKeyList (hwndDlg, param->FirstKeyFile); ! 430: } ! 431: else ! 432: { ! 433: free (kf); ! 434: } ! 435: return 1; ! 436: } ! 437: ! 438: if (lw == IDC_ADD_KEYFILE_PATH) ! 439: { ! 440: KeyFile *kf = malloc (sizeof (KeyFile)); ! 441: ! 442: if (BrowseDirectories (hwndDlg,"SELECT_KEYFILE_PATH", kf->FileName)) ! 443: { ! 444: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); ! 445: LoadKeyList (hwndDlg, param->FirstKeyFile); ! 446: } ! 447: else ! 448: { ! 449: free (kf); ! 450: } ! 451: return 1; ! 452: } ! 453: ! 454: if (lw == IDC_KEYREMOVE) ! 455: { ! 456: HWND list = GetDlgItem (hwndDlg, IDC_KEYLIST); ! 457: LVITEM LvItem; ! 458: memset (&LvItem, 0, sizeof(LvItem)); ! 459: LvItem.mask = LVIF_PARAM; ! 460: LvItem.iItem = -1; ! 461: ! 462: while (-1 != (LvItem.iItem = ListView_GetNextItem (list, LvItem.iItem, LVIS_SELECTED))) ! 463: { ! 464: ListView_GetItem (list, &LvItem); ! 465: param->FirstKeyFile = KeyFileRemove (param->FirstKeyFile, (KeyFile *) LvItem.lParam); ! 466: } ! 467: ! 468: LoadKeyList (hwndDlg, param->FirstKeyFile); ! 469: return 1; ! 470: } ! 471: ! 472: if (lw == IDC_KEYREMOVEALL) ! 473: { ! 474: KeyFileRemoveAll (¶m->FirstKeyFile); ! 475: LoadKeyList (hwndDlg, NULL); ! 476: return 1; ! 477: } ! 478: ! 479: if (lw == IDC_GENERATE_KEYFILE) ! 480: { ! 481: DialogBoxParamW (hInst, ! 482: MAKEINTRESOURCEW (IDD_KEYFILE_GENERATOR), hwndDlg, ! 483: (DLGPROC) KeyfileGeneratorDlgProc, (LPARAM) 0); ! 484: return 1; ! 485: } ! 486: ! 487: if (lw == IDOK) ! 488: { ! 489: param->EnableKeyFiles = IsButtonChecked (GetDlgItem (hwndDlg, IDC_KEYFILES_ENABLE)); ! 490: EndDialog (hwndDlg, IDOK); ! 491: return 1; ! 492: } ! 493: ! 494: if (lw == IDCANCEL) ! 495: { ! 496: KeyFileRemoveAll (¶m->FirstKeyFile); ! 497: *param = origParam; ! 498: ! 499: EndDialog (hwndDlg, IDCLOSE); ! 500: return 1; ! 501: } ! 502: ! 503: case WM_DROPFILES: ! 504: { ! 505: HDROP hdrop = (HDROP) wParam; ! 506: ! 507: int i = 0, count = DragQueryFile (hdrop, -1, NULL, 0); ! 508: ! 509: while (count-- > 0) ! 510: { ! 511: KeyFile *kf = malloc (sizeof (KeyFile)); ! 512: DragQueryFile (hdrop, i++, kf->FileName, sizeof (kf->FileName)); ! 513: param->FirstKeyFile = KeyFileAdd (param->FirstKeyFile, kf); ! 514: LoadKeyList (hwndDlg, param->FirstKeyFile); ! 515: } ! 516: ! 517: DragFinish (hdrop); ! 518: } ! 519: return 1; ! 520: ! 521: case WM_NOTIFY: ! 522: if (((LPNMHDR) lParam)->code == LVN_ITEMCHANGED) ! 523: { ! 524: EnableWindow (GetDlgItem (hwndDlg, IDC_KEYREMOVE), ! 525: ListView_GetNextItem (GetDlgItem (hwndDlg, IDC_KEYLIST), -1, LVIS_SELECTED) != -1); ! 526: return 1; ! 527: } ! 528: break; ! 529: ! 530: case WM_CLOSE: ! 531: KeyFileRemoveAll (¶m->FirstKeyFile); ! 532: *param = origParam; ! 533: ! 534: EndDialog (hwndDlg, IDCLOSE); ! 535: return 1; ! 536: ! 537: break; ! 538: ! 539: } ! 540: ! 541: return 0; ! 542: } ! 543: ! 544: ! 545: #endif /* #ifdef _WIN32 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.