参考文档:【加密算法】AES
1. 密钥
密钥是AES算法实现加密和解密的根本。对称加密算法之所以对称,是因为这类算法对明文的加密和解密需要使用同一个密钥。
AES支持三种长度的密钥:128位,192位,256位
平时大家所说的AES128,AES192,AES256,实际上就是指的AES算法对不同长度密钥的使用。
2. 填充
要想了解填充的概念,我们先要了解AES的分组加密特性。
什么是分组加密呢?我们来看看下面这张图:
AES算法在对明文加密的时候,并不是把整个明文一股脑加密成一整段密文,而是把明文拆分成一个个独立的明文块,每一个明文块长度 128bit(16byte)。
这些明文块经过 AES 加密器的复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的 AES 加密结果。
但是这里涉及到一个问题:
假如一段明文长度是 192bit,如果按每 128bit 一个明文块来拆分的话,第二个明文块只有 64bit,不足 128bit。这时候怎么办呢?就需要对明文块进行填充(Padding)。
AES加密的填充方式:
- NoPadding:不做任何填充,但是要求明文必须是 16 字节的整数倍,一般不会使用。
- PKCS5Padding(默认):如果明文块少于 16 个字节(128bit),在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。
比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为 - PKCS7Padding:对于 AES 来说 PKCS5Padding 和 PKCS7Padding 是完全一样的,不同在于 PKCS5 限定了块大小为 8bytes 而PKCS7 没有限定。在 AES 加密当中严格来说是不能使用 pkcs5 的,因为 AES 的块大小是 16bytes 而 pkcs5 只能用于 8bytes,通常我们在 AES 加密中所说的 pkcs5 指的就是 pkcs7!
- ZerosPadding:全部填充 0x00,无论缺多少全部填充 0x00,已经是 128bits 倍数仍要填充。
- ISO10126Padding:如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字节,最后一个字符值等于缺少的字符数,其他字符填充随机数。
比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则可能补全为
需要注意的是,如果在AES加密的时候使用了某一种填充方式,解密的时候也必须采用同样的填充方式。
3. 模式
AES 的工作模式,体现在把明文块加密成密文块的处理过程中。AES 加密算法提供了五种不同的工作模式:ECB、CBC、CTR、CFB、OFB
模式之间的主题思想是近似的,在处理细节上有一些差别。
- ECB 模式(默认):
电码本模式 Electronic Codebook Book - CBC 模式:
密码分组链接模式 Cipher Block Chaining - CTR 模式:
计算器模式 Counter - CFB 模式:
密码反馈模式 Cipher FeedBack - OFB 模式:
输出反馈模式 Output FeedBack
3.1 ECB 模式
ECB 模式(Electronic Codebook Book)是最简单的工作模式,在该模式下,每一个明文块的加密都是完全独立,互不干涉的。
这样的好处是什么呢?
- 简单
- 有利于并行计算
缺点同样也很明显:
- 相同的明文块经过加密会变成相同的密文块,因此安全性较差。
3.2 CBC 模式
CBC 模式(Cipher Block Chaining)引入了一个新的概念:初始向量IV(Initialization Vector)。
IV 是做什么用的呢?它的作用和MD5的“加盐”有些类似,目的是防止同样的明文块始终加密成同样的密文块。
从图中可以看出,CBC 模式在每一个明文块加密前会让明文块和一个值先做异或操作。IV 作为初始化变量,参与第一个明文块的异或,后续的每一个明文块和它前一个明文块所加密出的密文块相异或。
这样以来,相同的明文块加密出的密文块显然是不一样的。
CBC 模式的好处是什么呢?
- 安全性更高
坏处也很明显:
- 无法并行计算,性能上不如 ECB
- 引入初始化向量IV,增加复杂度。
4. 加密流程
加密会经历以下流程:
- 初始轮(Initial Round) 1次
- 普通轮(Rounds) N次
- 最终轮(Final Round) 1次
AES 的 Key 支持三种长度:AES128,AES192,AES256。Key 的长度决定了 AES 加密的轮数。
除去初始轮,各种 Key 长度对应的轮数如下:
- AES128:10轮
- AES192:12轮
- AES256:14轮
初始轮只有一个步骤:
- 加轮密钥(AddRoundKey)
普通轮有四个步骤:
- 字节代替(SubBytes)
- 行移位(ShiftRows)
- 列混淆(MixColumns)
- 加轮密钥(AddRoundKey)
最终轮有三个步骤:
- 字节代替(SubBytes)
- 行移位(ShiftRows)
- 加轮密钥(AddRoundKey)
接下来,我们对步骤进行详解
4.1 字节替代
首先需要说明的是,16 字节的明文块在每一个处理步骤中都被排列成 4X4 的二维数组。
所谓字节替代,就是把明文块的每一个字节都替代成另外一个字节。替代的依据是什么呢?
依据一个被称为 S 盒(Subtitution Box)的16X16大小的二维常量数组。
假设明文块当中 a[2,2] = 5B(一个字节是两位16进制),那么输出值b[2,2] = S[5][11]。
4.2 行位移
这一步很简单,就像图中所描述的:
- 第一行不变
- 第二行循环左移 1 个字节
- 第三行循环左移 2 个字节
- 第四行循环左移 3 个字节
4.3 列混淆
这一步,输入数组的每一列要和一个名为修补矩阵(fixed matrix)的二维常量数组做矩阵相乘,得到对应的输出列。
4.4 加轮密钥
这一步是唯一利用到密钥的一步,128bit 的密钥也同样被排列成 4X4 的矩阵。
让输入数组的每一个字节 a[i,j] 与密钥对应位置的字节 k[i,j] 异或一次,就生成了输出值 b[i,j]。
需要补充一点,加密的每一轮所用到的密钥并不是相同的。这里涉及到一个概念:扩展密钥(KeyExpansions)。
扩展密钥(KeyExpansions)
AES 源代码中用长度 4 * 4 *(10+1) 字节的数组 W 来存储所有轮的密钥。W{0-15} 的值等同于原始密钥的值,用于为初始轮做处理。
后续每一个元素 W[i] 都是由 W[i-4] 和 W[i-1] 计算而来,直到数组 W 的所有元素都赋值完成。
W 数组当中,W{0-15} 用于初始轮的处理,W{16-31} 用于第1轮的处理,W{32-47} 用于第2轮的处理 …一直到 W{160-175} 用于最终轮(第10轮)的处理。
解密流程基本是把加密流程倒置过来,顺序变为最终轮 -> 普通轮 -> 初始轮。扩展密钥的使用顺序也和加密相反。