对于希尔加解密很多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 % m
for x in range(1, m):
if (a * x) % m == 1:
return x
return None
def 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_inv
def char_to_num(char):
"""
将字符转换为对应的数字。这里将空格、逗号和句号也视为字符集的一部分。
"""
if char == ' ':
return 26
elif char == ',':
return 27
elif char == '.':
return 28
else:
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 text
def 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到4
for overlap in range(1, 5): # 重叠度从1到4
if 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加密后的密文:wwwwooooeeeennnn
1. 加密
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))