对称加密算法之AES加密

对称加密算法之AES加密

简介

前世今生

​ AES全称Advanced Encryption Standard,也就是高级加密标准。

​ 在DES的安全性被发现存在明显缺陷后,亟需有另一种算法来替代DES。DES的56bit的密钥长度太小,虽然三重DES解决了密钥长度的问题,但是三重DES还是存在一些明显的缺陷。1997年4月15日,NIST发起征集AES算法的活动,目的是确定一个非保密的,公开披露的,全球免费使用的加密算法,来保护隐私,也能够替代DES。其基本要求就是:执行性能比三重DES快、至少和三重DES一样安全、数据分组长度为128bit、密钥长度为128/192/256bit。

​ 由比利时的Joan Daemen和Vincent Rijmen所设计的“Rijndael数据加密算法”最终获胜。

​ 经过时间的检验,至少到到目前为止,AES的安全性能是良好的。经过这么多年的分析和测试,至今没有发现AES的明显缺点,也没有找到明显的安全漏洞。如今,生活的很多领域也都用到了AES算法,如IPsec所使用的加密算法等。

一些特性

​ AES加密算法的分组长度只能为128bit,但是其密钥长度是可以变动的,分别可以为128bit/196bit/256bit三种类型。而根据不同的密钥长度,其加密轮数也会得到变化。如表所示。但目前比较广泛使用的是128bit长度的密钥

AES 密钥长度(32位比特字) 分组长度(32位比特字) 加密轮数
AES-128 4 4 10
AES-192 6 4 12
AES-256 8 4 14

​ 在初始状态会将明文和密钥分组中的128位再分为16组,每组一个字节。

​ 密钥虽然只有4个字(32bit,在任何条件都认为1字=4字节是不严谨的,会根据系统位数而产生差异,计算机进行数据处理时,一次存取、加工和传送的数据长度称为字),但是会根据此密钥产生额外40个字,分别用在十轮的加密过程中。

具体过程

过程总览

​ 如上图所示,加密的第一轮到第九轮的函数是一样的,都经过过字节代换、行移位、列混合、轮密钥加的四个阶段,但有两个特殊点,第一点是在第一轮之前,先要进行一次轮密钥加,先将明文和原始密钥进行一次轮密钥加的操作;第二是在第十轮时,没有列混合这一步骤。

​ 如果我们将明文所分成的十六个字节用以下矩阵表示,可能会好理解一点。

​ 其次是图中的w[]数组,也就是由原密钥拓展而来,w[0]-w[3]为原密钥的四个字,w[4]-w[43]则是由原密钥拓展而来,用于十轮的加密中。如下图所示。

 

字节代换

字节代换操作

​ 这本来是一个计算的过程,但可以将字节代换的各种可能字节的变换结果排成一个表,也就是AES中的S盒,如下图

​ 对于一个输入0xXY(XY分别表示一个十六进制的数,两个组合起来表示一个字节),X为行向量,Y为列向量,查找在表中的位置。比如对于0x57,在表中查找到结果:0x5b

​ 矩阵表示如下

字节代换逆操作

​ 很显然,上面那个正向操作是加密时需要用到的,那么对于解密过程,也同样有其逆运算过程,但是也跟上面的正向操作一样。对于各种变换操作,可以制成一个表,也就是逆S盒,如下表

行移位

​ 对行移位,用矩阵也很好解释。

​ 看图即可,可以说尽在不言中了。

对于行移位的逆变换:

​ 行移位的逆变换也就是将状态矩阵中的每一位执行相反的操作,也就是状态矩阵的第一行右移零个字节,第二行右移1个字节,第三行右移2个字节,第四行右移3个字节。

列混合

列混合运算

​ 列混合就是通过矩阵相乘来实现的,把经过移位后的矩阵与固定矩阵相乘,来得到混淆后的状态,如图所示

​ 但注意,这个矩阵相乘的过程跟普通的乘法过程并不相同,其结果的第j列可以如下图所示来计算,可以看到,矩阵运算中加法等价于两字节异或、乘法则是GF(2^8)乘法。

一点知识补充

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

