# AES128加解密流程详细介绍
公司想要对嵌入式设备里的文本进行加密,只能用AES128试试,经过一上午的了解,整理了下流程。
参考文章: AES加密 https://zhuanlan.zhihu.com/p/125633081 https://www.sohu.com/a/278722262_100245441
AES加密每次只能加密16字节,我们先要学会如何对16字节数据进行加密,学会之后再学习大文件加密就简单多了。
下面介绍如何对16字节数据进行加密。
AES加密开始前要准备的东西
1、你要加密的16字节数据
只能是16字节哦,不足16字节会有相应的补位方法,后面会讲。超过16字节那就拆分成N块16字节,每块分别加密。
2、只有你和对方知道的16字节密钥
千万不要弄丢了,要保存好。
先看一下AES整个流程
AES加密第一步:轮密钥加先把要加密的明文16字节数据排列成4x4矩阵
再把16字节密钥也排列成4x4矩阵
然后两个4x4矩阵相加(每个字节相异或)
这样就完成了轮密钥加,记住这个步骤,并把这个步骤编成模块,后面还要用。
加密第二步:字节代替字节代替也叫做S盒变换 AES有个固定的S盒,下图即为S盒
把第一步轮密钥加后产生的每一个字节用十六进制表示 然后以十六进制的第一个数字为行,第二个数字为列,在S盒表中查找对应的数字,用这个数字来代替原先的数字,这样就完成了字节变换。(比如原字节为0x1a,就以1为行,a为列,找到表中对应的0xa2来代替0x1a的位置)
加密第三步:行移位
就是把上一步得到的矩阵每行左环移,第一行不变,第二行环移1位,第三行环移2位,第三行环移3位。
加密第四步:列混淆
将上一步得到的矩阵a左乘矩阵c,得到新的矩阵b。 这里的矩阵c是固定的,如下,应该是AES标准规定的。
注意这个乘法不是通常的10进制乘法,观察这个矩阵,里面有三种数字1,2,3,假如一个数y左乘他们其中一个,下面分三种情况介绍:
1 * y = y2 * y 时,如果 y 的首位为0,则 2 * y = y << 2 , 如果 y 的首位为1,则 2 * y = ( (y<<
1) & ( (1<<
8) - 1) ) ^ (0x1b)3 * y = (2 * y) ^ y
(2 * y 的计算方法在上面已经讲了,这里再异或一下 y 就行) 其他情况的数以此类推,都把乘数拆分成1,2,3的积或和形式再用乘法分配律,比如 9 * y = (2 * 2 * 2 + 1) * y = (2 * 2 * 2 * y) ^ (1* y)
加密第五步:再来一遍轮密钥加步骤还是第一步那个步骤,把上一步产生的4x4矩阵与4x4密钥相加,但是这里要加的密钥不再是那个原始密钥了,新的密钥要通过那个原始密钥计算产生,下面讲一下计算方法。
用原始密钥生成扩展密钥的方法如下图所示
这里的K矩阵就是原始密钥,把每一列用4维向量w来表示,就拆分成了w0,w1,w2,w3,将w3进行g中的运算,先是把4个字节左环移,然后对这4个字节进行S盒变换,S盒变换在上面已经介绍过了,变换完后,最左面的字节与RCj相加,AES128加密要把以上步骤进行10轮,RCj在每一轮的计算中都不一样,具体如下
这里我们进行第一轮,就把RCj取01,相加完成后,将得到的w'与w0相加,产生w4,将w4与w1相加产生w5,将w5与w2相加产生w6,将w6与w3相加产生w7,这样,新一轮的密钥诞生了,他就是w4,w5,w6,w7
将新密钥与第四步得到的数据相加,就完成了这一步的轮密钥加。
这个计算后面还要用,编写成模块等待调用。
加密第六步:将以上步骤重复10轮,就可以得到密文注意最后一轮不要再列混淆了,最后得到的结果就是16字节的密文。
下面说解密过程
学会加密过程,解密过程就很容易理解了。
我们之前在每一轮的“轮密钥加”中得到的4个word新密钥都要保存下来,把原始密钥放到最前面,后面10轮产生的密钥依次排列,得到44 word的数组,(这里默认1个word等于4个byte),这个44 word的数组就叫做“扩展密钥”。
解密过程也是进行10轮,但每一轮的“轮密钥加”使用的4个word密钥是在这个44 word的扩展密钥中从后往前取,每次取4个word(注意这4个word之间不用再逆序了)。
解密第一步:轮密钥加将4x4密文与扩展密钥的最后4word相加,得到4x4矩阵
解密第二步:逆向行移位将加密步骤里的行移位的移位顺序反向操作即可
解密第三步:逆向字节代替将上一步中得到的4x4矩阵中的每个元素用逆向s盒中对应的元素代替,代替方法和加密过程中的一样,逆向S盒如下所示
const byte Inv_S_Box[256] =
{
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
};
解密第四步:轮密钥加这里使用的密钥就是从扩展密钥中接着第一步中的“轮密钥加”再往前数4个word,与上一步产生的4x4矩阵相加。
解密第五步:将以上步骤重复10轮,就可以得到解密后的明文注意最后一轮不要再逆向列混淆了。
以上我们只学会了对16字节数据加密和解密,但是一个文件不可能只有16字节,如何对整个文件进行加密和解密,下面进行介绍。
方法一:电子密码本 / ECB可能有人想到将一个文件分成多个16字节的小块,对每一块进行加密再拼到一起不就可以了,这种加密方式叫做“电子密码本 / ECB”,如下图所示
下面就可以看看这样做对图片加密的效果
左边是源文件,右面是将源文件按顺序对每个16字节的小块分别加密再拼到一起后的效果,结果发现加密并没起什么作用,还是能看出来这是一只企鹅。
为什么会造成这种结果,原因很简单,16字节白色小块加密完是一种固定模式,16字节黑色小块加密完是一种固定模式,16字节黄色小块加密完是一种固定模式,这三种固定模式按原图顺序排列,还是能把企鹅的轮廓勾勒出来。
ECB模式的优点:简单、快速、支持并行计算(加密、解密) ECB模式的缺陷:明文中的重复排列会反应在密文中,通过删除、替换密文分组能够对明文进行操作,对包含某些比特错误的密文进行解密时,对应的分组会出错;不可以抵御重放攻击。
那能不能让同一种颜色的小块加密完不再是同一种模式,答案是能,下面介绍几种常用的方法。
方法二:密码块链接 / CBC方法如下图
图中的CIPHk就是对输入的4x4字节矩阵AES加密那10轮的整个过程,CIPH-1k就是AES解密整个过程,好理解吧。
可以看到在加解密的开始处出现了一个 initialization vector,简称IV,即初始向量,这个初始向量也是一个4x4矩阵,里面的内容是用户自己定义的,类似于密钥,注意这个初始向量的地位和密钥同等重要,一旦弄丢了就解不了密了,所以要好好保存。
加密步骤就是将用户自定义的初始向量与第一个4x4的明文块相加,然后进行AES加密得到第一个密文块,再用这第一个密文块与第二个明文块相加,再用AES加密得到第二个密文快,重复此步骤直到整个文件结束,将得到的第一个密文块、第二个密文块、、、按顺序排列起来就得到加密后的文件。
我们看看对那只企鹅图片按此方法加密后的效果
是不是完全看不出来这是一只企鹅了,加密成功。
加密学会了,解密按照上图的解密步骤进行就可以,很简单,注意解密用的初始向量和密钥一定要和加密时候的初始向量和密钥保持一致。
CBC模式优点:明文的重复排列不会反应在密文中;支持并行计算(仅解密);可以解密随意密文分组。 CBC模式缺陷:对包含某些错误比特的密文进行解密时,第一个分组的全部比特以及后一个分组的相应比特会出错;加密不支持并行计算。
方法三:密文反馈 / CFB
详细讲解一下此方法的加密流程:
1、首先把源文件分成多个s bits的小块,与前两种方法不同,前两种方法是将源文件拆分成4x4字节的小块,是以字节为单位,而CFB方法则是以bit为单位,将源文件分成s bits的小块(常用的数据段长度s有:1bit, 8bits 和128bits)。
2、然后对4x4的初始向量进行AES加密,得到的结果也是4x4,共16字节,128位,将这128 bits拆分成前s bits 和后(128-s)bits,取前s bits与第一个密文块(也是s bits长度)相加,相加后得到了一个s bits长度的结果,这个结果就是第一个密文块。对初始向量加密的后(128-s)bits 不要扔,下一步用。
3、上一步中,对初始向量加密的后(128-s)bits 与第一个密文块(s bits长)拼接到一起,又成了一个4x4,16字节,128位的数据块,然后继续对这个数据块进行AES加密,得到的128位数据继续拆分成前s和后128-s长的两段,前s bits与第二个s bits长的明文块相加得到第二个密文块。
4、重复上述步骤直到整个文件结束。
5、把得到的这些s bits长度的密文小块拼接到一起就成了密文。
简要介绍此方法的解密流程:
加密学会了,解密就好办了
1、首先对IV进行AES加密(你没看错,就是加密)
2、加密后结果拆分成前s bits与后(128-s)bits,都留着不要扔
3、前s bits与第一个s bits长度的密文块相加得到第一个s bits长度的明文块
4、上一步没扔的(128-s)bits与第一个密文块拼接成4x4字节的矩阵继续进行AES加密
5、重复上述步骤直到文件结束
6、将这些s bits长度的明文块拼接到一起,就得到了整个明文。
此方法与上两个方法的不同之处在于:
1、在上两个方法中,我们第一步做的都是对明文块进行加密,但在这个方法中,变成了首先对IV进行AES加密。
2、上两个方法是把源文件分成多个4x4也就是16字节的小块进行处理,但是这个方法是把源文件分成多个s bits的小块进行处理,以这种方法分段的好处是方便对以bit位单位的流媒体进行加解密。
3、上两个方法的解密过程都需要进行AES解密,但在这个方法中,无论是加密还是解密,全都使用AES加密,这样就能使程序结构简单化
CFB模式的优点:不需要填充(填充是什么,后面会讲);支持并行计算(仅解密);可以解密任意密文分组。 CFB模式的缺陷:加密不支持并行计算;对包含某些错误比特的密文进行解密时,第一个分组的全部比特以及后一个分组的相应比特会出错;不可以抵御重放攻击(重放攻击以后会讲)。
方法四:输出反馈 / OFB
这个看图就知道了,与上一个方法比简单好多
加密方法步骤(总共就三步超级简单):
1、如果存储空间足够的话,先不用明文参与计算,直接对初始向量进行AES加密,然后将加密后的结果再进行加密,得到n个输出块,如下图圈起来的部分
2、然后再让明文参与计算,让每一个明文块与上一步得到的n个输出块相加,就得到了n个密文块 如下图圈起来的部分
3、把这n个密文块拼到一起就得到了密文。
解密方法步骤也是超级简单
加密过程对初始向量进行循环AES加密后得到的n个数据块如果没有扔掉,这里直接拿来与n个密文块相加,得到的明文块拼接到一起就得到了明文,超级简单。
OFB模式的优点:不需求填充;可事前进行加密、解密的预备;加密、解密运用相同结构;对包含某些错误比特的密文进行解密时,只要明文中相对应的比特会出错。 OFB模式的缺陷:不支持并行计算、主动攻击者发转密文分组中的某些比特时,明文分组中相对应的比特也会被反转。
方法五:计数器模式 / CTR
首先看图,这里发现初始向量不见了,是不是很高兴能少记一个东西,
其实不然啊,看着好像是不见了,其实那个counter1就是初始向量,被骗了吧。
和上面几个方法一样,首先要定义一个4x4,共16字节,128bits的初始向量,然后再把这个初始向量任意分成两段,通常平分两半,每段64 bits,前半段不变,后半段加1就变成了counter2,再加1就变成了counter3,以此类推,这些counter就全都求出来了。因为后面的counter都是由第一个counter推出来的,所以只要记住counter1就行,就相当于初始向量。
加密步骤 1、对每个counter进行AES加密得到n个数据块
2、将这n个数据块与n个原文段相加,就得到了n个密文段
3、将这n个密文段拼到一起就成了密文
解密步骤 不再啰嗦了,记住counter1和AES的密钥,按步骤运算就行
CTR模式的优点:不需要填充、可事前进行加密、解密的预备、加密、解密运用相同结构、对包含某些错误比特的密文进行解密时,只要明文中相对应的比特会出错;支持并行计算(加密、解密) CTR模式的缺陷:主动攻击者反转密文分组中的某些比特时,明文分组中相对应的比特也会被反转。
以上就是对文件进行加密的通用方法,但是还有个问题,就是如果按照16字节对文件进行分块,最后一块不够16字节怎么办,这就需要进行填充,把不够的那一块填充成16字节。填充的方法有多种,下面进行介绍。
第一种,NoPadding就是不填充,就是逗你玩
第二种,PKCS#7缺n个字节,就在后面填n个n 比如最后一块只有13个字节,缺3个字节,就在后面填0x03 0x03 0x03 注意最后一块如果正好16个字节的话,也要再填充16个字节,0x10 0x10 0x10...0x10,否则无法解密。
第三种,ZerosPadding全部填充0x00,无论缺多少全部填充0x00,已经是128bits倍数仍要填充
第四种,ISO 10126最后一个字节是填充的字节数(包括最后一字节),其他全部填随机数
第五种,ANSI X9.23跟ISO 10126很像,只不过ANSI X9.23其他字节填的都是0而不是随机数
以上就是对文件进行AES加解密的全部方法,每种方法的攻击破解方法以后有机会再讲。