(加密基礎)RSA篇

RSA算法

RSA是一種非對稱加密算法,假如甲要和乙通訊,甲使用公鑰 A 加密,將密文傳遞給乙,乙使用私鑰 B 解密得到明文,其中公鑰是在網絡上進行傳遞的,私鑰只有乙自己擁有,不在網絡上傳遞,這樣即使知道了公鑰 A 也無法解密傳輸的信息

RSA算法原理和python代碼實現

1.生成公私鑰

1.1給定兩個質數P,Q

這裏的P,Q越大,該算法就會越安全,爲了方便描述,這裏給定P=67,Q=71,那麼他們的乘積n=4757

1.2計算n的歐拉函數φ(n)

根據歐拉函數的定義,φ(n)等於所有小於等於n的正整數中與n互質的個數,又因爲P*Q=n,且PQ均爲素數,所以φ(n) =(P-1)(Q-1)= 66 * 70 = 4620

1.3隨機選擇一個整數e(1<e<m) and e與m互質

這裏隨機選取e=101,注意,當e=m時會導致公私鑰相同

1.4給定整數d,使得(e*d)%m=1
因爲 (e*d)%m=1  

所以 e*d-m*y=1(y爲整數),由上述可知 e = 101,m = 4620 

所以 101d-4620y=1

根據相關定理(d,y)=1=101d-4620y

根據擴展歐幾里得算法:

4620=101x4+75
101=75x1+26
75=26x2+23
23=3x7+1
3=2x1+1
---->
101x1601-35x4620

得到d等於1601

計算完成後,得到公鑰 (n,e)=(4757,101) ,私鑰 (n,d)=(4757,1601),根據RSA算法的效果,除了接收方自己,沒有人知到私鑰,那麼通過公鑰能否得到私鑰呢

已知(e*d)%m=1,已知n,e,那麼要求d只需要求出n

而我們知道m是n的歐拉函數φ(n),想要知道m就必須將n分解成兩個質數的乘積
這裏由於數比較小,我們很容易分解出PQ的值,而隨着n的增大,分解會變得異常困難

2.加密生成密文

假設需要加密的數字時a
那麼將a轉化成int就是97
計算過程如下:

97^101%4757=3589

在這裏插入圖片描述

3.解密密文

根據公式
a^d % n = b

就可以得出明文

在這裏插入圖片描述

python代碼實現

由於C語言不支持大數,所以使用C語言實現異常麻煩這裏採用python代碼


# -*- coding: cp936 -*-


def isPrime(number):
    import math
    i = 2
    sqrtnum = (int)(math.sqrt(number))
    for i in range(2, sqrtnum + 1):
        if number % i == 0:
            return False
        i = i + 1
    return True


def is_ET_Prime(ee, tt):
    while tt != 0:
        a = ee
        ee = tt
        tt = a % tt
    if ee == 1:
        return True
    else:
        return False


def get_publickey(k, t):
    d = 0
    while ((d * k) % t != 1):
        d += 1
    return d


def encryption(plain, d, n):
    re = (plain ** d) % n

    return re


if __name__ == "__main__":
    print
    "~" * 70
    Flag = False
    while True:
        p = int(input("please input a prime p:"))
        q = int(input("please input a prime q:"))

        if (isPrime(p) and isPrime(q)):
            break
        else:
            print
            "p or q is not prime!"
            continue

    print
    "p=", p, "q=", q

    n = q * p
    t = (q - 1) * (p - 1)
    print("n=", n, "t=", t)

    print("~" * 70)

    Flag == False
    while Flag == False:
        e = int(input("please input a private key:"))
        Flag = is_ET_Prime(e, t)
        if Flag == False:
            print("e is not prime with the t!")

    print("the private key e=", e)

    d = get_publickey(e, t)
    print("the public key d=", d)

    plain = int(ord(input("please input the plain you want to entrypted:")))

    encry = encryption(plain, d, n)
    print("plain", plain, "is encrypted as", encry)
    #print(encry)
    plain1 = encryption(encry, e, n)
    print("encrypt", encry, "is decrypted as", plain1)

RSA共模攻擊

假設有一條信息m,由兩個不同的用戶使用公鑰進行加密(兩個用戶的e一般不同,模數n一般相同)

c1 = m^e1 mod n
c2 = m^e2 mod n

得到了兩個不同的密文c1,c2

共模攻擊這得到了這兩個密文c1,c2,因爲公鑰是公開的(e1,e2,n)已知

那麼攻擊者一共知道如下信息

gcd(e1, e2) = 1
m = c1^d1 mod n
m = c2^d2 mod n

那麼根據上述就可以直接求出明文m,由於gcd(e1,e2)那麼存在整數s1,s2使得e1*s1+e2*s2=1,又因爲

c1=m^e1 mod n
c2=m^e2 mod n

所以:

c1^s1 mod n=m^(e1*s1) mod n
c2^s2 mod n=m^(e2*s2) mod n
c1^s1*c2^s2 mod n=m^(e1*s1+e2*s2) mod n
又因爲e1*s1+e2*s2=1
所以
c1^s1*c2^s2  =m mod n
再由擴展歐幾里得算法和e1*s1+e2*s2=1,即可求出s1,s2

代碼模板:

from libnum import n2s,s2n
from gmpy2 import invert

def egcd(a, b):
if a == 0:
    return (b, 0, 1)
else:
    g, y, x = egcd(b % a, a)
    return (g, x - (b // a) * y, y)

def main():
    n = int(input("請輸入一個十六進制數n"),16)
    c1 = int(input("請輸入一個十六進制數c1"),16)
    c2 = int(input("請輸入一個十六進制數c2"),16)
    e1 = int(input("請輸入一個十六進制數e1"),16)
    e2 = int(input("請輸入一個十六進制數e2"),16)
    s = egcd(e1, e2)
    s1 = s[1]
    s2 = s[2]
    # 求模反元素
    if s1<0:
        s1 = - s1
        c1 = invert(c1, n)
    elif s2<0:
        s2 = - s2
        c2 = invert(c2, n)

    m = pow(c1,s1,n)*pow(c2,s2,n) % n
    print n2s(m)

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