量子准备就绪:混合密钥交换技术解析

本文深入探讨混合密钥交换机制,通过结合经典与后量子密码方案提升数据安全性。文章分析了不同KEM组合方法的安全性与性能权衡,并介绍了IETF标准化构造,为构建抗量子攻击的加密通信提供实用指导。

量子准备就绪:混合密钥交换

继我们之前关于签名混合的文章之后,本文涵盖了混合密钥交换的基础知识,以确保数据的最大安全性。

目录

  • 快速回顾:定义
  • 组合KEM
  • 经验教训

更迫切的是,与数字签名方案相比,我们在互联网上交换共享秘密的方式需要过渡到后量子时代。由于对新的“后量子”密钥交换方案的认识相对不足,大多数机构鼓励使用混合方案,将著名经典方案的鲁棒性与较新方案提供的后量子保护结合起来。这篇博文详细介绍了混合密钥交换主要概念的最新进展。

快速回顾:定义

密钥封装机制

将某物称为密钥封装机制(KEM)只是一种花哨的说法,指的是您已经知道的一个通用解决方案:Alice 和 Bob 如何通过公共渠道共享秘密?在经典密码学中,这个问题通过 Diffie-Hellman 密钥交换来解决:Alice 和 Bob 发布各自的公钥,并将他们的私钥与对方的公钥混合,以得到只有他们知道的相同秘密值。在后量子密码学中,存在多种技术来建立这个共享秘密,其中一些已在之前关于基于格方案的文章中讨论过。

密钥封装机制由三个例程定义:

  1. KeyGen(),负责生成由私有部分和公共部分组成的密钥对。
  2. Encaps(K_pub),负责生成一个秘密值和一个“胶囊”,该胶囊是一个数据块,只有拥有相应私钥的人才能将其转换回秘密值。
  3. Decaps(K_priv, caps),用于通过相应的私钥从胶囊中恢复秘密值。

例如,经典的 Diffie-Hellman (DH) 密钥交换可以看作是一个 KEM,通过如下定义三个例程:

DH 公共参数:生成元 g

  • KeyGen():选择一个随机整数 s。返回 K_priv = s 和 K_pub = g ** s
  • Encaps(K_pub):封装可以看作是临时 Diffie-Hellman 密钥交换。首先选择一个随机整数 x,然后计算将充当胶囊的关联公钥 caps = g ** x,以及共享秘密 secret = K_pub ** x
  • Decaps(caps, K_priv):解密只是计算临时公钥与我们自己的私钥之间的密钥交换。secret = caps ** K_priv

混合化

混合化是将后量子和经典方案结合起来,以获得一种新的、更能抵抗经典和量子攻击的方案的做法。有关更多细节,更完整的定义已在我们之前关于混合签名的博文中介绍过。如果您还没有阅读,我们鼓励您阅读。

组合KEM

KEM 组合器在 F. Giacon、F. Heuer 和 B. Poettering 2018 年的一篇研究论文中进行了深入研究。在这篇论文中,他们介绍了一种组合器的通用构造,其中所有密钥交换都是并行执行的。实际的组合工作在最后进行,作为所有共享秘密、胶囊和公钥的函数 W,输出组合后的共享秘密。

在以下部分,我们研究此类函数,并深入探讨它们为何可能或不可能成为相关的选择。

连接共享秘密

在组合多个秘密时,人们可能采取的第一种方法是简单地将它们全部连接起来。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
- CombiKEM.KeyGen():
    S_X, P_X <= KEM_X.KeyGen()
    S_Y, P_Y <= KEM_Y.KeyGen()
    S <= S_X, S_Y
    P <= P_X, P_Y
    return S, P

- CombiKEM.Encaps(P):
    P_X, P_Y <= Split(P)
    ss_X, caps_X <= KEM_X.Encaps(P_X)
    ss_Y, caps_Y <= KEM_Y.Encaps(P_Y)
    ss <= ss_X || ss_Y                 <--- W
    caps <= caps_X, caps_Y
    return ss, caps

- CombiKEM.Decaps(caps, S):
    caps_X, caps_Y <= Split(caps)
    S_X, S_Y <= S
    ss_X <= KEM_X.Decaps(caps_X, S_X)
    ss_Y <= KEM_Y.Decaps(caps_Y, S_Y)
    ss <= ss_X || ss_Y                 <--- W
    return ss

然而,有几点原因说明这可能不是最好的做法:

  1. 最终共享秘密的长度随着组合的 KEM 数量及其输出大小而变化。
  2. 如果其中一个 KEM 被破解,最终的共享秘密将部分为攻击者所知。因此,它将不再完全是“秘密”的。

理想情况下,破坏组合器中除一个 KEM 之外的所有 KEM 都不应该提供足够的信息来猜测最终共享秘密的部分内容。直观地说,我们希望我们的 KEM 能够将每个 KEM 带来的熵扩散到最终共享秘密的所有位中。

连接共享秘密,然后哈希

根据先前学到的关于熵扩散的经验,可以将以下组合器视为下一次迭代:

这个组合器连接组件 KEM 的共享秘密,然后对它们执行密钥派生操作(例如使用哈希函数)以形成最终的共享秘密。这确保了在熵方面,每个输出位都依赖于每个输入位。然而,在我们理想的组合器必须“至少与”每个成分 KEM 一样好的世界里,这仍然不够。

为了进一步证明这一点,让我们研究一下“会话密钥不可区分性”的概念(在两篇 IACR 论文中讨论过)。它描述了对手在给定相应胶囊的情况下,区分共享秘密和随机数据块的能力。

会话密钥不可区分性可以被认为是猜测“盒子里有什么?”,给定两个可能的答案。

我们将在这里讨论两个级别的会话密钥不可区分性:

  1. 抗选择明文攻击不可区分性(IND-CPA):挑战者提供一个公钥、一个胶囊、其关联的共享秘密和一个随机数据块。对手可以访问一个封装预言机,他们可以随意调用任意多次,使用任何他们选择的公钥。在某个时刻,对手必须确定所提供的两个数据块中,哪一个是由所提供的胶囊包装的共享秘密。
  2. 抗选择密文攻击不可区分性(IND-CCA):挑战者仍然提供一个公钥、一个胶囊、其关联的共享秘密和一个随机数据块。对手现在可以访问一个 Encaps(P) 和一个 Decaps(caps) 预言机(解封装使用与挑战相同的密钥执行),他们可以随意调用任意多次,对除提供的胶囊外的任何输入进行调用。在某个时刻,对手必须确定所提供的两个数据块中,哪一个是由所提供的胶囊包装的共享秘密。

遵循我们“盒子里有什么?”的比喻,您可以将 IND-CPA 视为可以访问礼品包装机,允许您在猜测原始盒子里有什么之前包装任意多的物品。IND-CCA 则为您提供了包装和解包装机器,您可以向它们询问除解包装原始盒子之外的任何请求。

KEM 的安全性可以根据这些安全属性进行评定,我们希望我们的组合器能够达到与最佳成分 KEM 相同的会话密钥不可区分性级别。

遗憾的是,连接后哈希的组合器在一般情况下不符合我们的期望。确实,让我们考虑两个 KEM,KEM_X 和 KEM_Y。进一步假设 KEM_X 是 IND-CCA 安全的,但 KEM_Y 以某种方式被破坏,使得可以为一个固定的(但秘密的)私钥 k 找到胶囊/共享秘密碰撞,即对于某个胶囊 caps,找到 caps′ ≠ caps,使得 Decaps(caps,k) == Decaps(caps′,k)。我们注意到 KEM_Y 不是 IND-CCA 安全的;给定一个挑战 (caps,sA,sB),对手可以生成一个与 caps 碰撞的胶囊 caps′,然后使用 Decaps(caps′) 查询解封装预言机。然后对手可以使用预言机返回的共享秘密赢得游戏。

确实,当提供一个挑战 (caps,sA,sB)(其中 caps 由来自 KEM_X 的 X_caps 和来自 KEM_Y 的 Y_caps 组成)时,对手能够构造 Y_caps′ ≠ Y_caps,它用 KEM_Y 解封装到相同的共享秘密。因此,对手有两个不同的胶囊 caps = X_caps, Y_caps 和 caps′ = X_caps, Y_caps′,它们用我们的组合 KEM 解封装到相同的共享秘密。使用与 KEM_Y 不是 IND-CCA 相同的论点,复合 KEM 不是 IND-CCA,而 KEM_X 是 IND-CCA。

请注意,像前一个演示中的 KEM_Y 那样具有碰撞的 KEM,可以在给定较差的参数选择的情况下用 Diffie-Hellman 密钥交换来实例化:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# === DH 参数
p=1277723 # p = 2*q + 1, with q=638861 also prime
g=3       # order(g) = q


