轉發注明出處:http://www.cnblogs.com/0zcl/p/6120389.html
背景介紹
1976年以前,所有的加密方法都是同一種模式:
(1)甲方選擇某一種加密規則,對信息進行加密;
(2)乙方使用同一種規則,對信息進行解密。
由於加密和解密使用同樣規則(簡稱"密鑰"),這被稱為"對稱加密算法"(Symmetric-key algorithm)。
這種加密模式有一個最大弱點:甲方必須把加密規則告訴乙方,否則無法解密。保存和傳遞密鑰,就成了最頭疼的問題。

1976年,兩位美國計算機學家Whitfield Diffie 和 Martin Hellman,提出了一種嶄新構思,可以在不直接傳遞密鑰的情況下,完成解密。這被稱為"Diffie-Hellman密鑰交換算法"。這個算法啟發了其他科學家。人們認識到,加密和解密可以使用不同的規則,只要這兩種規則之間存在某種對應關系即可,這樣就避免了直接傳遞密鑰。
這種新的加密模式被稱為"非對稱加密算法"。
(1)乙方生成兩把密鑰(公鑰和私鑰)。公鑰是公開的,任何人都可以獲得,私鑰則是保密的。
(2)甲方獲取乙方的公鑰,然后用它對信息加密。
(3)乙方得到加密后的信息,用私鑰解密。
如果公鑰加密的信息只有私鑰解得開,那么只要私鑰不泄漏,通信就是安全的。

1977年,三位數學家Rivest、Shamir 和 Adleman 設計了一種算法,可以實現非對稱加密。這種算法用他們三個人的名字命名,叫做RSA算法。從那時直到現在,RSA算法一直是最廣為使用的"非對稱加密算法"。毫不誇張地說,只要有計算機網絡的地方,就有RSA算法。
這種算法非常可靠,密鑰越長,它就越難破解。根據已經披露的文獻,目前被破解的最長RSA密鑰是768個二進制位。也就是說,長度超過768位的密鑰,還無法破解(至少沒人公開宣布)。因此可以認為,1024位的RSA密鑰基本安全,2048位的密鑰極其安全。
RSA算法原理
RSA算法需要一些數學知識,不過別慫,不難的。我總結了一下,大概需要以下三部分的知識:
- 互質關系(這,很簡單)
- 歐拉公式(難,我是直接記公式的)
- 模反元素(不難的)
接下來說下每個部分的內容:
1、互質關系:如果兩個正整數,除了1以外,沒有其他公因子,我們就稱這兩個數是互質關系(coprime)。比如,15和32沒有公因子,所以它們是互質關系。這說明,不是質數也可以構成互質關系。
2、先說下 歐拉函數:φ(n)為比n小但與n互素的正整數個數,稱為n的歐拉函數。對任一素數p, 有φ(n)=p-1,而對於兩個不同的素數p和q,則對n=pq,可以證明φ(n)=φ(pq)=(p-1)(q-1)=φ(p)*φ(q)
3、模反元素:如何求模反元素(逆元),用輾轉相除法,我在上一篇博客<信息安全-4:公鑰密碼體制之背包算法[原創]>有說,看了一定會懂的!
上面3點一定要GET,不然不用往下看了~~
RSA算法的過程
RSA算法可歸納如下:
- 選擇兩個素數p和q,計算n=p*q,φ(n)=(p-1)(q-1),選擇整數e,使gcd(φ(n), e)=1,1<e<φ(n),計算逆元d=e-1modφ(n),於是得到公鑰KU={e, n},私鑰={d, n},而把p和q丟棄(PS:gcd(φ(n), e)=1 表示最大公約數為1,下面編程有用到~)。
- 加密(用公鑰KU):明文M<n, 密文:C=me mod n
- 解密(用私鑰KR):密文:C, 明文:M=Cd mod n
上面過程很重要!!! 剛開始看會有點懵逼,看下面的例子,一定會懂!
我們通過一個例子,來理解RSA算法。假設Alice想發送明文9726給Bob,這之間的過程是怎樣的?又是怎樣生成公鑰和私鑰呢?

(1)Bob生成密鑰
Bob選擇兩個互異素數p=101和q=113,計算:n=pq=101*113=11413, φ(n)=(p-1)(q-1)=100*112=11200
由於加密密鑰e必須與φ(n)沒有公因子,假設Bob隨機選擇了e=3533,則用輾轉相除法可求得: d=e-1=3533-1 mod 11200=6597
於是Bob公布他的公鑰KU={3533, 11413}, 將私鑰KR={6597, 11413}保密。
(2)Alice加密信息
由於Bob的公鑰是公開的,任何人都可得到,因此Alice使用Bob的公鑰來加密即將發送給Bob的明文信息。
Alice計算: 97263533 mod 11413=5761, 然后在一個信道上發送密文5761.
(3)Bob解密密文
當Bob接收到密文5761時,他用他的私鑰進行解密。
Bob計算: 57616597 mod 11413=9726, 這樣Bob就得到Alice發給他的明文信息了!!!
RSA算法編程實現
流程圖
我畫的流程圖網址: https://www.processon.com/diagraming/583fb2c0e4b0d0d77bcfa514

