S32K1xx CSEc 模块

一、 问题描述

为了安全启动,加密,随机数等功能,S32K1xx 需要使用 CSEc(Cryptographic Service Engine compressed)。

二、CSEc 介绍

2.1 特性

(1)遵循 GM-SHE+ 安全规范和 HIS-SHE 规范 1.1 rev 439。

(2)有 3~17 个使用者钥匙(取决于配置)

(3)AES-128 加解密、AES-128 CMAC 产生和验证

(4)ECB模式/CBC模式 加解密

(5)真/伪随机数产生(实际能获取的随机数是由伪随机算法产生)

(6)Miyaguchi-Preneel compression 功能

(6)安全启动模式:Sequential Boot Mode、Parallel Boot Mode、Strict Sequential(一旦设置不可改变)

2.2 通用介绍

CSec 主要功能在 FTFC Core 上实现,支持 HIS-SHE 规范 1.1。如图。
  
图中可以看到,如果 S32K1xx 要仿真 eeprom,需要使用 FlexRAM(DFlash) 作为一个备份区,FlexRAM 作为 EEERAM,这个是通过分区命令 PRGPART 实现的。如果要写入 仿真 eeprom,需要先写入 EEERAM,flash 系统在内部锁定接口并将数据写回备份区,每次开机的时候,也会从备份区检索并复制到 EEERAM。

在这里,要使能 CSEc 功能,必须将设备配置为仿真 eepeom,分区命令 PRGPART 就是用于启用 CSEc,在这个时候,可以选择密钥的个数,根据密钥个数不同,会占用 eeprom 不同的空间,这一部分空间是不可寻址的(相应的备份区也是不可寻址),所以密钥的安全的,称为安全 Flash。系统其他 master 都不能访问此安全 Flash,如图 1灰色部分。一旦配置了 FTFC 模块并夹杂器了用于安全操作的用户密钥,设备就已经准备好进行 HIS-SHE 和 GM-SHE+ 规范中描述的任何安全相关操作。

CSEc PRAM 接口用于为安全操作提供数据和命令头,这里的数据都是 128bit,如果数据少于 128bit,除了 CMAC 操作不需要填充(填充在内部处理,不需要外部填充),其余操作都需要填充数据块到 128bit。CSEc_PRAM 是 8*128bit 的RAM page,可以以字或字节形式访问。CSEc 操作的状态反应在 FSTAT 和 FCSESTAT 中,命令完成是还可以生成一个中断。如果要看 CSEc 命令执行过程中的任何错误,可以看 CSEc PRAM 的错误位位置。

注意:在芯片处于VLPR/HSRUN 模式时, CCOB 和 CSEc 命令不可用。仅有处于 RUN 模式是,这些命令曹科进行操作。

注意:一旦 CSEc 命令头被写入,CSEc将 FSTAT[CCIF] 置为0,命令就开始执行,完成命令通过 FSTAT[CCIF] 置为 1表示。如果开始执行 CCOB/CSEc 命令,此时 CCOB 接口、EEERAM 和 CSEc PRAM 被锁定,在命令完成前不准执行其他命令。也就是说,这些操作是互斥的,甚至在执行 CSEc 命令的时候也不能执行执行另外一个 CSEc 命令。

2.3 加密密钥

2.3.1 密钥种类

密钥名称

密钥 ID

存储类型

密钥大小(字节)

密钥计数大小(bit)

密钥属性(bit)

出厂默认状态

KBS

 

密钥IDs

写保护

Boot 保护

Debug 用途保护

密钥用途

通配符保护

仅验证

Secret_Key

×

0x0

ROM

16

-

-

-

-

-

NXP写入

UID

×

0x0

ROM

15

-

-

-

-

-

-

-

NXP写入

MASTER_E

CU_KEY

×

0x1

非易失性

16

28

 

 

BOOT_MAC

_KEY

×

0x2

非易失性

16

28

 

 

 

BOOT_MAC

×

0x3

非易失性

16

28

 

 

 

KEY_01~

KEY_10

1’b0

0x4~

0xD

非易失性

16

28

KEY_11~

KEY_17

1’b1

0x4~

0xA

非易失性

16

28

保留

1’b1

0xE

-

16

-

-

-

-

-

-

-

-

保留

1’b0

0xE

-

-

-

-

-

-

-

-

-

-

RAM_KEY

×

0xF

易失性

16

-

-

-

-

-

-

-

复位失效

注意:RAM_KEY 仅有 PLAIN_KEY 标志,且此标志仅对 RAM_KEY 实现。

注意:Secret_Key 和 UID 不在仿真 eeprom 分配的密钥空间内。

