RSA加密算法原理及RES簽名算法簡介(轉載)

第一部分:RSA算法原理與加密解密

1、RSA加密過程簡述java

A和B進行加密通訊時,B首先要生成一對密鑰。一個是公鑰,給A,B本身持有私鑰。A使用B的公鑰加密要加密發送的內容,而後B在經過本身的私鑰解密內容。算法

 

2、RSA加密算法基礎安全

整個RSA加密算法的安全性基於大數不能分解質因數。app

3、數學原理dom

(一)  互質關係:兩個數a和b沒有除1外的其餘公約數,則a與b互質函數

1.        任意兩個質數構成互質關係this

2.        兩個數中,若是大數爲質數,則兩數一定互質編碼

3.        1和任意整數互質加密

4.        當p>1時,p與p-1互質(相鄰兩數互質)spa

5.        當p=2n+1(n>0且n爲整數)時,p與p+2互質(相連的兩個奇數互質)

(二)  求歐拉函數:

定義:與正整數n互質且小於正整數n的正整數的個數。一般使用ψ(n)表示。

 

求取與正整數n互質的正整數的個數ψ(n),且ψ(n)知足ψ(n)∈(2,n)

1.        若是n=1,則ψ(n)=1

2.        若是n是質數,則ψ(n)=n-1

3.        若是n是質數p的次方,則:ψ(p^k)=p^k-p^(k-1) = p^k*(1-1/p)

4.        若p1和p2互質,n=p1*p2,則ψ(n)= ψ(p1*p2)= ψ(p1) ψ(p2)

5.        任意一個大於1的正整數均可以寫成一系列質數的積

6.        根據定理5,推導歐拉定理:

由於

         n = (p1^k1)* (p2^k2)*……(pr^kr)   (p1~pr都是質數)

因此

         ψ(n)= ψ((p1^k1)) ψ(p2^k2) ……ψ(pr^kr)   定理4

         ψ(n)= (p1^k1)*(1-1/p1) * (p2^k2)(1-1/p2)……(pr^kr)*(1-1/pr)   定理3

         ψ(n)= (p1^k1)* (p2^k2)*……(pr^kr) * (1-1/p1) (1-1/p2)…… (1-1/pr)

         ψ(n)=n (1-1/p1) (1-1/p2)…… (1-1/pr)  

(三)  歐拉定理:

正整數a與n互質,則下式恆成立

a^ψ(n) ≡1(mod n)

即:

         a的ψ(n)次冪除以n,餘數恆爲1

(四)  模反元素

若是兩個正整數a和n互質,則一定存在整數b使得a*b-1被n除餘數爲1

ab ≡1(mod n)

其中b被稱爲a的模反元素

 

4、RSA算法詳解:假設A和B要通訊

(一)  生成密鑰

1.        公鑰

1)        隨機生成兩個不相等的質數p和q(質數越大越安全)

2)        計算n,n=p*q 則n的二進制位數就是密鑰的長度。

3)        計算n的歐拉函數ψ(n)        

由於

n=p*q

因此

ψ(n) =ψ(p)* ψ(q)    定理4

又p和q爲質數

因此

ψ(p)=p-1    定理2

ψ(q)=q-1    定理2

因此

                   ψ(n) = (p-1)(q-1)

4)        獲取隨機正整數e,e知足  e∈(1, ψ(n))且e與ψ(n)互質(一般選擇65537)

將n和e封裝成公鑰

        

2.        私鑰

1)        計算e對於ψ(n)的模反元素d

e*d=1(modψ(n));

設正整數k, e*d = kψ(n)+1;

 

則ed-kψ(n)=1

  d = (kψ(n)+1) / e;

對於不定方程ax+by=c,設gcd(a,b)=d,若是ax+by=c有解,則d|c----->也就是說若是ed-kψ(n)=1 有解,則gcd(d,-k)可以整除1,而1顯然能夠被任何整數整除,因此該二元一次方程一定有解(d,k)

 

 (歐幾里得定理和擴展歐幾里得定理計算二元一次方程)

2)        將n和d封裝成私鑰

 

 

5、RSA算法可靠性論證

從上文能夠統計出整個算法涉及到的量有6個,其中三個爲由私鑰持有者生成,三個是私鑰持有者推導出來的

生成量:p,q,e

推導量:n, ψ(n),d

 

