公钥密码学
1976年Diffie和Hellman针对上面的问题提出了单向函数加密方法,这种方法和之前数千年来密码学中的所有方法有根本的区别,即公钥密码体制。
非对称加密算法使用完全不同但又是完全匹配的一对钥匙: 公钥和私钥 公钥:公开的,任何人都知道
私钥:只有自己知道
算法:一对密钥中用公钥加密的结果可以用私钥解密,反过来用私钥加密的结果也可以用公钥解密。
公钥加密的使用方式
Alice和Bob互发(公布)各自的公钥,私钥只有自己知道
Alice用对称密钥加密信件,再用Bob的公钥加密对称密
Bob用自己的私钥解密对称密钥,再用对称密钥解密信
公钥密码学与对称密码学比较
对称密码学基于替换和置换(混淆和扩散),运算速度快
公钥密码学基于数学理论(单向函数),运算速度慢
对称密码学使用单密钥,需要额外秘密信道协商密钥
公钥密码学使用两个独立的密钥,不需要秘密信道协商密钥
RSA算法
RSA算法1977年由MIT三位密码学家Rivest - Shamirh和Adleman发明,是迄今为止最为成熟完善的公钥密码体制。
RSA算法能够抵抗到目前为止已知的绝大多数密码攻击,已被ISo推荐为公钥数据加密标准。
RSA原理
公钥和私钥的产生
任意选择两个大的质数(素数)p和q,p不等于q,计算N=pq
根据欧拉函数,不大于N且与N互质的整数个数为(p-1)(q-1)
选择一个整数e 与(p-1)(q-1)互质,并且e小于(p-1)(q-1)
用以下这个公式计算d: dxe = 1(mod(p-1)(q-1))
将p和q销毁后,(N,e)是公钥, (N,d)是私钥
加密消息
假设Bob想给Alice送一个消息,他知道Alice产生的公钥N和e
将原始信息分为多段,每一段(假定为n)分别用以下公式计算出c : n^e= c (mod N)
将多个n计算出的多个c串在一起,就是密文,发送即可。
解密消息
Alice得到Bob的消息c后就可以利用她的密钥( N,d)来解码。她可以用以下这个公式来将c转换为n : c=n (mod N)
得到n后,她可以将原来的信息m重新复原。
RSA应用
加密少量数据
比起DES和其它对称算法来说, RSA的运算速度要慢得多。
实际使用时,RSA算法不用来加密消息,而是用来加密传输密钥,加密消息用对称算法,如 DES 。
实现数字签名
将RSA 算法反向使用(私钥加密公钥解密),对消息摘要加密,可以实现数字签名的功能。
数字签名可以防止数据篡改﹑数据抵赖和数据伪造发生。
RSA算法源码
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;
int prime[1305];//存放素数
int p[10005];//用筛选法求素数
void PRIME(){
int i,i2,k;
for(i=0;i<=10000;i+=2)
p[i]=0;
for(i=1;i<=10000;i+=2)
p[i]=1;
p[2]=1;p[1]=0;
for(i=3;i<=100;i+=2){
if(p[i]==1){
i2=i+i;
k=i2+i;
while(k<=10000){
p[k]=0;
k+=i2;
}
}
}
prime[0]=1;
prime[1]=2;
for(i=3;i<=10000;i+=2)
if(p[i])
prime[++prime[0]]=i;
}
// 计算逆元素
__int64 mod(__int64 a,__int64 n){
return (a%n+n)%n;
}
void gcd(__int64 a,__int64 b,__int64 &d,__int64 &x,__int64 &y){
if(b==0)
{
d=a;
x=1;
y=0;
return;
}
gcd(b,a%b,d,y,x);
y-=x*(a/b);
}
//a-1 mod n
__int64 Inv(__int64 a,__int64 n){ // 计算逆元素
__int64 d,x,y;
gcd(a,n,d,x,y);
if(d==1)
return mod(x,n);
else
return -1;
}
//求两个数的最大公约数
__int64 GCD(__int64 n,__int64 m){
__int64 t,r;
if(n<m){
t=n;
n=m;
m=t;
}
while((r=n%m)!=0){
n=m;
m=r;
}
return m;
}
//x=a^b(mod n)
__int64 ModPow(__int64 a,__int64 b,__int64 n){
__int64 d=1,i=0;
while(b>=(1<<i)) i++;
for(--i;i>=0;--i){
d=d*d%n;
if(b&(1<<i))
d=d*a%n;
}
return d;
}
int main(){
__int64 i,e,d,n,st,ed,eula;
__int64 m,c,ans;
PRIME();
printf("素数的个数:%d\n",prime[0]);
printf("选择两个不同的素数(输入编号,空格隔开):\n");//47和71分别是第15个和20个
while(scanf("%I64d%I64d",&st,&ed)!=EOF){
printf("你选择的两个素数分别是:%d和%d\n",prime[st],prime[ed]);
n=prime[st]*prime[ed];
printf("计算得到N是%I64d\n",n);
//N的Eula数
eula=(prime[st]-1)*(prime[ed]-1);
//找一个与eula互质的数
for(i=2;i<eula;i++)
if(GCD(eula,i)==1){
e=i;
break;
}
//e=79;
//上面找到了公开密钥n--e
d=Inv(e,eula);
//上面找到了私密钥n--d
printf("生成公钥:(%I64d %I64d)\n",e,n);
//输出密钥
printf("生成私钥:(%I64d %I64d)\n",d,n);
//切忌加密的数要比n小
printf("请输入要加密的数(<N)\n");
scanf("%I64d",&m);
c=ModPow(m,e,n);
printf("通过计算%I64d^%I64d(mod %I64d)得到密文=%I64d\n",m,e,n,c);
ans=ModPow(c,d,n);
printf("通过计算%I64d^%I64d(mod %I64d)得到明文=%I64d\n",c,d,n,ans);
printf("素数的个数:%d\n",prime[0]);
printf("选择两个不同的素数(输入编号,空格隔开):\n");//47和71分别是第15个和20个
}
return 0;
}