AES算法全景(图)

1,832 阅读13分钟

网络中,讨论AES算法的资料汗牛充栋,这里就不再重复了。笔者在相关学习和理解的基础上,试图先从一个全景的构图入手,提供一种新的角度和阅读,帮助读者更快更好的从整体结构上来理解其思路和设计。

全景图

如图所示(尽量放大看原图):

AESAllView.png

从这张图中,读者可以清晰的了解这个算法的要素和相关的关系。

要件

  • 数学算法

AES算法的数学理论基础,是伽罗瓦有限域和其计算规则,以及线性代数和矩阵运算。和普通数学算法不同,伽罗瓦域的求和和乘积操作,是另外一个一个逻辑。在GF中,求和就是异或操作,乘积就是GF乘法(有其特定的计算和处理方法)。

  • 设定

AES有三种类型,通过所使用的密钥长度来进行区分。这个分类主要影响到的是密钥扩展算法的实现,和AES加密的轮次(设定表中详)。

由于AES算法的类型和模式众多,为了方便讨论,图中内容的基本模式是AES-256-GCM,这个也是TLS-1.3算法和标准和优先推荐密码套件。

  • SBOX

在AES算法规则中,SBOX是一个16x16的矩阵(实际算法中是一个一维结构),包括了00~FF的256个数值。它看起来杂乱无章,但实际上是基于某种数学原理设计而成,也可以从一个公式和计算规则中推导计算而出。其目标是增加块变换算法的混淆性能。

SBOX的使用非常简单,就是使用查表替换方式,具体而言,就是对于某个值,可以转换为一个索引,在SBOX中查找此索引对应的值。它巧妙的利用到了SBOX的索引空间和值空间一一对应并可以灵活相互转换的特点。 这样, SBOX替换的逆向操作也非常简单,就是使用类型indexOf的函数进行操作查找原始索引。当然,工程上也经常使用一个预计算好的反向查找表来提高性能。

SBOX也可以有很多种,AES使用一个约定好的SBOX(其多项式表达式为x8+x4+x3+x+1)参与加密、解密和密钥扩展计算,我们可以将其看成一个常量。

  • 密钥扩展

笔者有其他文章专门详细讨论了这个课题。这里简单说来,就是可以将一个原始密钥,通过扩展算法,生成一系列子密钥,用于AES的轮次操作当中,每一轮使用的密钥都是不同的,在解密时,扩展密钥的算法相同,但密钥使用的顺序,可能是反向的。

  • 计算轮次

AES的计算,是分多轮操作的,每轮计算都具有特定的步骤和次序,从图中可以清晰的看到这些,并且很容易理解,这些步骤次序的设计原则就是尽量能够使用变量信息,对原始信息进行混淆和扩散,并保证这些操作是可逆的。

轮次中的具体操作都是针对块的,包括加密钥,字替换,行位移,列混合等四种。如果有循环轮次,则需要将本轮次的结果,作为下一轮次的输入(其实AES加解密中,就只有最后一轮操作不同)。所有步骤和操作都完成后,得到的那个最后的数据块,就是整个加密的结果-密文。

  • 加密钥

使用当前计算轮次的子密钥,和块对位的进行异或计算,就可以得到一个新的块。

  • 字替换

使用SBOX中,相同位置的数值,来替换块中相同位置的数值,会的到一个新的块,这个变换方式就是块替换。

  • 行位移

将每个块都可以分为4行,对于每行,都偏移一个特定的位置,就可以得到一个新的块。

  • 列混合

将需要处理的块,和一个常数块,进行线性代数的矩阵运算(当然计算规则是GF的),就可以得到混合后的新块。

  • 解密

如果要进行解密操作,基本上就是加密操作的逆运算。即将加密操作的步骤和方向都反向操作一遍。除操作步骤外,每一个步骤的具体操作,通常要使用对应加密函数的逆操作函数。

