《ASCE1885的信息安全》のCryptoAPI---密码服务提供者CSP函数

CryptoAPI的密码服务提供者函数主要有6个函数:

1)连接或断开CSP函数CryptAcquireContextCryptReleaseContext

2)枚举CSP函数CryptEnumProviders

3)获得或设置默认CSP函数CryptGetDefaultProviderCryptSetProvider

4)获取或设置CSP参数函数CryptGetProvParamCryptSetProvParam

 

一、连接CSP函数CryptAcquireContext

功能:连接CSP,获得指定CSP的密钥容器的句柄;

原型:

BOOL WINAPI CryptAcquireContext(

  __out  HCRYPTPROV *phProv,    //CSP句柄指针

  __in   LPCTSTR pszContainer,       //密钥容器名称,指向密钥容器的字符串指针;

         //如果dwFlagsCRYPT_VERIFYCONTEXTpszContainer必须为NULL

  __in   LPCTSTR pszProvider,          //指向CSP名称的字符串指针;

//NULL,表示使用默认的CSP

  __in   DWORD dwProvType,       //CSP类型

  __in   DWORD dwFlags         //标志位

);

其中,dwFlags取值如下所示:

CRYPT_VERIFYCONTEXT---指出应用程序不需要使用公私钥对,如程序只执行哈希和对称加密,只有程序需要创建签名和解密消息时才需要访问私钥

CRYPT_NEWKEYSET---使用指定的密钥容器名称创建一个新的密钥容器;如果pszContainerNULL,密钥容器就使用缺省的名称创建

CRYPT_MACHINE_KEYSET---由此标志创建的密钥容器只能由创建者本人或系统管理员身份的人使用

CRYPT_DELETEKETSET---删除由pszContainer指定的密钥容器;如果pszContainerNULL,缺省名称的容器就会被删除。此容器里的所有密钥对也会被删除

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("/nEnter继续"));

        

         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

 

你可能感兴趣的:(信息安全)