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()