Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3839 lines
96 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. cipher.c
  5. Abstract:
  6. This module implements the encryption utility for encrypted
  7. NTFS files.
  8. Author:
  9. Robert Reichel [RobertRe] 28-Feb-1997
  10. Robert Gu [RobertG] 24-Mar-1998
  11. Revision History:
  12. Code reused from compact.exe, file compression utility
  13. --*/
  14. //
  15. // Include the standard header files.
  16. //
  17. //#define UNICODE
  18. //#define _UNICODE
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <winioctl.h>
  22. #include <shellapi.h>
  23. #include <winefs.h>
  24. #include <malloc.h>
  25. #include <rc4.h>
  26. #include <randlib.h> // NewGenRandom() - Win2k and whistler
  27. #include <rpc.h>
  28. #include <wincrypt.h>
  29. #include "support.h"
  30. #include "msg.h"
  31. #define lstrchr wcschr
  32. #define lstricmp _wcsicmp
  33. #define lstrnicmp _wcsnicmp
  34. //
  35. // FIRST_COLUMN_WIDTH - When encrypting files, the width of the output
  36. // column which displays the file name
  37. //
  38. #define FIRST_COLUMN_WIDTH (20)
  39. #define ENUMPATHLENGTH (4096)
  40. #define DosDriveLimitCount (26)
  41. #define PASSWORDLEN 1024
  42. #define UserChooseYes 0
  43. #define UserChooseNo 1
  44. #define ChoiceNotDefined 3
  45. #define KEYPATH TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\EFS\\CurrentKeys")
  46. #define KEYPATHROOT HKEY_CURRENT_USER
  47. #define CERT_HASH TEXT("CertificateHash")
  48. #define WIPING_DIR TEXT("EFSTMPWP\\")
  49. #define RANDOM_BYTES(pv, cb) NewGenRandom(NULL, NULL, pv, cb)
  50. #define YEARCOUNT (LONGLONG) 10000000*3600*24*365 // One Year's tick count
  51. //
  52. // Local data structure
  53. //
  54. typedef struct _CIPHER_VOLUME_INFO {
  55. LPWSTR VolumeName[DosDriveLimitCount];
  56. LPWSTR DosDeviceName[DosDriveLimitCount];
  57. } CIPHER_VOLUME_INFO, *PCIPHER_VOLUME_INFO;
  58. //
  59. //
  60. // definitions for initializing and working with random fill data.
  61. //
  62. typedef struct {
  63. RC4_KEYSTRUCT Key;
  64. CRITICAL_SECTION Lock;
  65. BOOL LockValid;
  66. PBYTE pbRandomFill;
  67. DWORD cbRandomFill;
  68. LONG cbFilled;
  69. BOOLEAN fRandomFill; // is fill randomized?
  70. } SECURE_FILL_INFO, *PSECURE_FILL_INFO;
  71. // Local procedure types
  72. //
  73. typedef BOOLEAN (*PACTION_ROUTINE) (
  74. IN PTCHAR DirectorySpec,
  75. IN PTCHAR FileSpec
  76. );
  77. typedef VOID (*PFINAL_ACTION_ROUTINE) (
  78. );
  79. //
  80. // Declare global variables to hold the command line information
  81. //
  82. BOOLEAN DoSubdirectories = FALSE; // recurse
  83. BOOLEAN IgnoreErrors = FALSE; // keep going despite errs
  84. BOOLEAN UserSpecifiedFileSpec = FALSE;
  85. BOOLEAN ForceOperation = FALSE; // encrypt/decrypt even if already so
  86. BOOLEAN Quiet = FALSE; // be less verbose
  87. BOOLEAN DisplayAllFiles = FALSE; // dsply hidden, system?
  88. BOOLEAN DoFiles = FALSE; // operation for files "/a"
  89. BOOLEAN SetUpNewUserKey = FALSE; // Set up new user key
  90. BOOLEAN RefreshUserKeyOnFiles = FALSE; // Refresh User Key on EFS files
  91. BOOLEAN DisplayFilesOnly = FALSE; // Do not refresh $EFS, just display the file names
  92. BOOLEAN FillUnusedSpace = FALSE; // Fill unused disk space with random data
  93. BOOLEAN GenerateDRA = FALSE; // Generate Data Recovery Certificate files
  94. TCHAR StartingDirectory[MAX_PATH]; // parameter to "/s"
  95. ULONG AttributesNoDisplay = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
  96. BOOLEAN DisplayUseOptionW = FALSE;
  97. //
  98. // Declare global variables to hold encryption statistics
  99. //
  100. LARGE_INTEGER TotalDirectoryCount;
  101. LARGE_INTEGER TotalFileCount;
  102. TCHAR Buf[1024]; // for displaying stuff
  103. SECURE_FILL_INFO GlobalSecureFill;
  104. BOOLEAN GlobalSecureFillInitialized;
  105. #if 0
  106. #define TestOutPut
  107. #endif
  108. //
  109. // Now do the routines to list the encryption state and size of
  110. // a file and/or directory
  111. //
  112. BOOLEAN
  113. DisplayFile (
  114. IN PTCHAR FileSpec,
  115. IN PWIN32_FIND_DATA FindData
  116. )
  117. {
  118. TCHAR PrintState;
  119. //
  120. // Decide if the file is compressed and if so then
  121. // get the compressed file size.
  122. //
  123. if (FindData->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) {
  124. PrintState = 'E';
  125. } else {
  126. PrintState = 'U';
  127. }
  128. //
  129. // Print out the encryption state and file name
  130. //
  131. if (!Quiet &&
  132. (DisplayAllFiles ||
  133. (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
  134. swprintf(Buf, TEXT("%c %s",), PrintState, FindData->cFileName);
  135. DisplayMsg(CIPHER_THROW_NL, Buf);
  136. }
  137. TotalFileCount.QuadPart += 1;
  138. return TRUE;
  139. }
  140. BOOLEAN
  141. DoListAction (
  142. IN PTCHAR DirectorySpec,
  143. IN PTCHAR FileSpec
  144. )
  145. {
  146. PTCHAR DirectorySpecEnd;
  147. //
  148. // So that we can keep on appending names to the directory spec
  149. // get a pointer to the end of its string
  150. //
  151. DirectorySpecEnd = DirectorySpec + lstrlen(DirectorySpec);
  152. //
  153. // List the encryption attribute for the directory
  154. //
  155. {
  156. ULONG Attributes;
  157. if (!Quiet || Quiet) {
  158. Attributes = GetFileAttributes( DirectorySpec );
  159. if (0xFFFFFFFF == Attributes) {
  160. if (!Quiet || !IgnoreErrors) {
  161. //
  162. // Refrain from displaying error only when in quiet
  163. // mode *and* we're ignoring errors.
  164. //
  165. DisplayErr(DirectorySpec, GetLastError());
  166. }
  167. if (!IgnoreErrors) {
  168. return FALSE;
  169. }
  170. } else {
  171. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  172. DisplayMsg(CIPHER_LIST_EDIR, DirectorySpec);
  173. } else {
  174. DisplayMsg(CIPHER_LIST_UDIR, DirectorySpec);
  175. }
  176. }
  177. }
  178. TotalDirectoryCount.QuadPart += 1;
  179. }
  180. //
  181. // Now for every file in the directory that matches the file spec we will
  182. // will open the file and list its encryption state
  183. //
  184. {
  185. HANDLE FindHandle;
  186. WIN32_FIND_DATA FindData;
  187. //
  188. // setup the template for findfirst/findnext
  189. //
  190. //
  191. // Make sure we don't try any paths that are too long for us
  192. // to deal with.
  193. //
  194. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( FileSpec )) <
  195. MAX_PATH) {
  196. lstrcpy( DirectorySpecEnd, FileSpec );
  197. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  198. if (INVALID_HANDLE_VALUE != FindHandle) {
  199. do {
  200. //
  201. // append the found file to the directory spec and open the
  202. // file
  203. //
  204. if (0 == lstrcmp(FindData.cFileName, TEXT("..")) ||
  205. 0 == lstrcmp(FindData.cFileName, TEXT("."))) {
  206. continue;
  207. }
  208. //
  209. // Make sure we don't try any paths that are too long for us
  210. // to deal with.
  211. //
  212. if ((DirectorySpecEnd - DirectorySpec) +
  213. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  214. continue;
  215. }
  216. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  217. //
  218. // Now print out the state of the file
  219. //
  220. DisplayFile( DirectorySpec, &FindData );
  221. } while ( FindNextFile( FindHandle, &FindData ));
  222. FindClose( FindHandle );
  223. }
  224. }
  225. }
  226. //
  227. // For if we are to do subdirectores then we will look for every
  228. // subdirectory and recursively call ourselves to list the subdirectory
  229. //
  230. if (DoSubdirectories) {
  231. HANDLE FindHandle;
  232. WIN32_FIND_DATA FindData;
  233. //
  234. // Setup findfirst/findnext to search the entire directory
  235. //
  236. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( TEXT("*") )) <
  237. MAX_PATH) {
  238. lstrcpy( DirectorySpecEnd, TEXT("*") );
  239. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  240. if (INVALID_HANDLE_VALUE != FindHandle) {
  241. do {
  242. //
  243. // Now skip over the . and .. entries otherwise we'll recurse
  244. // like mad
  245. //
  246. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  247. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  248. continue;
  249. } else {
  250. //
  251. // If the entry is for a directory then we'll tack on the
  252. // subdirectory name to the directory spec and recursively
  253. // call otherselves
  254. //
  255. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  256. //
  257. // Make sure we don't try any paths that are too long for us
  258. // to deal with.
  259. //
  260. if ((DirectorySpecEnd - DirectorySpec) +
  261. lstrlen( TEXT("\\") ) +
  262. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  263. continue;
  264. }
  265. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  266. lstrcat( DirectorySpecEnd, TEXT("\\") );
  267. if (!DoListAction( DirectorySpec, FileSpec )) {
  268. FindClose( FindHandle );
  269. return FALSE || IgnoreErrors;
  270. }
  271. }
  272. }
  273. } while ( FindNextFile( FindHandle, &FindData ));
  274. FindClose( FindHandle );
  275. }
  276. }
  277. }
  278. return TRUE;
  279. }
  280. VOID
  281. DoFinalListAction (
  282. )
  283. {
  284. return;
  285. }
  286. BOOLEAN
  287. EncryptAFile (
  288. IN PTCHAR FileSpec,
  289. IN PWIN32_FIND_DATA FindData
  290. )
  291. {
  292. USHORT State = 1;
  293. ULONG i;
  294. BOOL Success;
  295. double f = 1.0;
  296. if ((FindData->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  297. !ForceOperation) {
  298. return TRUE;
  299. }
  300. // Success = DeviceIoControl(Handle, FSCTL_SET_COMPRESSION, &State,
  301. // sizeof(USHORT), NULL, 0, &Length, FALSE );
  302. if ( (0 == (FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) && (!DoFiles)) {
  303. //
  304. // Skip the files
  305. //
  306. return TRUE;
  307. }
  308. Success = EncryptFile( FileSpec );
  309. if (!Success) {
  310. if (Quiet && IgnoreErrors) {
  311. return FALSE || IgnoreErrors;
  312. }
  313. swprintf(Buf, TEXT("%s "), FindData->cFileName);
  314. DisplayMsg(CIPHER_THROW, Buf);
  315. for (i = lstrlen(FindData->cFileName) + 1; i < FIRST_COLUMN_WIDTH; ++i) {
  316. swprintf(Buf, TEXT("%c"), ' ');
  317. DisplayMsg(CIPHER_THROW, Buf);
  318. }
  319. DisplayMsg(CIPHER_ERR);
  320. if (!Quiet && !IgnoreErrors) {
  321. if (ERROR_INVALID_FUNCTION == GetLastError()) {
  322. // This error is caused by doing the fsctl on a
  323. // non-encrypting volume.
  324. DisplayMsg(CIPHER_WRONG_FILE_SYSTEM, FindData->cFileName);
  325. } else {
  326. DisplayErr(FindData->cFileName, GetLastError());
  327. }
  328. }
  329. return FALSE || IgnoreErrors;
  330. }
  331. if (!DisplayUseOptionW && ( 0 == (FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))){
  332. DisplayUseOptionW = TRUE;
  333. }
  334. if (!Quiet &&
  335. (DisplayAllFiles ||
  336. (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
  337. swprintf(Buf, TEXT("%s "), FindData->cFileName);
  338. DisplayMsg(CIPHER_THROW, Buf);
  339. for (i = lstrlen(FindData->cFileName) + 1; i < FIRST_COLUMN_WIDTH; ++i) {
  340. swprintf(Buf, TEXT("%c"), ' ');
  341. DisplayMsg(CIPHER_THROW, Buf);
  342. }
  343. DisplayMsg(CIPHER_OK);
  344. }
  345. TotalFileCount.QuadPart += 1;
  346. return TRUE;
  347. }
  348. BOOLEAN
  349. DoEncryptAction (
  350. IN PTCHAR DirectorySpec,
  351. IN PTCHAR FileSpec
  352. )
  353. {
  354. PTCHAR DirectorySpecEnd;
  355. //
  356. // If the file spec is null then we'll set the encryption bit for the
  357. // the directory spec and get out.
  358. //
  359. if (lstrlen(FileSpec) == 0) {
  360. USHORT State = 1;
  361. ULONG Length;
  362. DisplayMsg(CIPHER_ENCRYPT_DIR, DirectorySpec);
  363. if (!EncryptFile( DirectorySpec )) {
  364. if (!Quiet || !IgnoreErrors) {
  365. DisplayMsg(CIPHER_ERR);
  366. }
  367. if (!Quiet && !IgnoreErrors) {
  368. DisplayErr(DirectorySpec, GetLastError());
  369. }
  370. return FALSE || IgnoreErrors;
  371. }
  372. if (!Quiet) {
  373. DisplayMsg(CIPHER_OK);
  374. }
  375. TotalDirectoryCount.QuadPart += 1;
  376. TotalFileCount.QuadPart += 1;
  377. return TRUE;
  378. }
  379. //
  380. // So that we can keep on appending names to the directory spec
  381. // get a pointer to the end of its string
  382. //
  383. DirectorySpecEnd = DirectorySpec + lstrlen( DirectorySpec );
  384. //
  385. // List the directory that we will be encrypting within and say what its
  386. // current encryption attribute is.
  387. //
  388. {
  389. ULONG Attributes;
  390. if (!Quiet || Quiet) {
  391. Attributes = GetFileAttributes( DirectorySpec );
  392. if ( DoFiles ) {
  393. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  394. DisplayMsg(CIPHER_ENCRYPT_EDIR, DirectorySpec);
  395. } else {
  396. DisplayMsg(CIPHER_ENCRYPT_UDIR, DirectorySpec);
  397. }
  398. } else {
  399. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  400. DisplayMsg(CIPHER_ENCRYPT_EDIR_NF, DirectorySpec);
  401. } else {
  402. DisplayMsg(CIPHER_ENCRYPT_UDIR_NF, DirectorySpec);
  403. }
  404. }
  405. }
  406. TotalDirectoryCount.QuadPart += 1;
  407. }
  408. //
  409. // Now for every file in the directory that matches the file spec we will
  410. // will open the file and encrypt it
  411. //
  412. {
  413. HANDLE FindHandle;
  414. HANDLE FileHandle;
  415. WIN32_FIND_DATA FindData;
  416. //
  417. // setup the template for findfirst/findnext
  418. //
  419. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( FileSpec )) <
  420. MAX_PATH) {
  421. lstrcpy( DirectorySpecEnd, FileSpec );
  422. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  423. if (INVALID_HANDLE_VALUE != FindHandle) {
  424. do {
  425. //
  426. // Now skip over the . and .. entries
  427. //
  428. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  429. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  430. continue;
  431. } else {
  432. //
  433. // Make sure we don't try any paths that are too long for us
  434. // to deal with.
  435. //
  436. if ( (DirectorySpecEnd - DirectorySpec) +
  437. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  438. continue;
  439. }
  440. //
  441. // append the found file to the directory spec and open
  442. // the file
  443. //
  444. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  445. //
  446. // Hack hack, kludge kludge. Refrain from compressing
  447. // files named "\NTDLR" to help users avoid hosing
  448. // themselves.
  449. //
  450. if (IsNtldr(DirectorySpec)) {
  451. if (!Quiet) {
  452. DisplayMsg(CIPHER_SKIPPING, DirectorySpecEnd);
  453. }
  454. continue;
  455. }
  456. EncryptAFile( DirectorySpec, &FindData );
  457. }
  458. } while ( FindNextFile( FindHandle, &FindData ));
  459. FindClose( FindHandle );
  460. }
  461. }
  462. }
  463. //
  464. // If we are to do subdirectores then we will look for every subdirectory
  465. // and recursively call ourselves to list the subdirectory
  466. //
  467. if (DoSubdirectories) {
  468. HANDLE FindHandle;
  469. WIN32_FIND_DATA FindData;
  470. //
  471. // Setup findfirst/findnext to search the entire directory
  472. //
  473. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( TEXT("*") )) <
  474. MAX_PATH) {
  475. lstrcpy( DirectorySpecEnd, TEXT("*") );
  476. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  477. if (INVALID_HANDLE_VALUE != FindHandle) {
  478. do {
  479. //
  480. // Now skip over the . and .. entries otherwise we'll recurse
  481. // like mad
  482. //
  483. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  484. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  485. continue;
  486. } else {
  487. //
  488. // If the entry is for a directory then we'll tack on the
  489. // subdirectory name to the directory spec and recursively
  490. // call otherselves
  491. //
  492. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  493. //
  494. // Make sure we don't try any paths that are too long for us
  495. // to deal with.
  496. //
  497. if ((DirectorySpecEnd - DirectorySpec) +
  498. lstrlen( TEXT("\\") ) +
  499. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  500. continue;
  501. }
  502. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  503. lstrcat( DirectorySpecEnd, TEXT("\\") );
  504. if (!DoEncryptAction( DirectorySpec, FileSpec )) {
  505. FindClose( FindHandle );
  506. return FALSE || IgnoreErrors;
  507. }
  508. }
  509. }
  510. } while ( FindNextFile( FindHandle, &FindData ));
  511. FindClose( FindHandle );
  512. }
  513. }
  514. }
  515. return TRUE;
  516. }
  517. VOID
  518. DoFinalEncryptAction (
  519. )
  520. {
  521. TCHAR FileCount[32];
  522. TCHAR DirectoryCount[32];
  523. FormatFileSize(&TotalFileCount, 0, FileCount, FALSE);
  524. FormatFileSize(&TotalDirectoryCount, 0, DirectoryCount, FALSE);
  525. if ( DoFiles ) {
  526. DisplayMsg(CIPHER_ENCRYPT_SUMMARY, FileCount, DirectoryCount);
  527. if (DisplayUseOptionW) {
  528. DisplayMsg(CIPHER_USE_W);
  529. }
  530. } else {
  531. DisplayMsg(CIPHER_ENCRYPT_SUMMARY_NF, FileCount, DirectoryCount);
  532. }
  533. return;
  534. }
  535. BOOLEAN
  536. DecryptAFile (
  537. IN PTCHAR FileSpec,
  538. IN PWIN32_FIND_DATA FindData
  539. )
  540. {
  541. USHORT State = 0;
  542. ULONG Length;
  543. if (!(FindData->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
  544. !ForceOperation) {
  545. return TRUE;
  546. }
  547. if ( (0 == (FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) && (!DoFiles)) {
  548. //
  549. // Skip the files
  550. //
  551. return TRUE;
  552. }
  553. if (!DecryptFile(FileSpec, 0L )) {
  554. if (!Quiet || !IgnoreErrors) {
  555. swprintf(Buf, TEXT("%s "), FindData->cFileName);
  556. DisplayMsg(CIPHER_THROW, Buf);
  557. DisplayMsg(CIPHER_ERR);
  558. if (!Quiet && !IgnoreErrors) {
  559. if (ERROR_INVALID_FUNCTION == GetLastError()) {
  560. // This error is caused by doing the fsctl on a
  561. // non-compressing volume.
  562. DisplayMsg(CIPHER_WRONG_FILE_SYSTEM, FindData->cFileName);
  563. } else {
  564. DisplayErr(FindData->cFileName, GetLastError());
  565. }
  566. }
  567. }
  568. return FALSE || IgnoreErrors;
  569. }
  570. if (!Quiet &&
  571. (DisplayAllFiles ||
  572. (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
  573. swprintf(Buf, TEXT("%s "), FindData->cFileName);
  574. DisplayMsg(CIPHER_THROW, Buf);
  575. DisplayMsg(CIPHER_OK);
  576. }
  577. //
  578. // Increment our running total
  579. //
  580. TotalFileCount.QuadPart += 1;
  581. return TRUE;
  582. }
  583. BOOLEAN
  584. DoDecryptAction (
  585. IN PTCHAR DirectorySpec,
  586. IN PTCHAR FileSpec
  587. )
  588. {
  589. PTCHAR DirectorySpecEnd;
  590. //
  591. // If the file spec is null then we'll clear the encryption bit for the
  592. // the directory spec and get out.
  593. //
  594. if (lstrlen(FileSpec) == 0) {
  595. HANDLE FileHandle;
  596. USHORT State = 0;
  597. ULONG Length;
  598. DisplayMsg(CIPHER_DECRYPT_DIR, DirectorySpec);
  599. if (!DecryptFile( DirectorySpec, 0L )) {
  600. if (!Quiet || !IgnoreErrors) {
  601. DisplayMsg(CIPHER_ERR);
  602. }
  603. if (!Quiet && !IgnoreErrors) {
  604. DisplayErr(DirectorySpec, GetLastError());
  605. }
  606. return FALSE || IgnoreErrors;
  607. }
  608. if (!Quiet) {
  609. DisplayMsg(CIPHER_OK);
  610. }
  611. TotalDirectoryCount.QuadPart += 1;
  612. TotalFileCount.QuadPart += 1;
  613. return TRUE;
  614. }
  615. //
  616. // So that we can keep on appending names to the directory spec
  617. // get a pointer to the end of its string
  618. //
  619. DirectorySpecEnd = DirectorySpec + lstrlen( DirectorySpec );
  620. //
  621. // List the directory that we will be uncompressing within and say what its
  622. // current compress attribute is
  623. //
  624. {
  625. ULONG Attributes;
  626. if (!Quiet || Quiet) {
  627. Attributes = GetFileAttributes( DirectorySpec );
  628. if ( DoFiles) {
  629. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  630. DisplayMsg(CIPHER_DECRYPT_EDIR, DirectorySpec);
  631. } else {
  632. DisplayMsg(CIPHER_DECRYPT_UDIR, DirectorySpec);
  633. }
  634. } else {
  635. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  636. DisplayMsg(CIPHER_DECRYPT_EDIR_NF, DirectorySpec);
  637. } else {
  638. DisplayMsg(CIPHER_DECRYPT_UDIR_NF, DirectorySpec);
  639. }
  640. }
  641. }
  642. TotalDirectoryCount.QuadPart += 1;
  643. }
  644. //
  645. // Now for every file in the directory that matches the file spec we will
  646. // will open the file and uncompress it
  647. //
  648. {
  649. HANDLE FindHandle;
  650. WIN32_FIND_DATA FindData;
  651. //
  652. // setup the template for findfirst/findnext
  653. //
  654. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( FileSpec )) <
  655. MAX_PATH) {
  656. lstrcpy( DirectorySpecEnd, FileSpec );
  657. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  658. if (INVALID_HANDLE_VALUE != FindHandle) {
  659. do {
  660. //
  661. // Now skip over the . and .. entries
  662. //
  663. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  664. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  665. continue;
  666. } else {
  667. //
  668. // Make sure we don't try any paths that are too long for us
  669. // to deal with.
  670. //
  671. if ((DirectorySpecEnd - DirectorySpec) +
  672. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  673. continue;
  674. }
  675. //
  676. // append the found file to the directory spec and open
  677. // the file
  678. //
  679. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  680. //
  681. // Now decrypt the file
  682. //
  683. DecryptAFile( DirectorySpec, &FindData );
  684. }
  685. } while ( FindNextFile( FindHandle, &FindData ));
  686. FindClose( FindHandle );
  687. }
  688. }
  689. }
  690. //
  691. // If we are to do subdirectores then we will look for every subdirectory
  692. // and recursively call ourselves to list the subdirectory
  693. //
  694. if (DoSubdirectories) {
  695. HANDLE FindHandle;
  696. WIN32_FIND_DATA FindData;
  697. //
  698. // Setup findfirst/findnext to search the entire directory
  699. //
  700. if (((DirectorySpecEnd - DirectorySpec) + lstrlen( TEXT("*") )) <
  701. MAX_PATH) {
  702. lstrcpy( DirectorySpecEnd, TEXT("*") );
  703. FindHandle = FindFirstFile( DirectorySpec, &FindData );
  704. if (INVALID_HANDLE_VALUE != FindHandle) {
  705. do {
  706. //
  707. // Now skip over the . and .. entries otherwise we'll recurse
  708. // like mad
  709. //
  710. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  711. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  712. continue;
  713. } else {
  714. //
  715. // If the entry is for a directory then we'll tack on the
  716. // subdirectory name to the directory spec and recursively
  717. // call otherselves
  718. //
  719. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  720. //
  721. // Make sure we don't try any paths that are too long for us
  722. // to deal with.
  723. //
  724. if ((DirectorySpecEnd - DirectorySpec) +
  725. lstrlen( TEXT("\\") ) +
  726. lstrlen( FindData.cFileName ) >= MAX_PATH ) {
  727. continue;
  728. }
  729. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  730. lstrcat( DirectorySpecEnd, TEXT("\\") );
  731. if (!DoDecryptAction( DirectorySpec, FileSpec )) {
  732. FindClose( FindHandle );
  733. return FALSE || IgnoreErrors;
  734. }
  735. }
  736. }
  737. } while ( FindNextFile( FindHandle, &FindData ));
  738. FindClose( FindHandle );
  739. }
  740. }
  741. }
  742. return TRUE;
  743. }
  744. VOID
  745. DoFinalDecryptAction (
  746. )
  747. {
  748. TCHAR FileCount[32];
  749. TCHAR DirectoryCount[32];
  750. FormatFileSize(&TotalFileCount, 0, FileCount, FALSE);
  751. FormatFileSize(&TotalDirectoryCount, 0, DirectoryCount, FALSE);
  752. if (DoFiles) {
  753. DisplayMsg(CIPHER_DECRYPT_SUMMARY, FileCount, DirectoryCount);
  754. } else {
  755. DisplayMsg(CIPHER_DECRYPT_SUMMARY_NF, FileCount, DirectoryCount);
  756. }
  757. return;
  758. }
  759. VOID
  760. CipherConvertHashToStr(
  761. IN PBYTE pHashData,
  762. IN DWORD cbData,
  763. OUT LPWSTR OutHashStr
  764. )
  765. {
  766. DWORD Index = 0;
  767. BOOLEAN NoLastZero = FALSE;
  768. for (; Index < cbData; Index+=2) {
  769. BYTE HashByteLow = pHashData[Index] & 0x0f;
  770. BYTE HashByteHigh = (pHashData[Index] & 0xf0) >> 4;
  771. OutHashStr[Index * 5/2] = HashByteHigh > 9 ? (WCHAR)(HashByteHigh - 9 + 0x40): (WCHAR)(HashByteHigh + 0x30);
  772. OutHashStr[Index * 5/2 + 1] = HashByteLow > 9 ? (WCHAR)(HashByteLow - 9 + 0x40): (WCHAR)(HashByteLow + 0x30);
  773. if (Index + 1 < cbData) {
  774. HashByteLow = pHashData[Index+1] & 0x0f;
  775. HashByteHigh = (pHashData[Index+1] & 0xf0) >> 4;
  776. OutHashStr[Index * 5/2 + 2] = HashByteHigh > 9 ? (WCHAR)(HashByteHigh - 9 + 0x40): (WCHAR)(HashByteHigh + 0x30);
  777. OutHashStr[Index * 5/2 + 3] = HashByteLow > 9 ? (WCHAR)(HashByteLow - 9 + 0x40): (WCHAR)(HashByteLow + 0x30);
  778. OutHashStr[Index * 5/2 + 4] = L' ';
  779. } else {
  780. OutHashStr[Index * 5/2 + 2] = 0;
  781. NoLastZero = TRUE;
  782. }
  783. }
  784. if (!NoLastZero) {
  785. OutHashStr[Index*5/2] = 0;
  786. }
  787. }
  788. VOID
  789. CipherDisplayCrntEfsHash(
  790. )
  791. {
  792. DWORD rc;
  793. HKEY hRegKey = NULL;
  794. PBYTE pbHash;
  795. DWORD cbHash;
  796. DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1;
  797. WCHAR LocalComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  798. if (!GetComputerName ( LocalComputerName, &nSize )){
  799. //
  800. // This is not likely to happen.
  801. //
  802. return;
  803. }
  804. rc = RegOpenKeyEx(
  805. KEYPATHROOT,
  806. KEYPATH,
  807. 0,
  808. GENERIC_READ,
  809. &hRegKey
  810. );
  811. if (rc == ERROR_SUCCESS) {
  812. DWORD Type;
  813. rc = RegQueryValueEx(
  814. hRegKey,
  815. CERT_HASH,
  816. NULL,
  817. &Type,
  818. NULL,
  819. &cbHash
  820. );
  821. if (rc == ERROR_SUCCESS) {
  822. //
  823. // Query out the thumbprint, find the cert, and return the key information.
  824. //
  825. if (pbHash = (PBYTE)malloc( cbHash )) {
  826. rc = RegQueryValueEx(
  827. hRegKey,
  828. CERT_HASH,
  829. NULL,
  830. &Type,
  831. pbHash,
  832. &cbHash
  833. );
  834. if (rc == ERROR_SUCCESS) {
  835. LPWSTR OutHash;
  836. OutHash = (LPWSTR) malloc(((((cbHash + 1)/2) * 5)+1) * sizeof(WCHAR));
  837. if (OutHash) {
  838. CipherConvertHashToStr(pbHash, cbHash, OutHash);
  839. DisplayMsg(CIPHER_CURRENT_CERT, LocalComputerName, OutHash);
  840. free(OutHash);
  841. }
  842. }
  843. free(pbHash);
  844. }
  845. }
  846. RegCloseKey( hRegKey );
  847. }
  848. return;
  849. }
  850. BOOL
  851. CipherConvertToDriveLetter(
  852. IN OUT LPWSTR VolBuffer,
  853. IN PCIPHER_VOLUME_INFO VolumeInfo
  854. )
  855. {
  856. WCHAR DeviceName[MAX_PATH];
  857. WORD DriveIndex = 0;
  858. while (DriveIndex < DosDriveLimitCount) {
  859. if (VolumeInfo->VolumeName[DriveIndex]) {
  860. if (!wcscmp(VolBuffer, VolumeInfo->VolumeName[DriveIndex])) {
  861. lstrcpy(VolBuffer, TEXT("A:\\"));
  862. VolBuffer[0] += DriveIndex;
  863. return TRUE;
  864. }
  865. VolBuffer[48] = 0;
  866. if (VolumeInfo->DosDeviceName[DriveIndex] && QueryDosDevice( &(VolBuffer[4]), DeviceName, MAX_PATH)) {
  867. if (!wcscmp(DeviceName, VolumeInfo->DosDeviceName[DriveIndex])) {
  868. lstrcpy(VolBuffer, TEXT("A:\\"));
  869. VolBuffer[0] += DriveIndex;
  870. return TRUE;
  871. }
  872. }
  873. }
  874. DriveIndex++;
  875. }
  876. return FALSE;
  877. }
  878. VOID
  879. CipherTouchDirFiles(
  880. IN WCHAR *DirPath,
  881. IN PCIPHER_VOLUME_INFO VolumeInfo
  882. )
  883. {
  884. PTCHAR DirectorySpecEnd;
  885. HANDLE FindHandle;
  886. WIN32_FIND_DATA FindData;
  887. HANDLE hFile;
  888. //
  889. // So that we can keep on appending names to the directory spec
  890. // get a pointer to the end of its string
  891. //
  892. DirectorySpecEnd = DirPath + lstrlen( DirPath );
  893. //
  894. // setup the template for findfirst/findnext
  895. //
  896. if ((DirectorySpecEnd - DirPath) < ENUMPATHLENGTH - 2* sizeof(WCHAR)) {
  897. lstrcpy( DirectorySpecEnd, TEXT("*") );
  898. FindHandle = FindFirstFile( DirPath, &FindData );
  899. if (INVALID_HANDLE_VALUE != FindHandle) {
  900. do {
  901. //
  902. // Now skip over the . and .. entries
  903. //
  904. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  905. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  906. continue;
  907. } else {
  908. //
  909. // Make sure we don't try any paths that are too long for us
  910. // to deal with.
  911. //
  912. if ((DirectorySpecEnd - DirPath) +
  913. lstrlen( FindData.cFileName ) >= ENUMPATHLENGTH ) {
  914. continue;
  915. }
  916. if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
  917. (FindData.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED)) {
  918. //
  919. // append the found file to the directory spec and open
  920. // the file
  921. //
  922. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  923. //
  924. // Now touch the file
  925. //
  926. if (DisplayFilesOnly) {
  927. //swprintf(Buf, TEXT("%s",), DirPath);
  928. DisplayMsg(CIPHER_THROW_NL, DirPath);
  929. } else {
  930. hFile = CreateFileW(
  931. DirPath,
  932. GENERIC_READ,
  933. FILE_SHARE_READ | FILE_SHARE_WRITE,
  934. NULL,
  935. OPEN_EXISTING,
  936. 0,
  937. NULL
  938. );
  939. if ( INVALID_HANDLE_VALUE != hFile ){
  940. DisplayMsg(CIPHER_TOUCH_OK, DirPath);
  941. CloseHandle(hFile);
  942. } else {
  943. DisplayErr(DirPath, GetLastError());
  944. }
  945. }
  946. }
  947. }
  948. } while ( FindNextFile( FindHandle, &FindData ));
  949. FindClose( FindHandle );
  950. }
  951. }
  952. //
  953. // Setup findfirst/findnext to search the sub directory
  954. //
  955. if ((DirectorySpecEnd - DirPath) < ENUMPATHLENGTH - 2* sizeof(WCHAR)) {
  956. lstrcpy( DirectorySpecEnd, TEXT("*") );
  957. FindHandle = FindFirstFile( DirPath, &FindData );
  958. if (INVALID_HANDLE_VALUE != FindHandle) {
  959. do {
  960. //
  961. // Now skip over the . and .. entries otherwise we'll recurse
  962. // like mad
  963. //
  964. if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
  965. 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
  966. continue;
  967. } else {
  968. //
  969. // If the entry is for a directory then we'll tack on the
  970. // subdirectory name to the directory spec and recursively
  971. // call otherselves
  972. //
  973. if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
  974. BOOL b;
  975. WCHAR MountVolName[MAX_PATH];
  976. //
  977. // Make sure we don't try any paths that are too long for us
  978. // to deal with.
  979. //
  980. if ((DirectorySpecEnd - DirPath) +
  981. lstrlen( TEXT("\\") ) +
  982. lstrlen( FindData.cFileName ) >= ENUMPATHLENGTH ) {
  983. continue;
  984. }
  985. lstrcpy( DirectorySpecEnd, FindData.cFileName );
  986. lstrcat( DirectorySpecEnd, TEXT("\\") );
  987. //
  988. // Check if this DIR point to another volume
  989. //
  990. b = GetVolumeNameForVolumeMountPoint(DirPath, MountVolName, MAX_PATH);
  991. if (b) {
  992. if (CipherConvertToDriveLetter(MountVolName, VolumeInfo)){
  993. continue;
  994. }
  995. }
  996. CipherTouchDirFiles(DirPath, VolumeInfo);
  997. }
  998. }
  999. } while ( FindNextFile( FindHandle, &FindData ));
  1000. FindClose( FindHandle );
  1001. }
  1002. }
  1003. }
  1004. DWORD
  1005. CipherTouchEncryptedFiles(
  1006. )
  1007. {
  1008. WCHAR VolBuffer[MAX_PATH];
  1009. WCHAR *SearchPath = NULL;
  1010. HANDLE SearchHandle;
  1011. BOOL SearchNext = TRUE;
  1012. CIPHER_VOLUME_INFO VolumeInfo;
  1013. LPWSTR VolumeNames;
  1014. LPWSTR VolumeNamesCrnt;
  1015. LPWSTR DosDeviceNames;
  1016. LPWSTR DosDeviceNamesCrnt;
  1017. DWORD DriveIndex = 0;
  1018. WCHAR TmpChar;
  1019. BOOL b;
  1020. VolumeNames = (LPWSTR) malloc ( DosDriveLimitCount * MAX_PATH * sizeof(WCHAR) );
  1021. DosDeviceNames = (LPWSTR) malloc ( DosDriveLimitCount * MAX_PATH * sizeof(WCHAR) );
  1022. if ( !VolumeNames || !DosDeviceNames) {
  1023. if (VolumeNames) {
  1024. free(VolumeNames);
  1025. }
  1026. if (DosDeviceNames) {
  1027. free(DosDeviceNames);
  1028. }
  1029. return ERROR_NOT_ENOUGH_MEMORY;
  1030. }
  1031. //
  1032. // Don't popup when query floopy and etc.
  1033. //
  1034. SetErrorMode(SEM_FAILCRITICALERRORS);
  1035. lstrcpy(VolBuffer, TEXT("A:\\"));
  1036. VolumeNamesCrnt = VolumeNames;
  1037. DosDeviceNamesCrnt = DosDeviceNames;
  1038. //
  1039. // Get all the volume and device names which has a drive letter assigned
  1040. //
  1041. while (DriveIndex < DosDriveLimitCount) {
  1042. b = GetVolumeNameForVolumeMountPoint( VolBuffer,
  1043. VolumeNamesCrnt,
  1044. (DWORD)(VolumeNames + DosDriveLimitCount * MAX_PATH - VolumeNamesCrnt));
  1045. if (!b) {
  1046. VolumeInfo.VolumeName[DriveIndex] = NULL;
  1047. VolumeInfo.DosDeviceName[DriveIndex++] = NULL;
  1048. VolBuffer[0]++;
  1049. continue;
  1050. }
  1051. VolumeInfo.VolumeName[DriveIndex] = VolumeNamesCrnt;
  1052. VolumeNamesCrnt += lstrlen(VolumeNamesCrnt) + 1;
  1053. //
  1054. // The number 48 is copied from utils\mountvol\mountvol.c
  1055. //
  1056. TmpChar = VolumeInfo.VolumeName[DriveIndex][48];
  1057. VolumeInfo.VolumeName[DriveIndex][48] = 0;
  1058. if (QueryDosDevice( &(VolumeInfo.VolumeName[DriveIndex][4]),
  1059. DosDeviceNamesCrnt,
  1060. (DWORD)(DosDeviceNames + DosDriveLimitCount * MAX_PATH - DosDeviceNamesCrnt))) {
  1061. VolumeInfo.DosDeviceName[DriveIndex] = DosDeviceNamesCrnt;
  1062. DosDeviceNamesCrnt += lstrlen(DosDeviceNamesCrnt) + 1;
  1063. } else {
  1064. VolumeInfo.DosDeviceName[DriveIndex] = NULL;
  1065. }
  1066. VolumeInfo.VolumeName[DriveIndex][48] = TmpChar;
  1067. VolBuffer[0]++;
  1068. DriveIndex++;
  1069. }
  1070. SearchPath = (WCHAR *) malloc( ENUMPATHLENGTH * sizeof(WCHAR) );
  1071. if (!SearchPath) {
  1072. return ERROR_NOT_ENOUGH_MEMORY;
  1073. }
  1074. SearchHandle = FindFirstVolume(VolBuffer, MAX_PATH);
  1075. if ( INVALID_HANDLE_VALUE != SearchHandle ) {
  1076. if (DisplayFilesOnly) {
  1077. DisplayMsg(CIPHER_ENCRYPTED_FILES, NULL);
  1078. }
  1079. while ( SearchNext ) {
  1080. if (CipherConvertToDriveLetter(VolBuffer, &VolumeInfo)){
  1081. //
  1082. // Check if this volume is a NTFS volume
  1083. //
  1084. if(GetVolumeInformation(
  1085. VolBuffer, // Current root directory.
  1086. NULL, // Volume name.
  1087. 0, // Volume name length.
  1088. NULL, // Serial number.
  1089. NULL, // Maximum length.
  1090. NULL,
  1091. SearchPath, // File system type.
  1092. MAX_PATH
  1093. )){
  1094. if(!wcscmp(SearchPath, TEXT("NTFS"))){
  1095. lstrcpy( SearchPath, VolBuffer );
  1096. CipherTouchDirFiles(SearchPath, &VolumeInfo);
  1097. }
  1098. }
  1099. }
  1100. SearchNext = FindNextVolume(SearchHandle, VolBuffer, MAX_PATH);
  1101. }
  1102. FindVolumeClose(SearchHandle);
  1103. }
  1104. free(SearchPath);
  1105. free(VolumeNames);
  1106. free(DosDeviceNames);
  1107. return ERROR_SUCCESS;
  1108. }
  1109. BOOL
  1110. EncodeAndAlloc(
  1111. DWORD dwEncodingType,
  1112. LPCSTR lpszStructType,
  1113. const void * pvStructInfo,
  1114. PBYTE * pbEncoded,
  1115. PDWORD pcbEncoded
  1116. )
  1117. {
  1118. BOOL b = FALSE;
  1119. if (CryptEncodeObject(
  1120. dwEncodingType,
  1121. lpszStructType,
  1122. pvStructInfo,
  1123. NULL,
  1124. pcbEncoded )) {
  1125. *pbEncoded = (PBYTE)malloc( *pcbEncoded );
  1126. if (*pbEncoded) {
  1127. if (CryptEncodeObject(
  1128. dwEncodingType,
  1129. lpszStructType,
  1130. pvStructInfo,
  1131. *pbEncoded,
  1132. pcbEncoded )) {
  1133. b = TRUE;
  1134. } else {
  1135. free( *pbEncoded );
  1136. *pbEncoded = NULL;
  1137. }
  1138. } else {
  1139. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1140. }
  1141. }
  1142. return( b );
  1143. }
  1144. BOOLEAN
  1145. CreateSelfSignedRecoveryCertificate(
  1146. OUT PCCERT_CONTEXT * pCertContext,
  1147. OUT LPWSTR *lpContainerName,
  1148. OUT LPWSTR *lpProviderName
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. This routine sets up and creates a self-signed certificate.
  1153. Arguments:
  1154. Return Value:
  1155. TRUE on success, FALSE on failure. Call GetLastError() for more details.
  1156. --*/
  1157. {
  1158. BOOLEAN fReturn = FALSE;
  1159. DWORD rc = ERROR_SUCCESS;
  1160. PBYTE pbHash = NULL;
  1161. LPWSTR lpDisplayInfo = NULL;
  1162. HCRYPTKEY hKey = 0;
  1163. HCRYPTPROV hProv = 0;
  1164. GUID guidContainerName;
  1165. LPWSTR TmpContainerName;
  1166. *pCertContext = NULL;
  1167. *lpContainerName = NULL;
  1168. *lpProviderName = NULL;
  1169. //
  1170. // Create a key pair
  1171. //
  1172. //
  1173. // Container name
  1174. //
  1175. if ( ERROR_SUCCESS != UuidCreate(&guidContainerName) ) {
  1176. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1177. return(fReturn);
  1178. }
  1179. if (ERROR_SUCCESS == UuidToStringW(&guidContainerName, (unsigned short **)lpContainerName )) {
  1180. //
  1181. // Copy the container name into LSA heap memory
  1182. //
  1183. *lpProviderName = MS_DEF_PROV;
  1184. //
  1185. // Create the key container
  1186. //
  1187. if (CryptAcquireContext(&hProv, *lpContainerName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET )) {
  1188. if (CryptGenKey(hProv, AT_KEYEXCHANGE, RSA1024BIT_KEY | CRYPT_EXPORTABLE, &hKey)) {
  1189. DWORD NameLength = 64;
  1190. LPWSTR AgentName = NULL;
  1191. //
  1192. // Construct the subject name information
  1193. //
  1194. //lpDisplayInfo = MakeDNName();
  1195. AgentName = (LPWSTR)malloc(NameLength * sizeof(WCHAR));
  1196. if (AgentName){
  1197. if (!GetUserName(AgentName, &NameLength)){
  1198. free(AgentName);
  1199. AgentName = (LPWSTR)malloc(NameLength * sizeof(WCHAR));
  1200. //
  1201. // Try again with big buffer
  1202. //
  1203. if ( AgentName ){
  1204. if (!GetUserName(AgentName, &NameLength)){
  1205. rc = GetLastError();
  1206. free(AgentName);
  1207. AgentName = NULL;
  1208. }
  1209. } else {
  1210. rc = ERROR_NOT_ENOUGH_MEMORY;
  1211. }
  1212. }
  1213. } else {
  1214. rc = ERROR_NOT_ENOUGH_MEMORY;
  1215. }
  1216. if (AgentName) {
  1217. LPCWSTR DNNameTemplate = L"CN=%ws,L=EFS,OU=EFS File Encryption Certificate";
  1218. DWORD cbDNName = 0;
  1219. cbDNName = (wcslen( DNNameTemplate ) + 1) * sizeof( WCHAR ) + (wcslen( AgentName ) + 1) * sizeof( WCHAR );
  1220. lpDisplayInfo = (LPWSTR)malloc( cbDNName );
  1221. if (lpDisplayInfo) {
  1222. swprintf( lpDisplayInfo, DNNameTemplate, AgentName );
  1223. } else {
  1224. rc = ERROR_NOT_ENOUGH_MEMORY;
  1225. }
  1226. free(AgentName);
  1227. AgentName = NULL;
  1228. }
  1229. if (lpDisplayInfo) {
  1230. //
  1231. // Use this piece of code to create the PCERT_NAME_BLOB going into CertCreateSelfSignCertificate()
  1232. //
  1233. CERT_NAME_BLOB SubjectName;
  1234. SubjectName.cbData = 0;
  1235. if(CertStrToNameW(
  1236. CRYPT_ASN_ENCODING,
  1237. lpDisplayInfo,
  1238. 0,
  1239. NULL,
  1240. NULL,
  1241. &SubjectName.cbData,
  1242. NULL)) {
  1243. SubjectName.pbData = (BYTE *) malloc(SubjectName.cbData);
  1244. if (SubjectName.pbData) {
  1245. if (CertStrToNameW(
  1246. CRYPT_ASN_ENCODING,
  1247. lpDisplayInfo,
  1248. 0,
  1249. NULL,
  1250. SubjectName.pbData,
  1251. &SubjectName.cbData,
  1252. NULL) ) {
  1253. //
  1254. // Make the enhanced key usage
  1255. //
  1256. CERT_ENHKEY_USAGE certEnhKeyUsage;
  1257. LPSTR lpstr;
  1258. CERT_EXTENSION certExt;
  1259. lpstr = szOID_EFS_RECOVERY;
  1260. certEnhKeyUsage.cUsageIdentifier = 1;
  1261. certEnhKeyUsage.rgpszUsageIdentifier = &lpstr;
  1262. // now call CryptEncodeObject to encode the enhanced key usage into the extension struct
  1263. certExt.Value.cbData = 0;
  1264. certExt.Value.pbData = NULL;
  1265. certExt.fCritical = FALSE;
  1266. certExt.pszObjId = szOID_ENHANCED_KEY_USAGE;
  1267. //
  1268. // Encode it
  1269. //
  1270. if (EncodeAndAlloc(
  1271. CRYPT_ASN_ENCODING,
  1272. X509_ENHANCED_KEY_USAGE,
  1273. &certEnhKeyUsage,
  1274. &certExt.Value.pbData,
  1275. &certExt.Value.cbData
  1276. )) {
  1277. //
  1278. // finally, set up the array of extensions in the certInfo struct
  1279. // any further extensions need to be added to this array.
  1280. //
  1281. CERT_EXTENSIONS certExts;
  1282. CRYPT_KEY_PROV_INFO KeyProvInfo;
  1283. SYSTEMTIME StartTime;
  1284. FILETIME FileTime;
  1285. LARGE_INTEGER TimeData;
  1286. SYSTEMTIME EndTime;
  1287. certExts.cExtension = 1;
  1288. certExts.rgExtension = &certExt;
  1289. memset( &KeyProvInfo, 0, sizeof( CRYPT_KEY_PROV_INFO ));
  1290. KeyProvInfo.pwszContainerName = *lpContainerName;
  1291. KeyProvInfo.pwszProvName = *lpProviderName;
  1292. KeyProvInfo.dwProvType = PROV_RSA_FULL;
  1293. KeyProvInfo.dwKeySpec = AT_KEYEXCHANGE;
  1294. GetSystemTime(&StartTime);
  1295. SystemTimeToFileTime(&StartTime, &FileTime);
  1296. TimeData.LowPart = FileTime.dwLowDateTime;
  1297. TimeData.HighPart = (LONG) FileTime.dwHighDateTime;
  1298. TimeData.QuadPart += YEARCOUNT * 100;
  1299. FileTime.dwLowDateTime = TimeData.LowPart;
  1300. FileTime.dwHighDateTime = (DWORD) TimeData.HighPart;
  1301. FileTimeToSystemTime(&FileTime, &EndTime);
  1302. *pCertContext = CertCreateSelfSignCertificate(
  1303. hProv,
  1304. &SubjectName,
  1305. 0,
  1306. &KeyProvInfo,
  1307. NULL,
  1308. &StartTime,
  1309. &EndTime,
  1310. &certExts
  1311. );
  1312. if (*pCertContext) {
  1313. fReturn = TRUE;
  1314. } else {
  1315. rc = GetLastError();
  1316. }
  1317. free( certExt.Value.pbData );
  1318. } else {
  1319. rc = GetLastError();
  1320. }
  1321. } else {
  1322. rc = GetLastError();
  1323. }
  1324. free( SubjectName.pbData );
  1325. } else {
  1326. rc = ERROR_NOT_ENOUGH_MEMORY;
  1327. }
  1328. } else {
  1329. rc = GetLastError();
  1330. }
  1331. free( lpDisplayInfo );
  1332. } else {
  1333. rc = ERROR_NOT_ENOUGH_MEMORY;
  1334. }
  1335. CryptDestroyKey( hKey );
  1336. } else {
  1337. rc = GetLastError();
  1338. }
  1339. CryptReleaseContext( hProv, 0 );
  1340. hProv = 0;
  1341. if (ERROR_SUCCESS != rc) {
  1342. //
  1343. // Creating cert failed. Let's delete the key container.
  1344. //
  1345. CryptAcquireContext(&hProv, *lpContainerName, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET | CRYPT_SILENT );
  1346. }
  1347. } else {
  1348. rc = GetLastError();
  1349. }
  1350. if (ERROR_SUCCESS != rc) {
  1351. RpcStringFree( (unsigned short **)lpContainerName );
  1352. *lpContainerName = NULL;
  1353. }
  1354. } else {
  1355. rc = ERROR_NOT_ENOUGH_MEMORY;
  1356. }
  1357. if (!fReturn) {
  1358. if (*pCertContext) {
  1359. CertFreeCertificateContext( *pCertContext );
  1360. *pCertContext = NULL;
  1361. }
  1362. }
  1363. SetLastError( rc );
  1364. return( fReturn );
  1365. }
  1366. BOOLEAN
  1367. GetPassword(
  1368. OUT LPWSTR *PasswordStr
  1369. )
  1370. /*++
  1371. Routine Description:
  1372. Input a string from stdin in the Console code page.
  1373. We can't use fgetws since it uses the wrong code page.
  1374. Arguments:
  1375. Buffer - Buffer to put the read string into.
  1376. The Buffer will be zero terminated and will have any traing CR/LF removed
  1377. Return Values:
  1378. None.
  1379. --*/
  1380. {
  1381. int size;
  1382. LPSTR MbcsBuffer = NULL;
  1383. LPSTR Result;
  1384. DWORD Mode;
  1385. DWORD MbcsSize;
  1386. DWORD MbcsLength;
  1387. //
  1388. // Allocate a local buffer to read the string into
  1389. // Include room for the trimmed CR/LF
  1390. //
  1391. MbcsSize = (PASSWORDLEN+2) * sizeof(WCHAR);
  1392. MbcsBuffer = (LPSTR) malloc((PASSWORDLEN+2) * sizeof(WCHAR));
  1393. *PasswordStr = (LPWSTR) malloc((PASSWORDLEN+1) * sizeof(WCHAR));
  1394. if ( (MbcsBuffer == NULL) || (*PasswordStr == NULL) ) {
  1395. if (MbcsBuffer) {
  1396. free (MbcsBuffer);
  1397. }
  1398. if (*PasswordStr) {
  1399. free (*PasswordStr);
  1400. }
  1401. DisplayMsg(CIPHER_NO_MEMORY);
  1402. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1403. return FALSE;
  1404. }
  1405. DisplayMsg(CIPHER_PROMPT_PASSWORD);
  1406. // turn off echo
  1407. GetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), &Mode);
  1408. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE),
  1409. (~(ENABLE_ECHO_INPUT)) & Mode);
  1410. Result = fgets( MbcsBuffer, MbcsSize, stdin );
  1411. if ( Result == NULL ) {
  1412. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), Mode);
  1413. free(MbcsBuffer);
  1414. free (*PasswordStr);
  1415. *PasswordStr = NULL;
  1416. return TRUE;
  1417. }
  1418. DisplayMsg(CIPHER_CONFIRM_PASSWORD);
  1419. Result = fgets( (LPSTR)*PasswordStr, (PASSWORDLEN+1) * sizeof(WCHAR), stdin );
  1420. // turn echo back on
  1421. SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), Mode);
  1422. _putws ( L"\n" );
  1423. if (strcmp( (LPSTR) *PasswordStr, MbcsBuffer)){
  1424. //
  1425. // Password not match.
  1426. //
  1427. DisplayMsg(CIPHER_PASSWORD_NOMATCH);
  1428. free(MbcsBuffer);
  1429. free (*PasswordStr);
  1430. SetLastError(ERROR_INVALID_PASSWORD);
  1431. *PasswordStr = NULL;
  1432. return FALSE;
  1433. }
  1434. if ( Result == NULL ) {
  1435. free(MbcsBuffer);
  1436. free (*PasswordStr);
  1437. *PasswordStr = NULL;
  1438. return TRUE;
  1439. }
  1440. //
  1441. // Trim any trailing CR or LF char from the string
  1442. //
  1443. MbcsLength = lstrlenA( MbcsBuffer );
  1444. if ( MbcsLength == 0 ) {
  1445. free(MbcsBuffer);
  1446. free (*PasswordStr);
  1447. *PasswordStr = NULL;
  1448. return TRUE;
  1449. }
  1450. if ( MbcsBuffer[MbcsLength-1] == '\n' || MbcsBuffer[MbcsLength-1] == '\r' ) {
  1451. MbcsBuffer[MbcsLength-1] = '\0';
  1452. MbcsLength --;
  1453. }
  1454. //
  1455. // Convert the string to UNICODE
  1456. //
  1457. size = MultiByteToWideChar( GetConsoleOutputCP(),
  1458. 0,
  1459. MbcsBuffer,
  1460. MbcsLength+1, // Include trailing zero
  1461. *PasswordStr,
  1462. PASSWORDLEN );
  1463. free(MbcsBuffer);
  1464. if ( size == 0 ) {
  1465. DisplayErr(NULL, GetLastError());
  1466. free (*PasswordStr);
  1467. *PasswordStr = NULL;
  1468. return FALSE;
  1469. }
  1470. return TRUE;
  1471. }
  1472. DWORD
  1473. PromtUserYesNo(
  1474. IN LPWSTR FileName,
  1475. OUT DWORD *UserChoice
  1476. )
  1477. {
  1478. BOOLEAN Continue = TRUE;
  1479. LPWSTR Result;
  1480. LPWSTR Yesnotext;
  1481. DWORD TextLen;
  1482. //
  1483. // File exists
  1484. //
  1485. *UserChoice = ChoiceNotDefined;
  1486. TextLen = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1487. NULL, CIPHER_YESNOANSWER, 0, (LPVOID)&Yesnotext, 0, NULL);
  1488. if (TextLen && Yesnotext) {
  1489. while (TRUE) {
  1490. WCHAR FirstChar;
  1491. DisplayMsg(CIPHER_FILE_EXISTS, FileName);
  1492. Result = fgetws((LPWSTR)Buf, sizeof(Buf)/sizeof (WCHAR), stdin);
  1493. if (!Result) {
  1494. //
  1495. // Error or end of file. Just return.
  1496. //
  1497. LocalFree(Yesnotext);
  1498. return GetLastError();
  1499. }
  1500. //
  1501. // Trim any trailing CR or LF char from the string
  1502. //
  1503. FirstChar = towupper(Buf[0]);
  1504. if (Yesnotext[0] == FirstChar) {
  1505. *UserChoice = UserChooseYes;
  1506. break;
  1507. } else if (Yesnotext[1] == FirstChar) {
  1508. *UserChoice = UserChooseNo;
  1509. break;
  1510. }
  1511. }
  1512. LocalFree(Yesnotext);
  1513. } else {
  1514. return GetLastError();
  1515. }
  1516. return ERROR_SUCCESS;
  1517. }
  1518. DWORD
  1519. GenerateCertFiles(
  1520. IN LPWSTR StartingDirectory
  1521. )
  1522. {
  1523. HCERTSTORE memStore;
  1524. DWORD dwLastError = ERROR_SUCCESS;
  1525. PCCERT_CONTEXT pCertContext;
  1526. LPWSTR ContainerName;
  1527. LPWSTR ProviderName;
  1528. LPWSTR CertFileName;
  1529. LPWSTR PfxPassword;
  1530. if (!GetPassword( &PfxPassword )){
  1531. return GetLastError();
  1532. }
  1533. memStore = CertOpenStore(
  1534. CERT_STORE_PROV_MEMORY,
  1535. 0,
  1536. 0,
  1537. CERT_STORE_MAXIMUM_ALLOWED_FLAG,
  1538. NULL
  1539. );
  1540. CertFileName = (LPWSTR)malloc((wcslen(StartingDirectory)+5) * sizeof(WCHAR));
  1541. if (memStore && CertFileName) {
  1542. //
  1543. // Let's check if the files exist or not
  1544. //
  1545. wcscpy(CertFileName, StartingDirectory);
  1546. wcscat(CertFileName, L".PFX");
  1547. if (GetFileAttributes(CertFileName) != -1) {
  1548. DWORD UserChoice;
  1549. if (((dwLastError = PromtUserYesNo(CertFileName, &UserChoice)) != ERROR_SUCCESS) ||
  1550. (UserChoice != 0)) {
  1551. free(CertFileName);
  1552. CertCloseStore( memStore, 0 );
  1553. return dwLastError;
  1554. }
  1555. }
  1556. wcscpy(CertFileName, StartingDirectory);
  1557. wcscat(CertFileName, L".CER");
  1558. if (GetFileAttributes(CertFileName) != -1) {
  1559. DWORD UserChoice;
  1560. if (((dwLastError = PromtUserYesNo(CertFileName, &UserChoice)) != ERROR_SUCCESS) ||
  1561. (UserChoice != 0)) {
  1562. free(CertFileName);
  1563. CertCloseStore( memStore, 0 );
  1564. return dwLastError;
  1565. }
  1566. }
  1567. //
  1568. // Generate the cert first
  1569. //
  1570. if (CreateSelfSignedRecoveryCertificate(&pCertContext, &ContainerName, &ProviderName)){
  1571. HANDLE hFile;
  1572. HCRYPTPROV hProv = 0;
  1573. DWORD BytesWritten = 0;
  1574. //
  1575. // We got the certificate. Let's generate the CER file first
  1576. //
  1577. hFile = CreateFileW(
  1578. CertFileName,
  1579. GENERIC_WRITE,
  1580. 0,
  1581. NULL,
  1582. CREATE_ALWAYS,
  1583. FILE_ATTRIBUTE_NORMAL,
  1584. NULL
  1585. );
  1586. if ( INVALID_HANDLE_VALUE != hFile) {
  1587. //
  1588. // Let's write out the CER file
  1589. //
  1590. if(!WriteFile(
  1591. hFile,
  1592. pCertContext->pbCertEncoded,
  1593. pCertContext->cbCertEncoded,
  1594. &BytesWritten,
  1595. NULL
  1596. )){
  1597. dwLastError = GetLastError();
  1598. } else {
  1599. DisplayMsg(CIPHER_CER_CREATED);
  1600. }
  1601. CloseHandle(hFile);
  1602. } else {
  1603. dwLastError = GetLastError();
  1604. }
  1605. if (CertAddCertificateContextToStore(memStore, pCertContext, CERT_STORE_ADD_ALWAYS, NULL)){
  1606. CRYPT_DATA_BLOB PFX;
  1607. memset( &PFX, 0, sizeof( CRYPT_DATA_BLOB ));
  1608. //
  1609. // Asking password
  1610. //
  1611. if (PFXExportCertStoreEx(
  1612. memStore,
  1613. &PFX,
  1614. PfxPassword,
  1615. NULL,
  1616. EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | REPORT_NO_PRIVATE_KEY)){
  1617. PFX.pbData = (BYTE *) malloc(PFX.cbData);
  1618. if (PFX.pbData) {
  1619. if (PFXExportCertStoreEx(
  1620. memStore,
  1621. &PFX,
  1622. PfxPassword,
  1623. NULL,
  1624. EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY | REPORT_NO_PRIVATE_KEY)){
  1625. //
  1626. // Write out the PFX file
  1627. //
  1628. wcscpy(CertFileName, StartingDirectory);
  1629. wcscat(CertFileName, L".PFX");
  1630. hFile = CreateFileW(
  1631. CertFileName,
  1632. GENERIC_WRITE,
  1633. 0,
  1634. NULL,
  1635. CREATE_ALWAYS,
  1636. FILE_ATTRIBUTE_NORMAL,
  1637. NULL
  1638. );
  1639. if ( INVALID_HANDLE_VALUE != hFile) {
  1640. //
  1641. // Let's write out the CER file
  1642. //
  1643. if(!WriteFile(
  1644. hFile,
  1645. PFX.pbData,
  1646. PFX.cbData,
  1647. &BytesWritten,
  1648. NULL
  1649. )){
  1650. dwLastError = GetLastError();
  1651. } else {
  1652. DisplayMsg(CIPHER_PFX_CREATED);
  1653. }
  1654. CloseHandle(hFile);
  1655. } else {
  1656. dwLastError = GetLastError();
  1657. }
  1658. } else {
  1659. dwLastError = GetLastError();
  1660. }
  1661. free( PFX.pbData );
  1662. } else {
  1663. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  1664. }
  1665. } else {
  1666. dwLastError = GetLastError();
  1667. }
  1668. }
  1669. //
  1670. // Let's delete the key
  1671. //
  1672. CertFreeCertificateContext(pCertContext);
  1673. RpcStringFree( (unsigned short **)&ContainerName );
  1674. CryptAcquireContext(&hProv, ContainerName, ProviderName, PROV_RSA_FULL, CRYPT_DELETEKEYSET | CRYPT_SILENT );
  1675. } else {
  1676. dwLastError = GetLastError();
  1677. }
  1678. //
  1679. // Close Store and free the
  1680. //
  1681. free(CertFileName);
  1682. CertCloseStore( memStore, 0 );
  1683. } else {
  1684. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  1685. }
  1686. if (PfxPassword){
  1687. free(PfxPassword);
  1688. }
  1689. if (ERROR_SUCCESS != dwLastError) {
  1690. DisplayErr(NULL, dwLastError);
  1691. }
  1692. return dwLastError;
  1693. }
  1694. DWORD
  1695. SecureInitializeRandomFill(
  1696. IN OUT PSECURE_FILL_INFO pSecureFill,
  1697. IN ULONG FillSize,
  1698. IN PBYTE FillValue OPTIONAL
  1699. )
  1700. /*++
  1701. FillValue = NULL
  1702. Use Random fill and random mixing logic.
  1703. FillValue = valid pointer to fill byte
  1704. Fill region with specified value, with no random mixing.
  1705. --*/
  1706. {
  1707. DWORD dwLastError;
  1708. __try {
  1709. //
  1710. // allocate the critical section.
  1711. //
  1712. InitializeCriticalSection( &pSecureFill->Lock );
  1713. } __except (EXCEPTION_EXECUTE_HANDLER )
  1714. {
  1715. return ERROR_NOT_ENOUGH_MEMORY;
  1716. }
  1717. pSecureFill->LockValid = TRUE;
  1718. pSecureFill->cbRandomFill = FillSize;
  1719. pSecureFill->pbRandomFill = VirtualAlloc(
  1720. NULL,
  1721. FillSize,
  1722. MEM_COMMIT,
  1723. PAGE_READWRITE
  1724. );
  1725. if( pSecureFill->pbRandomFill != NULL )
  1726. {
  1727. BYTE RandomFill[256];
  1728. if( FillValue != NULL )
  1729. {
  1730. memset( pSecureFill->pbRandomFill, *FillValue, pSecureFill->cbRandomFill );
  1731. pSecureFill->fRandomFill = FALSE;
  1732. return ERROR_SUCCESS;
  1733. }
  1734. //
  1735. // initialize the region with initial random pad.
  1736. //
  1737. pSecureFill->fRandomFill = TRUE;
  1738. RANDOM_BYTES( RandomFill, sizeof(RandomFill) );
  1739. rc4_key( &pSecureFill->Key, sizeof(RandomFill), RandomFill );
  1740. rc4( &pSecureFill->Key, pSecureFill->cbRandomFill, pSecureFill->pbRandomFill );
  1741. //
  1742. // initialize the key.
  1743. //
  1744. RANDOM_BYTES( RandomFill, sizeof(RandomFill) );
  1745. rc4_key( &pSecureFill->Key, sizeof(RandomFill), RandomFill );
  1746. ZeroMemory( RandomFill, sizeof(RandomFill) );
  1747. return ERROR_SUCCESS;
  1748. }
  1749. dwLastError = GetLastError();
  1750. DeleteCriticalSection( &pSecureFill->Lock );
  1751. pSecureFill->LockValid = FALSE;
  1752. return dwLastError;
  1753. }
  1754. VOID
  1755. SecureMixRandomFill(
  1756. IN OUT PSECURE_FILL_INFO pSecureFill,
  1757. IN ULONG cbBytesThisFill
  1758. )
  1759. {
  1760. LONG Result;
  1761. LONG Compare;
  1762. if( !pSecureFill->fRandomFill )
  1763. {
  1764. return;
  1765. }
  1766. //
  1767. // update the fill once it has been used 8 times.
  1768. //
  1769. Compare = (LONG)(8 * pSecureFill->cbRandomFill);
  1770. Result = InterlockedExchangeAdd(
  1771. &pSecureFill->cbFilled,
  1772. cbBytesThisFill
  1773. );
  1774. if( (Result+Compare) > Compare )
  1775. {
  1776. Result = 0;
  1777. //
  1778. // if there was a race condition, only one thread will update the random fill.
  1779. //
  1780. if( TryEnterCriticalSection( &pSecureFill->Lock ) )
  1781. {
  1782. rc4( &pSecureFill->Key, pSecureFill->cbRandomFill, pSecureFill->pbRandomFill );
  1783. LeaveCriticalSection( &pSecureFill->Lock );
  1784. }
  1785. }
  1786. }
  1787. DWORD
  1788. SecureDeleteRandomFill(
  1789. IN PSECURE_FILL_INFO pSecureFill
  1790. )
  1791. {
  1792. if( pSecureFill->pbRandomFill != NULL )
  1793. {
  1794. VirtualFree( pSecureFill->pbRandomFill, pSecureFill->cbRandomFill, MEM_RELEASE );
  1795. }
  1796. if( pSecureFill->LockValid )
  1797. {
  1798. DeleteCriticalSection( &pSecureFill->Lock );
  1799. }
  1800. ZeroMemory( pSecureFill, sizeof(*pSecureFill) );
  1801. return ERROR_SUCCESS;
  1802. }
  1803. #define MaxFileNum 100000000
  1804. #define MaxDigit 9
  1805. HANDLE
  1806. CreateMyTempFile(
  1807. LPWSTR TempPath
  1808. )
  1809. {
  1810. static DWORD TempIndex = 0;
  1811. WCHAR TempFileName[MAX_PATH];
  1812. WCHAR TempIndexString[MaxDigit+2];
  1813. DWORD TempPathLength;
  1814. HANDLE TempHandle;
  1815. BOOLEAN ContinueSearch = TRUE;
  1816. DWORD RetCode;
  1817. if (wcslen(TempPath) >= (MAX_PATH - 3 - MaxDigit)) {
  1818. //
  1819. // Path too long. This should not happen as the TempPath should be the root of the volume
  1820. //
  1821. SetLastError(ERROR_LABEL_TOO_LONG);
  1822. return INVALID_HANDLE_VALUE;
  1823. }
  1824. wcscpy(TempFileName, TempPath);
  1825. TempPathLength = wcslen(TempPath);
  1826. while ( (TempIndex <= MaxFileNum) && ContinueSearch ) {
  1827. wsprintf(TempIndexString, L"%ld", TempIndex);
  1828. wcscat(TempFileName, TempIndexString);
  1829. wcscat(TempFileName, L".E");
  1830. TempHandle = CreateFileW(
  1831. TempFileName,
  1832. GENERIC_WRITE,
  1833. 0,
  1834. NULL,
  1835. CREATE_NEW,
  1836. FILE_ATTRIBUTE_NORMAL |
  1837. FILE_FLAG_DELETE_ON_CLOSE,
  1838. NULL
  1839. );
  1840. if (TempHandle != INVALID_HANDLE_VALUE) {
  1841. return TempHandle;
  1842. }
  1843. RetCode = GetLastError();
  1844. switch (RetCode) {
  1845. case ERROR_INVALID_PARAMETER :
  1846. case ERROR_WRITE_PROTECT :
  1847. case ERROR_FILE_NOT_FOUND :
  1848. case ERROR_BAD_PATHNAME :
  1849. case ERROR_INVALID_NAME :
  1850. case ERROR_PATH_NOT_FOUND :
  1851. case ERROR_NETWORK_ACCESS_DENIED :
  1852. case ERROR_DISK_CORRUPT :
  1853. case ERROR_FILE_CORRUPT :
  1854. case ERROR_DISK_FULL :
  1855. ContinueSearch = FALSE;
  1856. break;
  1857. default:
  1858. TempFileName[TempPathLength] = 0;
  1859. break;
  1860. }
  1861. TempIndex++;
  1862. }
  1863. //
  1864. // We got the filename.
  1865. //
  1866. return TempHandle;
  1867. }
  1868. DWORD
  1869. SecureProcessMft(
  1870. IN LPWSTR DriveLetter,
  1871. IN HANDLE hTempFile
  1872. )
  1873. {
  1874. NTFS_VOLUME_DATA_BUFFER VolumeData;
  1875. DWORD cbOutput;
  1876. __int64 TotalMftEntries;
  1877. PHANDLE pHandleArray = NULL;
  1878. DWORD FreeMftEntries;
  1879. DWORD i;
  1880. DWORD dwLastError = ERROR_SUCCESS;
  1881. //
  1882. // get the count of MFT records. This will fail if not NTFS, so bail in that case.
  1883. //
  1884. if(!DeviceIoControl(
  1885. hTempFile,
  1886. FSCTL_GET_NTFS_VOLUME_DATA, // dwIoControlCode
  1887. NULL,
  1888. 0,
  1889. &VolumeData,
  1890. sizeof(VolumeData),
  1891. &cbOutput,
  1892. NULL
  1893. ))
  1894. {
  1895. return GetLastError();
  1896. }
  1897. TotalMftEntries = VolumeData.MftValidDataLength.QuadPart / VolumeData.BytesPerFileRecordSegment;
  1898. if( TotalMftEntries > (0xFFFFFFFF/sizeof(HANDLE)) )
  1899. {
  1900. return ERROR_INVALID_PARAMETER;
  1901. }
  1902. FreeMftEntries = (DWORD)TotalMftEntries;
  1903. pHandleArray = HeapAlloc(GetProcessHeap(), 0 , FreeMftEntries*sizeof(HANDLE));
  1904. if( pHandleArray == NULL )
  1905. {
  1906. return ERROR_NOT_ENOUGH_MEMORY;
  1907. }
  1908. ZeroMemory( pHandleArray, FreeMftEntries * sizeof(HANDLE) );
  1909. for( i=0;i< FreeMftEntries ; i++ )
  1910. {
  1911. WCHAR szTempPath[ MAX_PATH + 1 ];
  1912. DWORD FillIndex;
  1913. pHandleArray[i] = CreateMyTempFile(DriveLetter);
  1914. if( pHandleArray[i] == INVALID_HANDLE_VALUE )
  1915. {
  1916. dwLastError = GetLastError();
  1917. break;
  1918. }
  1919. //
  1920. // for each file created, write at most BytesPerFileRecordSegment data to it.
  1921. //
  1922. for( FillIndex = 0 ; FillIndex < (VolumeData.BytesPerFileRecordSegment/8) ; FillIndex++ )
  1923. {
  1924. DWORD dwBytesWritten;
  1925. if(!WriteFile(
  1926. pHandleArray[i],
  1927. GlobalSecureFill.pbRandomFill,
  1928. 8,
  1929. &dwBytesWritten,
  1930. NULL
  1931. ))
  1932. {
  1933. break;
  1934. }
  1935. }
  1936. if (i && !(i % 200)) {
  1937. //
  1938. // Keep users informed for every 50 files we created.
  1939. //
  1940. printf(".");
  1941. }
  1942. }
  1943. if( dwLastError == ERROR_DISK_FULL )
  1944. {
  1945. dwLastError = ERROR_SUCCESS;
  1946. }
  1947. #ifdef TestOutPut
  1948. printf("\nmft error=%lu entries created=%lu total = %I64u\n", dwLastError, i, TotalMftEntries);
  1949. #endif
  1950. for (i=0;i < FreeMftEntries;i++) {
  1951. if( pHandleArray[i] != INVALID_HANDLE_VALUE &&
  1952. pHandleArray[i] != NULL
  1953. )
  1954. {
  1955. CloseHandle( pHandleArray[i] );
  1956. }
  1957. }
  1958. if( pHandleArray != NULL )
  1959. {
  1960. HeapFree(GetProcessHeap(), 0, pHandleArray );
  1961. }
  1962. return dwLastError;
  1963. }
  1964. DWORD
  1965. SecureProcessFreeClusters(
  1966. IN LPWSTR DrivePath,
  1967. IN HANDLE hTempFile
  1968. )
  1969. {
  1970. HANDLE hVolume = INVALID_HANDLE_VALUE;
  1971. WCHAR VolumeName[100]; // 50 should be enough. 100 is more than enough.
  1972. NTFS_VOLUME_DATA_BUFFER VolumeData;
  1973. STARTING_LCN_INPUT_BUFFER LcnInput;
  1974. VOLUME_BITMAP_BUFFER *pBitmap = NULL;
  1975. MOVE_FILE_DATA MoveFile;
  1976. __int64 cbBitmap;
  1977. DWORD cbOutput;
  1978. unsigned __int64 ClusterLocation;
  1979. unsigned __int64 Lcn;
  1980. BYTE Mask;
  1981. unsigned __int64 Free = 0;
  1982. DWORD Fail = 0;
  1983. #ifdef TestOutPut
  1984. DWORD dwStart, dwStop;
  1985. #endif
  1986. __int64 ClusterIndex;
  1987. DWORD dwLastError = ERROR_SUCCESS;
  1988. //
  1989. // first, find out if there are free or reserved clusters.
  1990. // this will fail if the volume is not NTFS.
  1991. //
  1992. if (!GetVolumeNameForVolumeMountPoint(
  1993. DrivePath,
  1994. VolumeName,
  1995. sizeof(VolumeName)/sizeof(WCHAR) )){
  1996. return GetLastError();
  1997. }
  1998. VolumeName[wcslen(VolumeName)-1] = 0; // Truncate the trailing slash
  1999. if(!DeviceIoControl(
  2000. hTempFile,
  2001. FSCTL_GET_NTFS_VOLUME_DATA, // dwIoControlCode
  2002. NULL,
  2003. 0,
  2004. &VolumeData,
  2005. sizeof(VolumeData),
  2006. &cbOutput,
  2007. NULL
  2008. ))
  2009. {
  2010. dwLastError = GetLastError();
  2011. goto Cleanup;
  2012. }
  2013. if( VolumeData.FreeClusters.QuadPart == 0 &&
  2014. VolumeData.TotalReserved.QuadPart == 0 )
  2015. {
  2016. return ERROR_SUCCESS;
  2017. }
  2018. hVolume = CreateFileW( VolumeName,
  2019. FILE_READ_ATTRIBUTES | GENERIC_WRITE,
  2020. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  2021. NULL,
  2022. OPEN_EXISTING,
  2023. FILE_FLAG_NO_BUFFERING, // no buffering
  2024. NULL
  2025. );
  2026. if( hVolume == INVALID_HANDLE_VALUE )
  2027. {
  2028. dwLastError = GetLastError();
  2029. goto Cleanup;
  2030. }
  2031. //
  2032. // allocate space for the volume bitmap.
  2033. //
  2034. cbBitmap = sizeof(VOLUME_BITMAP_BUFFER) + (VolumeData.TotalClusters.QuadPart / 8);
  2035. if( cbBitmap > 0xFFFFFFFF )
  2036. {
  2037. dwLastError = ERROR_INVALID_PARAMETER;
  2038. goto Cleanup;
  2039. }
  2040. pBitmap = HeapAlloc(GetProcessHeap(), 0, (DWORD)cbBitmap);
  2041. if( pBitmap == NULL )
  2042. {
  2043. dwLastError = ERROR_NOT_ENOUGH_MEMORY;
  2044. goto Cleanup;
  2045. }
  2046. //
  2047. // grab the volume bitmap.
  2048. //
  2049. LcnInput.StartingLcn.QuadPart = 0;
  2050. ZeroMemory( &MoveFile, sizeof(MoveFile) );
  2051. MoveFile.FileHandle = hTempFile;
  2052. MoveFile.StartingVcn.QuadPart = 0;
  2053. MoveFile.ClusterCount = 1;
  2054. #ifdef TestOutPut
  2055. dwStart = GetTickCount();
  2056. #endif
  2057. if(!DeviceIoControl(
  2058. hVolume,
  2059. FSCTL_GET_VOLUME_BITMAP,
  2060. &LcnInput,
  2061. sizeof(LcnInput),
  2062. pBitmap,
  2063. (DWORD)cbBitmap,
  2064. &cbOutput,
  2065. NULL
  2066. ))
  2067. {
  2068. dwLastError = GetLastError();
  2069. goto Cleanup;
  2070. }
  2071. //
  2072. // insure file is only bytes per cluster in length.
  2073. // this will shrink the file if necessary. We waited until after we fetched the
  2074. // volume bitmap to insure we only process the free clusters that existed prior to
  2075. // the shrink operation.
  2076. //
  2077. if(SetFilePointer(
  2078. hTempFile,
  2079. (LONG)VolumeData.BytesPerCluster,
  2080. NULL,
  2081. FILE_BEGIN
  2082. ) == INVALID_SET_FILE_POINTER)
  2083. {
  2084. dwLastError = GetLastError();
  2085. goto Cleanup;
  2086. }
  2087. if(!SetEndOfFile( hTempFile ))
  2088. {
  2089. dwLastError = GetLastError();
  2090. goto Cleanup;
  2091. }
  2092. Mask = 1;
  2093. Lcn = pBitmap->StartingLcn.QuadPart;
  2094. for(ClusterIndex = 0 ; ClusterIndex < VolumeData.TotalClusters.QuadPart ; ClusterIndex++)
  2095. {
  2096. if( (pBitmap->Buffer[ClusterIndex/8] & Mask) == 0 )
  2097. {
  2098. DWORD dwMoveError = ERROR_SUCCESS;
  2099. //
  2100. // move a single cluster from the temp file to the free cluster.
  2101. //
  2102. MoveFile.StartingLcn.QuadPart = Lcn;
  2103. if(!DeviceIoControl(
  2104. hVolume,
  2105. FSCTL_MOVE_FILE, // dwIoControlCode
  2106. &MoveFile,
  2107. sizeof(MoveFile),
  2108. NULL,
  2109. 0,
  2110. &cbOutput,
  2111. NULL
  2112. ))
  2113. {
  2114. dwMoveError = GetLastError();
  2115. }
  2116. //
  2117. // if it succeeded, or the cluster was in use, mark it used in the bitmap.
  2118. //
  2119. if( dwMoveError == ERROR_SUCCESS || dwMoveError == ERROR_ACCESS_DENIED )
  2120. {
  2121. pBitmap->Buffer[ClusterIndex/8] |= Mask;
  2122. } else {
  2123. Fail++;
  2124. }
  2125. Free++;
  2126. if ( !(Free % 200) ) {
  2127. //
  2128. // Keep users informed for every 50 files we created.
  2129. //
  2130. printf(".");
  2131. }
  2132. }
  2133. Lcn ++;
  2134. Mask <<= 1;
  2135. if(Mask == 0)
  2136. {
  2137. Mask = 1;
  2138. }
  2139. }
  2140. #ifdef TestOutPut
  2141. dwStop = GetTickCount();
  2142. printf("\nFreeCount = %I64x fail = %lu elapsed = %lu\n", Free, Fail, dwStop-dwStart);
  2143. #endif
  2144. Cleanup:
  2145. if( pBitmap != NULL )
  2146. {
  2147. HeapFree( GetProcessHeap(), 0, pBitmap );
  2148. }
  2149. if( hVolume != INVALID_HANDLE_VALUE )
  2150. {
  2151. CloseHandle( hVolume );
  2152. }
  2153. return dwLastError;
  2154. }
  2155. DWORD
  2156. SecureDeleteFreeSpace(
  2157. IN LPWSTR Directory
  2158. )
  2159. /*++
  2160. This routine fills the disk specified by the input Directory parameter with random fill.
  2161. Input is of the form "C:\", for instance.
  2162. Notes on approaches not employed here:
  2163. Alternate method would use defrag API to move random fill around the
  2164. free cluster map. Requires admin priviliges to the volume. Slower than filling volume with
  2165. a new file.
  2166. Variant on alternate method: fill volume 80% with file, grab free cluster map,
  2167. delete file associated with 80% fill, then use defrag API to fill the free cluster map
  2168. mentioned previously.
  2169. Does not fill cluster slack space for each file on the system. Could do this by
  2170. enumerating all files, and then extending+fill to slack boundry+restore original
  2171. EOF.
  2172. Does not fill $LOG. Queried file system folks on whether this is possible by creating
  2173. many small temporary files containing random fill.
  2174. --*/
  2175. {
  2176. UINT DriveType;
  2177. DWORD DirNameLength;
  2178. DWORD BufferLength;
  2179. LPWSTR PathName = NULL;
  2180. LPWSTR TempDirName = NULL;
  2181. BOOL b;
  2182. BOOL DirCreated = FALSE;
  2183. DWORD Attributes;
  2184. DWORD SectorsPerCluster;
  2185. DWORD BytesPerSector;
  2186. WCHAR TempFileName[ MAX_PATH + 1 ];
  2187. HANDLE hTempFile = INVALID_HANDLE_VALUE;
  2188. DWORD dwWriteBytes;
  2189. unsigned __int64 TotalBytesWritten;
  2190. unsigned __int64 NotifyBytesWritten;
  2191. unsigned __int64 NotifyInterval;
  2192. ULARGE_INTEGER TotalFreeBytes;
  2193. PBYTE pbFillBuffer = NULL;
  2194. ULONG cbFillBuffer;
  2195. NTFS_VOLUME_DATA_BUFFER VolumeData;
  2196. __int64 MftEntries = 0;
  2197. BOOLEAN ClustersRemaining = FALSE;
  2198. DWORD cbOutput;
  2199. DWORD dwLastError = ERROR_SUCCESS;
  2200. DWORD dwTestError;
  2201. #ifdef TestOutPut
  2202. ULARGE_INTEGER StartTime;
  2203. ULARGE_INTEGER StopTime;
  2204. #endif
  2205. //
  2206. // collect information about the disk in question.
  2207. //
  2208. DirNameLength = wcslen(Directory);
  2209. BufferLength = (DirNameLength + 1) <= MAX_PATH ?
  2210. (MAX_PATH + 1) * sizeof(WCHAR) : (DirNameLength + 1) * sizeof (WCHAR);
  2211. PathName = (LPWSTR) malloc(BufferLength);
  2212. if ( !PathName ) {
  2213. return ERROR_NOT_ENOUGH_MEMORY;
  2214. }
  2215. TempDirName = (LPWSTR) malloc(BufferLength + wcslen(WIPING_DIR) * sizeof (WCHAR));
  2216. if ( !TempDirName ) {
  2217. free(PathName);
  2218. return ERROR_NOT_ENOUGH_MEMORY;
  2219. }
  2220. b = GetVolumePathNameW(
  2221. Directory,
  2222. PathName,
  2223. BufferLength
  2224. );
  2225. if (!b) {
  2226. dwLastError = GetLastError();
  2227. goto Cleanup;
  2228. }
  2229. DriveType = GetDriveTypeW( PathName );
  2230. if( DriveType == DRIVE_REMOTE ||
  2231. DriveType == DRIVE_CDROM )
  2232. {
  2233. dwLastError = ERROR_NOT_SUPPORTED;
  2234. goto Cleanup;
  2235. }
  2236. if(!GetDiskFreeSpaceW(
  2237. PathName,
  2238. &SectorsPerCluster,
  2239. &BytesPerSector,
  2240. NULL,
  2241. NULL
  2242. ))
  2243. {
  2244. dwLastError = GetLastError();
  2245. goto Cleanup;
  2246. }
  2247. //
  2248. // allocate memory chunk to accomodate cluster size data
  2249. //
  2250. cbFillBuffer = GlobalSecureFill.cbRandomFill;
  2251. pbFillBuffer = GlobalSecureFill.pbRandomFill;
  2252. //
  2253. // determine how many bytes free space on the disk to enable notification of
  2254. // overall progress.
  2255. //
  2256. if(!GetDiskFreeSpaceExW(
  2257. PathName,
  2258. NULL,
  2259. NULL,
  2260. &TotalFreeBytes
  2261. ))
  2262. {
  2263. dwLastError = GetLastError();
  2264. goto Cleanup;
  2265. }
  2266. //
  2267. // Let's Create the temp directory
  2268. //
  2269. wcscpy(TempDirName, PathName);
  2270. wcscat(TempDirName, WIPING_DIR);
  2271. if (!CreateDirectory(TempDirName, NULL)){
  2272. //
  2273. // Could not create our temp directory. Quit.
  2274. //
  2275. if ((dwLastError = GetLastError()) != ERROR_ALREADY_EXISTS){
  2276. goto Cleanup;
  2277. }
  2278. }
  2279. DirCreated = TRUE;
  2280. //
  2281. // generate temporary file.
  2282. //
  2283. if( GetTempFileNameW(
  2284. TempDirName,
  2285. L"fil",
  2286. 0,
  2287. TempFileName
  2288. ) == 0 )
  2289. {
  2290. dwLastError = GetLastError();
  2291. goto Cleanup;
  2292. }
  2293. Attributes = GetFileAttributes(TempFileName);
  2294. if (0xFFFFFFFF == Attributes) {
  2295. dwLastError = GetLastError();
  2296. goto Cleanup;
  2297. }
  2298. if (Attributes & FILE_ATTRIBUTE_ENCRYPTED) {
  2299. if (!DecryptFile(TempFileName, 0)){
  2300. dwLastError = GetLastError();
  2301. goto Cleanup;
  2302. }
  2303. }
  2304. hTempFile = CreateFileW(
  2305. TempFileName,
  2306. GENERIC_WRITE,
  2307. 0, // exclusive access
  2308. NULL,
  2309. OPEN_EXISTING,
  2310. FILE_ATTRIBUTE_NORMAL |
  2311. FILE_FLAG_NO_BUFFERING | // no buffering
  2312. FILE_FLAG_DELETE_ON_CLOSE, // delete file when it closes.
  2313. NULL
  2314. );
  2315. if( hTempFile == INVALID_HANDLE_VALUE )
  2316. {
  2317. dwLastError = GetLastError();
  2318. goto Cleanup;
  2319. }
  2320. if (Attributes & FILE_ATTRIBUTE_COMPRESSED) {
  2321. USHORT State = COMPRESSION_FORMAT_NONE;
  2322. //
  2323. // Uncompress the directory first
  2324. //
  2325. b = DeviceIoControl(hTempFile,
  2326. FSCTL_SET_COMPRESSION,
  2327. &State,
  2328. sizeof(USHORT),
  2329. NULL,
  2330. 0,
  2331. &BufferLength,
  2332. FALSE
  2333. );
  2334. if ( !b ){
  2335. dwLastError = GetLastError();
  2336. goto Cleanup;
  2337. }
  2338. }
  2339. TotalBytesWritten = 0;
  2340. //
  2341. // tell the user something happened for each 1% processed.
  2342. //
  2343. NotifyInterval = (TotalFreeBytes.QuadPart / 100);
  2344. NotifyBytesWritten = NotifyInterval;
  2345. dwWriteBytes = cbFillBuffer;
  2346. #ifdef TestOutPut
  2347. GetSystemTimeAsFileTime( (FILETIME*)&StartTime );
  2348. #endif
  2349. while( TRUE )
  2350. {
  2351. DWORD BytesWritten;
  2352. if( TotalBytesWritten >= NotifyBytesWritten )
  2353. {
  2354. printf(".");
  2355. NotifyBytesWritten += NotifyInterval;
  2356. }
  2357. //
  2358. // mix random fill.
  2359. //
  2360. SecureMixRandomFill( &GlobalSecureFill, dwWriteBytes );
  2361. if(!WriteFile(
  2362. hTempFile,
  2363. pbFillBuffer,
  2364. dwWriteBytes,
  2365. &BytesWritten,
  2366. NULL
  2367. ))
  2368. {
  2369. if( GetLastError() == ERROR_DISK_FULL )
  2370. {
  2371. dwLastError = ERROR_SUCCESS;
  2372. //
  2373. // if the attempted write failed, enter a retry mode with downgraded
  2374. // buffersize to catch the last bits of slop.
  2375. //
  2376. if( dwWriteBytes > BytesPerSector )
  2377. {
  2378. dwWriteBytes = BytesPerSector;
  2379. continue;
  2380. }
  2381. } else {
  2382. dwLastError = GetLastError();
  2383. }
  2384. break;
  2385. }
  2386. TotalBytesWritten += BytesWritten;
  2387. }
  2388. #ifdef TestOutPut
  2389. GetSystemTimeAsFileTime( (FILETIME*)&StopTime );
  2390. {
  2391. ULARGE_INTEGER ElapsedTime;
  2392. SYSTEMTIME st;
  2393. ElapsedTime.QuadPart = (StopTime.QuadPart - StartTime.QuadPart);
  2394. FileTimeToSystemTime( (FILETIME*)&ElapsedTime, &st );
  2395. printf("\nTotalWritten = %I64u time = %02u:%02u:%02u.%02u\n",
  2396. TotalBytesWritten,
  2397. st.wHour,
  2398. st.wMinute,
  2399. st.wSecond,
  2400. st.wMilliseconds
  2401. );
  2402. }
  2403. #endif
  2404. //
  2405. // at this point, the disk should be full.
  2406. // If the disk is NTFS:
  2407. // 1. Fill the MFT.
  2408. // 2. Fill any free/reserved clusters.
  2409. //
  2410. dwTestError = SecureProcessMft( TempDirName, hTempFile );
  2411. // dwTestError = SecureProcessMft( PathName, hTempFile );
  2412. #ifdef TestOutPut
  2413. if (ERROR_SUCCESS != dwTestError) {
  2414. printf("\nWriting NTFS MFT & LOG. Error:");
  2415. DisplayErr(NULL, dwTestError);
  2416. }
  2417. #endif
  2418. dwTestError = SecureProcessFreeClusters( PathName, hTempFile );
  2419. #ifdef TestOutPut
  2420. if (ERROR_SUCCESS != dwTestError) {
  2421. printf("\nWriting NTFS reserved clusters. Error:");
  2422. DisplayErr(NULL, dwTestError);
  2423. }
  2424. #endif
  2425. Cleanup:
  2426. if (hTempFile != INVALID_HANDLE_VALUE) {
  2427. //
  2428. // flush the buffers. Likely has no effect if we used FILE_FLAG_NO_BUFFERING
  2429. //
  2430. //Sleep(INFINITE);
  2431. FlushFileBuffers( hTempFile );
  2432. CloseHandle( hTempFile );
  2433. }
  2434. if (DirCreated && TempDirName) {
  2435. RemoveDirectory(TempDirName);
  2436. }
  2437. if( PathName != NULL ){
  2438. free(PathName);
  2439. }
  2440. if ( TempDirName != NULL ) {
  2441. free(TempDirName);
  2442. }
  2443. return dwLastError;
  2444. }
  2445. BOOL CheckMinVersion ()
  2446. {
  2447. OSVERSIONINFOEX osvi;
  2448. DWORDLONG dwlConditionMask = 0;
  2449. BOOL GoodVersion;
  2450. // Initialize the OSVERSIONINFOEX structure.
  2451. ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
  2452. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  2453. osvi.dwMajorVersion = 5;
  2454. osvi.dwMinorVersion = 0;
  2455. osvi.wServicePackMajor = 3;
  2456. // Initialize the condition mask.
  2457. VER_SET_CONDITION( dwlConditionMask, VER_MAJORVERSION,
  2458. VER_GREATER_EQUAL );
  2459. VER_SET_CONDITION( dwlConditionMask, VER_MINORVERSION,
  2460. VER_GREATER_EQUAL );
  2461. VER_SET_CONDITION( dwlConditionMask, VER_SERVICEPACKMAJOR,
  2462. VER_GREATER_EQUAL );
  2463. // Perform the test.
  2464. GoodVersion = VerifyVersionInfo(
  2465. &osvi,
  2466. VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR,
  2467. dwlConditionMask
  2468. );
  2469. //
  2470. // Check HotFix here
  2471. //
  2472. // if (!GoodVersion) {
  2473. // GoodVersion = WeHaveTheHotFixVersion();
  2474. // }
  2475. //
  2476. return GoodVersion;
  2477. }
  2478. VOID
  2479. __cdecl
  2480. main()
  2481. {
  2482. PTCHAR *argv;
  2483. ULONG argc;
  2484. ULONG i;
  2485. PACTION_ROUTINE ActionRoutine = NULL;
  2486. PFINAL_ACTION_ROUTINE FinalActionRoutine = NULL;
  2487. TCHAR DirectorySpec[MAX_PATH];
  2488. TCHAR FileSpec[MAX_PATH];
  2489. PTCHAR p;
  2490. BOOL b;
  2491. InitializeIoStreams();
  2492. argv = CommandLineToArgvW(GetCommandLine(), &argc);
  2493. if (NULL == argv) {
  2494. DisplayErr(NULL, GetLastError());
  2495. return;
  2496. }
  2497. //
  2498. // Scan through the arguments looking for switches
  2499. //
  2500. for (i = 1; i < argc; i += 1) {
  2501. if (argv[i][0] == '/') {
  2502. if (0 == lstricmp(argv[i], TEXT("/e"))) {
  2503. if (ActionRoutine != NULL && ActionRoutine != DoEncryptAction) {
  2504. DisplayMsg(CIPHER_USAGE, NULL);
  2505. return;
  2506. }
  2507. ActionRoutine = DoEncryptAction;
  2508. FinalActionRoutine = DoFinalEncryptAction;
  2509. } else if (0 == lstricmp(argv[i], TEXT("/d"))) {
  2510. if (ActionRoutine != NULL && ActionRoutine != DoListAction) {
  2511. DisplayMsg(CIPHER_USAGE, NULL);
  2512. return;
  2513. }
  2514. ActionRoutine = DoDecryptAction;
  2515. FinalActionRoutine = DoFinalDecryptAction;
  2516. } else if (0 == lstricmp(argv[i], TEXT("/a"))){
  2517. DoFiles = TRUE;
  2518. } else if (0 == lstricmp(argv[i], TEXT("/q"))) {
  2519. Quiet = TRUE;
  2520. } else if (0 == lstricmp(argv[i], TEXT("/k"))){
  2521. SetUpNewUserKey = TRUE;
  2522. } else if (0 == lstricmp(argv[i], TEXT("/u"))){
  2523. RefreshUserKeyOnFiles = TRUE;
  2524. } else if (0 == lstricmp(argv[i], TEXT("/n"))){
  2525. DisplayFilesOnly = TRUE;
  2526. } else if (0 == lstricmp(argv[i], TEXT("/h"))){
  2527. DisplayAllFiles = TRUE;
  2528. } else if (0 == lstrnicmp(argv[i], TEXT("/s"), 2)) {
  2529. PTCHAR pch;
  2530. DoSubdirectories = TRUE;
  2531. pch = lstrchr(argv[i], ':');
  2532. if (NULL != pch) {
  2533. lstrcpy(StartingDirectory, pch + 1);
  2534. } else {
  2535. //
  2536. // We require an explicit directory to be passed.
  2537. //
  2538. DisplayMsg(CIPHER_USAGE, NULL);
  2539. return;
  2540. }
  2541. } else if (0 == lstricmp(argv[i], TEXT("/i"))) {
  2542. IgnoreErrors = TRUE;
  2543. } else if (0 == lstricmp(argv[i], TEXT("/f"))) {
  2544. ForceOperation = TRUE;
  2545. } else if (0 == lstrnicmp(argv[i], TEXT("/r"), 2)){
  2546. PTCHAR pch;
  2547. GenerateDRA = TRUE;
  2548. pch = lstrchr(argv[i], ':');
  2549. if (NULL != pch) {
  2550. lstrcpy(StartingDirectory, pch + 1);
  2551. } else {
  2552. //
  2553. // We require an explicit file to be passed.
  2554. //
  2555. DisplayMsg(CIPHER_USAGE, NULL);
  2556. return;
  2557. }
  2558. } else if (0 == lstrnicmp(argv[i], TEXT("/w"), 2)){
  2559. PTCHAR pch;
  2560. FillUnusedSpace = TRUE;
  2561. pch = lstrchr(argv[i], ':');
  2562. if (NULL != pch) {
  2563. lstrcpy(StartingDirectory, pch + 1);
  2564. } else {
  2565. //
  2566. // We require an explicit directory to be passed.
  2567. //
  2568. DisplayMsg(CIPHER_USAGE, NULL);
  2569. return;
  2570. }
  2571. } else {
  2572. DisplayMsg(CIPHER_USAGE, NULL);
  2573. return;
  2574. }
  2575. } else {
  2576. UserSpecifiedFileSpec = TRUE;
  2577. }
  2578. }
  2579. if (SetUpNewUserKey) {
  2580. DWORD RetCode;
  2581. //
  2582. // Set up new user key here
  2583. //
  2584. RetCode = SetUserFileEncryptionKey(NULL);
  2585. if ( ERROR_SUCCESS != RetCode ) {
  2586. //
  2587. // Display error info.
  2588. //
  2589. DisplayErr(NULL, GetLastError());
  2590. } else {
  2591. //
  2592. // Get the new hash and display it.
  2593. //
  2594. CipherDisplayCrntEfsHash();
  2595. }
  2596. //
  2597. // Create user key should not be used with other options.
  2598. // We will ignore other options if user do.
  2599. //
  2600. return;
  2601. }
  2602. if (RefreshUserKeyOnFiles) {
  2603. DWORD RetCode;
  2604. RetCode = CipherTouchEncryptedFiles();
  2605. if (RetCode != ERROR_SUCCESS) {
  2606. DisplayErr(NULL, RetCode);
  2607. }
  2608. return;
  2609. }
  2610. if (GenerateDRA) {
  2611. DWORD RetCode;
  2612. RetCode = GenerateCertFiles(StartingDirectory);
  2613. return;
  2614. }
  2615. if (FillUnusedSpace) {
  2616. BYTE FillByte[2] = { 0x00, 0xFF };
  2617. DWORD WriteValue[3] = {CIPHER_WRITE_ZERO, CIPHER_WRITE_FF, CIPHER_WRITE_RANDOM};
  2618. PBYTE pFillByte[3] = {&FillByte[0], &FillByte[1], NULL};
  2619. LPWSTR WriteChars;
  2620. DWORD RetCode;
  2621. if (!CheckMinVersion()) {
  2622. DisplayErr(NULL, ERROR_OLD_WIN_VERSION);
  2623. return;
  2624. }
  2625. //
  2626. // We are going to erase the disks
  2627. //
  2628. DisplayMsg(CIPHER_WIPE_WARNING, NULL);
  2629. for (i = 0; i < 3; i++) {
  2630. RetCode = SecureInitializeRandomFill( &GlobalSecureFill, 4096 * 128, pFillByte[i] );
  2631. if (RetCode != ERROR_SUCCESS) {
  2632. SecureDeleteRandomFill(&GlobalSecureFill);
  2633. break;
  2634. }
  2635. if ( ERROR_SUCCESS == GetResourceString(&WriteChars, WriteValue[i])){
  2636. //LoadStringW(0, WriteValue[i], WriteChars, sizeof(WriteChars)/sizeof(WCHAR));
  2637. DisplayMsg(CIPHER_WIPE_PROGRESS, WriteChars);
  2638. LocalFree(WriteChars);
  2639. }
  2640. RetCode = SecureDeleteFreeSpace(StartingDirectory);
  2641. printf("\n");
  2642. SecureDeleteRandomFill( &GlobalSecureFill );
  2643. if (RetCode != ERROR_SUCCESS) {
  2644. break;
  2645. }
  2646. }
  2647. if (RetCode != ERROR_SUCCESS) {
  2648. DisplayErr(NULL, RetCode);
  2649. }
  2650. return;
  2651. }
  2652. //
  2653. // If the use didn't specify an action then set the default to do a listing
  2654. //
  2655. if (ActionRoutine == NULL) {
  2656. ActionRoutine = DoListAction;
  2657. FinalActionRoutine = DoFinalListAction;
  2658. }
  2659. //
  2660. // If the user didn't specify a file spec then we'll do just "*"
  2661. //
  2662. if (!UserSpecifiedFileSpec) {
  2663. //
  2664. // Get our current directory because the action routines might move us
  2665. // around
  2666. //
  2667. if (DoSubdirectories) {
  2668. if (ActionRoutine != DoListAction) {
  2669. (VOID)(ActionRoutine)( StartingDirectory, TEXT("") );
  2670. }
  2671. if (!SetCurrentDirectory( StartingDirectory )) {
  2672. DisplayErr(StartingDirectory, GetLastError());
  2673. return;
  2674. }
  2675. } else {
  2676. GetCurrentDirectory( MAX_PATH, StartingDirectory );
  2677. }
  2678. (VOID)GetFullPathName( TEXT("*"), MAX_PATH, DirectorySpec, &p );
  2679. lstrcpy( FileSpec, p ); *p = '\0';
  2680. (VOID)(ActionRoutine)( DirectorySpec, FileSpec );
  2681. } else {
  2682. //
  2683. // Get our current directory because the action routines might move us
  2684. // around
  2685. //
  2686. if (!DoSubdirectories) {
  2687. GetCurrentDirectory( MAX_PATH, StartingDirectory );
  2688. } else if (!SetCurrentDirectory( StartingDirectory )) {
  2689. DisplayErr(StartingDirectory, GetLastError());
  2690. return;
  2691. }
  2692. //
  2693. // Now scan the arguments again looking for non-switches
  2694. // and this time do the action, but before calling reset
  2695. // the current directory so that things work again
  2696. //
  2697. for (i = 1; i < argc; i += 1) {
  2698. if (argv[i][0] != '/') {
  2699. SetCurrentDirectory( StartingDirectory );
  2700. //
  2701. // Handle a command with "." as the file argument specially,
  2702. // since it doesn't make good sense and the results without
  2703. // this code are surprising.
  2704. //
  2705. if ('.' == argv[i][0] && '\0' == argv[i][1]) {
  2706. argv[i] = TEXT("*");
  2707. GetFullPathName(argv[i], MAX_PATH, DirectorySpec, &p);
  2708. *p = '\0';
  2709. p = NULL;
  2710. } else {
  2711. PWCHAR pwch;
  2712. DWORD PathLen;
  2713. //
  2714. // We need to deal with path longer than MAX_PATH later.
  2715. // This code is based on Compact. They have the same problem
  2716. // as we do. So far, we have not heard any one complaining about this.
  2717. // Let's track this in the RAID.
  2718. //
  2719. PathLen = GetFullPathName(argv[i], MAX_PATH, DirectorySpec, &p);
  2720. if ( 0 == PathLen ){
  2721. DisplayMsg(CIPHER_INVALID_PARAMETER, argv[i]);
  2722. break;
  2723. }
  2724. //
  2725. // We want to treat "foobie:xxx" as an invalid drive name,
  2726. // rather than as a name identifying a stream. If there's
  2727. // a colon, there should be only a single character before
  2728. // it.
  2729. //
  2730. pwch = wcschr(argv[i], ':');
  2731. if (NULL != pwch && pwch - argv[i] != 1) {
  2732. DisplayMsg(CIPHER_INVALID_PATH, argv[i]);
  2733. break;
  2734. }
  2735. //
  2736. // GetFullPathName strips trailing dots, but we want
  2737. // to save them so that "*." will work correctly.
  2738. //
  2739. if ('.' == argv[i][lstrlen(argv[i]) - 1]) {
  2740. lstrcat(DirectorySpec, TEXT("."));
  2741. }
  2742. }
  2743. if (p != NULL) {
  2744. lstrcpy( FileSpec, p ); *p = '\0';
  2745. } else {
  2746. FileSpec[0] = '\0';
  2747. }
  2748. if (!(ActionRoutine)( DirectorySpec, FileSpec ) &&
  2749. !IgnoreErrors) {
  2750. break;
  2751. }
  2752. }
  2753. }
  2754. }
  2755. //
  2756. // Reset our current directory back
  2757. //
  2758. SetCurrentDirectory( StartingDirectory );
  2759. //
  2760. // And do the final action routine that will print out the final
  2761. // statistics of what we've done
  2762. //
  2763. (FinalActionRoutine)();
  2764. }