AES加解密算法详解

0 AES简介

  美国国家标准技术研究所在2001年发布了高级加密标准(AES)。AES是一个对称分组密码算法,旨在取代DES成为广泛使用的标准。

  根据使用的密码长度,AES最常见的有3种方案,用以适应不同的场景要求,分别是AES-128、AES-192和AES-256。

1 算法流程

  AES加解密的流程图如下(以128位密钥为例):

技术分享

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


AES加密过程涉及到4种操作:字节替代(SubBytes)、行移位(ShiftRows)、列混淆(MixColumns)和轮密钥加(AddRoundKey)。解密过程分别为对应的逆操作。由于每一步操作都是可逆的,按照相反的顺序进行解密即可恢复明文。加解密中每轮的密钥分别由初始密钥扩展得到。算法中16字节的明文、密文和轮密钥都以一个4x4的矩阵表示。

  AES算法中,密钥扩展也是理解AES算法的关键,接下来分别对上述5种操作进行介绍。

1.0 预备知识:有限域GF(2^8)的加法和乘法 

AES 加密算法使用相当简单明了的技术来代替和置换,除 MixColumns 例程以外。MixColumns 使用特殊的加法和乘法。AES 所用的加法和乘法是基于数学(译者注:近世代数)的域论。尤其是 AES 基于有限域GF(2^8)。 
  GF(2^8)由一组从 0x00 到 0xff 的256个值组成,加上加法和乘法,因此是(2^8)。GF代表伽罗瓦域,以发明这一理论的数学家的名字命名。GF(2^8) 的一个特性是一个加法或乘法的操作的结果必须是在{0x00 ... 0xff}这组数中。虽然域论是相当深奥的,但GF(2^8)加法的最终结果却很简单。GF(2^8) 加法就是异或(XOR)操作。 
  然而,GF(2^8)的乘法有点繁难。AES的加密和解密例程需要知道怎样只用七个常量 0x01、0x02、0x03、0x09、0x0b、0x0d 和 0x0e 来相乘。所以我不全面介绍GF(2^8)的乘法,而只是针对这七种特殊情况进行说明。 
  在GF(2^8)中用0x01的乘法是特殊的;它相当于普通算术中用1做乘法并且结果也同样—任何值乘0x01等于其自身。 
  现在让我们看看用0x02做乘法。和加法的情况相同,理论是深奥的,但最终结果十分简单。只要被乘的值小于0x80,这时乘法的结果就是该值左移1比特位。如果被乘的值大于或等于0x80,这时乘法的结果就是左移1比特位再用值0x1b异或。它防止了“域溢出”并保持乘法的乘积在范围以内。 
一旦你在GF(2^8)中用0x02建立了加法和乘法,你就可以用任何常量去定义乘法。用0x03做乘法时,你可以将 0x03 分解为2的幂之和。为了用 0x03 乘以任意字节b, 因为 0x03 = 0x02 + 0x01,因此: 
b * 0x03 = b * (0x02 + 0x01) = (b * 0x02) + (b * 0x01)

这是可以行得通的,因为你知道如何用 0x02 和 0x01 相乘和相加,同理,用0x0d去乘以任意字节b可以这样做:

b * 0x0d   = b * (0x08 + 0x04 + 0x01) 

= (b * 0x08) + (b * 0x04) + (b * 0x01) 

= (b * 0x02 * 0x02 * 0x02) + (b * 0x02 * 0x02) + (b * 0x01)

在加解密算法中,AES MixColumns 例程的其它乘法遵循大体相同的模式,如下所示: 

b * 0x09   = b * (0x08 + 0x01) 

= (b * 0x02 * 0x02 * 0x02) + (b * 0x01)b * 0x0b 

= b * (0x08 + 0x02 + 0x01) 

= (b * 0x02 * 0x02 * 0x02) + (b * 0x02) + (b * 0x01)b * 0x0e 

= b * (0x08 +0x04 + 0x02) 

= (b * 0x02 * 0x02 * 0x02) + (b * 0x02 * 0x02) + (b * 0x02)  

总之,在GF(2^8)中,加法是异或操作。其乘法将分解成加法和用0x02做的乘法,而用0x02做的乘法是一个有条件的左移1比特位。AES规范中包括大量有关GF(2^8)操作的附加信息。

1.1 密钥扩展

密钥扩展的原理图如下:

 技术分享


