返回列表 发布新帖
查看: 21|回复: 0

加密的数据还能被篡改?用AEAD 拯救你的数据安全

2

主题

0

回帖

10

积分

新手上路

积分
10
发表于 2025-6-6 01:57:56 | 查看全部 |阅读模式 北京市 新国信通信有限公司

你是不是觉得只要对数据加密后数据就一定不会被篡改了?那你就大错特错了。

一个意想不到的实验结果

首先,我们来看一个神奇的实验:

from __future__ import annotations

from cryptography.hazmat.primitives.ciphers import Cipher , algorithms , modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend

# ==================================================
# AES-CBC-256 核心加解密(非AEAD)
# ==================================================
def aes_cbc_encrypt(plain_data: bytes , key: bytes , iv: bytes) -> bytes:
    """CBC加密(需要PKCS7填充)"""
    # 添加填充
    padder = padding.PKCS7(128).padder()
    padded_data = padder.update(plain_data) + padder.finalize()

    # 加密
    cipher = Cipher(algorithms.AES(key) , modes.CBC(iv) , backend = default_backend())
    encryptor = cipher.encryptor()
    return encryptor.update(padded_data) + encryptor.finalize()

def aes_cbc_decrypt(ciphertext: bytes , key: bytes , iv: bytes) -> bytes:
    """CBC解密(无完整性验证)"""
    # 解密
    cipher = Cipher(algorithms.AES(key) , modes.CBC(iv) , backend = default_backend())
    decryptor = cipher.decryptor()
    padded_plaintext = decryptor.update(ciphertext) + decryptor.finalize()

    # 移除填充
    unpadder = padding.PKCS7(128).unpadder()
    return unpadder.update(padded_plaintext) + unpadder.finalize()

if __name__ == "__main__":
    # 固定输入值(实际使用中应为随机值)
    plaintext = b"Transfer $100 to Alice"
    key = b"12345678901234567890123456789012"  # 256-bit key,仅用作测试
    iv = b"1234567890123456"  # 16 字节 CBC IV

    print("===== AES-CBC-256 演示 =====")

    print(f'原始明文数据:{plaintext.hex()}')

    # CBC加密
    cbc_ciphertext = aes_cbc_encrypt(plaintext , key , iv)
    print(f"密文: {cbc_ciphertext.hex()}")

    # CBC解密(原始数据)
    cbc_decrypted = aes_cbc_decrypt(cbc_ciphertext , key , iv)
    print(f"对正常的密文解密后的结果: {cbc_decrypted.hex()}, 解密成功:{cbc_decrypted.hex() == plaintext.hex()}")

    # 篡改第1个字节(在真实攻击中更隐蔽)
    # 如果改末尾的字节则可能会解填充失败,会显式的抛出异常
    tampered_ciphertext = bytes([ cbc_ciphertext[ 0 ] ^ 0x01 ]) + cbc_ciphertext[ 1: ]

    # 解密被篡改的密文 - 不报错但得到错误结果
    tampered_decrypted = aes_cbc_decrypt(tampered_ciphertext , key , iv)
    print(
            f"篡改后的密文解密出的结果: {tampered_decrypted.hex()},"
            f"解密成功: {tampered_decrypted.hex() == plaintext.hex()},",
            f"解出的数据错误但解密过程无异常")

猜一猜运行代码后会不会抛出异常?

答案是:不会!!!

运行代码后我们可以得到如下的输出:

看到没,在测试代码中,我们只改动了一个字节:

最后解密出来的结果却大相径庭,并且结果过程没有丝毫的错误提示。
这就是非 AEAD加密模式的致命缺陷:只管加密,不防篡改。(例如AES-CBC 是典型的非 AEAD 加密算法)

为什么加密不等于安全?

AES-CBC等传统加密模式统统都面临着以下的困境:

  • 解密不验证完整性 - 就像保险箱没有防伪标签
  • 篡改后仍输出数据 - 接收方拿到假货而不自知
  • 攻击成本极低 - 黑客只需修改几个字节就能改变语义 金融系统、身份认证、医疗数据... 这些关键系统如果只用传统加密,那么数据被恶意篡改的风险极高。

划重点:什么是AEAD?

AEAD(Authenticated Encryption with Associated Data)的出现彻底改变了游戏规则,它同时做到三件事:

  • 保密性 - 数据加密(Encryption)
  • 完整性 - 防篡改(Authentication)
  • 身份验证 - 防重放攻击(Nonce机制)
AES-GCM 是典型的 AEAD 加密算法

让我们再看一个实验:
from __future__ import annotations

from typing import Tuple

from cryptography.hazmat.primitives.ciphers import Cipher , algorithms , modes
from cryptography.hazmat.backends import default_backend

