AES(Advanced Encryption Standard)是当前最广泛使用的对称分组加密算法,由美国国家标准与技术研究院(NIST)于 2001 年正式发布。AES 以其卓越的安全性和高效的性能,成为现代加密协议中的核心组件,广泛应用于 TLS、IPsec、Wi-Fi 等众多安全通信协议中。

在本章中,我们将深入剖析 AES 加密算法的核心原理与实现细节。我们将从分组密码的基础特性出发,逐步拆解 AES 的 10、12 或 14 轮加密过程,详细分析其状态矩阵的构造、每轮的操作步骤(SubBytes、ShiftRows、MixColumns、AddRoundKey)以及最终的密钥扩展机制,全面理解 AES 的加密过程和安全性分析。

AES 加密算法 🫡

AES 块长度为 128 位,密钥长度可以是 128 位、192 位或 256 位,分别对应 10、12 或 14 轮加密过程,明文按照 128 位分组,加密得到 128 位密文。

AES 算法不同于 DES 的 Feistel 结构,而是采用了 Substitution-Permutation Network(SPN)结构,直接使用四个 “算法层” 对整个数据块进行变换。
AES 加密算法示意图

密钥扩展(Key Expansion)

标准的 128 位 AES 密钥对应由 11 组子密钥,分别在一开始和每一轮参与密钥加法层的运算。

子密钥的生成是一列为单位的,一列是 4 字节(32 位),每一轮需要 4 列(128 位)的子密钥。对于 128 位密钥,原始密钥占用前 4 列,后续的 7 组子密钥通过迭代计算得到,储存在 $w[0..43]$ 的子密钥数组中。

具体来说,子密钥的生成过程如下:

  1. 将原始密钥分成 4 列,每列 4 字节,填充到子密钥数组的前 4 列。
  2. 从第 5 列开始,依次计算每一列的子密钥:
    • 如果当前列索引 $i$ 是 4 的倍数,则进行 G 函数特殊处理,然后将前一列的子密钥与当前列的前一列的子密钥进行异或运算。
    • 否则,直接将前一列的子密钥与当前列的前一列的子密钥进行异或运算。
      密钥扩展算法

G 函数是为了增加密钥扩展的非线性和消除 AES 中的对称性(轮常量的参与),进行如下操作:

  1. 将输入的 4 字节进行循环左移(RotWord),即将第一个字节移到最后。
  2. 将每个字节通过 S 盒进行字节替代(SubWord),得到一个新的 4 字节。
  3. 将第一个字节与一个轮常量(Rcon)进行异或运算,得到最终的 4 字节输出。
    密钥扩展中的 G 函数
@staticmethod
defkey_expansion(k,r):
 #fips-197 Figure 11
    k = list(k) # in case k is bytes
    Nk = len(k) // 4
    subkeys=[k[i:i+4]foriinrange(0,4*Nk,4*Nk,4)]

    i = Nk
    while i < 4*(r+1):
        t=subkeys[i-1]
    if i % Nk == 0:
        tt=AES.sub_word(AES.rot_word(t))
        t=[tt[0] ^AES.Rcon[i // Nk]] + tt[1:]
    elif Nk > 6 and i % Nk == 4:
        t = AES.sub_word(t)
    subkeys.append(AES.word_xor(subkeys[i - Nk], t))
    i += 1
return subkeys

密钥加密层(Key Additon Layer)

AES 的内部状态是由一个 4x4 的字节矩阵(State)构成的,每个元素是一个字节(8 位)。输入的 16 字节按照如下方式排列:

将排列好的明文和子密钥逐字节异或,并将结果输出:

@staticmethod
def add_round_key(s, k):
    for i in range(16):
        s[i] ^= k[i]

字节替代层(Substitution Layer)

让输入的每一个字节,通过 S 盒代换(映射)到另外一个字节此处的 S 盒是可以经过每种方式计算出来的,也可以直接使用计算好的进行代换。这个比较基础,我就不展开了。

@staticmethod
def sub_bytes(s):
    for i in range(16):
        s[i] = AES.Sbox[s[i]]

扩散层(Diffusion Layer)

扩散层包括行移位层(Shift Rows层)和列混淆层(Mix Column层)。行位移和列混淆都是 AES 的混淆层,目的是为了将单个字节的变换扩散到整个状态矩阵中,增加算法的安全性。

行移位层:对于 4x4 的矩阵,在做行移位时,第一行保持不变,第二行往左移动一格,第三行左移两格,第四行左移三格。

列混淆层:将整个字节矩阵乘上一个列混淆矩阵(有限域上的矩阵运算),相当于正常矩阵运算结果取模。

@staticmethod
def shift_rows(s):
    s[i] = list(s[0::5] + s[4::5] + s[3:4:5] + s[8::5] + s[2:8:5] +s[12::5] + s[1:12:5])

@staticmethod
def mix_columns(s):
    def xtime(a):
        return((((a << 1) ^ 0x1B) & 0XFF) if (a & 0x80) else (a <<1))

    for i in range(4):
        t=s[4*i] s[4*i+1] ^s[4*i+2]^s[4*i+3]
        u=s[4*i]
        s[4*i] ^=t xtime(s[4*i] ^ s[4*i+1])
        s[4*i+1] ^= t xtime(s[4*i+1] ^ s[4*i+2])
        s[4*i+2] ^= t xtime(s[4*i+2] ^ s[4*i+3])
        s[4*i+3] ~ t xtime(s[4*i+3] ^ u)

轮加密过程

这里就是一开始的示意图了,不过要注意的是最后一轮没有 Mix Column 层。

# start
r=0
k_sch=self.subkeys[0] + self.subkeys[1] + self.subkeys[2] + self.subkeys[3]

state = list(msg)
AES.add_round_key(state,k_sch)

# round 1~rounds'-1
for r in range(1,self.rounds):
    AES.sub_bytes(state)
    AES.shift_rows(state)
    AES.mix_columns(state)
    k_sch=self.subkeys[4*r] + self.subkeys[4*r+1] + self.subkeys[4*r+2] + self.subkeys[4*r+3]
    AES.add_round_key(state,k_sch)

# the last round
r = self.rounds
AES.sub_bytes(state)
AES.shift_rows(state)
k_sch=self.subkeys[-4] + self.subkeys[-3] +self.subkeys[-2] + self.subkeys[-1]
AES.add_round_key(state,k_sch)

# convert 'list'stateto'bytes'output
output=bytes(state)
return output

AES 加解密 😆

AES 的加密和解密过程非常相似,主要区别在于解密过程中需要使用逆向的操作顺序和逆向的 S 盒、逆向的行移位以及逆向的列混淆。由于 AES 是一个 SPN 结构的算法,解密过程需要对每一轮的操作进行逆向处理,这里就不展开了,感兴趣的同学可以参考 AES 的官方文档或者相关的加密算法教材。

# 我们可以使用 Python 的 Crypto 库来实现 AES 的加密和解密,以下是一个简单的示例:
from Crypto.Cipher import AES

key = b""
aes = AES.new(key,mode=AES.MODE_ECB)
plaintext = b""

ciphertext = aes.encrypt(plaintext)
aes.decrypt(ciphertext)

上一章:加解密模式分析 - DES 加密算法 👈
下一章:加解密模式分析 - 分组模式解析 👈
回到开始:关于我 👈

相关链接: