My question pertains to the scenario after the client and the HS have exchanged a symmetric key. So, we have the following circuit:

Client -- c_relay_1(guard) -- c_relay_2 -- RP -- s_relay_3 -- s_relay_2 -- s_relay_1(guard) -- HS

Client encrypts payload with HS symmetric key, then the cell is encrypted in the following way:


At the RP the payload is encrypted only with the HS symmetric key. Later, the server's 3 relays encrypt the cell again in a similar fashion towards the HS. Is this correct?

1 Answer 1


I'm 99% certain that is how it works. And since it uses regular circuit/relay crypto, there are actually two symmetric keys at each end, one for the forward direction and one for the backward direction. Both the client and service add an imaginary "hop" to their circuit paths, which performs the end-to-end encryption/decryption.

Code path on the service:

hs_circ_service_rp_has_opened() -> hs_circuit_setup_e2e_rend_circ() -> finalize_rend_circuit() -> cpath_extend_linked_list()

Code path on the client:

handle_rendezvous2() -> hs_circuit_setup_e2e_rend_circ() -> finalize_rend_circuit() -> cpath_extend_linked_list()
  • Huh, 2 keys at each end? I thought the session key was the result of the Diffie-Hellman exchange, which yields a single shared key. When a client first talks to an introduction point it sends the first half of DH, when the server answers to the rendezvous it sends the 2nd half of DH. Jan 4, 2021 at 17:50
  • @Christian Tor uses the ntor handshake to exchange seed material and derive keys. Both the forward and backward keys are derived from this handshake data. Onion services use a modification of this handshake [NTOR-WITH-EXTRA-DATA] during the introduction, and pass the handshake data in the Rendezvous cell.
    – Steve
    Jan 4, 2021 at 19:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .