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.

354 lines
9.8 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // FILE : nt_rand.c //
  3. // DESCRIPTION : Crypto CP interfaces: //
  4. // CPGenRandom //
  5. // AUTHOR : //
  6. // HISTORY : //
  7. // Jan 25 1995 larrys Changed from Nametag //
  8. // Feb 23 1995 larrys Changed NTag_SetLastError to SetLastError //
  9. // Apr 10 1995 larrys Fix comments //
  10. // Oct 27 1995 rajeshk Added provider parameter to GenRandom call //
  11. // Nov 3 1995 larrys Merge for NT checkin //
  12. // Oct 14 1996 jeffspel Changed GenRandom to NewGenRandom //
  13. // May 5 2000 dbarlow Clean up error return codes //
  14. // //
  15. // Copyright (C) 1993 - 2000, Microsoft Corporation //
  16. // All Rights Reserved //
  17. /////////////////////////////////////////////////////////////////////////////
  18. #include <nt.h>
  19. #include <ntrtl.h>
  20. #include <nturtl.h>
  21. #include <crypt.h>
  22. #include "precomp.h"
  23. #include "sha.h"
  24. #include "rsa_fast.h"
  25. #include "rsa_math.h"
  26. #include "randlib.h"
  27. static CONST BYTE DSSPRIVATEKEYINIT[] =
  28. { 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89,
  29. 0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76,
  30. 0xc3, 0xd2, 0xe1, 0xf0 };
  31. static CONST BYTE DSSPERMSGINIT[] =
  32. { 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe,
  33. 0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0,
  34. 0x67, 0x45, 0x23, 0x01 };
  35. static CONST BYTE MODULUS[] =
  36. { 0xf5, 0xc1, 0x56, 0xb1, 0xd5, 0x48, 0x42, 0x2e,
  37. 0xbd, 0xa5, 0x44, 0x41, 0xc7, 0x1c, 0x24, 0x08,
  38. 0x3f, 0x80, 0x3c, 0x90 };
  39. static BYTE l_rgbRNGState[A_SHA_DIGEST_LEN];
  40. //
  41. // Function : AddSeeds
  42. //
  43. // Description : This function adds the 160 bit seeds pointed to by pdwSeed1
  44. // and pdwSeed2, it also adds 1 to this sum and mods the sum by
  45. // 2^160.
  46. //
  47. /*static*/ void
  48. AddSeeds(
  49. IN CONST DWORD *pdwSeed1,
  50. IN OUT DWORD *pdwSeed2)
  51. {
  52. DWORD dwTmp;
  53. DWORD dwOverflow = 1;
  54. DWORD i;
  55. for (i = 0; i < 5; i++)
  56. {
  57. dwTmp = dwOverflow + pdwSeed1[i];
  58. dwOverflow = (dwOverflow > dwTmp);
  59. pdwSeed2[i] = pdwSeed2[i] + dwTmp;
  60. dwOverflow = ((dwTmp > pdwSeed2[i]) || dwOverflow);
  61. }
  62. }
  63. /*
  64. Given SHA(message), compute SHA(message) mod qdigit.
  65. Output is in the interval [0, qdigit-1].
  66. Although SHA(message) may exceed qdigit,
  67. it cannot exceed 2*qdigit since the leftmost bit
  68. of qdigit is 1.
  69. */
  70. /*static*/ void
  71. SHA_mod_q(
  72. CONST BYTE *pbHash, // In
  73. CONST BYTE *pbQ, // In
  74. BYTE *pbNewHash) // Out
  75. {
  76. BYTE rgbHash[A_SHA_DIGEST_LEN];
  77. if (-1 != Compare((DWORD*)rgbHash, // hash is greater so subtract
  78. (DWORD*)pbQ,
  79. A_SHA_DIGEST_LEN / sizeof(DWORD)))
  80. {
  81. Sub((DWORD*)pbNewHash,
  82. (DWORD*)rgbHash,
  83. (DWORD*)pbQ,
  84. A_SHA_DIGEST_LEN / sizeof(DWORD));
  85. }
  86. else
  87. memcpy(pbNewHash, pbHash, A_SHA_DIGEST_LEN / sizeof(DWORD));
  88. } /* SHA_mod_q */
  89. //
  90. // Function : RNG16BitStateCheck
  91. //
  92. // Description : This function compares each 160 bits of the buffer with
  93. // the next 160 bits and if they are the same the function
  94. // errors out. The IN buffer is expected to be A_SHA_DIGEST_LEN
  95. // bytes long. The function fails if the RNG is gets the same
  96. // input buffer of 160 bits twice in a row.
  97. //
  98. /*static*/ BOOL
  99. RNG16BitStateCheck(
  100. IN OUT DWORD *pdwOut,
  101. IN DWORD *pdwIn,
  102. IN DWORD cbNeeded)
  103. {
  104. BOOL fRet = FALSE;
  105. if (0 == memcmp(l_rgbRNGState, pdwIn, A_SHA_DIGEST_LEN))
  106. {
  107. memcpy(l_rgbRNGState, (BYTE*)pdwIn, A_SHA_DIGEST_LEN);
  108. goto ErrorExit;
  109. }
  110. memcpy(l_rgbRNGState, (BYTE*)pdwIn, A_SHA_DIGEST_LEN);
  111. memcpy((BYTE*)pdwOut, (BYTE*)pdwIn, cbNeeded);
  112. fRet = TRUE;
  113. ErrorExit:
  114. return fRet;
  115. }
  116. //
  117. // Function : FIPS186Gen
  118. //
  119. // Description : FIPS 186 RNG, the seed is generated by calling NewGenRandom.
  120. //
  121. /*static*/ DWORD
  122. FIPS186Gen(
  123. IN HANDLE hRNGDriver,
  124. IN BYTE **ppbContextSeed,
  125. IN DWORD *pcbContextSeed,
  126. IN CONST BYTE *pbInitValue, // this is t, must be 20 bytes
  127. IN CONST BYTE *pbModulus, // this must be a 20 byte prime
  128. IN OUT BYTE *pb,
  129. IN DWORD cb)
  130. {
  131. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  132. DWORD rgdwSeed[A_SHA_DIGEST_LEN/sizeof(DWORD)]; // 160 bits
  133. DWORD rgdwNewSeed[A_SHA_DIGEST_LEN/sizeof(DWORD)]; // 160 bits
  134. A_SHA_CTX SHACtxt;
  135. BYTE rgbBuf[A_SHA_DIGEST_LEN];
  136. DWORD cbBuf;
  137. BYTE *pbTmp = pb;
  138. DWORD cbTmp = cb;
  139. DWORD i;
  140. DWORD dwSts;
  141. DWORD cbContextSeed = 0;
  142. if (ppbContextSeed && pcbContextSeed)
  143. cbContextSeed = *pcbContextSeed;
  144. while (cbTmp)
  145. {
  146. #ifdef USE_HW_RNG
  147. #ifdef _M_IX86
  148. // get a 160 bit random seed
  149. if (INVALID_HANDLE_VALUE != hRNGDriver)
  150. {
  151. dwSts = HWRNGGenRandom(hRNGDriver,
  152. (BYTE*)rgdwNewSeed,
  153. sizeof(rgdwNewSeed));
  154. if (ERROR_SUCCESS != dwSts)
  155. {
  156. dwReturn = dwSts;
  157. goto ErrorExit;
  158. }
  159. }
  160. else
  161. #endif // _M_IX86
  162. #endif // USE_HW_RNG
  163. {
  164. // get a 160 bit random seed
  165. if (!NewGenRandom(ppbContextSeed, pcbContextSeed,
  166. (BYTE*)rgdwNewSeed, sizeof(rgdwNewSeed)))
  167. {
  168. dwReturn = (DWORD)NTE_FAIL; // NewGenRandom doesn't set LastError.
  169. goto ErrorExit;
  170. }
  171. }
  172. for (i = 0; i < A_SHA_DIGEST_LEN/sizeof(DWORD); i++)
  173. rgdwSeed[i] ^= rgdwNewSeed[i];
  174. A_SHAInit (&SHACtxt);
  175. memcpy(SHACtxt.state, pbInitValue, A_SHA_DIGEST_LEN);
  176. // perform the one way function
  177. A_SHAUpdate(&SHACtxt, (BYTE*)rgdwSeed, sizeof(rgdwSeed));
  178. if (cbContextSeed)
  179. A_SHAUpdate(&SHACtxt, *ppbContextSeed, cbContextSeed);
  180. A_SHAFinal(&SHACtxt, rgbBuf);
  181. for (i = 0; i < cbContextSeed && i < A_SHA_DIGEST_LEN; i++)
  182. (*ppbContextSeed)[i] ^= rgbBuf[i];
  183. // continuous 16 bit state check
  184. if (A_SHA_DIGEST_LEN < cbTmp)
  185. cbBuf = A_SHA_DIGEST_LEN;
  186. else
  187. cbBuf = cbTmp;
  188. if (!RNG16BitStateCheck((DWORD*)pbTmp, (DWORD*)rgbBuf, cbBuf))
  189. {
  190. dwReturn = (DWORD)NTE_FAIL;
  191. goto ErrorExit;
  192. }
  193. pbTmp += cbBuf;
  194. cbTmp -= cbBuf;
  195. if (0 == cbTmp)
  196. break;
  197. // modular reduction with modulus Q
  198. SHA_mod_q(rgbBuf, pbModulus, (BYTE*)rgdwNewSeed);
  199. // (1 + previous seed + new random) mod 2^160
  200. AddSeeds(rgdwNewSeed, rgdwSeed);
  201. }
  202. dwReturn = ERROR_SUCCESS;
  203. ErrorExit:
  204. return dwReturn;
  205. }
  206. DWORD
  207. FIPS186GenRandom(
  208. IN HANDLE *phRNGDriver,
  209. IN BYTE **ppbContextSeed,
  210. IN DWORD *pcbContextSeed,
  211. IN OUT BYTE *pb,
  212. IN DWORD cb)
  213. {
  214. return FIPS186Gen(*phRNGDriver, ppbContextSeed, pcbContextSeed,
  215. DSSPRIVATEKEYINIT, MODULUS, pb, cb);
  216. }
  217. void
  218. FIPS186GenRandomWithException(
  219. IN HANDLE *phRNGDriver,
  220. IN BYTE **ppbContextSeed,
  221. IN DWORD *pcbContextSeed,
  222. IN OUT BYTE *pb,
  223. IN DWORD cb)
  224. {
  225. DWORD dwSts;
  226. dwSts = FIPS186Gen(*phRNGDriver, ppbContextSeed, pcbContextSeed,
  227. DSSPRIVATEKEYINIT, MODULUS, pb, cb);
  228. if (ERROR_SUCCESS != dwSts)
  229. {
  230. // nasty way to cause an error but need either this
  231. // or redo rsa32.lib
  232. RaiseException((DWORD)NTE_FAIL, 0, 0, 0);
  233. }
  234. }
  235. /*
  236. - CPGenRandom
  237. -
  238. * Purpose:
  239. * Used to fill a buffer with random bytes
  240. *
  241. *
  242. * Parameters:
  243. * IN hUID - Handle to the user identifcation
  244. * IN dwLen - Number of bytes of random data requested
  245. * OUT pbBuffer - Pointer to the buffer where the random
  246. * bytes are to be placed
  247. *
  248. * Returns:
  249. */
  250. BOOL WINAPI
  251. CPGenRandom(
  252. IN HCRYPTPROV hUID,
  253. IN DWORD dwLen,
  254. OUT BYTE *pbBuffer)
  255. {
  256. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  257. PNTAGUserList pTmpUser;
  258. BOOL fRet;
  259. DWORD dwSts;
  260. EntryPoint
  261. // check the user identification
  262. pTmpUser = NTLCheckList(hUID, USER_HANDLE);
  263. if (NULL == pTmpUser)
  264. {
  265. dwReturn = (DWORD)NTE_BAD_UID;
  266. goto ErrorExit;
  267. }
  268. dwSts = FIPS186Gen(pTmpUser->hRNGDriver,
  269. &pTmpUser->ContInfo.pbRandom,
  270. &pTmpUser->ContInfo.ContLens.cbRandom,
  271. DSSPRIVATEKEYINIT,
  272. MODULUS,
  273. pbBuffer,
  274. dwLen);
  275. if (ERROR_SUCCESS != dwSts)
  276. {
  277. dwReturn = dwSts;
  278. goto ErrorExit;
  279. }
  280. dwReturn = ERROR_SUCCESS;
  281. ErrorExit:
  282. fRet = (ERROR_SUCCESS == dwReturn);
  283. if (!fRet)
  284. SetLastError(dwReturn);
  285. return fRet;
  286. }
  287. //
  288. // Function: NewGenRandom
  289. //
  290. // Description: Stub to eliminate the need to link with
  291. // randlib.lib. Now using RtlGenRandom() instead.
  292. //
  293. // Returns: True for success. False for failure.
  294. //
  295. unsigned int
  296. RSA32API
  297. NewGenRandom(
  298. IN OUT unsigned char **ppbRandSeed /*unused*/,
  299. IN unsigned long *pcbRandSeed /*unused*/,
  300. IN OUT unsigned char *pbBuffer,
  301. IN unsigned long dwLength
  302. )
  303. {
  304. return (unsigned int)RtlGenRandom( pbBuffer, dwLength );
  305. }