AES加密算法[转]加密它:用新的高级加密标准(AES)保持你的数据安全原著:James McCaffrey翻译:小刀人原文出处:MSDN Magazine November 2003 (Encrypt It)本文的代码下载:msdnmag200311AES.exe (143KB)本文假设你熟悉C# 和位(bit)操作。
摘要AES(The Advanced Encryption Standard)是美国国家标准与技术研究所用于加密电子数据的规范。
它被预期能成为人们公认的加密包括金融、电信和政府数字信息的方法。
本文展示了AES的概貌并解析了它使用的算法。
包括一个完整的C#实现和加密.NET数据的举例。
在读完本文后你将能用AES加密、测试基于AES的软件并能在你的系统中使用AES加密。
--------------------------------------------------------------------------------美国国家标准与技术研究所(NIST)在2002年5月26日建立了新的高级数据加密标准(AES)规范。
本文中我将提供一个用C#编写的的能运行的AES 实现,并详细解释到底什么是AES 以及编码是如何工作的。
我将向您展示如何用AES 加密数据并扩展本文给出的代码来开发一个商业级质量的AES 类。
我还将解释怎样把AES 结合到你的软件系统中去和为什么要这么做,以及如何测试基于AES 的软件。
注意本文提供的代码和基于本文的任何其它的实现都在联邦加密模块出口控制的适用范围之内(详情请参看Commercial Encryption Export Controls )。
AES 是一个新的可以用于保护电子数据的加密算法。
明确地说,AES 是一个迭代的、对称密钥分组的密码,它可以使用128、192 和256 位密钥,并且用128 位(16字节)分组加密和解密数据。
与公共密钥密码使用密钥对不同,对称密钥密码使用相同的密钥加密和解密数据。
通过分组密码返回的加密数据的位数与输入数据相同。
迭代加密使用一个循环结构,在该循环中重复置换(permutations )和替换(substitutions)输入数据。
Figure 1 显示了AES 用192位密钥对一个16位字节数据块进行加密和解密的情形。
Figure 1 部分数据AES算法概述AES 算法是基于置换和代替的。
置换是数据的重新排列,而代替是用一个单元数据替换另一个。
AES 使用了几种不同的技术来实现置换和替换。
为了阐明这些技术,让我们用Figure 1 所示的数据讨论一个具体的AES 加密例子。
下面是你要加密的128位值以及它们对应的索引数组:00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15192位密钥的值是:00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 170 1 2 3 4 5 6 7 8 9 10 1112 13 14 15 16 17 18 19 20 21 22 23Figure 2 S-盒(Sbox )当AES 的构造函数(constructor)被调用时,用于加密方法的两个表被初始化。
第一个表是代替盒称为S-盒。
它是一个16×16的矩阵。
S-盒的前五行和前五列如Figure 2 所示。
在幕后,加密例程获取该密钥数组并用它来生成一个名为w[]的密钥调度表,Figure 3 所示。
Figure 3 密钥调度表(Key Sched)w[] 最初的Nk (6) 行被作为种子,用原始密钥值(0x00 到0x17)。
剩余行从种子密钥来产生。
变量Nk 代表以32 位字为单位的种子密钥长度。
稍后我分析AES 实现时你将清楚地看到w[] 是怎样产生的。
关键是这里现在有许多密钥使用而不只是一个。
这些新的密钥被称为轮密钥(round keys)以将它们与原始种子密钥区别开来。
Figure 4 State (态)数组AES 加密例程开始是拷贝16 字节的输入数组到一个名为State (态)的4×4 字节矩阵中。
(参见Figure 4)。
AES 加密算法取名为Cipher,它操作State[],其过程描述的伪代码参见Figure 5 。
在规范中,加密算法实现的一个预备的处理步骤被称为AddRoundKey(轮密钥加)。
AddRoundKey 用密钥调度表中的前四行对State 矩阵实行一个字节一个字节的异或(XOR)操作,并用轮密钥表w[c,r] 异或输入State[r,c]。
举个例子,如果State 矩阵的第一行保存的字节是{ 00, 44, 88, cc },第一列密钥调度表是{ 00, 04, 08, 0c },那么新的State[0,2] 值是用w[2,0]( 0x08 或0x80 )异或State[0,2](0x88)的结果:1 0 0 0 1 0 0 00 0 0 0 1 0 0 0 XOR1 0 0 0 0 0 0 0AES 算法的主循环对State 矩阵执行四个不同的操作,在规范中被称为SubBytes(字节替换)、ShiftRows(行位移变换)、MixColumns(列混合变换)和AddRoundKey。
除了每次循环AddRoundKey 都被调用并使用密钥调度表的下面四行外,AddRoundKey 与预备处理步骤中的AddRoundKey 相同。
SubBytes 例程是一个代替操作,它将State 矩阵中的每个字节替换成一个由Sbox 决定的新字节。
比如,如果State[0,1]的值是0x40 如果你想找到它的代替者,你取State[0,1] 的值(0x40) 并让x 等于左边的数字(4)并让y 等于右边的数字(0)。
然后你用x 和y 作为索引进到Sbox 表中寻找代替值,如Figure2 所示。
ShiftRows 是一个置换操作,它将State 矩阵中的字节向左旋转。
Figure 6 示范了ShiftRows 如何操作State[]。
State 的第0行被向左旋转0个位置,State 的第1行被向左旋转1个位置,State 的第2行被向左旋转2个位置,而State 的第3行被向左旋转3个位置。
Figure 6 对State 进行ShiftRows 操作MixColumns 是一个代替操作,它是理解AES 算法时最具技巧(或者说是最需要动脑筋的部分)的部分。
它用State 字节列的值进行数学域加和域乘的结果代替每个字节。
我将在下一节中详细解释专门的域加和域乘细节。
假设State[0,1] 的值是0x09,并且列1上的其它值分别为0x60,0xe1 和0x04,那么State[0,1]的新值计算如下:State[0,1] = (State[0,1] * 0x01) + (State[1,1] * 0x02) +(State[2,1] * 0x03) +(State[3,1] * 0x01) = (0x09 * 0x01) + (0x60 * 0x02) + (0xe1 * 0x03) +(0x04 * 0x01)= 0x57此处加法和乘法是专门的数学域操作,而不是平常整数的加法和乘法。
SubBytes、ShiftRows、MixColumns 和AddRoundKey 四个操作在一个执行Nr 次的循环里被调用,Nr 为给定密钥大小的轮数减1。
加密算法使用的轮数要么是10,12,要么是14,这依赖于种子密钥长度是128位、192 位还是256 位。
在这个例子中,因为Nr 等于12,则这四个操作被调用11次。
该迭代完成后,在拷贝State 矩阵到输出参数前,加密算法调用SubBytes、ShiftRows 和AddRoundKey 后结束。
大致说来,AES 加密算法的核心有四个操作。
AddRoundKey 使用从种子密钥值中生成的轮密钥代替 4 组字节。
SubBytes 替换用一个代替表替换单个字节。
ShiftRows 通过旋转4字节行的4 组字节进行序列置换。
MixColumns 用域加和域乘的组合来替换字节。
有限域GF(28)的加法和乘法正如你所看到的,AES 加密算法使用相当简单明了的技术来代替和置换,除MixColumns 例程以外。
MixColumns 使用特殊的加法和乘法。
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)中,加法是异或操作。