C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统

基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)

大家好,今天给大家介绍基于C#+asp.net+C++的RSA文件加密系统设计与实现,文章末尾附有本毕业设计的论文和源码下载地址哦。需要下载开题报告PPT模板及论文答辩PPT模板等的小伙伴,可以进入我的博客主页查看左侧最下面栏目中的自助下载方法哦

文章目录:

  • 基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)
    • 1、项目简介
    • 2、资源详情
    • 3、关键词:
    • 4、毕设简介
    • 5、资源下载

1、项目简介

  1. 本文设计的是一套完整实用的RSA文件加密解决方案,并具体编码实现。本文采用费马小定理测试素数,使用Montgomery加快大数模乘运算,用C++实现RSA加密算法类库,并在32位windows平台封装成组件。在.Net平台引用此组件,实现可以对任意文件进行RSA加密操作的窗体应用程序。经过加密的文件以及密钥文件都是文本文件。本文首先给出关键类类图、整个应用程序的结构描述文档,然后对关键模块流程图、详细的接口文档进行阐述,并给出关键的实现代码,最后对应用程序进行测试,对测试结果进行分析研究,进而对应用程序进行改进,对关键算法进行尽可能的优化,最终得到一个在windows运行的可以用指定密钥对任意文件进行RSA加密并可解密的完整应用程序,和一些相关的可移植组件。

2、资源详情

项目难度:中等难度
适用场景:相关题目的毕业设计
配套论文字数:13898个字37页
包含内容:整套源码+完整毕业论文


3、关键词:

RSA;文件加密;Montgomery;费马定理

4、毕设简介

提示:以下为毕业论文的简略介绍,项目源码及完整毕业论文下载地址见文末。

引言
1.1课题背景
RSA公钥加密算法是第一个既能用于数据加密也能用于数字签名的算法。它易于理解和操作,也十分流行。算法的名字以发明者的姓氏首字母命名:Ron Rivest, Adi Shamir 和Leonard Adleman。虽然自1978年提出以来,RSA的安全性一直未能得到理论上的证明,但它经历了各种攻击,至今(2006年)未被完全攻破。随着越来越多的商业应用和标准化工作,RSA已经成为最具代表性的公钥加密技术。VISA、MasterCard、IBM、Microsoft等公司协力制定的安全电子交易标准(Secure Electronic Transactions,SET)就采用了标准RSA算法,这使得RSA在我们的生活中几乎无处不在。网上交易加密连接、网上银行身份验证、各种信用卡使用的数字证书、智能移动电话和存储卡的验证功能芯片等,大多数使用RSA技术。

当今公钥加密更广泛应用于互联网身份认证,本课题将公钥加密算法RSA应用于小型文件加密。将任意文件加密成文本的解决方案,使其使用更加灵活。整个工程的分层设计,给引用移植和后续开发带来便利。

1.2 RSA算法介绍与应用现状
RSA算法可以简单叙述如下:
<密钥生成>
取素数p,q,令n=p×q.
取与(p-1)×(q-1)互素的整数e,
由方程d×e=1 (mod (p-1)×(q-1))解出d,
二元组(e,n)作为公开密钥,
二元组(d,n)作为私有密钥.

<加密解密>
b=ae mod n,c=bd mod n.
附录中给出了证明a=c (mod n).

RSA公开密钥加密算法自20世纪70年代提出以来,已经得到了广泛认可和应用。发展至今,电子安全领域的各方面已经形成了较为完备的国际规范。RSA作为最重要的公开密钥算法,在各领域的应用数不胜数。RSA在硬件方面,以技术成熟的IC应用于各种消费类电子产品。

