一、总述
在1.0、2.0版本的代码上改进了加密模式,原来为ECB模式,现改进为CBC模式,即为在原来的基础上增添异或过程。
二、3.0版本代码
GUI代码:
import tkinter as tk
from tkinter import filedialog
import os
import mydecode
import myencode
import hashlib
class FileEncryptionApp:
def __init__(self, root):
# 常量定义
self.key = b''
self.encoded_key = b''
# 获取随机IV
self.IV = os.urandom(16)
# 设置整个弹窗属性
self.root = root
self.root.title("SM4算法文件加解密")
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
window_width = 800
window_height = 600
x = (screen_width - window_width) // 2
y = (screen_height - window_height) // 2
root.geometry(f"{window_width}x{window_height}+{x}+{y}")
# 设置输入密钥文本框属性
self.key_label = tk.Label(root, text="请输入密钥:")
self.key_label.configure(font=("Times New Roman", 14))
self.key_label.pack()
self.input_frame = tk.Text(root)
self.input_frame.pack(side=tk.LEFT, padx=0, pady=0, fill=tk.BOTH, expand=True)
self.text_box = tk.Text(self.input_frame, height=4, width=10)
self.text_box.configure(bg="white")
self.text_box.configure(font=("Times New Roman", 14))
self.text_box.pack(fill=tk.BOTH, expand=True)
# 设置上传文件、加密文件、解密文件按钮及对应方法名字
self.button_frame = tk.Frame(root)
self.button_frame.pack(side=tk.LEFT, padx=10, pady=10)
self.upload_button = tk.Button(root, text="确认密钥", command=self.encrypt_key, font=("Times New Roman", 14))
self.upload_button.pack()
self.upload_button = tk.Button(root, text="上传文件", command=self.upload_file, font=("Times New Roman", 14))
self.upload_button.pack()
self.encrypt_button = tk.Button(root, text="加密文件", command=self.encrypt_file, font=("Times New Roman", 14))
self.encrypt_button.pack()
self.decrypt_button = tk.Button(root, text="解密文件", command=self.decrypt_file, font=("Times New Roman", 14))
self.decrypt_button.pack()
self.file_label = tk.Label(root, text="")
self.file_label.pack()
# 获取加密密钥
def encrypt_key(self):
self.key = self.text_box.get(1.0, tk.END)
# 去掉输入key的末尾换行符
self.key = self.key[:-1]
# 计算输入key的32位哈希
hash_object = hashlib.md5()
hash_object.update(self.key.encode())
en_key = hash_object.hexdigest()
print(en_key)
self.encoded_key = myencode.encode_key(en_key.encode(), self.IV.hex().encode())
tk.messagebox.showinfo("确认成功", "密钥加密成功!")
def upload_file(self):
self.file_path = filedialog.askopenfilename()
self.file_label.config(text=f"已上传文件:{os.path.basename(self.file_path)}")
self.num = len(self.file_path)
last_dot_index = self.file_path.rfind('.')
last_part = self.file_path[last_dot_index + 1:]
self.num1 = len(last_part) + 1
def encrypt_file(self):
if hasattr(self, 'file_path'):
# self.name = len(self.file_path)
# print(self.file_path[:self.num - self.num1])
myencode.encode(self.encoded_key, self.file_path, self.file_path[:self.num - self.num1] + " " + "padding" + self.file_path[self.num - self.num1:], self.file_path[:self.num - self.num1] + " " + "encode" + self.file_path[self.num - self.num1:], self.IV)
tk.messagebox.showinfo("加密", "文件加密成功!")
else:
tk.messagebox.showerror("错误", "请先上传文件!")
def decrypt_file(self):
if hasattr(self, 'file_path'):
# num = len(self.file_path)
# print(self.file_path[num - 4:])
mydecode.decode(self.encoded_key, self.file_path, self.file_path[:self.num - self.num1] + " " +"decode" + self.file_path[self.num - self.num1:])
tk.messagebox.showinfo("解密", "文件解密成功!")
else:
tk.messagebox.showerror("错误", "请先上传文件!")
if __name__ == "__main__":
root = tk.Tk()
app = FileEncryptionApp(root)
root.mainloop()
myencode.py代码:
import os
import SM4
from Crypto.Util.Padding import pad # 使用 PyCryptodome 的填充函数
def encode_key(parse, key):
SM4.msg = parse
SM4.mk = key
SM4.len_num = int(len(parse) / 32)
file_key = SM4.encode()
return file_key
def xorfunc(str1, str2):
return bytes(a ^ b for a, b in zip(str1, str2))
def encode(key, old_file_name, padding_file_name, encode_file_name, iv):
# 读取原文件并填充
with open(old_file_name, "rb") as fin:
data = fin.read()
data = pad(data, 16) # 使用 PKCS#7 填充数据
# 开始加密
cipher = b""
previous_cipher_block = iv # CBC 模式需要初始向量
# 分组加密
for i in range(0, len(data), 16):
# 提取当前明文块
plaintext_block = data[i:i + 16]
# 与上一个密文块进行异或
plaintext_block = xorfunc(plaintext_block, previous_cipher_block)
# 对当前块进行加密
SM4.msg = plaintext_block.hex().encode()
SM4.mk = key
encrypted_block = bytes.fromhex(SM4.encode())
# 将加密结果添加到密文中
cipher += encrypted_block
# 更新上一个密文块
previous_cipher_block = encrypted_block
# 将 IV 和密文写入文件
with open(encode_file_name, "wb") as fout:
fout.write(iv)
fout.write(cipher)
print("文件加密成功!")
mydecode.py代码:
from Crypto.Util.Padding import unpad # 使用 PyCryptodome 的填充函数
import SM4
# 常量定义
message = "文件解密成功!"
def xorfunc(str1, str2):
return bytes(a ^ b for a, b in zip(str1, str2))
def decode(key, encode_file_name, decode_file_name):
# 读取加密文件
with open(encode_file_name, "rb") as fin:
# 读取 IV
iv = fin.read(16)
# 读取密文
cipher = fin.read()
# 开始解密
previous_cipher_block = iv
decrypted_data = b""
# 分组解密
for i in range(0, len(cipher), 16):
# 提取当前密文块
cipher_block = cipher[i:i + 16]
# 对当前密文块进行解密
SM4.msg = cipher_block.hex().encode()
SM4.mk = key
decrypted_block = bytes.fromhex(SM4.decode())
# 与上一个密文块进行异或
decrypted_block = xorfunc(decrypted_block, previous_cipher_block)
# 将解密结果添加到解密数据中
decrypted_data += decrypted_block
# 更新上一个密文块
previous_cipher_block = cipher_block
# 去掉填充并写入解密文件
decrypted_data = unpad(decrypted_data, 16)
with open(decode_file_name, "wb") as fout:
fout.write(decrypted_data)
print("文件解密成功!")
SM4.py代码:
ROUND = 32
FK = [0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc]
CK = [0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279]
SBOX = [[0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05],
[0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99],
[0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62],
[0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6],
[0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8],
[0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35],
[0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87],
[0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e],
[0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1],
[0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3],
[0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f],
[0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51],
[0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8],
[0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0],
[0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84],
[0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48]]
# 线性变换函数
def line_mes(x):
y = x ^ (((x << 2) | (x >> 30)) & 0xffffffff) ^ (((x << 10) | (x >> 22)) & 0xffffffff) ^ (
((x << 18) | (x >> 14)) & 0xffffffff) ^ (((x << 24) | (x >> 8)) & 0xffffffff)
return y
def line_key(x):
y = x ^ (((x << 13) | (x >> 19)) & 0xffffffff) ^ (((x << 23) | (x >> 9)) & 0xffffffff)
return y
# 非线性变换函数
def ST(a, b, c, d, n):
e = '{:08x}'.format(a ^ b ^ c ^ d)
a0 = SBOX[int(e[0], 16)][int(e[1], 16)]
b0 = SBOX[int(e[2], 16)][int(e[3], 16)]
c0 = SBOX[int(e[4], 16)][int(e[5], 16)]
d0 = SBOX[int(e[6], 16)][int(e[7], 16)]
X = int('{:02x}'.format(a0) + '{:02x}'.format(b0) + '{:02x}'.format(c0) + '{:02x}'.format(d0), 16)
if n == 0:
Y = line_mes(X) # 加密消息使用的线性变换函数
else:
Y = line_key(X) # 加密密钥使用的线性变换函数
return Y
# 密钥扩展函数
def key_expansion(mk):
rk = []
mk0 = int(mk[:8], 16)
mk1 = int(mk[8:16], 16)
mk2 = int(mk[16:24], 16)
mk3 = int(mk[24:32], 16)
k0 = mk0 ^ FK[0]
k1 = mk1 ^ FK[1]
k2 = mk2 ^ FK[2]
k3 = mk3 ^ FK[3]
for i in range(ROUND):
rk.append(k0 ^ ST(k1, k2, k3, CK[i], 1))
k0 = k1
k1 = k2
k2 = k3
k3 = rk[i]
return rk
# 加密解密函数
def cryption(msg, mk, mode):
rk = key_expansion(mk)
if mode == 1:
rk = rk[::-1]
x0 = int(msg[:8], 16)
x1 = int(msg[8:16], 16)
x2 = int(msg[16:24], 16)
x3 = int(msg[24:32], 16)
for i in range(ROUND):
temp = x0 ^ ST(x1, x2, x3, rk[i], 0)
x0 = x1
x1 = x2
x2 = x3
x3 = temp # 反序运算
cipher = '{:08x}'.format(x3) + '{:08x}'.format(x2) + '{:08x}'.format(x1) + '{:08x}'.format(x0)
return cipher
msg = b'0123456789abcdeffedcba9876543210'
mk = b'0123456789abcdeffedcba9876543210'
# len_num = 7
def encode():
if len(msg) % 32 == 0:
cipher = cryption(msg.decode(), mk, 0)
return cipher
else:
return "Encode error"
def decode():
if len(msg) % 32 == 0:
plain = cryption(msg, mk, 1)
return plain
else:
return "Decode error"