【信息科学与控制工程】

针对AES最后一轮加密的Cache攻击方法

陆 垚,陈开颜,王寅龙

(陆军工程大学, 石家庄 050000)

摘要:Flush+Reload攻击是以Cache结构构建隐蔽信道,在加密算法执行路径上进行指令攻击,针对OpenSSL0.9.8.b中AES加密代码实现,分析了其加密实现的薄弱点在于一次加密只使用一次Te4表,提出了一种针对AES最后一轮加密实施Flush+Reload攻击的方法;实验结果表明:当收集280×103的AES加密密文和计时数据后,通过表项值与密文值的异或运算,找到最多的共有解可得到最后一轮加密的密钥值,并结合4个Te表值恢复全部的轮密钥。

关键词:AES查表法;Rijndael 算法;flush+reload攻击;Cache计时攻击;T表

1997年1月,美国国家标准技术研究所宣布开发AES加密标准,使其成为新的联邦信息处理标准,取代旧的数据加密标准DES和3DES[1]。在AES 算法中,除最后一轮外,其他每一轮都要执行这4 种变换:字节替换、行移位、列混淆和轮密钥加,最后一轮不执行列混淆变换,且常采用流水线模式进行加密,这种加密模式需要消耗大量的运算资源且效率低下,尤其是在加密大文件或大数据量时,缺点体现更加明显。在传统PC环境下,实现对大文件的AES加密变成了查表操作,虽然需要占用内存容量,但却很大程度节省了计算单元,加快了运行速度。

Cache是位于CPU与主存DRAM间的高速缓冲存储器,是为了协调CPU处理速度快而主存储器传送数据慢的硬件结构,当进程被执行时,根据替换算法策略将循环使用的数据载入到Cache中,再次使用时从Cache中快速调用,现代CPU通常有2~3个层次的缓存结构,一级缓存、二级缓存和三级缓存,与主存地址的三种映射方法:全相联、直接映射、组组映射[2];而Cache 计时攻击又是旁路攻击中一种重要的方法,是利用一个与密码进程共享Cache的间谍进程监测密码进程对Cache 的访问情况从而获取密钥,与其他旁路攻击手段相比,具有无需物理接触密码设备、可通过网络远程获取密钥的优点,侧通道攻击初期,最常见的攻击目标是单核CPU内的L1缓存[3-4]。2014年,Yarom等[5]首次实现了跨内核/vm的Flush+Reload攻击,在GnuPG中RSA上实现,恢复超过90%的密钥位。而后Flush+Reload攻击被应用于更多的加密库和加密算法。例如,Benger等[6]推测了对OpenSSL的ECDSA签名实现上Flush+Reload攻击的方法。同年,Irazoqui等[7] 提出了更快的攻击,在云平台中,用不到一分钟的时间内恢复整个密钥位。不久之后,Zhang等[8] 在PaaS云中验证了Flush+ Reload攻击的适用性,并获得一个用户购物车的条目数。在2015年,Irazoqui等[9]展示了从错误填充cbc的TLS包中恢复隐私数据—幸运13攻击。而后,Gruss等[10]提出了在LLC缓存上应用Flush+Reload攻击检测受害者键击的方法,他们的攻击中往往需要依赖特殊手段中断加密进程才能精确计时,本文的工作是对前人工作的拓展,将flush+reload攻击方法运用于AES最后一轮加密,并提出了一种不需要干预加密进程正常执行的攻击方法。

1 AES查表实现及flush+reload缓存攻击原理

1.1 AES查表法的实现

AES加密在OpenSSL0.9.8.b[11]中的实现方法,实际就是将AES轮加密转换为查找T表的操作,查找Te0~Te3四个表,最后一轮加密查找Te4表,解密运算需要查找表Td0~Td4,每个表都是256项的32 bits大小的值构成,即用10个1 kb大小的查找表操作代替了AES的流水线运算。在明文异或初始密钥后,共进行了9轮轮加密操作,在源代码1中展示了OpenSSL0.9.8.b中的轮加密操作,以第一轮为例,每一轮的4个32 bits的输出值,由16个查找表操作完成。

#ifdef FULL_UNROLL

/* round 1:*/

t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];

#由明文异或初始密钥后的状态值s0~s3四个32 bits值作为输入;

以s0的高8bits为索引值查找Te0表,得到32 bits表项值,同理查找Te1~Te3;

