RSA原理及Python實現

簡介

RSA是第一個安全,實用的公鑰加密算法,已成爲國家標準,是目前應用廣泛的公鑰加密體制,RSA的基礎是數論的歐拉定理,它的安全性依賴於大整數因子分解的困難性,因爲加解密次序可換,可用於加解密,可用於設計數字簽名體制。

算法流程

  1. 選取兩個安全的大素數p和q(其長度要足夠長至少要是1024位)
  2. 計算乘積n = p * q, 計算phi(n) = (p-1)*(q-1),其中phi(n)爲n的歐拉函數
  3. 隨機選取整數e,作爲公鑰,要求滿足gcd(e, phi(n)) =1 ,即e與phi(n)互素
  4. 用擴展歐幾里得算法計算私鑰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"爲例能夠正確加解密並且輸出加解密的公鑰以及私鑰。

F5RHAO.png

詳細代碼(放在github上了):RSA加解密

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章