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.

714 lines
17 KiB

  1. /*
  2. File: capiprim.cpp
  3. Title: Cryptographic Primitives using CryptoAPI
  4. Author: Matt Thomlinson
  5. Date: 11/22/96
  6. Functions in this module:
  7. FMyPrimitiveCryptHMAC
  8. Derives a quality HMAC (Keyed message-authentication code).
  9. The HMAC is computed in the following (standard HMAC) manner:
  10. KoPad = KiPad = DESKey key setup buffer
  11. XOR(KoPad, 0x5c5c5c5c)
  12. XOR(KiPad, 0x36363636)
  13. HMAC = SHA1(KoPad | SHA1(KiPad | Data))
  14. */
  15. #include <pch.cpp>
  16. #pragma hdrstop
  17. #include "crypt.h"
  18. BOOL
  19. WINAPI
  20. _CryptEnumProvidersW(
  21. DWORD dwIndex,
  22. DWORD * pdwReserved,
  23. DWORD dwFlags,
  24. DWORD * pdwProvType,
  25. LPWSTR pszProvName,
  26. DWORD * pcbProvName
  27. );
  28. extern DWORD g_dwCryptProviderID;
  29. #define HMAC_K_PADSIZE 64
  30. extern CCryptProvList* g_pCProvList;
  31. BOOL FMyPrimitiveCryptHMAC(
  32. PBYTE pbKeyMaterial,
  33. DWORD cbKeyMaterial,
  34. PBYTE pbData,
  35. DWORD cbData,
  36. HCRYPTPROV hVerifyProv,
  37. DWORD dwHashAlg,
  38. HCRYPTHASH* phHash) // out
  39. {
  40. DWORD cb;
  41. BOOL fRet = FALSE;
  42. BYTE rgbKipad[HMAC_K_PADSIZE]; ZeroMemory(rgbKipad, HMAC_K_PADSIZE);
  43. BYTE rgbKopad[HMAC_K_PADSIZE]; ZeroMemory(rgbKopad, HMAC_K_PADSIZE);
  44. BYTE rgbHMACTmp[HMAC_K_PADSIZE+A_SHA_DIGEST_LEN];
  45. HCRYPTHASH hTmpHash = NULL;
  46. // truncate
  47. if (cbKeyMaterial > HMAC_K_PADSIZE)
  48. cbKeyMaterial = HMAC_K_PADSIZE;
  49. // fill pad bufs with keying material
  50. CopyMemory(rgbKipad, pbKeyMaterial, cbKeyMaterial);
  51. CopyMemory(rgbKopad, pbKeyMaterial, cbKeyMaterial);
  52. // assert we're a multiple for the next loop
  53. SS_ASSERT( (HMAC_K_PADSIZE % sizeof(DWORD)) == 0);
  54. // Kipad, Kopad are padded sMacKey. Now XOR across...
  55. for(DWORD dwBlock=0; dwBlock<HMAC_K_PADSIZE/sizeof(DWORD); dwBlock++)
  56. {
  57. ((DWORD*)rgbKipad)[dwBlock] ^= 0x36363636;
  58. ((DWORD*)rgbKopad)[dwBlock] ^= 0x5C5C5C5C;
  59. }
  60. // check passed-in prov
  61. if (hVerifyProv == NULL)
  62. {
  63. SetLastError(ERROR_INVALID_PARAMETER);
  64. goto Ret;
  65. }
  66. // create an intermediate hash
  67. if (!CryptCreateHash(
  68. hVerifyProv,
  69. dwHashAlg,
  70. NULL,
  71. 0,
  72. &hTmpHash))
  73. goto Ret;
  74. // prepend Kipad to data, Hash to get H1
  75. if (!CryptHashData(
  76. hTmpHash,
  77. rgbKipad,
  78. sizeof(rgbKipad),
  79. 0))
  80. goto Ret;
  81. if (!CryptHashData(
  82. hTmpHash,
  83. pbData,
  84. cbData,
  85. 0))
  86. goto Ret;
  87. // prepend Kopad to H1
  88. CopyMemory(rgbHMACTmp, rgbKopad, HMAC_K_PADSIZE);
  89. cb = A_SHA_DIGEST_LEN;
  90. if (!CryptGetHashParam(
  91. hTmpHash,
  92. HP_HASHVAL,
  93. rgbHMACTmp+HMAC_K_PADSIZE,
  94. &cb,
  95. 0))
  96. goto Ret;
  97. // do final hash w/ CryptoAPI into output hash
  98. // create the final hash
  99. if (!CryptCreateHash(
  100. hVerifyProv,
  101. dwHashAlg,
  102. NULL,
  103. 0,
  104. phHash))
  105. goto Ret;
  106. // hash ( Kopad | H1 ) to get HMAC
  107. if (!CryptHashData(
  108. *phHash,
  109. rgbHMACTmp,
  110. HMAC_K_PADSIZE + cb, // pad + hashsize
  111. 0))
  112. goto Ret;
  113. fRet = TRUE;
  114. Ret:
  115. if (hTmpHash)
  116. CryptDestroyHash(hTmpHash);
  117. return fRet;
  118. }
  119. #if DBG
  120. void CheckMACInterop(
  121. PBYTE pbMonsterKey,
  122. DWORD cbMonsterKey,
  123. PBYTE pbRandKey,
  124. DWORD cbRandKey,
  125. HCRYPTPROV hVerifyProv,
  126. ALG_ID algidHash)
  127. {
  128. HCRYPTHASH hHash = 0;
  129. BOOL fRet = FALSE;
  130. BYTE rgbOldHash[A_SHA_DIGEST_LEN];
  131. BYTE rgbCryptHash[A_SHA_DIGEST_LEN];
  132. DWORD cbHashSize = sizeof(rgbCryptHash);
  133. if (algidHash == CALG_SHA1)
  134. {
  135. if (!FMyPrimitiveCryptHMAC(
  136. pbMonsterKey, // key
  137. cbMonsterKey,
  138. pbRandKey, // data
  139. cbRandKey,
  140. hVerifyProv,
  141. algidHash,
  142. &hHash)) // output
  143. goto Ret;
  144. // nab crypt result
  145. if (!CryptGetHashParam(
  146. hHash,
  147. HP_HASHVAL,
  148. rgbCryptHash,
  149. &cbHashSize,
  150. 0))
  151. goto Ret;
  152. // nab raw result
  153. if (!FMyPrimitiveHMACParam(
  154. pbMonsterKey,
  155. cbMonsterKey,
  156. pbRandKey,
  157. cbRandKey,
  158. rgbOldHash))
  159. goto Ret;
  160. if (0 != memcmp(rgbOldHash, rgbCryptHash, A_SHA_DIGEST_LEN))
  161. goto Ret;
  162. }
  163. // else don't have interop test
  164. fRet = TRUE;
  165. Ret:
  166. if (!fRet)
  167. {
  168. OutputDebugString(TEXT("HMACs did not interop!!!!\n"));
  169. SS_ASSERT(0);
  170. }
  171. if (hHash)
  172. CryptDestroyHash(hHash);
  173. return;
  174. }
  175. #endif // DBG
  176. // USEC -- (US Export Controls)
  177. DWORD GetSaltForExportControl(
  178. HCRYPTPROV hProv,
  179. HCRYPTKEY hKey,
  180. PBYTE* ppbSalt,
  181. DWORD* pcbSalt)
  182. {
  183. DWORD dwRet;
  184. // fix bug: derived keys will be > 40 bits in length
  185. // fix is to stomp derived key with exposed salt (Provider knows what is legal!!)
  186. if (!CryptGetKeyParam(
  187. hKey,
  188. KP_SALT,
  189. NULL,
  190. pcbSalt,
  191. 0))
  192. {
  193. #if DBG
  194. if (GetLastError() != NTE_BAD_KEY)
  195. OutputDebugString(TEXT("GetSaltForExportControl failed in possible violation of ITAR!\n"));
  196. #endif
  197. /*
  198. dwRet = GetLastError();
  199. goto Ret;
  200. */
  201. // Assume key type doesn't support salt
  202. // report cbSalt = 0
  203. *pcbSalt = 0;
  204. *ppbSalt = (PBYTE)SSAlloc(0);
  205. dwRet = ERROR_SUCCESS;
  206. goto Ret;
  207. }
  208. *ppbSalt = (PBYTE)SSAlloc(*pcbSalt);
  209. if (!RtlGenRandom(
  210. *ppbSalt,
  211. *pcbSalt))
  212. {
  213. dwRet = GetLastError();
  214. goto Ret;
  215. }
  216. // don't get if salt zero len (bug workaround for NT5B1 RSAEnh)
  217. if (*pcbSalt != 0)
  218. {
  219. if (!CryptSetKeyParam(
  220. hKey,
  221. KP_SALT,
  222. *ppbSalt,
  223. 0))
  224. {
  225. dwRet = GetLastError();
  226. goto Ret;
  227. }
  228. }
  229. dwRet = ERROR_SUCCESS;
  230. Ret:
  231. return dwRet;
  232. }
  233. // USEC -- (US Export Controls)
  234. DWORD SetSaltForExportControl(
  235. HCRYPTKEY hKey,
  236. PBYTE pbSalt,
  237. DWORD cbSalt)
  238. {
  239. DWORD dwRet;
  240. DWORD cbAllowableSaltLen;
  241. // first check and make sure we can set this salt
  242. if (!CryptGetKeyParam(
  243. hKey,
  244. KP_SALT,
  245. NULL,
  246. &cbAllowableSaltLen,
  247. 0))
  248. {
  249. /*
  250. dwRet = GetLastError();
  251. goto Ret;
  252. */
  253. // If cbSalt == 0, no error
  254. if (cbSalt == 0)
  255. dwRet = ERROR_SUCCESS;
  256. else
  257. dwRet = GetLastError();
  258. goto Ret;
  259. }
  260. if (cbAllowableSaltLen != cbSalt)
  261. {
  262. dwRet = ERROR_INVALID_DATA;
  263. goto Ret;
  264. }
  265. // don't set if salt zero len (bug workaround for NT5B1 RSAEnh)
  266. if (cbSalt != 0)
  267. {
  268. // set the salt to stomp real key bits (export law)
  269. if (!CryptSetKeyParam(
  270. hKey,
  271. KP_SALT,
  272. pbSalt,
  273. 0))
  274. {
  275. dwRet = GetLastError();
  276. goto Ret;
  277. }
  278. }
  279. dwRet = ERROR_SUCCESS;
  280. Ret:
  281. return dwRet;
  282. }
  283. DWORD GetCryptProviderFromRequirements(
  284. DWORD dwAlgId1,
  285. DWORD* pdwKeySize1,
  286. DWORD dwAlgId2,
  287. DWORD* pdwKeySize2,
  288. DWORD* pdwProvType,
  289. LPWSTR* ppszProvName)
  290. {
  291. DWORD dwRet;
  292. DWORD cbProvName=0, cbNecessary;
  293. HCRYPTPROV hQueryProv = NULL;
  294. LPWSTR pTemp;
  295. SS_ASSERT(pdwKeySize1);
  296. SS_ASSERT(pdwKeySize2);
  297. *ppszProvName=NULL;
  298. for (int iProvIndex=0; ;iProvIndex++)
  299. {
  300. if (!_CryptEnumProvidersW(
  301. iProvIndex,
  302. NULL,
  303. 0,
  304. pdwProvType,
  305. NULL,
  306. &cbNecessary))
  307. {
  308. dwRet = GetLastError();
  309. if (dwRet == ERROR_NO_MORE_ITEMS)
  310. dwRet = NTE_PROV_DLL_NOT_FOUND;
  311. // end of providers OR
  312. // trouble enumerating providers: both fatal
  313. goto Ret;
  314. }
  315. if (cbNecessary > cbProvName)
  316. {
  317. if (*ppszProvName == NULL)
  318. *ppszProvName = (LPWSTR)SSAlloc(cbNecessary);
  319. else {
  320. pTemp = (LPWSTR)SSReAlloc(*ppszProvName, cbNecessary);
  321. if (NULL == pTemp) {
  322. SSFree(*ppszProvName);
  323. }
  324. *ppszProvName = pTemp;
  325. }
  326. if (*ppszProvName == NULL)
  327. {
  328. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  329. goto Ret;
  330. }
  331. cbProvName = cbNecessary;
  332. }
  333. if (!_CryptEnumProvidersW(
  334. iProvIndex,
  335. NULL,
  336. 0,
  337. pdwProvType,
  338. *ppszProvName,
  339. &cbNecessary))
  340. {
  341. // trouble enumerating providers: fatal
  342. dwRet = GetLastError();
  343. goto Ret;
  344. }
  345. if (!CryptAcquireContextU(
  346. &hQueryProv,
  347. NULL,
  348. *ppszProvName,
  349. *pdwProvType,
  350. CRYPT_VERIFYCONTEXT))
  351. {
  352. // trouble acquiring context, to go next csp
  353. continue;
  354. }
  355. if ((FProviderSupportsAlg(hQueryProv, dwAlgId1, pdwKeySize1)) &&
  356. (FProviderSupportsAlg(hQueryProv, dwAlgId2, pdwKeySize2)) )
  357. goto CSPFound;
  358. // release
  359. CryptReleaseContext(hQueryProv, 0);
  360. hQueryProv = NULL;
  361. }
  362. CSPFound:
  363. dwRet = ERROR_SUCCESS;
  364. Ret:
  365. if (hQueryProv != NULL)
  366. CryptReleaseContext(hQueryProv, 0);
  367. if ((dwRet != ERROR_SUCCESS) && (*ppszProvName))
  368. {
  369. SSFree(*ppszProvName);
  370. *ppszProvName = NULL;
  371. }
  372. return dwRet;
  373. }
  374. // *pdwKeySize == -1 gets any size, reports size
  375. HCRYPTPROV
  376. GetCryptProviderHandle(
  377. DWORD dwDefaultCSPType,
  378. DWORD dwAlgId1,
  379. DWORD* pdwKeySize1,
  380. DWORD dwAlgId2,
  381. DWORD* pdwKeySize2)
  382. {
  383. DWORD dwRet;
  384. DWORD dwProvType;
  385. LPWSTR szProvName = NULL;
  386. CRYPTPROV_LIST_ITEM Elt, *pFoundElt;
  387. HCRYPTPROV hNewCryptProv=0;
  388. SS_ASSERT(pdwKeySize1);
  389. SS_ASSERT(pdwKeySize2);
  390. if(NULL == g_pCProvList)
  391. {
  392. SetLastError(PST_E_FAIL);
  393. return NULL;
  394. }
  395. // Adjust DES key sizes, to prevent the situation where the CSP
  396. // originally used for encryption accidently reported a 3DES key
  397. // size of 192 bits, and the current CSPs only enumerate support
  398. // for 3DES keys of 168 bits.
  399. if(dwAlgId1 == CALG_DES || dwAlgId1 == CALG_3DES)
  400. {
  401. *pdwKeySize1 = -1;
  402. }
  403. // check cache for satisfactory CSP
  404. CreateCryptProvListItem(&Elt,
  405. dwAlgId1,
  406. *pdwKeySize1,
  407. dwAlgId2,
  408. *pdwKeySize2,
  409. 0);
  410. if (NULL != (pFoundElt = g_pCProvList->SearchList(&Elt)) )
  411. {
  412. // report what we're returning
  413. *pdwKeySize1 = pFoundElt->dwKeySize1;
  414. *pdwKeySize2 = pFoundElt->dwKeySize2;
  415. return pFoundElt->hProv;
  416. }
  417. // not in cache: have to rummage
  418. // try default provider of given type, see if it satisfies
  419. if (CryptAcquireContextU(
  420. &hNewCryptProv,
  421. NULL,
  422. MS_STRONG_PROV,
  423. dwDefaultCSPType,
  424. CRYPT_VERIFYCONTEXT))
  425. {
  426. if ((FProviderSupportsAlg(hNewCryptProv, dwAlgId1, pdwKeySize1)) &&
  427. (FProviderSupportsAlg(hNewCryptProv, dwAlgId2, pdwKeySize2)) )
  428. goto CSPAcquired;
  429. // clean up non-usable CSP
  430. CryptReleaseContext(hNewCryptProv, 0);
  431. hNewCryptProv = NULL;
  432. // all other cases: fall through to enum CSPs
  433. }
  434. // rummage along providers on system to find someone who fits the bill
  435. if(ERROR_SUCCESS != (dwRet =
  436. GetCryptProviderFromRequirements(
  437. dwAlgId1,
  438. pdwKeySize1,
  439. dwAlgId2,
  440. pdwKeySize2,
  441. &dwProvType,
  442. &szProvName)))
  443. {
  444. SetLastError(dwRet);
  445. goto Ret;
  446. }
  447. // found one!
  448. // init csp
  449. if (!CryptAcquireContextU(
  450. &hNewCryptProv,
  451. NULL,
  452. szProvName,
  453. dwProvType,
  454. CRYPT_VERIFYCONTEXT))
  455. {
  456. // this a failure case
  457. // SetLastError already done for us
  458. hNewCryptProv = NULL;
  459. goto Ret;
  460. }
  461. CSPAcquired:
  462. SS_ASSERT(hNewCryptProv != NULL);
  463. // and add to internal list
  464. pFoundElt = (CRYPTPROV_LIST_ITEM*) SSAlloc(sizeof(CRYPTPROV_LIST_ITEM));
  465. if(NULL == pFoundElt)
  466. {
  467. // clean up non-usable CSP
  468. CryptReleaseContext(hNewCryptProv, 0);
  469. hNewCryptProv = NULL;
  470. goto Ret;
  471. }
  472. CreateCryptProvListItem(pFoundElt,
  473. dwAlgId1,
  474. *pdwKeySize1,
  475. dwAlgId2,
  476. *pdwKeySize2,
  477. hNewCryptProv);
  478. g_pCProvList->AddToList(pFoundElt);
  479. Ret:
  480. if (szProvName)
  481. SSFree(szProvName);
  482. return hNewCryptProv;
  483. }
  484. BOOL FProviderSupportsAlg(
  485. HCRYPTPROV hQueryProv,
  486. DWORD dwAlgId,
  487. DWORD* pdwKeySize)
  488. {
  489. PROV_ENUMALGS sSupportedAlgs;
  490. PROV_ENUMALGS_EX sSupportedAlgsEx;
  491. DWORD cbSupportedAlgs = sizeof(sSupportedAlgs);
  492. DWORD cbSupportedAlgsEx = sizeof(sSupportedAlgsEx);
  493. // must be non-null
  494. SS_ASSERT(pdwKeySize != NULL);
  495. // now we have provider; enum the algorithms involved
  496. for(int iAlgs=0; ; iAlgs++)
  497. {
  498. //
  499. // Attempt the EX alg enumeration
  500. if (CryptGetProvParam(
  501. hQueryProv,
  502. PP_ENUMALGS_EX,
  503. (PBYTE)&sSupportedAlgsEx,
  504. &cbSupportedAlgsEx,
  505. (iAlgs == 0) ? CRYPT_FIRST : 0 ))
  506. {
  507. if (sSupportedAlgsEx.aiAlgid == dwAlgId)
  508. {
  509. if(*pdwKeySize == -1)
  510. {
  511. *pdwKeySize = sSupportedAlgsEx.dwMaxLen;
  512. }
  513. else
  514. {
  515. if ((sSupportedAlgsEx.dwMinLen > *pdwKeySize) ||
  516. (sSupportedAlgsEx.dwMaxLen < *pdwKeySize))
  517. return FALSE;
  518. }
  519. return TRUE;
  520. }
  521. }
  522. else if (!CryptGetProvParam(
  523. hQueryProv,
  524. PP_ENUMALGS,
  525. (PBYTE)&sSupportedAlgs,
  526. &cbSupportedAlgs,
  527. (iAlgs == 0) ? CRYPT_FIRST : 0 ))
  528. {
  529. // trouble enumerating algs
  530. break;
  531. if (sSupportedAlgs.aiAlgid == dwAlgId)
  532. {
  533. // were we told to ignore size?
  534. if (*pdwKeySize != -1)
  535. {
  536. // else, if defaults don't match
  537. if (sSupportedAlgs.dwBitLen != *pdwKeySize)
  538. {
  539. return FALSE;
  540. }
  541. }
  542. // report back size
  543. *pdwKeySize = sSupportedAlgs.dwBitLen;
  544. return TRUE;
  545. }
  546. }
  547. else
  548. {
  549. // trouble enumerating algs
  550. break;
  551. }
  552. }
  553. return FALSE;
  554. }
  555. BOOL
  556. WINAPI
  557. _CryptEnumProvidersW(
  558. DWORD dwIndex,
  559. DWORD * pdwReserved,
  560. DWORD dwFlags,
  561. DWORD * pdwProvType,
  562. LPWSTR pszProvName,
  563. DWORD * pcbProvName
  564. )
  565. {
  566. HMODULE hAdvapi32;
  567. typedef BOOL (WINAPI *CRYPTENUMPROVIDERSW)(
  568. DWORD dwIndex,
  569. DWORD * pdwReserved,
  570. DWORD dwFlags,
  571. DWORD * pdwProvType,
  572. LPWSTR pszProvName,
  573. DWORD * pcbProvName
  574. );
  575. static CRYPTENUMPROVIDERSW _RealCryptEnumProvidersW;
  576. if (_RealCryptEnumProvidersW == NULL) {
  577. hAdvapi32 = GetModuleHandleA("advapi32.dll");
  578. if(hAdvapi32 == NULL)
  579. return FALSE;
  580. _RealCryptEnumProvidersW = (CRYPTENUMPROVIDERSW)GetProcAddress(hAdvapi32, "CryptEnumProvidersW");
  581. if(_RealCryptEnumProvidersW == NULL)
  582. return FALSE;
  583. }
  584. return _RealCryptEnumProvidersW(
  585. dwIndex,
  586. pdwReserved,
  587. dwFlags,
  588. pdwProvType,
  589. pszProvName,
  590. pcbProvName
  591. );
  592. }