一、所谓AES加密:

 

  

aes android 解密出错 aes解密教程_基本运算

 

二、中间怎么变换的呢?128位加密为例:

AES算法,基本变换包括SubBytes(字节替代)、ShiftRows(行移位)、MixColumns(列混淆)、AddRoundKey(轮密钥加)。

加密过程可参见:http://coolshell.cn/wp-content/uploads/2010/10/rijndael_ingles2004.swf

然后我会以这个视频动画为基础,加以说明:

 1)左边是需要加密的,右边是密钥:

    

aes android 解密出错 aes解密教程_d3_02

   

aes android 解密出错 aes解密教程_d3_03

 

2)SubBytes(字节替代)过程:

    

aes android 解密出错 aes解密教程_d3_04

    这一步可以直接查表:如19就对应着0xd4;a0对应0xe0;...

unsigned char sBox[] =

{ /*   0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f */

0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76, /*0*/ 

0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0, /*1*/

0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15, /*2*/

0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75, /*3*/

0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84, /*4*/

0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf, /*5*/

0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8, /*6*/ 

0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2, /*7*/

0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73, /*8*/

0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb, /*9*/

0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79, /*a*/

0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08, /*b*/

0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a, /*c*/

0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e, /*d*/

0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf, /*e*/

0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16  /*f*/

};

3)ShiftRows(行移位),这里也截取网上的图片来说明:

  

aes android 解密出错 aes解密教程_基本运算_05

 

 4)MixColumns(列混淆):

    

aes android 解密出错 aes解密教程_bc_06

    我第一次考到这里也没立即明白是怎么算出来的,这里是:用 State 字节列的值进行数学域加和域乘的结果代替每个字节。

    下面一段是截取前人成果:

AES 所用的加法和乘法是基于数学(译者注:近世代数)的域论。尤其是 AES 基于有限域GF(28)。
  GF(28)由一组从 0x00 到 0xff 的256个值组成,加上加法和乘法,因此是(28)。GF代表伽罗瓦域,以发明这一理论的数学家的名字命名。GF(28) 的一个特性是一个加法或乘法的操作的结果必须是在{0x00 ... 0xff}这组数中。虽然域论是相当深奥的,但GF(28)加法的最终结果却很简单。GF(28) 加法就是异或(XOR)操作。
  然而,GF(28)的乘法有点繁难。正如你稍后将在 C# 实现中所看到的,AES的加密和解密例程需要知道怎样只用七个常量 0x01、0x02、0x03、0x09、0x0b、0x0d 和 0x0e 来相乘。所以我不全面介绍GF(28)的乘法,而只是针对这七种特殊情况进行说明。
  在GF(28)中用0x01的乘法是特殊的;它相当于普通算术中用1做乘法并且结果也同样—任何值乘0x01等于其自身。
  现在让我们看看用0x02做乘法。和加法的情况相同,理论是深奥的,但最终结果十分简单。只要被乘的值小于0x80,这时乘法的结果就是该值左移1比特位。如果被乘的值大于或等于0x80,这时乘法的结果就是左移1比特位再用值0x1b异或。它防止了“域溢出”并保持乘法的乘积在范围以内。
一旦你在GF(28)中用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(28)中,加法是异或操作。其乘法将分解成加法和用0x02做的乘法,而用0x02做的乘法是一个有条件的左移1比特位。AES规范中包括大量 有关GF(28)操作的附加信息。

这下来看左上方的04是怎么得来的:

  0xd4*0x02 ⊕ 0xbf*0x03 ⊕ 0x5d*0x01 ⊕ 0x30 * 0x01

 =0xd4*0x02 ⊕ xbf*0x02 ⊕ 0xbf*0x01 ⊕ 0x5d*0x01 ⊕ 0x30 * 0x01

     =0xd4*0x02 ⊕ xbf*0x02 ⊕ 0xbf ⊕ 0x5d ⊕ 0x30    (注意这里的0xd4*02就是0xd4左移一位,然后异或0x1b (0001 1011)哦,加法就是求异或)

     =1010 1000⊕0001 1011 ⊕ 0111 1110 ⊕0001 1011 ⊕ 1011 1111 ⊕ 0101 1101 ⊕ 00110000

    0001 1011                       0001 1011                        0101 1101

   =1011 0011                    ⊕ 0110  0101                  ⊕  1110 0010                     ⊕ 00110000

    0110  0101

   =1101 0110 ⊕ 1110 0010 ⊕ 00110000

   =0011 0100 ⊕ 00110000

   =0000 0100

   =0x04

  

  5) AddRoundKey(轮密钥加):

密钥进行异或;

密钥求异或操作,得到的最终结果就是密文。

 

  注意:这的每轮一圈,密钥都要schedule一次(俗称:KeyExpansion(密钥扩展)),具体算法:

  <1>第n组第i列 为 第n-1组第i列 与 第n组第i-1列之和(模2加法,1<= i <=3)

  <2>对于每一组 第一列即i=0,有特殊的处理:

将前一列即第n-1组第3列的4个字节循环左移1个字节,

并对每个字节进行字节替代变换SubBytes

将第一行(即第一个字节)与轮常量rc[n]相加 

最后再与前一组该列相加。

这里的rc[n]是个定值:

  

aes android 解密出错 aes解密教程_bc_07

 

  就此AES加密过程结束!

 

三、解密的基本运算

  AES解密算法与加密不同,基本运算中除了AddRoundKey(轮密钥加)不变外,其余的都需要进行逆变换,即

  InvSubBytes(逆字节替代)、InvShiftRows(逆行移位)、InvMixColumns(逆列混淆)

 

 

非128位的文件如何加密,还有192 256位加密解密...