5.14 HWCrypto设备
5.14 HWCrypto设备
📚 本节导读
学习时长: 约 40 分钟
难度级别: ⭐⭐⭐⭐☆
前置知识: C 语言基础、密码学基础概念(AES/SHA)、5.1 设备驱动框架
🎯 学习目标
- 理解 OneOS HWCrypto 硬件加密框架的抽象设计
- 掌握加密上下文(ctx)的创建、初始化、销毁流程
- 了解对称加密(AES/DES/3DES/RC4/GCM)和哈希(MD5/SHA1/SHA2/CRC)的硬件加速
- 了解 RNG 随机数生成和 BIGNUM 大数运算
一、概述
HWCrypto(Hardware Crypto)是 OneOS 提供的硬件加密抽象层,利用 MCU 内置的硬件加密引擎(如 STM32 的 CRYP/HASH 模块)来加速加解密运算。HWCrypto 设备驱动位于 drivers/hwcrypto/ 目录下,核心头文件为 hwcrypto.h,实现文件为 hwcrypto.c。
注意:使用 HWCrypto 需要在
oneos_config.h中启用OS_USING_HWCRYPTO。
1.1 使用场景
一句话核心:HWCrypto 适用于对加解密/哈希性能有要求、且 MCU 内置对应硬件加密引擎的场景——把最耗 CPU 的数学运算交给硬件,让 CPU 腾出来处理业务。
与纯软件加密(Mbed TLS / OneTLS)对比:
| 维度 | HWCrypto(硬件) | Mbed TLS(软件) |
|---|---|---|
| 运算速度 | 快(专用硬件加速) | 慢(CPU 逐指令算) |
| CPU 占用 | 极低(硬件并行) | 高(占用大量 CPU) |
| 功耗 | 低(算完即停) | 较高 |
| 依赖 | 必须 MCU 有加密引擎 | 任何 MCU 可用 |
| 算法覆盖 | 受限于硬件支持的模式 | 全面(纯软件实现) |
| 典型场景 | 性能敏感、持续加解密 | 兜底、硬件不支持时 |
结论:硬件引擎支持的算法优先用 HWCrypto(快、省 CPU);硬件不支持的算法/模式才回退到 Mbed TLS 软件实现。两者可并存,通过
MBEDTLS_AES_ALT等宏把 Mbed TLS 底层替换为 HWCrypto 硬件加速。
典型应用场景:
| 场景 | 谁在用 | 用哪个算法 | 实际工作情况 |
|---|---|---|---|
| 固件签名校验 | 引导加载程序 | SHA256 | 启动时对固件镜像算一次哈希,比对签名,校验通过才跳转——哈希过程用硬件 SHA2 加速,缩短启动时间 |
| 安全通信(TLS/DTLS) | 通信任务 | AES-CBC / AES-GCM | 每条收发报文加解密,若用软件 AES 会占满 CPU 导致通信卡顿,改用硬件 AES 后吞吐量提升数倍 |
| 数据完整性 | 存储/日志任务 | CRC / MD5 | 对写入 Flash 的数据块算校验值,损坏可检测 |
| 会话密钥/随机盐 | 协议栈 | RNG | 生成密钥、随机数、nonce,硬件真随机数比伪随机更安全 |
| 密钥协商(RSA/ECC) | TLS 握手 | BIGNUM 大数 | 大数模幂运算极耗 CPU,硬件大数单元可显著加速握手 |
选型边界表(何时不该用它):
| 场景 | 该用什么 | 为什么 |
|---|---|---|
| MCU 无对应硬件加密引擎 | Mbed TLS 软件实现 | 没有硬件可调,HWCrypto 不可用 |
| 一次性/极低频的加解密 | Mbed TLS | 性能要求低,软件实现足够且更通用 |
| 需要软件算法全覆盖 | Mbed TLS | HWCrypto 只覆盖硬件支持的算法/模式 |
| 追求最大算法灵活性 | Mbed TLS + ALT 宏 | 通过 MBEDTLS_XXX_ALT 在需要时把热点算法替换为硬件 |
结合源码的使用注意点:
- 必须启用配置:
OS_USING_HWCRYPTO未开则整个框架不编译; - 先注册设备:使用前需确认硬件设备已注册(如
os_hwcrypto_hash_register),否则hash_create因hwcrypto_hash_device == OS_NULL返回空; - 对象大小:
os_hwcrypto_ctx_create的obj_size必须 ≥sizeof(struct os_hwcrypto_ctx),派生对象传派生结构体大小; - 用完销毁:
os_hwcrypto_ctx_destroy若不调用,硬件上下文和内存都会泄漏。
二、支持的算法类型
2.1 对称加密
| 主类型 | 子类型 | 说明 |
|---|---|---|
HWCRYPTO_TYPE_AES | AES_ECB / AES_CBC / AES_CFB / AES_CTR / AES_OFB | AES 加密(128/192/256 位) |
HWCRYPTO_TYPE_DES | DES_ECB / DES_CBC | DES 加密 |
HWCRYPTO_TYPE_3DES | 3DES_ECB / 3DES_CBC | 3DES 加密 |
HWCRYPTO_TYPE_RC4 | — | RC4 流加密 |
HWCRYPTO_TYPE_GCM | — | AES-GCM 认证加密 |
2.2 哈希(Hash)
| 主类型 | 子类型 | 说明 |
|---|---|---|
HWCRYPTO_TYPE_MD5 | — | MD5 哈希(16 字节输出) |
HWCRYPTO_TYPE_SHA1 | — | SHA-1 哈希(20 字节输出) |
HWCRYPTO_TYPE_SHA2 | SHA224 / SHA256 / SHA384 / SHA512 | SHA-2 系列哈希 |
2.3 其他
| 类型 | 说明 |
|---|---|
HWCRYPTO_TYPE_RNG | 硬件真随机数生成器 |
HWCRYPTO_TYPE_CRC | 硬件 CRC 校验 |
HWCRYPTO_TYPE_BIGNUM | 硬件大数运算(RSA/ECC 加速) |
三、核心数据结构
HWCrypto 框架围绕"设备(device)— 上下文(ctx)— 算法专属派生对象"三层结构组织。核心是:os_hwcrypto_device(硬件设备)+ os_hwcrypto_ctx(通用上下文基类),再通过 C 语言"首成员继承" 派生出 hwcrypto_hash、hwcrypto_symmetric、hwcrypto_rng 等算法专属对象(它们各自再带一套 ops 回调表)。
一句话核心:HWCrypto 用"基类上下文 + 首成员继承 + 回调表多态",让上层用一套统一的
os_hwcrypto_ctx*就能操作 AES/SHA/RNG 等不同硬件加密引擎。
3.1 加密设备 os_hwcrypto_device
来源:drivers/hwcrypto/hwcrypto.h
struct os_hwcrypto_device
{
struct os_device parent; /* Inherited from the standard device */
const struct os_hwcrypto_ops *ops; /* Hardware crypto ops */
uint64_t id; /* Unique id */
void *user_data; /* Device user data */
};字段详解(源码注释为英文原版,下表补充说明,不属于源码):
| 字段 | 类型 | 含义 |
|---|---|---|
parent | struct os_device | 首成员继承自标准设备 os_device_t,使 os_hwcrypto_device 可以当普通设备注册/查找 |
ops | const struct os_hwcrypto_ops * | 硬件加密通用操作接口(create/destroy/copy/reset) |
id | uint64_t | 设备唯一 ID,用于区分同一类型下的不同硬件实例 |
user_data | void * | 用户/厂商私有数据,HAL 层可存自定义配置 |
关键理解 ——
parent首成员继承:parent是结构体的第一个成员,其地址与整个os_hwcrypto_device的地址数值相等。因此把&device->parent传给os_device_register注册,本质就是把整个os_hwcrypto_device当作一个os_device挂进系统设备链表;反向用os_container_of可从parent找回完整的os_hwcrypto_device。
3.2 加密上下文 os_hwcrypto_ctx
来源:drivers/hwcrypto/hwcrypto.h
struct os_hwcrypto_ctx
{
struct os_hwcrypto_device *device; /* Binding device */
hwcrypto_type type; /* Encryption and decryption types */
void *contex; /* Hardware context */
};字段详解(源码注释为英文原版,下表补充说明,不属于源码):
| 字段 | 类型 | 含义 |
|---|---|---|
device | struct os_hwcrypto_device * | 绑定的加密设备(该 ctx 属于哪块硬件) |
type | hwcrypto_type | 加密类型(主类型 + 子类型,见 2.1 算法表) |
contex | void * | 硬件上下文指针:HAL 层私有数据(如 STM32 的 CRYP_HandleTypeDef),由 device->ops->create 创建 |
关键理解:
os_hwcrypto_ctx是所有算法上下文的"基类"。type是 32 位值,高 16 位(HWCRYPTO_MAIN_TYPE_MASK)是主类型、bit8~15 是子类型(详见 5.4os_hwcrypto_set_type的位运算演算)。contex是"黑盒"——框架只负责透传,具体内容由 HAL 层决定。
3.3 通用操作接口 os_hwcrypto_ops
来源:drivers/hwcrypto/hwcrypto.h
struct os_hwcrypto_ops
{
os_err_t (*create)(struct os_hwcrypto_ctx *ctx); /* Creating hardware context */
void (*destroy)(struct os_hwcrypto_ctx *ctx); /* Delete hardware context */
os_err_t (*copy)(struct os_hwcrypto_ctx *des, const struct os_hwcrypto_ctx *src); /* Cpoy hardware context */
void (*reset)(struct os_hwcrypto_ctx *ctx); /* Reset hardware context */
};函数指针详解(源码注释为英文原版,下表补充说明,不属于源码):
| 函数指针 | 说明 |
|---|---|
create | 创建硬件上下文(为 ctx->contex 分配并初始化 HAL 私有结构) |
destroy | 销毁硬件上下文(释放 contex 占用的硬件/内存资源) |
copy | 复制硬件上下文(des ← src,用于哈希状态快照等场景) |
reset | 重置硬件上下文(清空中间状态,可复用) |
注意:这里的
create/destroy/copy/reset是设备级通用回调(对应os_hwcrypto_ctx_*系列 API),与各算法专属回调(如 hash 的update/finish、symmetric 的crypt)是两套不同的回调表。
3.4 哈希上下文 hwcrypto_hash 与操作接口 hwcrypto_hash_ops
来源:drivers/hwcrypto/hw_hash.h
struct hwcrypto_hash_ops
{
os_err_t (*update)(struct hwcrypto_hash *hash_ctx, const uint8_t *in, os_size_t length); /* Process data */
os_err_t (*finish)(struct hwcrypto_hash *hash_ctx,
uint8_t *out,
os_size_t length); /* Get the final hash value */
};
struct hwcrypto_hash
{
struct os_hwcrypto_ctx parent; /* Inherit from hardware crypto context */
const struct hwcrypto_hash_ops *ops; /* Operations for hash crypto context */
};字段详解(源码注释为英文原版,下表补充说明,不属于源码):
| 结构体 | 字段 | 含义 |
|---|---|---|
hwcrypto_hash_ops | update | 处理一段数据(哈希运算的"喂数据"阶段,可多次调用) |
hwcrypto_hash_ops | finish | 取最终哈希值(out 写出,如 SHA256 写 32 字节) |
hwcrypto_hash | parent | 首成员继承 os_hwcrypto_ctx(基类字段:device/type/contex) |
hwcrypto_hash | ops | 哈希专属操作接口(update/finish) |
关键理解 —— 继承 + 多态:
hwcrypto_hash的第一个成员是os_hwcrypto_ctx parent,所以一个hwcrypto_hash对象同时也是一个合法的os_hwcrypto_ctx。上层拿到的os_hwcrypto_ctx *ctx实际指向hwcrypto_hash的开头,需要哈希专属操作时,把ctx强转为hwcrypto_hash *再访问->ops->update(见 5.5)。这种"把基类指针转回派生指针"正是 C 语言实现多态的常见手段。
各算法专属对象的继承关系总览:
| 算法专属对象 | 文件 | 继承基类 | 自带回调表 | 自带回调 |
|---|---|---|---|---|
hwcrypto_hash | hw_hash.h | os_hwcrypto_ctx | hwcrypto_hash_ops | update / finish |
hwcrypto_symmetric | hw_symmetric.h | os_hwcrypto_ctx | hwcrypto_symmetric_ops | crypt |
hwcrypto_rng | hw_rng.h | os_hwcrypto_ctx | hwcrypto_rng_ops | update |
hwcrypto_crc | hw_crc.h | os_hwcrypto_ctx | hwcrypto_crc_ops | update / digest |
hwcrypto_bignum | hw_bignum.h | os_hwcrypto_ctx | hwcrypto_bignum_ops | add / sub / mul / exp_mod |
提示:本节的
os_hwcrypto_ops(create/destroy/copy/reset)与各算法专属ops(update/finish/crypt 等)是两套层次——前者在device上、管"上下文生命周期";后者在派生对象上、管"具体运算"。阅读源码时注意区分。
四、API 总览
本章先给出 HWCrypto 框架对外暴露的 API 签名与参数含义,方便速查;完整源码、分步详解见第五章。API 分四类:上下文生命周期管理、哈希运算、对称加密、设备管理。
4.1 上下文管理(通用)
| API | 功能 | 返回 |
|---|---|---|
os_hwcrypto_ctx_create(device, type, obj_size) | 创建并初始化一个加密上下文(分配 obj_size 字节,调 ops->create) | struct os_hwcrypto_ctx *(失败 OS_NULL) |
os_hwcrypto_ctx_destroy(ctx) | 销毁上下文(调 ops->destroy 释放硬件资源后 os_free) | void |
os_hwcrypto_ctx_cpy(des, src) | 复制上下文(要求设备相同、主类型相同) | os_err_t |
os_hwcrypto_ctx_reset(ctx) | 重置上下文(调 ops->reset,可复用) | void |
os_hwcrypto_ctx_init(ctx, device, type) | 初始化已分配的内存为合法上下文 | os_err_t |
os_hwcrypto_set_type(ctx, type) | 设置上下文类型(含主类型兼容校验) | os_err_t |
os_hwcrypto_ctx_create 参数表:
| 参数 | 说明 |
|---|---|
device | 要绑定的硬件加密设备(os_hwcrypto_device*) |
type | 算法类型(如 HWCRYPTO_TYPE_SHA256 / HWCRYPTO_TYPE_AES_CBC) |
obj_size | 分配的对象大小(字节),必须 ≥ sizeof(struct os_hwcrypto_ctx),派生对象传派生结构体大小 |
4.2 哈希运算
| API | 功能 | 返回 |
|---|---|---|
os_hwcrypto_hash_create(type) | 创建哈希上下文(绑定框架内部的哈希设备 hwcrypto_hash_device) | struct os_hwcrypto_ctx * |
os_hwcrypto_hash_update(ctx, input, length) | 喂入一段数据参与哈希(可多次调用) | os_err_t |
os_hwcrypto_hash_finish(ctx, output, length) | 取最终哈希值(写入 output) | os_err_t |
os_hwcrypto_hash_destroy(ctx) | 销毁哈希上下文 | void |
os_hwcrypto_hash_cpy(des, src) | 复制哈希上下文(哈希状态快照) | os_err_t |
os_hwcrypto_hash_reset(ctx) | 重置哈希上下文 | void |
4.3 对称加密(AES/DES/3DES/RC4/GCM)
| API | 功能 | 返回 |
|---|---|---|
os_hwcrypto_symmetric_create(type) | 创建对称加密上下文 | struct os_hwcrypto_ctx * |
os_hwcrypto_symmetric_setkey(ctx, key, bitlen) | 设置密钥(bitlen 为密钥位数,如 128/192/256) | os_err_t |
os_hwcrypto_symmetric_setiv(ctx, iv, len) | 设置初始化向量 IV | os_err_t |
os_hwcrypto_symmetric_crypt(ctx, mode, length, in, out) | 加解密(mode 为 HWCRYPTO_MODE_ENCRYPT/DECRYPT,length 为块大小整数倍) | os_err_t |
os_hwcrypto_symmetric_destroy(ctx) | 销毁对称加密上下文 | void |
4.4 随机数(RNG)
| API | 功能 | 返回 |
|---|---|---|
os_hwcrypto_rng_update_ctx(ctx) | 从指定 RNG 上下文取一个随机数 | uint32_t |
os_hwcrypto_rng_update() | 从默认 RNG 上下文取一个随机数 | uint32_t |
注意:RNG 接口每次返回一个
uint32_t随机数,不是一次生成一整个字节数组。想生成 N 字节随机数据需循环调用(见 6.4 示例)。
4.5 设备管理
| API | 功能 | 返回 |
|---|---|---|
os_hwcrypto_register(device, name) | 注册 HWCrypto 设备到系统设备框架 | os_err_t |
os_hwcrypto_id(device) | 获取设备唯一 ID | uint64_t |
五、核心源码详解
说明:以下源码均取自
drivers/hwcrypto/hwcrypto.c、drivers/hwcrypto/hw_hash.c,与项目源码逐字一致(含原始英文注释)。
5.1 os_hwcrypto_ctx_create —— 创建加密上下文
一句话定位:参数校验后分配对象,调用 os_hwcrypto_ctx_init 创建硬件上下文。
函数签名:
struct os_hwcrypto_ctx *
os_hwcrypto_ctx_create(struct os_hwcrypto_device *device, hwcrypto_type type, uint32_t obj_size);参数/返回值:
| 参数 | 说明 |
|---|---|
device | 绑定的硬件加密设备(os_hwcrypto_device*) |
type | 算法类型(如 HWCRYPTO_TYPE_SHA256) |
obj_size | 分配对象大小(字节),必须 ≥ sizeof(struct os_hwcrypto_ctx) |
| 返回值 | 说明 |
|---|---|
OS_NULL | 参数非法 / 内存不足 / 硬件上下文创建失败 |
| 其他 | 成功创建的 os_hwcrypto_ctx * |
完整源码(drivers/hwcrypto/hwcrypto.c,与项目一致):
struct os_hwcrypto_ctx *
os_hwcrypto_ctx_create(struct os_hwcrypto_device *device, hwcrypto_type type, uint32_t obj_size)
{
struct os_hwcrypto_ctx *ctx;
os_err_t err;
/* Parameter checking */
if (device == OS_NULL || obj_size < sizeof(struct os_hwcrypto_ctx))
{
return OS_NULL;
}
ctx = os_calloc(1, obj_size);
if (ctx == OS_NULL)
{
return ctx;
}
memset(ctx, 0, obj_size);
/* Init context */
err = os_hwcrypto_ctx_init(ctx, device, type);
if (err != OS_SUCCESS)
{
os_free(ctx);
ctx = OS_NULL;
}
return ctx;
}分步详解:
第 1 步:参数校验(条件 device == OS_NULL 或 obj_size 过小)
/* Parameter checking */
if (device == OS_NULL || obj_size < sizeof(struct os_hwcrypto_ctx))
{
return OS_NULL;
}详细解释:device 为空(没有可用硬件)或 obj_size 小于基类 os_hwcrypto_ctx 大小,都属于非法调用,直接返回 OS_NULL。
关键理解 —— 为什么 obj_size 必须 ≥ sizeof(struct os_hwcrypto_ctx):os_hwcrypto_ctx 是基类,具体算法对象(如 hwcrypto_hash)比它大(基类 + 自带 ops 指针等)。obj_size 传入的是派生结构体的大小,因此必须不小于基类,否则 os_calloc 分配的内存装不下上下文,后续访问字段会越界。这是 C 语言继承下"分配派生对象"的基本约束。
第 2 步:分配并清零对象(无条件执行,但可能分配失败)
ctx = os_calloc(1, obj_size);
if (ctx == OS_NULL)
{
return ctx;
}
memset(ctx, 0, obj_size);详细解释:os_calloc(1, obj_size) 分配 obj_size 字节并自动清零(相当于 calloc)。若内存不足返回 OS_NULL,直接返回(此时 ctx == OS_NULL)。分配成功后 memset 清零(os_calloc 本已清零,此处再次清零是双保险)。
第 3 步:初始化上下文(条件 os_hwcrypto_ctx_init 返回值)
/* Init context */
err = os_hwcrypto_ctx_init(ctx, device, type);
if (err != OS_SUCCESS)
{
os_free(ctx);
ctx = OS_NULL;
}
return ctx;
}详细解释:调用 os_hwcrypto_ctx_init(见 5.2)设置类型、绑定设备、调 device->ops->create 创建硬件上下文。若初始化失败(err != OS_SUCCESS),必须 os_free(ctx) 释放已分配的内存并把 ctx 置空,防止内存泄漏。最后返回 ctx(成功为合法指针,失败为 OS_NULL)。
os_hwcrypto_ctx_create() 条件走向总结:
os_hwcrypto_ctx_create(device, type, obj_size) 条件走向总结:
├── device == OS_NULL 或 obj_size < sizeof(struct os_hwcrypto_ctx)(参数非法)
│ └── 返回 OS_NULL
├── 参数合法
│ ├── os_calloc(1, obj_size) 失败(内存不足)
│ │ └── 返回 OS_NULL
│ └── 分配成功,memset 清零
│ ├── os_hwcrypto_ctx_init(ctx, device, type) 返回 OS_SUCCESS
│ │ └── 返回 ctx(合法指针)
│ └── os_hwcrypto_ctx_init(ctx, device, type) 返回失败
│ ├── os_free(ctx);ctx = OS_NULL
│ └── 返回 OS_NULL5.2 os_hwcrypto_ctx_init —— 初始化上下文
一句话定位:在已分配的内存上设置类型、绑定设备并创建硬件上下文(供 os_hwcrypto_ctx_create 内部调用,也可用于静态/栈上上下文)。
函数签名:
os_err_t os_hwcrypto_ctx_init(struct os_hwcrypto_ctx *ctx, struct os_hwcrypto_device *device, hwcrypto_type type);参数/返回值:
| 参数 | 说明 |
|---|---|
ctx | 待初始化的上下文(必须已分配内存,本函数不分配) |
device | 绑定的硬件加密设备 |
type | 算法类型 |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 初始化成功 |
err(其他) | device->ops->create 创建硬件上下文失败的错误码 |
完整源码(drivers/hwcrypto/hwcrypto.c,与项目一致):
os_err_t os_hwcrypto_ctx_init(struct os_hwcrypto_ctx *ctx, struct os_hwcrypto_device *device, hwcrypto_type type)
{
os_err_t err;
/* Setting context type */
os_hwcrypto_set_type(ctx, type);
ctx->device = device;
/* Create hardware context */
err = ctx->device->ops->create(ctx);
if (err != OS_SUCCESS)
{
return err;
}
return OS_SUCCESS;
}分步详解:
第 1 步:设置上下文类型(无条件执行)
/* Setting context type */
os_hwcrypto_set_type(ctx, type);详细解释:调用 os_hwcrypto_set_type(见 5.4)给 ctx->type 赋算法类型,内部会做主类型兼容性校验。注意:os_hwcrypto_set_type 可能返回失败(如跨主类型切换),但这里忽略其返回值——因为 ctx_create 用的是新分配且已清零的上下文(type 为 HWCRYPTO_TYPE_NULL),set_type 一定会成功。
第 2 步:绑定设备(无条件执行)
ctx->device = device;详细解释:把 device 存入 ctx->device,建立"该上下文属于哪块硬件"的绑定关系,后续 create/destroy/copy/reset 都通过 ctx->device->ops 分发到这块硬件的回调。
第 3 步:创建硬件上下文并判断结果(条件 ops->create 返回值)
/* Create hardware context */
err = ctx->device->ops->create(ctx);
if (err != OS_SUCCESS)
{
return err;
}
return OS_SUCCESS;
}详细解释:调用绑定的设备的 ops->create(ctx),让 HAL 层为 ctx->contex 分配并初始化硬件私有结构。若创建失败,直接返回错误码 err,由上层 ctx_create 负责 os_free 释放。
os_hwcrypto_ctx_init() 条件走向总结:
os_hwcrypto_ctx_init(ctx, device, type) 条件走向总结:
├── os_hwcrypto_set_type(ctx, type) 设类型(忽略返回值)
├── ctx->device = device 绑定设备
├── err = ctx->device->ops->create(ctx) 创建硬件上下文
│ ├── err != OS_SUCCESS(创建失败)
│ │ └── 返回 err
│ └── err == OS_SUCCESS(创建成功)
│ └── 返回 OS_SUCCESS5.3 os_hwcrypto_ctx_destroy —— 销毁上下文
一句话定位:先调 device->ops->destroy 释放硬件上下文,再 os_free 释放内存。
函数签名:
void os_hwcrypto_ctx_destroy(struct os_hwcrypto_ctx *ctx);参数:
| 参数 | 说明 |
|---|---|
ctx | 要销毁的上下文,可传 OS_NULL(幂等,安全) |
完整源码(drivers/hwcrypto/hwcrypto.c,与项目一致):
void os_hwcrypto_ctx_destroy(struct os_hwcrypto_ctx *ctx)
{
if (ctx == OS_NULL)
{
return;
}
/* Destroy hardware context */
if (ctx->device->ops->destroy)
{
ctx->device->ops->destroy(ctx);
}
/* Free the resources */
os_free(ctx);
}分步详解:
第 1 步:判空(条件 ctx == OS_NULL)
if (ctx == OS_NULL)
{
return;
}详细解释:ctx 为空直接返回。这保证 os_hwcrypto_ctx_destroy(OS_NULL) 是安全的(幂等),允许调用方无脑销毁而不必每次都判空。
第 2 步:调用硬件销毁回调(条件 ops->destroy 非空)
/* Destroy hardware context */
if (ctx->device->ops->destroy)
{
ctx->device->ops->destroy(ctx);
}详细解释:调用设备 ops->destroy(ctx),让 HAL 层释放 ctx->contex 占用的硬件资源(如 STM32 CRYP 句柄、中断等)。判空保护:即使某厂商没实现 destroy,也不至于空指针崩溃。
第 3 步:释放上下文内存(无条件执行)
/* Free the resources */
os_free(ctx);
}详细解释:os_free(ctx) 释放 os_hwcrypto_ctx_create 分配的内存。注意:若上下文是静态/栈上创建的(用 os_hwcrypto_ctx_init 而非 create),则不应调用本函数(否则 os_free 非法内存),而应只调 ops->destroy。
os_hwcrypto_ctx_destroy() 条件走向总结:
os_hwcrypto_ctx_destroy(ctx) 条件走向总结:
├── ctx == OS_NULL
│ └── 直接 return(幂等,安全)
└── ctx != OS_NULL
├── ctx->device->ops->destroy 非空
│ └── 调 ops->destroy(ctx) 释放硬件上下文
├── ctx->device->ops->destroy 为空(厂商未实现)
│ └── 跳过销毁回调
└── os_free(ctx) 释放内存5.4 os_hwcrypto_set_type —— 设置上下文类型(含类型校验)
一句话定位:给上下文赋算法类型,但只有主类型一致或原类型为空时才允许,防止硬件上下文与类型错配。
函数签名:
os_err_t os_hwcrypto_set_type(struct os_hwcrypto_ctx *ctx, hwcrypto_type type);参数/返回值:
| 参数 | 说明 |
|---|---|
ctx | 目标上下文(可为空) |
type | 要设置的算法类型 |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 设置成功 |
OS_FAILURE | 主类型不兼容且原类型非空,拒绝设置 |
OS_INVAL | ctx == OS_NULL |
完整源码(drivers/hwcrypto/hwcrypto.c,与项目一致):
os_err_t os_hwcrypto_set_type(struct os_hwcrypto_ctx *ctx, hwcrypto_type type)
{
if (ctx)
{
/* Is it the same category? */
if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == (type & HWCRYPTO_MAIN_TYPE_MASK))
{
ctx->type = type;
return OS_SUCCESS;
}
/* Context is empty type */
else if (ctx->type == HWCRYPTO_TYPE_NULL)
{
ctx->type = type;
return OS_SUCCESS;
}
else
{
return OS_FAILURE;
}
}
return OS_INVAL;
}先理解类型编码 —— hwcrypto_type 的位布局:
hwcrypto_type 是一个 32 位枚举,用位域同时编码"主类型"和"子类型"(见 hwcrypto.h 定义):
32 位 hwcrypto_type:
┌──────────────┬─────────────┬──────────────┬──────────────┐
│ bit31..bit16 │ bit15..bit8 │ bit7..bit4 │ bit3..bit0 │
│ 主类型 │ 子类型 │ 保留 │ 保留 │
│ (MAIN_TYPE) │ (SUB_TYPE) │ │ │
└──────────────┴─────────────┴──────────────┴──────────────┘HWCRYPTO_MAIN_TYPE_MASK = (0xffffUL << 16):只保留高 16 位(主类型)。HWCRYPTO_SUB_TYPE_MASK = (0xffUL << 8):只保留 bit8~15(子类型)。- 例:
HWCRYPTO_TYPE_SHA256 = HWCRYPTO_TYPE_SHA2 | (0x02 << 8)——高 16 位是SHA2,子类型字节是0x02。
分步详解:
第 1 步:判空(条件 ctx == OS_NULL)
if (ctx)
{
/* Is it the same category? */
if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == (type & HWCRYPTO_MAIN_TYPE_MASK))
{
ctx->type = type;
return OS_SUCCESS;
}
/* Context is empty type */
else if (ctx->type == HWCRYPTO_TYPE_NULL)
{
ctx->type = type;
return OS_SUCCESS;
}
else
{
return OS_FAILURE;
}
}
return OS_INVAL;详细解释:ctx 为空则跳过整个 if 块,最终返回 OS_INVAL(参数非法)。ctx 非空时进入 if 块,内部再按主类型/空类型分支判断(见第 2/3/4 步)。
第 2 步:主类型一致 → 允许设置(条件 (ctx->type & MAIN_MASK) == (type & MAIN_MASK))
/* Is it the same category? */
if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == (type & HWCRYPTO_MAIN_TYPE_MASK))
{
ctx->type = type;
return OS_SUCCESS;
}详细解释:用掩码 & 分别取出 ctx->type 和 type 的主类型部分比较。若一致,说明是同一类算法(都是 SHA2、都是 AES……),只切换子类型(如 SHA256→SHA384)是安全的,直接赋值并返回 OS_SUCCESS。为什么允许:同一主类型对应的硬件引擎相同,切换子类型只是参数变化,不会造成硬件上下文错配。
第 3 步:原类型为空 → 允许设置(条件 ctx->type == HWCRYPTO_TYPE_NULL)
/* Context is empty type */
else if (ctx->type == HWCRYPTO_TYPE_NULL)
{
ctx->type = type;
return OS_SUCCESS;
}详细解释:若原类型是 HWCRYPTO_TYPE_NULL(0,尚未设置),则任何类型都可直接设置。这正是 ctx_create 新分配(清零后 type==NULL)后的场景。
第 4 步:跨主类型 → 拒绝(否则分支)
else
{
return OS_FAILURE;
}详细解释:原类型非空、且与原类型主类型不同(如原来是 AES、现在要设 SHA2),返回 OS_FAILURE 拒绝。为什么拒绝:AES 硬件引擎和 SHA2 硬件引擎不同,同一个上下文不可能同时承载两种不同硬件资源,必须避免错配。
数值演算 —— 掩码运算全过程(以 SHA256 → SHA384 切换为例):
| 计算项 | 代入 | 结果 |
|---|---|---|
ctx->type(当前 SHA256) | SHA2高16位 | 0x02<<8 | 0x????0200(高16位=SHA2) |
type(目标 SHA384) | SHA2高16位 | 0x03<<8 | 0x????0300 |
ctx->type & MAIN_MASK | 0x????0200 & 0xffff0000 | SHA2高16位 |
type & MAIN_MASK | 0x????0300 & 0xffff0000 | SHA2高16位 |
| 主类型比较 | SHA2高16位 == SHA2高16位 | 相等 → 允许切换 |
反例(AES → SHA2 切换):
| 计算项 | 代入 | 结果 |
|---|---|---|
ctx->type & MAIN_MASK | AES 主类型 | AES高16位 |
type & MAIN_MASK | SHA2 主类型 | SHA2高16位 |
| 主类型比较 | AES高16位 != SHA2高16位 | 不相等 → 且原类型非空 → 返回 OS_FAILURE |
os_hwcrypto_set_type() 条件走向总结:
os_hwcrypto_set_type(ctx, type) 条件走向总结:
├── ctx == OS_NULL
│ └── 返回 OS_INVAL
└── ctx != OS_NULL
├── (ctx->type & MAIN_MASK) == (type & MAIN_MASK)(主类型一致)
│ ├── ctx->type = type
│ └── 返回 OS_SUCCESS
├── 主类型不一致,但 ctx->type == HWCRYPTO_TYPE_NULL(原类型为空)
│ ├── ctx->type = type
│ └── 返回 OS_SUCCESS
└── 主类型不一致且原类型非空(跨主类型切换)
└── 返回 OS_FAILURE5.5 哈希封装 os_hwcrypto_hash_create / update / finish
哈希模块是 hwcrypto_hash.c 对通用上下文 API 的算法专属封装。它使用框架内部全局设备指针 hwcrypto_hash_device,把"哈希设备"(由 os_hwcrypto_hash_register 注册)封装成应用友好的 create/update/finish 三段式接口。
为什么哈希需要 update + finish 两段:哈希运算天然支持分段输入——
update可以多次调用喂入数据(如分块读取大文件),硬件内部累积状态;全部喂完后finish才输出最终摘要。这样应用不必一次把所有数据都塞进内存。
5.5.1 os_hwcrypto_hash_create —— 创建哈希上下文
函数签名:
struct os_hwcrypto_ctx *os_hwcrypto_hash_create(hwcrypto_type type);参数/返回值:
| 参数 | 说明 |
|---|---|
type | 哈希类型(HWCRYPTO_TYPE_MD5/SHA1/SHA224/SHA256/SHA384/SHA512) |
| 返回值 | 说明 |
|---|---|
OS_NULL | 无哈希设备 / 创建失败 |
| 其他 | 哈希上下文(实为 hwcrypto_hash 对象) |
完整源码(drivers/hwcrypto/hw_hash.c,与项目一致):
struct os_hwcrypto_ctx *os_hwcrypto_hash_create(hwcrypto_type type)
{
struct os_hwcrypto_ctx *ctx;
if (hwcrypto_hash_device == OS_NULL)
return OS_NULL;
ctx = os_hwcrypto_ctx_create(hwcrypto_hash_device, type, sizeof(struct hwcrypto_hash));
return ctx;
}分步详解:
第 1 步:无哈希设备则返回空(条件 hwcrypto_hash_device == OS_NULL)
if (hwcrypto_hash_device == OS_NULL)
return OS_NULL;详细解释:hwcrypto_hash_device 是 hw_hash.c 里的文件级静态全局变量(static struct os_hwcrypto_device *hwcrypto_hash_device = OS_NULL;),由 os_hwcrypto_hash_register 在系统启动时赋值。若未注册哈希设备就调用本函数,直接返回 OS_NULL,防止后续访问空设备。
第 2 步:通过通用接口创建派生对象(无条件执行)
ctx = os_hwcrypto_ctx_create(hwcrypto_hash_device, type, sizeof(struct hwcrypto_hash));
return ctx;
}详细解释:调用通用 os_hwcrypto_ctx_create(见 5.1),device 传全局哈希设备、type 传哈希类型,obj_size 传 sizeof(struct hwcrypto_hash)(比基类 os_hwcrypto_ctx 大,因为多了 ops 指针)。返回的对象实际是 hwcrypto_hash,但以 os_hwcrypto_ctx* 返回。
os_hwcrypto_hash_create() 条件走向总结:
os_hwcrypto_hash_create(type) 条件走向总结:
├── hwcrypto_hash_device == OS_NULL(未注册哈希设备)
│ └── 返回 OS_NULL
└── hwcrypto_hash_device != OS_NULL
└── os_hwcrypto_ctx_create(device, type, sizeof(hwcrypto_hash)) → 返回结果5.5.2 os_hwcrypto_hash_update —— 喂入一段数据
函数签名:
os_err_t os_hwcrypto_hash_update(struct os_hwcrypto_ctx *ctx, const uint8_t *input, os_size_t length);参数/返回值:
| 参数 | 说明 |
|---|---|
ctx | 哈希上下文 |
input | 要参与哈希的数据缓冲区 |
length | 数据长度(字节) |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 处理成功 |
OS_FAILURE | ctx 为空或 ops->update 未实现 |
完整源码(drivers/hwcrypto/hw_hash.c,与项目一致):
os_err_t os_hwcrypto_hash_update(struct os_hwcrypto_ctx *ctx, const uint8_t *input, os_size_t length)
{
if (ctx && ((struct hwcrypto_hash *)ctx)->ops->update)
{
return ((struct hwcrypto_hash *)ctx)->ops->update((struct hwcrypto_hash *)ctx, input, length);
}
return OS_FAILURE;
}分步详解:
第 1 步:判断 ctx 与 update 回调(条件 ctx 非空且 ops->update 非空)
if (ctx && ((struct hwcrypto_hash *)ctx)->ops->update)
{
return ((struct hwcrypto_hash *)ctx)->ops->update((struct hwcrypto_hash *)ctx, input, length);
}
return OS_FAILURE;
}详细解释:关键理解 —— C 语言继承多态:ctx 是 os_hwcrypto_ctx*,但实际对象是 hwcrypto_hash(首成员继承 os_hwcrypto_ctx,之后紧跟 ops)。把 ctx 强转为 hwcrypto_hash* 就能访问到哈希专属的 ops->update。为何能强转:因为 hwcrypto_hash 第一个成员就是 os_hwcrypto_ctx,其地址与 hwcrypto_hash 地址相等(见 3.4)。若 ctx 为空或 ops->update 未实现,返回 OS_FAILURE。
os_hwcrypto_hash_update() 条件走向总结:
os_hwcrypto_hash_update(ctx, input, length) 条件走向总结:
├── ctx != OS_NULL 且 ((hwcrypto_hash*)ctx)->ops->update 非空
│ └── 返回 ops->update((hwcrypto_hash*)ctx, input, length) 的结果
└── ctx == OS_NULL 或 ops->update 为空
└── 返回 OS_FAILURE5.5.3 os_hwcrypto_hash_finish —— 取最终哈希值
函数签名:
os_err_t os_hwcrypto_hash_finish(struct os_hwcrypto_ctx *ctx, uint8_t *output, os_size_t length);参数/返回值:
| 参数 | 说明 |
|---|---|
ctx | 哈希上下文 |
output | 输出缓冲区(写最终摘要,如 SHA256 需 32 字节) |
length | 输出缓冲区大小 |
| 返回值 | 说明 |
|---|---|
OS_SUCCESS | 计算完成并写出摘要 |
OS_FAILURE | ctx 为空或 ops->finish 未实现 |
完整源码(drivers/hwcrypto/hw_hash.c,与项目一致):
os_err_t os_hwcrypto_hash_finish(struct os_hwcrypto_ctx *ctx, uint8_t *output, os_size_t length)
{
if (ctx && ((struct hwcrypto_hash *)ctx)->ops->finish)
{
return ((struct hwcrypto_hash *)ctx)->ops->finish((struct hwcrypto_hash *)ctx, output, length);
}
return OS_FAILURE;
}分步详解:
第 1 步:判断 ctx 与 finish 回调(条件 ctx 非空且 ops->finish 非空)
if (ctx && ((struct hwcrypto_hash *)ctx)->ops->finish)
{
return ((struct hwcrypto_hash *)ctx)->ops->finish((struct hwcrypto_hash *)ctx, output, length);
}
return OS_FAILURE;
}详细解释:与 update 同理:强转 ctx 为 hwcrypto_hash* 后调 ops->finish(ctx, output, length),让硬件输出最终哈希摘要到 output。注意 length 是输出缓冲区容量,output 必须足够大(SHA256→32、SHA1→20、MD5→16),否则 HAL 层写入越界。
os_hwcrypto_hash_finish() 条件走向总结:
os_hwcrypto_hash_finish(ctx, output, length) 条件走向总结:
├── ctx != OS_NULL 且 ((hwcrypto_hash*)ctx)->ops->finish 非空
│ └── 返回 ops->finish((hwcrypto_hash*)ctx, output, length) 的结果
└── ctx == OS_NULL 或 ops->finish 为空
└── 返回 OS_FAILURE六、代码示例
6.1 SHA256 哈希计算
#include <oneos_config.h>
#include <hwcrypto/hwcrypto.h>
#include <hwcrypto/hw_hash.h>
void sha256_example(void)
{
struct os_hwcrypto_ctx *ctx;
uint8_t input[] = "Hello OneOS HWCrypto!";
uint8_t output[32]; /* SHA256 输出 32 字节 */
int i;
os_err_t ret;
/* 创建 SHA256 哈希上下文 */
ctx = os_hwcrypto_hash_create(HWCRYPTO_TYPE_SHA256);
if (ctx == OS_NULL)
{
os_kprintf("SHA256 context create failed!\r\n");
return;
}
/* 更新数据(喂入待哈希数据) */
ret = os_hwcrypto_hash_update(ctx, input, sizeof(input) - 1);
if (ret != OS_SUCCESS)
{
os_kprintf("SHA256 update failed, ret=%d\r\n", ret);
os_hwcrypto_hash_destroy(ctx);
return;
}
/* 完成计算(输出 32 字节摘要) */
ret = os_hwcrypto_hash_finish(ctx, output, sizeof(output));
if (ret != OS_SUCCESS)
{
os_kprintf("SHA256 finish failed, ret=%d\r\n", ret);
os_hwcrypto_hash_destroy(ctx);
return;
}
/* 输出结果 */
os_kprintf("SHA256(\"%s\") = ", input);
for (i = 0; i < 32; i++)
os_kprintf("%02x", output[i]);
os_kprintf("\r\n");
/* 销毁上下文 */
os_hwcrypto_hash_destroy(ctx);
}6.2 分段哈希计算
void sha256_stream_example(void)
{
struct os_hwcrypto_ctx *ctx;
uint8_t output[32];
uint8_t chunk1[] = "Hello ";
uint8_t chunk2[] = "OneOS ";
uint8_t chunk3[] = "World!";
os_err_t ret;
ctx = os_hwcrypto_hash_create(HWCRYPTO_TYPE_SHA256);
if (ctx == OS_NULL)
{
os_kprintf("SHA256 context create failed!\r\n");
return;
}
/* 分多次输入数据(顺序至关重要,影响最终摘要) */
ret = os_hwcrypto_hash_update(ctx, chunk1, sizeof(chunk1) - 1);
if (ret != OS_SUCCESS)
{
os_kprintf("update chunk1 failed, ret=%d\r\n", ret);
os_hwcrypto_hash_destroy(ctx);
return;
}
ret = os_hwcrypto_hash_update(ctx, chunk2, sizeof(chunk2) - 1);
if (ret != OS_SUCCESS)
{
os_kprintf("update chunk2 failed, ret=%d\r\n", ret);
os_hwcrypto_hash_destroy(ctx);
return;
}
ret = os_hwcrypto_hash_update(ctx, chunk3, sizeof(chunk3) - 1);
if (ret != OS_SUCCESS)
{
os_kprintf("update chunk3 failed, ret=%d\r\n", ret);
os_hwcrypto_hash_destroy(ctx);
return;
}
/* 最终完成计算 */
ret = os_hwcrypto_hash_finish(ctx, output, sizeof(output));
if (ret != OS_SUCCESS)
{
os_kprintf("SHA256 finish failed, ret=%d\r\n", ret);
os_hwcrypto_hash_destroy(ctx);
return;
}
os_hwcrypto_hash_destroy(ctx);
}6.3 MD5 哈希计算
void md5_example(void)
{
struct os_hwcrypto_ctx *ctx;
uint8_t input[] = "test data for MD5";
uint8_t output[16]; /* MD5 输出 16 字节 */
os_err_t ret;
int i;
ctx = os_hwcrypto_hash_create(HWCRYPTO_TYPE_MD5);
if (ctx == OS_NULL)
{
os_kprintf("MD5 context create failed!\r\n");
return;
}
ret = os_hwcrypto_hash_update(ctx, input, sizeof(input) - 1);
if (ret != OS_SUCCESS)
{
os_kprintf("MD5 update failed, ret=%d\r\n", ret);
os_hwcrypto_hash_destroy(ctx);
return;
}
ret = os_hwcrypto_hash_finish(ctx, output, sizeof(output));
if (ret != OS_SUCCESS)
{
os_kprintf("MD5 finish failed, ret=%d\r\n", ret);
os_hwcrypto_hash_destroy(ctx);
return;
}
os_kprintf("MD5: ");
for (i = 0; i < 16; i++) os_kprintf("%02x", output[i]);
os_kprintf("\r\n");
os_hwcrypto_hash_destroy(ctx);
}6.4 硬件随机数生成
先纠正一个常见误解:RNG 接口不是一次生成一整个字节数组。
hwcrypto_rng_ops只有一个回调update,每次返回一个uint32_t随机数(见hw_rng.h)。因此生成 N 字节随机数据需要循环调用,把每次的 32 位随机数拆成字节。
推荐用法:直接用 os_hwcrypto_rng_update()。RNG 设备在注册时(os_hwcrypto_rng_register)框架会自动创建默认上下文 ctx_default,应用无需自行管理设备,拿随机数最方便:
#include <oneos_config.h>
#include <hwcrypto/hw_rng.h>
void rng_example(void)
{
uint8_t random_data[32];
uint32_t word;
int i;
int j;
/* 循环调用 os_hwcrypto_rng_update() 生成 32 字节随机数
* 每次返回 1 个 uint32_t(4 字节),共需 8 次 */
for (i = 0; i < 32; i += 4)
{
word = os_hwcrypto_rng_update();
random_data[i + 0] = (uint8_t)(word & 0xff);
random_data[i + 1] = (uint8_t)((word >> 8) & 0xff);
random_data[i + 2] = (uint8_t)((word >> 16) & 0xff);
random_data[i + 3] = (uint8_t)((word >> 24) & 0xff);
}
os_kprintf("Random (%d bytes): ", sizeof(random_data));
for (j = 0; j < 32; j++) os_kprintf("%02x", random_data[j]);
os_kprintf("\r\n");
}另一种用法 —— 自定义上下文 + os_hwcrypto_rng_update_ctx(ctx):
若你需要用自定义 RNG 上下文(例如为每个加密会话单独建 ctx),可先通过 os_hwcrypto_ctx_create 创建 RNG 上下文,再传入 os_hwcrypto_rng_update_ctx:
#include <oneos_config.h>
#include <hwcrypto/hwcrypto.h>
#include <hwcrypto/hw_rng.h>
void rng_ctx_example(void)
{
/* 通过设备框架查找 RNG 设备(具体设备名以板级注册为准) */
struct os_hwcrypto_device *rng_dev =
(struct os_hwcrypto_device *)os_device_find("rng");
struct os_hwcrypto_ctx *ctx;
uint32_t value;
if (rng_dev == OS_NULL)
{
os_kprintf("rng device not found\r\n");
return;
}
/* 创建 RNG 上下文(obj_size 用派生结构体大小) */
ctx = os_hwcrypto_ctx_create(rng_dev, HWCRYPTO_TYPE_RNG, sizeof(struct hwcrypto_rng));
if (ctx == OS_NULL)
{
os_kprintf("rng ctx create failed\r\n");
return;
}
/* 取一个 32 位随机数(0 可能表示失败,需判断) */
value = os_hwcrypto_rng_update_ctx(ctx);
if (value == 0)
{
os_kprintf("rng update failed\r\n");
}
else
{
os_kprintf("Random value = 0x%08x\r\n", value);
}
/* 销毁上下文(返回 void,无需检查) */
os_hwcrypto_ctx_destroy(ctx);
}注意:
os_hwcrypto_rng_update_ctx返回0既可能表示"随机数恰好为 0",也可能是"取数失败"(hw_rng.c中ctx为空返回0)。对于安全敏感场景,应配合硬件状态寄存器二次确认。
七、HWCrypto 的适配(接入硬件加密引擎)
7.1 先认识适配层:HWCrypto 是怎么"长"到芯片上的
drivers/hwcrypto/ 下是跨平台统一的框架层(只管理上下文、类型、算法分发),不碰具体寄存器。真正操作硬件加密引擎的是各厂商 HAL 驱动,例如 ST 的 drivers/hal/st/drivers/drv_crypto_rng.c、drv_crypto_crc.c。一个算法类型对应一个厂商驱动文件,通过注册把自己挂进框架。
适配全景图:
┌──────────────────────────────────────────────────────────┐
│ 应用层(Application) │
│ os_hwcrypto_hash_create/update/finish、symmetric_crypt │
└──────────────────────────────┬───────────────────────────┘
▼
┌──────────────────────────────────────────────────────────┐
│ HWCrypto 框架层(drivers/hwcrypto/) │
│ os_hwcrypto_ctx_* / hash_* / symmetric_* / rng_* │
│ 管理上下文生命周期、类型校验、算法分发(不改) │
└──────────────────────────────┬───────────────────────────┘
│ ① 实现 os_hwcrypto_ops(create/destroy/copy/reset)
│ ② 实现算法专属 ops(如 hwcrypto_rng_ops.update)
▼
┌──────────────────────────────────────────────────────────┐
│ 厂商驱动适配层(drv_crypto_rng.c 等)★需实现★ │
│ 实现回调 + OS_DRIVER_INFO/probe 注册 │
└──────────────────────────────┬───────────────────────────┘
│ HAL 库(HAL_RNG_* / HAL_CRYP_* / HAL_HASH_*)
▼
┌──────────────────────────────────────────────────────────┐
│ 硬件(MCU 的 RNG / CRYP / HASH / CRC 外设) │
└──────────────────────────────────────────────────────────┘适配的关键洞察:接入一个新算法的硬件引擎,要做两件事:① 给 os_hwcrypto_ops 实现 create/destroy/copy/reset(管上下文生命周期);② 给算法专属 ops(如 hwcrypto_rng_ops)实现具体运算回调。框架层不用改。
7.2 以 ST RNG 为例,看一整套适配代码
以 drivers/hal/st/drivers/drv_crypto_rng.c 为例(与项目逐字一致,去除无关的空行后展示关键结构):
① 实现算法专属运算回调 —— hwcrypto_rng_ops.update:
static uint32_t stm32_rng_rand(struct hwcrypto_rng *ctx)
{
uint32_t gen_random = 0;
RNG_HandleTypeDef *HW_TypeDef = (RNG_HandleTypeDef *)(ctx->parent.contex);
struct stm32_hwcrypto_device *stm32_hw_dev = (struct stm32_hwcrypto_device *)ctx->parent.device->user_data;
os_mutex_lock(stm32_hw_dev->mutex, OS_WAIT_FOREVER);
if (HAL_RNG_GenerateRandomNumber(HW_TypeDef, &gen_random) != HAL_OK)
{
gen_random = 0;
}
os_mutex_unlock(stm32_hw_dev->mutex);
return gen_random;
}
static const struct hwcrypto_rng_ops rng_ops = {
.update = stm32_rng_rand,
};要点:
ctx->parent.contex(基类os_hwcrypto_ctx的contex字段)存的是 HAL 句柄RNG_HandleTypeDef*;ctx->parent.device->user_data是厂商私有设备结构(含互斥锁,保护 RNG 硬件并发访问)。
② 实现通用上下文回调 —— os_hwcrypto_ops:
static os_err_t stm32_rng_crypto_create(struct os_hwcrypto_ctx *ctx)
{
struct stm32_hwcrypto_device *stm32_hw_dev = (struct stm32_hwcrypto_device *)ctx->device->user_data;
RNG_HandleTypeDef *hrng = (RNG_HandleTypeDef *)stm32_hw_dev->handle;
OS_ASSERT(hrng != OS_NULL);
if (HAL_RNG_Init(hrng) != HAL_OK)
return OS_FAILURE;
ctx->contex = hrng;
((struct hwcrypto_rng *)ctx)->ops = &rng_ops;
return OS_SUCCESS;
}
static const struct os_hwcrypto_ops _ops = {
.create = stm32_rng_crypto_create,
.destroy = stm32_rng_crypto_destroy,
.copy = stm32_rng_crypto_clone,
.reset = stm32_rng_crypto_reset,
};要点:
create里调用 HAL 初始化硬件,把句柄存入ctx->contex,并给派生对象hwcrypto_rng的ops挂上rng_ops。这样应用调os_hwcrypto_rng_update_ctx(ctx)时,框架就能经ops->update走到stm32_rng_rand。
③ 通过驱动框架注册设备(OS_DRIVER_INFO + probe):
static int stm32_rng_probe(const os_driver_info_t *drv, const os_device_info_t *dev)
{
struct stm32_hwcrypto_device *st_hwcrypto = os_calloc(1, sizeof(struct stm32_hwcrypto_device));
OS_ASSERT(st_hwcrypto);
struct os_hwcrypto_device *hwcrypto = &st_hwcrypto->hwcrypto;
st_hwcrypto->handle = (void *)dev->info;
hwcrypto->ops = &_ops;
hwcrypto->id = stm32_hwcrypto_uid();
hwcrypto->user_data = hwcrypto;
if (os_hwcrypto_rng_register(hwcrypto, dev->name) != OS_SUCCESS)
{
os_kprintf("stm32 rng probe failed %s.\r\n", dev->name);
os_free(st_hwcrypto);
return -1;
}
st_hwcrypto->mutex = os_mutex_create(OS_NULL, OS_HWCRYPTO_DEFAULT_NAME, OS_FALSE);
return 0;
}
OS_DRIVER_INFO stm32_rng_driver = {
.name = "RNG_HandleTypeDef",
.probe = stm32_rng_probe,
};
OS_DRIVER_DEFINE(stm32_rng_driver, OS_INIT_LEVEL_DEVICE, OS_INIT_SUBLEVEL_MIDDLE);要点:
OS_DRIVER_INFO用"RNG_HandleTypeDef"作为匹配名,probe函数在板级配置表中找到对应硬件实例(dev->info指向hrng)后被调用,完成设备创建、ops 绑定、os_hwcrypto_rng_register注册。
7.3 接口契约:接入 HWCrypto 需要实现什么
| 层 | 接口 | 职责 | 对应 7.2 ST 代码 |
|---|---|---|---|
| 算法专属 ops | hwcrypto_rng_ops.update | 真正从硬件取一个随机数 | stm32_rng_rand |
| 通用上下文 ops | os_hwcrypto_ops.create | 初始化硬件、建 contex、挂算法 ops | stm32_rng_crypto_create |
| 通用上下文 ops | os_hwcrypto_ops.destroy | 释放硬件资源 | stm32_rng_crypto_destroy |
| 通用上下文 ops | os_hwcrypto_ops.copy | 复制硬件上下文 | stm32_rng_crypto_clone |
| 通用上下文 ops | os_hwcrypto_ops.reset | 重置硬件状态 | stm32_rng_crypto_reset |
| 驱动注册 | OS_DRIVER_INFO + probe + os_hwcrypto_*_register | 把设备挂进框架 | stm32_rng_probe |
7.4 接入新算法/新芯片的标准流程
第 1 步:确认框架是否已支持该算法——查 drivers/hwcrypto/ 下是否有对应 hw_xxx.c/h(hash/symmetric/rng/crc/bignum/gcm)。若没有,说明框架层未抽象该算法,需先扩展框架(一般不需要,常用算法都已覆盖)。
第 2 步:实现通用 os_hwcrypto_ops——为你的芯片实现 create/destroy/copy/reset,create 里初始化硬件句柄并挂算法 ops。
第 3 步:实现算法专属 ops——如 RNG 实现 hwcrypto_rng_ops.update、哈希实现 hwcrypto_hash_ops.update/finish、对称加密实现 hwcrypto_symmetric_ops.crypt。
第 4 步:写 probe 并注册——用 OS_DRIVER_INFO(name 匹配 HAL 句柄类型)+ probe 函数创建设备、调用对应的 os_hwcrypto_*_register 注册,用 OS_DRIVER_DEFINE 指定初始化层级。
第 5 步:板级配置表中加入硬件实例——在 board/peripherals.c(或 devices.c)用 OS_HAL_DEVICE_DEFINE("RNG_HandleTypeDef", "rng", hrng) 之类把 HAL 句柄实例化,probe 时 dev->info 就能取到它。
7.5 适配检查清单(快速自查)
| 检查项 | 说明 |
|---|---|
create 是否把硬件句柄正确存入 ctx->contex? | 否则算法 ops 里 (类型*)ctx->parent.contex 取到空/错地址 |
create 是否给派生对象挂上算法 ops? | 否则 update/finish 判空返回 OS_FAILURE |
os_hwcrypto_ops 四个回调是否都实现? | os_hwcrypto_register 有断言,缺一个会触发 OS_ASSERT |
| 多任务并发是否加锁? | RNG/CRYP 硬件是共享外设,如 ST 用 os_mutex 保护 |
板级配置是否匹配 OS_DRIVER_INFO.name? | 不匹配则 probe 不会被触发,设备注册不上 |
是否需要 user_data 存厂商私有数据? | 如互斥锁、句柄等,可放 os_hwcrypto_device.user_data |
八、注意事项
- 硬件依赖:HWCrypto 依赖 MCU 硬件加密引擎,软件模拟场景下应使用 MBED TLS / OneTLS
- 上下文大小:
os_hwcrypto_ctx_create的obj_size必须至少为sizeof(struct os_hwcrypto_ctx) - 类型兼容性:复制上下文时,源和目标必须是相同的设备和相同的主类型
- 中断安全:加密运算可能在中断上下文中进行,HAL 层需确保操作不阻塞
- 与软件加密配合:HWCrypto 可与 MBED TLS 配合,通过
MBEDTLS_AES_ALT等宏启用硬件加速 - RNG 接口语义:
os_hwcrypto_rng_update_ctx/os_hwcrypto_rng_update每次返回一个uint32_t,不是一次生成字节数组;生成 N 字节需循环调用
📝 本节小结
核心要点回顾
本节围绕 HWCrypto 设备展开,核心要点如下:
- 硬件加密抽象层:HWCrypto 是 OneOS 利用 MCU 硬件加密引擎加速运算的抽象层,框架层在
drivers/hwcrypto/,厂商适配在drivers/hal/*/drivers/drv_crypto_*。 - 支持的算法:AES/DES/3DES/RC4/GCM 对称加密、MD5/SHA1/SHA2 哈希、RNG/CRC/BIGNUM 等,每种算法都有"主类型 + 子类型"的位域编码。
- 继承 + 多态模型:
os_hwcrypto_ctx是基类,hwcrypto_hash/hwcrypto_symmetric/hwcrypto_rng等通过首成员继承派生;把基类指针强转回派生指针即可访问算法专属 ops,实现 C 语言多态。 - 上下文管理:
os_hwcrypto_ctx_create(参数校验 → 分配 → 初始化)→destroy(销毁硬件 → 释放内存),copy/reset支持快照与复用;os_hwcrypto_set_type用主类型掩码做兼容性校验。 - 哈希分段输入:哈希用
update(多次喂数据)+finish(输出摘要)两段式,支持分段输入大块数据。 - 类型兼容校验:
HWCRYPTO_MAIN_TYPE_MASK只比较主类型,主类型一致或原类型为空才允许切换,跨主类型拒绝。 - RNG 接口语义:
os_hwcrypto_rng_update_ctx/os_hwcrypto_rng_update每次返回一个uint32_t,生成 N 字节需循环调用。 - 硬件适配:接入硬件引擎 = 实现
os_hwcrypto_ops(create/destroy/copy/reset)+ 算法专属 ops + 用OS_DRIVER_INFO/probe 注册。
关键易错点速查
| 易错点 | 正确做法 |
|---|---|
| 用完上下文不销毁 | 加密/哈希结束应销毁 os_hwcrypto_ctx,避免资源泄漏 |
| 忽略哈希分段输入的顺序 | update 多次调用必须按顺序,finish 前不能中途读取结果 |
obj_size 传太小 | os_hwcrypto_ctx_create 的 obj_size 必须 ≥ sizeof(struct os_hwcrypto_ctx),派生对象传派生结构体大小 |
| 依赖硬件不支持的模式 | 不同 MCU 的加密引擎支持的模式不同,使用前需确认硬件能力 |
| 把 HWCrypto 当纯软件实现 | HWCrypto 依赖硬件引擎,芯片不支持时需回退软件加密(如 Mbed TLS) |
| 跨主类型切换上下文 | os_hwcrypto_set_type 只允许主类型一致或原类型为空的切换,跨主类型返回 OS_FAILURE |
| 混淆 RNG 接口 | RNG 每次返回一个 uint32_t,不是一次生成字节数组;循环调用拼接 |
ctx 是静态/栈上创建却调 ctx_destroy | 静态/栈上上下文只能用 ctx_init + ops->destroy,不能 os_free;os_hwcrypto_ctx_destroy 只用于 ctx_create 分配的对象 |
适配时漏实现 os_hwcrypto_ops 某回调 | os_hwcrypto_register 对 create/destroy/copy/reset 都有 OS_ASSERT,缺一个会断言失败 |
下一步
掌握了 HWCrypto 硬件加密设备后,接下来学习 LPMGR 低功耗管理:
- 5.15 LPMGR设备:了解 OneOS 的多级睡眠模式、外设挂起/恢复与 Tickless 机制。