RSA加密算法
RSA简介
RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。但在分布式计算和量子计算机理论日趋成熟的今天,RSA加密安全性受到了挑战。
RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。
RSA确定公钥和私钥步骤
(1)选择p,q,其中p,q为大素数。
(2)计算乘积n=p*q。
(3)求小于n且与n互质的数的个数,利用欧拉函数得到ϕ (n)=(p-1)(q-1)。
(4)随机选择整数e, 使 gcd(ϕ (n),e)=1,1<e<ϕ (n)。
(5)计算d,使d ≡ e -1mod ϕ(n)。
然后将(n,e)公开作为公钥PK(public key),将(p,q,d)私藏作为私钥SK(secret key)。
加密解密操作
(1)加密 (用e,n)
明文:0<M<n
密文:C≡M e (mod n)
(2)解密 (用d,n)
密文:C
明文:M ≡ C d (mod n)
扩展欧几里德算法解线性同余方程
其实在RSA产生密钥的过程中,最困难的一步就是通过e来获得d。因为这里需要用到扩展欧几里德算法来求线性同余方程,在讲述扩展欧几里德算法之前我先讲述欧几里德算法。
欧几里德算法
欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。
对于整数a,b一定存在这样的关系:a = kb+r。
而欧几里德算法是:gcd(a,b) = gcd(b,a%b)等同于gcd(a,b) = gcd(b,r)。
举个例子:求8和6的最大公约数。
gcd(8,6) = gcd(6,8%6) = gcd(6,2):也就是说8和6的最大公约数与6和2的最大公约数是一致的。
扩展欧几里德算法
扩展的欧几里德算法:对于不完全为 0 的非负整数 a,b,gcd(a,b)表示 a,b 的最大公约数,必然存在整数对 x,y ,使得 gcd(a,b)=ax+by。
ax+by = gcd(a , b)
bx1+(a%b)x2 = gcd(b ,a%b)
.......这样一直递推下去,直到a%b的这一项为0的时候停止,这是可以设置xn = 1 , 设置yn为任意数,一般我们设置为0。
由于根据欧几里德算法,每一个等式右边都是相等的,所以对于第一个第二个等式我们可以得到递推公式,求解过程如下:
ax + by = bx1 + (a%b)y1
= bx1 + (a – (a/b)*b)y1
= bx1 + ay1 – (a/b)y1*b
= ay1+ (x1 – (a/b)y1)*b
所以递推公式为:x = x1 , y = x1– (a/b)y1
RSA结合扩展欧几里德算法
其实到这里,有些人一定还是比较困惑求解d和扩展欧几里德算法关系到底在哪。下面就来解决这个问题:
在确定RSA密钥的第五个步骤中,是:d ≡ e-1mod ϕ(n)
将其做简单的变形为:ed ≡ 1 mod ϕ(n)。也就是ed mod ϕ(n) = 1。还记得欧几里德算法中说:对于整数a,b都可以写成a = kb+r,那么可以将ed mod ϕ(n) = 1继续写成ed - ϕ(n)k = 1。这样将d看成是x,k看作是y,所以求解d的过程也就是求解扩展欧几里德算法中的x的过程。
下面给出用java实现RSA算法的代码:
import java.math.BigInteger;
public class RSASystem {
private BigInteger n = null;
private BigInteger p = null;
private BigInteger q = null;
private BigInteger totient = null;//欧拉函数
private BigInteger e = null;
private BigInteger d = null;
public RSASystem(BigInteger p, BigInteger q){
this.p = p;
this.q = q;
setKey();
}
public void setKey(){
this.n = p.multiply(q);
this.totient = (p.subtract(BigInteger.valueOf(1))).multiply(q.subtract(BigInteger.valueOf(1)));
this.e = getE();
BigInteger[] temp = eGcd(e, totient);
d = temp[0];
}
private BigInteger[] eGcd(BigInteger a, BigInteger b){
BigInteger[] result = new BigInteger[2];
if(b.compareTo(BigInteger.valueOf(0)) == 0){
result[0] = BigInteger.valueOf(1);
result[1] = BigInteger.valueOf(0);
return result;
}
BigInteger[] temp = eGcd(b, a.mod(b));
result[0] = temp[1];
result[1] = temp[0].subtract((a.divide(b)).multiply(temp[1]));
return result;
}
private BigInteger getE() {
return totient.divide(BigInteger.valueOf(4)).nextProbablePrime();
}
/**
* RSA加密函数
* @param m 需要进行加密操作的明文
* @return
*/
public BigInteger encode(BigInteger m){
return m.modPow(this.e, this.n);
}
/**
* RSA解密函数
* @param c 需要进行解密操作的密文
* @return
*/
public BigInteger decode(BigInteger c){
return c.modPow(this.d, this.n);
}
public static void main(String[] args) {
RSASystem rsa = new RSASystem(BigInteger.valueOf(47), BigInteger.valueOf(71));
System.out.println("rsa n:"+rsa.n);
System.out.println("rsa totient:"+rsa.totient);
System.out.println("rsa e:"+ rsa.e);
System.out.println("rsa d:"+ rsa.d);
System.out.println(rsa.encode(BigInteger.valueOf(40)));
System.out.println(rsa.decode(BigInteger.valueOf(2722)));
}
}
其中BigInteger[] eGcd(BigInteger a, BigInteger b)方法就是使用递归的方法来实现扩展欧几里德算法的求解,最后的放回结果是一个数组,数组的的一个元素就是x的值,第二个元素就是y的值。