本文附有丰富的代码,故文章冗长,请对照目录查阅,各大板块均有上下文提示
目录
古典密码简介
古典密码主要有置换和代换的方法。置换:字母重新排列,字母本身不变,但其位置改变了(凯撒密码、移位变换)。代换:将明文中的字符替代成其他字符(仿射变换、多表代换)。
在线性空间的变化中,古典加密就是移动并拉伸物体,让物体变得与原来不一样;解密解释将物体移动回去拉伸回去,恢复物体的原样。
凯撒密码 移位变换 仿射变换可以理解为单表代换,这三种古典密码实质上可以归根于多表代换的特殊形式——单表代换,即一个字母一组。
在此文中,考虑到凯撒密码、移位密码的简单性,仅介绍仿射变换、多表代换加密。加密算法的详细内容请自行查阅,以下仅列出变换公式
仿射变换:
加密:
解密:
其中为密钥,且满足,, 为的乘法逆元。
多表代换:
将n个字母长的明文M分成M1,M2···Mi对每个分组:
加密:
解密:
为密钥,为的可逆矩阵(即),且满足,为密文分组。
1.加密算法基础准备
在这两种古典加密中最重要的是求逆元,即 的乘法逆元 , 的加密逆元 。两个逆元均用扩展欧几里得法。因此将扩展欧几里得、求逆元等算法封装在 类MathUitl 中。仿射变换、多表代换等加解密算法封装在 类TransAlgor 中,以供加解密使用。另一个 类IintiDeal 用与处理密钥输入等,现在不用关心。重要的地方均有注解,没注解就是你也一定会看懂!
# 本代码文件名:__util.py
import numpy as np
class MathUtil():
""" 数学运算工具类 """
def extendGcd(a, b):
"""扩展欧几里德算法"""
if b == 0:
return 1, 0
else:
x, y = MathUtil.extendGcd(b, a % b)
x, y = y, x - (a//b) * y
return x, y
def modInvElem(a:int, m=26):
"""求整数a关于1模m的乘法逆元"""
if (np.gcd(a, m) !=1): return -1
inva, _ = MathUtil.extendGcd(a, m)
inva %= m
return inva
def modInvMatrix(A, m=26):
"""求矩阵A关于1模m的乘法逆元"""
detA = np.linalg.det(A)
invA = np.linalg.inv(A)
Adjoint = detA * invA
inv_detA = MathUtil.modInvElem(round(detA), m)
cipher_invA = ((inv_detA % m) * Adjoint) % m
cipher_invA = np.round(cipher_invA).astype(int)
return cipher_invA
class TransAlgor():
""" 变换算法工具类 """
def affine(code, A, B, m=26):
"""仿射变换1模26算法"""
return (A * code + B) % m
def invAffine(code, invA, B, m=26):
"""仿射变换1模26逆算法"""
return invA * (code - B) % m
def polyalphabet(code:list, A, B, m=26) -> list:
"""多表代换1模26算法"""
group_len = len(B)
code = np.mat(code).reshape(group_len,1)
C = ((np.dot(A, code) + B) % m).reshape(-1)
C = C.tolist()[0]
return C
def invpolyalpha(code:list, invA, B, m=26) -> list:
"""多表代换1模26逆算法"""
group_len = len(B)
code = np.mat(code).reshape(group_len, 1)
M = (np.dot(invA, (code - B)) % m).reshape(-1)
M = M.tolist()[0]
return M
class InitDeal():
""" 键盘输入处理类 """
def inputKey() -> list:
""" 用户从键盘输入密钥 """
keyA = [[*map(eval, input("\n请输入n阶密钥方阵A:\n").split())]]
for _ in range(len(*keyA) - 1):
keyA.append([*map(eval, input().split())])
keyB = [*map(eval, input("\n请输入n维密钥向量B:\n").split())]
key = [keyA, keyB]
return key
def keyProcess(inputkey):
""" 输入密钥进行处理->逆元cipher_invA等密钥 """
A, B = inputkey
group_len = len(B)
A = np.mat(A).reshape(group_len,group_len)
B = np.mat(B).reshape(group_len,1)
try: cipher_invA = MathUtil.modInvMatrix(A)
except: return False
keylist = [A, B, cipher_invA]
return keylist
def dealText(textstr, group_len):
""" 将文本进行分组处理
@textstr: 字符串文本
@group_len: 分组长度
"""
# 文本字符串去空格, 长度用z补全, 如"abcabc"
textstr = textstr.replace(" ", "")
blank = len(textstr) % group_len
if blank != 0:
textstr = textstr + (group_len-blank) * "z"
# 统一转换成小写0~25编码列表, 如[0,1,2,0,1,2]
textlist = list(textstr.lower())
codelist = [ord(i)-97 for i in textlist]
# 将编码列表进行分组, 即编码子向量, 如[[0,1,2],[0,1,2]]
codegroup = []
for i in range(0, len(codelist), group_len):
codegroup.append(codelist[i:i+group_len])
return codegroup
class HerkCode():
""" 自定义编码类 """
def enCode(text):
""" 53编码 by Herk
@text: 待编码的字符串, 如"abc"
@return: 对应的编码流, 即"010203"
"""
pool = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
code = [(2-len(str(pool.index(i))))*'0'+str(pool.index(i)) for i in text]
return ''.join(code)
def deCode(code):
""" 53解码 by Herk
@code: 待解码的数字流, 如"010203"
@return: 对应的字符串, 即为"abc"
"""
pool = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
text = [pool[int(code[i:i+2])] for i in range(0, len(code), 2)]
return ''.join(text)
2.仿射变换加密类的实现
# 本代码文件名: affine.py
# 导入上面基础准备写好的类
from __util import *
class AffineCipher():
""" 仿射变换加密 """
def __init__(self, inputkey=None):
""" 密钥初始化构建
@inputkey: 例如[1, 3]
若密钥为空则从键盘输入
"""
self.inputkey = inputkey
self.buildKey()
def buildKey(self):
""" 生成相关密钥数据 """
if self.inputkey == None:
tips = "输入一对密钥: " # 例如输入: 1 3
self.inputkey = [*map(eval, input(tips).split())]
self.A, self.B = self.inputkey # 处理输入密钥, 得到密钥a,b
self.invA = MathUtil.modInvElem(self.A) # 计算密钥a的逆元
def enCrypt(self, messag):
""" 仿射变化加密
@messag: 明文字符串
@return: 密文字符串
"""
codelist = []
cipherlist = []
for i in messag:
codelist.append(ord(i))
for i in codelist:
if 65 <= i <= 90:
i -= 65
i = TransAlgor.affine(i, self.A, self.B) + 65
elif 97 <= i <= 122:
i -= 97
i = TransAlgor.affine(i, self.A, self.B) + 97
cipherlist.append(chr(i))
ciphertext = ''.join(cipherlist)
return ciphertext
def deCrypt(self, cipher):
""" 仿射变换解密
@cipher: 密文字符串
@return: 明文字符串
"""
codelist = []
plainlist = []
for i in cipher:
codelist.append(ord(i))
for i in codelist:
if 65 <= i <= 90:
i -= 65
i = TransAlgor.invAffine(i, self.invA, self.B) + 65
elif 97 <= i <= 122:
i -= 97
i = TransAlgor.invAffine(i, self.invA, self.B) + 97
plainlist.append(chr(i))
plaintext = ''.join(plainlist)
return plaintext
if __name__ == '__main__':
crypto = AffineCipher()
messag = input("输入明文: ")
print("加密结果:", crypto.enCrypt(messag))
cipher = input("输入密文: ")
print("解密结果:", crypto.deCrypt(cipher))
3.多表代换加密类的实现
# 本代码文件名: polyalphabet.py
# 导入上面基础准备写好的类
from __util import *
class PolyalphabetCipher():
""" 多表代换加密 """
def __init__(self, inputkey=None):
""" 实例化类时需要复写的属性 """
self.inputkey = inputkey
self.buildKey()
def buildKey(self):
""" 实例化对象后 必须构建密钥 """
if self.inputkey == None:
self.inputkey = InitDeal.inputKey()
key = InitDeal.keyProcess(self.inputkey)
self.A, self.B, self.invA = key
def enCrypt(self, plaintext):
""" 加密算法 返回密文 """
ciphertext = ""
codegroup = InitDeal.dealText(plaintext, len(self.B))
for group in codegroup:
group = TransAlgor.polyalphabet(group, self.A, self.B)
group = [chr(i+97) for i in group] # 密文编码->字母串列表
group = ''.join(group) # 字母串列表->密文串
ciphertext = ciphertext + group + " "
return ciphertext
def deCrypt(self, ciphertext):
""" 加密算法 返回明文 """
plaintext = ""
codegroup = InitDeal.dealText(ciphertext, len(self.B))
for group in codegroup:
group = TransAlgor.invpolyalpha(group, self.invA, self.B)
group = [chr(i+97) for i in group] # 明文编码->字母串列表
group = ''.join(group) # 字母串列表->明文串
plaintext = plaintext + group + " "
return plaintext
if __name__ == '__main__':
crypto = PolyalphabetCipher()
plaintext = input("输入明文: ")
print("加密结果:", crypto.enCrypt(plaintext))
ciphertext = input("输入密文: ")
print("解密结果:", crypto.deCrypt(ciphertext))
例题:仿射变换加密
from affine import *
key = [7, 21]
messag = "security"
cipher = "vlxijh"
crypto = AffineCipher(key)
print("仿射变换密钥对为: 7 21")
print("security 加密为:", crypto.enCrypt(messag))
print("vlxijh 解密为:", crypto.deCrypt(cipher))
例题:多表代换加密
from polyalphabet import *
keyA = [[11, 2, 19],
[5, 23, 25],
[20, 7, 17]]
keyB = [ 0, 0, 0]
# 实例化加密对象, 并传入参数进行构建
key = [keyA, keyB]
plaintext = "your pin no is four one two six"
ciphertext = "wgi fgj tmr lhh xth wbx zps brb"
crypto = PolyalphabetCipher(key)
print("密钥为:", key)
print("加密为:", crypto.enCrypt(plaintext))
print("解密为:", crypto.deCrypt(ciphertext))