当前位置: 首页 > news >正文

初识AES

AES(1)

零、 前言

​ 朝花夕拾杯中酒。从CTF开始攻击CBC模式下的加密漏洞,再到第四学期的《密码学基础》课程,时至今日,《密码工程》课程的需要以及自己对于对称密码的兴趣驱使,下定决心写下这篇笔记记录自己对于AES的认识以及学习。这篇文章工期拖得比较长,一方面是因为自己的拖延症,二是针对于密码学的工程应用以及编码硬实力的不足,自己翻阅了很多师傅的相关资料,也翻阅了部分教材和相关资料,会在结尾进行指明。由于作者本人的实力与阅历不足,本文在内容、专业知识、排版以及语法表达上或多或少存在错误,请读者仔细辨别并积极指出交流。很庆幸完成了这篇笔记。😊😊

一、AES背景介绍

199719971997999月,美国国家标准与技术研究院NISTNISTNIST公开征集新的高级加密标准(AdvancedEncryptionStandard,AES)(Advanced Encryption Standard, AES)(AdvancedEncryptionStandard,AES),取代DESDESDES算法.199819981998666月,提交过程截至,共收到212121个算法.经过简单筛选,199819981998888月,公开来自121212个国家的151515个候选算法进入第一轮.199919991999888月,555个候选算法进入第二轮,分别是MARSMARSMARSRC6RC6RC6RijndaelRijndaelRijndaelSerpentSerpentSerpentTwofishTwofishTwofish算法.200020002000101010月,由比利时密码学家DaemenDaemenDaemenRijmenRijmenRijmen共同设计的RijndaelRijndaelRijndael算法获胜,经过讨论和规范后,于200120012001121212月作为NIPS197NIPS 197NIPS197发布,成为高级加密标准AESAESAES

AESAESAES算法采用SPNSPNSPN结构,分组长度为128−bit(16−Byte)128-bit(16-Byte)128bit(16Byte).将输入按照字节划分,从000151515标号,并按照下图所示的顺序排列

04812
15913
261014
371115

AESAESAES算法共有三个版本,对应不同的密钥长度和安全强度:当密钥长度为128−bit128-bit128bit时,迭代轮数为101010轮;当密钥长度为192−bit192-bit192bit时,迭代轮数为121212轮;当密钥长度为256−bit256-bit256bit时,迭代轮数为141414轮,分别标记为AES−128/192/256AES-128/192/256AES128/192/256.

​ 本文将介绍AESAESAES的内部结构、AESAESAES加密、解密算法的各种编程语言实现、AESAESAES的各种工作模式、AESAESAES的优化策略以及优化结果展示。

二、内部结构

AESAESAES为分组对称密码,针对于其内部结构而言,每轮加密/解密由(逆)字节代换、(逆)行移位、(逆)列混合、轮密钥加四部分组成。所谓分组,即将需要加密的明文messagemessagemessage128−bit128-bit128bit分成组别,每一组都经过10/12/1410/12/1410/12/14轮上述的四部分操作进行加密。假设message=b′abcdefghijklmnopqrstuvwxyz′message = b'abcdefghijklmnopqrstuvwxyz'message=babcdefghijklmnopqrstuvwxyz,那么block0=b′abcdefghijklmnop′,bloc1=′qrstuvwxyz′block0=b'abcdefghijklmnop',bloc1='qrstuvwxyz'block0=babcdefghijklmnop,bloc1=qrstuvwxyz,而block1block1block1由于内容并不够128−bit128-bit128bit,所以我们需要进行填充,即block1=b"qrstuvwxyz\x00\x00\x00\x00\x00\x00"。注意,AESAESAES使用的四个组件都是可逆的,针对于解密而言,就是高度对称下的逆向组件的使用,接下来我们将从加密和解密中所用到的四个组件进行详细介绍。

​ 为了方便AESAESAES的展示和实现,我们通过状态矩阵来展示一个分组的加密或解密的详细过程,例如block0block0block0会根据先列后行的顺序被分配到状态矩阵中进行后续的组件操作。

aeim
bfjn
cgko
dhlp

​ 针对于明文信息,我们需要按照字节对应为相应的ASCII码进行后的加密/解密操作。

0x610x650x690x73
0x620x660x700x74
0x630x670x710x75
0x640x680x720x76
1. 字节代换
字节代换

​ 所谓字节代换,其实就是一个查表操作,而这里的表,我们称之为S盒S盒S
AESAESAESS盒S盒S

行/列0123456789ABCDEF
00x630x7c0x770x7b0xf20x6b0x6f0xc50x300x010x670x2b0xfe0xd70xab0x76
10xca0x820xc90x7d0xfa0x590x470xf00xad0xd40xa20xaf0x9c0xa40x720xc0
20xb70xfd0x930x260x360x3f0xf70xcc0x340xa50xe50xf10x710xd80x310x15
30x040xc70x230xc30x180x960x050x9a0x070x120x800xe20xeb0x270xb20x75
40x090x830x2c0x1a0x1b0x6e0x5a0xa00x520x3b0xd60xb30x290xe30x2f0x84
50x530xd10x000xed0x200xfc0xb10x5b0x6a0xcb0xbe0x390x4a0x4c0x580xcf
60xd00xef0xaa0xfb0x430x4d0x330x850x450xf90x020x7f0x500x3c0x9f0xa8
70x510xa30x400x8f0x920x9d0x380xf50xbc0xb6,0xda0x210x100xff0xf30xd2
80xcd0x0c0x130xec0x5f0x970x440x170xc40xa70x7e0x3d0x640x5d0x190x73
90x600x810x4f0xdc0x220x2a0x900x880x460xee0xb80x140xde0x5e0x0b0xdb
A0xe00x320x3a0x0a0x490x060x240x5c0xc20xd30xac0x620x910x950xe40x78
B0xe70xc80x370x6d0x8d0xd50x4e0xa90x6c0x560xf40xea0x650x7a0xae0x08
C0xba0x780x250x2e0x1c0xa60xb40xc60xe80xdd0x740x1f0x4b0xbd0x8b0x8a
D0x700x3e0xb50x660x480a030xf60x0e0x610x350x570xb90x860xc10x1d0x9e
E0xe10xf80x980x110x690xd90x8e0x940x9b0x1e0x870xe90xce0x550x280xdf
F0x8c0xa10x890x0d0xbf0xe60x420x680x410x990x2d0x0f0xb00x540xbb0x16

​ 状态矩阵中的元素按照下面的方式映射为一个新的字节:把该字节的高444位作为行值。低444位作为列值,去除S盒S盒S或者逆S盒逆S盒S中对应的行的元素作为输出。例如,加密时,输出的字节S1=b′0x12′S1=b'0x12'S1=b0x12,则查S盒S盒S的第0x01行0x01行0x010x02列0x02列0x02,得到值0xc90xc90xc9,然后替换S1S1S1原有的0x120x120x120xc90xc90xc9

逆字节代换

​ 操作步骤与实现过程与S盒S盒S一直,是字节代换的逆操作,一般称之为逆S盒逆S盒S
AESAESAES逆S盒逆S盒S

行/列0123456789ABCDEF
00x520x090x6a0xd50x300x360xa50x380xbf0x400xa30x9e0x810xf30xd70xfb
10x7c0xe30x390x820x9b0x2f0xff0x870x340x8e0x430x440xc40xde0xe90xcb
20x540x7b0x940x320xa60xc20x230x3d0xee0x4c0x950x0b0x420xfa0xc30x4e
30x080x2e0xa10x660x280xd90x240xb20x760x5b0xa20x490x6d0x8b0xd10x25
40x720xf80xf60x640x860x680x980x160xd40xa40x5c0xcc0x5d0x650xb60x92
50x6c0x700x480x500xfd0xed0xb90xda0x5e0x150x460x570xa70x8d0x9d0x84
60x900xd80xab0x000x8c0xbc0xd30x0a0xf70xe40x580x050xb80xb30x450x06
70xd00x2c0x1e0x8f0xca0x3f0x0f0x020xc10xaf0xbd0x030x010x130x8a0x6b
80x3a0x910x110x410x4f0x670xdc0xea0x970xf20xcf0xce0xf00xb40xe60x73
90x960xac0x740x220xe70xad0x350x850xe20xf90x370xe80x1c0x750xdf0x6e
A0x470xf10x1a0x710x1d0x290xc50x890x6f0xb70x620x0e0xaa0x180xbe0x1b
B0xfc0x560x3e0x4b0xc60xd20x790x200x9a0xdb0xc00xfe0x780xcd0x5a0xf4
C0x1f0xdd0xa80x330x880x070xc70x310xb10x120x100x590x270x800xec0x5f
D0x600x510x7f0xa90x190xb50x4a0x0d0x2d0xe50x7a0x9f0x930xc90x9c0xef
E0xa00xe00x3b0x4d0xae0x2a0xf50xb00xc80xeb0xbb0x3c0x830x530x990x61
F0x170x2b0x040x7e0xba0x770xd60x260xe10x690x140x630x550x210x0c0x7d
2. 行移位
行移位

