此翻译是使用机器学习生成的,可能不是100%准确。 查看英文版本

PQ 混合 ECIES-X25519-AEAD-Ratchet

使用 ML-KEM 的 ECIES 加密协议的后量子混合变体

注意

各种 router 实现中的实施、测试和部署正在进行中。请查看这些实现的文档以了解状态。

概述

这是 ECIES-X25519-AEAD-Ratchet 协议 ECIES 的 PQ 混合变体。它是整体 PQ 提案 Prop169 中第一个被批准的阶段。有关总体目标、威胁模型、分析、替代方案和其他信息,请参见该提案。

本规范仅包含与标准 ECIES 的差异,必须与该规范一起阅读。

设计

我们使用 NIST FIPS 203 标准 FIPS203 ,该标准基于但不兼容 CRYSTALS-Kyber(版本 3.1、3 及更早版本)。

混合握手按照 Noise-Hybrid 中的规范执行。

密钥交换

我们为 Ratchet 定义了一种混合密钥交换。PQ KEM 仅提供临时密钥,不直接支持静态密钥握手,如 Noise IK。

我们按照 FIPS203 定义三种 ML-KEM 变体,总共增加了 3 种新的加密类型。混合类型仅与 X25519 结合定义。

新的加密类型包括:

TypeCode
MLKEM512_X255195
MLKEM768_X255196
MLKEM1024_X255197
开销将是巨大的。当前典型的消息1和消息2大小(对于IK)约为100字节(在任何额外载荷之前)。根据算法不同,这将增加8倍到15倍。

需要新的加密技术

  • ML-KEM (原名 CRYSTALS-Kyber) FIPS203
  • SHA3-128 (原名 Keccak-256) FIPS202 仅用于 SHAKE128
  • SHA3-256 (原名 Keccak-512) FIPS202
  • SHAKE128 和 SHAKE256 (SHA3-128 和 SHA3-256 的 XOF 扩展) FIPS202

SHA3-256、SHAKE128 和 SHAKE256 的测试向量可在 NIST-VECTORS 获取。

注意 Java bouncycastle 库支持上述所有算法。C++ 库支持在 OpenSSL 3.5 OPENSSL 中提供。

规范

通用结构

请参阅通用结构规范 COMMON 了解密钥长度和标识符。

握手模式

握手使用Noise 握手模式。

使用以下字母映射:

  • e = 一次性临时密钥
  • s = 静态密钥
  • p = 消息载荷
  • e1 = 一次性临时PQ密钥,从Alice发送到Bob
  • ekem1 = KEM密文,从Bob发送到Alice

以下对 XK 和 IK 的混合前向保密 (hfs) 修改是按照 Noise-Hybrid 第 5 节中的规定进行的:

IK:                         IKhfs:
<- s                        <- s
...                         ...
-> e, es, s, ss, p          -> e, es, e1, s, ss, p
<- tag, e, ee, se, p        <- tag, e, ee, ekem1, se, p
<- p                        <- p
p ->                        p ->

e1 and ekem1 are encrypted. See pattern definitions below.
NOTE: e1 and ekem1 are different sizes (unlike X25519)

e1 模式定义如下,如 Noise-Hybrid 第 4 节所述:

For Alice:
    (encap_key, decap_key) = PQ_KEYGEN()

    // EncryptAndHash(encap_key)
    ciphertext = ENCRYPT(k, n, encap_key, ad)
    n++
    MixHash(ciphertext)

For Bob:
    // DecryptAndHash(ciphertext)
    encap_key = DECRYPT(k, n, ciphertext, ad)
    n++
    MixHash(ciphertext)

ekem1模式定义如下,如Noise-Hybrid 第4节所述:

For Bob:
    (kem_ciphertext, kem_shared_key) = ENCAPS(encap_key)

    // EncryptAndHash(kem_ciphertext)
    ciphertext = ENCRYPT(k, n, kem_ciphertext, ad)
    MixHash(ciphertext)

    // MixKey
    MixKey(kem_shared_key)