加密钥的逆操作最简单,只需要在使用对应的轮次子密钥进行一次异或操作,就可以还原块,这是XOR计算的特性决定的;字替换的逆操作要使用一个逆向SBOX,但其实也没那么复杂,不需要一个真的的ISBOX,只需要SBOX的索引逆查就可以了。行位移,只需要按照行和位移规则,反向偏移计算即可;列混合比较复杂,需要定义一个反向的矩阵运算函数来进行实现。 简单而言,这些运算都是可逆的,只需要按照次序和规则,反向计算,即可以得到原始信息。

  • GCM模式

前面讨论的所有内容,其实都是AES的核心算法,它关注于块加密的那个块的处理。但实际在工程和应用当中,一个原始的信息肯定包括多个块的处理。为了解决这些问题,提出了AES的操作模式,以保证除了核心的块加解密操作之外,整个过程的安全和高效。

和AES核心算法不同,AES的操作模式,并没有一个强制的标准和算法,因此在发展和使用的过程中,业界提出了很多模式,常见的AES模式有ECB、CBC、CBF、OBF、CTR等等,它们的差异主要在于如何处理初始化向量和块、密钥之间的关系。随着技术和安全需求的发展,又提出了CCM、GCM等新的模式,它们最核心的特点是加入了验证信息和过程,可以同时保证信息的完整性,大幅度提高了加解密过程和信息安全性。

本文讨论和展示的基础是AES-GCM模式。理由是它是TLS1.3的优先算法,应用最为广泛,并且也是NIST的推荐方案。原理上而言,GCM是在CTR(计数器模式)的基础上,增加了验证相关流程来实现的。通常认为,相对于以前和其他的模式,GCM有两个主要优势:

GCM基于计数器模式(CTR),可以使用并行运算。实际上它使用AES核心算法,计算的并不是要加密的明文,而是密钥,也就是为每个明文块都生成一个密钥,由于使用递增方式,这些密钥的输入是可以预测的,所以后续处理可以并行完成,这样就可以使并行计算成为可能。当然,要在程序中实现这一点,还要考验开发者调度多线程和使用系统资源的能力。另外,GCM引入了认证标签,可以简单的理解为一个加密签名,可以保证数据的完整性,提高了安全性,这个标签的设计也比较巧妙,使用一个信息链接反馈的运算机制,保证了逻辑的完整和严密。

其实,关于这个模式方案,业界也是有一些争论的。一般认为相对于CCM而言,GCM的性能稍好,但由于原理上来自CTR的原因,可能会有一些安全性方面的隐患,但好像CCM也有自己的问题,我们姑且认为相对而言GCM比较成熟稳定吧。由于GCM的设计比较复杂,相关内容比较多,这里不再展开讨论,有机会笔者另行撰文探讨。

小结

从前面的讨论,在理解了其原理和流程之后,我们应该可以觉得,AES算法架构非常简洁巧妙,基本计算也非常简单,就可以实现很好的开放包容。

事实也是如此,熟悉其原理的开发人员,几乎用任何语言就可以编写自己的AES算法实现,从而将其移植到任何一个计算平台和环境当中。我们看到的很多实现代码其实都没有超过300行,并且基本没有什么第三方依赖。甚至,在其基础上,开放者方便可以进行扩展(不推荐这么做,兼容性和可靠性考量),比如使用其他的SBOX、增加行替换、使用不同的Mix矩阵、修改密钥扩展函数等等,就可以“发明”新的密钥算法了。

附: AES实现代码(JS)

根据以上内容,这里有一个简单的AES算法核心的JS实现,完全没有第三方和库依赖,只有不到100行!当然,这个代码只是AES的算法核心代码,完整的应用,还需要搭配内容编码解码、块分割和补位、AES模式、初始化向量等等,所以这里的代码仅用作原理性的研究和学习。

另外,测试验证的示例数据,来自AES的技术白皮书:

nvlpubs.nist.gov/nistpubs/fi…

内容和步骤非常权威详细,可以用检查算法的每一步和最终结果是否正确(可能是书中的处理使用的是“字”的方式,和本文中代码使用数组稍有不同,所以调试过程中看到的矩阵正好是行列翻转的,但应该不影响运行、讨论和理解)。

附: AES算法确定过程

