RSA 加密概述
RSA使用公开密钥密码体制。所谓的公开密钥密码体制就是使用不同的加密密钥与解密密钥,是一种“由已知加密密钥推导出解密密钥在计算上是不可行的”密码体制。
在公开密钥密码体制中,加密密钥(即公开密钥)PK是公开信息,而解密密钥(即秘密密钥)SK是需要保密的。加密算法E和解密算法D也都是公开的。虽然解密密钥SK是由公开密钥PK决定的,但却不能根据PK计算出SK。
RSA广泛应用于计算机网络及通信领域,是目前使用最广泛的加密算法
RSA 加密过程
RSA 加密使用的数学知识
素数
素数又称质数,指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数。
互质数
指两个数中,最大公因子为1的数称为互质数,不是质数也可以构成互质关系。如15和32。
欧拉函数
也就是说,a的φ(n)次方被n除的余数为1。或者说,a的φ(n)次方减去1,可以被n整除。比如,3和7互质,而7的欧拉函数φ(7)等于6,所以3的6次方(729)减去1,可以被7整除(728/7=104)。
理解欧拉函数是掌握RSA加密的关键
模反元素
加密算法
随意选择两个大的质数p和q,p不等于q,计算N=p*q。
根据欧拉函数,求得r = (p-1)(q-1)
选择一个小于 r 的整数 e,求得 e 关于模 r 的模反元素,命名为d。(模反元素存在,当且仅当e与r互质)
将 p 和 q 的记录销毁。
算法示例
已知RSA算法中,素数p=5,q=7,模数n=35,公开密钥e=5,密文c=10,求明文。手工完成RSA公开密钥密码体制加密运算。
解:
1. 求出n = p*q = 35;
2. 根据欧拉函数r = (p-1)*(q-1) = 24;
3.题中e = 5,满足e < r ,并且e r 互质.
4.求出d,e*d%t == 1 d为e的模反元素
5. 此时e,d,n均以求出,开始进行加密.
6. 密文c进行反向解密
7. M = c^d%n = 10^5%35 = 5;
8. 明文为5
9. ======用加密进行验算=======
10. m = M^e%n = 10 == c 结果正确
这个例子中,(n,e)为私钥,(n,d)为公钥,可以看出加密用的是公钥,解密用的是私钥。
所以数字签名广泛使用RSA算法
RSA也可以用来为一个消息署名。假如甲想给乙传递一个署名的消息的话,那么她可以为她的消息计算一个散列值(Message digest),然后用她的密钥(private key)加密这个散列值并将这个“署名”加在消息的后面。这个消息只有用她的公钥才能被解密。乙获得这个消息后可以用甲的公钥解密这个散列值,然后将这个数据与他自己为这个消息计算的散列值相比较。假如两者相符的话,那么他就可以知道发信人持有甲的密钥,以及这个消息在传播路径上没有被篡改过。
再来一个示例:
假设p = 3、q = 11(p,q都是素数即可。),则N = pq = 33;
r = (p-1)(q-1) = (3-1)(11-1) = 20;
根据模反元素的计算公式,我们可以得出,e·d ≡ 1 (mod 20),即e·d = 20n+1 (n为正整数);我们假设n=1,则e·d = 21。e、d为正整数,并且e与r互质,则e = 3,d = 7。(两个数交换一下也可以。)
到这里,公钥和密钥已经确定。公钥为(N, e) = (33, 3),密钥为(N, d) = (33, 7)。
编程实现
import java.util.Scanner;
public class RSATest {
private static int KeyE; // 公钥
private static int KeyD; // 私钥
private static long MSG; // 待加密消息
private static int BASE = 3*11; // 基数,两个质数相乘
// 输入格式,请依次输入公钥,私钥和待加密的数据
// 如 7 3 5
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
KeyE = scan.nextInt();
KeyD = scan.nextInt();
MSG = scan.nextInt();
long encodeMsg = (long) Math.pow(MSG, KeyE)%BASE;
long decodeMsg = (long) (Math.pow(encodeMsg, KeyD)%BASE);
System.out.println("原数据:"+MSG);
System.out.println("加密后数据: "+encodeMsg);
System.out.println("解密加密后的数据: "+decodeMsg);
scan.close();
}
}