[ZYNQ] Encrypt external files based on file system using PUF key

如果使用Zynq® UltraScale+™设备,大部分数据是存储在设备的外面的(NVM),如果想增强数据的保密性,则需要启动Secure Storage来保护数据。保护数据的算法使用ZYNQ内置的GCM-AES硬件引擎,那么同样,对于GCM-AES来说确保Key的可信是最重要和最根本的事情。eFUSE/OTP保存着Secure Boot和Secure Storage使用的加密的Key,而且内置的PUF(physically unclonable function)对Key的保密性进行了增强。Key的写入eFUSE/OTP和配置PUF的过程叫做Provisioning,也只有在Provisioning之后,Secure Storage和Secure Boot才能使用RSA和GCM-AES保密与认证功能。

本文参考

  • (AN) Secure Storage Application Note [^1]

  • (Provisioning) - Programming BBRAM and eFUSEs Application Note [^2]

  • (TRM) Zynq UltraScale+ Device Technical Reference Manual (UG1085) - Security [^3]

1. Secure Storage High-Level Design

1.1 一般性的安全存储业务模式(非ZYNQ)

本节借助文献[^4]的根文件系统保护和应用程序数据保护来阐述以下对于Secure Storage的业务需求。

在台式机或手机上,用于加密文件系统的密钥来自交互式输入的用户密码。物联网和嵌入式设备通常没有这样丰富的操作流程。因此,需要在设备上存储和保护密钥。以下是一些保护机制:

  • 使用 SoC 机制加密密钥,ARM的使用方法

  • 将密钥存储在提供安全存储的外部加密或安全芯片(例如:ATECC508A)中

  • 使用外部可信平台模块 (TPM) 芯片

  • 远程证明

我们只来阐述第一种使用 SoC 机制加密密钥,ARM的使用方法。很多外部安全芯片如TPM容易受到I2C总线攻击。如果可能的话最好利用主处理器的安全存储功能。安全存储的最核心的业务逻辑就是:如何保护好密钥

我们来看一下加密过程:

  • 使用加密的方法保护文件系统;

  • 需要加密上述加密的密钥;

在NXP I.MX上面,每个设备都有一个不同的主密钥(通过PUF,PUF是根据每个设备的物理工艺不同,可以实现每个设备的黑密钥差异的硬件设备),该密钥被SoC内部的加解密引擎访问。因此,就可以编写安全应用程序,例如Linux内核安全驱动程序或者HSM系统,读取该唯一密钥,在HSM程序内部对密钥进行加密,输出一个key blob用于解密方解密。

Note,CAAM driver:https://mcuxpresso.nxp.com/api_doc/dev/721/group__caam__driver.html

如上图所示:

  • 先对文件系统进行加密,使用的密钥就是文件加密的密钥key0;

  • 再对key0进行加密(调用HSM或者Linux内核安全程序或者自己编写安全服务程序,需要保证解密方也能被调用)

  • 解密过程就是先call安全系统HSM或者Linux内核安全程序或者安全应用解密密钥,拿到密钥之后解密文件系统。

这个就是一般的文件系统的加密模型。

1.2 ZYNQ的Secure Storage设计

在上述的加密模型中,需要引入HSM或者Linux内核安全服务程序用来对文件系统加密的密钥进行加解密。在ZYNQ中可以使用PUF硬件来满足加密的需求。PUF硬件根据物理工艺不同,可以对写入eFUSE的密钥进行加扰和解扰(也算是一种加密手段),因此使实际存储在eFUSE上的每个设备的black key都是不一样的。

我们可以对一批设备假定1万台,管理员生成一个红密钥作为文件系统加密的密钥,管理员需要为每台设备Provisioning这个红密钥到eFUSE上,并启动PUF功能。这一万台设备的实际存储的黑密钥都是不一样的。这就能够抵御侧信道攻击,即便是有人用功率分析,分析出eFUSE的密钥,拿到的也是黑密钥,没有任何的实际用处。

