当前位置:编程学习 > VC++ >>

vc++网络安全编程范例(21)用CryptoAPI进行数据加密

 由于过于复杂的加密算法实现起来非常困难,所以在过去,许多应用程序只能使用非常简单的加密技术,这样做的结果就是加密的数据很容易被人破译。而使用Microsoft提供的加密应用程序接口(即Cryptography API),或称CryptoAPI,可以方便地在应用程序中加入强大的加密功能,而不必考虑基本的算法。本文将对CryptoAPI及其使用的数据加密原理作一简单的介绍,然后给出了用CryptoAPI编写加密程序的大致步骤,最后以一个文件的加密、解密程序为例演示CryptoAPI的部分功能。
 
1. CryptoAPI简介
 
CryptoAPI是一组函数,为了完成数学计算,必须具有密码服务提供者模块(CSP)。Microsoft通过捆绑RSA Base Provider在操作系统级提供一个CSP,使用RSA公司的公钥加密算法,更多的CSP可以根据需要增加到应用中。事实上,CSP有可能与特殊硬件设备(如智能卡)一起来进行数据加密。CryptoAPI接口允许简单的函数调用来加密数据,交换公钥,散列一个消息来建立摘要以及生成数字签名。它还提供高级的管理操作,如从一组可能的CSP中使用一个CSP。此外,CryptoAPI还为许多高级安全性服务提供了基础,包括用于电子商务的SET,用于加密客户机/服务器消息的PCT,用于在各个平台之间来回传递机密数据和密钥的PFX,代码签名等等。CryptoAPI的体系结构如图1。图1 CryptoAPI体系结构
 
目前支持CryptoAPI的Windows系统有:Windows 95 OSR2、Windows NT SP3及后续版本、Windows 98、Windows 2000等。CryptoAPI的配置信息存储在注册表中,包括如下密钥:
 
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft \ Cryptography \Defaults
 
HKEY_CURRENT_USER\ Software \ Microsoft \ Cryptography \Providers
 
2. 数据加密原理
 
数据加密流程如图2所示。
 
图2 数据加密流程
 
CryptoAPI使用两种密钥:会话密钥与公共/私人密钥对。会话密钥使用相同的加密和解密密钥,这种算法较快,但必须保证密钥的安全传递。公共/私人密钥对使用一个公共密钥和一个私人密钥,私人密钥只有专人才能使用,公共密钥可以广泛传播。如果密钥对中的一个用于加密,另一个一定用于解密。公共/私人密钥对算法很慢,一般只用于加密小批量数据,例如用于加密会话密钥。
 
CryptoAPI支持两种基本的编码方法:流式编码和块编码。流式编码在明码文本的每一位上创建编码位,速度较快,但安全性较低。块编码在一个完整的块上(一般为64位)工作,需要使用填充的方法对要编码的数据进行舍入,以组成多个完整的块。这种算法速度较慢,但更安全。
 
3. 应用举例
 
下面以两个文件加密与解密的C程序片断为例,演示一下CryptoAPI的强大功能。这两个程序均为Win32控制台应用,程序省略了出错处理,实际运行时请加入。
 
1 文件加密
 
#include <windows.h>
 
#include <stdio.h>
 
#include <stdlib.h>
 
#include <wincrypt.h>
 
//确定使用RC2块编码或是RC4流式编码
 
#ifdef USE_BLOCK_CIPHER
 
#define ENCRYPT_ALGORITHM CALG_RC2
 
#define ENCRYPT_BLOCK_SIZE 8
 
#else
 
#define ENCRYPT_ALGORITHM CALG_RC4
 
#define ENCRYPT_BLOCK_SIZE 1
 
#endif
 
void CAPIDecryptFile(PCHAR szSource, PCHAR szDestination, PCHAR szPassword);
 
void _cdecl main(int argc, char *argv[])
 
{
 
PCHAR szSource = NULL;
 
PCHAR szDestination = NULL;
 
PCHAR szPassword = NULL;
 
// 验证参数个数
 
if(argc != 3 && argc != 4) {
 
printf("USAGE: decrypt <source file> <dest file> [ <password> ]\n");
 
exit(1);
 
}
 
//读取参数.
 
szSource = argv[1];
 
szDestination = argv[2];
 
if(argc == 4) {
 
szPassword = argv[3];
 
}
 
CAPIDecryptFile(szSource, szDestination, szPassword);
 
}
 
