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.

272 lines
7.3 KiB

  1. // Copyright (c) 1996-1999 Microsoft Corporation
  2. //+============================================================================
  3. //
  4. // File: entropy.cxx
  5. //
  6. // This file implements the CEntropyRecorder class. That class is used
  7. // to generate truly random secrets. It does this by maintaining some
  8. // state whenever the Put method is called. It is the responsibility of
  9. // the caller to call this at non-predictable times, such as based on
  10. // the timing of user keystrokes or on non-solid-state disk latency.
  11. //
  12. //+============================================================================
  13. #include "pch.cxx"
  14. #pragma hdrstop
  15. #include "trkwks.hxx"
  16. #define THIS_FILE_NUMBER ENTROPY_CXX_FILE_NO
  17. //+----------------------------------------------------------------------------
  18. //
  19. // CEntropyRecord::Initialize
  20. //
  21. // Init the critsec and entropy array.
  22. //
  23. //+----------------------------------------------------------------------------
  24. void
  25. CEntropyRecorder::Initialize()
  26. {
  27. DWORD dwType;
  28. DWORD cb;
  29. HKEY hKey;
  30. _cs.Initialize();
  31. _fInitialized = TRUE;
  32. _cbTotalEntropy = _iNext = 0;
  33. memset(_abEntropy, 0, sizeof(_abEntropy));
  34. }
  35. //+----------------------------------------------------------------------------
  36. //
  37. // CEntropyRecord::UnInitialize
  38. //
  39. // Delete the critsec.
  40. //
  41. //+----------------------------------------------------------------------------
  42. void
  43. CEntropyRecorder::UnInitialize()
  44. {
  45. if (_fInitialized)
  46. {
  47. _cs.UnInitialize();
  48. _fInitialized = FALSE;
  49. }
  50. }
  51. //+----------------------------------------------------------------------------
  52. //
  53. // CEntropyRecorder::Put
  54. //
  55. // This method is called at random times. The performance counter is
  56. // queries, munged, and put into the entropy array.
  57. //
  58. //+----------------------------------------------------------------------------
  59. void
  60. CEntropyRecorder::Put()
  61. {
  62. LARGE_INTEGER li;
  63. QueryPerformanceCounter(&li);
  64. DWORD dw = li.LowPart ^ li.HighPart;
  65. WORD w = HIWORD(dw) ^ LOWORD(dw);
  66. _cs.Enter();
  67. PutEntropy(HIBYTE(w));
  68. PutEntropy(LOBYTE(w));
  69. _cs.Leave();
  70. }
  71. //+----------------------------------------------------------------------------
  72. //
  73. // CEntropyRecorder::PutEntropy
  74. //
  75. // Add a byte of entropy (from Put) to the entropy array.
  76. //
  77. //+----------------------------------------------------------------------------
  78. void
  79. CEntropyRecorder::PutEntropy( BYTE b )
  80. {
  81. //
  82. // Entries are written into the buffer in a circular fashion.
  83. // A count, _cbTotalEntropy, records total number of writes.
  84. // If _cbTotalEntropy > buffer size, then we have wrapped and
  85. // the entire buffer has entropy.
  86. //
  87. DWORD iNext = _iNext;
  88. iNext %= sizeof(_abEntropy);
  89. TrkAssert(iNext < sizeof(_abEntropy));
  90. _abEntropy[iNext] ^= b;
  91. _iNext = iNext+1;
  92. _cbTotalEntropy ++;
  93. }
  94. //+----------------------------------------------------------------------------
  95. //
  96. // CEntropyRecorder::GetEntropy
  97. //
  98. // Get the specified number of bytes of entropy. If we don't already have
  99. // enough bytes, we'll generate them here.
  100. //
  101. //+----------------------------------------------------------------------------
  102. BOOL
  103. CEntropyRecorder::GetEntropy( void * pv, ULONG cb )
  104. {
  105. BOOL fGotIt = FALSE;
  106. _cs.Enter();
  107. __try
  108. {
  109. TrkLog(( TRKDBG_VOLUME, TEXT("Getting entropy (%d/%d)"), cb, _cbTotalEntropy ));
  110. // Do we already have enough entropy?
  111. if( _cbTotalEntropy <= cb )
  112. {
  113. // No, we need to generate it.
  114. TrkLog(( TRKDBG_VOLUME, TEXT("Generating entropy") ));
  115. TCHAR tszSysDir[ MAX_PATH + 1 ];
  116. NTSTATUS Status = STATUS_SUCCESS;
  117. ULONG cPuts = 0;
  118. // Get the system directory.
  119. UINT cchPath = GetSystemDirectory( tszSysDir, ELEMENTS(tszSysDir) );
  120. if( 0 == cchPath || MAX_PATH < cchPath )
  121. {
  122. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't get system directory (%lu, %lu)"),
  123. cchPath, GetLastError() ));
  124. __leave;
  125. }
  126. // Keep opening the system directory, capturing entropy each time (with the call to Put),
  127. // until we have enough.
  128. while( _cbTotalEntropy <= cb )
  129. {
  130. HANDLE hSysDir = NULL;
  131. Status = TrkCreateFile( tszSysDir, FILE_READ_ATTRIBUTES, FILE_ATTRIBUTE_NORMAL,
  132. FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
  133. FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, &hSysDir );
  134. if( !NT_SUCCESS(Status) )
  135. {
  136. TrkLog(( TRKDBG_ERROR, TEXT("Couldn't open system directory (%08x)"),
  137. Status ));
  138. __leave;
  139. }
  140. NtClose( hSysDir );
  141. hSysDir = NULL;
  142. Put();
  143. // This is just a cautionary measure. Never let this loop eat all the
  144. // CPU forever.
  145. if( ++cPuts > 100 )
  146. {
  147. TrkLog(( TRKDBG_ERROR, TEXT("CEntropy::GetEntropy in infinite loop") ));
  148. __leave;
  149. }
  150. }
  151. TrkLog(( TRKDBG_VOLUME, TEXT("Generated enough entropy") ));
  152. } // if( _cbTotalEntropy <= cb )
  153. if (_cbTotalEntropy >= ELEMENTS(_abEntropy))
  154. {
  155. // Never allow _cbTotalEntropy to exceed ELEMENTS(_abEntropy)
  156. // if we're reading out, otherwise we'd get non-random data returned.
  157. _cbTotalEntropy = ELEMENTS(_abEntropy);
  158. }
  159. _cbTotalEntropy -= cb;
  160. _iNext = _cbTotalEntropy;
  161. memcpy(pv, _abEntropy, cb);
  162. memcpy(_abEntropy, _abEntropy+cb, sizeof(_abEntropy)-cb);
  163. memset(_abEntropy+sizeof(_abEntropy)-cb, 0, cb);
  164. fGotIt = TRUE;
  165. }
  166. __finally
  167. {
  168. _cs.Leave();
  169. }
  170. return(fGotIt);
  171. }
  172. //+----------------------------------------------------------------------------
  173. //
  174. // CEntropyRecorder::InitializeSecret
  175. //
  176. // Create a volume secret, using the entropy buffer.
  177. //
  178. //+----------------------------------------------------------------------------
  179. BOOL
  180. CEntropyRecorder::InitializeSecret( CVolumeSecret * pSecret )
  181. {
  182. return GetEntropy( pSecret, sizeof(*pSecret) );
  183. }
  184. //+----------------------------------------------------------------------------
  185. //
  186. // CEntropyRecorder::ReturnUnusedSecret
  187. //
  188. // Return entropy that was taken with InitializeSecret but not used.
  189. //
  190. //+----------------------------------------------------------------------------
  191. void
  192. CEntropyRecorder::ReturnUnusedSecret( CVolumeSecret * pSecret )
  193. {
  194. TrkAssert( *pSecret != CVolumeSecret() );
  195. _cs.Enter();
  196. if (_cbTotalEntropy <= sizeof(_abEntropy) - sizeof(*pSecret))
  197. {
  198. memcpy( _abEntropy+sizeof(*pSecret), _abEntropy, _cbTotalEntropy);
  199. memcpy( _abEntropy, pSecret, sizeof(CVolumeSecret) );
  200. _iNext = (_iNext + sizeof(*pSecret)) % sizeof(_abEntropy);
  201. _cbTotalEntropy += sizeof(*pSecret);
  202. }
  203. *pSecret = CVolumeSecret();
  204. _cs.Leave();
  205. }