​ 行移位是一个简单的做循环移位操作,当密钥长度为128−bit128-bit128bit时,状态矩阵的第一行循环左移0−Byte0-Byte0Byte,第二行循环左移1−Byte1-Byte1Byte,第三行循环左移2−Byte2-Byte2Byte,第四行循环左移3−Byte3-Byte3Byte
设行移位前的状态矩阵为:

S0S4S8SC
S1S5S9SD
S2S6SASE
S3S7SBSF

行移位后的状态矩阵为:

S0S4S8SC
S5S9SDS1
SASES2S6
SFS3S7SB
逆行移位

​ 行移位的逆变换就是将状态矩阵中的每一行执行相反方向的循环移位即可,例如AES−128AES-128AES128中的状态矩阵的第一行循环右移0−Byte0-Byte0Byte,第二行循环右移1−Byte1-Byte1Byte,第三行循环右移2−Byte2-Byte2Byte,第四行循环右移3−Byte3-Byte3Byte

3. 列混合
列变换 – 矩阵乘法

​ 列混合变换是通过在GF(28)GF(2^8)GF(28)上的矩阵相乘来实现的,经过行移位后的状态矩阵与固定的矩阵相乘,得到混淆后的状态矩阵。其中,加法运算a+b=a⊕ba+b=a \oplus ba+b=ab,乘法运算a⋅ba \cdot bab在模不可约多项式x8+x4+x3+x+1x ^ 8 + x ^ 4 + x ^ 3 + x + 1x8+x4+x3+x+1.
[s0,0′s0,1′s0,2′s0,3′s1,0′s1,1′s1,2′s1,3′s2,0′s2,1′s2,2′s2,3′s3,0′s3,1′s3,2′s3,3′]=[02030101010203010101020303010102][s0,0s0,1s0,2s0,3s1,0s1,1s1,2s1,3s2,0s2,1s2,2s2,3s3,0s3,1s3,2s3,3]\begin{bmatrix} s'_{0,0} & s'_{0,1} & s'_{0,2} & s'_{0,3} \\ s'_{1,0} & s'_{1,1} & s'_{1,2} & s'_{1,3} \\ s'_{2,0} & s'_{2,1} & s'_{2,2} & s'_{2,3} \\ s'_{3,0} & s'_{3,1} & s'_{3,2} & s'_{3,3} \end{bmatrix} = \begin{bmatrix} 02 & 03 & 01 & 01 \\ 01 & 02 & 03 & 01 \\ 01 & 01 & 02 & 03 \\ 03 & 01 & 01 & 02 \end{bmatrix} \begin{bmatrix} s_{0,0} & s_{0,1} & s_{0,2} & s_{0,3} \\ s_{1,0} & s_{1,1} & s_{1,2} & s_{1,3} \\ s_{2,0} & s_{2,1} & s_{2,2} & s_{2,3} \\ s_{3,0} & s_{3,1} & s_{3,2} & s_{3,3} \end{bmatrix} s0,0s1,0s2,0s3,0s0,1s1,1s2,1s3,1s0,2s1,2s2,2s3,2s0,3s1,3s2,3s3,3=02010103030201010103020101010302s0,0s1,0s2,0s3,0s0,1s1,1s2,1s3,1s0,2s1,2s2,2s3,2s0,3s1,3s2,3s3,3

列变换 – GF(0xff)乘法

​ 这里介绍一下在GF(28)GF(2^8)GF(28)中的乘法运算以及加法运算,其中加法运算就是按位异或的运算,而乘法相对来说有些复杂。首先,在GF(28)GF(2 ^ 8)GF(28)中每个元素都可以表示为8次二进制多项式8次二进制多项式8次二进制多项式,形式为:a(x)=a7x7+a6x6+a5x5+a4x4+a3x3+a2x2+a1x+1a(x) = a_7x^7+a_6x^6+a_5x^5+a_4x^4+a_3x^3+a_2x^2+a_1x+1a(x)=a7x7+a6x6+a5x5+a4x4+a3x3+a2x2+a1x+1,其中ai∈{0,1}a_i\in \{0,1\}ai{0,1}(系数遵循$GF(2)运算规则:0+0=0,0+1=1,1+1=0,0⋅0=0,0⋅1=0,1⋅1=10+0=0,0+1=1,1+1=0,0\cdot0=0,0\cdot1=0,1\cdot1=10+0=0,0+1=1,1+1=0,00=0,01=0,11=1.

​ 对于两个 GF(28){GF}(2^8)GF(28) 元素 A(x)=∑i=07aixiA(x) = \sum_{i=0}^7 a_i x^iA(x)=i=07aixiB(x)=∑i=07bixiB(x) = \sum_{i=0}^7 b_i x^iB(x)=i=07bixi,先执行普通多项式乘法(系数运算在 GF(2){GF}(2)GF(2) 下进行)。乘法结果是次数不超过 15 的多项式:C(x)=A(x)⋅B(x)=∑k=015ckxkC(x) = A(x) \cdot B(x) = \sum_{k=0}^{15} c_k x^kC(x)=A(x)B(x)=k=015ckxk.其中 ck=(∑i+j=k0≤i,j≤7aibj)mod2c_k = \left( \sum_{\substack{i+j=k \\ 0 \leq i,j \leq 7}} a_i b_j \right) \mod 2ck=(i+j=k0i,j7aibj)mod2(对每个次数 kkk,合并所有 i+j=ki+j=ki+j=k 的项,系数模 222)。

​ 由于最终结果需要属于GF(28)GF(2^8)GF(28),需将C(x)C(x)C(x)m(x)=x8+x4+x3+x+1m(x)=x^8+x^4+x^3+x+1m(x)=x8+x4+x3+x+1取模,得到次数<8的余式。利用模运算性质:因为m(x)≡0(modm(x))m(x)\equiv 0 (mod\ m(x))m(x)0(mod m(x)),所以x8≡x4+x3+x+1(modm(x))GF(2)x^8\equiv x^4 + x^ 3 + x + 1 (mod \ m(x))\ \ \ GF(2)x8x4+x3+x+1(mod m(x))   GF(2)−1=1-1=11=1,故x8=−(x4+x3+x+1)equivx4+x3+x+1)x ^ 8 = -(x^4+x^3+x+1) \ equiv x ^ 4 + x ^ 3 + x + 1)x8=(x4+x3+x+1) equivx4+x3+x+1)。对于更高次幂(如xk,k≥8x^k,k≥8xk,k8),可以通过反复替换x8x^8x8x4+x3+x+1x^4+x^3+x+1x4+x3+x+1来降低次数。例如:

  • x9≡x⋅x8≡x⋅(x4+x3+x+1)=x5+x4+x2+xx ^ 9 \equiv x \cdot x ^ 8 \equiv x \cdot (x ^ 4 + x ^ 3 + x + 1) = x ^ 5 + x ^ 4 + x ^ 2 + xx9xx8x(x4+x3+x+1)=x5+x4+x2+x
  • x10≡x⋅x9≡x⋅(x5+x4+x2+x)=x6+x5+x3+x2x ^ {10} \equiv x \cdot x ^ 9 \equiv x \cdot (x ^ 5 + x ^ 4 + x ^ 2 + x) = x ^ 6 + x ^ 5 + x ^ 3 + x ^ 2x10xx9x(x5+x4+x2+x)=x6+x5+x3+x2
  • 以此类推,直到所有次数≥8≥88的项都被替换为次数<8<88的项。

​ 因此,列变换的结果矩阵中的每一列元素与原矩阵的元素之间的关系如下:
s0,j′=(2⋅s0,j)⊕(3⋅s1,j)⊕s2,j⊕s3,js1,j′=s0,j⊕(2⋅s1,j)⊕(3⋅s2,j)⊕s3,js2,j′=s0,j⊕s1,j⊕(2⋅s2,j)⊕(3⋅s3,j)s3,j′=(3⋅s0,j)⊕s1,j⊕s2,j⊕(2⋅s3,j)\begin{align*} s'_{0,j} &= (2 \cdot s_{0,j}) \oplus (3 \cdot s_{1,j}) \oplus s_{2,j} \oplus s_{3,j} \\ s'_{1,j} &= s_{0,j} \oplus (2 \cdot s_{1,j}) \oplus (3 \cdot s_{2,j}) \oplus s_{3,j} \\ s'_{2,j} &= s_{0,j} \oplus s_{1,j} \oplus (2 \cdot s_{2,j}) \oplus (3 \cdot s_{3,j}) \\ s'_{3,j} &= (3 \cdot s_{0,j}) \oplus s_{1,j} \oplus s_{2,j} \oplus (2 \cdot s_{3,j}) \end{align*} s0,js1,js2,js3,j=(2s0,j)(3s1,j)s2,js3,j=s0,j(2s1,j)(3s2,j)s3,j=s0,js1,j(2s2,j)(3s3,j)=(3s0,j)s1,js2,j(2s3,j)
AESAESAES中我们采用位操作快速约简:若乘法结果的多项式含xk(k≥8)x^k(k≥8)xk(k8),则将结果与m(x)m(x)m(x)左移k−8k-8k8位的多项式异或(对应GF(2)GF(2)GF(2)的加法)

  • 若结果含x8x^8x8,则异或m(x)=x8+x4+x3+x+1m(x)=x^8+x^4+x^3+x+1m(x)=x8+x4+x3+x+1
  • 若含x9x^9x9,则异或x⋅m(x)=x9+x5+x4+x2+xx \cdot m(x) = x ^ 9 + x ^ 5 + x ^4 + x ^ 2 + xxm(x)=x9+x5+x4+x2+x
  • 重复此过程,知道消去所有次数≥8≥88的项。
