aboutsummaryrefslogtreecommitdiff
path: root/tor-spec.txt
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2023-08-23 10:43:19 -0400
committerNick Mathewson <nickm@torproject.org>2023-10-03 08:34:18 -0400
commit4e90709b8c25ba50e4361e5d6cf3807e849fdfc9 (patch)
tree2582c7a7153fce3aa79a94c362564355945564da /tor-spec.txt
parent53da9bef54aa8eb243466c891653f7f6a299bacb (diff)
downloadtorspec-4e90709b8c25ba50e4361e5d6cf3807e849fdfc9.tar.gz
torspec-4e90709b8c25ba50e4361e5d6cf3807e849fdfc9.zip
Copy description of ntorv3 into tor-spec.txt
Diffstat (limited to 'tor-spec.txt')
-rw-r--r--tor-spec.txt151
1 files changed, 149 insertions, 2 deletions
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"