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.

2131 lines
57 KiB

  1. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. Microsoft Windows, Copyright (C) Microsoft Corporation, 2000
  3. File: EncryptedData.cpp
  4. Content: Implementation of CEncryptedData.
  5. History: 11-15-99 dsie created
  6. ------------------------------------------------------------------------------*/
  7. #include "StdAfx.h"
  8. #include "CAPICOM.h"
  9. #include "EncryptedData.h"
  10. #include "Common.h"
  11. #include "Convert.h"
  12. ///////////////////////////////////////////////////////////////////////////////
  13. //
  14. // Local functions.
  15. //
  16. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  17. Function : DeriveKey
  18. Synopsis : Derive a session key.
  19. Parameter: HCRYPTPROV hCryptProv - CSP handler.
  20. ALG_ID AlgID - Encryption algorithm ID.
  21. DWORD dwKeyLength - Key length.
  22. DATA_BLOB SecretBlob - Secret blob.
  23. DATA_BLOB SaltBlob - Salt blob.
  24. BOOL dwEffectiveKeyLength - Effective key length.
  25. HCRYPTKEY * phKey - Pointer to HCRYPTKEY to receive session key.
  26. Remark :
  27. ------------------------------------------------------------------------------*/
  28. static HRESULT DeriveKey (HCRYPTPROV hCryptProv,
  29. ALG_ID AlgID,
  30. DWORD dwKeyLength,
  31. DATA_BLOB SecretBlob,
  32. DATA_BLOB SaltBlob,
  33. DWORD dwEffectiveKeyLength,
  34. HCRYPTKEY * phKey)
  35. {
  36. HRESULT hr = S_OK;
  37. HCRYPTHASH hHash = NULL;
  38. HCRYPTKEY hKey = NULL;
  39. DWORD dwFlags = CRYPT_EXPORTABLE | CRYPT_NO_SALT;
  40. DebugTrace("Entering DeriveKey().\n");
  41. //
  42. // Sanity check.
  43. //
  44. ATLASSERT(hCryptProv);
  45. ATLASSERT(AlgID);
  46. ATLASSERT(SecretBlob.cbData);
  47. ATLASSERT(SecretBlob.pbData);
  48. ATLASSERT(SaltBlob.cbData);
  49. ATLASSERT(SaltBlob.pbData);
  50. ATLASSERT(phKey);
  51. //
  52. // Create a hash object.
  53. //
  54. if (!::CryptCreateHash(hCryptProv, CALG_SHA1, 0, 0, &hHash))
  55. {
  56. hr = HRESULT_FROM_WIN32(::GetLastError());
  57. DebugTrace("Error [%#x]: CryptCreateHash() failed.\n", hr);
  58. goto ErrorExit;
  59. }
  60. //
  61. // Hash in the password data.
  62. //
  63. if(!::CryptHashData(hHash,
  64. SecretBlob.pbData,
  65. SecretBlob.cbData,
  66. 0))
  67. {
  68. hr = HRESULT_FROM_WIN32(::GetLastError());
  69. DebugTrace("Error [%#x]: CryptHashData() failed.\n", hr);
  70. goto ErrorExit;
  71. }
  72. //
  73. // Hash in the salt.
  74. //
  75. if(!::CryptHashData(hHash,
  76. SaltBlob.pbData,
  77. SaltBlob.cbData,
  78. 0))
  79. {
  80. hr = HRESULT_FROM_WIN32(::GetLastError());
  81. DebugTrace("Error [%#x]: CryptHashData() failed.\n", hr);
  82. goto ErrorExit;
  83. }
  84. //
  85. // Dump salt value.
  86. //
  87. #ifdef _DEBUG
  88. {
  89. HRESULT hr2;
  90. CComBSTR bstrSaltValue;
  91. if (FAILED(hr2 = ::BinaryToHexString(SaltBlob.pbData, SaltBlob.cbData, &bstrSaltValue)))
  92. {
  93. DebugTrace("Info [%#x]: BinaryToHexString() failed.\n", hr2);
  94. }
  95. else
  96. {
  97. DebugTrace("Info: Session salt value = %ls.\n", bstrSaltValue);
  98. }
  99. }
  100. #endif
  101. //
  102. // Set key length.
  103. //
  104. if (CALG_RC2 == AlgID || CALG_RC4 == AlgID)
  105. {
  106. dwFlags |= dwKeyLength << 16;
  107. }
  108. //
  109. // Derive a session key from the hash object.
  110. //
  111. if (!::CryptDeriveKey(hCryptProv,
  112. AlgID,
  113. hHash,
  114. dwFlags,
  115. &hKey))
  116. {
  117. hr = HRESULT_FROM_WIN32(::GetLastError());
  118. DebugTrace("Error [%#x]: CryptDeriveKey() failed.\n", hr);
  119. goto ErrorExit;
  120. }
  121. //
  122. // Dump key value.
  123. //
  124. #ifdef _DEBUG
  125. {
  126. BYTE pbKeyValue[256] = {0};
  127. DWORD cbKeyValue = ARRAYSIZE(pbKeyValue);
  128. if (!::CryptExportKey(hKey, NULL, PLAINTEXTKEYBLOB, 0, pbKeyValue, &cbKeyValue))
  129. {
  130. DebugTrace("Info [%#x]: CryptExportKey() failed.\n", HRESULT_FROM_WIN32(::GetLastError()));
  131. }
  132. else
  133. {
  134. HRESULT hr3;
  135. CComBSTR bstrKeyValue;
  136. if (FAILED(hr3 = ::BinaryToHexString(pbKeyValue, cbKeyValue, &bstrKeyValue)))
  137. {
  138. DebugTrace("Info [%#x]: BinaryToHexString() failed.\n", hr3);
  139. }
  140. else
  141. {
  142. DebugTrace("Info: Session key value = %ls.\n", bstrKeyValue);
  143. }
  144. }
  145. }
  146. #endif
  147. //
  148. // Set effective key length for RC2.
  149. //
  150. if (CALG_RC2 == AlgID)
  151. {
  152. DebugTrace("Info: DeriveKey() is setting RC2 effective key length to %d.\n", dwEffectiveKeyLength);
  153. if (!::CryptSetKeyParam(hKey, KP_EFFECTIVE_KEYLEN, (PBYTE) &dwEffectiveKeyLength, 0))
  154. {
  155. hr = HRESULT_FROM_WIN32(::GetLastError());
  156. DebugTrace("Error [%#x]: CryptSetKeyParam() failed.\n", hr);
  157. goto ErrorExit;
  158. }
  159. }
  160. //
  161. // Return session key to caller.
  162. //
  163. *phKey = hKey;
  164. CommonExit:
  165. //
  166. // Free resource.
  167. //
  168. if (hHash)
  169. {
  170. ::CryptDestroyHash(hHash);
  171. }
  172. DebugTrace("Leaving DeriveKey().\n");
  173. return hr;
  174. ErrorExit:
  175. //
  176. // Sanity check.
  177. //
  178. ATLASSERT(FAILED(hr));
  179. //
  180. // Free resource.
  181. //
  182. if (hKey)
  183. {
  184. ::CryptDestroyKey(hKey);
  185. }
  186. goto CommonExit;
  187. }
  188. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  189. Function : EncodeEncryptedData
  190. Synopsis : ASN.1 encode the cipher blob.
  191. Parameter: HCRYPTKEY hKey - Session key used to encrypt the data.
  192. DATA_BLOB SaltBlob - Salt blob.
  193. DATA_BLOB CipherBlob - Cipher blob.
  194. DATA_BLOB * pEncodedBlob - Pointer to DATA_BLOB to receive the
  195. ASN.1 encoded blob.
  196. Remark : The format is proprietory, and should not be documented. It is
  197. right now encoded as a PKCS_CONTENT_INFO_SEQUENCE_OF_ANY with
  198. proprietory OID.
  199. ------------------------------------------------------------------------------*/
  200. static HRESULT EncodeEncryptedData (HCRYPTKEY hKey,
  201. DATA_BLOB SaltBlob,
  202. DATA_BLOB CipherBlob,
  203. DATA_BLOB * pEncodedBlob)
  204. {
  205. HRESULT hr = S_OK;
  206. DWORD dwCAPICOMVersion = CAPICOM_VERSION;
  207. DATA_BLOB KeyParamBlob[3] = {{0, NULL}, {0, NULL}, {0, NULL}};
  208. DWORD i;
  209. CAPICOM_ENCTYPTED_DATA_INFO EncryptedDataInfo;
  210. CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY EncryptedDataFormat;
  211. CRYPT_CONTENT_INFO ContentInfo;
  212. CRYPT_DER_BLOB ContentBlob = {0, NULL};
  213. DebugTrace("Entering EncodeEncryptedData().\n");
  214. //
  215. // Sanity check.
  216. //
  217. ATLASSERT(hKey);
  218. ATLASSERT(pEncodedBlob);
  219. //
  220. // Initialize.
  221. //
  222. ::ZeroMemory(pEncodedBlob, sizeof(DATA_BLOB));
  223. ::ZeroMemory(&ContentInfo, sizeof(ContentInfo));
  224. ::ZeroMemory(&EncryptedDataInfo, sizeof(EncryptedDataInfo));
  225. ::ZeroMemory(&EncryptedDataFormat, sizeof(EncryptedDataFormat));
  226. //
  227. // Encode the version number.
  228. //
  229. if (FAILED(hr = ::EncodeObject(X509_INTEGER,
  230. &dwCAPICOMVersion,
  231. &EncryptedDataInfo.VersionBlob)))
  232. {
  233. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  234. goto ErrorExit;
  235. }
  236. //
  237. // Encode ALG_ID.
  238. //
  239. if (FAILED(hr = ::GetKeyParam(hKey,
  240. KP_ALGID,
  241. &KeyParamBlob[0].pbData,
  242. &KeyParamBlob[0].cbData)))
  243. {
  244. DebugTrace("Error [%#x]: GetKeyParam() failed for KP_ALGID.\n", hr);
  245. goto ErrorExit;
  246. }
  247. if (FAILED(hr = ::EncodeObject(X509_INTEGER,
  248. KeyParamBlob[0].pbData,
  249. &EncryptedDataInfo.AlgIDBlob)))
  250. {
  251. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  252. goto ErrorExit;
  253. }
  254. //
  255. // Encode key length.
  256. //
  257. if (FAILED(hr = ::GetKeyParam(hKey,
  258. KP_KEYLEN,
  259. &KeyParamBlob[1].pbData,
  260. &KeyParamBlob[1].cbData)))
  261. {
  262. DebugTrace("Error [%#x]: GetKeyParam() failed for KP_KEYLEN.\n", hr);
  263. goto ErrorExit;
  264. }
  265. if (FAILED(hr = ::EncodeObject(X509_INTEGER,
  266. KeyParamBlob[1].pbData,
  267. &EncryptedDataInfo.KeyLengthBlob)))
  268. {
  269. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  270. goto ErrorExit;
  271. }
  272. //
  273. // Encode IV value.
  274. //
  275. if (FAILED(hr = ::GetKeyParam(hKey,
  276. KP_IV,
  277. &KeyParamBlob[2].pbData,
  278. &KeyParamBlob[2].cbData)))
  279. {
  280. DebugTrace("Error [%#x]: GetKeyParam() failed for KP_IV.\n", hr);
  281. goto ErrorExit;
  282. }
  283. if (FAILED(hr = ::EncodeObject(X509_OCTET_STRING,
  284. &KeyParamBlob[2],
  285. &EncryptedDataInfo.IVBlob)))
  286. {
  287. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  288. goto ErrorExit;
  289. }
  290. //
  291. // Encode salt value.
  292. //
  293. if (FAILED(hr = ::EncodeObject(X509_OCTET_STRING,
  294. &SaltBlob,
  295. &EncryptedDataInfo.SaltBlob)))
  296. {
  297. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  298. goto ErrorExit;
  299. }
  300. //
  301. // Encode the cipher text.
  302. //
  303. if (FAILED(hr = ::EncodeObject(X509_OCTET_STRING,
  304. &CipherBlob,
  305. &EncryptedDataInfo.CipherBlob)))
  306. {
  307. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  308. goto ErrorExit;
  309. }
  310. //
  311. // Encode the entire content as PKCS_CONTENT_INFO_SEQUENCE_OF_ANY.
  312. //
  313. EncryptedDataFormat.pszObjId = szOID_CAPICOM_ENCRYPTED_CONTENT;
  314. EncryptedDataFormat.cValue = 6;
  315. EncryptedDataFormat.rgValue = (DATA_BLOB *) &EncryptedDataInfo;
  316. if (FAILED(hr = ::EncodeObject(PKCS_CONTENT_INFO_SEQUENCE_OF_ANY,
  317. &EncryptedDataFormat,
  318. &ContentBlob)))
  319. {
  320. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  321. goto ErrorExit;
  322. }
  323. //
  324. // Finally, wrap the entire encrypted content in CONTENT_INFO.
  325. //
  326. ContentInfo.pszObjId = szOID_CAPICOM_ENCRYPTED_DATA;
  327. ContentInfo.Content = ContentBlob;
  328. if (FAILED(hr = ::EncodeObject(PKCS_CONTENT_INFO,
  329. &ContentInfo,
  330. pEncodedBlob)))
  331. {
  332. DebugTrace("Error [%#x]: EncodeObject() failed.\n", hr);
  333. goto ErrorExit;
  334. }
  335. CommonExit:
  336. //
  337. // Free resource.
  338. //
  339. for (i = 0; i < 3; i++)
  340. {
  341. if (KeyParamBlob[i].pbData)
  342. {
  343. ::CoTaskMemFree(KeyParamBlob[i].pbData);
  344. }
  345. }
  346. if (EncryptedDataInfo.VersionBlob.pbData)
  347. {
  348. ::CoTaskMemFree(EncryptedDataInfo.VersionBlob.pbData);
  349. }
  350. if (EncryptedDataInfo.AlgIDBlob.pbData)
  351. {
  352. ::CoTaskMemFree(EncryptedDataInfo.AlgIDBlob.pbData);
  353. }
  354. if (EncryptedDataInfo.KeyLengthBlob.pbData)
  355. {
  356. ::CoTaskMemFree(EncryptedDataInfo.KeyLengthBlob.pbData);
  357. }
  358. if (EncryptedDataInfo.IVBlob.pbData)
  359. {
  360. ::CoTaskMemFree(EncryptedDataInfo.IVBlob.pbData);
  361. }
  362. if (EncryptedDataInfo.SaltBlob.pbData)
  363. {
  364. ::CoTaskMemFree(EncryptedDataInfo.SaltBlob.pbData);
  365. }
  366. if (EncryptedDataInfo.CipherBlob.pbData)
  367. {
  368. ::CoTaskMemFree(EncryptedDataInfo.CipherBlob.pbData);
  369. }
  370. if (ContentBlob.pbData)
  371. {
  372. ::CoTaskMemFree(ContentBlob.pbData);
  373. }
  374. DebugTrace("Leaving EncodeEncryptedData().\n");
  375. return hr;
  376. ErrorExit:
  377. //
  378. // Sanity check.
  379. //
  380. ATLASSERT(FAILED(hr));
  381. goto CommonExit;
  382. }
  383. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  384. Function : DecodeEncryptedData
  385. Synopsis : ASN.1 decode the cipher text blob.
  386. Parameter: DATA_BLOB EncodedBlob - Encoded cipher blob.
  387. CAPICOM_ENCTYPTED_DATA_INFO * pEncryptedDataInfo - Pointer to
  388. structure to
  389. receive decoded
  390. structure.
  391. Remark :
  392. ------------------------------------------------------------------------------*/
  393. static HRESULT DecodeEncryptedData (DATA_BLOB EncodedBlob,
  394. CAPICOM_ENCTYPTED_DATA_INFO * pEncryptedDataInfo)
  395. {
  396. HRESULT hr = S_OK;
  397. DATA_BLOB ContentInfoBlob = {0, NULL};
  398. DATA_BLOB EncryptedBlob = {0, NULL};
  399. CRYPT_CONTENT_INFO ContentInfo;
  400. CAPICOM_ENCTYPTED_DATA_INFO EncryptedDataInfo;
  401. CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY * pEncryptedDataFormat = NULL;
  402. DebugTrace("Entering DecodeEncryptedData().\n");
  403. //
  404. // Sanity check.
  405. //
  406. ATLASSERT(pEncryptedDataInfo);
  407. //
  408. // Initialize.
  409. //
  410. ::ZeroMemory(&ContentInfo, sizeof(ContentInfo));
  411. ::ZeroMemory(&EncryptedDataInfo, sizeof(EncryptedDataInfo));
  412. //
  413. // Decode the CONTENT_INFO.
  414. //
  415. if (FAILED(hr = ::DecodeObject(PKCS_CONTENT_INFO,
  416. EncodedBlob.pbData,
  417. EncodedBlob.cbData,
  418. &ContentInfoBlob)))
  419. {
  420. DebugTrace("Error [%#x]: DecodeObject() failed.\n", hr);
  421. goto ErrorExit;
  422. }
  423. ContentInfo = * ((CRYPT_CONTENT_INFO *) ContentInfoBlob.pbData);
  424. //
  425. // Make sure this is our CONTENT_INFO.
  426. //
  427. if (0 != ::strcmp(szOID_CAPICOM_ENCRYPTED_DATA, ContentInfo.pszObjId))
  428. {
  429. hr = CAPICOM_E_ENCRYPT_INVALID_TYPE;
  430. DebugTrace("Error [%#x]: Not a CAPICOM encrypted data.\n", hr);
  431. goto ErrorExit;
  432. }
  433. //
  434. // Decode the content blob.
  435. //
  436. if (FAILED(hr = ::DecodeObject(PKCS_CONTENT_INFO_SEQUENCE_OF_ANY,
  437. ContentInfo.Content.pbData,
  438. ContentInfo.Content.cbData,
  439. &EncryptedBlob)))
  440. {
  441. DebugTrace("Error [%#x]: DecodeObject() failed.\n", hr);
  442. goto ErrorExit;
  443. }
  444. pEncryptedDataFormat = (CRYPT_CONTENT_INFO_SEQUENCE_OF_ANY *) EncryptedBlob.pbData;
  445. //
  446. // Make sure it is the right format.
  447. //
  448. if (0 != ::strcmp(szOID_CAPICOM_ENCRYPTED_CONTENT, pEncryptedDataFormat->pszObjId))
  449. {
  450. hr = CAPICOM_E_ENCRYPT_INVALID_TYPE;
  451. DebugTrace("Error [%#x]: Not a CAPICOM encrypted content.\n", hr);
  452. goto ErrorExit;
  453. }
  454. //
  455. // Sanity check.
  456. //
  457. ATLASSERT(6 == pEncryptedDataFormat->cValue);
  458. //
  459. // Decode version.
  460. //
  461. if (FAILED(hr = ::DecodeObject(X509_INTEGER,
  462. pEncryptedDataFormat->rgValue[0].pbData,
  463. pEncryptedDataFormat->rgValue[0].cbData,
  464. &EncryptedDataInfo.VersionBlob)))
  465. {
  466. DebugTrace("Error [%#x]: DecodeObject() failed.\n", hr);
  467. goto ErrorExit;
  468. }
  469. //
  470. // Decode ALG_ID.
  471. //
  472. if (FAILED(hr = ::DecodeObject(X509_INTEGER,
  473. pEncryptedDataFormat->rgValue[1].pbData,
  474. pEncryptedDataFormat->rgValue[1].cbData,
  475. &EncryptedDataInfo.AlgIDBlob)))
  476. {
  477. DebugTrace("Error [%#x]: DecodeObject() failed.\n", hr);
  478. goto ErrorExit;
  479. }
  480. //
  481. // Decode key length.
  482. //
  483. if (FAILED(hr = ::DecodeObject(X509_INTEGER,
  484. pEncryptedDataFormat->rgValue[2].pbData,
  485. pEncryptedDataFormat->rgValue[2].cbData,
  486. &EncryptedDataInfo.KeyLengthBlob)))
  487. {
  488. DebugTrace("Error [%#x]: DecodeObject() failed.\n", hr);
  489. goto ErrorExit;
  490. }
  491. //
  492. // Decode IV value.
  493. //
  494. if (FAILED(hr = ::DecodeObject(X509_OCTET_STRING,
  495. pEncryptedDataFormat->rgValue[3].pbData,
  496. pEncryptedDataFormat->rgValue[3].cbData,
  497. &EncryptedDataInfo.IVBlob)))
  498. {
  499. DebugTrace("Error [%#x]: DecodeObject() failed.\n", hr);
  500. goto ErrorExit;
  501. }
  502. //
  503. // Decode salt value.
  504. //
  505. if (FAILED(hr = ::DecodeObject(X509_OCTET_STRING,
  506. pEncryptedDataFormat->rgValue[4].pbData,
  507. pEncryptedDataFormat->rgValue[4].cbData,
  508. &EncryptedDataInfo.SaltBlob)))
  509. {
  510. DebugTrace("Error [%#x]: DecodeObject() failed.\n", hr);
  511. goto ErrorExit;
  512. }
  513. //
  514. // Decode cipher text.
  515. //
  516. if (FAILED(hr = ::DecodeObject(X509_OCTET_STRING,
  517. pEncryptedDataFormat->rgValue[5].pbData,
  518. pEncryptedDataFormat->rgValue[5].cbData,
  519. &EncryptedDataInfo.CipherBlob)))
  520. {
  521. DebugTrace("Error [%#x]: DecodeObject() failed.\n", hr);
  522. goto ErrorExit;
  523. }
  524. //
  525. // Return decoded encrypted data to caller.
  526. //
  527. *pEncryptedDataInfo = EncryptedDataInfo;
  528. CommonExit:
  529. //
  530. // Free resource.
  531. //
  532. if (EncryptedBlob.pbData)
  533. {
  534. ::CoTaskMemFree(EncryptedBlob.pbData);
  535. }
  536. if (ContentInfoBlob.pbData)
  537. {
  538. ::CoTaskMemFree(ContentInfoBlob.pbData);
  539. }
  540. DebugTrace("Leaving DecodeEncryptedData().\n");
  541. return hr;
  542. ErrorExit:
  543. //
  544. // Sanity check.
  545. //
  546. ATLASSERT(FAILED(hr));
  547. //
  548. // Free resource.
  549. //
  550. if (EncryptedDataInfo.VersionBlob.pbData)
  551. {
  552. ::CoTaskMemFree(EncryptedDataInfo.VersionBlob.pbData);
  553. }
  554. if (EncryptedDataInfo.AlgIDBlob.pbData)
  555. {
  556. ::CoTaskMemFree(EncryptedDataInfo.AlgIDBlob.pbData);
  557. }
  558. if (EncryptedDataInfo.KeyLengthBlob.pbData)
  559. {
  560. ::CoTaskMemFree(EncryptedDataInfo.KeyLengthBlob.pbData);
  561. }
  562. if (EncryptedDataInfo.IVBlob.pbData)
  563. {
  564. ::CoTaskMemFree(EncryptedDataInfo.IVBlob.pbData);
  565. }
  566. if (EncryptedDataInfo.SaltBlob.pbData)
  567. {
  568. ::CoTaskMemFree(EncryptedDataInfo.SaltBlob.pbData);
  569. }
  570. if (EncryptedDataInfo.CipherBlob.pbData)
  571. {
  572. ::CoTaskMemFree(EncryptedDataInfo.CipherBlob.pbData);
  573. }
  574. goto CommonExit;
  575. }
  576. ///////////////////////////////////////////////////////////////////////////////
  577. //
  578. // CEncryptedData
  579. //
  580. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  581. Function : CEncryptedData::get_Content
  582. Synopsis : Return the content.
  583. Parameter: BSTR * pVal - Pointer to BSTR to receive the content.
  584. Remark :
  585. ------------------------------------------------------------------------------*/
  586. STDMETHODIMP CEncryptedData::get_Content (BSTR * pVal)
  587. {
  588. HRESULT hr = S_OK;
  589. DebugTrace("Entering CEncryptedData::get_Content().\n");
  590. try
  591. {
  592. //
  593. // Lock access to this object.
  594. //
  595. m_Lock.Lock();
  596. //
  597. // Check parameters.
  598. //
  599. if (NULL == pVal)
  600. {
  601. hr = E_INVALIDARG;
  602. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  603. goto ErrorExit;
  604. }
  605. //
  606. // Make sure content is already initialized.
  607. //
  608. if (0 == m_ContentBlob.cbData)
  609. {
  610. hr = CAPICOM_E_ENCRYPT_NOT_INITIALIZED;
  611. DebugTrace("Error: encrypt object has not been initialized.\n");
  612. goto ErrorExit;
  613. }
  614. //
  615. // Sanity check.
  616. //
  617. ATLASSERT(m_ContentBlob.pbData);
  618. //
  619. // Return content.
  620. //
  621. if (FAILED(hr = ::BlobToBstr(&m_ContentBlob, pVal)))
  622. {
  623. DebugTrace("Error [%#x]: BlobToBstr() failed.\n", hr);
  624. goto ErrorExit;
  625. }
  626. }
  627. catch(...)
  628. {
  629. hr = E_POINTER;
  630. DebugTrace("Exception: invalid parameter.\n");
  631. goto ErrorExit;
  632. }
  633. UnlockExit:
  634. //
  635. // Unlock access to this object.
  636. //
  637. m_Lock.Unlock();
  638. DebugTrace("Leaving CEncryptedData::get_Content().\n");
  639. return hr;
  640. ErrorExit:
  641. //
  642. // Sanity check.
  643. //
  644. ATLASSERT(FAILED(hr));
  645. ReportError(hr);
  646. goto UnlockExit;
  647. }
  648. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  649. Function : CEncryptedData::put_Content
  650. Synopsis : Initialize the object with content to be encrypted.
  651. Parameter: BSTR newVal - BSTR containing the content to be encrypted.
  652. Remark :
  653. ------------------------------------------------------------------------------*/
  654. STDMETHODIMP CEncryptedData::put_Content (BSTR newVal)
  655. {
  656. HRESULT hr = S_OK;
  657. DATA_BLOB ContentBlob = {0, NULL};
  658. DebugTrace("Entering CEncryptedData::put_Content().\n");
  659. try
  660. {
  661. //
  662. // Lock access to this object.
  663. //
  664. m_Lock.Lock();
  665. //
  666. // Check parameters.
  667. //
  668. if (0 == ::SysStringByteLen(newVal))
  669. {
  670. hr = E_INVALIDARG;
  671. DebugTrace("Error [%#x]: Parameter newVal is NULL or empty.\n", hr);
  672. goto ErrorExit;
  673. }
  674. //
  675. // Covert BSTR to blob.
  676. //
  677. if (FAILED(hr = ::BstrToBlob(newVal, &ContentBlob)))
  678. {
  679. DebugTrace("Error [%#x]: BstrToBlob() failed.\n", hr);
  680. goto ErrorExit;
  681. }
  682. //
  683. // Update content.
  684. //
  685. if (m_ContentBlob.pbData)
  686. {
  687. ::CoTaskMemFree(m_ContentBlob.pbData);
  688. }
  689. m_ContentBlob = ContentBlob;
  690. }
  691. catch(...)
  692. {
  693. hr = E_POINTER;
  694. DebugTrace("Exception: invalid parameter.\n");
  695. goto ErrorExit;
  696. }
  697. UnlockExit:
  698. //
  699. // Unlock access to this object.
  700. //
  701. m_Lock.Unlock();
  702. DebugTrace("Leaving CEncryptedData::put_Content().\n");
  703. return hr;
  704. ErrorExit:
  705. //
  706. // Sanity check.
  707. //
  708. ATLASSERT(FAILED(hr));
  709. ReportError(hr);
  710. //
  711. // Free resources.
  712. //
  713. if (ContentBlob.pbData)
  714. {
  715. ::CoTaskMemFree((LPVOID) ContentBlob.pbData);
  716. }
  717. goto UnlockExit;
  718. }
  719. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  720. Function : CEncryptedData::get_Algorithm
  721. Synopsis : Property to return the algorithm object.
  722. Parameter: IAlgorithm ** pVal - Pointer to pointer to IAlgorithm to receive
  723. the interfcae pointer.
  724. Remark :
  725. ------------------------------------------------------------------------------*/
  726. STDMETHODIMP CEncryptedData::get_Algorithm (IAlgorithm ** pVal)
  727. {
  728. HRESULT hr = S_OK;
  729. DebugTrace("Entering CEncryptedData::get_Algorithm().\n");
  730. try
  731. {
  732. //
  733. // Lock access to this object.
  734. //
  735. m_Lock.Lock();
  736. //
  737. // Check parameters.
  738. //
  739. if (NULL == pVal)
  740. {
  741. hr = E_INVALIDARG;
  742. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  743. goto ErrorExit;
  744. }
  745. //
  746. // Sanity check.
  747. //
  748. ATLASSERT(m_pIAlgorithm);
  749. //
  750. // Return interface pointer to caller.
  751. //
  752. if (FAILED(hr = m_pIAlgorithm->QueryInterface(pVal)))
  753. {
  754. DebugTrace("Unexpected error [%#x]: m_pIAlgorithm->QueryInterface() failed.\n", hr);
  755. goto ErrorExit;
  756. }
  757. }
  758. catch(...)
  759. {
  760. hr = E_POINTER;
  761. DebugTrace("Exception: invalid parameter.\n");
  762. goto ErrorExit;
  763. }
  764. UnlockExit:
  765. //
  766. // Unlock access to this object.
  767. //
  768. m_Lock.Unlock();
  769. DebugTrace("Leaving CEncryptedData::get_Algorithm().\n");
  770. return hr;
  771. ErrorExit:
  772. //
  773. // Sanity check.
  774. //
  775. ATLASSERT(FAILED(hr));
  776. ReportError(hr);
  777. goto UnlockExit;
  778. }
  779. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  780. Function : CEncryptedData::SetSecret
  781. Synopsis : Set the encryption secret used to generated the session key.
  782. Parameter: BSTR newVal - The secret.
  783. CAPICOM_SECRET_TYPE SecretType - Secret type, which can be:
  784. SECRET_PASSWORD = 0
  785. Remark : For v1.0, we only support password secret. But, we really need
  786. to consider plain text session key (See Q228786), as this is one
  787. of the frequently asked question on the public list server.
  788. ------------------------------------------------------------------------------*/
  789. STDMETHODIMP CEncryptedData::SetSecret (BSTR newVal,
  790. CAPICOM_SECRET_TYPE SecretType)
  791. {
  792. HRESULT hr = S_OK;
  793. DebugTrace("Entering CEncryptedData::SetSecret().\n");
  794. try
  795. {
  796. //
  797. // Lock access to this object.
  798. //
  799. m_Lock.Lock();
  800. //
  801. // Check parameters.
  802. //
  803. if (0 == ::SysStringLen(newVal) || 256 < ::SysStringLen(newVal))
  804. {
  805. hr = E_INVALIDARG;
  806. DebugTrace("Error [%#x]: Parameter newVal is either empty or greater than 256 characters.\n", hr);
  807. goto ErrorExit;
  808. }
  809. //
  810. // Determine secret type.
  811. //
  812. switch (SecretType)
  813. {
  814. case CAPICOM_SECRET_PASSWORD:
  815. {
  816. m_SecretType = SecretType;
  817. break;
  818. }
  819. default:
  820. {
  821. hr = E_INVALIDARG;
  822. DebugTrace("Error [%#x]: Unknown secret type (%#x).\n", hr, SecretType);
  823. goto ErrorExit;
  824. }
  825. }
  826. //
  827. // Initialize secret.
  828. //
  829. if (NULL == newVal)
  830. {
  831. m_bstrSecret.Empty();
  832. }
  833. else if (!(m_bstrSecret = newVal))
  834. {
  835. hr = E_OUTOFMEMORY;
  836. DebugTrace("Error [%#x]: m_bstrSecret = newVal failed.\n", hr);
  837. goto ErrorExit;
  838. }
  839. }
  840. catch(...)
  841. {
  842. hr = E_POINTER;
  843. DebugTrace("Exception: invalid parameter.\n");
  844. goto ErrorExit;
  845. }
  846. UnlockExit:
  847. //
  848. // Unlock access to this object.
  849. //
  850. m_Lock.Unlock();
  851. DebugTrace("Leaving CEncryptedData::SetSecret().\n");
  852. return hr;
  853. ErrorExit:
  854. //
  855. // Sanity check.
  856. //
  857. ATLASSERT(FAILED(hr));
  858. ReportError(hr);
  859. goto UnlockExit;
  860. }
  861. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  862. Function : CEncryptedData::Encrypt
  863. Synopsis : Encrypt the content.
  864. Parameter: CAPICOM_ENCODING_TYPE EncodingType - Encoding type.
  865. BSTR * pVal - Pointer to BSTR to receive the encrypted message.
  866. Remark : Note that since CAPI still does not support PKCS 7 EncryptedData
  867. type, therefore, the format of the encrypted data used here is
  868. propriety, and should not be documented.
  869. ------------------------------------------------------------------------------*/
  870. STDMETHODIMP CEncryptedData::Encrypt (CAPICOM_ENCODING_TYPE EncodingType,
  871. BSTR * pVal)
  872. {
  873. HRESULT hr = S_OK;
  874. HCRYPTPROV hCryptProv = NULL;
  875. HCRYPTKEY hSessionKey = NULL;
  876. DWORD dwBufLength = 0;
  877. DATA_BLOB SaltBlob = {0, NULL};
  878. DATA_BLOB CipherBlob = {0, NULL};
  879. DATA_BLOB MessageBlob = {0, NULL};
  880. DebugTrace("Entering CEncryptedData::Encrypt().\n");
  881. try
  882. {
  883. //
  884. // Lock access to this object.
  885. //
  886. m_Lock.Lock();
  887. //
  888. // Check parameters.
  889. //
  890. if (NULL == pVal)
  891. {
  892. hr = E_INVALIDARG;
  893. DebugTrace("Error [%#x]: Parameter pVal is NULL.\n", hr);
  894. goto ErrorExit;
  895. }
  896. //
  897. // Make sure we do have content to encrypt.
  898. //
  899. if (0 == m_ContentBlob.cbData)
  900. {
  901. hr = CAPICOM_E_ENCRYPT_NOT_INITIALIZED;
  902. DebugTrace("Error [%#x]: encrypt object has not been initialized.\n", hr);
  903. goto ErrorExit;
  904. }
  905. if (0 == m_bstrSecret.Length())
  906. {
  907. hr = CAPICOM_E_ENCRYPT_NO_SECRET;
  908. DebugTrace("Error [%#x]: secret is emtpty or not been set.\n", hr);
  909. goto ErrorExit;
  910. }
  911. //
  912. // Open a new message to encode.
  913. //
  914. if (FAILED(hr = OpenToEncode(&SaltBlob, &hCryptProv, &hSessionKey)))
  915. {
  916. DebugTrace("Error [%#x]: CEncryptedData::OpenToEncode() failed.\n", hr);
  917. goto ErrorExit;
  918. }
  919. //
  920. // Determine buffer length.
  921. //
  922. dwBufLength = m_ContentBlob.cbData;
  923. if (!::CryptEncrypt(hSessionKey,
  924. NULL,
  925. TRUE,
  926. 0,
  927. NULL,
  928. &dwBufLength,
  929. 0))
  930. {
  931. hr = HRESULT_FROM_WIN32(::GetLastError());
  932. DebugTrace("Error [%#x]: CryptEncrypt() failed.\n", hr);
  933. goto ErrorExit;
  934. }
  935. //
  936. // Sanity check.
  937. //
  938. ATLASSERT(m_ContentBlob.cbData <= dwBufLength);
  939. //
  940. // Copy clear text to another buffer.
  941. //
  942. if (!(CipherBlob.pbData = (PBYTE) ::CoTaskMemAlloc(dwBufLength)))
  943. {
  944. hr = E_OUTOFMEMORY;
  945. DebugTrace("Error: out of memory.\n");
  946. goto ErrorExit;
  947. }
  948. CipherBlob.cbData = dwBufLength;
  949. ::CopyMemory(CipherBlob.pbData,
  950. m_ContentBlob.pbData,
  951. m_ContentBlob.cbData);
  952. //
  953. // Encrypt.
  954. //
  955. dwBufLength = m_ContentBlob.cbData;
  956. if (!::CryptEncrypt(hSessionKey,
  957. NULL,
  958. TRUE,
  959. 0,
  960. CipherBlob.pbData,
  961. &dwBufLength,
  962. CipherBlob.cbData))
  963. {
  964. hr = HRESULT_FROM_WIN32(::GetLastError());
  965. DebugTrace("Error [%#x]: CryptEncrypt() failed.\n", hr);
  966. goto ErrorExit;
  967. }
  968. //
  969. // Encode the cipher text.
  970. //
  971. if (FAILED(hr = ::EncodeEncryptedData(hSessionKey,
  972. SaltBlob,
  973. CipherBlob,
  974. &MessageBlob)))
  975. {
  976. DebugTrace("Error [%#x]: Encode() failed.\n", hr);
  977. goto ErrorExit;
  978. }
  979. //
  980. // Now export the encoded message.
  981. //
  982. if (FAILED(hr = ::ExportData(MessageBlob, EncodingType, pVal)))
  983. {
  984. DebugTrace("Error [%#x]: ExportData() failed.\n", hr);
  985. goto ErrorExit;
  986. }
  987. //
  988. // Write encoded blob to file, so we can use offline tool such as
  989. // ASN parser to analyze message.
  990. //
  991. // The following line will resolve to void for non debug build, and
  992. // thus can be safely removed if desired.
  993. //
  994. DumpToFile("Encrypted.asn", MessageBlob.pbData, MessageBlob.cbData);
  995. }
  996. catch(...)
  997. {
  998. hr = E_POINTER;
  999. DebugTrace("Exception: invalid parameter.\n");
  1000. goto ErrorExit;
  1001. }
  1002. UnlockExit:
  1003. //
  1004. // Free resource.
  1005. //
  1006. if (MessageBlob.pbData)
  1007. {
  1008. ::CoTaskMemFree(MessageBlob.pbData);
  1009. }
  1010. if (CipherBlob.pbData)
  1011. {
  1012. ::CoTaskMemFree(CipherBlob.pbData);
  1013. }
  1014. if (hSessionKey)
  1015. {
  1016. ::CryptDestroyKey(hSessionKey);
  1017. }
  1018. if (hCryptProv)
  1019. {
  1020. ::ReleaseContext(hCryptProv);
  1021. }
  1022. //
  1023. // Unlock access to this object.
  1024. //
  1025. m_Lock.Unlock();
  1026. DebugTrace("Leaving CEncryptedData::Encrypt().\n");
  1027. return hr;
  1028. ErrorExit:
  1029. //
  1030. // Sanity check.
  1031. //
  1032. ATLASSERT(FAILED(hr));
  1033. ReportError(hr);
  1034. goto UnlockExit;
  1035. }
  1036. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1037. Function : CEncryptedData::Decrypt
  1038. Synopsis : Decrypt the encrypted content.
  1039. Parameter: BSTR EncryptedMessage - BSTR containing the encrypted message.
  1040. Remark :
  1041. ------------------------------------------------------------------------------*/
  1042. STDMETHODIMP CEncryptedData::Decrypt (BSTR EncryptedMessage)
  1043. {
  1044. HRESULT hr = S_OK;
  1045. HCRYPTPROV hCryptProv = NULL;
  1046. HCRYPTKEY hSessionKey = NULL;
  1047. DATA_BLOB ContentBlob = {0, NULL};
  1048. DWORD dwVersion = 0;
  1049. ALG_ID AlgId = 0;
  1050. DWORD dwKeyLength = 0;
  1051. CAPICOM_ENCTYPTED_DATA_INFO EncryptedDataInfo = {0};
  1052. CAPICOM_ENCRYPTION_ALGORITHM AlgoName;
  1053. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength;
  1054. DebugTrace("Entering CEncryptedData::Decrypt().\n");
  1055. try
  1056. {
  1057. //
  1058. // Lock access to this object.
  1059. //
  1060. m_Lock.Lock();
  1061. //
  1062. // Check parameters.
  1063. //
  1064. if (0 == ::SysStringByteLen(EncryptedMessage))
  1065. {
  1066. hr = E_INVALIDARG;
  1067. DebugTrace("Error [%#x]: Parameter EncryptedMessage is NULL or empty.\n", hr);
  1068. goto ErrorExit;
  1069. }
  1070. //
  1071. // Make sure secret is set.
  1072. //
  1073. if (0 == m_bstrSecret.Length())
  1074. {
  1075. hr = CAPICOM_E_ENCRYPT_NO_SECRET;
  1076. DebugTrace("Error [%#x]: secret is empty or not been set.\n", hr);
  1077. goto ErrorExit;
  1078. }
  1079. //
  1080. // Open a new message to decode.
  1081. //
  1082. if (FAILED(hr = OpenToDecode(EncryptedMessage,
  1083. &hCryptProv,
  1084. &hSessionKey,
  1085. &EncryptedDataInfo)))
  1086. {
  1087. DebugTrace("Error [%#x]: CEncryptedData::OpenToDecode() failed.\n", hr);
  1088. goto ErrorExit;
  1089. }
  1090. //
  1091. // Get version, AlgId and key length.
  1092. //
  1093. dwVersion = *((DWORD *) EncryptedDataInfo.VersionBlob.pbData);
  1094. AlgId = *((ALG_ID *) EncryptedDataInfo.AlgIDBlob.pbData);
  1095. dwKeyLength = *((DWORD *) EncryptedDataInfo.KeyLengthBlob.pbData);
  1096. DebugTrace("Info: CAPICOM EncryptedData version = %#x.\n", dwVersion);
  1097. DebugTrace("Info: AlgId = %#x.\n", AlgId);
  1098. DebugTrace("Info: dwKeyLength = %#x.\n", dwKeyLength);
  1099. //
  1100. // Copy cipher blob.
  1101. //
  1102. ContentBlob.cbData = ((DATA_BLOB *) EncryptedDataInfo.CipherBlob.pbData)->cbData;
  1103. if (!(ContentBlob.pbData = (LPBYTE) ::CoTaskMemAlloc(ContentBlob.cbData)))
  1104. {
  1105. hr = E_OUTOFMEMORY;
  1106. DebugTrace("Error [%#x]: CoTaskMemAlloc(ContentBlob.cbData) failed.\n", hr);
  1107. goto ErrorExit;
  1108. }
  1109. ::CopyMemory(ContentBlob.pbData,
  1110. ((DATA_BLOB *) EncryptedDataInfo.CipherBlob.pbData)->pbData,
  1111. ContentBlob.cbData);
  1112. //
  1113. // Decrypt.
  1114. //
  1115. if (!::CryptDecrypt(hSessionKey,
  1116. NULL,
  1117. TRUE,
  1118. 0,
  1119. ContentBlob.pbData,
  1120. &ContentBlob.cbData))
  1121. {
  1122. //
  1123. // Try again for v1.0 EncryptedData with 40 bits RC2.
  1124. //
  1125. if (NTE_BAD_DATA == (hr = HRESULT_FROM_WIN32(::GetLastError())))
  1126. {
  1127. DATA_BLOB SecretBlob = {m_bstrSecret.Length() * sizeof(WCHAR),
  1128. (BYTE *) m_bstrSecret.m_str};
  1129. DATA_BLOB SaltBlob = *((DATA_BLOB *) EncryptedDataInfo.SaltBlob.pbData);
  1130. DATA_BLOB IVBlob = *((DATA_BLOB *) EncryptedDataInfo.IVBlob.pbData);;
  1131. //
  1132. // For RC2, if encrypted with v1.0, then force 40-bits per bug 572627.
  1133. //
  1134. if (0x00010000 != dwVersion || CALG_RC2 != AlgId)
  1135. {
  1136. hr = HRESULT_FROM_WIN32(::GetLastError());
  1137. DebugTrace("Error [%#x]: CryptDecrypt() failed.\n", hr);
  1138. goto ErrorExit;
  1139. }
  1140. //
  1141. // This is most likely the case data was encrypted with
  1142. // CAPICOM v1.0 on .Net Server or later. So, try again with
  1143. // effective key length set to the same as key length.
  1144. //
  1145. DebugTrace("Info: Data most likely encrypted by CAPICOM v.10 RC2 on .Net Server or later, so forcing effective key length.\n");
  1146. //
  1147. // Derive the key again.
  1148. //
  1149. ::CryptDestroyKey(hSessionKey), hSessionKey = NULL;
  1150. if (FAILED(hr = ::DeriveKey(hCryptProv,
  1151. AlgId,
  1152. dwKeyLength,
  1153. SecretBlob,
  1154. SaltBlob,
  1155. dwKeyLength,
  1156. &hSessionKey)))
  1157. {
  1158. DebugTrace("Error [%#x]: DeriveKey() failed.\n", hr);
  1159. goto ErrorExit;
  1160. }
  1161. //
  1162. // Set IV.
  1163. //
  1164. if(IVBlob.cbData && !::CryptSetKeyParam(hSessionKey, KP_IV, IVBlob.pbData, 0))
  1165. {
  1166. hr = HRESULT_FROM_WIN32(::GetLastError());
  1167. DebugTrace("Error [%#x]: CryptSetKeyParam() failed for KP_IV.\n", hr);
  1168. goto ErrorExit;
  1169. }
  1170. //
  1171. // Copy cipher blob again, since previous copy is destroyed by
  1172. // CryptDecrypt because of in-place decryption.
  1173. //
  1174. ContentBlob.cbData = ((DATA_BLOB *) EncryptedDataInfo.CipherBlob.pbData)->cbData;
  1175. ::CopyMemory(ContentBlob.pbData,
  1176. ((DATA_BLOB *) EncryptedDataInfo.CipherBlob.pbData)->pbData,
  1177. ContentBlob.cbData);
  1178. //
  1179. // If this still fails, then there is nothing we can do further.
  1180. //
  1181. if (!::CryptDecrypt(hSessionKey,
  1182. NULL,
  1183. TRUE,
  1184. 0,
  1185. ContentBlob.pbData,
  1186. &ContentBlob.cbData))
  1187. {
  1188. hr = HRESULT_FROM_WIN32(::GetLastError());
  1189. DebugTrace("Error [%#x]: CryptDecrypt() failed.\n", hr);
  1190. goto ErrorExit;
  1191. }
  1192. }
  1193. }
  1194. //
  1195. // Convert ALG_ID to CAPICOM_ENCRYPTION_ALGORITHM.
  1196. //
  1197. if (FAILED(::AlgIDToEnumName(AlgId, &AlgoName)))
  1198. {
  1199. //
  1200. // Default to RC2.
  1201. //
  1202. AlgoName = CAPICOM_ENCRYPTION_ALGORITHM_RC2;
  1203. }
  1204. //
  1205. // Convert key length value to CAPICOM_ENCRYPTION_KEY_LENGTH.
  1206. //
  1207. if (FAILED(::KeyLengthToEnumName(dwKeyLength, AlgId, &KeyLength)))
  1208. {
  1209. //
  1210. // Default to maximum.
  1211. //
  1212. KeyLength = CAPICOM_ENCRYPTION_KEY_LENGTH_MAXIMUM;
  1213. }
  1214. //
  1215. // Reset member variables.
  1216. //
  1217. if (m_ContentBlob.pbData)
  1218. {
  1219. ::CoTaskMemFree((LPVOID) m_ContentBlob.pbData);
  1220. }
  1221. //
  1222. // Update member variables.
  1223. //
  1224. m_ContentBlob = ContentBlob;
  1225. m_pIAlgorithm->put_Name(AlgoName);
  1226. m_pIAlgorithm->put_KeyLength(KeyLength);
  1227. }
  1228. catch(...)
  1229. {
  1230. hr = E_POINTER;
  1231. DebugTrace("Exception: invalid parameter.\n");
  1232. goto ErrorExit;
  1233. }
  1234. UnlockExit:
  1235. //
  1236. // Free resource.
  1237. //
  1238. if (hSessionKey)
  1239. {
  1240. ::CryptDestroyKey(hSessionKey);
  1241. }
  1242. if (hCryptProv)
  1243. {
  1244. ::ReleaseContext(hCryptProv);
  1245. }
  1246. if (EncryptedDataInfo.VersionBlob.pbData)
  1247. {
  1248. ::CoTaskMemFree(EncryptedDataInfo.VersionBlob.pbData);
  1249. }
  1250. if (EncryptedDataInfo.AlgIDBlob.pbData)
  1251. {
  1252. ::CoTaskMemFree(EncryptedDataInfo.AlgIDBlob.pbData);
  1253. }
  1254. if (EncryptedDataInfo.KeyLengthBlob.pbData)
  1255. {
  1256. ::CoTaskMemFree(EncryptedDataInfo.KeyLengthBlob.pbData);
  1257. }
  1258. if (EncryptedDataInfo.SaltBlob.pbData)
  1259. {
  1260. ::CoTaskMemFree(EncryptedDataInfo.SaltBlob.pbData);
  1261. }
  1262. if (EncryptedDataInfo.IVBlob.pbData)
  1263. {
  1264. ::CoTaskMemFree(EncryptedDataInfo.IVBlob.pbData);
  1265. }
  1266. if (EncryptedDataInfo.CipherBlob.pbData)
  1267. {
  1268. ::CoTaskMemFree(EncryptedDataInfo.CipherBlob.pbData);
  1269. }
  1270. //
  1271. // Unlock access to this object.
  1272. //
  1273. m_Lock.Unlock();
  1274. DebugTrace("Leaving CEncryptedData::Decrypt().\n");
  1275. return hr;
  1276. ErrorExit:
  1277. //
  1278. // Sanity check.
  1279. //
  1280. ATLASSERT(FAILED(hr));
  1281. //
  1282. // Free resources.
  1283. //
  1284. if (ContentBlob.pbData)
  1285. {
  1286. ::CoTaskMemFree((LPVOID) ContentBlob.pbData);
  1287. }
  1288. ReportError(hr);
  1289. goto UnlockExit;
  1290. }
  1291. ////////////////////////////////////////////////////////////////////////////////
  1292. //
  1293. // Private member functions.
  1294. //
  1295. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1296. Function : CEncryptedData::OpenToEncode
  1297. Synopsis : Create and initialize an encrypt message for encoding.
  1298. Parameter: DATA_BLOB * pSaltBlob - Pointer to DATA_BLOB to receive the
  1299. salt value blob.
  1300. HCRYPTPROV * phCryptProv - Pointer to HCRYPTPROV to receive CSP
  1301. handler.
  1302. HCRYPTKEY * phKey - Pointer to HCRYPTKEY to receive session key.
  1303. Remark :
  1304. ------------------------------------------------------------------------------*/
  1305. STDMETHODIMP CEncryptedData::OpenToEncode(DATA_BLOB * pSaltBlob,
  1306. HCRYPTPROV * phCryptProv,
  1307. HCRYPTKEY * phKey)
  1308. {
  1309. HRESULT hr = S_OK;
  1310. HCRYPTPROV hCryptProv = NULL;
  1311. HCRYPTKEY hKey = NULL;
  1312. DATA_BLOB SaltBlob = {16, NULL};
  1313. CAPICOM_ENCRYPTION_ALGORITHM AlgoName;
  1314. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength;
  1315. DebugTrace("Entering CEncryptedData::OpenToEncode().\n");
  1316. //
  1317. // Sanity check.
  1318. //
  1319. ATLASSERT(pSaltBlob);
  1320. ATLASSERT(phCryptProv);
  1321. ATLASSERT(phKey);
  1322. ATLASSERT(m_ContentBlob.cbData && m_ContentBlob.pbData);
  1323. ATLASSERT(m_bstrSecret);
  1324. ATLASSERT(m_bstrSecret.Length());
  1325. //
  1326. // Get algorithm enum name.
  1327. //
  1328. if (FAILED(hr = m_pIAlgorithm->get_Name(&AlgoName)))
  1329. {
  1330. DebugTrace("Error [%#x]: m_pIAlgorithm->get_Name() failed.\n", hr);
  1331. goto ErrorExit;
  1332. }
  1333. //
  1334. // Get key length enum name.
  1335. //
  1336. if (FAILED(hr = m_pIAlgorithm->get_KeyLength(&KeyLength)))
  1337. {
  1338. DebugTrace("Error [%#x]: m_pIAlgorithm->get_KeyLength() failed.\n", hr);
  1339. goto ErrorExit;
  1340. }
  1341. //
  1342. // Get CSP context.
  1343. //
  1344. if (FAILED(hr = ::AcquireContext(AlgoName,
  1345. KeyLength,
  1346. &hCryptProv)))
  1347. {
  1348. DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr);
  1349. goto ErrorExit;
  1350. }
  1351. //
  1352. // Generate random salt.
  1353. //
  1354. if (!(SaltBlob.pbData = (BYTE *) ::CoTaskMemAlloc(SaltBlob.cbData)))
  1355. {
  1356. hr = E_OUTOFMEMORY;
  1357. DebugTrace("Error: out of memory.\n");
  1358. goto ErrorExit;
  1359. }
  1360. if (!::CryptGenRandom(hCryptProv, SaltBlob.cbData, SaltBlob.pbData))
  1361. {
  1362. hr = HRESULT_FROM_WIN32(::GetLastError());
  1363. DebugTrace("Error [%#x]: CryptGenRandom() failed.\n", hr);
  1364. goto ErrorExit;
  1365. }
  1366. //
  1367. // Generate the session key.
  1368. //
  1369. if (FAILED(hr = GenerateKey(hCryptProv,
  1370. AlgoName,
  1371. KeyLength,
  1372. SaltBlob,
  1373. &hKey)))
  1374. {
  1375. DebugTrace("Error [%#x]: GenerateKey() failed.\n", hr);
  1376. goto ErrorExit;
  1377. }
  1378. //
  1379. // Set CMSG_ENCRYPTED_ENCODE_INFO.
  1380. //
  1381. *pSaltBlob = SaltBlob;
  1382. *phCryptProv = hCryptProv;
  1383. *phKey = hKey;
  1384. CommonExit:
  1385. DebugTrace("Leaving CEncryptedData::OpenToEncode().\n");
  1386. return hr;
  1387. ErrorExit:
  1388. //
  1389. // Sanity check.
  1390. //
  1391. ATLASSERT(FAILED(hr));
  1392. //
  1393. // Free resource.
  1394. //
  1395. if (hKey)
  1396. {
  1397. ::CryptDestroyKey(hKey);
  1398. }
  1399. if (hCryptProv)
  1400. {
  1401. ::ReleaseContext(hCryptProv);
  1402. }
  1403. if (SaltBlob.pbData)
  1404. {
  1405. ::CoTaskMemFree(SaltBlob.pbData);
  1406. }
  1407. goto CommonExit;
  1408. }
  1409. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1410. Function : CEncryptedData::OpenToDecode
  1411. Synopsis : Open an encrypt message for decoding.
  1412. Parameter: BSTR EncryptedMessage - BSTR containing the encrypted message.
  1413. HCRYPTPROV * phCryptProv - Pointer to HCRYPTPROV to receive CSP
  1414. handler.
  1415. HCRYPTKEY * phKey - Pointer to HCRYPTKEY to receive session key.
  1416. CAPICOM_ENCTYPTED_DATA_INFO * pEncryptedDataInfo;
  1417. Remark :
  1418. ------------------------------------------------------------------------------*/
  1419. STDMETHODIMP CEncryptedData::OpenToDecode (
  1420. BSTR EncryptedMessage,
  1421. HCRYPTPROV * phCryptProv,
  1422. HCRYPTKEY * phKey,
  1423. CAPICOM_ENCTYPTED_DATA_INFO * pEncryptedDataInfo)
  1424. {
  1425. HRESULT hr = S_OK;
  1426. HCRYPTPROV hCryptProv = NULL;
  1427. HCRYPTKEY hKey = NULL;
  1428. DWORD dwVersion = 0;
  1429. ALG_ID AlgID = 0;
  1430. DWORD dwKeyLength = 0;
  1431. DATA_BLOB MessageBlob = {0, NULL};
  1432. DATA_BLOB SecretBlob = {m_bstrSecret.Length() * sizeof(WCHAR),
  1433. (BYTE *) m_bstrSecret.m_str};
  1434. DATA_BLOB SaltBlob;
  1435. DATA_BLOB IVBlob;
  1436. CAPICOM_ENCTYPTED_DATA_INFO EncryptedDataInfo = {0};
  1437. DebugTrace("Entering CEncryptedData::OpenToDecode().\n");
  1438. //
  1439. // Sanity check.
  1440. //
  1441. ATLASSERT(EncryptedMessage);
  1442. ATLASSERT(phCryptProv);
  1443. ATLASSERT(phKey);
  1444. ATLASSERT(pEncryptedDataInfo);
  1445. ATLASSERT(m_bstrSecret);
  1446. ATLASSERT(m_bstrSecret.Length());
  1447. try
  1448. {
  1449. //
  1450. // Import the message.
  1451. //
  1452. if (FAILED(hr = ::ImportData(EncryptedMessage, CAPICOM_ENCODE_ANY, &MessageBlob)))
  1453. {
  1454. DebugTrace("Error [%#x]: ImportData() failed.\n", hr);
  1455. goto ErrorExit;
  1456. }
  1457. //
  1458. // Decode the blob.
  1459. //
  1460. if (FAILED(hr = ::DecodeEncryptedData(MessageBlob,
  1461. &EncryptedDataInfo)))
  1462. {
  1463. DebugTrace("Error [%#x]: DecodeEncryptedData() failed.\n", hr);
  1464. goto ErrorExit;
  1465. }
  1466. //
  1467. // Retrieve values.
  1468. //
  1469. dwVersion = *((DWORD *) EncryptedDataInfo.VersionBlob.pbData);
  1470. AlgID = *((ALG_ID *) EncryptedDataInfo.AlgIDBlob.pbData);
  1471. dwKeyLength = *((DWORD *) EncryptedDataInfo.KeyLengthBlob.pbData);
  1472. SaltBlob = *((DATA_BLOB *) EncryptedDataInfo.SaltBlob.pbData);
  1473. IVBlob = *((DATA_BLOB *) EncryptedDataInfo.IVBlob.pbData);
  1474. //
  1475. // Get CSP context.
  1476. //
  1477. if (FAILED(hr = ::AcquireContext(AlgID,
  1478. dwKeyLength,
  1479. &hCryptProv)))
  1480. {
  1481. DebugTrace("Error [%#x]: AcquireContext() failed.\n", hr);
  1482. goto ErrorExit;
  1483. }
  1484. //
  1485. // Derive the key. For RC2, if encrypted with v1.0, then force
  1486. // 40-bits per bug 572627.
  1487. //
  1488. if (FAILED(hr = ::DeriveKey(hCryptProv,
  1489. AlgID,
  1490. dwKeyLength,
  1491. SecretBlob,
  1492. SaltBlob,
  1493. dwVersion == 0x00010000 ? 40 : dwKeyLength,
  1494. &hKey)))
  1495. {
  1496. DebugTrace("Error [%#x]: DeriveKey() failed.\n", hr);
  1497. goto ErrorExit;
  1498. }
  1499. //
  1500. // Set IV, if required.
  1501. //
  1502. if ((CALG_RC2 == AlgID) || (CALG_DES == AlgID) || (CALG_3DES == AlgID))
  1503. {
  1504. //
  1505. // Set IV.
  1506. //
  1507. if(IVBlob.cbData && !::CryptSetKeyParam(hKey, KP_IV, IVBlob.pbData, 0))
  1508. {
  1509. hr = HRESULT_FROM_WIN32(::GetLastError());
  1510. DebugTrace("Error [%#x]: CryptSetKeyParam() failed for KP_IV.\n", hr);
  1511. goto ErrorExit;
  1512. }
  1513. //
  1514. // Dump IV value.
  1515. //
  1516. #ifdef _DEBUG
  1517. {
  1518. HRESULT hr2;
  1519. CComBSTR bstrIVValue;
  1520. if (FAILED(hr2 = ::BinaryToHexString(IVBlob.pbData, IVBlob.cbData, &bstrIVValue)))
  1521. {
  1522. DebugTrace("Info [%#x]: BinaryToHexString() failed.\n", hr2);
  1523. }
  1524. else
  1525. {
  1526. DebugTrace("Info: Session IV value = %ls.\n", bstrIVValue);
  1527. }
  1528. }
  1529. #endif
  1530. }
  1531. //
  1532. // Return results to caller.
  1533. //
  1534. *phCryptProv = hCryptProv;
  1535. *phKey = hKey;
  1536. *pEncryptedDataInfo = EncryptedDataInfo;
  1537. }
  1538. catch(...)
  1539. {
  1540. hr = E_POINTER;
  1541. DebugTrace("Exception: invalid parameter.\n");
  1542. goto ErrorExit;
  1543. }
  1544. CommonExit:
  1545. //
  1546. // Free resource.
  1547. //
  1548. if (MessageBlob.pbData)
  1549. {
  1550. ::CoTaskMemFree(MessageBlob.pbData);
  1551. }
  1552. DebugTrace("Leaving CEncryptedData::OpenToDecode().\n");
  1553. return hr;
  1554. ErrorExit:
  1555. //
  1556. // Sanity check.
  1557. //
  1558. ATLASSERT(FAILED(hr));
  1559. //
  1560. // Free resource.
  1561. //
  1562. if (hKey)
  1563. {
  1564. ::CryptDestroyKey(hKey);
  1565. }
  1566. if (hCryptProv)
  1567. {
  1568. ::ReleaseContext(hCryptProv);
  1569. }
  1570. if (EncryptedDataInfo.VersionBlob.pbData)
  1571. {
  1572. ::CoTaskMemFree(EncryptedDataInfo.VersionBlob.pbData);
  1573. }
  1574. if (EncryptedDataInfo.AlgIDBlob.pbData)
  1575. {
  1576. ::CoTaskMemFree(EncryptedDataInfo.AlgIDBlob.pbData);
  1577. }
  1578. if (EncryptedDataInfo.KeyLengthBlob.pbData)
  1579. {
  1580. ::CoTaskMemFree(EncryptedDataInfo.KeyLengthBlob.pbData);
  1581. }
  1582. if (EncryptedDataInfo.SaltBlob.pbData)
  1583. {
  1584. ::CoTaskMemFree(EncryptedDataInfo.SaltBlob.pbData);
  1585. }
  1586. if (EncryptedDataInfo.IVBlob.pbData)
  1587. {
  1588. ::CoTaskMemFree(EncryptedDataInfo.IVBlob.pbData);
  1589. }
  1590. if (EncryptedDataInfo.CipherBlob.pbData)
  1591. {
  1592. ::CoTaskMemFree(EncryptedDataInfo.CipherBlob.pbData);
  1593. }
  1594. goto CommonExit;
  1595. }
  1596. /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1597. Function : CEncryptedData::GenerateKey
  1598. Synopsis : Generate the session key.
  1599. Parameter: HCRYPTPROV hCryptProv - CSP handler.
  1600. CAPICOM_ENCRYPTION_ALGORITHM AlogName - Algo enum name.
  1601. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength - Key length enum name.
  1602. DATA_BLOB SaltBlob - Salt blob.
  1603. HCRYPTKEY * phKey - Pointer to HCRYPTKEY to receive session key.
  1604. Remark :
  1605. ------------------------------------------------------------------------------*/
  1606. STDMETHODIMP CEncryptedData::GenerateKey (
  1607. HCRYPTPROV hCryptProv,
  1608. CAPICOM_ENCRYPTION_ALGORITHM AlgoName,
  1609. CAPICOM_ENCRYPTION_KEY_LENGTH KeyLength,
  1610. DATA_BLOB SaltBlob,
  1611. HCRYPTKEY * phKey)
  1612. {
  1613. HRESULT hr = S_OK;
  1614. HCRYPTKEY hKey = NULL;
  1615. ALG_ID AlgId = 0;
  1616. DWORD dwKeyLength = 0;
  1617. DATA_BLOB SecretBlob = {m_bstrSecret.Length() * sizeof(WCHAR),
  1618. (BYTE *) m_bstrSecret.m_str};
  1619. DWORD dwBlockLen = 0;
  1620. DWORD cbBlockLen = sizeof(dwBlockLen);
  1621. DATA_BLOB IVBlob = {0, NULL};
  1622. DebugTrace("Entering CEncryptedData::GenerateKey().\n");
  1623. //
  1624. // Sanity check.
  1625. //
  1626. ATLASSERT(hCryptProv);
  1627. ATLASSERT(phKey);
  1628. ATLASSERT(SaltBlob.cbData);
  1629. ATLASSERT(SaltBlob.pbData);
  1630. //
  1631. // Conver to ALG_ID.
  1632. //
  1633. if (FAILED(hr = ::EnumNameToAlgID(AlgoName, KeyLength, &AlgId)))
  1634. {
  1635. DebugTrace("Error [%#x]: EnumNameToAlgID() failed.\n", hr);
  1636. goto ErrorExit;
  1637. }
  1638. //
  1639. // Set key length for RC2 and RC4.
  1640. //
  1641. if ((CALG_RC2 == AlgId || CALG_RC4 == AlgId) &&
  1642. FAILED(hr = ::EnumNameToKeyLength(KeyLength, AlgId, &dwKeyLength)))
  1643. {
  1644. DebugTrace("Error [%#x]: EnumNameToKeyLength() failed.\n", hr);
  1645. goto ErrorExit;
  1646. }
  1647. //
  1648. // Derive a session key from the secret.
  1649. //
  1650. if (FAILED(hr = DeriveKey(hCryptProv,
  1651. AlgId,
  1652. dwKeyLength,
  1653. SecretBlob,
  1654. SaltBlob,
  1655. dwKeyLength,
  1656. &hKey)) )
  1657. {
  1658. DebugTrace("Error [%#x]: DeriveKey() failed.\n", hr);
  1659. goto ErrorExit;
  1660. }
  1661. //
  1662. // Generate random IV, if required.
  1663. //
  1664. if ((CALG_RC2 == AlgId) || (CALG_DES == AlgId) || (CALG_3DES == AlgId))
  1665. {
  1666. //
  1667. // Get block size.
  1668. //
  1669. if (!::CryptGetKeyParam(hKey, KP_BLOCKLEN, (BYTE *) &dwBlockLen, &cbBlockLen, 0))
  1670. {
  1671. hr = HRESULT_FROM_WIN32(::GetLastError());
  1672. DebugTrace("Error [%#x]: CryptGetKeyParam() failed for KP_BLOCKLEN.\n", hr);
  1673. goto ErrorExit;
  1674. }
  1675. //
  1676. // Make sure block length is valid.
  1677. //
  1678. if (IVBlob.cbData = dwBlockLen / 8)
  1679. {
  1680. //
  1681. // Allocate memory.
  1682. //
  1683. if (!(IVBlob.pbData = (BYTE *) ::CoTaskMemAlloc(IVBlob.cbData)))
  1684. {
  1685. hr = E_OUTOFMEMORY;
  1686. DebugTrace("Error: out of memory.\n");
  1687. goto ErrorExit;
  1688. }
  1689. //
  1690. // Generate random IV.
  1691. //
  1692. if(!::CryptGenRandom(hCryptProv, IVBlob.cbData, IVBlob.pbData))
  1693. {
  1694. hr = HRESULT_FROM_WIN32(::GetLastError());
  1695. DebugTrace("Error [%#x]: CryptGenRandom() failed.\n", hr);
  1696. goto ErrorExit;
  1697. }
  1698. //
  1699. // Set IV.
  1700. //
  1701. if(IVBlob.cbData && !::CryptSetKeyParam(hKey, KP_IV, IVBlob.pbData, 0))
  1702. {
  1703. hr = HRESULT_FROM_WIN32(::GetLastError());
  1704. DebugTrace("Error [%#x]: CryptSetKeyParam() failed for KP_IV.\n", hr);
  1705. goto ErrorExit;
  1706. }
  1707. //
  1708. // Dump IV value.
  1709. //
  1710. #ifdef _DEBUG
  1711. {
  1712. HRESULT hr2;
  1713. CComBSTR bstrIVValue;
  1714. if (FAILED(hr2 = ::BinaryToHexString(IVBlob.pbData, IVBlob.cbData, &bstrIVValue)))
  1715. {
  1716. DebugTrace("Info [%#x]: BinaryToHexString() failed.\n", hr2);
  1717. }
  1718. else
  1719. {
  1720. DebugTrace("Info: Session IV value = %ls.\n", bstrIVValue);
  1721. }
  1722. }
  1723. #endif
  1724. }
  1725. }
  1726. //
  1727. // Return session key to caller.
  1728. //
  1729. *phKey = hKey;
  1730. CommonExit:
  1731. //
  1732. // Free resource.
  1733. //
  1734. if (IVBlob.pbData)
  1735. {
  1736. ::CoTaskMemFree(IVBlob.pbData);
  1737. }
  1738. DebugTrace("Leaving EncryptedData::GenerateKey().\n");
  1739. return hr;
  1740. ErrorExit:
  1741. //
  1742. // Sanity check.
  1743. //
  1744. ATLASSERT(FAILED(hr));
  1745. //
  1746. // Free resource.
  1747. //
  1748. if (hKey)
  1749. {
  1750. ::CryptDestroyKey(hKey);
  1751. }
  1752. goto CommonExit;
  1753. }