《乱叫:端到端加密的毛茸茸指南》

2020-11-15 09:56:00

在美国参议院的“赚取IT”法案,欧盟的一系列反加密提案,以及澳大利亚新的反加密法律之间,很明显,办公室里的威权主义者将网络隐私视为对他们生存的威胁。

通常,当政府加大反隐私威吓力度时,技术专家们开始更大声地谈论Tor、Signal和其他隐私技术(通常只会被偏执狂淹没,他们认为Tor和Signal是政府的后门或什么愚蠢的东西;阴谋论毁了一切!)。

相反,我将向您展示如何为您正在开发的任何通信软件添加端到端加密。(希望在此过程中,我将避免做出任何奇怪的设计决定。)。

是的,你绝对应该这么做。我不管你的东西有多平庸;如果你希望人们用它来相互交流,你应该让它永远不能解密他们的通信。

你绝对不应该把你正在开发的东西标榜为Signal或WhatsApp的替代品。

这样做的目的是增加部署在互联网上的端到端加密量,服务运营商无法解密(即使是法院命令强制),并使E2EE正常化。我们的目标不是与高度专业化和经过同行评审的隐私技术竞争。

我不是律师,我是从事密码学工作的毛茸茸的人。这篇博文的内容不是法律咨询,也没有得到任何公司或组织的认可。向EFF询问法律问题。

你不必实施全套解决方案来保护用户,但你能走得越远,你的用户就越安全,不会受到侵犯隐私的监管。

在本页包含的示例中,我将使用钠密码库。具体地说,我的示例代码将使用用于JavaScript的Sodium-Plus库编写,因为它在性能和跨平台之间取得了很好的平衡。

