课程设计要求:
编写RSA算法的加解密程序,运行并验证。
(1)编程实现判断整数为素数和求模逆及模幂的算法:对于随机产生的一个正整数,使用Miller-Rabin素性检验算法判断输入的整数是否为素数;输入两个正整数,使用扩展的欧几里德算法判断两个整数互素并求出一个整数关于另一个整数的逆元;输入指数、底数和模数,使用快速指数算法完成模幂运算。
(2)将(1)中的算法整合实现RSA加解密算法:完成p和q的选取,公私钥的产生,以及对输入明文的加密和对密文的解密。
(3)要求实验报告中有对应的原理概述、算法分析、程序设计过程(包含调试记录)、程序源代码、程序验证记录和程序设计总结。
实验条件:
(1)主要设备: 586或更高机型,256MB或更高的内存,40G或更大的硬盘。
(2)主要软件:
①操作系统可为Windows9X、WinMe、Win2000或更高版本等;
②开发环境为VC++6.0或者TC++3.0。
(3)参考书目:
①《现代密码学》杨波编著清华大学出版社
实验三个主要准备内容:
实验在进行之前,我们先对这三个知识进行了学习,了解了RSA编程的思想,之后开始编程实践。
1)欧几里得算法求最大公约数
欧几里得算法又称辗转相除法,是指用于计算两个非负整数a,b的最大公约数。应用领域有数学和计算机两个方面。计算公式gcd(a,b) = gcd(b,a mod b)。算法的的基本步骤如下:
①给定两正整数m,n
②选取其中较小的数,假定为m
③若n%m非0,即存在余数,将n和m中较大的数n替换为余数,返回②
④若n%m为0,则最大公约数为m
2)Miller-Rabin素性概率检测法
素性测试(即测试给定的数是否为素数)是近代密码学中的一个非常重要的课题。虽然Wilson定理(对于给定的正整数n,n是素数的充要条件)给出了一个数是素数的充要条件,但根据它来素性测试所需的计算量太大,无法实现对较大整数的测试。目前,尽管高效的确定性的素性算法尚未找到,但已有一些随机算法可用于素性测试及大整数的因数分解。Miller-Rabin素性测试算法就是一个这样的算法。
Miller-Rabin素性测试算法的核心为费马小定理:
假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。逆推⼀下即p的 a^(p-1)%p !=1 (0
3)RSA算法
RSA公开密钥密码体制是一种使用不同的加密密钥与解密密钥,“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。
实验方法与步骤:
算法分析:
代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
int prime[10]={2,3,5,7,11,13,17,19,23,29};
_int64 Quick_Multiply(int a,int b,int c) //快速积(和快速幂差不多)
{
long ans=0,res=a;
while(b)
{
if(b&1)
ans=(ans+res)%c;
res=(res+res)%c;
b>>=1;
}
return (int)ans;
}
int Quick_Power(int a,int b,int c) //快速幂
{
int ans=1,res=a;
while(b)
{
if(b&1)
ans=Quick_Multiply(ans,res,c);
res=Quick_Multiply(res,res,c);
b>>=1;
}
return ans;
}
bool Miller_Rabin(int x) //判断素数
{
int i,j,k;
int s=0,t=x-1;
if(x==2) return true; //2是素数
if(x<2||!(x&1)) return false; //如果x是偶数或者是0,1,那它不是素数
while(!(t&1)) //将x分解成(2^s)*t的样子
{
s++;
t>>=1;
}
for(i=0;i<10&&prime[i]<x;++i) //随便选一个素数进行测试
{
int a=prime[i];
int b=Quick_Power(a,t,x); //先算出a^t
for(j=1;j<=s;++j) //然后进行s次平方
{
k=Quick_Multiply(b,b,x); //求b的平方
if(k==1&&b!=1&&b!=x-1) //用二次探测判断
return false;
b=k;
}
if(b!=1) return false; //用费马小定律判断
}
return true; //如果进行多次测试都是对的,那么x就很有可能是素数
}
//n大于a
int Euclid(_int64 a, _int64 n){
_int64 x, y, r, c;
x = n; y = a;
for (int i = 0;;){
if (y == 0)
return x;
if (y == 1)
return y;
c=int(x/y);
r=x-c*y;
x = y;
y = r;
}
}
_int64 extenEuclid (_int64 a,_int64 b,int &x,int &y) { //用递归算法实现
if (b == 0) {
x = 1, y = 0;
return a;
}
int r = extenEuclid(b, a % b, y, x);
y -= (a / b) * x;
return r;
}
int main()
{
int x1,y1,q,p;
printf(“请输入p:”);
scanf(“%ld”,&p);
while(!Miller_Rabin(p))//用Miller_Rabin判断p是否为素数
{
printf(“输入的p不是素数,请重新输入p:”);
scanf(“%ld”,&p);
}
printf(“请输入q:”);
scanf(“%ld”,&q);
while(!Miller_Rabin(q))
{
printf(“输入的q不是素数,请重新输入q:”);
scanf(“%d”,&q);
}
_int64 n1,fn1;
n1 = p*q; fn1 = (q – 1)*(p – 1);//选e与fn互素
printf(“n1 = p*q=%d\n”,n1);
printf(“fn1 = (p-1)*(q-1)=%d\n”,fn1);
int e1,d1;
for (e1 = 2; e1<fn1; e1 += 1){
if (Euclid(e1, fn1) == 1)//fn与e互素
break;
}
d1 = (extenEuclid (e1, fn1, x1, y1) == 1 ” />while(d1<0)//保证d是大于0的数
{
d1=d1+n1;
}
//以n, e为公钥, 私钥为d
printf(“e1=%d\n”,e1);
printf(“d1=%d\n”,d1);
//对输入明文进行加密 a^k=b(mod m)
_int64 m1;
printf(“请输入明文m(数字):”);
scanf(“%ld”,&m1);
_int64 c1=Quick_Power(m1,e1,n1);
printf(“密文为:%d\n”,c1);
//对输入密文进行解密
_int64 m2,c2;
printf(“请输入密文c(数字):”);
scanf(“%ld”,&c2);
m2=Quick_Power(c2,d1,n1);
printf(“明文为:%ld\n”,m2);
return 0;
}
实验总结:
RSA算法是一种用数论构造的也是迄今为止理论上最为成熟完善的公钥密码体制。该算法分为三步密钥的产生、加密、解密。
密钥的产生:
本次实验可谓是收获颇多,了解到了RSA算法的基本过程,用Miller-Rabin算法判断检验p和q是否为素数,其中还用到了费马小引理,对于指数的问题,可采用快速指数算法求解。在这个过程中也遇到了诸多的问题,比如VC6.0++中没有longlong这个类型使用int类型会过小,会出现溢出错误,后查阅资料可用_int64来扩大数的选取范围; 求逆元d时会出现d为负数的情况,不能用快速指数算法。对于本次实验实现的算法仍有不足之处,比如整数e的选取并不能达到随机选取,希望后续能将此算法进行改进,能够更加优化实现。
RSA算法属于非对称加密算法的一种,也是目前世界上最重要的加密算法。我们学习该算法时,发现在书面上实现较为容易。而再将其写为代码的过程中,我们遇到了一定的困难。
首先是利用Miller-Rabin素性检验算法判断输入的整数是否为素数,我们对该算法不够了解,故而在代码上始终存在问题。经过不断的学习、查找资料,并辅以网站的学习视频,终于解决了该问题,而在这个过程中,我们也收获颇多。
后来,我们在返回e和d的过程中也出现了各种奇怪的问题,比如:明明写了限制条件,使得d>0,但是最终返回的d还是为负数,我们不思其解,通过不断翻阅资料以及不断调试程序,我们试着将变量的取值范围扩大,最终解决了这个问题。
在之后,在扩展的欧几里得算法初,明明算法是正确的,但是返回的结果明显错误。我们试着修改算法,却发现结果仍错误,突然,我们发现了关键所在:返回值不对。算法并没有问题,只是返回值不对。这也让我们意识到我们仍需加强对基础知识的学习。
经过本次实验,我们对RSA算法有了更深的认识和了解。收获良多。
若有侵权请联系删除。如有疑问,欢迎私信。