白盒AES破解

0x00 前言

前面已经提到过白盒AES算法了,由于白盒AES性能比原来的算法慢,所以想着有没有办法在有源码的情况下把 key 还原出来。google之后发现看雪上有一篇讲破解白盒AES算法的,于是尝试了一下,并且成功获取到了原始的key,所以这里分享一下我的过程,原理 还是得参考 https://bbs.pediy.com/thread-254042.htm

0x01 破解

以前的文章已经讲过白盒AES 的原理了,这里直接讲如何破解。正如看雪文章里所言,可以使用DFA 对白盒AES进行破解。
这个攻击分为两步:

  1. 生成fault 数据
  2. 利用fault 数据还原始roundkey

准备工作

提前准备了一个 aes 算法工程, 我这里直接使用原始AES, 毕竟核心是如何构造出fault 数据。

https://github.com/TinyNiko/white_aes

还原RoundKey

首先我们需要固定住输入。我的demo代码中是直接做了一个aes 加密, 那么我们是可以知道原始 aeskey 的,后续只要验证,DFA攻击是否能还原出 key 就行。

1
2
const uint8_t *key = "\x6C\x28\x93\xF2\x1B\x61\x85\xE8\x56\x72\x38\xCB\x78\x18\x49\x45";
uint8_t plain[33] = "\x19\xec\x35\x72\xac\xca\xa7\x92\xbc\xb1\xe8\xe1\xdc\x59\x53\x66\x54\xbf\x08\x84 \x82\xa4\xef\x35\x5a\x66\x7f\xa1\x4e\x12\x24\xe9\x00";

记录第一次正确的aes 加密结果,记为 golden_ref

然后最关键的一步, 在第9列混合(Mix Column) 之前,更改状态矩阵的一个字节数据,比如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  uint8_t *pp = (uint8_t *)state;
for (round = 1; ; ++round)
{

SubBytes(state);
ShiftRows(state);
if (round == Nr) {
break;
}
if(round == Nr - 1){
// Modify index here
pp[15] = 0x33;
}
MixColumns(state);

AddRoundKey(round, state, RoundKey);
}
// Add round key to last round
AddRoundKey(Nr, state, RoundKey);
}

我在第九轮的列混合前, 加了一个判断,如果当前是第9轮,那么状态矩阵的最后一个字节变为 0x33(这个值随便填)。
然后记录这个时候的加密结果, 看看和 golden_ref 是不是只有4个字节不一样, 如果刚好四个字节不一样, 那么这个关键点就找到了, 如果只有1字节改变,
说明点找得太晚,如果有16字节不同说明点找得太早。

之后就是一个重复的过程,把状态矩阵里的每一个位置都改一遍, 就可以得到 16 组 不同的加密结果, 也就是fault 数据。

然后利用phonenixAES, 把 golden_reffault 数据 一起丢进去, 最后可以得到一个Roundkey 10。 至此,最关键的一步就完成了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/usr/bin/env python3
import phoenixAES

with open('tracefile', 'wb') as t:
t.write("""
868fc14bccc36e3c657b73271a32dcd7
ab8fc14bccc36e0f657b7e271a9edcd7
e98fc14bccc36ed9657b80271adcdcd7
d58fc14bccc36e5d657b6a271a38dcd7
da8fc14bccc36e0a657b62271a6fdcd7
865ac14b08c36e3c657b73201a3239d7
8613c14b86c36e3c657b73401a325cd7
86ecc14b82c36e3c657b73701a32afd7
86bdc14be4c36e3c657b73851a3257d7
868f004bcc0b6e3c617b73271a32dc7a
868f544bcc2c6e3c527b73271a32dc61
868f6f4bcccc6e3ce17b73271a32dc4a
868f394bcccc6e3c0e7b73271a32dc80
868fc1ecccc3993c657d73273c32dcd7
868fc1bfccc3a83c650f73274032dcd7
868fc1c7ccc38f3c651c7327da32dcd7
868fc1b1ccc33d3c658f73278632dcd7
""".encode('utf8'))

phoenixAES.crack_file('tracefile')
# Last round key #N found:
# 040D08DA68001026F3DC0D68897148B4

还原AES KEY

在拿到RoundKey 之后,我们可以使用 https://github.com/SideChannelMarvels/Stark 中的 aes_keyschedule 反推出aeskey,然后对这个
aeskey 进行验证即可。

总结

本文讲了一种破解白盒AES的方法。 文章我很早的时候就看过了,但是我一直担心内容会不会过于复杂,导致投入和产出不成比例, 最终我自己花了一个小时不到就搞定了,所以大家有好的想法还是花点时间早点去验证。