加密部分
加密部分比较简单
字符生成数据
这里需要一个函数将输入的字符串转化为矩阵,方便后续计算,l参数为切割的长度,因为输入字符不一定能被完整切割,所以在生成的矩阵最后一行对不足的补0
:
def gen_data(m,l=3):#将m生成定长的矩阵,每行为一个定长段
m = m.replace(" ","").lower()#全部变成小写
h = len(m)/l
if int(h)<h:
h = int(h)+1
M = np.zeros([int(h),int(l)])
#字符分成定长段
textArr = re.findall('.{'+str(l)+'}', m)
tem_text = m[(len(textArr)*l):]#防止添加空字符段
if len(tem_text) >0:
textArr.append(tem_text)
for i in range(len(textArr)):
tem = [ord(j) - 97 for j in textArr[i]]
# print(tem)
M[i] = np.pad(tem,(0,l-len(tem)))#最后一段数据不足时填充
return M
对该函数进行测试,生成的数据会将空格清除,并且全部变为小写:
gen_data('asdafgrefgergk')
----------->>
array([[ 0., 18., 3.],
[ 0., 5., 6.],
[17., 4., 5.],
[ 6., 4., 17.],
[ 6., 10., 0.]])
字符串加密
加密输入的参数A必须可逆
def gcd(a, b=26):
while a != 0:
a, b = b % a, a
return b
def duobiaodaihuan_en(A,B,m,N=26,l=3):
a = round(np.absolute(np.linalg.det(A)))
if a==0:
print('矩阵A不可逆')
return None
if int(gcd(a,N)) !=1:
print("A与N 不满足gcd条件")
return None
#加密过程
M = gen_data(m,l)
C = (np.dot(A,M.T)+B)%N
C = C.T.reshape(1,-1)#还是二维数组
result = [chr(int(i+97)) for i in C[0]]
return ''.join(result)
对该函数进行测试
A=np.array([[11,2,19],[5,23,25],[20,7,17]])#这个矩阵A是教材上提供的
B = np.random.randint(0,26,[3,1])#随机生成B
m = duobiaodaihuan_en(A,B,'YOUR PIN NO IS FOUR ONE TWO SIX')
m
-------->
'whefhftnnlidxudwctzqobsx'
解密部分
模逆运算
模逆矩阵的求法有点复杂,这里参考了哈其他博主的一些放法
def gcd(a, b=26):
while a != 0:
a, b = b % a, a
return b
#矩阵A的模逆运算
def inv_A(A,N=26):
det_inv = exgcd(int(round((det(a) % 26))), 26)
tem_A = np.linalg.det(A)*np.linalg.inv(a)%N
A_inv =tem_A*det_inv%N
return A_inv
def exgcd(a, m):
if gcd(a, m) != 1:
return None
u1, u2, u3 = 1, 0, a
v1, v2, v3 = 0, 1, m
while v3 != 0:
q = u3 // v3
v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3
return u1 % m
这个测试哈模逆矩阵
A = array([[11, 2, 19],
[ 5, 23, 25],
[20, 7, 17]])
inv_A(A)
------>
matrix([[10., 23., 7.],
[15., 9., 22.],
[ 5., 9., 21.]])
字符解密
与加密类似,只要提前把需要的参数准备好参考教材上的公式就好了
def duobiaodaihuan_de(A,B,m,N=26,l=3):
a = round(np.absolute(np.linalg.det(A)))
if a==0:
print('矩阵A不可逆')
return None
if int(gcd(a,N)) !=1:
print("A与N 不满足gcd条件")
return None
#解密过程过程
M = gen_data(m,l)
C = np.dot(inv_A(A,N),M.T-B)%N
C = C.T.reshape(1,-1)#还是二维数组
result = [chr(int(round(i+97))) for i in np.array(C)[0]]#注意用round,不然回少一个值
return ''.join(result)
测试上面加密的字符
duobiaodaihuan_de(A,B,m)
---->
'yourpinnoisfouronetwosix'
多表代换源码
#古典密码实现
import numpy as np
import re
def duobiaodaihuan_en(A,B,m,N=26,l=3):
a = round(np.absolute(np.linalg.det(A)))
if a==0:
print('矩阵A不可逆')
return None
if int(gcd(a,N)) !=1:
print("A与N 不满足gcd条件")
return None
#加密过程
M = gen_data(m,l)
C = (np.dot(A,M.T)+B)%N
C = C.T.reshape(1,-1)#还是二维数组
result = [chr(int(i+97)) for i in C[0]]
return ''.join(result)
def duobiaodaihuan_de(A,B,m,N=26,l=3):
a = round(np.absolute(np.linalg.det(A)))
if a==0:
print('矩阵A不可逆')
return None
if int(gcd(a,N)) !=1:
print("A与N 不满足gcd条件")
return None
#解密过程过程
M = gen_data(m,l)
C = np.dot(inv_A(A,N),M.T-B)%N
C = C.T.reshape(1,-1)#还是二维数组
result = [chr(int(round(i+97))) for i in np.array(C)[0]]#注意用round,不然回少一个值
return ''.join(result)
def gcd(a, b=26):
while a != 0:
a, b = b % a, a
return b
#矩阵A的模逆运算
def inv_A(A,N=26):
det_inv = exgcd(int(round((det(a) % 26))), 26)
tem_A = np.linalg.det(A)*np.linalg.inv(a)%N
A_inv =tem_A*det_inv%N
return A_inv
def exgcd(a, m):
if gcd(a, m) != 1:
return None
u1, u2, u3 = 1, 0, a
v1, v2, v3 = 0, 1, m
while v3 != 0:
q = u3 // v3
v1, v2, v3, u1, u2, u3 = (u1 - q * v1), (u2 - q * v2), (u3 - q * v3), v1, v2, v3
return u1 % m
def gen_data(m,l=3):#将m生成定长的矩阵,每行为一个定长段
m = m.replace(" ","").lower()#全部变成小写
h = len(m)/l
if int(h)<h:
h = int(h)+1
M = np.zeros([int(h),int(l)])
#字符分成定长段
textArr = re.findall('.{'+str(l)+'}', m)
tem_text = m[(len(textArr)*l):]#防止添加空字符段
if len(tem_text) >0:
textArr.append(tem_text)
for i in range(len(textArr)):
tem = [ord(j) - 97 for j in textArr[i]]
# print(tem)
M[i] = np.pad(tem,(0,l-len(tem)))#最后一段数据不足时填充
return M
A=np.array([[11,2,19],[5,23,25],[20,7,17]])
B = np.random.randint(0,26,[3,1])
m = duobiaodaihuan_en(A,B,'YOUR PIN NO IS FOUR ONE TWO SIX')
print(f"加密:{m}")
c = duobiaodaihuan_de(A,B,m)
print(f"解密:{c}")