笔者觉得,这是一个有趣而且重要的过程,能够也让我们能够更客观和正确的看待理解这一算法。(以下内容主要来自wiki百科)

1997年1月2日,NIST(National Institue Of Standards And Technology,国家标准和技术研究所,负责制定信息技术方面的管理组织)宣布,他们希望选择一个被称为AES的加密标准,作为DES的继任者(他们可能觉得DES已经不能在信息技术快速发展的时代,很好的保护信息了)。与DES一样,这应该是一种"不是机密的、加密算法公开披露的,能够在未来一个世纪内(口气好大)保护敏感的政府信息的"加密标准。然而,NIST并没有简单地宣布继任者是谁,而是要求有关各方就如何选择继任者提供方案。来自开放加密社区的兴趣立即高涨,NIST在三个月的评论期期间就收到了大量的提交。

1997年9月12日,在需求确认阶段,最终反馈的结果是确实需要一种新的密码算法,并且应该都是块密码,支持128位的块大小,以及支持128、192和256位的密钥长度(其实,这种需求和密码,在当时还是比较少见的)。在接下来的九个月,来自不同国家的十五种不同的设计出现并被提交。按字母顺序排列,他们分别是:CAST-256、CRYPTON、DEAL、DFC、E2、FROG、HPC、LOKI97、MAGENTA、MARS、RC6、Rijndael、SAFER+、以及Twofish。

在随后进行的辩论中,密码学家们对这些候选算法的优点和缺点进行了调查;他们的评估包括安全方面,也包含在各种各样的情景下算法的使用实现(个人电脑的各种架构、智能卡、硬件实现),以及其在有限资源的环境下的可行性(只有非常有限的内存的智能卡、在低逻辑门数下的实现,如FPGA等)。

其中的一些设计方案在密码分析过程中落选,原因是存在微小的缺陷甚至是存在致命的攻击方式,而另一些则是因为在不同环境中不良的性能表现或者是比其他的候选算法表现更差。NIST举行了两次会议讨论这些提交的方案(1998年8月AES1,1999年3月AES2)。在1999年8月,他们宣布将候选名单从15个缩减至5个(MARS、RC6、Rijndael、Serpent、Twofish,也被称为AES Finalist,AES决赛算法),都由著名的、在社区中被尊敬的密码学家们所设计。在AES2会议投票的投票结果如下:

  • Rijndael:86赞成,10反对
  • Serpent:59赞成,7反对
  • Twofish:31赞成,21反对
  • RC6:23赞成,37反对
  • MARS:13赞成,84反对

在另一轮更加激烈的密码分析之后,最终在2000年4月AES3会议上,五个算法的代表团队对关于为什么他们各自的算法应被选作AES的原因做了演讲以及辩论。最后,2000年8月2日,NIST宣布拟将Rijndael作为建议的AES标准,并于2001年2月28日通过在联邦公报上发布公告作为FIPS草案征求意见。2001年11月,NIST宣布,AES被批准为"联邦信息处理标准"。在这个过程中,NIST由于开放包容的态度以及选拔过程之中的专业和专注,赢得了来自密码社区的赞誉。落选的Twofish算法的作者之一,布魯斯·施奈爾),在竞选结束之后写道,"除了对NIST和AES选拔的赞美,我没什么可以说的了。"

对AES算法有理论上的攻击,但都需要海量的数据存储和运算时间。据估计,要攻击AES加密的攻击需要的运算量达到38万亿比特,这能超过2016年全球所有计算机上存储的所有数据,要处理这些数据,现有的计算能力需要数十亿年,这样看AES的破解,在目前是完全不可行的。

可以看到,一个强大而安全的密码算法的产生和成熟,是一个漫长而艰苦的过程。这些密码算法由这个世界上最顶尖的信息安全专家、数学家和密码学专家们构想和实现,并通过这个世界上最强大的计算机和最聪明的大脑来进行交叉测试和验证,并在学界和产业界进行广泛公开的讨论和筛选,又在现实的世界中长期稳定的应用,说明起码在人类现有的认知领域内,这个算法和设计是安全、有效和可信的。