w[]最初的 Nk 行被作为种子,用原始密钥值。剩余行从种子密钥来产生。变量 Nk 代表以 32 位字为单位的种子密钥长度。关键是这里现在有许多密钥使用而不只是一个。这些新的密钥被称为轮密钥(round keys)以将它们与原始种子密钥区别开来。

  密钥扩展过程说明:(以128位密钥为例,Nk=4,Nr=10)

    1)  将初始密钥以列为主,转化为4个32 bits的字,分别记为w[0…(Nk-1)];

    2)  按照如下方式,依次求解w[j],其中j是整数并且属于[4,K];(K=Nb*(Nr+1),Nb=4,Nr为轮数,128位密钥对应的Nr=10)

    3)  若j%4=0,则w[j]=w[j-4]⊕g(w[j-1]),否则w[j]=w[j-4]⊕w[j-1];

  函数g的流程说明:

    4)  将w循环左移一个字节;

    5)  分别对每个字节按S盒进行映射;

    6)  与32 bits的常量(RC[j/4],0,0,0)进行异或,RC是一个一维数组,其值如下。(RC的值只需要有10个,而此处用了11个,实际上RC[0]在运算中没有用到,增加RC[0]是为了便于程序中用数组表示。由于j的最小取值是4,j/4的最小取值则是1,因此不会产生错误。)

      RC = {00, 01, 02, 04, 08, 10, 20, 40, 80, 1B, 36}


算法操作流程  

AES 加密例程开始是拷贝 16 字节的输入数组到一个名为 State (态)的4×4 字节矩阵中。AES 加密算法取名为 Cipher,它操作 State[]。

SubBytes、ShiftRows、MixColumns 和 AddRoundKey 四个操作在一个执行 Nr 次的循环里被调用,Nr 为给定密钥大小的轮数减 1。加密算法使用的轮数要么是10,12,要么是14,这依赖于种子密钥长度是128位、192 位还是 256 位。

1.1 字节代替

  字节代替的主要功能是通过S盒完成一个字节到另外一个字节的映射。

  下图(a)为S盒,图(b)为S-1(S盒的逆)。

技术分享

技术分享

  S和S-1分别为16x16的矩阵。假设输入字节的值为a=a7a6a5a4a3a2a1a0

则输出值为S[a7a6a5a4][a3a2a1a0],S-1的变换也同理。

  例如:字节00替换后的值为(S[0][0]=)63,再通过S-1即可得到替换前的值,(S-1 [6][3]=)00。

1.2 行移位

  行移位的功能是实现一个4x4矩阵内部字节之间的置换。

1.2.1 正向行移位

  正向行移位的原理图如下:

技术分享

  实际移位的操作即是:第一行保存不变,第二行循环左移1个字节,第三行循环左移2个字节,第四行循环左移3个字节。假设矩阵的名字为state,用公式表示如下:state’[i][j] = state[i][(j+i)%4];其中i、j属于[0,3]

1.2.2 逆向行移位

  逆向行移位即是相反的操作,用公式表示如下:state’[i][j] = state[i][(4+j-i)%4];其中i、j属于[0,3]

1.3 列混淆

  列混淆:利用GF(28)域上算术特性的一个代替。

1.3.1 正向列混淆

  正向列混淆的原理图如下:

技术分享

  根据矩阵的乘法可知,在列混淆的过程中,每个字节对应的值只与该列的4个值有关系。此处的乘法和加法都是定义在GF(28)上的,需要注意如下几点:

    1) 将某个字节所对应的值乘以2,其结果就是将该值的二进制位左移一位,如果该值的最高位为1(表示该数值不小于128),则还需要将移位后的结果异或00011011(0x1b);

    2) 乘法对加法满足分配率,例如:07·S0,0=(01⊕02⊕04)·S0,0= S0,0⊕(02·S0,0)(04·S0,0)

    3) 此处的矩阵乘法与一般意义上矩阵的乘法有所不同,各个值在相加时使用的是模2加法(相当于是异或运算)。

  假设某一列的值如下图,运算过程如下:

  技术分享  

  技术分享

  同理可以求出另外几个值。

1.3.2 逆向列混淆

  逆向列混淆的原理图如下:

 技术分享

  由于:

 技术分享

说明两个矩阵互逆,经过一次逆向列混淆后即可恢复原文。

1.4 轮密码加

  任何数和自身的异或结果为0。加密过程中,每轮的输入与轮密钥异或一次;因此,解密时再异或上该轮的密钥即可恢复输入。

2 源码(以256密钥为例)

https://github.com/yangxt225/AES

参阅:

http://www.mamicode.com/info-detail-514466.html
http://wenku.baidu.com/view/97a8d94dfe4733687e21aabc.html?re=view

你可能感兴趣的:(algorithm)