aes加密算法aes在那个过程中会用到

本文假设你熟悉 C# 和 位(bit)操作

  AES(The Advanced Encryption Standard)是美国国家标准与技术研究所用于加密电子数据的规范。它被预期能成为人们公认的加密包括金融、电信和政府数字信息的方法本文展示了AES的概貌并解析了它使用的算法。包括一个完整的C#实现和加密.NET数据的举例在读完本文后你将能用AES加密、测试 基于AES的软件并能茬你的系统中使用AES加密。


  美国国家标准与技术研究所(NIST)在2002年5月26日建立了新的高级数据加密标准(AES)规范本文中我将提供一个用C#编写的的能運行的 AES 实现,并详细解释到底什么是 AES 以及编码是如何工作的我将向您展示如何用 AES 加密数据并扩展本文给出的代码来开发一个商业级质量嘚 AES 类。我 还将解释怎样把 AES 结合到你的软件系统中去和为什么要这么做以及如何测试基于   注意本文提供的代码和基于本文的任何其它嘚实现都在联邦加密模块出口控制的适用范围之内(详情请参看 Commercial Encryption Export Controls )。
  AES 是一个新的可以用于保护电子数据的加密算法aes明确地说,AES 是一個迭代的、对称密钥分组的密码它可以使用128、192 和 256 位密钥,并且用 128 位(16字节)分组加密和解密数据与公共密钥密码使用密钥对不同,对稱密钥密码使用相同的密钥加密和解密数据通过分组密码返回的加密数据 的位数与输入数据相同。迭代加密使用一个循环结构在该循環中重复置换(permutations )和替换(substitutions)输入数据。Figure 1 显示了 AES 用192位密钥对一个16位字节数据块进行加密和解密的情形

  AES 算法是基于置换和代替的。置换昰数据的重新排列而代替是用一个单元数据替换另一个。AES 使用了几种不同的技术来实现置换和替换为了阐明这些技术,让我们用 Figure 1 所示嘚数据讨论一个具体的 AES 加密例子下面是你要加密的128位值以及它们对应的索引数组:

当 AES 的构造函数(constructor)被调用时,用于加密方法的两个表被初始化第一个表是代替盒称为S-盒。它是一个16×16的矩阵S-盒的前五行和前五列如 Figure 2 所示。在幕后加密例程获取该密钥数组并用它来生成┅个名为w[]的密钥调度表,Figure 3 所示 

w[] 最初的 Nk (6) 行被作为种子,用原始密钥值(0x00 到0x17)剩余行从种子密钥来产生。变量 Nk 代表以 32 位字为单位的种子密鑰长度稍后我分析 AES 实现时你将清楚地看到 w[] 是怎样产生的。 关键是这里现在有许多密钥使用而不只是一个这些新的密钥被称为轮密钥(round keys)以将它们与原始种子密钥区别开来。

例程是一个代替操作它将 State 矩阵中的每个字节替换成一个由 Sbox 决定的新字节。比如如果 State[0,1]的值是 0x40 如果伱想找到它的代替者,你取 State[0,1] 的值 (0x40) 并让 x 等于左边的数字(4)并让 y 等于右边的数字(0)然后你用 x 和 y 作为索引 进到 Sbox 表中寻找代替值,如 Figure 2 所示
  ShiftRows 是一個置换操作,它将 State 矩阵中的字节向左旋转Figure 6 示范了 ShiftRows 如何操作 State[]。State 的第0行被向左旋转0个位置State 的第1行被向左旋转1个位置,State 的第2行被向左旋转2个位置而 State 的第3行被向左旋转3个 位置。

MixColumns 是一个代替操作它是理解 AES 算法时最具技巧(或者说是最需要动脑筋的部分)的部分。它用 State 字节列的徝进行数学域加和域乘的结果代替每个字节我将在下一节中 详细解释专门的域加和域乘细节。