For Alice:
    // DecryptAndHash(ciphertext)
    kem_ciphertext = DECRYPT(k, n, ciphertext, ad)
    MixHash(ciphertext)

    // MixKey
    kem_shared_key = DECAPS(kem_ciphertext, decap_key)
    MixKey(kem_shared_key)

已定义的 ML-KEM 操作

我们定义以下函数,对应于 FIPS203 中定义的加密构建块。

(encap_key, decap_key) = PQ_KEYGEN()

Alice 创建封装密钥和解封装密钥。封装密钥在 NS 消息中发送。encap_key 和 decap_key 的大小根据 ML-KEM 变体而变化。

(ciphertext, kem_shared_key) = ENCAPS(encap_key)

Bob 使用在 NS 消息中接收到的密文计算密文和共享密钥。密文在 NSR 消息中发送。密文大小根据 ML-KEM 变体而变化。kem_shared_key 始终为 32 字节。

kem_shared_key = DECAPS(ciphertext, decap_key)

Alice 使用在 NSR 消息中收到的密文计算共享密钥。kem_shared_key 始终为 32 字节。

请注意,encap_key 和 ciphertext 都在 Noise 握手消息 1 和 2 中的 ChaCha/Poly 块内被加密。它们将作为握手过程的一部分被解密。

kem_shared_key 通过 MixHash() 混合到链式密钥中。详见下文。

Noise 握手 KDF

概述

混合握手在 Noise-Hybrid 中定义。第一条消息从 Alice 发送到 Bob,在消息载荷之前包含 e1(封装密钥)。这被视为一个额外的静态密钥;对其调用 EncryptAndHash()(作为 Alice)或 DecryptAndHash()(作为 Bob)。然后照常处理消息载荷。

第二条消息,从 Bob 发送给 Alice,在消息载荷之前包含 ekem1,即密文。这被视为一个额外的静态密钥;对其调用 EncryptAndHash()(作为 Bob)或 DecryptAndHash()(作为 Alice)。然后,计算 kem_shared_key 并调用 MixKey(kem_shared_key)。接着按常规处理消息载荷。

Noise 标识符

这些是 Noise 初始化字符串:

  • “Noise_IKhfselg2_25519+MLKEM512_ChaChaPoly_SHA256”
  • “Noise_IKhfselg2_25519+MLKEM768_ChaChaPoly_SHA256”
  • “Noise_IKhfselg2_25519+MLKEM1024_ChaChaPoly_SHA256”

NS消息的Alice KDF

在 ’es’ 消息模式之后和 ’s’ 消息模式之前,添加:

This is the "e1" message pattern:

    (encap_key, decap_key) = PQ_KEYGEN()

    // EncryptAndHash(encap_key)
    // AEAD parameters
    k = keydata[32:63]
    n = 0
    ad = h
    ciphertext = ENCRYPT(k, n, encap_key, ad)
    n++

    // MixHash(ciphertext)
    h = SHA256(h || ciphertext)

End of "e1" message pattern.

NOTE: For the next section (payload for XK or static key for IK),
the keydata and chain key remain the same, and n now equals 1
(instead of 0 for non-hybrid).

NS 消息的 Bob KDF

在 ’es’ 消息模式之后和 ’s’ 消息模式之前,添加:

This is the "e1" message pattern:

    // DecryptAndHash(encap_key_section)
    // AEAD parameters
    k = keydata[32:63]
    n = 0
    ad = h
    encap_key = DECRYPT(k, n, encap_key_section, ad)
    n++

    // MixHash(encap_key_section)
    h = SHA256(h || encap_key_section)

End of "e1" message pattern.

NOTE: For the next section (payload for XK or static key for IK),
the keydata and chain key remain the same, and n now equals 1
(instead of 0 for non-hybrid).

NSR 消息的 Bob KDF

在 ’ee’ 消息模式之后和 ‘se’ 消息模式之前,添加:

This is the "ekem1" message pattern:

    (kem_ciphertext, kem_shared_key) = ENCAPS(encap_key)

    // EncryptAndHash(kem_ciphertext)
    // AEAD parameters
    k = keydata[32:63]
    n = 0
    ad = h
    ciphertext = ENCRYPT(k, n, kem_ciphertext, ad)

    // MixHash(ciphertext)
    h = SHA256(h || ciphertext)

    // MixKey(kem_shared_key)
    keydata = HKDF(chainKey, kem_shared_key, "", 64)
    chainKey = keydata[0:31]

End of "ekem1" message pattern.

Alice KDF for NSR 消息

在 ’ee’ 消息模式之后和 ‘ss’ 消息模式之前,添加:

This is the "ekem1" message pattern:

    // DecryptAndHash(kem_ciphertext_section)
    // AEAD parameters
    k = keydata[32:63]
    n = 0
    ad = h
    kem_ciphertext = DECRYPT(k, n, kem_ciphertext_section, ad)

    // MixHash(kem_ciphertext_section)
    h = SHA256(h || kem_ciphertext_section)

    // MixKey(kem_shared_key)
    kem_shared_key = DECAPS(kem_ciphertext, decap_key)
    keydata = HKDF(chainKey, kem_shared_key, "", 64)
    chainKey = keydata[0:31]

End of "ekem1" message pattern.

split() 的密钥派生函数

未更改

消息格式

NS 格式

变更:当前的 ratchet 在第一个 ChaCha 部分包含静态密钥,在第二部分包含载荷。使用 ML-KEM 后,现在有三个部分。第一部分包含加密的 PQ 公钥。第二部分包含静态密钥。第三部分包含载荷。

加密格式:

+----+----+----+----+----+----+----+----+
|                                       |
+         New Session Ephemeral         +
|            Public Key                 |
+            32 bytes                   +
|      Encoded with Elligator2          |
+----+----+----+----+----+----+----+----+
|                                       |
+         ML-KEM encap_key              +
|       ChaCha20 encrypted data         |
+   (see table below for length)        +
|                                       |
~                                       ~
|                                       |
+----+----+----+----+----+----+----+----+
|  Poly1305 Message Authentication Code |
+      (MAC) for encap_key Section      +
|              16 bytes                 |
+----+----+----+----+----+----+----+----+
|                                       |
+         X25519 Static Key             +
|       ChaCha20 encrypted data         |
+            32 bytes                   +
|                                       |
+----+----+----+----+----+----+----+----+
|  Poly1305 Message Authentication Code |
+     (MAC) for Static Key Section      +
|              16 bytes                 |
+----+----+----+----+----+----+----+----+
|                                       |
+          Payload Section              +
|       ChaCha20 encrypted data         |
~                                       ~
|                                       |
+----+----+----+----+----+----+----+----+
|  Poly1305 Message Authentication Code |
+      (MAC) for Payload Section        +
|              16 bytes                 |
+----+----+----+----+----+----+----+----+

解密格式:

Payload Part 1:

+----+----+----+----+----+----+----+----+
|                                       |
+         ML-KEM encap_key              +
|                                       |
+   (see table below for length)        +
|                                       |
~                                       ~
|                                       |
+----+----+----+----+----+----+----+----+

Payload Part 2:

+----+----+----+----+----+----+----+----+
|                                       |
+         X25519 Static Key             +
|            (32 bytes)                 |
+                                       +
|                                       |
+----+----+----+----+----+----+----+----+

Payload Part 3:

+----+----+----+----+----+----+----+----+
|                                       |
+          Payload Section              +
|                                       |
~                                       ~
|                                       |
+                                       +
|                                       |
+----+----+----+----+----+----+----+----+

大小:

