Loading... # 古典密码代码 今天开始上密码课,才想起了之前寒假一时兴起写了古典密码的加密解密python代码,故在此总结下 ## 移位密码 ~~~python def run(): print('*'*5 + '移位密码' + '*'*5) choice = input('请选择加密/解密(e/d):') move = int(input('输入右移位数:')) if choice == 'E' or choice == 'e': encrypt(move) elif choice == 'D' or choice == 'd': decrypt(move) else: print('输入有误') # 加密 def encrypt(move): m = input('请输入明文:') print('加密开始……') c = '' for i in m: # 遍历明文字符,进行对应操作 if ord(i) == 32: # 空格 c = c + ' ' elif ord(i) in range(65, 91): # 大写 c = c + chr(65 + (ord(i) - 65 + move) % 26) elif ord(i) in range(97, 123): # 小写 c = c + chr(97 + (ord(i) - 97 + move) % 26) else: # 其他字符 c = c + i print('密文:' + c) # 解密 def decrypt(move): c = input('请输入密文:') m = '' print('解密开始……') for i in c: if ord(i) == 32: m = m + ' ' elif ord(i) in range(65, 91): m = m + chr(65 + (ord(i) - 65 - move) % 26) elif ord(i) in range(97, 123): m = m + chr(97 + (ord(i) - 97 - move) % 26) else: m = m + i print('明文:' + m) if __name__ == '__main__': run() ~~~ ## 凯撒密码 导入移位密码文件,设置move为3即可 ~~~python import Transposition as yiwei def run(): print('*' * 5 + '凯撒密码' + '*' * 5) choice = input('请选择加密/解密(e/d):') move = 3 if choice == 'E' or choice == 'e': yiwei.encrypt(move) elif choice == 'D' or choice == 'd': yiwei.decrypt(move) else: print('输入有误') if __name__ == '__main__': run() ~~~ ## 仿射密码 线性变换,需要输入k1、k0 ~~~python def run(): print('*' * 5 + '仿射密码' + '*' * 5) k1 = int(input('请输入k1:')) k0 = int(input('请输入k0:')) choice = input('请选择加密/解密(e/d):') if choice == 'E' or choice == 'e': encrypt(k0, k1) elif choice == 'D' or choice == 'd': decrypt(k0, k1) else: print('输入有误') def encrypt(k0, k1): m = input('请输入明文:') c = '' print('加密开始……') for i in m: if m.isspace(): c = c + ' ' elif i.islower(): c = c + chr(((ord(i) - 97) * k1 + k0) % 26 + 97) elif i.isupper(): c = c + chr(((ord(i) - 65) * k1 + k0) % 26 + 65) else: c = c + i print('密文:' + c) def decrypt(k0, k1): c = input('请输入密文:') m = '' print('解密开始……') inv = 0 for i in range(26): if k1 * i % 26 == 1: inv = i break for i in c: if c.isspace(): m = m + ' ' elif i.islower(): m = m + chr(((ord(i) - 97 - k0) * inv) % 26 + 97) elif i.isupper(): m = m + chr(((ord(i) - 65 - k0) * inv) % 26 + 65) else: m = m + i print('明文:' + m) if __name__ == '__main__': run() ~~~ ## 密钥短语密码 ```python def run(): print('*' * 5 + '密钥短语密码(小写)' + '*' * 5) choice = input('请选择加密/解密(e/d):') key = list(input('输入密钥短语:')) keys = create_k(key) if choice == 'E' or choice == 'e': encrypt(keys) elif choice == 'D' or choice == 'd': decrypt(keys) else: print('输入有误') # 创建密钥列表 def create_k(key): keys = [] for i in key: if i not in keys: # 如果已存在keys列表中,则不添加 keys.append(i) for j in range(97, 123): # 按a-z顺序添加,除非已存在 apha = chr(j) if apha not in keys: keys.append(apha) print('Your key:' + ''.join(keys)) return keys def encrypt(keys): m = input('请输入明文:') c = '' print('加密开始……') for i in m: if i.isspace(): c = c + ' ' else: c = c + keys[ord(i) - 97] # 将明文字符与新的26字母表,即keys相对应 print('密文:' + c) def decrypt(keys): c = input('请输入密文:') m = '' print('解密开始……') for i in c: if i.isspace(): m = m + ' ' else: m = m + chr(keys.index(i) + 97) print('明文:' + m) if __name__ == '__main__': run() ``` ## 维吉尼亚密码 ~~~python def run(): print('*' * 5 + '维吉尼亚密码' + '*' * 5) choice = input('请选择加密/解密(e/d):') k = input('请输入密钥:') if choice == 'E' or choice == 'e': encrypt(k) elif choice == 'D' or choice == 'd': decrypt(k) else: print('输入有误') def encrypt(k): m = input('请输入明文:') c = '' print('加密开始……') for i in range(len(m)): if m[i].isspace(): c = c + ' ' elif m[i].islower(): c = c + chr((ord(m[i]) - 97 + ord(k[i % len(k)]) - 97) % 26 + 97) elif m[i].isupper(): c = c + chr((ord(m[i]) - 65 + ord(k[i % len(k)]) - 65) % 26 + 65) else: c = c + m[i] print('密文:' + c) def decrypt(k): c = input('请输入密文:') m = '' print('解密开始……') for i in range(len(c)): if c[i].isspace(): m = m + ' ' elif c[i].islower(): m = m + chr((ord(c[i]) - ord(k[i % len(k)])) % 26 + 97) elif c[i].isupper(): m = m + chr((ord(c[i]) - ord(k[i % len(k)])) % 26 + 65) print('明文:' + m) if __name__ == '__main__': run() ~~~ ## 希尔密码 这部分比较难写代码,在网上搜集了很多学习资料,最后才发现比较符合自己想法的文章https://hstar.me/2020/08/hill-cipher-study/ 算法如图: ![image-20220224214234407.png](http://xherlock.top/usr/uploads/2022/02/1347672989.png) 然后稍微复习了下线性代数:https://www.shuxuele.com/algebra/matrix-inverse-minors-cofactors-adjugate.html 但是这里的算法并不是简单的求矩阵逆,还要与替换表的长度26进行相应的模运算,网上很多都是简单的求逆矩阵 快速求模乘法逆:https://www.delftstack.com/zh/howto/python/mod-inverse-python/,使用pow()内置函数:pow(a,-1,m),a为要找到模逆的数,m为模数 还有个比较关键的细节:关于python的取整函数 * int:去除小数部分,即只保留前面的整数,向0取整 * round:遵循四舍五入原则,本例中应使用该法 ~~~python import numpy as np # 与矩阵计算相关的库 def run(): print('*' * 5 + '希尔密码' + '*' * 5) choice = input('请选择加密/解密(e/d):') if choice == 'E' or choice == 'e': encrypt() elif choice == 'D' or choice == 'd': decrypt() else: print('输入有误') # 创建密钥矩阵 def create_k(): print('**输入密钥模式**') print('1:数字密钥;2:字母密钥') choice = int(input('请选择模式(数字):')) n = int(input('请输入密钥矩阵的行数:')) k_list = [] print('请输入' + str(n) + '*' + str(n) + '可逆矩阵(每行' + str(n) + '个,空格隔开):') for i in range(1, n + 1): while True: row = input(f'第{i}行:') row_list = row.split(' ') if choice == 1: row_list = [int(j) for j in row_list] elif choice == 2: row_list = [ord(j) - 97 for j in row_list] # 判断矩阵每行个数是否正确 if len(row_list) != n: print('输入个数错误,请重新输入:') else: break k_list.append(row_list) # print(k_list) if if_inv_matrix(k_list): return np.array(k_list) else: print('不存在逆矩阵!') # 判断矩阵是否存在逆 def if_inv_matrix(k_list): try: np.linalg.inv(k_list) except: return False return True def encrypt(): m = input('请输入明文:') print('加密开始……') c = '' m_list = [] for i in m: m_list.append(ord(i) - 97) k = create_k() # 检查并补齐明文,使之满足n维向量与n*n矩阵相乘 row_num = len(k) add_m_num = (row_num - len(m_list) % row_num) % row_num if add_m_num != 0: for n in range(add_m_num): m_list.append(0) print(f'添加了{add_m_num}个0补齐明文') # 分组乘积 for j in range(int(len(m_list) / row_num)): # 线性代数乘积 M = m_list[j * row_num: (j + 1) * row_num] c_list = np.matmul(k, M) c = c + ''.join([chr(x % 26 + 97) for x in c_list]) # print(c[:len(c) - add_m_num]) print('密文:' + c) # 求最大公因数 def gcd(a, b): if b == 0: return a return gcd(b, a % b) def decrypt(): c = input('请输入密文:') m = '' print('解密开始……') c_list = [] for i in c: c_list.append(ord(i) - 97) k = create_k() row_num = len(k) det_k = np.linalg.det(k) # 获取密钥矩阵的行列式 inv_det_k = pow(int(det_k), -1, 26) # 求密钥矩阵行列式模逆 if gcd(inv_det_k, 26) != 1: print('密钥矩阵行列式与26不互质,无法解密!') return elif inv_det_k == 0: print('密钥矩阵行列式不能为0!') return inv_k = inv_det_k * np.linalg.inv(k) * det_k % 26 # 求希尔密码密钥矩阵的逆矩阵(同上公式) for j in range(int(len(c_list) / row_num)): # 线性代数乘积 C = np.array(c_list[j * row_num: (j + 1) * row_num]) # print(C) m_list = np.matmul(inv_k, C) # 这里一定要注意不要用int来取整,他这里省略了小数部分,应该用近似round,血泪教训! m = m + ''.join([chr(round(x) % 26 + 97) for x in m_list]) print('明文:' + m + '(由于可能存在补齐的明文,请自行去掉末尾可能多余的a)') if __name__ == '__main__': run() ~~~ ## Playfair密码 这个是真复杂,难想,一直算出来的与在线网站加密解密不一样,最后才发现原来有两种主流方式 * 在重复数字后加‘x’ * 第二个重复数字改成‘x’ 第一种是我的法和[普莱费尔密码加密/解密 - 一个工具箱 - 好用的在线工具都在这里! (atoolbox.net)](http://www.atoolbox.net/Tool.php?Id=912)这个网址的方法 第二种是pycipher库下的Playfair的方法和[CTF在线工具-在线普莱菲尔密码加密|在线普莱菲尔密码解密|普莱菲尔密码算法|Playfair Cipher (hiencode.com)](http://www.hiencode.com/playfair.html)和[普莱菲尔密码 - Playfair Cipher - 在线工具网 (wtool.com.cn)](https://wtool.com.cn/playfair.html)等的方法 最后验证出自己结果正确时真高兴,shit,手算了老多遍了 ~~~python def run(): print('*' * 5 + 'Playfair密码' + '*' * 5) choice = input('请选择加密/解密(e/d):') if choice == 'E' or choice == 'e': encrypt() elif choice == 'D' or choice == 'd': decrypt() else: print('输入有误') # 初始化5*5矩阵 def create_k(): key = input('请输入密钥:') key = key.replace(' ', '') keys = [] # 创建密钥列表 for i in key: if i not in keys: if i == 'j': # keys.append('i') else: keys.append(i) for j in range(97, 123): apha = chr(j) if apha not in keys: if apha == 'j': if 'i' not in keys: keys.append('i') else: continue else: keys.append(apha) # 创建密钥矩阵 # 初始化5*5矩阵,这里构建不能采用[[0]*5]*5,否则后面赋值错误,会变换整列 k_arr = [[0] * 5 for i in range(5)] k = 0 print('\t**密钥矩阵**') for i in range(5): for j in range(5): k_arr[i][j] = keys[k] print(keys[k], end='\t') if (k + 1) % 5 == 0: print('') k += 1 return k_arr # 获取字符对应矩阵的位置 def get_index(p, k_arr): if p == 'j': p = 'i' for i in range(len(k_arr)): for j in range(len(k_arr)): if k_arr[i][j] == p: return i, j def encrypt(): m = input('请输入明文:') m = m.replace(' ', '') # 去除空格 print('加密开始……') c = '' c_list = [] k_arr = create_k() for i in range(0, len(m) + 1, 2): if i < len(m) - 1: if m[i] == m[i + 1]: # m = m[:i + 1] + 'x' + m[i + 2:] # 第二个重复字母改成‘x’ m = m[:i + 1] + 'x' + m[i + 1:] # 在重复字母后加‘x’ if len(m) % 2 != 0: m = m + 'x' print('整理后的明文:' + m) for j in range(0, len(m), 2): P1 = get_index(m[j], k_arr) P2 = get_index(m[j+1], k_arr) print(P1, P2) if P1[0] == P2[0]: # P1、P2在同一行 C1 = k_arr[P1[0]][(P1[1] + 1) % 5] C2 = k_arr[P2[0]][(P2[1] + 1) % 5] elif P1[1] == P2[1]: # P1、P2在同一列 C1 = k_arr[(P1[0] + 1) % 5][P1[1]] C2 = k_arr[(P2[0] + 1) % 5][P2[1]] else: C1 = k_arr[P1[0]][P2[1]] C2 = k_arr[P2[0]][P1[1]] c_list.append(C1 + C2) c = ''.join(c_list) print('密文:' + c) def decrypt(): c = input('请输入密文:') m = '' print('解密开始……') m_list = [] k_arr = create_k() for j in range(0, len(c), 2): C1 = get_index(c[j], k_arr) C2 = get_index(c[j+1], k_arr) if C1[0] == C2[0]: # C1、C2在同一行 P1 = k_arr[C1[0]][(C1[1] - 1) % 5] P2 = k_arr[C2[0]][(C2[1] - 1) % 5] elif C1[1] == C2[1]: # C1、C2在同一列 P1 = k_arr[(C1[0] - 1) % 5][C1[1]] P2 = k_arr[(C2[0] - 1) % 5][C2[1]] else: P1 = k_arr[C1[0]][C2[1]] P2 = k_arr[C2[0]][C1[1]] m_list.append(P1 + P2) m = ''.join(m_list) # 删除添加的x,但是无法准确判断结尾x是否存在明文中,需要结合语义进行判断 for i in range(len(m)): if 0 < i < len(m) - 1 and m[i] == 'x' and m[i - 1] == m[i + 1]: m = m[:i] + m[i+1:] print('明文:' + m + '(若结尾存在x,请自行判断x是否需要存在)') if __name__ == '__main__': run() ~~~ ## 总代码: ~~~python import Transposition as yiwei import Caesar import Affine import KeyPhrase as kp import Vigenere as vig import Hill import Playfair as pf def run(): while True: print('*'*10 + 'Powered By Xherlock' + '*'*10) print(' ' * 10 + '1.移位密码') print(' ' * 10 + '2.凯撒密码') print(' ' * 10 + '3.仿射密码') print(' ' * 10 + '4.密钥短语密码') print(' ' * 10 + '5.维吉尼亚密码') print(' ' * 10 + '6.希尔密码') print(' ' * 10 + '7.Playfair密码') choice = int(input('请选择密码种类:')) if choice == 1: yiwei.run() elif choice == 2: Caesar.run() elif choice == 3: Affine.run() elif choice == 4: kp.run() elif choice == 5: vig.run() elif choice == 6: Hill.run() elif choice == 7: pf.run() print('\n') if __name__ == '__main__': run() ~~~ 最后修改:2022 年 02 月 24 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 0 如果觉得我的文章对你有用,请随意赞赏