[C++]将PFX证书导入USB-KEY

网上找到的代码貌似都不太靠谱,于是自己写了一个,下面只公布主要的函数

 

void CImportPFXDlg::ImportPFX(LPCTSTR PFX_FILE, LPCTSTR PFX_PASS)
{
	//打开文件
	HANDLE hFile = NULL;
	hFile = ::CreateFile(PFX_FILE, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
	if (hFile == INVALID_HANDLE_VALUE)
	{
		::AfxMessageBox(_T("CreateFile Fail!"));
		return;
	}

	//分配内存
	DWORD dwSize = ::GetFileSize(hFile, NULL);
	BYTE *pP12 = NULL;
	if (!(pP12 = new BYTE[dwSize]))
	{
		::CloseHandle(hFile);
		::AfxMessageBox(_T("new pP12 Fail!"));
		return;
	}

	//读取证书内容
	DWORD dwRead = 0;
	if (!::ReadFile(hFile, pP12, dwSize, &dwRead, NULL))
	{
		::CloseHandle(hFile);
		::AfxMessageBox(_T("ReadFile Fail!"));
		return;
	}

	//关闭文件
	::CloseHandle(hFile);

	//生成结构体
	CRYPT_DATA_BLOB CDB;
	CDB.cbData = dwSize;
	CDB.pbData = pP12;

	//将证书导入临时证书库
	HCERTSTORE hStore = NULL;
	if (!(hStore = PFXImportCertStore(&CDB, PFX_PASS, CRYPT_EXPORTABLE)))
	{
		delete pP12; pP12 = NULL;
		::AfxMessageBox(_T("PFXImportCertStore Fail!"));
		return;
	}
	delete pP12; pP12 = NULL;

	//枚举临时证书库中导入的证书
	PCCERT_CONTEXT pCertContext = NULL;
	HCRYPTPROV hCertProv = NULL;
	HCRYPTKEY hKey = NULL;
	BYTE *pPK = NULL;
	HCRYPTKEY hPrvKey = NULL;
	HCRYPTPROV hProv = NULL;
	while (pCertContext = CertEnumCertificatesInStore(hStore, pCertContext))
	{
		//对比“颁发给”和“颁发者”是否一致(对于根证书是一致的,不要导入根证书)
		//if (!CertCompareCertificateName(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
		//								&pCertContext->pCertInfo->Issuer,
		//								&pCertContext->pCertInfo->Subject))
		{
			//获取私钥临时 CSP 句柄
			DWORD dwKeySpec = 0;
			if (!CryptAcquireCertificatePrivateKey(pCertContext,
												   CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
												   NULL,
												   &hCertProv,
												   &dwKeySpec,
												   NULL))
			{
				DWORD dwRet = GetLastError();
				::AfxMessageBox(_T("CryptAcquireCertificatePrivateKey Fail!"));
				goto cleanup;
			}

			//获取密钥对
			if (!CryptGetUserKey(hCertProv, ((m_cmbCertType.GetCurSel() == 0) ? AT_KEYEXCHANGE : AT_SIGNATURE), &hKey))
			{
				DWORD dwRet = GetLastError();
				::AfxMessageBox(_T("CryptGetUserKey Fail!"));
				goto cleanup;
			}

			//获取私钥长度
			DWORD dwPKSize = 0;
			if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, NULL, &dwPKSize))
			{
				DWORD dwRet = GetLastError();
				::AfxMessageBox(_T("CryptExportKey dwPKSize Fail!"));
				goto cleanup;
			}

			//分配内存
			if (!(pPK = new BYTE[dwPKSize]))
			{
				DWORD dwRet = GetLastError();
				::AfxMessageBox(_T("new pPK Fail!"));
				goto cleanup;
			}

			//导出私钥
			if (!CryptExportKey(hKey, NULL, PRIVATEKEYBLOB, 0, pPK, &dwPKSize))
			{
				DWORD dwRet = GetLastError();
				::AfxMessageBox(_T("CryptExportKey pPK Fail!"));
				goto cleanup;
			}

			//获取 UKEY 的 CSP 句柄
			
			//获取密钥容器名称
			CString csContainer;
			if (m_cmbContainer.GetCurSel() == 0) //新建密钥容器
			{
				m_edtContainer.GetWindowText(csContainer);
				if (!CryptAcquireContext(&hProv, (LPCTSTR)csContainer, CSP_NAME, PROV_RSA_FULL, CRYPT_NEWKEYSET))
				{
					DWORD dwRst = ::GetLastError();
					::AfxMessageBox(_T("CryptAcquireContext m_edtContainer Fail!"));
					goto cleanup;
				}
			}
			else //证书导入现有容器
			{
				m_cmbContainer.GetWindowText(csContainer);
				if (!CryptAcquireContext(&hProv, (LPCTSTR)csContainer, CSP_NAME, PROV_RSA_FULL, 0))
				{
					DWORD dwRst = ::GetLastError();
					::AfxMessageBox(_T("CryptAcquireContext m_cmbContainer Fail!"));
					goto cleanup;
				}
			}

			//将私钥导入到 CSP,并获取其句柄
			if (!CryptImportKey(hProv, pPK, dwPKSize, NULL, 0, &hPrvKey))
			{
				DWORD dwRst = ::GetLastError();
				::AfxMessageBox(_T("CryptImportKey Fail!"));
				goto cleanup;
			}

			//将证书导入到密钥容器
			if (!CryptSetKeyParam(hPrvKey, KP_CERTIFICATE, pCertContext->pbCertEncoded, 0))
			{
				DWORD dwRst = ::GetLastError();
				::AfxMessageBox(_T("CryptSetKeyParam Fail!"));
				goto cleanup;
			}

			break;
		}
	}

cleanup:

	//销毁私钥句柄
	CryptDestroyKey(hPrvKey);

	//关闭 UKEY 的 CSP 句柄
	CryptReleaseContext(hProv, 0);

	//释放私钥内存
	delete pPK; pPK = NULL;

	//销毁密钥对句柄
	CryptDestroyKey(hKey);

	//释放证书句柄
	CertFreeCertificateContext(pCertContext);

	//关闭临时证书库
	CertCloseStore(hStore, 0);
}


 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值