一文搞懂RSA算法原理及简单实现
前言
RSA算法是最重要的算法之一,它是一種非對稱加密,是目前最有影響力的加密方式之一。這篇文章我們通過實現(xiàn)一種簡單的RSA加密來探究它的原理。
計算公鑰和私鑰
RSA中的公鑰和私鑰需要結(jié)合在一起工作。公鑰用來對數(shù)據(jù)塊加密,之后 ,只有對應(yīng)的私鑰才能用來解密。生成密鑰時,需要遵循幾個步驟以確保公鑰和私鑰的這種關(guān)系能夠正常工作。這些步驟也確保沒有實際方法能夠從一個密鑰推出另一個。
開始前,首先要選擇兩個大的素數(shù),記為p和q。根據(jù)當(dāng)今求解大數(shù)因子的技術(shù)水平,這兩個數(shù)應(yīng)該至少有200位,這們在實踐中才可以認(rèn)為是安全的。
然后,開始計算n:
n = pq
接下來,選擇一個小的奇數(shù)e,它將成為公鑰的一部分。選擇e最需要考慮的重點是它與(p-1)(q-1)不能有相同的因子。換句話說,e與(p-1)(q-1)是互為素數(shù)關(guān)系的。比如,如果p=11而q=19,那么n=11 X 19=209。這里選擇e=17,因為(p-1)(q-1)=10 X 18 =180,而17和180沒有相同的因子。通常選擇3、17、65、537作為e的值。使用這些值不會對RSA的安全性造成影響,因為解密數(shù)據(jù)還需要用到私鑰。
一旦為e選擇了一個值,接下來開始計算相對應(yīng)的值d,d將成為私鑰的一部分。d的值就是計算e的倒數(shù)對(p-1)(q-1)的取模結(jié)果,公式如下:
d = e-1 mod (p-1)(q-1)
這里d和e是模乘法逆元的關(guān)系。
思考一下這個問題:當(dāng)d為多少時可以滿足ed mod (p-1)(q-1) = 1 ?比如在等式 17d mod 180 = 1中,d的一個可能值是53。其他的可能值是233、413、593等。在實踐中,可以利用歐幾里德算法來計算模乘法逆元。這里就不再展開。
現(xiàn)在有了e和d的值,將(e,n)作為公鑰P,將(d,n)作為私鑰S并保持其不可見。
如何計算d?
上面p、q、e需要預(yù)設(shè)三個素數(shù),n很容易求出來,但是d的計算就涉及到模的運算了
什么是模、取模和模運算?
取模:
https://baike.baidu.com/item/%E5%8F%96%E6%A8%A1%E8%BF%90%E7%AE%97/10739384?fr=aladdin
模運算:
https://baike.baidu.com/item/%E6%A8%A1%E8%BF%90%E7%AE%97/4376110
具體就不細(xì)說了,但是要注意取模和取余的區(qū)別
這里d = e-1 mod (p-1)(q-1)
簡化為:
d = e-1 % m
這是乘法逆元的問題。我們對上面的進行處理
d * e = e-1 % m * e
(d * e) % m = (e-1 % m * e) %m
根據(jù)模運算的結(jié)合率
(a%p * b)%p=(a * b)%p
(d * e) % m = (e-1 % m * e) %m = (e-1 * e) % m = 1 % m
所以我們最后得到
(d * e) % m = 1 % m
這里由于n說我們自己定義的,一定是正數(shù),所以1%n=1
所以最后變?yōu)橛嬎?/p>
(d * e) % m = 1
并且e和d一定有一組解滿足他們都小于m。我們只需求這組解即可。
根據(jù)費馬小定理,如果a和b互質(zhì),則
ab-1 % b = 1
那么已經(jīng)要求e與m互質(zhì),所以
(e * em-2) % m = 1
所以d的一個解是em-2,但是這個很可能比m大,則可以表示為m + k,那么
(e * (m + k)) % m = 1
根據(jù)模的加法運算規(guī)則
(em % m + e*k % m) % m = 1
因為em % m一定是0,所以上面的可以轉(zhuǎn)為
e*k % m = 1
如果k還大于m,則重復(fù)上面的步驟直到k小于m。這時k就是d。
因為e小于m,所以d一定有一個小于m的解使 (d * e) % m = 1成立
代碼
簡單的算法是遍歷找到d,代碼:
var q = 13; var p = 17; var n = q * p; var e = 7; var tmp = (q - 1) * (p - 1); var d; for (d = 1; ; d++) {if (e * d % tmp === 1) {break} }這里還需要進行優(yōu)化,因為一般n都是超大數(shù),而e則比較小,所以d也會很大,這里就需要大量的循環(huán),優(yōu)化后如下:
var d;for (var j = 1; j < e; j++) {if ((tmp * j + 1) % e === 0) {d = (tmp * j + 1) / e;break;}}因為 (d * e) % m = 1也就是
d * e = k * m + 1
而且d也需要小于m,所以k一定小于e,而e是比較小的值,所以我們將循環(huán)改成k即可減少大量的計算。
加密和解密數(shù)據(jù)分組
要使用RSA算法對數(shù)據(jù)進行加密和解密,首先要確定分組的大小。為了實現(xiàn)這一步,必須確保該分組可以保存的最大數(shù)值要小于n的位數(shù)。比如,如果p和q都是200位數(shù)字的素數(shù),則n的結(jié)果將小于400位。因而,所選擇的分組所能保存的最大值應(yīng)該要以是接近于400。在實踐中,通常選擇的位數(shù)都是比n小的2的整數(shù)次冪。比如,如果n是209,要選擇的分組大小就是7位,因為27 = 128比209小,但28 = 256又大于209。
要從緩沖區(qū)M中加密第(i)組明文Mi ,使用公鑰(e,n)來獲取M的數(shù)值,對其求e次冪,然后再對n取模。這將產(chǎn)生一組密文Ci。對n的取模操作確保了Ci將和明文的分組大小保持一致。因而,要加密明文分組有:
Ci = Mie mod n
之前提到過,歐拉函數(shù)是采用冪模運算來加密數(shù)據(jù)的基礎(chǔ),根據(jù)歐拉函數(shù)及其推導(dǎo)式,能夠?qū)⒚芪慕饷芑卦摹?/p>
要對緩沖區(qū)中C中的第(i)組密文進行解密,使用私鑰(d,n)來獲取Ci的數(shù)值部分,對其求d次冪,然后再對n取模。這將產(chǎn)生一組明文Mi。因此,要解密密文分組有:
Mi = Cid mod n
計算過程及優(yōu)化
這里加密解密的算法一樣,只不過key值不同而已,涉及的是模的冪運算
以加密為例
Ci = Mie mod n
因為需要考慮大數(shù)的問題,所以模的冪運算不能直接運算,比如如果我先直接計算Mie,由于Mi有可能是很大的數(shù),這樣它的e次冪就會是一個超級數(shù)字,計算機無法計算和存儲
所以這里我們就需要對模冪運算進行優(yōu)化,就涉及到了蒙哥馬利算法
參考
https://blog.csdn.net/zgzczzw/article/details/52712980
https://blog.csdn.net/linraise/article/details/17490769)
蒙哥馬利算法比較復(fù)雜,包含三個算法進行優(yōu)化。
我們先設(shè)計一個簡單的算法,先將模冪運算轉(zhuǎn)化為模乘運算
關(guān)于模運算,有如下幾個公式:
結(jié)合律(a%p*b)%p=(a*b)%p同理((a*b) % p * c)% p = (a*b*c) % p 四則運算(a * b) % p = (a % p * b % p) % p (a^b) % p = ((a % p)^b) % p我們先利用上面兩個結(jié)合律,所以:
a2%n = (a * a) %n = (a%n * a) %n
因為a%n取模一定比a小,所以a%n*a就要比a2小很多,類推
a3%n = (a2 * a) %n = ((a2%n)*a)%n
得出
an%n = ((an-1%n)*a)%n
這是一個簡單遞歸算法,通過這個算法,每次乘完都會做一個取模運算,運算的數(shù)據(jù)就會小很多。
代碼:
function encode(x, e, n) {var result = x % n;for (var i = 1; i < e ; i++) {result = (result * x) % n;}return result }function decode(x, d, n) {var result = x % n;for (var i = 1; i < d ; i++) {result = (result * x) % n;}return result }當(dāng)然,上面僅僅是簡單例子,因為如果冪數(shù)較大比如d就會是一個超大數(shù),這樣循環(huán)次數(shù)就會很多,計算時間很長。
根據(jù)模的運算法則:
(a % p * b) % p = (a * b) % p
(a * b) % p = (a % p * b % p) % p
我們可以得出,當(dāng)指數(shù)(假設(shè)為e)是偶數(shù)時
se % n = ((se/2 % n) * (se/2 % n)) % n
當(dāng)為奇數(shù)時則可以先轉(zhuǎn)成偶數(shù)
se % n = ((se - 1 % n) * e) % n
這樣就可以用二分法和位運算來優(yōu)化算法。如下:
function modpow(x, p, m) {if(p === 1){return mod(x, m)}var mid;if((p & 1) === 0){mid = (p >> 1);var tmp1 = modpow(x, mid, m);return mod(tmp1 * tmp1, m);}else{return mod(modpow(x, p - 1, m) * x, m)} }1、利用遞歸二分。因為開方所以每個節(jié)點的兩個子節(jié)點都相等,所以計算其中一個就可以,這樣我們只需計算二叉樹的一條路徑就可以了,整體復(fù)雜度只有O(log2n)。比如2n只需要計算n + x次(最多壞情況每次都是奇數(shù)則是2n),比2n次計算節(jié)省大量的時間,而且數(shù)據(jù)越大節(jié)省時間越多。
2、位運算。在判斷奇偶數(shù)時,沒有使用除法,因為除法運算復(fù)雜度很大,耗時比其他運算長很多。這里使用位運算,只需判斷最低位是否為0即可,而除2運算則可以用右移一位代替。因為計算機中位運算最快,所以這樣會節(jié)省大量的時間。
正確性驗證
加密我們可以理解,因為運算中有模參與,所以不可逆。但是加密后為什么通過私鑰就可以解密,解密一定正確么?
首先加密
k = se % n
然后對k解密
r = ((se % n)d) %n
根據(jù)(a^b) % p = ((a % p)^b) % p可得
r = (se)d % n = se*d % n
通過之前的計算可知 (d * e) % m = 1,而m是(q-1)(p-1),所以
d * e = k(q-1)(p-1) + 1 (k未知)
而且n=pq,所以
r = sk(q-1)(p-1) + 1 % (pq)
根據(jù)費馬小定理,如果a和b互質(zhì),則
ab-1 = 1 mod b
所以考慮兩種情況:
1、s與n即pq互質(zhì)
因為p和q是兩個大質(zhì)數(shù),所以s與n互質(zhì)就相當(dāng)于s分別于p和q互質(zhì)
所以根據(jù)費馬小定理
sp-1 = 1 mod p
即
sp-1 % p = 1
所以根據(jù)冪模的運算法則(a^b) % p = ((a % p)^b) % p
sk(q-1)(p-1) % p = (sp-1 % p)k(q-1) % p
因為sp-1 % p = 1,所以
sk(q-1)(p-1) % p = 1k(q-1) % p = 1
同理可以得出
sk(q-1)(p-1) % q = 1
所以sk(q-1)(p-1) - 1可以被p和q都整除,得出
sk(q-1)(p-1) % (pq) = 1
回到之前
r = sk(q-1)(p-1) + 1 % (pq) = (sk(q-1)(p-1) * s) % (pq)
根據(jù)模的結(jié)合率(a%p * b)%p=(a * b)%p
r = ( (sk(q-1)(p-1) % (pq)) * s ) % (pq)
上面推出sk(q-1)(p-1) % (pq) = 1,所以
r = s % (pq)
因為pq = n所以最終
r = s % n
根據(jù)上面RSA算法要求,可知s一定是小于n的數(shù),所以s對n取模結(jié)果也是s
所以 r = s 驗證了RSA的正確性。
2、s于n不互質(zhì)
總結(jié)
以上是生活随笔為你收集整理的一文搞懂RSA算法原理及简单实现的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 浅析在公众号中使用弛声sdk为什么上传解
- 下一篇: 如何实现一套可切换的声网+阿里的直播引擎