此程序已通过文鼎创USBkey多key测试。
#include <stdio.h>
#include <direct.h>
#include <string.h>
#include <vector>
#include <Windows.h>
#include <Wincrypt.h>
using namespace std;
#pragma warning(disable:4996)
#pragma comment(lib, "Crypt32")
#define PROV_LENGTH 255
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
struct keyInfo
{
string certUserName;
string providerName;
string containerName;
};
void GetListProvider(vector<string> &vProList)
{
DWORD dwIndex = 0;
DWORD dwType = 0;
char szKeyName[PROV_LENGTH] = {0};
DWORD dwMaxSubKey = PROV_LENGTH;
while (CryptEnumProviders(dwIndex++, NULL, 0, &dwType, szKeyName, &dwMaxSubKey))
{
if (dwType == PROV_RSA_FULL && strnicmp("Microsoft", szKeyName, 9)) //csp类型 + 不区分大小写比较前9个字符
{
//printf("%s\n", szKeyName);
vProList.push_back(szKeyName);
}
memset(szKeyName, 0, PROV_LENGTH);
dwMaxSubKey = PROV_LENGTH;
}
}
DWORD GetCertificate(HCRYPTPROV hProv, BYTE* pCertificate, DWORD* pCertificateLen)
{
if(hProv == NULL) return -1;
//获取所获取密钥类型的句柄
//获取公私钥对和交换密钥,公私钥用来签名,而交换密钥用来导出会话密钥
HCRYPTKEY hSignKey;
if(CryptGetUserKey(hProv, AT_SIGNATURE, &hSignKey ) == FALSE)
{
printf("CSP获取密钥句柄失败\n");
return -1;
}
if(CryptGetKeyParam(hSignKey, KP_CERTIFICATE, pCertificate, pCertificateLen, 0) == FALSE)
{
printf("CSP得到密钥参数失败\n");
return -1;
}
if(CryptDestroyKey(hSignKey) == FALSE)
{
printf("CSP销毁密钥失败\n");
return -1;
}
return 0;
}
DWORD DecodeX509Cert(BYTE* pCertificate, DWORD certificateLen, char keyID[255], char userName[255])
{
PCCERT_CONTEXT pctx = CertCreateCertificateContext(MY_ENCODING_TYPE, pCertificate, certificateLen); //从编码证书中创建一个证书上下文。但这个上下文并不放到证书库里
if(pctx == NULL)
{
printf("解析证书失败\n");
return -1;
}
//找到扩展对象
PCERT_EXTENSION pCertExt = CertFindExtension(szOID_AUTHORITY_KEY_IDENTIFIER2, pctx->pCertInfo->cExtension, pctx->pCertInfo->rgExtension); //通过OID来查找扩展
if (!pCertExt)
{
printf("证书属性不存在\n");
return -1;
}
//解码对象,得到属性结构体
DWORD ulDataLen = 512;
BYTE btData[512] = {0};
CHAR csProperty[512] = {0};
PCERT_AUTHORITY_KEY_ID2_INFO pAuthorityKeyID2 = (PCERT_AUTHORITY_KEY_ID2_INFO)btData;
if (CryptDecodeObject(MY_ENCODING_TYPE, szOID_AUTHORITY_KEY_IDENTIFIER2,
pCertExt->Value.pbData, pCertExt->Value.cbData, CRYPT_DECODE_NOCOPY_FLAG, pAuthorityKeyID2, &ulDataLen)) //对属性结构体进行解码
{
//获取颁发机构标识符
for (ULONG ulIndex = 0; ulIndex < pAuthorityKeyID2->KeyId.cbData; ulIndex++)
{
CHAR csKeyID[8] = {0};
sprintf_s(csKeyID, 8, "%02x ", pAuthorityKeyID2->KeyId.pbData[ulIndex]);
strcat_s(csProperty, 512, csKeyID);
}
csProperty[strlen(csProperty)-1] = 0;
strcpy(keyID, csProperty);
//获取userName
TCHAR sName[255];
DWORD nNameSize = 255;
DWORD nNameType = 0;
CertGetNameString(pctx, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, &nNameType, sName, nNameSize); //得到证书的主题或颁发者名称并且把它转换成字符串
strcpy(userName, sName);
CertFreeCertificateContext(pctx);
return 0;
}
else
{
CertFreeCertificateContext(pctx);
return -1;
}
}
int getKeyList()
{
//1.获取注册表中的Provider
printf("\n**1**---------------------------------获取Provider-------------------------------\n");
vector<string> vProvList;
GetListProvider(vProvList);
int numProv = vProvList.size();
if (numProv == 0)
{
printf("获取注册表中的Provider失败\n");
return -1;
}
for (int i = 0; i < numProv; i++)
{
printf("%s\n", vProvList[i].c_str());
}
printf("\n");
vector<string> vContainer;
printf("\n**2**---------------------------------取出Container-------------------------------\n");
//2.获取Provider对应的句柄,枚举Container
for (int i = 0; i < numProv; i++)
{
HCRYPTPROV hProv = NULL;
if (CryptAcquireContext(&hProv, NULL, vProvList[i].c_str(), PROV_RSA_FULL, 0)) //获取Provider对应的句柄
{
printf("%s---ok\n", vProvList[i].c_str());
BYTE pbData[512] = {0};
DWORD cbData = 512;
if (CryptGetProvParam(hProv, PP_ENUMCONTAINERS, pbData, &cbData, CRYPT_FIRST)) //枚举container
{
printf("[%s]\n", pbData);
vContainer.push_back((char*)pbData);
memset(pbData, 0, sizeof(pbData));
cbData = 512;
while (CryptGetProvParam(hProv, PP_ENUMCONTAINERS, pbData, &cbData, CRYPT_NEXT))
{
printf("[%s]\n", pbData);
vContainer.push_back((char*)pbData);
memset(pbData, 0, sizeof(pbData));
cbData = 512;
}
}
else
{
DWORD errcode=GetLastError();
printf("[%s]CryptGetProvParam失败!--%d\n",vProvList[i].c_str(),errcode);
}
CryptReleaseContext(hProv, 0);
printf("\n");
}
else
{
DWORD errcode=GetLastError();
printf("[%s]------CryptAcquireContext失败!---%d\n",vProvList[i].c_str(),errcode);
}
}
printf("\n**3**---------------------------------取出Container对应证书-------------------------------\n");
//3.打开Container、Provider对应的加密设备,取出签名证书,取出证书信息(颁发机构标识符等)
for (size_t i = 0; i < vContainer.size(); i++)
{
for (int j = 0; j < numProv; j++)
{
HCRYPTPROV hProv = NULL;
if (CryptAcquireContext(&hProv, vContainer[i].c_str(), vProvList[j].c_str(), PROV_RSA_FULL, 0))
{
printf("[%s]------open container ok\n", vContainer[i].c_str());
BYTE pbData[512] = {0};
DWORD cbData = 512;
BYTE pCertificate[4096] = {0};
DWORD certificateLen = 4096;
if (!GetCertificate(hProv, pCertificate, &certificateLen)) //获取签名证书
{
char userName[255] = {0};
char keyID[255] = {0};
if (!DecodeX509Cert(pCertificate, certificateLen, keyID, userName)) //获取证书【颁发机构标识符】-【用户名】
{
printf(">>>>>>>>>>>>>证书信息\n");
printf("keyID=%s\n", keyID);
printf("userName=%s\n", userName);
}
}
CryptReleaseContext(hProv, 0);
printf("\n");
}
else
{
printf("[%s]------CryptAcquireContext失败!\n",vProvList[j].c_str());
}
}
}
return 0;
}
int main()
{
char buffer[100] = {0};
getcwd(buffer, 100);
printf("%s\n", buffer);
getKeyList();
printf("\n\n########################################################################\n\n");
Sleep(1000);
getKeyList();
getchar();
return 0;
}
插入两个文鼎创USBkey运行效果如图所示: