package com.test.rsa;

/*
* 為了選擇公鑰和私鑰,Bob必須執行如下步驟:
* 1)選擇兩個大素數p和q.那麼p和q應該多大呢?該值越大,RSA越難於破解,但是執行加密和解密所用的時間也越長。RSA實驗室推
* 薦,公司使用時,p和q的乘積為1024位元的數量級,對於"價值不太高的資訊",p和q的乘積應為768位元的數量級[RSA Key 2007]
* (這導致人們想知道為什麼在公司的使用被認為比在其他場合下的使用重要得多!).對於選擇大素數的方法的討論參見[Caldwell 2007]
* 2)計算n=pq和z=(p-1)(q-1)
* 3)選擇小於n的一個數e,且使e和z沒有(非1的)公因數(這時稱e與z互素).使用字母e表示這個數是因為這個值將用於加密.
* 4)找到一個數d,使得ed-1可以被z整除(就是說,沒有餘數).使用字母d表示這個數是因為這個值將被用於解密.換句話說,給定e,
* 然後選擇d使得ed被z除的整數餘數為1.(當整數x被整數n除時,整數餘數表示為x mod n.)
* 5)Bob對外公佈的公鑰就是二元組(n,e);其私鑰就是二元組(n,d).
*
*
* 假設Bob想給Alice送一個訊息m,他知道Alice產生的n和e。他使用起先與Alice約好的格式將m轉換為一個小於n的整數num,
* 比如他可以將每一個字轉換為這個字的Unicode碼,然後將這些數字連在一起組成一個數字。假如他的資訊非常長的話,
* 他可以將這個資訊分為幾段,然後將每一段轉換為num。用下面這個公式他可以將num加密為c:
* num^e ≡ c (mod n)
* 計算c並不複雜。Bob算出c後就可以將它傳遞給Alice。
*
*/ /**
* @author [email protected]
* RSA 簡單實現學習
*/
public class Main { public static void main(String[] args) {
int p = 2;
int q = 11;
int n = p*q;
int z = (p-1)*(q-1);
int e = 3; Main main =new Main();
int d = main.getd(e, z); System.out.println("n: "+n);
System.out.println("*****");
int enc = main.encrypt(20, e, n);
System.out.println("*****");
main.decrypt(enc, d, n); }
/**
計算e對於z的模反元素d,所謂"模反元素"就是指有一個整數d,可以使得 ed 被φ(n)除的餘數為1。
ed ≡ 1 (mod φ(n)) 這個式子等價於 ed - 1 = kφ(n)
於是,找到模反元素d,實質上就是對下面這個二元一次方程求解。
ed + zk = 1
已知 e=5, φ(n)=96,
5d + 96k = 1
這個方程可以用"擴充套件歐幾里得演算法"求解,此處省略具體過程。
*/
public int getd(int e,int z) {
//實際上即使需要找到一個整數d滿足 ed-1=kz -> d= (kz+1)/e,其中k當然也是整數
/*
int k=1;
Object object = (k*z+1)/e;
while(!(object instanceof Integer)) {
k++;
}
System.out.println("d: "+object.toString());
return Integer.parseInt(object.toString());
*/
int k=1;
while(true) {
if((k*z+1)%e==0) {
System.out.print("k: "+k+" ");
System.out.print("z: "+z+" ");
System.out.print("e: "+e+" ");
System.out.println("d: "+(k*z+1)/e);
return (k*z+1)/e;
}
k++;
}
} /**
* 加密函式 輸入明文num,金鑰(e,n),輸出密文c,c滿足 num^e ≡ c (mod n)
* @param msg 待加密資訊
* @param e 金鑰
* @param n 金鑰
* @return 密文
*/
public int encrypt(int num,int e,int n) {
System.out.println("待加密數字: "+num);
System.out.println("加密後數字: "+(int)(Math.pow(num, e)%n));
return (int)(Math.pow(num, e)%n);
}
/**
* 解密函式 輸入密文num,金鑰(d,n),輸出明文msg,msg滿足 num^d ≡ msg (mod n)
* @param num 密文
* @param d 金鑰
* @param n 金鑰
* @return 明文
*/
public int decrypt(int num,int d,int n) {
System.out.println("待解密數字: "+num);
System.out.println("解密後數字: "+(int)(Math.pow(num, d)%n));
return (int)(Math.pow(num, d)%n);
}
} 執行結果:
k: 2 z: 10 e: 3 d: 7
n: 22
*****
待加密數字: 20
加密後數字: 14
*****
待解密數字: 14
解密後數字: 20

2016.04.03
– 此前一直得到錯誤的執行結果,後來才知道被加密的整數是必須要小於n的。至於為什麼,等明白了再回來補。
– 整理:
密文 c = m^e mod n (1)
明文 m = c^d mod n (2)
(2)式是可以根據(1)式進行證明的。