测信道攻击——用DPA攻击固件中的AES
上篇攻击AES的方法其实属于SPA,本实验用更牛逼的方法,DPA来攻击AES,而且是货真价实的AES。关于DPA,我前面有篇博客有所讲解(初识测信道攻击)。下面开始环境配置,这里需要注意的是,notebook中给出的SS_VER是’SS_VER_1_1’,我运行后总是失败,换成前面实验用的SS_VER_2_1就好了。这里编译、上传固件、安装就不多解释了,与之前实验一致。
1 | SCOPETYPE = 'OPENADC' |
1 | %run "../../Setup_Scripts/Setup_Generic.ipynb" |
1 | %%bash -s "$PLATFORM" "$CRYPTO_TARGET" "$SS_VER" |
1 | cw.program_target(scope, prog, "../../../hardware/victims/firmware/simpleserial-aes/simpleserial-aes-{}.hex".format(PLATFORM)) |
抓取2500条能量迹
1 | from tqdm import tnrange |
在实验利用一个bit恢复AES key中之所以能成功是攻击流中存在S-box。本次实验使用能量分析去破解AES密钥。之前的方法能生效是因为我们攻击的数据流就在S-box中,而实战中我们不知道数值,只知道能量消耗,要找到他们对应的二进制是比较困难的。而本攻击方式是利用S-box输出结果的一个bit(无论哪个都行)将能量分成两个部分(0和1),利用1消耗能量是大于0的,而且根据之前的实验,数据总线中数据的值与能量消耗之间有一定联系。DPA分析AES只需要整个能量迹包含了加密流程发生的时间段。
S-box是固定的:
1 | sbox = [ |
0,1两组对比的能量线
1 | %matplotlib notebook |
查看输入数据
1 | print(textin_array[0]) |
1 | CWbytearray(b'39 79 82 4f 97 0e a3 b9 1d 07 14 78 df 3c a7 89') |
定义能量迹的数量和每条能量迹的点的数量
1 | numtraces = np.shape(trace_array)[0] #total number of traces |
对两组能量迹取平均值,再取两者差的绝对值,看谁最大谁就最可能是密钥了
1 | guess_byte = 0 |
发现0x2b最大,即2b为key的第一个字节
1 | Guessing 00: 0.0016756559017779837 |
计算差异的函数,也用来解决幽灵峰问题
1 | def calculate_diffs(guess, byteindex=0, bitnum=0): |
查看不同key对应的差异图
1 | cw.plot(calculate_diffs(0x2B)) * cw.plot(calculate_diffs(0x2C)) * cw.plot(calculate_diffs(0x2D)) |
最后就是把剩下的字节都猜了,补全代码
1 | from tqdm import tnrange |
结果来看都猜对了!
我这次实验是成功了,但也有一些情况是没有成功的,下面是关于DPA攻击失败的一些问题以及解决方式
- 抓取的是幽灵峰的话可以尝试增加抓取的能量迹数量
- 修改攻击的目标位数,如最低位改为第三位,或者把很多位的结果都跑一下综合一下
如何解决幽灵峰的问题
先运行下这段准备好的DPA攻击代码
1 | from tqdm import tnrange |
画出猜测错误key的前几个可能值和真实key的差异图
1 | cw.plot(full_diffs_list[0][0x2B]) * cw.plot(full_diffs_list[0][0x40]) * cw.plot(full_diffs_list[0][0xBF]) |
正确key的峰形会在某些地方拥有比错误key的峰形高。
有关幽灵峰的问题之后再细补充
Reference