python文件压缩加解密过程

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实现了文件数据的加解密过程,同时保证数据密文传输和完整性;


Comments(0) Add Your Comment

Not Comment!