AES加密算法是密码学中的高级加密标准,AES为分组加密法,把明文分成一组一组的,每组长度相等,每次加密一组数据,直到加密完整个明文,在AES标准规范中,分组长度只能是128位,AES是按照字节进行加密的,也就是说每个分组为16个字节(每个字节8位)。密钥的长度可以使用128位、192位或256位。这导致密钥长度不同,推荐加密的轮数也不同。
AES算法思想:
1)设计简单;
2)在多个平台上速度快,编码紧凑;
3)抵抗所有已知攻击;
4)没有采用Feistel结构,轮函数由3个不同的可逆均匀变换构成:非线性层、线性混合层和密钥加层。
AES算法常用于微信小程序加密传输,是最常见的对称加密算法(加密和解密用相同的密钥)之一 .
下面简单介绍下各个部分的作用与意义:
明文P
- 没有经过加密的数据。
密钥K
- 用来加密明文的密码,在对称加密算法中,加密与解密的密钥是相同的。密钥为接收方与发送方协商产生,但不可以直接在网络上传输,否则会导致密钥泄漏,通常是通过非对称加密算法加密密钥,然后再通过网络传输给对方,或者直接面对面商量密钥。密钥是绝对不可以泄漏的,否则会被攻击者还原密文,窃取机密数据。
AES加密函数
- 设AES加密函数为E,则 C = E(K, P),其中P为明文,K为密钥,C为密文。也就是说,把明文P和密钥K作为加密函数的参数输入,则加密函数E会输出密文C
密文C
- 经加密函数处理后的数据
AES解密函数
- 设AES解密函数为D,则 P = D(K, C),其中C为密文,K为密钥,P为明文。也就是说,把密文C和密钥K作为解密函数的参数输入,则解密函数会输出明文P。
关键变量
1. data(明文):需要加密的数据;
2. aesKey(密钥):用于生成独特的加密规则;
3. IV(向量/偏移量):辅助生成独特的加密规则(也可以不用,建议使用,可以提高安全性);
4. charEncoding(字符编码格式):设置加密所用的字符编码格式(基本上都使用 Utf8 ,前后端都能识别);
AES算法原理
密钥
密钥是AES算法实现加密和解密的根本。对称加密算法之所以对称,是因为这类算法对明文的加密和解密需要使用同一个密钥。
AES支持三种长度的密钥:
128位,192位,256位
平时大家所说的AES128,AES192,AES256,实际上就是指的AES算法对不同长度密钥的使用。
填充
要想了解填充的概念,我们先要了解AES的分组加密特性。什么是分组加密呢?我们来看看下面这张图:AES算法在对明文加密的时候,并不是把整个明文一股脑加密成一整段密文,而是把明文拆分成一个个独立的明文块,每一个明文块长度128bit。
这些明文块经过AES加密器的复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的AES加密结果。
假如一段明文长度是192bit,如果按每128bit一个明文块来拆分的话,第二个明文块只有64bit,不足128bit。这时候怎么办呢?就需要对明文块进行填充(Padding)。
填充涉及以下三种填充模式:
- NoPadding:不做任何填充,但是要求明文必须是16字节的整数倍。
不做任何填充,但是要求明文必须是16字节的整数倍。
- PKCS5Padding(默认):
如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。
比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6}
- ISO10126Padding:
如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字节,最后一个字符值等于缺少的字符数,其他字符填充随机数。
比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则可能补全为{1,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6}
常见的加密模式包括:
ECB(Electronic Codebook)模式:将每个分组独立加密,适用于对称性较弱的数据。
CBC(Cipher Block Chaining)模式:前一个分组的密文与当前分组的明文进行异或操作后再加密,增加了分组之间的关联性。
CTR(Counter)模式:通过使用计数器生成密钥流,将密钥流与明文进行异或操作得到密文。
AES算法流程
16字节明文按照此顺序放入矩阵,规则为:从上到下,从左到右,依次进行。
同样的,密钥K也需要分组,原理与明文P相同,下图为128位密钥矩阵:
大概流程:
AddRoundKey (轮密钥加)— 矩阵中的每一个字节都与该次轮密钥(round key)做XOR运算;每个子密钥由密钥生成方案产生。
SubBytes(字节替代) — 通过非线性的替换函数,用查找表的方式把每个字节替换成对应的字节。
ShiftRows(行移位) — 将矩阵中的每个横列进行循环式移位。
MixColumns (列混淆)— 为了充分混合矩阵中各个直行的操作。这个步骤使用线性转换来混合每列的四个字节。
以上为AES在加密中的大致流程。
AES加密算法涉及4种操作:字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。下图给出了AES加解密的流程,从图中可以看出:
1、解密算法的每一步分别对应加密算法的逆操作;
2、加解密所有操作的顺序正好是相反的。正是由于这几点(再加上加密算法与解密算法每步的操作互逆)保证了算法的正确性。加解密中每轮的密钥分别由种子密钥经过密钥扩展算法得到。算法中16字节的明文、密文和轮子密钥都以一个4x4的矩阵表示。
注意: 根据密钥长度不同,加密的轮数也不同,在第一轮之前要进行轮密钥加,最后一轮没有进行列混淆操作。
字节替换:
属于非线性替换,具体原理就是通过一个替换表(S盒)对每个字节进行替换,实际上就是一个查表操作,并且此过程可逆,将每一个字节的前4位作为行值,后4位作为列值,去S盒查找,进行输出。
下图为S盒(x表示行,y表示列),例如字节为0x14,那么前四位的16进制为1,后四位的16进制为4,去查找s盒中的第1行第4列的值,可以看出为0xfa,就把原先的字节0x14替换为0xfa。
解密过程与此相同,唯一就是采用的是逆S盒。
行位移:
对于4*4的矩阵,操作为:
第0行:保持不动;
第1行:循环左移1个字节;
第2行:循环左移2个字节;
第3行:循环左移3个字节。
解密过程变为循环右移,每行移动字节数与加密过程相同,下图为列位移示意图。
列混淆:
实际上为44的矩阵与另一个44矩阵异或相乘(注意为右乘操作),重新得到一个4*4的矩阵,如下图所示。
解密过程为重新与此矩阵异或,因为两次异或得到的值为原数据本身。
轮密钥加
轮密钥与状态矩阵进行逐比特异或操作。
这个轮密钥是由种子密钥通过密钥编排算法得到的,并且轮密钥长度与分组长度相同。
解密过程与之相同,两次异或得到原始数据。
密钥编排算法基本规则:
1)轮密钥的比特数等于分组长度乘以轮数加1;
例如:将128位比特明文进行加密,总共需要(10+1)*128=1408比特密钥。
2)种子密钥扩展为扩展密钥;
3)轮密钥从扩展密钥中取,第一轮取扩展密钥的第0~3列,依次类推。
过程为:
定义:w[0]~w[3]为初始密钥
如果i=4的倍数,即i为每组的第一列,则执行以下3个步骤
1)将w[i-1]循环左移一个字节:
w’[i]=w[i-1]左移一个字节得到。
w’[4]=w[3]左移一个字节得到={09,cf,4f,3c}左移一个字节={cf,4f,3c,09}
2)分别对w’[i]的每个字节进行S盒替换,本质上就是查表,再替换为另一个字节。
即查表后为w’‘[i]。
例如,w’[4]查表后的w’'[4]={8a,84,eb,01},需s盒的自行查看。
3)将前两步的结果同轮常量Rcon[j]进行异或,j表示轮数,Rcon[j]如下图所示
那么w[i]=w[i-4]⊕w’[i]⊕Rcon[j],此时j=1,因为为第一轮。
即w[4]=w[0]⊕w’‘[4]⊕Rcon[1],
那么w[8]=w[4]⊕w’'[8]⊕Rcon[2],……
如果i≠4的倍数,即i为每组的第二、三、四列,则执行以下一个步骤
即w[i]=w[i-4]⊕w[i-1]
例如w[5]=w[1]⊕w[4],w[6]=w[2]⊕[5],……
最终的到一个扩展密钥:{w[4],w[5],w[6],w[7]},之后的每一轮密钥都是在前一轮基础上形成的。
常遇问题
以下是一些可能导致结果不一致的原因:
加密工具使用的是不同的加密算法或加密模式,例如CBC、CFB、OFB等等。
加密工具使用的是不同的填充方案,例如PKCS#5、PKCS#7、ISO 10126等等。
加密工具对原始数据进行了预处理或后处理,例如添加了Salt或IV。
加密工具在进行加密时使用了不同的编码方式,例如Base64、Hex、UTF-8等等。