前面已经提到过白盒AES算法了,由于白盒AES性能比原来的算法慢,所以想着有没有办法在有源码的情况下把 key 还原出来。google之后发现看雪上有一篇讲破解白盒AES算法的,于是尝试了一下,并且成功获取到了原始的key,所以这里分享一下我的过程,原理 还是得参考 https://bbs.pediy.com/thread-254042.htm
以前的文章已经讲过白盒AES 的原理了,这里直接讲如何破解。正如看雪文章里所言,可以使用DFA 对白盒AES进行破解。
这个攻击分为两步:
提前准备了一个 aes 算法工程, 我这里直接使用原始AES, 毕竟核心是如何构造出fault 数据。
https://github.com/TinyNiko/white_aes
首先我们需要固定住输入。我的demo代码中是直接做了一个aes 加密, 那么我们是可以知道原始 aeskey 的,后续只要验证,DFA攻击是否能还原出 key 就行。
1 | const uint8_t *key = "\x6C\x28\x93\xF2\x1B\x61\x85\xE8\x56\x72\x38\xCB\x78\x18\x49\x45"; |
记录第一次正确的aes 加密结果,记为 golden_ref
。
然后最关键的一步, 在第9
轮 列混合(Mix Column)
之前,更改状态矩阵的一个字节数据,比如
1 | uint8_t *pp = (uint8_t *)state; |
我在第九轮的列混合前, 加了一个判断,如果当前是第9轮,那么状态矩阵的最后一个字节变为 0x33(这个值随便填)。
然后记录这个时候的加密结果, 看看和 golden_ref
是不是只有4个字节不一样, 如果刚好四个字节不一样, 那么这个关键点就找到了, 如果只有1字节改变,
说明点找得太晚,如果有16字节不同说明点找得太早。
之后就是一个重复的过程,把状态矩阵里的每一个位置都改一遍, 就可以得到 16 组 不同的加密结果, 也就是fault 数据。
然后利用phonenixAES, 把 golden_ref
和fault 数据
一起丢进去, 最后可以得到一个Roundkey 10
。 至此,最关键的一步就完成了。
1 | #!/usr/bin/env python3 |
在拿到RoundKey 之后,我们可以使用 https://github.com/SideChannelMarvels/Stark 中的 aes_keyschedule 反推出aeskey,然后对这个
aeskey 进行验证即可。
本文讲了一种破解白盒AES的方法。 文章我很早的时候就看过了,但是我一直担心内容会不会过于复杂,导致投入和产出不成比例, 最终我自己花了一个小时不到就搞定了,所以大家有好的想法还是花点时间早点去验证。