聚焦未受保护的AES128白盒实现
引言
一切始于我研究@elvanderb制作的NSC2013 crackme,简而言之,你需要破解一个经过高度混淆的AES128白盒实现。这个挑战可以通过多种方式解决:
- 最简单的方法:无需了解白盒、加密甚至AES的任何知识;只需将函数视为黑盒,尝试发现其内部运作中的“设计缺陷”。
- 精英方法:需要理解并恢复整个白盒的设计,然后识别设计弱点,使挑战者能够直接攻击并恢复加密密钥。@doegox最近写了一篇非常棒的详细文章,强烈推荐阅读:Oppida/NoSuchCon挑战。
令人烦恼的是,网络上没有太多可理解的可用C代码来实现这类功能,尽管如此,你确实可以找到一些不错的学术参考文献;它们是构建自己实现的绝佳资源。
本文旨在以简单的方式简要介绍AES白盒的外观,并展示设计的重要性,以防止加密密钥被提取。今天讨论的实现完全不是我的创作,我只是遵循了James A. Muir撰写的一篇非常棒的论文(即使对于像我这样的非数学/密码学人士也是如此!)的第一部分(可能会另写一篇文章讨论第二部分?谁知道呢)。
想法很简单:我们将从一个干净的纯C语言AES128加密函数开始,通过几个步骤修改并转换它为一个白盒实现。
像往常一样,所有代码都可以在我的github账户上找到;鼓励你破解它们!
当然,我们将用这篇文章简要介绍白盒密码学是什么,它的目标是什么,以及为什么它有点酷。
在深入之前,以下是内容目录:
目录
- 引言
- AES128
- 介绍
- 密钥调度
- 加密过程
- 变换
- AddRoundKey
- SubBytes
- ShiftRows
- MixColumns
- 组合在一起
- 白盒化AES128的约7个步骤
- 介绍
- 步骤1:将第一个AddRoundKey带入循环,并将最后一个踢出循环
- 步骤2:SubBytes然后ShiftRows等于ShiftRows然后SubBytes
- 步骤3:先ShiftRows,但需要ShiftRows轮密钥
- 步骤4:白盒化它,就像它很热一样
- 步骤5:将MixColumns转换为查表
- 步骤6:添加一个小异或表
- 步骤7:组合TBoxes和Ty表
- 最终代码
- 攻击白盒:提取密钥
- 混淆它?
- 最后的话
AES128
介绍
好了,我们开始:这部分只是对AES(使用128位密钥)大致工作原理的回顾。如果你已经了解,请随意跳到下一级。基本上在这里,我只是想让我们构建第一个函数:一个简单的块加密。如你所料,函数的签名将如下所示:
|
|
加密工作在11轮中进行,第一轮和最后一轮与另外九轮略有不同;但它们都依赖于四个不同的操作。这些操作称为:AddRoundKey、SubBytes、ShiftRows、MixColumns。每轮使用一个128位轮密钥修改一个128位状态。这些轮密钥是通过密钥扩展(称为密钥调度)函数从加密密钥生成的。注意第一个轮密钥实际上是加密密钥。
AES加密的第一部分是执行密钥调度以获取我们的轮密钥;一旦我们拥有所有轮密钥,就只是使用我们看到的四个不同操作来生成加密的明文。
我知道我相当喜欢以视觉方式查看加密算法的工作原理,如果这也是你的情况,请查看这个SWF动画(这里没有漏洞,不用担心):[Rijndael_Animation_v4_eng.swf];否则你也可以阅读FIPS-197文档。
密钥调度
密钥调度就像是算法中最重要的部分。正如我之前所说,这个函数是一个派生函数:它接受加密密钥作为输入,并将生成加密过程将使用的轮密钥作为输出。
我不太想详细解释它是如何工作的(因为用文字解释有点棘手),我宁愿建议你阅读FIPS文档或跟随flash动画。以下是我的密钥调度的样子:
|
|
太好了,随意转储轮密钥并与官方测试向量进行比较,以说服自己这玩意儿有效。一旦我们有了这个函数,我们需要构建核心加密算法将使用和重用的不同原语。其中一些就像1行C代码,非常简单;其他一些则有点复杂,但无论如何。
加密过程
变换
AddRoundKey
这是一个非常简单的操作:它接受一个轮密钥(根据你当前所在的轮次),状态,并将状态的每个字节与轮密钥进行异或。
|
|
SubBytes
另一个简单的操作:它接受状态作为输入,并使用前向替换盒S_box替换每个字节。
|
|
如果你对S_box的值是如何计算的感兴趣,你应该阅读我朋友@kutioo写的以下博客文章:[AES SBox and ParisGP]。
ShiftRows
这个操作有点不那么棘手,但仍然相当直接。想象状态是一个4x4