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.

893 lines
21 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // FILE : fipsdll.c //
  3. // DESCRIPTION : //
  4. // AUTHOR : //
  5. // HISTORY : //
  6. // Nov 29 1999 jeffspel Created //
  7. // //
  8. // Copyright (C) 1999 Microsoft Corporation All Rights Reserved //
  9. /////////////////////////////////////////////////////////////////////////////
  10. #include <ntddk.h>
  11. #include <fipsapi.h>
  12. #include <rsa_fast.h>
  13. #include <rsa_math.h>
  14. #include <randlib.h>
  15. //
  16. // Fill in the DESTable struct with the decrypt and encrypt
  17. // key expansions.
  18. //
  19. // Assumes that the second parameter points to DES_BLOCKLEN
  20. // bytes of key.
  21. //
  22. //
  23. #pragma alloc_text(PAGER32C, FipsDesKey)
  24. #pragma alloc_text(PAGER32C, FipsDes)
  25. #pragma alloc_text(PAGER32C, Fips3Des3Key)
  26. #pragma alloc_text(PAGER32C, Fips3Des)
  27. #pragma alloc_text(PAGER32C, FipsSHAInit)
  28. #pragma alloc_text(PAGER32C, FipsSHAUpdate)
  29. #pragma alloc_text(PAGER32C, FipsSHAFinal)
  30. #pragma alloc_text(PAGER32C, FipsCBC)
  31. #pragma alloc_text(PAGER32C, FIPSGenRandom)
  32. #pragma alloc_text(PAGER32C, FipsCBC)
  33. #pragma alloc_text(PAGER32C, FIPSGenRandom)
  34. #pragma alloc_text(PAGER32C, FipsBlockCBC)
  35. #pragma alloc_text(PAGER32C, FipsHmacSHAInit)
  36. #pragma alloc_text(PAGER32C, FipsHmacSHAUpdate)
  37. #pragma alloc_text(PAGER32C, FipsHmacSHAFinal)
  38. #pragma alloc_text(PAGER32C, HmacMD5Init)
  39. #pragma alloc_text(PAGER32C, HmacMD5Update)
  40. #pragma alloc_text(PAGER32C, HmacMD5Final)
  41. void *
  42. __stdcall
  43. RSA32Alloc(
  44. unsigned long cb
  45. )
  46. {
  47. return (void *)ExAllocatePool(PagedPool, cb);
  48. }
  49. void
  50. __stdcall
  51. RSA32Free(
  52. void *pv
  53. )
  54. {
  55. ExFreePool( pv );
  56. }
  57. VOID FipsDesKey(DESTable *DesTable, UCHAR *pbKey)
  58. {
  59. UCHAR rgbTmpKey[DES_KEYSIZE];
  60. RtlCopyMemory(rgbTmpKey, pbKey, DES_KEYSIZE);
  61. deskey(DesTable, rgbTmpKey);
  62. RtlZeroMemory(rgbTmpKey, DES_KEYSIZE);
  63. }
  64. //
  65. // Encrypt or decrypt with the key in DESTable
  66. //
  67. //
  68. VOID FipsDes(UCHAR *pbOut, UCHAR *pbIn, void *pKey, int iOp)
  69. {
  70. DESTable TmpDESTable;
  71. RtlCopyMemory(&TmpDESTable, pKey, sizeof(DESTable));
  72. des(pbOut, pbIn, &TmpDESTable, iOp);
  73. RtlZeroMemory(&TmpDESTable, sizeof(DESTable));
  74. }
  75. //
  76. // Fill in the DES3Table structs with the decrypt and encrypt
  77. // key expansions.
  78. //
  79. // Assumes that the second parameter points to 3 * DES_BLOCKLEN
  80. // bytes of key.
  81. //
  82. //
  83. VOID Fips3Des3Key(PDES3TABLE pDES3Table, UCHAR *pbKey)
  84. {
  85. UCHAR rgbTmpKey[DES3_KEYSIZE];
  86. RtlCopyMemory(rgbTmpKey, pbKey, DES3_KEYSIZE);
  87. tripledes3key(pDES3Table, rgbTmpKey);
  88. RtlZeroMemory(rgbTmpKey, DES3_KEYSIZE);
  89. }
  90. //
  91. // Encrypt or decrypt with the key in pKey
  92. //
  93. VOID Fips3Des(UCHAR *pbIn, UCHAR *pbOut, void *pKey, int op)
  94. {
  95. DES3TABLE Tmp3DESTable;
  96. RtlCopyMemory(&Tmp3DESTable, pKey, sizeof(DES3TABLE));
  97. tripledes(pbIn, pbOut, &Tmp3DESTable, op);
  98. RtlZeroMemory(&Tmp3DESTable, sizeof(DES3TABLE));
  99. }
  100. //
  101. // Initialize the SHA context.
  102. //
  103. VOID FipsSHAInit(A_SHA_CTX *pShaCtx)
  104. {
  105. A_SHAInit(pShaCtx);
  106. }
  107. //
  108. // Hash data into the hash context.
  109. //
  110. VOID FipsSHAUpdate(A_SHA_CTX *pShaCtx, UCHAR *pb, unsigned int cb)
  111. {
  112. A_SHAUpdate(pShaCtx, pb, cb);
  113. }
  114. //
  115. // Finish the SHA hash and copy the final hash value into the pbHash out param.
  116. //
  117. VOID FipsSHAFinal(A_SHA_CTX *pShaCtx, UCHAR *pbHash)
  118. {
  119. A_SHAFinal(pShaCtx, pbHash);
  120. }
  121. typedef void (*FIPSCIPHER)(UCHAR*, UCHAR*, void*, int);
  122. //
  123. // FipsCBC (cipher block chaining) performs a XOR of the feedback register
  124. // with the plain text before calling the block cipher
  125. //
  126. // NOTE - Currently this function assumes that the block length is
  127. // DES_BLOCKLEN (8 bytes).
  128. //
  129. // Return: Failure if FALSE is returned, TRUE if it succeeded.
  130. //
  131. BOOL FipsCBC(
  132. ULONG EncryptionAlg,
  133. PBYTE pbOutput,
  134. PBYTE pbInput,
  135. void *pKeyTable,
  136. int Operation,
  137. PBYTE pbFeedback
  138. )
  139. {
  140. UCHAR rgbTmpKeyTable[DES3_TABLESIZE]; // 3DES is the max table size
  141. ULONG cbKeyTable;
  142. FIPSCIPHER FipsCipher;
  143. BOOL fRet = TRUE;
  144. PBYTE pbOutputSave = NULL, pbInputSave = NULL, pbFeedbackSave = NULL;
  145. UINT64 OutputAlignedBuffer, InputAlignedBuffer, FeedbackAlignedBuffer;
  146. #ifdef IA64
  147. #define ALIGNMENT_BOUNDARY 7
  148. #else
  149. #define ALIGNMENT_BOUNDARY 3
  150. #endif
  151. // align input buffer
  152. if ((ULONG_PTR) pbInput & ALIGNMENT_BOUNDARY) {
  153. InputAlignedBuffer = *(UINT64 UNALIGNED *) pbInput;
  154. pbInputSave = pbInput;
  155. if (pbOutput == pbInput) {
  156. pbOutput = (PBYTE) &InputAlignedBuffer;
  157. }
  158. pbInput = (PBYTE) &InputAlignedBuffer;
  159. }
  160. // align output buffer
  161. if ((ULONG_PTR) pbOutput & ALIGNMENT_BOUNDARY) {
  162. OutputAlignedBuffer = *(UINT64 UNALIGNED *) pbOutput;
  163. pbOutputSave = pbOutput;
  164. pbOutput = (PBYTE) &OutputAlignedBuffer;
  165. }
  166. if ((ULONG_PTR) pbFeedback & ALIGNMENT_BOUNDARY) {
  167. FeedbackAlignedBuffer = *(UINT64 UNALIGNED *) pbFeedback;
  168. pbFeedbackSave = pbFeedback;
  169. pbFeedback = (PBYTE) &FeedbackAlignedBuffer;
  170. }
  171. //
  172. // determine the algorithm to use
  173. //
  174. switch(EncryptionAlg)
  175. {
  176. case FIPS_CBC_DES:
  177. {
  178. FipsCipher = des;
  179. cbKeyTable = DES_TABLESIZE;
  180. break;
  181. }
  182. case FIPS_CBC_3DES:
  183. {
  184. FipsCipher = tripledes;
  185. cbKeyTable = DES3_TABLESIZE;
  186. break;
  187. }
  188. default:
  189. fRet = FALSE;
  190. goto Ret;
  191. }
  192. RtlCopyMemory(rgbTmpKeyTable, (UCHAR*)pKeyTable, cbKeyTable);
  193. //
  194. // optimize very common codepath: 8 byte blocks
  195. //
  196. if (Operation == ENCRYPT)
  197. {
  198. ((PUINT64) pbOutput)[0] =
  199. ((PUINT64) pbInput)[0] ^ ((PUINT64) pbFeedback)[0];
  200. FipsCipher(pbOutput, pbOutput, rgbTmpKeyTable, ENCRYPT);
  201. ((PUINT64) pbFeedback)[0] = ((PUINT64) pbOutput)[0];
  202. }
  203. else
  204. {
  205. //
  206. // two cases for output:
  207. // input and output are separate buffers
  208. // input and output are same buffers
  209. //
  210. if( pbOutput != pbInput )
  211. {
  212. FipsCipher(pbOutput, pbInput, rgbTmpKeyTable, DECRYPT);
  213. ((PUINT64) pbOutput)[0] ^= ((PUINT64) pbFeedback)[0];
  214. ((PUINT64) pbFeedback)[0] = ((PUINT64) pbInput)[0];
  215. } else {
  216. UINT64 inputTemp;
  217. inputTemp = ((PUINT64) pbInput)[0];
  218. FipsCipher(pbOutput, pbInput, rgbTmpKeyTable, DECRYPT);
  219. ((PUINT64) pbOutput)[0] ^= ((PUINT64) pbFeedback)[0];
  220. ((PUINT64) pbFeedback)[0] = inputTemp;
  221. }
  222. }
  223. RtlZeroMemory(rgbTmpKeyTable, DES3_TABLESIZE);
  224. if (pbInputSave) {
  225. *(UINT64 UNALIGNED *) pbInputSave = InputAlignedBuffer;
  226. }
  227. if (pbOutputSave) {
  228. *(UINT64 UNALIGNED *) pbOutputSave = OutputAlignedBuffer;
  229. }
  230. if (pbFeedbackSave) {
  231. *(UINT64 UNALIGNED *) pbFeedbackSave = FeedbackAlignedBuffer;
  232. }
  233. Ret:
  234. return fRet;
  235. }
  236. //
  237. // FipsBlockCBC (cipher block chaining) performs a XOR of the feedback register
  238. // with the plain text before calling the block cipher
  239. //
  240. // NOTE - Currently this function assumes that the block length is
  241. // DES_BLOCKLEN (8 bytes).
  242. //
  243. // Return: Failure if FALSE is returned, TRUE if it succeeded.
  244. //
  245. BOOL FipsBlockCBC(
  246. ULONG EncryptionAlg,
  247. PBYTE pbOutput,
  248. PBYTE pbInput,
  249. ULONG Length,
  250. void *pKeyTable,
  251. int Operation,
  252. PBYTE pbFeedback
  253. )
  254. {
  255. UCHAR rgbTmpKeyTable[DES3_TABLESIZE]; // 3DES is the max table size
  256. ULONG cbKeyTable;
  257. FIPSCIPHER FipsCipher;
  258. BOOL fRet = TRUE;
  259. ASSERT ((Length % DESX_BLOCKLEN == 0) && (Length > 0));
  260. if ((Length % DESX_BLOCKLEN != 0) || (Length == 0)) {
  261. return FALSE;
  262. }
  263. //
  264. // determine the algorithm to use
  265. //
  266. switch(EncryptionAlg)
  267. {
  268. case FIPS_CBC_DES:
  269. {
  270. FipsCipher = des;
  271. cbKeyTable = DES_TABLESIZE;
  272. break;
  273. }
  274. case FIPS_CBC_3DES:
  275. {
  276. FipsCipher = tripledes;
  277. cbKeyTable = DES3_TABLESIZE;
  278. break;
  279. }
  280. default:
  281. fRet = FALSE;
  282. goto Ret;
  283. }
  284. RtlCopyMemory(rgbTmpKeyTable, (UCHAR*)pKeyTable, cbKeyTable);
  285. //
  286. // optimize very common codepath: 8 byte blocks
  287. //
  288. if (Operation == ENCRYPT)
  289. {
  290. ULONGLONG tmpData; // Make sure the input buffer not touched more than once. Else EFS will break mysteriously.
  291. ULONGLONG chainBlock;
  292. chainBlock = *(ULONGLONG *)pbFeedback;
  293. while (Length > 0){
  294. tmpData = *(ULONGLONG *)pbInput;
  295. tmpData ^= chainBlock;
  296. FipsCipher(pbOutput, (PUCHAR)&tmpData, rgbTmpKeyTable, ENCRYPT);
  297. chainBlock = *(ULONGLONG *)pbOutput;
  298. Length -= DES_BLOCKLEN;
  299. pbInput += DES_BLOCKLEN;
  300. pbOutput += DES_BLOCKLEN;
  301. }
  302. ((PUINT64) pbFeedback)[0] = chainBlock;
  303. }
  304. else
  305. {
  306. PUCHAR pBuffer;
  307. PUCHAR pOutBuffer;
  308. ULONGLONG SaveFeedBack;
  309. //
  310. // two cases for output:
  311. // input and output are separate buffers
  312. // input and output are same buffers
  313. //
  314. pBuffer = pbInput + Length - DES_BLOCKLEN;
  315. pOutBuffer = pbOutput + Length - DES_BLOCKLEN;
  316. SaveFeedBack = *(ULONGLONG *)pBuffer;
  317. while (pBuffer > pbInput) {
  318. FipsCipher(pOutBuffer, pBuffer, rgbTmpKeyTable, DECRYPT);
  319. ((PUINT64) pOutBuffer)[0] ^= *(ULONGLONG *)( pBuffer - DES_BLOCKLEN );
  320. pBuffer -= DES_BLOCKLEN;
  321. pOutBuffer -= DES_BLOCKLEN;
  322. }
  323. FipsCipher(pOutBuffer, pBuffer, rgbTmpKeyTable, DECRYPT);
  324. ((PUINT64) pOutBuffer)[0] ^= *(ULONGLONG *)pbFeedback;
  325. ((PUINT64) pbFeedback)[0] = SaveFeedBack;
  326. }
  327. RtlZeroMemory(rgbTmpKeyTable, DES3_TABLESIZE);
  328. Ret:
  329. return fRet;
  330. }
  331. //
  332. // Function: FipsHmacSHAInit
  333. //
  334. // Description: Initialize a SHA-HMAC context
  335. //
  336. VOID FipsHmacSHAInit(
  337. OUT A_SHA_CTX *pShaCtx,
  338. IN UCHAR *pKey,
  339. IN unsigned int cbKey)
  340. {
  341. PUCHAR key = pKey;
  342. ULONG key_len = cbKey;
  343. UCHAR k_ipad[MAX_LEN_PAD]; /* inner padding - key XORd with ipad */
  344. UCHAR tk[A_SHA_DIGEST_LEN];
  345. ULONG i;
  346. UCHAR tmpKey[MAX_KEYLEN_SHA];
  347. //
  348. // if key is longer than 64 bytes reset it to key=A_SHA_(key) */
  349. //
  350. if (key_len > MAX_KEYLEN_SHA) {
  351. A_SHA_CTX tctx;
  352. A_SHAInit(&tctx);
  353. A_SHAUpdate(&tctx, key, key_len);
  354. A_SHAFinal(&tctx, tk);
  355. key = tk;
  356. key_len = A_SHA_DIGEST_LEN;
  357. }
  358. // For FIPS compliance
  359. RtlCopyMemory(tmpKey, key, key_len);
  360. //
  361. // Zero out the scratch arrays
  362. //
  363. RtlZeroMemory(k_ipad, sizeof(k_ipad));
  364. RtlCopyMemory(k_ipad, tmpKey, key_len);
  365. //
  366. // XOR key with ipad and opad values
  367. //
  368. for (i = 0; i < MAX_KEYLEN_SHA/sizeof(unsigned __int64); i++) {
  369. ((unsigned __int64*)k_ipad)[i] ^= 0x3636363636363636;
  370. }
  371. //
  372. // Init the algorithm context
  373. //
  374. A_SHAInit(pShaCtx);
  375. //
  376. // Inner A_SHA_: start with inner pad
  377. //
  378. A_SHAUpdate(pShaCtx, k_ipad, MAX_KEYLEN_SHA);
  379. RtlZeroMemory(tmpKey, key_len);
  380. }
  381. //
  382. // Function: FipsHmacSHAUpdate
  383. //
  384. // Description: Add more data to a SHA-HMAC context
  385. //
  386. VOID FipsHmacSHAUpdate(
  387. IN OUT A_SHA_CTX *pShaCtx,
  388. IN UCHAR *pb,
  389. IN unsigned int cb)
  390. {
  391. A_SHAUpdate(pShaCtx, pb, cb);
  392. }
  393. //
  394. // Function: FipsHmacSHAFinal
  395. //
  396. // Description: Return result of SHA-HMAC
  397. //
  398. VOID FipsHmacSHAFinal(
  399. IN A_SHA_CTX *pShaCtx,
  400. IN UCHAR *pKey,
  401. IN unsigned int cbKey,
  402. OUT UCHAR *pHash)
  403. {
  404. UCHAR k_opad[MAX_LEN_PAD]; /* outer padding - key XORd with opad */
  405. UCHAR tk[A_SHA_DIGEST_LEN];
  406. PUCHAR key = pKey;
  407. ULONG key_len = cbKey;
  408. ULONG i;
  409. UCHAR tmpKey[MAX_KEYLEN_SHA];
  410. A_SHAFinal(pShaCtx, pHash);
  411. //
  412. // if key is longer than 64 bytes reset it to key=A_SHA_(key) */
  413. //
  414. if (key_len > MAX_KEYLEN_SHA) {
  415. A_SHA_CTX tctx;
  416. A_SHAInit(&tctx);
  417. A_SHAUpdate(&tctx, key, key_len);
  418. A_SHAFinal(&tctx, tk);
  419. key = tk;
  420. key_len = A_SHA_DIGEST_LEN;
  421. }
  422. // For FIPS Compliance
  423. RtlCopyMemory(tmpKey, key, key_len);
  424. RtlZeroMemory(k_opad, sizeof(k_opad));
  425. RtlCopyMemory(k_opad, tmpKey, key_len);
  426. //
  427. // XOR key with ipad and opad values
  428. //
  429. for (i = 0; i < MAX_KEYLEN_SHA/sizeof(unsigned __int64); i++) {
  430. ((unsigned __int64*)k_opad)[i] ^= 0x5c5c5c5c5c5c5c5c;
  431. }
  432. //
  433. // Now do outer A_SHA_
  434. //
  435. A_SHAInit(pShaCtx);
  436. //
  437. // start with outer pad
  438. //
  439. A_SHAUpdate(pShaCtx, k_opad, MAX_KEYLEN_SHA);
  440. //
  441. // then results of 1st hash
  442. //
  443. A_SHAUpdate(pShaCtx, pHash, A_SHA_DIGEST_LEN);
  444. A_SHAFinal(pShaCtx, pHash);
  445. RtlZeroMemory(tmpKey, key_len);
  446. }
  447. //
  448. // Function: HmacMD5Init
  449. //
  450. // Description: Initialize a MD5-HMAC context
  451. //
  452. VOID HmacMD5Init(
  453. OUT MD5_CTX *pMD5Ctx,
  454. IN UCHAR *pKey,
  455. IN unsigned int cbKey)
  456. {
  457. PUCHAR key = pKey;
  458. ULONG key_len = cbKey;
  459. UCHAR k_ipad[MAX_LEN_PAD]; /* inner padding - key XORd with ipad */
  460. UCHAR tk[MD5DIGESTLEN];
  461. ULONG i;
  462. //
  463. // if key is longer than 64 bytes reset it to key=MD5(key) */
  464. //
  465. if (key_len > MAX_KEYLEN_MD5) {
  466. MD5_CTX tctx;
  467. MD5Init(&tctx);
  468. MD5Update(&tctx, key, key_len);
  469. MD5Final(&tctx);
  470. //
  471. // Copy out the partial hash
  472. //
  473. RtlCopyMemory (tk, tctx.digest, MD5DIGESTLEN);
  474. key = tk;
  475. key_len = MD5DIGESTLEN;
  476. }
  477. //
  478. // Zero out the scratch arrays
  479. //
  480. RtlZeroMemory(k_ipad, sizeof(k_ipad));
  481. RtlCopyMemory(k_ipad, key, key_len);
  482. //
  483. // XOR key with ipad and opad values
  484. //
  485. for (i = 0; i < MAX_KEYLEN_MD5/sizeof(unsigned __int64); i++) {
  486. ((unsigned __int64*)k_ipad)[i] ^= 0x3636363636363636;
  487. }
  488. //
  489. // Init the algorithm context
  490. //
  491. MD5Init(pMD5Ctx);
  492. //
  493. // Inner MD5: start with inner pad
  494. //
  495. MD5Update(pMD5Ctx, k_ipad, MAX_KEYLEN_MD5);
  496. }
  497. //
  498. // Function: HmacMD5Update
  499. //
  500. // Description: Add more data to a MD5-HMAC context
  501. //
  502. VOID HmacMD5Update(
  503. IN OUT MD5_CTX *pMD5Ctx,
  504. IN UCHAR *pb,
  505. IN unsigned int cb)
  506. {
  507. MD5Update(pMD5Ctx, pb, cb);
  508. }
  509. //
  510. // Function: HmacMD5Final
  511. //
  512. // Description: Return result of MD5-HMAC
  513. //
  514. VOID HmacMD5Final(
  515. IN MD5_CTX *pMD5Ctx,
  516. IN UCHAR *pKey,
  517. IN unsigned int cbKey,
  518. OUT UCHAR *pHash)
  519. {
  520. UCHAR k_opad[MAX_LEN_PAD]; /* outer padding - key XORd with opad */
  521. UCHAR tk[MD5DIGESTLEN];
  522. PUCHAR key = pKey;
  523. ULONG key_len = cbKey;
  524. ULONG i;
  525. MD5Final(pMD5Ctx);
  526. //
  527. // Copy out the partial hash
  528. //
  529. RtlCopyMemory (pHash, pMD5Ctx->digest, MD5DIGESTLEN);
  530. //
  531. // if key is longer than 64 bytes reset it to key=MD5(key) */
  532. //
  533. if (key_len > MAX_KEYLEN_MD5) {
  534. MD5_CTX tctx;
  535. MD5Init(&tctx);
  536. MD5Update(&tctx, key, key_len);
  537. MD5Final(&tctx);
  538. //
  539. // Copy out the partial hash
  540. //
  541. RtlCopyMemory (tk, tctx.digest, MD5DIGESTLEN);
  542. key = tk;
  543. key_len = MD5DIGESTLEN;
  544. }
  545. RtlZeroMemory(k_opad, sizeof(k_opad));
  546. RtlCopyMemory(k_opad, key, key_len);
  547. //
  548. // XOR key with ipad and opad values
  549. //
  550. for (i = 0; i < MAX_KEYLEN_MD5/sizeof(unsigned __int64); i++) {
  551. ((unsigned __int64*)k_opad)[i] ^= 0x5c5c5c5c5c5c5c5c;
  552. }
  553. //
  554. // Now do outer MD5
  555. //
  556. MD5Init(pMD5Ctx);
  557. //
  558. // start with outer pad
  559. //
  560. MD5Update(pMD5Ctx, k_opad, MAX_KEYLEN_MD5);
  561. //
  562. // then results of 1st hash
  563. //
  564. MD5Update(pMD5Ctx, pHash, MD5DIGESTLEN);
  565. MD5Final(pMD5Ctx);
  566. RtlCopyMemory(pHash, pMD5Ctx->digest, MD5DIGESTLEN);
  567. }
  568. static UCHAR DSSPRIVATEKEYINIT[] =
  569. { 0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89,
  570. 0x98, 0xba, 0xdc, 0xfe, 0x10, 0x32, 0x54, 0x76,
  571. 0xc3, 0xd2, 0xe1, 0xf0};
  572. static UCHAR MODULUS[] =
  573. { 0xf5, 0xc1, 0x56, 0xb1, 0xd5, 0x48, 0x42, 0x2e,
  574. 0xbd, 0xa5, 0x44, 0x41, 0xc7, 0x1c, 0x24, 0x08,
  575. 0x3f, 0x80, 0x3c, 0x90};
  576. UCHAR g_rgbRNGState[A_SHA_DIGEST_LEN];
  577. //
  578. // Function : AddSeeds
  579. //
  580. // Description : This function adds the 160 bit seeds pointed to by pdwSeed1 and
  581. // pdwSeed2, it also adds 1 to this sum and mods the sum by
  582. // 2^160.
  583. //
  584. VOID AddSeeds(
  585. IN ULONG *pdwSeed1,
  586. IN OUT ULONG *pdwSeed2
  587. )
  588. {
  589. ULONG dwTmp;
  590. ULONG dwOverflow = 1;
  591. ULONG i;
  592. for (i = 0; i < 5; i++)
  593. {
  594. dwTmp = dwOverflow + pdwSeed1[i];
  595. dwOverflow = (dwOverflow > dwTmp);
  596. pdwSeed2[i] = pdwSeed2[i] + dwTmp;
  597. dwOverflow = ((dwTmp > pdwSeed2[i]) || dwOverflow);
  598. }
  599. }
  600. void SHA_mod_q(
  601. IN UCHAR *pbHash,
  602. IN UCHAR *pbQ,
  603. OUT UCHAR *pbNewHash
  604. )
  605. //
  606. // Given SHA(message), compute SHA(message) mod qdigit.
  607. // Output is in the interval [0, qdigit-1].
  608. // Although SHA(message) may exceed qdigit,
  609. // it cannot exceed 2*qdigit since the leftmost bit
  610. // of qdigit is 1.
  611. //
  612. {
  613. UCHAR rgbHash[A_SHA_DIGEST_LEN];
  614. if (-1 != Compare((DWORD*)rgbHash, // hash is greater so subtract
  615. (DWORD*)pbQ,
  616. A_SHA_DIGEST_LEN / sizeof(ULONG)))
  617. {
  618. Sub((DWORD*)pbNewHash,
  619. (DWORD*)rgbHash,
  620. (DWORD*)pbQ,
  621. A_SHA_DIGEST_LEN / sizeof(ULONG));
  622. }
  623. else
  624. {
  625. memcpy(pbNewHash, pbHash, A_SHA_DIGEST_LEN);
  626. }
  627. } // SHA_mod_q
  628. //
  629. // Function : RNG16BitStateCheck
  630. //
  631. // Description : This function compares each 160 bits of the buffer with
  632. // the next 160 bits and if they are the same the function
  633. // errors out. The IN buffer is expected to be A_SHA_DIGEST_LEN
  634. // bytes long. The function fails if the RNG is gets the same
  635. // input buffer of 160 bits twice in a row.
  636. //
  637. BOOL RNG16BitStateCheck(
  638. IN OUT ULONG *pdwOut,
  639. IN ULONG *pdwIn,
  640. IN ULONG cbNeeded
  641. )
  642. {
  643. BOOL fRet = FALSE;
  644. if (RtlEqualMemory(g_rgbRNGState, pdwIn, A_SHA_DIGEST_LEN))
  645. {
  646. RtlCopyMemory(g_rgbRNGState, (BYTE*)pdwIn, A_SHA_DIGEST_LEN);
  647. goto Ret;
  648. }
  649. RtlCopyMemory(g_rgbRNGState, (BYTE*)pdwIn, A_SHA_DIGEST_LEN);
  650. RtlCopyMemory((BYTE*)pdwOut, (BYTE*)pdwIn, cbNeeded);
  651. fRet = TRUE;
  652. Ret:
  653. return fRet;
  654. }
  655. //
  656. // Function : FIPSGenRandom
  657. //
  658. // Description : FIPS 186 RNG, the seed is generated by calling NewGenRandom.
  659. //
  660. BOOL FIPSGenRandom(
  661. IN OUT UCHAR *pb,
  662. IN ULONG cb
  663. )
  664. {
  665. ULONG rgdwSeed[A_SHA_DIGEST_LEN/sizeof(ULONG)]; // 160 bits
  666. ULONG rgdwNewSeed[A_SHA_DIGEST_LEN/sizeof(ULONG)]; // 160 bits
  667. A_SHA_CTX SHACtxt;
  668. UCHAR rgbBuf[A_SHA_DIGEST_LEN];
  669. ULONG cbBuf;
  670. UCHAR *pbTmp = pb;
  671. ULONG cbTmp = cb;
  672. ULONG i;
  673. BOOL fRet = FALSE;
  674. while (cbTmp)
  675. {
  676. // get a 160 bit random seed
  677. if (! NewGenRandom(
  678. NULL, NULL, (BYTE*)rgdwNewSeed, sizeof(rgdwNewSeed)))
  679. {
  680. goto Ret;
  681. }
  682. for (i = 0; i < A_SHA_DIGEST_LEN/sizeof(ULONG); i++)
  683. {
  684. rgdwSeed[i] ^= rgdwNewSeed[i];
  685. }
  686. A_SHAInit (&SHACtxt);
  687. RtlCopyMemory(SHACtxt.state, DSSPRIVATEKEYINIT, A_SHA_DIGEST_LEN);
  688. // perform the one way function
  689. A_SHAUpdate(&SHACtxt, (BYTE*)rgdwSeed, sizeof(rgdwSeed));
  690. A_SHAFinal(&SHACtxt, rgbBuf);
  691. // continuous 16 bit state check
  692. if (A_SHA_DIGEST_LEN < cbTmp)
  693. {
  694. cbBuf = A_SHA_DIGEST_LEN;
  695. }
  696. else
  697. {
  698. cbBuf = cbTmp;
  699. }
  700. if (!RNG16BitStateCheck((ULONG*)pbTmp, (ULONG*)rgbBuf, cbBuf))
  701. {
  702. goto Ret;
  703. }
  704. pbTmp += cbBuf;
  705. cbTmp -= cbBuf;
  706. if (0 == cbTmp)
  707. break;
  708. // modular reduction with modulus Q
  709. SHA_mod_q(rgbBuf, MODULUS, (UCHAR*)rgdwNewSeed);
  710. // (1 + previous seed + new random) mod 2^160
  711. AddSeeds(rgdwNewSeed, rgdwSeed);
  712. }
  713. fRet = TRUE;
  714. Ret:
  715. return fRet;
  716. }