首页/新闻资讯/正文详情

Erlang/OTP Crypto 引擎存储密钥(Engine Stored Keys)使用指南:签名、验签与口令保护

发布时间:2026/9/23 9:50:53 来源:云帆数科 栏目:资讯中心
Erlang/OTP Crypto 引擎存储密钥(Engine Stored Keys)使用指南:签名、验签与口令保护
Erlang/OTP Crypto 引擎存储密钥Engine Stored Keys使用指南签名、验签与口令保护【免费下载链接】otpErlang/OTP项目地址: https://gitcode.com/gh_mirrors/ot/otp导读本文面向 Erlang/OTP 开发者系统讲解如何使用存放在加密引擎Engine中的公钥与私钥完成crypto:sign/4签名与crypto:verify/5验签操作。引擎可以将密钥存放在比普通文件系统更安全的存储介质中如硬件安全模块 HSM本文聚焦于如何构造engine_key_ref()映射、如何为受口令保护的密钥传入密码并结合 crypto 应用 的 NIF 底层实现与 engine_SUITE 测试套件 印证其调用链。读完本文你将掌握在 Erlang 中直接使用引擎托管密钥完成签名/验签的完整实战方案。背景OpenSSL Engine API 与密钥存储OpenSSL 对外暴露了一套 Engine API允许为部分或全部密码学操作插入替代实现。当配置适当时OpenSSL 会调用引擎的实现而非自身默认实现典型场景是硬件加速即把特定密码学运算交给硬件完成以获得更高性能。引擎的职责之一是提供私钥或公钥的存储。这类存储往往比普通文件系统更安全——例如密钥可以永不离开硬件设备。关于如何加载load一个引擎请参阅 Engine Load 章节本文不再赘述加载过程而专注于如何使用存储在引擎中的密钥。从底层契约看一个能提供密钥存储的引擎必须向 OpenSSL 注册两个回调ENGINE_set_load_privkey_function——用于加载私钥ENGINE_set_load_pubkey_function——用于加载公钥。在 OTP 仓库中otp_test_engineotp_test_engine.c就是这样一个示例引擎其bind_helper函数明确调用了这两个函数if (!ENGINE_set_load_privkey_function(e, test_privkey_load)) goto err; if (!ENGINE_set_load_pubkey_function(e, test_pubkey_load)) goto err;这意味着任何希望被 crypto 应用当作密钥存储使用的引擎都必须实现并注册这两个函数否则在调用加载密钥时会失败。使用引擎存储密钥的前置条件OTP 的 crypto 应用要求用户提供关于密钥的两项或三项信息已加载的引擎引用——引擎必须先被加载参见 Engine Load 章节 或 crypto:engine_load/3引擎中的密钥引用key_id——一个 Erlang 字符串或二进制其具体含义取决于所加载的引擎例如在示例引擎中它就是一个密钥文件的路径可选的密钥口令password——仅当密钥在引擎内受口令保护时需要。随后构造一个 Erlang 映射map作为密钥参数传入签名/验签函数。该映射的类型定义在 crypto.erl 中-type key_id() :: string() | binary() . -type password() :: string() | binary() . -type engine_key_ref() :: #{engine : engine_ref(), key_id : key_id(), password password(), term() term() }.字段语义如下字段是否必填类型说明engine必填engine_ref()term()由crypto:engine_load/3等函数返回的引擎引用key_id必填string() \| binary()引擎中密钥的标识符含义取决于引擎实现password可选string() \| binary()密钥口令仅当密钥在引擎中受保护时需要其他term() term()可选任意引擎相关的扩展字段提示用户应用通常处于更高抽象层例如 SSL 应用中的t:ssl:key/0此时引擎密钥映射会作为底层密钥载体被透明使用只有直接使用 crypto 应用时才需要亲手构造上述映射。场景一使用引擎存储的私钥签名假设引擎已在1处加载成功返回的引擎引用为EngineRef。构造私钥引用映射并调用crypto:sign/4完成 RSA 签名1 {ok, EngineRef} crypto:engine_load(....). {ok,#Ref0.2399045421.3028942852.173962} 2 PrivKey #{engine EngineRef, key_id id of the private key in Engine}. ... 3 Signature crypto:sign(rsa, sha, The message, PrivKey). 65,6,125,254,54,233,84,77,83,63,168,28,169,214,121,76, 207,177,124,183,156,185,160,243,36,79,125,230,231,...关键点key_id的取值完全取决于引擎——对示例引擎而言它是一个密钥文件的路径见下文与传入普通 RSA 私钥rsa_private()相比这里传入的是一个engine_key_ref()映射sign/4的规格crypto.erl明确接受engine_key_ref()作为Key的合法取值。底层调用链从映射到 ENGINE_load_private_key从源码看crypto:sign/4最终会进入 NIF 层。在 pkey.c 的get_pkey_private_key中当检测到传入的Key是一个 map 时会走引擎分支if (enif_is_map(env, argv[key_arg_num])) { #ifdef HAS_ENGINE_SUPPORT /* Use key stored in engine */ ENGINE *e; if (!get_engine_and_key_id(env, argv[key_arg_num], id, e)) assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, Couldnt get engine and/or key id)); password get_key_password(env, argv[key_arg_num]); *pkey ENGINE_load_private_key(e, id, NULL, password); if (!*pkey) assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, Couldnt get private key from engine));这里有两个值得注意的实现细节get_engine_and_key_idengine.c从映射中读取engine字段对应的资源对象enif_get_resource并从key_id字段取出二进制内容再zero_terminate成 C 字符串——所以key_id本质上是一个会被当作 C 字符串传递的标识符比如文件路径或硬件槽位号。get_key_passwordengine.c从映射中读取可选的password字段若映射中不存在该字段返回NULL即无口令。随后password被直接传给 OpenSSL 的ENGINE_load_private_key(e, id, NULL, password)。示例引擎如何解析 key_idOTP 自带的测试引擎把key_id解释为 PEM 文件的路径otp_test_engine.c 中的test_key_load会fopen(id, r)再根据公私钥标志分别调用PEM_read_PrivateKey或PEM_read_PUBKEY。这解释了测试套件中key_id为何形如rsa_private_key.pem。真实产品引擎则可能把key_id解释为 HSM 中的槽位、标签或对象句柄。场景二使用引擎存储的公钥验签用上一节的签名与消息构造公钥引用映射并调用crypto:verify/54 PublicKey #{engine EngineRef, key_id id of the public key in Engine}. ... 5 crypto:verify(rsa, sha, The message, Signature, PublicKey). true 6说明这里把公钥也放在引擎中仅用于演示“引擎存储公钥亦可使用”公钥当然也可以像往常一样公开处理例如直接传 RSA 公钥元组/二进制引擎存储并不是必须的。底层同样走引擎分支在 pkey.c 的get_pkey_public_key路径中会调用ENGINE_load_public_key(e, id, NULL, password)从引擎取出公钥用于验签。场景三使用受口令保护的私钥与第一个签名示例相同区别仅在映射中增加password字段——当引擎内的密钥受口令保护时必须提供该字段否则引擎无法解开密钥6 PrivKeyPwd #{engine EngineRef, key_id id of the pwd protected private key in Engine, password password}. ... 7 crypto:sign(rsa, sha, The message, PrivKeyPwd). 140,80,168,101,234,211,146,183,231,190,160,82,85,163, 175,106,77,241,141,120,72,149,181,181,194,154,175,76, 223,... 8测试用例佐证engine_SUITEcrypto 应用的测试套件 engine_SUITE.erl 专门验证了“使用引擎存储公私钥”这一能力可作为真实可运行的模式参考sign_verify_rsa(Config) - Priv #{engine engine_ref(Config), key_id key_id(Config, rsa_private_key.pem)}, Pub #{engine engine_ref(Config), key_id key_id(Config, rsa_public_key.pem)}, sign_verify(rsa, sha, Priv, Pub). sign_verify_rsa_pwd(Config) - Priv #{engine engine_ref(Config), key_id key_id(Config, rsa_private_key_pwd.pem), password password}, Pub #{engine engine_ref(Config), key_id key_id(Config, rsa_public_key_pwd.pem)}, sign_verify(rsa, sha, Priv, Pub).从测试用例可以观察到的实践要点算法覆盖面除 RSA 外测试还覆盖了 DSA、ECDSA、EdDSA 的引擎密钥签名/验签sign_verify_dsa、sign_verify_ecdsa、sign_verify_eddsa说明engine_key_ref()可配合多种pk_sign_verify_algs()使用口令错误处理sign_verify_rsa_pwd_bad_pwd用例故意传入Bad password并期望捕获error:{badarg,_,_}异常——这印证了错误口令会在 NIF 层以badarg形式抛出对应 pkey.c 中 Couldnt get private key from engine 的错误路径key_id 语义测试中的key_id对应测试数据目录下的 PEM 文件路径再次印证“key_id 的具体语义由引擎决定”。常见问题与注意事项引擎未加载使用engine_key_ref()前必须先加载引擎并获得EngineRef否则映射中engine字段无法解析为有效的引擎资源NIF 层会抛出badargCouldnt get engine and/or key id。引擎不支持密钥加载如果引擎没有调用ENGINE_set_load_privkey_function/ENGINE_set_load_pubkey_function注册加载函数ENGINE_load_private_key/ENGINE_load_public_key会失败表现为加载密钥失败的错误。无引擎支持的构建若底层 OpenSSL 实现未启用引擎支持HAS_ENGINE_SUPPORT未定义传 map 会直接得到badargNo engine support参见 pkey.c。口令与 key_id 的类型key_id和password均为string() | binary()底层会将其转换为以\0结尾的 C 字符串因此不要包含嵌入的空字符。OpenSSL 版本差异OpenSSL 3.0 已弃用deprecateCrypto Engine API加载动态库的文件名要求在不同 SSL 版本间也可能存在差异详见 Engine Load 章节 的注意事项在使用引擎功能时请以实际部署的 OpenSSL/LibreSSL 版本为准。延伸阅读Engine Load引擎加载指南——引擎的加载、注册方法、卸载与列举crypto.erl 引擎 API 实现——engine_load/3的 Erlang 层实现与错误处理otp_test_engine.c——OTP 自带的测试引擎演示了密钥存储引擎的完整 C 实现含test_privkey_load/test_pubkey_load/pem_passwd_cb_fun口令回调engine_SUITE.erl——覆盖 RSA/DSA/ECDSA/EdDSA 引擎密钥签名验签的完整测试套件pkey.c——签名/验签 NIF 层中引擎密钥的解析与加载逻辑。【免费下载链接】otpErlang/OTP项目地址: https://gitcode.com/gh_mirrors/ot/otp创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

Python实现旅游评论细粒度情感分析
Python实现旅游评论细粒度情感分析

1. 项目背景与核心价值旅游行业正经历着从传统服务向数据驱动决策的转型过程。作为从业多年的数据分析师,我深刻体会到用户评论中蕴含的情感倾向对景区运营、服务改进和营销策略制定的重要性。传统的人工阅读分析方式不仅效率低下,而且难以应对海量评论数… · 2026/9/23 9:50:47

蔬菜价格预测毕设实战:LSTM时序建模从数据清洗到调参全攻略
蔬菜价格预测毕设实战:LSTM时序建模从数据清洗到调参全攻略

简介:基于长短期记忆网络(LSTM)的蔬菜价格预测毕业设计项目,涵盖完整源码、项目说明与数据集,面向计算机相关专业正在准备毕业设计或课程设计的学生,也适合需要实战练习的初学者。项目经导师指导并通过评审… · 2026/9/23 9:50:47

清空聊天记录能恢复吗 面试必问的3种底层恢复方案对比
清空聊天记录能恢复吗 面试必问的3种底层恢复方案对比

清空聊天记录能恢复吗 面试必问的3种底层恢复方案对比 是不是也遇到过这种糟心事儿?刚把微信或者钉钉里的关键需求聊天记录清空了,转头发现没截图,脑子一懵:这数据还能找回来吗? 别慌,先深呼吸。在开发圈和测试圈,这不仅是生活常识,更是个典型的… · 2026/9/23 9:50:47

