From e67c9afd100a8822a5aa4e8201a56eb2cf5374af Mon Sep 17 00:00:00 2001 From: Emil Engler Date: Sat, 17 Jun 2023 22:57:42 +0200 Subject: tor-spec: provide pseudocode for digest check This commit implements a pseudocode example for the digest in both: encryption and decryption cases. The pseudocode itself is a combination of Python code and the Rust slice type. Fixes #205 --- tor-spec.txt | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'tor-spec.txt') diff --git a/tor-spec.txt b/tor-spec.txt index b42ee26..669851f 100644 --- a/tor-spec.txt +++ b/tor-spec.txt @@ -49,6 +49,7 @@ Table of Contents 5.6. Handling relay_early cells 6. Application connections and stream management 6.1. Relay cells + 6.1.1. Calculating the 'Digest' field 6.2. Opening streams and transferring data 6.2.1. Opening a directory stream 6.3. Closing streams @@ -1791,6 +1792,48 @@ see tor-design.pdf. understood, the cell must be dropped and ignored. Its contents still count with respect to the digests and flow control windows, though. +6.1.1. Calculating the 'Digest' field + + The 'Digest' field itself serves the purpose to check if a cell has been + fully decrypted, that is, all onion layers have been removed. Having a + single field, namely 'Recognized' is not sufficient, as outlined above. + + When ENCRYPTING a RELAY cell, an implementation does the following: + + # Encode the cell in binary (recognized and digest set to zero) + tmp = cmd + [0, 0] + stream_id + [0, 0, 0, 0] + length + data + padding + + # Update the digest with the encoded data + digest_state = hash_update(digest_state, tmp) + digest = hash_calculate(digest_state) + + # The encoded data is the same as above with the digest field not being + # zero anymore + encoded = cmd + [0, 0] + stream_id + digest[0..4] + length + data + + padding + + # Now we can encrypt the cell by adding the onion layers ... + + When DECRYPTING a RELAY cell, an implementation does the following: + + decrypted = decrypt(cell) + + # Replace the digest field in decrypted by zeros + tmp = decrypted[0..5] + [0, 0, 0, 0] + decrypted[9..] + + # Update the digest field with the decrypted data and its digest field + # set to zero + digest_state = hash_update(digest_state, tmp) + digest = hash_calculate(digest_state) + + if digest[0..4] == decrypted[5..9] + # The cell has been fully decrypted ... + + The caveat itself is that only the binary data with the digest bytes set to + zero are being taken into account when calculating the running digest. The + final plain-text cells (with the digest field set to its actual value) are + not taken into the running digest. + 6.2. Opening streams and transferring data To open a new anonymized TCP connection, the OP chooses an open -- cgit v1.2.3-54-g00ecf