首页/我的作品/密码学/5.3 AES深度图解:字节替换、行移位、列混合
密码学:守护数字世界的秘密

5.3 AES深度图解:字节替换、行移位、列混合

第 29 / 78 篇 · Crazy Boy

AES(高级加密标准)是一种分组密码,它把明文分成固定长度的块(128位,即16字节),然后通过多轮复杂的变换,把每一块加密成密文。AES的轮数取决于密钥长度:128位密钥需要10轮,192位需要12轮,256位需要14轮。每一轮(除了最后一轮)都包含四个步骤:字节替换、行移位、列混合、轮密钥加。最后一轮省略列混合。

这四步操作像一台精密的机器,把数据反复“搅拌”,直到无法辨认出任何原始特征。下面我们用图解的方式,一步步拆解AES的加密过程。

AES的状态矩阵

在加密开始前,128位的明文被排列成一个4×4的矩阵,每个元素是一个字节(8位)。这个矩阵称为状态矩阵(State)。例如,明文的前4个字节放在第一列,接着4个字节放在第二列,以此类推:

+----+----+----+----+
| a0 | a4 | a8 | a12| ← 每个格子是一个字节
+----+----+----+----+
| a1 | a5 | a9 | a13|
+----+----+----+----+
| a2 | a6 | a10| a14|
+----+----+----+----+
| a3 | a7 | a11| a15|
+----+----+----+----+

注意:AES是按列填充的,这一点和通常的按行阅读不同,但理解这一点对后面的行移位很重要。

第一步:字节替换(SubBytes)

作用:对每个字节独立进行非线性替换,增加混淆性。

AES有一个固定的替换表,称为S盒(S-box)。它是一个16×16的表格,每个字节的高4位作为行索引,低4位作为列索引,从表中取出一个新的字节。例如,输入字节为0x53,高4位是5,低4位是3,查表得到0xED。

S盒的设计非常巧妙,它具备非线性特性,并且能抵抗差分密码分析和线性密码分析。更重要的是,S盒是可逆的——解密时使用逆S盒。

图解:可以把状态矩阵的每个格子都看作一个小盒子,里面装着一个字节。字节替换就是用S盒把每个盒子里的内容换成另一个字节。

原始矩阵           S盒变换后
+---+---+---+---+ +---+---+---+---+
| a0| a4| a8|a12| → |b0| b4| b8|b12|
+---+---+---+---+ +---+---+---+---+
| a1| a5| a9|a13| → |b1| b5| b9|b13|
+---+---+---+---+ +---+---+---+---+
| a2| a6|a10|a14| → |b2| b6|b10|b14|
+---+---+---+---+ +---+---+---+---+
| a3| a7|a11|a15| → |b3| b7|b11|b15|
+---+---+---+---+ +---+---+---+---+

第二步:行移位(ShiftRows)

作用:对矩阵的每一行进行循环左移,打乱字节的顺序,实现扩散。

规则如下:

  • 第0行(第一行)不移位。
  • 第1行向左循环移1个字节。
  • 第2行向左循环移2个字节。
  • 第3行向左循环移3个字节。

用矩阵表示更加直观。假设经过字节替换后的状态矩阵为:

b0  b4  b8  b12
b1 b5 b9 b13
b2 b6 b10 b14
b3 b7 b11 b15

行移位后变为:

b0  b4  b8  b12     ← 第0行不变
b5 b9 b13 b1 ← 第1行左移1位(b1移到末尾)
b10 b14 b2 b6 ← 第2行左移2位(b2,b6移到前面)
b15 b3 b7 b11 ← 第3行左移3位(b3,b7,b11移到前面)

这个操作的目的是让每一列的数据分散到不同列中,为下一步的列混合做准备。

第三步:列混合(MixColumns)

作用:对每一列的四个字节进行线性变换,进一步混合数据。

列混合是把每一列看作一个多项式,并与一个固定多项式相乘,然后取模。但在实际实现中,它是通过矩阵乘法完成的。对于每一列,将四个字节视为一个向量,左乘一个固定的4×4矩阵(在GF(2⁸)有限域中):

[ s0']   [ 2 3 1 1 ] [ s0 ]
[ s1'] = [ 1 2 3 1 ] [ s1 ]
[ s2'] [ 1 1 2 3 ] [ s2 ]
[ s3'] [ 3 1 1 2 ] [ s3 ]

这里的乘法和加法都是在有限域GF(2⁸)中定义的,不是普通的整数运算。有限域运算听起来复杂,但硬件实现时可以用查表完成,软件上也有快速算法。

直观理解:列混合就像把一列里的四个字节搅在一起,每个输出字节都依赖于输入列的所有四个字节。经过这一步,矩阵的扩散性大大增强——改变任何一个字节,都会影响到整列的所有字节。

例如,对于第一列(b0, b5, b10, b15),经过列混合后得到新的四个字节(c0, c5, c10, c15)。其他列类似。

图解:把列混合想象成一个搅拌机,每一列的四个字节进去,出来四个新字节,每个新字节都是由原来的四个字节混合而成。

第四步:轮密钥加(AddRoundKey)

作用:将状态矩阵与当前轮的轮密钥进行异或(XOR)。

轮密钥是由初始密钥通过密钥扩展算法生成的,每一轮使用不同的128位轮密钥。轮密钥也排列成4×4的矩阵,与状态矩阵逐字节异或。

异或是简单的比特运算:两个比特相同得0,不同得1。这一步是给状态矩阵加上“密钥的味道”。

一轮完整的AES加密(图解)

我们可以用一张流程图概括一轮AES加密的四个步骤:

┌─────────────────┐
│ 状态矩阵 │
│ (16字节) │
└────────┬────────┘
↓
┌─────────────────┐
│ 1. 字节替换 │ ← 每个字节查S盒
│ (SubBytes) │
└────────┬────────┘
↓
┌─────────────────┐
│ 2. 行移位 │ ← 每行循环左移
│ (ShiftRows) │
└────────┬────────┘
↓
┌─────────────────┐
│ 3. 列混合 │ ← 每列矩阵乘
│ (MixColumns) │
└────────┬────────┘
↓
┌─────────────────┐
│ 4. 轮密钥加 │ ← 与轮密钥异或
│ (AddRoundKey) │
└────────┬────────┘
↓
┌─────────────────┐
│ 下一轮的状态 │
└─────────────────┘

对于128位密钥,这样的过程重复10轮,但最后一轮不执行列混合。初始状态在加密开始前会先与初始轮密钥进行一次异或(称为初始轮密钥加)。

一个具体例子(简化)

假设我们有一个极简的状态矩阵(仅用于演示,实际AES的每个字节是8位,这里用数字代替):

原始矩阵:

[ 1, 2, 3, 4 ]
[ 5, 6, 7, 8 ]
[ 9,10,11,12]
[13,14,15,16]

  1. 字节替换:每个数字按S盒(假设)替换成另一个数字(实际S盒不是简单的线性关系):

    [ 11, 22, 33, 44 ]
    [ 55, 66, 77, 88 ]
    [ 99, 10, 11, 12 ]
    [ 13, 14, 15, 16 ]
  2. 行移位:

    • 第0行不变:[11,22,33,44]
    • 第1行左移1位:[66,77,88,55]
    • 第2行左移2位:[11,12,99,10]
    • 第3行左移3位:[16,13,14,15]
      得到:
      [11,22,33,44]
      [66,77,88,55]
      [11,12,99,10]
      [16,13,14,15]
  3. 列混合:对每一列进行矩阵乘(这里仅示意结果,实际计算复杂):
    假设第一列(11,66,11,16)变换后得到(23,45,67,89)。其他列类似。

  4. 轮密钥加:与轮密钥异或,得到最终的状态矩阵。

这个过程反复进行,直到最后一轮。

为什么AES安全?

AES的安全性来自三个层面的设计:

  • 混淆:字节替换引入了非线性,使得明文和密文之间的关系极其复杂,无法用简单的线性方程描述。
  • 扩散:行移位和列混合让每一个明文字节的影响迅速扩散到整个密文块——改变一个明文字节,大约一半的密文字节会发生变化(这被称为“雪崩效应”)。
  • 密钥的参与:每一轮都加入不同的轮密钥,使得即使知道算法,没有密钥也无法还原。

经过10轮这样的搅拌,密文已经完全失去了明文的任何统计特征。时至今日,除了暴力穷举(256位AES的密钥空间大到无法实现),还没有任何有效的方法能攻破AES。

下一节,我们将讨论如何把AES应用到实际中——当数据长度超过128位时,我们需要选择一种工作模式。