基于Python的BERT文本相似度检测系统源码全解析
基于Python的BERT文本相似度检测系统源码全解析

简介:一套基于Python与BERT模型的深度学习文本相似度检测系统毕业设计源码,面向计算机相关专业毕业生和NLP入门学习者,可用于课程设计、论文实现或实战演练。系统采用Python 3.6.8与MySQL 5.7搭建,利用BERT双向Transformer提取深层… · 2026/9/23 11:17:17

DM9000A 网卡在 VxWorks 下的 END 驱动开发与避坑指南
DM9000A 网卡在 VxWorks 下的 END 驱动开发与避坑指南

简介:这份资源面向从事嵌入式网络驱动开发的工程师与学习者,聚焦DM9000A以太网控制器在VxWorks实时操作系统下的驱动实现,帮助读者理解硬件寄存器操作、内核驱动结构与中断处理机制。压缩包共2个文件,包含1个c源码与1个txt说明文档… · 2026/9/23 11:17:17

告别语法陷阱:程序员从入门到精通的质量保证实战
告别语法陷阱:程序员从入门到精通的质量保证实战

告别语法陷阱:程序员从入门到精通的质量保证实战 刚学完Python语法,兴奋地去搭项目,结果代码一跑全崩?别慌,这是绝大多数新手的通病。很多兄弟以为背下if-else和循环结构就入门了,其实真正的入门到精通,卡在“质量保证”这一步。你写的代… · 2026/9/23 11:17:05