# === KeyGen()
# Alice 私钥
a = 130376
# Alice 公钥
A = pow(g, a, p)


# === Encaps(A)
# Bob 临时私钥
b = 644734
# Bob 临时公钥
B = pow(g, b, p)
# 共享秘密和胶囊
ss, caps = pow(A, b, p), B


# === Decaps(caps, a)
assert pow(caps, a, p) == ss

# === 碰撞 !
# 其他胶囊,碰撞(利用 `a` 是偶数的事实)
v = 1277722    # order(v) = 2
caps_coll = (caps*v) % p
assert caps != caps_coll and pow(caps_coll, a, p) == ss

正如您所看到的,对于给定的胶囊和选择不当的私钥,可以在此方案中立即找到碰撞胶囊。

尽管如此,根据 M. Barbosa 等人的说法,如果您能证明组件 KEM 的密文第二原像抵抗性,那么“连接然后哈希”的组合是安全的。这个属性在我们的示例中显然没有得到遵守,因为 KEM_Y 是专门为了提供碰撞而设计的,因此导致了结果 KEM 的 IND-CCA 被破坏。

连接共享秘密、胶囊,然后哈希

对于一般情况,M. Campagna 和 A. Petcher 2020 年的论文提出将每个 KEM 的胶囊和公钥也纳入混合中。这个补充允许防御前一段中介绍的攻击,因为碰撞胶囊的最终共享秘密现在将会不同。然而,后量子算法的胶囊和密钥比经典算法大得多。因此,这种构造带来了不可忽视的开销,表现为密钥派生函数调用的输入更大。

为了避免这种性能缺陷,IETF 的复合 ML-KEM 草案提出了不同的方法。通过证明 ML-KEM 具有密文第二原像抵抗性,他们可以安全地从 KDF 输入中省略庞大的 ML-KEM 胶囊和公钥。这种方法保持了所需的 IND-CCA 安全性,而没有性能损失。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
KemCombiner<KDF>(mlkemSS, tradSS, tradCT, tradPK, Domain) -> ss
[...]
    if KDF is "SHA3-256":
        ss = SHA3-256(mlkemSS || tradSS || tradCT || tradPK || Domain)

    else if KDF is "HMAC-{Hash}":
        ss = HMAC-{Hash}(key={0}, text=mlkemSS || tradSS || tradCT || tradPK || Domain)
        ss = truncate(ss, 256)
    
    return ss

IETF 复合 ML-KEM 中使用的组合器函数。Domain 是一个常量,用于指示具体组合了哪对算法。

经验教训

混合密钥交换提供了一条谨慎的前进道路,将经典算法经过时间考验的安全性与后量子方案面向未来的特性相结合。然而,本文表明,用于组合这些方案的方法与方案本身同样关键。我们已经看到,简单地连接共享秘密是不够的,甚至更直观的“连接后哈希”方法也可能引入细微的漏洞。

要构建真正有弹性的混合 KEM,有两条主要路径:

  1. 一种通用构造,不仅将共享秘密,还将每个 KEM 的胶囊和公钥纳入最终的密钥派生函数中。这是更安全的路径,但由于后量子产物的庞大尺寸,可能会带来显著的性能成本。
  2. 一种更优化的方法,例如 IETF 为复合 ML-KEM 所采用的方法,依赖于证明组件 KEM 更强的安全属性,例如密文第二原像抵抗性。这允许一种更精简的组合,从哈希中省略了庞大的后量子胶囊和密钥,在不牺牲安全性的情况下实现了高性能。

总之,设计安全的混合机制是一项细致的任务,无论是对于签名还是密钥交换。开发人员应依赖经过标准化和严格分析的构造,例如 IETF 提出的构造,而不是依赖直觉发明自定义解决方案。这些标准为实现高安全性和实用性能提供了可信赖的蓝图,确保我们的加密通信对所有对手(包括现在和未来的对手)保持机密。

参考文献

  1. https://www.synacktiv.com/en/publications/quantum-readiness-lattice-bas
  2. https://synacktiv.com/en/publications/quantum-readiness-hybridizing-sig
  3. a. b. https://eprint.iacr.org/2018/024.pdf
  4. a. b. https://eprint.iacr.org/2020/1364.pdf
  5. https://eprint.iacr.org/2024/039
  6. https://datatracker.ietf.org/doc/draft-ietf-lamps-pq-composite-kem/
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计