密鑰中只有公鑰被髮布,全部人均可以獲取。而公鑰由n和e封裝起來,所以,若是要破解一份RSA加密過的密文,咱們必須使用私鑰(私鑰由n和d封裝而成)

n能夠從公鑰獲取。

 

(假設mc爲明文,c爲密文,則公鑰由n和e封裝則意味着求取密文的運算中,n,e和mc是已知數,只有c是未知數;私鑰由n和d封裝,同上,解密密文的運算中,n,d和c是已知的,只有mc是未知數。)

 

所以,破解私鑰的關鍵就是破解e對於ψ(n)的模反元素d。

         其數學關係是:  e*d=1(modψ(n));

所以需須要先求出ψ(n),而求出ψ(n)須要知道ψ(p)和ψ(q)(由於ψ(n)= ψ(p* ψ(q))

 

而p和q只能經過分解n的質因數得到。因此,整個RSA算法都基於n這個大數不能分解質因數這個基礎上。

        

所以,只要n夠大,私鑰就不會被破解

 

 

6、加解密過程:假設明文是m,c是密文

(一)  加密:使用公鑰(n,e)

先將其換算成asc碼或者unicode等其餘數值。且m必須小於n

則加密算法是

         m^e=c(mod n)

推出

         m^e / n = k ……c這裏c就是密文,k咱們不關心

(二)  解密:使用私鑰(n,d)

1.        簡單的說解密就是經過下式求m。(必定能夠求解出m)

c^d = m(mod n)

推出
c^d / n = k … … m    m就是明文編碼,不關心k

 

查表得出明文

 

 

第二部分:RSA算法簽名與驗籤

 

假設A要想B發送消息,A會先計算出消息的消息摘要,而後使用本身的私鑰加密這段摘要加密,最後將加密後的消息摘要和消息一塊兒發送給B,被加密的消息摘要就是「簽名」。

B收到消息後,也會使用和A相同的方法提取消息摘要,而後使用A的公鑰解密A發送的來簽名,並與本身計算出來的消息摘要進行比較。若是相同則說明消息是A發送給B的,同時,A也沒法否定本身發送消息給B的事實。

其中,A用本身的私鑰給消息摘要加密成爲「簽名」;B使用A的公鑰解密簽名文件的過程,就叫作「驗籤」。

 

數字簽名的做用是保證數據完整性,機密性和發送方角色的不可抵賴性

 

下面是對簽名和驗簽過程的簡要描述:

 

l  簽名過程:

1.        A計算消息m的消息摘要,記爲 h(m)

2.        A使用私鑰(n,d)對h(m)加密,生成簽名s ,s知足:

s=(h(m))^d mod n;

因爲A是用本身的私鑰對消息摘要加密,因此只用使用s的公鑰才能解密該消息摘要,這樣A就不能否認本身發送了該消息給B。

3.        A發送消息和簽名(m,s)給B。

 

l  驗簽過程:

1.        B計算消息m的消息摘要,記爲h(m);

2.        B使用A的公鑰(n,e)解密s,獲得

H(m) = s^e mod n;

3.        B比較H(m)與h(m),相同則證實

 

第三部分:總結

 

下面簡單總結加密和解密的完整過程。

 

l  簽名過程:

1.        A提取消息m的消息摘要h(m),並使用本身的私鑰對摘要h(m)進行加密,生成簽名s

2.        A將簽名s和消息m一塊兒,使用B的公鑰進行加密,生成密文c,發送給B。

l  驗證過程:

1.        B接收到密文c,使用本身的私鑰解密c獲得明文m和數字簽名s

2.        B使用A的公鑰解密數字簽名s解密獲得H(m).

3.        B使用相同的方法提取消息m的消息摘要h(m)

4.        B比較兩個消息摘要。相同則驗證成功;不一樣則驗證失敗。

 

下面是借鑑一個網友的Demo,加上我本身註釋後,打包的一個Demo。

 

EnAndDe.java

 

package com.joe.main;

import java.io.*;
import java.math.BigInteger;
import java.util.ArrayList;

/**
 * <p>
 * Company: 建工學院
 * </p>
 * 
 * @author 04信息(1)程晟
 * @modify Joe
 * @Description Demo說明:
 *              一、按照加密解密和簽名驗籤的邏輯,編寫簡單的demo,不涉及java中繼承的RSA相關類和Sigesture簽名類
 *              二、只能對數字和字母進行加密, 不涉及編碼和解碼問題 。 三、不作數字簽名和驗證了,涉及到提取信息摘要。
 */
public class EnAndDe {
	private long p = 0;
	private long q = 0;
	private long n = 0;
	private long t = 0; // 歐拉函數

	private long e = 0; // 公匙
	private long d = 0; // 密匙

	private String mc; // 明文
	private long c = 0; // 密文
	private long word = 0; // 解密後明文

	// 判斷是一個數 x 否爲素數素數就是判斷在 (2,√x)範圍內有沒有除1外的因數,若是沒有則x數素數
	public boolean isPrime(long t) {
		long k = 0;
		k = (long) Math.sqrt((double) t);
		for (int i = 2; i <= k; i++) {
			if ((t % i) == 0) {
				return false;
			}
		}
		return true;
	}

	// 隨機產生大素數(1e6數量級,注意,太大了要超出範圍)
	public void bigprimeRandom() {
		do {
			p = (long) (Math.random() * 1000000);
		} while (!this.isPrime(p));
		do {
			q = (long) (Math.random() * 1000000);
		} while (p == q || !this.isPrime(q));
	}

	// 輸入PQ
	public void inputPQ() throws Exception {

		this.bigprimeRandom();
		System.out.println("自動生成兩個大素數p,q分別爲:" + this.p + " " + this.q);

		this.n = (long) p * q;
		this.t = (long) (p - 1) * (q - 1);

		System.out.println("這兩個素數的乘積爲p*q:" + this.n);
		System.out.println("所得的t=(p-1)(q-1):" + this.t);
	}

	// 求最大公約數
	public long gcd(long a, long b) {
		long gcd;
		if (b == 0)
			gcd = a;
		else
			gcd = gcd(b, a % b);
		return gcd;

	}

	// 生成公匙
	public void getPublic_key() throws Exception {
		do {

			this.e = (long) (Math.random() * 100000);
			// e知足 e∈(1, ψ(n))且e與ψ(n)最大公約數爲1,即 e與t互質
		} while ((this.e >= this.t) || (this.gcd(this.t, this.e) != 1));
		System.out.println("生成的公鑰爲:" + "(" + this.n + "," + this.e + ")");
	}

	// 生成私鑰 e*d=1(modψ(n))==> d = (kψ(n)+1) / e
	public void getPrivate_key() {
		long value = 1; // value 是e和d的乘積
		outer: for (long k = 1;; k++) {
			value = k * this.t + 1;
			if ((value % this.e == 0)) {
				this.d = value / this.e;
				break outer;
			}
		}
		System.out.println("產生的一個私鑰爲:" + "(" + this.n + "," + this.d + ")");
	}

	// 輸入明文
	public void getText() throws Exception {
		System.out.println("請輸入明文:");
		BufferedReader stdin = new BufferedReader(new InputStreamReader(
				System.in));
		mc = stdin.readLine();

	}

	// 解密密文
	public void pascolum() throws Exception {
		this.getText();
		System.out.println("輸入明文爲: " + this.mc);
		// 加密
		ArrayList cestr = new ArrayList();
		for (int i = 0; i < mc.length(); i++) {
			this.c = this.colum((long) mc.charAt(i), this.n, this.e);
			cestr.add(c);
		}
		System.out.println("加密後所得的密文爲:" + cestr);
		// 解密
		StringBuffer destr = new StringBuffer();
		for (int j = 0; j < cestr.size(); j++) {
			this.word = this.colum(Long.parseLong(cestr.get(j).toString()),
					this.n, this.d);
			destr.append((char) word);
		}
		System.out.println("解密後所得的明文爲:" + destr);

	}

	// 加密、解密計算
	public long colum(long mc, long n, long key) {
		BigInteger bigy = new BigInteger(String.valueOf(mc));
		BigInteger bign = new BigInteger(String.valueOf(n));
		BigInteger bigkey = new BigInteger(String.valueOf(key));
		return Long.parseLong(bigy.modPow(bigkey, bign).toString());// 備註1
	}

	public static void main(String[] args) {
		try {
			EnAndDe t = new EnAndDe();
			t.inputPQ();
			t.getPublic_key();
			t.getPrivate_key();
			t.pascolum();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

備註1:modPow(a,b)是java類BigInteger中的一個方法,返回結果是:調用該方法的對象的a次冪,模b的結果

相關文章
相關標籤/搜索