示例演示

​对a,b∈GF(28),a+b=a⊕b,3⋅a=2⋅a⊕a.记字节a按比特表示为a7a6a5a4a3a2a1a0(a7为最高位)对应GF(28)中的多项式a7x7+a6x6+a5x5+a4x4+a3x3+a2x2+a1x+a0,2对应GF(28)中的x,则2⋅a可看作:x(a7x7+a6x6+⋯+a1x+a0)mod(x8+x4+x3+x+1)=a7x8+a6x7+⋯+a1x2+a0xmod(x8+x4+x3+x+1){a6x7+a5x6+⋯+a1x2+a0,a7=0a6x7+⋯+(a3+1)x4+(a2+1)x3+a1x2+(a0+1)x+1,a7=1再将多项式表示成二进制串的形式,2⋅a={a6a5⋯a1a00,a7=0a6a5⋯a1a00⊕00011011,a7=1={a7a6a5⋯a1a0<<1,a7=0(a7a6a5⋯a1a0<<1)⊕00011011,a7=1→2⋅a=(a7a6a5⋯a1a0<<1)⊕a7⋅(00011011)​ 对a, b \in GF(2 ^ 8),a + b = a \oplus b, 3 \cdot a = 2 \cdot a \oplus a.记字节a按比特表\\示为a_7a_6a_5a_4a_3a_2a_1a_0(a_7为最高位)对应GF(2 ^ 8)中的多项式\\ a_7x ^ 7 + a_6 x ^ 6 + a_5x^5+a_4x^4+a_3x^3+a_2x^2+a_1x+a_0,\\ 2对应GF(2 ^ 8)中的x,则2 \cdot a可看作:\\ x(a_7x^7+a_6x^6+\cdots+a_1x+a_0)\ \ mod\ (x^8+x^4+x^3+x+1)\\ =a_7x^8+a_6x^7+\cdots+a_1x^2+a_0x\ \ mod\ (x^8+x^4+x^3+x+1)\\ \begin{cases} a_6x^7+a_5x^6+\cdots+a_1x^2+a_0, & a_7 = 0 \\ a_6x^7+\cdots+(a_3+1)x^4+(a_2+1)x^3+a_1x^2+(a_0+1)x+1, & a_7 = 1 \end{cases}\\ 再将多项式表示成二进制串的形式,2 \cdot a = \begin{cases} a_6a_5\cdots a_1a_00, & a_7 = 0 \\ a_6a_5\cdots a_1a_00 \oplus 00011011, & a_7 = 1 \end{cases}\\ =\begin{cases} a_7a_6a_5\cdots a_1a_0<<1, & a_7 = 0 \\ (a_7a_6a_5\cdots a_1a_0<<1)\oplus 00011011, & a_7 = 1 \end{cases} \rightarrow 2 \cdot a = (a_7a_6a_5\cdots a_1a_0 << 1)\oplus a_7 \cdot (00011011) a,bGF(28)a+b=ab3a=2aa.记字节a按比特表示为a7a6a5a4a3a2a1a0(a7为最高位)对应GF(28)中的多项式a7x7+a6x6+a5x5+a4x4+a3x3+a2x2+a1x+a02对应GF(28)中的x,则2a可看作:x(a7x7+a6x6++a1x+a0)  mod (x8+x4+x3+x+1)=a7x8+a6x7++a1x2+a0x  mod (x8+x4+x3+x+1){a6x7+a5x6++a1x2+a0,a6x7++(a3+1)x4+(a2+1)x3+a1x2+(a0+1)x+1,a7=0a7=1再将多项式表示成二进制串的形式,2a={a6a5a1a00,a6a5a1a0000011011,a7=0a7=1={a7a6a5a1a0<<1,(a7a6a5a1a0<<1)00011011,a7=0a7=12a=(a7a6a5a1a0<<1)a7(00011011)
​ 由此,我们可以看出再加密过程中,列混合矩阵中出现最大的0x030x030x03我们至多需要两次异或运算与一次左移运算即可完成,也印证了我们前面提到的加密过程中的计算量<解密时的计算量,加密算法较解密算法而言更加常用。

逆列变换

[s0,0′s0,1′s0,2′s0,3′s1,0′s1,1′s1,2′s1,3′s2,0′s2,1′s2,2′s2,3′s3,0′s3,1′s3,2′s3,3′]=[0E0B0D09090E0B0D0D090E0B0B0D090E][s0,0s0,1s0,2s0,3s1,0s1,1s1,2s1,3s2,0s2,1s2,2s2,3s3,0s3,1s3,2s3,3]\begin{bmatrix} s'_{0,0} & s'_{0,1} & s'_{0,2} & s'_{0,3} \\ s'_{1,0} & s'_{1,1} & s'_{1,2} & s'_{1,3} \\ s'_{2,0} & s'_{2,1} & s'_{2,2} & s'_{2,3} \\ s'_{3,0} & s'_{3,1} & s'_{3,2} & s'_{3,3} \end{bmatrix}= \begin{bmatrix} 0\text{E} & 0\text{B} & 0\text{D} & 0\text{9} \\ 0\text{9} & 0\text{E} & 0\text{B} & 0\text{D} \\ 0\text{D} & 0\text{9} & 0\text{E} & 0\text{B} \\ 0\text{B} & 0\text{D} & 0\text{9} & 0\text{E} \end{bmatrix} \begin{bmatrix} s_{0,0} & s_{0,1} & s_{0,2} & s_{0,3} \\ s_{1,0} & s_{1,1} & s_{1,2} & s_{1,3} \\ s_{2,0} & s_{2,1} & s_{2,2} & s_{2,3} \\ s_{3,0} & s_{3,1} & s_{3,2} & s_{3,3} \end{bmatrix} s0,0s1,0s2,0s3,0s0,1s1,1s2,1s3,1s0,2s1,2s2,2s3,2s0,3s1,3s2,3s3,3=0E090D0B0B0E090D0D0B0E09090D0B0Es0,0s1,0s2,0s3,0s0,1s1,1s2,1s3,1s0,2s1,2s2,2s3,2s0,3s1,3s2,3s3,3

注:加密算法中的列混合矩阵中参数最大为0x030x030x03,具体实现时至多采用三次运算(两次异或和一次移位)即可完成3⋅a3 \cdot a3a,但是在解密时可能采用的计算就比较复杂(0x0E0x0E0x0E),这是因为在工程实践中,加密比解密更加常用,例如,CTFCTFCTFOFBOFBOFB工作模式中,只用到加密算法;分组密码作为部件去构造杂凑函数或消息认证码时,大多数情况下只用到加密算法……

4. 轮密钥加

​ 轮密钥加是128−bit128-bit128bit的状态直接和128−bit128-bit128bit的轮密钥进行逐比特异或运算,如下图所示:

flowchart TD%% 简化的矩阵表示subgraph InputState[输入状态矩阵]A[4×4字节矩阵<br>X₀₀ X₀₁ X₀₂ X₀₃<br>X₁₀ X₁₁ X₁₂ X₁₃<br>X₂₀ X₂₁ X₂₂ X₂₃<br>X₃₀ X₃₁ X₃₂ X₃₃]endsubgraph InputKey[轮密钥矩阵]K[4×4字节矩阵<br>K₀₀ K₀₁ K₀₂ K₀₃<br>K₁₀ K₁₁ K₁₂ K₁₃<br>K₂₀ K₂₁ K₂₂ K₂₃<br>K₃₀ K₃₁ K₃₂ K₃₃]endOp[轮密钥加<br>AddRoundKey<br>逐字节异或操作]subgraph OutputState[输出状态矩阵]R[4×4字节矩阵<br>R₀₀ R₀₁ R₀₂ R₀₃<br>R₁₀ R₁₁ R₁₂ R₁₃<br>R₂₀ R₂₁ R₂₂ R₂₃<br>R₃₀ R₃₁ R₃₂ R₃₃]endInputState --> OpInputKey --> OpOp --> OutputState
5. 密钥扩展

​ 由于AES−128/192/1256AES-128/192/1256AES128/192/1256在密钥扩展中的流程是一致的,但是由于迭代次数不一致,所以扩展出的密钥长度并不一致。但其中的思想是一致的。我们在这里介绍的是AES−128AES-128AES128,我们输入的key(16−Byte)key(16-Byte)key(16Byte),这里我们规定其中的密钥矩阵每一列的4−Byte4-Byte4Byte为一个字,起初的四个字会被当成主密钥进行扩展,最终扩展出来的为长度为44−字44-字44的密钥,其中每4−字4-字4参与每轮的轮密钥加操作,其中前四个字会在迭代前与明文进行异或。

扩展规则:

设主密钥为w[0],w[1],w[2],w[3]w[0],w[1],w[2],w[3]w[0],w[1],w[2],w[3],对WWW数组扩充404040个新列,构造总共444444列的扩展密钥数组。

  1. iii不是444的倍数
    w[i]=w[i−4]⊕w[i−1]w[i]=w[i-4] \oplus w[i-1]w[i]=w[i4]w[i1]
  2. iii444的倍数
    w[i]=w[i−4]⊕T(w[i−1])w[i]=w[i-4] \oplus T(w[i-1])w[i]=w[i4]T(w[i1])
T函数

​ T函数由三部分组成:字循环、字节代换、轮常量异或

  1. 字循环:将字中的4个字节循环左移1个字节
    [b₀, b₁, b₂, b₃] → [b₁, b₂, b₃, b₀]
  2. 字节代换:使用S盒S盒S进行字节代换
  3. 轮常量异或:与轮常量Rcon[j]Rcon[j]Rcon[j]进行异或
    轮常量表:
轮数 jRcon[j]轮数 jRcon[j]
101 00 00 00620 00 00 00
202 00 00 00740 00 00 00
304 00 00 00880 00 00 00
408 00 00 0091B 00 00 00
510 00 00 001036 00 00 00
示例演示

初始密钥:3C A1 0B 21 57 F0 19 16 90 2E 13 80 AC C1 07 BD

初始W数组:

  • W[0] = 3C A1 0B 21
  • W[1] = 57 F0 19 16
  • W[2] = 90 2E 13 80
  • W[3] = AC C1 07 BD

计算第一轮子密钥(W[4] ~ W[7])
W[4] 计算 (i=4i = 4i=4,是444的倍数)

T(W[3])计算:
1. 字循环:AC C1 07 BD → C1 07 BD AC
2. 字节代换:C1 07 BD AC → 78 C5 7A 91
3. 轮常量异或:78 C5 7A 91 ⊕ 01 00 00 00 = 79 C5 7A 91W[4] = W[0] ⊕ T(W[3]) = 3C A1 0B 21 ⊕ 79 C5 7A 91 = 45 64 71 B0

W[5] 计算 (i=5i = 5i=5,不是444的倍数)

W[5] = W[1] ⊕ W[4] = 57 F0 19 16 ⊕ 45 64 71 B0 = 12 94 68 A6

W[6] 计算 (i=5i = 5i=5,不是444的倍数)

W[6] = W[2] ⊕ W[5] = 90 2E 13 80 ⊕ 12 94 68 A6 = 82 BA 7B 26

W[7] 计算 (i=5i = 5i=5,不是444的倍数)

W[7] = W[3] ⊕ W[6] = AC C1 07 BD ⊕ 82 BA 7B 26 = 2E 7B 7C 9B

第一轮密钥结果:45 64 71 B0 12 94 68 A6 82 BA 7B 26 2E 7B 7C 9B

三、加密 and 解密流程

第1轮解密 Round 1 Decryption
第8至2轮解密 Rounds 8-2 Decryption
最终轮 Final Round
第2至9轮 Rounds 2-9
第1轮 Round 1
密钥扩展 Key Expansion
轮密钥加
AddRoundKey
逆S盒字节替换
InvSubBytes
逆行移位
InvShiftRows
逆列混合
InvMixColumns
轮密钥加
AddRoundKey
逆S盒字节替换
InvSubBytes
逆行移位
InvShiftRows
逆列混合
InvMixColumns
轮密钥加
AddRoundKey
行移位
ShiftRows
S盒字节替换
SubBytes
轮密钥加
AddRoundKey
列混合
MixColumns
行移位
ShiftRows
S盒字节替换
SubBytes
轮密钥加
AddRoundKey
列混合
MixColumns
行移位
ShiftRows
S盒字节替换
SubBytes
密钥扩展算法
Key Expansion Algorithm
128位主密钥
Master Key
轮密钥 K0
轮密钥 K1
...
轮密钥 K9
轮密钥 K10
128位明文
Plaintext
轮密钥加
AddRoundKey
128位密文
Ciphertext
轮密钥加
AddRoundKey
逆行移位
InvShiftRows
逆S盒字节替换
InvSubBytes
轮密钥加
AddRoundKey
逆列混合
InvMixColumns
逆行移位
InvShiftRows
逆S盒字节替换
InvSubBytes
轮密钥加
AddRoundKey
128位明文
Plaintext

注:其中解密的流程并不固定,其中针对于每一轮中的逆组件使用,逆行移位操作与逆S盒S盒S操作可以调换先后顺序。

四、AES加密 and 解密代码实现

​ 声明:为了适应大多数人的需求,减少重复知识的冗余。我们将对AES−128AES-128AES128进行编码。其实针对于目前主流的编程语言而言,都已经有对应的库进行了支持。但是这避免不了我们会有使用AESAESAES源码的需求。便于博客管理以及避免文章篇幅很长,在这里只写下参照上述流程基本实现的主流语言编程下的加密与解密代码,针对于课程需要,还会有很多软件实现策略和优化策略,我们放在后面的文章中详细介绍,例如调用AESNI指令、T表法优化等软件实现的优化策略。

C/C++
/** File Name: AES_test.cpp* Author: chen_xing*/
#include <iostream>
#include <vector>
#include <iomanip>
#include <sstream>
#include <cstdint>
#include <algorithm>
#include <stdexcept>
using namespace std;class AES
{
private:static constexpr uint8_t Rcon[14] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D};vector<uint8_t> key;vector<vector<uint8_t>> W;vector<uint8_t> S, S_inv;int rounds, nk;// GF(2^8)乘法uint8_t _gmul(uint8_t a, uint8_t b){uint8_t p = 0;for (int i = 0; i < 8; ++i){if (b & 1)p ^= a;bool hi = a & 0x80;a <<= 1;if (hi)a ^= 0x1B;b >>= 1;}return p;}// 向量异或vector<uint8_t> _xor_vec(const vector<uint8_t> &a, const vector<uint8_t> &b){vector<uint8_t> res(a.size());for (size_t i = 0; i < a.size(); ++i)res[i] = a[i] ^ b[i];return res;}// 字节转矩阵vector<vector<uint8_t>> _bytes_to_matrix(const vector<uint8_t> &text){vector<vector<uint8_t>> m(4, vector<uint8_t>(4));for (int i = 0; i < 16; i++)m[i % 4][i / 4] = text[i];return m;}// 矩阵转字节vector<uint8_t> _matrix_to_bytes(const vector<vector<uint8_t>> &m){vector<uint8_t> res(16);for (int i = 0; i < 16; i++)res[i] = m[i % 4][i / 4];return res;}// 字循环vector<uint8_t> _rot_word(vector<uint8_t> w){rotate(w.begin(), w.begin() + 1, w.end());return w;}// 字替换vector<uint8_t> _sub_word(vector<uint8_t> w){for (auto &x : w)x = S[x];return w;}// 生成S盒void _generate_sbox(){S.assign(256, 0);S[0] = 0x63;uint8_t p = 1, q = 1;for (int i = 0; i < 255; ++i){p = p ^ (p << 1) ^ ((p & 0x80) ? 0x1B : 0);q ^= q << 1;q ^= q << 2;q ^= q << 4;q ^= (q & 0x80) ? 0x09 : 0x00;uint8_t xformed = q ^ ((q << 1) | (q >> 7)) ^((q << 2) | (q >> 6)) ^((q << 3) | (q >> 5)) ^((q << 4) | (q >> 4)) ^ 0x63;S[p] = xformed;}}// 生成逆S盒void _generate_sinvbox(){S_inv.assign(256, 0);for (int i = 0; i < 256; ++i)S_inv[S[i]] = i;}// 密钥扩展void _key_expansion(){for (int i = nk; i < (rounds + 1) * 4; ++i){vector<uint8_t> temp = W[i - 1];if (i % nk == 0){temp = _sub_word(_rot_word(temp));temp[0] ^= Rcon[i / nk - 1];}else if (nk == 8 && i % nk == 4){temp = _sub_word(temp);}W.push_back(_xor_vec(W[i - nk], temp));}}// 轮密钥加vector<vector<uint8_t>> _round_key_add(vector<vector<uint8_t>> &block, int round){for (int c = 0; c < 4; c++)for (int r = 0; r < 4; r++)block[r][c] ^= W[round * 4 + c][r];return block;}// 字节替换vector<vector<uint8_t>> _sub_bytes(vector<vector<uint8_t>> &block){for (auto &row : block)for (auto &b : row)b = S[b];return block;}// 行移位vector<vector<uint8_t>> _shift_rows(vector<vector<uint8_t>> &block){for (int r = 1; r < 4; r++)rotate(block[r].begin(), block[r].begin() + r, block[r].end());return block;}// 列混合vector<vector<uint8_t>> _mix_columns(vector<vector<uint8_t>> &s){for (int c = 0; c < 4; c++){uint8_t a0 = s[0][c], a1 = s[1][c], a2 = s[2][c], a3 = s[3][c];s[0][c] = _gmul(a0, 2) ^ _gmul(a1, 3) ^ a2 ^ a3;s[1][c] = a0 ^ _gmul(a1, 2) ^ _gmul(a2, 3) ^ a3;s[2][c] = a0 ^ a1 ^ _gmul(a2, 2) ^ _gmul(a3, 3);s[3][c] = _gmul(a0, 3) ^ a1 ^ a2 ^ _gmul(a3, 2);}return s;}// 逆字节替换vector<vector<uint8_t>> _inv_sub_bytes(vector<vector<uint8_t>> &block){for (auto &row : block)for (auto &b : row)b = S_inv[b];return block;}// 逆行移位vector<vector<uint8_t>> _inv_shift_rows(vector<vector<uint8_t>> &block){for (int r = 1; r < 4; r++)rotate(block[r].begin(), block[r].begin() + (4 - r), block[r].end());return block;}// 逆列混合vector<vector<uint8_t>> _inv_mix_columns(vector<vector<uint8_t>> &s){for (int c = 0; c < 4; c++){uint8_t a0 = s[0][c], a1 = s[1][c], a2 = s[2][c], a3 = s[3][c];s[0][c] = _gmul(a0, 14) ^ _gmul(a1, 11) ^ _gmul(a2, 13) ^ _gmul(a3, 9);s[1][c] = _gmul(a0, 9) ^ _gmul(a1, 14) ^ _gmul(a2, 11) ^ _gmul(a3, 13);s[2][c] = _gmul(a0, 13) ^ _gmul(a1, 9) ^ _gmul(a2, 14) ^ _gmul(a3, 11);s[3][c] = _gmul(a0, 11) ^ _gmul(a1, 13) ^ _gmul(a2, 9) ^ _gmul(a3, 14);}return s;}public:AES(const vector<uint8_t> &key_){key = key_;size_t len = key.size();if (len == 16){rounds = 10;nk = 4;}else if (len == 24){rounds = 12;nk = 6;}else if (len == 32){rounds = 14;nk = 8;}elsethrow invalid_argument("Invalid AES key length");_generate_sbox();_generate_sinvbox();// 初始化密钥扩展for (size_t i = 0; i < len; i += 4)W.push_back(vector<uint8_t>(key.begin() + i, key.begin() + i + 4));_key_expansion();}// PKCS7 填充vector<uint8_t> pad(const vector<uint8_t> &data){size_t pad_len = 16 - (data.size() % 16);vector<uint8_t> res = data;res.insert(res.end(), pad_len, static_cast<uint8_t>(pad_len));return res;}// 去除 PKCS7 填充vector<uint8_t> unpad(const vector<uint8_t> &data){if (data.empty() || data.size() % 16 != 0)throw runtime_error("Invalid data length for unpad");uint8_t pad_len = data.back();if (pad_len == 0 || pad_len > 16)throw runtime_error("Invalid padding");for (size_t i = data.size() - pad_len; i < data.size(); ++i)if (data[i] != pad_len)throw runtime_error("Bad padding byte");return vector<uint8_t>(data.begin(), data.end() - pad_len);}vector<uint8_t> encrypt(const vector<uint8_t> &plaintext){vector<uint8_t> data = pad(plaintext);vector<uint8_t> out;for (size_t i = 0; i < data.size(); i += 16){auto block = vector<uint8_t>(data.begin() + i, data.begin() + i + 16);auto state = _bytes_to_matrix(block);// 初始轮密钥加state = _round_key_add(state, 0);// 主轮for (int r = 1; r < rounds; ++r){state = _sub_bytes(state);state = _shift_rows(state);state = _mix_columns(state);state = _round_key_add(state, r);}// 最终轮state = _sub_bytes(state);state = _shift_rows(state);state = _round_key_add(state, rounds);auto encrypted_block = _matrix_to_bytes(state);out.insert(out.end(), encrypted_block.begin(), encrypted_block.end());}return out;}vector<uint8_t> decrypt(const vector<uint8_t> &ciphertext){if (ciphertext.size() % 16 != 0)throw invalid_argument("Ciphertext length must be multiple of 16");vector<uint8_t> out;for (size_t i = 0; i < ciphertext.size(); i += 16){auto block = vector<uint8_t>(ciphertext.begin() + i, ciphertext.begin() + i + 16);auto state = _bytes_to_matrix(block);// 初始轮state = _round_key_add(state, rounds);state = _inv_shift_rows(state);state = _inv_sub_bytes(state);// 主轮for (int r = rounds - 1; r > 0; --r){state = _round_key_add(state, r);state = _inv_mix_columns(state);state = _inv_shift_rows(state);state = _inv_sub_bytes(state);}// 最终轮state = _round_key_add(state, 0);auto decrypted_block = _matrix_to_bytes(state);out.insert(out.end(), decrypted_block.begin(), decrypted_block.end());}return unpad(out);}
};int main()
{string msg = "He who conquers others is strong; he who conquers himself is mighty.";vector<uint8_t> data(msg.begin(), msg.end());// key = chenxing_AES_c++vector<uint8_t> key = {'c', 'h', 'e', 'n', 'x', 'i', 'n', 'g', '_', 'A', 'E', 'S', '_', 'c', '+', '+'};AES aes(key);// 加密auto enc = aes.encrypt(data);cout << "Encrypted (hex): ";for (auto c : enc)cout << hex << setw(2) << setfill('0') << (int)c;cout << dec << endl;// 解密auto dec = aes.decrypt(enc);cout << "Decrypted: " << string(dec.begin(), dec.end()) << endl;// 验证cout << "Match: " << (msg == string(dec.begin(), dec.end())) << endl;return 0;
}
Python
class AES():Rcon = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D]def __init__(self, key: bytes):key_length = len(key)if key_length == 16:  # 128位self.rounds = 10self.nk = 4  # 密钥字数elif key_length == 24:  # 192位self.rounds = 12self.nk = 6elif key_length == 32:  # 256位self.rounds = 14self.nk = 8else:raise ValueError(f"Invalid AES key length: {key_length} bytes")self.key = keyself.S = self._generate_sbox()self.S_inv = self._generate_sinvbox()self.W = [list(key[i:i + 4]) for i in range(0, len(key), 4)]self._key_expansion()def _xor(self, a, b=None):if b is None:assert len(a) > 0return a[0] ^ self._xor(a[1:]) if len(a) > 1 else a[0]assert len(a) == len(b)return [x ^ y for x, y in zip(a, b)]def _gmul(self, a, b):p = 0while b:if b & 1:p ^= aa = a << 1if a >> 8:a ^= 0x11B  # AES不可约多项式b >>= 1return pdef _multiply(self, a, b):return self._xor([self._gmul(x, y) for x, y in zip(a, b)])def _matrix_multiply(self, const, state):result = [[0] * 4 for _ in range(4)]for i in range(4):for j in range(4):for k in range(4):result[i][j] ^= self._gmul(const[i][k], state[k][j])return resultdef _permutation(self, lis, table):return [table[i] for i in lis]def _block_permutation(self, block, table):return [[table[block[i][j]] for j in range(4)] for i in range(4)]def _left_shift(self, block, n):return block[n:] + block[:n]def _rot_word(self, word):return word[1:] + word[:1]def _sub_word(self, word):return [self.S[b] for b in word]def _bytes_to_matrix(self, text: bytes) -> list[list[int]]:return [[text[j * 4 + i] for j in range(4)] for i in range(4)]def _matrix_to_bytes(self, block: list[list[int]]) -> bytes:return bytes([block[j][i] for i in range(4) for j in range(4)])def _generate_sbox(self):S = [0x63] + [0] * 255r = lambda x, s: (x << s | x >> 8 - s) % 256p, q = 1, 1for _ in range(255):p = (p ^ (p * 2) ^ [27, 0][p < 128]) % 256q ^= q * 2q ^= q * 4q ^= q * 16q &= 255q ^= [9, 0][q < 128]S[p] = q ^ r(q, 1) ^ r(q, 2) ^ r(q, 3) ^ r(q, 4) ^ 99return Sdef _generate_sinvbox(self):S_inv = [0] * 256for i in range(256):S_inv[self.S[i]] = ireturn S_invdef _key_expansion(self):for i in range(self.nk, (self.rounds + 1) * 4):temp = self.W[i - 1].copy()if i % self.nk == 0:temp = self._sub_word(self._rot_word(temp))temp[0] ^= self.Rcon[i // self.nk - 1]elif self.nk == 8 and i % self.nk == 4:temp = self._sub_word(temp)self.W.append(self._xor(self.W[i - self.nk], temp))def _row_shift(self, block: list[list[int]]) -> list[list[int]]:return [self._left_shift(block[i], i) for i in range(4)]def _inv_row_shift(self, block: list[list[int]]) -> list[list[int]]:return [self._left_shift(block[i], 4 - i) for i in range(4)]def _column_mix(self, block: list[list[int]]) -> list[list[int]]:return self._matrix_multiply([self._left_shift([2, 3, 1, 1], 4 - i) for i in range(4)], block)def _inv_column_mix(self, block: list[list[int]]) -> list[list[int]]:return self._matrix_multiply([self._left_shift([14, 11, 13, 0x9], 4 - i) for i in range(4)], block)def _round_key_add(self, block: list[list[int]], key: list[list[int]]) -> list[list[int]]:return [self._xor(block[i], [key[j][i] for j in range(4)]) for i in range(4)]def _encrypt(self, block: list[list[int]]) -> list[list[int]]:block = self._round_key_add(block, [self.W[i] for i in range(4)])for i in range(1, self.rounds):block = self._block_permutation(block, self.S)block = self._row_shift(block)block = self._column_mix(block)block = self._round_key_add(block, [self.W[i * 4 + j] for j in range(4)])block = self._block_permutation(block, self.S)block = self._row_shift(block)block = self._round_key_add(block, [self.W[i] for i in range(self.rounds * 4, (self.rounds + 1) * 4)])return blockdef _decrypt(self, block: list[list[int]]) -> list[list[int]]:block = self._round_key_add(block, [self.W[i] for i in range(self.rounds * 4, (self.rounds + 1) * 4)])for i in range(self.rounds - 1, 0, -1):block = self._inv_row_shift(block)block = self._block_permutation(block, self.S_inv)block = self._round_key_add(block, [self.W[i * 4 + j] for j in range(4)])block = self._inv_column_mix(block)block = self._inv_row_shift(block)block = self._block_permutation(block, self.S_inv)block = self._round_key_add(block, [self.W[i] for i in range(4)])return blockdef encrypt(self, plaintext: bytes) -> bytes:assert len(plaintext) % 16 == 0, ValueError(f"Incorrect AES plaintext length ({len(plaintext)} bytes)")ciphertext = b''for i in range(0, len(plaintext), 16):block = plaintext[i:i + 16]block = self._bytes_to_matrix(block)block = self._encrypt(block)ciphertext += self._matrix_to_bytes(block) return ciphertextdef decrypt(self, ciphertext: bytes) -> bytes:assert len(ciphertext) % 16 == 0, ValueError(f"Incorrect AES ciphertext length ({len(ciphertext)} bytes)")plaintext = b''for i in range(0, len(ciphertext), 16):block = ciphertext[i:i + 16]block = self._bytes_to_matrix(block)block = self._decrypt(block)plaintext += self._matrix_to_bytes(block)return plaintextif __name__ == "__main__":key = b'chen_xing_AES_py'aes = AES(key)# 胜人者有力,自强者胜。test_plaintext = b'He who conquers others is strong; he who conquers himself is mighty.'# 填充到16字节if len(test_plaintext) % 16 != 0:test_plaintext = test_plaintext.ljust(16 * ((len(test_plaintext) // 16) + 1), b'\x00')encrypted = aes.encrypt(test_plaintext)decrypted = aes.decrypt(encrypted)print(f"Decrypted: {decrypted}")print(f"Test - Match: {test_plaintext == decrypted}")
Java
import java.util.Arrays;public class AES {private static final int[] RCON = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D};private final int Nk;        // 密钥字数private final int Nr;        // 轮数private final int Nb = 4;    // 状态矩阵列数private final byte[] key;    // 原始密钥private final int[][] w;     // 扩展密钥private final byte[] S = new byte[256];     // S盒private final byte[] S_INV = new byte[256]; // 逆S盒public AES(byte[] key) {// 根据密钥长度确定参数int len = key.length;if (len == 16) {Nk = 4;Nr = 10;} else if (len == 24) {Nk = 6;Nr = 12;} else if (len == 32) {Nk = 8;Nr = 14;} else {throw new IllegalArgumentException("Invalid AES key length: " + len);}this.key = Arrays.copyOf(key, key.length);generateSBox();generateSInvBox();// 密钥扩展:总字数 = Nb * (Nr + 1)int totalWords = Nb * (Nr + 1);w = new int[totalWords][4];keyExpansion();}// ---------- GF(2^8) 运算辅助函数 ----------/*** 在GF(2^8)中乘以x(即2)*/private static int xtime(int a) {a <<= 1;if ((a & 0x100) != 0) {a ^= 0x11b; // AES不可约多项式}return a & 0xff;}/*** 在GF(2^8)中乘法运算*/private static int mul(int a, int b) {int res = 0;while (b != 0) {if ((b & 1) != 0) {res ^= a;}a = xtime(a);b >>>= 1;}return res & 0xff;}// ---------- S盒生成 ----------/*** 生成AES S盒*/private void generateSBox() {// 使用指数运算 a^254 在GF(2^8)中计算乘法逆元S[0] = 0x63;for (int i = 1; i < 256; i++) {int inv = gfInv(i);int x = inv;// 仿射变换int y = x ^ ((x << 1) | (x >>> 7))^ ((x << 2) | (x >>> 6))^ ((x << 3) | (x >>> 5))^ ((x << 4) | (x >>> 4))^ 0x63;S[i] = (byte) (y & 0xff);}}/*** 生成逆S盒*/private void generateSInvBox() {for (int i = 0; i < 256; i++) {S_INV[S[i] & 0xFF] = (byte) i;}}/*** 在GF(2^8)中计算乘法逆元*/private int gfInv(int a) {if (a == 0) return 0;int result = 1;int base = a;int exp = 254; // a^254 是逆元while (exp > 0) {if ((exp & 1) != 0) {result = mul(result, base);}base = mul(base, base);exp >>= 1;}return result & 0xff;}// ---------- 密钥扩展 ----------/*** AES密钥扩展算法*/private void keyExpansion() {// 用原始密钥填充前Nk个字for (int i = 0; i < Nk; i++) {for (int j = 0; j < 4; j++) {w[i][j] = key[4 * i + j] & 0xFF;}}// 扩展剩余的字for (int i = Nk; i < w.length; i++) {int[] temp = Arrays.copyOf(w[i - 1], 4);if (i % Nk == 0) {temp = subWord(rotWord(temp));temp[0] ^= RCON[i / Nk - 1];} else if (Nk > 6 && (i % Nk) == 4) {temp = subWord(temp);}for (int j = 0; j < 4; j++) {w[i][j] = w[i - Nk][j] ^ temp[j];}}}/*** 字循环:将字向左循环移位*/private int[] rotWord(int[] word) {return new int[]{word[1], word[2], word[3], word[0]};}/*** 字替换:使用S盒替换字中的每个字节*/private int[] subWord(int[] word) {int[] out = new int[4];for (int i = 0; i < 4; i++) {out[i] = S[word[i]] & 0xFF;}return out;}// ---------- 状态矩阵辅助函数 ----------/*** 将字节数组转换为状态矩阵*/private int[][] bytesToState(byte[] in, int offset) {int[][] state = new int[4][4];for (int i = 0; i < 16; i++) {state[i % 4][i / 4] = in[offset + i] & 0xFF;}return state;}/*** 将状态矩阵转换为字节数组*/private void stateToBytes(int[][] state, byte[] out, int offset) {for (int i = 0; i < 16; i++) {out[offset + i] = (byte) (state[i % 4][i / 4]);}}// ---------- 核心变换操作 ----------/*** 字节替换*/private void subBytes(int[][] state) {for (int row = 0; row < 4; row++) {for (int col = 0; col < 4; col++) {state[row][col] = S[state[row][col]] & 0xff;}}}/*** 逆字节替换*/private void invSubBytes(int[][] state) {for (int row = 0; row < 4; row++) {for (int col = 0; col < 4; col++) {state[row][col] = S_INV[state[row][col]] & 0xff;}}}/*** 行移位*/private void shiftRows(int[][] state) {for (int row = 1; row < 4; row++) {int[] temp = Arrays.copyOf(state[row], 4);for (int col = 0; col < 4; col++) {state[row][col] = temp[(col + row) % 4];}}}/*** 逆行移位*/private void invShiftRows(int[][] state) {for (int row = 1; row < 4; row++) {int[] temp = Arrays.copyOf(state[row], 4);for (int col = 0; col < 4; col++) {state[row][(col + row) % 4] = temp[col];}}}/*** 列混合*/private void mixColumns(int[][] state) {for (int col = 0; col < 4; col++) {int a0 = state[0][col];int a1 = state[1][col];int a2 = state[2][col];int a3 = state[3][col];state[0][col] = (mul(2, a0) ^ mul(3, a1) ^ a2 ^ a3) & 0xff;state[1][col] = (a0 ^ mul(2, a1) ^ mul(3, a2) ^ a3) & 0xff;state[2][col] = (a0 ^ a1 ^ mul(2, a2) ^ mul(3, a3)) & 0xff;state[3][col] = (mul(3, a0) ^ a1 ^ a2 ^ mul(2, a3)) & 0xff;}}/*** 逆列混合*/private void invMixColumns(int[][] state) {for (int col = 0; col < 4; col++) {int a0 = state[0][col];int a1 = state[1][col];int a2 = state[2][col];int a3 = state[3][col];state[0][col] = (mul(0x0e, a0) ^ mul(0x0b, a1) ^ mul(0x0d, a2) ^ mul(0x09, a3)) & 0xff;state[1][col] = (mul(0x09, a0) ^ mul(0x0e, a1) ^ mul(0x0b, a2) ^ mul(0x0d, a3)) & 0xff;state[2][col] = (mul(0x0d, a0) ^ mul(0x09, a1) ^ mul(0x0e, a2) ^ mul(0x0b, a3)) & 0xff;state[3][col] = (mul(0x0b, a0) ^ mul(0x0d, a1) ^ mul(0x09, a2) ^ mul(0x0e, a3)) & 0xff;}}/*** 轮密钥加*/private void addRoundKey(int[][] state, int round) {for (int col = 0; col < 4; col++) {for (int row = 0; row < 4; row++) {state[row][col] ^= w[round * 4 + col][row];}}}// ---------- 单块加密/解密 ----------/*** 加密单个16字节块*/public byte[] encryptBlock(byte[] inputBlock) {if (inputBlock.length != 16) {throw new IllegalArgumentException("Block size must be 16 bytes");}int[][] state = bytesToState(inputBlock, 0);// 初始轮密钥加addRoundKey(state, 0);// 主轮(前Nr-1轮)for (int round = 1; round < Nr; round++) {subBytes(state);shiftRows(state);mixColumns(state);addRoundKey(state, round);}// 最终轮(无列混合)subBytes(state);shiftRows(state);addRoundKey(state, Nr);byte[] output = new byte[16];stateToBytes(state, output, 0);return output;}/*** 解密单个16字节块*/public byte[] decryptBlock(byte[] inputBlock) {if (inputBlock.length != 16) {throw new IllegalArgumentException("Block size must be 16 bytes");}int[][] state = bytesToState(inputBlock, 0);// 初始轮addRoundKey(state, Nr);invShiftRows(state);invSubBytes(state);// 主轮(前Nr-1轮)for (int round = Nr - 1; round > 0; round--) {addRoundKey(state, round);invMixColumns(state);invShiftRows(state);invSubBytes(state);}// 最终轮addRoundKey(state, 0);byte[] output = new byte[16];stateToBytes(state, output, 0);return output;}// ---------- PKCS#7 填充 ----------/*** PKCS#7填充*/private byte[] pkcs7Pad(byte[] data) {int padLength = 16 - (data.length % 16);if (padLength == 0) {padLength = 16;}byte[] padded = Arrays.copyOf(data, data.length + padLength);Arrays.fill(padded, data.length, padded.length, (byte) padLength);return padded;}/*** 去除PKCS#7填充*/private byte[] pkcs7Unpad(byte[] data) {if (data.length == 0 || data.length % 16 != 0) {throw new IllegalArgumentException("Invalid padded data length");}int paddingLength = data[data.length - 1] & 0xFF;if (paddingLength < 1 || paddingLength > 16) {throw new IllegalArgumentException("Invalid padding length");}// 验证填充字节for (int i = data.length - paddingLength; i < data.length; i++) {if ((data[i] & 0xFF) != paddingLength) {throw new IllegalArgumentException("Invalid padding bytes");}}return Arrays.copyOf(data, data.length - paddingLength);}// ---------- 多块加密/解密 (ECB模式) ----------/*** 加密任意长度数据*/public byte[] encrypt(byte[] plaintext) {byte[] paddedData = pkcs7Pad(plaintext);byte[] ciphertext = new byte[paddedData.length];for (int i = 0; i < paddedData.length; i += 16) {byte[] block = Arrays.copyOfRange(paddedData, i, i + 16);byte[] encryptedBlock = encryptBlock(block);System.arraycopy(encryptedBlock, 0, ciphertext, i, 16);}return ciphertext;}/*** 解密任意长度数据*/public byte[] decrypt(byte[] ciphertext) {if (ciphertext.length % 16 != 0) {throw new IllegalArgumentException("Ciphertext length must be multiple of 16 bytes");}byte[] decryptedData = new byte[ciphertext.length];for (int i = 0; i < ciphertext.length; i += 16) {byte[] block = Arrays.copyOfRange(ciphertext, i, i + 16);byte[] decryptedBlock = decryptBlock(block);System.arraycopy(decryptedBlock, 0, decryptedData, i, 16);}return pkcs7Unpad(decryptedData);}// ---------- 辅助函数 ----------/*** 将字节数组转换为十六进制字符串*/public static String bytesToHex(byte[] bytes) {StringBuilder hexString = new StringBuilder();for (byte b : bytes) {hexString.append(String.format("%02x", b & 0xFF));}return hexString.toString();}// ---------- 测试函数 ----------public static void main(String[] args) throws Exception {byte[] key = "chenxingAES_JAVA".getBytes("UTF-8");AES aes = new AES(key);String plainText = "He who conquers others is strong; he who conquers himself is mighty.";byte[] plaintextBytes = plainText.getBytes("UTF-8");// 加密byte[] ciphertext = aes.encrypt(plaintextBytes);System.out.println("Ciphertext (hex): " + bytesToHex(ciphertext));// 解密byte[] decryptedBytes = aes.decrypt(ciphertext);String decryptedText = new String(decryptedBytes, "UTF-8");System.out.println("Decrypted text: " + decryptedText);// 验证boolean isMatch = Arrays.equals(plaintextBytes, decryptedBytes);System.out.println("Match: " + isMatch);if (!isMatch) {throw new RuntimeException("Encryption/decryption mismatch!");}}
}
Rust
use std::convert::TryInto;struct AES {rounds: usize,nk: usize,w: Vec<[u8; 4]>,sbox: [u8; 256],inv_sbox: [u8; 256],
}impl AES {const RCON: [u8; 14] = [0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36, 0x6C, 0xD8, 0xAB, 0x4D];pub fn new(key: &[u8]) -> Self {let (nk, rounds) = match key.len() {16 => (4, 10),24 => (6, 12),32 => (8, 14),_ => panic!("Invalid AES key length: {} bytes", key.len()),};let mut aes = AES {rounds,nk,w: Vec::new(),sbox: [0u8; 256],inv_sbox: [0u8; 256],};aes.generate_sbox();aes.generate_inv_sbox();aes.key_expansion(key);aes}/// 在GF(2^8)中乘法运算fn gmul(mut a: u8, mut b: u8) -> u8 {let mut product: u8 = 0;while b != 0 {if b & 1 != 0 {product ^= a;}let high_bit = a & 0x80;a <<= 1;if high_bit != 0 {a ^= 0x1b;}b >>= 1;}product}/// 在GF(2^8)中指数运算fn gf_pow(mut base: u8, mut exponent: u32) -> u8 {let mut result: u8 = 1;while exponent != 0 {if exponent & 1 != 0 {result = AES::gmul(result, base);}base = AES::gmul(base, base);exponent >>= 1;}result}/// 生成AES S盒fn generate_sbox(&mut self) {self.sbox[0] = 0x63;for i in 1..256 {let inv = if i == 0 { 0 } else { AES::gf_pow(i as u8, 254) };let x = inv;// 仿射变换let y = x ^ x.rotate_left(1) ^ x.rotate_left(2) ^ x.rotate_left(3) ^ x.rotate_left(4) ^ 0x63;self.sbox[i] = y;}}/// 生成逆S盒fn generate_inv_sbox(&mut self) {for i in 0..256 {self.inv_sbox[self.sbox[i] as usize] = i as u8;}}/// 字循环:将字向左循环移位fn rot_word(word: [u8; 4]) -> [u8; 4] {[word[1], word[2], word[3], word[0]]}/// 字替换:使用S盒替换字中的每个字节fn sub_word(&self, word: [u8; 4]) -> [u8; 4] {[self.sbox[word[0] as usize],self.sbox[word[1] as usize],self.sbox[word[2] as usize],self.sbox[word[3] as usize],]}/// AES密钥扩展算法fn key_expansion(&mut self, key: &[u8]) {let nb = 4; // 状态矩阵列数let total_words = nb * (self.rounds + 1);self.w = vec![[0u8; 4]; total_words];// 用原始密钥填充前Nk个字for i in 0..self.nk {self.w[i].copy_from_slice(&key[4 * i..4 * i + 4]);}// 扩展剩余的字for i in self.nk..total_words {let mut temp = self.w[i - 1];if i % self.nk == 0 {temp = Self::rot_word(temp);temp = self.sub_word(temp);temp[0] ^= Self::RCON[i / self.nk - 1];} else if self.nk > 6 && i % self.nk == 4 {temp = self.sub_word(temp);}for j in 0..4 {self.w[i][j] = self.w[i - self.nk][j] ^ temp[j];}}}/// 轮密钥加fn add_round_key(state: &mut [[u8; 4]; 4], expanded_key: &[[u8; 4]], round: usize) {for col in 0..4 {for row in 0..4 {state[row][col] ^= expanded_key[round * 4 + col][row];}}}/// 字节替换fn sub_bytes(&self, state: &mut [[u8; 4]; 4]) {for row in 0..4 {for col in 0..4 {state[row][col] = self.sbox[state[row][col] as usize];}}}/// 逆字节替换fn inv_sub_bytes(&self, state: &mut [[u8; 4]; 4]) {for row in 0..4 {for col in 0..4 {state[row][col] = self.inv_sbox[state[row][col] as usize];}}}/// 行移位fn shift_rows(&self, state: &mut [[u8; 4]; 4]) {for row in 1..4 {state[row].rotate_left(row);}}/// 逆行移位fn inv_shift_rows(&self, state: &mut [[u8; 4]; 4]) {for row in 1..4 {state[row].rotate_right(row);}}/// 单列混合fn mix_single_column(&self, column: [u8; 4]) -> [u8; 4] {[Self::gmul(2, column[0]) ^ Self::gmul(3, column[1]) ^ column[2] ^ column[3],column[0] ^ Self::gmul(2, column[1]) ^ Self::gmul(3, column[2]) ^ column[3],column[0] ^ column[1] ^ Self::gmul(2, column[2]) ^ Self::gmul(3, column[3]),Self::gmul(3, column[0]) ^ column[1] ^ column[2] ^ Self::gmul(2, column[3]),]}/// 列混合fn mix_columns(&self, state: &mut [[u8; 4]; 4]) {for col in 0..4 {let column = [state[0][col], state[1][col], state[2][col], state[3][col]];let mixed_column = self.mix_single_column(column);for row in 0..4 {state[row][col] = mixed_column[row];}}}/// 逆列混合fn inv_mix_columns(&self, state: &mut [[u8; 4]; 4]) {for col in 0..4 {let column = [state[0][col], state[1][col], state[2][col], state[3][col]];state[0][col] = Self::gmul(0x0e, column[0]) ^ Self::gmul(0x0b, column[1]) ^ Self::gmul(0x0d, column[2]) ^ Self::gmul(0x09, column[3]);state[1][col] = Self::gmul(0x09, column[0]) ^ Self::gmul(0x0e, column[1]) ^ Self::gmul(0x0b, column[2]) ^ Self::gmul(0x0d, column[3]);state[2][col] = Self::gmul(0x0d, column[0]) ^ Self::gmul(0x09, column[1]) ^ Self::gmul(0x0e, column[2]) ^ Self::gmul(0x0b, column[3]);state[3][col] = Self::gmul(0x0b, column[0]) ^ Self::gmul(0x0d, column[1]) ^ Self::gmul(0x09, column[2]) ^ Self::gmul(0x0e, column[3]);}}/// 将16字节块转换为4x4状态矩阵fn bytes_to_state(block: &[u8; 16]) -> [[u8; 4]; 4] {let mut state = [[0u8; 4]; 4];for i in 0..16 {state[i % 4][i / 4] = block[i];}state}/// 将4x4状态矩阵转换为16字节块fn state_to_bytes(state: &[[u8; 4]; 4]) -> [u8; 16] {let mut block = [0u8; 16];for i in 0..16 {block[i] = state[i % 4][i / 4];}block}/// 加密单个16字节块pub fn encrypt_block(&self, block: &[u8; 16]) -> [u8; 16] {let mut state = Self::bytes_to_state(block);// 初始轮密钥加Self::add_round_key(&mut state, &self.w, 0);// 主轮(前Nr-1轮)for round in 1..self.rounds {self.sub_bytes(&mut state);self.shift_rows(&mut state);self.mix_columns(&mut state);Self::add_round_key(&mut state, &self.w, round);}// 最终轮(无列混合)self.sub_bytes(&mut state);self.shift_rows(&mut state);Self::add_round_key(&mut state, &self.w, self.rounds);Self::state_to_bytes(&state)}/// 解密单个16字节块pub fn decrypt_block(&self, block: &[u8; 16]) -> [u8; 16] {let mut state = Self::bytes_to_state(block);// 初始轮Self::add_round_key(&mut state, &self.w, self.rounds);self.inv_shift_rows(&mut state);self.inv_sub_bytes(&mut state);// 主轮(前Nr-1轮)for round in (1..self.rounds).rev() {Self::add_round_key(&mut state, &self.w, round);self.inv_mix_columns(&mut state);self.inv_shift_rows(&mut state);self.inv_sub_bytes(&mut state);}// 最终轮Self::add_round_key(&mut state, &self.w, 0);Self::state_to_bytes(&state)}// ---------- PKCS7 填充辅助函数 ----------/// PKCS7填充fn pkcs7_pad(data: &[u8]) -> Vec<u8> {let padding_length = 16 - (data.len() % 16);let mut padded_data = Vec::with_capacity(data.len() + padding_length);padded_data.extend_from_slice(data);padded_data.extend(std::iter::repeat(padding_length as u8).take(padding_length));padded_data}/// 去除PKCS7填充fn pkcs7_unpad(data: &[u8]) -> Vec<u8> {if data.is_empty() || data.len() % 16 != 0 {panic!("Invalid padded data: length must be non-zero and multiple of 16");}let padding_length = data[data.len() - 1] as usize;if padding_length == 0 || padding_length > 16 {panic!("Invalid padding length: {}", padding_length);}// 验证所有填充字节for &byte in &data[data.len() - padding_length..] {if byte as usize != padding_length {panic!("Invalid padding bytes");}}data[..data.len() - padding_length].to_vec()}pub fn encrypt(&self, plaintext: &[u8]) -> Vec<u8> {let padded_data = Self::pkcs7_pad(plaintext);let mut ciphertext = Vec::with_capacity(padded_data.len());for chunk in padded_data.chunks(16) {let block: [u8; 16] = chunk.try_into().unwrap();ciphertext.extend_from_slice(&self.encrypt_block(&block));}ciphertext}pub fn decrypt(&self, ciphertext: &[u8]) -> Vec<u8> {if ciphertext.len() % 16 != 0 {panic!("Ciphertext length must be multiple of 16 bytes");}let mut decrypted_data = Vec::with_capacity(ciphertext.len());for chunk in ciphertext.chunks(16) {let block: [u8; 16] = chunk.try_into().unwrap();decrypted_data.extend_from_slice(&self.decrypt_block(&block));}Self::pkcs7_unpad(&decrypted_data)}
}/// 将字节数组转换为十六进制字符串
fn bytes_to_hex(bytes: &[u8]) -> String {bytes.iter().map(|byte| format!("{:02x}", byte)).collect::<Vec<String>>().join("")
}fn main() {let key = b"chenxingAES_Rust";let aes = AES::new(key);let plaintext = b"He who conquers others is strong; he who conquers himself is mighty.";// 加密let ciphertext = aes.encrypt(plaintext);println!("Ciphertext (hex): {}", bytes_to_hex(&ciphertext));// 解密let decrypted = aes.decrypt(&ciphertext);println!("Decrypted: {}", String::from_utf8_lossy(&decrypted));// 验证assert_eq!(plaintext, decrypted.as_slice());println!("Successfully!!!");
}#[cfg(test)]
mod tests {use super::*;#[test]fn test_aes_round_trip() {let key = b"chenxingAES_Rust";let aes = AES::new(key);let test_data = b"Test AES encryption and decryption";let encrypted = aes.encrypt(test_data);let decrypted = aes.decrypt(&encrypted);assert_eq!(test_data, decrypted.as_slice());}#[test]fn test_single_block() {let key = b"chenxingAES_Rust";let aes = AES::new(key);let block = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff];let encrypted = aes.encrypt_block(&block);let decrypted = aes.decrypt_block(&encrypted);assert_eq!(block, decrypted);}
}

参考资料

​ 很庆幸,在各位前辈的基础上,我们得以很便捷地得到相关知识的干货,也很推荐读者读一下其他师傅的相关博客,完善程度以及过程分析超级高。

[1]AES加密算法原理的详细介绍与实现-CSDN博客

http://www.dtcms.com/a/533155.html

相关文章:

  • (五)图文结合-详解BLE连接原理及过程
  • 资产管理公司网站建设费用怎么入账电子商务行业发展趋势及前景
  • 机器学习日报05
  • 成都公园城市建设局网站seo诊断分析工具
  • 算法基础 典型题 数学(基础)
  • 网站开发运作wordpress数据库字典
  • 博州住房和城乡建设部网站wordpress开发教程
  • 邢台123网站模板百度推广官方投诉电话
  • 找网站开发人员wordpress ftp附件
  • Xshell 总是在最前端显示
  • 湖北省建设厅官方网站文件网站建设方案书写
  • 网站的成功案例wordpress 登陆白屏
  • 网站开发代码语言网站蜘蛛抓取
  • 斯坦福大学 | CS336 | 从零开始构建语言模型 | Spring 2025 | 笔记 | Lecture 6: Kernels,Triton
  • 【第十九周】自然语言处理的学习笔记04
  • 巴中住房和城乡建设局网站wordpress.exe
  • 7-SpringCloud-服务网关 Gateway-高级特性 Route
  • wordpress建站文本教程公司门户网站是什么
  • 淘宝商品详情 API 在品牌假货识别与维权中的技术应用与实践
  • docker容器内部署flask
  • 手机玩win游戏:Termux安装box86+wine运行windows游戏,仙剑四测试完美通过!
  • 网站首页改版影响优化网站开发 京东
  • 西安米德建站平面设计网站建设
  • 北京专业网站建设公司哪家好手表哪个网站做的好
  • Vue3 Props
  • 数字信号处理——傅里叶变换
  • C++中使用gRPC over Unix Domain Sockets的高性能进程间通信技术解析
  • 量价分析模型
  • 网建网站昆明长尾词seo怎么优化
  • 【攻防实战】Redis未授权RCE联动metasploit打穿三层内网(下)