TypeType CodeX lenNS lenNS Enc lenNS Dec lenPQ key lenpl len
X2551943296+pl64+plpl--pl
MLKEM512_X25519532912+pl880+pl800+pl800pl
MLKEM768_X255196321296+pl1360+pl1184+pl1184pl
MLKEM1024_X255197321680+pl1648+pl1568+pl1568pl
注意载荷必须包含一个 DateTime 块,所以最小载荷大小是 7。最小 NS 大小可以相应地计算出来。

NSR 格式

变更:当前的 ratchet 在第一个 ChaCha 部分有一个空负载,而负载在第二部分。使用 ML-KEM 后,现在有三个部分。第一部分包含加密的 PQ 密文。第二部分有一个空负载。第三部分包含负载。

加密格式:

+----+----+----+----+----+----+----+----+
|       Session Tag 8 bytes             |
+----+----+----+----+----+----+----+----+
|                                       |
+       Ephemeral Public Key            +
|            32 bytes                   |
+      Encoded with Elligator2          +
|                                       |
+----+----+----+----+----+----+----+----+
|                                       |
+         ML-KEM ciphertext             +
|       ChaCha20 encrypted data         |
+   (see table below for length)        +
|                                       |
~                                       ~
|                                       |
+----+----+----+----+----+----+----+----+
|  Poly1305 Message Authentication Code |
+     (MAC) for ciphertext Section      +
|              16 bytes                 |
+----+----+----+----+----+----+----+----+
|  Poly1305 Message Authentication Code |
+   (MAC) for key Section (no data)     +
|              16 bytes                 |
+----+----+----+----+----+----+----+----+
|                                       |
+          Payload Section              +
|       ChaCha20 encrypted data         |
~                                       ~
|                                       |
+                                       +
|                                       |
+----+----+----+----+----+----+----+----+
|  Poly1305 Message Authentication Code |
+      (MAC) for Payload Section        +
|              16 bytes                 |
+----+----+----+----+----+----+----+----+

解密格式:

Payload Part 1:

+----+----+----+----+----+----+----+----+
|                                       |
+         ML-KEM ciphertext             +
|                                       |
+   (see table below for length)        +
|                                       |
~                                       ~
|                                       |
+----+----+----+----+----+----+----+----+

Payload Part 2:

empty

Payload Part 3:

+----+----+----+----+----+----+----+----+
|                                       |
+          Payload Section              +
|                                       |
~                                       ~
|                                       |
+                                       +
|                                       |
+----+----+----+----+----+----+----+----+

大小:

TypeType CodeY lenNSR lenNSR Enc lenNSR Dec lenPQ CT lenopt len
X2551943272+pl32+plpl--pl
MLKEM512_X25519532856+pl816+pl768+pl768pl
MLKEM768_X255196321176+pl1136+pl1088+pl1088pl
MLKEM1024_X255197321656+pl1616+pl1568+pl1568pl
请注意,虽然 NSR 通常会有非零载荷,但 ratchet 规范 [ECIES](/docs/specs/ecies/) 并不要求如此,因此最小载荷大小为 0。可以相应地计算最小 NSR 大小。

开销分析

密钥交换

大小增加(字节):

TypePubkey (NS)Ciphertext (NSR)
MLKEM512_X25519+816+784
MLKEM768_X25519+1200+1104
MLKEM1024_X25519+1584+1584
速度:

CLOUDFLARE 报告的速度:

TypeRelative speed
X25519 DH/keygenbaseline
MLKEM5122.25x faster
MLKEM7681.5x faster
MLKEM10241x (same)
XK4x DH (keygen + 3 DH)
MLKEM512_X255194x DH + 2x PQ (keygen + enc/dec) = 4.9x DH = 22% slower
MLKEM768_X255194x DH + 2x PQ (keygen + enc/dec) = 5.3x DH = 32% slower
MLKEM1024_X255194x DH + 2x PQ (keygen + enc/dec) = 6x DH = 50% slower
## 安全分析

NIST安全类别在NIST-PQ-END 第10页幻灯片中有总结。初步标准:我们的最低NIST安全类别对于混合协议应为2,对于纯PQ协议应为3。

