不要使用 Session(Signal 的分支)
去年,我详细列出了一款应用需要具备哪些条件,才能让我认为它是 Signal 的竞争对手。之后,有几个人问我如何看待一个名为 Session 的 Signal 分支。我当时的回答和今天要说的一样:不要使用 Session。
几个月前,我建议避免使用 Session 的主要原因很简单:他们决定移除前向保密性(这是他们从 libsignal 继承的加密协议的重要安全特性)。缺乏前向保密性会让你暴露在**密钥泄露冒充攻击(KCI)**的风险中,任何想要跻身“成年人桌”的端到端加密应用都应该防止这种攻击。这也是为什么我不推荐 Tox 的原因。
仅凭这一点,就足以让任何人赶紧远离 Session。毕竟,从加密安全协议中移除重要的安全特性,正是某些恶意政府会做的事情(尤其是当这种改变的借口是引入“群组”和“洋葱路由”时——计算机犯罪分子可能会因为对 Tor 网络的熟悉而觉得这些听起来很诱人)。
不幸的是,有些人就是喜欢在消息应用上固执己见。所以,让我们更深入地看看 Session。
我没有在发布这篇博客之前私下向 Session 的开发团队披露这些问题。
我认为,加密问题并不总是需要与软件供应商进行协调披露。正如 Bruce Schneier 所说,完全披露安全漏洞是一个“非常好的主意”。
我将这篇博客分为两个部分:安全问题和吐槽。
安全问题
1. Ed25519 密钥的熵不足
Session 与 Signal 的一个不同之处在于,它使用 Ed25519 而不是 X25519 来处理所有事情。Session 的 KeyPairUtilities
对象生成的 Ed25519 密钥对只有 128 位的熵,而不是 Ed25519 种子应有的约 253 位(经过钳位后)。
fun generate(): KeyPairGenerationResult {
val seed = sodium.randomBytesBuf(16)
try {
return generate(seed)
} catch (exception: Exception) {
return generate()
}
}
这重要吗?
你可能会认为,清除 Ed25519 种子的高 128 位是没问题的,原因可能是:
- 它在钳位之前会用 SHA512 进行哈希。
- Ed25519 只提供 128 位的安全性。
- 某些秘密的(可能不合理的)第三个论点。
确实,如果你关注的是椭圆曲线离散对数问题(ECDLP)的安全性,Ed25519 的目标是 128 位的安全级别。在这种模型中,实现 128 位的安全性需要 256 位的秘密,因为对 ECDLP 的最佳攻击需要大约 次猜测。
此外,拥有 256 位的秘密使得方案的多用户安全性更容易推理,而 128 位的秘密则使这一点变得困难得多。当你的秘密只有 种可能时,你的多用户安全性就不再像 Ed25519 预期的那样安全。
更糟糕的是,如果你知道高 128 位被初始化为 0,你可以通过修改版的 Pollard's rho 算法,在 次查询中找到对应的私钥。这意味着 Session 的 KeyPairUtilities
类只提供了 64 位的 ECDLP 安全性。
64 位的 ECDLP 安全性意味着什么?
简单来说,这意味着一个分布式计算项目可以在 次查询中找到给定 Ed25519 公钥的私钥。这大约相当于找到 SHA1 碰撞的攻击成本,而我们知道这是可行且经济的。
根据 Shattered 论文的估算,通过租用 Amazon EC2 的 GPU 计算资源,SHA1 碰撞攻击的成本大约在 7.5 万到 12 万美元之间。
我不知道这是单纯的愚蠢,还是一个只有资源充足的对手才能破解的 NOBUS 后门。