AES 在网络安全中的应用及其算法原理

作者:陈年老陈皮 发布时间: 2026-05-29 阅读量:6

AES 是由美国国家标准与技术研究院(NIST)于 2001 年发布的对称分组加密算法,替代了原有的 DES 算法,成为国际通用的加密标准。

AES 在网络安全中的应用

安全启动:保障固件可信性

安全启动是设备网络安全的第一道防线,其目标是确保设备上电后只运行经过制造商授权的固件程序,防止攻击者篡改 Bootloader 或应用程序。

AES 在安全启动中的应用流程:

  1. 制造商在发布固件时,使用 SHA-256 算法计算固件的哈希值(固件 "指纹")

  2. 使用 AES 算法对哈希值进行加密,或使用 AES-CMAC 计算固件的认证码

  3. 将加密后的哈希值 / CMAC 值与固件一起存储在设备 Flash 中

  4. 设备启动时,硬件安全模块(HSM)首先加载 Bootloader

  5. 重新计算当前固件的哈希值 / CMAC 值,与存储的加密值解密后对比

  6. 若校验通过,则继续启动流程;若校验失败,则拒绝启动并触发安全机制

OTA 软件更新:防止传输篡改与窃取

OTA(Over-the-Air)远程升级是智能设备的核心功能,但更新包在公网传输过程中面临被窃取、篡改和伪造的风险。AES 算法与数字签名、哈希算法结合,构建了 OTA 更新的完整安全体系。

AES 在 OTA 中的应用流程:

  1. 制造商生成 OTA 更新包后,使用 SHA-256 计算更新包的完整性哈希值

  2. 使用 AES-CBC 模式对整个更新包进行加密,防止传输过程中被窃取

  3. 使用制造商的私钥对加密后的更新包和哈希值进行数字签名

  4. 将加密更新包、签名和哈希值一起推送给设备

  5. 设备接收后,首先使用制造商公钥验证数字签名,确认更新包来源合法

  6. 使用 AES 密钥解密更新包,重新计算哈希值并与接收值对比,确认完整性

  7. 所有校验通过后,才执行固件升级操作

AES 算法核心

核心特性如下:

  • 分组长度:固定为 128 位(16 字节),所有明文和密文均以 128 位为基本处理单元

  • 密钥长度:支持 128 位、192 位和 256 位三种规格,密钥越长安全性越高,计算开销也相应增大

  • 对称加密:加密和解密使用相同的密钥,密钥的安全存储和分发是应用的关键

  • 运算效率:硬件和软件实现均能达到极高的处理速度,适合嵌入式设备的算力限制

AES 算法本身定义了单块数据的加密和解密流程,而在实际应用中,需要结合不同的工作模式处理任意长度的数据,并解决单块加密带来的安全性问题。网络安全中最常用的三种工作模式为 ECB、CBC 和 CMAC。

AES 主流工作模式原理与特性

1.ECB 模式(电子密码本模式)

ECB 是最简单的 AES 工作模式,其核心思想是将明文按 128 位分组后,每个分组独立使用相同的密钥进行加密。

加密工作原理

  1. 将明文按照 128 位块大小进行分组,最后一块不足 128 位时进行填充

  2. 对每个明文分组单独执行 AES 加密运算,得到对应的密文分组

  3. 将所有密文分组按顺序拼接,得到最终密文

解密工作原理

与加密过程完全对称,将密文按 128 位分组后,每个分组独立使用相同密钥解密,最后去除填充并拼接得到明文。

特性分析

  • 优点:实现简单,运算速度快,支持并行处理

  • 缺点:相同的明文分组会生成相同的密文分组,无法隐藏数据模式,易遭受统计分析攻击。该模式安全性极低,仅适用于短数据且安全性要求不高的场景,行业中不推荐用于敏感数据加密。

2.CBC 模式(密码分组链接模式)

CBC 模式通过引入链式依赖关系解决了 ECB 模式的安全性问题,是目前设备 OTA 升级、固件加密等场景中最常用的加密模式。

加密工作原理

  1. 生成一个 128 位的随机初始向量(IV),IV 无需保密但必须保证每次加密唯一

  2. 将第一个明文分组与 IV 进行异或运算,结果使用 AES 密钥加密得到第一个密文分组

  3. 后续每个明文分组先与前一个密文分组进行异或运算,再使用 AES 密钥加密

  4. 所有密文分组与 IV 一起传输,用于后续解密

解密工作原理

  1. 使用相同的密钥和传输的 IV 创建解密器

  2. 对第一个密文分组执行 AES 解密,结果与 IV 异或得到第一个明文分组

  3. 后续每个密文分组解密后,与前一个密文分组异或得到对应的明文分组

  4. 去除填充并拼接所有明文分组,得到原始明文

特性分析

  • 优点:相同明文分组在不同位置会生成不同密文,有效隐藏数据模式,安全性远高于 ECB 模式

  • 缺点:加密过程是串行的,无法并行处理;若某一密文分组传输错误,会导致后续所有分组解密失败(错误传播)

3.CMAC 模式(基于密码的消息认证码)

AES-CMAC 不是传统的加密模式,而是基于 AES 算法的消息认证码生成算法,用于验证数据的完整性和真实性,无法用于数据解密。它解决了传统 MAC 算法的安全缺陷,被广泛应用于设备安全启动、CAN 总线消息认证等场景。

工作原理

  1. 基于 AES 密钥生成两个子密钥 K1 和 K2,用于处理最后一个数据块

  2. 将消息按 128 位分组,最后一块不足时进行填充

  3. 采用链式加密方式处理前 N-1 个数据块,每个块与前一个加密结果异或后再加密

  4. 对最后一个数据块,根据是否需要填充选择与 K1 或 K2 异或,最终加密结果即为 CMAC 值

43ad52ce-4847-819e-a73c-e9874a4bc73e.png

特性分析

  • 只有持有相同密钥的双方才能生成相同的 CMAC 值

  • 消息的任何微小改动都会导致 CMAC 值发生显著变化

  • 生成的 CMAC 值长度为 128 位,可根据需求截断使用

AES 算法的 Python 实现

以下基于pycryptodome库实现汽车网络安全中常用的三种 AES 工作模式,首先安装依赖库:

pip install pycryptodome

AES-ECB 加解密实现

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes

def aes_ecb_encrypt(plaintext: str, key: bytes) -> bytes:
    """AES-ECB模式加密(仅用于演示,生产环境不推荐)"""
    cipher = AES.new(key, AES.MODE_ECB)
    padded_plaintext = pad(plaintext.encode("utf-8"), AES.block_size)
    return cipher.encrypt(padded_plaintext)

def aes_ecb_decrypt(ciphertext: bytes, key: bytes) -> str:
    """AES-ECB模式解密"""
    cipher = AES.new(key, AES.MODE_ECB)
    decrypted_padded = cipher.decrypt(ciphertext)
    decrypted_text = unpad(decrypted_padded, AES.block_size)
    return decrypted_text.decode("utf-8")

# 示例运行
if __name__ == "__main__":
    # 生成128位安全随机密钥(每次运行都会不同)
    key = get_random_bytes(16)  # 改为32即可生成AES-256密钥
    plaintext = "AES ECB 网络安全测试"
    
    encrypted = aes_ecb_encrypt(plaintext, key)
    decrypted = aes_ecb_decrypt(encrypted, key)
    
    print("=" * 60)
    print(f"随机生成的AES-128密钥(十六进制): {key.hex()}")
    print("=" * 60)
    print(f"原始明文: {plaintext}")
    print(f"加密后密文(十六进制): {encrypted.hex()}")
    print(f"解密后明文: {decrypted}")
    print("=" * 60)
8e0729e3-6a4a-ffb0-cc56-9da9ba580775.png

AES-CBC 加解密实现

from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
from Crypto.Random import get_random_bytes

