RSA加密算法
RSA加密算法 是一種 非對稱加密算法,在公開密鑰加密和電子商業中被廣泛使用。例如:
- 在HTTPS協議的加密層(SSL/TLS)作爲密鑰交換的方法
- 支付寶支付API作爲簽名算法
- 銀聯支付API作爲簽名算法
- Secure Shell(安全外殼協議,簡稱SSH)是一種加密的網絡傳輸協議
非對稱加密算法
公開密鑰密碼學 (英語:Public-key cryptography,也稱 非對稱式密碼學 )是密碼學的一種算法,它需要兩個密鑰,一個是公開密鑰,另一個是私有密鑰;一個用作加密,另一個則用作解密。 使用其中一個密鑰把明文加密後所得的密文,只能用相對應的另一個密鑰才能解密得到原本的明文;甚至連最初用來加密的密鑰也不能用作解密。由於加密和解密需要兩個不同的密鑰,故被稱爲非對稱加密; 不同於加密和解密都使用同一個密鑰的對稱加密。雖然兩個密鑰在數學上相關,但如果知道了其中一個,並不能憑此計算出另外一個;因此其中一個可以公開,稱爲公鑰,任意向外發布;不公開的密鑰爲私鑰,必須由用戶自行嚴格祕密保管,絕不透過任何途徑向任何人提供,也不會透露給被信任的要通信的另一方。
工作原理
本質就是依賴於三個自然數:n,e,d,n 和 d 構成一個密鑰,n 和 e 構成另一個密鑰。對於(n,d)與(n,e)這兩個密鑰,無論用哪個密鑰加密出來的密文都可以用另一個密鑰解開, 所以不必強調哪個用於加密,哪個用於解密,只要把一個公佈出去(稱爲公鑰),另一個自己藏着(稱爲私鑰)就行了。
根據這種特性,通常,
- 使用 公鑰加密 , 私鑰解密 ,實現 加密。
- 使用 私鑰加密 , 公鑰解密 ,實現 數字簽名 。
- 代替 密碼散列函數+Token,比如MD5、SHA2,做 消息認證。
(關於加密、數字簽名,消息認證可以期待下篇文章。)
關於
- 如何確定n,e,d這三個自然數?
- 如何進行加密解密?
- 已知公鑰如何破解私鑰?
我們需要了解RSA加解密的數學原理,主要包括
- 互質
- 歐拉函數
- 同餘
- 歐拉定理
- 模反元素
- 擴展歐幾里得算法
數學原理
你可以快速瀏覽這些定理和性質,然後進入下一章節,筆者在下一章節回答上述三個問題的同時,儘可能地將所需定理和性質做出了明確標註,閱讀過程中可以隨時回過頭來確認。
因子
一個整數被另一整數整除,後者即是前者的 因子,如1、2、4、8都爲8的因子。
質數
大於1的自然數,除1和本身外沒有其他正因子,稱爲 質數 。
互質
兩個自然數,除1以外沒有其他公因子,則稱它們爲 互質 。
互質性質
根據以上定理可以得出以下幾個性質(並不止於以下性質)
- 任意兩個不相等質數一定互質(因爲質數的因子只有1和本身,如果不相等則公因子只有1)
- 1和任意自然數都互質(只有1是公因子)
- 一個數是質數,另一個數只要不是前者的倍數,則二者互質(質數的因子只有1和本身,如果後者的因子不包含這個前者,那麼二者公因子只有1)
- 兩個數,較大的數是質數,那麼二者互質(可由 互質性質3 得到)
- 兩個不等質數之 積 的因子有4個,即,1,兩個不等質數以及積本身(由 質數定理 和 組合 可以得到)
歐拉函數
我們把用來表示“ 小於或等於n的正整數中與n互質的數的數目 ”的函數,稱爲歐拉函數,計作φ(n)
歐拉函數性質
-
若n是質數,那麼
φ(n)=n−1
由 互質性質4 可得。
-
若n=pq,且p,q是 兩個不相等的質數,那麼
φ(n)=(p−1)(q−1)
證明:
- 求φ(n),即求:小於等於的n的正整數,有多少數與n互質
- 逆向思考,可以先求:小於等於的n的正整數,有多少數與n不互質
- 由於p、q爲n的質因子,所以,如果一個數不與n互質,那麼這個數一定是p或q的整數倍(由 互質性質5 得)
- 由於n=pq,所以,(n−1)中包含1q,2q,3q...(p−1)q,一共(p−1)個q的倍數;同時包含1p,2p,3p...(q−1)p,一共(q−1)個p的倍數
- 又因爲p、q是n的質因子,所以,n是p、q的最小公倍數,即,在小於等於n的正整數中不存在p、q的其它公倍數
- 所以,小於等於的n的正整數,有(p−1)+(q−1)個數與n不互質
- 所以,小於等於的n的正整數,與n互質的數有
φ(n)=n−1−((p−1)+(q−1))φ(n)=pq−p−q+1φ(n)=(p−1)(q−1)
同餘
兩個整數a,b,若它們除以正整數m所得的餘數相等,則稱a,b對於模m同餘,記作
a%m=b%m⟹a≡b(modm)
同餘性質
- 當b<m時,b=a%m
- 整除性 ,a≡b(modm)⇒a−b=c∗m,c∈Z ,(即是說 a 和 b 之差是 m 的整數倍)
- 保持基本運算 ,a≡b(modm)c≡d(modm)}⇒{a±c≡b±d(modm)ac≡bd(modm)
這性質更可進一步引申成爲這樣:
a≡b(modm)⇒{an≡bn(modm),∀n∈Zan≡bn(modm),∀n∈N0
- 放大縮小底數 ,k爲整數,n爲正整數,(km±a)n≡(±a)n(modm)
同餘性質3、4 可以根據 同餘性質2 整除性來證明。
例如,證明:a≡b(modm)⇒an≡bn(modm)
a=c∗m+b,c∈Za∗n=(c∗m+b)∗nan=cn∗m+bnan≡bn(modm)
其它可同理證明。
同餘性質 是證明RSA加解密的關鍵。
歐拉定理
對任何兩個互質的正整數a 、n,n≥2,有
aϕ(n)≡1(modn)
費馬小定理
如果n是質數p,那麼
ap−1≡1(modp)
由 歐拉函數性質1 可得
模反元素
如果兩個正整數a和n互質,那麼一定可以找到整數b,使得ab−1被n整除
ab≡1(modn)
此時b就是a關於n的 模反元素。由 歐拉定理 可證,b一定存在。
aϕ(n)=a×aϕ(n)−1≡1(modn)
aϕ(n)−1就是a關於n的 模反元素b 。模反元素可以通過 擴展歐幾里得算法 求得。
歐幾里得算法
定義
又稱 輾轉相除法 ,是求最大公約數(最大公因子)的算法。兩個整數a,b的最大公約數,記作gcd(a,b)
計算過程
將前兩次餘數
分別作爲被除數
與除數
,得到新的餘數
,
ri+1=ri−1−qiri,(r0=a,r1=b)
遞歸計算,直到 ri+1=0,那麼此時 最大公約數 爲gcd(a,b)=ri
證明
證明,ri+1=0時,ri是a,b的 最大公因子 (g=gcd(a,b) )
- 因爲a=mg,b=ng,所以r2=r0−r1=a−q1b=mg−q1ng,所以r0,r1,r2可以被g整除,同理(遞降歸納)可求所有餘數r0,r1...ri−1,ri都可以被g整除,所以g≤ri
- 當ri+1=0,有0=ri−1−qiri,即ri整除ri−1
- 又當ri=ri−2−qi−1ri−1,(r0=a,r1=b),又因爲ri整除ri−1,那麼ri可以整除ri−2,同理(遞降歸納),ri可以整除所有餘數r0,r1...ri−2,ri−1
- 又因爲r0=a,r1=b,所以,此時ri≤g
- 結論,由於g≤ri,當ri+1=0時,ri≤g,所以當ri+1=0時,ri=g
擴展歐幾里得算法
定義
顧名思義是 歐幾里得算法 的擴展。已知整數a、b,擴展歐幾里得算法 可以在求得a、b的最大公約數的同時,能找到整數x、y(其中一個很可能是負數),使它們滿足 貝祖等式
ax+by=gcd(a,b)
在歐幾里得算法中,我們僅僅利用了每步帶餘除法所得的餘數。擴展歐幾里得算法還利用了帶餘除法所得的商,在輾轉相除的同時也能得到 貝祖等式
計算過程
擴展歐幾里得算法 在 歐幾里得算法 的基礎上增加了兩個遞歸等式的計算
ri+1=ri−1−qiri,(r0=a,r1=b)si+1=si−1−qisi,(s0=1,s1=0)ti+1=ti−1−qiti,(t0=0,t1=1)
遞歸計算,直到 ri+1=0,那麼此時
gcd(a,b)=ri=asi+bti
證明
證明,ri=asi+bti,i∈N(已知條件爲上述三等式),使用 完整歸納法
- 當i=0,r0=as0+bt0=a∗1+b∗0=a
- 當i=1,r1=as1+bt1=a∗0+b∗1=b
- 假設ri=asi+bti,ri−1=asi−1+bti−1成立,那麼
ri+1=ri−1−qiri=(asi−1+bti−1)−qi(asi+bti)=a∗(si−1−qisi)+b∗(ti−1−qiti)=asi+1+bti+1
所以ri=asi+bti,i∈N成立,si,ti滿足 貝祖等式。
Python實現
def ext_euclid(a, b):
r0, r1 = a, b
s0, s1 = 1, 0
t0, t1 = 0, 1
if a * b == 0:
raise Exception("a,b must be nonzero!")
while r1 != 0:
q = r0 // r1
r0, r1 = r1, r0 - q * r1
s0, s1 = s1, s0 - q * s1
t0, t1 = t1, t0 - q * t1
return r0, s0, t0
Java實現
public BigInteger[] extEuclid(String a, String b) {
BigInteger r0 = new BigInteger(a), r1 = new BigInteger(b),
s0 = BigInteger.ONE, s1 = BigInteger.ZERO,
t0 = BigInteger.ZERO, t1 = BigInteger.ONE;
if(r0.multiply(r1).equals(BigInteger.ZERO))
throw new IllegalArgumentException("a,b must be nonzero!");
BigInteger q;
BigInteger intermediate;
while (!r1.equals(BigInteger.ZERO)){
BigInteger[] quotientAndRemainder = r0.divideAndRemainder(r1);
q = quotientAndRemainder[0];
r0 = r1;r1 =quotientAndRemainder[1];
intermediate = s0 ;s0 = s1;s1=intermediate.subtract(s1.multiply(q));
intermediate = t0 ;t0 = t1;t1=intermediate.subtract(t1.multiply(q));
}
return new BigInteger[]{r0,s0,t0};
}
確定n,e,d
- 選擇兩個 不等質數 p,q,讓n=pq。假設p=17,q=23,那麼 n=17∗23=391
- 由上述 歐拉函數性質2 得,φ(n)=(p−1)(q−1)。我們隨機選擇一個數e,保證1<e<φ(n),同時保證,e與φ(n)互質。那麼 φ(n)=(17−1)∗(23−1)=352,隨機選擇e=57
- 求e關於φ(n)的 模反元素d ,即, ed≡1(modφ(n))⇒ed−k∗φ(n)=1,k,d∈Z,
57d+352k1=1
根據 擴展歐幾里得算法 可求,(d,k1)=(105,−17),d=105
加密解密
計算過程
設 明文
爲m,密文
爲c,如果用(n,e)加密,(n,d)解密,過程如下:
-
加密公式me≡c(modn),m<nc<nc=me%n
-
解密公式cd≡m(modn),m<n⇒m=cd%n
-
已知 明文
爲m=38,用(n,e)=(391,57)加密c=me%n=3857%391=327
-
已知 密文
爲c=327,用(n,d)=(391,105)解密m=cd%n=327105%391=38
Python實現
print(pow(38, 57, 391))
print(pow(327, 105, 391))
Java實現
System.out.println(BigInteger.valueOf(38).modPow(BigInteger.valueOf(57), BigInteger.valueOf(391)));
System.out.println(BigInteger.valueOf(327).modPow(BigInteger.valueOf(105), BigInteger.valueOf(391)));
證明
證明,已知加密公式
me≡c(modn),m<n,證明解密公式
cd≡m(modn),m<n成立。
-
根據已知條件,得出公式
me≡c(modn),m<n同餘性質3,保持基本運算med≡cd(modn)⟹cd≡med(modn)ed≡1(modφ(n))cd≡m1+kφ(n)(modn)⟹cd≡m∗mkφ(n)(modn)
-
當m與n互質,mφ(n)≡1(modn)(根據 歐拉定理)
1≡mφ(n)(modn)cd≡m∗mkφ(n)(modn)}同餘性質3,保持基本運算cd≡m(modn)
-
當m與n不互質
- 因爲m與n不互質,所以m與n,除1外有額外公共因子(根據 互質 定理)
- 因爲n=pq,所以n有四個因子,1、n、p、q(根據 互質性質5)
- 又因爲m<n,所以m=hp,h<q,h∈N∗ 或 m=hq,h<p,h∈N∗
- 假設m=hp,h<q,h∈N∗,此時h與q互質(根據 互質性質4 ),同時因爲p與q互質,所以m與q互質。
- cd≡m∗mkφ(n)(modn)歐拉函數性質2m∗mk(p−1)(q−1)(modn)⟹m∗(mq−1)k(p−1)(modn)
- m與q互質歐拉定理mφ(q)≡1(modq)歐拉函數性質1mq−1≡1(modq)同餘性質3(mq−1)k(p−1)≡1k(p−1)(modq)同餘性質2,整除性(mq−1)k(p−1)=1+tq,t∈N
- 由4,5,6可得
cd≡m∗(mq−1)k(p−1)(modn)(mq−1)k(p−1)=1+tq,t∈Nm=hp,h∈N∗⎭⎬⎫⟹cd≡[hp∗(1+tq)](modn)⟹cd≡(hp+th∗pq)(modn),th∈N⟹cd≡(hp+th∗n)(modn),th∈N同餘性質4,放大縮小底數cd≡hp(modn)⟹cd≡m(modn)
破解私鑰
假如我們已知公鑰(n,e),所謂破解私鑰(n,d),就是通過n,e,求出d。
已知ed≡1(modφ(n)),所以要求d,先求φ(n),
加密時我們通過p,q計算出φ(n),而破解時我們根本不知道p,q,需要通過對n進行 因數分解 求出φ(n)。
所以,要破解私鑰,就要對n進行 因數分解 ,n越大破解越困難。
目前已破解748-bit的密鑰,如果你覺得1024-bit還不夠安全,你可以使用2048-bit的密鑰,如果未來它們也被破解了,你只需要增加到更大。