PUF可以理解为一个函数,这个函数输入红密钥、IV、ID等信息,输出一个AES-GCM加密的key blob结果,包含了tag、密文等。当我们要使用密钥解密文件系统的时候,则需要先把key blob输入进去,此时,ZYNQ读取到key blob则对输入的tag和密文解密,解密之后就可以拿到真实的红密钥,也会对tag进行验证,tag验证通过,红密钥才可信,解密者拿红密钥对文件系统进行解密。ZYNQ只是对密钥加密和解密做了封装,而文件系统的加密解密需要自己的应用程序来做

1.2.1 加密解密High-Level角度过程

Alice的加密

我们来看看Alice加密过程,Alice产生一个Red Key,用于真实文件系统加密,Alice把Red Key注入FPGA中,得到了密文的Key Blob。与此同时,Alice使用Red Key对文件加密,得到加密了的文件系统。

Bob的解密

FPGA内部提供了AES-256-GCM加速引擎来完成加密及认证的AEAD操作。Bob拿到Key Blob之后喂给FPGA,FPGA会输出Red Key和一个GCM的AUTH结果(tag),如果AUTH结果(tag对比)通过,那么Bob可以使用红密钥对加密的文件进行解密,最后拿到解密后的文件。

FPGA在这里充当的角色是对Red Key进行加解密验证。

1.2.2 FPGA SoC内部过程

如图所示,为Alice加密和Bob解密在External Memory以及FPGA SoC内部的加解密全过程:

在FPGA SoC内部,主要是利用PUF的物理特性,产生一个PUF Key,用做内部数据加密的密钥。FPGA内部依旧使用AES-GCM-256来完成加密操作。Alice和Bob可以在External Memory协商数据加密的方式。

在FPGA内部,生成的黑色密钥是被写入到eFUSE中的,正因为每一个PUF的物理工艺不同导致的即便是数据一致,也会让每个设备驻留在eFUSE内部的数据不一致。这就达到了防止DPA的目的。

加密过程

如图,注,这里的New Data指的就是Alice的Red Key

  1. Alice把明文Red Key喂给FPGA;

  2. FPGA产生一个PUF使用的Key(PUF物理工艺差异产生的数,不同芯片不一致,同一个芯片就是一致的),用于把Red Key加密成为一个Black Key,并写入eFUSE;

  3. FPGA输出Black Key和TAG值,到外部内存;

  4. FPGA读回Black Key和TAG值,组成Key Blob;

  5. FPGA对Black Key进行解密,解密得到一个TAG1的值;

  6. FPGA对比TAG1和TAG是否一致,以此检验是否加密成功;若不一致,进入“惩罚”流程,比如烧写FUSE的User Data,告知解密失败过。

1.2.3 解密过程

解密的过程:

  1. Bob把Key Blob输入到FPGA内部;

  2. FPGA读取到Key Blob分离出black key和TAG;

  3. FPGA重新让PUF产生一个Key(PUF物理工艺差异产生的数,同一个设备,这个值必然一致);

  4. FPGA使用PUF产生的Key解密black key成为red key,并输出TAG1;

  5. FPGA校验TAG1和Key Blob输入的TAG是否一致,若一致则解密成功并输出Red Key。

1.2.2 FPGA的安全角度考量

在ZYNQ内部,有很多安全关键因素在设计中被考虑到,我们应该熟悉其背后的设计逻辑,明白他们的设计意图。一种是对于防重放攻击的抵御,一种是防DPA,除此之外还有对black KEY 考量FIPS legal KEK的因素。(PUF key的来源是因为每个设备工艺不一致生成的一串数据,这串数据是不符合标准的。生成key的需要真随机数或者DRBG才能达到生成key的质量。如果想要black key达到质量,我们则需要让加密前的数据达到质量,这样加密后的数据就达到了key的质量要求。)

防重放攻击

防重放攻击的设计体现在,Alice对于Red Key的输入不光是有 Red Key和IV这些成分,除此之外还有ID放入到OTP的256bits长度的User Data里面。Alice产生Key之后,可以增加ID,在解密的时候,除了要验证解密的信息的GCM的TAG之外,还要对比解析出来的ID信息,和OTP/eFUSE上的ID进行对比。这样很可能就可以有效的抵御重放攻击。

id在bootgen的时候通过以下方法指定:

功率分析攻击(DPA)

PUF Key是直接加载到SoC内部的加密引擎中的。为了防止eFUSE中的Key被分析出来,ZYNQ给了两个建议:

  • 尽量让User Data短。PUF Key在SoC中不是对所有的数据加密,而是加密第一部分,因此存在没有加密的部分。如果User Data过长,就难保后面的数据的保密性。入侵者Mallory很可能使用DPA功率分析分析出后面User Data的数据;

  • 如果User Data不得不做的很长。ZYNQ推荐使用Rolling Key/OP Key的方式,进行加密;

Operational Key (OP Key)

实际上在boot中也不希望使用私密的key频繁加密,以下是提供了OP Key方法来帮忙减少使用私密的key:

bootgen在生成image的时候,会把op key放到image header里面,还包含了IV这类的信息。当需要进行解密的时候,使用私密的key对第一个块进行解密,从解密的信息中读取OP key,然后利用该key解下一个块,以此类推。这样私密的Key只使用了一次。

Note, DPA功率分析,可以通过频谱分析出eFUSE上的数据

Keys Rolling

以下为Key Rolling的过程:

FIPS Legay的key审查

使用SoC PUF产生的加密数据,也就是Block Key,如果作为Key的话,处于密码学安全边界之外,换句话说,此密钥不符合FIPS-legal KEK标准。因此我们需要在产生Red Key阶段就产生一个符合FIPS标准的Key,这样加密出来的Key就会处于密码学安全边界内。

2. Secure Storage Low-Level Design

2.1 eFUSE/OTP Provisioning

eFUSE array包含一个256的块,在这个块里面提供GCM-AES-256的key给加解密引擎。eFUSE的key可以存储为明文形式(red key),混淆模式(gray key),或者是加密模式(black key)。

eFUSE的写入过程叫做Provisioning。通过PJTAG(on MIO)使RPU或者APU处理器写寄存器的方式完成Provisioning。 Ref, Programming BBRAM and eFUSEs Application Note (XAPP1319).

在一些老的ZYNQ设计中是支持读回操作来验证写入的eFUSE数据是否正确。在一些eFUSE的SoC设计中,有驱动接口是支持读出eFUSE上面值的。以前我们在做Provisioning工具的时候,都是先利用写接口写入eFUSE数据,然后再通过读接口读回数据,对比写入和读出的数据来判断是否真的写成功eFUSE。但对于现阶段的ZYNQ来说具备很高的风险性,所以这个途径已经被关闭读回了。取而代之的是,写入eFUSE之后同时会返回CRC32,可以通过对比返回的CRC来确定值是否正确。

从安全角度来看,无法确定“一次性”的功能给eFUSE带来多少的增益。但是要注意,确保电压稳定,否则可能导致eFUSE写入失败。在烧录eFUSE的时候,一定要确保电压、温度这些条件稳定。否则可能使eFUSE烧写发生错误。写eFUSE的时候不要用SPA对密钥进行分析,SPA是通过接入不同电压,静态分析eFUSE的功率变化。所以在烧录eFUSE时候为了保持稳定电压,xilinx建议不要这个时候做SPA分析。

最后,请注意通过APB总线,可以加载Key到 key update register 中。这个设计主要是为了boot阶段使用了rolling key,对不同块加密的时候要频繁的换key。就是通过这个寄存器实现。

HRoTS

ZYNQ的HRoTS基于RSA-4096认证,而且需要基于两类的public key:

Primay的2个公钥,一个需要存储在外部的内存中,一个需要把其hash值存入eFUSE;因此,Primay的pk hash是一个根凭证。

最小需要做Provisioning的信息如上。

2.2 eFUSE layout

在FPGA系统中,逻辑和处理单元是分开的两部分:

  • PS: 处理系统 (Processing System) :就是与FPGA无关的ARM的SoC的部分。

  • PL: 可编程逻辑 (Progarmmable Logic): 就是FPGA部分。

因此,存在两类eFUSE,一个是256-PS的eFUSEs,还有是128-PL的eFUSEs。 PL的eFUSEs顾名思义,是给可编程逻辑 (Progarmmable Logic)使用的,我们用不到。我们更关心处理系统 (Processing System) 的侧的eFUSE,也就是存储密钥之类的eFUSE。

参考:https://docs.xilinx.com/r/dqE2tE0k~iMhpEDoQwXIKg/2Ubsx6RiXaJnAO2rAuCVYA?section=XREF_67790_Zynq_UltraScale

Size

Name

Description

MACRO define

32

USER_{0:7}

256 user defined eFUSEs:Note: In the input.hfile (see text), write data in the XSK_EFUSEPS_USER{0:7}_FUSES macro and execute the write by setting the XSK_EFUSEPS_USER{0:7}_FUSE macro = True.

USER{0:7}_FUSE

1

USER_WRLK

8 user-defined eFUSE locks.USER_WRLK columns:0: Locks USER_0,1: Locks USER_1,...7: Locks USER_7,Note: Each eFUSE permanently locks the entire corresponding user-defined USER_{0:7} eFUSE row so it cannot be changed.

USER_WRLK_{0:7}

1

LBIST_EN

Enables logic BIST to run during boot.

LBIST_EN

3

LPD_SC

Enables zeroization of registers in low power domain (LBD) during boot.Note: Any of the eFUSE programmed will perform zeroization. Xilinx recommends programming all of them.

LPD_SC_EN

3

FPD_SC

Enables zeroization of registers in full power domain (FBD) during boot.Note: MGTs must be powered to perform zeroization of the FPD.Note: Any of the eFUSE programmed will perform zeroization. Xilinx recommends programming all of them.

FPD_SC_EN

3

PBR_BOOT_ERROR

When programmed, boot is halted on any PMU error.

PBR_BOOT_ERR

32

CHASH

PUF helper data(参考:2.2.1 PUF Helper Data)

N/A - handled by PUF registration software directly.

24

AUX

PUF helper data: ECC vector

N/A - handled by PUF registration software directly.

1

SYN_INVLD

Invalidates PUF helper data stored in eFUSEs.

XSK_PUF_SYN_INVALID

1

SYN_LOCK

Locks PUF helper data from future programming.

XSK_PUF_SYN_WRLK

1

REG_DIS

Disables PUF registration.

XSK_PUF_REGISTER_DISABLE

1

AES_RD

Disables the AES key CRC integrity check for eFUSE key storage.

AES_RD_LOCK

1

AES_WR

Locks AES key from future programming.

AES_WR_LOCK

1

ENC_ONLY^(1)^^(2)^

When programmed, all partitions are required to be encrypted. Xilinx recommends using this only if security is required and the hardware root of trust (RSA_EN) is not used.

ENC_ONLY

1

BBRAM_DIS

Disables the use of the AES key stored in BBRAM.

BBRAM_DISABLE

1

ERR_DIS

Prohibits error messages from being read via JTAG (ERROR_STATUS register).Note: The error is still readable from inside the device.

ERR_DISABLE

1

JTAG_DIS^(1)^

Disables JTAG. IDCODE and BYPASS are the only allowed commands.

JTAG_DISABLE

1

DFT_DIS^(1)^

Disables design for test (DFT) boot mode.

DFT_DISABLE

3

PROG_GATE

When programmed, these fuses prohibit the PROG_GATE feature from being engaged. If any of these are programmed, the PL is always reset when the PS is reset.Note: Only one eFUSE needs to be programed to prohibit the PROG_GATE feature from being engaged. Xilinx recommends programming all three.

PROG_GATE_DISABLE

1

SEC_LK

When programmed, the device does not enable BSCAN capability while in secure lockdown.

