Leaked source code of windows server 2003
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.

1568 lines
39 KiB

  1. /*++
  2. Copyright (c) 1993, 1998 Microsoft Corporation
  3. Module Name:
  4. randlib.c
  5. Abstract:
  6. This module implements the core cryptographic random number generator
  7. for use by system components.
  8. The #define KMODE_RNG affects whether the file is built in a way
  9. suitable for kernel mode usage. if KMODE_RNG is not defined, the file
  10. is built in a way suitable for user mode usage.
  11. Author:
  12. Scott Field (sfield) 27-Nov-96
  13. Jeff Spelman (jeffspel) 14-Oct-96
  14. --*/
  15. #ifndef KMODE_RNG
  16. #include <nt.h>
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h>
  20. #else
  21. #include <ntosp.h>
  22. #include <windef.h>
  23. #ifdef USE_HW_RNG
  24. #ifdef _M_IX86
  25. #include <io.h>
  26. #include "deftypes.h" //ISD typedefs and constants
  27. #include "ioctldef.h" //ISD ioctl definitions
  28. #endif // _M_IX86
  29. #endif // USE_HW_RNG
  30. #endif // KMODE_RNG
  31. #include <zwapi.h>
  32. #include <winioctl.h>
  33. #include <lmcons.h>
  34. #include <rc4.h>
  35. #include <sha.h>
  36. #include <md4.h>
  37. #include <ntddksec.h> // IOCTL_
  38. #include <randlib.h>
  39. #include "vlhash.h"
  40. #include "circhash.h"
  41. #include "cpu.h"
  42. #include "seed.h"
  43. #ifdef KMODE_RNG
  44. //#include <ntos.h>
  45. #ifdef USE_HW_RNG
  46. #ifdef _M_IX86
  47. static DWORD g_dwHWDriver = 0;
  48. static PFILE_OBJECT g_pFileObject = NULL;
  49. static PDEVICE_OBJECT g_pDeviceObject = NULL;
  50. #endif // _M_IX86
  51. #endif // USE_HW_RNG
  52. #endif // KMODE_RNG
  53. #include "umkm.h"
  54. //
  55. // note: RAND_CTXT_LEN dictates the maximum input quantity for re-seed entropy
  56. // is. We make this fairly large, so that we can take all the entropy generated
  57. // during the GatherRandomBits(). Since the lifetime of the RandContext structure
  58. // is very short, and it lives on the stack, this larger than necessary size
  59. // is ok. The last few items processed during GatherRandomBits() are of
  60. // variable size, up to a maximum of of UNLEN for the username.
  61. //
  62. #define RAND_CTXT_LEN (256)
  63. #define RC4_REKEY_PARAM_NT (16384) // rekey less often on NT
  64. #ifndef KMODE_RNG
  65. #define RC4_REKEY_PARAM_DEFAULT (512) // rekey every 512 bytes by default
  66. #else
  67. #define RC4_REKEY_PARAM_DEFAULT RC4_REKEY_PARAM_NT
  68. #endif
  69. static unsigned int g_dwRC4RekeyParam = RC4_REKEY_PARAM_DEFAULT;
  70. static CircularHash g_CircularHashCtx;
  71. #ifndef WINNT_RNG
  72. static BYTE g_VeryLargeHash[A_SHA_DIGEST_LEN*4];
  73. #endif
  74. static void * g_RC4SafeCtx;
  75. #ifndef KMODE_RNG
  76. typedef NTSYSAPI NTSTATUS (NTAPI *NTQUERYSYSTEMINFORMATION) (
  77. IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
  78. OUT PVOID SystemInformation,
  79. IN ULONG SystemInformationLength,
  80. OUT PULONG ReturnLength OPTIONAL
  81. );
  82. typedef NTSYSAPI NTSTATUS (NTAPI *NTOPENFILE) (
  83. OUT PHANDLE FileHandle,
  84. IN ACCESS_MASK DesiredAccess,
  85. IN POBJECT_ATTRIBUTES ObjectAttributes,
  86. OUT PIO_STATUS_BLOCK IoStatusBlock,
  87. IN ULONG ShareAccess,
  88. IN ULONG OpenOptions
  89. );
  90. typedef NTSYSAPI VOID (NTAPI *RTLINITUNICODESTRING) (
  91. PUNICODE_STRING DestinationString,
  92. PCWSTR SourceString
  93. );
  94. typedef BOOL (WINAPI *GETCURSORPOS)(
  95. LPPOINT lpPoint
  96. );
  97. typedef LONG (WINAPI *GETMESSAGETIME)(
  98. VOID
  99. );
  100. GETCURSORPOS ___GetCursorPosRNG = NULL;
  101. GETMESSAGETIME ___GetMessageTimeRNG = NULL;
  102. #define _GetCursorPos ___GetCursorPosRNG
  103. #define _GetMessageTime ___GetMessageTimeRNG
  104. #ifndef WINNT_RNG
  105. NTQUERYSYSTEMINFORMATION ___NtQuerySystemInformationRNG = NULL;
  106. NTOPENFILE ___NtOpenFileRNG = NULL;
  107. RTLINITUNICODESTRING ___RtlInitUnicodeStringRNG = NULL;
  108. #define _NtQuerySystemInformation ___NtQuerySystemInformationRNG
  109. #define _NtOpenFile ___NtOpenFileRNG
  110. #define _RtlInitUnicodeString ___RtlInitUnicodeStringRNG
  111. #else
  112. #define _NtQuerySystemInformation NtQuerySystemInformation
  113. #define _NtOpenFile NtOpenFile
  114. #define _RtlInitUnicodeString RtlInitUnicodeString
  115. #endif
  116. #ifndef WINNT_RNG
  117. HANDLE g_hKsecDD = NULL;
  118. #else
  119. extern HANDLE g_hKsecDD;
  120. #endif
  121. #else
  122. #define _NtQuerySystemInformation ZwQuerySystemInformation
  123. #endif // !KMODE_RNG
  124. /// TODO: cache hKeySeed later.
  125. ///extern HKEY g_hKeySeed;
  126. //
  127. // private function prototypes.
  128. //
  129. BOOL
  130. GenRandom (
  131. IN PVOID hUID,
  132. OUT BYTE *pbBuffer,
  133. IN size_t dwLength
  134. );
  135. BOOL
  136. RandomFillBuffer(
  137. OUT BYTE *pbBuffer,
  138. IN DWORD *pdwLength
  139. );
  140. BOOL
  141. GatherRandomKey(
  142. IN BYTE *pbUserSeed,
  143. IN DWORD cbUserSeed,
  144. IN OUT BYTE *pbRandomKey,
  145. IN OUT DWORD *pcbRandomKey
  146. );
  147. BOOL
  148. GatherRandomKeyFastUserMode(
  149. IN BYTE *pbUserSeed,
  150. IN DWORD cbUserSeed,
  151. IN OUT BYTE *pbRandomKey,
  152. IN OUT DWORD *pcbRandomKey
  153. );
  154. BOOL
  155. IsRNGWinNT(
  156. VOID
  157. );
  158. #ifdef _M_IX86
  159. unsigned int
  160. QueryForHWRandomBits(
  161. IN DWORD *pdwRandom,
  162. IN OUT DWORD cdwRandom
  163. );
  164. #endif //_M_IX86
  165. #ifdef KMODE_RNG
  166. #ifdef ALLOC_PRAGMA
  167. #pragma alloc_text(PAGE, NewGenRandom)
  168. #pragma alloc_text(PAGE, NewGenRandomEx)
  169. #pragma alloc_text(PAGE, GenRandom)
  170. #pragma alloc_text(PAGE, RandomFillBuffer)
  171. #pragma alloc_text(PAGE, InitializeRNG)
  172. #pragma alloc_text(PAGE, ShutdownRNG)
  173. #ifdef _M_IX86
  174. #pragma alloc_text(PAGE, QueryForHWRandomBits)
  175. #endif //_M_IX86
  176. #pragma alloc_text(PAGE, GatherRandomKey)
  177. #endif // ALLOC_PRAGMA
  178. #endif // KMODE_RNG
  179. /************************************************************************/
  180. /* NewGenRandom generates a specified number of random bytes and places */
  181. /* them into the specified buffer. */
  182. /************************************************************************/
  183. /* */
  184. /* Pseudocode logic flow: */
  185. /* */
  186. /* if (bits streamed >= threshold) */
  187. /* { */
  188. /* Gather_Bits() */
  189. /* SHAMix_Bits(User, Gathered, Static -> Static) */
  190. /* RC4Key(Static -> newRC4Key) */
  191. /* SaveToRegistry(Static) */
  192. /* } */
  193. /* else */
  194. /* { */
  195. /* Mix_Bits(User, Static -> Static) */
  196. /* } */
  197. /* */
  198. /* RC4(newRC4Key -> outbuf) */
  199. /* bits streamed += sizeof(outbuf) */
  200. /* */
  201. /************************************************************************/
  202. unsigned int
  203. RSA32API
  204. NewGenRandomEx(
  205. IN RNG_CONTEXT *pRNGContext,
  206. IN OUT unsigned char *pbRandBuffer,
  207. IN unsigned long cbRandBuffer
  208. )
  209. {
  210. unsigned char **ppbRandSeed;
  211. unsigned long *pcbRandSeed;
  212. unsigned int fRet;
  213. #ifdef KMODE_RNG
  214. PAGED_CODE();
  215. #endif // KMODE_RNG
  216. fRet = TRUE;
  217. if( pRNGContext->cbSize != sizeof( RNG_CONTEXT ) )
  218. return FALSE;
  219. if( pRNGContext->pbRandSeed && pRNGContext->cbRandSeed ) {
  220. ppbRandSeed = &pRNGContext->pbRandSeed;
  221. pcbRandSeed = &pRNGContext->cbRandSeed;
  222. } else {
  223. ppbRandSeed = NULL;
  224. pcbRandSeed = NULL;
  225. }
  226. if(!InitializeRNG( NULL ))
  227. {
  228. return FALSE;
  229. }
  230. InitRand( ppbRandSeed, pcbRandSeed );
  231. if( pRNGContext->Flags & RNG_FLAG_REKEY_ONLY ) {
  232. //
  233. // caller wants REKEY only.
  234. //
  235. fRet = GatherRandomKey( NULL, 0, pbRandBuffer, &cbRandBuffer );
  236. } else {
  237. //
  238. // standard RNG request.
  239. //
  240. fRet = GenRandom(0, pbRandBuffer, cbRandBuffer);
  241. }
  242. if( ppbRandSeed && pcbRandSeed ) {
  243. DeInitRand( *ppbRandSeed, *pcbRandSeed);
  244. }
  245. return fRet;
  246. }
  247. unsigned int
  248. RSA32API
  249. NewGenRandom (
  250. IN OUT unsigned char **ppbRandSeed,
  251. IN unsigned long *pcbRandSeed,
  252. IN OUT unsigned char *pbBuffer,
  253. IN unsigned long dwLength
  254. )
  255. {
  256. RNG_CONTEXT RNGContext;
  257. #ifdef KMODE_RNG
  258. PAGED_CODE();
  259. #endif // KMODE_RNG
  260. RtlZeroMemory( &RNGContext, sizeof(RNGContext) );
  261. RNGContext.cbSize = sizeof(RNGContext);
  262. if( ppbRandSeed && pcbRandSeed ) {
  263. BOOL fRet;
  264. RNGContext.pbRandSeed = *ppbRandSeed;
  265. RNGContext.cbRandSeed = *pcbRandSeed;
  266. fRet = NewGenRandomEx( &RNGContext, pbBuffer, dwLength );
  267. *pcbRandSeed = RNGContext.cbRandSeed;
  268. return fRet;
  269. }
  270. return NewGenRandomEx( &RNGContext, pbBuffer, dwLength );
  271. }
  272. unsigned int
  273. RSA32API
  274. InitRand(
  275. IN OUT unsigned char **ppbRandSeed,
  276. IN unsigned long *pcbRandSeed
  277. )
  278. {
  279. static BOOL fInitialized = FALSE;
  280. #ifdef KMODE_RNG
  281. PAGED_CODE();
  282. #endif // KMODE_RNG
  283. if( !fInitialized ) {
  284. InitCircularHash(
  285. &g_CircularHashCtx,
  286. 7,
  287. CH_ALG_MD4,
  288. 0 // CH_MODE_FEEDBACK
  289. );
  290. #ifndef WINNT_RNG
  291. //
  292. // get prior seed.
  293. //
  294. ReadSeed( g_VeryLargeHash, sizeof( g_VeryLargeHash ) );
  295. #endif
  296. fInitialized = TRUE;
  297. }
  298. if( ppbRandSeed != NULL && pcbRandSeed != NULL && *pcbRandSeed != 0 )
  299. UpdateCircularHash( &g_CircularHashCtx, *ppbRandSeed, *pcbRandSeed );
  300. return TRUE;
  301. }
  302. unsigned int
  303. RSA32API
  304. DeInitRand(
  305. IN OUT unsigned char *pbRandSeed,
  306. IN unsigned long cbRandSeed
  307. )
  308. {
  309. PBYTE pbCircularHash;
  310. DWORD cbCircularHash;
  311. #ifdef KMODE_RNG
  312. PAGED_CODE();
  313. #endif // KMODE_RNG
  314. if( pbRandSeed == NULL || cbRandSeed == 0 )
  315. return TRUE;
  316. if(GetCircularHashValue( &g_CircularHashCtx, &pbCircularHash, &cbCircularHash )) {
  317. unsigned long cbToCopy;
  318. if( cbRandSeed > cbCircularHash ) {
  319. cbToCopy = cbCircularHash;
  320. } else {
  321. cbToCopy = cbRandSeed;
  322. }
  323. memcpy(pbRandSeed, pbCircularHash, cbToCopy);
  324. }
  325. return TRUE;
  326. }
  327. unsigned int
  328. RSA32API
  329. InitializeRNG(
  330. VOID *pvReserved
  331. )
  332. {
  333. void *pvCtx;
  334. void *pvOldCtx;
  335. #ifdef KMODE_RNG
  336. PAGED_CODE();
  337. #endif // KMODE_RNG
  338. if( g_RC4SafeCtx ) {
  339. return TRUE;
  340. }
  341. if(!rc4_safe_startup( &pvCtx )) {
  342. return FALSE;
  343. }
  344. pvOldCtx = INTERLOCKEDCOMPAREEXCHANGEPOINTER( &g_RC4SafeCtx, pvCtx, NULL );
  345. if( pvOldCtx ) {
  346. //
  347. // race condition occured during init.
  348. //
  349. rc4_safe_shutdown( pvCtx );
  350. }
  351. return TRUE;
  352. }
  353. void
  354. RSA32API
  355. ShutdownRNG(
  356. VOID *pvReserved
  357. )
  358. {
  359. void *pvCtx;
  360. #ifdef KMODE_RNG
  361. PAGED_CODE();
  362. #endif // KMODE_RNG
  363. pvCtx = InterlockedExchangePointer( &g_RC4SafeCtx, NULL );
  364. if( pvCtx ) {
  365. rc4_safe_shutdown( pvCtx );
  366. }
  367. #ifndef KMODE_RNG
  368. #ifndef WINNT_RNG
  369. {
  370. HANDLE hFile;
  371. hFile = InterlockedExchangePointer( &g_hKsecDD, NULL );
  372. if( hFile ) {
  373. CloseHandle( hFile );
  374. }
  375. }
  376. #endif
  377. #endif
  378. #if 0
  379. // TODO later: finish logic for caching registry key.
  380. hKey = InterlockedExchangePointer( &g_hKeySeed, NULL );
  381. if( hKey ) {
  382. REGCLOSEKEY( hKey );
  383. }
  384. #endif
  385. }
  386. BOOL
  387. GenRandom (
  388. IN PVOID hUID,
  389. OUT BYTE *pbBuffer,
  390. IN size_t dwLength
  391. )
  392. {
  393. DWORD dwBytesThisPass;
  394. DWORD dwFilledBytes;
  395. #ifdef KMODE_RNG
  396. PAGED_CODE();
  397. #endif // KMODE_RNG
  398. dwFilledBytes = 0;
  399. // break request into chunks that we rekey between
  400. while(dwFilledBytes < dwLength)
  401. {
  402. dwBytesThisPass = dwLength - dwFilledBytes;
  403. if(!RandomFillBuffer(
  404. pbBuffer + dwFilledBytes,
  405. &dwBytesThisPass
  406. )) {
  407. return FALSE;
  408. }
  409. dwFilledBytes += dwBytesThisPass;
  410. }
  411. return TRUE;
  412. }
  413. BOOL
  414. RandomFillBuffer(
  415. OUT BYTE *pbBuffer,
  416. IN DWORD *pdwLength
  417. )
  418. {
  419. unsigned int RC4BytesUsed;
  420. unsigned int KeyId;
  421. #ifdef KMODE_RNG
  422. PAGED_CODE();
  423. #endif // KMODE_RNG
  424. //
  425. // update circular hash with user supplied bits.
  426. //
  427. if(!UpdateCircularHash( &g_CircularHashCtx, pbBuffer, *pdwLength ))
  428. return FALSE;
  429. //
  430. // select key.
  431. //
  432. rc4_safe_select( g_RC4SafeCtx, &KeyId, &RC4BytesUsed );
  433. //
  434. // check if re-key required.
  435. //
  436. if ( RC4BytesUsed >= g_dwRC4RekeyParam )
  437. {
  438. PBYTE pbCircularHash;
  439. DWORD cbCircularHash;
  440. BYTE pbRandomKey[ 256 ];
  441. DWORD cbRandomKey = sizeof(pbRandomKey);
  442. RC4BytesUsed = g_dwRC4RekeyParam;
  443. if(!GetCircularHashValue(
  444. &g_CircularHashCtx,
  445. &pbCircularHash,
  446. &cbCircularHash
  447. )) {
  448. return FALSE;
  449. }
  450. if(!GatherRandomKey( pbCircularHash, cbCircularHash, pbRandomKey, &cbRandomKey ))
  451. return FALSE;
  452. //
  453. // Create RC4 key
  454. //
  455. rc4_safe_key(
  456. g_RC4SafeCtx,
  457. KeyId,
  458. cbRandomKey,
  459. pbRandomKey
  460. );
  461. RtlZeroMemory( pbRandomKey, sizeof(pbRandomKey) );
  462. }
  463. //
  464. // only use RC4_REKEY_PARAM bytes from each RC4 key
  465. //
  466. {
  467. DWORD dwMaxPossibleBytes = g_dwRC4RekeyParam - RC4BytesUsed;
  468. if (*pdwLength > dwMaxPossibleBytes)
  469. *pdwLength = dwMaxPossibleBytes;
  470. }
  471. rc4_safe( g_RC4SafeCtx, KeyId, *pdwLength, pbBuffer );
  472. return TRUE;
  473. }
  474. #ifdef KMODE_RNG
  475. #ifdef USE_HW_RNG
  476. #ifdef _M_IX86
  477. #define NUM_HW_DWORDS_TO_GATHER 4
  478. #define INTEL_DRIVER_NAME L"\\Device\\ISECDRV"
  479. unsigned int
  480. QueryForHWRandomBits(
  481. IN DWORD *pdwRandom,
  482. IN OUT DWORD cdwRandom
  483. )
  484. {
  485. UNICODE_STRING ObjectName;
  486. IO_STATUS_BLOCK StatusBlock;
  487. KEVENT Event;
  488. PIRP pIrp = NULL;
  489. ISD_Capability ISD_Cap; //in/out for GetCapability
  490. ISD_RandomNumber ISD_Random; //in/out for GetRandomNumber
  491. PDEVICE_OBJECT pDeviceObject = NULL;
  492. DWORD i = 0;
  493. unsigned int Status = ERROR_SUCCESS;
  494. PAGED_CODE();
  495. if (1 == g_dwHWDriver)
  496. {
  497. Status = STATUS_ACCESS_DENIED;
  498. goto Ret;
  499. }
  500. RtlZeroMemory( &ObjectName, sizeof(ObjectName) );
  501. RtlZeroMemory( &StatusBlock, sizeof(StatusBlock) );
  502. RtlZeroMemory(&ISD_Cap, sizeof(ISD_Cap));
  503. if (NULL == g_pDeviceObject)
  504. {
  505. ObjectName.Length = sizeof(INTEL_DRIVER_NAME) - sizeof(WCHAR);
  506. ObjectName.MaximumLength = sizeof(INTEL_DRIVER_NAME);
  507. ObjectName.Buffer = INTEL_DRIVER_NAME;
  508. Status = IoGetDeviceObjectPointer(&ObjectName,
  509. FILE_ALL_ACCESS,
  510. &g_pFileObject,
  511. &pDeviceObject);
  512. if ( !NT_SUCCESS(Status) )
  513. {
  514. g_dwHWDriver = 1;
  515. goto Ret;
  516. }
  517. if (NULL == g_pDeviceObject)
  518. {
  519. InterlockedExchangePointer(&g_pDeviceObject, pDeviceObject);
  520. }
  521. }
  522. //
  523. // If this fails then it is because there is no such device
  524. // which signals completion.
  525. //
  526. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  527. ISD_Cap.uiIndex = ISD_RNG_ENABLED; //Set input member
  528. pIrp = IoBuildDeviceIoControlRequest(
  529. IOCTL_ISD_GetCapability,
  530. g_pDeviceObject,
  531. &ISD_Cap,
  532. sizeof(ISD_Cap),
  533. &ISD_Cap,
  534. sizeof(ISD_Cap),
  535. FALSE,
  536. &Event,
  537. &StatusBlock);
  538. if (pIrp == NULL) {
  539. Status = STATUS_INSUFFICIENT_RESOURCES;
  540. goto Ret;
  541. }
  542. Status = IoCallDriver(g_pDeviceObject, pIrp);
  543. if (Status == STATUS_PENDING) {
  544. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  545. Status = StatusBlock.Status;
  546. }
  547. if (ISD_Cap.iStatus != ISD_EOK) {
  548. Status = STATUS_NOT_IMPLEMENTED;
  549. goto Ret;
  550. }
  551. // now get the random bits
  552. for (i = 0; i < cdwRandom; i++) {
  553. RtlZeroMemory(&ISD_Random, sizeof(ISD_Random));
  554. KeInitializeEvent(&Event, NotificationEvent, FALSE);
  555. pIrp = IoBuildDeviceIoControlRequest(
  556. IOCTL_ISD_GetRandomNumber,
  557. g_pDeviceObject,
  558. &ISD_Random,
  559. sizeof(ISD_Random),
  560. &ISD_Random,
  561. sizeof(ISD_Random),
  562. FALSE,
  563. &Event,
  564. &StatusBlock);
  565. if (pIrp == NULL) {
  566. Status = STATUS_INSUFFICIENT_RESOURCES;
  567. goto Ret;
  568. }
  569. Status = IoCallDriver(g_pDeviceObject, pIrp);
  570. if (Status == STATUS_PENDING) {
  571. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  572. Status = StatusBlock.Status;
  573. }
  574. if (ISD_Random.iStatus != ISD_EOK) {
  575. Status = STATUS_NOT_IMPLEMENTED;
  576. goto Ret;
  577. }
  578. pdwRandom[i] = pdwRandom[i] ^ ISD_Random.uiRandomNum;
  579. }
  580. Ret:
  581. return Status;
  582. }
  583. #endif // _M_IX86
  584. #endif // USE_HW_RNG
  585. #endif // KMODE_RNG
  586. BOOL
  587. GatherRandomKey(
  588. IN BYTE *pbUserSeed,
  589. IN DWORD cbUserSeed,
  590. IN OUT BYTE *pbRandomKey,
  591. IN OUT DWORD *pcbRandomKey
  592. )
  593. {
  594. LPBYTE pbWorkingBuffer = NULL;
  595. DWORD cbWorkingBuffer;
  596. DWORD cbBufferRemaining;
  597. BYTE *pbCurrentBuffer;
  598. DWORD *pdwTmp;
  599. BOOL fRet;
  600. #ifdef KMODE_RNG
  601. PAGED_CODE();
  602. #endif // KMODE_RNG
  603. //
  604. // in NT Usermode, try to re-seed by calling the Kernelmode RNG.
  605. //
  606. #ifndef KMODE_RNG
  607. #ifdef WINNT_RNG
  608. return GatherRandomKeyFastUserMode(
  609. pbUserSeed,
  610. cbUserSeed,
  611. pbRandomKey,
  612. pcbRandomKey
  613. );
  614. #else
  615. if(GatherRandomKeyFastUserMode(
  616. pbUserSeed,
  617. cbUserSeed,
  618. pbRandomKey,
  619. pcbRandomKey
  620. ))
  621. {
  622. return TRUE;
  623. }
  624. #endif
  625. #endif
  626. #ifndef WINNT_RNG
  627. //
  628. // verify current working buffer has space for candidate data.
  629. //
  630. #define VERIFY_BUFFER( size ) { \
  631. if( cbBufferRemaining < size ) \
  632. goto finished; \
  633. }
  634. //
  635. // update working buffer and increment to next QWORD aligned boundary.
  636. //
  637. #define UPDATE_BUFFER( size ) { \
  638. DWORD dwSizeRounded; \
  639. dwSizeRounded = (size + sizeof(ULONG64)) & ~(sizeof(ULONG64)-1); \
  640. if(dwSizeRounded > cbBufferRemaining) \
  641. goto finished; \
  642. pbCurrentBuffer += dwSizeRounded; \
  643. cbBufferRemaining -= dwSizeRounded; \
  644. }
  645. cbWorkingBuffer = 3584;
  646. pbWorkingBuffer = (PBYTE)ALLOC( cbWorkingBuffer );
  647. if( pbWorkingBuffer == NULL ) {
  648. return FALSE;
  649. }
  650. cbBufferRemaining = cbWorkingBuffer;
  651. pbCurrentBuffer = pbWorkingBuffer;
  652. //
  653. // pickup user supplied bits.
  654. //
  655. VERIFY_BUFFER( cbUserSeed );
  656. RtlCopyMemory( pbCurrentBuffer, pbUserSeed, cbUserSeed );
  657. UPDATE_BUFFER( cbUserSeed );
  658. //
  659. // ** indicates US DoD's specific recommendations for password generation
  660. //
  661. //
  662. // process id
  663. //
  664. #ifndef KMODE_RNG
  665. pdwTmp = (PDWORD)pbCurrentBuffer;
  666. *pdwTmp = GetCurrentProcessId();
  667. UPDATE_BUFFER( sizeof(DWORD) );
  668. #else
  669. {
  670. PHANDLE hTmp = (PHANDLE)pbCurrentBuffer;
  671. VERIFY_BUFFER( sizeof(HANDLE) );
  672. *hTmp = PsGetCurrentProcessId();
  673. UPDATE_BUFFER( sizeof(HANDLE) );
  674. }
  675. #endif
  676. //
  677. // thread id
  678. //
  679. #ifndef KMODE_RNG
  680. pdwTmp = (PDWORD)pbCurrentBuffer;
  681. *pdwTmp = GetCurrentThreadId();
  682. UPDATE_BUFFER( sizeof(DWORD) );
  683. #else
  684. {
  685. PHANDLE hTmp = (PHANDLE)pbCurrentBuffer;
  686. VERIFY_BUFFER( sizeof(HANDLE) );
  687. *hTmp = PsGetCurrentThreadId();
  688. UPDATE_BUFFER( sizeof(HANDLE) );
  689. }
  690. #endif
  691. //
  692. // ** ticks since boot (system clock)
  693. //
  694. #ifndef KMODE_RNG
  695. pdwTmp = (PDWORD)pbCurrentBuffer;
  696. *pdwTmp = GetTickCount();
  697. UPDATE_BUFFER( sizeof(DWORD) );
  698. #else
  699. {
  700. PLARGE_INTEGER Tick = (PLARGE_INTEGER)pbCurrentBuffer;
  701. VERIFY_BUFFER( sizeof(LARGE_INTEGER) );
  702. KeQueryTickCount( Tick );
  703. UPDATE_BUFFER( sizeof(LARGE_INTEGER) );
  704. }
  705. #endif // !KMODE_RNG
  706. //
  707. // ** system time, in ms, sec, min (date & time)
  708. //
  709. #ifndef KMODE_RNG
  710. {
  711. PSYSTEMTIME psysTime = (PSYSTEMTIME)pbCurrentBuffer;
  712. VERIFY_BUFFER( sizeof( *psysTime ) );
  713. GetLocalTime(psysTime);
  714. UPDATE_BUFFER( sizeof( *psysTime ) );
  715. }
  716. #else
  717. {
  718. PSYSTEM_TIMEOFDAY_INFORMATION pTimeOfDay;
  719. ULONG cbSystemInfo;
  720. pTimeOfDay = (PSYSTEM_TIMEOFDAY_INFORMATION)pbCurrentBuffer;
  721. VERIFY_BUFFER( sizeof(*pTimeOfDay) );
  722. _NtQuerySystemInformation(
  723. SystemTimeOfDayInformation,
  724. pTimeOfDay,
  725. sizeof(*pTimeOfDay),
  726. &cbSystemInfo
  727. );
  728. UPDATE_BUFFER( cbSystemInfo );
  729. }
  730. #endif // !KMODE_RNG
  731. //
  732. // ** hi-res performance counter (system counters)
  733. //
  734. {
  735. LARGE_INTEGER *pliPerfCount = (PLARGE_INTEGER)pbCurrentBuffer;
  736. VERIFY_BUFFER( sizeof(*pliPerfCount) );
  737. #ifndef KMODE_RNG
  738. QueryPerformanceCounter(pliPerfCount);
  739. #else
  740. /// ZwQueryPerformanceCounter(pliPerfCount, NULL);
  741. // Defined in zwapi.h, but not exported by ntoskrnl.exe ???
  742. #endif // !KMODE_RNG
  743. UPDATE_BUFFER( sizeof(*pliPerfCount) );
  744. }
  745. #ifndef KMODE_RNG
  746. //
  747. // memory status
  748. //
  749. {
  750. MEMORYSTATUS *pmstMemStat = (MEMORYSTATUS *)pbCurrentBuffer;
  751. VERIFY_BUFFER( sizeof(*pmstMemStat) );
  752. pmstMemStat->dwLength = sizeof(MEMORYSTATUS);
  753. GlobalMemoryStatus( pmstMemStat );
  754. UPDATE_BUFFER( sizeof(*pmstMemStat) );
  755. }
  756. #endif // !KMODE_RNG
  757. //
  758. // free disk clusters
  759. //
  760. #ifndef KMODE_RNG
  761. {
  762. PDWORD pdwDiskInfo = (PDWORD)pbCurrentBuffer;
  763. VERIFY_BUFFER( (sizeof(DWORD) * 4) );
  764. GetDiskFreeSpace(
  765. NULL,
  766. &pdwDiskInfo[0], // sectors per cluster
  767. &pdwDiskInfo[1], // bytes per sector
  768. &pdwDiskInfo[2], // number of free clusters
  769. &pdwDiskInfo[3] // total number of clusters
  770. );
  771. UPDATE_BUFFER( (sizeof(DWORD) * 4) );
  772. }
  773. #endif // !KMODE_RNG
  774. #ifndef KMODE_RNG
  775. {
  776. //
  777. // hash the entire user environment block.
  778. // we do this instead of GetUserName & GetComputerName,
  779. // as the environment block contains these values, plus additional
  780. // values.
  781. //
  782. static BOOL fHashedEnv;
  783. static BYTE HashEnv[ MD4_LEN ];
  784. if( !fHashedEnv ) {
  785. LPVOID lpEnvBlock;
  786. BOOL fAnsi = FALSE;
  787. //
  788. // try the Unicode version first, as, on WinNT, this returns us
  789. // a pointer to the existing Unicode environment block, rather
  790. // than an allocated copy. Fallback to ANSI if this fails (eg: Win9x)
  791. //
  792. lpEnvBlock = GetEnvironmentStringsW();
  793. if( lpEnvBlock == NULL )
  794. {
  795. lpEnvBlock = GetEnvironmentStringsA();
  796. fAnsi = TRUE;
  797. }
  798. if( lpEnvBlock != NULL ) {
  799. ULONG cbEntry;
  800. PBYTE pbEntry;
  801. MD4_CTX MD4Ctx;
  802. MD4Init( &MD4Ctx );
  803. pbEntry = (PBYTE)lpEnvBlock;
  804. cbEntry = 0;
  805. do {
  806. if( !fAnsi ) {
  807. pbEntry += (cbEntry + sizeof(WCHAR));
  808. cbEntry = lstrlenW( (LPWSTR)pbEntry ) * sizeof(WCHAR);
  809. } else {
  810. pbEntry += (cbEntry + sizeof(CHAR));
  811. cbEntry = lstrlenA( (LPSTR)pbEntry ) * sizeof(CHAR);
  812. }
  813. MD4Update(
  814. &MD4Ctx,
  815. (unsigned char *)pbEntry,
  816. (unsigned int)cbEntry
  817. );
  818. } while( cbEntry );
  819. MD4Final( &MD4Ctx );
  820. CopyMemory( HashEnv, MD4Ctx.digest, sizeof(HashEnv) );
  821. if( !fAnsi ) {
  822. FreeEnvironmentStringsW( lpEnvBlock );
  823. } else {
  824. FreeEnvironmentStringsA( lpEnvBlock );
  825. }
  826. }
  827. //
  828. // only try this once. if it failed once, it will likely never
  829. // succeed.
  830. //
  831. fHashedEnv = TRUE;
  832. }
  833. VERIFY_BUFFER( (sizeof(HashEnv)) );
  834. CopyMemory( pbCurrentBuffer, HashEnv, sizeof(HashEnv) );
  835. UPDATE_BUFFER( (sizeof(HashEnv)) );
  836. }
  837. #endif // !KMODE_RNG
  838. //
  839. // this code path has been moved to the end so that our CombineRand()
  840. // operation on NT mixes in with everything slammed into the
  841. // rand context buffer.
  842. //
  843. #ifndef KMODE_RNG
  844. if(!IsRNGWinNT()) {
  845. //
  846. // only user info if we are not running on NT.
  847. // this prevents deadlocks on WinNT when the RNG is called from CSRSS
  848. //
  849. POINT *ppoint;
  850. LONG *plTime;
  851. //
  852. // cursor position
  853. //
  854. ppoint = (POINT*)pbCurrentBuffer;
  855. VERIFY_BUFFER( sizeof(*ppoint) );
  856. _GetCursorPos(ppoint);
  857. UPDATE_BUFFER( sizeof(*ppoint) );
  858. //
  859. // last messages' timestamp
  860. //
  861. plTime = (LONG*)pbCurrentBuffer;
  862. VERIFY_BUFFER( sizeof(*plTime) );
  863. *plTime = _GetMessageTime();
  864. UPDATE_BUFFER( sizeof(*plTime) );
  865. } else
  866. #endif // !KMODE_RNG
  867. {
  868. unsigned char *pbCounterState = (unsigned char*)pbCurrentBuffer;
  869. unsigned long cbCounterState = 64;
  870. VERIFY_BUFFER(cbCounterState);
  871. if(GatherCPUSpecificCounters( pbCounterState, &cbCounterState )) {
  872. UPDATE_BUFFER( cbCounterState );
  873. }
  874. //
  875. // call NtQuerySystemInformation on NT if available.
  876. //
  877. if( (void*)_NtQuerySystemInformation ) {
  878. PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pSystemProcessorPerformanceInfo;
  879. PSYSTEM_PERFORMANCE_INFORMATION pSystemPerformanceInfo;
  880. PSYSTEM_EXCEPTION_INFORMATION pSystemExceptionInfo;
  881. PSYSTEM_LOOKASIDE_INFORMATION pSystemLookasideInfo;
  882. PSYSTEM_INTERRUPT_INFORMATION pSystemInterruptInfo;
  883. PSYSTEM_PROCESS_INFORMATION pSystemProcessInfo;
  884. ULONG cbSystemInfo;
  885. NTSTATUS Status;
  886. //
  887. // fixed length system info calls.
  888. //
  889. pSystemProcessorPerformanceInfo = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)pbCurrentBuffer;
  890. VERIFY_BUFFER( sizeof(*pSystemProcessorPerformanceInfo) );
  891. Status = _NtQuerySystemInformation(
  892. SystemProcessorPerformanceInformation,
  893. pSystemProcessorPerformanceInfo,
  894. sizeof(*pSystemProcessorPerformanceInfo),
  895. &cbSystemInfo
  896. );
  897. if ( NT_SUCCESS(Status) ) {
  898. UPDATE_BUFFER( cbSystemInfo );
  899. }
  900. pSystemPerformanceInfo = (PSYSTEM_PERFORMANCE_INFORMATION)pbCurrentBuffer;
  901. VERIFY_BUFFER( sizeof(*pSystemPerformanceInfo) );
  902. Status = _NtQuerySystemInformation(
  903. SystemPerformanceInformation,
  904. pSystemPerformanceInfo,
  905. sizeof(*pSystemPerformanceInfo),
  906. &cbSystemInfo
  907. );
  908. if ( NT_SUCCESS(Status) ) {
  909. UPDATE_BUFFER( cbSystemInfo );
  910. }
  911. pSystemExceptionInfo = (PSYSTEM_EXCEPTION_INFORMATION)pbCurrentBuffer;
  912. VERIFY_BUFFER( sizeof(*pSystemExceptionInfo) );
  913. Status = _NtQuerySystemInformation(
  914. SystemExceptionInformation,
  915. pSystemExceptionInfo,
  916. sizeof(*pSystemExceptionInfo),
  917. &cbSystemInfo
  918. );
  919. if ( NT_SUCCESS(Status) ) {
  920. UPDATE_BUFFER( cbSystemInfo );
  921. }
  922. pSystemLookasideInfo = (PSYSTEM_LOOKASIDE_INFORMATION)pbCurrentBuffer;
  923. VERIFY_BUFFER( sizeof(*pSystemLookasideInfo) );
  924. Status = _NtQuerySystemInformation(
  925. SystemLookasideInformation,
  926. pSystemLookasideInfo,
  927. sizeof(*pSystemLookasideInfo),
  928. &cbSystemInfo
  929. );
  930. if ( NT_SUCCESS(Status) ) {
  931. UPDATE_BUFFER( cbSystemInfo );
  932. }
  933. //
  934. // variable length system info calls.
  935. //
  936. pSystemInterruptInfo = (PSYSTEM_INTERRUPT_INFORMATION)pbCurrentBuffer;
  937. cbSystemInfo = cbBufferRemaining;
  938. Status = _NtQuerySystemInformation(
  939. SystemInterruptInformation,
  940. pSystemInterruptInfo,
  941. cbSystemInfo,
  942. &cbSystemInfo
  943. );
  944. if ( NT_SUCCESS(Status) ) {
  945. UPDATE_BUFFER( cbSystemInfo );
  946. }
  947. pSystemProcessInfo = (PSYSTEM_PROCESS_INFORMATION)pbCurrentBuffer;
  948. cbSystemInfo = cbBufferRemaining;
  949. Status = _NtQuerySystemInformation(
  950. SystemProcessInformation,
  951. pSystemProcessInfo,
  952. cbSystemInfo,
  953. &cbSystemInfo
  954. );
  955. if ( NT_SUCCESS(Status) ) {
  956. UPDATE_BUFFER( cbSystemInfo );
  957. }
  958. } // _NtQuerySystemInformation
  959. }
  960. #ifdef KMODE_RNG
  961. #ifdef USE_HW_RNG
  962. #ifdef _M_IX86
  963. // attempt to get bits from the INTEL HW RNG
  964. {
  965. DWORD rgdwHWRandom[NUM_HW_DWORDS_TO_GATHER];
  966. NTSTATUS Status;
  967. VERIFY_BUFFER( sizeof(rgdwHWRandom) );
  968. Status = QueryForHWRandomBits(
  969. rgdwHWRandom,
  970. NUM_HW_DWORDS_TO_GATHER
  971. );
  972. if ( NT_SUCCESS(Status) ) {
  973. UPDATE_BUFFER( sizeof(rgdwHWRandom) );
  974. }
  975. }
  976. #endif // _M_IX86
  977. #endif // USE_HW_RNG
  978. #endif // KMODE_RNG
  979. finished:
  980. {
  981. RC4_KEYSTRUCT rc4Key;
  982. BYTE NewSeed[ sizeof(g_VeryLargeHash) ];
  983. BYTE LocalHash[ sizeof( g_VeryLargeHash ) ];
  984. DWORD cbBufferSize;
  985. RtlCopyMemory( LocalHash, g_VeryLargeHash, sizeof(g_VeryLargeHash) );
  986. rc4_key( &rc4Key, sizeof(LocalHash), LocalHash );
  987. cbBufferSize = cbWorkingBuffer - cbBufferRemaining;
  988. if( cbBufferSize > cbWorkingBuffer )
  989. cbBufferSize = cbWorkingBuffer;
  990. fRet = VeryLargeHashUpdate(
  991. pbWorkingBuffer, // buffer to hash
  992. cbBufferSize,
  993. LocalHash
  994. );
  995. RtlCopyMemory( NewSeed, LocalHash, sizeof(LocalHash) );
  996. RtlCopyMemory( g_VeryLargeHash, LocalHash, sizeof(LocalHash) );
  997. rc4( &rc4Key, sizeof( NewSeed ), NewSeed );
  998. //
  999. // write seed out.
  1000. //
  1001. WriteSeed( NewSeed, sizeof(NewSeed) );
  1002. RtlZeroMemory( NewSeed, sizeof(NewSeed) );
  1003. rc4_key( &rc4Key, sizeof(LocalHash), LocalHash );
  1004. RtlZeroMemory( LocalHash, sizeof(LocalHash) );
  1005. rc4( &rc4Key, *pcbRandomKey, pbRandomKey );
  1006. RtlZeroMemory( &rc4Key, sizeof(rc4Key) );
  1007. if( pbWorkingBuffer ) {
  1008. FREE( pbWorkingBuffer );
  1009. }
  1010. }
  1011. return fRet;
  1012. #endif // WINNT_RNG
  1013. }
  1014. #ifndef KMODE_RNG
  1015. BOOL
  1016. GatherRandomKeyFastUserMode(
  1017. IN BYTE *pbUserSeed,
  1018. IN DWORD cbUserSeed,
  1019. IN OUT BYTE *pbRandomKey,
  1020. IN OUT DWORD *pcbRandomKey
  1021. )
  1022. /*++
  1023. This routine attempts to gather RNG re-seed material for usermode callers
  1024. from the Kernel mode version of the RNG. This is accomplished by making
  1025. a device IOCTL into the ksecdd.sys device driver.
  1026. --*/
  1027. {
  1028. HANDLE hFile;
  1029. NTSTATUS Status;
  1030. if(!IsRNGWinNT())
  1031. return FALSE;
  1032. hFile = g_hKsecDD;
  1033. if( hFile == NULL ) {
  1034. UNICODE_STRING DriverName;
  1035. OBJECT_ATTRIBUTES ObjA;
  1036. IO_STATUS_BLOCK IOSB;
  1037. HANDLE hPreviousValue;
  1038. //
  1039. // call via the ksecdd.sys device driver to get the random bits.
  1040. //
  1041. if( _NtOpenFile == NULL || _RtlInitUnicodeString == NULL ) {
  1042. return FALSE;
  1043. }
  1044. //
  1045. // have to use the Nt flavor of the file open call because it's a base
  1046. // device not aliased to \DosDevices
  1047. //
  1048. _RtlInitUnicodeString( &DriverName, DD_KSEC_DEVICE_NAME_U );
  1049. InitializeObjectAttributes(
  1050. &ObjA,
  1051. &DriverName,
  1052. OBJ_CASE_INSENSITIVE,
  1053. 0,
  1054. 0
  1055. );
  1056. //
  1057. // needs to be non-alertable, else, the DeviceIoControl may return
  1058. // STATUS_USER_APC.
  1059. //
  1060. Status = _NtOpenFile(
  1061. &hFile,
  1062. SYNCHRONIZE | FILE_READ_DATA,
  1063. &ObjA,
  1064. &IOSB,
  1065. FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
  1066. FILE_SYNCHRONOUS_IO_NONALERT
  1067. );
  1068. if( !NT_SUCCESS(Status) )
  1069. return FALSE;
  1070. hPreviousValue = INTERLOCKEDCOMPAREEXCHANGEPOINTER(
  1071. &g_hKsecDD,
  1072. hFile,
  1073. NULL
  1074. );
  1075. if( hPreviousValue != NULL ) {
  1076. //
  1077. // race condition, set current value to previously initialized version.
  1078. //
  1079. CloseHandle( hFile );
  1080. hFile = hPreviousValue;
  1081. }
  1082. }
  1083. return DeviceIoControl(
  1084. hFile,
  1085. IOCTL_KSEC_RNG_REKEY, // indicate a RNG rekey
  1086. pbUserSeed, // input buffer (existing material)
  1087. cbUserSeed, // input buffer size
  1088. pbRandomKey, // output buffer
  1089. *pcbRandomKey, // output buffer size
  1090. pcbRandomKey, // bytes written to output buffer
  1091. NULL
  1092. );
  1093. }
  1094. BOOL
  1095. IsRNGWinNT(
  1096. VOID
  1097. )
  1098. /*++
  1099. This function determines if we are running on Windows NT and furthermore,
  1100. if it is appropriate to make use of certain user operations where the
  1101. code is running.
  1102. If the function returns TRUE, the caller cannot make calls to user
  1103. based function and should use an alternative approach such as
  1104. NtQuerySystemInformation.
  1105. If the function returns FALSE, the caller can safely call user based
  1106. functions to gather random material.
  1107. --*/
  1108. {
  1109. static BOOL fIKnow = FALSE;
  1110. // we assume WinNT in case of error.
  1111. static BOOL fIsWinNT = TRUE;
  1112. OSVERSIONINFO osVer;
  1113. if(fIKnow)
  1114. return(fIsWinNT);
  1115. RtlZeroMemory(&osVer, sizeof(osVer));
  1116. osVer.dwOSVersionInfoSize = sizeof(osVer);
  1117. if( GetVersionEx(&osVer) ) {
  1118. fIsWinNT = (osVer.dwPlatformId == VER_PLATFORM_WIN32_NT);
  1119. if( fIsWinNT ) {
  1120. #ifndef WINNT_RNG
  1121. //
  1122. // if we're on NT, collect entry point address.
  1123. //
  1124. HMODULE hNTDll = GetModuleHandleW( L"ntdll.dll" );
  1125. if( hNTDll ) {
  1126. _NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(
  1127. hNTDll,
  1128. "NtQuerySystemInformation"
  1129. );
  1130. //
  1131. // On WinNT, adjust the rekey param to be a much larger value
  1132. // because we have more entropy to key from.
  1133. //
  1134. if( _NtQuerySystemInformation )
  1135. g_dwRC4RekeyParam = RC4_REKEY_PARAM_NT;
  1136. _NtOpenFile = (NTOPENFILE)GetProcAddress(
  1137. hNTDll,
  1138. "NtOpenFile"
  1139. );
  1140. _RtlInitUnicodeString = (RTLINITUNICODESTRING)GetProcAddress(
  1141. hNTDll,
  1142. "RtlInitUnicodeString"
  1143. );
  1144. }
  1145. #else
  1146. g_dwRC4RekeyParam = RC4_REKEY_PARAM_NT;
  1147. #endif
  1148. } else {
  1149. //
  1150. // collect entry point addresses for Win95
  1151. //
  1152. HMODULE hUser32 = LoadLibraryA("user32.dll");
  1153. if( hUser32 ) {
  1154. _GetCursorPos = (GETCURSORPOS)GetProcAddress(
  1155. hUser32,
  1156. "GetCursorPos"
  1157. );
  1158. _GetMessageTime = (GETMESSAGETIME)GetProcAddress(
  1159. hUser32,
  1160. "GetMessageTime"
  1161. );
  1162. }
  1163. }
  1164. }
  1165. // even on an error, this is as good as it gets
  1166. fIKnow = TRUE;
  1167. return fIsWinNT;
  1168. }
  1169. #endif // !KMODE_RNG