CRYPTOAPI 例程
概述
随本文提供的CRYPTOAPI 例程是一个“完整”的加密/解密工具。程序能够向默认的CSP中添加与移除用户,使用或不使用密码进行加密与解密文件,签署与验证签名,显示默认CSP的性能。
程序有下列命令行结构。
Usage: Encrypt switch [arguments]
Where switch and optional arguments are one of:
Switch Arguments Description
/A[DDUSER] to add user to CSP table
/R[EMOVEUSER] to remove user from CSP table
/E[NCRYPT] uf ef [pwd] to encrypt a file
/D[ECRYPT] ef uf [pwd] to decrypt a file
/S[IGN] uf sf [desc] to sign a file
/V[ERIFY] uf sf [desc] to verify a signed file
/C[SP] to show CSP statistics
and uf = name of an unencrypted file
ef = name of an encrypted file
sf = name of a signed file
pwd = optional password
desc = optional signature description
编码问题
写作这篇文章时,需要显式地在例程中定义特定的常量,因为加密API头文件(wincrypt.h) 使用 _WIN32_WINNT 常量来检测正在使用哪个Windows NT版本。当我写此例程时,此常量尽管需要,但当前的编译器仍然未定义它。定义此常量代码才不会编译出错,可以在以后的编译器定义它后再将其移除。
API函数 CryptAcquireContext 有一个未文档化的常量值 MS_DEF_PROV。这个常量用来指代默认CSP。这个值用在 /ADDUSER 命令行开关中。这允许程序使用任何已安装的CSP,不需要知道其名字。
增加或者删除一个用户
/ADDUSER 与 /REMOVERUSER 开关用来增加或删除一个默认的加密客户端。为使其它加密功能运行正常,/ADDUSER 开关必须首先被调用。
下面一系列操作会被执行:
一个默认密鈅容器被创建
一个数字签名密鈅对在密鈅容器中被创建
一个密鈅交换密鈅对在密鈅容器中被创建
这项操作仅需执行一次,除非操作系统重装。假如默认的密鈅容器与密鈅对已经创建,那么再次使用这个开关没有效果。
从命令行运行/ADDUSER 开关如下:
Encrypt /ADDUSER
从命令行运行/REMOVEUSER开关如下:
Encrypt /REMOVEUSER
加密或解密文件
/ENCRYPT 开关用来加密文件。通过这个开关加密的文件以后可以通过 /DECRYPT 开关解密。
注意:为了给默认用户创建一个密鈅容器,必须在进行任何加密前调用/ADDUSER 开关。
从命令行运行/ENCRYPT开关如下:
Encrypt /encrypt <source file> <destination file> [ <password> ]
<source file> 参数指定要加密的明文文件文件名, <destination file>参数指定要创建的加密文件文件名。可选参数 <password>指定一个要加密文件的密码。如果未指定密码,使用一个随机的会话密鈅加密这个文件。会话密鈅然后使用默认用户的交换密鈅公鈅加密后随加密的文件一同保存。在此情况下,相应的密鈅交换私鈅用来解密(用/DECRYPT)会话密鈅,然后用此会话密鈅解密此文件。
从命令行运行/DECRYPT开关如下:
Encrypt /decrypt <source file> <destination file> [ <password> ]
<source file> 参数指定要解密的密文文件文件名,<destination file>参数指定要创建的明文文件文件名。可选参数 <password>指定一个要解密文件的密码。要是向/DECRYPT开关提供一个假密码,不会产生错误。这对安全性起着重要作用,因为这样对某些人来说就没有办法“中断”数据来知道是否他们正在这样做。只有数据的合法接收者才能解密,并且确实知道解密成功。
对文件签名并且验证
/SIGN 开关用于签名文件。通过这个开关签名的文件以后可以通过/VERIFY开关验证。
注意:为了给默认用户创建一个密鈅容器,必须在进行任何加密前调用/ADDUSER 开关。
从命令行运行/SIGN开关如下:
Encrypt /sign <source file> <signature file> <description>
<source file> 参数指定要签名的文件名,<signature file> 参数指定要放置签名数据的文件名。 <description> 参数指定一个对签名数据的文本描述。假如不需要指定描述,此参数可为空引用(””)。参阅联机文档对 CryptSignHash 的说明以获得更多关于签名与描述字符的信息。(译注:description参数在MSDN文档中不被建议使用)
/VERIFY 开关与 /SIGN使用一样的参数。假如源文件内容,签名文件,或描述字符串从文件签名以来改变了,将报告一个错误。
显示 CSP的统计信息
/CSP 开关列出被默认PROV_RSA_FULL提供者支持的算法。默认时是Microsoft RSA Base Provider,它已包含在操作系统中。
注意:为了给默认用户创建一个密鈅容器,必须在进行任何加密前调用/ADDUSER 开关。
从命令行运行/CSP开关如下:
Encrypt /csp
另外为了列出每个被支持的算法的名字,这个开关还列出:
算法的类型(加密,散列,密鈅交换,签名)
算法所使用的密鈅长度 (对散列算法是散列出的散列值的位数)
算法的算法标志符。为了使用特定的算法来创建密鈅或者散列,可以将这个值传给适当的加密API函数。
结论
本文向你展示了如何加密与解密文件,如何对文件进行签名与验证。加密API也可以用来实现提供一个安全环境。鉴于微软在API中提供的强大安全性能,我强烈建议你在安全消息上使用它,但不要忘记了加密你数据的密码啊。如果忘了,那么就没办法找回来了。在以后的文章中,我会向你展示如何加密数据,在互联网上或者以其它传输方式公开传输。到那时,乐享“keeping a secret!”吧。
译注:下载的例程中需要修改与错误之处在下面标出,我的环境VC6 sp5+WinXP专业版
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、运行程序,并使用各个开关查看运行结果