SECURE_LOCK

15

When any one of the eFUSEs is programmed, every boot must be authenticated using RSA. Xilinx recommends programming all 15 eFUSEs.

RSA_ENABLE

1

PPK0_WR

Primary public key write lock. When programmed, this prohibits future programming of PPK0.

PPK0_WR_LOCK

2

PPK0_INVLD

When either of the eFUSEs are programmed, PPK0 is revocated. Xilinx recommends programming both eFUSEs when revocating PPK0.

PPK0_INVLD

1

PPK1 WR

Primary public key write lock. When programmed this prohibits future programming of PPK1.

PPK1_WR_LOCK

2

PPK1_INVLD

When either of the eFUSEs are programmed, PPK1 is revocated. Xilinx recommends programming both eFUSEs when revocating PPK1.

PPK1_INVLD

32

SPK_ID

Secondary public key ID.Note: Write the SPK ID bits into the XSK_EFUSEPS_SPK_ID eFUSE array and set XSK_EFUSEPS_SPKID = True.

SPK_ID

256

AES

User AES keyNote: Write data in the XSK_EFUSEPS_AES_KEY macro and execute the write by setting the XSK_EFUSEPS_WRITE_AES_KEYmacro = True.

AES_KEY

384

PPK0

User primary public key0 HASHNote: Write data in the XSK_EFUSEPS_PPK0_HASH macro. To program 256 bits, use the LSBs and set XSK_EFUSEPS_PPK0_IS_SHA3 = False. To program 384 bits, set XSK_EFUSEPS_PPK0_IS_SHA3 = True. Execute the write by setting the XSK_EFUSEPS_WRITE_PPK0_HASH macro = True.

PPK0_HASH

384

PPK1

User primary public key1 HASHNote: Write data in the XSK_EFUSEPS_PPK1_HASH macro. To program 256 bits, use the LSBs and set XSK_EFUSEPS_PPK1_IS_SHA3 = False. To program 384 bits, set XSK_EFUSEPS_PPK1_IS_SHA3 = True. Execute the write by setting the XSK_EFUSEPS_WRITE_PPK1_HASH macro = True.

PPK1_HASH

N/A

PUF_HD

Syndrome of PUF HD. These eFUSEs are programmed using Xilinx provided software, Xilskey

N/A - handled by PUF registration software directly.

这个表,很关键,eFUSE会影响到ZYNQ处理器的工作状态、安全信息,配置错了之后,Xilinx已经声明不接受要求eFUSE复原的返厂件。在操作这些位的时候,尤其是Provisioning的时候,会影响其他非安全的测试。

IMPORTANT: THESE INSTRUCTIONS MODIFY THE EFUSES ON THE ZCU102 DEVELOPMENT BOARD AND MAY LIMIT FUTURE USE OF THE DEVELOPMENT BOARD FOR NON-SECURE TESTING AND DEBUGGING!

2.2 PUF

2.2.1 PUF Helper Data

PUF使用大约4Kb的辅助数据来帮助PUF在正确的寿命、规定的工作温度和电压范围内重新创建原始KEK值。辅助数据由Syndrome值、Aux值和Chash值组成(请参见表:PUF辅助数据)。助手数据可以存储在eFUSE或引导映像中。

PUF Helper Data Field

Size (Bits)

Description

Syndrome

4060

鉴于环形振荡器在温度、电压和时间上的微小变化,这些比特有助于PUF恢复正确的PUF特征

Aux

24

这是一个汉明码,允许PUF对PUF签名执行某种程度的纠错。

Chash

32

•如果CHASH未被编写,则只要使用(bh_auth或rsa_en),就可以使用boot-header black key。

•如果对CHASH进行了编写,则只要(使用bh_auth或rsa_en)且eFUSE的Syndrome数据未失效,就可以使用eFUSE的black key。

•如果对CHASH进行了编写,则只要使用(bh_auth或rsa_en)且efuse的Syndrome数据无效,就可以使用boot-header black key。