其中还有另外两个存在

Key_name

Address

Type

Size(字节)

PRNG_KEY

N/A

RAM

16

PRNG_STATE

N/A

RAM

16

(1)SECRET_KEY – 设备制造过程中编程的一个随机值,该值从未公开,并在内部用于生成派生密钥(derived key)。例如:伪随机数生成器密钥(PRNG_KEY)。不可寻址,不可改变。

(2)UID – 唯一识别号,写在安全 Flash 中。,不可寻址,不可改变。

(3)BOOT_MAC_KEY – 用于安全启动进程,验证软件的完整性

(4)BOOT_MAC – 用于安全启动进程,装载 MAC 值。

(5)KEY_01 ~ KEY_17 – 用户密钥,存在 EEERAM 空间中配置的密钥空间内。可以用分区指令配置 3~17 个用户密钥

(6)RAM_KEY – 可用于任何任意操作,不受 CSEc 控制,容易受到攻击。

(7)PRNG_KEY 和 PRNG_STATE – 不能被用户直接访问,而是由伪随机数在内部使用。

2.3.2 密钥ID

每个密钥都拥有的一个相关联的识别号。(KBS 不是 HIS-SHE 规范,这里是为了容纳更多的密钥)。

2.3.3 密钥计数值

每一个密钥都有一个计数器,用于跟踪更新。密钥更新的时候,计数器值必须增加,改计数器值 28bit。

2.3.4 密钥属性

每个密钥都有属性,MASTER_ECU_KEY、BOOT_MAC_KEY 和用户密钥都有相应的标志(flag)。这些标志包含在计算 M2 时。(表中密钥属性打√表示对该密钥可相应的更改该标志)

2.3.4.1 写保护标志(WRITE_PROT)

一旦设置,即使知道授权密钥,也不能更改密钥。该标志一旦设置写保护就不可逆,将阻止设备重置到出厂默认状态。

2.3.4.2 Boot 保护标志(BOOT_PROT)

一旦设置,如果在安全启动步骤中计算的 MAC 值与存储在安全 flash 的 BOOT_MAC 不匹配,则不能使用该密钥。

2.3.4.3 Debug 用途保护标志(DEBUG_PROT)

一旦设置,如果调试器现在(或曾经)连接到 MCU,则不能使用该密钥。

2.3.4.4 密钥用途标志(KEY_USAGE)

一旦设置了该标志,该密钥用于 CMAC 生成/验证。如果清除该标志,则密钥用于加密。

2.3.4.5 通配符保护标志(WILDCARD)

一旦设置,无法通过提供特殊的通配符UID(如 UID=0)来更新密钥。

2.3.4.6 仅验证标志(VERIFY_ONLY)

一旦设置(分区配置里面设置 SFE=0x01),那么该密钥仅仅能用于验证,不能产生 MAC。

2.3.5 密钥管理

密钥管理包括将密钥添加到安全 flash 以及使用新密钥更新现有密钥的过程。

2.3.5.1 密钥添加和更新

这个章节对 MASTER_ECU_KEY,BOOT_MAC_KEY,BOOT_MAC 和所有用户密钥适用。

添加密钥必须使用 HIS-SHE 规范中定义的协议。这确保机密性、完整性、真实性并防止重放攻击。为了添加密钥,必须先计算以下值:(以下,| 代表值的连接,不是 或)

派生两个密钥 K1 和 K2:

K1 = KDF(KEYAuthID ,KEY_UPDATE_ENC_C)

K2 = KDF(KEYAuthID ,KEY_UPDATE_MAC_C)

KDF:密钥派生函数,从一个密钥派生出一个密钥。此函数为:

KDF(K,constant)=AES-MP(K| constant)

AES-MP:Miyaguchi-Preneel compression 功能

KEYAuthID:授权密钥值,如果该密钥没写入,那么密钥初始值是 1。

KEY_UPDATE_ENC_C: HIS-SHE 指定的常值:0x01015348_45008000_00000000_000000B0

KEY_UPDATE_MAC_C: HIS-SHE 指定的常值:0x01025348_45008000_00000000_000000B0


M1 = UID | ID | AuthID   (128bit)

UID:当 WILDCARD =0 时,UID 可以设置为 0 参与计算,不必使用真实的 UID。120 bit

ID:要被更新的密钥 ID,这是一个 4bit 大小的值,不包含 KBS。    

AuthID:授权密钥 ID,可以是用户密钥或 MASTER_ECU_KEY 密钥的 ID。4bit 大小,不包含 KBS。

M2 = ENCCBC,K1,IV=0( CID’ | FID’ |’00...00’n|KEYID’)    (256bit)

