安全协议实验报告基于OpenSSL CryptoAPI的数字签名系统设计与实现 李鑫 3277.docx
《安全协议实验报告基于OpenSSL CryptoAPI的数字签名系统设计与实现 李鑫 3277.docx》由会员分享,可在线阅读,更多相关《安全协议实验报告基于OpenSSL CryptoAPI的数字签名系统设计与实现 李鑫 3277.docx(20页珍藏版)》请在冰豆网上搜索。
安全协议实验报告基于OpenSSLCryptoAPI的数字签名系统设计与实现李鑫3277
上海电力学院
安全协议大作业
题目:
基于OpenSSL/CryptoAPI的数字签名系统设计与实现
学号:
20103277学生姓名:
李鑫
院系:
计算机科学与技术学院
专业:
信息安全
班级:
2010251
2013年 12 月 13 日
基于OpenSSL/CryptoAPI的数字签名系统设计与实现
李鑫
(上海电力学院信息安全系,上海市201300)
摘要:
数字签名(又称公钥数字签名、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。
一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
数字签名是非对称密钥加密技术与数字摘要技术的应用。
数字签名了的文件的完整性是很容易验证的(不需要骑缝章,骑缝签名,也不需要笔迹专家),而且数字签名具有不可抵赖性(不需要笔迹专家来验证)。
关键字:
数字签名;签名验证;哈希算法
0引言
1.CryptoAPI简介
CryptoAPI是一组函数,为了完成数学计算,必须具有密码服务提供者模块(CSP)。
Microsoft通过捆绑RSABaseProvider在操作系统级提供一个CSP,使用RSA公司的公钥加密算法,更多的CSP可以根据需要增加到应用中。
事实上,CSP有可能与特殊硬件设备(如智能卡)一起来进行数据加密。
CryptoAPI接口允许简单的函数调用来加密数据,交换公钥,散列一个消息来建立摘要以及生成数字签名。
它还提供高级的管理操作,如从一组可能的CSP中使用一个CSP。
此外,CryptoAPI还为许多高级安全性服务提供了基础,包括用于电子商务的SET,用于加密客户机/服务器消息的PCT,用于在各个平台之间来回传递机密数据和密钥的PFX,代码签名等等。
目前支持CryptoAPI的Windows系统有:
Windows95OSR2、WindowsNTSP3及后续版本、Windows98、Windows2000等。
CryptoAPI的配置信息存储在注册表中,包括如下密钥:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Cryptography\Defaults
HKEY_CURRENT_USER\Software\Microsoft\Cryptography\Providers
2.数据加密原理
CryptoAPI使用两种密钥:
会话密钥与公共/私人密钥对。
会话密钥使用相同的加密和解密密钥,这种算法较快,但必须保证密钥的安全传递。
公共/私人密钥对使用一个公共密钥和一个私人密钥,私人密钥只有专人才能使用,公共密钥可以广泛传播。
如果密钥对中的一个用于加密,另一个一定用于解密。
公共/私人密钥对算法很慢,一般只用于加密小批量数据,例如用于加密会话密钥。
CryptoAPI支持两种基本的编码方法:
流式编码和块编码。
流式编码在明码文本的每一位上创建编码位,速度较快,但安全性较低。
块编码在一个完整的块上(一般为64位)工作,需要使用填充的方法对要编码的数据进行舍入,以组成多个完整的块。
这种算法速度较慢,但更安全。
一、实验原理
基本介绍
简单地说,所谓数字签名就是附加在数据单元上的一些数据,或是对数据单元所作的密码变换。
这种数据或变换允许数据单元的接收者用以确认数据单元的来源和数据单元的完整性并保护数据,防止被人(例如接收者)进行伪造。
它是对电子形式的消息进行签名的一种方法,一个签名消息能在一个通信网络中传输。
基于公钥密码体制和私钥密码体制都可以获得数字签名,主要是基于公钥密码体制的数字签名。
包括普通数字签名和特殊数字签名。
普通数字签名算法有RSA、ElGamal、Fiat-Shamir、Guillou-Quisquarter、Schnorr、Ong-Schnorr-Shamir数字签名算法、Des/DSA,椭圆曲线数字签名算法和有限自动机数字签名算法等。
特殊数字签名有盲签名、代理签名、群签名、不可否认签名、公平盲签名、门限签名、具有消息恢复功能的签名等,它与具体应用环境密切相关。
显然,数字签名的应用涉及到法律问题,美国联邦政府基于有限域上的离散对数问题制定了自己的数字签名标准(DSS)。
主要功能
保证信息传输的完整性、发送者的身份认证、防止交易中的抵赖发生。
数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。
接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用HASH函数对收到的原文产生一个摘要信息,与解密的摘要信息对比。
如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。
数字签名是个加密的过程,数字签名验证是个解密的过程。
签名过程
“发送报文时,发送方用一个哈希函数从报文文本中生成报文摘要,然后用自己的私人密钥对这个摘要进行加密,这个加密后的摘要将作为报文的数字签名和报文一起发送给接收方,接收方首先用与发送方一样的哈希函数从接收到的原始报文中计算出报文摘要,接着再用发送方的公用密钥来对报文附加的数字签名进行解密,如果这两个摘要相同、那么接收方就能确认该数字签名是发送方的。
数字签名有两种功效:
一是能确定消息确实是由发送方签名并发出来的,因为别人假冒不了发送方的签名。
二是数字签名能确定消息的完整性。
因为数字签名的特点是它代表了文件的特征,文件如果发生改变,数字签名的值也将发生变化。
不同的文件将得到不同的数字签名。
一次数字签名涉及到一个哈希函数、发送者的公钥、发送者的私钥。
”
数字签名:
发送方用自己的密钥对报文X进行Encrypt(编码)运算,生成不可读取的密文Dsk,然后将Dsk传送给接收方,接收方为了核实签名,用发送方的公用密钥进行Decrypt(解码)运算,还原报文。
设计流程图
二、实验设备
PC机,WindowsXP,VC++6.0.
三、实验过程
实验流程图
必要的截图
四、实验总结
由于过于复杂的加密算法实现起来非常困难,所以在过去,许多应用程序只能使用非常简单的加密技术,这样做的结果就是加密的数据很容易被人破译。
而使用Microsoft提供的加密应用程序接口(即CryptographyAPI),或称CryptoAPI,可以方便地在应用程序中加入强大的加密功能,而不必考虑基本的算法。
本文将对CryptoAPI及其使用的数据加密原理作一简单的介绍,然后给出了用CryptoAPI编写加密程序的大致步骤,最后以一个文件的加密、解密程序为例演示CryptoAPI的部分功能。
利用了CryptAPI,加密解密功能变得异常简单,只需要调用相关的函数即可,而不用关心具体过程,开发商已经为我们做了相关的内部工作。
用它来实现数字签名,也变得十分便捷,只需要按照微软的要求调用相关的函数就可以了,实验过程中利用了网上的资料和书本的光盘资料。
虽然写程序过程中遇到了各种问题,但是在网上收集资料后都予以解决了。
经过学习,对CryptAPI编程有了一点了解,需要学习的东西还很多。
五、实验源代码:
在VC++6.0下实现基于哈希的数字签名。
声明的头文件和函数:
#include
#include
#include
#include
//函数申明
voidHandleError(char*s);
HCRYPTPROVGetCryptProv();
voidprint(char*s);
变量声明:
//变量申明及初始化
HCRYPTPROVhProv;
//BYTE*pbBuffer=(BYTE*)"Thedatathatistobehashedandsigned.";
//DWORDdwBufferLen=strlen((char*)pbBuffer)+1;
BYTE*pbBuffer;
DWORDdwBufferLen;
HCRYPTHASHhHash;
HCRYPTKEYhKey;
HCRYPTKEYhPubKey;
BYTE*pbKeyBlob;
BYTE*pbSignature;
DWORDdwSigLen;
DWORDdwBlobLen;
CStringstring;
LPTSTRszDescription="TestDataDescription";
初始化代码:
BOOLCMyDlg:
:
OnInitDialog()
{
//TODO:
Addextrainitializationhere
m_edit="我是李鑫,来自2010251班,学号20103277,有事您说话!
";
SetDlgItemText(IDC_EDIT1,m_edit);
GetDlgItem(IDOK2)->EnableWindow(FALSE);
returnTRUE;//returnTRUEunlessyousetthefocustoacontrol
}
添加的代码:
//////////////////////////////////////////////////////////////////////////
voidCMyDlg:
:
OnOK()
{
//TODO:
Addextravalidationhere
string="";
UpdateData(TRUE);
pbBuffer=(BYTE*)m_edit.GetBuffer(m_edit.GetLength());
dwBufferLen=strlen(m_edit);
//-------------------------------------------------------------------
//获取CSP句柄
hProv=GetCryptProv();
//-------------------------------------------------------------------
//获取密钥对,其中的私钥用于创建数字签名,公钥将用于验证签名。
if(CryptGenKey(
hProv,
AT_SIGNATURE,
0,
&hKey))
{
print("签名密钥对已经被获取.\n");
}
else
{
HandleError("创建签名密钥出错.\n");
}
//-------------------------------------------------------------------
//导出密钥对的公钥,确定密钥块数据长度
if(CryptExportKey(
hKey,
NULL,
PUBLICKEYBLOB,
0,
NULL,
&dwBlobLen))
{
print("公钥块的数据长度已经确定.\n");
}
else
{
HandleError("计算密钥数据块长度出错.");
}
//-------------------------------------------------------------------
//分配空间
if(pbKeyBlob=(BYTE*)malloc(dwBlobLen))
{
print("已经为此数据块分配了内存空间.\n");
}
else
{
HandleError("所需内存不够.\n");
}
//-------------------------------------------------------------------
//导出密钥对的公钥
if(CryptExportKey(
hKey,
NULL,
PUBLICKEYBLOB,
0,
pbKeyBlob,
&dwBlobLen))
{
print("公钥块中的数据已经写入到导出块中.\n");
}
else
{
HandleError("ErrorduringCryptExportKey.");
}
//-------------------------------------------------------------------
//创建哈希句柄
if(CryptCreateHash(
hProv,
CALG_MD5,
0,
0,
&hHash))
{
print("哈希句柄已经创建.\n");
}
else
{
HandleError("哈希句柄创建失败.\n");
}
//-------------------------------------------------------------------
//计算输入数据的哈希值
if(CryptHashData(
hHash,
pbBuffer,
dwBufferLen,
0))
{
print("缓冲区中的数据已经进行了哈希处理.\n");
}
else
{
HandleError("计算哈希值时出错.\n");
}
//-------------------------------------------------------------------
//确定签名信息的长度
dwSigLen=0;
if(CryptSignHash(
hHash,
AT_SIGNATURE,
szDescription,
0,
NULL,
&dwSigLen))
{
CStringstr1;
str1.Format("签名信息的长度%d找到.\n",dwSigLen);
string+=str1;
//print("签名信息的长度%d找到.\n",dwSigLen);
}
else
{
HandleError("确定哈希签名的长度时出错.\n");
}
//-------------------------------------------------------------------
//分配空间
if(pbSignature=(BYTE*)malloc(dwSigLen))
{
print("给此签名消息分配了内存空间.\n");
}
else
{
HandleError("签名消息所需内存不够.");
}
//-------------------------------------------------------------------
//对哈希数据进行数字签名
if(CryptSignHash(
hHash,
AT_SIGNATURE,
szDescription,
0,
pbSignature,
&dwSigLen))
{
print("\n对哈希数据已经进行了数字签名.\n");
AfxMessageBox(string);
}
else
{
HandleError("哈希数据进行数字签名失败.\n");
}
//-------------------------------------------------------------------
//销毁哈希句柄
if(hHash)
{
CryptDestroyHash(hHash);
}
CStringstr2;
str2+="哈希句柄已经被销毁.\n这个程序的签名阶段已经完成.\n\n";
AfxMessageBox(str2);
//print("哈希句柄已经被销毁.\n");
//print("这个程序的签名阶段已经完成.\n\n");
GetDlgItem(IDOK2)->EnableWindow(TRUE);
//CDialog:
:
OnOK();
}
//////////////////////////////////////////////////////////////////////////
voidCMyDlg:
:
OnCancel()
{
//TODO:
Addextracleanuphere
CDialog:
:
OnCancel();
}
voidCMyDlg:
:
OnOk2()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
string="";
//-------------------------------------------------------------------
//从密钥块数据中导入公钥到CSP。
if(CryptImportKey(
hProv,
pbKeyBlob,
dwBlobLen,
0,
0,
&hPubKey))
{
print("公钥已经被导入.\n");
}
else
{
HandleError("导入公钥失败.");
}
//-------------------------------------------------------------------
//创建哈希句柄
if(CryptCreateHash(
hProv,
CALG_MD5,
0,
0,
&hHash))
{
print("哈希句柄已经被重新创建.\n");
}
else
{
HandleError("重新创建哈希句柄时出错.\n");
}
//-------------------------------------------------------------------
//计算输入数据的哈希值
if(CryptHashData(
hHash,
pbBuffer,
dwBufferLen,
0))
{
print("新的哈希值已经计算出.\n");
}
else
{
HandleError("计算新的哈希值时出错.\n");
}
//-------------------------------------------------------------------
//验证数字签名
if(CryptVerifySignature(
hHash,
pbSignature,
dwSigLen,
hPubKey,
szDescription,
0))
{
print("\n此数字签名已经被验证.\n");
AfxMessageBox(string);
}
else
{
print("签名未生效!
\n");
AfxMessageBox(string);
}
//-------------------------------------------------------------------
//释放内存
if(pbSignature)
{
free(pbSignature);
}
if(hHash)
{
CryptDestroyHash(hHash);
}
if(hProv)
{
CryptReleaseContext(hProv,0);
}
GetDlgItem(IDOK2)->EnableWindow(FALSE);
}
//获取加密提供者句柄
HCRYPTPROVGetCryptProv()
{
HCRYPTPROVhCryptProv;
//获取加密提供者句柄
if(CryptAcquireContext(
&hCryptProv,
NULL,
MS_DEF_PROV,
PROV_RSA_FULL,
0))
{
print("加密服务提供者句柄获取成功!
\n");
}
else
{
//重新建立一个新的密钥集
if(!
CryptAcquireContext(&hCryptProv,NULL,MS_DEF_PROV,PROV_RSA_FULL,CRYPT_NEWKEYSET))
{
HandleError("重新建立一个新的密钥集出错!
");
}
}
returnhCryptProv;
}
voidHandleError(char*s)
{
CStringstr;
str.Format("程序执行发生错误!
\n%s\n错误代码为:
%x.\n程序终止执行!
\n",s,GetLastError());
AfxMessageBox(str);
exit
(1);
}
voidprint(char*s)
{
string+=s;
}