From 4e90709b8c25ba50e4361e5d6cf3807e849fdfc9 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 23 Aug 2023 10:43:19 -0400 Subject: Copy description of ntorv3 into tor-spec.txt --- tor-spec.txt | 151 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 2 deletions(-) (limited to 'tor-spec.txt') diff --git a/tor-spec.txt b/tor-spec.txt index 669851f..3e13fcd 100644 --- a/tor-spec.txt +++ b/tor-spec.txt @@ -31,6 +31,7 @@ Table of Contents 5.1.2. EXTEND and EXTENDED cells 5.1.3. The "TAP" handshake 5.1.4. The "ntor" handshake + 5.1.4.1. The "ntor-v3" handshake. 5.1.5. CREATE_FAST/CREATED_FAST cells 5.2. Setting circuit keys 5.2.1. KDF-TOR @@ -1030,7 +1031,7 @@ see tor-design.pdf. 0x0000 TAP -- the original Tor handshake; see 5.1.3 0x0001 reserved 0x0002 ntor -- the ntor+curve25519+sha256 handshake; see 5.1.4 - + 0x0003 ntor-v3 -- ntor extended with extra data; see 5.1.4.1 The format of a CREATE cell is one of the following: @@ -1311,6 +1312,152 @@ see tor-design.pdf. into the keys needed for the Tor relay protocol, using the KDF described in 5.2.2 and the tag m_expand. +5.1.4.1. The "ntor-v3" handshake + + This handshake extends the ntor handshake to include support + for extra data transmitted as part of the handshake. Both + the client and the server can transmit extra data; in both cases, + the extra data is encrypted, but only server data receives + forward secrecy. + + To advertise support for this handshake, servers advertise the + "Relay=4" subprotocol version. To select it, clients use the + 'ntor-v3' HTYPE value in their CREATE2 cells. + + In this handshake, we define: + + PROTOID = "ntor3-curve25519-sha3_256-1" + t_msgkdf = PROTOID | ":kdf_phase1" + t_msgmac = PROTOID | ":msg_mac" + t_key_seed = PROTOID | ":key_seed" + t_verify = PROTOID | ":verify" + t_final = PROTOID | ":kdf_final" + t_auth = PROTOID | ":auth_final" + + `ENCAP(s)` -- an encapsulation function. We define this + as `htonll(len(s)) | s`. (Note that `len(ENCAP(s)) = len(s) + 8`). + + `PARTITION(s, n1, n2, n3, ...)` -- a function that partitions a + bytestring `s` into chunks of length `n1`, `n2`, `n3`, and so + on. Extra data is put into a final chunk. If `s` is not long + enough, the function fails. + + H(s, t) = SHA3_256(ENCAP(t) | s) + MAC(k, msg, t) = SHA3_256(ENCAP(t) | ENCAP(k) | s) + KDF(s, t) = SHAKE_256(ENCAP(t) | s) + ENC(k, m) = AES_256_CTR(k, m) + + EXP(pk,sk), KEYGEN: defined as in curve25519 + + DIGEST_LEN = MAC_LEN = MAC_KEY_LEN = ENC_KEY_LEN = PUB_KEY_LEN = 32 + + ID_LEN = 32 (representing an ed25519 identity key) + + For any tag "t_foo": + H_foo(s) = H(s, t_foo) + MAC_foo(k, msg) = MAC(k, msg, t_foo) + KDF_foo(s) = KDF(s, t_foo) + + Other notation is as in the ntor description in 5.1.4 above. + + The client begins by knowing: + + B, ID -- The curve25519 onion key and Ed25519 ID of the server that it + wants to use. + CM -- A message it wants to send as part of its handshake. + VER -- An optional shared verification string: + + The client computes: + + x,X = KEYGEN() + Bx = EXP(B,x) + secret_input_phase1 = Bx | ID | X | B | PROTOID | ENCAP(VER) + phase1_keys = KDF_msgkdf(secret_input_phase1) + (ENC_K1, MAC_K1) = PARTITION(phase1_keys, ENC_KEY_LEN, MAC_KEY_LEN) + encrypted_msg = ENC(ENC_K1, CM) + msg_mac = MAC_msgmac(MAC_K1, ID | B | X | encrypted_msg) + + The client then sends, as its CREATE handshake: + + NODEID ID [ID_LEN bytes] + KEYID B [PUB_KEY_LEN bytes] + CLIENT_PK X [PUB_KEY_LEN bytes] + MSG encrypted_msg [len(CM) bytes] + MAC msg_mac [MAC_LEN bytes] + + The client remembers x, X, B, ID, Bx, and msg_mac. + + When the server receives this handshake, it checks whether NODEID is as + expected, and looks up the (b,B) keypair corresponding to KEYID. If the + keypair is missing or the NODEID is wrong, the handshake fails. + + Now the relay uses `X=CLIENT_PK` to compute: + + Xb = EXP(X,b) + secret_input_phase1 = Xb | ID | X | B | PROTOID | ENCAP(VER) + phase1_keys = KDF_msgkdf(secret_input_phase1) + (ENC_K1, MAC_K1) = PARTITION(phase1_keys, ENC_KEY_LEN, MAC_KEY_LEN) + + expected_mac = MAC_msgmac(MAC_K1, ID | B | X | MSG) + + If `expected_mac` is not `MAC`, the handshake fails. Otherwise + the relay computes `CM` as: + + CM = DEC(MSG, ENC_K1) + + The relay then checks whether `CM` is well-formed, and in response + composes `SM`, the reply that it wants to send as part of the + handshake. It then generates a new ephemeral keypair: + + y,Y = KEYGEN() + + and computes the rest of the handshake: + + Xy = EXP(X,y) + secret_input = Xy | Xb | ID | B | X | Y | PROTOID | ENCAP(VER) + ntor_key_seed = H_key_seed(secret_input) + verify = H_verify(secret_input) + + RAW_KEYSTREAM = KDF_final(ntor_key_seed) + (ENC_KEY, KEYSTREAM) = PARTITION(RAW_KEYSTREAM, ENC_KEY_LKEN, ...) + + encrypted_msg = ENC(ENC_KEY, SM) + + auth_input = verify | ID | B | Y | X | MAC | ENCAP(encrypted_msg) | + PROTOID | "Server" + AUTH = H_auth(auth_input) + + The relay then sends as its CREATED handshake: + + Y Y [PUB_KEY_LEN bytes] + AUTH AUTH [DIGEST_LEN bytes] + MSG encrypted_msg [len(SM) bytes, up to end of the message] + + Upon receiving this handshake, the client computes: + + Yx = EXP(Y, x) + secret_input = Yx | Bx | ID | B | X | Y | PROTOID | ENCAP(VER) + ntor_key_seed = H_key_seed(secret_input) + verify = H_verify(secret_input) + + auth_input = verify | ID | B | Y | X | MAC | ENCAP(MSG) | + PROTOID | "Server" + AUTH_expected = H_auth(auth_input) + + If AUTH_expected is equal to AUTH, then the handshake has + succeeded. The client can then calculate: + + RAW_KEYSTREAM = KDF_final(ntor_key_seed) + (ENC_KEY, KEYSTREAM) = PARTITION(RAW_KEYSTREAM, ENC_KEY_LKEN, ...) + + SM = DEC(ENC_KEY, MSG) + + SM is the message from the relay, and the client uses KEYSTREAM to + generate the shared secrets for the newly created circuit. + + Now both parties share the same KEYSTREAM, and can use it to generate + their circuit keys. + 5.1.5. CREATE_FAST/CREATED_FAST cells When initializing the first hop of a circuit, the OP has already @@ -2421,7 +2568,7 @@ see tor-design.pdf. "4" -- support the ntorv3 (version 3) key exchange and all features in 0.4.7.3-alpha. This adds a new CREATE2 cell type. See proposal 332 - for more details. + and section 5.1.4.1 above for more details. 9.4. "HSIntro" -- cgit v1.2.3-54-g00ecf