在这里对于n,当 SFE=0x00,n=95;当 SFE=0x01,n=94;这里表示 n个 0

这里使用 AES-128 CBC 加密,密钥使用 K1,IV=0

CID’:新的计数值(28bit),开始于 0x0000001,密钥每更新一次计数值就加1

FID’:密钥属性

对于 SFE=0x00,有五个标志位:WRITE_PROT | BOOT_PROT | DEBUG_PROT | KEY_USAGE | WILD_CARD (5bit)

对于 SFE=0x01,有六个标志位:WRITE_PROT | BOOT_PROT | DEBUG_PROT | KEY_USAGE | WILD_CARD|BERIFY_ONLY (6bit)

KEYID’:新的密钥值 (128bit)

M3 = CMACK2(M1|M2)    (128bit)

密钥使用 K2,值为 M1 和 M2 的连接,生成 CMAC

有了以上三个值就可以开始使用 CSE_LOAD_KEY 命令更新密钥,此后 CSEc 会返回 M4 和 M5,用户可以使用这两个值与自己计算的M4 和 M5 对比。如果对比没错误,且 CSE_ECR 返回 NO_ERROR,那么 CMD_LOAD_KEY 命令就成功了。 

派生两个密钥 K3 和 K4

K3 = KDF(KEYID ,KEY_UPDATE_ENC_C)

K4 = KDF(KEYID ,KEY_UPDATE_MAC_C)

与 K1 和 K2 大致差不多,KEYID:被更新的密钥的值

M4 = UID | ID | AuthID | M4*    (256bit)

UID:当 WILDCARD =0 时,UID 可以设置为 0 参与计算,不必使用真实的 UID。120 bit

ID:被更新的密钥 ID,这是一个 4bit 大小的值,不包含 KBS。

AuthID:授权密钥 ID,可以是用户密钥或 MASTER_ECU_KEY 密钥的 ID。4bit 大小,不包含 KBS。

M4*:加密的计数值。M4*=ENCECB,K3(CID’(28bit) | “1”(1bit) | “00…00”(99bit))

这里使用 AES-128 ECB 加密,密钥使用 K3

M5 = CMACK4(M4)     (128bit)

密钥使用 K4,值为 M4,生成 CMAC

2.3.5.2 授权

从上文可知,密钥更新绕不过授权密钥,以下列出了每个密钥的授权密钥可以是那种:

要更新的密钥

当前可做为授权的密钥

MASTER_ECU_KEY

BOOT_MAC_KEY

BOOT_MAC

KEY_<N>

RAM_KEY

MASTER_ECU_KEY

 

 

 

 

BOOT_MAC_KEY

 

 

 

BOOT_MAC

 

 

 

KEY_<N>

 

 

 

RAM_KEY

 

 

 

 

2.3.5.3 擦除密钥

密钥不能单独擦除,要么密钥存在,要么所有密钥连同仿真 EEPROM 功能一起去掉(FCNFG[RAMRDY]变为1,FCNFG[EEERDY]变为 0),CSEc 通过 2 个命令:CMD_DBG_CHAL 和 CMD_DBG_AUTH 实现该功能。

CMD_DBG_CHAL:请求一个随机数 CHALLENGE(128bit)

CMD_DBG_AUTH:返回授权参数 AUTHORIZATION(128bit),计算方式如下:

K = KDF(KEYMASTER_ECU_KEY,DEBUG_KEY_C)

KEYMASTER_ECU_KEY:MASTER_ECU_KEY 的值

DEBUG_KEY_C:HIS-SHE 指定的常值0x01035348 45008000 00000000 000000B0

AUTHORIZATION = CMACK(CHALLENGE|UID)

注意:这两个命令之间必须连贯,即 CMD_DBG_CHAL 后需要跟着 CMD_DBG_AUTH,如果中间跟随了其他的 CSEc 指令,那么在执行 CMD_DBG_CHAL 必须重新在执行 CMD_DBG_AUTH。

注意:擦除密钥功能中,条件之一是不能有密钥置位写保护标志。

注意:若密钥存在,则不能启动擦除所有 flash 的指令,必须先擦除密钥之后,才能执行擦除所有 flash 指令。

注意:写完指令后复位,这样才会真正生效,擦除所有密钥。

2.4 CSEc PRNG 接口

下面是 CSEc PRAM接口,写入word0就会触发相应的指令执行。

2.4.1 CSEc 命令头

如下图,是 CSEc 命令头。

2.4.1.1 FuncID

8bit 大小,有效值从 0x00~0x16,具体看 CSEc 指令。

