分享
 
 
 

用CryptoAPI进行数据加密

王朝vc·作者佚名  2006-01-08
窄屏简体版  字體: |||超大  

VCKBASE Online Help Journal No.10

用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的体系结构如下图:

---- 目前支持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.数据加密原理

---- 数据加密的流程如下图:

---- CryptoAPI使用两种密钥:会话密钥与公共/私人密钥对。会话密钥使用相同的加密和解密密钥,这种算法较快,但必须保证密钥的安全传递。公共/私人密钥对使用一个公共密钥和一个私人密钥,私人密钥只有专人才能使用,公共密钥可以广泛传播。如果密钥对中的一个用于加密,另一个一定用于解密。公共/私人密钥对算法很慢,一般只用于加密小批数据,例如用于加密会话密钥。

---- CryptoAPI支持两种基本的编码方法:流式编码和块编码。流式编码在明码文本的每一位上创建编码位,速度较快,但安全性较低。块编码在一个完整的块上(一般为64位)上工作,需要使用填充的方法对要编码的数据进行舍入,以组成多个完整的块。这种算法速度较慢,但更安全。

---- 3.应用举例

---- 下面以两个文件加密与解密的C程序片断为例,演示一下CryptoAPI的强大功能。这两个程序均为Win32控制台应用,程序省略了出错处理,实际运行时请加入。

---- ①文件加密 #include < windows.h >

#include < stdio.h >

#include < stdlib.h >

#include < wincrypt.h >

//确定使用RC2块编码或是RC4流式编码

#ifdef USE_BLOCK_CIPHER

#define ENCRYPT_ALGORITHMCALG_RC2

#define ENCRYPT_BLOCK_SIZE8

#else

#define ENCRYPT_ALGORITHMCALG_RC4

#define ENCRYPT_BLOCK_SIZE1

#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");

……//关闭文件、释放内存

}

②文件解密

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)) == NULL);

// 从源文件中读隐码.

fread(pbKeyBlob, 1, dwKeyBlobLen, hSource);

// 将隐码输入CSP

CryptImportKey(hProv, pbKeyBlob,

dwKeyBlobLen, 0, 0, &hKey);

} 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;

}

dwBlockLen = 1000 - 1000 % ENCRYPT_BLOCK_SIZE;

if(ENCRYPT_BLOCK_SIZE > 1) {

dwBufferLen = dwBlockLen + ENCRYPT_BLOCK_SIZE;

} else {

dwBufferLen = dwBlockLen;

}

pbBuffer = malloc(dwBufferLen);

//解密源文件并写入目标文件

do {

dwCount = fread(pbBuffer, 1, dwBlockLen, hSource);

eof = feof(hSource);

// 解密数据

CryptDecrypt(hKey, 0, eof, 0, pbBuffer, &dwCount);

// 将解密过的数据写入目标文件

fwrite(pbBuffer, 1, dwCount, hDestination);

} while(!feof(hSource));

printf("OK\n");

……//关闭文件、释放内存

}

---- 以上代码在Windows NT4.0、Visual C++6.0环境中编译通过。

---- 除直接用于加密数据外,CryptoAPI还广泛用于产生并确认数字签名,这里就不一一举例说明了,有兴趣的读者可以参考MSDN文档。

©1997-2000 VCKBASE.COM All Rights Reserved.

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有