RSA在软件方面的应用,主要集中在Internet上。加密连接、数字签名和数字证书的核心算法广泛使用RSA。日常应用中,有比较著名的工具包Open SSL(SSL,Security Socket Layer,是一个安全传输协议,在Internet上进行数据保护和身份确认。Open SSL是一个开放源代码的实现了SSL及相关加密技术的软件包,由加拿大的Eric Yang等发起编写的。相关详细介绍见http://www.openssl.org/about/ )。Open SSL应用RSA实现签名和密钥交换,已经在各种操作系统得到非常广泛的应用。另外,家喻户晓的IE浏览器,自然也实现了SSL协议,集成了使用RSA技术的加密功能,结合MD5和SHA1,主要用于数字证书和数字签名,对于习惯于使用网上购物和网上银行的用户来说,几乎天天都在使用RSA技术。

1.3 RSA应用于文件加密的分析
1.3.1 文件加密使用RSA的可行性
通过1.2节的论述,不难看出RSA当今的应用多在于数字签名和证书等方面。之所以只应用于这些短小数据的加密解密,是因为RSA算法加密极慢,速度是DES对称密钥加密速度的千分之一左右。正是因为这样,把RSA应用于普通文件加密的想法一直被忽略。通常文件被想象成大数据块,但是实际上在日常应用中,有些极其重要的文本资料是并不太大的,比如因担心遗忘而用普通文本记录的银行帐号和密码、不应被陌生人知道的重要电话号码、几千字节大的重要小图片等。

虽然RSA加密运算的速度十分慢,但是在PC性能越来越好的今天,对于几千字节的数据进行一次几百位密钥的RSA加密,所消耗的时间应该是可以接受的。下面结合大数运算程序的调试,从理论上简单的分析消耗时间。在一台普通配置的PC机上对一个整数进行幂模运算,因为公开密钥的e通常取的较小,所以指数取一个小整数,比如C353,模一个70字节长的整数(140位十六进制,大数单元以线性组方式实现,对应到RSA算法中,这相当于约560bit的n),调试一个函数测试,按初等数论中的知识对程序进行算法优化,最终在一台配置为AMD Athron2800+,外频333MHZ,物理内存512MB的PC上测试需要约45毫秒时间。如果按这种速度,逐字节对1KB的数据进行同样的运算,所消耗的时间理论上为45毫秒的1024倍即约45秒。这个时间并不是非常长。

其实从一个简单的角度来说,既然RSA用于数字签名可行,那就完全可以用于同样大小的普通文件。对于较大的文件,如果分成与数字签名同样大小的段(这里假设数字签名较短,不分段一次计算加密完成),分开的各段逐一进行加密运算,那所需要的时间也只是按文件大小线性的增长。通常数字签名为几十字节,加密运算并不需要很长的等待,这就说明对于几百字节或一两K字节大小的文件来说,如果进行RSA加密,并不会是非常漫长的工作。当然,如果文件更大,加密就显得十分漫长了。比如按前面叙述的45毫秒大数运算程序推理,加密1M字节大小的文件需要约1天的时间。所以,要在普通PC用几百位以上的长密钥RSA加密文件,文件不能过大,一般可以接受的上限是几KB。如果要在较短时间内加密大文件,需要缩短密钥长度以减小运算量,这将带来安全性隐患。

本文的第3章将根据实际调试好的软件,测试给出具体的时间消耗数据。例如,在一台配置为AMD Athron2800+,外频333MHZ,物理内存512MB的PC上测试实现的软件,以560bit的n逐字节加密一个1KB大小的文件需要55秒。通常记录如银行帐号密码等重要数据的文本文件大小不足百字节,加密只需要数秒钟。所以对于小型文件,进行较长密钥的RSA加密是完全可行的。

1.3.2 文件加密使用RSA的意义
如1.3.1节所述,小型文件加密可以使用RSA。比如,因担心遗忘而用普通文本记录的银行帐号和密码、不应被陌生人知道的重要电话号码、几千字节大的重要小图片等。可行的方法未必是必要的,本小节讨论何种文件适合用非对称密钥加密,即RSA加密文件的意义所在。

对于前面叙述的带有重要信息的小型文本和二进制数据的维护,①如果不加密,将无法放心的保存在计算机上,尤其是连网的或机房里的公共计算机。②如果借助功能强大的大型多用户数据保护程序维护几个小型文件,显得十分烦琐,好比杀鸡用牛刀。③如果采用对称密钥加密,即加密解密的密钥相同,只适合部分情况。在某些情况下,使用对称密钥加密文件,交流使用不够方便。比如,张三由于某种原因,需要将自己的某个文件在公共计算机上留给李四,而不希望别人看到内容。如果采用对称密钥加密,张三和李四提前约好一个密码就可以。但是如果张三想要在同一台公共计算机上再留一个秘密文件给王五,而不希望别人看到,就要和王五另外约定一个密码。如果需要在这台公共计算机上留十个文件给不同的人,自己就要记和十个人约定好的密码,这样以来交流起来不够方便,因为对于张三,要自己维护太多的密钥。非对称密钥(公开密钥方式)恰好解决这样的问题。只要大家都在这台计算机或这台计算机可以访问到的地方,留下自己的公开密钥,一切就变的容易解决了。张三要留给李四的文件,就用李四的公开密钥加密,要留给王五的文件,就用王五的公开密钥加密。李四和王五只要把留给自己的文件用自己的私有密钥解密,就可以得到留给自己的文件了。显然,非对称密钥体制更适合多用户交流,而将这种加密方式直接应用于文件加密,使我们在公开场合的交流更加灵活方便。

综上所述,使用前面叙述的方式加密文件有两点重要意义:①应用非对称密钥加密任意文件,使非对称密钥的应用不仅仅局限于互联网络。②非对称加密后的数据变换成文本,使得我们可以通过几乎任何方式安全传递任意文件,比如在只有http的环境使用xml方式。

2 RSA文件加密软件的设计与实现
2.1 需求分析与总体设计
2.1.1 功能分析
经过1.3.2节的论述,我们可以将对软件的要求总结如下:
① 可以按要求的位数生成非对称密钥。
② 可以用指定密钥以RSA算法加密任意一个文件,加密生成的数据为纯文本。
③ 可以装载加密过的文件,并用指定的密钥解密还原出原文件。
④ 提示信息完整、操作舒适、图形界面雅观
按上述描述,给出Use Case和Statechart如图2-1。
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第1张图片

图2-1 本项目的 Use Case和Statechart
根据以上分析,一般来说,需要进行编码的程序有
①RSA密钥生成 ②RSA加密解密 ③任意文件的读取 ④各环节必要的数据编码转换 ⑤图形操作界面。

2.1.2 工程方案选择
综合考虑复用性、可维护性和执行效率,较妥当的方法是分层设计。核心的RSA算法由C++类库实现,针对用户所在的操作系统封装成本地化组件。其他各功能如文件操作、数据编码转换和图形界面等,由托管代码借助虚拟机平台标准库的功能快速开发实现(本文针对选用.Net上的C#论述,选用java由JNI或其他方式调用本地组件,设计模式上是完全类似的)。这种开发方式,核心功能集中在最底层,在不断的封装中针对具体环境对组件功能不断扩充,任意一个层面的封装都可以被直接应用到其他项目,比如在Web使用以前为某窗体程序写的组件、给嵌入式设备交叉编译算法库等。但是每一层都需要依赖底层的所有组件。图2-2形象的说明了分层设计给复用带来的好处。
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第2张图片

图2-2 综合考虑复用性、可维护性和执行效率的分层设计
选用这种设计方案,上层使用C#,底层算法使用C++,可以由一个Visual Studio解决方案管理,给调试带来极大的方便。整个工程分四层,实现RSA加密算法的C++核心类库、封装C++核心类库的DLL组件、引用DLL的.Net类、实现文件操作功能的.Net窗体应用程序。2.2节详细介绍各部分的设计与开发。

考虑到工作量,本软件加解密数据没有严格遵从RSA标准PKCS #1,而是在满足设计要求的前提下,以一种尽可能简单的方式实现加密和解密。

2.2 各部分的设计与开发
2.2.1 实现RSA加密算法的C++核心类库
1 大数存储和四则运算
根据RSA算法的要求,为了实现大数的各种复杂运算,需要首先实现大数存储和基本四则运算的功能。当今开源的大数运算C++类有很多,多用于数学分析、天文计算等,本文选用了一个流行的大数类型,并针对RSA算法和本项目的具体需要对其进行了扩充和改进。下面简单介绍大数存储和四则运算的实现原理。

最先完成的功能是大数的存储,存储功能由flex_unit类提供。和普通的类型一样,每一个大数对应一个flex_unit的实例。类flex_unit中,用一个无符号整数指针unsigned * a指向一块内存空间的首地址,这块内存空间用来存储一个大数,所以可以说,大数是被存储在一个以unsigned为单元的线性组中。在方法void reserve( unsigned x )中通过C++的new来给a开辟空间,当flex_unit的实例中被存入比当前存储的数更大的数时,就会调用reserve来增加存储空间,但是当flex_unit的实例中被存入比当前存储的数更小的数时,存储空间并不会自动紧缩,这是为了在运算的时候提高执行效率。结合指针a,有两个重要的无符号整数来控制存储,unsigned z和unsigned n,z是被分配空间的单元数,随数字变大不断增大,不会自己紧缩,而n是当前存储的大数所占的单元数,组成一个大数的各unsigned单元的存入和读出由set、get方法完成,变量n是只读的。类型unsigned在32位机是32位的,所以对于flex_unit这个大数类来说,每个大数最大可以达到 2**32个字节长,这已经超过了32位机通常的最大内存容量,所以是足够进行RSA所需要的各种运算的。图2-3形象的说明了大数存储类flex_unit对大数的管理。
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第3张图片

图2-3 flex_unit对大数的管理

在flex_unit的存储功能基础上,将其派生,得到vlong_value,在vlong_value中实现四则运算函数,并实现强制转换运算符unsigned,以方便大数类型和普通整数的互相赋值。当大数被强制转换为unsigned时,将取其最低四字节的值。四则运算实现的原理十分简单,都是按最基本的算术原理实现的,四则运算过程的本质就是按一定数制对数字的计算,比如相加,就是低位单元对齐,逐单元相加并进位,减法同理。而乘除法和取余也都是按照竖式运算的原理实现,并进行了必要的优化。虽然实现了四则运算函数,但是若是程序里的运算都要调用函数,显得烦琐而且看起来不美观,所以我们另写一个类vlong,关联(Associate,即使用vlong_value类型的对象或其指针作为成员)vlong_value,在vlong重载运算符。这样,当我们操作vlong大数对象的时候,就可以像使用一个简单类型一样使用各种运算符号了。之所以将vlong_value的指针作为成员而不是直接构造的对象,也是为了提高执行效率,因为大型对象的拷贝要消耗不少机器时间。

2 大数幂模与乘模运算•Montgomery幂模算法
在实现了vlong类型后,大数的存储和四则运算的功能都完成了。考虑到RSA算法需要进行幂模运算,需要准备实现这些运算的方法。所以写一个vlong的友元,完成幂模运算功能。幂模运算是RSA 算法中比重最大的计算,最直接地决定了RSA 算法的性能,针对快速幂模运算这一课题,西方现代数学家提出了很多的解决方案。经查阅相关数学著作,发现通常都是依据乘模的性质 ,先将幂模运算化简为乘模运算。

通常的分解习惯是指数不断的对半分,如果指数是奇数,就先减去一变成偶数,然后再对半分,例如求D= ,E=15,可分解为如下6个乘模运算。

C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第4张图片

归纳分析以上方法,对于任意指数E,可采用如图2-4的算法流程计算 。
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第5张图片

图2-4 幂模运算分解为乘模运算的一种流程
按照上述流程,列举两个简单的幂模运算实例来形象的说明这种方法。
① 求 的值
开始 D = 1 P = 2 mod 17 = 2 E = 15
E奇数 D = DP mod n = 2 P = PP mod n = 4 E= (E-1)/2 =7
E奇数 D = DP mod n = 8 P = PP mod n = 16 E= (E-1)/2 =3
E奇数 D = DP mod n = 9 P = PP mod n = 1 E= (E-1)/2 =1
E奇数 D = DP mod n = 9 P = PP mod n = 1 E= (E-1)/2 =0
最终D = 9 即为所求。
② 求 的值
开始 D = 1 P = 2 mod 13 = 2 E = 8
E偶数 D = 1 P = PP mod n = 4 E = E/2 =4
E偶数 D = 1 P = PP mod n = 3 E = E/2 =2
E偶数 D = 1 P = PP mod n = 9 E = E/2 =1
E奇数 D = DP mod n = 9 P = 不需要计算 E = (E-1)/2 =0
最终D = 9 即为所求。

观察上述算法,发现E根据奇偶除以二或减一除以二实际就是二进制的移位操作,所以要知道需要如何乘模变量,并不需要反复对E 进行除以二或减一除以二的操作,只需要验证E 的二进制各位是0 还是1 就可以了。同样是计算 ,下面给出从右到左扫描二进制位进行的幂模算法描述,设中间变量D,P,E的二进制各位下标从左到右为u,u-1,u-2,…,0。
Powmod(C,E,n)
{
D=1;
P=C mod n;
for i=0 to u do
{
if(Ei=1)D=DP(mod n);
   P=P
P(mod n);
   }
   return D;
}

有些文献将上述算法称为平方乘积二进制快速算法,例如参考文献中的《基于RSA算法的一种新的加密核设计》,其实这种算法本质上和图2-4的流程完全一致,只是把根据指数奇偶分开的减一和除以二合并成对指数二进制各位的判断而已。在本软件的代码中采用直接扫描vlong二进制各位的办法。

剩下的问题就是乘模运算了。提高乘模运算的速度是提高模幂运算速度的关键。一般情况下,n是数百位乃至千位以上的二进制整数,用普通的除法求模而进行乘模运算是不能满足速度的要求的。为此,Montgomery在1983年提出了一种模加右移的乘模算法(主要著作发表于1985年),从而避免了通常求模算法中费时的除法步骤。本软件仅仅是应用Montgomery(蒙哥马利)算法,算法的具体推导证明需要颇多数论知识,不在本文的讨论范围内,如需了解可参见蒙哥马利的相关著作。下面简单描述RSA中常用的Montgomery(蒙哥马利)算法供参考理解源程序。
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第6张图片

本软件程序中,RSA核心运算使用的乘模算法就是 M(AB)。虽然M(AB)并不是乘模所需要的真正结果,但只要在幂模算法中进行相应的修改,就可以调用这个乘模算法进行计算了。

将上述乘模算法结合前面叙述的幂模算法,构成标准Montgomery幂模算法,即本软件所使用的流程,叙述如下。
M(m) //蒙哥马利乘模

{
k = ( m * n’ ) mod R;
x = (m + k*n ) / R;
if (x>=n) x -= n;
return x;
}
exp(C,E,n) //蒙哥马利幂模

{
D=R-n;
P=CR mod n;
i=0;
while(true)
{
if(E的当前二进制位Ei==1)D=M(D
P); //从低位到高位检测二进制位
i+=1;
if(i==E的二进制位数)break;
   P=M(PP);
   }
   return D
R-1 (mod n);
}
在具体的实现中,对应monty类的mul和exp方法。全局函数modexp初始化monty对象并调用其exp方法,使用的时候直接调用modexp即可。

3 寻找素数•Eratosthenes筛选与Fermat素数测试
首先要说明的是,事实上,当今的计算机还不足以聪明到立刻计算生成一个很大的随机素数。一般来说,要得到100%准确的大素数,都是通过查已经计算好的素数表的方式。但是素数表的方式给RSA的安全性带来隐患,因为攻击者如果得到了密钥生成时所使用的素数表,攻破RSA加密的难度将会大大降低。本程序起初使用素数表的方式,后来考虑到安全性问题,生成密钥的方式改为随机计算生成。这样,短时间内如果要得到一个100%准确的大素数是很困难的,只能以尽可能高的概率得到一个大素数。

经过2.2.1.1和2.2.1.2小节,所有的大数运算功能都准备完毕,在此基础上,本工程将寻找素数的功能置于类Prime_factory_san之中。外部只要调用本类实例的成员vlong find_prime( vlong & start )就可以以大数start为起点,得到一个数,这个数是素数的概率很大。下面介绍寻找素数的原理。

首先在需要寻找素数的整数范围内对整数进行筛选,把所有确知为合数的整数排除出去。程序中构造了一个数组b[],大小为一轮素数搜索的范围,记搜索范围大小为SS。b[0]到b[SS]分别对应大数start到start+SS。b[]中所有元素先初始化为1,如果对应的大数确定为合数,就将b[]中对应的元素置为0。最后,只需对那些b[]中为1的元素对应的大数进行比较确切的素数测试即可,只要被测试的数是素数概率达到一定门限,就判这个数为素数。这样做既保证了这段程序可以在短时间内执行完,又保证了可以以比较高的准确度得到素数。

函数find_prime先把b[]的所有元素赋值为1,然后按参数start给标记数组b[]的各元素赋0值。下面描述标记数组b[]的赋0值算法。首先,在类Prime_factory_san被构造的时候,构造函数中从2开始搜寻一些小素数,记录在数组pl[]中,共记录NP个。这些小素数用来当作因子,他们的倍数将被从大素数搜索范围内剔除(即把数组b[]的对应元素标记为0),剔除的程序代码如下。
for (i=0;i {
unsigned p = pl[i];
unsigned r = start % vlong§;
if ® r = p - r;
while ( r < SS )
{
b[r] = 0;
r += p;
}
}

这里利用start对各小素数因子p求模的办法,得到当前p在素数搜索范围内的最小倍数在b[]中的对应位置,将其剔除后,不断后移p个位置,将这个小素数因子p在搜索范围内的所有倍数全部剔除,如图2-5所示。在完成对所有小素数因子的类似操作后,他们的倍数在搜索范围内的位置标记b[r]被全部标记为0。实际上这就是Eratosthenes筛选法。

C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第7张图片

图2-5 在素数搜索范围内剔除小素数因子p的倍数

接下来,对可能为素数的数(即标记数组b[]中值为1的元素对应的数)进行素数测试。数论学家利用费马小定理研究出了多种素数测试方法,本程序使用一种最简单的方式,直接应用费马小定理。取一个与p互素的整数A,对于大素数p来说应该满足Ap-1mod p=1,但是我们把p代入一个大整数,满足这个关系的数不一定是素数。这时我们改变A,进行多次测试,如果多次测试都通过,这个数是素数的概率就比较大。按这种原理,我们编写素数测试函数如下。

int is_probable_prime_san( const vlong &p )
{
  const rep = 4; //测试次数
  const unsigned any[rep] = { 2,3,5,7 }; //测试用的底数
  for ( unsigned i=0; i<rep; i+=1 )
if ( modexp( any[i], p-vlong(1), p ) != vlong(1) ) return 0;
 //modexp是幂模函数,按上一小节叙述的算法编码。
//这里modexp计算any[i]p-1mod p。
  return 1;
}

测试通过,程序就判定这个数为找到的素数,将找到的素数返回给上层程序使用。在这里其实有一个不可忽视的问题,就是得到一个测试通过的合数。对于这种情况,RSA算法加密解密是否还可以实现,是一个需要从数学角度论证的问题。因为得到素数的概率很高,经过一整天的生成密钥和加密操作,没有发现失败的密钥, 所以本文暂没有对这个问题进行讨论。

实际得到素数的流程:
(1) 先得到一个随机的大整数N当作寻找的起点.
(2) 确定一个寻找范围的大小SS,把(N,N+SS)范围内的小素数倍数去掉,即前面叙述的古希腊某人发明的筛选法.小素数因子从2开始取,取几百个(论文中将小素数因子个数记为NP).
(3) 对范围内没有去掉的数逐一进行素数测试,一个数如果通过测试次数达到一定标准,就判为素数.
(4) 如果范围内没找到素数,就令N=N+SS,回到(2)继续寻找.
用以上算法,直到以某成功概率得到素数为止

综上所述,总结素数寻找的流程,如图2-6所示。
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第8张图片

图2-6 函数find_prime寻找素数的流程框图
得到了大素数,即RSA算法中的p、q,我们就可以计算出密钥,进行加密等操作了。

4 二元一次不定方程
在RSA 算法中,往往要在已知A、M的情况下,求B的最小值,使得 (AB) mod M = 1。即相当于求解B、N都是未知数的二元一次不定方程 AB-MN=1的最小整数解。
而针对不定方程ax-by=1 的最小整数解,古今中外都进行过详尽的研究,西方有著名的欧几里德算法,即一种辗转相除法,中国有秦九韶的“大衍求一术”。欧几里德算法是一种递归算法,较容易理解。下面举例说明用欧几里德算法求解二元一次不定方程的最小整数解。
给定不定方程11x-49y=1,求最小的x
(1) 11 x - 49 y = 1 49 mod 11 = 5
(2) 11 x - 5 y = 1 11 mod 5 = 1
(3) x - 5 y = 1 5 mod 1 = 0
逆向代入:
令y=0 代入(3)得x=1
令x=1 代入(2)得y=2
令y=2 代入(1)得x=9
x=9;y=2即为所求。
程序中,全局函数vlong modinv( const vlong &a, const vlong &m )用来完成这种算法。对应前面的叙述,参数a对应A,参数m对应M,函数返回值即为B的最小值。

5 RSA算法实现加密与解密
最后,类RSA_san基于前面的准备工作,实现RSA密钥生成和加解密的功能(算法在此不再赘述,RSA算法协议见(http://www.di-mgt.com.au/rsa_alg.html)。为了方便阅读,整个类的源程序中,所使用的变量字母均和RSA算法协议中一致。在类RSA_san的构造函数里,执行准备一对随机密钥的操作。之后可以直接使用类的其他成员进行RSA加解密操作。类中各成员频繁的用到字符串和vlong类型的转换,因为大数是用字符串置入的,而把大数读出,也是保存在字符指针指向的一段内存空间里,所以也是字符串。所以,需要实现一系列的编码转换函数,比如将unsigned指针指向的一段空间里保存的一个大数,表示成十六进制形式的字符串文本。编码转换通常是用C风格的指针操作和sprintf函数来完成。

需要加密和解密的数据也是通过字符串参数置入的。由于字符串的结尾字符“\0”实际上也可能是需要加密的数据,所以置入的串长度并不能以“\0”来决定,程序里引入一个unsigned类型的参数来决定置入的串长度,这样就解决了加密连0数据时候被截断的问题。
因为是对文件加密的软件,需要加密的数据通常并不止几字节,本软件默认的分块大小是1字节,即逐个字节作为参数,调用C++核心模块中的方法。

加密解密流程均为标准RSA算法,具体过程见下图:
①生成密钥:
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第9张图片

图2-7 随机生成密钥
相关代码:

public static int GetRandomString()//实现随机字串的获得
		{
			Random rnd = new Random();
			Byte[]b=new Byte[System.Math.Max(RSAprimeplen1,RSAprimeplen2)];
			s1="";
			s2="";
			for(int i=0;i<RSAprimeplen1;i++)
			{
				Byte tmp=System.Convert.ToByte(254.0*rnd.NextDouble());
				if(tmp!=0)b[i]=tmp;else b[i]=1;			}
			s1=wujunjie_rsa.FromASCIIByteArray(b);
			
			for(int i=0;i<RSAprimeplen2;i++)
			{
				Byte tmp=System.Convert.ToByte(254.0*rnd.NextDouble());
				if(tmp!=0)b[i]=tmp;else b[i]=1;
			}
			s2=wujunjie_rsa.FromASCIIByteArray(b);
			
			return 1;}

②加密过程:
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第10张图片

图2-8 载入待加密的文本

C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第11张图片

图2-9 准备加密文本
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第12张图片

图2-10加密后生成的文本

C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第13张图片

图2-11加密过程完成
相关代码:

private void menuItem10_Click(object sender, System.EventArgs e)//公钥加密
		{
			if(wujunjie_rsa.charlist.Count==0)
			{
				emptymsg em=new emptymsg(this); 
				em.Show();
				return;
			}

			Stream myStream ;
			SaveFileDialog saveFileDialog1 = new SaveFileDialog();
 
			saveFileDialog1.Filter = "Hex text files (*.hextxt)|*.hextxt|All files (*.*)|*.*"  ;
			saveFileDialog1.FilterIndex = 1 ;
			saveFileDialog1.RestoreDirectory = true ;
 
			if(saveFileDialog1.ShowDialog() == DialogResult.OK)
			{
				if((myStream=saveFileDialog1.OpenFile()) != null)
				{
					textBox1.Text+="\r\n正在对读入的文件进行处理,请稍候:)\r\n";
					System.Threading.Thread.Sleep(500);
					HighResolutionTimer timer = new HighResolutionTimer(); 
					timer.Start();
					using (StreamWriter sw = new StreamWriter(myStream)) 
					{
						sw.WriteLine("# RSA.HexText");
						sw.WriteLine("#___________________________________________");

						Byte []b=new Byte[wujunjie_rsa.RSAstep];
						wujunjie_rsa.result_hexstrings.Clear();
						progressBar1.Minimum=0;
						progressBar1.Maximum=wujunjie_rsa.charlist.Count;
						for(int i=0;i<wujunjie_rsa.charlist.Count;i+=System.Convert.ToInt32(wujunjie_rsa.RSAstep))
						{
							for(int j=0;j<wujunjie_rsa.RSAstep;j++)
							{
								b[j]=System.Convert.ToByte(wujunjie_rsa.charlist[i+j]);
							}
							string s;
							wujunjie_rsa.RSA_san_en(b,wujunjie_rsa.RSAstep);
							s=wujunjie_rsa.get_result_hexstring();
							wujunjie_rsa.result_hexstrings.Add(s);
							progressBar1.Value=i+1;
						}

						for(int i=0;i<wujunjie_rsa.result_hexstrings.Count;i++)
						{
							string hs=System.Convert.ToString(wujunjie_rsa.result_hexstrings[i]);
							if(hs==null||hs=="")sw.WriteLine("0");
							else sw.WriteLine(hs);
						}

						sw.WriteLine("#___________________________________________");
						sw.Write("# ");
						sw.WriteLine(DateTime.Now);

						wujunjie_rsa.result_hexstrings.Clear();

					}
					myStream.Close();
					timer.Stop(); 
					textBox1.Text+="\r\n消耗时间:"+timer.ElapsedTime+"\r\n";

					textBox1.Text+="\r\n处理完成,新生成文件\r\n"+saveFileDialog1.FileName+"\r\n";
					progressBar1.Value=0;
				}
			}
		} 

③解密过程:
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第14张图片

图2-12 载入加密后生成的文本
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第15张图片

图2-13解密已加密的文本
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第16张图片

图2-14 解密生成解密文件

C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第17张图片

图2-15 解密过程完成
相关代码:

private void menuItem8_Click(object sender, System.EventArgs e)//私钥解密
		{
			if(wujunjie_rsa.hextxtlist.Count==0)
			{
				emptymsg em=new emptymsg(this); 
				em.Show();
				return;
			}

			Stream myStream ;
			SaveFileDialog saveFileDialog1 = new SaveFileDialog();
 
			saveFileDialog1.Filter = "Text files (*.txt)|*.txt|All files (*.*)|*.*"  ;
			saveFileDialog1.FilterIndex = 2 ;
			saveFileDialog1.RestoreDirectory = true ;
 
			if(saveFileDialog1.ShowDialog() == DialogResult.OK)
			{
				if((myStream=saveFileDialog1.OpenFile()) != null)
				{
					textBox1.Text+="\r\n正在对十六进制文本进行处理,请稍候:)\r\n";
					System.Threading.Thread.Sleep(500);
					HighResolutionTimer timer = new HighResolutionTimer(); 
					timer.Start(); 
					using (BinaryWriter bn = new BinaryWriter(myStream))
					{
						progressBar1.Minimum=0;
						progressBar1.Maximum=wujunjie_rsa.hextxtlist.Count;
						for(int i=0;i<wujunjie_rsa.hextxtlist.Count;i++)
						{
							wujunjie_rsa.RSA_san_dn_hexstring(System.Convert.ToString(wujunjie_rsa.hextxtlist[i]));

							for(uint j=0;j<wujunjie_rsa.RSAstep;j++)
							{
								bn.Write(wujunjie_rsa.get_result_byte(j));
							}
							progressBar1.Value=i+1;
						
						}
					}

					myStream.Close();
					timer.Stop(); 
					textBox1.Text+="\r\n消耗时间:"+timer.ElapsedTime+"\r\n";

					textBox1.Text+="\r\n处理完成,新生成文件\r\n"+saveFileDialog1.FileName+"\r\n";
					progressBar1.Value=0;}
			}	
		}

6 核心类库综述
综上几小节所述,实现RSA加密算法的C++核心类库由六个类组成,类名和对应的功能描述总结如表2-1所示。各个类之间的关系如图2-16所示。

表2-1 RSA加密算法的C++类库中的类
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第18张图片

C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第19张图片

图2-16 C++核心功能类图

另外需要说明的是,程序中有几个不属于任何类的全局函数,比如应用辗转相除法求最大公约数的函数gcd、解同余方程的函数modinv等。按常规设计模式来说,不应当出现类之外的函数,但是因为这些函数使用频繁,考虑到机器效率,直接置于全局,不再另行包装。

2.2.2 封装C++核心类库的DLL组件
在Visual Studio当前的解决方案中以VC++创建一个win32dll工程,将测试好的实现RSA加密算法的C++核心类库中的所有文件加入到此工程下,新建一对cpp和h文件,把可能用到的功能全部规划为新文件中的全局函数,并以C接口导出,即__declspec(dllexport)。由于核心类库的对外功能都使由RSA_san类提供的,所以在新cpp文件中全局的声明一个RSA_san类的对象指针(RSA_san WRSA),全局函数int start_RSA_san()初始化WRSA对象,在初始化成功后,其他全局函数通过调用*WRSA对象的公开方法实现各种功能,如加密、读取密钥等。在关闭上层引用程序以前,应执行int finish_RSA_san()来释放WRSA,该函数执行delete WRSA的操作。其他接口函数的使用见DLL接口文档。

另外,DLL组件可以自己在全局函数中实现一些其他功能,作为对核心类库功能的补充。C接口的DLL组件可以被诸如VB、Delphi等开发环境方便的引用。

2.2.3 引用DLL的.Net类与实现文件操作功能的窗体应用程序
在C#编写的.Net类里,使用特性[DllImport(“rsa.dll”)]引用C接口的DLL组件。类中接口DLL的函数都以静态成员的方式对外公开,其他.Net程序可以直接使用。在类库中还提供了任意长度随机串的生成函数,此函数用于生成寻找素数的大数起点。

文件操作使用.Net基础类库中的System.IO中的类实现。一般因为文件操作十分简单,用流输入输出的方式包装完成,程序中将文件操作直接放在菜单项关联的事件处理函数中。

窗体等图形操作界面直接由Visual Studio的所见即所得的方式完成,不需要编码实现。
最终实现的应用程序,结构如图2-17所示。
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第20张图片

图2-17 本软件的Visual Studio解决方案

3 软件整体测试与分析改进
3.1 编写测试各项性能需要的精确计时类
由于.Net基础类库提供的计时功能十分不精确,无法胜任软件性能测试的工作,这里使用Windows API 函数QueryPerformanceCounter和QueryPerformanceFrequency进行精确计时。功能被封装在C#类HighResolutionTimer中,使用时只需构造一个此类的对象,在计时开始的时候调用其Start方法,计时结束时调用其Stop方法,然后访问其ElapsedTime属性,就可以得到一个以秒为单位的float型精确的计时值了。API 函数QueryPerformanceCounter和QueryPerformanceFrequency是靠查询CPU的高精度计时器来计时的,所以可以轻松的精确到毫秒级计时。
附录中给出了这个类的源代码。

3.2 测试数据与分析改进
3.2.1 密钥生成测试
生成密钥运算最费时的工作是寻找素数。如2.2.1.3小节所叙述,寻找素数是一项颇为复杂的工作,其速度可能受以下变量的影响:RSA加密需要的n的位数(寻找素数的整数起点大小start)、大素数测试时底数A的个数(针对一个整数的素数测试次数)、小素数因子p的个数NP、一轮寻找遍历的整数个数SS等。其中最具影响力的因素显然是RSA加密需要的n的位数。以下对各变量分别进行测试,暂且忽略操作系统调度对测试的影响。

1 测试加密使用的n的位数对耗时的影响
即 在固定A、NP、SS等变量的情况下,改变加密位数n,测试密钥生成的时间消耗情况。测试时,A取4个值,分别为2、3、5、7,NP取200,SS取1000。测试PC配置为CPU CR1.7GHZ/外频100MHZ/物理内存512MDDR/MSI6398主板845 Ultra-AD芯片组,下文测试中,未说明PC配置的也都在同一PC完成,不再重复。统计数据如表3-1所示。

C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第21张图片

表3-1 RSA加密模数n与密钥生成耗时的关系

观察表3-1上的统计数据,很容易发现随着加密位数的增加,密钥生成需要的时间显著增加。在测试范围内,随着加密位数增大,每一行中的最大最小值差距也呈粗略的增大趋势。也就是说对于长密钥来说,RSA随机生成密钥消耗时间的可能范围较大。这是因为对于大整数来说,可能出现在较长一段区间中没有素数的情况。

在较常用的1024位RSA加密时,用本软件的算法,测试时最长出现了17秒多的计算,虽然这对于用户来说时漫长的等待,但是考虑到安全性,还是舍弃了素数表和密钥库的方案,而使用大素数随机生成,以获得更高的安全性。

表3-1仅能从实验的角度直观理解,具体到一次密钥生成的运算,所需要的时间是很不确定的,比如,一次1280位的密钥生成,需要的时间完全可能比一次896位的密钥生成时间短,由于素数分布规律非常奥妙,加上测试运算需要的时间颇长,这里很难给出对于一个具体位数的密钥生成所需时间的统计模型。

另外需要说明的是,表3-1的加密位数在实际软件设置时并不严格。这是因为,实际作为参数设置的是两个大素数的搜索起点。如果随机生成的起点整数大小比较接近更长一位的整数的话(例如FFFF很接近10000),向后寻找所得到的素数很可能长出一位。而且,两个k位长的整数相乘的结果也未必是2k位,比如100*100=10000,相乘结果是2k-1位。所以,在表3-1实际测试填写时,加密位数可能会有几位的差距,但是这不碍大局。

3.2.2 数据输入输出测试
主要测试文件的输入输出性能。实际上就是测试.Net基础类库中实现文件操作的System.IO中的StreamReader、StreamWriter等类的读写性能。直接在Visual Studio调试一个简单的C#文件读写程序,得到本软件中使用的文件操作方法的执行性能。在配置为CPU CR1.7GHZ/外频100MHZ/物理内存512M DDR/MSI6398主板845 Ultra-AD芯片组/UTA133 2M缓存硬盘的PC上,读入一个100KB的文件仅需要35毫秒,写出一个100KB的文件需要29毫秒。这样的时间消耗,相对于繁复的RSA计算所消耗的时间来说,是完全可以忽略不计的。

3.2.3 加密解密测试
进行对任意文件加密与解密的测试,这里给出几组从不同角度进行测试的数据。
1 用同样的密钥对不同大小的文件公钥加密、私钥解密,各自消耗的时间与待加密文件大小的关系
随机生成两组密钥,一组n长512bit,一组n长1024bit。密钥具体数据见附录(n的实际位数有微小差距)。
分别对一组不同大小的文件进行公钥加密。统计消耗时间情况如表3-2所示。

表3-2待加密文件大小与加密时间的关系(时间单位:秒)
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第22张图片

从表3-2可以看出,使用同一公开密钥加密不同大小的文件,消耗时间随着文件大小的增加而增加,和1.3.1小节分析的完全一致。对于较大的文件,加密位数对时间的影响十分明显。对于250字节的文件来说,1024bit的公钥加密比512bit的耗时多1.5倍左右;1024bit的私钥解密比512bit的耗时多3倍以上。对于一定的加密位数来说,私钥解密所需要的时间比公钥加密需要的时间长。对于一定大小的文件,使用512bit的密钥,私有密钥解密需要的时间是公开密钥加密需要时间的2倍左右;而如果使用1024bit的密钥,私有密钥解密需要的时间是公开密钥加密需要时间的3倍以上。再测试几个1280bit的密钥加解密,发现私有密钥解密所需要的时间相对于公钥加密时间更长。可见,本软件密钥长度越长,私有密钥解密与公开密钥加密的耗时比越大,这和其他软件是一致的。因为根据PCKS #1的RSA的应用建议,e是比较短的,而d和n的长度差不多,这就使得求与d、n有关的幂模运算量比与e、n有关的幂模运算量大很多,而且随着n的增加,两组幂模运算的运算量差距也迅速加大。

3 在更快的PC,对进行文件加密测试
在一些性能更好的PC上,本软件可以获得更好的性能,测试数据同样可以分析得到以上段落叙述的结论。下面对照表3-4,给出一组其他PC上同样的测试得到的数据,测试PC配置为CPU AMD Athron2800+,外频333MHZ,物理内存512MB。数据见表3-3。

表3-3 待加密文件大小与加密时间的关系再次测试(时间单位:秒)
C#毕业设计——基于C#+asp.net+C++的RSA文件加密系统设计与实现(毕业论文+程序源码)——RSA文件加密系统_第23张图片

对于这组数据,经过一系列各种机型、各种Windows操作系统(包括Windows XP/2000SP4/ME/98,均需.Net框架)上的测试,本软件均能正常运行。在2006年初主流配置的PC上运行此软件,逐字节加密1KB大小的文件,消耗时间均在1分钟以内。

结论
经过一系列的RSA密钥生成、文件输入输出和加密解密测试,做简要的性能分析如下。

① 软件消耗时间的运算,大部分集中在C++核心类库,即RSA相关的各种运算。其中,幂模运算和寻找素数对时间的消耗最大,在核心优化时应优先考虑。
② 文件输入输出消耗时间其次,因为磁盘读写速度要远远低于内存读写速度。所以,应该将频繁的读写操作尽量集中到内存,然后一次性写入磁盘。

针对以上两点,软件应进行一系列改进和优化。主要有以下几方面。
① 在要对文件进行加密解密的时候,先将文件按一定的数据结构读入内存,然后进行加密或解密操作。运算数据都读取自内存。
② 在对加密或解密完成的数据进行写出的时候,都是将其直接写到指定好的文件,即直接写入磁盘。这是因为,考虑到中途可能因为意外断电等原因引起操作中断,为了保护已经花费时间运算完成的数据,将其直接写入磁盘。
③ 在关键算法上做进一步优化,例如在寻找素数时,素数测试使用更快速的算法。
④ 对C++核心类库进行重点优化,使其运算效率尽可能提高。其中包括对各类之间的组织细节、各程序模块的具体编写等,进行全面细致的检查和修改,例如将大数据类型以对象指针传递而不拷贝,将简单的for循环展开等。
由于开发时间仓促等因素,在书写本文时,软件并未完成全面细致的优化。

该系统应用于文件加密适合交流管理小型文件,将任意文件以非对称密钥加密成文本可以对其更方便的交流和管理,有广阔的开发前景。本项目应用的设计模式兼顾执行效率和可复用性。应用本程序可以方便的在公众论坛等环境交流要求高度安全的各种数据,包括任意二进制和文本文件。

参考文献
[1] 华罗庚.数论导引[M].北京:科学出版社.1979.6。
[2] 蔡乐才,张仕斌.应用密码学[M].北京:中国电力出版社.2005.2。
[3] 沈世镒,陈鲁生.现代密码学[M].北京:科学出版社.2004.1。
[4] 施向东,董平.基于RSA算法的一种新的加密核设计[J].北京:微计算机信息,2005,12: 39-41。
[5] 吴春明,秦建. RSA在软件实现中的算法研究[J].北京:农业网络信息,2006, 08:41-46。
[6]范益波,曾晓洋.基于16位的Montgomery模乘法器设计[J].北京:通讯学报 2006,27(4):107-113。
[7] 陈发来,李尚志.数学实验——素数[M].北京:高等教育出版社.2004.8。

附 录
省略

致 谢
省略


5、资源下载

本项目源码及完整论文如下,有需要的朋友可以点击进行下载。如果链接失效可点击下方卡片扫码自助下载。

序号 毕业设计全套资源(点击下载)
本项目源码 基于C#+asp.net+C++的RSA文件加密系统设计与实现(源码+文档)C#_asp.net_C++_RSA文件加密.zip

你可能感兴趣的:(精选毕业设计完整源码+论文,asp.net,c#,c++)