基于python,可以实现任意文件的加解密,源码放在资料区
- 实验的目的与要求
1.目的:设计实现一种实现消息认证的通信方案
2.要求:
2.1基本功能:设计实现一种实现消息认证的通信(基于对称密钥的、基于数字签
名的、基于仲裁方的等,任选)方案,至少实现对消息来源认证、完整性检查功能,
考虑抗抵赖、抗合谋攻击等功能。
2.2扩展功能:要求有图形界面、可对多种文件类型进行通信认证(可选择文件路
径)、对认证的消息进行正确性验证。
二、实验正文
- 通信方案基本结构
- 实验原理
首先给发送方A和接收方B分配两者的公私钥,A将文件转化成二进制流,然后产生随机的32字节AES密钥。A先用hash256产生定长为32字节的消息摘要,通过RSA算法用A的私钥对消息摘要进行签名,将明文,消息摘要和数字签名拼接用AES密钥加密产生初始化向量iv和密文ct,再用B的公钥对AES密钥进行加密,最后把初始化向量iv,密文ct加密后后的AES密钥拼接发送给B。
B接收后先别拆出iv,ct和加密后的AES密钥,用B的私钥先解出原始的AES密钥,再解出明文,消息摘要和数字签名,对消息摘要和数字签名进行验证。
-
- 逻辑图
2.代码实现
2.1生成AB的公私钥,并保存为pem文件,防止私钥泄露
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend
Aprivate_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
Apublic_key = Aprivate_key.public_key()
Bprivate_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
backend=default_backend()
)
Bpublic_key = Bprivate_key.public_key()
# Apublic_key, Aprivate_key = rsa.newkeys(2048)
# Bpublic_key, Bprivate_key = rsa.newkeys(2048)
with open('Aprivate_key.pem', 'wb') as file:
private_key_pem = Aprivate_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
)
file.write(private_key_pem)
# 将公钥保存到文件
with open('Apublic_key.pem', 'wb') as file:
public_key_pem = Apublic_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
file.write(public_key_pem)
with open('Bprivate_key.pem', 'wb') as file:
private_key_pem = Bprivate_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption()
)
file.write(private_key_pem)
# 将公钥保存到文件
with open('Bpublic_key.pem', 'wb') as file:
public_key_pem = Bpublic_key.public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo
)
file.write(public_key_pem)
def load_rsa_public_key(public_key_path):
with open(public_key_path, 'rb') as key_file:
public_key = serialization.load_pem_public_key(
key_file.read(),
backend=default_backend()
)
return public_key
def loader_Aprivate_key():
with open('Aprivate_key.pem', 'rb') as file:
Aprivate_key = serialization.load_pem_private_key(
file.read(),
password=None
)
return Aprivate_key
2.2读取pem文件
def read_pem_key(file_path):
with open(file_path, 'r') as f:
key = RSA.import_key(f.read())
return key
2.3AES密钥的加解密
def read_pem_key(file_path):
with open(file_path, 'r') as f:
key = RSA.import_key(f.read())
return key
def decrypt_aes_key_with_rsa(private_key_file, encrypted_aes_key):
private_key = read_pem_key(private_key_file)
cipher_rsa = PKCS1_OAEP.new(private_key)
decrypted_aes_key = cipher_rsa.decrypt(encrypted_aes_key)
return decrypted_aes_key
2.3用AES加解密明文
def encrypt_message_with_aes(message, aes_key):
cipher_aes = AES.new(aes_key, AES.MODE_CBC)
ct_bytes = cipher_aes.encrypt(pad(message, AES.block_size))
iv = b64encode(cipher_aes.iv).decode('utf-8')
ct = b64encode(ct_bytes).decode('utf-8')
return iv, ct
def decrypt_message_with_aes(iv, ct, aes_key):
iv = b64decode(iv)
ct = b64decode(ct)
cipher_aes = AES.new(aes_key, AES.MODE_CBC, iv)
pt_bytes = unpad(cipher_aes.decrypt(ct), AES.block_size)
return pt_bytes
2.4消息摘要的生成和验证,验证数据的完整性
def generate_digest(message):
hasher = hashlib.sha256()
hasher.update(message)
digest = hasher.hexdigest()
return digest
def verify_digest(message, digest):
expected_digest = generate_digest(message)
return digest == expected_digest
2.5数字签名的生成和验证,验证消息来源的正确性
def sign_message_with_rsa(private_key_file, message):
with open(private_key_file, "rb") as key_file:
key = RSA.import_key(key_file.read())
# 将消息转换为字节类对象
message_bytes = message.encode('utf-8')
# 使用 SHA256 哈希算法处理消息
hash_obj = SHA256.new(message_bytes)
# 使用 RSA 私钥对哈希值进行签名
signer = pkcs1_15.new(key)
signature = signer.sign(hash_obj)
return signature
def verify_signature_with_rsa(public_key_file, message, signature):
with open(public_key_file, "rb") as key_file:
key = RSA.import_key(key_file.read())
# 将消息转换为字节类对象
message_bytes = message
# 使用 SHA256 哈希算法处理消息
hash_obj = SHA256.new(message_bytes)
# 使用 RSA 公钥验证签名
verifier = pkcs1_15.new(key)
try:
verifier.verify(hash_obj, signature)
return True
except (ValueError, TypeError):
return False
2.6图形界面实现代码,采用place()方法
root=tk.Tk()
root.title('测试窗口')
root.geometry('500x300+500+250')
frame1=tk.Frame(root)
tk.Label(frame1,text='选择你的身份',font=("Simsun",16),pady=10).place(relx=0.37,rely=0.15,anchor='w')
button_sender=tk.Button(frame1, text="发送方",font=("SimSun", 14),command=open_frame2)
button_sender.place(relx=0.42,rely=0.31,anchor='w')
button_receiver=tk.Button(frame1, text="接受方",font=("SimSun", 14),command=open_frame4)
button_receiver.place(relx=0.42,rely=0.5,anchor='w')
frame1.pack(fill=tk.BOTH, expand=True)
frame2=tk.Frame(root)
tk.Label(frame2,text='根据标签中的内容提供相应的文件',font=("Simsun",16),pady=10).place(relx=0.05,rely=0.15,anchor='w')
tk.Label(frame2, text="源文件:",font=("SimSun", 14),pady=10).place(relx=0.05,rely=0.31,anchor='w')
entry_message=tk.Entry(frame2, width=23,font=("SimSun", 14))
entry_message.place(relx=0.3,rely=0.31,anchor='w')
button_message= tk.Button(frame2, text="选择路径",font=("SimSun", 14), command=select_message_file)
button_message.place(relx=0.8,rely=0.31,anchor="w")
tk.Label(frame2,text='A私钥pem文件:',font=("SimSun", 14),padx=0,pady=9).place(relx=0.05,rely=0.43,anchor='w')
entry_Aprivate_send = tk.Entry(frame2, width=23,font=("SimSun", 14))
entry_Aprivate_send.place(relx=0.3,rely=0.43,anchor="w")
button_Aprivate= tk.Button(frame2, text="选择路径",font=("SimSun", 14), command=select_Aprivate_key_file)
button_Aprivate.place(relx=0.8,rely=0.43,anchor="w")
tk.Label(frame2,text='B公钥pem文件:',font=("SimSun", 14),padx=0,pady=0).place(relx=0.05,rely=0.55,anchor="w")
entry_Bpublic_send= tk.Entry(frame2, width=23,font=("SimSun", 14))
entry_Bpublic_send.place(relx=0.3,rely=0.55,anchor="w")
button_Bpubic= tk.Button(frame2, text="选择路径",font=("SimSun", 14), command=select_Bpublic_key_file)
button_Bpubic.place(relx=0.8,rely=0.55,anchor="w")
button_encrypt= tk.Button(frame2, text="加密文件",font=18,command=sender)
button_encrypt.place(relx=0.4,rely=0.7,anchor='w')
#frame2.pack(fill=tk.BOTH, expand=True)
frame3=tk.Frame(root)
tk.Label(frame3,text='选择加密文件另存为地址',font=("Simsun",16),pady=10).place(relx=0.26,rely=0.15,anchor='w')
button_choice= tk.Button(frame3, text="选择路径",font=("SimSun", 14), command=loader_sum_message_file)
button_choice.place(relx=0.4,rely=0.31,anchor='w')
button_back31= tk.Button(frame3, text="返回重新选择",font=("SimSun", 14), command=open_frame31)
button_back31.place(relx=0.36,rely=0.5,anchor='w')
#frame3.pack(fill=tk.BOTH, expand=True)
frame4=tk.Frame(root)
tk.Label(frame4,text='根据标签中的内容提供相应的文件',font=("Simsun",16),pady=10).place(relx=0.05,rely=0.15,anchor='w')
tk.Label(frame4, text="加密后的文件:",font=("SimSun", 14),pady=10).place(relx=0.05,rely=0.31,anchor='w')
entry_encrypted_message=tk.Entry(frame4, width=23,font=("SimSun", 14))
entry_encrypted_message.place(relx=0.3,rely=0.31,anchor='w')
button_encrypted_message= tk.Button(frame4, text="选择路径",font=("SimSun", 14), command=select_encrypted_message_file)
button_encrypted_message.place(relx=0.8,rely=0.31,anchor="w")
tk.Label(frame4,text='A公钥pem文件:',font=("SimSun", 14),padx=0,pady=9).place(relx=0.05,rely=0.43,anchor='w')
entry_Apublic_send = tk.Entry(frame4, width=23,font=("SimSun", 14))
entry_Apublic_send.place(relx=0.3,rely=0.43,anchor="w")
button_Apublic= tk.Button(frame4, text="选择路径",font=("SimSun", 14), command=select_Apublic_key_file)
button_Apublic.place(relx=0.8,rely=0.43,anchor="w")
tk.Label(frame4,text='B私钥pem文件:',font=("SimSun", 14),padx=0,pady=0).place(relx=0.05,rely=0.55,anchor="w")
entry_Bprivate_send= tk.Entry(frame4, width=23,font=("SimSun", 14))
entry_Bprivate_send.place(relx=0.3,rely=0.55,anchor="w")
button_Bprivate= tk.Button(frame4, text="选择路径",font=("SimSun", 14), command=select_Bprivate_key_file)
button_Bprivate.place(relx=0.8,rely=0.55,anchor="w")
button_decrypt= tk.Button(frame4, text="解密文件",font=18,command=receiver)
button_decrypt.place(relx=0.4,rely=0.7,anchor='w')
#frame4.pack(fill=tk.BOTH, expand=True)
frame5=tk.Frame(root)
tk.Label(frame5,text='选择解密文件另存为地址',font=("Simsun",16),pady=10).place(relx=0.26,rely=0.15,anchor='w')
button_choice= tk.Button(frame5, text="选择路径",font=("SimSun", 14), command=loader_decrypted_message_file)
button_choice.place(relx=0.4,rely=0.31,anchor='w')
button_back51= tk.Button(frame5, text="返回重新选择",font=("SimSun", 14), command=open_frame51)
button_back51.place(relx=0.36,rely=0.5,anchor='w')
#frame5.pack(fill=tk.BOTH, expand=True)
root.mainloop()
3.图形界面实现
3.1选择界面
3.2发送方界面
3.3.1以txt为例
文件选择
保存路径
加密后的文件
接受方界面
文件选择
消息完整性和正确性验证
解密后的文件
3.3.2以png为例
加密前的文件
文件选择
加密后的文件
文件选择
消息完整性和正确性验证
解密后的文件
三、反思与总结
1.遇到的困难:一开始选择RSA加密文件,因为RSA公私钥位数的问题,会导致过大的文件无法加密,甚至只能加密短的txt文件,最后选择采用对称加密体制,用AES加密可以不限制文件大小,防止AES密钥泄露采用RSA对其加密
2.对纯txt文件加密后,原文以ASCII字符出现,AES密钥会以中文字符出现,导致会被人轻易看出