aboutsummaryrefslogtreecommitdiff
path: root/rend-spec-v3.txt
diff options
context:
space:
mode:
Diffstat (limited to 'rend-spec-v3.txt')
-rw-r--r--rend-spec-v3.txt329
1 files changed, 259 insertions, 70 deletions
diff --git a/rend-spec-v3.txt b/rend-spec-v3.txt
index 257fdb2..8edd0da 100644
--- a/rend-spec-v3.txt
+++ b/rend-spec-v3.txt
@@ -216,6 +216,9 @@ Table of contents:
* Instantiate MAC(key=k, message=m) with H(k_len | k | m),
where k_len is htonll(len(k)).
+ When we need a particular MAC key length below, we choose
+ MAC_KEY_LEN=32 (256 bits).
+
For legacy purposes, we specify compatibility with older versions of
the Tor introduction point and rendezvous point protocols. These used
RSA1024, DH1024, AES128, and SHA1, as discussed in
@@ -238,9 +241,10 @@ Table of contents:
LSPEC (Link specifier) [LSLEN bytes]
Link specifier types are as described in tor-spec.txt. Every set of
- link specifiers MUST include at minimum specifiers of type [00]
+ link specifiers SHOULD include at minimum specifiers of type [00]
(TLS-over-TCP, IPv4), [02] (legacy node identity) and [03] (ed25519
- identity key).
+ identity key). Sets of link specifiers without these three types
+ SHOULD be rejected.
As of 0.4.1.1-alpha, Tor includes both IPv4 and IPv6 link specifiers
in v3 onion service protocol link specifier lists. All available
@@ -592,7 +596,7 @@ Table of contents:
the public blinded identity key for a service. This key is used
as an index in the DHT-like structure of the directory system
(see [SUBCRED]).
- KP_blind_id, KS_blind_id.
+ KP_hs_blind_id, KS_hs_blind_id.
Descriptor signing key -- A key used to sign hidden service
descriptors. This is signed by blinded signing keys. Unlike
@@ -603,33 +607,38 @@ Table of contents:
KP_hs_desc_sign, KS_hs_desc_sign.
Introduction point authentication key -- A short-term signing
- keypair used to identify a hidden service to a given
- introduction point. A fresh keypair is made for each
+ keypair used to identify a hidden service's session at a given
+ introduction point. The service makes a fresh keypair for each
introduction point; these are used to sign the request that a
hidden service host makes when establishing an introduction
point, so that clients who know the public component of this key
can get their introduction requests sent to the right
service. No keypair is ever used with more than one introduction
point. (previously called a "service key" in rend-spec.txt)
- KP_hs_intro_tid, KS_hs_intro_tid
- ("hidden service introduction point temporary id").
+ KP_hs_ipt_sid, KS_hs_ipt_sid
+ ("hidden service introduction point session id").
Introduction point encryption key -- A short-term encryption
keypair used when establishing connections via an introduction
- point. Plays a role analogous to Tor nodes' onion keys. A fresh
- keypair is made for each introduction point.
- KP_hs_intro_ntor, KS_hs_intro_ntor.
+ point. Plays a role analogous to Tor nodes' onion keys. The service
+ makes a fresh keypair for each introduction point.
+ KP_hss_ntor, KS_hss_ntor.
+
+ Ephemeral descriptor encryption key -- A short-lived encryption
+ keypair made by the service, and used to encrypt the inner layer
+ of hidden service descriptors when client authentication is in
+ use.
+ KP_hss_desc_enc, KS_hss_desc_enc
- Symmetric keys defined in this document:
+ Nonces defined in this document:
- Descriptor encryption keys -- A symmetric encryption key used to
- encrypt the body of hidden service descriptors. Derived from the
- current period and the hidden service credential.
- K_desc_enc.
+ N_hs_desc_enc -- a nonce used to derive keys to decrypt the inner
+ encryption layer of hidden service descriptors. This is
+ sometimes also called a "descriptor cookie".
Public/private keypairs defined elsewhere:
- Onion key -- Short-term encryption keypair (KS_onion_ntor, KP_onion_ntor).
+ Onion key -- Short-term encryption keypair (KS_ntor, KP_ntor).
(Node) identity key (KP_relayid).
@@ -651,7 +660,8 @@ Table of contents:
Specifically, each authorized client possesses:
- An x25519 keypair used to compute decryption keys that allow the client to
- decrypt the hidden service descriptor. See [HS-DESC-ENC].
+ decrypt the hidden service descriptor. See [HS-DESC-ENC]. This is
+ the client's counterpart to KP_hss_desc_enc.
KP_hsc_desc_enc, KS_hsd_desc_enc.
- An ed25519 keypair which allows the client to compute signatures which
@@ -722,7 +732,7 @@ Table of contents:
* the daily subcredential,
* the hidden service directories' public keys,
* a shared random value that changes in each time period,
- shared_random_value.
+ shared_random_value.
* a set of network-wide networkstatus consensus parameters.
(Consensus parameters are integer values voted on by authorities
and published in the consensus documents, described in
@@ -811,7 +821,7 @@ Table of contents:
derived, the uploading or downloading party calculates:
for replicanum in 1...hsdir_n_replicas:
- hs_index(replicanum) = H("store-at-idx" |
+ hs_service_index(replicanum) = H("store-at-idx" |
blinded_public_key |
INT_8(replicanum) |
INT_8(period_length) |
@@ -825,7 +835,7 @@ Table of contents:
Then, for each node listed in the current consensus with the HSDir flag,
we compute a directory index for that node as:
- hsdir_index(node) = H("node-idx" | node_identity |
+ hs_relay_index(node) = H("node-idx" | node_identity |
shared_random_value |
INT_8(period_num) |
INT_8(period_length) )
@@ -836,7 +846,7 @@ Table of contents:
Finally, for replicanum in 1...hsdir_n_replicas, the hidden service
host uploads descriptors to the first hsdir_spread_store nodes whose
- indices immediately follow hs_index(replicanum). If any of those
+ indices immediately follow hs_service_index(replicanum). If any of those
nodes have already been selected for a lower-numbered replica of the
service, any nodes already chosen are disregarded (i.e. skipped over)
when choosing a replica's hsdir_spread_store nodes.
@@ -988,6 +998,28 @@ Table of contents:
Consider that the service is at 01:00 right after SRV#2: it will upload its
second descriptor using TP#2 and SRV#2.
+2.2.4.3. Directory behavior for handling descriptor uploads [DIRUPLOAD]
+
+ Upon receiving a hidden service descriptor publish request, directories MUST
+ check the following:
+
+ * The outer wrapper of the descriptor can be parsed according to
+ [DESC-OUTER]
+ * The version-number of the descriptor is "3"
+ * If the directory has already cached a descriptor for this hidden service,
+ the revision-counter of the uploaded descriptor must be greater than the
+ revision-counter of the cached one
+ * The descriptor signature is valid
+
+ If any of these basic validity checks fails, the directory MUST reject the
+ descriptor upload.
+
+ NOTE: Even if the descriptor passes the checks above, its first and second
+ layers could still be invalid: directories cannot validate the encrypted
+ layers of the descriptor, as they do not have access to the public key of the
+ service (required for decrypting the first layer of encryption), or the
+ necessary client credentials (for decrypting the second layer).
+
2.2.5. Expiring hidden service descriptors [EXPIRE-DESC]
Hidden services set their descriptor's "descriptor-lifetime" field to 180
@@ -1188,10 +1220,11 @@ Table of contents:
"encrypted" field.
If client auth is enabled, the hidden service generates a fresh
- descriptor_cookie key (32 random bytes) and encrypts it using each
- authorized client's identity x25519 key. Authorized clients can use the
- descriptor cookie to decrypt the second layer of encryption. Our encryption
- scheme requires the hidden service to also generate an ephemeral x25519
+ descriptor_cookie key (`N_hs_desc_enc`, 32 random bytes) and encrypts
+ it using each authorized client's identity x25519 key. Authorized
+ clients can use the descriptor cookie (`N_hs_desc_enc`) to decrypt
+ the second (inner) layer of encryption. Our encryption scheme
+ requires the hidden service to also generate an ephemeral x25519
keypair for each new descriptor.
If client auth is disabled, fake data is placed in each of the fields below
@@ -1209,13 +1242,13 @@ Table of contents:
If client authorization is disabled, the value here should be "x25519".
- "desc-auth-ephemeral-key" SP key NL
+ "desc-auth-ephemeral-key" SP KP_hs_desc_ephem NL
[Exactly once]
- This field contains an ephemeral x25519 public key generated by the
- hidden service and encoded in base64. The key is used by the encryption
- scheme below.
+ This field contains `KP_hss_desc_enc`, an ephemeral x25519 public
+ key generated by the hidden service and encoded in base64. The key
+ is used by the encryption scheme below.
If client authorization is disabled, the value here should be a fresh
x25519 pubkey that will remain unused.
@@ -1230,23 +1263,16 @@ Table of contents:
data of the right size (that's 8 bytes for 'client-id', 16 bytes for 'iv'
and 16 bytes for 'encrypted-cookie' all encoded with base64).
- When client authorization is enabled, each "auth-client" line contains
- the descriptor cookie encrypted to each individual client. We assume that
- each authorized client possesses a pre-shared x25519 keypair which is
- used to decrypt the descriptor cookie.
+ When client authorization is enabled, each "auth-client" line
+ contains the descriptor cookie `N_hs_desc_enc` encrypted to each
+ individual client. We assume that each authorized client possesses
+ a pre-shared x25519 keypair (`KP_hsc_desc_enc`) which is used to
+ decrypt the descriptor cookie.
- We now describe the descriptor cookie encryption scheme. Here are the
- relevant keys:
+ We now describe the descriptor cookie encryption scheme. Here is what
+ the hidden service computes:
- client_x = private x25519 key of authorized client
- client_X = public x25519 key of authorized client
- hs_y = private key of ephemeral x25519 keypair of hidden service
- hs_Y = public key of ephemeral x25519 keypair of hidden service
- descriptor_cookie = descriptor cookie used to encrypt the descriptor
-
- And here is what the hidden service computes:
-
- SECRET_SEED = x25519(hs_y, client_X)
+ SECRET_SEED = x25519(KS_hs_desc_ephem, KP_hsc_desc_enc)
KEYS = KDF(N_hs_subcred | SECRET_SEED, 40)
CLIENT-ID = fist 8 bytes of KEYS
COOKIE-KEY = last 32 bytes of KEYS
@@ -1259,7 +1285,7 @@ Table of contents:
- The "encrypted-cookie" field contains the descriptor cookie ciphertext
as follows and is encoded in base64:
- encrypted-cookie = STREAM(iv, COOKIE-KEY) XOR descriptor_cookie
+ encrypted-cookie = STREAM(iv, COOKIE-KEY) XOR N_hs_desc_enc.
See section [FIRST-LAYER-CLIENT-BEHAVIOR] for the client-side logic of
how to decrypt the descriptor cookie.
@@ -1272,6 +1298,12 @@ Table of contents:
discussed in [HS-DESC-SECOND-LAYER] below. The blob is base64 encoded
and enclosed in -----BEGIN MESSAGE---- and ----END MESSAGE---- wrappers.
+ Compatibility note: The C Tor implementation does not include a final
+ newline when generating this first-layer-plaintext section; other
+ implementations MUST accept this section even if it is missing its final
+ newline. Other implementations MAY generate this section without a final
+ newline themselves, to avoid being distinguishable from C tor.
+
2.5.1.3. Client behavior [FIRST-LAYER-CLIENT-BEHAVIOR]
The goal of clients at this stage is to decrypt the "encrypted" field as
@@ -1342,10 +1374,10 @@ Table of contents:
[Exactly once]
- A space-separated list of integers denoting CREATE2 cell format numbers
- that the server recognizes. Must include at least ntor as described in
- tor-spec.txt. See tor-spec section 5.1 for a list of recognized
- handshake types.
+ A space-separated list of integers denoting CREATE2 cell HTYPEs
+ (handshake types) that the server recognizes. Must include at least
+ ntor as described in tor-spec.txt. See tor-spec section 5.1 for a list
+ of recognized handshake types.
"intro-auth-required" SP types NL
@@ -1354,7 +1386,7 @@ Table of contents:
A space-separated list of introduction-layer authentication types; see
section [INTRO-AUTH] for more info. A client that does not support at
least one of these authentication types will not be able to contact the
- host. Recognized types are: 'password' and 'ed25519'.
+ host. Recognized types are: 'ed25519'.
"single-onion-service"
@@ -1374,7 +1406,7 @@ Table of contents:
point section]
The link-specifiers is a base64 encoding of a link specifier
- block in the format described in BUILDING-BLOCKS.
+ block in the format described in [BUILDING-BLOCKS] above.
As of 0.4.1.1-alpha, services include both IPv4 and IPv6 link
specifiers in descriptors. All available addresses SHOULD be
@@ -1386,11 +1418,20 @@ Table of contents:
recognize; instead, it should use them verbatim in its EXTEND
request to the introduction point.
- The client MAY perform basic validity checks on the link
- specifiers in the descriptor. These checks SHOULD NOT leak
+ The client SHOULD perform the basic validity checks on the link
+ specifiers in the descriptor, described in `tor-spec.txt`
+ section 5.1.2. These checks SHOULD NOT leak
detailed information about the client's version, configuration,
or consensus. (See 3.3 for service link specifier handling.)
+ When connecting to the introduction point, the client SHOULD send
+ this list of link specifiers verbatim, in the same order as given
+ here.
+
+ The client MAY reject the list of link specifiers if it is
+ inconsistent with relay information from the directory, but SHOULD
+ NOT modify it.
+
"onion-key" SP "ntor" SP key NL
[Exactly once per introduction point]
@@ -1399,22 +1440,48 @@ Table of contents:
key of the introduction point Tor node used for the ntor handshake
when a client extends to it.
+ "onion-key" SP KeyType SP key.. NL
+
+ [Any number of times]
+
+ Implementations should accept other types of onion keys using this
+ syntax (where "KeyType" is some string other than "ntor");
+ unrecognized key types should be ignored.
+
"auth-key" NL certificate NL
[Exactly once per introduction point]
- The certificate is a proposal 220 certificate wrapped in "-----BEGIN
- ED25519 CERT-----" cross-certifying the introduction point
- authentication key using the descriptor signing key. The introduction
- point authentication key is included in the mandatory signing-key
- extension. The certificate type must be [09].
+ The certificate is a proposal 220 certificate wrapped in
+ "-----BEGIN ED25519 CERT-----". It contains the introduction
+ point authentication key (`KP_hs_ipt_sid`), signed by
+ the descriptor signing key (`KP_hs_desc_sign`). The
+ certificate type must be [09], and the signing key extension
+ is mandatory.
+
+ NOTE: This certificate was originally intended to be
+ constructed the other way around: the signing and signed keys
+ are meant to be reversed. However, C tor implemented it
+ backwards, and other implementations now need to do the same
+ in order to conform. (Since this section is inside the
+ descriptor, which is _already_ signed by `KP_hs_desc_sign`,
+ the verification aspect of this certificate serves no point in
+ its current form.)
"enc-key" SP "ntor" SP key NL
[Exactly once per introduction point]
The key is a base64 encoded curve25519 public key used to encrypt
- the introduction request to service.
+ the introduction request to service. (`KP_hss_ntor`)
+
+ "enc-key" SP KeyType SP key.. NL
+
+ [Any number of times]
+
+ Implementations should accept other types of onion keys using this
+ syntax (where "KeyType" is some string other than "ntor");
+ unrecognized key types should be ignored.
"enc-key-cert" NL certificate NL
@@ -1423,13 +1490,22 @@ Table of contents:
Cross-certification of the encryption key using the descriptor
signing key.
- For "ntor" keys, certificate is a proposal 220 certificate wrapped
- in "-----BEGIN ED25519 CERT-----" armor, cross-certifying the
- descriptor signing key with the ed25519 equivalent of a curve25519
- public encryption key derived using the process in proposal 228
- appendix A. The certificate type must be [0B], and the signing-key
+ For "ntor" keys, certificate is a proposal 220 certificate
+ wrapped in "-----BEGIN ED25519 CERT-----" armor. The subject
+ key is the the ed25519 equivalent of a curve25519 public
+ encryption key (`KP_hss_ntor`), with the ed25519 key
+ derived using the process in proposal 228 appendix A. The
+ signing key is the descriptor signing key (`KP_hs_desc_sign`).
+ The certificate type must be [0B], and the signing-key
extension is mandatory.
+ NOTE: As with "auth-key", this certificate was intended to be
+ constructed the other way around. However, for compatibility
+ with C tor, implementations need to construct it this way. It
+ serves even less point than "auth-key", however, since the
+ encryption key `KP_hss_ntor` is already available from
+ the `enc-key` entry.
+
"legacy-key" NL key NL
[None or at most once per introduction point]
@@ -1463,6 +1539,11 @@ Table of contents:
Clients who manage to extract the introduction points of the hidden service
can proceed with the introduction protocol as specified in [INTRO-PROTOCOL].
+ Compatibility note: At least some versions of OnionBalance do not include
+ a final newline when generating this inner plaintext section; other
+ implementations MUST accept this section even if it is missing its final
+ newline.
+
2.5.3. Deriving hidden service descriptor encryption keys [HS-DESC-ENCRYPTION-KEYS]
In this section we present the generic encryption format for hidden service
@@ -1573,7 +1654,7 @@ Table of contents:
The AUTH_KEY_LEN field determines the length of the AUTH_KEY
field. The AUTH_KEY field contains the public introduction point
- authentication key.
+ authentication key, KP_hs_ipt_sid.
The EXT_FIELD_TYPE, EXT_FIELD_LEN, EXT_FIELD entries are reserved for
extensions to the introduction protocol. Extensions with
@@ -1597,8 +1678,8 @@ Table of contents:
SIG_LEN is the length of the signature.
SIG is a signature, using AUTH_KEY, of all contents of the cell, up
- to but not including SIG. These contents are prefixed with the string
- "Tor establish-intro cell v1".
+ to but not including SIG_LEN and SIG. These contents are prefixed
+ with the string "Tor establish-intro cell v1".
Upon receiving an ESTABLISH_INTRO cell, a Tor node first decodes the
key and the signature, and checks the signature. The node must reject
@@ -1783,6 +1864,11 @@ Table of contents:
INTRODUCE2 cell with exactly the same contents to the service, and sends an
INTRODUCE_ACK response to the client.
+ (Note that the introduction point does not "clean up" the
+ INTRODUCE1 cells that it retransmits. Specifically, it does not
+ change the order or multiplicity of the extensions sent by the
+ client.)
+
The same rules for multiplicity, ordering, and handling unknown types
apply to the extension fields here as described [EST_INTRO] above.
@@ -1862,8 +1948,15 @@ Table of contents:
The hidden service should handle invalid or unrecognised link specifiers
the same way as clients do in section 2.5.2.2. In particular, services
- MAY perform basic validity checks on link specifiers, and SHOULD NOT
+ SHOULD perform basic validity checks on link specifiers, and SHOULD NOT
reject unrecognised link specifiers, to avoid information leaks.
+ The list of link specifiers received here SHOULD either be rejected, or
+ sent verbatim when extending to the rendezvous point, in the same order
+ received.
+
+ The service MAY reject the list of link specifiers if it is
+ inconsistent with relay information from the directory, but SHOULD
+ NOT modify it.
The ONION_KEY_TYPE field is:
@@ -2022,7 +2115,8 @@ Table of contents:
The hidden service host now also knows the keys generated by the
handshake, which it will use to encrypt and authenticate data
end-to-end between the client and the server. These keys are as
- computed in tor-spec.txt section 5.1.4.
+ computed in tor-spec.txt section 5.1.4, except that instead of using
+ AES-128 and SHA1 for this hop, we use AES-256 and SHA3-256.
3.4. Authentication during the introduction phase. [INTRO-AUTH]
@@ -2030,7 +2124,10 @@ Table of contents:
One mechanism to do so is the credential mechanism, where only users who
know the credential for a hidden service may connect at all.
-3.4.1. Ed25519-based authentication.
+ There is one defined authentication type: `ed25519`.
+
+
+3.4.1. Ed25519-based authentication `ed25519`.
To authenticate with an Ed25519 private key, the user must include an
extension field in the encrypted part of the INTRODUCE1 cell with an
@@ -2662,3 +2759,95 @@ Appendix F. Two methods for managing revision counters.
Similarly, implementations SHOULD NOT let the revision counter
increase forever without resetting it -- doing so links the service
across changes in the blinded public key.
+
+Appendix G. Text vectors
+
+ G.1. Test vectors for hs-ntor / NTOR-WITH-EXTRA-DATA
+
+ Here is a set of test values for the hs-ntor handshake, called
+ [NTOR-WITH-EXTRA-DATA] in this document. They were generated by
+ instrumenting Tor's code to dump the values for an INTRODUCE/RENDEZVOUS
+ handshake, and then by running that code on a Chutney network.
+
+ We assume an onion service with:
+
+ KP_hs_ipd_sid = 34E171E4358E501BFF21ED907E96AC6B
+ FEF697C779D040BBAF49ACC30FC5D21F
+ KP_hss_ntor = 8E5127A40E83AABF6493E41F142B6EE3
+ 604B85A3961CD7E38D247239AFF71979
+ KS_hss_ntor = A0ED5DBF94EEB2EDB3B514E4CF6ABFF6
+ 022051CC5F103391F1970A3FCD15296A
+ N_hs_subcred = 0085D26A9DEBA252263BF0231AEAC59B
+ 17CA11BAD8A218238AD6487CBAD68B57
+
+ The client wants to make in INTRODUCE request. It generates
+ the following header (everything before the ENCRYPTED portion)
+ of its INTRODUCE1 cell:
+
+ H = 000000000000000000000000000000000000000002002034E171E4358E501BFF
+ 21ED907E96AC6BFEF697C779D040BBAF49ACC30FC5D21F00
+
+ It generates the following plaintext body to encrypt. (This
+ is the "decrypted plaintext body" from [PROCESS_INTRO2].
+
+ P = 6BD364C12638DD5C3BE23D76ACA05B04E6CE932C0101000100200DE6130E4FCA
+ C4EDDA24E21220CC3EADAE403EF6B7D11C8273AC71908DE565450300067F0000
+ 0113890214F823C4F8CC085C792E0AEE0283FE00AD7520B37D0320728D5DF39B
+ 7B7077A0118A900FF4456C382F0041300ACF9C58E51C392795EF870000000000
+ 0000000000000000000000000000000000000000000000000000000000000000
+ 000000000000000000000000000000000000000000000000000000000000
+
+ The client now begins the hs-ntor handshake. It generates
+ a curve25519 keypair:
+
+ x = 60B4D6BF5234DCF87A4E9D7487BDF3F4
+ A69B6729835E825CA29089CFDDA1E341
+ X = BF04348B46D09AED726F1D66C618FDEA
+ 1DE58E8CB8B89738D7356A0C59111D5D
+
+ Then it calculates:
+
+ ENC_KEY = 9B8917BA3D05F3130DACCE5300C3DC27
+ F6D012912F1C733036F822D0ED238706
+ MAC_KEY = FC4058DA59D4DF61E7B40985D122F502
+ FD59336BC21C30CAF5E7F0D4A2C38FD5
+
+ With these, it encrypts the plaintext body P with ENC_KEY, getting
+ an encrypted value C. It computes MAC(MAC_KEY, H | X | C),
+ getting a MAC value M. It then assembles the final INTRODUCE1
+ body as H | X | C | M:
+
+ 000000000000000000000000000000000000000002002034E171E4358E501BFF
+ 21ED907E96AC6BFEF697C779D040BBAF49ACC30FC5D21F00BF04348B46D09AED
+ 726F1D66C618FDEA1DE58E8CB8B89738D7356A0C59111D5DADBECCCB38E37830
+ 4DCC179D3D9E437B452AF5702CED2CCFEC085BC02C4C175FA446525C1B9D5530
+ 563C362FDFFB802DAB8CD9EBC7A5EE17DA62E37DEEB0EB187FBB48C63298B0E8
+ 3F391B7566F42ADC97C46BA7588278273A44CE96BC68FFDAE31EF5F0913B9A9C
+ 7E0F173DBC0BDDCD4ACB4C4600980A7DDD9EAEC6E7F3FA3FC37CD95E5B8BFB3E
+ 35717012B78B4930569F895CB349A07538E42309C993223AEA77EF8AEA64F25D
+ DEE97DA623F1AEC0A47F150002150455845C385E5606E41A9A199E7111D54EF2
+ D1A51B7554D8B3692D85AC587FB9E69DF990EFB776D8
+
+ Later the service receives that body in an INTRODUCE2 cell. It
+ processes it according to the hs-ntor handshake, and recovers
+ the client's plaintext P. To continue the hs-ntor handshake,
+ the service chooses a curve25519 keypair:
+
+ y = 68CB5188CA0CD7924250404FAB54EE13
+ 92D3D2B9C049A2E446513875952F8F55
+ Y = 8FBE0DB4D4A9C7FF46701E3E0EE7FD05
+ CD28BE4F302460ADDEEC9E93354EE700
+
+ From this and the client's input, it computes:
+
+ AUTH_INPUT_MAC = 4A92E8437B8424D5E5EC279245D5C72B
+ 25A0327ACF6DAF902079FCB643D8B208
+ NTOR_KEY_SEED = 4D0C72FE8AFF35559D95ECC18EB5A368
+ 83402B28CDFD48C8A530A5A3D7D578DB
+
+ The service sends back Y | AUTH_INPUT_MAC in its RENDEZVOUS1 cell
+ body. From these, the client finishes the handshake, validates
+ AUTH_INPUT_MAC, and computes the same NTOR_KEY_SEED.
+
+ Now that both parties have the same NTOR_KEY_SEED, they can derive
+ the shared key material they will use for their circuit.