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.

658 lines
19 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: cryptfnc.cpp
  4. //
  5. // Module: CMSECURE.LIB
  6. //
  7. // Synopsis: This file implements the cryptfnc class that provides
  8. // easy to use interfaces on the CryptoAPI.
  9. //
  10. // Copyright (c) 1996-1999 Microsoft Corporation
  11. //
  12. // Author: AshishS Created 12/03/96
  13. // henryt modified for CM 5/21/97
  14. //
  15. //+----------------------------------------------------------------------------
  16. #include "cryptfnc.h"
  17. #ifdef UNICODE
  18. #define LoadLibraryExU LoadLibraryExW
  19. #else
  20. #define LoadLibraryExU LoadLibraryExA
  21. #endif
  22. #include "linkdll.h" // LinkToDll and BindLinkage
  23. CCryptFunctions::~CCryptFunctions()
  24. {
  25. // Release provider handle.
  26. if (m_hProv != 0)
  27. {
  28. m_fnCryptReleaseContext(m_hProv, 0);
  29. }
  30. if (m_AdvApiLink.hInstAdvApi32)
  31. {
  32. FreeLibrary(m_AdvApiLink.hInstAdvApi32);
  33. ZeroMemory(&m_AdvApiLink, sizeof(m_AdvApiLink));
  34. }
  35. }
  36. CCryptFunctions::CCryptFunctions()
  37. {
  38. m_hProv = 0;
  39. ZeroMemory(&m_AdvApiLink, sizeof(m_AdvApiLink));
  40. }
  41. BOOL CCryptFunctions::m_fnCryptAcquireContext(HCRYPTPROV *phProv, LPCSTR pszContainer, LPCSTR pszProvider,
  42. DWORD dwProvType, DWORD dwFlags)
  43. {
  44. BOOL bReturn = FALSE;
  45. MYDBGASSERT(m_AdvApiLink.pfnCryptAcquireContext);
  46. if (m_AdvApiLink.pfnCryptAcquireContext)
  47. {
  48. bReturn = m_AdvApiLink.pfnCryptAcquireContext(phProv, pszContainer, pszProvider,
  49. dwProvType, dwFlags);
  50. }
  51. return bReturn;
  52. }
  53. BOOL CCryptFunctions::m_fnCryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey,
  54. DWORD dwFlags, HCRYPTHASH *phHash)
  55. {
  56. BOOL bReturn = FALSE;
  57. MYDBGASSERT(m_AdvApiLink.pfnCryptCreateHash);
  58. if (m_AdvApiLink.pfnCryptCreateHash)
  59. {
  60. bReturn = m_AdvApiLink.pfnCryptCreateHash(hProv, Algid, hKey, dwFlags, phHash);
  61. }
  62. return bReturn;
  63. }
  64. BOOL CCryptFunctions::m_fnCryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags,
  65. BYTE *pbData, DWORD *pdwDataLen)
  66. {
  67. BOOL bReturn = FALSE;
  68. MYDBGASSERT(m_AdvApiLink.pfnCryptDecrypt);
  69. if (m_AdvApiLink.pfnCryptDecrypt)
  70. {
  71. bReturn = m_AdvApiLink.pfnCryptDecrypt(hKey, hHash, Final, dwFlags, pbData, pdwDataLen);
  72. }
  73. return bReturn;
  74. }
  75. BOOL CCryptFunctions::m_fnCryptDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData,
  76. DWORD dwFlags, HCRYPTKEY *phKey)
  77. {
  78. BOOL bReturn = FALSE;
  79. MYDBGASSERT(m_AdvApiLink.pfnCryptDeriveKey);
  80. if (m_AdvApiLink.pfnCryptDeriveKey)
  81. {
  82. bReturn = m_AdvApiLink.pfnCryptDeriveKey(hProv, Algid, hBaseData, dwFlags, phKey);
  83. }
  84. return bReturn;
  85. }
  86. BOOL CCryptFunctions::m_fnCryptDestroyHash(HCRYPTHASH hHash)
  87. {
  88. BOOL bReturn = FALSE;
  89. MYDBGASSERT(m_AdvApiLink.pfnCryptDestroyHash);
  90. if (m_AdvApiLink.pfnCryptDestroyHash)
  91. {
  92. bReturn = m_AdvApiLink.pfnCryptDestroyHash(hHash);
  93. }
  94. return bReturn;
  95. }
  96. BOOL CCryptFunctions::m_fnCryptDestroyKey(HCRYPTKEY hKey)
  97. {
  98. BOOL bReturn = FALSE;
  99. MYDBGASSERT(m_AdvApiLink.pfnCryptDestroyKey);
  100. if (m_AdvApiLink.pfnCryptDestroyKey)
  101. {
  102. bReturn = m_AdvApiLink.pfnCryptDestroyKey(hKey);
  103. }
  104. return bReturn;
  105. }
  106. BOOL CCryptFunctions::m_fnCryptEncrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags,
  107. BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen)
  108. {
  109. BOOL bReturn = FALSE;
  110. MYDBGASSERT(m_AdvApiLink.pfnCryptEncrypt);
  111. if (m_AdvApiLink.pfnCryptEncrypt)
  112. {
  113. bReturn = m_AdvApiLink.pfnCryptEncrypt(hKey, hHash, Final, dwFlags, pbData, pdwDataLen, dwBufLen);
  114. }
  115. return bReturn;
  116. }
  117. BOOL CCryptFunctions::m_fnCryptHashData(HCRYPTHASH hHash, CONST BYTE *pbData, DWORD dwDataLen, DWORD dwFlags)
  118. {
  119. BOOL bReturn = FALSE;
  120. MYDBGASSERT(m_AdvApiLink.pfnCryptHashData);
  121. if (m_AdvApiLink.pfnCryptHashData)
  122. {
  123. bReturn = m_AdvApiLink.pfnCryptHashData(hHash, pbData, dwDataLen, dwFlags);
  124. }
  125. return bReturn;
  126. }
  127. BOOL CCryptFunctions::m_fnCryptReleaseContext(HCRYPTPROV hProv, ULONG_PTR dwFlags)
  128. {
  129. BOOL bReturn = FALSE;
  130. MYDBGASSERT(m_AdvApiLink.pfnCryptReleaseContext);
  131. if (m_AdvApiLink.pfnCryptReleaseContext)
  132. {
  133. bReturn = m_AdvApiLink.pfnCryptReleaseContext(hProv, dwFlags);
  134. }
  135. return bReturn;
  136. }
  137. BOOL CCryptFunctions::m_pfnCryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE* pbBuffer)
  138. {
  139. BOOL bReturn = FALSE;
  140. MYDBGASSERT(m_AdvApiLink.pfnCryptGenRandom);
  141. if (m_AdvApiLink.pfnCryptGenRandom)
  142. {
  143. bReturn = m_AdvApiLink.pfnCryptGenRandom(hProv, dwLen, pbBuffer);
  144. }
  145. return bReturn;
  146. }
  147. //
  148. // Calls m_pfnCryptGenRandom to create a random key
  149. //
  150. BOOL CCryptFunctions::GenerateRandomKey(PBYTE pbData, DWORD cbData)
  151. {
  152. BOOL fReturn = FALSE;
  153. if (pbData)
  154. {
  155. fReturn = m_pfnCryptGenRandom(m_hProv, cbData, pbData);
  156. }
  157. return fReturn;
  158. }
  159. //+----------------------------------------------------------------------------
  160. //
  161. // Func: CCryptFunctions::GenerateSessionKeyFromPassword
  162. //
  163. // Desc: this function Generates a SessionKey using the pszPassword parameter
  164. //
  165. // Args: [phKey] - location to store the session key
  166. // [pszPassword] - password to generate the session key from
  167. // [dwEncKeyLen] - how many bits of encryption
  168. //
  169. // Return: BOOL (FALSE if a fatal error occurred, else TRUE)
  170. //
  171. // Notes:
  172. //
  173. //-----------------------------------------------------------------------------
  174. BOOL CCryptFunctions::GenerateSessionKeyFromPassword(
  175. HCRYPTKEY * phKey,
  176. LPTSTR pszPassword,
  177. DWORD dwEncKeyLen)
  178. {
  179. DWORD dwLength;
  180. HCRYPTHASH hHash = 0;
  181. // Create hash object.
  182. //
  183. if (!m_fnCryptCreateHash(m_hProv, // handle to CSP
  184. CALG_SHA, // use SHA hash algorithm
  185. 0, // not keyed hash
  186. 0, // flags - always 0
  187. &hHash)) // address where hash object should be created
  188. {
  189. MYDBG(("Error 0x%x during CryptCreateHash", GetLastError()));
  190. goto cleanup;
  191. }
  192. // Hash password string.
  193. //
  194. dwLength = lstrlen(pszPassword) * sizeof(TCHAR);
  195. if (!m_fnCryptHashData(hHash, // handle to hash object
  196. (BYTE *)pszPassword, // address of data to be hashed
  197. dwLength, // length of data
  198. 0)) // flags
  199. {
  200. MYDBG(("Error 0x%x during CryptHashData", GetLastError()));
  201. goto cleanup;
  202. }
  203. // Create block cipher session key based on hash of the password.
  204. //
  205. if (!m_fnCryptDeriveKey(m_hProv, //CSP provider
  206. CALG_RC2, // use RC2 block cipher algorithm
  207. hHash, //handle to hash object
  208. (dwEncKeyLen << 16), // just the key length, no flags - we do not need the key to be exportable
  209. phKey)) //address the newly created key should be copied
  210. {
  211. MYDBG(("Error 0x%x during CryptDeriveKey", GetLastError()));
  212. goto cleanup;
  213. }
  214. // Destroy hash object.
  215. m_fnCryptDestroyHash(hHash);
  216. return TRUE;
  217. cleanup:
  218. // Destroy hash object.
  219. if (hHash != 0)
  220. {
  221. m_fnCryptDestroyHash(hHash);
  222. }
  223. return FALSE;
  224. }
  225. // This function must be called before any member functions of the
  226. // class are used.
  227. // Returns FALSE if a Fatal error occured, TRUE otherwise
  228. BOOL CCryptFunctions::InitCrypt()
  229. {
  230. LPCSTR ArrayOfCryptFuncs [] =
  231. {
  232. #ifdef UNICODE
  233. "CryptAcquireContextW", // this has never been tested
  234. #else
  235. "CryptAcquireContextA",
  236. #endif
  237. "CryptCreateHash",
  238. "CryptDecrypt",
  239. "CryptDeriveKey",
  240. "CryptDestroyHash",
  241. "CryptDestroyKey",
  242. "CryptEncrypt",
  243. "CryptHashData",
  244. "CryptReleaseContext",
  245. "CryptGenRandom", // to create a random session key
  246. NULL
  247. };
  248. BOOL bRet = LinkToDll(&(m_AdvApiLink.hInstAdvApi32), TEXT("Advapi32.dll"), ArrayOfCryptFuncs,
  249. m_AdvApiLink.apvPfn);
  250. if (!bRet)
  251. {
  252. goto cleanup;
  253. }
  254. // Get handle to user default provider.
  255. if (! m_fnCryptAcquireContext(&m_hProv, // address to get the handle to CSP
  256. CM_CRYPTO_CONTAINER, // contianer name
  257. MS_DEF_PROV, // provider
  258. PROV_RSA_FULL, // type of provider
  259. 0)) // no flags
  260. {
  261. DWORD dwError = GetLastError();
  262. MYDBGTST(dwError, ("Error 0x%x during CryptAcquireContext", dwError));
  263. MYDBG(("Calling CryptAcquireContext again to create keyset"));
  264. if (! m_fnCryptAcquireContext(&m_hProv,// handle to CSP
  265. CM_CRYPTO_CONTAINER,// contianer name
  266. MS_DEF_PROV, // provider
  267. PROV_RSA_FULL, // type of provider
  268. CRYPT_NEWKEYSET) ) // create the keyset
  269. {
  270. MYDBG(("Fatal Error 0x%x during second call to CryptAcquireContext", GetLastError()));
  271. goto cleanup;
  272. }
  273. }
  274. return TRUE;
  275. cleanup:
  276. // Release provider handle.
  277. if (m_hProv != 0)
  278. {
  279. m_fnCryptReleaseContext(m_hProv, 0);
  280. }
  281. return FALSE;
  282. }
  283. // Given a key string, and data to encrypt this function generates a
  284. // session key from the key string. This session key is then used to
  285. // encrypt the data.
  286. // Returns FALSE if a Fatal error occured, TRUE otherwise
  287. BOOL CCryptFunctions::EncryptDataWithKey(
  288. LPTSTR pszKey, // password
  289. PBYTE pbData, // Data to be encrypted
  290. DWORD dwDataLength, // Length of data in bytes
  291. PBYTE *ppbEncryptedData, // Encrypted secret key will be stored here
  292. DWORD *pdwEncryptedBufferLen, // Length of this buffer
  293. PFN_CMSECUREALLOC pfnAlloc,
  294. PFN_CMSECUREFREE pfnFree,
  295. DWORD dwEncKeySize // how many bits of encryption do we want? (0 implies "don't care")
  296. )
  297. {
  298. HCRYPTKEY hKey = 0;
  299. DWORD dwErr;
  300. DWORD dwBufferLen;
  301. BOOL fOk = FALSE;
  302. PBYTE pbBuf = NULL;
  303. //
  304. // Init should have been successfully called before
  305. // if no data to be encrypted, don't do anything
  306. //
  307. if (m_hProv == 0 || !dwDataLength)
  308. {
  309. return FALSE;
  310. }
  311. if (!GenerateSessionKeyFromPassword(&hKey, pszKey, dwEncKeySize))
  312. goto cleanup;
  313. // copy the data into another buffer to encrypt it
  314. *pdwEncryptedBufferLen = dwDataLength;
  315. dwBufferLen = dwDataLength + DEFAULT_CRYPTO_EXTRA_BUFFER_SIZE;
  316. while (1)
  317. {
  318. //
  319. // alloc memory for output buffer
  320. //
  321. if (pfnAlloc)
  322. {
  323. *ppbEncryptedData = (PBYTE)pfnAlloc(dwBufferLen);
  324. }
  325. else
  326. {
  327. *ppbEncryptedData = (PBYTE)HeapAlloc(GetProcessHeap(),
  328. HEAP_ZERO_MEMORY,
  329. dwBufferLen);
  330. }
  331. if (!*ppbEncryptedData)
  332. {
  333. MYDBG(("EncryptDataWithKey: out of memory error"));
  334. goto cleanup;
  335. }
  336. // copy the data into another buffer to encrypt it
  337. memcpy (*ppbEncryptedData, pbData, dwDataLength);
  338. // now encrypt the secret key using the key generated
  339. if ( ! m_fnCryptEncrypt(hKey,
  340. 0, // no hash required
  341. TRUE, // Final packet
  342. 0, // Flags - always 0
  343. *ppbEncryptedData, // data buffer
  344. pdwEncryptedBufferLen, // length of data
  345. dwBufferLen ) ) // size of buffer
  346. {
  347. MYDBG(("Error 0x%x during CryptEncrypt", GetLastError()));
  348. if (pfnFree)
  349. {
  350. pfnFree(*ppbEncryptedData);
  351. }
  352. else
  353. {
  354. HeapFree(GetProcessHeap(), 0, *ppbEncryptedData);
  355. }
  356. *ppbEncryptedData = NULL;
  357. dwErr = GetLastError();
  358. //
  359. // if the output is too small, realloc it.
  360. //
  361. if (dwErr == ERROR_MORE_DATA || dwErr == NTE_BAD_LEN)
  362. {
  363. dwBufferLen += DEFAULT_CRYPTO_EXTRA_BUFFER_SIZE;
  364. continue;
  365. }
  366. goto cleanup;
  367. }
  368. //
  369. // we now have the data encrypted. we need to uuencode it.
  370. //
  371. if (pfnAlloc)
  372. {
  373. pbBuf = (PBYTE)pfnAlloc(*pdwEncryptedBufferLen);
  374. }
  375. else
  376. {
  377. pbBuf = (PBYTE)HeapAlloc(GetProcessHeap(),
  378. HEAP_ZERO_MEMORY,
  379. *pdwEncryptedBufferLen);
  380. }
  381. if (!pbBuf)
  382. {
  383. MYDBG(("EncryptDataWithKey: out of memory error"));
  384. if (pfnFree)
  385. {
  386. pfnFree(*ppbEncryptedData);
  387. }
  388. else
  389. {
  390. HeapFree(GetProcessHeap(), 0, *ppbEncryptedData);
  391. }
  392. *ppbEncryptedData = NULL;
  393. goto cleanup;
  394. }
  395. memcpy(pbBuf, *ppbEncryptedData, *pdwEncryptedBufferLen);
  396. uuencode(pbBuf, *pdwEncryptedBufferLen, (CHAR*)*ppbEncryptedData, dwBufferLen);
  397. //
  398. // set the encrypted buffer len
  399. //
  400. *pdwEncryptedBufferLen = lstrlen((LPTSTR)*ppbEncryptedData);
  401. if (pfnFree)
  402. {
  403. pfnFree(pbBuf);
  404. }
  405. else
  406. {
  407. HeapFree(GetProcessHeap(), 0, pbBuf);
  408. }
  409. pbBuf = NULL;
  410. break;
  411. }
  412. fOk = TRUE;
  413. cleanup:
  414. // destroy session key
  415. if (hKey != 0)
  416. m_fnCryptDestroyKey(hKey);
  417. return fOk;
  418. }
  419. // Given a key string, and encrypted data using EncryptDataWithPassword,
  420. // this function generates a session key from the key string. This
  421. // session key is then used to decrypt the data.
  422. // returns
  423. // CRYPT_FNC_NO_ERROR no error
  424. // CRYPT_FNC_BAD_PASSWORD password bad try again
  425. // CRYPT_FNC_INSUFFICIENT_BUFFER larger buffer is required
  426. // *pdwEncrytedBufferLen is set to required length
  427. // CRYPT_FNC_INIT_NOT_CALLED InitCrypt not successfully called
  428. // CRYPT_FNC_INTERNAL_ERROR
  429. DWORD CCryptFunctions::DecryptDataWithKey(
  430. LPTSTR pszKey, // password
  431. PBYTE pbEncryptedData, // Encrypted data
  432. DWORD dwEncrytedDataLen, // Length of encrypted data
  433. PBYTE *ppbData, // Decrypted Data will be stored here
  434. DWORD *pdwDataBufferLength,// Length of the above buffer in bytes
  435. PFN_CMSECUREALLOC pfnAlloc,
  436. PFN_CMSECUREFREE pfnFree,
  437. DWORD dwEncKeySize // how many bits of encryption do we want? (0 implies "don't care")
  438. )
  439. {
  440. DWORD dwBufferLen;
  441. DWORD dwUUDecodeBufLen;
  442. HCRYPTKEY hKey = 0;
  443. DWORD dwError;
  444. DWORD dwMaxBufSize = 1024 * 10; // Just some max buffer size (10K) in order to exit the while loop
  445. //
  446. // Init should have been successfully called before
  447. // if no data to be decrypted, then don't do anything
  448. //
  449. if (m_hProv == 0 || !dwEncrytedDataLen)
  450. {
  451. dwError = CRYPT_FNC_INIT_NOT_CALLED;
  452. goto cleanup;
  453. }
  454. if (!GenerateSessionKeyFromPassword(&hKey, pszKey, dwEncKeySize))
  455. {
  456. dwError = CRYPT_FNC_INTERNAL_ERROR;
  457. goto cleanup;
  458. }
  459. // copy the data into another buffer to encrypt it
  460. dwBufferLen = dwEncrytedDataLen + DEFAULT_CRYPTO_EXTRA_BUFFER_SIZE;
  461. // *pdwDataBufferLength = dwEncrytedDataLen;
  462. //
  463. // Loop until we get to dwMaxBufSize. This is a safeguard to get out
  464. // of the infinite loop problem. DBCS passwords used to loop continuously.
  465. //
  466. while(dwBufferLen < dwMaxBufSize)
  467. {
  468. //
  469. // alloc memory for output buffer
  470. //
  471. if (pfnAlloc)
  472. {
  473. *ppbData = (PBYTE)pfnAlloc(dwBufferLen);
  474. }
  475. else
  476. {
  477. *ppbData = (PBYTE)HeapAlloc(GetProcessHeap(),
  478. HEAP_ZERO_MEMORY,
  479. dwBufferLen);
  480. }
  481. if (!*ppbData)
  482. {
  483. dwError = CRYPT_FNC_OUT_OF_MEMORY;
  484. goto cleanup;
  485. }
  486. //
  487. // set uudecode output buf size
  488. //
  489. dwUUDecodeBufLen = dwBufferLen;
  490. uudecode((char*)pbEncryptedData, (CHAR*)*ppbData, &dwUUDecodeBufLen);
  491. *pdwDataBufferLength = dwUUDecodeBufLen;
  492. // now decrypt the secret key using the key generated
  493. if ( ! m_fnCryptDecrypt(hKey,
  494. 0, // no hash required
  495. TRUE, // Final packet
  496. 0, // Flags - always 0
  497. *ppbData, // data buffer
  498. pdwDataBufferLength )) // length of data
  499. {
  500. DWORD dwCryptError = GetLastError();
  501. MYDBGTST(dwCryptError, ("Error 0x%x during CryptDecrypt", dwCryptError));
  502. if (pfnFree)
  503. {
  504. pfnFree(*ppbData);
  505. }
  506. else
  507. {
  508. HeapFree(GetProcessHeap(), 0, *ppbData);
  509. }
  510. *ppbData = NULL;
  511. //
  512. // if the output is too small, realloc it.
  513. //
  514. if (dwCryptError == NTE_BAD_LEN)
  515. {
  516. dwBufferLen *= 2; // to speed up memory alloc double the size
  517. continue;
  518. }
  519. // CryptDecrypt fails with error NTE_BAD_DATA if the password
  520. // is incorrect. Hence we should check for this error and prompt the
  521. // user again for the password. If the data is garbled in transit, then the secret key
  522. // will still be decrypted into a wrong value and the user will not
  523. // know about it.
  524. if (dwCryptError == NTE_BAD_DATA)
  525. {
  526. dwError = CRYPT_FNC_BAD_KEY;
  527. }
  528. else
  529. {
  530. dwError = CRYPT_FNC_INTERNAL_ERROR;
  531. }
  532. goto cleanup;
  533. }
  534. break;
  535. }
  536. if (dwBufferLen < dwMaxBufSize)
  537. {
  538. dwError = CRYPT_FNC_NO_ERROR;
  539. }
  540. else
  541. {
  542. CMTRACE1(TEXT("DecryptDataWithKey: not enough buffer = %d bytes"), dwBufferLen);
  543. MYDBGASSERT(FALSE);
  544. dwError = NTE_BAD_LEN;
  545. }
  546. cleanup:
  547. // destroy session key
  548. if (hKey != 0)
  549. {
  550. m_fnCryptDestroyKey(hKey);
  551. }
  552. return dwError;
  553. }