# ==================================================
# AES-GCM-256 核心加解密(AEAD模式)
# ==================================================
def aes_gcm_encrypt(plain_data: bytes , key: bytes , nonce: bytes , ad: bytes) -> Tuple[ bytes , bytes ]:
    """GCM加密(返回密文和认证标签)"""
    cipher = Cipher(algorithms.AES(key) , modes.GCM(nonce) , backend = default_backend())
    encryptor = cipher.encryptor()

    # 添加关联数据认证
    if ad:
        encryptor.authenticate_additional_data(ad)

    # 加密并获取认证标签
    ciphertext = encryptor.update(plain_data) + encryptor.finalize()
    return ciphertext , encryptor.tag

def aes_gcm_decrypt(ciphertext: bytes , tag: bytes , key: bytes , nonce: bytes , ad: bytes) -> bytes:
    """GCM解密(带完整性验证)"""
    cipher = Cipher(algorithms.AES(key) , modes.GCM(nonce , tag) , backend = default_backend())
    decryptor = cipher.decryptor()

    # 添加关联数据认证
    if ad:
        decryptor.authenticate_additional_data(ad)

    # 解密(如果验证失败会抛出异常)
    return decryptor.update(ciphertext) + decryptor.finalize()

if __name__ == "__main__":
    # 固定输入值(实际使用中应为随机值)
    plaintext = b"Secret message! AEAD is awesome!"
    key = b"12345678901234567890123456789012"  # 256-bit key 仅用作测试
    nonce = b"123456789012"  # GCM 12 字节 nonce
    ad = b"Additional data"  # GCM关联数据

    print("\n===== AES-GCM-256 演示 =====")

    print(f'原始明文数据: {plaintext.hex()}')

    # GCM加密
    gcm_ciphertext , tag = aes_gcm_encrypt(plaintext , key , nonce , ad)
    print(f"密文数据: {gcm_ciphertext.hex()}")
    print(f"认证标签: {tag.hex()}")

    # GCM解密(原始数据)
    gcm_decrypted = aes_gcm_decrypt(gcm_ciphertext , tag , key , nonce , ad)
    print(f"正常的密文解密结果: {gcm_decrypted.decode()}, 解密成功:{gcm_decrypted.hex() == plaintext.hex()}")

    # 尝试篡改密文的第一个字节
    tampered_gcm_ciphertext = bytes([ gcm_ciphertext[ 0 ] ^ 0x01 ]) + gcm_ciphertext[ 1: ]

    # 解密篡改后的密文 - 应该失败
    try:
        aes_gcm_decrypt(tampered_gcm_ciphertext , tag , key , nonce , ad)
        print("解密成功 (不应该发生)")
    except Exception as e:
        print(f"篡改测试: {e} 解密失败,AEAD检测到密文篡改!")

    # 尝试篡改关联数据
    try:
        aes_gcm_decrypt(gcm_ciphertext , tag , key , nonce , b"tampered_ad")
        print("解密成功 (不应该发生)")
    except Exception as e:
        print(f"AD篡改测试: {e} 解密失败,AEAD检测到AD篡改!")
运行代码后我们得到以下结果:

我们可以清楚的看到,对于正确的密文,可以正确解密出明文;而对于被篡改后的密文,则会捕获解密失败的异常。

这就是 AEAD 的特殊功效:

  1. 认证标签(Tag):数据的"数字指纹",由密钥+密文生成,哪怕改动1个比特,标签就会失效
  2. 关联数据(AD):若伪造关联数据,则解密立即失败
  3. Nonce防御重放攻击:每次加密使用唯一Nonce(编号)防重放攻击

当前支持AEAD的加密算法


目前超过90%的HTTPS流量使用AES-GCM或ChaCha20-Poly1305,而TLS 1.3更是强制使用AEAD技术!
安全不是产品,而是持续的过程。
真正的安全不是相信数据未被篡改,而是能证明它未被篡改。

虽然AEAD提供终极防护,但如果实现不当(如密钥泄漏或随机数重用),仍然可能导致各种数据风险,因此,AEAD不是银弹,因为黑客从不攻击算法本身,而是寻找人犯错留下的缝隙。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
爱云外,爱奶昔~
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

相关网站

Naixi Global

站内导航

奶昔SSO 奶昔云盘

商业推广

联系我们
  • 扫码加入QQ群
© 2025 Naixi Networks 版权所有 · 由武汉云外创想信息技术有限公司运营 鄂ICP备2021000007号-3|增值电信业务经营许可证鄂B1.B2-20222603号
关灯 在本版发帖
扫一扫添加QQ群
QQ客服返回顶部
快速回复 返回顶部 返回列表