/*szSource为要加密的文件名称,szDestination为加密过的文件名称,szPassword为加密口令*/
 
void CAPIEncryptFile(PCHAR szSource, PCHAR szDestination, PCHAR szPassword){
 
FILE *hSource = NULL;
 
FILE *hDestination = NULL;
 
INT eof = 0;
 
HCRYPTPROV hProv = 0;
 
HCRYPTKEY hKey = 0;
 
HCRYPTKEY hXchgKey = 0;
 
HCRYPTHASH hHash = 0;
 
PBYTE pbKeyBlob = NULL;
 
DWORD dwKeyBlobLen;
 
PBYTE pbBuffer = NULL;
 
DWORD dwBlockLen;
 
DWORD dwBufferLen;
 
DWORD dwCount;
 
hSource= fopen(szSource,"rb"));// 打开源文件
 
hDestination = fopen(szDestination,"wb") ;//.打开目标文件
 
// 连接缺省的CSP
 
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0));
 
if(szPassword == NULL) {
 
//口令为空,使用随机产生的会话密钥加密
 
// 产生随机会话密钥。
 
CryptGenKey(hProv, ENCRYPT_ALGORITHM, CRYPT_EXPORTABLE, &hKey)
 
// 取得密钥交换对的公共密钥
 
CryptGetUserKey(hProv, AT_KEYEXCHANGE, &hXchgKey);
 
// 计算隐码长度并分配缓冲区
 
CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, NULL, &dwKeyBlobLen);
 
pbKeyBlob=malloc(dwKeyBlobLen)) == NULL) ;
 
// 将会话密钥输出至隐码
 
CryptExportKey(hKey, hXchgKey, SIMPLEBLOB, 0, pbKeyBlob, &dwKeyBlobLen))
 
// 释放密钥交换对的句柄
 
CryptDestroyKey(hXchgKey);
 
hXchgKey = 0;
 
// 将隐码长度写入目标文件
 
fwrite(&dwKeyBlobLen, sizeof(DWORD), 1, hDestination);
 
//将隐码长度写入目标文件
 
fwrite(pbKeyBlob,1,dwKeyBlobLen, hDestination);
 
} else {
 
//口令不为空, 使用从口令派生出的密钥加密文件
 
CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash);// 建立散列表
 
CryptHashData(hHash, szPassword,
 
strlen(szPassword), 0); //散列口令
 
// 从散列表中派生密钥
 
CryptDeriveKey(hProv, ENCRYPT_ALGORITHM, hHash, 0, &hKey);
 
// 删除散列表
 
CryptDestroyHash(hHash);
 
hHash = 0;
 
}
 
//计算一次加密的数据字节数,必须为ENCRYPT_BLOCK_SIZE的整数倍dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;
 
//如果使用块编码,则需要额外空间
 
if(ENCRYPT_BLOCK_SIZE > 1) {
 
dwBufferLen=dwBlockLen + ENCRYPT_BLOCK_SIZE;
 
} else {
 
dwBufferLen = dwBlockLen;
 
}
 
//分配缓冲区
 
pbBuffer = malloc(dwBufferLen);
 
//加密源文件并写入目标文件
 
do {
 
// 从源文件中读出dwBlockLen个字节
 
dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);
 
eof = feof(hSource);
 
//加密数据
 
CryptEncrypt(hKey, 0, eof, 0, pbBuffer, &dwCount, dwBufferLen);
 
// 将加密过的数据写入目标文件
 
fwrite(pbBuffer, 1, dwCount, hDestination);
 
} while(!feof(hSource));
 
printf("OK\n");
 
......//关闭文件、释放内存
 
}
 
2 文件解密
 
void CAPIDecryptFile(PCHAR szSource, PCHAR szDestination, PCHAR szPassword)
 
{
 
......//变量声明、文件操作同文件加密程序
 
CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, 0);
 
if(szPassword == NULL) {
 
// 口令为空,使用存储在加密文件中的会话密钥解密
 
// 读隐码的长度并分配内存
 
fread(&dwKeyBlobLen,sizeof(DWORD),1,hSource);
 
pbKeyBlob=malloc(dwKeyBlobLen))== N
补充:综合编程 , 安全编程 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,