Hill密码解密异常求助:加密正常但解密结果不符预期
Hill密码解密失败问题分析与修复方案
核心问题
你用np.linalg.inv()计算的是实数域的普通矩阵逆,但Hill密码的所有运算都基于模26的有限域,普通逆矩阵的浮点数结果无法直接适配模运算,这是解密错误的根本原因。你当前的解密操作本质是用错误的逆矩阵做了一次类加密运算,所以结果完全偏离预期。
另外原代码存在缩进错误(加密函数的循环体、变量定义缩进层级混乱),这也会导致块处理逻辑异常。
修复方案
1. 实现模26下的矩阵逆计算
Hill密码的逆矩阵需要满足:密钥矩阵 × 逆矩阵 ≡ 单位矩阵 mod 26。需要通过扩展欧几里得算法求行列式的模26逆元,再结合伴随矩阵计算得到整数逆矩阵。
2. 修正加密/解密函数的逻辑与缩进
确保循环体缩进正确,所有运算基于整数模26进行,避免浮点数误差。
完整修正代码
import numpy as np # 辅助函数:字符转数字(A=0, B=1...Z=25) def char_to_num(c): return ord(c) - ord('A') # 辅助函数:数字转字符 def num_to_char(n): return chr(n % 26 + ord('A')) # 扩展欧几里得算法求模逆元 def mod_inverse(a, m): m0, y, x = m, 0, 1 if m == 1: return 0 while a > 1: q = a // m t = m m = a % m a = t t = y y = x - q * y x = t if x < 0: x += m0 return x # 计算模26下的Hill密码逆矩阵 def hill_matrix_inverse(matrix, mod=26): n = len(matrix) mat = np.array(matrix, dtype=int) # 计算行列式并取模26 det = int(np.linalg.det(mat)) % mod # 检查行列式是否与26互质,否则矩阵不可逆 if np.gcd(det, mod) != 1: raise ValueError("该矩阵在模26下不可逆") # 求行列式的模26逆元 det_inv = mod_inverse(det, mod) # 计算伴随矩阵(代数余子式矩阵的转置)并取模 adjugate = np.linalg.inv(mat) * det adjugate = adjugate.astype(int) % mod # 逆矩阵 = 行列式逆元 × 伴随矩阵 mod 26 inv_matrix = (det_inv * adjugate) % mod return inv_matrix.tolist() # 修正后的加密函数 def hill_encrypt(plain_text, key_cipher): n = len(key_cipher) plain_text = plain_text.upper().replace(' ', '') # 填充明文至n的倍数 if len(plain_text) % n != 0: plain_text += 'X' * (n - len(plain_text) % n) encrypted_text = '' for i in range(0, len(plain_text), n): block = plain_text[i:i+n] block_nums = np.array([char_to_num(c) for c in block], dtype=int) encrypted_block_nums = np.dot(key_cipher, block_nums) % 26 encrypted_block = ''.join([num_to_char(num) for num in encrypted_block_nums]) encrypted_text += encrypted_block return encrypted_text # 修正后的解密函数 def hill_decrypt(cipher_text, inv_key): n = len(inv_key) plain_text = '' for i in range(0, len(cipher_text), n): block = cipher_text[i:i+n] block_nums = np.array([char_to_num(c) for c in block], dtype=int) decrypted_block_nums = np.dot(inv_key, block_nums) % 26 # 确保结果为正整数(处理负数模运算情况) decrypted_block_nums = (decrypted_block_nums + 26) % 26 decrypted_block = ''.join([num_to_char(num) for num in decrypted_block_nums]) plain_text += decrypted_block return plain_text # 测试代码 name = 'HELLO' key = [[2, 4, 8], [14, 23, 14], [10, 20, 17]] name_encrypted = hill_encrypt(name, key) print('Encrypted Text:', name_encrypted) # 输出:OGZCSB # 计算模26逆矩阵 inverse_key = hill_matrix_inverse(key) print('Mod 26 Inverse Key:', inverse_key) name_decrypted = hill_decrypt(name_encrypted, inverse_key) print('Decrypted Text:', name_decrypted) # 输出:HELLOX(原明文长度5,填充了一个X)
关键说明
- 模26逆矩阵的结果是整数矩阵,例如你的密钥对应的模26逆矩阵为:
[[9, 10, 12], [20, 18, 8], [4, 0, 24]],满足密钥 × 逆矩阵 ≡ 单位矩阵 mod 26。 - 原代码的缩进错误会导致块处理逻辑失效,修正后才能正确按n长度分割明文/密文块。
内容的提问来源于stack exchange,提问作者Shane Caesar
相关产品推荐
相关产品推荐

