- 物联网
- 嵌入式
- 操作系统
- 实时系统
【免费下载链接】RIOT
RIOT - The friendly OS for IoT
本文聚焦 RIOT 操作系统中 tests/sys/psa_crypto_mac 测试:它是对 PSA Crypto 模块MAC 部分的专项配置测试,验证在最小化模块裁剪(仅启用 MAC、不引入对称加密与签名等无关组件)的前提下,HMAC SHA-256 计算能否正确运行。读完本文,你将掌握该测试的目录结构、构建配置、模块依赖链与后端自动选择机制,理解psa_mac_compute()的底层调用链,并学会如何在自己的 RIOT 应用中裁剪出最小可用的 PSA MAC 配置。
测试定位:为什么需要一份"仅 MAC"的配置测试
PSA Crypto 是 Arm 提出的跨厂商密码学 API 规范,RIOT 在 sys/psa_crypto 中提供了完整实现,涵盖对称加密(cipher)、消息认证码(MAC)、哈希(hash)、非对称签名(asymmetric)与密钥管理(key management)等能力。模块数量众多,每个能力又对应若干伪模块与可选后端。
examples/advanced/psa_crypto 是展示 PSA Crypto API 用法的综合示例(AES 128 CBC、HMAC SHA-256、ECDSA P256、EdDSA Ed25519 四种操作一应俱全),但综合示例无法回答一个问题:当只启用 MAC 功能、其他全部裁剪时,配置是否正确、依赖是否自洽。这正是tests/sys/psa_crypto_mac存在的意义——README 开宗明义:
This is a configuration test for only the mac of the PSA crypto module. It is based off the psa_crypto example.
因此,该测试目录中的 Makefile 只引入psa_crypto、psa_mac、psa_mac_hmac_sha_256三个模块,测试程序也仅执行 HMAC SHA-256 一次运算,以此验证模块裁剪后构建、链接、运行全流程的正确性。
测试目录结构一览
tests/sys/psa_crypto_mac/ ├── Makefile # 模块选择与编译参数 ├── Makefile.ci # 内存不足、不参与 CI 的板子清单 ├── README.md # 测试说明(本文关联文档) ├── example_hmac_sha256.c # HMAC SHA-256 计算逻辑(源自 psa_crypto 示例) ├── main.c # 测试入口:计时执行并检查返回值 └── tests/ └── 01-run.py # testrunner 脚本:断言串口输出 "All Done"构建配置逐行解析:三个模块与一个编译参数
Makefile 是整个测试的核心配置,内容如下:
include ../Makefile.sys_common USEMODULE += ztimer USEMODULE += ztimer_usec USEMODULE += psa_crypto USEMODULE += psa_mac USEMODULE += psa_mac_hmac_sha_256 CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=1 include $(RIOTBASE)/Makefile.include逐项解读:
USEMODULE += psa_crypto:启用 PSA Crypto 实现本体。在 Makefile.dep 中,它会自动引入random与prng_sha256prng作为随机数依赖。USEMODULE += psa_mac:启用 MAC 功能。依赖解析见 sys/psa_crypto/Makefile.dep:psa_mac会进一步引入psa_key_management,因为 MAC 计算必须先从密钥槽获取密钥材料。USEMODULE += psa_mac_hmac_sha_256:声明具体算法(HMAC SHA-256)。依赖解析见 sys/psa_crypto/Makefile.dep:它会自动引入psa_hash与psa_hash_sha_256(注释说明"超过一个 SHA-256 分组长度的密钥需要先做哈希"),并根据目标平台特性自动选择一个后端。CFLAGS += -DCONFIG_PSA_SINGLE_KEY_COUNT=1:将单密钥槽数量配置为 1。这个值决定了 psa_crypto_slot_management.h 中的PSA_SINGLE_KEY_COUNT,进而决定PSA_KEY_SLOT_COUNT = PSA_PROTECTED_KEY_COUNT + PSA_ASYMMETRIC_KEYPAIR_COUNT + PSA_SINGLE_KEY_COUNT。测试程序同时导入 32 字节和 128 字节两把 HMAC 密钥,但两者串行使用、先psa_destroy_key再导入,所以单槽配置足以覆盖。这是对"配置测试"身份的又一次印证:显式压到最小资源占用。
后端自动选择:periph 硬件加速还是 RIOT 软件哈希
RIOT 的 PSA 实现允许同一算法由不同后端提供(板载外设、软件库、安全元件),并在 sys/psa_crypto/Makefile.include 中把psa_mac_hmac_sha_256及其三个后端声明为伪模块,且强制同一时刻只能选择一个后端:
## MAC PSEUDOMODULES += psa_mac PSEUDOMODULES += psa_mac_hmac_sha_256 PSEUDOMODULES += psa_mac_hmac_sha_256_backend_periph PSEUDOMODULES += psa_mac_hmac_sha_256_backend_riot PSEUDOMODULES += psa_mac_hmac_sha_256_custom_backend # check that one and only one backend has been selected ifneq (,$(filter psa_mac_hmac_sha_256,$(USEMODULE))) ifneq (1,$(call backends,psa_mac_hmac_sha_256)) $(error "One (and only one) backend should be selected for psa_mac_hmac_sha_256") endif endif选哪个后端,取决于目标板卡是否具备periph_hmac_sha_256特性。依赖解析在 Makefile.dep 中完成:
## HMAC SHA-256 ifneq (,$(filter psa_mac_hmac_sha_256,$(USEMODULE))) USEMODULE += psa_hash USEMODULE += psa_hash_sha_256 ifeq (,$(filter psa_mac_hmac_sha_256_custom_backend,$(USEMODULE))) FEATURES_OPTIONAL += periph_hmac_sha_256 include $(RIOTMAKE)/features_check.inc.mk ifneq (,$(filter periph_hmac_sha_256,$(FEATURES_USED))) USEMODULE += psa_mac_hmac_sha_256_backend_periph else USEMODULE += psa_mac_hmac_sha_256_backend_riot endif endif endif- 目标板具备
periph_hmac_sha_256特性(例如 nRF52840 的 CryptoCell 310 加速器),自动选择psa_mac_hmac_sha_256_backend_periph,并追加FEATURES_REQUIRED += periph_hmac_sha_256; - 否则回退到
psa_mac_hmac_sha_256_backend_riot,该后端依赖hashes、psa_riot_hashes、psa_riot_hashes_hmac_sha256,即 RIOT 自带的软件哈希实现(Makefile.dep); - 应用也可以通过显式声明
psa_mac_hmac_sha_256_custom_backend跳过自动选择,改用自定义后端(如安全元件)。
用native板构建时,native不具备periph_hmac_sha_256,因此会走 RIOT 软件哈希路径;用BOARD=nrf52840dk构建时则会自动接入 CryptoCell 310 硬件加速。上游示例 examples/advanced/psa_crypto/README.md 给出了同一块 nRF52840dk 上不同后端的 HMAC SHA-256 耗时对比(CryptoCell 310 约 282 µs、RIOT 软件哈希约 468 µs、ATECC608A 安全元件约 56376 µs),供读者直观理解后端差异。
测试程序走读:计时 + 状态断言
入口 main.c
main.c 使用 RIOT 的ztimer对 HMAC 计算计时,并检查返回值:
#include <stdio.h> #include "psa/crypto.h" #include "ztimer.h" extern psa_status_t example_hmac_sha256(void); int main(void) { bool failed = false; psa_status_t status; ztimer_acquire(ZTIMER_USEC); ztimer_now_t start = ztimer_now(ZTIMER_USEC); status = example_hmac_sha256(); printf("HMAC SHA256 took %d us\n", (int)(ztimer_now(ZTIMER_USEC) - start)); if (status != PSA_SUCCESS) { failed = true; printf("HMAC SHA256 failed: %s\n", psa_status_to_humanly_readable(status)); } ztimer_release(ZTIMER_USEC); if (failed) { puts("Tests failed..."); } else { puts("All Done"); } return 0; }关键点:
- 程序没有显式调用
psa_crypto_init()。RIOT 的 PSA 实现通过自动初始化机制完成库初始化(psa_crypto.c 中的psa_crypto_init()负责初始化密钥槽并置位lib_initialized;若未初始化,psa_mac_compute()会直接返回PSA_ERROR_BAD_STATE)。 - 若返回码非
PSA_SUCCESS,通过psa_status_to_humanly_readable()打印可读的错误名(同一函数在 psa_crypto.c 中把错误码映射为字符串)。 - 通过
ztimer打印耗时,作为后端差异的实测佐证——这继承了上游示例"测量处理时间"的做法。
HMAC SHA-256 计算逻辑
example_hmac_sha256.c 头注释明确说明内容复制自examples/advanced/psa_crypto。它依次演示了 PSA Crypto MAC 的完整用法:
- 初始化密钥属性:
psa_key_attributes_init()后,依次设置算法PSA_ALG_HMAC(PSA_ALG_SHA_256)、用途PSA_KEY_USAGE_SIGN_MESSAGE、位长PSA_BYTES_TO_BITS(HMAC_KEY_LEN)与类型PSA_KEY_TYPE_HMAC; - 按输出长度分配摘要缓冲:
PSA_MAC_LENGTH(PSA_KEY_TYPE_HMAC, HMAC_KEY_LEN, PSA_ALG_HMAC(PSA_ALG_SHA_256)); - 导入 32 字节密钥(标准 RFC 4231 测试向量
0x0b重复 32 次)并调用psa_mac_compute()一次性完成 HMAC 计算; - 销毁密钥:
psa_destroy_key(key_id); - 导入 128 字节长密钥并再次
psa_mac_compute(),验证超过 SHA-256 分组长度(64 字节)的密钥路径(这正是 Makefile.dep 中"长密钥需要先哈希"注释对应的代码路径); - 全程若任一步返回非
PSA_SUCCESS即提前返回。
值得注意的细节:源码注释指出"某些 PSA 后端要求数据位于 RAM 而非 ROM,因此这些值不能是const",这解释了HMAC_MSG[]等缓冲区为何特意声明为可写的static数组——这是与硬件后端(如 CryptoCell、安全元件)兼容的实践。
底层实现:psa_mac_compute 的完整调用链
测试调用的是公开 PSA API,RIOT 在 psa_crypto.c 中实现psa_mac_compute(),其流程可概括为五步:
- 状态与参数检查:库未初始化返回
PSA_ERROR_BAD_STATE;input/mac/mac_length为 NULL 返回PSA_ERROR_INVALID_ARGUMENT; - 读取密钥属性:
psa_get_key_attributes()取得密钥的类型与位长; - 算法与缓冲区校验:内部函数
psa_mac_validate_alg_and_key_and_size()(psa_crypto.c)检查PSA_ALG_IS_HMAC(alg)(否则PSA_ERROR_NOT_SUPPORTED)、PSA_MAC_LENGTH()计算出的 MAC 长度不小于 4 字节(过短的 MAC 可被暴力破解,代码注释明确以 32 位为安全下限)、不超过PSA_MAC_MAX_SIZE,以及调用方提供的缓冲mac_size是否够大(否则PSA_ERROR_BUFFER_TOO_SMALL); - 获取并锁定密钥槽:
psa_get_and_lock_key_slot_with_policy()以PSA_KEY_USAGE_SIGN_MESSAGE策略校验用途并加锁,防止并发访问; - 位置分发执行:
psa_location_dispatch_mac_compute()根据密钥所在位置(本地内存、受保护内存或安全元件)路由到底层实现。
底层实现再经 psa_crypto_algorithm_dispatch.c 按算法分发:
#if IS_USED(MODULE_PSA_MAC_HMAC_SHA_256) case PSA_ALG_HMAC(PSA_ALG_SHA_256): return psa_mac_compute_hmac_sha256(attributes, key_data, *key_bytes, input, input_length, mac, mac_size, mac_length); #endifpsa_mac_compute_hmac_sha256()等低层包装函数的声明集中在 sys/psa_crypto/include/psa_mac.h,每个算法(HMAC MD5/SHA-1/SHA-224/SHA-256/SHA-384/SHA-512/SHA3 系列)都对应一组compute/verify/sign_setup/verify_setup/update/sign_finish/verify_finish/abort包装,由IS_USED(MODULE_PSA_MAC_HMAC_*)条件编译控制——这正是 Makefile 中"只启用psa_mac_hmac_sha_256"时,其余算法代码全部被裁剪掉的原因,也是该测试能验证"最小 MAC 配置"的机制基础。
运行与自动化验证
测试的自动化断言由 tests/01-run.py 完成——它只做一件事:通过 RIOT testrunner 框架等待串口输出精确匹配All Done,匹配即判测试通过。
常用运行方式(RIOT 标准流程):
# 在 native 上构建并运行(软件哈希后端) make -C tests/sys/psa_crypto_mac BOARD=native flash term # 或直接跑自动化测试 make -C tests/sys/psa_crypto_mac BOARD=native test # 指定硬件板(将自动选用板载 HMAC 硬件加速后端) make -C tests/sys/psa_crypto_mac BOARD=nrf52840dk flash term若 HMAC 计算失败,程序会打印HMAC SHA256 failed: <PSA 错误名>与Tests failed...,测试脚本因此无法匹配All Done而报失败——错误信息中的可读错误名可直接对应上述psa_mac_compute()各校验分支。
受限于 Flash/RAM 容量,并非所有板子都能运行本测试。Makefile.ci 声明了BOARD_INSUFFICIENT_MEMORY,将arduino-duemilanove、arduino-leonardo、arduino-nano、arduino-uno、atmega328p、atmega328p-xplained-mini、atmega8、nucleo-l011k4等小内存 AVR/Cortex-M0 板排除在 CI 之外——这些板资源不足以承载 PSA Crypto 模块,这也是"配置测试"必须同时验证的边界条件。
进阶:从测试到自定义配置
本测试验证的是"最小 MAC 配置",若需要在实际应用中做更多扩展,可参考其上游 examples/advanced/psa_crypto:
- 启用更多 MAC 算法:在
USEMODULE中追加psa_mac_hmac_sha_1、psa_mac_hmac_sha_384等,每个算法同样支持_backend_periph/_backend_riot/_custom_backend三选一; - 使用安全元件:示例支持 Microchip ATECCX08A 设备,通过
SECURE_ELEMENT=1/2启用,并使用PSA_KEY_LOCATION_PRIMARY_SECURE_ELEMENT或PSA_KEY_LOCATION_SE_MIN与PSA_KEY_LOCATION_SE_MAX之间的自定义 location 值;设备槽位配置结构(key_type_allowed、key_persistent、slot_occupied)定义于 cryptoauthlib 包中,注意当前实现尚不支持使用设备上已预存的密钥; - 通过 Kconfig 配置:模块选择用 Make,编译期配置(如
CONFIG_PSA_SINGLE_KEY_COUNT、CONFIG_PSA_PROTECTED_KEY_COUNT、CONFIG_PSA_ASYMMETRIC_KEYPAIR_COUNT)则可用menuconfig进行,slot 数量配置的宏定义与联动关系见 psa_crypto_slot_management.h。
小结
tests/sys/psa_crypto_mac虽是一个小型测试,却是理解 RIOT PSA Crypto 模块化设计的最佳切片:它同时验证了模块裁剪的正确性(psa_crypto+psa_mac+psa_mac_hmac_sha_256三个模块即可完成 HMAC 计算)、后端自动选择机制(periph_hmac_sha_256特性驱动 periph/riot 后端切换)、密钥槽资源配置(CONFIG_PSA_SINGLE_KEY_COUNT=1的最小化)、API 调用链(psa_mac_compute→ 密钥槽加锁 → 算法分发 → 低层 wrapper)以及自动化验证流程(testrunner 断言All Done)。阅读本文后,你可以基于这份最小配置,在自己的 RIOT 应用中快速搭建 PSA MAC 功能,并根据目标硬件自由切换软件或硬件后端。
- 物联网
- 嵌入式
- 操作系统
- 实时系统
【免费下载链接】RIOT
RIOT - The friendly OS for IoT
相关推荐
GetQzonehistory:QQ空间历史数据抓取架构深度解析与技术实现
GetQzonehistory:QQ空间历史数据抓取架构深度解析与技术实现 在数字化记忆保存日益重要的今天,GetQzonehistory作为一个专业的Pyth
物联网嵌入式操作系统实时系统RIOT PSA Crypto Secure Element 测试指南:在 ATECC608A 上验证 AES-128、HMAC-SHA256 与 ECDSA P256
RIOT PSA Crypto Secure Element 测试指南:在 ATECC608A 上验证 AES 128、HMAC SHA256 与 ECDSA
物联网嵌入式操作系统实时系统FreeShow安全与隐私保护:教堂数据管理的最佳实践与配置指南
FreeShow安全与隐私保护:教堂数据管理的最佳实践与配置指南 FreeShow作为一款免费开源的教堂演示软件,在帮助教会高效管理礼拜内容的同时,也非常重视数
物联网嵌入式操作系统实时系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考