2025-06-19 13:49:00 by wst
算法实践需求:
发送方发送数据,并对数据进行压缩加密;
接收方接收数据,使用私钥解密并验证数据;
方法:
1. 生成发送方的公私钥、接收方的公私钥;
2. 生成对称密钥aes_key(解密数据用),随机字符串nonce;
3. 使用aes_key加密压缩的数据,生成encrypted_data和tag;
4. 使用(接收方)的公钥public_key加密aes_key,生成encrypted_aes_key;
5. 创建aes_key的指纹信息key_fingerprint,并用public_key加密指纹信息生成签名signature;
6. 拼接以上所有数据(encrypted_aes_key + nonce + tag + signature + encrypted_data)并写入文件output中;
7. 从output中读取文件内容,拆解出encrypted_aes_key 、 nonce 、 tag 、 signature 、 encrypted_data;
8. 接收方使用私钥解密出aes_key;
9. 接收方使用私钥private_key解密签名signature得到指纹信息decrypted_signature;
10. 再次生成aes_key的指纹current_fingerprint,并和decrypted_signature对比是否相等;如不等则抛出异常;
11. 使用aes解密encrypted_data,并连带tag一起验证数据,通过后返回压缩数据compressed;
12. 使用zlib解压数据得到原始数据;
代码如下:
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP, AES
from Crypto.Random import get_random_bytes
from Crypto.Hash import SHA256
import zlib
def generate_rsa_keys(key_size=2048):
"""生成RSA公钥/私钥对"""
key = RSA.generate(key_size)
private_key = key.export_key()
public_key = key.publickey().export_key()
return private_key, public_key
def rsa_encrypt(data, public_key):
"""使用RSA公钥加密数据"""
rsa_key = RSA.import_key(public_key)
cipher = PKCS1_OAEP.new(rsa_key)
return cipher.encrypt(data)
def rsa_decrypt(encrypted_data, private_key):
"""使用RSA私钥解密数据"""
rsa_key = RSA.import_key(private_key)
cipher = PKCS1_OAEP.new(rsa_key)
return cipher.decrypt(encrypted_data)
def gcm_encrypt_file(input_path, public_key, output_path=None):
"""
使用AES-GCM加密文件
文件格式:
[256字节 RSA加密的AES密钥]
[12字节 AES-GCM nonce]
[16字节 AES-GCM认证标签]
[剩余部分 AES加密数据]
"""
# 读取文件内容
with open(input_path, 'rb') as f:
file_data = f.read()
# 压缩数据
compressed = zlib.compress(file_data, level=6)
# 生成随机AES密钥和nonce
aes_key = get_random_bytes(32) # AES-256
nonce = get_random_bytes(12) # AES-GCM推荐12字节nonce
# 使用AES-GCM模式加密数据
cipher = AES.new(aes_key, AES.MODE_GCM, nonce=nonce)
# 可选:添加额外关联数据(如文件元数据)
# cipher.update(b"Additional authenticated data")
# 加密并生成认证标签
encrypted_data, tag = cipher.encrypt_and_digest(compressed)
# 用RSA公钥加密AES密钥
encrypted_aes_key = rsa_encrypt(aes_key, public_key)
# 如果提供私钥,则对密钥进行签名
signature = b''
# 创建密钥指纹用于签名
key_fingerprint = SHA256.new(aes_key).digest()
signature = rsa_encrypt(key_fingerprint, public_key)
# print("校验输入内容:")
# print("AES密钥:",encrypted_aes_key, len(encrypted_aes_key))
# print("Nonce:", nonce, len(nonce))
# print("Tag:", tag, len(tag))
# print("Signature:", signature, len(signature))
# print("Encrypted data:", encrypted_data, len(encrypted_data))
# 准备输出数据
output = encrypted_aes_key + nonce + tag + signature + encrypted_data
# 写入输出文件或返回数据
if output_path:
with open(output_path, 'wb') as f:
f.write(output)
return True
else:
return output
def gcm_decrypt_file(input_path, private_key, output_path=None):
"""
使用AES-GCM解密文件
执行自动完整性验证
"""
# 读取加密文件
with open(input_path, 'rb') as f:
encrypted_file = f.read()
# 解析文件各部分
rsa_key_size = 512 # 2048位RSA
nonce_size = 12 # AES-GCM nonce大小
tag_size = 16 # AES-GCM认证标签大小
signature_size = 512
# 计算各部分的位置
encrypted_aes_key = encrypted_file[:rsa_key_size]
nonce = encrypted_file[rsa_key_size:rsa_key_size+nonce_size]
tag = encrypted_file[rsa_key_size+nonce_size:rsa_key_size+nonce_size+tag_size]
signature_start = rsa_key_size+nonce_size+tag_size
signature = encrypted_file[signature_start:signature_start+signature_size]
encrypted_data_start = signature_start + signature_size
encrypted_data = encrypted_file[encrypted_data_start:]
# print("校验输出内容:")
# print("AES密钥:", encrypted_aes_key, len(encrypted_aes_key))
# print("Nonce:", nonce, len(nonce))
# print("Tag:", tag, len(tag))
# print("Signature:", signature, len(signature))
# print("Encrypted data:", encrypted_data, len(encrypted_data))
# 用接收方私钥解密AES密钥
aes_key = rsa_decrypt(encrypted_aes_key, private_key)
# 如果提供发送方公钥,验证密钥签名
# 使用发送方公钥解密签名
decrypted_signature = rsa_decrypt(signature, private_key)
# 创建当前密钥指纹
current_fingerprint = SHA256.new(aes_key).digest()
# 验证签名是否匹配
if decrypted_signature != current_fingerprint:
raise ValueError("密钥签名验证失败! 可能来自未知来源或密钥被篡改")
# 使用AES-GCM解密数据
cipher = AES.new(aes_key, AES.MODE_GCM, nonce=nonce)
# 可选:验证额外关联数据(需与加密时一致)
# cipher.update(b"Additional authenticated data")
try:
compressed = cipher.decrypt_and_verify(encrypted_data, tag)
except ValueError as e:
# 认证失败,数据可能已被篡改
raise ValueError("GCM认证失败! 文件内容或密钥可能已被篡改") from e
# 解压缩数据
decompressed = zlib.decompress(compressed)
# 写入输出文件或返回数据
if output_path:
with open(output_path, 'wb') as f:
f.write(decompressed)
return True
else:
return decompressed
# ========== 使用示例 ==========
if __name__ == "__main__":
# 生成接收方密钥对
receiver_private, receiver_public = generate_rsa_keys(4096)
# 生成发送方密钥对(用于密钥签名)
sender_private, sender_public = generate_rsa_keys(4096)
# 保存密钥
with open("receiver_private.pem", "wb") as f:
f.write(receiver_private)
with open("receiver_public.pem", "wb") as f:
f.write(receiver_public)
with open("sender_private.pem", "wb") as f:
f.write(sender_private)
with open("sender_public.pem", "wb") as f:
f.write(sender_public)
# 创建测试文件
with open("test_file.txt", "wb") as f:
f.write(b"This is a test file for AES-GCM encryption and decryption.")
print("=== 使用AES-GCM加密(带密钥签名验证)===")
# 发送方操作:压缩并加密文件
gcm_encrypt_file(
input_path="test_file.txt",
public_key=receiver_public,
output_path="encrypted_gcm_signed.bin"
)
# 接收方操作:解密文件并验证签名
try:
gcm_decrypt_file(
input_path="encrypted_gcm_signed.bin",
private_key=receiver_private,
output_path="decrypted_gcm_signed.txt"
)
print("文件解密成功且密钥签名已验证!")
except ValueError as e:
print(f"安全警告: {e}")
print("\n=== 使用AES-GCM加密(无签名)===")
# 发送方操作:压缩并加密文件(无签名)
gcm_encrypt_file(
input_path="test_file.txt",
public_key=receiver_public,
output_path="encrypted_gcm.bin"
)
# 接收方操作:解密文件(无需签名验证)
try:
gcm_decrypt_file(
input_path="encrypted_gcm.bin",
private_key=receiver_private,
output_path="decrypted_gcm.txt"
)
print("文件解密成功,GCM完整性已验证!")
except ValueError as e:
print(f"安全警告: {e}")
print("\n=== 篡改测试 ===")
# 篡改加密文件
with open("encrypted_gcm.bin", "rb") as f:
corrupted_data = f.read()
# 修改一个字节
corrupted_data = corrupted_data[:400] + bytes([corrupted_data[400] ^ 0x01]) + corrupted_data[401:]
with open("corrupted_gcm.bin", "wb") as f:
f.write(corrupted_data)
# 尝试解密被篡改的文件
print("尝试解密被篡改的文件...")
try:
gcm_decrypt_file(
input_path="corrupted_gcm.bin",
private_key=receiver_private,
output_path="decrypted_corrupted.txt"
)
except ValueError as e:
print(f"成功检测到篡改: {e}")
总结:
这里通过aes实现了文件数据的加解密过程,同时保证数据密文传输和完整性;