ReadMe:
- 運行環境為python3.4 Windows8.1, 程序代碼用Python語言寫的
- 質數P,Q是我自己給出的,當然也可以隨機生成
- 運行時,必須先加密再解密,因為先加密才有逆元給解密模塊進行運算
- 運行時有一些測試打印出來,為了方便了解程序運行過程,我這里就沒有去除。
源代碼
1 #RSA加密算法 2 3 import random 4 # p,q是兩個不同的素數n=pq,按理說應該隨機產生,這里我用p=101,q=103為例 5 6 P = 101 7 Q = 113 8 N = P * Q 9 global _E # 把逆元定義為全局變量,才能在解密模塊調用 10 _E = 0 #初始為0 11 12 #歐拉公式:如果n是質數,則 φ(n)=n-1 。因為質數與小於它的每一個數,都構成互質關系 13 F = (P-1) * (Q-1) 14 15 16 #求最大公約數,若最大公約數是1,且m,n>1,m與n不等,則說明m,n互質 17 def comm_div(m, n): #m>n 18 temp = m % n 19 while(temp != 0): 20 m = n 21 n = temp 22 temp = m % n 23 if n == 1: #說明互質,返回True 24 return True 25 26 27 # 在1-9999之間隨機選擇一個整數e,條件是1< e < F,且e與F 互質 28 # 互質即說明e,F的公因子有且僅有1 29 def e_product(): 30 while True: 31 rand = random.randrange(2, F) 32 if comm_div(F, rand): 33 e = rand 34 return e 35 36 37 #用輾轉相除法求質數e關於歐拉公式F的逆元 38 def _e_product(e, F): 39 a_list = [] 40 m = F 41 n = e 42 temp = m % n 43 44 while (temp != 0): 45 a = (m - temp) / n 46 a_list.append(a) 47 m = n 48 n = temp 49 temp = m % n 50 print("a_list:", a_list) 51 a_list.reverse() #逆序 52 print("a_list_reverse:", a_list) 53 b_list = [] 54 b_list.append(1) 55 b_list.append(a_list[0]) 56 print("(最初插入的兩個1及a_list[0])b_list:", b_list) 57 for i in range(len(a_list)-1): 58 b = b_list[-1] * a_list[i+1] + b_list[-2] 59 b_list.append(b) 60 61 print("b_list", b_list) 62 #a_list存放的是商數,如果商數個數是偶數 b_list[-1]即為所求逆元 63 #若為奇數,F-b_list[-1]為所求的逆元 64 if len(a_list) % 2 == 0: #偶數 65 return b_list[-1] 66 else: 67 return F - b_list[-1] 68 69 70 #傳入明文(數字)和公鑰,進行加密,返回密文 71 def core_encryption(clear_text, e, N): 72 clear = clear_text 73 for i in range(e-1): 74 clear_text = clear_text * clear 75 cipher_text = clear_text % N 76 return cipher_text 77 78 79 def encryption(clear_text): 80 clear_text = int(clear_text) 81 e = e_product() 82 print("隨機產生的e:%s" % e) 83 global _E #對全局變量進行重新賦值,需要global 84 _E = _e_product(e, F) 85 # print("逆元_e:", _E) 86 # print("逆元類型:",type(_E)) 87 print("公鑰KU:%d,%d\n私鑰KR:%d,%d" % (e,N, _E,N)) 88 cipher_text = core_encryption(clear_text,e,N) 89 return cipher_text 90 91 92 #根據之前加密生成的私鑰進行解密,所以必須先有加密才行的 93 def decryption(cipher_text, _e, N): 94 cipher_text = int(cipher_text) 95 cipher = cipher_text 96 # print(_e) 97 # print("逆元_e類型:",type(_e)) 98 for i in range(_e-1): 99 cipher_text = cipher_text * cipher 100 clear_text = cipher_text % N 101 return clear_text 102 103 104 if __name__ == "__main__": 105 while True: 106 print("必須先加密后解密!".center(50, "-")) 107 choice = input("Input E for encryption or D for decryption:") 108 if choice == "E": 109 clear_text = input("請輸入明文(只允許數字):") 110 if clear_text.strip().isalnum(): 111 print("加密成功!密文為:%d" % encryption(clear_text)) 112 if choice == "D": 113 cipher_text = input("請輸入密文:") 114 if cipher_text.strip().isalnum(): 115 print("解密成功!明文為:%d" % decryption(cipher_text, _E, N))
問題
在測試時我遇到了下面這個問題
1 C:\Python34\python3.exe C:/Users/Administrator/PycharmProjects/xingxi/playfair/RSA.py 2 --------------------必須先加密后解密!--------------------- 3 Input E for encryption or D for decryption:E 4 請輸入明文(只允許數字):9726 5 隨機產生的e:2147 6 a_list: [5.0, 4.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0] 7 a_list_reverse: [1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 4.0, 5.0] 8 (最初插入的兩個1及a_list[0])b_list: [1, 1.0] 9 b_list [1, 1.0, 2.0, 3.0, 8.0, 11.0, 19.0, 30.0, 49.0, 79.0, 128.0, 591.0, 3083.0] 10 公鑰KU:2147,11413 11 私鑰KR:3083,11413 12 加密成功!密文為:5200 13 --------------------必須先加密后解密!--------------------- 14 Input E for encryption or D for decryption:D 15 請輸入密文:5200 16 Traceback (most recent call last): 17 File "C:/Users/Administrator/PycharmProjects/xingxi/playfair/RSA.py", line 116, in <module> 18 print("解密成功!明文為:%d" % decryption(cipher_text, _E, N)) 19 File "C:/Users/Administrator/PycharmProjects/xingxi/playfair/RSA.py", line 99, in decryption 20 for i in range(_e-1): 21 TypeError: 'float' object cannot be interpreted as an integer 22 23 Process finished with exit code 1
現在已經解決了,問題出在了下面第6行代碼,rang()函數里面不能是float型,只需要int(_e-1)轉型即可解決!
1 def decryption(cipher_text, _e, N): 2 cipher_text = int(cipher_text) 3 cipher = cipher_text 4 # print(_e) 5 # print("逆元_e類型:",type(_e)) 6 for i in range(_e-1): 7 cipher_text = cipher_text * cipher 8 clear_text = cipher_text % N 9 return clear_text
你可能會說,毛線,這么簡單的坑你都跳(鄙視臉)。
好吧,這都怪我在這之前輸出了一條測試print("_e:%d" % _e),然后我運行時看到輸出的是整型,就蒙比了,心想:明明是int型,怎么會爆錯說float型!!!這大概就是所謂的被自己挖的坑坑到懷疑人生吧~~
測試(為了方便我日后再來看,一些打印測試我沒有去除)
1 C:\Python34\python3.exe C:/Users/Administrator/PycharmProjects/xingxi/playfair/RSA.py 2 --------------------必須先加密后解密!--------------------- 3 Input E for encryption or D for decryption:E 4 請輸入明文(只允許數字):9726 5 隨機產生的e:4031 6 a_list: [2.0, 1.0, 3.0, 1.0, 1.0, 17.0, 2.0, 1.0, 3.0] 7 a_list_reverse: [3.0, 1.0, 2.0, 17.0, 1.0, 1.0, 3.0, 1.0, 2.0] 8 (最初插入的兩個1及a_list[0])b_list: [1, 3.0] 9 b_list [1, 3.0, 4.0, 11.0, 191.0, 202.0, 393.0, 1381.0, 1774.0, 4929.0] 10 公鑰KU:4031,11413 11 私鑰KR:6271,11413 12 加密成功!密文為:325 13 --------------------必須先加密后解密!--------------------- 14 Input E for encryption or D for decryption:D 15 請輸入密文:325 16 解密成功!明文為:9726 17 --------------------必須先加密后解密!--------------------- 18 Input E for encryption or D for decryption:E 19 請輸入明文(只允許數字):25 20 隨機產生的e:6403 21 a_list: [1.0, 1.0, 2.0, 1.0, 75.0, 2.0] 22 a_list_reverse: [2.0, 75.0, 1.0, 2.0, 1.0, 1.0] 23 (最初插入的兩個1及a_list[0])b_list: [1, 2.0] 24 b_list [1, 2.0, 151.0, 153.0, 457.0, 610.0, 1067.0] 25 公鑰KU:6403,11413 26 私鑰KR:1067,11413 27 加密成功!密文為:10272 28 --------------------必須先加密后解密!--------------------- 29 Input E for encryption or D for decryption:D 30 請輸入密文:10272 31 解密成功!明文為:25 32 --------------------必須先加密后解密!--------------------- 33 Input E for encryption or D for decryption:
注:RSA算法背景參考自http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
博客參考書籍:信息安全概論(凌捷 謝贊福 編著)
接下來一個月信息安全方面可能最多會再寫一篇博客, 重心會放在人工智能和操作系統!fight!
