**************************************************************************************************
(1)利用PFXImportCertStore函数将P12结构证书导入一个临时的内存型证书库,注意要用
CRYPT_EXPORTABLE 标志,获得该库的句柄hImportStore。
(3)利用CertFindCertificateInSto
(4)利用上面得到的证书上文pCertContext,通过CryptAcquireCertificateP
(5)利用临时CSP句柄hCryptProv,私钥的类型dwKeySpec,通过CryptGetUserKey获得证书对应的私钥句柄hUserKey。
(6)利用私钥句柄hUserKey,通过CryptExportKey将私钥以PRIVATEKEYBLOB的形式导出来,获得私钥的blob和长度。
(7) 通过CryptAcquireContext函数,创建密钥容器并获得USBKey CSP的句柄hProv。
(8) 利用获得hProv和上面获得的私钥blob和长度,通过CryptImportKey函数将私钥导进USBKey CSP中,并返回私钥句柄hKey。
(9) 利用私钥句柄hKey,和前面获得的证书上下文pCertContext的内容,通过CryptSetKeyParam函数,KP_CERTIFICATE标志将证书写进对应的密钥容器。
**************************************************************************************************
网上找到的代码貌似都不太靠谱,于是自己写了一个,下面只公布主要的函数
- 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 = CertEnumCertificatesInSt ore(hStore, pCertContext)) { //对比“颁发给”和“颁发者”是否一致(对于根证书是一致的,不要导入根证书) //if (!CertCompareCertificateNa me(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, // &pCertContext->pCertInfo->Issuer, // &pCertContext->pCertInfo->Subject)) { //获取私钥临时 CSP 句柄 DWORD dwKeySpec = 0; if (!CryptAcquireCertificateP rivateKey(pCertContext, CRYPT_ACQUIRE_COMPARE_KEY_FLAG, NULL, &hCertProv, &dwKeySpec, NULL)) { DWORD dwRet = GetLastError(); ::AfxMessageBox(_T("CryptAcquireCertificateP rivateKey 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); //释放证书句柄 CertFreeCertificateConte xt(pCertContext); //关闭临时证书库 CertCloseStore(hStore, 0); - }