2.4.1.2 Func Format

指定数据如何传输到 CSEc 或者从 CSEc 中传输出来。这里给了两种:

0x00:复制方式,将所有数据和命令,即如果传输到 CSEc,内核或 DMA 会先复制信息,然后复制到 CSEc_PRAM 中。

0x01:指针方式,内核和 DMA 将提供指针信息给指令功能调用。

2.4.1.3 CallSeq

如果一个指令不能提供完整的数据的时候(比如使用 ECB 加密或解密,此时的数据超过 7*128bit),那么该信息指定是否是指令第一个调用(是第一个调用说明该指令与前面的指令无关)。

0x00:第一个调用

0x01:第2/n 个调用

注意:如果是第 2/n 个调用,将会忽略 Func Format、KeyID、MAC_LENGTH、MESSAGE_LENGTH、PAGE_LENGTH,这些仅仅在第一次调用获取。

2.4.1.4 KeyID

密钥 ID,指示目前指令使用的是哪一个密钥(包含 KBS,如果密钥中不含 KBS,需要往 KBS 位置 0)。

2.4.1.5 Error bits


每一个 bit 代表一种错误。如下错误码说明(按照错误码实现的优先级顺序->从最高到最低):

1.ERC_GENERAL_ERROR:FuncID 是无效的

2.ERC_SEQUENCE_ERROR:CallSeq 无效

3.ERC_ GENERAL_ERROR:Message 长度为 0

4.ERC_KEY_INVALID:密钥无效,如KeyID[7:5]不为0或者 KeyIDx是 0x0E 这些保留值等

5.ERC_KEY_NOT_AVAILABLE:例如:密钥设置Boot 保护标志,但安全启动不成功

6.ERC_KEY_EMPTY:密钥未初始化/不存在或者没分区

7.ERC_NO_SECURE_BOOT:

8.ERC_KEY_WRITE_PROTECTED:更新的密钥已经带有写保护标志

9.ERC_KEY_UPDATE_ERROR:密钥更新失败

10.ERC_RNG_SEED:没有初始化。即还没运行 CMD_INIT_RNG

11.ERC_NO_DEBUGGING:CMD_DBG_AUTH 校验失败

12.ERC_BUSY:

13.ERC_MEMORY_FAILURE:通用内存技术故障(如 ECC 错误)

14.ERC_GENERAL_ERROR:未定义的错误

15.ERC_NO_ERROR:没有错误

2.5 启动模式和验证

2.5.1 启动模式

CSEc 允许用户在 flash 中验证引导代码,这将产生的 MAC 与先前存储的 MAC 值进行比较。总共有三种启动模式,顺序(Sequential)启动模式、严格顺序(Strict Sequrntial)启动模式和并行(Parallel)启动模式。这可以使用 CMD_BOOT_DEFINE 来达成。

2.5.1.1 顺序启动模式

复位后, flash 退出复位,内核保持在复位状态或从 ROM 代码执行,安全启动过程验证应用程序固件块。如果安全启动成功,则标志 BOOT_PROT=1 的密钥可用;否则使用标志 BOOT_PROT=1 的密钥使用的时候将会阻塞。最后,内核开始执行应用程序。

  

下面是其安全启动过程的流程,只有最后成功并 stop 之后应用代码才可以使用被启动保护的密钥。

2.5.1.2 严格顺序启动模式

复位后, flash 退出复位,内核保持在复位状态或从 ROM 代码执行,安全启动过程验证应用程序固件块。如果安全启动成功,则标志 BOOT_PROT=1 的密钥可用,然后内核开始执行应用程序;否则内核保持复位。

注意:这个模式一旦设置就不能更改为其他启动模式。在设置为此模式之前,必须先存储 BOOT_MAC(自动 BOOT_MAC 计算不会在这种模式下运行)

2.5.1.3 并行启动模式

复位后, flash 和内核退出复位,内核开始执行应用程序,安全启动过程验证应用程序固件块。如果安全启动成功,则标志 BOOT_PROT=1 的密钥可用;否则使用标志 BOOT_PROT=1 的密钥使用的时候将会阻塞,此时,内核开始执行应用程序。

注意:在安全启动过程中内核发起任何模式转换都将被终止,FLASH_CLK 必须是默认的 FIRC_CLK。

2.5.2 验证 MAC 写入

在上文的 boot 中可以看到,这里需要往 CSEc 空间写一个 MAC 值,这样才可以进行比较,这里添加的方式有两种(如果是严格顺序启动模式就只能手动添加)。

2.5.2.1 手动写入

