簡介
RSA是第一個安全,實用的公鑰加密算法,已成爲國家標準,是目前應用廣泛的公鑰加密體制,RSA的基礎是數論的歐拉定理,它的安全性依賴於大整數因子分解的困難性,因爲加解密次序可換,可用於加解密,可用於設計數字簽名體制。
算法流程
- 選取兩個安全的大素數p和q(其長度要足夠長至少要是1024位)
- 計算乘積n = p * q, 計算phi(n) = (p-1)*(q-1),其中phi(n)爲n的歐拉函數
- 隨機選取整數e,作爲公鑰,要求滿足gcd(e, phi(n)) =1 ,即e與phi(n)互素
- 用擴展歐幾里得算法計算私鑰d。滿足d * e=1(mod phi(n)),e和n是公鑰,d是祕鑰。
我的代碼是固定了公鑰爲65537,產生的兩個大素數是通過Miller-Rabin算法進行塑素性檢測並且產生素數p還有q。
核心代碼及分析
首先是先產生兩個大素數p和q,這裏的核心代碼是下面的代碼,這裏是根據消息的長度去產生p和q,怎麼知道這兩大數是個素數呢?就得通過Miller-Rabin概率素數測試算法,先判斷一次費馬小定理,滿足的話就有可能是一個素數,然後再經過5次的Miller-Rabin素性測試,這樣就可以很大概率說明其是素數,兩次調用這樣的過程就可以產生p和q。
#輾轉相除法求最大公因數
def gcd(a, b):
if a > b: a, b = b, a
while b != 0:
a, b = b, a%b
return a
def isPrime(n):
"""
判斷一個數是否爲素數
厄拉託塞師除法
"""
if n <= 1:
return False
for i in range(2, int(math.sqrt(n)) + 1):
if n % i== 0:
return False
return True
#開始選擇p q
def random_prime(half_len):
while True:
n = random.randint(0, 1 << half_len)#求2^half_len之間的大數
if n % 2 != 0:
found = True
# 隨機性測試
for i in range(0, 5): #5的時候錯誤率已經小於千分之一
if prime_test(n) == False:
found = False
break
if found == True:
return n
#Miller-Rabin
def prime_test(n):
"""
測試n是否爲素數
"""
q = n - 1
k = 0
# 尋找k,q 是否滿足2^k*q =n - 1
while q % 2 == 0:
k += 1
q = q // 2
a = random.randint(2, n - 2)
# 如果 a^q mod n= 1, n 可能是一個素數
if fast_mod(a, q, n) == 1:
return True
# 如果存在j滿足 a ^ ((2 ^ j) * q) mod n == n-1, n 可能是一個素數
for j in range(0, k):
if fast_mod(a, (2 ** j) * q, n) == n - 1:
return True
# n 不是素數
return False
因爲是固定好公鑰e=65537的,所以下一步的關鍵就是要實現通過擴展歐幾里得算法去求出私鑰d,這裏面的關鍵代碼如下,先是求出phi(n)然後就通過擴展歐幾里得算法求出私鑰d,然擴展歐幾裏的算法使用了遞歸的方法去實現,但是產生的私鑰d有可能是一個負數,你得對其進行處理,最後產生一個大於零的私鑰。
def generate_key(key_len): #key_len要比消息長度大
"""
生成n, e, d
"""
p = random_prime(key_len // 2)
q = random_prime(key_len // 2)
n = p * q
ph_n = (p -1) * (q -1)
print("ph_n:"+str(ph_n))
e = 65537 #e取固定值
d = generate_d(ph_n, e)
return (n ,e, d)
def ext_gcd(a, b):
if b == 0:
return 1, 0, a
else:
x, y, q = ext_gcd(b, a % b)
x, y = y, (x - (a // b) * y)
return x, y, q
#產生祕鑰d
def generate_d(ph_n, e):
(x, y, r) = ext_gcd(ph_n, e)
# y maybe < 0, so convert it
if y < 0:
#return y % ph_n
return y + ph_n #直接用加法效率高一丟丟
return y
在執行運算的時候使用了一個快速冪的方法,這個方法可以將數值大一點的數簡化其模冪運算的過程,代碼如下,當然這樣的過程也可以使用python裏面的pow函數去實現。
def fast_mod(b, n, m):
"""
快速冪
"""
ret = 1
tmp = b
while n:
if n & 0x1:
ret = ret * tmp % m
tmp = tmp * tmp % m
n >>= 1
return ret
正確性
以"helloworldaaa"爲例能夠正確加解密並且輸出加解密的公鑰以及私鑰。