RSA算法
RSA公钥加密算法是RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。1987年7月首次在美国公布,当时他们三人都在麻省理工学院工作实习。RSA就是他们三人姓氏开头字母拼在一起组成的。
RSA是目前最有影响力和最常用的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密标准。同时RSA算法还能用于数字签名,因此,RSA是被应用最为广泛的公钥密码算法之一。
RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥,即RSA算法是基于因子分解难题原理形成的加密算法。
RSA加密算法属于现代密码中的公钥密码机制。
1、RSA加密过程
RSA算法的关键是需要生成公钥和密钥;
- 选择两个大素数p和q,n = p * q;
- 则n的简化剩余系的个数(n的欧拉函数)φ(n) = (p - 1) (q - 1)。(由费马小定理容易证明)。
- 设RSA算法的公钥为e,私钥为d,选择较小素数e,保证 1 < e < φ(n), gcd(e,φ(n)) = 1,由式子:ed = 1 mod φ(n),计算私钥d的值;
- 公开n,e的值,保留p,q,d的值。即完成RSA密钥生成的过程;
- 加密时:设明文为m,密文为c,则c = me mod n;
- 解密时:m = cd mod n,即可完成解密。
RSA的安全性依赖于大数分解,但是否等同于大数分解一直未能得到理论上的证明,因为没有证明破解RSA就一定需要作大数分解。假设存在一种无须分解大数的算法,那它肯定可以修改成为大数分解算法。 RSA 的一些变种算法已被证明等价于大数分解。不管怎样,分解n是最显然的攻击方法。人们已能分解多个十进制位的大素数。因此,模数n必须选大一些,从安全性考虑,n的值至少要为1024~2048比特。
2、RSA数字签名过程
RSA算法同样能够应用于数字签名领域。
- 与RSA加密过程中的密钥生成阶段一样,生成公钥e和私钥d,并公开e和n,保留d;
- 在数字签名时,签名者计算 c = md mod n;
- 他人验证时,计算 m = ce mod n,即完成验证。
RSA算法的一般攻击方式
1、因子分解攻击
从上面RSA算法的加密过程我们可以看出模数n的重要性,如果我们知道了n的因子p和q的值,我们就能很容易的计算出**φ(n)**的值,进而通过 ed = 1 mod φ(n),就能计算出私钥d的值,进行破解。
因此,对RSA算法最直接的攻击方式就是因子分解攻击,但此方法也是最困难的方法,对于大数的因子分解到目前为止一直都是一个难题。
大数因子分解算法:Pollard’s Rho算法。能够较快找到一个合数的较小因子。
// 大数因子分解
public BigInteger rho(BigInteger N) {
BigInteger divisor;
BigInteger c = new BigInteger(N.bitLength(), random);
BigInteger x = new BigInteger(N.bitLength(), random);
BigInteger xx = x;
if (N.mod(TWO).compareTo(ZERO) == 0)
return TWO;
do {
x = x.multiply(x).mod(N).add(c).mod(N);
xx = xx.multiply(xx).mod(N).add(c).mod(N);
xx = xx.multiply(xx).mod(N).add(c).mod(N);
divisor = x.subtract(xx).gcd(N);
} while ((divisor.compareTo(ONE)) == 0);
return divisor;
}
public void factor(BigInteger M) {
BigInteger N = M;
if (N.compareTo(ONE) == 0)
return;
if (N.isProbablePrime(5)) {
p = N;
return;
}
BigInteger divisor = rho(N);
factor(divisor);
factor(N.divide(divisor));
}
Pollard’s Rho算法代码参考https://introcs.cs.princeton.edu/java/99crypto/PollardRho.java.html
因子分解攻击核心部分就是Pollard’s Rho算法,只要能够解出因子,剩下的部分就很容易了。
求乘法逆元方法,利用拓展欧几里得算法计算乘法逆元,计算求取私钥 d = e-1 mod φ(n);
//乘法逆元
public BigInteger inv(BigInteger A, BigInteger B){
BigInteger a = A, b = B;
BigInteger quotient, remainder, lastY;
BigInteger x = ZERO, y = ONE;
BigInteger X = ONE, Y = ONE;
while (!a.equals(ZERO)){
quotient = b.divide(a);
remainder = b.mod(a);
b = a;
a = remainder;
lastY = y;
y = y.multiply(quotient);
if (X.equals