在这里需要两个条件:1.代码已经编写完成;2.已知 BOOT_MAC_KEY(可以是已经写到安全 flash 的,也可以还未写入)

根据以上两个条件,有两种方式:

使用AES-128 CMAC 算法、 BOOT_MAC_KEY 值和编译好的bin 文件算出 CMAC,然后创建另一个工程,用于将这个 CMAC 值写入 BOOT_MAC 里面,需要注意,如果 BOOT_MAC_KEY 还未写入,需要在此工程中写入,如果想直接通过此工程计算,可以将 BOOT_MAC_KEY 写到 RAM_KEY 中,然后再计算 CMAC ,最后将此值写入 BOOT_MAC。

2.5.2.2 自动写入

可以在同一套代码里面进行如下(严格顺序启动模式不可用):

1.代码分区,BOOT_MAC_KEY 已经写入到安全 flash,其他密钥此时也可以写入。

2.运行 CMD_BOOT_DEFINE,设置启动模式大 BOOT_SIZE

3.外部复位设备,此时 CSEc 会计算 BOOT_MAC 并存储到 BOOT_MAC 里面。再次复位,就可以顺利验证了。

2.5.2.3 更新代码产生新的 BOOT_MAC

如果所有密钥没有置位写保护标志,那么可以擦掉所有代码,如上面一样重新开始。但如果有写保护标志,或者不是所有密钥的值都是已知的,那么就不能擦除掉密钥,可以用离线的方式算出 CMAC 值或者使用 RAM_KEY 和 CSEc 产生新的 BOOT_MAC 值。

2.6 基础操作

2.6.1 随机数生成

PRNG 有一个 PRNG_STATE(128bit),在输出负反馈模式下使用 AES 产生伪随机数值。
1.使用 CMD_INIT_RNG 命令将使用 SECRET_KEY 派生一个密钥用于 PRNG,并使用 TRNG(真随机数)为 PRNG 生成 128bit seed 值。

2.CMD_RND 命令更新 PRNG_STATE 并返回 128bit 伪随机数值,这个是根据 HIS-SHE 规范和 AIS20 标准。如下:

PRNG_STATEi = ENCECB,PRNG_KEY(PRNG_STATEi-1)

RND = PRNG_STATEi

2.6.2 UID 检索:

UID(Unique Identifiwe Number) 对于用户而言只能使用 CMD_GET_ID 命令获取,需要注意的是,如果没有 MASTER_ECU_KEY,那么这将返回 0。

2.6.3 AES-128 加密和解密

CSEc 支持 ECB 和 CBC 模式下 AES-128 的加密和解密,密钥必须是启用加密(KEY_USAGE=0) 的密钥或 RAN_KEY 中选择。RAM_KEY 有潜在风险,不推荐(CMD_ENC_ECB,CMD_ENC_CBC,CMD_DEC_ECB,CMD_DEC_CBC 是用于加解密的命令)。

对于 改加密和解密而言,是以 128bit数据块进行运算的,填充是必须的,且填充由应用程序完成。

2.6.3.1 ECB 模式

当需要对单块 (128bit) 的数据进行加密和解密时,采用 ECB 模式。这种模式相同的输入值可以解码为相同的输出值,这可能可通过统计分析方式进行解析。

对于此模式,仅需要密钥和输入值就能加密为密文,反过来使用相同的密钥就能将密文变为明文。

2.6.3.2 CBC 模式

当需要对多块(128bit 分为一块)进行加密和解密时,需要用到 CBC 模式。上一个块的密文会与下一个块的明文异或,然后再使用密钥进行加密,所以,第一个块需要一个初始向量IV。如下图:
 

2.6.4 CMAC 产生和验证

CSEc 使用 AES-128 CMAC 算法进行消息认证,密钥必须是启用加密(KEY_USAGE=1) 的密钥或 RAN_KEY 中选择。CMD_VERIFY_MAC 命令用于比较计算 MAC 值和输入的 MAC 值。这里不需要应用代码填充数据块,在内部会自行填充。

2.6.5 bootloader 校验完整性和真实性

2.6.5 应用代码校验完整性和真实性
 
三、参考文档

(1) NXP:《S32K1XXRM.pdf》

(2) NXP:《AN5401_Getting Started with CSEc Security Module.pdf》

(3) NXP:《AN4234_Using the Cryptographic Service Engine (CSE).pdf》

(4) NXP:《AN4235_Using CSE to protect your application via a circle of trust.pdf》

★博文内容均由个人提供,与平台无关,如有违法或侵权,请与网站管理员联系。

★文明上网,请理性发言。内容一周内被举报5次,发文人进小黑屋喔~

评论