1 背景
当竞争对手获得我们的产品后,可能会采取以下常见行为来侵犯我们的知识产权:产品克隆、软件破解、软件篡改等。这些都是常见的侵权方式。
产品克隆
竞争对手可能通过购买样机,复制其PCB(俗称抄板),购买相应的元器件,并复制非易失性器件(如Flash)中的软件内容来克隆产品。如果这些步骤能让系统启动并执行所有预设功能,竞争对手便可轻松实现产品克隆。
常规芯片策略:在授权的主芯片中嵌入特定信息,系统启动时需与Flash存储器中的程序互相验证。对手若无法复制主芯片的特定信息。若竞争对手不能复制主芯片中的特定信息,那么在系统启动时,Flash程序无法过验证,系统将无法启动。
软件破解
当产品无法直接克隆,对手可以通过查询软件具体实现来了解系统的运行机制,寻找可能的漏洞,或者获取受知识产权保护的信息。
常规芯片策略:为了不让对手看到软件原始信息,可以对软件进行加密。加密后的软件存在 Flash 上,芯片上电时,进行解密执行。对手仅仅读取 Flash 上的内容无法了解软件原始信息。
软件篡改
如果整体或部分替换 Flash 上的软件,或让操作系统运行自己开发的恶意代码,有可能可以获取到系统的关键信息。
常规芯片策略:在运行程序之前,芯片先对程序进行认证,确保程序是未被篡改后才能运行程序。对手若是篡改了Flash上的程序,芯片将不执行程序。
2 Zynq-7000芯片常用的防御方法
针对这些常见侵权手段, 咱们的Zynq-7000上也有一些相对应的防御方法。
Zynq针对攻击的常用防御方法
2.1 针对产品克隆
通过嵌入片内密钥确保产品不被克隆。首先,将AES密钥烧录进Zynq的eFUSE或BBRAM。然后,存储在Flash中的加密软件需依赖eFUSE或BBRAM中的AES密钥进行解密,才能运行。
因此,即使对手抄板并复制Flash中的软件,由于无法复制Zynq-7000芯片片内的AES密钥,软件还是无法运行。
2.2 针对软件破解
通过AES加密保护软件。
在Zynq中,AES加密机制包含了AES加密和HMAC认证:
1. 加密时,先对待加密的软件组件使用HMAC密钥进行签名(HMAC Signature)。
2. HMAC Signature与软件组件共同形成HMAC Authenticated Image。
3. 用AES密钥对HMAC Authenticated Image进行加密,形成AES Encrypted Image。
4. 接着将加密软件烧录至Flash。
5. 将AES密钥烧入PL端eFUSE或BBRAM。
6. 芯片启动时,Zynq的内置AES 解密器利用PL端eFUSE或BBRAM中的AES密钥解密组件。
7. 接着通过HMAC验证解密后的软件组件的完整性。
8. 最后运行解密后的软件。
因此,即使对手能够读取Flash中的加密软件,也无法获取软件的原始内容。
2.3 针对软件篡改
通过RSA认证防止软件被篡改。
如上图, 分别对FSBL,BIT,和UBOOT这三个Partition进行RSA认证:
1. 分别使用主私钥PSK和次私钥SSK对次公钥SPK和Partiton进行签名,生成次公钥签名(SPK Signature)与Partition签名(Partition Signature)。
2. 将RSA主公钥PPK、次公钥SPK,次公钥签名(SPK Signature)与Partition签名(Partition Signature)等组合成为每个Partiton的RSA证书。
3. 并将RSA证书放在每个对应Partition的尾部(FSBL,BIT,和UBOOT)。
4. 接着计算RSA主公钥PPK的SHA-256哈希值作为RSA密钥
5. 将生成的RSA密钥烧录到PS端的eFUSE中。
6. Zynq芯片启动时,首先用SHA-256算法对主公钥PPK进行哈希计算,并与eFUSE中的值进行比对,验证主公钥PPK的完整性。
7. 然后,利用主公钥PPK解密次公钥签名(SPK Signature),与BOOTBIN内的次公钥哈希值比对,确认次公钥的SPK的完整性。
8. 最后,使用次公钥SPK解密Partiton签名(Partition Signature),与BOOTBIN内的Partiton哈希值进行比对,确保Partiton的完整性。
因此,无论对手尝试篡改主公钥PPK、次公钥SPK还是Partiton,都将导致程序无法正常启动。
注意:若使用QSPI存储认证所需的镜像文件,则该文件应放置在QSPI的32K偏移地址处。
2.4 小结
Zynq-7000应对攻击的主要策略为AES加密和RSA认证。对于最高安全需求,如对软件的来源有严格要求时,RSA校验应与AES加密结合使用,但在常规项目中,AES加密已经足够满足需求。
3 防御策略的部署
在实施加密和认证策略前,首先要知道涉及到了哪些硬件模块。
3.1 硬件模块
Zynq-7000在安全启动时用到的硬件
eFUSE SHA256(PPK):PS端只能编程一次的非易失性保险丝。可用于存储RSA使能bit和主公钥的哈希值(PPK Hash)用于RSA认证。
eFUSE Array:PL端只能编程一次的非易失性保险丝。可用于存放256-bit AES密钥和一些安全控制寄存器(如JTAG端口的使能)。
BBRAM:PL端 带电池的BRAM 用于存放PL AES key,作用与eFUSE Array相同。但是PL eFUSE,PL BBRAM只能二选一。
HMAC:Hash认证引擎。用于认证加密组件内部的文件签名。AES和HMAC是一起使用的,无法分开使用。
BootROM:用于存放只读的启动代码。
AES Decryptor:AES 解密器。使用PL端eFUSE Array中的AES密钥对文件进行解密。解密后的文件还需要进行HMAC认证。
NVM Controllers:非易失性存储控制器。
3.2 保护的软件
在实施防御策略前,我们需要知道要保护哪些软件组件。
3.2.1 需要防御的软件组件
最严格的防御case:
在通常的Zynq设计中,需要保护的软件逻辑组件包括FSBL、Bitstream、U-Boot、Linux、Applications。每个组件都可以选择是否加密和认证。上表展示了最严格的加密和认证的case。
安全启动模式的信任链
如上图,在安全启动流程中存在着一个信任链,即要确保某个步骤是安全可靠的,必须保证前面的所有步骤都是安全可靠的。例如,如果我要加密认证Linux applications,就需要加密认证之前的所有步骤。
已明确需要保护的软件组件后,接下来就是使用加密和认证策略对这些软件组件进行打包。
3.2.2 组件打包生成的镜像
安全启动镜像格式
上图展示了使用了加密和认证的镜像文件,可以看出FSBL和其他组件被 AES/ HMAC 加密认证, 中间隔着 RSA 认证。
4 安全启动流程
4.1 启动流程总览
BootROM支持安全启动和非安全启动两种模式。由于本文主要研究Zynq的防护,因此重点放在安全启动模式上。然而,这两种启动模式在大体上是相似的。
Zynq启动流程图:
上图显示,Zynq的启动,无论是安全还是非安全,均分为三个阶段。接下来的“4.2 安全启动流程”将深入解析这三个阶段。
4.2 安全启动流程
安全启动框图:
使用认证和加密的安全启动步骤:
Stage0:
Stage1:
Stage2:
5 防御策略实战
在理论上了解了Zynq-7000芯片的防御策略后,接下来将实际应用这些策略。具体步骤包括生成密钥和软件(BOOT.bin)、烧录密钥、烧录软件(BOOT.bin)以及进行安全启动。
5.1 实战环境
软件:Vivado 2018.3
硬件:Zynq 7020平台、Win10 PC
5.2 实战应用
AES加密可以选择PL端eFUSE或BBRAM来实现。考虑到BBRAM加密需要电池供电,并且带电池的系统由于电磁兼容性问题在设计和维护上都较为困难,实际生产中更偏向于使用eFUSE。因此,本文展示的例子是软件使用AES加密,芯片启动时使用PL端eFUSE中的AES密钥解密。
本文AES加密的软件包括三部分:FSBL、bit流和裸机代码。
5.2.1 生成密钥和BOOT.bin
1. 创建生成system_wrapper.hdf
2. 将硬件平台导入SDK
3. SDK菜单栏File → New → Application Project
4. 新建FSBL应用工程及其bsp板级支持包
5. 选择Zynq FSBL模板
生成的FSBL工程:
6. 使能FSBL的debug和RSA认证功能
1、右击FSBL点击Properties
2、点击C/C++ Build > Settings > ARM gcc compiler > Symbols。在Defined symbols中添加DEBUG,FSBL_DEBUG_GENERAL,FSBL_DEBUG_INFO,和RSA_SUPPORT。最后点击OK重新编译FSBL
7. 打包FSBL、bit流和裸机代码,生成加密的BOOT.bin
1、在菜单栏Xilinx → Create Boot Image
2、选择BIF配置文件和BOOT.bin输出的位置
3、点击Security→Encryption → Use Encryption使用加密。
4、选择EFUSE加密方式。若已存在AES密钥文件(扩展名为.nky),则需将该密钥文件导入至“Key file”栏中。
5、若无AES密钥文件,仅需填写“Part name”栏,并将“Key file”栏留空。请确保“Part name”与器件名称一致。之后,在生成加密的BOOT.bin文件时,SDK会自动创建一个新的AES密钥文件。
6、在Boot image Partitions 下加入需要打包并加密的分区,并选择AES加密。
7、本文对FSBL、bit流、裸机代码三个分区都进行了加密。
8. 点击 Create Image生成密钥和加密的镜像文件。
BOOT.bin为加密后的镜像文件,.nky为密钥文件
.nky的密钥:Device为器件的Part name,Key 0为AES私钥,Key StartCBC为初始向量StartCBC,Key HMAC为HMAC私钥。
5.2.2烧录密钥
• 使用Vivado GUI界面烧录(调试版)
1、JTAG模式下连接芯片
2、选择下载eFUSE
3、选择5.2.1中生成的密钥文件
4、eFUSE中的控制寄存器(根据自己的需求选择寄存器功能)
-
- R_EN_B_Key:使AES密钥不可读。
- R_EN_B_User:使自定义的user code不可读。
- eFUSE_Secure_Boot:只能安全启动,并且只能使用eFUSE中的密钥(JTAG关闭)。
- BBRAM_Key_Disable:可以非安全启动,在安全启动的模式下只能使用eFUSE中的密钥。
5、烧录完成Console中打印成功字样
• 使用Secure Key Driver程序烧录eFUSE(生产方案)
原理讲解:SDK的xilskey库中自带一个eFUSE烧录的example程序,其中封装了一个JTAG库,该库包含了烧录eFUSE所需的JTAG协议(这部分协议未公开)。因此,我们可以使用该example程序通过MIO控制JTAG引脚来进行eFUSE的烧录。下面将介绍如何使用SDK自带的example程序实现eFUSE烧录。
1、硬件连接要求
引出4个MIO管脚连接到JTAG管脚。例如:
注意:不要使用特殊的MIO[2-8],因为这些引脚在上电初期用于特定功能的复用
2、在5.2.1节中创建的FSBL项目的BSP(板级支持包)中添加xilskey库。
3、导入eFUSE烧录的模板工程
4、修改工程中的xilskey_input.h头文件
根据自己的需求更改XSK_EFUSEPS_DRIVER和XSK_EFUSEPL_DRIVER,如果不需要烧录PS端的eFUSE可以将XSK_EFUSEPS_DRIVER注释掉。
当MIO51、MIO49、MIO50、MIO46连接到JTAG引脚上时,修改代码如下
注:如果需要大批量烧录eFUSE,可以将烧录程序存放在SD卡中。这样,只需启动一次SD卡,就可以完成eFUSE的烧录。
9、利用SDK内的Bootgen工具,将xilkey_efuse_example项目打包成BOOT.bin文件,以便进行密钥烧录
10、将密钥烧录文件放入非易事性器件中(如SD卡)。
11、Zynq 上电后,从非易失性器件中启动密钥烧录文件,烧录PL端的eFUSE。
12、如果烧录成功,可通过串口打印信息看到已烧录的密钥。
5.2.3烧录软件
由于TH7011没有SD卡,暂时使用SDK中的工具将加密后的镜像文件放入QSPI中
5.2.4安全启动
给芯片上电并从QSPI中安全启动,通过串口可见打印信息。若加载的软件组件显示“Encrypted”字样,则表示该组件已经加密。
通过安全启动启动的软件不能使用软件系统复位功能。若需重置系统,必须通过芯片的PS_POR_B引脚进行复位。
注意:加密的BOOT.bin无法在未烧录密钥的Zynq芯片上启动。
Reference
1. ug585-Zynq-7000-TRM
2. xapp1175_zynq_secure_boot
3. ug821-zynq-7000-swdev
4. https://blog.csdn.net/weixin_40374201/article/details/109699069
5. https://mp.weixin.qq.com/s/vBUjcWHsqsaFCdlJkQN8pw
6. https://xilinx.eetrend.com/d6-xilinx/article/2015-07/8834.html
7. https://support.xilinx.com/s/article/959688?language=zh_CN
8. https://xilinx.eetrend.com/d6-xilinx/article/2015-07/8834.html
文章评论