3.解密(用d,n)对于密文C由M=Cˆd(modn)得到明文M。
3.实现过程:
1.输入p,q判断为素数,计算n=p*q,ψ(n)=(p-1)(q-1)
2.输入e判断是否与ψ(n)互质,计算d=eˆ-1(modψ(n))
3.输出公钥为(e,n)私钥为(d,n)
4.输入明文(数字)M计算密文C=Mˆe(modn)
5.输入密文C计算明文M=Cˆd(modn)
二.设计思路:
1.关键问题:
(1)素数的判断:
首先在输入p,q之后应该有一个函数intsushu()可以判断p,q是否为素数,并返回1(是)或0(否)。
考虑到程序中数据类型为long型,依次用2~√n之间的数去除n,如果能整除则不为素数。
该算法时间复杂度为O(√n)。
intsushu(longm)
{inti;
for(i=2;i*i<=m;i++)
if(m%i==0)return0;
return1;}
(2)互质的判断:
在输入e之后需要判断e与ψ(n)是否互质,所以用该有判断互质的函数intgcd()返回1(是),其他(否)。
根据欧几里德算法
gcd(a,b)=gcd(b,amodb)
证明:
a可以表示成a=kb+r,则r=amodb
假设d是a,b的一个公约数,则有
d|a,d|b,而r=a-kb,因此d|r
因此d是(b,amodb)的公约数
假设d是(b,amodb)的公约数,则
d|b,d|r,但是a=kb+r
因此d也是(a,b)的公约数
因此(a,b)和(b,amodb)的公约数是一样的,其最大公约数也必然相等
所以若gcd(a,b)=1则a与b互质。
intgcd(longa,longb)
{if(b==0)returna;
returngcd(b,a%b);}
(3)求乘法逆元:
因为需要计算私钥d=eˆ-1(modψ(n)),所以有函数longExtendedEuclid()计算d并返回d的值,这里用到扩展欧几里德算法。
大体思路与欧几里德算法一致:
如果gcd(a,b)=d,则存在m,n,使得d=ma+nb,称呼这种关系为a、b组合整数d,m,n称为组合系数。
当d=1时,有ma+nb=1,此时可以看出m是a模b的乘法逆元,n是b模a的乘法逆元。
longExtendedEuclid(longf,longd,long*result)
{intx1,x2,x3,y1,y2,y3,t1,t2,t3,q;
x1=y2=1;x2=y1=0;x3=(f>=d)?
f:
d;y3=(f>=d)?
d:
f;
while
(1){
if(y3==0){*result=x3;return0;}
if(y3==1){*result=y2;return1;}
q=x3/y3;t1=x1-q*y1;t2=x2-q*y2;t3=x3-q*y3;
x1=y1;x2=y2;x3=y3;y1=t1;y2=t2;y3=t3;}
}
(4)快速幂模算法:
在加密解密时都要用到类似AˆB(modC)的计算,当指数B较大时,如果先计算AˆB的值时间较慢,且结果过大会溢出。
依据模运算的性质(a*b)modn=((amodn)*(bmodn))modn可以将AˆB分解为较小几个数的乘积分别进行模运算
例如(3^999)可以分解为(3^512)*(3^256)*(3^128)*(3^64)*(3^32)*(3^4)*(3^2)*3 这样只要做16次乘法。
把999转为2进制数:
1111100111,其各位就是要乘的数。
所以程序中要有函数inta_b_Mod_c(longa,longb,longc)计算aˆbmodc的值并返回结果。
inta_b_Mod_c(longa,longb,longc)
{intdigit[32];longi,k,resualt=1;
i=0;
while(b)
{digit[i++]=b%2;
b>>=1;}
for(k=i-1;k>=0;k--)
{resualt=(resualt*resualt)%c;
if(digit[k]==1){resualt=(resualt*a)%c;}
}
returnresualt;
}
2.总操作界面:
1.输入两个素数P,Q
2.输入公钥E
3.查看当前密钥信息
4.加密
5.解密
6.帮助
0.退出
三.程序实现流程图:
(1)流程图:
(2)各功能模块:
命令
对应函数
功能描述
1
input_P_Q
输入素数P,Q
2
input_E
输入公钥E
3
print_miyao
显示密钥信息
4
jiami
加密
5
jiemi
解密
6
print_help
帮助
四.程序测试:
1输入两个素数p=47,q=71则n=47*71=3337
2.输入e=79,计算得d=eˆ-1mod(p-1)(q-1)=79ˆ-1mod3220=1019因此公钥为(79,3337)私钥为(1019,3337)
3.输入明文688并加密
4.输入密文1570并解密
五.总结、改进思考:
1.大数类库的建立:
本程序作为RSA加密解密过程演示程序,变量均为long型,因此密钥长度较小,而RSA的安全性建立在密钥长度很长,大素数难以分解的前提上。
所以为了能够提高安全性,应该建立一个大数类库,对512位或1024位大数进行存取,及简单运算。
一个最容易理解的方法就是将大数用十进制表示,并将每一位(0–9)都做为一个单独的数用数组进行管理。
做加减乘除等运算时,人工的对其进行进、借位。
然而计算机对于10进制数的处理并不在行,而且表示非2n进制的数会浪费很多空间,所以应该采用8进制、16进制、32进制、64进制的表示法,使得每一位数字都能占据一个完整的内存空间。
目前绝大多数PC机都是基于32位运算的,所以采用2ˆ32进制表示大数将会很大提高计算机的处理效率。
现实中,就使用32位的整数数组进行存储每一位数,另设一个布尔值表示正负。
进行计算时常会遇到进位借位的情况,而且常常会超过2ˆ32次方,幸好目前的编译器都支持64位整数,可以满足(232-1)*(232-1)以内的运算,所以使用64位整数作为运算中间量将会是很好的选择。
大数除了加减乘除等基本运算以外,还有一些如赋值、比较、左右移位、或、与等,为了方便使用,我们可以利用面向对象的方法把大数进行封装,并利用C++的特性进行运算符重载,使它成为一个整体对象来进行操作。
这样我们就可像使用int一样来使用它了。
2.大素数随机生成,以及判断:
真正的RSA加密时密钥的生成应该是自动完成的,而不是用户手动制定p,q,e。
所以在使用大数类库后随之而来一个问题就是如何随机的生成两个大素数,以及大素数的判断。
由于素数有无穷多个,且没有固定的生成方式,所以大素数的生成基本是采用在一定范围内(比如奇数,且不会被小素数整除的)随机选取大数后再进行素数检测,直到有通过检测的数。
因此大数的素数检测算法就是关键了,如果按照之前的素数检测算法需要依次除2到√n的数,时间复杂度O(√n)太大。
所以我们要用更为快速的算法。
米勒拉宾测试是一个不确定的算法,只能从概率意义上判定一个数可能是素数。
是目前公认的最高效的素性测试之一。
大体步骤如下:
输入奇数n,判断n为素数或者合数。
计算r和R,使得,R奇。
随即选择a,。
fori=0tor,计算。
若,则输入合数。
若,则输入素数。
设j=max{i:
},则输入素数。
若,则输出素数,否则输出合数。
参考书目:
[1]刘嘉勇等《应用密码学》
[2]胡道元闵京华《网络安全》
[3]张四兰等《可信赖的高效素数生成和检验算法》
附程序代码:
#include
#include
#include
voidinput_P_Q(long&P,long&Q,long&N,long&N1);
voidinput_E(long&E,long&D,longn1);
voidprint_miyao(longe,longn,longd);
voidjiami(longe,longn);
voidjiemi(longd,longn);
voidprint_help();
intsushu(longm);
intgcd(longa,longb);
longExtendedEuclid(longf,longd,long*result);
inta_b_Mod_c(longa,longb,longc);
voidmain()
{
longP=0,Q=0,E=0,N=0,N1=0,D=0;
cout<<"==========================RSA模拟=====================