RSA是由MIT的三位數學家R.L.Rivest,A.Shamir和L.Adleman[Rivest等1978, 1979]提出的一種用數論構造雙鑰的方法,被稱爲MIT體制,後來被普遍稱之爲RSA體制。其既能夠做爲加密,又能夠用於數字簽字。RSA算法的安全性基於數論中大整數分解的困難性。python
算法描述算法
1.獨立的選取兩個大素數p和q
2.計算\(n = p * q\),其歐拉函數值爲\(\phi(n) = (p-1) * (q-1)\)
3.隨機選一個整數\(e\),\(1\leq e\leq \phi(n) , gcd(\phi(n),e) = 1\) #gcd爲最大公約數
4.在模\(\phi(n)\)下,計算e的逆元\(d = e^{-1} mod \phi(n)\) #意思是\((e * d) mod \phi(n) =1\)
5.以n,e爲公鑰,密鑰爲d安全
加密
將明文分組,每組的數要求小於n(字符串就想辦法映射到整數)
計算\(c = m^e mod n\),其中m爲明文,c爲能夠傳輸的密文app
解密
計算\(m = c^d mod n\)函數
這個過程當中只有算法描述中的第三步可能不是直接想到求解方法,對應這個問題,能夠用擴展的歐幾里得算法來求逆元。加密
如下算法內容來源自華中科技大學的PPT,在此註明。spa
問題:求A關於模N的逆元B
迭代計算
N = A × a0 + r0
A = r0 × a1 + r1
r0= r1 × a2 + r2
r1= r2 × a3 + r3
……
rn-2= rn-1 × an + rn
rn-1= rn-2× an+1+ 0
對上面的商數逆向排列(不含餘數爲0的商)
其中\(b_{-1} = 1\),\(b_0 = a_n\),\(b_i = a_{n-i} * b_{i-1} + b_{i-2}\)
若是商的個數爲偶數,則\(b_n\)就是所求的B
若是商的個數爲奇數,則\(N-b_n\)就是所求的Bcode
例1:求61關於模105的逆元
105=61×1+44
61 =44×1+17
44 =17×2+10
17 =10×1+7
10 =7 ×1+3
7 =3 ×2+1
3 =3 ×1+0blog
因爲商的個數爲偶數(不包括餘數爲0的商),因此31就是61關於105的逆元ip
例二:求31關於模105的逆元
105=31×3+12
31 =12×2+7
12 =7 ×1+5
7 =5 ×1+2
5 =2 ×2+1
2 =1 ×2+0
商的個數是奇數,因此105-44 = 61爲31關於模105的逆元
代碼實現以下:
# coding=utf8 class RSA: def encrypt(self, string, n, e): ''' use RSA algorithm to encrypt string :param string: the String need to be encrypt :param n: p * q :param e: encrypt code number :return: encrypt number 這裏是將字符先轉換爲ASCII值再加密 ''' s = [] for i in string: s.append(str(ord(i))) for i in range(len(s)): s[i] = int(s[i]) ** e % n return s def decrypt(self, p, q, e, encoding): ''' :param p: prime number p :param q: prime number q :param e: encrypt code number :param encoding: the string that need to be decrypted :return: the string that decrypt the encoding number 這裏相應的多了一步將ASCII轉爲字符後拼接的過程 ''' f_n = (p - 1) * (q - 1) n = p * q d = RSA.ext_euclid(e, f_n) s = [] for i in range(len(encoding)): s.append(chr(encoding[i] ** d % n)) return ''.join(s) @staticmethod def ext_euclid(e, f_n): ''' :param e: encrypt code number :param f_n: p * q :return: the number that multiply e mod n equals 1 ''' nc = f_n if e > f_n or type(e) != int or type(f_n) != int: return -1 quotient = [] #商的列表 remainder = -1 #餘數 while remainder != 0: quotient.append(f_n / e) remainder = f_n - (f_n / e) * e f_n = e e = remainder quotient = quotient[:-1][::-1] #對應上面寫的將商逆序寫出來 d_list = [1, quotient[0]] for i in range(1, len(quotient)): d_list.append(d_list[-1] * quotient[i] + d_list[-2]) return d_list[-1] if len(quotient) % 2 == 0 else nc - d_list[-1] #若是商的個數是偶數,直接返回bn,不然返回N - bn if __name__ == '__main__': r = RSA() p = int(raw_input("p = ")) q = int(raw_input("q = ")) e = int(raw_input("e = ")) string = raw_input("String: ") en = r.encrypt(string, p * q, e) print "encrypted code: ", ' '.join(map(str, en)) print "decrypted code: ", r.decrypt(p, q, e, en)
運行如圖:
這裏能夠用小素數的緣由是在代碼中將明文簡單的按字符分組了,但這樣會收到頻率分析的攻擊,在此僅是實驗用。