完整word版基于CryptoAPI的文件加解密系统的设计与实现.docx
《完整word版基于CryptoAPI的文件加解密系统的设计与实现.docx》由会员分享,可在线阅读,更多相关《完整word版基于CryptoAPI的文件加解密系统的设计与实现.docx(37页珍藏版)》请在冰豆网上搜索。
完整word版基于CryptoAPI的文件加解密系统的设计与实现
基于CryptoAPI的文件加解密系统的设计与实现
摘要:
随着网络技术的快速发展,使我们的生活丰富多彩,工作的效率也提高了不少.尽管网络的出现给我们带来了很多的福利和方便,但网络安全问题也在时时困扰着我们,病毒、黑客的侵犯,各种威胁之声的不断传出,网络安全问题也就成为了社会关注的重点问题.文件的安全就是安全问题之一,文件可能会包含了很多的机密,一旦被黑客窃取,那损失是不可想象的。
所以下面我们简单的谈谈文件加解密的相关算法。
因为过于复杂的加密算法实现起来非常困难,所以在过去,许多应用程序只能使用非常简单的加密技术,这样做的结果就是加密的数据很容易就可以被人破译。
而使用Microsoft提供的加密应用程序接口(即CryptographyAPI),或称CryptoAPI,就可以方便地在应用程序中加入强大的加密功能,而不必考虑基本的算法。
我们利用CryptoAPI来实现对文件的加密和解密。
关键词:
文件的加解密,CryptoAPI。
一、设计要求与实现:
基于CryptoAPI的文件加解密系统的设计与实现
二、设计环境与工具
1软件环境、工具
Windows8。
1、visualstudio2012
2CryptoAPI加密服务提供者CSP
加密服务相关的所有操作都在CSP实现,它是真正实现加密相关服务的独立模块,既可以由软件实现也可以由硬件实现。
每个CSP必须包含一个动态链接库和一个签名文件,签名文件用于保证底层CSP的安全性,CryptoAPI接口在加载每个CSP时,需要验证CSP的签名,如果签名无效,则拒绝加载,CSP的签名由微软公司签发。
同时,每个CSP都有一个名字和一个类型,名字必须是唯一的,这样便于CryptoAPI找到对应的CSP.
CSP是真正实行加密的独立模块,可以由软件实现也可以由硬件实现.CSP必须符合CryptoAPI接口规范。
每个CSP有一个密钥库,密钥库用于存储密钥。
每个密钥库包括一个或多个密钥容器(KeyContainers).每个密钥容器中包含属于一个特定用户的所有密钥对。
每个密钥容器被赋予一个唯一的名字。
在销毁密钥容器前,CSP将永久保存每一个密钥容器,包括保存每个密钥容器中的公/私钥对。
每个CSP都有一个名字和一个类型。
每个CSP的名字是唯一的,这样便于CryptoAPI找到对应的CSP.目前已经有9种CSP类型,并且还在增长.下表列出它们支持的密钥交换算法、签名算法、对称加密算法和Hash算法。
二、详细设计
(1)原理概述
CryptoAPI是一组函数,为了完成数学计算,必须具有密码服务提供者模块(CSP)。
Microsoft通过捆绑RSABaseProvider在操作系统级提供一个CSP,使用RSA公司的公钥加密算法,更多的CSP可以根据需要增加到应用中。
事实上,CSP有可能与特殊硬件设备(如智能卡)一起来进行数据加密。
CryptoAPI接口允许简单的函数调用来加密数据,交换公钥,散列一个消息来建立摘要以及生成数字签名。
它还提供高级的管理操作,如从一组可能的CSP中使用一个CSP。
此外,CryptoAPI还为许多高级安全性服务提供了基础,包括用于电子商务的SET,用于加密客户机/服务器消息的PCT,用于在各个平台之间来回传递机密数据和密钥的PFX,代码签名等等。
数据加解密,程序分为四大主要部分:
1、获取CSP句柄:
真正实现加密相关服务的独立模块.
2、获取加密密钥:
进行加、解密,必然需要构造密钥。
两种方法:
通过哈希值构造通过随机数构造。
3、数据加密与解密:
实现对数据进行加密解密操作。
4、相关资源释放:
释放申请的相关资源.
(下图为数据加解密的流程)
(参考《网络安全程序设计教程》李红娇 著)
(2)CryptoAPI应用程序的编译环境
⑴包含的头文件
#includeh>
#include〈wincrypt.h>
⑵包含的静态链接库
链接CryptoAPI函数必须有静态库Crypto32.lib的支持,部分CryptoAPI函数可能还需要静态库advapi32。
lib及CryptUI。
lib的支持。
⑶若在VC++6。
0和VS2012上编译程序,则需加上以下语句
#ifndef_WIN32_WINNT
#define_WIN32_WINNT0x0400
#endif
(3)实验步骤
1) 在VS2012下实现基于CryptoAPI的文件加密。
a、创建会话密钥
为保证数据加密效率,CryptoAPI规定数据加密操作必须基于对称密码进行。
于是,加密方进行加密操作首先必须创建会话密钥,一般可以通过调用函数CryptoGenKey或CryptDeriveKey创建,在创建会话密钥时指定加密算法。
b、加密数据
在创建会话密钥后,则可以调用CryptEncrypt函数进行加密操作。
加密操作需要注意的是每次加密数据块的长度必须根据具体的算法和算法类型确定,一般来说,加密数据块长度为算法规定的基准加密块长度的整数倍.对于分组密码,需为密文数据块预留一个基准块长度的空间。
c、安全保存或交换会话密钥
数据加密完成后,当在今后的某个时间或其他用户需要解密数据时,必须保存会话密钥以备后用,或者是传输会话密钥给特定用户以使其能正确进行解密操作.
2) 在VS2012下实现基于CryptoAPI的文件解密。
a、获取会话密钥
根据保存或传输会话密钥方式不同,进行相应的操作正确获取会话密钥
b、解密数据
利用获取的会话密钥调用函数CryptDecrypt解密数据,它和函数CryptEncrypt互为逆操作.同样的,解密操作需要注意的是每次解密数据块的长度必须根据具体的算法和算法类型确定,一般来说,解密数据块长度为算法基准加密块长度的整数倍。
要求:
1) 算法的详细实现过程。
a) 获得csp句柄
b) 构造密钥
c) 数据加密
d) 数据解密
e) 释放相关资源
2) 算法实现的流程图
三、实验结果
原文件
加密后
解密后
PS:
我们在加密的时候,没有采用通过随机数创建密钥,然后只能通过输入密码创建加密密钥。
截图:
未加密
四、设计总结
由于多方尝试并编写Openssl对文件的加解密方法,均以失败告终,所以我们小组决定采用新的加密算法,即WindowsCryptoAPI,由微软公司提出的一种安全加密应用服务框架。
本次试验的主要内容是基于CryptoAPI的文件加解密系统的设计与实现,在仔细看懂代码的基础上,真正明白了CryptoAPI的结构体系。
在加密操作时,首先要创建会话密钥,在创建会话密钥时指定加密算法,注意的是,创建会话密钥时,它制定具体的加密算法应该注意具体的CSP是否支持此算法。
我们在做加密的时候,没有加入通过随机数创建会话密钥,只能进行输入密码创建加密密钥。
然后是进行数据的加密操作,当完成以后要进行安全保存或者交换会话密钥。
解密时要获取会话密钥,然后进行数据解密。
CryptoAPI除直接用于加密数据外,还为许多高级安全性服务提供了基础,包括用于电子商务的SET,用于加密客户机/服务器消息的PCT,用于在各个平台之间来回传递机密数据和密钥的PFX,代码签名等等.通过此次编写程序,我对基于CryptoAPI的文件加解密系统有了更深层次的了解,对之前做过的基于CryptoAPI实现文件完整性校验的实验理解的更加透彻.
在编写程序的过程中,遇到了很多棘手的问题,但是这些问题,我通过了找老师,上网查询问题出错的原因等方法努力的寻求答案,到现在为止,程序已经顺利完成,运行无阻。
自己根据要求,从零开始做一份实验真的不容易,需要对整体结构局势进行把握,在做之前要做好多重准备工作,例如运行环境(软、硬件环境)、输入的形式和输入值的范围、输出的形式描述、功能描述。
细节决定成败,对于我而言,这次的作业让我清楚认识到,注重细节的重要性,有时候一个字母的大小写,几个变量的数据类型的统一性,考虑后选择的更为合适的数据类型,重复执行的问题等等,这些都让我不断进步.
五、源代码
加密:
#ifndef_WIN32_WINNT
#define_WIN32_WINNT0x0400
#endif
#include#include〈string。
h>
#include〈iostream〉
#include〈conio.h>
#include〈windows。
h〉
#include
#defineMY_ENCODING_TYPE(PKCS_7_ASN_ENCODING|X509_ASN_ENCODING)
#defineKEYLENGTH0x00800000
#defineENCRYPT_ALGORITHMCALG_RC4
#defineENCRYPT_BLOCK_SIZE8
classEnc{
public:
HCRYPTPROVGetCryptProv();
BOOLEncryptFile(
PCHARszSource,
PCHARszDestination,
PCHARszPassword);
HCRYPTKEYGenKeyByPassword(HCRYPTPROVhCryptProv,PCHARszPassword);
};
#include#include"Enc。
h"
usingnamespacestd;
//功能:
加密原文szSource文件,加密后的数据存储在szDestination文件中
//参数:
//szSource:
原文文件名
//szDestination:
加密后数据存储文件
//szPassword:
用户输入的密码
BOOLEnc:
:
EncryptFile(
PCHARszSource,
PCHARszDestination,
PCHARszPassword)
{
//变量申明与初始化。
FILE*hSource;
FILE*hDestination;
HCRYPTPROVhCryptProv;
HCRYPTKEYhKey;
PBYTEpbBuffer;
DWORDdwBlockLen;
DWORDdwBufferLen;
DWORDdwCount;
//打开原文文件。
if(hSource=fopen(szSource,"rb”))
{
cout<<”原文文件”〈〈szSource〈〈”已经打开。
\n”;
}
else
{
cout〈<"打开原文文件出错!
”〈〈endl;
}
//打开目标文件。
if(hDestination=fopen(szDestination,"wb"))
{
cout〈〈"目标文件”<\n"〈}
else
{
cout〈<”打开目标文件出错!
"<}
//获取加密服务者句柄
hCryptProv=GetCryptProv();
//创建会话密钥。
if(!
szPassword||strcmp(szPassword,"”)==0)
{
//hKey=GenKeyByRandom(hCryptProv,hDestination);当输入密码为空时,则创建随机的加密密钥,并导出创建的密钥保存到文件中.
cout〈〈”你输入的密钥为空!
请正确输入!
”<〈endl;
}
else
{
//当输入密码不为空时,则通过输入密码创建加密密钥
hKey=GenKeyByPassword(hCryptProv,szPassword);
}
//因为加密算法按ENCRYPT_BLOCK_SIZE大小块加密,所以被加密的
//数据长度必须是ENCRYPT_BLOCK_SIZE的整数倍。
下面计算一次加密的
//数据长度。
dwBlockLen=1000-1000%ENCRYPT_BLOCK_SIZE;
//确定加密后密文数据块大小。
若是分组密码模式,则必须有容纳额外块的空间
if(ENCRYPT_BLOCK_SIZE>1)
dwBufferLen=dwBlockLen+ENCRYPT_BLOCK_SIZE;
else
dwBufferLen=dwBlockLen;
//分配内存空间.
if(pbBuffer=(BYTE*)malloc(dwBufferLen))
{
cout<<”已经为缓冲区分配了内存.\n";
}
else
{
cout〈<”所需内存不够。
\n";
}
//循环加密原文件
do
{
//每次从原文件中读取dwBlockLen字节数据.
dwCount=fread(pbBuffer,1,dwBlockLen,hSource);
if(ferror(hSource))
{
cout〈<”读取明文文件出错!
\n”;
}
//—-----———---—-———-—-—-—-—---—--—-——----——-——-—---——---————-—---————
//加密数据。
if(!
CryptEncrypt(
hKey,//密钥
0,//如果数据同时进行散列和加密,这里传入一个散列对象
feof(hSource),//如果是最后一个被加密的块,输入TRUE。
如果不是输入FALSE.
//这里通过判断是否到文件尾来决定是否为最后一块。
0,//保留
pbBuffer,//输入被加密数据,输出加密后的数据
&dwCount,//输入被加密数据实际长度,输出加密后数据长度
dwBufferLen))//pbBuffer的大小.
{
cout〈〈"加密数据时出错。
\n";
}
//——————--——-————--—--—--—-—-—-—--———————-——---—-——-—--—---——----—---
//把加密后数据写到密文文件中
fwrite(pbBuffer,1,dwCount,hDestination);
if(ferror(hDestination))
{
cout<〈"写入密文时出错。
";
}
}while(!
feof(hSource));
//---——-—-----—-—--—---———--—------————--——--—--—-—---——-——-——-----——
//关闭文件
if(hSource)
{
if(fclose(hSource))
cout〈〈”关闭原文文件出错!
";
}
if(hDestination)
{
if(fclose(hDestination))
cout〈〈"关闭目标文件出错!
”;
}
//—-—-—-—--—---—----—-—————————-——-—-———-———-——-———-——---——-——-—-----
//释放内存空间.
if(pbBuffer)
free(pbBuffer);
//-——-—-—-—-—-——---—---———-——----—-—-—-——-—--—————-—-—--—-—-———-——-——
//销毁会话密钥
if(hKey)
{
if(!
(CryptDestroyKey(hKey)))
cout<〈"销毁会话密钥时出错”<}
//----—-——--——-—--—-——-——---——--—-—--——-—-—-—------————---——-——-——-——
//释放CSP句柄
if(hCryptProv)
{
if(!
(CryptReleaseContext(hCryptProv,0)))
cout〈<”释放CSP句柄时出错”<〈endl;
}
return(TRUE);
}//endEncryptfile
//获取加密提供者句柄
HCRYPTPROVEnc:
:
GetCryptProv()
{
HCRYPTPROVhCryptProv;//加密服务提供者句柄
//获取加密提供者句柄
if(CryptAcquireContext(
&hCryptProv,//加密服务提供者句柄
NULL,//密钥容器名,这里使用登陆用户名
MS_ENHANCED_PROV,//加密服务提供者
PROV_RSA_FULL,//加密服务提供者类型,可以提供加密和签名等功能
0))//标志
{
cout<<"加密服务提供者句柄获取成功!
\n”;
}
else
{
//重新建立一个新的密钥集
if(!
CryptAcquireContext(&hCryptProv,NULL,MS_ENHANCED_PROV,PROV_RSA_FULL,CRYPT_NEWKEYSET))
{
cout〈<"重新建立一个新的密钥集出错!
”;
}
}
returnhCryptProv;
}
//GenKeyByRandom:
通过输入密码创建会话密钥
//参数:
hCryptProvCSP句柄
//szPassword输入密码
HCRYPTKEYEnc:
:
GenKeyByPassword(HCRYPTPROVhCryptProv,PCHARszPassword)
{
HCRYPTKEYhKey;
HCRYPTHASHhHash;
//--——-——------——-———-———————--—--—————-———---——---—---—---——-—--—-——
//创建哈希句柄.
if(CryptCreateHash(
hCryptProv,
CALG_MD5,
0,
0,
&hHash))
{
cout〈〈"一个哈希句柄已经被创建.\n";
}
else
{
cout〈<”ErrorduringCryptCreateHash!
\n";
}
//--—--—-—-—————--—-——-—--———-——--—-—---—-——————--—--———-——--—--——-—-
//计算输入密码的哈希值。
if(CryptHashData(
hHash,
(BYTE*)szPassword,
strlen(szPassword),
0))
{
cout<<”密码已经被添加到了哈希表中.\n”;
}
else
{
cout〈<"计算输入密码的哈希值时出错.\n”;
}
//——-———-—-——-—-———--———-—-—---—-—————--—-—-—-——--———-—-—----——-——-—-
//通过哈希值创建会话密钥。
if(CryptDeriveKey(
hCryptProv,
ENCRYPT_ALGORITHM,
hHash,
KEYLENGTH,
&hKey))
{
cout〈<”通过密码的哈希值获得了加密密钥。
\n”;
}
else
{
cout〈〈”ErrorduringCryptDeriveKey!
\n";
}
//-—————-———-——-—-------------——-—--—---——-—---—-——--—-------—-—---—-
//销毁哈希句柄。
if(hHash)
{
if(!
(CryptDestroyHash(hHash)))
cout〈<”ErrorduringCryptDestroyHash"〈〈endl;
hHash=0;
}
//返回创建的会话密钥
returnhKey;
}
解密:
#ifndef_WIN32_WINNT
#define_WIN32_WINNT0x0400
#endif
#include#include〈string。
h〉
#includeh〉
#include〈windows.h>
#includeh>
#include#defineMY_ENCODING_TYPE(PKCS_7_ASN_ENCODING|X509_ASN_ENCODING)
#defineKEYLENGTH0x00800000
#defineENCRYPT_ALGORITHMCALG_RC4
#defineENCRYPT_BLOCK_SIZE8
classDec{//加密文件的方法
public:
HCRYPTPROVGetCryptProv();//方法的原型
BOOLDecryptFile(
PCHARszSource,
PCHARszDestination,
CHAR*szPassword);
HCRYPTKEYGenKeyByPassword(HCRYPTPROVhCryptProv,PCHARszPassword);//通过输入口令创建会话密钥,我们的密码
HCRYPTKEYGenKeyFromFile(HCRYPTPROVhCryptProv,FILE*hSource);
};
#ifndef_WIN32_WINNT
#define_WIN32_WINNT0x0400
#endif
#includeh>
#includeh>
#include〈conio。
h>
#include〈windows.h〉
#include〈wincrypt。
h>
#include〈iostream>
#defineMY_ENCODING_TYPE(PKCS_7_ASN_ENCODING|X509_ASN_ENCODING)
#defineKEYLENGTH0x00800000
#defineENCRYPT_ALGORITHMCALG_RC4
#defineENCRYPT_BLOCK_SIZE8
#include〈iostream〉
#include”Dec。
h”
usingnamespacestd;
/*
功能:
解密密文