ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Mbed TLS PSA 迁移策略解析:MD Light 与 Block Cipher 的 Legacy/PSA 双路分发机制

Mbed TLS PSA 迁移策略解析:MD Light 与 Block Cipher 的 Legacy/PSA 双路分发机制 Mbed TLS PSA 迁移策略解析MD Light 与 Block Cipher 的 Legacy/PSA 双路分发机制【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware本文基于 Flipper Zero 固件仓库中自带的 Mbed TLS 架构文档 md-cipher-dispatch.md系统讲解 Mbed TLS 在不破坏向后兼容的前提下如何让传统legacy密码学接口暗中调度到 PSA 驱动加速层的迁移策略核心机制包括 MD light 哈希抽象、MBEDTLS_MD_CAN_xxx能力宏、运行时分发dispatch规则以及面向 GCM/CCM 的内部块密码抽象层。读完后你将理解该仓库中md、block_cipher模块的宏依赖关系与双路分发实现原理并能据此分析 Mbed TLS 在受限设备如 Flipper Zero 这类嵌入式目标上的裁剪与加速方式。背景为什么需要这份迁移策略Mbed TLS 正在从传统 legacy 接口向 PSAPlatform Security Architecture接口迁移但迁移不能一刀切。文档开篇明确了本策略的适用对象那些未受MBEDTLS_USE_PSA_CRYPTO约束、目前仍在使用 legacy 密码 API、且需要过渡到 PSA 的代码。它是总策略文档 strategy.md 的细化补充且与旧策略存在一个关键差异本工作中 PSA 不再被视为黑盒——可以改动实验性功能也可以调用内部接口。理解现状必须先理解MBEDTLS_USE_PSA_CRYPTO的局限。该选项会让库的部分模块改用 PSA API 做密码运算但它只作用于pk.h、X.509 和 TLS且启用后应用必须在使用这些模块前调用psa_crypto_init()。迁移工作因此要解决两个问题让未被覆盖的模块哈希、对称密码等也能调用 PSA——仅在确定能正常工作的前提下。这相当于让这些模块无条件地获得部分 use-PSA行为可用 PSA 加速器时受益不可用时回退。让调用链穿透生效。例如 X.509 调用pk做 PSS 验证pk再调用 RSARSA 又要计算哈希——这条链上的哈希计算也应走 PSA对应上游 issue #6497 描述的问题。使用 PSA 接口的收益文档概括为两点其一是 PSA 驱动通常是硬件加速器往往比内置软件实现性能更好、安全性也更好其二是很多场景下有了 PSA 驱动后软件实现可以整体移除从而减小代码体积。此外还能消除冗余比如md.c与psa_crypto_mac.c中 HMAC 实现的重复、hkdf.c与psa_crypto.c中 HKDF 实现的重复。对 Flipper Zero 固件而言Mbed TLS 以第三方库形式整体集成在 lib/mbedtls 目录通过 lib/mbedtls.scons 参与构建配置调整集中在 lib/mbedtls_cfg.h。本文讨论的双路分发机制正是这类受限嵌入式构建中用驱动替代软件实现、压缩固件体积的基础。需求分析用户故事与目标文档用五个用户故事定义了约束边界这些是理解整套设计取舍的前提向后兼容使用 Mbed TLS 接口含 legacy 密码接口的应用开发者期望代码在新的小版本中继续工作。接口设计使用 Mbed TLS 做密码运算的库代码开发者需要知道该调哪些函数、检查哪些 feature 宏才能让代码在所有配置下都能工作文档指出这与 X.509、TLS 面临的问题相同。硬件加速厂商两个诉求一方面希望构建 Mbed TLS 时尽量用自己的硬件加速另一方面希望不构建与硬件功能重复的软件实现以最小化代码体积。维护者两个诉求需要清晰的何时用哪个接口规则以避免非常规配置下的 bug需要避免代码重复。由此得出目标让更多非 PSA 接口在底层走 PSA 接口同时在不成立的情况下不破坏现有代码。同时文档明确了非目标Non-goals现阶段的目标不是让更多代码直接调用psa_xxx函数而是让更多代码在 PSA 驱动可用时调用 PSA 驱动至于分发机制本身如何实现是次要问题。另一个容易被忽略的依赖规则变化是判断某个密码机制是否可用传统上查MBEDTLS_SHA256_C、MBEDTLS_AES_C MBEDTLS_CIPHER_MODE_CBC这类模块宏在 PSA 接口侧则要看PSA_WANT_xxx符号。双路分发机制正是为弥合这两套依赖判定而设计。问题剖析三个域与混合域困境调用方分类文档首先把实现或使用密码机制的代码分成五类基础密码机制的软件实现哈希、AES 等——预期不变组合型密码机制的软件实现HMAC、CTR_DRBG、RSA 等PSS/OAEP 需要调用哈希且 PKCS1v1.5 需要知道哈希长度——它们必须保证只要辅助机制的 legacy 实现可用组合机制就能工作无论 PSA 实现是否同时可用PSA crypto 接口的实现本身——预期不变可能向改造后的胶水代码暴露一些内部功能受MBEDTLS_USE_PSA_CRYPTO约束的代码pk.h、X.509、TLS不含 TLS 1.3 特有部分始终使用 PSA 的代码TLS 1.3除与 1.2 共用部分外、LMS。据此划分出三个域domainLegacy 域不与 PSA 交互。哈希、密码原语、算术的实现。混合域mixed domain目前不用 PSA但应当尽量用。包括组合型密码原语LMS 除外以及MBEDTLS_USE_PSA_CRYPTO关闭时的 pk、X.509、TLS。PSA 域MBEDTLS_USE_PSA_CRYPTO开启时的 pk、X.509、TLS以及 TLS 1.3、LMS。非 use-PSA 模块清单文档逐一盘点了调用其他模块做密码运算、但不能做任何 PSA 假设的模块这是改造范围的事实清单哈希与 HMAC 类driver-only 哈希改造之后entropy经 MD-light 调哈希ECDSAHMAC_DRBGmd.h暴露于 APIECJPAKE经 MD-light 调哈希md.h暴露于 APIMD哈希与 HMACHKDF经md.h调 HMACmd.h暴露于 APIHMAC_DRBG经md.h调哈希和 HMACmd.h暴露于 APIPKCS12经 MD-light 调哈希PKCS5经md.h调 HMACmd.h暴露于 APIPKCS7经 MD 调哈希RSAPSS 与 OAEP 经 MD-light 调哈希md.h暴露于 APIPEM经 MD-light 调 MD5 哈希对称密码与 AEAD 类driver-only cipher 改造之前每个模块都记录了实际使用的模式、方向与所调函数模块实际使用依赖调用的函数PEMAES/DES/3DES 的 CBC 无填充仅解密无硬依赖AES_C/DES_C保护setkey_dec()crypt_cbc()低层 APIPKCS12实践中是 2DES/3DES 的 CBC PKCS7 填充仅解密check_config.h中对CIPHER_C的无条件依赖cipher.h暴露于 APIsetup、setkey、set_iv、reset、update、finishPKCS5PBES23DES/DES 的 CBC PKCS7 填充加密解密双向CIPHER_C无条件依赖setup、setkey、cryptCTR_DRBGAES 的 ECB仅加密AES_C无条件依赖setkey_enc、crypt_ecbaes.h低层 APICCMAES/Camellia/Aria 的 ECB仅加密AES_C \|\| CAMELLIA_C \|\| ARIA_C与CIPHER_C无条件依赖也被cipher.c调用info、setup、setkey、update多次从不 finishCMACAES/DES 的 ECB仅加密AES_C \|\| DES_C与CIPHER_C无条件依赖同上GCMAES/Camellia/Aria 的 ECB仅加密同 CCM同上NIST_KWAES 的 ECB加解密双向AES_C \|\| DES_C与CIPHER_C无条件依赖cipher.h暴露于 API同上Cipher任何密码/AEAD、任何模式、任何方向——文档特别提醒一点PSA cipher 构建在 Cipher 层之上而 PSA AEAD 直接调用底层 AEAD 模块GCM、CCM、ChachaPoly——这正是 GCM/CCM 模块会被两条路径同时使用、因而必须谨慎改造的原因。为什么 PSA 不总是可用这是整个设计的核心约束。以下情形中调用psa_xxx()做哈希或密码运算并不合适需要回退到 legacy 软件实现MBEDTLS_PSA_CRYPTO_C未启用存在尚未初始化初始化发生在psa_crypto_init()中的 PSA 驱动对 cipher 而言keystore 尚未初始化而 Mbed TLS 使用了自实现的 PSA ITS此时文件系统还不可访问。文档提到一个可能的绕过分发到 keystore 查找之后的内部函数而非 PSA API 函数但这与MBEDTLS_PSA_CRYPTO_CLIENT不兼容某个机制在 legacy 接口启用但 PSA 接口未启用——这不是设计意图但确实可能出现。例如为支持 PEM 的 PBKDF1 解码而启用MBEDTLS_MD5_C却不想启用PSA_ALG_WANT_MD5因为 MD5 在PSA_ALG_RSA_PSS和PSA_ALG_DETERMINISTIC_ECDSA中不受支持MBEDTLS_PSA_CRYPTO_CLIENT启用但客户端尚未建立与服务端的连接发生在psa_crypto_init()中MBEDTLS_PSA_CRYPTO_CLIENT启用但当前操作本身就是与 crypto 服务加密通信的实现的一部分或者本地实现因避免昂贵的远程调用反而更快。间接知识Indirect knowledge问题以rsa.c中 RSA-PSS 签名需要计算哈希为例当mbedtls_rsa_rsassa_pss_sign()被应用代码直接调用时应调用内置实现——走 PSA 加速器属于行为变化只有在不增加失败风险或性能下降时才允许这一点与MBEDTLS_USE_PSA_CRYPTO的开关状态无关因为rsa.h不在其作用范围内。而当它被X.509 代码调用时哈希就应该走 PSA当前没走即 issue #6497。一般化之后混合域模块的规则是被 PSA 域模块调用时必须调用 PSA调用方不在 PSA 域、且 PSA 调用不保证成功时不得调用 PSA或必须有回退。而最终调用方是谁这一信息在实际执行时是拿不到的只能靠参数、预处理符号和运行时状态推断。另外文档强调了一条非支持保证PSA_WANT_xxx关闭应当保证经 PSA API 尝试该机制必然失败——这一性质由测试套件test_suite_psa_crypto_not_supported自动枚举测试用例兜底因此不便为个别机制开例外。RSA-PSS 实例推演文档用 RSA-PSS 走了一遍完整推演。RSA 属于混合域因此被psa_sign_hash等 PSA 函数调用时有 PSA 哈希加速器就必须用它被用户代码调用时若 PSA 不可用无论原因是MBEDTLS_PSA_CRYPTO_C关闭、该哈希的PSA_WANT_ALG_xxx关闭还是加速器驱动尚未初始化必须调用内置哈希实现。RSA 依据mbedtls_md_type_t参数知道要算哪个哈希混合域模块普遍以数值类型接收算法参数例外是 HMAC_DRBG 和 HKDF 接收const mbedtls_md_info_t*CMAC 接收const mbedtls_cipher_info_t*。一种最保守的方案是双重编码沿用MBEDTLS_MD_SHA256分发到 legacy 代码另加MBEDTLS_MD_SHA256_USE_PSA强制走 PSA。这最大限度保住向后兼容但代价是非 PSA 代码永远享受不到加速器也失去了移除软件实现的空间。按域分析调用方如何判断哈希可用性Legacy 域调用方只要MBEDTLS_SHA256_C启用就要求 RSA-PSS 支持 SHA-256且任何时刻都必须工作例如驱动未初始化时不关心负支持。PSA 域调用方PSA_WANT_ALG_SHA_256启用且psa_crypto_init()已调用就要求支持。负支持未启用则必须拒绝可以在 PSA 层调用 RSA 模块之前拦截不必压给rsa.c。混合域调用方要求取决于其调用方RSA 决定算法可用性的机制同样适用于它。结论RSA 必须能在MBEDTLS_SHA256_C或PSA_WANT_ALG_SHA_256任一启用时做 SHA-256若只有PSA_WANT_ALG_SHA_256启用意味着 SHA-256 来自加速器驱动则只在psa_crypto_init()调用后需要工作。再细分编译时可用性的四种组合MBEDTLS_PSA_CRYPTO_CLIENT调用 PSA 是否划算取决于性能只在服务端有加速器时走服务端更好反之 RPC 开销可能吃掉加速收益且必须已成功连接服务端。其余枚举假设该选项关闭。无 PSA 加速器直接调mbedtls_sha256即可调用链细节无关紧要。有 PSA 加速器、无软件实现可以调加速器除非需要保证失败——文档作者表示当时想不出必须保证失败的场景。两者都有优先 PSA但前提是驱动可用。对哈希而言假设驱动已初始化就够曾考虑要求哈希驱动免初始化也能工作对 cipher 更复杂因为 cipher 函数依赖 keystore且 cipher 加速器可能还需要熵源侧信道防护而熵源在开机早期未必可用。文档还指出一个微妙点当有 PSA 加速器但没有软件实现时预处理符号不应表示该算法在 legacy 域可用只能在 PSA 域可用混合域接口不能保证算法可用但被请求时必须尝试。规范设计MD Light定义与自动启用MD light是md.h的一个子集实现前文描述的混合域哈希计算接口由mbedtls_config.h中的MBEDTLS_MD_LIGHT激活。以下情形会在build_info.h中自动启用它启用了某个需要计算哈希的混合域模块MBEDTLS_MD_C启用。MD light 包含的类型mbedtls_md_type_t、mbedtls_md_info_t、mbedtls_md_context_t包含的函数mbedtls_md_info_from_type、mbedtls_md_init、mbedtls_md_free、mbedtls_md_setupMBEDTLS_MD_C关闭时hmac参数必须为 0、mbedtls_md_clone、mbedtls_md_get_size、mbedtls_md_get_type、mbedtls_md_starts、mbedtls_md_update、mbedtls_md_finish、mbedtls_md。与完整 MD 不同MD light不支持把mbedtls_md_context_t*作为空指针传入但若干函数仍需支持const mbedtls_md_info_t*为空——因为尝试使用不受支持的算法时mbedtls_md_info_from_type会返回NULL。MD 算法支持宏对每个哈希算法只要其可通过 MD light 使用md.h就定义宏MBEDTLS_MD_CAN_xxx仅在MBEDTLS_MD_LIGHT启用时定义。判定条件是二选一对应的MBEDTLS_xxx_C已定义或者MBEDTLS_PSA_CRYPTO_C/MBEDTLS_PSA_CRYPTO_CLIENT之一启用且对应的PSA_WANT_ALG_xxx启用。由于 legacy 与 PSA 对部分算法的拼法不同而 MD 是 legacy 接口故采用 legacy 命名#if defined(MBEDTLS_MD_LIGHT) #if defined(MBEDTLS_SHA256_C) || \ (defined(MBEDTLS_PSA_CRYPTO_C) PSA_WANT_ALG_SHA_256) #define MBEDTLS_MD_CAN_SHA256 #endif #endif内部支持宏至少一个哈希有 PSA 驱动时定义MBEDTLS_MD_SOME_PSA至少一个哈希有 legacy 实现时定义MBEDTLS_MD_SOME_LEGACY。MD 上下文中的 PSA 支持MD 上下文必须容纳二选一某 legacy 模块的上下文或指向它的指针或 PSA 上下文或指针。文档作者倾向去掉指针间接层但那会使 MD 上下文始终等于最大支持哈希上下文的大小因此该规范版本保留指针且为统一性 PSA 侧也用指针日后可能简化enum { MBEDTLS_MD_ENGINE_LEGACY, MBEDTLS_MD_ENGINE_PSA, } mbedtls_md_engine_t; // private type typedef struct mbedtls_md_context_t { mbedtls_md_type_t type; #if defined(MBEDTLS_MD_SOME_PSA) mbedtls_md_engine_t engine; #endif void *md_ctx; // mbedtls_xxx_context or psa_hash_operation #if defined(MBEDTLS_MD_C) void *hmac_ctx; #endif } mbedtls_md_context_t;所有字段均为私有。engine字段看似与type冗余但当某算法同时有 legacy 模块与 PSA 加速器时在上下文设置时刻依据加速器的运行时可用性做选择该选择必须记录在上下文中。Info 结构包含准则、编码转换与运行时判定由于 MD light 要支持仅经 PSA 启用的哈希mbedtls_md_info_t结构体的包含必须以MBEDTLS_MD_CAN_xxx为准则而不能只看 legacy 模块mbedtls_md_info_from_type同样适用此准则。实现需要从 legacy 类型编码转换到 PSA 编码static inline psa_algorithm_t psa_alg_of_md_info( const mbedtls_md_info_t *md_info );运行时支持判定由私有函数承担int psa_can_do_hash(psa_algorithm_t hash_alg);返回 1 表示hash_alg此刻可以经 PSA 执行0 表示不行只对经 PSA 启用的算法有定义起步实现是PSA crypto 的驱动子系统已初始化则返回 1。使用注意对未经 PSA 启用的算法调用它是安全的——无论返回 0 还是 1对该算法调 PSA 哈希函数都会返回PSA_ERROR_NOT_SUPPORTED。哈希操作的分发规则每个执行哈希运算或上下文管理的函数都要决定走 PSA 还是 legacy拿到已建立的上下文时用其engine字段拿到mbedtls_md_type_t type或const mbedtls_md_info_t *中的type时若该哈希有 PSA 加速器且psa_can_do_hash(alg)为真调用对应 PSA 函数如适用则把 engine 置为MBEDTLS_MD_ENGINE_PSAMBEDTLS_MD_SOME_PSA未定义时跳过此步否则按现有方式按类型分发到 legacy 模块MBEDTLS_MD_SOME_LEGACY未定义时跳过若两条路都不通返回MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE。这里隐含一个假设经 PSA 启动的操作必须能完成即mbedtls_psa_crypto_free不得在 PSA 操作进行中调用文档要求将此写入说明。PSA 函数返回后MD light 调用mbedtls_md_error_from_psa转换状态码。强制所有 legacy 算法在 PSA 中可用前文分析认为没有必须legacy 有而 PSA 无的强需求唯一例外场景是MBEDTLS_PSA_CRYPTO_CLIENT下机制只存在于本地的情形但没有明确需求因此规范采用了一条简化性质若某算法有 legacy 实现则它也必然经 PSA 可用。MBEDTLS_PSA_CRYPTO_CONFIG关闭时本已如此启用时需要修改include/mbedtls/config_psa.h使该性质成立。这条性质带来两个简化混合域代码只要知道psa_crypto_init()已被调用就可以调用 PSA 代码而无须逐一检查算法支持混合域代码也可以假设 PSA 的缓冲区尺寸计算对所有它支持的算法都正确。MD light 优化项以下优化不是实现 MD light 所必需但能显著缩减代码体积剥离名称从mbedtls_md_info_t中移除哈希名称mbedtls_md_info_from_string和mbedtls_md_get_name改用 switch-case 或独立列表实现移除 info 结构中的元数据mbedtls_md_get_size及需要块大小的模块改查 PSA 宏不再从 info 结构取优化类型转换重排mbedtls_md_type_t枚举值使其等于 PSA 编码的低 8 位从而转换只需一次按或static inline psa_algorithm_t psa_alg_of_md_info( const mbedtls_md_info_t *md_info ) { if( md_info NULL ) return( PSA_ALG_NONE ); return( PSA_ALG_CATEGORY_HASH | md_info-type ); }统一 HMAC 与 PSAPSA 有自己的 HMAC 实现在MBEDTLS_MD_C与PSA_WANT_ALG_HMAC同时存在且 HMAC 未完全由驱动提供的构建中应只保留一份实现——用 PSA 驱动接口调用替换md.h中的实现混合域模块由此还能获得直接由 PSA 驱动加速的 HMAC。对MBEDTLS_PSA_CRYPTO_CLIENT的改进MD light 目前只在算法经MBEDTLS_PSA_CRYPTO_C可用时分发到 PSA而MBEDTLS_USE_PSA_CRYPTO要求MBEDTLS_PSA_CRYPTO_C所以混合域代码实际不会经由 CLIENT 触发 PSA现状可接受。架构扩展支持 CLIENT 的路线是编译期依赖改为检查defined(MBEDTLS_PSA_CRYPTO_C) || defined(MBEDTLS_PSA_CRYPTO_CLIENT)MBEDTLS_PSA_CRYPTO_CLIENT实现方需随psa_crypto_init()一并提供psa_can_do_hash()或更通用的psa_can_do届时它成为公共接口不能随意变更。3.x 的取舍范围削减与优先级不支持无MBEDTLS_USE_PSA_CRYPTO的 PK、X.509、TLS这些模块不需要支持 driver-only 哈希和 cipher想充分发挥驱动的用户需自行开启该宏。注意 TLS 1.3 同样适用此限制——其中哈希的部分用法和全部 cipher 用法与 TLS 1.2 共用代码受该宏管辖详见 use-psa-crypto.md。该限制在 4.0 中会自然消失届时该宏不再是选项而是常开。不支持无MBEDTLS_PSA_CRYPTO_C的MBEDTLS_PSA_CRYPTO_CLIENT事实上并不支持这种组合构建——例如MBEDTLS_USE_PSA_CRYPTO与MBEDTLS_SSL_PROTO_TLS1_3都硬性要求MBEDTLS_PSA_CRYPTO_C尽管从原理上讲只需 CLIENT 即可。既然 4.0 前不打算解除此限制driver-only 哈希/cipher 支持在 3.x 中带同样的限制是可接受的但设计上仍应顾及 CLIENT避免日后补充时更加困难。cipher 优先面向受限设备与现代 TLS首要目标是类似 TF-M medium profile 的配置加上仅 AEAD 密码套件的 TLS。明确排除加密 PEM、PKCS5 与 PKCS12 加密、PK parse 中的 PKCS8 加密密钥高度受限设备上不常用NIST-KW同上理由CMAC同上且它可直接加速TLS 中的 CBC 密码套件业界早已不推荐。块密码原语的双路分发设计权衡按上述优先级初期只支持GCM、CCM 和 CTR-DRBG三者都只用块密码原语的加密方向且都通过ECB 模式访问原语Cipher 层和aes.h的 ECB 只支持单块与 PSA 实现真正的 ECB 模式不同。GCM/CCM 目前经 Cipher 层同时支持 AES、Aria、CamelliaDES 因块尺寸小被标准排除CTR-DRBG 则直接用aes.h低层 API。GCM 与 CCM 需求与在栈中的位置高度相似应采用同一设计CTR-DRBG 则不同它只用 AES 且无扩展计划且在栈中位置特殊——用户只关心随机数能不能用栈中没有任何一环会问CTR-DRBG-AES 是否可用不像 AES-GCM 会被 TLS 询问。因此结论是两套设计CTR-DRBG只需检查AES_C是否存在不存在则回退到 PSAGCM/CCM需要一个统一抽象层能统一使用 AES/Aria/Camellia 并分发到内置实现或驱动。该抽象层可以是新内部模块也可以是扩展现有 Cipher API 的子集。复用 Cipher 子集的理由无需设计、实现、测试新模块GCM/CCM 无需改代码只改依赖避免与仍启用CIPHER_C的构建产生代码重复日后若支持 NIST-KW、CMAC、PKCS5、PKCS12 等其他 Cipher 用户只需扩展分发即可。代价则是继承cipher_info_t结构的负担它目前承担三种用途判断是否支持、查询块大小、setup()参数以及上下文动态分配这类存疑的实现决策若为此重构 Cipher要么导致完整 Cipher 与子集构建之间实现差异显著要么把简化工作量摊到整个 Cipher。两种方案的原型验证表明新内部模块的代码体积收益更大、代码更干净最终采用新模块路线即文档后文的 Internal block cipher abstraction曾称 Cipher light。内部块密码抽象层规范定义新模块由config_adjust_legacy_crypto.h自动启用需要它的模块即 CCM、GCM在CIPHER_C不可用、或需要 PSA 分发时启用它。注意 CCM 和 GCM 目前硬依赖完整CIPHER_C由check_config.h强制此硬依赖将被上述自动启用机制取代。对外 APIvoid mbedtls_block_cipher_init(mbedtls_block_cipher_context_t *ctx); void mbedtls_block_cipher_free(mbedtls_block_cipher_context_t *ctx); int mbedtls_block_cipher_setup(mbedtls_block_cipher_context_t *ctx, mbedtls_cipher_id_t cipher_id); int mbedtls_block_cipher_setkey(mbedtls_block_cipher_context_t *ctx, const unsigned char *key, unsigned key_bitlen); int mbedtls_block_cipher_encrypt(mbedtls_block_cipher_context_t *ctx, const unsigned char input[16], unsigned char output[16]);仅支持 AES、ARIA、Camellia由setup()中的mbedtls_cipher_id_t标识——因为调用方GCM/CCM就是这样标识它们的。双路分发机制与 MD light 高度同构。块密码上下文包含二选一legacy 模块上下文AES/ARIA/Camellia或一个 PSA key identifier另有一个字段指示当前用的是哪个所有字段私有。engine字段的理由与 MD 相同算法同时有 legacy 与 PSA 加速器时在setup()时刻按加速器运行时可用性做选择并记录。运行时支持判定int psa_can_do_cipher(psa_key_type_t key_type, psa_algorithm_t cipher_alg);语义同psa_can_do_hash返回 1 表示该操作此刻可经 PSA 执行。模块内每个函数都要知道走哪条路除setup()外全部查上下文的engine字段setup()则根据 key 类型与psa_can_do_cipher()的返回值设定 engine。同样假设经 PSA 启动的操作必须能完成mbedtls_psa_crypto_free不得在其进行中调用。PSA 函数返回后block_cipher各函数调用mbedtls_cipher_error_from_psa转换状态码。仓库中的落地实现从文档到源码以上规范在当前仓库的 Mbed TLS 副本中已有相当部分落地下面给出可核对的实现证据。能力宏与自动启用config_adjust_legacy_crypto.hconfig_adjust_legacy_crypto.h 精确实现了 MD light 一节描述的宏体系MBEDTLS_MD_LIGHT由混合域模块自动启用随后对每个算法同时维护两组宏——PSA 侧的MBEDTLS_MD_CAN_xxxMBEDTLS_MD_xxx_VIA_PSA以MBEDTLS_PSA_ACCEL_ALG_xxx为前提覆盖 MD5、SHA-1、SHA-224/256/384/512、RIPEMD160、SHA3-224/256/384/512与 legacy 侧的MBEDTLS_MD_CAN_xxxMBEDTLS_MD_SOME_LEGACY以MBEDTLS_xxx_C为前提。这正对应文档info 结构包含以MBEDTLS_MD_CAN_xxx为准则的要求。块密码侧第 202-266 行定义了MBEDTLS_BLOCK_CIPHER_{AES,ARIA,CAMELLIA}_VIA_PSA前提MBEDTLS_PSA_ACCEL_KEY_TYPE_xxx、_VIA_LEGACY前提MBEDTLS_xxx_C、派生的MBEDTLS_BLOCK_CIPHER_CAN_xxx与MBEDTLS_BLOCK_CIPHER_SOME_PSA。自动启用规则与规范一致#if (defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C)) \ (!defined(MBEDTLS_CIPHER_C) || defined(MBEDTLS_BLOCK_CIPHER_SOME_PSA)) #define MBEDTLS_BLOCK_CIPHER_C #endif即无CIPHER_C时启用等价旧方案的兜底或存在 PSA 驱动可加速时也启用——与文档仅当CIPHER_C不可用或需要 PSA 分发时自动启用逐字对应。此外还派生出MBEDTLS_CCM_GCM_CAN_{AES,ARIA,CAMELLIA}让 GCM/CCM 的能力判断同时覆盖两条路径。上下文结构block_cipher.hblock_cipher.h 定义了mbedtls_block_cipher_id_tAES/CAMELLIA/ARIA、engine 枚举MBEDTLS_BLOCK_CIPHER_ENGINE_LEGACY/MBEDTLS_BLOCK_CIPHER_ENGINE_PSA以及上下文结构id字段、条件编译的engine与psa_key_id以及存放各 legacy 上下文的 union。值得注意的实现差异文档草稿阶段 MD 上下文暂时保留指针而块密码上下文最终实现直接内嵌各算法上下文的 union而非指针省去了间接层——与 MD 侧作者倾向去掉指针间接的取向一致代价是上下文尺寸等于最大算法上下文恰好是该层仅支持三种 128 位块密码时可以接受的。分发与密钥导入block_cipher.cblock_cipher.c 的mbedtls_block_cipher_setup实现了规范中的setup()判定流程先把调用方传入的mbedtls_cipher_id_t映射为内部 id然后在MBEDTLS_BLOCK_CIPHER_SOME_PSA下查询psa_can_do_cipher(psa_key_type, PSA_ALG_ECB_NO_PADDING)成功则置engine MBEDTLS_BLOCK_CIPHER_ENGINE_PSA直接返回否则回落到按 id 初始化对应 legacy 上下文未知 id 返回MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA。block_cipher.c 的setkey在 PSA 路径上把 key 作为一次性导入的 PSA 密钥处理设置 key type、bits、算法PSA_ALG_ECB_NO_PADDING与用途PSA_KEY_USAGE_ENCRYPT经psa_import_key得到psa_key_id失败时走错误转换legacy 路径按 id 调mbedtls_aes_setkey_enc/mbedtls_aria_setkey_enc/mbedtls_camellia_setkey_enc。block_cipher.c 的encrypt按engine字段分流PSA 路径调用psa_cipher_encrypt(ctx-psa_key_id, PSA_ALG_ECB_NO_PADDING, ...)处理 16 字节块legacy 路径调各算法的crypt_ecb。free对应地按 engine 选择psa_destroy_key或各mbedtls_xxx_free。API 声明与文档规范完全一致见 block_cipher_internal.hinit以 inlinememset实现注释还特别提醒setup()参数是mbedtls_cipher_id_t而非mbedtls_block_cipher_id_t——呼应规范中以调用方习惯的标识方式传入的设计。错误码转换psa_util_internal.h规范中调用 PSA 函数后转换状态码的机制在 psa_util_internal.h 中实现mbedtls_error_pair_t双字段表 psa_status_to_mbedtls()逐表查找、未命中再走psa_generic_status_to_mbedtls兜底并用PSA_TO_MBEDTLS_ERR_LIST宏缩短模块侧的调用。其中psa_to_md_errors表恰在MBEDTLS_MD_LIGHT下声明、psa_to_cipher_errors表恰在MBEDTLS_BLOCK_CIPHER_SOME_PSA下声明与文档MD light 调mbedtls_md_error_from_psa、block_cipher 调mbedtls_cipher_error_from_psa的分工一一对应block_cipher.c 中mbedtls_cipher_error_from_psa即封装了该表查询。小结这套迁移策略的本质是在不改公共 API、不破坏向后兼容的前提下为混合域模块安装一个编译期判定能力MBEDTLS_MD_CAN_xxx/MBEDTLS_BLOCK_CIPHER_CAN_xxx宏族 MBEDTLS_BLOCK_CIPHER_C自动启用、运行期判定路径psa_can_do_hash/psa_can_do_cipher 上下文engine字段的双路分发机制驱动可用且就绪时走 PSA从而可以用硬件加速替代软件实现、删减代码体积否则透明回落到 legacy 实现。在 Flipper Zero 固件中阅读md.c、gcm.c、ccm.c、ctr_drbg.c这些模块时凡是看到MBEDTLS_MD_SOME_PSA、MBEDTLS_BLOCK_CIPHER_SOME_PSA条件分支其背后都是本文所述的规范在起作用而 lib/mbedtls_cfg.h 与 lib/mbedtls.scons 则决定了这些宏在最终固件中实际取何值。【免费下载链接】flipperzero-firmwareFlipper Zero firmware source code项目地址: https://gitcode.com/GitHub_Trending/fl/flipperzero-firmware创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表