CryptoAPI的密码服务提供者函数主要有6个函数:
1)连接或断开CSP函数CryptAcquireContext、CryptReleaseContext;
2)枚举CSP函数CryptEnumProviders;
3)获得或设置默认CSP函数CryptGetDefaultProvider、CryptSetProvider;
4)获取或设置CSP参数函数CryptGetProvParam、CryptSetProvParam;
一、连接CSP函数CryptAcquireContext:
功能:连接CSP,获得指定CSP的密钥容器的句柄;
原型:
BOOL WINAPI CryptAcquireContext(
__out HCRYPTPROV *phProv, //CSP句柄指针
__in LPCTSTR pszContainer, //密钥容器名称,指向密钥容器的字符串指针;
//如果dwFlags为CRYPT_VERIFYCONTEXT,pszContainer必须为NULL
__in LPCTSTR pszProvider, //指向CSP名称的字符串指针;
//为NULL,表示使用默认的CSP
__in DWORD dwProvType, //CSP类型
__in DWORD dwFlags //标志位
);
其中,dwFlags取值如下所示:
CRYPT_VERIFYCONTEXT---指出应用程序不需要使用公私钥对,如程序只执行哈希和对称加密,只有程序需要创建签名和解密消息时才需要访问私钥
CRYPT_NEWKEYSET---使用指定的密钥容器名称创建一个新的密钥容器;如果pszContainer为NULL,密钥容器就使用缺省的名称创建
CRYPT_MACHINE_KEYSET---由此标志创建的密钥容器只能由创建者本人或系统管理员身份的人使用
CRYPT_DELETEKETSET---删除由pszContainer指定的密钥容器;如果pszContainer为NULL,缺省名称的容器就会被删除。此容器里的所有密钥对也会被删除
CRYPT_SILENT---应用程序要求CSP不显示任何用户界面
返回值:操作成功返回TRUE,否则返回FALSE。调用GetLastError()可获得更多信息。
二、枚举CSP函数CryptEnumProviders:
功能:枚举计算机上的所有CSP;此函数可以得到第一个或下一个可用的CSP,循环调用可以得到计算机上所有可用的CSP。
原型:
BOOL WINAPI CryptEnumProviders(
__in DWORD dwIndex, //枚举下一个CSP的索引
__in DWORD *pdwReserved, //保留参数,必须为NULL
__in DWORD dwFlags, //保留参数,必须为0
__out DWORD *pdwProvType, //CSP的类型
__out LPTSTR pszProvName, //指向接收CSP名称的缓冲区字符串指针
__inout DWORD *pcbProvName //指出pszProvName字符串的大小
);
返回值:操作成功返回TRUE,否则返回FALSE。调用GetLastError()可获得更多信息。
该函数的使用示例如下:
#include <windows.h>
#include <wincrypt.h>
#include <iostream>
int _tmain(int argc, _TCHAR* argv[])
{
DWORD cbName;
DWORD dwType;
DWORD dwIndex;
WCHAR *pszName = NULL;
setlocale(LC_CTYPE, ""); //用于显示Unicode字符串
printf("枚举可用的CSP:/n");
printf("CSP提供者类型/tCSP提供者名称/n");
printf("______________/t____________________________________/n");
//循环调用CryptEnumProviders函数
dwIndex = 0;
while(CryptEnumProviders(dwIndex, NULL, 0,
&dwType, NULL, &cbName))
{
//cbName返回下一个提供者名称的长度,分配相应的内存空间给pszName
if(!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName)))
{
printf("调用LocalAlloc时出错/n");
return -1;
}
//获得提供者名称
if(CryptEnumProviders(dwIndex++, NULL, 0,
&dwType, pszName, &cbName))
{
wprintf(L" %4.0d/t%s/n", dwType, pszName);
}
else
{
printf("调用CryptEnumProviders函数出错/n");
return -1;
}
LocalFree(pszName);
}
printf("/nCSP提供者类型和名称列举完毕/n");
system("pause");
return 0;
}
三、获得默认CSP函数CryptGetDefaultProvider:
功能:获得系统默认的CSP;
原型:
BOOL WINAPI CryptGetDefaultProvider(
__in DWORD dwProvType, //CSP类型
__in DWORD *pdwReserved, //保留参数,必须为NULL
__in DWORD dwFlags, //标志位
__out LPTSTR pszProvName, //指向接收CSP名称的缓冲区字符串指针
__inout DWORD *pcbProvName //指出pszProvName字符串的大小
);
其中系统预定义的CSP类型有:
PROV_RSA_FULL PROV_RSA_SIGN PROV_DSS PROV_DSS_DH
PROV_DH_SCHANNEL PROV_FORTEZZA PROV_MS_EXCHANGE
PROV_RSA_SCHANNEL PROV_SSL
而参数dwFlags取值如下:
CRYPT_USER_DEFAULT---返回用户上下文指定类型的默认CSP
CRYPT_MACHINE_DEFAULT---返回计算机指定类型的默认CSP
返回值:操作成功返回TRUE,否则返回FALSE;调用GetLastError()可获得更多信息。
该函数使用示例如下:
#include <windows.h>
#include <wincrypt.h>
#include <iostream>
#pragma comment(lib, "crypt32.lib")
int _tmain(int argc, _TCHAR* argv[])
{
DWORD cbProvName = 0;
WCHAR *pbProvName = NULL;
setlocale(LC_CTYPE, ""); //用于显示Unicode字符串
printf("获得系统指定类型的默认CSP:/n");
//获得RSA_FULL类型的默认CSP名称的长度
if(!(CryptGetDefaultProvider(PROV_RSA_FULL, NULL,
CRYPT_MACHINE_DEFAULT, NULL, &cbProvName)))
{
printf("获得RSA_FULL类型的默认CSP名称的长度时出错/n");
return -1;
}
//给CSP名称字符串缓冲区分配空间
if(!(pbProvName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbProvName)))
{
printf("调用LocalAlloc分配内存时出错/n");
return -1;
}
//获取默认CSP名称
if(CryptGetDefaultProvider(PROV_RSA_FULL, NULL,
CRYPT_MACHINE_DEFAULT, pbProvName, &cbProvName))
{
wprintf(L"指定类型的CSP的默认名称是:%s/n", pbProvName);
}
else
{
printf("获取名称时出错/n");
return -1;
}
LocalFree(pbProvName);
system("pause");
return 0;
}
四、设置默认CSP函数CryptSetProvider:
功能:设置系统默认的CSP
原型:
BOOL WINAPI CryptSetProvider(
__in LPCTSTR pszProvName, //CSP类型
__in DWORD dwProvType //CSP名称的缓冲区字符串指针
);
返回值:操作成功返回TRUE,否则返回FALSE;调用GetLastError()可获得更多信息。
五、获得CSP属性参数函数CryptGetProvParam:
功能:获得CSP各种参数属性
原型:
BOOL WINAPI CryptGetProvParam(
__in HCRYPTPROV hProv, //CSP句柄
__in DWORD dwParam, //指定查询的参数
__out BYTE *pbData, //指向接收数据的缓冲区指针
__inout DWORD *pdwDataLen, //指出pbData数据长度
__in DWORD dwFlags //标志位
);
其中dwParam支持的参数为:
PP_CONTAINER---指向密钥名称的字符串;
PP_ENUMALGS---不断的读出CSP支持的所有算法;
PP_ENUMALGS_EX---比PP_ENUMALGS获得更多的算法信息;
PP_ENUMCONTAINERS---不断的读出CSP支持的密钥容器;
PP_IMPTYPE---指出CSP怎样实现的;
PP_NAME---指向CSP名称的字符串;
PP_VERSION---CSP的版本号;
PP_KEYSIZE_INC---AT_SIGNATURE的位数;
PP_KEYX_KEYSIZE_INC---AT_KEYEXCHANGE的位数;
PP_KEYSIZE_SEC_DESCR---密钥的安全描述;
PP_UNIQUE_CONTAINER---当前密钥容器的唯一名称;
PP_PROVTYPE---CSP的类型;
PP_USE_HARDWARE_RNG---指出硬件是否支持随机数发生器;
PP_KEYSPEC---返回CSP密钥的信息。
返回值:操作成功返回TRUE,否则返回FALSE,使用GetLastError获取更多信息。
六、设置CSP参数函数CryptSetProvParam:
功能:设置CSP各种参数属性;
原型:
BOOL WINAPI CryptSetProvParam(
__in HCRYPTPROV hProv, //CSP句柄
__in DWORD dwParam, //指定设置的参数
__in const BYTE *pbData, //指向设置数据的缓冲区指针
__in DWORD dwFlags //标志位
);
其中,dwParam支持的参数:
PP_CLIENT_HWND---设置Windows句柄;
PP_KEYSET_SEC_DESCR---密钥的安全描述;
PP_USE_HARDWARE_RNG---指出硬件是否支持随机数发生器。
返回值:操作成功返回TRUE,否则返回FALSE,使用GetLastError获取更多信息。
七、断开CSP函数CryptReleaseContext:
功能:断开CSP,释放CSP句柄,和CryptAcquireContext相对应;
原型:
BOOL WINAPI CryptReleaseContext(
__in HCRYPTPROV hProv, //CSP句柄
__in DWORD dwFlags //标志位,保留参数,必须为0
);
返回值:操作成功返回TRUE,否则返回FALSE,使用GetLastError获取更多信息。
下面看一个例子:
#include <windows.h>
#include <wincrypt.h>
#include <iostream>
#pragma comment(lib, "crypt32.lib")
void HandleError(TCHAR* s);
void Wait(TCHAR* s);
int _tmain(int argc, _TCHAR* argv[])
{
HCRYPTPROV hProv;
LPTSTR pszName;
DWORD dwType;
DWORD cbName;
DWORD dwIndex = 0;
BYTE* ptr;
ALG_ID aiAlgid;
DWORD dwBits;
DWORD dwNameLen;
CHAR szName[100];
BYTE pbData[1024];
DWORD cbData = 1024;
DWORD dwIncrement = sizeof(DWORD);
DWORD dwFlags = CRYPT_FIRST;
DWORD dwParam = PP_CLIENT_HWND;
CHAR* pszAlgType = NULL;
BOOL fMore = TRUE;
printf("列举可用的CSP提供者类型/n");
printf("CSP提供者类型 CSP提供者类型名称/n");
_tprintf(TEXT("______________ ________________________________/n"));
//循环调用CryptEnumProviderType函数枚举当前计算机支持的CSP类型
while(CryptEnumProviderTypes(dwIndex, NULL, 0,
&dwType,
NULL, //第一次调用设置为NULL
&cbName)) //将要输出的pszName的长度
{
//为pszName分配内存
if(!(pszName = (LPTSTR)LocalAlloc(LMEM_ZEROINIT, cbName)))
{
HandleError(TEXT("调用LocalAlloc分配内存出错/n"));
}
//获取CSP提供者类型名
if(CryptEnumProviderTypes(dwIndex++, NULL, 0,
&dwType, pszName, &cbName))
{
_tprintf(TEXT(" %d %s/n"), dwType, pszName);
}
else
{
HandleError(TEXT("调用CryptEnumProviderTypes出错/n"));
}
LocalFree(pszName);
}
//连接CSP,创建CSP句柄
if(!CryptAcquireContext(&hProv, NULL, NULL,
PROV_RSA_FULL, NULL))
{
HandleError(TEXT("调用CryptAcquireContext函数出错/n"));
}
//获得CSP参数,枚举支持的密码算法
printf("/n枚举支持的密码算法/n");
printf("算法ID 位数 类型 长度 算法名称/n");
printf("___________________________________________________________________/n");
while(fMore)
{
if(CryptGetProvParam(hProv, PP_ENUMALGS, pbData,
&cbData, dwFlags))
{
//从pbData缓冲区中解析出算法信息
dwFlags = 0;
ptr = pbData;
aiAlgid = *(ALG_ID*)ptr;
ptr += sizeof(ALG_ID);
dwBits = *(DWORD*)ptr;
ptr += dwIncrement;
dwNameLen = *(DWORD*)ptr;
ptr += dwIncrement;
strncpy_s(szName, (char*)ptr, dwNameLen);
//获取算法类型
switch(GET_ALG_CLASS(aiAlgid))
{
case ALG_CLASS_DATA_ENCRYPT:
pszAlgType = "加密 ";
break;
case ALG_CLASS_HASH:
pszAlgType = "哈希 ";
break;
case ALG_CLASS_KEY_EXCHANGE:
pszAlgType = "交换 ";
break;
case ALG_CLASS_SIGNATURE:
pszAlgType = "签名 ";
break;
default:
pszAlgType = "未知 ";
break;
}
//打印算法信息
printf("%8.8xh %-4d %s %-2d %s/n",
aiAlgid, dwBits, pszAlgType, dwNameLen, szName);
}
else
{
fMore = FALSE;
}
}
Wait(TEXT("/n按Enter继续"));
if(!(CryptReleaseContext(hProv, 0)))
{
HandleError(TEXT("调用CryptReleaseContext时出错/n"));
}
if(GetLastError() == ERROR_NO_MORE_ITEMS)
{
_tprintf(TEXT("/n程序成功执行完毕/n"));
}
else
{
HandleError(TEXT("读取算法信息时出错"));
}
system("pause");
return 0;
}
void HandleError(TCHAR* s)
{
_tprintf(TEXT("程序运行出现错误./n"));
_tprintf(TEXT("%s/n"),s);
_tprintf(TEXT("错误代码%x/n."), GetLastError());
_tprintf(TEXT("程序终止./n"));
exit(1);
}
void Wait(TCHAR* s)
{
char x;
_tprintf(s);
x = getchar();
}
参考文献:《精通PKI网络安全认证技术与编程实现》+ MSDN