力扣周赛485场:字符串处理与二分查找实战解析
力扣周赛485场:字符串处理与二分查找实战解析

1. 力扣周赛485场实战复盘作为一名常年混迹力扣的算法工程师,我参加了第485场周赛并成功AC前三题。这次比赛整体难度适中,但暴露了我编码基本功不够扎实的问题。下面我将详细拆解每道题的解题思路、实现细节和优化方向,希望能给算法爱好者们提… · 2026/9/23 11:16:58

Mac长图截取工作流:从截图到信息交付的重构
Mac长图截取工作流:从截图到信息交付的重构

1. 为什么Mac用户真正需要的不是“截图”,而是“长图工作流”在Mac上截一张全屏图,CommandShift3按下去,咔嚓一声完事——这谁不会?但真到用的时候,比如要保存网页长评论、导出微信聊天记录、抓取滚动的API文档、录下整… · 2026/9/23 11:16:52

为什么会这样源码解析
为什么会这样源码解析

3步拆解报错逻辑:一文搞懂为什么代码会这样 看了一堆教程还是不会写项目?别慌,这太正常了。 大多数人的卡点不在语法,而在不知道 为什么会这样 。 今天不背八股文,我们直接上手一个极简的日志监控系统。… · 2026/9/23 11:16:52

3招搞定手机怎么下载微信面试难题实战项目解析
3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A… · 2026/9/23 0:00:03

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型
你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型

你有新短消息请注意查收:3个新手避坑指南搞定消息系统选型 面试被问“高并发下如何保证消息不丢失”,你张口就是“用Redis”,结果面试官追问“如果Redis宕机了怎么办”,你瞬间卡壳。这种场景太常见了,很多新手在背八股文时,只记住了技术名词… · 2026/9/23 0:00:29

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧
Win7无线热点配置工具源码解析:解决API失效的3个实战技巧

Win7无线热点配置工具源码解析:解决API失效的3个实战技巧 Win7无线热点配置工具在Win10/11上跑不动?不是你的问题,是版本升级后 API 全变了。很多老项目里的 netsh wlan… · 2026/9/23 0:00:36

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码