CategoryAs Secure As
1AES128
2SHA256
3AES192
4SHA384
5AES256
### 握手

这些都是混合协议。可能需要优先选择 MLKEM768;MLKEM512 的安全性不够。

NIST 安全类别 FIPS203

AlgorithmSecurity Category
MLKEM5121
MLKEM7683
MLKEM10245
## 类型偏好

基于安全类别和密钥长度,建议用于初始支持的类型是:

MLKEM768_X25519 (类型 6)

实现说明

库支持

Bouncycastle、BoringSSL 和 WolfSSL 库现在支持 MLKEM。OpenSSL 支持将在 2025 年 4 月 8 日的 3.5 版本中提供 OPENSSL

共享 Tunnels

基于消息1(新会话消息)的长度检查,应该可以在同一个tunnel上自动分类/检测多种协议。以MLKEM512_X25519为例,消息1的长度比当前ratchet协议大816字节,最小消息1大小(仅包含DateTime载荷)为919字节。当前ratchet的大多数消息1载荷小于816字节,因此可以将其分类为非混合ratchet。大消息可能是POST请求,这种情况比较少见。

因此推荐的策略是:

  • 如果消息 1 少于 919 字节,则是当前的 ratchet 协议。
  • 如果消息 1 大于或等于 919 字节,则可能是 MLKEM512_X25519。首先尝试 MLKEM512_X25519,如果失败,则尝试当前的 ratchet 协议。

这应该允许我们在同一个目标上高效支持标准ratchet和混合ratchet,就像我们之前在同一个目标上支持ElGamal和ratchet一样。因此,我们可以比不能为同一个目标支持双协议的情况下更快地迁移到MLKEM混合协议,因为我们可以为现有目标添加MLKEM支持。

要求支持的组合包括:

  • X25519 + MLKEM512
  • X25519 + MLKEM768
  • X25519 + MLKEM1024

以下组合可能比较复杂,不要求必须支持,但可能会支持,这取决于具体实现:

  • 多个 MLKEM
  • ElG + 一个或多个 MLKEM
  • X25519 + 一个或多个 MLKEM
  • ElG + X25519 + 一个或多个 MLKEM

不要求在同一个目标上支持多种 MLKEM 算法(例如,MLKEM512_X25519 和 MLKEM_768_X25519)。只需选择一种即可。这取决于具体实现。

不需要在同一个目标上支持三种算法(例如 X25519、MLKEM512_X25519 和 MLKEM769_X25519)。分类和重试策略可能过于复杂。配置和配置用户界面可能过于复杂。这取决于具体实现。

不需要在同一个目标上同时支持ElGamal和混合算法。ElGamal已经过时,而且只有ElGamal + hybrid(没有X25519)意义不大。另外,ElGamal和Hybrid New Session Messages都很大,所以分类策略通常需要尝试两种解密方式,这会很低效。具体实现依赖于实现方式。

客户端可以在同一tunnel上为X25519和混合协议使用相同或不同的X25519静态密钥,具体取决于实现。

前向保密性

ECIES 规范允许在新会话消息载荷中包含 Garlic Messages,这允许初始流数据包(通常是 HTTP GET)与客户端的 leaseset 一起进行 0-RTT 传输。然而,新会话消息载荷不具备前向保密性。由于本提案强调为棘轮增强前向保密性,实现可能或应该推迟包含流载荷或完整流消息,直到第一个现有会话消息。这将以牺牲 0-RTT 传输为代价。策略也可能取决于流量类型或 tunnel 类型,或者例如 GET 与 POST 的区别。具体取决于实现。

新会话大小

MLKEM 将显著增加新会话消息的大小,如上所述。这可能会大大降低新会话消息通过 tunnel 传输的可靠性,因为它们必须被分片成多个 1024 字节的 tunnel 消息。传输成功率与分片数量成指数反比关系。实现可以使用各种策略来限制消息大小,但代价是牺牲 0-RTT 传输。具体取决于实现。

参考资料

Was this page helpful?