CRYPTO

本文档是《Rockchip Crypto/HWRNG 开发指南》,旨在介绍Rockchip公司生产的RK系列芯片中Crypto(加密)和HWRNG(硬件随机数生成器)的开发流程。文档详细阐述了驱动开发、上层应用开发、硬件启用方法、性能数据等关键信息。文档适用于技术支持工程师和软件开发工程师,以确保他们能够有效地利用Rockchip提供的硬件加密和随机数生成功能。

1. 概述

Rockchip Crypto (加密引擎,Cryptography) 是 Rockchip 系列芯片集成的硬件加密引擎,支持 AES、RSA、SHA、ECC 等算法,提供硬件加速功能,降低 CPU 负载。

Rockchip HWRNG(硬件真随机数生成器,TRNG)基于物理噪声源生成不可预测的随机数,满足安全应用需求。

1.1 Crypto 版本演进

以下是 Crypto 版本演进的表格:

Crypto 版本

算法

描述

crypto v1

DES/TDES

支持 ECB/CBC 两种模式,其中 TDES 支持 EEE 和 EDE 两种密钥模式

AES

支持 ECB/CBC/CTR/XTS 模式,支持 128/192/256 bit 三种密钥长度

HASH

支持 SHA1/SHA256/MD5

RSA

支持 512/1024/2048 三种密钥长度(RK3126、RK3128、RK3288 和 RK3368 不支持)

TRNG

支持 256bit 硬件随机数

crypto v2

DES/TDES

支持 ECB/CBC/OFB/CFB 四种模式,其中 TDES 只支持 EDE 密钥模式

AES

支持 ECB/CBC/OFB/CFB/CTR/CTS/XTS/CCM/GCM/CBC-MAC/CMAC

SM4

支持 ECB/CBC/OFB/CFB/CTR/CTS/XTS/CCM/GCM/CBC-MAC/CMAC(可选)

HASH

支持 MD5/SHA1/SHA224/SHA256/SHA384/SHA512/SM3/SHA512-224/SHA512-256(SM3 可选)

HMAC

支持 MD5/SHA1/SHA256/SHA512/SM3 带硬件填充

RSA/ECC

支持最大 4096bit 的常用大数运算操作,通过软件封装可实现 RSA/ECC 算法

TRNG

支持 256bit 硬件随机数

crypto v3

特性说明

在 crypto v2 算法基础上,增加多线程支持;从 RV1106 开始的平台自动识别支持的算法,compatible 统一使用 rockchip,crypto-v3 作为标识符

crypto v4

特性说明

在 crypto v3 算法基础上,优化 IP 芯片面积,使用同一个 CRYPTO CORE 硬件,例化出 NSCRYPTO/SCRYPTO/KEYLAD 三个硬件 IP;驱动使用兼容 crypto v3 代码,compatible 统一使用 rockchip,crypto-v4 作为标识符

1.2 各平台版本支持情况

以下是 Rockchip 芯片平台与 Crypto IP 版本的对应关系表格:

Crypto 版本 芯片平台 说明
v1 RK3399、RK3288、RK3368、RK3328/RK3228H、RK322x、RK3128、RK1108、RK3126 基础加密引擎,支持 AES/RSA
v2 RK3326/PX30、RK3308、RK1808、RV1126/RV1109、RK2206、RK356x、RK3588 新增 SHA、国密算法支持
v3 RV1106 支持 ECC 和 DMA 传输
v4 RK3528、RK3562 优化性能,支持 SM2/SM3/SM4 国密算法

  • RK356x 包含 RK3566、RK3568 等型号。

  • RV1106 为 v3 版本中唯一支持的芯片。

  • v4 版本芯片需搭配最新 SDK 实现完整国密功能。

2. 驱动开发

2.1 驱动代码说明

2.1.1 HWRNG 驱动

驱动代码路径:drivers/char/hw_random/rockchip-rng.c

因为HWRNG驱动比较简单,因此crypto v1/v2, trngv1, rkrng四种平台都集中到同一个.c 文件中。驱动中不区分具体的芯片型号,只按照 "rockchip,cryptov1-rng" 和 "rockchip,cryptov2-rng" , "rockchip,trngv1" , "rockchip,rkrng" 四种 compatible 进行划分。目前 "rockchip,trngv1" , "rockchip,rkrng" 为独立的 HWRNG 模块,其他两种 HWRNG 均内置在CYRPTO 模块中。

2.1.2 Crypto 驱动

路径:drivers/crypto/rockchip/

驱动相关文件如下:

