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.

255 lines
5.9 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1997 Microsoft Corporation. All Rights Reserved.
  5. Component: Random number generator
  6. File: randgen.cpp
  7. Owner: DmitryR
  8. This file contains the implementation of the random number
  9. generator.
  10. ===================================================================*/
  11. #include "denpre.h"
  12. #pragma hdrstop
  13. #include "randgen.h"
  14. #include "memchk.h"
  15. /*===================================================================
  16. Random DWORD using rand()
  17. ===================================================================*/
  18. #define RAND_DWORD() (((rand() & 0xffff) << 16) | (rand() & 0xffff))
  19. /*===================================================================
  20. Random number generator class
  21. ===================================================================*/
  22. class CRandomGenerator
  23. {
  24. private:
  25. DWORD m_fInited : 1; // inited?
  26. DWORD m_fCSInited : 1; // critical section inited?
  27. HCRYPTPROV m_hCryptProvider; // crypt provider
  28. CRITICAL_SECTION m_csLock; // critical section
  29. DWORD m_cItems; // number of items in the array
  30. DWORD *m_pdwItems; // pointer to the array of random DWORDs
  31. DWORD m_iItem; // next random item index
  32. public:
  33. CRandomGenerator()
  34. :
  35. m_fInited(FALSE),
  36. m_fCSInited(FALSE),
  37. m_hCryptProvider(NULL),
  38. m_cItems(0),
  39. m_pdwItems(NULL),
  40. m_iItem(0)
  41. {
  42. }
  43. ~CRandomGenerator()
  44. {
  45. UnInit();
  46. }
  47. HRESULT Init(DWORD cItems = 128)
  48. {
  49. Assert(!m_fInited);
  50. m_hCryptProvider = NULL;
  51. if (cItems > 0 && gGlob.fWinNT())
  52. {
  53. CryptAcquireContext
  54. (
  55. &m_hCryptProvider,
  56. NULL,
  57. NULL,
  58. PROV_RSA_FULL,
  59. CRYPT_VERIFYCONTEXT
  60. );
  61. }
  62. if (!m_hCryptProvider)
  63. {
  64. return HRESULT_FROM_WIN32(GetLastError());
  65. }
  66. HRESULT hr;
  67. ErrInitCriticalSection(&m_csLock, hr);
  68. if (FAILED(hr))
  69. return hr;
  70. m_fCSInited = TRUE;
  71. m_pdwItems = new DWORD[cItems];
  72. if (!m_pdwItems)
  73. return E_OUTOFMEMORY;
  74. m_cItems = cItems;
  75. m_iItem = cItems; // to start with new chunk
  76. m_fInited = TRUE;
  77. return S_OK;
  78. }
  79. HRESULT UnInit()
  80. {
  81. if (m_hCryptProvider)
  82. {
  83. CryptReleaseContext(m_hCryptProvider, 0);
  84. m_hCryptProvider = NULL;
  85. }
  86. if (m_fCSInited)
  87. {
  88. DeleteCriticalSection(&m_csLock);
  89. m_fCSInited = FALSE;
  90. }
  91. if (m_pdwItems)
  92. {
  93. delete [] m_pdwItems;
  94. m_pdwItems = NULL;
  95. }
  96. m_cItems = 0;
  97. m_iItem = 0;
  98. m_fInited = FALSE;
  99. return S_OK;
  100. }
  101. HRESULT Generate(DWORD *pdwDwords, DWORD cDwords)
  102. {
  103. Assert(pdwDwords);
  104. Assert(cDwords > 0);
  105. Assert(m_fInited);
  106. DWORD i;
  107. // use CryptGenRandom
  108. Assert(cDwords <= m_cItems); // requested # of items < m_cItems
  109. Assert(m_fCSInited);
  110. EnterCriticalSection(&m_csLock);
  111. if (m_iItem+cDwords-1 >= m_cItems)
  112. {
  113. BOOL fSucceeded = CryptGenRandom
  114. (
  115. m_hCryptProvider,
  116. m_cItems * sizeof(DWORD),
  117. reinterpret_cast<BYTE *>(m_pdwItems)
  118. );
  119. if (!fSucceeded)
  120. {
  121. // Failed -> use rand()
  122. // Dont use rand() instead throw an error.
  123. return HRESULT_FROM_WIN32(GetLastError());
  124. }
  125. m_iItem = 0; // start over
  126. }
  127. for (i = 0; i < cDwords; i++)
  128. pdwDwords[i] = m_pdwItems[m_iItem++];
  129. LeaveCriticalSection(&m_csLock);
  130. return S_OK;
  131. }
  132. };
  133. // Pointer to the sole instance of the above
  134. static CRandomGenerator *gs_pRandomGenerator = NULL;
  135. /*===================================================================
  136. E x t e r n a l A P I
  137. ===================================================================*/
  138. /*===================================================================
  139. InitRandGenerator
  140. To be called from DllInit()
  141. Parameters
  142. Returns:
  143. HRESULT
  144. ===================================================================*/
  145. HRESULT InitRandGenerator()
  146. {
  147. gs_pRandomGenerator = new CRandomGenerator;
  148. if (!gs_pRandomGenerator)
  149. return E_OUTOFMEMORY;
  150. return gs_pRandomGenerator->Init();
  151. }
  152. /*===================================================================
  153. UnInitRandGenerator
  154. To be called from DllUnInit()
  155. Parameters
  156. Returns:
  157. HRESULT
  158. ===================================================================*/
  159. HRESULT UnInitRandGenerator()
  160. {
  161. if (gs_pRandomGenerator)
  162. {
  163. gs_pRandomGenerator->UnInit();
  164. delete gs_pRandomGenerator;
  165. }
  166. return S_OK;
  167. }
  168. /*===================================================================
  169. GenerateRandomDword
  170. Returns random DWORD
  171. Parameters
  172. Returns:
  173. Random number
  174. ===================================================================*/
  175. DWORD GenerateRandomDword()
  176. {
  177. DWORD dw;
  178. Assert(gs_pRandomGenerator);
  179. gs_pRandomGenerator->Generate(&dw, 1);
  180. return dw;
  181. }
  182. /*===================================================================
  183. GenerateRandomDwords
  184. Returns random DWORDs
  185. Parameters
  186. pdwDwords array of DWORDs to fill
  187. cDwords # of DWORDs
  188. Returns:
  189. Random number
  190. ===================================================================*/
  191. HRESULT GenerateRandomDwords
  192. (
  193. DWORD *pdwDwords,
  194. DWORD cDwords
  195. )
  196. {
  197. Assert(gs_pRandomGenerator);
  198. return gs_pRandomGenerator->Generate(pdwDwords, cDwords);
  199. }