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.

1339 lines
38 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // FILE : swnt_pk.c //
  3. // DESCRIPTION : //
  4. // Software nametag public key management functions. These functions //
  5. // isolate the peculiarities of public key management without a token //
  6. // //
  7. // AUTHOR : //
  8. // HISTORY : //
  9. // Jan 25 1995 larrys Changed from Nametag //
  10. // Mar 01 1995 terences Fixed key pair handle creation //
  11. // Mar 08 1995 larrys Fixed warning //
  12. // Mar 23 1995 larrys Added variable key length //
  13. // Apr 17 1995 larrys Added 1024 key gen //
  14. // Apr 19 1995 larrys Changed CRYPT_EXCH_PUB to AT_KEYEXCHANGE //
  15. // Aug 16 1995 larrys Removed exchange key stuff //
  16. // Sep 12 1995 larrys Removed 2 DWORDS from exported keys //
  17. // Sep 28 1995 larrys Changed format of PKCS //
  18. // Oct 04 1995 larrys Fixed problem with PKCS format //
  19. // Oct 27 1995 rajeshk RandSeed Stuff added hUID to PKCS2Encrypt //
  20. // Nov 3 1995 larrys Merge for NT checkin //
  21. // Dec 11 1995 larrys Added check for error return from RSA routine //
  22. // May 15 1996 larrys Changed NTE_NO_MEMORY to ERROR_NOT_ENOUGHT... //
  23. // Oct 14 1996 jeffspel Changed GenRandoms to NewGenRandoms //
  24. // May 8 2000 dbarlow Reworked status return codes //
  25. // //
  26. // Copyright (C) 1993 - 2000, Microsoft Corporation //
  27. // All Rights Reserved //
  28. /////////////////////////////////////////////////////////////////////////////
  29. #include "precomp.h"
  30. #include "randlib.h"
  31. #include "ntagum.h"
  32. #include "swnt_pk.h"
  33. #include "protstor.h"
  34. #include "sha.h"
  35. #define GetNextAlignedValue(c, alignment) ((c + alignment) & ~(alignment - 1))
  36. extern CSP_STRINGS g_Strings;
  37. extern void
  38. FIPS186GenRandomWithException(
  39. IN HANDLE *phRNGDriver,
  40. IN BYTE **ppbContextSeed,
  41. IN DWORD *pcbContextSeed,
  42. IN OUT BYTE *pb,
  43. IN DWORD cb);
  44. // do the modular exponentiation calculation M^PubKey mod N
  45. DWORD
  46. RSAPublicEncrypt(
  47. IN PEXPO_OFFLOAD_STRUCT pOffloadInfo,
  48. IN BSAFE_PUB_KEY *pBSPubKey,
  49. IN BYTE *pbInput,
  50. IN BYTE *pbOutput)
  51. {
  52. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  53. BOOL fOffloadSuccess = FALSE;
  54. DWORD cbMod;
  55. //
  56. // Two checks (needed for FIPS) before offloading to the offload
  57. // module.
  58. //
  59. // First check is if there is an offload module, this
  60. // will only be the case if the pOffloadInfo is not NULL.
  61. //
  62. // Second check is if this public key is OK, by checking
  63. // the magic value in the key struct.
  64. //
  65. if (NULL != pOffloadInfo)
  66. {
  67. if (RSA1 != pBSPubKey->magic)
  68. {
  69. dwReturn = (DWORD)NTE_BAD_KEY;
  70. goto ErrorExit;
  71. }
  72. cbMod = (pBSPubKey->bitlen + 7) / 8;
  73. fOffloadSuccess = ModularExpOffload(pOffloadInfo,
  74. pbInput,
  75. (BYTE*)&(pBSPubKey->pubexp),
  76. sizeof(pBSPubKey->pubexp),
  77. (BYTE*)pBSPubKey +
  78. sizeof(BSAFE_PUB_KEY),
  79. cbMod, pbOutput, NULL, 0);
  80. }
  81. if (!fOffloadSuccess)
  82. {
  83. if (!BSafeEncPublic(pBSPubKey, pbInput, pbOutput))
  84. {
  85. dwReturn = ERROR_NOT_ENOUGH_MEMORY; // ?Really?
  86. goto ErrorExit;
  87. }
  88. }
  89. dwReturn = ERROR_SUCCESS;
  90. ErrorExit:
  91. return dwReturn;
  92. }
  93. // do the modular exponentiation calculation M^PrivKey Exponent mod N
  94. DWORD
  95. RSAPrivateDecrypt(
  96. IN PEXPO_OFFLOAD_STRUCT pOffloadInfo,
  97. IN BSAFE_PRV_KEY *pBSPrivKey,
  98. IN BYTE *pbInput,
  99. IN BYTE *pbOutput)
  100. {
  101. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  102. BOOL fOffloadSuccess = FALSE;
  103. DWORD cbMod;
  104. DWORD cbHalfKeylen;
  105. OFFLOAD_PRIVATE_KEY OffloadPrivateKey;
  106. //
  107. // Two checks (needed for FIPS) before offloading to the offload
  108. // module.
  109. //
  110. // First check is if there is an offload module, this
  111. // will only be the case if the pOffloadInfo is not NULL.
  112. //
  113. // Second check is if this private key is OK, by checking
  114. // the magic value in the key struct.
  115. //
  116. if (NULL != pOffloadInfo)
  117. {
  118. if (RSA2 != pBSPrivKey->magic)
  119. {
  120. dwReturn = (DWORD)NTE_BAD_KEY;
  121. goto ErrorExit;
  122. }
  123. cbMod = (pBSPrivKey->bitlen + 7) / 8;
  124. cbHalfKeylen = (pBSPrivKey->keylen + 1) / 2;
  125. OffloadPrivateKey.dwVersion = CUR_OFFLOAD_VERSION;
  126. OffloadPrivateKey.pbPrime1 =
  127. (BYTE*)pBSPrivKey + sizeof(BSAFE_PRV_KEY) + cbHalfKeylen * 2;
  128. OffloadPrivateKey.cbPrime1 = cbHalfKeylen;
  129. OffloadPrivateKey.pbPrime2 =
  130. (BYTE*)pBSPrivKey + sizeof(BSAFE_PRV_KEY) + cbHalfKeylen * 3;
  131. OffloadPrivateKey.cbPrime2 = cbHalfKeylen;
  132. fOffloadSuccess = ModularExpOffload(pOffloadInfo,
  133. pbInput,
  134. (BYTE*)pBSPrivKey + sizeof(BSAFE_PUB_KEY)
  135. + cbHalfKeylen * 7,
  136. cbMod,
  137. (BYTE*)pBSPrivKey + sizeof(BSAFE_PUB_KEY),
  138. cbMod, pbOutput, (PVOID) &OffloadPrivateKey, 0);
  139. }
  140. if (!fOffloadSuccess)
  141. {
  142. if (!BSafeDecPrivate(pBSPrivKey, pbInput, pbOutput))
  143. {
  144. dwReturn = ERROR_NOT_ENOUGH_MEMORY; // ?Really?
  145. goto ErrorExit;
  146. }
  147. }
  148. dwReturn = ERROR_SUCCESS;
  149. ErrorExit:
  150. return dwReturn;
  151. }
  152. BOOL
  153. CheckDataLenForRSAEncrypt(
  154. IN DWORD cbMod, // length of the modulus
  155. IN DWORD cbData, // length of the data
  156. IN DWORD dwFlags) // flags
  157. {
  158. BOOL fRet = FALSE;
  159. if (dwFlags & CRYPT_OAEP)
  160. {
  161. // if the OAEP flag is set then check for that length
  162. if (cbMod < (cbData + A_SHA_DIGEST_LEN * 2 + 1))
  163. goto ErrorExit;
  164. }
  165. else
  166. {
  167. // Check for PKCS 1 type 2 padding
  168. // one byte for the top zero byte, one byte for the type,
  169. // and one byte for the low zero byte,
  170. // plus a minimum padding string is 8 bytes
  171. if (cbMod < (cbData + 11))
  172. goto ErrorExit;
  173. }
  174. fRet = TRUE;
  175. ErrorExit:
  176. return fRet;
  177. }
  178. /************************************************************************/
  179. /* MaskGeneration generates a mask for OAEP based on the SHA1 hash */
  180. /* function. */
  181. /* NULL for the ppbMask parameter indicates the buffer is to be alloced.*/
  182. /************************************************************************/
  183. /*static*/ DWORD
  184. MaskGeneration(
  185. IN BYTE *pbSeed,
  186. IN DWORD cbSeed,
  187. IN DWORD cbMask,
  188. OUT BYTE **ppbMask,
  189. IN BOOL fAlloc)
  190. {
  191. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  192. DWORD dwCount;
  193. BYTE rgbCount[sizeof(DWORD)];
  194. BYTE *pbCount;
  195. A_SHA_CTX SHA1Ctxt;
  196. DWORD cb = cbMask;
  197. BYTE *pb;
  198. DWORD i;
  199. DWORD j;
  200. // NULL for *ppbMask indicates the buffer is to be alloced
  201. if (fAlloc)
  202. {
  203. *ppbMask = (BYTE*)_nt_malloc(cbMask);
  204. if (NULL == *ppbMask)
  205. {
  206. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  207. goto ErrorExit;
  208. }
  209. }
  210. pb = *ppbMask;
  211. dwCount = (cbMask + (A_SHA_DIGEST_LEN - 1)) / A_SHA_DIGEST_LEN;
  212. for (i = 0; i < dwCount; i++)
  213. {
  214. // clear the hash context
  215. memset(&SHA1Ctxt, 0, sizeof(SHA1Ctxt));
  216. // hash the seed and the count
  217. A_SHAInit(&SHA1Ctxt);
  218. A_SHAUpdate(&SHA1Ctxt, pbSeed, cbSeed);
  219. // Reverse the count bytes
  220. pbCount = (BYTE*)&i;
  221. for (j = 0; j < sizeof(DWORD); j++)
  222. rgbCount[j] = pbCount[sizeof(DWORD) - j - 1];
  223. A_SHAUpdate(&SHA1Ctxt, rgbCount, sizeof(DWORD));
  224. A_SHAFinal(&SHA1Ctxt, SHA1Ctxt.HashVal);
  225. // copy the bytes from this hash into the mask buffer
  226. if (cb >= A_SHA_DIGEST_LEN)
  227. memcpy(pb, SHA1Ctxt.HashVal, A_SHA_DIGEST_LEN);
  228. else
  229. {
  230. memcpy(pb, SHA1Ctxt.HashVal, cb);
  231. break;
  232. }
  233. cb -= A_SHA_DIGEST_LEN;
  234. pb += A_SHA_DIGEST_LEN;
  235. }
  236. dwReturn = ERROR_SUCCESS;
  237. ErrorExit:
  238. return dwReturn;
  239. }
  240. /************************************************************************/
  241. /* ApplyPadding applies OAEP (Bellare-Rogoway) padding to a RSA key */
  242. /* blob. The function does the seed generation, MGF and masking. */
  243. /************************************************************************/
  244. /*static*/ DWORD
  245. ApplyPadding(
  246. IN PNTAGUserList pTmpUser,
  247. IN OUT BYTE* pb, // buffer
  248. IN DWORD cb) // length of the data to mask not including seed
  249. {
  250. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  251. BYTE rgbSeed[A_SHA_DIGEST_LEN];
  252. BYTE *pbMask = NULL;
  253. BYTE rgbSeedMask[A_SHA_DIGEST_LEN];
  254. BYTE *pbSeedMask;
  255. DWORD i;
  256. DWORD dwSts;
  257. // generate the random seed
  258. dwSts = FIPS186GenRandom(&pTmpUser->hRNGDriver,
  259. &pTmpUser->ContInfo.pbRandom,
  260. &pTmpUser->ContInfo.ContLens.cbRandom,
  261. rgbSeed, A_SHA_DIGEST_LEN);
  262. if (ERROR_SUCCESS != dwSts)
  263. {
  264. dwReturn = dwSts; // NTE_FAIL
  265. goto ErrorExit;
  266. }
  267. // generate the data mask from the seed
  268. dwSts = MaskGeneration(rgbSeed, sizeof(rgbSeed), cb, &pbMask, TRUE);
  269. if (ERROR_SUCCESS != dwSts)
  270. {
  271. dwReturn = dwSts;
  272. goto ErrorExit;
  273. }
  274. // XOR the data mask with the data
  275. for (i = 0; i < cb; i++)
  276. pb[i + A_SHA_DIGEST_LEN + 1] = (BYTE)(pb[i + A_SHA_DIGEST_LEN + 1] ^ pbMask[i]);
  277. // generate the seed mask from the masked data
  278. pbSeedMask = rgbSeedMask;
  279. dwSts = MaskGeneration(pb + A_SHA_DIGEST_LEN + 1, cb,
  280. A_SHA_DIGEST_LEN, &pbSeedMask, FALSE);
  281. if (ERROR_SUCCESS != dwSts)
  282. {
  283. dwReturn = dwSts;
  284. goto ErrorExit;
  285. }
  286. // XOR the seed mask with the seed and put that into the
  287. // pb buffer
  288. for (i = 0; i < A_SHA_DIGEST_LEN; i++)
  289. pb[i + 1] = (BYTE)(rgbSeed[i] ^ rgbSeedMask[i]);
  290. dwReturn = ERROR_SUCCESS;
  291. ErrorExit:
  292. if (pbMask)
  293. _nt_free(pbMask, cb);
  294. return dwReturn;
  295. }
  296. /************************************************************************/
  297. /* RemovePadding checks OAEP (Bellare-Rogoway) padding on a RSA decrypt */
  298. /* blob. */
  299. /************************************************************************/
  300. /*static*/ DWORD
  301. RemovePadding(
  302. IN OUT BYTE* pb,
  303. IN DWORD cb)
  304. {
  305. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  306. BYTE rgbSeedMask[A_SHA_DIGEST_LEN];
  307. BYTE *pbSeedMask;
  308. BYTE *pbMask = NULL;
  309. DWORD i;
  310. DWORD dwSts;
  311. memset(rgbSeedMask, 0, A_SHA_DIGEST_LEN);
  312. // check the most significant byte is 0x00
  313. if (0x00 != pb[0])
  314. {
  315. dwReturn = (DWORD)NTE_BAD_DATA;
  316. goto ErrorExit;
  317. }
  318. // generate the seed mask from the masked data
  319. pbSeedMask = rgbSeedMask;
  320. dwSts = MaskGeneration(pb + A_SHA_DIGEST_LEN + 1, cb - (A_SHA_DIGEST_LEN + 1),
  321. A_SHA_DIGEST_LEN, &pbSeedMask, FALSE);
  322. if (ERROR_SUCCESS != dwSts)
  323. {
  324. dwReturn = dwSts;
  325. goto ErrorExit;
  326. }
  327. // XOR the seed mask with the seed and put that into the
  328. // pb buffer
  329. for (i = 0; i < A_SHA_DIGEST_LEN; i++)
  330. pb[i + 1] = (BYTE)(pb[i + 1] ^ rgbSeedMask[i]);
  331. // generate the data mask from the seed
  332. dwSts = MaskGeneration(pb + 1, A_SHA_DIGEST_LEN,
  333. cb - (A_SHA_DIGEST_LEN + 1), &pbMask, TRUE);
  334. if (ERROR_SUCCESS != dwSts)
  335. {
  336. dwReturn = dwSts;
  337. goto ErrorExit;
  338. }
  339. // XOR the data mask with the data
  340. for (i = 0; i < cb - (A_SHA_DIGEST_LEN + 1); i++)
  341. {
  342. pb[i + A_SHA_DIGEST_LEN + 1] =
  343. (BYTE)(pb[i + A_SHA_DIGEST_LEN + 1] ^ pbMask[i]);
  344. }
  345. dwReturn = ERROR_SUCCESS;
  346. ErrorExit:
  347. if (pbMask)
  348. _nt_free(pbMask, cb - (A_SHA_DIGEST_LEN + 1));
  349. return dwReturn;
  350. }
  351. /************************************************************************/
  352. /* OAEPEncrypt performs a RSA encryption using OAEP (Bellare-Rogoway) */
  353. /* as the padding scheme. The current implementation uses SHA1 as the */
  354. /* hash function. */
  355. /************************************************************************/
  356. /*static*/ DWORD
  357. OAEPEncrypt(
  358. IN PNTAGUserList pTmpUser,
  359. IN BSAFE_PUB_KEY *pBSPubKey,
  360. IN BYTE *pbPlaintext,
  361. IN DWORD cbPlaintext,
  362. IN BYTE *pbParams,
  363. IN DWORD cbParams,
  364. OUT BYTE *pbOut)
  365. {
  366. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  367. BYTE *pbInput = NULL;
  368. BYTE *pbOutput = NULL;
  369. BYTE *pbReverse = NULL;
  370. A_SHA_CTX SHA1Ctxt;
  371. DWORD i;
  372. DWORD cb;
  373. DWORD dwSts;
  374. memset(&SHA1Ctxt, 0, sizeof(SHA1Ctxt));
  375. // start off by hashing the Encoding parameters (pbParams)
  376. A_SHAInit(&SHA1Ctxt);
  377. if (0 != cbParams)
  378. A_SHAUpdate(&SHA1Ctxt, pbParams, cbParams);
  379. A_SHAFinal(&SHA1Ctxt, SHA1Ctxt.HashVal);
  380. // alloc space for an internal buffer
  381. pbInput = (BYTE *)_nt_malloc(pBSPubKey->keylen * 2
  382. + ((pBSPubKey->bitlen + 7) / 8));
  383. if (NULL == pbInput)
  384. {
  385. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  386. goto ErrorExit;
  387. }
  388. pbOutput = pbInput + pBSPubKey->keylen;
  389. pbReverse = pbInput + pBSPubKey->keylen * 2;
  390. // add the pHash
  391. memcpy(pbReverse + A_SHA_DIGEST_LEN + 1, SHA1Ctxt.HashVal,
  392. A_SHA_DIGEST_LEN);
  393. // figure the length of PS,
  394. // put the 0x01 byte in, skipping past the PS,
  395. // note that the PS is zero bytes so it is just there
  396. cb = ((pBSPubKey->bitlen + 7) / 8) - (1 + cbPlaintext);
  397. pbReverse[cb] = 0x01;
  398. cb++;
  399. // copy in the message bytes
  400. memcpy(pbReverse + cb, pbPlaintext, cbPlaintext);
  401. // do the seed generation, MGF and masking
  402. cb = ((pBSPubKey->bitlen + 7) / 8) - (A_SHA_DIGEST_LEN + 1);
  403. dwSts = ApplyPadding(pTmpUser, pbReverse, cb);
  404. if (ERROR_SUCCESS != dwSts)
  405. {
  406. dwReturn = dwSts;
  407. goto ErrorExit;
  408. }
  409. // byte reverse the whole thing before RSA encrypting
  410. for (i = 0; i < (pBSPubKey->bitlen + 7) / 8; i++)
  411. pbInput[i] = pbReverse[((pBSPubKey->bitlen + 7) / 8) - i - 1];
  412. // RSA encrypt this
  413. dwSts = RSAPublicEncrypt(pTmpUser->pOffloadInfo, pBSPubKey,
  414. pbInput, pbOutput);
  415. if (ERROR_SUCCESS != dwSts)
  416. {
  417. dwReturn = dwSts; // NTE_FAIL
  418. goto ErrorExit;
  419. }
  420. memcpy(pbOut, pbOutput, (pBSPubKey->bitlen + 7) / 8);
  421. dwReturn = ERROR_SUCCESS;
  422. ErrorExit:
  423. if (pbInput)
  424. {
  425. memset(pbInput, 0, pBSPubKey->keylen * 2 + (pBSPubKey->bitlen + 7) / 8);
  426. _nt_free(pbInput, pBSPubKey->keylen * 2 + (pBSPubKey->bitlen + 7) / 8);
  427. }
  428. return dwReturn;
  429. }
  430. /************************************************************************/
  431. /* OAEPDecrypt performs a RSA decryption checking that OAEP */
  432. /* (Bellare-Rogoway) is the padding scheme. The current implementation */
  433. /* uses SHA1 as the hash function. */
  434. /************************************************************************/
  435. /*static*/ DWORD
  436. OAEPDecrypt(
  437. IN PNTAGUserList pTmpUser,
  438. IN BSAFE_PRV_KEY *pBSPrivKey,
  439. IN CONST BYTE *pbBlob,
  440. IN DWORD cbBlob,
  441. IN BYTE *pbParams,
  442. IN DWORD cbParams,
  443. OUT BYTE **ppbPlaintext,
  444. OUT DWORD *pcbPlaintext)
  445. {
  446. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  447. BYTE* pbOutput = NULL;
  448. BYTE* pbInput = NULL;
  449. BYTE* pbReverse = NULL;
  450. A_SHA_CTX SHA1Ctxt;
  451. DWORD cb;
  452. DWORD i;
  453. DWORD dwSts;
  454. DWORD dwAlignedBufLen = 0;
  455. memset(&SHA1Ctxt, 0, sizeof(SHA1Ctxt));
  456. cb = (pBSPrivKey->bitlen + 7) / 8;
  457. if (cbBlob > cb)
  458. {
  459. dwReturn = (DWORD)NTE_BAD_DATA;
  460. goto ErrorExit;
  461. }
  462. dwAlignedBufLen = GetNextAlignedValue(pBSPrivKey->keylen + 2, sizeof(DWORD));
  463. pbOutput = (BYTE *)_nt_malloc(dwAlignedBufLen * 2 + cb);
  464. if (NULL == pbOutput)
  465. {
  466. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  467. goto ErrorExit;
  468. }
  469. pbInput = pbOutput + dwAlignedBufLen;
  470. pbReverse = pbOutput + dwAlignedBufLen * 2;
  471. // perform the RSA decryption
  472. memcpy(pbInput, pbBlob, cb);
  473. dwSts = RSAPrivateDecrypt(pTmpUser->pOffloadInfo, pBSPrivKey,
  474. pbInput, pbOutput);
  475. if (ERROR_SUCCESS != dwSts)
  476. {
  477. dwReturn = dwSts; // NTE_FAIL
  478. goto ErrorExit;
  479. }
  480. for (i = 0; i < cb; i++)
  481. pbReverse[i] = pbOutput[cb - i - 1];
  482. // remove OAEP (Bellare-Rogoway) padding
  483. dwSts = RemovePadding(pbReverse, cb);
  484. if (ERROR_SUCCESS != dwSts)
  485. {
  486. dwReturn = dwSts; // NTE_FAIL
  487. goto ErrorExit;
  488. }
  489. // hash the Encoding parameters (pbParams)
  490. A_SHAInit(&SHA1Ctxt);
  491. if (0 != cbParams)
  492. A_SHAUpdate(&SHA1Ctxt, pbParams, cbParams);
  493. A_SHAFinal(&SHA1Ctxt, SHA1Ctxt.HashVal);
  494. // check the hash of the encoding parameters against the message
  495. if (0 != memcmp(SHA1Ctxt.HashVal, pbReverse + A_SHA_DIGEST_LEN + 1,
  496. A_SHA_DIGEST_LEN))
  497. {
  498. dwReturn = (DWORD)NTE_BAD_DATA;
  499. goto ErrorExit;
  500. }
  501. // check the zero bytes and check the 0x01 byte
  502. for (i = A_SHA_DIGEST_LEN * 2 + 1; i < cb; i++)
  503. {
  504. if (0x01 == pbReverse[i])
  505. {
  506. i++;
  507. break;
  508. }
  509. else if (0x00 != pbReverse[i])
  510. {
  511. dwReturn = (DWORD)NTE_BAD_DATA;
  512. goto ErrorExit;
  513. }
  514. }
  515. *pcbPlaintext = cb - i;
  516. *ppbPlaintext = (BYTE*)_nt_malloc(*pcbPlaintext);
  517. if (NULL == *ppbPlaintext)
  518. {
  519. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  520. goto ErrorExit;
  521. }
  522. memcpy(*ppbPlaintext, pbReverse + i, *pcbPlaintext);
  523. dwReturn = ERROR_SUCCESS;
  524. ErrorExit:
  525. // scrub the output buffer
  526. if (pbOutput)
  527. {
  528. memset(pbOutput, 0, dwAlignedBufLen * 2 + cb);
  529. _nt_free(pbOutput, dwAlignedBufLen * 2 + cb);
  530. }
  531. return dwReturn;
  532. }
  533. /*static*/ DWORD
  534. PKCS2Encrypt(
  535. PNTAGUserList pTmpUser,
  536. DWORD dwFlags,
  537. BSAFE_PUB_KEY *pKey,
  538. BYTE *InBuf,
  539. DWORD InBufLen,
  540. BYTE *OutBuf)
  541. {
  542. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  543. BYTE *pScratch = NULL;
  544. BYTE *pScratch2 = NULL;
  545. BYTE *pLocal;
  546. DWORD temp;
  547. DWORD z;
  548. DWORD dwSts;
  549. pScratch = (BYTE *)_nt_malloc(pKey->keylen);
  550. if (NULL == pScratch)
  551. {
  552. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  553. goto ErrorExit;
  554. }
  555. pScratch2 = (BYTE *)_nt_malloc(pKey->keylen);
  556. if (NULL == pScratch2)
  557. {
  558. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  559. goto ErrorExit;
  560. }
  561. memset(pScratch, 0, pKey->keylen);
  562. pScratch[pKey->datalen - 1] = PKCS_BLOCKTYPE_2;
  563. dwSts = FIPS186GenRandom(&pTmpUser->hRNGDriver,
  564. &pTmpUser->ContInfo.pbRandom,
  565. &pTmpUser->ContInfo.ContLens.cbRandom,
  566. pScratch+InBufLen+1,
  567. (pKey->datalen)-InBufLen-2);
  568. if (ERROR_SUCCESS != dwSts)
  569. {
  570. dwReturn = dwSts; // NTE_FAIL
  571. goto ErrorExit;
  572. }
  573. pLocal = pScratch + InBufLen + 1;
  574. // Need to insure that none of the padding bytes are zero.
  575. temp = pKey->datalen - InBufLen - 2;
  576. while (temp)
  577. {
  578. if (*pLocal == 0)
  579. {
  580. dwSts = FIPS186GenRandom(&pTmpUser->hRNGDriver,
  581. &pTmpUser->ContInfo.pbRandom,
  582. &pTmpUser->ContInfo.ContLens.cbRandom,
  583. pLocal, 1);
  584. if (ERROR_SUCCESS != dwSts)
  585. {
  586. dwReturn = dwSts; // NTE_FAIL
  587. goto ErrorExit;
  588. }
  589. }
  590. else
  591. {
  592. pLocal++;
  593. temp--;
  594. }
  595. }
  596. #ifdef CSP_USE_SSL3
  597. // if SSL2_FALLBACK has been specified then put threes in the 8
  598. // least significant bytes of the random padding
  599. if (CRYPT_SSL2_FALLBACK & dwFlags)
  600. memset(pScratch + InBufLen + 1, 0x03, 8);
  601. #endif
  602. // Reverse the session key bytes
  603. for (z = 0; z < InBufLen; ++z)
  604. pScratch[z] = InBuf[InBufLen - z - 1];
  605. dwSts = RSAPublicEncrypt(pTmpUser->pOffloadInfo,
  606. pKey, pScratch, pScratch2);
  607. if (ERROR_SUCCESS != dwSts)
  608. {
  609. dwReturn = dwSts;
  610. goto ErrorExit;
  611. }
  612. memcpy(OutBuf, pScratch2, (pKey->bitlen + 7) / 8);
  613. dwReturn = ERROR_SUCCESS;
  614. ErrorExit:
  615. if (pScratch)
  616. _nt_free(pScratch, pKey->keylen);
  617. if (pScratch2)
  618. _nt_free(pScratch2, pKey->keylen);
  619. return dwReturn;
  620. }
  621. /*static*/ DWORD
  622. PKCS2Decrypt(
  623. IN PNTAGUserList pTmpUser,
  624. IN BSAFE_PRV_KEY *pKey,
  625. IN DWORD dwFlags,
  626. IN CONST BYTE *InBuf,
  627. OUT BYTE **ppbOutBuf,
  628. OUT DWORD *pcbOutBuf)
  629. {
  630. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  631. DWORD i;
  632. BYTE *pScratch = NULL;
  633. BYTE *pScratch2 = NULL;
  634. DWORD z;
  635. DWORD dwSts;
  636. pScratch = (BYTE *)_nt_malloc(pKey->keylen * 2);
  637. if (NULL == pScratch)
  638. {
  639. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  640. goto ErrorExit;
  641. }
  642. pScratch2 = pScratch + pKey->keylen;
  643. memcpy(pScratch2, InBuf, (pKey->bitlen + 7) / 8);
  644. dwSts = RSAPrivateDecrypt(pTmpUser->pOffloadInfo, pKey,
  645. pScratch2, pScratch);
  646. if (ERROR_SUCCESS != dwSts)
  647. {
  648. dwReturn = dwSts; // NTE_FAIL
  649. goto ErrorExit;
  650. }
  651. if ((pScratch[pKey->datalen - 1] != PKCS_BLOCKTYPE_2) ||
  652. (pScratch[pKey->datalen] != 0))
  653. {
  654. dwReturn = (DWORD) NTE_BAD_DATA;
  655. goto ErrorExit;
  656. }
  657. i = pKey->datalen - 2;
  658. while ((i > 0) && (pScratch[i]))
  659. i--;
  660. *ppbOutBuf = (BYTE *)_nt_malloc(i);
  661. if (NULL == *ppbOutBuf)
  662. {
  663. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  664. goto ErrorExit;
  665. }
  666. *pcbOutBuf = i;
  667. #ifdef CSP_USE_SSL3
  668. // if SSL2_FALLBACK has been specified then check if threes
  669. // are in the 8 least significant bytes of the random padding
  670. if (CRYPT_SSL2_FALLBACK & dwFlags)
  671. {
  672. BOOL fFallbackError = TRUE;
  673. for (z = i + 1; z < i + 9; z++)
  674. {
  675. if (0x03 != pScratch[z])
  676. {
  677. fFallbackError = FALSE;
  678. break;
  679. }
  680. }
  681. if (fFallbackError)
  682. {
  683. dwReturn = (DWORD)NTE_BAD_VER;
  684. goto ErrorExit;
  685. }
  686. }
  687. #endif
  688. // Reverse the session key bytes
  689. for (z = 0; z < i; ++z)
  690. (*ppbOutBuf)[z] = pScratch[i - z - 1];
  691. dwReturn = ERROR_SUCCESS;
  692. ErrorExit:
  693. if (pScratch)
  694. _nt_free(pScratch, pKey->keylen);
  695. return dwReturn;
  696. }
  697. /************************************************************************/
  698. /* RSAEncrypt performs a RSA encryption. */
  699. /************************************************************************/
  700. DWORD
  701. RSAEncrypt(
  702. IN PNTAGUserList pTmpUser,
  703. IN BSAFE_PUB_KEY *pBSPubKey,
  704. IN BYTE *pbPlaintext,
  705. IN DWORD cbPlaintext,
  706. IN BYTE *pbParams,
  707. IN DWORD cbParams,
  708. IN DWORD dwFlags,
  709. OUT BYTE *pbOut)
  710. {
  711. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  712. DWORD dwSts;
  713. // check the length of the data
  714. if (!CheckDataLenForRSAEncrypt((pBSPubKey->bitlen + 7) / 8,
  715. cbPlaintext, dwFlags))
  716. {
  717. dwReturn = (DWORD)NTE_BAD_LEN;
  718. goto ErrorExit;
  719. }
  720. // use OAEP if the flag is set
  721. if (dwFlags & CRYPT_OAEP)
  722. {
  723. // use OAEP if the flag is set
  724. dwSts = OAEPEncrypt(pTmpUser, pBSPubKey, pbPlaintext,
  725. cbPlaintext, pbParams, cbParams, pbOut);
  726. if (ERROR_SUCCESS != dwSts)
  727. {
  728. dwReturn = dwSts;
  729. goto ErrorExit;
  730. }
  731. }
  732. else
  733. {
  734. // use PKCS #1 Type 2
  735. dwSts = PKCS2Encrypt(pTmpUser, dwFlags, pBSPubKey,
  736. pbPlaintext, cbPlaintext, pbOut);
  737. if (ERROR_SUCCESS != dwSts)
  738. {
  739. dwReturn = dwSts;
  740. goto ErrorExit;
  741. }
  742. }
  743. dwReturn = ERROR_SUCCESS;
  744. ErrorExit:
  745. return dwReturn;
  746. }
  747. /************************************************************************/
  748. /* RSADecrypt performs a RSA decryption. */
  749. /************************************************************************/
  750. DWORD
  751. RSADecrypt(
  752. IN PNTAGUserList pTmpUser,
  753. IN BSAFE_PRV_KEY *pBSPrivKey,
  754. IN CONST BYTE *pbBlob,
  755. IN DWORD cbBlob,
  756. IN BYTE *pbParams,
  757. IN DWORD cbParams,
  758. IN DWORD dwFlags,
  759. OUT BYTE **ppbPlaintext,
  760. OUT DWORD *pcbPlaintext)
  761. {
  762. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  763. DWORD dwSts;
  764. // use OAEP if the flag is set
  765. if (dwFlags & CRYPT_OAEP)
  766. {
  767. // use OAEP if the flag is set
  768. dwSts = OAEPDecrypt(pTmpUser, pBSPrivKey, pbBlob, cbBlob, pbParams,
  769. cbParams, ppbPlaintext, pcbPlaintext);
  770. if (ERROR_SUCCESS != dwSts)
  771. {
  772. dwReturn = dwSts;
  773. goto ErrorExit;
  774. }
  775. }
  776. else
  777. {
  778. // use PKCS #1 Type 2
  779. dwSts = PKCS2Decrypt(pTmpUser, pBSPrivKey, dwFlags, pbBlob,
  780. ppbPlaintext, pcbPlaintext);
  781. if (ERROR_SUCCESS != dwSts)
  782. {
  783. dwReturn = dwSts;
  784. goto ErrorExit;
  785. }
  786. }
  787. dwReturn = ERROR_SUCCESS;
  788. ErrorExit:
  789. return dwReturn;
  790. }
  791. //
  792. // Function : EncryptAndDecryptWithRSAKey
  793. //
  794. // Description : This function creates a buffer and then encrypts that with
  795. // the passed in private key and decrypts with the passed in
  796. // public key. The function is used for FIPS 140-1 compliance
  797. // to make sure that newly generated/imported keys work and
  798. // in the self test during DLL initialization.
  799. //
  800. DWORD
  801. EncryptAndDecryptWithRSAKey(
  802. IN BYTE *pbRSAPub,
  803. IN BYTE *pbRSAPriv,
  804. IN BOOL fSigKey,
  805. IN BOOL fEncryptCheck)
  806. {
  807. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  808. BSAFE_PRV_KEY *pBSafePriv = (BSAFE_PRV_KEY*)pbRSAPriv;
  809. BYTE *pb = NULL;
  810. DWORD cb;
  811. DWORD cbKey;
  812. DWORD i;
  813. // alloc space for the plaintext and ciphertext
  814. cb = pBSafePriv->keylen;
  815. cbKey = pBSafePriv->bitlen / 8;
  816. pb = _nt_malloc(cb * 3);
  817. if (NULL == pb)
  818. {
  819. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  820. goto ErrorExit;
  821. }
  822. // reverse the hash so it is in little endian
  823. for (i = 0; i < 16; i++)
  824. pb[i] = (BYTE)(i + 1);
  825. memset(pb + 17, 0xFF, cbKey - 18);
  826. if (fSigKey)
  827. {
  828. // encrypt with the private key
  829. if (!BSafeDecPrivate(pBSafePriv, pb, pb + cb))
  830. {
  831. dwReturn = (DWORD)NTE_BAD_KEY;
  832. goto ErrorExit;
  833. }
  834. }
  835. else
  836. {
  837. // encrypt with the public key
  838. if (!BSafeEncPublic((BSAFE_PUB_KEY*)pbRSAPub, pb, pb + cb))
  839. {
  840. dwReturn = (DWORD)NTE_BAD_KEY;
  841. goto ErrorExit;
  842. }
  843. }
  844. // we can't do this check when importing private keys since many
  845. // applications use private keys with exponent of 1 to import
  846. // plaintext symmetric keys
  847. if (fEncryptCheck)
  848. {
  849. if (0 == (memcmp(pb, pb + cb, cb)))
  850. {
  851. dwReturn = (DWORD)NTE_BAD_KEY;
  852. goto ErrorExit;
  853. }
  854. }
  855. if (fSigKey)
  856. {
  857. // decrypt with the public key
  858. if (!BSafeEncPublic((BSAFE_PUB_KEY*)pbRSAPub, pb + cb, pb + (cb * 2)))
  859. {
  860. dwReturn = (DWORD)NTE_BAD_KEY;
  861. goto ErrorExit;
  862. }
  863. }
  864. else
  865. {
  866. // encrypt with the private key
  867. if (!BSafeDecPrivate(pBSafePriv, pb + cb, pb + (cb * 2)))
  868. {
  869. dwReturn = (DWORD)NTE_BAD_KEY;
  870. goto ErrorExit;
  871. }
  872. }
  873. // compare to the plaintext and the decrypted text
  874. if (memcmp(pb, pb + cb * 2, cbKey))
  875. {
  876. dwReturn = (DWORD)NTE_BAD_KEY;
  877. goto ErrorExit;
  878. }
  879. dwReturn = ERROR_SUCCESS;
  880. ErrorExit:
  881. if (pb)
  882. _nt_free(pb, cbB * 3);
  883. return dwReturn;
  884. }
  885. DWORD
  886. ReGenKey(
  887. HCRYPTPROV hUser,
  888. DWORD dwFlags,
  889. DWORD dwWhichKey,
  890. HCRYPTKEY *phKey,
  891. DWORD bits)
  892. {
  893. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  894. BYTE **ThisPubKey, **ThisPrivKey;
  895. DWORD *pThisPubLen, *pThisPrivLen;
  896. BYTE *pNewPubKey = NULL;
  897. BYTE *pNewPrivKey = NULL;
  898. DWORD PrivateKeySize, PublicKeySize;
  899. DWORD localbits;
  900. PNTAGUserList pOurUser;
  901. BOOL fSigKey;
  902. LPWSTR szPrompt;
  903. BOOL *pfExportable;
  904. BOOL fAlloc = FALSE;
  905. BOOL fInCritSec = FALSE;
  906. BSAFE_OTHER_INFO OtherInfo;
  907. BSAFE_OTHER_INFO *pOtherInfo = NULL;
  908. DWORD dwSts;
  909. PNTAGKeyList pTmpKey = NULL;
  910. memset(&OtherInfo, 0, sizeof(OtherInfo));
  911. // ## MTS: No user structure locking
  912. pOurUser = (PNTAGUserList) NTLCheckList(hUser, USER_HANDLE);
  913. if (NULL == pOurUser)
  914. {
  915. dwReturn = (DWORD)NTE_BAD_UID;
  916. goto ErrorExit;
  917. }
  918. // wrap with a try since there is a critical sections in here
  919. __try
  920. {
  921. EnterCriticalSection(&pOurUser->CritSec);
  922. fInCritSec = TRUE;
  923. localbits = bits;
  924. if (!BSafeComputeKeySizes(&PublicKeySize, &PrivateKeySize,
  925. &localbits))
  926. {
  927. dwReturn = (DWORD)NTE_FAIL;
  928. goto ErrorExit;
  929. }
  930. pNewPubKey = (BYTE *)_nt_malloc(PublicKeySize);
  931. if (NULL == pNewPubKey)
  932. {
  933. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  934. goto ErrorExit;
  935. }
  936. fAlloc = TRUE;
  937. // allocate space for the new key exchange public key
  938. pNewPrivKey = (BYTE *)_nt_malloc(PrivateKeySize);
  939. if (NULL == pNewPrivKey)
  940. {
  941. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  942. goto ErrorExit;
  943. }
  944. // generate the key exchange key pair
  945. if (INVALID_HANDLE_VALUE != pOurUser->hRNGDriver)
  946. {
  947. OtherInfo.pRNGInfo = &pOurUser->hRNGDriver;
  948. OtherInfo.pFuncRNG = FIPS186GenRandomWithException;
  949. pOtherInfo = &OtherInfo;
  950. }
  951. // ?Note? -- Shouldn't this be in a try/except?
  952. if (!BSafeMakeKeyPairEx2(pOtherInfo,
  953. (BSAFE_PUB_KEY *) pNewPubKey,
  954. (BSAFE_PRV_KEY *) pNewPrivKey,
  955. bits,
  956. 0x10001))
  957. {
  958. dwReturn = (DWORD)NTE_FAIL;
  959. goto ErrorExit;
  960. }
  961. // test the RSA key to make sure it works
  962. dwSts = EncryptAndDecryptWithRSAKey(pNewPubKey, pNewPrivKey,
  963. TRUE, TRUE);
  964. if (ERROR_SUCCESS != dwSts)
  965. {
  966. dwReturn = dwSts;
  967. goto ErrorExit;
  968. }
  969. // test the RSA key to make sure it works
  970. dwSts = EncryptAndDecryptWithRSAKey(pNewPubKey, pNewPrivKey,
  971. FALSE, TRUE);
  972. if (ERROR_SUCCESS != dwSts)
  973. {
  974. dwReturn = dwSts;
  975. goto ErrorExit;
  976. }
  977. if (dwWhichKey == NTPK_USE_SIG)
  978. {
  979. ThisPubKey = &pOurUser->ContInfo.pbSigPub;
  980. ThisPrivKey = &pOurUser->pSigPrivKey;
  981. pThisPubLen = &pOurUser->ContInfo.ContLens.cbSigPub;
  982. pThisPrivLen = &pOurUser->SigPrivLen;
  983. pfExportable = &pOurUser->ContInfo.fSigExportable;
  984. fSigKey = TRUE;
  985. szPrompt = g_Strings.pwszCreateRSASig;
  986. }
  987. else
  988. {
  989. ThisPubKey = &pOurUser->ContInfo.pbExchPub;
  990. ThisPrivKey = &pOurUser->pExchPrivKey;
  991. pThisPubLen = &pOurUser->ContInfo.ContLens.cbExchPub;
  992. pThisPrivLen = &pOurUser->ExchPrivLen;
  993. pfExportable = &pOurUser->ContInfo.fExchExportable;
  994. fSigKey = FALSE;
  995. szPrompt = g_Strings.pwszCreateRSAExch;
  996. }
  997. if (*ThisPubKey)
  998. {
  999. ASSERT(*pThisPubLen);
  1000. ASSERT(*pThisPrivLen);
  1001. ASSERT(*ThisPrivKey);
  1002. _nt_free (*ThisPubKey, *pThisPubLen);
  1003. _nt_free (*ThisPrivKey, *pThisPrivLen);
  1004. }
  1005. #ifdef NTAGDEBUG
  1006. else
  1007. {
  1008. ASSERT(*pThisPrivLen == 0);
  1009. ASSERT(*pThisPubLen == 0);
  1010. ASSERT(*ThisPrivKey == 0);
  1011. ASSERT(*ThisPubKey == 0);
  1012. }
  1013. #endif
  1014. fAlloc = FALSE;
  1015. *pThisPrivLen = PrivateKeySize;
  1016. *pThisPubLen = PublicKeySize;
  1017. *ThisPrivKey = pNewPrivKey;
  1018. *ThisPubKey = pNewPubKey;
  1019. if (dwFlags & CRYPT_EXPORTABLE)
  1020. *pfExportable = TRUE;
  1021. else
  1022. *pfExportable = FALSE;
  1023. // if the context being used is a Verify Context then the key is not
  1024. // persisted to storage
  1025. if (!(pOurUser->Rights & CRYPT_VERIFYCONTEXT))
  1026. {
  1027. // write the new keys to the user storage file
  1028. dwSts = ProtectPrivKey(pOurUser, szPrompt, dwFlags, fSigKey);
  1029. if (ERROR_SUCCESS != dwSts)
  1030. {
  1031. dwReturn = dwSts;
  1032. goto ErrorExit;
  1033. }
  1034. }
  1035. if (dwWhichKey == NTPK_USE_SIG)
  1036. {
  1037. if (!CPGetUserKey(hUser, AT_SIGNATURE, phKey))
  1038. {
  1039. dwReturn = GetLastError();
  1040. goto ErrorExit;
  1041. }
  1042. dwSts = NTLValidate(*phKey, hUser, SIGPUBKEY_HANDLE, &pTmpKey);
  1043. if (ERROR_SUCCESS != dwSts)
  1044. {
  1045. // NTLValidate doesn't know what error to set
  1046. // so it set NTE_FAIL -- fix it up.
  1047. dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts;
  1048. goto ErrorExit;
  1049. }
  1050. }
  1051. else
  1052. {
  1053. if (!CPGetUserKey(hUser, AT_KEYEXCHANGE, phKey))
  1054. {
  1055. dwReturn = GetLastError();
  1056. goto ErrorExit;
  1057. }
  1058. dwSts = NTLValidate(*phKey, hUser, EXCHPUBKEY_HANDLE, &pTmpKey);
  1059. if (ERROR_SUCCESS != dwSts)
  1060. {
  1061. // NTLValidate doesn't know what error to set
  1062. // so it set NTE_FAIL -- fix it up.
  1063. dwReturn = (dwSts == NTE_FAIL) ? (DWORD)NTE_BAD_KEY : dwSts;
  1064. goto ErrorExit;
  1065. }
  1066. }
  1067. //
  1068. // Fix-up archivability.
  1069. //
  1070. if (0 != (CRYPT_ARCHIVABLE & dwFlags))
  1071. {
  1072. pTmpKey->Rights |= CRYPT_ARCHIVABLE;
  1073. pTmpKey->Permissions |= CRYPT_ARCHIVE;
  1074. }
  1075. }
  1076. __except ( EXCEPTION_EXECUTE_HANDLER )
  1077. {
  1078. dwReturn = ERROR_INVALID_PARAMETER;
  1079. goto ErrorExit;
  1080. }
  1081. dwReturn = ERROR_SUCCESS;
  1082. ErrorExit:
  1083. if (fInCritSec)
  1084. LeaveCriticalSection(&pOurUser->CritSec);
  1085. if (fAlloc)
  1086. {
  1087. if (pNewPrivKey)
  1088. _nt_free(pNewPrivKey, PrivateKeySize);
  1089. if (pNewPubKey)
  1090. _nt_free(pNewPubKey, PublicKeySize);
  1091. }
  1092. return dwReturn;
  1093. }
  1094. //
  1095. // Routine : DerivePublicFromPrivate
  1096. //
  1097. // Description : Derive the public RSA key from the private RSA key. This is
  1098. // done and the resulting public key is placed in the appropriate
  1099. // place in the context pointer (pTmpUser).
  1100. //
  1101. DWORD
  1102. DerivePublicFromPrivate(
  1103. IN PNTAGUserList pUser,
  1104. IN BOOL fSigKey)
  1105. {
  1106. DWORD dwReturn = ERROR_INTERNAL_ERROR;
  1107. DWORD *pcbPubKey;
  1108. BYTE **ppbPubKey = NULL;
  1109. BSAFE_PUB_KEY *pBSafePubKey;
  1110. BSAFE_PRV_KEY *pBSafePrivKey;
  1111. DWORD cb;
  1112. // variable assignments depending on if its sig or exch
  1113. if (fSigKey)
  1114. {
  1115. pcbPubKey = &pUser->ContInfo.ContLens.cbSigPub;
  1116. ppbPubKey = &pUser->ContInfo.pbSigPub;
  1117. pBSafePrivKey = (BSAFE_PRV_KEY*)pUser->pSigPrivKey;
  1118. }
  1119. else
  1120. {
  1121. pcbPubKey = &pUser->ContInfo.ContLens.cbExchPub;
  1122. ppbPubKey = &pUser->ContInfo.pbExchPub;
  1123. pBSafePrivKey = (BSAFE_PRV_KEY*)pUser->pExchPrivKey;
  1124. }
  1125. // figure out how much space is needed for the public key
  1126. cb = ((((pBSafePrivKey->bitlen >> 1) + 63) / 32) * 8); // 8 = 2 * DIGIT_BYTES (rsa_fast.h)
  1127. cb += sizeof(BSAFE_PUB_KEY);
  1128. // check if space has been alloced for the public key and if
  1129. // so is it large enough
  1130. if (cb > *pcbPubKey)
  1131. {
  1132. _nt_free(*ppbPubKey, *pcbPubKey);
  1133. *pcbPubKey = cb;
  1134. *ppbPubKey = _nt_malloc(*pcbPubKey);
  1135. if (NULL == *ppbPubKey)
  1136. {
  1137. dwReturn = ERROR_NOT_ENOUGH_MEMORY;
  1138. goto ErrorExit;
  1139. }
  1140. }
  1141. // copy over the public key components
  1142. pBSafePubKey = (BSAFE_PUB_KEY*)*ppbPubKey;
  1143. pBSafePubKey->magic = RSA1;
  1144. pBSafePubKey->keylen = pBSafePrivKey->keylen;
  1145. pBSafePubKey->bitlen = pBSafePrivKey->bitlen;
  1146. pBSafePubKey->datalen = pBSafePrivKey->datalen;
  1147. pBSafePubKey->pubexp = pBSafePrivKey->pubexp;
  1148. memcpy(*ppbPubKey + sizeof(BSAFE_PUB_KEY),
  1149. (BYTE*)pBSafePrivKey + sizeof(BSAFE_PRV_KEY),
  1150. cb - sizeof(BSAFE_PUB_KEY));
  1151. dwReturn = ERROR_SUCCESS;
  1152. ErrorExit:
  1153. return dwReturn;
  1154. }