drivers/crypto/rockchip  
|-- procfs.c                // 实现 proc 文件系统统计信息(如时钟速率、算法列表等功能)  
|-- procfs.h                // proc 文件系统相关头文件,定义相关数据结构与函数声明  
|-- rk_crypto_bignum.c      // 加密模块中 PKA(公钥算法)大整数运算相关 API 实现  
|-- rk_crypto_bignum.h      // 加密模块中 PKA 大整数运算相关头文件,声明数据结构与函数  
|-- rk_crypto_core.c        // Linux 加密驱动框架及公共接口的具体实现代码  
|-- rk_crypto_core.h        // Linux 加密驱动通用头文件,包含公共定义与宏  
|-- rk_crypto_ahash_utils.c // 哈希算法(ahash,通用哈希)相关通用 API 实现  
|-- rk_crypto_ahash_utils.h // 哈希算法(ahash)通用头文件,定义相关工具函数与结构  
|-- rk_crypto_skcipher_utils.c // 对称密钥加密算法(skcipher)通用 API 实现  
|-- rk_crypto_skcipher_utils.h // 对称密钥加密算法(skcipher)通用头文件  
|-- rk_crypto_utils.c       // 加密模块通用工具函数 API 实现,供多模块复用  
|-- rk_crypto_utils.h       // 加密模块通用工具头文件,声明公共函数与数据结构  
|-- rk_crypto_v1.c          // crypto v1 版本硬件相关接口的具体实现代码  
|-- rk_crypto_v1.h          // crypto v1 版本的结构定义与接口声明头文件  
|-- rk_crypto_v1_skcipher.c // crypto v1 版本分组密码算法(如 AES 等)的实现  
|-- rk_crypto_v1_ahash.c    // crypto v1 版本哈希算法(如 SHA、MD5 等)的实现  
|-- rk_crypto_v1_reg.h      // crypto v1 版本硬件寄存器定义,描述寄存器地址与功能  
|-- rk_crypto_v2.c          // crypto v2 版本硬件相关接口的具体实现代码  
|-- rk_crypto_v2.h          // crypto v2 版本的结构定义与接口声明头文件  
|-- rk_crypto_v2_skcipher.c // crypto v2 版本分组密码算法的实现  
|-- rk_crypto_v2_ahash.c    // crypto v2 版本哈希算法的实现  
|-- rk_crypto_v2_akcipher.c // crypto v2 版本 RSA 等非对称加密算法的实现  
|-- rk_crypto_v2_pka.c      // crypto v2 版本 PKA 操作(如大整数运算)的实现  
|-- rk_crypto_v2_reg.h      // crypto v2 版本硬件寄存器定义  
|-- rk_crypto_v3.c          // crypto v3/v4 版本硬件相关接口的具体实现代码  
|-- rk_crypto_v3.h          // crypto v3/v4 版本的结构定义与接口声明头文件  
|-- rk_crypto_v3_skcipher.c // crypto v3/v4 版本分组密码算法的实现  
|-- rk_crypto_v3_ahash.c    // crypto v3/v4 版本哈希算法的实现  
|-- rk_crypto_v3_reg.h      // crypto v3/v4 版本硬件寄存器定义  
`-- cryptodev_linux         // 向用户空间导出加密接口,供用户态程序调用内核加密功能  

当前驱动实现的算法情况如下表:

Crypto 版本

算法

模式/描述

crypto v1

AES

ECB/CBC

DES/TDES

ECB/CBC

HASH

SHA1/SHA256/MD5

crypto v2/v3/v4(驱动实现)

AES

ECB/CBC/OFB/CFB/CTR/GCM

DES/TDES

ECB/CBC/CFB/OFB

SM4

ECB/CBC/OFB/CFB/OFB/CTR/GCM

HASH

SHA1/SHA256/SHA384/SHA512/MD5/SM3

HMAC

HMAC_SHA1/HMAC_SHA256/HMAC_SHA512/HMAC_MD5/HMAC_SM3

RSA

最大 4096bit

crypto v2/v3/v4硬件完整版

AES(128/192/256)

ECB/CBC/OFB/CFB/CTR/XTS/CTS/CCM/GCM/CBC-MAC/CMAC(注:删除线部分驱动未实现)

SM4

ECB/CBC/OFB/CFB/CTR/XTS/CTS/CCM/GCM/CBC-MAC/CMAC(注:删除线部分驱动未实现)

DES/TDES

ECB/CBC/OFB/CFB

HASH

MD5/SHA-1/SHA256/SHA512/SM3/SHA224/SHA384/SHA512-224/SHA512-384(注:删除线部分驱动未实现)

HMAC

SHA-1/SHA-256/SHA-512/MD5/SM3

RSA

4096bit PKA 大数运算支持

crypto v2/v3/v4 硬件差异表

芯片平台 AES DES/TDES SM3/SM4 HASH HMAC RSA 多线程
RK3326/PX30/RK3308 × ×
RK1808 AES-128(内核驱动视为不支持) × × SHA-1/SHA-224/SHA-256/MD5 ×
RV1126/RV1109 AES-128/AES-256 ×
RK2206 × ×
RK3568/RK3588 ×
RV1106 × SHA-1/SHA-224/SHA-256/MD5
RK3562 × SHA-1/SHA-224/SHA-256/MD5
RK3528

备注:

  1. RK1808:AES 仅支持 128bit,对于 kernel 驱动来说可认为不支持 AES。

  2. RV1126/RV1109:因不支持 AES-192,AES-192 部分只能通过软算法实现,但软算法不支持硬算法的所有模式,建议不要改动代码里已配置好的算法列表。

2.2 启用硬件 HWRNG

2.2.1 内核配置

hwrng驱动会默认编译进内核,由dts文件决定是否使能。

方法一:Menuconfig中配置

 Linux/arm64 4.4.194 内核配置中,与 Rockchip 随机数生成器相关的配置如下:  

- **配置路径**:  
  **Device Drivers  Character devices  Hardware Random Number Generator Core support**  

- **核心配置项**:  
  - **Rockchip Random Number Generator support**:  
    若该项标记为 `[*]`,表示启用 Rockchip 随机数生成器支持。此时,内核将驱动 Rockchip 硬件随机数生成器(HWRNG),为系统提供硬件级随机数生成功能,适用于加密密钥生成等安全场景。

方法二:内核config文件中配置 config中配置(一般情况下rockchip_defconfig 中已默认配置好): 只需要添加如下语句即可

CONFIG_HW_RANDOM=y
CONFIG_HW_RANDOM_ROCKCHIP=y

2.2.2 板级 DTS 文件配置

当前大部分芯片 dtsi 都已配置好 hwrng 节点,只需在板级 dts 中将 rng 模块使能即可,如下所示:

&rng {
    status = "okay";
}

2.2.3 新增芯片 DTSI 文件配置

如果是新增芯片或者因为其他原因导致dtsi中未配置hwrng节点,那么可以参考以下方式进行配置。 在 arch/arm64/boot/dts/rockchip/rkxxx.dtsi 中添加 HWRNG 节点。

crypto v1:

rng: rng@ff060000 {
    compatible = "rockchip,cryptov1-rng";
    reg = <0x0 0xff060000 0x0 0x4000>;
    clocks = <&cru SCLK_CRYPTO>, <&cru HCLK_CRYPTO_SLV>;
    clock-names = "clk_crypto", "hclk_crypto";
    assigned-clocks = <&cru SCLK_CRYPTO>, <&cru HCLK_CRYPTO_SLV>;
    assigned-clock-rates = <150000000>, <100000000>;
    status = "disabled";
};

crypto v2: 实际 TRNG 不需要依赖全部的 clock,只需依赖 hclk_crypto 一个即可。

rng: rng@ff500400 {
    compatible = "rockchip,cryptov2-rng";
    reg = <0xff500400 0x80>; # 需要加上0x400,如果rng在crypto内部
    clocks = <&cru HCLK_CRYPTO>;
    clock-names = "hclk_crypto";
    power-domains = <&power RV1126_PD_CRYPTO>;
    resets = <&cru SRST_CRYPTO_CORE>;
    reset-names = "reset";
    status = "disabled";
};

trng v1: 目前RK3588和RV1106使用的是trng v1的随机数模块,该模块与crypto v2中拆分出的trng模块设计完全不同,提升了随机性。

rng: rng@fe378000 {
    compatible = "rockchip,trngv1";
    reg = <0x0 0xfe378000 0x0 0x200>;
    interrupts = <GIC_SPI 400 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&scmi_clk SCMI_HCLK_SECURE_NS>;
    clock-names = "hclk_trng";
    resets = <&scmi_reset SRST_H_TRNG_NS>;
    reset-names = "reset";
    status = "disabled";
};

2.2.4 确认 HWRNG 已启用

确认硬件驱动调用

执行命令:

cat /sys/devices/virtual/misc/hw_random/rng_current  

若输出为 rockchip,则表明当前调用的是 Rockchip 硬件随机数驱动。

Linux 系统随机数获取

在 Linux 系统中,执行以下命令获取随机数(每次执行随机数内容不同):

cat /dev/hwrng | od -x | head -n 1  
Android 系统随机数获取

在 Android 系统中,通过以下命令获取随机数(每次执行随机数内容不同):

cat /dev/hw_random | od -x | head -n 1  

2.3 启用硬件 Crypto

当前驱动代码 crypto v1 支持 rk3328,crypto v2 支持 px30/rv1126/rk3568/rk3588,crypto v3支持rv1106。 对于以上平台,只需开启 config 和 dts node 即可启用硬件 crypto。从rv1106开始,支持的feature均会在寄存器信息中体现,crypto v3可以自动适配后续新增芯片的新增功能。

2.3.1 内核配置

方法一:Menuconfig中配置 在 menuconfig 配置中使能 Rockchip 加解密驱动支持,在 dts 中会自动根据芯片平台 compatible id 进行自动适配 v1/v2/v3。(要先确保CONFIG_CRYPTO_HW开启,才能看到硬件crypto的相关配置项)

 Linux 内核配置界面(以 Linux/arm64 5.10.66 为例),进入 **Cryptographic API -> Hardware crypto devices** 菜单后,与 Rockchip 加密引擎相关的配置项如下:  

- **Rockchip's Cryptographic Engine driver**  
  该项标记为 `[*]` 时,表示启用 Rockchip 加密引擎驱动,使内核支持 Rockchip 芯片的硬件加密功能(如 AES、RSA 等算法的硬件加速)。  

- **Export rockchip crypto device for user space**  
  该项标记为 `[*]` 时,意味着将 Rockchip 加密设备接口导出到用户空间,允许用户态程序调用硬件加密功能,便于上层应用开发调用硬件加密资源。

方法二:内核config文件中配置 在 config 文件中添加如下语句,其中的 CONFIG_CRYPTO_DEV_ROCKCHIP_V3 只是示例,要根据实际的芯片配置,建议使用menuconfig的形式进行修改,会自动选择平台:

CONFIG_CRYPTO_HW=y
CONFIG_CRYPTO_DEV_ROCKCHIP=y
CONFIG_CRYPTO_DEV_ROCKCHIP_V3=y
CONFIG_CRYPTO_DEV_ROCKCHIP_DEV=y

2.3.2 板级 DTS 文件配置

确认 crypto 的 dts 节点配置正常后,直接在板级 dts 文件中开启 crypto 模块即可,如下所示:

&crypto {
    status = "okay";
};

2.3.3 新增芯片平台支持

如果芯片 dtsi 中没有配置 crypto 的 dts 节点,则需要按照以下步骤添加支持。

1. 确定crypto I版本

确定芯片 crypto IP 的版本 v1/ v2/v3,从RV1106开始的V3版本,compatible基本已确定为"rockchip,crypto-v3",算法的裁剪和feature均由软件自行适配,只需配置好dts即可。

2. 修改驱动代码drivers/crypto/rockchip/rk_crypto_core.c

主要在驱动代码中添加algs_name, soc_data,compatible等信息

/* 增加芯片支持的算法信息,px30属于crypto v2,支持的算法参见crypto_v2_algs */  
/* 特别注意:crypto_v2_algs为crypto v2支持的所有算法。*/  
/* 某些芯片在crypto v2上做了裁剪,如rk1808不支持SHA512算法,因此需要对比TRM确认支持的算法 */  
static char *px30_algs_name[] = {  
    "ecb(aes)", "cbc(aes)", "xts(aes)",  
    "ecb(des)", "cbc(des)",  
    "ecb(des3_ede)", "cbc(des3_ede)",  
    "sha1", "sha256", "sha512", "md5",  
};  

/* 绑定px30_algs_name到px30_soc_data */  
static const struct rk_crypto_soc_data px30_soc_data =  
    RK_CRYPTO_V2_SOC_DATA_INIT(px30_algs_name, false);  

/* 绑定px30_soc_data到id_table */  
static const struct of_device_id crypto_of_id_table[] = {  
    /* crypto v2 in belows */  
    {  
        .compatible = "rockchip,px30-crypto",  
        .data = (void *)&px30_soc_data,  
    },  
    {  
        .compatible = "rockchip,rv1126-crypto",  
        .data = (void *)&rv1126_soc_data,  
    },  
    /* crypto v1 in belows */  
    {  
        .compatible = "rockchip,rk3288-crypto",  
        .data = (void *)&rk3288_soc_data,  
    },  
    { /* sentinel */ }  
};
3. 新增芯片 DTSI 文件配置

arch/arm64/boot/dts/rockchip/rkxxx.dtsi 中添加 crypto 节点。

注解

  1. 根据芯片 TRM 进行修改确定 CRYPTO 基地址

  2. clocks 的宏不同平台可能略有不同,如果 dts 出现报错,可以去 include/dtbindings/clock 目录下, grep -rn CRYPTO 查找对应的 clock 宏名称,如下所示: troy@inno:~/kernel/include/dt-bindings/clock$ grep -rn CRYPTO rk3328-cru.h:57:#define SCLK_CRYPTO 59 rk3328-cru.h:206:#define HCLK_CRYPTO_MST 336 rk3328-cru.h:207:#define HCLK_CRYPTO_SLV 337 rk3328-cru.h:284:#define SRST_CRYPTO 68

一、Crypto v1 DTS 配置
crypto: crypto-controller@ff8a0000 {  
    /* 根据实际配置 crypto 基地址 */  
    compatible = "rockchip,rk3288-crypto"; /* 修改为对应芯片平台,如 "rk3399-crypto" */  
    reg = <0x0 0xff8a0000 0x0 0x4000>; /* 根据实际配置 crypto 基地址 */  
    interrupts = <GIC_SPI 48 IRQ_TYPE_LEVEL_HIGH>; /* 根据实际配置 crypto 中断号 */  
    clocks = <&cru ACLK_CRYPTO>, <&cru HCLK_CRYPTO>,  
             <&cru SCLK_CRYPTO>, <&cru ACLK_DMAC1>;  
    clock-names = "aclk", "hclk", "sclk", "apb_pclk";  
    resets = <&cru SRST_CRYPTO>;  
    reset-names = "crypto-rst";  
    status = "disabled";  
};  
  • 配置说明

    • compatible:匹配芯片平台的 crypto 驱动,需根据实际芯片修改。

    • reg:设置 crypto 硬件寄存器的基地址和地址范围。

    • interrupts:配置 crypto 模块使用的中断号及类型。

    • clocksclock-names:指定 crypto 所需时钟源及名称。

    • resetsreset-names:定义 crypto 模块的复位源及名称。

    • status:当前设为 disabled,启用时需改为 okay

二、Crypto v2 DTS 配置

对于大部分 Crypto v2 芯片,HWRNG 寄存器地址位于 crypto 地址空间内,配置 reg 时需拆分地址空间(CIPHER、RSA 等部分)。

crypto: crypto@ff500000 {  
    /* 根据实际配置 crypto 基地址 */  
    compatible = "rockchip,rv1126-crypto"; /* 修改为对应芯片平台 */  
    reg = <0xff500000 0x400>, <0xff500480 0x3B80>; /* 根据实际配置 crypto 基地址 */  
    interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;  
    clocks = <&cru CLK_CRYPTO_CORE>, <&cru CLK_CRYPTO_PKA>,  
             <&cru ACLK_CRYPTO>, <&cru HCLK_CRYPTO>;  
    clock-names = "aclk", "hclk", "sclk", "apb_pclk";  
    power-domains = <&power RV1126_PD_CRYPTO>;  
    resets = <&cru SRST_CRYPTO_CORE>;  
    reset-names = "crypto-rst";  
    status = "disabled";  
};  
  • 配置说明

    • compatible:匹配 Crypto v2 芯片平台的驱动。

    • reg:拆分地址空间,第一部分为 CIPHER/HASH 使用寄存器,第二部分为 RSA(PKA)等使用寄存器。

    • interrupts:配置中断号及类型。

    • clocksclock-names:指定所需时钟源及名称。

    • power-domains:关联芯片电源域(按需配置)。

    • resetsreset-names:定义复位源及名称。

    • status:当前设为 disabled,启用时需改为 okay

4. 板级crypto开启
&crypto {
    status = "okay";
};

2.3.4 确认 Crypto 已启用

通过命令 cat /proc/crypto | grep rk 可以查看系统注册的 RK 硬件 crypto 算法。(以 RV1126 为例)

driver : pkcs1pad(rsa-rk,sha256)
driver : rsa-rk
driver : hmac-sm3-rk
driver : hmac-md5-rk
driver : hmac-sha512-rk
driver : hmac-sha256-rk
driver : hmac-sha1-rk
driver : sm3-rk
driver : md5-rk
driver : sha512-rk
driver : sha256-rk
driver : sha1-rk
driver : ofb-des3_ede-rk
driver : cfb-des3_ede-rk
driver : cbc-des3_ede-rk
driver : ecb-des3_ede-rk
driver : ofb-des-rk
driver : cfb-des-rk
driver : cbc-des-rk
driver : ecb-des-rk
driver : xts-aes-rk
driver : ctr-aes-rk
driver : cfb-aes-rk
driver : cbc-aes-rk
driver : ecb-aes-rk
driver : xts-sm4-rk
driver : ctr-sm4-rk
driver : ofb-sm4-rk
driver : cfb-sm4-rk
driver : cbc-sm4-rk
driver : ecb-sm4-rk

通过命令cat /proc/rkcrypto(需要确保升级最新代码,旧的代码不支持该功能),可以查看rockchip crypto驱动的相关信息。包括crypto 版本,clock时钟频率,当前可用的算法,以及当前驱动运行的一些统计信息,后续会不断进行完善补充。(CRYPTO Version中"CRYPTO V3.0.0.0 multi"表示当前平台支持crypto支持多线程)。

Rockchip Crypto Version: CRYPTO V2.0.0.0
use_soft_aes192 : false
clock info:
aclk 350000000
hclk 150000000
sclk 350000000
pka 350000000
Valid algorithms:
CIPHER:
ecb(sm4)
cbc(sm4)
cfb(sm4)
ofb(sm4)
ctr(sm4)
ecb(aes)
cbc(aes)
cfb(aes)
ofb(aes)
ctr(aes)
ecb(des)
cbc(des)
cfb(des)
ofb(des)
ecb(des3_ede)
cbc(des3_ede)
cfb(des3_ede)
ofb(des3_ede)
AEAD:
gcm(sm4)
gcm(aes)
HASH:
sha1
sha224
sha256
sha384
sha512
md5
sm3
HMAC:
hmac(sha1)
hmac(sha256)
hmac(sha512)
hmac(md5)
hmac(sm3)
ASYM:
rsa
Statistic info:
busy_cnt : 1
equeue_cnt : 28764
dequeue_cnt : 28765
done_cnt : 310710
complete_cnt : 28765
fake_cnt : 0
irq_cnt : 310710
timeout_cnt : 0
error_cnt : 0
last_error : 0
Crypto queue usage [0/50], ever_max = 1, status: idle

3. 应用层开发

3.1 用户空间调用 HWRNG

user space 有两种方式可以获取到硬件 hwrng 输出的随机数:

  • 读取 kernel 驱动节点

  • 调用 librkcrypto 库中的接口

注解

hwrng 硬件驱动注册成功后可以为 kernel random 驱动增加熵,hwrng 产生的随机数会输入到 random 驱动的熵池中。kernel 的 random 驱动是 CSPRNG(Cryptography Secure Pseudo Random Number Generator),是符合密码学安全标准的。因此如果对随机数质量要求较高的话,可以读取 /dev/random 或者 /dev/urandom 节点获取随机数。

3.1.1 读取内核驱动节点

若 kernel 已开启 rng,在 user space 可通过读取节点获取随机数。Linux 平台读取节点为 /dev/hwrng,Android 平台为 /dev/hw_random。参考代码如下:

#ifdef ANDROID  
#define HWRNG_NODE       "/dev/hw_random"  
#else  
#define HWRNG_NODE       "/dev/hwrng"  
#endif  

RK_RES rk_get_random(uint8_t *data, uint32_t len) {  
    RK_RES res = RK_CRYPTO_SUCCESS;  
    int hwrng_fd = -1;  
    int read_len = 0;  

    hwrng_fd = open(HWRNG_NODE, O_RDONLY, 0);  
    if (hwrng_fd < 0) {  
        E_TRACE("open %s error!", HWRNG_NODE);  
        return RK_CRYPTO_ERR_GENERIC;  
    }  

    read_len = read(hwrng_fd, data, len);  
    if (read_len != len) {  
        E_TRACE("read %s error!", HWRNG_NODE);  
        res = RK_CRYPTO_ERR_GENERIC;  
    }  

    close(hwrng_fd);  
    return res;  
}

3.1.2 调用 librkcrypto API

参考下文 API 说明:rk_get_random。

3.2 用户空间调用 Crypto

user space 使用 librkcrypto api 接口进行调用。本节是对 librkcrypto 的使用说明。

注解

注意:使用前请确认 kernel 中硬件 crypto 是否已启用,启用方法与确认方法参考启用硬件 crypto和确认硬件 crypto 已启用的方法。

3.2.1 适用范围

API RK3588 RK356x RV1109/1126
rk_crypto_mem_alloc/free
rk_crypto_init/deinit
rk_get_random
rk_hash_init/update/update_virt/final
rk_cipher_init/crypt/crypt_virt/final
rk_ae_init/set_aad/set_aad_virt/crypt/crypt_virt/final
rk_rsa_pub_encrypt/priv_decrypt/priv_encrypt/pub_decrypt
rk_rsa_sign/verify
rk_write_oem_otp_key
rk_oem_otp_key_is_written
rk_set_oem_hr_otp_read_lock
rk_oem_otp_key_cipher
rk_oem_otp_key_cipher_virt

3.2.2 版本依赖

V1.2.0版本librkcrypto库功能依赖kernel以下提交点,若kernel crypto驱动没更新到以下提交点,可能会导致部分功能不可用。 kernel 4.19

commit c255a0aa097afbf7f28e3c0770c5ab778e5616b2
Author: Lin Jinhan <troy.lin@rock-chips.com>
Date: Tue Sep 13 17:20:46 2022 +0800
crypto: rockchip: rk3326/px30 add aes gcm support
Signed-off-by: Lin Jinhan <troy.lin@rock-chips.com>
Change-Id: I75949554d4f573c63092841eef76765a69cc6b24

kernel 5.10

commit 47e85085826daf6401265b803ac9ac7116ae6bb4
Author: Lin Jinhan <troy.lin@rock-chips.com>
Date: Tue Sep 13 17:20:46 2022 +0800
crypto: rockchip: rk3326/px30 add aes gcm support
Signed-off-by: Lin Jinhan <troy.lin@rock-chips.com>
Change-Id: I75949554d4f573c63092841eef76765a69cc6b24

3.2.3 注意事项

  • 对称算法的输入数据长度,要求与所选算法和模式的数据长度要求一致。 比如 ECB/CBC 等要求 block 对齐,CTS/CTR 等则无数据长度对齐要求。API 中不做填充处理。

  • 如果计算数据量较大,为了提高效率,建议选用通过 dma_fd 传递数据的算法接口。 由于 crypto 只支持 4G 以内连续物理地址,因此 dma fd 分配的 buffer 必须是 4G 以内物理连续地址(CMA)。可以使用 librkcrypto 提供的 rk_crypto_mem 相关接口分配,也可以自行用 DRM 等内存分配接口分配得到 dma fd。

  • CMA 配置: 由于 crypto 只支持 4G 以内的 CMA 地址访问,如果设备使用内存超过 4G,需要修改 dts 中 CMA 的配置,否则 rk_crypto_mem 虽然能分配成功,但是分配出的内存无法使用。以下以 rk3588-android.dtsi 平台为例。其中 0x10000000 为 CMA 的起始地址(256MB 处,尽量不要修改),0x00800000 为 CMA 的大小,可以根据实际需要进行修改。CMA 相关说明见文档<Rockchip_Developer_Guide_Linux_CMA_CN>。

--- a/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3588-android.dtsi
@@ -70,7 +70,8 @@
            cma {
                        compatible = "shared-dma-pool";
                        reusable;
-                       size = <0x0 (8 * 0x100000)>;
+                       //size = <0x0 (8 * 0x100000)>;
+                       reg = <0x0 0x10000000 0x0 0x00800000>;
                        linux,cma-default;
                };
  • 使用以下接口前,需确保 TEE 功能可用,TEE 相关说明见<Rockchip_Developer_Guide_TEE_SDK_CN>文档。

  • rk_set_oem_hr_otp_read_lock :当设置的 key_id 为 RK_OEM_OTP_KEY0/1/2 时,设置成功后,会影响其他 OTP 区域的属性。 例如部分 OTP 区域变为不可写,详见<Rockchip_Developer_Guide_OTP_CN>文档。因此,建议优先使用 RK_OEM_OTP_KEY3 。

  • rk_oem_otp_key_cipher_virt :支持的 len 最大值受 TEE 的共享内存影响,如果使用本接口前已占用 TEE 共享内存,那么 len 的最大值可能比预期的小。

3.2.4 关键数据结构

3.2.4.1 rk_crypto_mem
typedef struct {  
    void        *vaddr;  
    int         dma_fd;  
    size_t      size;  
} rk_crypto_mem;  
  • vaddr:内存的虚拟地址。

  • dma_fd:内存对应的 DMA 文件描述符句柄。

  • size:内存区域的大小。

3.2.4.2 rk_cipher_config
typedef struct {  
    uint32_t    algo;  
    uint32_t    mode;  
    uint32_t    operation;  
    uint8_t     key[64];  
    uint32_t    key_len;  
    uint8_t     iv[16];  
    void        *reserved;  
} rk_cipher_config;  
  • algo:算法类型,取值参考 RK_CRYPTO_ALGO,具体范围以 API 描述为准。

  • mode:算法模式,参考 RK_CIPHER_MODE,支持 ECB/CBC/CTR/CFB/OFB 等模式。

  • operation:加解密模式,参考 RK_CRYPTO_OPERATION

  • key:密钥明文(使用 otp key 操作时无效)。

  • key_len:密钥长度(单位:字节)。

  • iv:初始向量(ECB 模式无效,其他模式下,执行 rk_cipher_crypt/crypt_virt 会自动更新,用于多次分段计算)。

  • reserved:预留字段。

3.2.4.3 rk_ae_config
typedef struct {  
    uint32_t    algo;  
    uint32_t    mode;  
    uint32_t    operation;  
    uint8_t     key[32];  
    uint32_t    key_len;  
    uint8_t     iv[16];  
    uint32_t    iv_len;  
    uint32_t    tag_len;  
    uint32_t    aad_len;  
    uint32_t    payload_len;  
    void        *reserved;  
} rk_ae_config;  
  • algo:算法类型,参考 RK_CRYPTO_ALGO,支持 AES/SM4。

  • mode:算法模式,参考 RK_CIPHER_MODE,支持 GCM/CCM。

  • operation:加解密模式,参考 RK_CRYPTO_OPERATION

  • key:密钥明文(使用 keyladder 操作时无效)。

  • key_len:密钥长度(单位:字节)。

  • iv:初始向量。

  • iv_len:IV 的长度(单位:字节)。

  • tag_len:TAG 的长度(单位:字节)。

  • aad_len:AAD 的长度(单位:字节)。

  • payload_len:Payload 的长度(单位:字节)。

  • reserved:预留字段。

3.2.4.4 rk_hash_config
typedef struct {  
    uint32_t    algo;  
    uint8_t     *key;  
    uint32_t    key_len;  
} rk_hash_config;  
  • algo:算法类型,参考 RK_CRYPTO_ALGO,支持 HASH/HMAC 等多种算法。

  • key:hash-mac 密钥(仅当 algo 为 HMAC 类型算法时有效)。

  • key_len:key 的长度(单位:字节)。

3.2.4.5 rk_rsa_pub_key
typedef struct {  
    const uint8_t     *n;  
    const uint8_t     *e;  
    uint16_t          n_len;  
    uint16_t          e_len;  
} rk_rsa_pub_key;  
  • n:模长,与 OpenSSL 相同,大端模式。

  • e:指数,与 OpenSSL 相同,大端模式。

  • n_len:模长的长度。

  • e_len:指数的长度。

3.2.4.6 rk_rsa_pub_key_pack

typedef struct {  
    enum RK_RSA_KEY_TYPE    key_type;  
    rk_rsa_pub_key          key;  
} rk_rsa_pub_key_pack;  
  • key_type:密钥类型,参考 RK_RSA_KEY_TYPE,支持明文密钥和 OTP_KEY 加密后的密文密钥,librkcrypto 会将传入的密钥,用对应的 otp key 密钥解密后再使用。

  • key:公钥内容,结构定义见 rk_rsa_pub_key

3.2.4.7 rk_rsa_priv_key
typedef struct {  
    const uint8_t     *n;  
    const uint8_t     *e;  
    const uint8_t     *d;  
    const uint8_t     *p;  
    const uint8_t     *q;  
    const uint8_t     *dp;  
    const uint8_t     *dq;  
    const uint8_t     *qp;  
    uint16_t          n_len;  
    uint16_t          e_len;  
    uint16_t          d_len;  
    uint16_t          p_len;  
    uint16_t          q_len;  
    uint16_t          dp_len;  
    uint16_t          dq_len;  
    uint16_t          qp_len;  
} rk_rsa_priv_key;  
  • n:模长,与 OpenSSL 相同,采用大端模式。

  • e:指数,与 OpenSSL 相同,采用大端模式。

  • d:模反元素(即私钥),与 OpenSSL 相同,采用大端模式。

  • p:可选参数。

  • q:可选参数。

  • dp:可选参数。

  • dq:可选参数。

  • qp:可选参数。

  • n_len:模长 n 的长度。

  • e_len:指数 e 的长度。

  • d_len:私钥 d 的长度。

  • p_len:参数 p 的长度。

  • q_len:参数 q 的长度。

  • dp_len:参数 dp 的长度。

  • dq_len:参数 dq 的长度。

  • qp_len:参数 qp 的长度。

3.2.4.8 rk_rsa_priv_key_pack

typedef struct {  
    enum RK_RSA_KEY_TYPE    key_type;  
    rk_rsa_priv_key         key;  
} rk_rsa_priv_key_pack;  
  • key_type:密钥类型,参考 RK_RSA_KEY_TYPE,支持明文密钥和 OTP_KEY 加密后的密文密钥,librkcrypto 会将传入的密钥,通过对应的 otp key 密钥解密后使用。

  • key:私钥内容,具体结构定义参考 rk_rsa_priv_key

3.2.5 常量定义

略 详见Rockchip_Developer_Guide_Crypto_HWRNG_CN.pdf

3.2.6 API 列表

略 详见Rockchip_Developer_Guide_Crypto_HWRNG_CN.pdf

3.2.7 Debug 日志

librkcrypto 的日志级别如下所示:

日志级别
TRACE_TOP 0
TRACE_ERROR 1
TRACE_INFO 2
TRACE_DEBUG 3
TRACE_VERBOSE 4
TRACE_BUTT -

默认日志级别为 TRACE_INFO

可以通过设置环境变量修改日志级别,需要在 librkcrypto 库加载之前设置环境变量才会生效。也可以在 rk_crypto_init 之前通过 rkcrypto_set_trace_level 接口进行设置。具体设置方法如下:

  • Android: setprop vendor.rkcrypto.trace.level 1/2/3/4

  • Linux: export rkcrypto_trace_level=1/2/3/4

4. 硬件 Crypto 性能数据

  • 性能数据参考了典型的芯片在 uboot 下的性能,具体详细的性能见 librkcrypto 源码中的 perf_reports 目录。

  • perf_reports 目录的性能为应用层调用 kernel crypto 内核驱动在最高 CPU/DDR 定频下的实测,由于系统调用的原因,性能会比uboot 测试的性能略低。

4.1 U-Boot 层性能

4.1.1 Crypto v1 性能数据

测试环境(uboot RK3399): 时钟:CRYPTO_CORE = 200M,不同芯片的最高频率略有不同 CIPHER/HASH 算法性能测试:

算法

实际 (MBps)

理论 (MBps)

DES

-

<= 94

TDES

-

<= 31

AES-128

-

<= 290

AES-192

-

<= 246

AES-256

-

< 213

MD5

125

< 196

SHA1

125

< 158

SHA256

125

-

RSA 算法性能测试:

| RSA 算法长度(nbits) | 公钥加密/私钥解密 (ms) |
|---------------------|-----------------------|
| 2048                | 8 / 632               |

4.1.2 crypto v2 / v3 /v4 性能数据

这几个版本的CRYPTO IP计算核心没有发生大的变化,性能差异只体现在CRYPTO IP的工作主频上,CRYPTO V3的主频最高可以到350M,其理论性能可以在V2的基础上进行简单换算。 测试环境(uboot RV1126 V2): 时钟:CRYPTO_CORE = 200M,CRYPTO_PKA=300M, DDR=786M Hash/HMAC:总共测试 128M 的数据,每次计算 4M 的数据 DES/3DES/AES/SM4:总共测试 128M 数据,每次计算 4M 的明文和 4M 的 aad 数据

ALGO

MODE

Actual (Mbps)

Theoretical (Mbps)

HASH/HMAC

MD5

183

196

SHA1

148

158

SHA256/224

183

196

SHA512/384/512_224/512_256

288

316

SM3

183

--

DES

ECB

289

352

CBC/CFB/OFB

79

88

3DES

ECB

107

116

CBC/CFB/OFB

27

29

AES (128 | 192 | 256)

ECB/CTR/XTS

447 | 442 | 436

1066 | 914 | 800

CBC/CFB/OFB/CTS

234 | 204 | 180

266 | 228 | 200

CMAC/CBC_MAC

245 | 212 | 186

266 | 228 | 200

CCM(data+aad)

180 | 162 | 146

--

GCM(data+aad)

196 | 184 | 174

--

SM4

ECB/CTR/XTS

320

--

CBC/CFB/OFB/CTS

87

--

CMAC/CBC_MAC

89

--

CCM(data+aad)

156

--

GCM(data+aad)

114

--

RSA 测试方法:生成 rsa key,包含 n, e, d,执行加密和解密测试。

加密测试:密文 = d ^e % n

解密测试:明文 = d^d % n

RSA类型

ENC/DEC

Time(ms)

-----------

---------

----------

RSA-1024

ENC

< 1

DEC

12

RSA-2048

ENC

1

DEC

93

RSA-3072

ENC

1

DEC

304

RSA-4096

ENC

2

DEC

710

5. References

  1. Rockchip 官方文档:Rockchip_Developer_Guide_Crypto_HWRNG_CN.pdf

  2. Linux 内核源码:drivers/crypto/rockchip/

  3. NIST SP 800-90B:随机数生成安全标准

6. 附录

6.1 术语

  • TRNG:真随机数生成器(True Random Number Generator)。

  • DMA:直接内存访问(Direct Memory Access)。

  • OTP:一次性可编程存储器(One-Time Programmable)。

:实际开发需结合具体芯片型号(如 RK3588)和官方 SDK 进行适配。