8. COSE 使用的算法分类
- COSE 使用的算法分类
本节给出可在 COSE 中使用的不同算法类型的分类. 此分类不应被视为穷尽性的. 未来会创建新的算法, 它们可能不适合此分类.
8.1. 签名算法
签名算法提供数据来源和数据完整性服务. 数据来源提供一种能力, 即基于谁签署了数据来推断数据由谁发起. 数据完整性提供一种能力, 即验证数据自签署以来未被修改.
签名算法方案一般有两类. 第一类是带附录的签名. 在此方案中, 处理消息内容并生成签名; 该签名称为附录. ECDSA 和 RSA Probabilistic Signature Scheme (RSASSA-PSS) 等算法使用此方案. (实际上, RSASSA-PSS 中的 SSA 表示 Signature Scheme with Appendix.)
此方案的签名函数为:
signature = Sign(message content, key)
valid = Verification(message content, key, signature)
第二类方案是带消息恢复的签名; [PVSig] 是这类算法的一个示例. 在此方案中, 消息内容会被处理, 但其中一部分会包含在签名中. 将消息内容的字节移入签名可以使已签名消息更小; 签名大小仍可能较大, 但消息内容已经缩小. 这会影响实现这些算法的系统以及使用它们的应用. 第一, 在签名被验证之前, 消息内容并不完全可用. 在那之前, 包含在签名内部的那部分消息无法恢复. 第二个影响是, 对签名强度的安全分析可能在很大程度上依赖消息内容的结构. 最后, 如果对一条消息应用多个签名, 所有签名算法都将需要消费相同的消息内容字节. 这意味着在单条消息中不支持混合带消息恢复的签名方案和带附录的签名方案.
此方案的签名函数为:
signature, message sent = Sign(message content, key)
valid, message content = Verification(message sent, key, signature)
目前尚未为 COSE 正式定义任何消息恢复签名算法. 鉴于此方案带来的新约束, 虽然一些问题已经被识别, 但在集成消息恢复签名算法时很可能还会出现其他问题. 第一个被定义的算法将需要对这些问题作出决策, 而这些决策很可能会约束之后定义的任何算法.
下文使用以下术语:
message content bytes: 应用提供给签名操作的字节串.
to-be-signed bytes: 传入签名算法的字节串.
recovered bytes: 在签名验证过程中恢复出的字节.
已经识别出的一些问题包括:
-
to-be-signed bytes 与 message content bytes 并不相同. 这是因为在签名处理期间会构造一条更大的待签名消息. recovered bytes 的长度可能超过 message content 的长度, 但不会超过 to-be-signed bytes 的长度. 例如, 如果外部提供的数据包含机密信息, 这可能引出隐私考虑事项.
-
可能难以确定 recovered bytes 与 to-be-signed bytes 的对应位置, 因为 recovered bytes 包含不在 message content bytes 中的数据. 一种可能的选择是创建填充方案来防止这种情况.
-
并非所有消息恢复签名算法都从 to-be-signed bytes 的末尾获取 recovered bytes. 这是一个问题, 因为 message content bytes 位于 to-be-signed bytes 的末尾. 如果待恢复的字节从 to-be-signed bytes 的开头取得, 那么默认情况下, recovered bytes 中可能不包含任何 message content bytes. 一种可能的处理方式是, 当 recovered bytes 从 to-be-signed bytes 的开头而不是末尾取得时, 反转 to-be-signed 数据.
签名算法与 COSE_Signature 和 COSE_Sign1 结构一起使用. 在撰写本文时, 只定义了带附录的签名供 COSE 使用; 然而, 由于可能实现有效的大小缩减, 使用带消息恢复的签名算法已经引起相当大的兴趣.
8.2. Message Authentication Code (MAC) 算法
Message Authentication Code (MAC) 提供数据认证和完整性保护. 它们不提供或仅提供非常有限的数据来源. 例如, MAC 不能用于向第三方证明发送者的身份.
MAC 使用与带附录签名算法相同的方案. 消息内容被处理, 并生成认证码. 该认证码通常称为 tag.
MAC 函数为:
tag = MAC_Create(message content, key)
valid = MAC_Verify(message content, key, tag)
MAC 算法可以基于分组密码算法 (即 AES-MAC) 或散列算法 (即 Hash-based Message Authentication Code (HMAC)). [RFC9053] 使用这两种构造各定义了一种 MAC 算法.
MAC 算法用于 COSE_Mac 和 COSE_Mac0 结构.
8.3. 内容加密算法
内容加密算法使用对称密钥为可能很大的数据块提供数据机密性. 它们为被加密的数据提供完整性; 但是, 它们不提供或仅提供非常有限的数据来源. (例如, 不能用它向第三方证明发送者的身份.) 提供数据来源的能力与 CEK 的获取方式相关.
COSE 将合法内容加密算法集合限制为同时支持对内容和附加数据进行认证的算法. 加密过程会生成某种类型的认证值, 但从算法定义角度看, 该值可能是显式的, 也可能是隐式的. 为简单起见, 认证码通常被定义为附加到 ciphertext 流之后. 加密函数为:
ciphertext = Encrypt(message content, key, additional data)
valid, message content = Decrypt(ciphertext, key, additional data)
大多数 AEAD 算法在逻辑上定义为仅当解密有效时才返回消息内容. 许多实现会遵循此约定, 但并非全部. 如果解密未通过验证, MUST NOT 使用消息内容.
这些算法用于 COSE_Encrypt 和 COSE_Encrypt0.
8.4. Key Derivation Functions (KDFs)
KDF 用于接受某个 secret 值并生成另一个不同的值. secret 值有三类:
-
均匀随机的 secret. 这是由良好随机数生成器创建的 secret 类型.
-
非均匀随机的 secret. 这是由密钥协商等操作创建的 secret 类型.
-
非随机的 secret. 这是人们为密码等事物生成的 secret 类型.
通用 KDF 很适合第一类 secret, 对第二类 secret 可以做得相当不错, 但通常不适合最后一类 secret. 对于非随机 secret, 需要使用 Argon2 [RFC9106] 这样的函数.
同一个 KDF 可以被设置为以不同方式处理前两类 secret. [RFC9053] Section 5.1 中定义的 KDF 就是这样的函数. 这反映在围绕 HMAC-based Extract-and-Expand Key Derivation Function (HKDF) 定义的一组算法中.
使用 KDF 时, 包含的一个组件是上下文信息. 上下文信息用于允许从同一 secret 派生出不同的密钥信息. 使用基于上下文的密钥材料被认为是良好的安全实践.
8.5. 内容密钥分发方法
内容密钥分发方法 (recipient 算法) 可以定义为若干不同类别. COSE 能够支持多类 recipient 算法. 本节列出若干类别. 对于 [RFC7516] 中定义的 recipient 算法类别, 使用相同名称. 其他规范可能对 recipient 算法类别使用不同术语, 或不支持某些 recipient 算法类别.
8.5.1. Direct Encryption
Direct Encryption 类算法在发送者和 recipient 之间共享一个 secret, 该 secret 直接或经处理后用作 CEK. 使用 direct-encryption 模式时, 它 MUST 是消息上唯一使用的模式.
recipient 的 COSE_Recipient 结构组织如下:
-
"protected" 字段 MUST 是零长度字节串, 除非它用于内容密钥的计算.
-
"alg" header 参数 MUST 存在.
-
标识共享 secret 的 header 参数 SHOULD 存在.
-
"ciphertext" 字段 MUST 是零长度字节串.
-
"recipients" 字段 MUST 不存在.
8.5.2. Key Wrap
在 key wrap 模式中, CEK 随机生成, 然后使用发送者与 recipient 之间的共享 secret 对该密钥加密. 当前为 COSE 定义的所有 key wrap 算法都是 AE 算法. 如果系统具备任何随机密钥生成能力, key wrap 模式被认为优于 Direct Encryption. 这是因为共享密钥用于 wrap 随机数据, 而不是具有某种组织结构且事实上可能重复相同内容的数据. 使用 key wrap 会失去 direct-encryption 算法提供的弱数据来源属性.
recipient 的 COSE_Recipient 结构组织如下:
-
如果 key wrap 算法是 AE 算法, "protected" 字段 MUST 是零长度字节串.
-
"recipients" 字段通常不存在, 但可以使用. 应用 MUST 处理存在 recipient 字段且其中算法不受支持的情况. 无法解密该特定 recipient 是一种可接受的处理方式. 无法处理该消息不是一种可接受的处理方式.
-
待加密的 plaintext 是下一层向下的密钥 (通常是内容层).
-
至少, "unprotected" 字段 MUST 包含 "alg" header 参数, 并且 SHOULD 包含标识共享 secret 的 header 参数.
8.5.3. Key Transport
在某些标准中, key transport 模式也称为 key encryption 模式. key transport 模式不同于 key wrap 模式, 因为它使用非对称加密算法而不是对称加密算法来保护密钥. [RFC8230] 定义了一组 key transport 算法.
使用 key transport 算法时, recipient 的 COSE_Recipient 结构组织如下:
-
"protected" 字段 MUST 是零长度字节串.
-
待加密的 plaintext 是下一层向下的密钥 (通常是内容层).
-
至少, "unprotected" 字段 MUST 包含 "alg" header 参数, 并且 SHOULD 包含标识非对称密钥的参数.
8.5.4. Direct Key Agreement
Direct Key Agreement 类 recipient 算法使用密钥协商方法创建共享 secret. 然后对该共享 secret 应用 KDF, 派生一个用于保护数据的密钥. 该密钥通常用作 CEK 或 MAC 密钥, 但如果使用超过两层, 也可用于其他目的 (见 Appendix B).
最常用的密钥协商算法是 Diffie-Hellman, 但也存在其他变体. 由于 COSE 设计用于存储转发环境而不是在线环境, 许多 DH 变体无法使用, 因为消息接收方无法提供任何动态密钥材料. 其副作用之一是无法实现前向保密 (见 [RFC4949]). COSE 对象的接收方始终会使用静态密钥.
支持的两个 DH 变体是:
Ephemeral-Static (ES) DH: 消息发送者创建一次性 DH 密钥, 并为 recipient 使用静态密钥. 使用临时发送者密钥意味着不需要额外随机输入, 因为它会为每条消息随机生成.
Static-Static (SS) DH: 发送者和 recipient 都使用静态密钥. 使用静态密钥允许 recipient 获得消息数据来源的弱版本. 使用 Static-Static 密钥协商时, KDF 需要某些唯一数据, 以确保为每条消息创建不同密钥.
使用 direct key agreement 模式时, 消息中 MUST 只有一个 recipient. 此方法直接创建密钥, 因而难以与其他 recipient 混合. 如果需要多个 recipient, 则需要使用带 key wrap 的版本.
recipient 的 COSE_Recipient 结构组织如下:
-
至少, headers MUST 包含 "alg" header 参数, 并且 SHOULD 包含标识 recipient 非对称密钥的 header 参数.
-
对于 Static-Static 版本, headers SHOULD 标识发送者的密钥; 对于 ephemeral-static 版本, headers MUST 包含发送者的临时密钥.
8.5.5. Key Agreement with Key Wrap
Key Agreement with Key Wrap 使用随机生成的 CEK. 然后使用 key wrap 算法和从密钥协商算法计算出的共享 secret 派生的密钥对 CEK 加密. 其函数为:
encryptedKey = KeyWrap(KDF(DH-Shared, context), CEK)
recipient 的 COSE_Recipient 结构组织如下:
-
"protected" 字段被输入到 KDF context 结构中.
-
待加密的 plaintext 是下一层向下的密钥 (通常是内容层).
-
该层中 MUST 存在 "alg" header 参数.
-
标识 recipient 密钥的 header 参数 SHOULD 存在. 标识发送者密钥的 header 参数 SHOULD 存在.