RSA公鑰加密+(Euclid)歐幾里德擴充套件演算法
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的值。