ARTICLE DETAIL

资讯详情

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

jose 中 Recipient 接口完全指南:构建多接收者 General JWE 的逐接收者加密配置

jose 中 Recipient 接口完全指南:构建多接收者 General JWE 的逐接收者加密配置 网络安全认证鉴权后端【免费下载链接】joseJWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes项目地址https://gitcode.com/gh_mirrors/jo/jose点击查看免费下载本篇指南以 jose 项目官方 API 文档 docs/jwe/general/encrypt/interfaces/Recipient.md 为骨架完整讲解Recipient接口的五个方法、参数类型与返回值并结合 src/jwe/general/encrypt.ts 的源码实现与 test/jwe/general.test.ts 的测试用例进行纵深剖析。读完本文你将掌握如何使用GeneralEncrypt为不同接收者配置各自的密钥管理算法alg与逐接收者 Header如何通过setKeyManagementParameters注入 ECDH-ES 的apu/apv与 PBES2 的p2c参数以及多接收者场景下底层encrypt()的校验规则与 CEK 共享机制。Recipient 是什么General JWE 对象的单个接收者构建器在 General JSON Serialization 中一个 JWE 对象可以同时携带多个接收者recipient每个接收者拥有独立的密钥封装结果encrypted_key与可选 Header。jose 中的Recipient接口正是用于构建这种 General JWE 对象中单个接收者的中间句柄。官方文档对其定位只有一句话Used to build General JWE objects individual recipients.它在整个加密流程中的位置是每次调用GeneralEncrypt.addRecipient(key)都会返回一个新的Recipient对象你可以在这个对象上继续链式调用setUnprotectedHeader()、setKeyManagementParameters()配置该接收者专属的信息然后再添加下一个接收者最后调用encrypt()完成整个 General JWE 的加密。相关类的说明见 GeneralEncrypt 类文档 与 General JWE 加密模块入口。方法总览Recipient接口共声明 5 个方法下表为完整签名方法签名说明addRecipient()addRecipient(key: KeyInput, options?: CritOption): Recipient在外层 GeneralEncrypt 实例上追加一个新接收者对GeneralEncrypt.addRecipient()的简写转发done()done(): GeneralEncrypt返回包裹当前 Recipient 的外层GeneralEncrypt实例encrypt()encrypt(): PromiseGeneralJWE触发加密并解析出 General JWE 对象对GeneralEncrypt.encrypt()的简写转发无参数每个接收者的密钥已由各自的addRecipient提供setKeyManagementParameters()setKeyManagementParameters(parameters: JWEKeyManagementHeaderParameters): Recipient设置 JWE 密钥管理参数如 ECDH-ES 的apu/apv、PBES2 的p2c这些参数会被写入合适的 JOSE HeadersetUnprotectedHeader()setUnprotectedHeader(unprotectedHeader: JWEHeaderParameters): Recipient设置 JWE Per-Recipient Unprotected Header仅属于该接收者、不受完整性保护的 Header其中addRecipient()、encrypt()、done()是转发型方法它们把调用原样转发给创建该 Recipient 的外层GeneralEncrypt实例setUnprotectedHeader()与setKeyManagementParameters()是配置型方法负责写入该接收者自身的状态。逐方法详解addRecipient(key, options?)追加下一个接收者▸ addRecipient(key, options?): Recipient这是对外层GeneralEncrypt.addRecipient()的简写调用官方文档原文A shorthand for calling addRecipient() on the enclosing GeneralEncrypt instance。它允许你在构建一个接收者配置的中间直接追加下一个接收者而不必先取回外层实例。参数说明参数类型说明keyKeyInput用于为该接收者加密 Content Encryption KeyCEK的公钥或密钥。不同算法对密钥的曲率/位长/用途有不同要求options?CritOptionJWE 加密选项目前仅含critCritical Header声明KeyInput是CryptoKey | KeyObject | JWK | Uint8Array的联合类型见 KeyInput 类型别名即Web Crypto 的CryptoKey、Node.js 的KeyObject、JWK 对象或裸密钥字节Uint8Array用于dir直加密与 AES-KW / AES-GCMKW / PBES2 等对称算法。options.crit是一个{ [propName: string]: boolean }对象true表示该 Header 参数必须被完整性保护false表示不关心它只做语法与完整性校验不会替你处理该参数的含义详见 CritOption。在源码 src/jwe/general/encrypt.ts 中IndividualRecipient.addRecipient()的实现只是简单的参数转发addRecipient(...args: ParametersGeneralEncrypt[addRecipient]) { return this.#parent.addRecipient(...args) }因此Recipient.addRecipient(key)与generalEncrypt.addRecipient(key)完全等价返回值同样是新的Recipient。setUnprotectedHeader(unprotectedHeader)设置 Per-Recipient Unprotected Header▸ setUnprotectedHeader(unprotectedHeader): Recipient官方文档定义Sets the JWE Per-Recipient Unprotected Header on the Recipient object. 这个 Header 只隶属于当前接收者在最终序列化时写入该接收者条目内的header成员并且不参与完整性保护区别于setProtectedHeader设置的、被 base64url 编码进protected的 Header。这是最常用的配置入口——绝大多数多接收者场景用它来给每个接收者指定不同的alg。参数类型为JWEHeaderParameters该接口收录了alg、enc、crit、cty、jku、jwk、kid、typ、x5c、x5t、x5u、zip等标准 JWE Header 参数同时允许通过索引签名携带任意自定义成员。源码实现src/jwe/general/encrypt.ts利用assertNotSet保证一个接收者上只能调用一次该方法setUnprotectedHeader(unprotectedHeader: types.JWEHeaderParameters): this { assertNotSet(this.state[0], setUnprotectedHeader) this.state[0] unprotectedHeader return this }重复调用会抛出ERR_JWE_INVALID错误。setKeyManagementParameters(parameters)注入密钥管理算法参数▸ setKeyManagementParameters(parameters): Recipient这是Recipient最独特的方法。官方文档明确说明请用它而不是 Header setter来配置算法输入例如ECDH-ES 系列的apuAgreement PartyUInfo与apvAgreement PartyVInfo——用于 ECDH 的 ConcatKDF 密钥派生PBES2 系列的p2cPBES2 Count——即 PBKDF2 迭代次数。这些参数会被自动写入合适的 JOSE Header。参数类型为JWEKeyManagementHeaderParameters其可用成员如下成员类型说明apu?Uint8ArrayECDH-ES apuAgreement PartyUInfo作为 JOSE Header 参数参与 ConcatKDFapv?Uint8ArrayECDH-ES apvAgreement PartyVInfo作为 JOSE Header 参数参与 ConcatKDFp2c?numberPBES2 p2cPBES2 Count作为 JOSE Header 参数与 PBKDF2 迭代次数epk?CryptoKey \| KeyObject已弃用仅用于测试与向量校验iv?Uint8Array已弃用仅用于测试与向量校验p2s?Uint8Array已弃用仅用于测试与向量校验源码实现同样带单次调用约束src/jwe/general/encrypt.tssetKeyManagementParameters(parameters: types.JWEKeyManagementHeaderParameters): this { assertNotSet(this.state[1], setKeyManagementParameters) this.state[1] parameters return this }关于这些参数最终落在哪个 Header测试 test/jwe/general.test.ts 揭示了两种行为单接收者p2c、apu、apv等派生/注入参数进入JWE Protected Header受完整性保护如setKeyManagementParameters({ p2c: 4096 })后protectedHeader(jwe).p2c 4096多接收者生成的密钥管理参数进入该接收者的Per-Recipient Unprotected Header因此必须保证与其它 Header 名称不冲突详见下文Disjoint 校验。encrypt()触发加密并返回 GeneralJWE▸ encrypt(): PromiseGeneralJWE官方文档原文A shorthand for calling encrypt() on the enclosing GeneralEncrypt instance. Takes no arguments — each recipients key is supplied to addRecipient. 即该方法不需要任何参数因为每个接收者的密钥已经在各自addRecipient(key)调用时提供完毕。返回值是PromiseGeneralJWEGeneralJWE即 General JWE JSON Serialization 令牌其成员包括必选的ciphertext与recipients可选的aad、iv、protected、tag、unprotected。其中recipients是PickFlattenedJWE, header | encrypted_key[]数组——每个元素只含encrypted_key和/或header这正是Recipient对象状态在最终结果中的落点。源码中IndividualRecipient.encrypt()同样是纯转发src/jwe/general/encrypt.ts。done()取回外层 GeneralEncrypt▸ done(): GeneralEncrypt官方文档原文Returns the enclosing GeneralEncrypt instance。当你想在某个接收者配置完成后退回外层对象继续调用setProtectedHeader()、setSharedUnprotectedHeader()、setAdditionalAuthenticatedData()等外层方法时使用。实现为一行src/jwe/general/encrypt.tsdone() { return this.#parent }完整实战一个双接收者 General JWE 的构建与输出综合官方 GeneralEncrypt 类文档 中的示例与测试 test/jwe/general.test.ts 的双接收者场景完整可运行代码如下import * as jose from jose const plaintext new TextEncoder().encode(It’s a dangerous business, Frodo, going out your door.) // 假设 ecPublicKey 为 EC 公钥rsaPublicKey 为 RSA 公钥 const jwe await new jose.GeneralEncrypt(plaintext) .setProtectedHeader({ enc: A256GCM }) // 内容加密算法所有接收者共享 .addRecipient(ecPublicKey) // 接收者 1 .setUnprotectedHeader({ alg: ECDH-ESA256KW }) // 接收者 1 的密钥管理算法 .addRecipient(rsaPublicKey) // 接收者 2 .setUnprotectedHeader({ alg: RSA-OAEP-384 }) // 接收者 2 的密钥管理算法 .encrypt() console.log(jwe)输出结构形如成员顺序可能不同{ protected: eyJlbmMiOiJBMjU2R0NNIn0..., iv: ..., ciphertext: ..., tag: ..., recipients: [ { header: { alg: ECDH-ESA256KW, epk: { kty: EC, crv: P-256, x: ..., y: ... } }, encrypted_key: ... }, { header: { alg: RSA-OAEP-384 }, encrypted_key: ... } ] }可见enc进入共享的protectedHeader而每个接收者各自的alg以及 ECDH-ES 生成的epk落在各自的header中encrypted_key则是用该接收者密钥封装的 CEK。解密时任一接收者的私钥/密钥都可解开对应的encrypted_key从而解出同一份明文——这就是多接收者 JWE 的核心价值一次加密多个持有不同密钥的人都能解密。如果希望在同一接收者上同时使用setKeyManagementParameters配置 PBES2 计数可以这样写对应测试 test/jwe/general.test.tsconst jwe await new jose.GeneralEncrypt(plaintext) .setProtectedHeader({ alg: PBES2-HS256A128KW, enc: A128GCM }) .addRecipient(secret) // 对称密钥 .setKeyManagementParameters({ p2c: 4096 }) // 自定义 PBKDF2 迭代次数 .encrypt()不指定p2c时默认值为2048且每个接收者的p2s盐值各自随机生成、互不相同测试见 test/jwe/general.test.ts。源码级原理IndividualRecipient 状态与 encrypt() 的多接收者流程Recipient是接口其具体实现是IndividualRecipient类src/jwe/general/encrypt.ts。每个实例内部维护一个四元组状态type RecipientState [ unprotectedHeader: types.JWEHeaderParameters | undefined, keyManagementParameters: types.JWEKeyManagementHeaderParameters | undefined, key: types.KeyInput, crit: types.CritOption[crit], ]并通过#parent私有字段持有外层GeneralEncrypt引用。GeneralEncrypt.addRecipient()src/jwe/general/encrypt.ts在内部#recipients数组中 push 一个新的IndividualRecipient并返回它addRecipient(key: types.KeyInput, options?: types.CritOption): Recipient { const recipient new IndividualRecipient(this, key, options?.crit) this.#recipients.push(recipient) return recipient }真正加密发生在外层GeneralEncrypt.encrypt()src/jwe/general/encrypt.ts其多接收者分支的关键逻辑如下必须至少有一个接收者否则抛出JWEInvalid(at least one recipient must be added)单接收者优化若只有一个接收者走createJWE的 flattened 路径结果仍包装为 General 形式recipients: [{}]此时Recipient配置的alg等可进入 protected 或 shared unprotected Header对应测试 test/jwe/general.test.tsdir与ECDH-ES只能有单个接收者这两类算法直接确定/派生 CEK无法为多个接收者独立封装多接收者场景下抛JWEInvalid(dir alg may only have a single recipient)等错误enc必须全局一致所有接收者共享同一个内容加密算法不一致时抛JWEInvalid(JWE enc ... must be the same for all recipients)共享 CEK多接收者场景只调用一次generateCek(checked[0][3])生成一个 CEK第一个接收者完成内容加密产出ciphertext、iv、tag后续接收者仅用各自的密钥对同一个 CEK 做密钥封装encryptKeyManagement并将封装结果 base64url 编码后写入各自条目的encrypted_keyDisjoint 校验若密钥管理算法产生了新的 Header 参数如 ECDH-ES 的epk、PBES2 的p2s/p2c这些参数会合并进该接收者的 Per-Recipient Header并调用checkDisjoint确保protected、Shared Unprotected 与 Per-Recipient Header 的参数名互不重叠RFC 7516 §7.2.1 要求否则抛ERR_JWE_INVALID测试见 test/jwe/general.test.ts。另外值得注意的是encrypt()对 Header 只读取一次测试 test/jwe/general.test.ts 用 getter 验证了protectedHeader与逐接收者 Header 均只被读取一次并做规范化输出这保证了 API 的确定性行为。边界约束与常见错误一览结合文档类型说明与源码/测试使用Recipient时需注意以下边界每个配置型方法仅能调用一次setUnprotectedHeader与setKeyManagementParameters在同一接收者上重复调用会抛ERR_JWE_INVALIDsetKeyManagementParameters的参数必须是纯对象null、字符串、数组、Date、数字、布尔值都会抛TypeError测试 test/jwe/general.test.tsalg缺失时无法加密多接收者场景若未在任何 Header 指定algencrypt()抛JWEInvalid(JWE alg (Algorithm) Header Parameter missing or invalid)单接收者必须有 JOSE Header单接收者且未调用任何 Header setter 时抛JWEInvalid(either setProtectedHeader, setUnprotectedHeader, or sharedUnprotectedHeader must be called before #encrypt())测试 test/jwe/general.test.tsplaintext 必须是Uint8Array传入ArrayBuffer等其它类型会在encrypt()时抛TypeErrorcrit只做校验、不做处理即使声明了crit中的自定义参数操作成功后的业务侧仍需自行验证其存在性与语义见 CritOption 中的警告。总结与参考路径Recipient是 jose General JWE 加密中连接多个接收者与共享密文的关键接口它用setUnprotectedHeader与setKeyManagementParameters承载逐接收者的算法与密钥管理配置用addRecipient、encrypt、done维护与GeneralEncrypt外层实例之间的流畅链式调用。理解它的方法与状态语义是正确构建多接收者 JWE以及理解底层 CEK 共享、Header 归属与 Disjoint 规则的前提。接口文档docs/jwe/general/encrypt/interfaces/Recipient.md外层类文档docs/jwe/general/encrypt/classes/GeneralEncrypt.md源码实现src/jwe/general/encrypt.tsRecipient接口见 L20-L57IndividualRecipient见 L66-L98GeneralEncrypt.encrypt()见 L200-L332测试用例test/jwe/general.test.ts相关类型KeyInput、CritOption、JWEKeyManagementHeaderParameters、JWEHeaderParameters、GeneralJWE赞分享网络安全认证鉴权后端【免费下载链接】joseJWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes项目地址https://gitcode.com/gh_mirrors/jo/jose点击查看免费下载相关推荐deck.gl OrbitController 深入解析3D 轨道视图交互控制器的用法、选项与自定义扩展deck.gl OrbitController 深入解析3D 轨道视图交互控制器的用法、选项与自定义扩展 导读 OrbitController 是 deck.网络安全认证鉴权后端ScyllaDB nodetool viewbuildstatus 命令详解监控物化视图构建进度ScyllaDB nodetool viewbuildstatus 命令详解监控物化视图构建进度 nodetool viewbuildstatus 用于查询网络安全认证鉴权后端jose 中的 CompactDecryptGetKey 接口Compact JWE 动态密钥解析完全指南jose 中的 CompactDecryptGetKey 接口Compact JWE 动态密钥解析完全指南 导读 本文深入解析 jose 库中 jwe/com网络安全认证鉴权后端上一篇LibTomMath安全编程指南模逆运算与密码学应用最佳实践下一篇Snap.svg SVG动画导出将动效保存为视频或GIF创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表