标题:反伽罗瓦洋葱:改进的Tor电路流量加密
作者:nickm
日期:2025-11-29 18:12:06
内容:

能谈论密码学总是件好事。尤其是在我们即将淘汰 Tor 中最古老、最重要的加密算法之一,并用一种​​名为反伽罗瓦洋葱(Counter Galois Onion)的、有研究支持的新设计取而代之的时候。

此次全面改革将保护用户免受更广泛的在线攻击者(如下所述)的攻击,并为未来开展更多加密工作奠定基础。

我们这里讨论的是哪种密码学?

这里提到的算法是 Tor 的中继加密算法。虽然 Tor 使用标准的 TLS 协议进行中继之间以及客户端与中继之间的通信,但它需要一种专门的算法来加密用户数据在电路中经过多个中继时产生的加密信号。

这就是中继加密算法。客户端与其电路中的每个中继共享一个对称密钥,并使用这些密钥加密发送出去的消息,即“中继单元”。每个中继可以移除一层加密,直到客户端的单元到达出口中继。

当然,我们需要确保数据在从客户端传输的过程中不被篡改。为此,我们在数据单元中包含一个加密摘要。该摘要不仅包含当前数据单元,还包含之前通过该电路发送的所有数据单元(以防止数据顺序被更改)以及另一个共享的秘密密钥(以确保摘要的不可预测性)。

因此,加上摘要后,客户端的行为如下:它们计算并设置摘要,然后多次使用流密码(在 Tor 的情况下是 AES-128-CTR)对每个中继的单元格进行加密。

如果进行大量简化,那么继电器单元看起来有点像这样:

场地 宽度
2 字节
消化 4 字节
其他东西 ...

“零”字段的存在是为了让出口节点以外的节点可以避免检查摘要:如果一个中继节点收到一个值不为零的单元格,那么它就可以知道自己不是该单元格的接收者,因此不需要检查摘要:它只需解密该单元格并将其转发给下一个中继节点。

我们在设计这个算法时没有给它命名。现在我们要替换它,最好有个识别方法,所以我们把它叫做“tor1”。

Tor1加密算法示意图
图 1. tor1 加密算法,用作中间层。

输入是消息 M。计数器 CTR 通过伪随机函数(PRF,使用 AES-128-CTR 实现)扩展,生成字节流。这些字节与 M 进行异或运算,生成密文 C。

Tor1加密算法示意图
图 2:tor1 加密算法,用于发起消息。

将消息 M 与哈希状态 HS 混合,并将摘要的一部分附加到消息上。然后将整个结果与伪随机函数 (AES-128-CTR) 进行异或运算,生成密文 C。

等等,这个设计看起来好滑稽!

是啊,现在肯定不会那样建了,对吧?所以我们才要把它换掉。

在如今高质量在线课程优秀入门资料层出不穷的时代,人们很容易忘记Tor 项目初期密码学资源的匮乏程度。当时AES 算法刚刚问世认证加密作为一个独立的学科领域也才刚刚兴起。

现有的设计并不适合 Tor 的需求。最初的洋葱路由论文并没有明确提出身份验证机制。像MixmasterMixminion这样的设计针对较大的消息体进行了优化,并且需要为每一层加密都生成一个完整的摘要。(例如,Mixmaster 最多支持 20 个转发器,因此每条消息都必须预留空间来存储 20 个摘要(以及其他内容)。)

当前 tor1 设计中的一些“奇怪之处”虽然过时,但并不糟糕;而另一些奇怪之处则更值得解决。

那么,tor1 设计存在哪些问题?

有几个。首先是最重要的一个:

问题 1:标签攻击

标记攻击使攻击者能够通过在网络中的某个位置修改流量,并观察另一个位置的可预测变化来追踪流量。即使标记攻击未能立即成功,其副作用也会为攻击者提供越来越多的重试机会。

这是我们正在用CGO解决的最重要的攻击。即使不考虑下面提到的其他问题,单是这个问题本身就值得修复。

这种攻击的主要版本出现的原因在于 tor1 使用 AES-CTR 加密,且没有逐跳认证,这意味着中继加密是可塑的。由于计数器模式通过将密钥流 S 与明文 P 进行异或运算来生成密文 C (C = S ⊕ P),因此,攻击者如果能够将自己的模式 M 异或到密文中,就能得到 C' = (S ⊕ P) ⊕ M = S ⊕ (P ⊕ M)——也就是说,(P ⊕ M) 的一个有效加密。

攻击者可以利用这种攻击来确保控制电路的两端。他们将一个模式与电路一端的单元格进行异或运算,然后移除该模式,观察另一端是否有乱码单元格恢复清晰。任何具有诚实端点的电路都会失败(且不会被去匿名化),但客户端会不断重试,直到最终选择恶意端点为止。

如果攻击者选择中继单元中已知的明文部分作为其标记(例如报头或零空间),那么他们就可以通过在末端检索该标记来利用它通过电路传递标识符:

 M = (P ⊕ M) ⊕ P.

然后可以使用 M 来传输用户的 IP 地址或唯一标识符。

与概率流量相关性相比,这种攻击可以立即提供明确的结果,并且强度更高:它还允许攻击者确保他们成功传输的所有流量在电路用于任何应用程序流量之前都完全去匿名化。

对攻击者而言,不利之处在于客户端可以检测到由此导致的电路故障率。目前,当电路故障率过高时,Tor 客户端会发出日志通知和警告。然而,正如一些细心的用户所发现的那样,当针对 Tor 的 DDoS 攻击变得严重时,这些检测器会发出误报。

这类攻击(攻击者能够滥用 Tor 协议,在应用程序活动之前在中继节点之间传输信息)被称为内部隐蔽信道攻击。Tor 正在更新其威胁模型,以明确涵盖这些攻击途径以及其他两类攻击途径。

问题2:前向保密性始于电路闭合之时

这次攻击和之后的那次攻击远没有上面提到的标记攻击那么严重;我们提到它们只是为了完整性。

在许多现代在线协议中,包括Signal等即时通讯应用,用于解密消息的密钥会在消息解密后立即销毁,以防止密钥被窃取并用于后续用途。但 Tor 的旧加密算法 (tor1) 并不具备这种特性:在整个通信链路的生命周期内,密钥始终保持不变。这意味着,如果在链路仍在运行时密钥被窃取,则链路上的所有先前通信内容都可能被解密。

如果电路的寿命只有几分钟,那倒也还好,但有些电路会持续存在好几天。(此外,寿命更长的电路可能更有利于匿名性,尤其是在用户需要保持持久身份的情况下,因此增强电路的安全性是明智之举。)

虽然与标签问题相比,这次攻击微不足道,但我们不妨在更新加密技术的同时,也把它解决掉。

问题 3:4 字节的身份验证器?真的吗?

是的,这不太好。仅仅使用 4 字节的摘要意味着伪造单元格而不被发现的概率只有四十亿分之一。

实际上,这种攻击效果并不好:如果攻击者的猜测没有成功,那么他们发送的无效消息会导致电路故障,除非客户端通过他们建立另一个电路,否则他们无法再次尝试。虽然用于抵抗标记攻击的路径偏差机制在这里也有效,但最好还是不要用到它们。

(另外,它使用的是 SHA-1 算法,这至少可以说已经过时了。2

那么,过去我们是如何考虑替换它的呢?

我们曾多次想替换这个算法,但一直被设计和效率问题所困扰。

我们绝对不想效仿邮件转发器的设计,为每一层加密都添加一个身份验证器:那样会造成巨大的开销。如果我们在洋葱服务中尝试类似的方法,大约 15% 的带宽都将用于身份验证器字段。

宽块密码是一种很有前途的设计元素:这种密码(或密码的使用模式)将整个消息加密成一个不透明的块:密文的任何变化都会使整个消息变得混乱,就像普通分组密码中的单个块一样。

(严格来说,如果要抵御标记攻击,这需要是一种“强伪随机排列”(SPRP)。)

你可以通过将明文的一部分保留为已知值(例如,16 字节的零)来将宽块密码变成认证密码。

但大多数宽块密码设计都比较昂贵。几乎所有强密码(例如BEARESS、LIONESSbiIGEHHFHFH)都需要对数据进行两次完整加密和两次哈希运算。像HCTR2这样的新模式只需要一次加密,但仍然需要两次哈希运算。(相比之下,tor1 在 3 跳电路上对一个单元进行加密需要 3 次加密和 1 次哈希运算,而上述设计之一则需要大约 6 次加密和 6 次哈希运算。)

我们愿意为改进加密技术付出一些CPU 成本(而且我们应该预料到会付出一些成本,因为身份验证不是免费的),但我们需要将成本控制在最低限度。

现在,任何宽块设计都需要多次迭代:可以证明,除非至少迭代两次,否则无法确保更改任何一位都可能导致其他所有位发生混乱。但我们希望尽可能降低这些迭代的成本!

此外,还有一些从零开始构建的宽块设计(而不是基于底层密码的设计,例如AEZ)也取得了卓越的成果。

我们最终决定采用哪种方案?

多年来,密码学家们一直在寻找这方面的好解决方案。

Jean Paul DegabrieleAlessandro MelloniJean-Pierre MünchMartijn Stam设计了一种名为“反伽罗瓦洋葱”( Counter Galois Onion,简称 CGO)的方案。它基于一种名为“稳健伪随机置换”( Rugged Pseudorandom Permutation,简称 RPRP)的结构:本质上,它是一种宽块密码设计,能够抵抗单向延展性(加密操作如此,解密操作则不然)。如果我们部署时客户端始终解密,而中继始终加密,那么我们就能以比完整 SPRP 更低的成本获得一种抗标记的3密码!

作者使用他们称之为 UIV+ 的 RPRP(参见论文),实现了我们所有的目标(抗标记性、即时前向保密性、更长的认证标签、有限的带宽开销、相对高效的操作和现代化的密码学)。

(就在这篇博文发布前不久,他们修改了论文并发布了新的安全证明。)

我们编写了一份规范,与他们的论文和参考实现相符。

它是如何运作的?

CGO 的工作原理是,如果有人篡改了您加密数据的任何部分,整个消息以及所有未来的消息都将无法恢复。以下是具体原理!

(如果您不喜欢阅读密码图,可以跳过本节。如果您非常喜欢阅读密码图,建议您查看规范论文!)

下图展示了 UIV+ 构建模块,并说明了如何使用它来构建 CGO 加密。

图 3:UIV+ 加密

输入 X 被分成两部分:较短的 X_L 和较长的 X_R。X_R 和一个“微调”值 H 本身作为微调参数传递给一个可调分组密码 E_T(使用LRW2实例化),然后 E_T 用于加密 X_L。此加密的输出作为伪随机函数 (PRF) 的种子,该伪随机函数与 X_R 进行异或运算以对其进行加密。

图 4:中间层 CGO 加密。

CGO 将每条消息视为一个 16 字节的标签 T 和一个 493 字节的密文 C。它们分别作为 X_L 和 X_R 传递给上述 UIV+ 加密算法。调整值(UIV+ 中的 H)在这里被称为 T':每个单元格加密后的“T”值将作为下一个单元格的 T' 值。

图 5:发起 CGO 消息

在消息生成时,CGO 会将消息标签初始化为随机数 N。消息加密过程中,N 值和加密密钥都会使用“更新”算法进行转换。新的 N 值和新的加密密钥将用于加密下一个单元格。

好吧,但是所有这些密码学技术是如何解决我们最初提出的问题呢?

首先(也是最重要的),防止标签攻击主要受以下两个因素控制:

  1. 对4进行加密时,消息被转换为宽块结构,因此对输入的任何更改都会导致整个输出无法恢复。
  2. T' 和 N 值的链接意味着消息的加密取决于所有先前的消息,因此如果一条消息被篡改,所有后续消息都将无法恢复。

其次,通过图 5 中的 Update 构造实现前向保密性。每次生成或接收新单元时,用于生成或接收该单元的密钥都会发生不可恢复的转换,因此加密器/解密器不再持有解密先前单元所需的密钥。

第三,截断的摘要现在被替换为一个较长的 16 字节身份验证器,就像明智的人使用的那样。

题外话:如果我们错了呢?

CGO 是一个相当新的设计,因此我们有理由质疑它是否存在一些弱点,导致其安全性低于预期。我的回答是:确实有可能!攻击手段只会随着时间的推移而不断改进,尽管 CGO 背后的密码学家们技艺精湛、备受推崇,但即使是最优秀的密码学家也会犯错。目前确实存在一个安全证明,但它出现的时间较短,尚未经过深入的审查。随着时间的推移,当更多密码学家关注 CGO 时,我们(希望)会对其安全性更有信心。(如果我们最终决定需要替换它,我们之前为将其添加到 Arti 和 C Tor 实现中所做的工作,将使日后迁移到其他系统变得更加容易。)

但我们相当肯定的是,CGO 不太可能存在任何使其比 tor1更差的弱点。

我们的实施进展如何?

开始了!

我们已经实现了 Arti(Rust 版 Tor 实现)的加密算法。我们也用 C 语言实现了它,因为如果中继服务器不支持 C 语言,它就毫无用处,而 Arti 中继项目目前仍在开发中。

为了实现这个功能,我们不得不重构大量代码,修改其原有的假设:例如,我们修改了所有关于中继单元布局的假设,以及所有关于中继加密只有一种方式的假设。这些修改将有助于我们未来对中继单元格式和加密方式进行其他更改。

接下来的步骤是:

感谢您的帮助!

感谢多年来为这项工作做出贡献的所有密码学家、程序员、研究人员和密码朋克。还要感谢所有推动这项工作和现代密码学发展现状的研究人员;我们今天所取得的成就都建立在他们的工作基础之上。

感谢 Mike Perry 帮助我撰写本文,并确保威胁模型的各个部分正确无误。

最后,感谢多年来所有为 Tor 捐款的人!我们的大部分工作都得益于民主、人权和劳工局的资助,但许多关键部分(包括多年来的基础工作以及所有与洋葱服务相关的部分)都来自我们的非限定性资金,而这些资金又依赖于像您这样的捐助者。感谢您相信我们的使命,感谢您帮助 Tor 变得更好!<3


  1. 为什么不直接使用多层嵌套的 TLS 呢?首先,因为每一层 TLS 都会增加带宽开销,而这种开销会迅速累积。其次,由于 TLS 实现并非以匿名性为目标,它们往往会生成大小不一的记录,这使得流量难以保持一致性。第三,由于 TLS 协议存在多种不同的实现方式,客户端实现通常彼此不同:我们需要特别注意确保每个客户端都使用相同的 TLS 实现,并锁定标志和选项。这将使升级和移植变得极其困难

  2. 是的,tor1 算法使用的是 SHA-1。当时是 2002 年,OpenSSL 还不支持 SHA-256。不过,情况并没有看起来那么糟糕:我们实际上并不需要抗碰撞性,而且在相关情况下攻击者也无法看到摘要,因此 SHA-1 的常规弱点并没有完全显现出来。

     

    不过,一旦 tor1 最终被取代,我们将非常乐意和 SHA-1 说再见。

  3. 理论上,客户可以自行标记流量,但这样做并不会给他们带来任何好处

  4. 记住RPRP特性:加密过程不易变形,但解密过程容易变形。





Counter Galois Onion: Improved encryption for Tor circuit traffic

It's always a good day when we can talk about cryptography. Especially when we are sunsetting one of the oldest and most important encryption algorithms in Tor and replacing it with a research-backed new design, called Counter Galois Onion.

This overhaul will defend users against a broader class of online attackers (described below), and form the basis for more encryption work in the future.

Which cryptography are we talking about here?

The algorithm in question is Tor's relay encryption. While Tor uses the standard TLS protocol for communication between relays, and between clients and relays, it needs a specialized algorithm for encrypting user data as it traverses multiple relays in a circuit.1

That's the relay encryption algorithm. The client shares a symmetric key with each relay on its circuit, and encrypts an outgoing message, or "relay cell" with each one of those keys. Each relay can remove a single layer of encryption, until the client's cell reaches the exit relay.

Of course, we need to make sure that the data isn't modified on the way from the client. For that, we include a cryptographic digest in the cell. The digest covers not only the cell itself, but also all previous cells sent through the circuit (to prevent re-ordering) and another secret shared key (to make the digest unpredictable).

So with the digest added, clients behave as follows: they calculate and set the digest, then they use a stream cipher (AES-128-CTR in Tor's case) multiple times to encrypt the cell for each relay.

If we simplify a lot, then a relay cell looks a little like this:

Field Width
Zero 2 bytes
Digest 4 bytes
Other stuff ...

The "zero" field is there so that nodes other than the exit can avoid checking the digest: If a relay gets a cell with a value other than zero, then it can tell that it isn't the recipient of that cell, so it doesn't need to check the digest: it just decrypts the cell and forwards it to the next relay.

When we designed this algorithm, we didn't give it a name. Now that we're replacing it, it helps to have some way to identify it, so we're calling it "tor1".

A diagram of the Tor1 encryption algorithm
Figure 1. The tor1 encryption algorithm, as used at a middle layer.

The input is a message M. A counter CTR is expanded via a psueodrandom function (PRF, instantiated with AES-128-CTR), to produce a stream of bytes. These bytes are xored with M to produce a ciphertext C.

A diagram of the Tor1 encryption algorithm
Figure 2: The tor1 encryption algorithm, as used to originate a message.

The message M is mixed with the hash state HS, and a portion of the digest is appended to the message. The whole thing is then xored with the PRF (AES-128-CTR) to produce our ciphertext C.

Wait, that design looks funny!

Yeah, you wouldn't build it that way nowadays, would you? That's why we're replacing it.

In today's world of high-quality online courses and excellent introductory material, it's easy to forget the general state of accessible cryptography resources when Tor was getting started. AES was brand new, and authenticated encryption as a separate field of study had just started to emerge.

Existing designs weren't suitable for Tor's needs. The original onion routing paper didn't specify a means for authentication. Designs like mixmaster and mixminion were optimized for larger message sizes, and required a separate full digest for every possible layer of encryption. (For example, Mixmaster supported up to 20 remailers, so had to reserve space for 20 digests (and other stuff) in every message.)

Some of the "weird things" in the current tor1 design are outdated, but not awful; others are things that are more valuable to resolve.

So, what are the problems with the tor1 design?

There are a few. First the big one:

Problem 1: Tagging attacks

Tagging attacks enable an active adversary to trace traffic by modifying it in one place on the network, and observing predicatable changes in another. Even when tagging attacks don't succeed immediately, their side effects can give the attacker more and more opportunities to retry.

This is the most important attack we're solving with CGO. Even without the other problems below, this one would be worth fixing on its own.

The main version of this attack arises because tor1's use of AES-CTR encryption with no hop-by-hop authentication means that the relay encryption is malleable. Since counter mode derives its ciphertext C by XORing a secret key stream S with the plaintext P (C = S ⊕ P), an attacker who can XOR their own pattern M in to the ciphertext will produce C' = (S ⊕ P) ⊕ M = S ⊕ (P ⊕ M) — that is, a valid encryption of (P ⊕ M).

An attacker can use this attack to ensure that they control both ends of the circuit. They XOR a pattern onto a cell at one end, and then see if any garbled cells at the other end become clear when whey remove that same pattern. Any circuits with an honest endpoint will fail (and not be deanonymized), but the client will retry them until they eventually choose a malicious endpoint.

If the attacker chooses a known-plaintext portion of the relay cell for their marker (such as the header or slack zero space), then they can use their marker to communicate an identifier across the circuit, by retrieving it at the end:

 M = (P ⊕ M) ⊕ P.

M can then be used to transmit an IP address or unique identifier for the user.

In comparison to probabilistic traffic correlation, this attack provides definite results immediately, with a strength multiplier: it also allows the attacker to ensure that all the traffic they successfully carry is fully deanonymized, before the circuit is used for any application traffic at all.

The downside for the attacker is that the resulting failure rate of circuits can be detected by the client. Currently, Tor clients emit log notices and warnings when circuit failure rates are excessively high. Unfortunately, as vigilant users have noticed, when the DDoS attacks on Tor become severe, these detectors give false alarms.

This class of attacks (where an adversary is able to abuse the Tor Protocol to transmit information between relays before application activity) is known as Internal Covert Channel attacks. Tor is in the process of updating its threat model to cover these attack vectors explicitly, along with two other categories of attack vectors.

Problem 2: Forward secrecy begins when a circuit closes

This attack and the one after it are much less severe than the tagging attack above; we mention them for the sake of completeness.

In many modern online protocols, including messaging apps like Signal, the keys used to decrypt a message are destroyed as soon as the message is decrypted, so that nobody can steal them and use them later on. But Tor's old encryption algorithm (tor1) doesn't provide this property: the same AES keys are used for the entire life of the circuit. That means that if a key was stolen while the circuit was still alive, all previous traffic on the circuit could be decrypted.

When a circuit's lifetime is on the order of minutes, that's not so bad, but sometimes circuits stay around for days. (What's more, longer-lived circuits may be better for anonymity, especially when the user is maintaining a persistent identity, so it's a good idea to make them stronger.)

Although this attack is minor in comparison to the tagging issue, we may as well address it while we are updating our encryption.

Problem 3: A 4-byte authenticator? Seriously?

Yeah, that's not great. The use of a mere 4-byte digest means that there's a one-in-4-billion chance to forge a cell undetected.

That isn't a very good attack in practice: if the attacker doesn't get lucky with their guess, then their invalid message causes the circuit to fail, and they can't try again unless the client builds another circuit through them. The same pathbias mechanisms that help resist tagging attacks also help here, but it would be better not to need them.

(Also, it's using SHA-1, which is showing its age, to say the least.2)

So, how did we think about replacing this in the past?

We've wanted to replace this algorithm a few times, but we've been hung up on issues of design and efficiency.

We definitely don't want to follow remailer designs by adding one authenticator per layer of encryption: that way lies big overhead. If we tried something like that with onion services, we'd be devoting something like 15% of our bandwidth to authenticator fields.

One promising design element has been wide-block ciphers: these are ciphers (or modes of using ciphers) that encrypt an entire message as if it were a single opaque block: any change in the ciphertext garbles the entire message as if it were a single block in a regular block cipher.

(Technically, this needs to be a "strong pseudorandom permutation" (SPRP) if it's going to resist tagging attacks.)

You can make a wide-block cipher into an authenticated cipher by reserving some portion of the plaintext for a known value -- say, 16 bytes of zeros.

But most wide-block cipher designs are comparatively expensive. Nearly all of the strong ones (BEARESS, LIONESS, biIGE, HHFHFH) require two full encryptions and two hashes over the data. Newer modes like HCTR2 require only one encryption pass, but still need two hashes. (For comparison: tor1 requires 3 encryptions and one hash for a cell on a 3-hop circuit, whereas one of these designs requires on the order of 6 encryptions and 6 hashes.)

We're willing to pay some CPU cost for improved cryptography (and we should expect to pay some cost, since authentication doesn't come for free) but we need to keep the cost to a minimum.

Now, multiple passes are necessary for any wide-block design: it's provable that there's no way to make sure that changing any bit will potentially garble every other bit unless there are at least two passes. But we'd like to make these passes as cheap as possible!

There has also been excellent work on other wide-block designs built from scratch, rather than from an underlying cipher (notably AEZ).

What are we going with?

For years now, cryptographers have been looking for good solutions here.

Jean Paul Degabriele, Alessandro Melloni, Jean-Pierre Münch, and Martijn Stam have a design that they're calling Counter Galois Onion (CGO). It's based on a kind of construction called a Rugged Pseudorandom Permutation (RPRP): essentially, it's a design for a wide-block cipher that resists malleability in one direction (for the encrypt operation, but not the decrypt operation). If we deploy this so that clients always decrypt and relays always encrypt, then we have a tagging resistant3 cipher at less cost than a full SPRP!

Using a RPRP that they call UIV+ (see the paper), the authors achieve all of our goals (tagging resistance, immediate forward secrecy, longer authentication tags, limited bandwidth overhead, relatively efficient operation, and modernized cryptography).

(Shortly before this blog post went up, they revised their paper and released a new security proof.)

We've written a specification which matches their paper and their reference implementation.

How does it work?

CGO makes it so that if anybody tampers with any part of your encrypted data, the entire message, and all future messages, become unrecoverable. Here's how!

(If you don't like reading cipher diagrams, you may want to skip this section. And if you really like reading them, you should check out the specification and the paper!)

The figures below present the UIV+ building block, and show how it is used to build CGO encryption.

Figure 3: UIV+ encryption

The input X is split into two parts: A short X_L, and a longer X_R. X_R, and a "tweak" value H, are themselves passed as tweaks to a tweakable block cipher E_T (instantiated with LRW2), which is then used used to encrypt X_L. The output of this encryption seeds a PRF, which is xored into X_R to encrypt it.

Figure 4: Middle-layer CGO encryption.

CGO treats every message as a 16-byte tag T, and a 493-byte ciphertext C. These are passed as X_L and X_R to the UIV+ encryption algorithm above. The tweak value (H in UIV+) is here called T': each cell's "T" value, after encryption, is taken as the T' for the next cell.

Figure 5: Originating a CGO message

When _originating_ the message, CGO initializes its tag as a nonce value N. The value of N, _and the encryption keys_, are all transformed using an "Update" algorithm as the message is encrypted. The new N, and the new encryption keys, will be used to encrypt the next cell.

Okay, but how does all of this cryptography solve the problems we began with?

First (and most importantly) tagging attacks are prevented by two factors:

  1. When encrypting4, the message is transformed in a wide-block construction, so that any change to the input renders the entire output unrecoverable.
  2. The chaining of T' and N values means that a message's encryption depends on all previous messages, so if a single message is garbled, all subsequent messages will be unrecoverable.

Second, forward secrecy is achieved with the Update construction in figure 5. Every time a new cell is originated or received, the keys used to originate or receive it are transformed unrecoverably, so that the encryptor/decryptor no longer holds the keys necessary to decrypt earlier cells.

Third, the truncated digest is now replaced with a nice long 16-byte authenticator, like sensible people use.

Aside: What if we're wrong?

CGO is a fairly new design, and it's reasonable to ask whether there could be weaknesses in it that would make it worse than it's designed to be. I'd answer: There might be! Attacks only get better with time, and although the cryptographers behind CGO are skilled and well regarded, even the best cryptographers can make mistakes. There is a security proof, but it's fairly recent, and and it hasn't yet gotten intensive scrutiny. With time, as CGO gets attention from more cryptographers, we'll (hopefully) gain more confidence in its strength. (And if we do decide that we need to replace it, the work we've done to add it to Arti and the C Tor implementation will make it much easier to do a later migration to a different system later on.)

But what we are pretty sure about is that there aren't likely to be any weaknesses in CGO that would make it worse than tor1.

Where does our implementation stand?

It's underway!

We've implemented the cryptography for Arti, the Rust Tor implementation. We've also implemented it in C, since it won't do us any good unless relays support it too, and the Arti relay project is still a work in progress.

In order to build this implementation, we've had to refactor a lot of code to revise its existing assumptions: for example, we've had to revise all the places where we assumed anything about the layout of a relay cell, or where we assumed that there was only one way to do relay encryption. These changes will help us with any other changes to relay cell formatting and encryption in the future.

Our next steps are:

Thanks for your help!

Thanks to all the cryptographers, programmers, researchers, and cypherpunks who have contributed to this work over the years. Thanks also to all the researchers who have advanced this work, and the state of modern cryptography; we all stand on the work they have built.

And thanks to Mike Perry for helping me write this and get the parts of the threat model right.

And finally, thanks to everybody who has donated to Tor over the years! A lot of this work is done through a grant from the Bureau of Democracy, Human Rights, and Labor, but many critical parts of this work (including years of past groundwork, and all the parts related to onion services) have been paid for out of our unrestricted funds, which rely on donors like you. Thanks for believing in our mission, and thanks for helping to make Tor better! <3


  1. Why not just use multiple layers of nested TLS? First, because each layer of TLS adds bandwidth overhead, and that overhead adds up fast. Second, because TLS implementations aren't aiming for anonymity, they tend to do things like generate records of different sizes, making it hard to cause traffic to appear uniform. Third, because the TLS protocol exists in many different flavors that client implementations are often distinguishable from one another: we would need to take special care to keep every client on the same TLS implementation, with locked-down flags and options. That would make upgrading and portability highly difficult.

  2. Yeah, the tor1 algorithm uses SHA-1. It was 2002, and OpenSSL didn't have SHA-256 support yet. This isn't as bad as it looks, though: we don't actually need collision resistence here, and the attacker doesn't actually get to see the digest under relevant circumstances, so the regular weaknesses of SHA-1 don't apply in full force.

     

    Nonetheless: we will be quite glad to say goodbye to SHA-1 once tor1 is finally replaced.

  3. Technically, the client can tag their own traffic, but they wouldn't gain anything by doing so.

  4. Remember the RPRP property: encryption resists malleability, but decryption is malleable.


返回列表 网站首页