文章中罗列了自己在练习使用CryptAPI各种函数的过程中所碰到的各种问题,因此文章并没有特定的组织结构。
问题1:在学习CryptAPI的开始是去MSDN上找的范例http://msdn.microsoft.com/en-us/library/ms867086.aspx,其中包含实例源代码的下载Down 5003.exe,这应该是最为权威的CryptAPI函数使用教程,下载下来以后会发现在环境VC6.0 SP5 + WinXP SP3 下难以编译通过,需要做如下修改后才可以直接运行。
解决办法:
直接下载经过本人修改后的程序CryptAPI函数调用实例(修改后),下载后可直接在VC6.0 SP5环境下运行。否则按照下面步骤一步步修改即可。
1、运行下载后的ZIP自解压文件,将代码解压到工作目录中,使用VC6打开Encrypt.mdp,提示需要将项目文件转换为VS6的格式
2、将CryptErr.cpp文件从FileView中删除后,再重新引入,解决项目文件中此文件引用错误的问题
3、手工创建并添加stdafx.h与stdafx.cpp预处理文件到FileView中。最好从其它项目中直接复制过来,将本项目中用不到的内容删除在CryptErr.cpp、Cencrypt.cpp、main.cpp文件最顶部添加预处理头文件#include "stdafx.h"
4、将CryptErr.h文件中,定义NT版本的定义删除
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
在stdafx.h中添加对NT版本的定义
#define _WIN32_WINNT 0x0400
5、程序在显示CSP时Cencrypt类有一错误,CEncrypt::Statistics()函数中
将语句
if (!::CryptGetProvParam(this->m_hCryptProvider, PP_ENUMALGS, pbData, &dwDataLen, 0))
中最后参数0改为dwFlags,修改后语句如下:
if (!::CryptGetProvParam(this->m_hCryptProvider, PP_ENUMALGS, pbData, &dwDataLen, dwFlags))
6、运行程序,并使用各个开关查看运行结果
备注:此程序运行通过后会在"工程目录\Debug\Encrypt.exe"可执行文件。如需要使用此程序,则需要在cmd窗口执行此文件,并使用提示给出的参数即可。(如图示加密文件D:\t.txt后将加密文件保存为D:\e.txt,密码为123)
问题2:在VC6.0编译环境下,在确保程序没有错误的情况下会碰到各种编译问题,例如缺少链接库,类型为定义等问题,主要问题在于VC6.0的编译器采用的标准太旧导致CryptAPI编译出错,因此在运行CryptAPI之前,要做好环境的设置。
解决办法:
最好的解决办法就是使用VS2005以上的版本作为自己的编译环境。如若使用VC6.0作为编译环境,则需要做如下工作;
1、首先需要Crypt32.lib,将它加到project->setting->link下面,当然你也可以在程序中用#pragma comment (lib, "crypt32.lib")加入。
2、在程序开头,你要加入两个头文件 windows.h 和 wincrypt.h,和一个#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
注意添加<windows.h>一定要在<wincrypt.h>之前,因为在<wincrypt.h>编译的过程中大量的引用了<windows.h>
当包含wincrypt.h头文件时,一般都需要定义#define _WIN32_WINNT 0xxx(具体的值),否则将得到如下错误:error C2065: undeclared identifier,不同的操作系统会有不同定义,我的操作环境 VC6.0 + win XP 设置为 #define _WIN32_WINNT 0400。从网上搜集的具体操作系统对应关系如下:
- <span style="font-family: 'Microsoft YaHei'; "><span style="font-size:18px;">Windows Server 2003 family: _WIN32_WINNT>=0x0502 WINVER>=0x0502
- Windows XP: _WIN32_WINNT>=0x0501 WINVER>=0x0501
- Windows 2000: _WIN32_WINNT>=0x0500 WINVER>=0x0500
- Windows NT 4.0: _WIN32_WINNT>=0x0400 WINVER>=0x0400
- Windows Me: _WIN32_WINDOWS=0x0500 WINVER>=0x0500
- Windows 98: _WIN32_WINDOWS>=0x0410 WINVER>=0x0410
- Windows 95: _WIN32_WINDOWS>=0x0400 WINVER>=0x0400
- Internet Explorer 6.0: _WIN32_IE>=0x0600
- Internet Explorer 5.6: _WIN32_IE>=0x0560
- Internet Explorer 5.01, 5.5: _WIN32_IE>=0x0501
- Internet Explorer 5.0, 5.0a, 5.0b: _WIN32_IE>=0x0500
- Internet Explorer 4.01: _WIN32_IE>=0x0401
- Internet Explorer 4.0: _WIN32_IE>=0x0400
- Internet Explorer 3.0, 3.01, 3.02: _WIN32_IE>=0x0300</span></span>
问题3: 如果使用VS2005作为自己的编译工具,在每个项目调试时会提示:无法找到“XXX.exe”的调试信息。
解决办法:
首先打开菜单 项目->项目属性页
1. 选择 配置属性->链接器->调试->生成调试信息 改为 是
2. 选择 配置属性->C/C++ ->常规->调试信息格式 改为 用于“编辑并继续”的程序数据库(/ZI)
3. 选择 配置属性->C/C++ ->优化->优化 改为 禁用(/Od)
问题4: 在使用USBkey等内嵌CSP的硬件设备时,如何查看所连接电脑是否已经将内嵌CSP注册于本机中?
解决办法:
可以查看注册表
CryptoAPI的配置信息存储在注册表中,包括如下表目:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft \ Cryptography \Defaults
HKEY_CURRENT_USER\ Software \ Microsoft\ Cryptography \Providers
问题05: 调试时出现提示:error LNK2019: 无法解析的外部符号 __imp__CertCloseStore@8,该符号在函数 _main 中被引用。
解决办法:
一般出现lnk2019错误都是库文件没添加造成的。(如何寻找缺失的具体哪个库?可以在MSDN中搜索函数名称,查找到函数相关的库)
可以使用语句“#pragma comment (lib, "XXXX.lib")”
或者
项目--》属性--》配置属性--》链接器--》输入--》附加依赖项。在其中加入所需库文件,同时在“链接器--》常规--》附加库目录”中填入相应库名。
问题06:在调试程序的时候,设置了断点,在启动调试后断点失效,显示为空心断点并由黄色感叹号标注,并给予提示:难以命中断点,原因是编译器或者调试器优化等。
解决办法:
该问题的情况很复杂,可能导致此问题的一个原因为程序的编译为Release,而不是Debug模式,需要将编译模式更改为Debug即可。