[返回]
计算机世界2000年第31期

对“用CryptoAPI进行数据加密”一文的补充

武汉 程义军

  读了贵刊2000年第19期B16版“用CryptoAPI进行数据加密”一文,觉得很有所获,急忙将其键入,编译、运行,却出现了错误。当然,并不是原文提供的代码有错,而是原文的作者忽略了一个重要的问题。如果你的机器曾运行过这种数据加密程序,那当然可以正确地运行。如果是第一次才运行此程序,那将会出现问题,错误就在 CryptAcquireContext的调用上。

  在调用CryptEncrypt进行数据加密之前,需要取得当前机器缺省的密钥容器,而CryptAcquireContext(&hProv,NULL,NULL,PROV_RSA_FULL,0)就是用于连接缺省的CSP的,如果当前机器未曾设置过缺省的密钥容器, CryptAcquireContext 调用就会出错。因此必须为机器创建缺省的密钥容器。

  创建缺省的密钥容器也需要调用CryptoAPI进行。下面介绍一种创建缺省的密钥容器的控制台程序InitUser.c。本程序的功能为:

  1. 用你的机器名称UserName创建一个缺省的密钥容器。
  2. 在密钥容器中创建一个数字签名密钥对。
  3. 在密钥容器中创建一个密钥交换对。

  本程序在一台机器上只须执行一次,执行之后,你将会看到在系统注册表的HKEY_CURRENT_USER\Software\microsoft下多了一个主键: Cryptography\UserKeys,并填入一些十六进制的值。之后,你就可以顺利地使用数据加密程序了,甚至可以使用数字签名了。

  程序清单:

< InitUser.c >
#include < windows.h >
#include < stdio.h >
#include < stdlib.h >
#include < wincrypt.h >
//主程序不需要任何参数
void _cdecl main(void)
{
    HCRYPTPROV   hProv;
    HCRYPTKEY    hKey;
    CHAR 	   szUserName[100];
    DWORD 	   dwUserNameLen = 100;
// 试图获取缺省的密钥容器,
若失败,则创建一个缺省容器
if(!CryptAcquireContext(&hProv, NULL,
MS_DEF_PROV, PROV_RSA_FULL, 0))
{
//若获取缺省密钥容器发生错误,
就创建一个缺省密钥容器, 使用参数
CRYPT_NEWKEYSET if(!CryptAcquireContext
(&hProv,NULL,MS_DEF_PROV,
PROV_RSA_FULL,CRYPT_NEWKEYSET))
    {
	printf(“创建缺省密钥容器发生错误!\n");
	exit(1);
    }
   // 取得缺省密钥容器名
   if(!CryptGetProvParam(hProv, PP_CONTAINER,
    szUserName, &dwUserNameLen, 0))	{
	    // 出错误时容器名置空
	    szUserName[0] = 0;
	}
 printf(“Create key container ‘%s'\n",szUserName);
}
// 试图获取签名密钥的名柄
if(!CryptGetUserKey(hProv, AT_SIGNATURE, &hKey))
{
if(GetLastError() == NTE_NO_KEY)
{	    // 创建数字签名密钥对
printf(“Create signature key pair\n");
if(!CryptGenKey(hProv,AT_SIGNATURE,0,&hKey))
{
printf(“错误代码: %x 创建数字签名
     密钥对发生错误!\n", GetLastError());
exit(1);
} 
else
{
CryptDestroyKey(hKey);
}
}
else
{
printf(“错误代码: %x during 
CryptGetUserKey!\n", GetLastError());
              exit(1);
	}
}
// 试图取得交换密钥的句柄,
没有交换密钥时,创建交换密钥
if(!CryptGetUserKey(hProv,AT_KEYEXCHANGE,&hKey))
{
if(GetLastError()==NTE_NO_KEY) 
{//没有交换密钥时,创建交换密钥对
printf(“创建交换密钥\n");
if(!CryptGenKey(hProv,AT_KEYEXCHANGE,0,&hKey))
{
printf(“Error %x during CryptGenKey!\n", GetLastError());
exit(1);
} 
else 
{
	CryptDestroyKey(hKey);
	}
}
else
{
printf(“Error %x duringCryptGetUserKey!\n", GetLastError());
exit(1);
}
    }
CryptReleaseContext(hProv,0);	//释放句柄
printf(“OK\n");
exit(0);
}

  以上程序在WinNT4.0及Win98、VC5++上编译通过,机器环境为赛扬333。若编译时发生HCRYPTPROV、HCRYPTKEY类型等错误,请打开 vc\include\wincrypt.h,将其头部的#if(_WIN32_WINNT >= 0x0400)及尾部的#endif /* _WIN32_WINNT >= 0x0400 */两行注释掉,存盘,即可编译成功。