def aes_cbc_encrypt(plaintext: str, key: bytes) -> tuple[bytes, bytes]:
    """AES-CBC模式加密,返回(密文, 初始向量IV)"""
    iv = get_random_bytes(AES.block_size)  # 每次加密必须生成新的随机IV
    cipher = AES.new(key, AES.MODE_CBC, iv)
    padded_plaintext = pad(plaintext.encode("utf-8"), AES.block_size)
    ciphertext = cipher.encrypt(padded_plaintext)
    return ciphertext, iv

def aes_cbc_decrypt(ciphertext: bytes, key: bytes, iv: bytes) -> str:
    """AES-CBC模式解密"""
    decipher = AES.new(key, AES.MODE_CBC, iv)
    decrypted_padded = decipher.decrypt(ciphertext)
    decrypted_text = unpad(decrypted_padded, AES.block_size)
    return decrypted_text.decode("utf-8")

# 示例运行
if __name__ == "__main__":
    # 生成128位安全随机密钥(每次运行都会不同)
    key = get_random_bytes(16)
    plaintext = "AES CBC OTA更新包加密测试"
    
    ciphertext, iv = aes_cbc_encrypt(plaintext, key)
    decrypted = aes_cbc_decrypt(ciphertext, key, iv)
    
    print("=" * 60)
    print(f"随机生成的AES-128密钥(十六进制): {key.hex()}")
    print(f"随机生成的初始向量IV(十六进制): {iv.hex()}")
    print("=" * 60)
    print(f"原始明文: {plaintext}")
    print(f"加密后密文(十六进制): {ciphertext.hex()}")
    print(f"解密后明文: {decrypted}")
    print("=" * 60)
fc264886-ca0a-3f09-bfb7-8500f50b9e1c.png

AES-CMAC 消息认证实现

from Crypto.Cipher import AES
from Crypto.Util.strxor import strxor
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes

def left_shift(data: bytes) -> bytes:
    """字节数据左移1位,用于生成子密钥"""
    result = bytearray(len(data))
    carry = 0
    for i in reversed(range(len(data))):
        result[i] = ((data[i] << 1) & 0xff) | carry
        carry = (data[i] >> 7) & 1
    if carry:
        result[-1] ^= 0x87  # AES-CMAC标准固定常数
    return bytes(result)

def generate_subkeys(key: bytes) -> tuple[bytes, bytes]:
    """生成AES-CMAC所需的两个子密钥K1和K2"""
    cipher = AES.new(key, AES.MODE_ECB)
    zero_block = b"\x00" * AES.block_size
    l = cipher.encrypt(zero_block)
    k1 = left_shift(l)
    k2 = left_shift(k1)
    return k1, k2

def aes_cmac(key: bytes, message: bytes) -> bytes:
    """计算AES-CMAC消息认证码"""
    k1, k2 = generate_subkeys(key)
    block_size = AES.block_size
    padded_message = pad(message, block_size)
    num_blocks = len(padded_message) // block_size

    if num_blocks == 0:
        padded_message = b"\x00" * block_size
        num_blocks = 1

    x = b"\x00" * block_size
    cipher = AES.new(key, AES.MODE_ECB)

    # 处理前N-1个数据块
    for i in range(num_blocks - 1):
        block = padded_message[i*block_size : (i+1)*block_size]
        x = cipher.encrypt(strxor(x, block))

    # 处理最后一个数据块(根据是否填充选择子密钥)
    last_block = padded_message[(num_blocks-1)*block_size :]
    if len(message) % block_size == 0:
        last_block = strxor(last_block, k1)
    else:
        last_block = strxor(last_block, k2)

    return cipher.encrypt(strxor(x, last_block))

# 示例运行
if __name__ == "__main__":
    # 生成128位安全随机密钥(每次运行都会不同)
    key = get_random_bytes(16)
      
    message = "AES-CMAC 安全启动固件校验测试"
    cmac_value = aes_cmac(key, message.encode('utf-8'))
    
    print("=" * 60)
    print(f"随机生成的AES-128密钥(十六进制): {key.hex()}")
    print("=" * 60)
    print(f"测试消息: {message}")
    print(f"AES-CMAC认证码(十六进制): {cmac_value.hex()}")
    print("=" * 60)
eac399cf-1149-adb7-e956-f7a1b9f6783c.png