1. 程式人生 > >RSA公鑰加密+(Euclid)歐幾里德擴充套件演算法

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的值。