本文旨在說明RSA加密算法的原理及實現,而其相關的數學部分的證實則不是本文內容。html
著做權歸做者全部。java
商業轉載請聯繫做者得到受權,非商業轉載請註明出處。算法
做者:Coding-Naga安全
發表日期: 2016年2月29日網絡
本文連接:http://blog.csdn.net/lemon_tree12138/article/details/50696926dom
來源:CSDN
函數
更多內容:分類 » 數據加密與信息安全加密
1977年,三位數學家Rivest、Shamir 和 Adleman 設計了一種算法,能夠實現非對稱加密。這種算法用他們三我的的名字命名,叫作RSA算法。從那時直到如今,RSA算法一直是最廣爲使用的"非對稱加密算法"。絕不誇張地說,只要有計算機網絡的地方,就有RSA算法。spa
-- 摘自網絡.net
此部分旨在補充本文的完整性。若是說你已經瞭解,或是不想了解此部份內容。那麼能夠直接跳過此部分的閱讀。
雖然說只是補充說明(只能是補充的緣由是由於博主的數學也是比較差的-_-!!!),可是此部分的內容倒是至關重要的。博主仍是但願能夠從新閱讀一下此部分。
從小學開始,咱們就瞭解了什麼是質數。互質是針對多個數字而言的,若是兩個正整數,除了1之外,沒有其餘公因子,那麼就稱這兩個數是互質關係(注意,這裏並無說這兩個數必定是質數或有一個爲質數。好比15跟4就是互質關係)。如下有一些關於質數與互質的性質:
歐拉函數是求小於x而且和x互質的數的個數。其通式爲:φ(x) = x(1-1/p1)(1-1/p2)(1-1/p3)(1-1/p4)…..(1-1/pn)。
其中p1, p2……pn爲x的全部質因數,x是不爲0的整數。看到這裏是否是有一些頭疼,太理論的東西的確不夠具象。咱們且不去理會後面公式計算與論證,由於已經超出本文的範圍了。就前一句來講說吧,歐拉函數是求小於x而且和x互質的數的個數。這裏我能夠列舉一個例子:
令x = 16,那麼x的全部質因數爲:φ(16) = 16 * (1 - 1/2) = 8
咱們也能夠枚舉出全部比16小,且與16互質的數:1, 3, 5, 7, 9, 11, 13, 15
如今也給出部分歐拉函數的性質:
歐拉函數更多參考請見這裏的連接。
定義:若是兩個正整數a和n互質,那麼必定能夠找到整數b,使得 ab-1 被n整除,或者說ab被n除的餘數是1。
關於模反元素的求解,使用的是樸素的解法。若是讀者想要更進一步瞭解的話,請自行搜索其餘解法(好比:展轉相除法、歐幾里德算法)。
在RSA原理以前,我想仍是有必要了解一下非對稱加密算法的加密跟解密過程。下面就是一幅非稱加密算法的流程圖。
在此能夠看到,非對稱加密是經過兩個密鑰(公鑰-私鑰)來實現對數據的加密和解密的。公鑰用於加密,私鑰用於解密。對於非對稱的加密和解密爲何可使用不一樣的密鑰來進行,這些都是數學上的問題了。不一樣的非對稱加密算法也會應用到不一樣的數學知識。上面也對RSA中使用的數學問題作了一個小小的介紹。如今就來看看RSA算法是怎麼來對數據進行加密的吧,以下是一幅RSA加密算法流程及加密過程圖。
就以上圖中的Bob和Alice來舉例吧。
如今Alice經過密鑰生成器生成了一對密鑰(公鑰-私鑰)。只把公鑰對外公開了。並說,你有什麼要跟我說的,就用模冪運算和公鑰加密後發給我吧。
此時,Bob已經得到了Alice發佈的公鑰。使用模冪運算對明文進行了加密,就把加密後的密文發送給了Alice。
Alice得到Bob發來的密文並無使用公鑰對密文進行解密,並得到了明文。由於解密過程須要使用的密鑰是私鑰。
下面的代碼只是根據RSA算法的定義,使用Java開發語言實現。且這裏只是展現了一些關鍵步驟,完整過程能夠參見下面的源碼下載文檔。
public class RSA { /** * 得到(公/私)密鑰 */ public final Map<String, RSAKey> getCipherKeys() { ... int[] primes = getRandomPrimes(2); int modulus = modulus(primes[0], primes[1]); int euler = euler(primes[0], primes[1]); int e = cipherExponent(euler); int inverse = inverse(euler, e); publicKey.setExponent(e); publicKey.setModulus(modulus); privateKey.setExponent(inverse); privateKey.setModulus(modulus); ... } /** * 加密 */ public int encode(int plaintext, RSAPublicKey key) { return modularPower2(plaintext, key.getExponent(), key.getModulus()); } /** * 解密 */ public int decode(int chipertext, RSAPrivateKey key) { return modularPower2(chipertext, key.getExponent(), key.getModulus()); } // 隨機生成count個素數 private final int[] getRandomPrimes(int count) { ... try { primeLabels = FileReadUtils.readLines("./data/prime_table"); } catch (IOException e) { e.printStackTrace(); } for (int i = 0; i < primes.length; i++) { primes[i] = Integer.parseInt(primeLabels.get(indexs.get(i))); } return primes; } // 計算公共模數 private final int modulus(int p, int q) { return p * q; } // 計算歐拉數 private final int euler(int p, int q) { return (p - 1) * (q - 1); } // 計算加密指數 private final int cipherExponent(int euler) { Random random = new Random(); int e = 7; do { e = random.nextInt(euler - 1); } while (!isCoprime(e, euler) || e <= 1); return e; } // 判斷兩個數互素 private final boolean isCoprime(int number1, int number2) { int sqrt = (int) Math.sqrt(Math.max(number1, number2)); for (int i = 2; i <= sqrt; i++) { if (number1 % i == 0 && number2 % 2 == 0) { return false; } } return true; } // 計算「模的逆元」 // (d * e) ≡ 1 mod euler private final int inverse(int euler, int e) { ... while (flag) { q = m[2] / n[2]; for (int i = 0; i < 3; i++) { temp[i] = m[i] - q * n[i]; m[i] = n[i]; n[i] = temp[i]; } if (n[2] == 1) { if (n[1] < 0) { n[1] = n[1] + euler; } return n[1]; } if (n[2] == 0) { flag = false; } } return 0; } // 模冪運算 private final int modularPower(int base, int e, int modular) { int result = 1; do { if (isOdd(e)) { result = (result * (base % modular)) % modular; e -= 1; } else { base = (base * base) % modular; e /= 2; } } while (e > 0); result %= modular; return result; } }