RSA加密算法简单介绍以及python实现
RSA加密算法簡單介紹
注:本篇文章只是本人在學完RSA加密之后的個人總結,若有不正確的地方,歡迎指正OVO
RSA是一種公鑰加密算法,它具有公鑰和私鑰兩種密鑰:公鑰用來加密,并且是公開的,私鑰是用來解密的,是不公開的,也不需要和數據一起傳送,這樣就能防止密鑰在網絡傳輸時泄露。
RSA算法設計的原理是依靠著模冪運算,例如加密、解密以及密鑰的產生。
1.密鑰設計
首先,我們需要了解密鑰設計的思想:
①加密計算:c = m^e mod n;
②解密計算:m = c^d mod n;
其中m為明文, c為密文,e為公鑰,d為私鑰,n為一個我們要產生的大數。
所以,根據以上兩個式子有:
dk( ek(m) ) = m
= (m^e mod n) ^d mod n ? ???? # 這里也就是先加密再解密
= m^(ed) mod n
那么要實現解密生成的數據和明文一樣,**m^(ed) mod n一定要等于m。①**
m^φ(n) mod n = 1 → m ^(tφ(n)) mod n = 1 → m ^(tφ(n)+1) mod n = m ②
∴① ②中兩個式子相對應,即有:ed = (t*φ(n)+1) → ed = 1 mod φ(n)。
不難看出,公鑰e和私鑰d是關于φ(n)互逆的。
到這里,可能會有疑問,為什么別人不能根據公鑰e和 φ(n)來直接求得私鑰呢?,這就是接下來要講的:如何生成n使別人難以計算φ(n)。
2.大數n的生成
首先,我們需要知道一個定理:若n = p*q, 且p,q為素數,那么φ(n) =φ(p) * φ(q) = (p-1) * (q-1)
而且我們知道,想要分解一個大的數是非常困難的,所以我們需要找兩個大數p,q,來使生成的n難以被分解計算,而且我們需要p,q都是素數,才能滿足上述定理,所以我們問題就變成了如何產生大素數p,q。
3.產生大素數p,q
我們思路可以是這樣:要產生大素數,我們可以先用隨機數產生一個大數,然后再判斷其是否為素數就行。
產生大數簡單,random庫可以實現,那么如何驗證其是否為素數呢?這里我們不能使用簡單的素數判別法:如遍歷比它小的所有數,并且對其取余,看是否為0。因為這樣只適用于小數,對于大數來說,計算時間太長了,根本行不通。所以這里我們需要采用一種素數檢測法:Miller-Rabin算法
Miller-Rabin算法思想:
首先,由費馬小定理:a^p-1 = 1 mod p (p為素數),我們可以將p-1寫成2 ^k*m形式,其中,a我們可隨機生成,但需滿足1<=a<=n-1。
那么a ^p-1 = ((a ^m) ^2) ^2 … ,所以我們可以先驗算a ^m mod p的結果是否為±1,
若是,那么a ^p-1 = ((a ^m) ^2) ^2 … 一定為1,那么可以判斷出p為素數;
若不是,令b=a^ m mod p的結果,然后依次計算b, b^ 2,b^ 4,…,b^ 2^(k-1) mod n,若發現有一個為±1,則p是素數,否則,p為合數。
但是,這種算法并不是100%正確,有時候也會將合數當成素數輸出,所以一般情況下,我們可以產生偽隨機數來進行素數檢測,而不是使用隨機數來檢測。
Miller-Rabin算法具體代碼如下:
#判斷是否為素數(Miller-Rabbin),RoundTime表示循環測試的次數,提高準確率 def _MillerRabin(self, num: int, times: int):# Miller-Rabin素性檢驗# return False if n is not primem = num-1k = 0while m & 1 == 0:m >>= 1k += 1for _ in range(times):x = random.randrange(2, num)x = self._FastExpMod(x, m, num)for _ in range(k):y = (x*x) % numif y == 1 and x != 1 and x != num-1:return Falsex = yif y != 1:return Falsereturn True4.密鑰生成
我們生成兩個大素數p,q后,我們就可以直接得到φ(n)。對于公鑰e,我們可以隨機生成,但需要滿足gcd(e,φ(n))=1(可以使用歐幾里得除法來判斷余數是否為1)。
然后對于私鑰d,因為ed = 1 mod φ(n)所以我們只需要求逆元就能得到d,然而求逆元可以根據歐幾里得除法逆過程來求得。歐幾里得除法求逆代碼如下:
#求x,y為兩個所求逆元,其中y為私鑰def _ExtendedEuclidean(self, a: int, b: int):# 擴展歐幾里得算法# return x, y, gcd(a,b)# 使得x*a + y*b = gcd(a,b)# 非遞歸實現if b == 0:return 1, 0, ay = s1 = 1x = s2 = 0q, r = divmod(a, b)while r:m = xn = yx = s1 - x*qy = s2 - y*qs1 = ms2 = na = bb = rq, r = divmod(a, b)return x, y, b5.加解密
加解密過程我們只需根據:
①加密計算:c = m^e mod n;
②解密計算:m = c^d mod n; 來計算就行。
但是,對于大數的計算,我們不能直接使用高級語言所給定的計算來求,這樣也會導致時間太長,我們在這需要使用平方-乘算法來求。該算法具體代碼如下:
#平方乘算法求余數 base^n mod mod def _FastExpMod(self, base: int, exp: int, mod: int):# 快速冪取模: 蒙哥馬利冪模運算# return base**exp % modbase = base % modexp = exp % modpower = 1while exp:if exp & 1:power = (power * base) % modexp >>= 1base = (base * base) % modreturn power全部代碼
import randomclass RSA:def __init__(self):self._lowPrimes = [2, 3, 5, 7, 11, 13, 17, 19]for i in range(self._lowPrimes[-1]+1, 1000):for p in self._lowPrimes:if i % p:continueelse:breakelse:self._lowPrimes.append(i)def _FastExpMod(self, base: int, exp: int, mod: int):# 快速冪取模: 蒙哥馬利冪模運算# return base**exp % mod# base = base % mod# exp = exp % modpower = 1while exp:if exp & 1:power = (power * base) % modexp >>= 1base = (base * base) % modreturn powerdef _MillerRabin(self, num: int, times: int):# Miller-Rabin素性檢驗# return False if n is not primem = num-1k = 0while m & 1 == 0:m >>= 1k += 1for _ in range(times):x = random.randrange(2, num)x = self._FastExpMod(x, m, num)for _ in range(k):y = (x*x) % numif y == 1 and x != 1 and x != num-1:return Falsex = yif y != 1:return Falsereturn Truedef _IsNotPrime(self, num: int, times: int = 10):# 分解質因數測試 + Miller-Rabin素性檢驗# return True if n is not primeif num < 2:return True# 分解質因數for p in self._lowPrimes:d, m = divmod(num, p)if m == 0:if d == 1:return Falseelse:return True# Miller-RabinisP = self._MillerRabin(num, times)return not isPdef _FindPrime(self, low_bits: int, high_bits: int) -> int:# 在區間[2^lowBits,2^highBits)尋找一個素數lowNum = 1 << low_bitshighNum = 1 << high_bitsn = random.randrange(lowNum, highNum)while self._IsNotPrime(n):n = random.randrange(lowNum, highNum)return ndef _ExtendedEuclidean(self, a: int, b: int):# 擴展歐幾里得算法# return x, y, gcd(a,b)# 使得x*a + y*b = gcd(a,b)# 非遞歸實現if b == 0:return 1, 0, ay = s1 = 1x = s2 = 0q, r = divmod(a, b)while r:m = xn = yx = s1 - x*qy = s2 - y*qs1 = ms2 = na = bb = rq, r = divmod(a, b)return x, y, bdef hex2int(self, x: str) -> int:# hex字符串轉換為整數return int(x, 16)def int2hex(self, x: int) -> str:# 整數轉換為hex字符串return hex(x)[2:]def hex2bin(self, x: str) -> str:# hex字符串轉換為字節數組if len(x) & 1:x = "0" + xbuffer = bytearray()for i in range(0, len(x), 2):buffer.append(self.hex2int(x[i:i+2]))x = bytes(buffer)return x.decode()def RSA_Key_Gen(self):# 生成RSA密鑰對key_len = 1024p = self._FindPrime(key_len-6, key_len-2)q = self._FindPrime(key_len+2, key_len+6)n = p * qphi = (p-1)*(q-1)gcd = 0while gcd != 1:e = random.randint(1, 2**100)_, d, gcd = self._ExtendedEuclidean(phi, e) # 歐幾里得求逆元if d < 0:d += phiwith open("RSA_Public_Key.txt", 'w') as f:res = str(n)+"\n"+str(e)f.write(res)with open("RSA_Secret_Key.txt", 'w') as f:res = str(n)+"\n"+str(d)f.write(res)def Encrypt(self, plain_text: str, public_key: tuple) -> int:data = int(plain_text.encode().hex(), 16) # 明文進行處理n, e = public_key # 獲得公鑰result = self._FastExpMod(data, e, n)return resultdef Decrypt(self, secret_text: int, secret_key: tuple) -> str:n, d = secret_keyresult = self._FastExpMod(secret_text, d, n)return self.hex2bin(self.int2hex(result))總結
以上是生活随笔為你收集整理的RSA加密算法简单介绍以及python实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 模拟试题B
- 下一篇: 倒计时适用于各种数据大屏