PageRenderTime 28ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/Common/Keyfiles.c

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