实验二 RSA数字签名
(1)了解RSA算法的特点
(2)掌握RSA算法的加解密原理
(3)掌握RSA数字签名算法的原理
二、实验内容
RSA 公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。
RSA 算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。
RSA 的算法涉及三个参数,n、e1、e2。其中,n是两个大质数 p、 q 的积, n 的二进制表示时所占用的位数,就是所谓的密钥长度。e1 和 e2 是一对相关的值, e1 可以任意取,但要求 e1 与 (p-1)*(q-1 )互质; 再选择 e2,要求( e2*e1 )mod((p-1 )*(q-1 ))=1 。( n,e1),(n,e2)就是密钥对。其中 (n, e1)为公钥, (n, e2)为私钥。
RSA 加解密的算法完全相同, 设 A 为明文, B 为密文,则: A=B^e2 mod n ;B=A^e1 mod n ;(公钥加密体制中,一般用公钥加密,私钥解密)e1 和 e2 可以互换使用,即:A=B^e1 mod n ; B=A^e2 mod n;
密钥生成:
首先要使用概率算法来验证随机产生的大的整数是否质数,这样的算法比较快而且可以消除掉大多数非质数。假如有一个数通过了这个测试的话,那么要使用一个精确的测试来保证它的确是一个质数。
密钥分配:
和其它加密过程一样,对RSA 来说分配公钥的过程是非常重要的。分配公钥的过程必须能够抵挡一个从中取代的攻击。假设 Eve 交给 Bob 一个公钥,并使Bob 相信这是 Alice 的公钥,并且她可以截下Alice 和 Bob 之间的信息传递,那么她可以将她自己的公钥传给 Bob,Bob 以为这是 Alice 的公钥。
步骤如下(这里设B 为实现的)
( 1)B 寻找出两个大素数 p 和 q。
( 2)B 计算出 n=p*q 和 (n) =( p-1) * ( q-1)。
( 3)B 选择一个随机数e( 0<e< (n) ) ,满足( e, (n))=1 (即 e 与欧拉函数互素(n))。
( 4)B 使用欧几里得算法计算e 的模余(n)的乘法逆元素d。
( 5)B 在目录中公开 n 和 e 作为他的公开密钥,保密p、q 和 d。
开始 |
输入两个素数p、q
|
输入不等于N公约数的e
|
调用ExtendEuclid(e,N,&d)
|
找出N=(p-1)*(q-1)的所有公约数
|
开始加密调用Encryption()
|
调用Prime()
|
Yes
|
No
|
输出明文,结束 |
i=0
|
i++
|
输入明文长度Len及明文
|
调用multiplication(m1[i],e,n)
|
i<len |
Yes
|
i=0
|
No
|
输出密文
|
开始解密调用Decipher()
|
i<len |
调用multiplication(m1[i],e,n)
|
i++
|
Yes
|
No
|
加密时,对每一明文m 计算密文cΞme ( modn )
解密时,对每一密文c 计算明文mΞcd ( modn )
算法流程图如下所示:
三、实验结果:
四、实验源代码:
#include<iostream.h>
#include<math.h>
#include<stdio.h>
typedef int Elemtype;
Elemtype p,q,e;
Elemtype fn;
Elemtype m,c;
int flag=0;
typedef void(*Msghandler)(void);
struct MsgMap{
char ch;
Msghandler handler;
};
/* 公钥*/
struct PU{
Elemtype e;
Elemtype n;
}pu;
/* 私钥*/
struct PR{
Elemtype d;
Elemtype n;
}pr;
/* 判定一个数是否为素数*/
bool test_prime(Elemtype m){
if(m<=1){
return false;
}
else if(m==2){
return true;
}
else{
for(int i=2;i<=sqrt(m);i++){
if((m%i)==0){
return false;
break;
}
}
return true;
}
}
/* 将十进制数据转化为二进制数组*/
void switch_to_bit(Elemtype b,Elemtype bin[32]){
int n=0;
while(b>0){
bin[n]=b%2;
n++;
b/=2;
}
}
/* 初始化主界面*/
void Init(){
cout<<"******************************************"<<endl;
cout<<"*** Welcome to use RSA encoder ***"<<endl;
cout<<"*** 1.setkey ***"<<endl;
cout<<"*** 2.加密***"<<endl;
cout<<"*** 3.解密***"<<endl;
cout<<"*** 4.退出***"<<endl;
cout<<"******************************************"<<endl;
cout<<"press a key:"<<endl;
}
/* 将两个数排序,大的在前面*/
void order(Elemtype &in1,Elemtype &in2){
Elemtype a=(in1>in2?in1:in2);
Elemtype b=(in1<in2?in1:in2);
in1=a;
in2=b;
}
/* 求最大公约数*/
Elemtype gcd(Elemtype a,Elemtype b){
order(a,b);
int r;
if(b==0){
return a;
}
else{
while(true){
r=a%b;
a=b;
b=r;
if(b==0){
return a;
break;
}
}
}
}
/* 用扩展的欧几里得算法求乘法逆元*/
Elemtype extend_euclid(Elemtype m,Elemtype bin){
order(m,bin);
Elemtype a[3],b[3],t[3];
a[0]=1,a[1]=0,a[2]=m;
b[0]=0,b[1]=1,b[2]=bin;
if(b[2]==0){
return a[2]=gcd(m,bin);
}
if(b[2]==1){
return b[2]=gcd(m,bin);
}
while(true){
if(b[2]==1){
return b[1];
break;
}
int q=a[2]/b[2];
for(int i=0;i<3;i++){
t[i]=a[i]-q*b[i];
a[i]=b[i];
b[i]=t[i];
}
}
}
/* 快速模幂算法*/
Elemtype modular_multiplication(Elemtype a,Elemtype b,Elemtype n){
Elemtype f=1;
Elemtype bin[32];
switch_to_bit(b,bin);
for(int i=31;i>=0;i--){
f=(f*f)%n;
if(bin[i]==1){
f=(f*a)%n;
}
}
return f;
}
/* 产生密钥*/
void produce_key(){
cout<<" 输入素数p 和q:";
cin>>p>>q;
while(!(test_prime(p)&&test_prime(q))){
cout<<" 输入错误,请重新输入!"<<endl;
cout<<" 输入素数p 和q:";
cin>>p>>q;
};
pr.n=p*q;
pu.n=p*q;
fn=(p-1)*(q-1);
cout<<"fn 为: "<<fn<<endl;
cout<<" 输入随机数e:";
cin>>e;
while((gcd(fn,e)!=1)){
cout<<"e 输入错误,请重新输入!"<<endl;
cout<<" 输入随机数e:";
cin>>e;
}
pr.d=(extend_euclid(fn,e)+fn)%fn;
pu.e=e;
flag=1;
cout<<" 公钥(e,n) :"<<pu.e<<","<<pu.n<<endl;
cout<<" 私钥d:"<<pr.d<<endl;
cout<<" 请输入下一步操作序号:"<<endl;
}
/* 加密*/
void encrypt(){
if(flag==0){
cout<<"setkey first:"<<endl;
produce_key();
}
cout<<" 输入明文m:";
cin>>m;
c=modular_multiplication(m,pu.e,pu.n);
cout<<" 密文c 为:"<<c<<endl;
cout<<" 请输入下一步操作序号:"<<endl;
}
/* 解密*/
void decrypt(){
if(flag==0){
cout<<"setkey first:"<<endl;
produce_key();
}
cout<<" 输入密文c:";
cin>>c;
m=modular_multiplication(c,pr.d,pr.n);
cout<<" 明文m 为:"<<m<<endl;
cout<<" 请输入下一步操作序号:"<<endl;
}
/* 消息映射*/
MsgMap Messagemap[]={
{'1',produce_key},
{'3',decrypt},
{'2',encrypt},
{'4',NULL}
};
/* 主函数,提供循环*/
void main(){
Init();
char d;
while((d=getchar())!='4'){
int i=0;
while(Messagemap[i].ch){
if(Messagemap[i].ch==d){
Messagemap[i].handler();
break;
}
i++;}
} }
五、实验心得:
通过本次试验学会了RSA算法的基本特点,掌握了RSA算法的加解密原理。
特别要注意的是,RSA 的算法的三个参数,n、e1、e2。其中,n是两个大质数p、 q 的积, n 的二进制表示时所占用的位数,就是所谓的密钥长度。e1 和 e2 是一对相关的值, e1 可以任意取,但要求 e1 与 (p-1)*(q-1 )互质; 再选择 e2,要求( e2*e1 )mod((p-1 )*(q-1 ))=1 。( n,e1),(n,e2)就是密钥对。其中 (n, e1)为公钥, (n, e2)为私钥。理解互质,公钥与私钥之间的关系非常重要。