[tor-dev] Proposal 295: Using the ATL construction for relay cryptography (solving the crypto-tagging attack)
Nick Mathewson
nickm at torproject.org
Wed Jul 4 20:42:31 UTC 2018
Here is (I hope) the correct version of this proposal, reformatted.
Filename: 295-relay-crypto-with-atl.txt
Title: Using ADL-GCM for relay cryptography (solving the crypto-tagging attack)
Author: Tomer Ashur
Created: 09 Apr 2018
Status: Open
0. Context
Although Crypto Tagging Attacks were identified already in the
original Tor design, it was not before the rise of the Procyonidae in
2012 that their severity was fully realized. In Proposal 202 (Two
improved relay encryption protocols for Tor cells) Nick Mathewson
discussed two approaches to stymie tagging attacks and generally
improve Tor's cryptography. In Proposal 261 (AEZ for relay
cryptography) Mathewson puts forward a concrete approach which uses
the tweakable wide-block cipher AEZ.
1. Motivation
For motivations, see proposal 202.
2. Summary and preliminaries
This proposal suggests an alternative approach to Proposal 261 using
the notion of Release (of) Unverified Plaintexts (RUP-security). It
describes an improved algorithm for circuit encryption based on
CTR-mode which is already used in Tor, and an additional component
for hashing. When this additional component is GHash, a GCM-based
solution can be used from the OpenSSL library.
Incidentally, and similar to Proposal 261, this proposal employs the
ENCODE-then-ENCIPHER approach thus it improves Tor's E2E integrity by
using (sufficiently enough) redundancy.
For more information about the scheme and a security proof for its
RUP-security see
Tomer Ashur, Orr Dunkelman, Atul Luykx: Boosting Authenticated
Encryption Robustness with Minimal Modifications. CRYPTO (3)
2017: 3-33 available online at https://eprint.iacr.org/2017/239 .
2.1. Cryptographic algorithms
As an encryption primitive we use AES. We denote one call to the
primitive by E(ยท), e.g.,
Z = E_k(X)
where k is a K-bit key, X is the input to AES and Z is the output. We
omit k where it is irrelevant or is clear from context. While we
propose to set K=256 to ensure long-term post-quantum resistance, we
stress that the solution also works for other key lengths.
To encrypt, we use AES is counter mode and a nonce N to produce a
random bit stream, e.g.,
CTR(N) = E(N)||E(N+1)||...||E(N+l) = z_1||z_2||...||Z_{n+1} = Z
and XOR Z with the message M to produce the ciphertext C, e.g.,
C = Z ^ M
For authentication, we use the universal hash function GHASH and a
key k, e.g.,
T = H(K||X) = H_k(X)
where K is a 256-bit key, X an arbitrary length string, and T a
unique authentication tag for X. While we propose to set K=256 to
ensure long-term post-quantum resistance, we stress that the solution
works for any universal hash function as well as for keys of length
K!=256.
3. The proposed solution
3.1 An overview of the proposed solution
Noting that in CTR-mode the nonce is essential for the
encryption/decryption operations, the proposed solution is based on
linking the nonce and the transmitted data in such a way that any
change to the data (e.g., through a tagging attack) randomizes the
nonce and results in a random value Z' != Z for CTR(N' != N).
3.1.1. 'Forward' direction (same direction as CREATE):
When preparing a message to be sent in the forward direction, the
client is responsible for encrypting all layers. The client starts by
digesting the message to create a synthetic tweak T_0 = H_{k_fM}(M)
and uses this tweak to encrypt an all-zero string to create a
synthetic IV: S_0 = T_0 ^ E_{k_fE}(0 ^ T_0).
The message and the synthetic IV (i.e., M||S_0) are passed as input
to the first encryption layer which uses S_0 to produce the random
stream Z = CTR_k1(S_0) and the ciphertext C = Z ^ M. Then, a tweak T
= H_k2(C) is generated by digesting the ciphertext of this
layer. Finally, S_0 is encrypted using AES and the tweak T to produce
an encrypted nonce S = T ^ E_k3(N ^ T) which is appended to the the
ciphertext and is used as the nonce for the next encryption layer.
After encrypting 3 times, the client sends C||S to the guard. Whereas
the protocol previously required that the nonce be kept in sync
between each node and the client, this is no longer required as it
can now be recovered from C||S. To decrypt, the node first computes T
= H_k2(C) then uses it to obtain S = D_k3(S ^ T) ^ T. Finally, CTR(S)
is used to decrypt C into M. The once-decrypted nonce is appended to
the data and M||S is sent to the next node which repeats this
process.
The exit verifies the integrity of the message by digesting it and
using the resulting T to decrypt S_0 into N. If N=0, the message is
authenticated. Otherwise, if the message has been changed by an
adversary, N!=0 and the circuit is destroyed.
3.1.2 'Back' direction (opposite direction from CREATE):
When sending back a message from the exit to the client, each node
adds an additional layer of encryption. The exit starts by digesting
the message to create a synthetic tweak T_0 = H_{k_bM}(M) and uses
this tweak to encrypt an all-zero string to create a synthetic IV:
S_0 = T_0 ^ E_{k_bE}(0 ^ T_0). The synthetic IV is then used to
produce the random stream Z = CTR_k1(S_0) and uses that to encrypt
the plaintext through C = Z ^ M. The nonce is appended to the
ciphertext and C||S_0 is sent to the next node.
Receiving a message from the exit, the middle starts by producing a
tweak T = H_k2(C). The tweak is then used to encrypt the nonce
through S = T ^ E_k3(N ^ T) which is then used to produce the random
stream Z' = CTR_k1(S). Finally, the message is encrypted via C' = Z'
^ C and the encrypted nonce is appended to C'. The message C'||S is
sent to the next node which repeats this procedure.
When the message arrives at the client, the client peels each layer
using the nonce that is appended at the end of the message. The
decrypted layer is used to compute the tweak T = H_k2(P), which is
used to decrypt this layer's nonce into the next layer's nonce.
The client verifies the integrity of the message by digesting it and using
the resulting T to decrypt S_0 into N. If N=0, the message is
authenticated. Otherwise, if the message has been changed by an adversary,
N!=0 and the circuit is destroyed.
3.2 Circuit management
3.2.1 Creating circuits
The general process of creating a circuit remains the same (see
tor-spec.txt), except for step 5 where instead of creating a pair of
keys (kf_1,kb_1) for forward and backward communication,
respectively, 2 triplets of keys (kf_1,kf_2,kf_3) and
(kb_1,kb_2,kb_3) are created for communication in the forward and
backward directions, respectively. Two additional pairs of
"authentication keys" (k_fM,k_fE) and (k_bM,k_bE) are created between
the client and the exit in the forward and backward directions,
respectively.
note: the keys can be created by running KDF-RFC5869 3 times in each
direction, or by running it once in each direction to create a
master-key and derive the rest as subkeys from this master key
3.2.2 Routing relay cells
When an OR receives a RELAY or RELAY_EARLY cell, it checks the cell's
circID and determines whether it has a corresponding circuit along
that connection. If not, the OR drops the cell.
Otherwise, if the OR is not at the OP edge of the circuit (that is,
either an 'exit node' or a non-edge node), it de/encrypts the payload
with the stream cipher, as follows (the message structure is C||S):
'Forward' relay cell (same direction as CREATE)
(input structure is: C||S):
1. T = H_{kf_2}(T'||C); digest ciphertext (T' is a running digest
of all previous cells, i.e., last round's T)
2. N = T ^ D_{kf_3}(S ^ T); decrypt nonce
3. M = CTR_{kf_1}(N) ^ C; decrypt message
(output structure is M||N)
'Back' relay cell (opposite direction from CREATE)
(input structure is: M||N):
1. T = H_{kb_2}(T'||M); digest ciphertext (T' is a running digest
of all previous cells, i.e., last round's T)
2. S = T ^ E_{kb_3}(N ^ T); encrypt nonce
3. C = CTR_{kb_1}(S) ^ M; encrypt message
(output structure is C||S)
Note that in counter mode, decrypt (D) and encrypt (E) are the same
operation.
The OR then decides whether it recognizes the relay cell, by
inspecting the payload as described in Section 4.1 below. If the OR
recognizes the cell, it processes the contents of the relay cell.
Otherwise, it passes the decrypted relay cell along the circuit if
the circuit continues. If the OR at the end of the circuit
encounters an unrecognized relay cell, an error has occurred: the OR
sends a DESTROY cell to tear down the circuit.
4. Application connections and stream management
4.1 Relay cells
Within a circuit, the OP and the exit node use the contents of RELAY
packets to tunnel end-to-end commands and TCP connections ("Streams")
across circuits. End-to-end commands can be initiated by either
edge; streams are initiated by the OP.
The payload of each unencrypted RELAY cell consists of:
Relay command [1 byte]
'Recognized' [2 bytes]
StreamID [2 bytes]
Length [2 bytes]
Data [PAYLOAD_LEN-23 bytes]
The 'recognized' field is used for a simple indication if the cell
still encrypted or not. When sending cells, the unencrypted
'recognized' MUST be set to zero.
When receiving and decrypting cells the 'recognized' will always be
zero if we're the endpoint that the cell is destined for. For cells
that we should relay, the 'recognized' field will usually be nonzero,
but will accidentally be zero with P=2^-32.
The old Digest field is removed, since sufficient information for
authentication is now included in the all-zero string used to create the
nonce for the first encryption layer.
The 'Length' field of a relay cell contains the number of bytes in
the relay payload which contain real payload data. The remainder of
the payload is padded with NUL bytes.
4.2 Appending the encrypted nonce
When a cell is prepared by the client to be sent in the 'forward'
direction, as explained in Section 3.2.2, the encrypted nonce S is
appended to the encrypted cell (occupying the last 16 bytes of the
cell). If the cell is prepared to be sent to a node supporting the
new protocol, S is used as the nonce for the next round's
encryption. Otherwise, if the next node only supports the old
protocol, S is still appended to the encrypted cell, but a
synchronized nonce (as per the old protocol) is used for encryption.
When a cell is sent along the circuit in the 'backward' direction,
nodes supporting the new protocol always assume that the last 16
bytes of the input are the nonce used by the previous node, which
they process as per Section 3.2.2. If the previous node also supports
the new protocol, these cells are indeed the nonce. If the previous
node only supports the old protocol, these bytes are either encrypted
NUL bytes or encrypted data.
4.3 Authenticating the message
End-to-end authentication is performed in both directions in the same
way. Once the final layer of encryption is removed, the
message-to-be-authenticated is digested and this digest is used to
decrypt the nonce used in this layer. If the decrypted nonce is
all-zero, the message is authentic. Otherwise, if a change was made
to the ciphertext or the encrypted nonce somewhere along the circuit,
the nonce decrypts into a random value and the circuit is destroyed.
More information about the tor-dev
mailing list