RSA加密演算法詳解
研究RSA
不知為何,這幾天突然有些心煩。望蒼茫大地,憑添幾分憂傷,可能是下雨的緣故。本篇主要想詳細介紹RSA加密演算法的原理,經常聽別人說,這裡是自己想搞清楚,弄明白。首先介紹了基本的數學原理,然後給出一個具體的計算例子和相關的理論充分性證明。
轉載請註明出處:http://www.haomou.net/2014/08/27/2014_rsa/
RSA由來
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的乘積以外,不能表示為任何其它兩個整數的乘積。例如,15=3*5,所以15不是素數;又如,12=6*2=4*3,所以12也不是素數。另一方面,13除了等於13*1以外,不能表示為其它任何兩個整數的乘積,所以13是一個素數。素數也稱為“質數”。
####什麼是“互質數”(或“互素數”)?
小學數學教材對互質數是這樣定義的:“公約數只有1的兩個數,叫做互質數。”這裡所說的“兩個數”是指自然數。
判別方法主要有以下幾種(不限於此):
(1)兩個質數一定是互質數。例如,2與7、13與19。
(2)一個質數如果不能整除另一個合數,這兩個數為互質數。例如,3與10、5與 26。
(3)1不是質數也不是合數,它和任何一個自然數在一起都是互質數。如1和9908。
(4)相鄰的兩個自然數是互質數。如 15與 16。
(5)相鄰的兩個奇數是互質數。如 49與 51。
(6)大數是質數的兩個數是互質數。如97與88。
(7)小數是質數,大數不是小數的倍數的兩個數是互質數。如 7和 16。
(8)兩個數都是合數(二數差又較大),小數所有的質因數,都不是大數的約數,這兩個數是互質數。如357與715,357=3×7×17,而3、7和17都不是715的約數,這兩個數為互質數。等等。
####什麼是模指數運算?
指數運算誰都懂,不必說了,先說說模運算。模運算是整數運算,有一個整數m,以n為模做模運算,即m mod n。怎樣做呢?讓m去被n整除,只取所得的餘數作為結果,就叫做模運算。例如,10 mod 3=1;26 mod 6=2;28 mod 2 =0等等。
模指數運算就是先做指數運算,取其結果再做模運算。如2^3 mod 5 = 3
什麼是同餘式
表示同餘關係的數學表示式,與等式相似。將等式中的等號“=”換成同餘符號“≡”,必要時在式尾綴以(mod m) 註明模m(即除數),就是同餘式。含有未知數的同餘式叫做同餘方程,通常要求整數解。
如果兩個正整數 a和 b之差能被 n整除,那麼我們就說 a和 b對模n同餘,記作:
a ≡b (mod n)
####什麼是費馬定理
若p是素數,a與p互素,則
a^(p-1)≡1 (mod p)
什麼是尤拉定理
尤拉函式φ(n)表示不大於n且與n互素的正整數的個數。
當n是素數,φ(n)=n-1。n=pq,p,q均為素數時,則φ(n)= φ(p)φ(q)=(p-1)(q-1)。
對於互素的a和n,有a^φ(n)≡1(mod n)
什麼是模反元素?
如果兩個正整數a和n互質,那麼一定可以找到整數b,使得ab-1被n整除或者說ab被n除的餘數是1。這時,b就叫做a的”模反元素”。
比如,3和11互質,那麼3的模反元素就是4,因為 (3 × 4)-1 可以被11整除。顯然,模反元素不止一個, 4加減11的整數倍都是3的模反元素 {…,-18,-7,4,15,26,…},即如果b是a的模反元素,則 b+kn 都是a的模反元素。尤拉定理可以用來證明模反元素必然存在。
金鑰生成步驟
這裡通過例項來說明。假設愛麗絲要與鮑勃進行加密通訊,她該怎麼生成公鑰和私鑰呢?
第一步,隨機選擇兩個不相等的質數p和q。
愛麗絲選擇了61和53。(實際應用中,這兩個質數越大,就越難破解。)
第二步,計算p和q的乘積n。
愛麗絲就把61和53相乘。
n = 61×53 = 3233
n的長度就是金鑰長度。3233寫成二進位制是110010100001,一共有12位,所以這個金鑰就是12位。實際應用中,RSA金鑰一般是1024位,重要場合則為2048位。
第三步,計算n的尤拉函式φ(n)。
根據公式:
φ(n) = (p-1)(q-1)
愛麗絲算出φ(3233)等於60×52,即3120。
第四步,隨機選擇一個整數e,條件是1< e < φ(n),且e與φ(n) 互質。
愛麗絲就在1到3120之間,隨機選擇了17。(實際應用中,常常選擇65537。)
第五步,計算e對於φ(n)的模反元素d。
所謂”模反元素”就是指有一個整數d,可以使得ed被φ(n)除的餘數為1。
ed ≡ 1 (mod φ(n))
這個式子等價於
ed - 1 = kφ(n)
於是,找到模反元素d,實質上就是對下面這個二元一次方程求解。
ex + φ(n)y = 1
已知 e=17, φ(n)=3120,
17x + 3120y = 1
這個方程可以用”擴充套件歐幾里得演算法”求解,此處省略具體過程。總之,愛麗絲算出一組整數解為 (x,y)=(2753,-15),即 d=2753。
至此所有計算完成。
第六步,將n和e封裝成公鑰,n和d封裝成私鑰。
在愛麗絲的例子中,n=3233,e=17,d=2753,所以公鑰就是 (3233,17),私鑰就是(3233, 2753)。
實際應用中,公鑰和私鑰的資料都採用ASN.1格式表達。如下:
比如上面顯示的這個公鑰,那麼怎麼看出加密指數和模數呢?
下面是我隨便從IE裡匯出的一個證書的公鑰
1
|
30 81 89 02 81 81 00 ee fa 1f c9 b0 43 df 7e 75 81 4e 31 71 91 0b fc 15 9d d9 4a 8a 51 f5 09 18 c6 7c c5 f1 27 c4 01 62 fc bf fc 84 29 a6 2f e6 1e 02 06 0b 96 89 d3 42 b1 73 9f 02 ae 75 62 09 3f 83 80 34 46 60 39 0a e3 21 4e e7 04 42 d5 7e 5e 98 45 27 5d 04 b9 27 32 c0 65 a4 94 85 13 25 db 16 f2 fb 51 c7 ff 28 62 d1 83 31 4f a9 a4 f4 c5 4f 9d 00 2e 14 3f 95 16 9c 4e 25 07 1b d5 7d 38 71 d8 40 f8 aa 71 02 03 01 00 01
|
在PKCS#1中的RSA的公鑰的標準格式為
1 2 3 4 5 6 7 |
PKCS#1 : An RSA public key should be represented with the ASN.1 type RSAPublickey: RSAPublickey ::= SEQUENCE { modulus INTEGER, -- n publicExponent INTEGER -- e } |
然後按照ASN的標準編碼,所以說:
1 2 3 4 5 6 |
30 81 89 02 81 81 00 ee fa 1f c9 b0 43 df 7e 75 81 4e 31 71 91 0b fc 15 9d d9 4a 8a 51 f5 09 18 c6 7c c5 f1 27 c4 01 62 fc bf fc 84 29 a6 2f e6 1e 02 06 0b 96 89 d3 42 b1 73 9f 02 ae 75 62 09 3f 83 80 34 46 60 39 0a e3 21 4e e7 04 42 d5 7e 5e 98 45 27 5d 04 b9 27 32 c0 65 a4 94 85 13 25 db 16 f2 fb 51 c7 ff 28 62 d1 83 31 4f a9 a4 f4 c5 4f 9d 00 2e 14 3f 95 16 9c 4e 25 07 1b d5 7d 38 71 d8 40 f8 aa 71 02 03 01 00 01 |
0x30 0x81 0x89 是一個標識頭,整個編碼應該是:
1 2 3 4 5 6 |
02 81 81 00 ee fa 1f c9 b0 43 df 7e 75 81 4e 31 71 91 0b fc 15 9d d9 4a 8a 51 f5 09 18 c6 7c c5 f1 27 c4 01 62 fc bf fc 84 29 a6 2f e6 1e 02 06 0b 96 89 d3 42 b1 73 9f 02 ae 75 62 09 3f 83 80 34 46 60 39 0a e3 21 4e e7 04 42 d5 7e 5e 98 45 27 5d 04 b9 27 32 c0 65 a4 94 85 13 25 db 16 f2 fb 51 c7 ff 28 62 d1 83 31 4f a9 a4 f4 c5 4f 9d 00 2e 14 3f 95 16 9c 4e 25 07 1b d5 7d 38 71 d8 40 f8 aa 71 02 03 01 00 01 |
而
1 2 3 4 5 6 |
02 81 81 00 ee fa 1f c9 b0 43 df 7e 75 81 4e 31 71 91 0b fc 15 9d d9 4a 8a 51 f5 09 18 c6 7c c5 f1 27 c4 01 62 fc bf fc 84 29 a6 2f e6 1e 02 06 0b 96 89 d3 42 b1 73 9f 02 ae 75 62 09 3f 83 80 34 46 60 39 0a e3 21 4e e7 04 42 d5 7e 5e 98 45 27 5d 04 b9 27 32 c0 65 a4 94 85 13 25 db 16 f2 fb 51 c7 ff 28 62 d1 83 31 4f a9 a4 f4 c5 4f 9d 00 2e 14 3f 95 16 9c 4e 25 07 1b d5 7d 38 71 d8 40 f8 aa 71 |
是n的編碼。
0x02 0x03 0x01 0x00 0x01是e的編碼,不過你還是看不出來這什麼整數,
舉個例子
對於上面的0x02,0x03,0x01,0x00,0x01 其中0x02,0x03是e的編碼的標識頭
e的表示是0x01,0x00,0x01,所以e就是0x01256^2+0x00256^1+1=65537
同理n就是
1 2 3 4 5 6 |
81 00 ee fa 1f c9 b0 43 df 7e 75 81 4e 31 71 91 0b fc 15 9d d9 4a 8a 51 f5 09 18 c6 7c c5 f1 27 c4 01 62 fc bf fc 84 29 a6 2f e6 1e 02 06 0b 96 89 d3 42 b1 73 9f 02 ae 75 62 09 3f 83 80 34 46 60 39 0a e3 21 4e e7 04 42 d5 7e 5e 98 45 27 5d 04 b9 27 32 c0 65 a4 94 85 13 25 db 16 f2 fb 51 c7 ff 28 62 d1 83 31 4f a9 a4 f4 c5 4f 9d 00 2e 14 3f 95 16 9c 4e 25 07 1b d5 7d 38 71 d8 40 f8 aa 71 02 03 01 00 01 |
注意,這個是一個整數的編碼,也要像e,那樣解碼。
RSA演算法的可靠性
回顧上面的金鑰生成步驟,一共出現六個數字:
1 2 3 4 5 6 |
p q n φ(n) e d |
這六個數字之中,公鑰用到了兩個(n和e),其餘四個數字都是不公開的。其中最關鍵的是d,因為n和d組成了私鑰,一旦d洩漏,就等於私鑰洩漏。
那麼,有無可能在已知n和e的情況下,推匯出d?
(1)ed≡1 (mod φ(n))。只有知道e和φ(n),才能算出d。
(2)φ(n)=(p-1)(q-1)。只有知道p和q,才能算出φ(n)。
(3)n=pq。只有將n因數分解,才能算出p和q。
結論:如果n可以被因數分解,d就可以算出,也就意味著私鑰被破解。
可是,大整數的因數分解,是一件非常困難的事情。目前,除了暴力破解,還沒有發現別的有效方法。維基百科這樣寫道:
“對極大整數做因數分解的難度決定了RSA演算法的可靠性。換言之,對一極大整數做因數分解愈困難,RSA演算法愈可靠。
假如有人找到一種快速因數分解的演算法,那麼RSA的可靠性就會極度下降。但找到這樣的演算法的可能性是非常小的。今天只有短的RSA金鑰才可能被暴力破解。到2008年為止,世界上還沒有任何可靠的攻擊RSA演算法的方式。
只要金鑰長度足夠長,用RSA加密的資訊實際上是不能被解破的。”
舉例來說,你可以對3233進行因數分解(61×53),但是你沒法對下面這個整數進行因數分解。
1 2 3 4 5 6 7 8 9 |
12301866845301177551304949 58384962720772853569595334 79219732245215172640050726 36575187452021997864693899 56474942774063845925192557 32630345373154826850791702 61221429134616704292143116 02221240479274737794080665 351419597459856902143413 |
它等於這樣兩個質數的乘積:
1 2 3 4 5 6 7 8 9 10 11 |
33478071698956898786044169 84821269081770479498371376 85689124313889828837938780 02287614711652531743087737 814467999489 × 36746043666799590428244633 79962795263227915816434308 76426760322838157396665112 79233373417143396810270092 798736308917 |
事實上,這大概是人類已經分解的最大整數(232個十進位制位,768個二進位制位)。比它更大的因數分解,還沒有被報道過,因此目前被破解的最長RSA金鑰就是768位。
加密和解密
有了公鑰和金鑰,就能進行加密和解密了。
(1)加密要用公鑰 (n,e)
假設鮑勃要向愛麗絲髮送加密資訊m,他就要用愛麗絲的公鑰 (n,e) 對m進行加密。這裡需要注意,m必須是整數(字串可以取ascii值或unicode值),且m必須小於n。
所謂”加密”,就是算出下式的c:
1
|
me ≡ c (mod n)
|
愛麗絲的公鑰是 (3233, 17),鮑勃的m假設是65,那麼可以算出下面的等式:
1
|
6517 ≡ 2790 (mod 3233)
|
於是,c等於2790,鮑勃就把2790發給了愛麗絲。
(2)解密要用私鑰(n,d)
愛麗絲拿到鮑勃發來的2790以後,就用自己的私鑰(3233, 2753) 進行解密。可以證明,下面的等式一定成立:
1
|
cd ≡ m (mod n)
|
也就是說,c的d次方除以n的餘數為m。現在,c等於2790,私鑰是(3233, 2753),那麼,愛麗絲算出
1
|
27902753 ≡ 65 (mod 3233)
|
因此,愛麗絲知道了鮑勃加密前的原文就是65。
至此,”加密–解密”的整個過程全部完成。
我們可以看到,如果不知道d,就沒有辦法從c求出m。而前面已經說過,要知道d就必須分解n,這是極難做到的,所以RSA演算法保證了通訊安全。
你可能會問,公鑰(n,e) 只能加密小於n的整數m,那麼如果要加密大於n的整數,該怎麼辦?有兩種解決方法:一種是把長資訊分割成若干段短訊息,每段分別加密;另一種是先選擇一種”對稱性加密演算法”(比如DES),用這種演算法的金鑰加密資訊,再用RSA公鑰加密DES金鑰。
私鑰解密的證明
最後,我們來證明,為什麼用私鑰解密,一定可以正確地得到m。也就是證明下面這個式子:
1
|
c^d ≡ m (mod n)
|
因為,根據加密規則
1
|
m^e ≡ c (mod n)
|
於是,c可以寫成下面的形式:
1
|
c = m^e - kn
|
將c代入要我們要證明的那個解密規則:
1
|
|