对于希尔加解密很多writeup都说用在线工具,所以研究了一下,写了一个方便的加解密python代码,根据给定的字母表及私钥字符串,尝试不同纬度不同重叠的加密矩阵输出加解密结果。运行效果如下:
代码文件Hill希尔加解密_final.py
import numpy as np
import string
# 导入自定义模块以创建矩阵和转换字符串
from util_create_matrix import create_matrix_from_list, create_numbers_from_string# 定义了使用的字符集,包括所有小写字母、空格、逗号和句点
alphabet = "abcdefghijklmnopqrstuvwxyz ,."
# 密钥短语,用于生成加密/解密所需的密钥矩阵
key_phrase = "www.verymuch.net"def mod_inverse(a, m):"""计算模m下a的逆元。逆元是满足 (a * x) % m == 1 的整数x。"""a = a % mfor x in range(1, m):if (a * x) % m == 1:return xreturn Nonedef matrix_mod_inv(matrix, modulus):"""计算给定矩阵在模modulus下的逆矩阵。这是通过先计算矩阵的行列式及其模逆,然后应用数学公式来实现的。"""det = int(np.round(np.linalg.det(matrix))) # 计算行列式并取整det_inv = mod_inverse(det, modulus) # 计算行列式的模逆matrix_modulus_inv = (det_inv * np.round(det * np.linalg.inv(matrix)).astype(int) % modulus)return matrix_modulus_invdef char_to_num(char):"""将字符转换为对应的数字。这里将空格、逗号和句号也视为字符集的一部分。"""if char == ' ':return 26elif char == ',':return 27elif char == '.':return 28else:return string.ascii_lowercase.index(char)def num_to_char(num):"""将数字转换回对应的字符。与char_to_num函数相对应。"""if num == 26:return ' 'elif num == 27:return ','elif num == 28:return '.'else:return string.ascii_lowercase[num]def prepare_text(text, block_size):"""准备文本以适应加密/解密过程,确保文本长度是block_size的倍数,不足部分以'x'填充。"""while len(text) % block_size != 0:text += 'x'return textdef text_to_numbers(text):"""将文本字符串转换为数字序列,每个字符映射到其在字母表中的位置。"""return [char_to_num(char) for char in text]def numbers_to_text(numbers):"""将数字序列转换回文本字符串,每个数字映射回其对应的字符。"""return ''.join(num_to_char(number) for number in numbers)def hill_encrypt_decrypt(text, key_matrix, operation="encrypt"):"""执行希尔加密或解密操作。根据操作类型,此函数使用key_matrix直接加密,或首先计算其逆矩阵进行解密。"""block_size = key_matrix.shape[0] # 确定密钥矩阵的大小,用于分块大小text = prepare_text(text, block_size) # 根据分块大小调整文本长度text_numbers = text_to_numbers(text) # 将文本转换为数字序列result = [] # 存储加密或解密结果的数字序列# 如果是解密操作,计算密钥矩阵的逆矩阵if operation == "decrypt":key_matrix = matrix_mod_inv(key_matrix, 29) # 对每个文本块执行矩阵乘法和模运算for i in range(0, len(text_numbers), block_size):block = np.array(text_numbers[i:i+block_size])encrypted_block = np.dot(key_matrix, block) % 29 # 模29保证结果在字母表范围内result.extend(encrypted_block)return numbers_to_text(result) # 将数字序列转换回文本# 主函数,负责用户交互和调用加密/解密函数
def main():choice = input("请选择操作:\n1. 加密\n2. 解密\n") # 用户选择加密还是解密text = input("请输入明文:" if choice == '1' else "请输入密文:") # 获取用户输入的文本key_numbers = create_numbers_from_string(alphabet, key_phrase, 0) # 根据密钥短语生成密钥数字序列# 尝试不同的密钥矩阵维度和重叠度进行加密/解密for dim in range(2, 5): # 维度从2到4for overlap in range(1, 5): # 重叠度从1到4if overlap > dim:break # 如果重叠度大于维度,则不再尝试try:key_matrix = np.array(create_matrix_from_list(key_numbers, dim, overlap))if choice == '1':encrypted = hill_encrypt_decrypt(text, key_matrix, "encrypt")print(f"使用dim={dim}, overlap={overlap}加密后的密文:{encrypted}")else:decrypted = hill_encrypt_decrypt(text, key_matrix,"decrypt")print(f"使用dim={dim}, overlap={overlap}解密后的明文:{decrypted}")except ValueError as e:print(e)break # 如果出现异常,则停止尝试当前维度和重叠度的组合if __name__ == "__main__":main() # 运行主函数'''
请选择操作:
1. 加密
2. 解密
1
请输入明文:love and peaceee
使用dim=2, overlap=1加密后的密文:....vveeddbbqqcc
使用dim=2, overlap=2加密后的密文:....vveeddbbqqcc
使用dim=3, overlap=1加密后的密文: cgweozrcmhmrik, q
使用dim=3, overlap=2加密后的密文: hcwwezhrmmhrmi,u
使用dim=3, overlap=3加密后的密文: wwwzzzmmmrrr,,,
使用dim=4, overlap=1加密后的密文:waoootu.epj,nv o
使用dim=4, overlap=2加密后的密文:wspooq,uedhjnyt
使用dim=4, overlap=3加密后的密文:wesaonqte.dpnjyv
使用dim=4, overlap=4加密后的密文:wwwwooooeeeennnn1. 加密
2. 解密
2
请输入密文:waoootu.epj,nv o
Singular matrix
使用dim=3, overlap=1解密后的明文:tpzhhnkhfxvqotthau
使用dim=3, overlap=2解密后的明文:ftgczahelg .ielcjq
Singular matrix
使用dim=4, overlap=1解密后的明文:love and peaceee
使用dim=4, overlap=2解密后的明文:e.nlnldaayiekhkb
使用dim=4, overlap=3解密后的明文:znwwvkzandgqvdex
Singular matrix
'''
代码文件util_create_matrix.py
def create_matrix_from_list(numbers, dim=4, overlap=1):"""根据提供的数字列表、矩阵维度和重叠度,生成指定维度的矩阵。参数:- numbers: 数字列表,用于填充矩阵。- dim: 整数,表示矩阵的维度(例如2x2, 3x3, 4x4等)。- overlap: 整数,指定相邻行之间的重叠数字数量。返回:- 生成的矩阵,为dim x dim大小。如果提供的数字不足以填满矩阵,返回错误信息。"""# 计算根据维度和重叠度需要的数字总数total_numbers_needed = dim * dim - (dim - 1) * overlap# 如果提供的数字不足以构成矩阵,返回错误信息if len(numbers) < total_numbers_needed:return "提供的数字不足以形成指定维度的矩阵。"# 构造矩阵matrix = []for i in range(dim):start_index = i * (dim - overlap) # 计算当前行起始数字的索引end_index = start_index + dim # 计算当前行结束数字的索引row = numbers[start_index:end_index] # 提取当前行的数字matrix.append(row) # 将当前行添加到矩阵中return matrix# 示例:使用整数参数调用函数并打印结果
numbers_list = [22, 22, 22, 28, 21, 4, 17, 24, 12, 20, 2, 7, 28, 13, 4, 19]
dim = 4 # 矩阵的维度
overlap = 1 # 行之间的重叠数字数量
matrix = create_matrix_from_list(numbers_list, dim, overlap)
print(matrix)def create_numbers_from_string(alphabet, key_string, start=0):"""根据给定的字母表和字符串,返回一个数字列表,表示字符串中每个字符在字母表中的位置。位置计数从start参数指定的数字开始。参数:- alphabet: 字符串,定义可用字符的序列。- key_string: 字符串,需要转换为数字列表的文本。- start: 整数,数字列表的起始值,默认为0。返回:- 数字列表,其中包含key_string中每个字符对应的位置。"""return [alphabet.index(char) + start for char in key_string]# 示例:将字符串转换为数字列表并打印结果
alphabet = "abcdefghijklmnopqrstuvwxyz ,."
print(create_numbers_from_string(alphabet, "www.verymuch.net", 0))