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.

258 lines
6.3 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)
  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 -> Dont use rand() instead throw an error.
  122. // Unlock, else it will result in a deadlock. NT raid 530674
  123. LeaveCriticalSection (&m_csLock);
  124. return HRESULT_FROM_WIN32(GetLastError());
  125. }
  126. m_iItem = 0; // start over
  127. }
  128. for (i = 0; i < cDwords; i++)
  129. pdwDwords[i] = m_pdwItems[m_iItem++];
  130. LeaveCriticalSection(&m_csLock);
  131. return S_OK;
  132. }
  133. };
  134. // Pointer to the sole instance of the above
  135. static CRandomGenerator *gs_pRandomGenerator = NULL;
  136. /*===================================================================
  137. E x t e r n a l A P I
  138. ===================================================================*/
  139. /*===================================================================
  140. InitRandGenerator
  141. To be called from DllInit()
  142. Parameters
  143. Returns:
  144. HRESULT
  145. ===================================================================*/
  146. HRESULT InitRandGenerator()
  147. {
  148. gs_pRandomGenerator = new CRandomGenerator;
  149. if (!gs_pRandomGenerator)
  150. return E_OUTOFMEMORY;
  151. return gs_pRandomGenerator->Init();
  152. }
  153. /*===================================================================
  154. UnInitRandGenerator
  155. To be called from DllUnInit()
  156. Parameters
  157. Returns:
  158. HRESULT
  159. ===================================================================*/
  160. HRESULT UnInitRandGenerator()
  161. {
  162. if (gs_pRandomGenerator)
  163. {
  164. gs_pRandomGenerator->UnInit();
  165. delete gs_pRandomGenerator;
  166. }
  167. return S_OK;
  168. }
  169. /*===================================================================
  170. GenerateRandomDword
  171. Returns random DWORD
  172. Parameters
  173. Returns:
  174. Random number
  175. ===================================================================*/
  176. DWORD GenerateRandomDword()
  177. {
  178. DWORD dw = 0;
  179. Assert(gs_pRandomGenerator);
  180. gs_pRandomGenerator->Generate(&dw, 1);
  181. return dw;
  182. }
  183. /*===================================================================
  184. GenerateRandomDwords
  185. Returns random DWORDs
  186. Parameters
  187. pdwDwords array of DWORDs to fill
  188. cDwords # of DWORDs
  189. Returns:
  190. Random number
  191. ===================================================================*/
  192. HRESULT GenerateRandomDwords
  193. (
  194. DWORD *pdwDwords,
  195. DWORD cDwords
  196. )
  197. {
  198. Assert(gs_pRandomGenerator);
  199. return gs_pRandomGenerator->Generate(pdwDwords, cDwords);
  200. }