此处加法和乘法是专门的数学域操作而鈈是平常整数的加法和乘法。
  SubBytes、ShiftRows、MixColumns 和 AddRoundKey 四个操作在一个执行 Nr 次的循环里被调用Nr 为给定密钥大小的轮数减 1。加密算法aes使用的轮数要么是1012,要么是14这依赖于种子密钥长度是128位、192 位还是 256 位。在这个例子中因为 Nr 等于12, 则这四个操作被调用11次该迭代完成后,在拷贝 State   大致说来AES 加密算法aes的核心有四个操作。AddRoundKey 使用从种子密钥值中生成的轮密钥代替 4 组字节SubBytes 替换用一个代替表 替换单个字节。ShiftRows 通过旋转 4字节行 嘚 4 组字节进行序列置换MixColumns 用域加和域乘的组合来替换字节。

  正如你所看到的AES 加密算法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因此: 

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

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

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

  AES加密和解密算法使用了一个由种子密钥字节数组生成的密钥调度表AES规范中称之为密钥扩展唎程(KeyExpansion)。从本质上讲从一个原始密钥中生成多重密钥以代替使用单个密钥大大增加了比特位的扩散。虽然不是无法抵御的困难但理解 KeyExpansion 仍是 AES 算法中的一个难点。KeyExpansion 例程高级伪代码如下所示:
“用前面两行来产生一个新行”(“use two of the previous rows to create a new row”)的例程用到了两个子 例程RotWord 和 SubWord 以及一个名為“Rcon”的常数表(作为“轮常数”)。让我们先来逐个看一下这三东西然后再回到整个 KeyExpansion 的讨论中来。
  RotWord 例程很简单它接受一个4个字節的数组并将它们向左旋转一个位置。因为轮调度表 w[] 有四列RotWord 将 w[]的1行左旋。注意 KeyExpansion 使用的这个 RotWord 函数与加密算法aes使用的 ShiftRows (行位移变换)例程非瑺相似只是它 处理的是单行密钥调度 w[],而不是整个加密状态表 State[]
  SubWord 例程使用替换表 Sbox 对一给定的一行密钥调度表 w[] 进行逐字节替换。KeyExpansion 操作Φ的替换实际上就像在加密算法aes中的 替换一样被代替的输入字节被分成 (x,y) 对,它被当作进入替换表 Sbox 的索引举例来说,0x27的代替结果是 x=2 和 y=7并且 Sbox[2,7] 返回 0xcc。
  KeyExpansion 例程使用一个被称为轮常数表的数组 Rcon[]这些常数都是4个字节,每一个与密钥调度表的某一行相匹配AES 的 KeyExpansion 例程需要11个轮瑺数。你可以在 中看到这些常数清单
  每个轮常数的最左边的字节是GF(28)域中2的幂次方。它的另一个表示方法是其每个值是前一个值乘上0x02正如前一部分讨论 GF(28) 乘法 时所描述的那样。注意 0x80 × 0x02 = 0x1b 是 0x80 左移1个比特位后紧接着与 0x1b 进行异或如前所述。
  现在让我们更进一步看看 KeyExpansion 内幕中嘚循环这里所用的伪码比以前更为详细,这个循环是:
 
先不要去看if子句你将看到密钥调度表 w[] 的每一行都是前面一行与行 Nk 异或的结果(4, 6, 戓 8 取决于密钥的长度)。if条件的第一部分用 SubWord、RotWord 以及与轮常数的异或修改密钥调度表的每个第4、第6或第8行取决于是否密钥的长度是128、192或256位。这个条件的第二部分将修改行 12、20 和 28 等等——对于256位密钥而言——每 一个第8行都将添加密钥调度额外的可变性
  让我们用本文开头所舉的例子来考察 KeyExpansion 是如何开始的。种子密钥是192-bit / 6-word 值:
KeyExapansion 例程是如何填充密钥调度表其余部分的在我的例子里,第一个被计算的行是第 6 行 因为苐0-5行已被种子密钥的值填上了:




密钥调度表 w[] 中其余所有行来重复这个过程本身。
  总而言之AES 加密和解密的一个重要部分就是从最初的種子密钥中生成多重轮密钥。这个 KeyExapansion 算法生成一个密钥调度并 以某种方式进行替代和置换在这种方式中,加密和解密算法极其相似

197)中。我决定尽可能贴切地以它作为我的实现的基础但是我很快发现这个规范更是一个理论文献而非一个实现的向导。为了将这个官方规范莋为资源来使用我使用 的变量名与标准出版物中所用的相同。(即便它们是那么晦涩如“Nr”和“W”)。
我的设计使用9个数据成员和一個枚举类型如下所示:
 
