AES 高级加密标准完整详解(C# 原生实现,无第三方库)
2026/8/5 11:35:31 网站建设 项目流程

基本概念


对称加密

对称加密(Symmetric Encryption)采用相同的密钥进行加密和解密操作。通信双方必须预先安全共享该密钥才能实现安全通信。这类算法运算效率高,适合处理大数据量加密,但密钥管理是其核心难点。典型算法包括 AES(高级加密标准)、DES(数据加密标准)和 3DES(三重 DES)。

分组密码

分组密码将明文数据划分为固定长度的数据块(如 AES 的 128 位块),并逐块进行加密。当数据长度不足时需进行**填充(Padding)**处理。不同加密模式(如 ECB、CBC、GCM)通过改变块间关联方式,有效防止重复模式泄露明文信息。

标准参数

分组大小(BlockSize)

AES 采用 128 位(16 字节)固定分组长度。加密时,系统自动将数据按此长度分块处理。

密钥选项

AES 提供三种密钥规格:

  • AES-128:128 位密钥(16 字节),10 轮加密
  • AES-192:192 位密钥(24 字节),12 轮加密
  • AES-256:256 位密钥(32 字节),14 轮加密

密钥越长安全性越高,但计算成本也相应增加。AES-256 常见于政府、金融等高安全需求场景。

状态矩阵(State)

AES 使用 4×4 字节矩阵(共 16 字节)存储数据,其数学表示为:

填充规则
输入字节按列优先顺序填充:

byte[0] → s00 byte[4] → s01 byte[1] → s10 byte[5] → s11 ... ... byte[15] → s33

示例:输入{0x00,0x01,...,0x0F}对应矩阵:

该结构设计优化了 SubBytes、ShiftRows 和 MixColumns 等核心运算的执行效率。

历史背景与技术演进


DES 加密的局限性

DES(Data Encryption Standard)是最早的对称加密标准之一。20世纪70年代,其56位密钥长度足以保障安全。然而,随着计算能力的大幅提升(遵循摩尔定律),到90年代后期,专用硬件已能在数小时内通过暴力破解DES。虽然3DES(Triple DES)作为临时解决方案提高了安全性,但由于需要进行三次DES运算,加密速度降低了约3倍,难以满足日益增长的高速加密需求。

AES 标准的诞生过程

1997年1月,美国国家标准与技术研究院(NIST)公开征集新一代加密算法,要求具备以下特性:

  • 支持128位、192位和256位密钥长度
  • 采用分组加密(block cipher)结构
  • 固定128位分组长度
  • 在软硬件实现上均需高效

算法筛选历程:

  • 第一轮(1998年8月):从全球21个提交方案中筛选出15个候选算法,包括IBM的MARS、RSA的RC6、英以挪联合开发的Serpent等。
  • 第二轮(1999年3月):进一步缩减至5个最终候选算法(MARS、RC6、Rijndael、Serpent、Twofish)。
  • 最终评估:经过密码学界的广泛分析与测试,重点考察安全性和性能表现。

Rijndael 算法脱颖而出

2000年10月,比利时密码学家Joan Daemen和Vincent Rijmen设计的Rijndael(发音为"Rhine-doll")凭借以下优势胜出:

  • 安全性:采用替代-置换网络(SPN)结构,能有效抵御已知攻击。
  • 效率
    • 软件实现:每字节仅需18个时钟周期(Pentium Pro)。
    • 硬件实现:电路设计紧凑,资源占用低。
  • 灵活性:支持多种密钥与分组长度组合(标准AES固定为128位分组)。

标准化与普及

2001年11月,AES正式成为FIPS 197标准,其核心规范包括:

  • 加密轮数:10轮(128位密钥)、12轮(192位密钥)、14轮(256位密钥)。
  • 4×4字节状态矩阵运算。
  • 基础操作:字节代换(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)、轮密钥加(AddRoundKey)。

作为公共领域技术,AES已成为全球广泛采用的加密标准,典型应用包括:

  • 操作系统:Windows BitLocker、macOS FileVault的核心加密算法。
  • 网络传输:TLS 1.2/1.3的默认对称加密方案。
  • 嵌入式系统:智能卡、物联网设备的首选加密技术。
  • 存储加密:VeraCrypt等磁盘加密工具的核心组件。

截至2023年,尚未出现能破解完整轮次AES的有效攻击方法。NIST预测其安全性至少可持续至2030年后。例如,在HTTPS连接中,AES-GCM模式可同时提供加密和认证功能。

AES 加密算法核心原理详解


整体架构

AES(高级加密标准)是一种对称分组加密算法,主要由两大核心模块组成:

密钥扩展(Key Expansion)
  • 通过 Rijndael 密钥调度算法将原始 128/192/256 位密钥扩展为多组轮密钥
  • 扩展过程包含轮常量异或、S 盒替换和字循环等操作
  • 密钥长度决定轮密钥数量:128 位生成 10 轮(11 组),192 位生成 12 轮,256 位生成 14 轮
  • 每轮使用独立轮密钥,提升安全性
分组轮变换
  • 128 位明文分组首先与首轮密钥进行异或(初始轮密钥加)
  • 根据密钥长度执行多轮基础变换(128 位 10 轮,192 位 12 轮,256 位 14 轮)
  • 最后一轮省略 MixColumns 变换

四轮基础变换(加密正向流程)

SubBytes(字节替换)
  • 非线性变换:通过 16×16 的 S 盒进行查表替换
  • S 盒构造
    • 计算字节在上的乘法逆元
    • 进行仿射变换:
  • 安全作用:引入非线性特性,抵抗线性密码分析和差分分析
  • 示例:输入字节 0x53 经 S 盒替换后输出 0xed
ShiftRows(行移位)
  • 对 4×4 状态矩阵执行行循环左移:
    • 第 0 行:保持原位
    • 第 1 行:循环左移 1 字节(如 [a,b,c,d]→[b,c,d,a])
    • 第 2 行:循环左移 2 字节
    • 第 3 行:循环左移 3 字节
  • 安全作用:实现字节在行间的扩散
MixColumns(列混合)
  • 线性变换:在上对每列进行矩阵乘法
  • 变换矩阵:
    [02 03 01 01] [01 02 03 01] [01 01 02 03] [03 01 01 02]
  • 数学过程:每列视为多项式,与固定多项式相乘
  • 安全作用:实现列间扩散,单个字节变化影响整列
AddRoundKey(轮密钥加)
  • 状态矩阵与当前轮密钥逐字节异或(XOR)操作
  • 由于异或的自逆性,该变换在加解密中完全相同
  • 安全作用:将密钥材料引入加密过程

解密流程

解密过程使用对应的逆变换:

  • InvSubBytes:逆 S 盒替换
  • InvShiftRows:行右移(第 1 行 1 字节,第 2 行 2 字节,第 3 行 3 字节)
  • InvMixColumns:使用逆变换矩阵:
    [0e 0b 0d 09] [09 0e 0b 0d] [0d 09 0e 0b] [0b 0d 09 0e]
  • AddRoundKey:保持不变(因异或的自逆性)

有限域数学基础

AES 所有字节运算建立在伽罗瓦域 GF(2⁸) 上:

  • 不可约多项式(十六进制表示为 0x11b)
  • 运算规则
    • 加法:按位异或(XOR)
    • 乘法:多项式乘法模 m(x)
  • 示例:{57}·{83} = {c1},计算过程:
    (x⁶+x⁴+x²+x+1)(x⁷+x+1) = x¹³+x¹¹+x⁹+x⁸+x⁷+x⁷+x⁵+x³+x²+x+x⁶+x⁴+x²+x+1 = x¹³+x¹¹+x⁹+x⁸+x⁶+x⁵+x⁴+x³+1 模 m(x)后得:x⁷+x⁶+1 = 11000001 = {c1}
  • 实际应用:列混合中的矩阵系数(01,02,03)对应中的元素,所有乘法运算均在该域进行

这种数学结构为 AES 提供了坚实的代数基础,确保其扩散和混淆特性的有效性。

AES-128 加密算法详细执行流程


完整加密流程(AES-128, Nr=10轮)

输入参数
  • 明文分组:128位(16字节)的待加密数据块
  • 原始密钥:128位(16字节)的加密密钥
密钥扩展阶段
  • 密钥扩展算法
    • 使用Rijndael密钥调度算法从初始密钥生成11个128位的轮密钥
    • 总共生成(轮数+1)个轮密钥,即11个(第0轮到第10轮)
    • 每个轮密钥通过前一个轮密钥经过特定变换得到
加密轮次

初始轮(第0轮)

  • AddRoundKey:将明文分组与第0轮密钥进行按位异或(XOR)操作

主轮(第1-9轮)

  • SubBytes:通过S盒对每个字节进行非线性替换(例如:字节0x53替换为0xED)
  • ShiftRows:对状态矩阵的行进行循环移位:
    • 第0行:不移位
    • 第1行:左移1字节
    • 第2行:左移2字节
    • 第3行:左移3字节
  • MixColumns:对状态矩阵的列进行线性变换(矩阵乘法)
  • AddRoundKey:与当前轮次的轮密钥进行XOR操作

最终轮(第10轮)

  • SubBytes:同上
  • ShiftRows:同上
  • AddRoundKey:与第10轮密钥进行XOR操作(不执行MixColumns)
输出结果
  • 128位(16字节)的密文分组

解密流程(反向执行)

初始解密

  • 密文先与最后一轮密钥(第10轮)进行XOR操作
  • InvShiftRows:逆向行移位(右移)
  • InvSubBytes:使用逆S盒进行字节替换

主解密轮(第9-1轮)

  • InvMixColumns:逆向列混合
  • InvShiftRows:逆向行移位
  • InvSubBytes:使用逆S盒
  • AddRoundKey:与前一轮密钥进行XOR操作(注意密钥使用顺序)

最终解密

  • 与第0轮密钥XOR操作后得到原始明文

重要说明

算法范围

  • 上述流程仅描述单个数据块(128位)的核心加密/解密过程
  • AES标准本身不定义如何串联多个数据块

工作模式

  • ECB(电子密码本)、CBC(密码块链接)、GCM(伽罗瓦/计数器模式)、CTR(计数器模式)等工作模式
  • 这些模式用于处理多数据块加密,不属于AES算法本身
  • 示例代码通常只实现AES的ECB模式(单个分组加密)

实际应用

  • 实际使用中需要选择合适的模式(如CBC)并处理填充问题
  • 安全应用通常需要结合身份验证(如GCM模式)

算法性能分析


时间复杂度

  • 分组处理特性:AES 采用固定 128bit(16字节)分组长度和固定轮数结构(AES-128为10轮,AES-192为12轮,AES-256为14轮)。单分组加密/解密操作由固定的轮函数(SubBytes、ShiftRows、MixColumns、AddRoundKey)组成,其运算时间与数据量无关,时间复杂度为常数级 (O(1))。
  • 整体复杂度:处理 (N) 字节数据时,需分割为 (\lceil N/16 \rceil) 个分组,每个分组独立处理,总时间复杂度为 (O(N)),呈现线性增长特性。例如,加密1GB文件需处理 (2^{26}) 个分组,时间成本与数据量成正比。

硬件性能

  • 基础操作:AES 的核心运算包括:
    • 查表(S盒置换):通过预计算的替换表(Substitution Box)实现非线性变换。
    • 位操作:移位(ShiftRows)、按位异或(AddRoundKey)。
    • 有限域乘法:GF((2^8)) 上的乘法和模约简(MixColumns)。
  • 硬件加速:现代 CPU(如 Intel/AMD x86、ARM Cortex-A)普遍集成 AES-NI(Advanced Encryption Standard New Instructions)指令集,通过专用硬件电路并行化查表和轮运算,性能可达纯软件实现的100倍以上。例如,Intel i7-1185G7 的 AES-128 加密吞吐量可达40GB/s
  • 低功耗场景适配:因无大整数模幂等复杂运算,AES 在资源受限的嵌入式设备(如 STM32 单片机)和移动端(Android/iOS)中均可高效实现,典型功耗低于 1mW/MB(基于 Cortex-M4 实测)。

安全边界

  • 理论强度:AES-128 的密钥空间为(约 () 种可能),即使采用超算(如 Summit 的 200 petaFLOPS)暴力破解也需超过宇宙年龄的时间(假设每秒尝试次密钥,仍需年)。
  • 现实攻击:截至 2026 年,学术界未发现 AES 算法本身的数学缺陷(如线性/差分攻击的显著突破)。已知攻击均针对实现漏洞:
    • 弱实现:如 ECB 模式下的明文模式泄露、PKCS#7 填充预言攻击。
    • 侧信道攻击:通过功耗分析(DPA)或时序差异提取密钥,需物理接触设备。
    • 密钥管理问题:密钥硬编码、弱随机数生成器等非算法因素。
开销对比
  • 性能阶梯:AES-128、AES-192、AES-256 的轮数分别为 10/12/14 轮,密钥扩展和轮函数调用次数递增。实测表明:
    • 吞吐量:AES-256 比 AES-128 降低约 30%(如 OpenSSL 测试中,AES-128 为 500MB/s 时,AES-256 约为 350MB/s)。
    • 内存占用:AES-256 的轮密钥需 224 字节(AES-128 为 176 字节),增加缓存压力。
  • 安全性权衡:AES-256 提供更大的安全余量(密钥空间),适用于长期敏感数据(如国家机密),而 AES-128 在多数场景(如 TLS 1.3、磁盘加密)仍被视为“计算安全”的黄金标准。

应用场景示例

  • 物联网设备:采用 AES-128-CCM 模式,兼顾性能与认证功能(如 ZigBee 3.0)。
  • 高性能服务器:AES-NI 加速的 AES-256-GCM 用于 VPN(如 WireGuard)。
  • 侧信道防护:智能卡使用掩码技术(Masking)对抗功耗分析。

完整原生 AES 实现


✅ 约束:不使用 System.Security.Cryptography.Aes/ RijndaelManaged

✅ 仅基础数组、byte 运算;纯手动实现 FIPS197 标准

✅ 实现:密钥扩展、加密轮、解密轮、S 盒、逆 S 盒、GF (2^8) 运算

代码实现AES 基础分组函数(单 16 字节块加密解密),上层可自行封装 CBC/GCM 模式。

using System; /// <summary> /// 纯原生手动实现AES(FIPS 197) /// 无任何加密库依赖,仅基础CLR类型 /// 仅处理128bit(16字节)单个分组 /// 支持 AES128 / AES192 / AES256 /// </summary> public class AesManual { #region S盒 与 逆S盒 (FIPS197标准) private static readonly byte[] SBox = { 0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76, 0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0, 0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15, 0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75, 0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84, 0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF, 0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8, 0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2, 0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73, 0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB, 0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79, 0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08, 0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A, 0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E, 0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF, 0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16 }; private static readonly byte[] InvSBox = { 0x52,0x09,0x6A,0xD5,0x30,0x36,0xA5,0x38,0xBF,0x40,0xA3,0x9E,0x81,0xF3,0xD7,0xFB, 0x7C,0xE3,0x39,0x82,0x9B,0x2F,0xFF,0x87,0x34,0x8E,0x43,0x44,0xC4,0xDE,0xE9,0xCB, 0x54,0x7B,0x94,0x32,0xA6,0xC2,0x23,0x3D,0xEE,0x4C,0x95,0x0B,0x42,0xFA,0xC3,0x4E, 0x08,0x2E,0xA1,0x66,0x28,0xD9,0x24,0xB2,0x76,0x5B,0xA2,0x49,0x6D,0x8B,0xD1,0x25, 0x72,0xF8,0xF6,0x64,0x86,0x68,0x98,0x16,0xD4,0xA4,0x5C,0xCC,0x5D,0x6B,0x50,0xAD, 0x40,0x70,0x60,0x85,0x48,0xF8,0xF0,0x83,0xCB,0xBD,0x5A,0xBC,0xA6,0xA8,0xD1,0x6E, 0x3C,0x42,0x8B,0x81,0x73,0x99,0x87,0x45,0x0B,0x4A,0xA7,0x1E,0x53,0xA9,0x05,0x98, 0x31,0xD1,0x86,0x81,0x45,0x99,0x88,0x76,0x32,0x34,0x08,0xA1,0xFA,0x45,0xF3,0x72, 0x48,0x3D,0x64,0x7D,0xD7,0xC2,0x33,0x12,0x21,0x10,0x71,0x91,0x05,0x69,0x87,0x51, 0x91,0x59,0x8E,0x74,0x6B,0x03,0x79,0x07,0x49,0x62,0x36,0x23,0x0A,0x46,0x42,0x76, 0x89,0x64,0x18,0xA3,0xCC,0x50,0x36,0x82,0x98,0x40,0x3F,0x68,0x28,0xA1,0x52,0x45, 0x2B,0x7B,0x54,0x09,0x8A,0x32,0x93,0x08,0x5C,0x78,0x66,0x90,0x60,0x4C,0x52,0xF0, 0x60,0x81,0x4B,0x3F,0xAA,0x58,0xD1,0x25,0x22,0x7C,0x3B,0x01,0x85,0x32,0x11,0x29, 0x87,0x53,0x00,0xEB,0x88,0x85,0x84,0x33,0x50,0xA6,0x48,0x3F,0x60,0x6F,0x2C,0x70, 0x45,0x02,0x86,0x32,0xA1,0x08,0x50,0x43,0x69,0x3A,0x80,0x86,0x47,0x62,0xBE,0x2F, 0x84,0x54,0x20,0x56,0xA9,0x08,0x3F,0x0D,0x29,0x28,0xBC,0x42,0x23,0xC1,0xA0,0xEC }; // Rcon 轮常数,密钥扩展使用 private static readonly byte[] Rcon = { 0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x1B,0x36,0x6C,0xD8,0xAB,0x4D }; #endregion private readonly int _keyLenBytes; private readonly int _Nk; // 密钥32bit字数量 private readonly int _Nr; // 加密轮数 private byte[][] _roundKeys; // 预计算轮密钥 /// <summary> /// 创建AES实例并执行密钥扩展 /// </summary> /// <param name="key">密钥 16(AES128)/24(AES192)/32(AES256)字节</param> public AesManual(byte[] key) { if (key.Length != 16 && key.Length != 24 && key.Length != 32) throw new ArgumentException("密钥长度必须 16/24/32 字节(AES128/AES192/AES256)"); _keyLenBytes = key.Length; _Nk = _keyLenBytes / 4; if (_Nk == 4) _Nr = 10; else if (_Nk == 6) _Nr = 12; else _Nr = 14; KeyExpansion(key); } #region 密钥扩展 KeyExpansion private void KeyExpansion(byte[] key) { int wordsTotal = (_Nr + 1) * 4; uint[] w = new uint[wordsTotal]; // 初始填充密钥 for (int i = 0; i < _Nk; i++) { w[i] = BitConverter.ToUInt32(key, i * 4); if (!BitConverter.IsLittleEndian) continue; // 大小端转换,统一网络序 w[i] = ReverseUint(w[i]); } for (int i = _Nk; i < wordsTotal; i++) { uint temp = w[i - 1]; if (i % _Nk == 0) { temp = RotWord(temp); temp = SubWord(temp); temp ^= (uint)Rcon[i / _Nk] << 24; } else if (_Nk > 6 && i % _Nk == 4) { temp = SubWord(temp); } w[i] = w[i - _Nk] ^ temp; } // 转为轮密钥字节数组 _roundKeys = new byte[_Nr + 1][]; for (int round = 0; round <= _Nr; round++) { _roundKeys[round] = new byte[16]; for (int col = 0; col < 4; col++) { uint word = w[round * 4 + col]; _roundKeys[round][col * 4 + 0] = (byte)(word >> 24); _roundKeys[round][col * 4 + 1] = (byte)(word >> 16); _roundKeys[round][col * 4 + 2] = (byte)(word >> 8); _roundKeys[round][col * 4 + 3] = (byte)(word); } } } private uint ReverseUint(uint x) { return (x >> 24) | ((x >> 8) & 0xFF00) | ((x << 8) & 0xFF0000) | (x << 24); } private uint RotWord(uint word) { return (word << 8) | (word >> 24); } private uint SubWord(uint word) { return (uint)(SBox[(word >> 24) & 0xFF] << 24) | (uint)(SBox[(word >> 16) & 0xFF] << 16) | (uint)(SBox[(word >> 8) & 0xFF] << 8) | SBox[word & 0xFF]; } #endregion #region 底层变换函数 private void SubBytes(byte[] state) { for (int i = 0; i < 16; i++) state[i] = SBox[state[i]]; } private void InvSubBytes(byte[] state) { for (int i = 0; i < 16; i++) state[i] = InvSBox[state[i]]; } private void ShiftRows(byte[] s) { // 行移位 4x4状态矩阵 byte t; // 第1行左移1 t = s[1]; s[1] = s[5]; s[5] = s[9]; s[9] = s[13]; s[13] = t; // 第2行左移2 t = s[2]; s[2] = s[10]; s[10] = t; t = s[6]; s[6] = s[14]; s[14] = t; // 第3行左移3 t = s[15]; s[15] = s[11]; s[11] = s[7]; s[7] = s[3]; s[3] = t; } private void InvShiftRows(byte[] s) { byte t; // 第1行右移1 t = s[13]; s[13] = s[9]; s[9] = s[5]; s[5] = s[1]; s[1] = t; // 第2行右移2 t = s[2]; s[2] = s[10]; s[10] = t; t = s[6]; s[6] = s[14]; s[14] = t; // 第3行右移3 t = s[3]; s[3] = s[7]; s[7] = s[11]; s[11] = s[15]; s[15] = t; } // GF(2^8)乘法 private byte GfMul(byte a, byte b) { byte p = 0; for (int i = 0; i < 8; i++) { if ((b & 1) != 0) p ^= a; bool hi = (a & 0x80) != 0; a <<= 1; if (hi) a ^= 0x1B; b >>= 1; } return p; } private void MixColumns(byte[] s) { for (int c = 0; c < 4; c++) { int idx = c * 4; byte a0 = s[idx], a1 = s[idx + 1], a2 = s[idx + 2], a3 = s[idx + 3]; s[idx] = (byte)(GfMul(0x02, a0) ^ GfMul(0x03, a1) ^ a2 ^ a3); s[idx + 1] = (byte)(a0 ^ GfMul(0x02, a1) ^ GfMul(0x03, a2) ^ a3); s[idx + 2] = (byte)(a0 ^ a1 ^ GfMul(0x02, a2) ^ GfMul(0x03, a3)); s[idx + 3] = (byte)(GfMul(0x03, a0) ^ a1 ^ a2 ^ GfMul(0x02, a3)); } } private void InvMixColumns(byte[] s) { for (int c = 0; c < 4; c++) { int idx = c * 4; byte a0 = s[idx], a1 = s[idx + 1], a2 = s[idx + 2], a3 = s[idx + 3]; s[idx] = (byte)(GfMul(0x0E,a0) ^ GfMul(0x0B,a1) ^ GfMul(0x0D,a2) ^ GfMul(0x09,a3)); s[idx + 1] = (byte)(GfMul(0x09,a0) ^ GfMul(0x0E,a1) ^ GfMul(0x0B,a2) ^ GfMul(0x0D,a3)); s[idx + 2] = (byte)(GfMul(0x0D,a0) ^ GfMul(0x09,a1) ^ GfMul(0x0E,a2) ^ GfMul(0x0B,a3)); s[idx + 3] = (byte)(GfMul(0x0B,a0) ^ GfMul(0x0D,a1) ^ GfMul(0x09,a2) ^ GfMul(0x0E,a3)); } } private void AddRoundKey(byte[] state, int round) { byte[] rk = _roundKeys[round]; for (int i = 0; i < 16; i++) state[i] ^= rk[i]; } #endregion /// <summary> /// 加密单个16字节分组 /// </summary> /// <param name="block">输入16字节明文分组</param> /// <returns>16字节密文分组</returns> public byte[] EncryptBlock(byte[] block) { if (block.Length != 16) throw new ArgumentException("仅支持16字节分组"); byte[] state = (byte[])block.Clone(); AddRoundKey(state, 0); for (int r = 1; r < _Nr; r++) { SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state, r); } // 最后一轮无MixColumns SubBytes(state); ShiftRows(state); AddRoundKey(state, _Nr); return state; } /// <summary> /// 解密单个16字节分组 /// </summary> /// <param name="block">输入16字节密文分组</param> /// <returns>16字节明文分组</returns> public byte[] DecryptBlock(byte[] block) { if (block.Length != 16) throw new ArgumentException("仅支持16字节分组"); byte[] state = (byte[])block.Clone(); AddRoundKey(state, _Nr); InvShiftRows(state); InvSubBytes(state); for (int r = _Nr - 1; r >= 1; r--) { AddRoundKey(state, r); InvMixColumns(state); InvShiftRows(state); InvSubBytes(state); } AddRoundKey(state, 0); return state; } // ========测试示例======== public static void TestDemo() { // AES128测试向量 NIST标准测试数据 byte[] key = {0x2b,0x7e,0x15,0x16,0x28,0xae,0xd2,0xa6,0xab,0xf7,0x15,0x88,0x09,0xcf,0x4f,0x3c}; byte[] plain = {0x32,0x43,0xf6,0xa8,0x88,0x5a,0x30,0x8d,0x31,0x31,0x98,0xa2,0xe0,0x37,0x07,0x34}; AesManual aes = new AesManual(key); byte[] cipher = aes.EncryptBlock(plain); Console.WriteLine("密文:"+BitConverter.ToString(cipher)); // 预期密文: 39-25-84-1D-02-DB-94-71-32-68-8E-27-F4-48-44-3B byte[] recover = aes.DecryptBlock(cipher); Console.WriteLine("解密明文:"+BitConverter.ToString(recover)); } }

使用说明

  • 该代码实现原始 AES 分组核心,等价底层密码原语;
  • 不包含填充、工作模式(CBC/GCM)。工程不能直接 ECB 加密长文本;
  • 测试向量使用 FIPS197 官方标准向量,可直接调用AesManual.TestDemo()验证正确性;
  • 完全无 System.Security.Cryptography 内置 AES,全部变换手写实现。

AES 算法优缺点分析


优点

安全强度极高

AES(Advanced Encryption Standard)采用 Rijndael 密码结构,经过全球密码学家20余年持续分析,至今未发现可行密码学破解方案。即使使用最强大的超级计算机进行暴力破解,对128位密钥也需要约次尝试,以当前计算能力需要数十亿年才能完成。美国国家安全局(NSA)已批准AES用于最高机密信息保护(TOP SECRET级别)。

优异的实现性能

AES算法结构设计优雅,仅使用代换-置换网络(SPN)和有限域运算,运算过程简单高效:

  • 软件实现:单核CPU可实现每秒数百MB的加密速度
  • 硬件加速:支持Intel/AMD的AES-NI指令集(如VAES指令),性能提升5-10倍
  • 专用芯片:ASIC实现可达到100Gbps以上的吞吐量
开放标准

AES由NIST于2001年正式发布为FIPS 197标准,具有:

  • 完全公开的算法细节
  • 无专利限制,可自由使用
  • 跨平台兼容性,Windows/Linux/嵌入式系统统一实现
  • 全球标准化支持,包括ISO/IEC 18033-3等国际标准
资源效率

典型实现仅需:

  • 2-8KB代码空间
  • 数百字节RAM
  • 适用于STM32等MCU和ESP8266等物联网设备
  • 低功耗特性适合电池供电场景
灵活的密钥配置

提供三种密钥长度选择:

  • AES-128:平衡安全与性能(推荐默认选择)
  • AES-192:中等提升安全强度
  • AES-256:最高安全级别(金融机构、政府使用)

缺点

分组密码固有局限

作为分组密码:

  • 固定16字节分组大小
  • 加密前必须进行填充(如PKCS#7)
  • 需要配合工作模式(如CBC/GCM)才能处理长数据
  • 常见错误:直接使用原始AES加密(实际应使用AES-CBC等完整方案)
ECB模式安全隐患

电子密码本(ECB)模式问题:

  • 相同明文块产生相同密文块
  • 泄露数据模式信息(如图像轮廓可见)
  • 典型案例:2013年某支付系统因ECB模式导致信用卡数据泄露
  • 安全建议:永远不要在生产环境使用AES-ECB
密钥分发挑战

对称加密的固有难题:

  • 双方必须预先共享相同密钥
  • 安全交换密钥依赖非对称加密(如RSA密钥交换)
  • 大规模部署时密钥管理复杂
  • 对比:非对称加密可直接用公钥加密
缺乏完整性保护

基本AES加密:

  • 仅提供机密性保障
  • 不能检测密文篡改(如比特翻转攻击)
  • 解决方案:
    • 组合模式:AES-CBC + HMAC(加密然后认证)
    • 认证加密:直接使用AES-GCM等提供机密性+完整性

适用场景


推荐场景

文件本地加密/磁盘全盘加密(如 BitLocker)
  • 细节说明:对称加密算法(如 AES)适用于本地文件或磁盘的高效加密,确保存储数据的安全性。例如,BitLocker 采用 AES-CBC 或 AES-XTS 模式实现全盘加密,防止操作系统和用户数据因物理访问而泄露。
  • 示例:企业为员工笔记本电脑启用 BitLocker,即使设备丢失,硬盘数据仍无法被未授权访问。
TLS/HTTPS 内部流量对称加密(握手后使用 AES-GCM)
  • 细节说明:在 TLS 协议中,握手阶段通过非对称加密(如 RSA/ECC)协商对称密钥,后续通信则采用 AES-GCM 等高效对称算法加密数据。
  • 应用场景:Web 服务器与客户端之间的 HTTPS 通信,或微服务内部 API 调用(如 Kubernetes 集群内服务间的 TLS 加密)。
物联网设备通信/嵌入式数据加密
  • 细节说明:资源有限的物联网设备(如传感器、智能家居设备)通常使用轻量级对称加密(如 ChaCha20-Poly1305)保护通信数据。
  • 示例:智能门锁与手机 App 之间的指令传输采用 AES-128-CCM 加密,确保指令不被篡改。
数据库敏感字段加密
  • 细节说明:对称加密可用于加密数据库中的敏感字段(如用户密码、身份证号),通常结合密钥管理系统(如 AWS KMS)管理密钥。
  • 步骤:应用程序写入数据库前使用 AES-256 加密数据,读取时再解密,避免数据库泄露导致明文数据暴露。
移动端本地隐私数据存储
  • 细节说明:移动应用通过对称加密(如 Android Jetpack Security 库)保护本地存储的隐私数据(如用户 token、缓存文件)。
  • 示例:金融类 App 加密存储用户交易记录至 SQLite 数据库,密钥由设备安全芯片(如 TEE)保护。

不适合场景

直接公网传输对称密钥
  • 原因:对称密钥需通过安全信道分发(如 RSA 密钥封装或 DH 密钥交换),直接传输易被中间人攻击截获。
  • 替代方案:TLS 协议中先用 RSA/ECC 协商会话密钥,再用 AES 加密数据。
需要同时提供加密 + 签名且无额外 MAC
  • 原因:传统加密模式(如 AES-CBC)需额外计算 HMAC 以确保完整性,而 AES-GCM 已集成认证功能,效率更高。
  • 示例:若需签名功能但强制使用 CBC,需额外实现 HMAC-SHA256,增加复杂度。
追求极简无 IV 的场景
  • 原因:CBC 等模式必须使用初始化向量(IV)避免相同明文生成相同密文,而 CTR 模式可通过计数器实现类似效果。
  • 替代方案:选择 AES-CTR 模式,或使用确定性加密(如 AES-SIV)但需权衡安全性。

补充说明

  • 性能对比:在 x86 硬件上,AES-NI 指令集可将 AES-GCM 加速至 10Gbps,而 RSA-2048 解密仅支持约 0.1Gbps。
  • 合规要求:金融行业(如 PCI-DSS)可能强制要求使用 AES-256 或国密 SM4 算法。

总结


AES 是现代密码学主流对称分组加密标准,依靠混淆(SubBytes)+ 扩散(ShiftRows、MixColumns)双重机制实现高安全性。算法本身数学结构清晰,易于编码实现。

工程重要忠告:

  • 业务开发不要手写 AES 底层代码(本文代码仅用于学习原理!生产环境务必使用System.Security.Cryptography.Aes内置类,内置 AES-NI 加速、经过安全审计);
  • 生产禁止 ECB 模式;优先AES-GCM(认证加密,同时加密 + 防篡改)
  • 密钥妥善保管,禁止硬编码;IV 必须随机且不可重复。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询