[C++]将PFX证书导入USB-KEY
2012-07-20 10:11
302 查看
**************************************************************************************************
(1) 利用PFXImportCertStore函数将P12结构证书导入一个临时的内存型证书库,注意要用
CRYPT_EXPORTABLE 标志,获得该库的句柄hImportStore。
(3) 利用CertFindCertificateInStore函数获得hImportStore证书库中的证书上下文pCertContext。
(4) 利用上面得到的证书上文pCertContext,通过CryptAcquireCertificatePrivateKey函数获得临时CSP句柄 hCryptProv,证书对应私钥的类型dwKeySpec。
(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 = 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) 利用PFXImportCertStore函数将P12结构证书导入一个临时的内存型证书库,注意要用
CRYPT_EXPORTABLE 标志,获得该库的句柄hImportStore。
(3) 利用CertFindCertificateInStore函数获得hImportStore证书库中的证书上下文pCertContext。
(4) 利用上面得到的证书上文pCertContext,通过CryptAcquireCertificatePrivateKey函数获得临时CSP句柄 hCryptProv,证书对应私钥的类型dwKeySpec。
(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 = 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);
}
相关文章推荐
- [C++]将PFX证书导入USB-KEY
- 将PFX证书导入USB-KEY
- 将PFX证书导入USB-KEY
- xp终于换成xin7了,但是以前ntfs加密的内容得把xp的pfx证书导入才能使用
- OpenSSL生成.key、.crt、.pfx证书(Windows下)
- 【Win 10 应用开发】导入.pfx证书
- java keytool支持的类型及如何将证书导入jks中
- [转]关于OpenSSL支持USB-KEY证书的尝试
- PowerShell 运维菜鸟系列-01-批量为n台服务器导入PFX证书(2017年除夕奉献)
- java keytool支持的类型及如何将证书导入jks中
- [转]PFX证书导入到USBKEY(代码)
- 关于OpenSSL支持USB-KEY证书的尝试
- java keytool导入和删除证书
- Microsoft Windows 2008 IIS 7.0 -PFX证书导入
- 关于OpenSSL支持USB-KEY证书的尝试
- Python 调用CAPICOM 读取 USB-KEY数字证书
- Lync 项目经验-32-批量为n台服务器导入PFX证书-实战(图解)
- C++ 自动导入数字证书
- Openssl将crt证书和key私钥合成pfx证书
- Linux下pfx证书导出key和crt