这里需要引入一点数学知识了,来描述xtime()运算
首先,要知道有限域GF(2^8)的概念。GF域的名字很好听,叫伽罗华域
- 什么是有限域,形象地说,域有这样一个性质:在加法和乘法上具有封闭性。也就是说对域中的元素进行加法或乘法运算后的结果仍然是域中的元素。
- 对于GF(2),比较好理解,也就是mod2之后,其值一定在[0.1]之间。
- 那么推广到GF(p),也就是modp之后,其值一定在p[0.p-1]之间,所以p一定要素数,这个也很好理解。
- 对于一个字节有8位对吧,也就是能表示的十进制最大值为255,所以我们希望其值位于0-255之间,所以要mod256。但是显然,256并不是一个质数,并不能得到我们想要结果。这时候如何解决呢?
- 多项式运算与素多项式,这里我们引入了多项式来表达一个字节中不同的位。对于一个字节,假设其为'b7b6b5b4b3b2b1b0',那么就可以看成多项式的系数b7x^7+b6*x^6+b5*x^5+b4*x^4+b3*x^3+b2*x^2+b1*x^1+b0。而多项式运算跟普通的加加减法乘除法还是很不一样的,这就给了用来解决这一问题的契机。至于素多项式,就是用多项式表示的素数的意思了。那么至于为什么mod素多项式就可以表示整个数据段的原理我还是不是特别明白。
- 有限域GF(2^8),那么此时终于能够解释这个的完整含义了。显然其意义在于,使8位bit具有封闭性,处于一个有限域中。那么可以确定一个素多项式x^8 + x^4 + x^3 +x +1,不止这一个,但一般用这个。
- 介绍完GF(2^8)了,下一步就是xtime运算了。xtime运算是用来干嘛的呢。我们回到刚才的多项式乘法,显然对于多项式乘法,我们可以使用多项式直接相乘后,除以素多项式即可,也就是mod的操作。为什么乘了又除的,很显然,在完成乘法之后,其多项式表示的值已经超过了有限域了。所以需要mod运算取余数。
- 既然讲到了这里,那还是要讲一下多项式除法的运算,也就是多项式中的mod运算。直接讲多项式除法不知道怎么讲,等会在附录中直接上例子吧。
- xtime():说了这么多,终于说到xtime()运算了,其实说白了,xtime()运算不过是计算多项式乘法的一种技巧运算罢了。如果你自己本来就会多项式乘法运算的话是不一定需要记这个东西的。记得多了反而加重了记忆负担,过一段时间就不明所以了。但是,显然这是相较于真人而言的。对于计算机来说,实现多项式乘法并不方便,而使用移位和异或运算相结合的xtime()运算就可以很方便的在计算机中实现。所以,xtime()是为计算机计算多项式乘法而生的。
- 为什么xtime()运算可以简化多项式乘法,我们看一下两个普通的多项式乘法:
 - '57'·'13'拆分成二进制的话就是01010111·00011001=01010111·(00010000+00001000+00000001)=01010111·00010000+01010111·00001000+01010111·00000001。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

​ 终于把基础的数学知识给补充完了,那么接下来就是具体介绍,计算机如何实现多项式乘法了。

  • 显然,任何值*0x01=自身

  • 其次,任何值*0x02,也就是上面的例子中01010111·00000010,我们先从它本来的应用去理解,如果把它看作多项式乘法(x^6+x^4+x^3+x^2+x^1+1)*x的话,x^7+x^5+x^4+x^3+x^2+x,得到10101110,也就是对前面的那个二进制表示进行了左移一位的操作。其实我们的xtime()运算,就是*0x02的操作。移位后还有个判断其是否越界的过程,如果越界了直接减去素多项式即可。有人要问了,不是进行mod吗,为什么减去素多项式m(x)就可以了,显然因为我们只左移了一位,再大也不会大到哪里去。直接减去素多项式m(x)即可得到余数。

  • 一个左移操作即可覆盖到所有的多项式子。我们再看任何值*0x04,也就是假如说01010111·00000100,显然完成了*0x02,左移一位后,再左移一位即可。也就是对上诉*0x02得到的结果进行一个xtime()运算就可以了。所以对于对于后面的这些数,不过就是一个累计迭代的过程。

  • 在上面的tip中我们也讲了,任何一个数字都可以分解成上诉那种形式,也就可以很轻易地使用xtime运算来完成多项式乘法了。

    那么讲到这一步,列混合到底是什么才算讲清楚了。

列混合逆运算

​ 那么用于解密的时候所使用的逆运算也就如下

也是多项式乘法,用上诉教授的多项式乘法的方法计算即可。

轮密钥加

所谓轮密钥加,也就是将128位的轮密钥Ki同状态矩阵中的数据进行逐位异或操作,如下图所示。注意,这是字逐位异或的结果,也就是S0 S1 S2 S3 组成的32位字与密钥字W[4i]的异或运算。

轮密钥加的逆运算同正向的轮密钥加运算完全一致,这是因为异或的逆操作是其自身。轮密钥加非常简单,但却能够影响S数组中的每一位。

密钥拓展

可以看到,除了跟轮密钥运算的操作外,其余的操作基本都是些混淆运算,所以真正让整个加密不具有线性结构的操作也就是轮密钥加的操作。密钥只有128bit,不可能对每一轮的运算都使用同一个密钥对吧,所以此处要根据原密钥,对密钥进行混淆,进行拓展。

怎么做呢,如下图所示

首先AES会将初始密钥输入到一个4*4的状态矩阵中,每一个元素都代表一个字节。在这个矩阵中,每一列的4个字节组成一个字,并分别命名为W[0]、W[1]、W[2]、W[3]。

在此基础上,接着就会对W数组扩充出另外的40个元素,新元素产生的递归方式如下(也可以看图):


1.如果i不是4的倍数,那么第i列由如下等式确定:
W[i]=W[i-4]⨁W[i-1]
2.如果i是4的倍数,那么第i列由如下等式确定:
W[i]=W[i-4]⨁T(W[i-1])

其中T运算一个相对复杂的运算,也需要用到S盒以及另一组了轮常量Rcon[j]。

函数T由3部分组成:字循环、字节代换和轮常量异或,这3部分的作用分别如下。
a.字循环:将1个字中的4个字节循环左移1个字节。即将输入字[b0, b1, b2, b3]变换成[b1,b2,b3,b0]。
b.字节代换:对字循环的结果使用S盒进行字节代换。
c.轮常量异或:将前两步的结果同轮常量Rcon[j]进行异或,其中j表示轮数。

Rcon[j]具体值如下

讲到这里,AES就算讲得差不多了。

 

posted @ 2022-03-13 22:09  三木森林  阅读(762)  评论(0编辑  收藏  举报