Calculating the response for a fast handshake

I’m not sure which category this should best belong to, but here goes:

I’m reading through the specification and looking through the code (a slightly modified torpy), and I can’t figure out what the handshake_response should be.

According to CREATE and CREATED cells - Tor Specifications and
Setting circuit keys - Tor Specifications, both the OP and the first hop generate random key material:

def handshake(self):
        return secrets.token_bytes(TOR_DIGEST_LEN)

and then the OP sends it X to the first hop, and the first hop responds with a handshake_response such that with it we can

def complete_handshake(self, handshake_response):
        # tor ref: fast_client_handshake
        peer_value = handshake_response[:TOR_DIGEST_LEN]
        key_hash = handshake_response[TOR_DIGEST_LEN:]
        shared_secret = self.handshake + peer_value
        computed_auth, key_material = kdf_tor(shared_secret)
        if computed_auth != key_hash:
            raise KeyAgreementError('Auth input does not match.')
        return key_material[:KeyAgreement.KEY_MATERIAL_LENGTH]

, where

def tor_digest(msg):
    return sha1(msg)


def kdf_tor(shared_secret):
    # tor ref: crypto_expand_key_material_TAP
    t = shared_secret + bytes([0])
    computed_auth = tor_digest(t)
    key_material = b''
    for i in trange(1, 5):
        t = shared_secret + bytes([i])
        tsh = tor_digest(t)
        key_material += tsh
    return computed_auth, key_material

So, how do we calculate the handshake_response? Am I being slow and missing something?
I tried looking into the source (Tor: core/crypto/onion_fast.c Source File), but I’m not that good with C, so I didn’t really get it from there either.

1 Like