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.

1010 lines
30 KiB

  1. /****************************************************************************/
  2. /* capienc.cpp */
  3. /* */
  4. /* FIPS encrpt/decrypt */
  5. /* */
  6. /* Copyright (C) 2002-2004 Microsoft Corporation */
  7. /****************************************************************************/
  8. #include <adcg.h>
  9. extern "C" {
  10. #define TRC_GROUP TRC_GROUP_CORE
  11. #define TRC_FILE "capienc"
  12. #include <atrcapi.h>
  13. }
  14. #include "capienc.h"
  15. #include "sl.h"
  16. #define TERMSRV_NAME L"terminal_server_client"
  17. const BYTE DESParityTable[] = {0x00,0x01,0x01,0x02,0x01,0x02,0x02,0x03,
  18. 0x01,0x02,0x02,0x03,0x02,0x03,0x03,0x04};
  19. // IV for all block ciphers
  20. BYTE rgbIV[] = {0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF};
  21. //
  22. // Name: PrintData
  23. //
  24. // Purpose: Print out the data in debugger
  25. //
  26. // Returns: No
  27. //
  28. // Params: IN pKeyData: point to the data to be printed
  29. // IN cbSize: the size of the key
  30. void PrintData(BYTE *pKeyData, DWORD cbSize)
  31. {
  32. DWORD dwIndex;
  33. TCHAR Buffer[128];
  34. for( dwIndex = 0; dwIndex<cbSize; dwIndex++ ) {
  35. StringCchPrintf(Buffer, 128, TEXT("0x%x "), pKeyData[dwIndex]);
  36. OutputDebugString(Buffer);
  37. if( dwIndex > 0 && (dwIndex+1) % 8 == 0 )
  38. OutputDebugString((TEXT("\n")));
  39. }
  40. }
  41. //
  42. // Name: Is_WinXP_or_Later
  43. //
  44. // Purpose: Tell if the OS is WinXP or later
  45. //
  46. // Returns: TRUE if it's WinXP or later
  47. //
  48. // Params: No
  49. BOOL Is_WinXP_or_Later ()
  50. {
  51. OSVERSIONINFO osvi;
  52. BOOL bIsWinXPorLater = FALSE;
  53. ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
  54. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  55. if (GetVersionEx(&osvi)) {
  56. bIsWinXPorLater = ((osvi.dwMajorVersion >= 5) && (osvi.dwMinorVersion >= 1));
  57. }
  58. return bIsWinXPorLater;
  59. }
  60. //
  61. // Name: Mydesparityonkey
  62. //
  63. // Purpose: Set the parity on the DES key to be odd
  64. //
  65. // Returns: No
  66. //
  67. // Params: IN/OUT pbKey: point to the key
  68. // IN cbKey: the size of the key
  69. void Mydesparityonkey(
  70. BYTE *pbKey,
  71. DWORD cbKey
  72. )
  73. {
  74. DWORD i;
  75. for (i=0;i<cbKey;i++)
  76. {
  77. if (!((DESParityTable[pbKey[i]>>4] + DESParityTable[pbKey[i]&0x0F]) % 2))
  78. pbKey[i] = pbKey[i] ^ 0x01;
  79. }
  80. }
  81. //
  82. // Name: Expandkey
  83. //
  84. // Purpose: Expand a 21-byte 3DES key to a 24-byte 3DES key (including parity bit)
  85. // by inserting a parity bit after every 7 bits in the 21-byte DES
  86. //
  87. // Returns: No
  88. //
  89. // Params: IN/OUT pbKey: point to the key
  90. //
  91. #define PARITY_UNIT 7
  92. void Expandkey(
  93. BYTE *pbKey
  94. )
  95. {
  96. BYTE pbTemp[DES3_KEYLEN];
  97. DWORD i, dwCount;
  98. UINT16 shortTemp;
  99. BYTE *pbIn, *pbOut;
  100. memcpy(pbTemp, pbKey, sizeof(pbTemp));
  101. dwCount = (DES3_KEYLEN * 8) / PARITY_UNIT;
  102. pbOut = pbKey;
  103. for (i=0; i<dwCount; i++) {
  104. pbIn = ((pbTemp + (PARITY_UNIT * i) / 8));
  105. //shortTemp = *(pbIn + 1);
  106. shortTemp = *pbIn + (((UINT16)*(pbIn + 1)) << 8);
  107. shortTemp = shortTemp >> ((PARITY_UNIT * i) % 8);
  108. //shortTemp = (*(unsigned short *)((pbTemp + (PARITY_UNIT * i) / 8))) >> ((PARITY_UNIT * i) % 8);
  109. *pbOut = (BYTE)(shortTemp & 0x7F);
  110. pbOut++;
  111. }
  112. }
  113. // Name: HashData
  114. //
  115. // Purpose: Hash the data using SHA.
  116. //
  117. // Returns: TRUE if succeeded
  118. //
  119. // Params: IN pCapiFunctionTable: CAPI function table
  120. // IN hProv: Handle of the cript provider
  121. // IN pbData: point to the data to be hashed
  122. // IN dwDataLen: the size of the data to be hashed
  123. // OUT phHash: point to the hash
  124. BOOL HashData(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, PBYTE pbData, DWORD dwDataLen, HCRYPTHASH* phHash)
  125. {
  126. BOOL rc = FALSE;
  127. DC_BEGIN_FN("HashData");
  128. //
  129. // Create a hash object.
  130. //
  131. if(!pCapiFunctionTable->pfnCryptCreateHash(hProv, CALG_SHA1, 0, 0, phHash)) {
  132. TRC_ERR((TB, _T("Error %x during CryptCreateHash!\n"), GetLastError()));
  133. goto done;
  134. }
  135. //
  136. // Hash in the data.
  137. //
  138. if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData, dwDataLen, 0)) {
  139. TRC_ERR((TB, _T("Error %x during CryptHashData!\n"), GetLastError()));
  140. goto done;
  141. }
  142. rc = TRUE;
  143. done:
  144. DC_END_FN();
  145. return rc;
  146. }
  147. // Name: HashDataEx
  148. //
  149. // Purpose: Hash 2 set of data using SHA.
  150. //
  151. // Returns: TRUE if succeeded
  152. //
  153. // Params: IN pCapiFunctionTable: CAPI function table
  154. // IN hProv: Handle of the cript provider
  155. // IN pbData: point to the data to be hashed
  156. // IN dwDataLen: the size of the data to be hashed
  157. // IN pbData2: point to the data to be hashed
  158. // IN dwDataLen2: the size of the data to be hashed
  159. // OUT phHash: point to the hash
  160. BOOL HashDataEx(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, PBYTE pbData, DWORD dwDataLen,
  161. PBYTE pbData2, DWORD dwDataLen2, HCRYPTHASH* phHash)
  162. {
  163. BOOL rc = FALSE;
  164. DC_BEGIN_FN("HashDataEx");
  165. //
  166. // Create a hash object.
  167. //
  168. if(!pCapiFunctionTable->pfnCryptCreateHash(hProv, CALG_SHA1, 0, 0, phHash)) {
  169. printf("Error %x during CryptCreateHash!\n", GetLastError());
  170. goto done;
  171. }
  172. //
  173. // Hash in the data.
  174. //
  175. if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData, dwDataLen, 0)) {
  176. printf("Error %x during CryptHashData!\n", GetLastError());
  177. goto done;
  178. }
  179. if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData2, dwDataLen2, 0)) {
  180. printf("Error %x during CryptHashData!\n", GetLastError());
  181. goto done;
  182. }
  183. rc = TRUE;
  184. done:
  185. DC_END_FN();
  186. return rc;
  187. }
  188. // Name: HmacHashData
  189. //
  190. // Purpose: Hash the data using HmacSHA.
  191. //
  192. // Returns: TRUE if succeeded
  193. //
  194. // Params: IN pCapiFunctionTable: CAPI function table
  195. // IN hProv: Handle of the cript provider
  196. // IN pbData: point to the data to be hashed
  197. // IN dwDataLen: the size of the data to be hashed
  198. // IN hKey: handle to the key
  199. // OUT phHash: point to the hash
  200. BOOL HmacHashData(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, PBYTE pbData, DWORD dwDataLen,
  201. HCRYPTKEY hKey, HCRYPTHASH* phHash)
  202. {
  203. BOOL rc = FALSE;
  204. BYTE bmacinfo[sizeof(HMAC_INFO)];
  205. HMAC_INFO* pmac;
  206. memset(bmacinfo, 0, sizeof(bmacinfo));
  207. pmac = (HMAC_INFO*)bmacinfo;
  208. pmac->HashAlgid = CALG_SHA1;
  209. DC_BEGIN_FN("HmacHashData");
  210. //
  211. // Create a hash object.
  212. //
  213. if(!pCapiFunctionTable->pfnCryptCreateHash(hProv, CALG_HMAC, hKey, 0, phHash)) {
  214. TRC_ERR((TB, _T("Error %x during CryptCreateHash!\n"), GetLastError()));
  215. goto done;
  216. }
  217. rc = pCapiFunctionTable->pfnCryptSetHashParam(*phHash, HP_HMAC_INFO, bmacinfo, 0);
  218. //
  219. // Hash in the data.
  220. //
  221. if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData, dwDataLen, 0)) {
  222. TRC_ERR((TB, _T("Error %x during CryptHashData!\n"), GetLastError()));
  223. goto done;
  224. }
  225. rc = TRUE;
  226. done:
  227. DC_END_FN();
  228. return rc;
  229. }
  230. // Name: HmacHashDataEx
  231. //
  232. // Purpose: Hash 2 set of data using HmacSHA.
  233. //
  234. // Returns: TRUE if succeeded
  235. //
  236. // Params: IN pCapiFunctionTable: CAPI function table
  237. // IN hProv: Handle of the cript provider
  238. // IN pbData: point to the data to be hashed
  239. // IN dwDataLen: the size of the data to be hashed
  240. // IN pbData2: point to the data to be hashed
  241. // IN dwDataLen2: the size of the data to be hashed
  242. // IN hKey: handle to the key
  243. // OUT phHash: point to the hash
  244. BOOL HmacHashDataEx(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, PBYTE pbData, DWORD dwDataLen,
  245. PBYTE pbData2, DWORD dwDataLen2, HCRYPTKEY hKey, HCRYPTHASH* phHash)
  246. {
  247. BOOL rc = FALSE;
  248. BYTE bmacinfo[sizeof(HMAC_INFO)];
  249. HMAC_INFO* pmac;
  250. memset(bmacinfo, 0, sizeof(bmacinfo));
  251. pmac = (HMAC_INFO*)bmacinfo;
  252. pmac->HashAlgid = CALG_SHA1;
  253. DC_BEGIN_FN("HmacHashDataEx");
  254. //
  255. // Create a hash object.
  256. //
  257. if(!pCapiFunctionTable->pfnCryptCreateHash(hProv, CALG_HMAC, hKey, 0, phHash)) {
  258. TRC_ERR((TB, _T("Error %x during CryptCreateHash!\n"), GetLastError()));
  259. goto done;
  260. }
  261. rc = pCapiFunctionTable->pfnCryptSetHashParam(*phHash, HP_HMAC_INFO, bmacinfo, 0);
  262. //
  263. // Hash in the data.
  264. //
  265. if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData, dwDataLen, 0)) {
  266. TRC_ERR((TB, _T("Error %x during CryptHashData!\n"), GetLastError()));
  267. goto done;
  268. }
  269. if(!pCapiFunctionTable->pfnCryptHashData(*phHash, pbData2, dwDataLen2, 0)) {
  270. TRC_ERR((TB, _T("Error %x during CryptHashData!\n"), GetLastError()));
  271. goto done;
  272. }
  273. rc = TRUE;
  274. done:
  275. DC_END_FN();
  276. return rc;
  277. }
  278. // Name: DumpHashes
  279. //
  280. // Purpose: Get the hash bits from hash handle
  281. //
  282. // Returns: TRUE if succeeded
  283. //
  284. // Params: IN pCapiFunctionTable: CAPI function table
  285. // IN phHash: point to hash handle
  286. // OUT pbBytes: point data buffer to get hash
  287. // IN dwTotal: len of the data buffer
  288. BOOL DumpHashes(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTHASH* phHash, PBYTE pbBytes, DWORD dwTotal)
  289. {
  290. BOOL rc = FALSE;
  291. DC_BEGIN_FN("DumpHashes");
  292. if (!pCapiFunctionTable->pfnCryptGetHashParam(*phHash, HP_HASHVAL, pbBytes, &dwTotal , 0)) {
  293. TRC_ERR((TB, _T("Error %x during CryptGetHashParam!\n"), GetLastError()));
  294. goto done;
  295. }
  296. //
  297. //destroy the hash, we don't need it anymore
  298. //
  299. if(*phHash) {
  300. pCapiFunctionTable->pfnCryptDestroyHash(*phHash);
  301. *phHash = 0;
  302. }
  303. rc = TRUE;
  304. done:
  305. DC_END_FN();
  306. return rc;
  307. }
  308. // Name: TSCAPI_Init
  309. //
  310. // Purpose: Initialize the CAPI function table.
  311. //
  312. // Returns: TRUE - succeeded
  313. // FALSE - failed
  314. //
  315. // Params: IN pCapiData: CAPI data
  316. BOOL TSCAPI_Init(PCAPIData pCapiData)
  317. {
  318. BOOL rc = FALSE;
  319. // FIPS is only available on WinXP and later
  320. if (!Is_WinXP_or_Later()) {
  321. goto done;
  322. }
  323. pCapiData->hAdvapi32 = LoadLibrary(L"advapi32.dll");
  324. if (pCapiData->hAdvapi32 == NULL) {
  325. goto done;
  326. }
  327. if ((pCapiData->CapiFunctionTable.pfnCryptAcquireContext = (CRYPTACQUIRECONTEXT *)GetProcAddress(
  328. pCapiData->hAdvapi32, "CryptAcquireContextW")) == NULL) {
  329. goto done;
  330. }
  331. if ((pCapiData->CapiFunctionTable.pfnCryptReleaseContext = (CRYPTRELEASECONTEXT *)GetProcAddress(
  332. pCapiData->hAdvapi32, "CryptReleaseContext")) == NULL) {
  333. goto done;
  334. }
  335. if ((pCapiData->CapiFunctionTable.pfnCryptGenRandom = (CRYPTGENRANDOM *)GetProcAddress(
  336. pCapiData->hAdvapi32, "CryptGenRandom")) == NULL) {
  337. goto done;
  338. }
  339. if ((pCapiData->CapiFunctionTable.pfnCryptEncrypt = (CRYPTENCRYPT *)GetProcAddress(
  340. pCapiData->hAdvapi32, "CryptEncrypt")) == NULL) {
  341. goto done;
  342. }
  343. if ((pCapiData->CapiFunctionTable.pfnCryptDecrypt = (CRYPTDECRYPT *)GetProcAddress(
  344. pCapiData->hAdvapi32, "CryptDecrypt")) == NULL) {
  345. goto done;
  346. }
  347. if ((pCapiData->CapiFunctionTable.pfnCryptImportKey = (CRYPTIMPORTKEY *)GetProcAddress(
  348. pCapiData->hAdvapi32, "CryptImportKey")) == NULL) {
  349. goto done;
  350. }
  351. if ((pCapiData->CapiFunctionTable.pfnCryptSetKeyParam = (CRYPTSETKEYPARAM *)GetProcAddress(
  352. pCapiData->hAdvapi32, "CryptSetKeyParam")) == NULL) {
  353. goto done;
  354. }
  355. if ((pCapiData->CapiFunctionTable.pfnCryptDestroyKey = (CRYPTDESTROYKEY *)GetProcAddress(
  356. pCapiData->hAdvapi32, "CryptDestroyKey")) == NULL) {
  357. goto done;
  358. }
  359. if ((pCapiData->CapiFunctionTable.pfnCryptCreateHash = (CRYPTCREATEHASH *)GetProcAddress(
  360. pCapiData->hAdvapi32, "CryptCreateHash")) == NULL) {
  361. goto done;
  362. }
  363. if ((pCapiData->CapiFunctionTable.pfnCryptHashData = (CRYPTHASHDATA *)GetProcAddress(
  364. pCapiData->hAdvapi32, "CryptHashData")) == NULL) {
  365. goto done;
  366. }
  367. if ((pCapiData->CapiFunctionTable.pfnCryptSetHashParam = (CRYPTSETHASHPARAM *)GetProcAddress(
  368. pCapiData->hAdvapi32, "CryptSetHashParam")) == NULL) {
  369. goto done;
  370. }
  371. if ((pCapiData->CapiFunctionTable.pfnCryptGetHashParam = (CRYPTGETHASHPARAM *)GetProcAddress(
  372. pCapiData->hAdvapi32, "CryptGetHashParam")) == NULL) {
  373. goto done;
  374. }
  375. if ((pCapiData->CapiFunctionTable.pfnCryptDestroyHash = (CRYPTDESTROYHASH *)GetProcAddress(
  376. pCapiData->hAdvapi32, "CryptDestroyHash")) == NULL) {
  377. goto done;
  378. }
  379. rc = TRUE;
  380. done:
  381. return rc;
  382. }
  383. // Name: TSCAPI_Enable
  384. //
  385. // Purpose: Some CAPI initialization
  386. //
  387. // Returns: TRUE - succeeded
  388. // FALSE - failed
  389. //
  390. // Params: IN pCapiData: CAPI data
  391. BOOL TSCAPI_Enable(PCAPIData pCapiData)
  392. {
  393. BOOL rc = FALSE;
  394. DWORD Error;
  395. DWORD dwExtraFlags = 0;
  396. HRESULT hr;
  397. DC_BEGIN_FN("TSCAPI_Enable");
  398. // Get handle to the default provider.
  399. if(!pCapiData->CapiFunctionTable.pfnCryptAcquireContext(&(pCapiData->hProv),
  400. TERMSRV_NAME, MS_ENHANCED_PROV, PROV_RSA_FULL, dwExtraFlags)) {
  401. // Could not acquire a crypt context, get the reason of failure
  402. Error = GetLastError();
  403. hr = HRESULT_FROM_WIN32(Error);
  404. if (hr == NTE_BAD_KEYSET) {
  405. //
  406. //create a new keyset
  407. //
  408. if(!pCapiData->CapiFunctionTable.pfnCryptAcquireContext(&(pCapiData->hProv), TERMSRV_NAME,
  409. MS_ENHANCED_PROV, PROV_RSA_FULL, dwExtraFlags | CRYPT_NEWKEYSET)) {
  410. Error = GetLastError();
  411. TRC_ERR((TB, _T("Error %x during CryptAcquireContext!\n"), GetLastError()));
  412. goto done;
  413. }
  414. }
  415. else {
  416. goto done;
  417. }
  418. }
  419. rc = TRUE;
  420. done:
  421. DC_END_FN();
  422. return rc;
  423. }
  424. // Name: TSCAPI_Term
  425. //
  426. // Purpose: Terminate the CAPI .
  427. //
  428. // Returns: TRUE if succeeded
  429. //
  430. //
  431. // Params: IN pCapiData: CAPI data
  432. BOOL TSCAPI_Term(PCAPIData pCapiData)
  433. {
  434. BOOL rc = TRUE;
  435. DC_BEGIN_FN("TSCAPI_Enable");
  436. if (pCapiData->hEncKey) {
  437. rc = pCapiData->CapiFunctionTable.pfnCryptDestroyKey(pCapiData->hEncKey);
  438. pCapiData->hEncKey = NULL;
  439. }
  440. if (pCapiData->hDecKey) {
  441. rc = pCapiData->CapiFunctionTable.pfnCryptDestroyKey(pCapiData->hDecKey);
  442. pCapiData->hDecKey = NULL;
  443. }
  444. if (pCapiData->hProv) {
  445. rc = pCapiData->CapiFunctionTable.pfnCryptReleaseContext(pCapiData->hProv, 0);
  446. pCapiData->hProv = NULL;
  447. }
  448. DC_END_FN();
  449. return rc;
  450. }
  451. // Name: TSCAPI_GenerateRandomNumber
  452. //
  453. // Purpose: Generates random number using CAPI in user mode
  454. //
  455. // Returns: TRUE if succeeded
  456. //
  457. //
  458. // Params: IN pCapiData: CAPI data
  459. // OUT pbRandomBits: pointer to a buffer where a random key is returned.
  460. // IN cbLen: length of the random key required.
  461. BOOL TSCAPI_GenerateRandomNumber(
  462. PCAPIData pCapiData,
  463. LPBYTE pbRandomBits,
  464. DWORD cbLen)
  465. {
  466. BOOL rc = FALSE;
  467. DC_BEGIN_FN("TSCAPI_GenerateRandomNumber");
  468. if (pCapiData->CapiFunctionTable.pfnCryptGenRandom(pCapiData->hProv, cbLen, pbRandomBits)) {
  469. rc = TRUE;
  470. }
  471. done:
  472. DC_END_FN();
  473. return rc;
  474. }
  475. // Name: ImportKey
  476. //
  477. // Purpose: Import the key in bits to crypt provider
  478. //
  479. // Returns: TRUE if succeeded
  480. //
  481. //
  482. // Params: IN pCapiData: CAPI data
  483. // IN hProv: handle to the crypt provider
  484. // IN Algid: Algorithm identifier
  485. // IN pbKey: point to the buffer contain the key bits
  486. // IN dwKeyLen: length of the key.
  487. // IN dwFlags: dwFlags used in CryptImportKey
  488. // OUT phKey: point to the key handle
  489. BOOL ImportKey(PCAPI_FUNCTION_TABLE pCapiFunctionTable, HCRYPTPROV hProv, ALG_ID Algid, PBYTE pbKey, DWORD dwKeyLen, DWORD dwFlags, HCRYPTKEY* phKey)
  490. {
  491. BOOL rc = FALSE;
  492. PBYTE pbData = NULL;
  493. DWORD cbLen = 0;
  494. DWORD Error;
  495. //
  496. //create blob header first
  497. //
  498. BLOBHEADER blobHead;
  499. blobHead.bType = PLAINTEXTKEYBLOB;
  500. blobHead.bVersion = 2;
  501. blobHead.reserved = 0;
  502. blobHead.aiKeyAlg = Algid;
  503. DC_BEGIN_FN("ImportKey");
  504. //
  505. //calculate the length
  506. //
  507. cbLen = sizeof(blobHead) + sizeof(dwKeyLen) + dwKeyLen;
  508. pbData = (PBYTE)LocalAlloc(LPTR, cbLen);
  509. if(NULL == pbData) {
  510. TRC_ERR((TB, _T("Out of memory\n")));
  511. goto done;
  512. }
  513. //
  514. //copy data. First data must be header, then the size of the key, then the key
  515. //
  516. memcpy( pbData, &blobHead, sizeof(blobHead));
  517. memcpy( pbData + sizeof(blobHead), &dwKeyLen, sizeof(dwKeyLen));
  518. memcpy( pbData + sizeof(blobHead) + sizeof(dwKeyLen), pbKey, dwKeyLen);
  519. if( !pCapiFunctionTable->pfnCryptImportKey( hProv, pbData, cbLen, 0, dwFlags, phKey)) {
  520. Error = GetLastError();
  521. TRC_ERR((TB, _T("Failed to import plaint text key Error = 0x%x\n"), Error));
  522. *phKey = 0;
  523. goto done;
  524. }
  525. rc = TRUE;
  526. done:
  527. DC_END_FN();
  528. if(pbData) {
  529. LocalFree(pbData);
  530. }
  531. return rc;
  532. }
  533. // Name: TSCAPI_DeriveKey
  534. //
  535. // Purpose: Derive the key from the hash.
  536. //
  537. // Returns: TRUE if succeeded
  538. //
  539. // Params: IN pCapiFunctionTable: CAPI function table
  540. // IN hProv: crypt provider handle
  541. // OUT phKey: point to key handle
  542. // IN rgbSHABase: base data used to derive the key
  543. // IN cbSHABase: size of the base data
  544. // OUT pbKey: point to the derived DESkey
  545. // OUT pdwKeyLen: point to the key length
  546. BOOL TSCAPI_DeriveKey(
  547. PCAPI_FUNCTION_TABLE pCapiFunctionTable,
  548. HCRYPTPROV hProv,
  549. HCRYPTKEY *phKey,
  550. BYTE *rgbSHABase,
  551. DWORD cbSHABase,
  552. BYTE *pbKey,
  553. DWORD *pdwKeyLen)
  554. {
  555. BOOL rc = FALSE;
  556. BOOL fRet = FALSE;
  557. BYTE rgb3DESKey[MAX_FIPS_SESSION_KEY_SIZE];
  558. DC_BEGIN_FN("TSCAPI_DeriveKey");
  559. //
  560. //Generate the key as follows
  561. //1. Hash the secret. Call the result H1 (rgbSHABase in our case)
  562. //2. Use 1st 21 bytes of [H1|H1] as the 3DES key
  563. //3. Expand the 21-byte 3DES key to a 24-byte 3DES key (including parity bit), which
  564. // will be used by CryptAPI
  565. //4. Set the parity on the 3DES key to be odd
  566. //
  567. //Step 2 - [H1|H1]
  568. //
  569. memcpy(rgb3DESKey, rgbSHABase, cbSHABase);
  570. memcpy(rgb3DESKey + cbSHABase, rgbSHABase, DES3_KEYLEN - cbSHABase);
  571. //
  572. //Step 3 - Expand the key
  573. //
  574. Expandkey(rgb3DESKey);
  575. //
  576. //Step 4 - Set parity
  577. //
  578. Mydesparityonkey(rgb3DESKey, sizeof(rgb3DESKey));
  579. //
  580. //import the key as PLAINTEXT into the csp
  581. //
  582. rc = ImportKey(pCapiFunctionTable, hProv, CALG_3DES, rgb3DESKey, sizeof(rgb3DESKey), 0, phKey);
  583. if (!rc) {
  584. goto done;
  585. }
  586. //give the key to the caller
  587. //
  588. memcpy(pbKey, rgb3DESKey, sizeof(rgb3DESKey));
  589. *pdwKeyLen = sizeof(rgb3DESKey);
  590. rc = TRUE;
  591. done:
  592. DC_END_FN();
  593. return rc;
  594. }
  595. // Name: TSCAPI_MakeSessionKeys
  596. //
  597. // Purpose: Make the key from client/server random numbers
  598. //
  599. // Returns: TRUE if succeeded
  600. //
  601. // Params: IN pCapiData: CAPI Data
  602. // IN pKeyPair: Randow numbers used to generate key
  603. // IN pEnumMethod: To generate Encrypt or Decrypt key, If NULL, both keys
  604. BOOL TSCAPI_MakeSessionKeys(
  605. PCAPIData pCapiData,
  606. RANDOM_KEYS_PAIR *pKeyPair,
  607. CryptMethod *pEnumMethod)
  608. {
  609. BOOL rc = FALSE;
  610. HCRYPTHASH hHash;
  611. DWORD dwKeyLen;
  612. BYTE rgbSHABase1[A_SHA_DIGEST_LEN];
  613. BYTE rgbSHABase2[A_SHA_DIGEST_LEN];
  614. DC_BEGIN_FN("TSCAPI_MakeSessionKeys");
  615. memset(rgbSHABase1, 0, sizeof(rgbSHABase1));
  616. memset(rgbSHABase2, 0, sizeof(rgbSHABase2));
  617. //
  618. // Client Encrypt/Server Decrypt key
  619. //
  620. if ((pEnumMethod == NULL) ||
  621. (*pEnumMethod == Encrypt)) {
  622. if (!pCapiData->CapiFunctionTable.pfnCryptCreateHash(pCapiData->hProv, CALG_SHA1, 0, 0, &hHash)) {
  623. TRC_ERR((TB, _T("CryptCreateHash failed with %u"), GetLastError()));
  624. goto done;
  625. }
  626. if (!pCapiData->CapiFunctionTable.pfnCryptHashData(hHash, pKeyPair->clientRandom + RANDOM_KEY_LENGTH/2, RANDOM_KEY_LENGTH/2, 0)) {
  627. TRC_ERR((TB, _T("CryptHashData failed with %u"), GetLastError()));
  628. goto done;
  629. }
  630. if (!pCapiData->CapiFunctionTable.pfnCryptHashData(hHash, pKeyPair->serverRandom + RANDOM_KEY_LENGTH/2, RANDOM_KEY_LENGTH/2, 0)) {
  631. TRC_ERR((TB, _T("CryptHashData failed with %u"), GetLastError()));
  632. goto done;
  633. }
  634. if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, rgbSHABase1, sizeof(rgbSHABase1))) {
  635. goto done;
  636. }
  637. dwKeyLen = sizeof(pCapiData->bEncKey);
  638. if (!TSCAPI_DeriveKey(&(pCapiData->CapiFunctionTable), pCapiData->hProv, &(pCapiData->hEncKey), rgbSHABase1,
  639. sizeof(rgbSHABase1), pCapiData->bEncKey, &dwKeyLen)) {
  640. goto done;
  641. }
  642. //
  643. //set the IV
  644. //
  645. if(!pCapiData->CapiFunctionTable.pfnCryptSetKeyParam(pCapiData->hEncKey, KP_IV, rgbIV, 0 )) {
  646. TRC_ERR((TB, _T("Error %x during CryptSetKeyParam!\n"), GetLastError()));
  647. goto done;
  648. }
  649. }
  650. //
  651. // Server Encrypt/Client Decrypt key
  652. //
  653. if ((pEnumMethod == NULL) ||
  654. (*pEnumMethod == Decrypt)) {
  655. if (!pCapiData->CapiFunctionTable.pfnCryptCreateHash(pCapiData->hProv, CALG_SHA1, 0, 0, &hHash)) {
  656. TRC_ERR((TB, _T("CryptCreateHash failed with %u"), GetLastError()));
  657. goto done;
  658. }
  659. if (!pCapiData->CapiFunctionTable.pfnCryptHashData(hHash, pKeyPair->clientRandom, RANDOM_KEY_LENGTH/2, 0)) {
  660. TRC_ERR((TB, _T("CryptHashData failed with %u"), GetLastError()));
  661. goto done;
  662. }
  663. if (!pCapiData->CapiFunctionTable.pfnCryptHashData(hHash, pKeyPair->serverRandom, RANDOM_KEY_LENGTH/2, 0)) {
  664. TRC_ERR((TB, _T("CryptHashData failed with %u"), GetLastError()));
  665. goto done;
  666. }
  667. if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, rgbSHABase2, sizeof(rgbSHABase2))) {
  668. goto done;
  669. }
  670. dwKeyLen = sizeof(pCapiData->bDecKey);
  671. if (!TSCAPI_DeriveKey(&(pCapiData->CapiFunctionTable), pCapiData->hProv, &(pCapiData->hDecKey), rgbSHABase2,
  672. sizeof(rgbSHABase2), pCapiData->bDecKey, &dwKeyLen)) {
  673. goto done;
  674. }
  675. //
  676. //set the IV
  677. //
  678. if(!pCapiData->CapiFunctionTable.pfnCryptSetKeyParam(pCapiData->hDecKey, KP_IV, rgbIV, 0 )) {
  679. TRC_ERR((TB, _T("Error %x during CryptSetKeyParam!\n"), GetLastError()));
  680. goto done;
  681. }
  682. }
  683. //
  684. // Get the signing key
  685. // The signing key is SHA(rgbSHABase2|rgbSHABase1)
  686. //
  687. if (pEnumMethod == NULL) {
  688. if (!HashDataEx(&(pCapiData->CapiFunctionTable), pCapiData->hProv, rgbSHABase2, sizeof(rgbSHABase2),
  689. rgbSHABase1, sizeof(rgbSHABase1), &hHash)) {
  690. goto done;
  691. }
  692. if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, pCapiData->bSignKey, sizeof(pCapiData->bSignKey))) {
  693. goto done;
  694. }
  695. rc = ImportKey(&(pCapiData->CapiFunctionTable), pCapiData->hProv, CALG_RC2, pCapiData->bSignKey, sizeof(pCapiData->bSignKey), CRYPT_IPSEC_HMAC_KEY, &(pCapiData->hSignKey));
  696. if (!rc) {
  697. goto done;
  698. }
  699. }
  700. rc = TRUE;
  701. done:
  702. DC_END_FN();
  703. return rc;
  704. }
  705. // Name: TSCAPI_AdjustDataLen
  706. //
  707. // Purpose: In Block encryption mode, adjust the data len to multiple of blocks
  708. //
  709. // Returns: Adjusted data length
  710. //
  711. // Params: IN dataLen: Data length needed to be encrypted
  712. DCUINT TSCAPI_AdjustDataLen(DCUINT dataLen)
  713. {
  714. return (dataLen - dataLen % FIPS_BLOCK_LEN + FIPS_BLOCK_LEN);
  715. }
  716. // Name: TSCAPI_EncryptData
  717. //
  718. // Purpose: Encrypt the data and compute the signature
  719. //
  720. // Returns: No
  721. //
  722. // Params: IN pCapiData: CAPI Data
  723. // IN/OUT pbData: pointer to the data buffer being encrypted, encrypted data is
  724. // returned in the same buffer.
  725. // IN/OUT pdwDataLen: data length to be encrypted, and returns encrypted data length
  726. // IN dwPadLen: padding length in the data buffer
  727. // OUT pbSignature: pointer to a signature buffer where the data signature is returned.
  728. // IN dwEncryptionCount: running counter of all encryptions
  729. BOOL TSCAPI_EncryptData(
  730. PCAPIData pCapiData,
  731. LPBYTE pbData,
  732. DWORD *pdwDataLen,
  733. DWORD dwBufLen,
  734. LPBYTE pbSignature,
  735. DWORD dwEncryptionCount)
  736. {
  737. BOOL rc = FALSE;
  738. DWORD Error;
  739. HCRYPTHASH hHash;
  740. BYTE rgbSHA[A_SHA_DIGEST_LEN];
  741. BYTE pbHmac[A_SHA_DIGEST_LEN];
  742. DWORD dwTemp = dwBufLen;
  743. DC_BEGIN_FN("TSCAPI_EncryptData");
  744. // Compute signature
  745. if (!HmacHashDataEx(&(pCapiData->CapiFunctionTable), pCapiData->hProv, pbData, *pdwDataLen, (BYTE *)&dwEncryptionCount,
  746. sizeof(dwEncryptionCount), pCapiData->hSignKey, &hHash)) {
  747. goto done;
  748. }
  749. if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, pbHmac, sizeof(pbHmac))) {
  750. goto done;
  751. }
  752. // Take the 1st 8 bytes of Hmac as signature
  753. memcpy(pbSignature, pbHmac, MAX_SIGN_SIZE);
  754. rc = pCapiData->CapiFunctionTable.pfnCryptEncrypt(pCapiData->hEncKey,
  755. NULL, //Hash
  756. FALSE, //Final
  757. 0,
  758. pbData,
  759. &dwTemp,
  760. dwBufLen);
  761. if (!rc) {
  762. TRC_ERR((TB, _T("Error %x during CryptEncrypt!\n"), GetLastError()));
  763. goto done;
  764. }
  765. rc = TRUE;
  766. done:
  767. DC_END_FN();
  768. return rc;
  769. }
  770. // Name: TSCAPI_DecryptData
  771. //
  772. // Purpose: Decrypt the data and compare the signature
  773. //
  774. // Returns: TRUE if successfully decrypted the data
  775. //
  776. // Params: IN PCAPIData: CAPI Data
  777. // IN/OUT pbData: pointer to the data buffer being decrypted, decrypted data is
  778. // returned in the same buffer.
  779. // IN dwDataLen: data length to be decrypted
  780. // IN dwPadLen: padding length in the data buffer
  781. // IN pbSignature: pointer to a signature buffer
  782. // IN dwDecryptionCount: running counter of all encryptions
  783. BOOL TSCAPI_DecryptData(
  784. PCAPIData pCapiData,
  785. LPBYTE pbData,
  786. DWORD dwDataLen,
  787. DWORD dwPadLen,
  788. LPBYTE pbSignature,
  789. DWORD dwDecryptionCount)
  790. {
  791. BOOL rc = FALSE;
  792. DWORD dwLen = dwDataLen;
  793. DWORD Error;
  794. HCRYPTHASH hHash;
  795. BYTE abSignature[A_SHA_DIGEST_LEN];
  796. BYTE rgbSHA[A_SHA_DIGEST_LEN];
  797. DC_BEGIN_FN("TSCAPI_DecryptData");
  798. // data length check
  799. if (dwDataLen <= dwPadLen) {
  800. TRC_ERR((TB, _T("Bad data length, padLen %d is larger than DataLen %d"),
  801. dwPadLen, dwDataLen));
  802. goto done;
  803. }
  804. rc = pCapiData->CapiFunctionTable.pfnCryptDecrypt(pCapiData->hDecKey,
  805. NULL, //Hash
  806. FALSE, //Final
  807. 0,
  808. pbData,
  809. &dwLen);
  810. if (!rc) {
  811. TRC_ERR((TB, _T("Error %x during CryptDecrypt!\n"), GetLastError()));
  812. goto done;
  813. }
  814. // Compute signature
  815. if (!HmacHashDataEx(&(pCapiData->CapiFunctionTable), pCapiData->hProv, pbData, dwDataLen - dwPadLen, (BYTE *)&dwDecryptionCount,
  816. sizeof(dwDecryptionCount), pCapiData->hSignKey, &hHash)) {
  817. goto done;
  818. }
  819. if (!DumpHashes(&(pCapiData->CapiFunctionTable), &hHash, abSignature, sizeof(abSignature))) {
  820. goto done;
  821. }
  822. //
  823. // check to see the sigature match.
  824. //
  825. if(!memcmp(
  826. (LPBYTE)abSignature,
  827. pbSignature,
  828. MAX_SIGN_SIZE)) {
  829. rc = TRUE;;
  830. }
  831. done:
  832. DC_END_FN();
  833. return rc;
  834. }