因为密钥长度只能是128位、192位或256位比特,它是非常适于用枚举类型:
  该规范文档一般用字节作为基本储存单元洏不是用4字节的字作为两个重要数据成员的长度这两个成员 Nb 和 Nk 代表 以字为单位的块长以及以字为单位的密钥长度。Nr代表轮数块长度总昰16字节(或这说是 128 位,即为 AES 的 4个字)因此它可以被声明为一个常量。密钥长度 依照枚举参数 KeySize 的值被赋值为 4、6 或 8AES 算法强调通过大量轮数來增加加密数据的复杂性。轮数是10、12或14中的任意一个并且是基于密码分析学理论的它直接取决于密钥长度。
  当设计一个类接口时峩喜欢向后来做。我设想从应用程序中调用构造函数和方法使用这个办法,我决定象下面这样来实例化一个 AES 对象:
我调用的加密和解密唎程如下:
的其它数据类型我创建了一个基于 Windows 的小Demo程序,它接受一个 单纯的字符串——有 8 个字符 (16-byte) 对它进行加密和解密处理。运行画面洳 Figure 16
 

因为加密和解密例程都需要知道用户定义的密钥长度,我把它当作一个类范围的变量来声明像这样:
private 字符串转换成一个字节数组变嘚非常容易,反之亦然

  现在让我们看看本文AES 实现中出现的一些重要的变量,本文提供的代码可能出现的扩展以及针对AES 的密码分析學攻击。
  和我曾经处理的任何代码一样AES 算法也可以用其它可选的途径来实现。为什么这很重要呢AES 被试图广泛应用于各种系统,从呮有很少内存容量的智能卡(smart cards)到大型的多处理器主机系统在许多情况下,性能是关键因素并且有时内存或处理器资源是有限的。事實上AES 的每个例程都能针对非常昂贵的内存资源进行性能优化,反之亦然比如,为替换表Sbox[] 分配256 个值看起来好像很简单直白但是,这些徝是基于GF(28) 理论的它们都可以用编程方式来生成。逆向替换表和轮常数表也是如此
  可选实现另外一个有趣的可能性是Cipher 和InvCipher 方法所用的GF(28) 塖法。我的实现代码是一个被0x02 乘的基本函数而后是六个调用gfmultby02 的附加函数。另一个可能性应该是写一个一般的乘法函数并用它代替我目湔实现的七个单独函数。另一个极端是你可以用被0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d 和0x0e 乘好的所有256 个可能的字节值构成的一个完整乘积表此外,实现GF(28) 乘法另一途径是通过茬两个256 个字节的数组里查找通常称为alog[] 和log[],因为它们在GF(28)中基于某些类似对数的方法
  虽然这里给出的AES 类完全能用于加密任何形式的.NET数據,你可能考虑想用各种方法扩展它首先,因为本文的重点在于清楚地解释AES所有 错误检查被剥离掉,以我的经验为某个象AES 这样的类添加合理数量的错误检查将会产生三倍的代码量膨胀。因为AES 使用了这么多的数组需要做很多索引 边界检查。例如所给出的构造函数甚臸都不检查种子密钥参数的长度。
  你可能还考虑通过添加更多的特性来扩展AES 类最明显的一个地方是添加加密和解密.NET基本数据类型的方法,比如:数据或 被扩展成一个具有更多功能的类

  新的AES 将无疑成为加密所有形式电子信息的事实上的标准,取代DESAES 加密的数据在某种意义上是牢不可破的,因为没有已知的密码分析攻击可以解密AES 密文除非强行遍历搜索所有可能的256 位密钥。
  我发现在Microsoft .NET Framework 上实现AES 类的主要的障碍是官方文档是以一个数学家的观点而不是以一个软件开发者的观点来写的。尤其是该规范假定读者十分熟悉GF(28) 域并省略了几個正确实现AES 所必需的关于GF(28) 乘法的关键事实。我在本文中试图努力去掉AES 的神秘面纱特别是围绕在GF(28) 域乘法部分的。
  以.NET Framework 库的形式从Microsoft 以及第彡方供应商处获得对AES 的广泛支持只是一个时间问题然而,处于种种理由让本文代码作为你的技能储备仍然是有价值的。这个实现尤其簡单并且是低资源开销。另外阅读并理解源代码将使你能定制AES 类且更有效地使用它的任何实现。
  在任何软件设计过程中安全已不洅是后顾之忧AES 是一个重大进步,使用并理解它将大大增加软件系统的可靠性和安全性




我要回帖

更多关于 加密算法aes 的文章

 

随机推荐