Const{SodiumPlus}=Required(';Na-plus';);(Async Function(){//自动选择后端const钠=等待SodiumPlus.auto();//在此执行其他操作})();

LibNa通常是在软件中开发密码功能的正确选择,并且在大多数编程语言中都可用,

如果你倾向于选择不同的库,你应该咨询你的密码学家(是的,如果你在做不同的事情,你应该在你的工资单上有一个)关于你的设计选择。

还记得上面我说过的话吗?“你不必实施一整套的解决方案来保护用户,但你能负担得起的程度越高,你的用户就能越安全地免受侵犯隐私的监控”。

你在实施这篇博客文章中概述的步骤方面走了多远,应该通过威胁模型来告知,而不是临时判断。

例如,如果您正在加密用户数据并将其存储在云中,则可能需要通过泥坑测试:

1.首先,把你的设备扔进泥坑。2.下一步,滑进水坑,砸自己的头。当你恢复意识时,你会完全好起来,但你的一生都不会回忆起你的设备密码或钥匙。3.现在试着找回你的云数据。你成功了吗?如果是这样的话,你就完了。或者说得不那么戏剧化,我应该说:你的云提供商可以访问你的加密数据,如果政府想要的话,政府也可以访问,任何知道如何绕过你的云提供商的内部政策检查的流氓员工都可以这样做。

马修·格林(Matthew Green)描述了“泥坑测试”(Mud Puddle Test),苹果产品肯定无法通过这一测试。

如果您必须为您的用户通过泥坑测试,请确保您在产品或服务的文档中明确和透明地说明了这一点。

这个难题中最简单的一块是加密两端之间传输的数据(因此,满足端到端加密的最宽松定义)。

在这一层,您已经有某种对称密钥可用于在发送数据之前对其进行加密,以及在接收数据时对其进行解密。

例如,下面的代码将加密/解密字符串,并返回带有版本前缀的十六进制字符串。

实际上,它使用的是XChaCha20-Poly1305,与AES-GCM相比,XChaCha20-Poly1305对定时泄漏的敏感度较低。然而,与AES-GCM一样,这种加密模式不提供消息或密钥承诺。

如果您想要消息或密钥提交,则应该使用基于散列函数的KDF从$key派生两个密钥:一个用于实际加密,另一个作为密钥承诺值。

您可能会做出的另一个设计选择是使用Base64而不是十六进制对密文进行编码。这并不会显著改变这里的设计,但它确实意味着您的解码逻辑必须适应这一点。

您应该对密文进行版本化,并将其包含在提供给您的AEAD加密模式的AAD中。我在上面使用了“v1”和“v2”作为版本字符串,但您也可以使用您的软件名称。

如果你不熟悉Elliptic Curve Diffie-Hellman或认证的Key Exhcanges,这个博客上最早的两篇文章就是关于这些主题的。

对于将ECDH扩展为认证密钥交换协议,有许多流派的思想。

我们将实现信号协议所称的X3DH,而不是进行某种交互式EdDSA+ECDH混合,因为X3DH提供了密码可否认性(有关更多信息,请参阅X3DH规范的这一节)。

目前,我将采用客户端-服务器模型。这可能适合也可能不适合您的设计。在对等配置中,您可以用“服务器”代替“其他参与者”。

每位参与者需要上传一次Ed25519身份密钥(这一细节将在另一节中介绍),该密钥将用于签署X25519公钥捆绑包,以用于X3DH。

根据Signal的X3DH规范,在向服务器推送100个一次性密钥时,需要使用x3dh_pre_key(SecretKey,1)来生成“签名的预密钥”包,并使用x3dn_pre_key(SecretKey,100)。

(如果有未烧录的)密钥的一次性密钥之一(X25519公钥)-然后将其删除

我们抽象了一些细节(即KDF()、传输机制、会话密钥管理机制等)。其中一些将高度特定于您的应用程序,因此充实它们没有多大意义。

需要记住的一件事:根据X3DH规范,参与者应该定期(例如每周)将他们在服务器中签名的预密钥更换为新的密钥。当它们开始耗尽时,它们还应该发布更多的一次性密钥。

使用X3DH来处理每条消息是低效且没有必要的。即使是信号协议也不能做到这一点。

相反,Signal指定了双棘轮协议,该协议结合了后续消息上的对称密钥棘轮和基于Diffie-Hellman的棘轮协议。

有必要通读该规范以了解它们对密钥派生函数(KDF)和KDF链的用法。

虽然建议使用HKDF作为信号协议的指定,但严格地说,您可以使用任何安全密钥PRF来实现相同的目标。

下面是一个对称KDF链的示例,它使用具有512位当前会话密钥摘要的BLAKE2b;BLAKE2b摘要的最左半部分成为新的会话密钥,而最右半部分成为加密密钥。

为了节省时间,完整的DHRatchet实现留给读者作为练习(因为它主要是一个状态机),但是使用钠加(crypto_box_keypair(),crypto_scalarmult())提供的适当函数应该相对简单。

信令协议规定了X3DH和双棘轮,用于安全地加密双方之间的信息。

群组对话比较棘手,因为您必须能够加密多个收件人可以解密的信息、添加/删除对话参与者等。

到目前为止,我读到的处理组密钥协议的最佳设计是IETF Messaging Layer Security RFC草案。

在这篇博客文章中,我不打算实现整个MLS RFC。如果你想支持多个设备或组对话,你需要一个完整的MLS实现来使用。

这是一个很大的领域,但我们还没有完成。

到目前为止,我们已经解决了加密、初始密钥协议和会话密钥管理问题。然而,我们没有详细说明身份密钥(具体是签名密钥-Ed25519,而不是Diffie-Hellman密钥)是如何管理的。到目前为止,这一细节只是在某种程度上挥舞着手。

在科技博客中有一种米姆(Meme)写了一篇题为“程序员相信的谎言_”的帖子。

对我们来说幸运的是,身份是毛茸茸比大多数人更好理解的主题之一(由于Fursonas):身份与人类有多对多的关系。

在端到端加密协议中,每个身份将由一些标识符(电话号码、电子邮件地址、用户名和服务器主机名等)组成。以及Ed25519密钥对(将为其发布公钥)。

但是,如何知道给定的公钥对于给定的身份是否正确呢?

这就是我们进入密码学中的一个难题的地方,其中可用的解决方案完全依赖于您的威胁模型:公钥基础设施(PKI)。

密钥透明度/证书透明度(CT)-TLS还可以确保CA颁发的证书是可审核的(尽管它最初的目的是取代证书颁发机构)。

在这一点上,你可以选择自己的冒险,这取决于你正在构建的软件类型和你的客户是谁,什么才是最合适的。

我特别喜欢的一种设计叫做Gossamer,这是一种没有证书颁发机构的PKI设计,最初是为了让WordPress的自动更新更安全(即每个开发人员都可以在他们的主题和插件更新上签名)。

由于我们只需要为我们的端到端加密协议中的每个参与者维护一个最新的Ed25519身份密钥库,这使得Gossamer成为一个合适的起点。

Gossamer指定了可以执行的操作的有限语法:AppendKey、RevokeKey、AppendUpdate、RevokeUpdate和AttestUpdate。这些操作被签署并发布到仅附加的加密分类帐。

我建议执行第六个操作:AttestKey,这样您就可以拥有类似WoT的保证和密钥签名方。(如果没有其他问题,您应该能够证明网络中其他加密分类帐的身份密钥在某个时间点是可信的。)。

在上一节中,我建议使用Gossamer作为身份密钥的PKI。这将提供与X3DH和双棘轮一起使用的Ed25519密钥对,该密钥对又将提供用于对称认证加密的会话密钥。

如果您已经实现了本小节之前的所有内容,那么您就拥有了一个全栈的端到端加密协议。但是,让我们让情报机构和监视资本家变得更加疯狂,让我们的软件后门变得不切实际(而且不可能悄悄地后门)。

对我们来说,实现很简单:按照最初的目的使用Gossamer(即保护您的软件分发渠道)。

Gossamer提供最新的验证密钥,并承诺提供每个软件更新的加密分类账。你可以在这里了解更多关于它的灵感。

仅仅使用Gossamer来管理密钥和更新签名是不够的。您需要独立的第三方才能使用AttestUpdate操作来断言以下一项或多项内容:

他们审查了源代码,没有发现后门或可利用漏洞的证据。

(然后,您应该让您的用户决定他们信任哪些独立的第三方来审查软件更新。)

美国政府对“罪犯蒙在鼓里”叫苦连天,对如何解决“蒙在鼓里的问题”感到疑惑不已。

如果更多的软件开发商在他们的通信软件中实现端到端加密,那么也许有一天他们将无法使用拉网式监视来监视公民,他们将被迫进行实际的侦察工作,以解决实际的犯罪问题。

让我们一起告诉每个先进民族国家的情报界,他们不经常听到的一个词:

这就是为什么我们正在建设的东西不打算与Signal竞争的主要原因之一(也不能这样宣传):

Signal是一个隐私工具,他们的服务器无法识别谁可以联系谁。

我们在这里建立的并不是一个完整的隐私解决方案,它只是提供端到端的加密(可能会让NSA的员工在办公桌前哭泣)。