之后4个表项值与轮密钥前32 bits值rk[4]进行异或运算,得到该轮输出的前32 bits值。

t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[5];

t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[6];

t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[7];

以128 bits的输入值中的8 bits为索引16次查找Te0~Te3表,与密钥扩展得到的轮密钥进行异或,得到4个32 bits的表项值,连接成为128 bits就得到了单轮的输出值,并作为下一轮的输入值。

#endif /* ?FULL_UNROLL */

/*

* apply last round and

* map cipher state to byte array block:

*/

s0 =

(Te4[(t0 >> 24) ] & 0xff000000) ^

(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^

(Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^

(Te4[(t3 ) & 0xff] & 0x000000ff) ^

rk[0];

PUTU32(out,s0);

#以第9轮加密输出t0~t3四个32 bits为输入值,取其高8 bits为索引值查找Te4表得到32 bits的表项值,而后提取表项值的前8 bits;

以t1中间16~23 bit为索引查找Te4表得到32 bits的表项值,提取中间的8 bits值,同理索引t2、t3提取另外两个8bits的表项值;

四个8 bits的表项值连接为32 bits值与轮密钥r[0]异或运算,得到32 bits的密文值,同理s1~s3。

在第9轮加密操作执行之后,源代码2展示了OpenSSL0.9.8.b中实现的最后一轮加密操作,只执行了16次查找Te4表的操作,而实际Te4表就是将8 bits表项值重复4次扩展成为32 bits长度的表项值,在源代码3中展示了OpenSSL 0.9.8b中Te4表的一部分。

最后一轮加密就是将第9轮加密输出作为本轮的输入按8 bits大小划分,以8 bits为索引查找表Te4,得到32 bits大小的表项值,并压缩到8 bits大小,然后由16个8 bits的表项值连接成为128 bits的值,异或最后一轮密钥值得到密文输出值。

1.2 flush+reload的攻击原理

在当代操作系统和管理程序中允许不同进程/用户共享相同的物理内存的。所有Linux操作系统都实现了内核相同页面的合并Kernel Samepage Merging(KSM)机制,它合并属于不同进程的重复只读内存页,KSM内核守护进程ksmd扫描用户内存,寻找可能在用户之间共享的页面,为这些页面创建签名。这些签名保存在重复数据删除表中。当发现两个或多个具有相同签名的页面时,将对它们进行完全交叉检查,以确定它们是否相同。为了创建签名,当在候选项中发现重复的页面签名并对内容进行交叉检查时,ksmd会自动使用写时复制(COW)标记其中一个重复的页面,并在进程/用户之间共享它,同时删除另一个副本。此外,VMware实现的透明的页面共享Transparent Page Sharing(TPS),这是与KSM类似的机制,也允许不同的vm共享内存。

攻击的先决条件:

① 由于KSM机制,间谍进程和受害者(加密进程)实现主存或页面共享。

② 支持clflush指令,能够从所有缓存层次结构中驱逐数据。

③ 使用rdtsc指令能够得到精准的时间戳,或者在屏蔽指令mfence/lfence指令下得到的精确CPU周期。

图1展示了flush+reload的攻击方法,在step1中的Cache中数据块是在间谍进程和受害者间主存或页共享的,step2间谍进程通过clflush指令将该数据块从缓存中清除,step3中受害者执行加密进程,会将加密进程所使用的数据从共享主存中加载到缓存中,在step4中间谍进程重载了该数据块的主存地址,在step3之前和step4之后使用rdtsc指令记录时时间戳,如果这个数据块被加密进程所使用的,那么发生命中,检测为低的重载计时值,否则被监测到高的重载计时差值,进而遍历所有的共享地址空间,就能够得到加密时使用数据对应的活动地址集,即Te表的地址集(由于轮密钥生成操作与明文无关,轮密钥生成运算只执行一次后就直接使用,而加密查找Te表的操作要持续执行,所以在连续执行加密进程时,不用考虑Td0~Td4进入到cache中)。

2 攻击原理及步骤

攻击步骤:

① 在加密进程持续执行时,使用flush+reload基本方法判断共享主存中活动的地址集,即加密进程数据的地址,通过对源代码的学习,可以知道加密进程的数据就是表Td0~Td4、Te0~Te4、rcon的数据,rcon是拥有10个32 bits表项值的小表,加密进程不加载表Td0~Td4(Td表用于解密),可以得到Te0~Te4地址;

② 对Te4表中第一个cacheline大小的数据块进行监控,使用flush+reload方法,记录重载监控内存块的和时间和对应的密文(< [],t >);

③ 筛选计时小于阈值即发生cache命中的密文,与监控地址内的数据Te4,共同恢复最后一轮的密钥。

图1 flush+reload攻击方法

2.1 获得加密进程活动地址集方法

使用mmap函数映射共享空间,在共享空间地址中查看加密操作的活动地址集。

在算法1中描述了如何获取Te0~Te4的表地址;其中,rdtsc函数由mfence/lfence屏障指令和rdtsc计时指令构成,确保指令顺序执行。

2.2 利用flush+reload方法求解密文值对应的监测计时

间谍进程对Te4表中一个Cacheline长度的数据块进行监控,在加密进程执行前对其flush操作,在加密进程执行后测量reload该Cacheline的用时t,常用加密库中加密用到的数据都经过优化,几乎都是对齐的,故不需要求解偏移地址,如果未对齐也可以选择监控Te4表中占用的第二个Cacheline数据进行实验,在实验中只需要监测Te4表中一个Cacheline大小的数据块,共16个32 bits的表项值的数据块,存储在密文字节向量(< [],t >),使用字典中键值对X= dict(′[]′:t)的数据类型的采集,在算法2描述了求解该键值对的过程。

1:Input:byte *Te4[0], #以*Te4地址为例获取计时

long unsigned int Plaintext[] #明文

2:Output:X= dict(′Cι[16]′:t) #使用键值对dict的数据结构,采集密文及对应监测地址的重载时间

3:P[16]= Plaintext.split(16) #将明文按16个字节长度分割

4:flush(*Te4[0]) #将*Te4[0]地址数据从cache中驱逐

5:Cι[16] = Encryption(P[16]) #执行加密进程

6:st = rdtsc() #记录时间戳

7:reload (*Te4[0]) #重新将*Te4[0]地址数据载入到cache中

8:ed = rdtsc() #记录时间戳

9:t=ed-st #记录重载时间

10:return X= dict(′Cι[16]′:t) #返回密文和其对监控地址的重载计时

2.3 密钥恢复算法

Cι表示M组密文中的第ι组密文,定义一个阈值,提取小于时间阈值的多组密文值Cι,这些密文在最后一轮加密时使用了监控的Cacheline内的数据,即发生了Cache命中,Cι=(c0,…,c15),在源代码2中以s0为例展开:

s0 =(Te4[(t0 >> 24)] & 0xff000000) ^(Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^(Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^(Te4[(t3) & 0xff] & 0x000000ff) ^rk[0];

s0=(c0,c1,c2,c3,);

rk[0]代表32 bits的密钥值,按8 bits长度展开,则

rk[0]=( k0,k1,k2,k3);

代入k0s0中,以32 bits分割s0则

c0= Te4[(t0 >> 24)] & 0xff000000^k0

在源代码3中,由于采取重复值扩展,可得

byte(Te4[(t)])=

Te4[(t)] & 0xff000000= Te4[(t)] & 0x00ff0000=

Te4[(t)] & 0x0000ff00=Te4[(t)] & 0x000000ff;

用16个8 bits长度的A0A15代替最后一轮四个32 bits 输入值t0~t3,那么t0 >> 24代表最后一轮输入的第一个byte值,可表示为A0,则

c0= byte(Te4[(A0)])^k0,那么有

k0= byte(Te4[(A0)])^c0

得到了恢复最后一轮密钥值一般公式:

ki=byte(Te4(Aj)) ^ c i,其中k i代表最后一轮第i位byte密钥值,Aj代表行移位操作产生的偏移。

恢复密钥简码如算法3所示,对于每组发生命中的密文值,需要在被监控Cacheline数据块中的16个表项值和16个密钥位置间进行定位,会产生256个算数值。

1:Input:long unsigned int X[],long unsigned int Threshold

2:Output:byte K[]

3:int Count_key[] #定义密钥值的统计数

4:byte Y[][16] #定义一个m行16列的密文数组

5:Cι[16] = Ciphertext.split(16) #将密文按16字节长度分割

6:forι= 0 to M do #筛选发生cache命中的密文

8: Y[m][16] ← Cι[16]

9:end

10:for i=0 to 15 do#循环恢复最后一轮16位密钥字节

11: int Count_key[16]={0}

12: for ι′ = 0 to m do #使用m个命中密文计算

13: for j = 0 to 15 do

#每次命中,可能来源于被监控cacheline大小的内存块中的16个字节,每个内存块中字节都要计算

14: Count_key[Y[ι′][i] ^ Te4[0][j]]++

#统计相同密钥值的计数

15: end

16: end

17:k[i] = Count_key.index(max(Count_key[])) #最大计数值对应的索引数据,就为第i个密钥字节的正确值

18:end

19:return K9[]={k[0],k[1],…,k[15]}#K9最后一轮的密钥值

图2展示了对最后一轮密钥的第二个字节k1的攻击,对Te4表的第1组64 byte大小的数据块Te4[0]进行监控,在加密进程执行后,从M组密文中收集reload时间小于阈值的m组,即发生命中,这些密文在加密的最后一轮使用了被监控的数据块,对这些密文值进行图2中的运算, 其中只有一个是正确的数值,通过对计算值Count_key[Y[ι′][i] ^ Te4[0][j]]的统计,最多的共有解max(Count_key[])对应的Y[ι′][i] ^ Te4[0][j]为正确的密钥值,如下:

图2 恢复k1的密钥byte值

ι′代表m组命中密文组中的第ι′个,对应的max(Count_key[k])为4,是实验中计数最多的,即k1 = b3。

3 实验结果

实验是在Ubuntu16.04.3系统中,以OpenSSL0.9.8.b加密库中AES算法为攻击目标,实验设备为Intel i5-4590四核心、3.3 GHz的CPU处理器,该处理器有3层Cache结构,每个core上的存储结构相同,一个L1数据缓存和L1指令缓存,都为32 kb大小、一个256 kb大小的L2缓存,四个core共用一个6 MB大小的L3缓存。其每个Cacheline大小为64 bytes,每个Te4表中的元素为4 bytes,所以1次攻击可以检测16个表值是否发生命中,图3展示了对命中、未命中两种情况各10 000次攻击数量的计时分布,通过实验可以观测到Cached数据重载计时相对集中,主要因为缓存技术成熟,L1、L2、L3缓存速度差异不明显,导致缓存不同层级间的计时差异不到5个CPU周期,Cached数据计时平均值在5个周期,而Uncached数据重载计时相对分散,平均值在26个周期,差距在11个周期,取阈值(2tCached+tUncached)/3等于11,恰好能区分97%以上的计时值,这个阈值是通过图4中实验得出的最优解。

图3 对i5-4590进行50 000次flush-reload计时攻击(区分命中、未命中)

为了获得准确的密钥值,本实验取103量级的共有解作为密钥值,图4表示了恢复正确密钥与密文数据量之间的关系,在获得280×103组密文数据量后,就能够完整的恢复最后一轮密钥值,而理论需要256×103组密文,是实际值的91.5%,对比图3的97%分辨率差距6.5%左右,证明在加密进程不同于单纯的数据替换,在加密进程执行时,系统的其他进程会产生额外的噪声影响,且密文数据在280×103之前显示为逐渐上升的曲线,证明最后一轮16个密钥字节中的部分密钥字节先达到103量级,优先被确认恢复,不同于理想的所有密钥字节的平行恢复,这是因为产生命中密文的相关密钥位置是随机的,命中密文不是平均使用16个密钥字节的,更加符合实际情况。

图4 获得最后一轮密钥值对应的密文量

4 结论

本文工作是从OpenSSL0.9.8.b的AES加密实现代码中找到了可实施Cache攻击的薄弱点,提出了一种通用性强、不依赖偏移地址、不需干预加密进程、不需加密前明文数据预处理的攻击方法。实验表明对比使用Flush+Flush攻击方法,Flush+Reload攻击具有更好的分辨率,FF方法的数据替换只能区分93%的计时,本文提出的攻击方法能够分辨97%以上的计时值,且Cached与Uncached数据计时差异明显。不需要特殊手段中断加密进程,使得此攻击更加有效、更加适用于真实的加密环境。在加密进程执行时进入缓存的数据只有明文和T表的数据,也可对明文进行标记,使其区别于T表的数据作为明文输入,执行更加精准的攻击,然而此攻击依赖于加密算法单次访问Te4表,如果多次访问,就要去除更大体量的噪音值,下一步将完善此进程,应用与其他加密算法库实现的AES查表法。

参考文献:

[1]DAEMEN J,RIJMEN V.AES the advanced encryption standard[J].The Design of Rijndael,2002(3):71-74.

[2]PATTERSON D A,HENNESSY J L,GOLDBERG D.Computer architecture:a quantitative approach[M].Morgan Kaufmann Publishers Inc.2008.

[3]RISTENPART T,TROMER E,SHACHAM H,et al.Hey,you,get off of my cloud:exploring information leakage in third-party compute clouds[C]//Proceedings of the 16th ACM conference on Computer and communications security.ACM,2009:199-212.

[4]ZHANG Y,JUELS A,REITER M K,et al.Cross-VM side channels and their use to extract private keys[C]//Proceedings of the 2012 ACM conference on Computer and communications security.ACM,2012:305-316.

[5]YAROM Y,FALKNER K.Flush+reload:a high resolution,low noise,L3 Cache side-channel attack[C]//Proceedings of the 23rd USENIX conference on Security Symposium.San Diego:Association,2014:719-732.

[6]BENGER N,VAN DE POL J,SMART N P,et al.“Ooh Aah…Just a Little Bit”:A small amount of side channel can go a long way[C]//International Workshop on Cryptographic Hardware and Embedded Systems.Springer,Berlin,Heidelberg,2014:75-92.

[7]IRAZOQUI G,INCI M S,EISENBARTH T,et al.Wait a minute! A fast,Cross-VM attack on AES[C]//International Workshop on Recent Advances in Intrusion Detection.Springer,Cham,2014:299-319.

[8]ZHANG Y,JUELS A,REITER M K,et al.Cross-tenant side-channel attacks in PaaS clouds[C]//Proceedings of the 2014 ACM SIGSAC Conference on Computer and Communications Security.ACM,2014:990-1003.

[9]IRAZOQUI G,INCI M S,EISENBARTH T,et al.Lucky 13 strikes back[C]//Proceedings of the 10th ACM Symposium on Information,Computer and Communications Security.ACM,2015:85-96.

[10]GRUSS D,SPREITZER R,MANGARD S.Cache template attacks:Automating attacks on inclusive last-level caches[C]//24th {USENIX} Security Symposium({USENIX} Security 15).2015:897-912.

[11]GULLASCH D,BANGERTER E,KRENN S.Cache games:Bringing access-based cache attacks on AES to practice[C]//2011 IEEE Symposium on Security and Privacy.IEEE,2011:490-505.

A Cache Attack Method Against the Last Round of AES Encryption

LU Yao, CHEN Kaiyan, WANG Yinlong

(Simulation Center of Army Engineering University, Shijiazhuang 050000, China)

Abstract: Flush+Reload attacks build a hidden channel using the Cache structure, and hasinstruction attack on the execution path of encryption algorithm. We analyzed security of AES encryption source code of OpenSSL0.9.8b in view of cache time attack to find its weakness. The weak point of encryption implementation is that the encryption only uses Te4 table once, and then proposes a method of “Flush+Reload” attack against the last round of AES encryption. Experiments show, when collects 280×103 ciphertext and timing data, with the xor entry of table value with ciphertext value, we find the most same solution, and it’s the secret key value of last round of encryption, then all rounds secret keys can be recovered by 4 Te table values and last round key values.

Key words: AES; Rijndael algorithm; flush+reload attack ; cache timing attacks; T table

收稿日期:2019-07-08;

修回日期:2019-11-06

基金项目:国家自然科学基金项目(57377170;61602505;61271152)

作者简介:陆垚(1987—),男,硕士研究生,主要从事计算机硬件安全、旁路攻击研究,E-mail:294102746@qq.com。

通讯作者:陈开颜(1970—),女,副教授,主要从事旁路攻击研究,E-mail:chen_wu2013@163.com。

doi: 10.11809/bqzbgcxb2020.06.030

本文引用格式:陆垚,陈开颜,王寅龙.针对AES最后一轮加密的Cache攻击方法[J].兵器装备工程学报,2020,41(06):149-154.

Citation format:LU Yao, CHEN Kaiyan, WANG Yinlong.A Cache Attack Method Against the Last Round of AES Encryption[J].Journal of Ordnance Equipment Engineering,2020,41(06):149-154.

中图分类号:TP309.1

文献标识码:A

文章编号:2096-2304(2020)06-0149-06

科学编辑 闫怀志 博士(北京理工大学副教授、硕导)

责任编辑 唐定国