rsa資料加密的python實現
阿新 • • 發佈:2020-12-11
目前只是嘗試了p和q在100以內,實現更大的數,需要的改動不大,就不贅述了
from random import randint
from math import sqrt
class rsa():
def __init__(self):
self.create()
def change(self, p, q):
try:
assert p * q > 255 and self.isprime(p) and self.isprime(q) # n應該大於255
#注:因為一個字串使轉二進位制時得到的01串共16位,
# 一個字串分割成兩個8位的01串,所以m應小於2^8
self.p = p
self.q = q
self.n = p * q
self.fn = (p - 1) * (q - 1) # 尤拉函式
self.e, self.d = self.returnED(self.fn)
return True
except:
return False
def create(self):
self.numList = []
n = 100 # 100內選素數
self.getprimelist(n)
num1 = len(self.numList) / 2 - 1
self.n = 0
while self.n <= 255:
self.p = self.numList[randint(0, int(num1))]
self.q = self.numList[randint(0, int(num1)) + int(len(self.numList) / 2)]
self.n = self.p * self.q
self.fn = (self.p - 1) * (self.q - 1)#尤拉函式
self.e, self.d = self.returnED(self.fn)
# 明文字串轉二進位制
def isprime(self,num):
if num > 1:
for i in range(2, int(sqrt(num))+1):
if num % i == 0:
return False
return True
else:
print('變數有誤,請輸入大於1的整數。')
def get_p_bin(self, Texts):
"""字串轉二進位制
Text:字串
return 字串對應的二進位制的編碼
"""
Text_bin = ''
for text in Texts:
s = ord(text)
s_bin = '{:016b}'.format(s)
Text_bin = Text_bin + s_bin
return Text_bin
# 密文字串轉二進位制
def get_c_bin(self, Texts):
"""字串轉二進位制
Text:字串
return 字串對應的二進位制的編碼
"""
Text_bin = ''
for text in Texts:
s = ord(text)
s_bin = '{:08b}'.format(s)
Text_bin = Text_bin + s_bin
return Text_bin
# 二進位制轉字元函式
def bin_str(self, s):
'''獲取16位的01串,返回對應的漢字'''
try:
return chr(int(s, 2))
except:
return -1
#求最大公約數
def gcd(self, a, b):
"""求最大公約數"""
c = a % b
while c != 0: # 輾轉相除法
a = b
b = c
c = a % b
# 當餘數為0時,迴圈結束
return b
#展示
def disp(self):
return self.n, self.e, self.p, self.q, self.d, self.fn
#獲取素數表
def getprimelist(self, n):
"""生成小於n的素數表"""
primelist = n * [1] # 全1矩陣
primelist[:2] = [0, 0] # 0和1不是素數
for i in range(2, int(sqrt(n))): # 只需要篩選到最大數的平方根即可,比最大數小的合數必然存在比最大數的平方根小的數
if primelist[i] == 1: # 確認除數是素數
for j in range(i * 2, n, i):
primelist[j] = 0 # 倍數肯定不是素數
for i in range(n):
if primelist[i] == 1:
self.numList.append(i)
#尤拉法求模逆元
def Euler(self, e, fn):
'''
e為d的係數,fn為k的係數ed=1(modfn)
'''
if fn == 0:
return 1, 0, e
else:
x, y, q = self.Euler(fn, e % fn)
x, y = y, (x - (e // fn) * y)
return x, y, q
#返回公鑰e和金鑰d
def returnED(self, fn):
e = randint(10, fn - 1)
while self.gcd(e, self.fn) != 1:
e = randint(10, fn - 1)
d, x, y = self.Euler(e, fn)
while d < 0:
d = d + fn
# print(f'e,d={e},{d}')
return e, d
#模冪演算法
def powmod(self, a, b, c):
"""a:底數
b:指數
c:模
"""
b_bin = bin(b)[2:]
b_bin = b_bin[::-1]
M = a
ans = 1
for i in range(len(b_bin)):
if b_bin[i] == '1':
ans = ans * M % c
M = (M * M) % c
return ans
#二進位制字串分割函式
def distribute(self, m):
""""給二進位制字串分組"""
mL = []
mlen = len(m)
i = 0
while 8 * (i + 1) <= mlen:
# print(f'm[{i*8}:{(i+1)*8}]:',m[i*8:(i+1)*8])
mL.append(int(m[i * 8:(i + 1) * 8], 2))
i += 1
return mL
#加密函式
def encryption(self, text):
m = self.get_p_bin(text) # 明文
mL = self.distribute(m)#8位為一組
self.__plaintext = mL
c = ''
for m in mL:
c = c + str(self.powmod(m, self.e, self.n)) + ' ' # 密文,m的e次方冪
#print("已完成c運算, c=", c)
self.__ciphertext = c
return self.__ciphertext
#解密函式
def dencryption(self, texts, flag):
'''flag=0字串
flag=2二進位制
flag=10十進位制
flag=16十六進位制
'''
cL = []
if flag == 0:
for text in texts:
cL.append(int(self.get_c_bin(text),2))
elif flag == 2:
texts = list(texts.split(' ')[:-1])
for text in texts:
cL.append(int(text, 2))
elif flag == 10:
cL = texts.split(' ')[:-1]
elif flag == 16:
texts = list(texts.split(' ')[:-1])
for text in texts:
cL.append(int(text, 16))
m = []
for c in cL:
m.append(str(self.powmod(int(c), self.d, self.n)))
#print("已完成m運算, m=", m)
self.__plaintext = m
return self.__plaintext
# 以數字形式展示
def showc_in_num(self, n):
''''n代表進位制,目前僅支援2進位制和16進位制'''
cstr = ''
s_hex = ''
s_bin = ''
c = self.__ciphertext
if n == 2:
for i in c.split(' ')[:-1]:
s_bin = s_bin + '{:b}'.format(int(i)) + ' '
return s_bin
elif n == 16:
s_hex = ''
for i in c.split(' ')[:-1]:
s_hex = s_hex + '{:x}'.format(int(i)) + ' '
return s_hex
elif n == 10:
return c
else:
return '請期待後續版本,感謝您的信賴'
# 明文以文字形式展示
def show_mtext(self):
'''明文'''
M = self.__plaintext
m_text = ''
for i in range(len(M)//2):
mystr = '{:08b}{:08b}'.format(int(M[2*i]),int(M[2*i+1]))
m_text = m_text+self.bin_str(mystr)
return m_text
# 密文以文字形式展示
def show_ctext(self):
'''密文'''
C = self.__ciphertext
C = C.split(' ')[:-1]
c_text = ''
for i in range(len(C)):
mystr= '{:016b}'.format(int(C[i]))
c_text = c_text + self.bin_str(mystr)
return c_text
if __name__ == '__main__':
R = rsa()
print(R.change(1051,1009))
text = '面朝大海,春暖花開!!'
R.encryption(text)
c = R.show_ctext()
print('c = ',c)
R.dencryption(c, 0)
print('m = ',R.show_mtext())
結果