技术细节
介绍
《A Full Break of the Bitstream Encryption of Xilinx 7-Series FPGAs》论文介绍了两种针对Xilinx 7-Series FPGA的攻击,分别破坏了FPGA加密比特流的机密性和真实性,导致FPGA芯片失去了安全保障,想要从根本上解决这个问题只能更换FPGA芯片。
本文将介绍攻击所涉及到的知识和技术细节,如有不足之处,还请指出。
论文链接: https://www.usenix.org/system/files/sec20fall_ender_prepub.pdf.
技术说明
- 攻击不需要任何复杂的工具,只需要访问FPGA的JTAG或SelectMap接口,技术成本低,且不需要其他方面的专业技术;
- 如果FPGA连接的有微处理器,且微处理器连接了JTAG或SelectMap接口,便可以通过微处理器进行攻击,如果微处理器连接了网络,甚至可以远程发起攻击(只有当攻击者能够远程访问配置接口和加密比特流时,才有可能进行远程攻击);
- 通过这种攻击,攻击者可以获取7系FPGA中完整的解密后的比特流数据,也可以解密Virtex-6设备上的部分比特流;
- 此攻击利用了7系FPGA的设计漏洞。通过修改载入FPGA的加密比特流,利用FPGA本身作为解密软件,并使其将解密后的比特流写入WBSTAR寄存器中;
- 由于WBSTAR寄存器为32位,所以该攻击每次只能获取32位的解密比特流,所以想要获取全部的比特流,需要重复攻击步骤,且需要一定的时间;
Bitstream格式说明
上图中灰色部分为加密段
- SYNC:同步字段。
- 配置报头:包含了CBC加密向量并给出了下面加密部分的长度。
- HMAC报头:设置HMAC密钥(ipad),启动HMAC计算,用于验证比特流。
- 次要配置报头:配置其他的设置。
- fabric data:结构数据,用于配置结构。
- 配置页脚:结束配置,也用于比特流对齐。
- HMAC页脚:包含HMAC的opad和HMAC标记,该标记用于验证加密部分。
- 全局配置页脚:结束比特流和启动FPGA结构。
具体的格式内容如下:
其中wirte WBSTAR即为攻击要用到的指令,NOP为空指令。为了方便描述,将图中一行也就是128位称之为一块,每块有4个字,每个字包含32位比特流。下文也将采用这种方式进行解释。
CBC扩展性
Xilinx使用密码块链(CBC)模式,AES为比特流加密的底层密码。此攻击就是利用了CBC加密的扩展性。如上图所示,
P
i
P_i
Pi为明文块,
C
i
C_i
Ci为密文块,
k
k
k为加密密钥,
I
V
IV
IV为初始向量,
∆
∆
∆为攻击者设定的字。当攻击者将
C
1
C_1
C1于
∆
∆
∆异或后,在解密之后的明文
P
2
P_2
P2中也将于
∆
∆
∆异或,即改变密文的内容可以改变下一个块中明文的内容。
攻击步骤
1. 获取加密比特流
在物理访问的情况下,攻击者可以在加电期间对配置总线进行窃听或者从非易失性存储器中读出存储的加密比特流。在远程的情况下,攻击者可以从微处理器中提取加密比特流,或者从远程更新服务下载。我是从vivado中获取的,vivado中设置比特流加密和热启动的过程如脚注所示1。
2.创建恶意比特流
攻击者想要利用FPGA作为解密工具就要先创建恶意比特流,让FPGA将目标数据写入WBSTAR寄存器中。我们在这里选择WBSTAR命令,因为它是HMAC头之后第一个块中的最后一个命令,但是可以选择第一个块中的任何其他命令。WBSTAR指令最后10位数值为计数,代表指令后的第几块写入寄存器,正常情况其值1,即将接下来的一个字写入WBSTAR寄存器,而通常该字为全零,也就是写入得是空数据。
(为了方便介绍,作者在图中比特流前添加标记,每个标记代表一个块的比特流,如下图)
现在,攻击者可以通过在⓪块中与write WBSTAR指令相应的字中添加∆来更改加密比特流中的这个长度字段,从而利用CBC的扩展性,被操纵的块(HMAC头)会变成随机数据(图中用X标记)。然而,这种改变与比特流无关,因为其他的改变无论如何都会导致HMAC验证失败,并且比特流对于配置逻辑仍然有效,因为只更改了HMAC ipad长度。
加密数据的长度(不包括HMAC页眉和页脚)必须是512位的倍数,因为SHA-2在512位比特流上运行。因此,操作的加密数据必须至少有四个 ASE块 长,因此我们将写WBSTAR操作的长度设置为 0xD =13 (∆=0xC),即,所有数据直到512位加密数据块的末尾都写入WBSTAR寄存器,但当多个块写入同一个寄存器时,该寄存器中只存储最后写入的块。在512位块的末尾,我们放置待解密块④。该块可以是来自加密比特流的任何AES块,包括加密的结构数据。由于比特流加密采用的是CBC模式,因此③必须是来自CBC链的块,即它是④的“IV”,在FPGA解密过程中需要用到它。②用于增加加密块的长度(可以是随机的),使其长度达到512位。它位于WBSTAR写操作的块和两个解密块之间。注意,该随机块②和“IV”块③在解密是被解密为随机数据。由于WBSTAR写入操作写入13个字,所有随机数据都被认作为存储在WBSTAR寄存器中的数据,但是最后只有所需的解密字存储在WBSTAR寄存器中。
Xilinx的FPGA开发都是使用vivado产生比特流,而作者在论文中提到vivado所产生的比特流指令分布都差不多,所以攻击者可以通过观察推断所要修改的指令在比特流中的位置。为此我简单的学习了FPGA的开发流程和vivado的使用,实现了一个简单的功能,并生成了对应的未加密的比特流,如下图2:
根据Xilinx官网给出的7系FPGA比特流配置数据字段可以看出,蓝色高亮字段即为写入WBSTAR寄存器的指令(可能是未开启加密功能,此比特流没有HMAC验证,所以也就没有HMAC报头)。对应的加密比特流部分如下图:
从图中可以看出,比特流从0008 5B98开始进行加密,加密后完全看不出其中所含的信息。若和论文中描述的相同,则开始加密后的16个字为HMAC报头,蓝色高亮字段正下方即为需要修改的字段。
要读出最后一个块④中的其他字,应相应地改变∆值,即将写入长度设置为10、11或12。但是,需要注意的是配置逻辑会把写入WBSTAR寄存器的下一个字解释为指令,而它可能是来自结构的数据。因此,它可能不是正确的指令,从而导致不必要的随机命令。因此,需要改动块③中的加密比特流以将第13个(以及第12个、第11个)字更改为NOP命令。这可以防止配置逻辑错误地解释最后的字。
3.重置FPGA
在修改了加密比特流之后,将比特流载入FPGA。因为更改了比特流,所以HMAC验证无效,配置会自动重置了FPGA。但是HMAC在比特流的最后进行验证,写入指令已经执行完毕,解密比特流已经写入寄存器。在自动重置期间,WBSTAR寄存器中的内容不会被重置,所以其中的数据得以保留。
4.从寄存器中读出比特流
这个步骤只需要将论文中给出的读出比特流载入到FPGA中即可,如下图。在该比特流载入FPGA后,我推测是将WBSTAR寄存器中的内容写入外部存储器中,可以利用第一步用到的方法获取解密的比特流。
5.手动重置FPGA
攻击者需要手动重置FPGA配置逻辑,否则下次读取将失败。攻击者可以通过向JTAG接口发送JPROGRAM命令或在SelectMAP中将PROGRAM_B引脚置为低从而触发重置。
重复以上步骤即可读出所有比特流数据。
进阶攻击
由于HMAC验证的密钥也在加密比特流中,所以只要读出完整比特流即可获得HMAC密钥,而有了密钥,攻击者可以直接创建验证有效的加密比特流,甚至设置自己的HMAC验证密钥并计算相应的有效标记。
以下将介绍创建有效加密比特流的详细步骤:
如上图,设 d e c K A E S ( ) dec_{KAES}() decKAES()为AES解密函数, C i C_i Ci是密文块, P i P_i Pi是明文块,则 P i = d e c K A E S ( C i ) ⊕ C i − 1 P_i=dec_{KAES}(C_i)⊕C_{i-1} Pi=decKAES(Ci)⊕Ci−1,利用第一种攻击我们可以获得 P i P_i Pi,为了产生我们想要的 P i ′ P'_i Pi′,设置 C i − 1 ′ = P i ⊕ C i − 1 ⊕ P i ′ C'_{i-1}=P_i⊕C_{i-1}⊕P'_i Ci−1′=Pi⊕Ci−1⊕Pi′,即可将 P i P_i Pi转变成我们希望的 P i ′ P'_i Pi′,此时 P i − 1 = d e c K A E S ( C i − 1 ′ ) ⊕ C i − 2 P_{i-1}=dec_{KAES}(C'_{i-1})⊕C_{i-2} Pi−1=decKAES(Ci−1′)⊕Ci−2,同样的我们利用第一种攻击获取解密后的 P i − 1 P_{i-1} Pi−1,同时设置 C i − 2 ′ = P i − 1 ⊕ C i − 2 ⊕ P i − 1 ′ C'_{i-2}=P_{i-1}⊕C_{i-2}⊕P'_{i-1} Ci−2′=Pi−1⊕Ci−2⊕Pi−1′ 3,即可将 P i − 1 P_{i-1} Pi−1转变成我们希望的 P i − 1 ′ P'_{i-1} Pi−1′。执行此过程向 P 1 ′ P'_1 P1′,将 C 0 ′ C'_0 C0′设置成初始向量IV。通过此过程即可加密攻击者自己的比特流,或直接修改并生成一个有效的HMAC标记。至此比特流的真实性也被破坏。
总结
这两种攻击能够成功的主要原因有两个:
- 在HMAC验证之前,解密的数据已经又配置逻辑进行了解释和执行。通常,在比特流的末尾会检查恶意比特流,这样可以阻止修改后的比特流的内容在结构中运行。然而,攻击者只在逻辑内部运行,在配置逻辑中的命令不受HMAC保护。
- HMAC密钥KHMAC存储在加密比特流中。因此能够绕过加密机制的攻击者就可以读取KHMAC,从而计算有效标记。
以上内容均为个人理解,如有错误,还望指出。
比特流的加密设置流程如下图,需要在configuration中设置热启动
热启动设置
↩︎图片中只是比特流的一部分,实际的长度要比这个长的多。由于我所写的功能较为简单,下面的比特流基本为0,且操作指令与论文中不同,只能作为参考。 ↩︎
此处存在一个问题,在该论文中,作者设置 C i − 2 ′ = P i − 1 ⊕ C i − 2 ′ ⊕ P i − 1 ′ C'_{i-2}=P_{i-1}⊕C'_{i-2}⊕P'_{i-1} Ci−2′=Pi−1⊕Ci−2′⊕Pi−1′,而我觉得这样就不能正确的生成 P i − 1 ′ P'_{i-1} Pi−1′,应该将后面的 C i − 2 ′ C'_{i-2} Ci−2′改为 C i − 2 C_{i-2} Ci−2,但是不确定是否正确,所以希望了解的网友能够指出。 ↩︎