helper data 简单的说是帮助生成PUF key时候所需要的材料(Syndrome,Aux)。如图所示,生成PUF key及调用AES引擎的过程。PUF原数据复原的算法,可以参考:[Helper Data Algorithms for PUF-Based Key Generation: Overview and Analysis](https://lirias.kuleuven.be/retrieve/334181) (有点专业和复杂。。) 特征值(Syndrome)和Aux(汉明距)是算法需要的输入。汉明距是实现比特纠错码的一种手段,可以参考,文献:[ https://blog.csdn.net/weixin_45783996/article/details/116203267]。

生成puf helper data的过程参考:

2.2.2 PUF operations

只有CSU可以访问PUF,所以PUF的初始化包括黑密钥的产生,必然是在CSU阶段完成。PUF暴露出以下接口供CSU操作:

Command

Description

Registration

产生一个新的KEK并且关联helper data

Re-registration

产生一个新的KEK并且关联新的helper data

Reuse

使用已经存在的KEK进行加解密,并且关联helper data

当一个设备上电的时候,CSU bootROM会检测已经校验过的boot header,确认以下信息:

  • 是否使用了PUF;

  • 加密的密钥存储在哪里?(eFUSE 或者 boot image)

  • helper data存储在哪里?(eFUSE 或者 boot image)

接着CSU初始化PUF,并且加载helper data,最后产生KEK,这个过程叫做regeneration。一旦KEK产生成功,CSU bootROM使用它来解密剩下boot image需要的key。

2.2.3 PUF Control eFUSEs

eFUSE也给PUF留了一些功能接口:

Command

Description

REG_DIS

屏蔽PUF的注册

SYN_INVALID

使存在eFUSE上的helper data无效

SYN_LOCK

屏蔽修改eFUSE上的helper data的功能

Xilinx也做了PUF的强度分析,包含加密,安全强度KEK,过温过压的测试的数据报告,需要联系FAE或者销3. Example售才可以拿到这个报告。

3.1 Provisioning

Provisioning是所有安全机制的基础。其目的是把根凭证写入eFUSE或者其他存储密钥的敏感介质。包含RSA的根密钥,也包含GCM的Key。

在ZYNQ中我们需要Provisioning的内容:

  • PPK HASH (主引导Primary Public Key Hash)

  • GCM-AES Key (用于image解密)

  • PSK ID (写入key的id信息,作为PUF解密时候比对,参考'防重放攻击'一节)

在调试阶段为了不伤害eFUSE。对于PPK HASH,zynq提供了bh_boot模式,即可以绕过eFUSE的PPK HASH检测,直接使用AC中的hash值。

同样,为了不伤害eFUSE。对于GCM-AES key,我们可以不使用eFUSE,而把Key烧录到BBRAM中。

在调试阶段,推荐配置为

  • ppk hash,对于验证,使用bh_boot(不需要包含到Provisioning过程中)

  • gcm aes key,对于验证,使用bbram (需要包含到Provisioning过程中)

  • id

  • ID,对于验证,在bootgen阶段选择spk_id = 0,不需要包含到Provisioning中。

在产品阶段,必须配置为: ppk hash 和 gcm aes key都需要在eFUSE中。

我们可以把完整的Provisioning过程总结为:

  • 手动产生两对RSA密钥,产生gcm-aes-key;

  • 使能PUF eFUSE的配置;

  • 使用写入寄存器的方法写入eFUSE。

可以通过JTAG烧录eFUSE(这种方法数据操作互动型,具备一定的危险性,eFUSE烧录不可撤销),因此建议使用配置寄存器的方法烧录eFUSE

3.1.1 Gen Key

密钥生成主要是需要以下材料:

  • AES Key Generation

    • 输出nky文件(包含key和iv)

  • RSA Asymmetric Key Generation

    • 输出1:psk0.pem

    • 输出2:ssk0.pem

  • Generate SHA3 of Public RSA Asymmetric Key

    • 输出是:sha3.txt

3.1.2 PUF eFUSE config

PUF eFUSE的配置需要使用Vitis建立AP的工程,使用ZYNQ上面的AP来完成PUF的配置。非常重要的提示:这一步会修改eFUSE上面的内容

需要配置的项目是:

  • XSK_PUF_INFO_ON_UART

  • XSK_PUF_PROGRAM_EFUSE

  • XSK_PUF_PROGRAM_SECUREBITS

  • XSK_PUF_SYN_WRLK

  • XSK_PUF_AES_KEY

  • XSK_PUF_IV

XSK_PUF_AES_KEY是用户指定的,而且这个XSK_PUF_IV和AES Key Generation中的IV不相关。这个IV是用于PUF KEK的red key加密。

3.1.3 RSA eFUSE config

这一步是配置RSA相关的信息到eFUSE上面,非常重要的提示:这一步会修改eFUSE上面的内容

  • XSK_EFUSEPS_RSA_ENABLE

  • XSK_EFUSEPS_PPK0_WR_LOCK

  • XSK_EFUSEPS_WRITE_PPK0_HASH

  • XSK_EFUSEPS_PPK0_HASH

3.1.4 RSA Key Revocation Support

RSA密钥提供了撤销一个分区的secondary密钥(SPK)的能力,而无需撤销所有分区的密钥。这是通过使用新的BIF参数spk_select利用USER_FUSE0USER_FUSE7 位域实现(如果这些位域没有用于表示其他信息,只用于表示密钥的id,最多可以撤销256个SPK,如图所示)。

下图表示ZYNQ使用SPK_ID进行SPK revocation的过程。

以下是使用辅助密钥创建经过身份验证的映像的步骤:

  • 使用bootgen生成RSA密钥对。

  • 我们在步骤1中生成了一个辅助密钥(SSK)。如果需要更多的SSK,请重复步骤1以创建SSK密钥。

  • 使用bootgen和下面的bif文件模板生成经过验证的引导映像。下面的模板假设bootloader和u-boot使用[sskfile]标记提供的密钥进行了验证,并且该密钥根据eFUSE中存储的SPK_ID进行了验证;PMU FW和ATF images使用sskfile提供的密钥进行验证,并根据存储在USER_eFUSE中的SPK_ID bitmap 验证该密钥。(确保在生成映像时使用命令行参数–efuseppkbits<path_to_sha_txt_file>命令bootgen生成PPK哈希。)

  • 使能RSA认证通过设定 “RSA_EN” 在eFUSE上. 参考 Programming BBRAM and eFUSEs Application Note (XAPP1319)

  • 写入在第三步创建的PPK的SHA-3 hash 到eFUSE的PPK0 hash位域。

确保在生成image时使用命令行参数–efuseppkbits<path_to_sha_txt_file>命令bootgen生成PPK hash。

模板示例: image header和FSBL使用不同的SSK进行身份验证(分别为ssk1.pem和ssk2.pem),用以下bif文件:

the_ROM_image: {
[auth_params]ppk_select = 0
[pskfile]psk.pem
[sskfile]ssk1.pem
[bootloader, authentication = rsa, spk_select = spk-efuse, spk_id = x00000001, sskfile = ssk2.pem]zynqmp_fsbl.elf
[destination_cpu =a53-0, authentication = rsa, spk_select = user-efuse,spk_id = 0x1, sskfile = ssk3.pem]Application1.elf
[destination_cpu =a53-0, authentication = rsa, spk_select = spk-efuse, spk_id = 0x00000001, sskfile = ssk4.pem]Application2.elf
}

相同的SSK将作用于image header和FSBL(ssk2.pem):

the_ROM_image: {
[auth_params]ppk_select = 0 [pskfile]psk.pem
[bootloader, authentication = rsa, spk_select = spk-efuse, spk_id = 0x00000001, sskfile = ssk2.pem]zynqmp_fsbl.elf
[destination_cpu =a53-0, authentication = rsa, spk_select = user-efuse, spk_id = 1, sskfile = ssk3.pem]Application1.elf
[destination_cpu =a53-0, authentication = rsa, spk_select = spk-efuse, spk_id = 0x00000001, sskfile = ssk4.pem]Application2.elf
}

注意:

  • spk_select = spk-efuse 表示 指定的分区将会使用spk_ideFUSE位域。

  • spk_select = user-efuse 指示 指定的分区将会使用user eFUSE位域,而CSU ROM总是使用spk_ideFUSE位域。

3.2 PUF Enc/Dec demo

完成上面PUF的注册,我们假定eFUSE和PUF的配置已经OK了,现在我们需要编写APU(Application Processor Unit)的固件(bare-mental程序),来使用PUF的加密和解密功能。

该固件是在xilinx的vitis ide上完成的,vitis已经集成了ZYNQ所用的bsp驱动包,并提供了相应的操作key、加密解密、访问寄存器、控制外设等接口。

打开vitis ide创建工程:

选择bsp包:

选择processor为APU (Application Processor Unit):CortexA53_0:

导入bare-mental的源码(下面就是源码核心):

源码进行编译:

最后生成BOOT.BIN文件,将其复制到SD卡的boot分区。启动即可运行。

3.2.1 加密

对于一个PUF加密过程的程序:

void puf_encrypt(u8 *Iv, u8 *Dst, u8 *Src, u32 Size) {

	XCsuDma_Config *Config;
	XCsuDma_Configure ConfigurValues = {0};

    /* Configure PUF configuration 0 and configure the shutter. */
	XilSKey_WriteReg(XSK_ZYNQMP_CSU_BASEADDR, XSK_ZYNQMP_CSU_PUF_CFG0,
                    XSK_ZYNQMP_CSU_PUF_CFG0_DEFAULT);
	XilSKey_WriteReg(XSK_ZYNQMP_CSU_BASEADDR, XSK_ZYNQMP_CSU_PUF_SHUT,
                    XSK_ZYNQMP_CSU_PUF_SHUT_DEFAULT);


	// Spin up the PUF and connect the key to the AES engine
	XilSKey_WriteReg(XSK_ZYNQMP_CSU_BASEADDR, XSK_ZYNQMP_CSU_PUF_CMD,
                    XSK_ZYNQMP_PUF_REGENERATION);

    /* Wait for the PUF regeneration to complete. */
	usleep(PUF_REGEN_TIME_US);

	/* Initialize & configure the DMA */
	Config = XCsuDma_LookupConfig(XSK_CSUDMA_DEVICE_ID);
	XCsuDma_CfgInitialize(&CsuDma, Config, Config->BaseAddress);

	/* Initialize AES engine */
	XSecure_AesInitialize(&AesInstance, &CsuDma, XSK_PUF_DEVICE_KEY, (u32 *) Iv, NULL);

	/* Set the data endianess for IV */
	XCsuDma_GetConfig(&CsuDma, XCSUDMA_SRC_CHANNEL,
				&ConfigurValues);
	ConfigurValues.EndianType = 1U;
	XCsuDma_SetConfig(&CsuDma, XCSUDMA_SRC_CHANNEL,
					&ConfigurValues);

	/* Enable CSU DMA Dst channel for byte swapping.*/
	XCsuDma_GetConfig(&CsuDma, XCSUDMA_DST_CHANNEL,
			&ConfigurValues);
	ConfigurValues.EndianType = 1U;
	XCsuDma_SetConfig(&CsuDma, XCSUDMA_DST_CHANNEL,
			&ConfigurValues);

	/* Request to encrypt the AES key using PUF Key	 */
	XSecure_AesEncryptData(&AesInstance, (u8 *) Dst, (u8 *) Src, Size);

   /* Clear the PUF key. */
	XilSKey_WriteReg(XSK_ZYNQMP_CSU_BASEADDR, XSK_ZYNQMP_CSU_PUF_CMD,
                    XSK_ZYNQMP_PUF_RESET);
}

3.2.2 解密

Ref

最后更新于