mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-28 06:13:31 +01:00
Adjust spec to parameterize cell and key lengths. This should please Ian.
svn:r5922
This commit is contained in:
parent
cc349042f6
commit
7dbea118ce
159
doc/tor-spec.txt
159
doc/tor-spec.txt
@ -17,7 +17,9 @@ TODO: (very soon)
|
||||
- Copy prose from tor-design to make everything more readable.
|
||||
when do we rotate which keys (tls, link, etc)?
|
||||
|
||||
0. Notation:
|
||||
0. Preliminaries
|
||||
|
||||
0.1. Notation and encoding
|
||||
|
||||
PK -- a public key.
|
||||
SK -- a private key
|
||||
@ -30,27 +32,79 @@ when do we rotate which keys (tls, link, etc)?
|
||||
|
||||
All numeric values are encoded in network (big-endian) order.
|
||||
|
||||
Unless otherwise specified, all symmetric ciphers are AES in counter
|
||||
mode, with an IV of all 0 bytes. Asymmetric ciphers are either RSA
|
||||
with 1024-bit keys and exponents of 65537, or DH where the generator (g)
|
||||
is 2 and the modulus (p) is the 1024-bit safe prime from rfc2409,
|
||||
section 6.2, whose hex representation is:
|
||||
H(m) -- a cryptographic hash of m.
|
||||
|
||||
0.2. Security parameters
|
||||
|
||||
Tor uses a stream cipher, a public-key cipher, the Diffie-Hellman
|
||||
protocol, and and a hash function.
|
||||
|
||||
KEY_LEN -- the length of the stream cipher's key, in bytes.
|
||||
|
||||
PK_ENC_LEN -- the length of a public-key encrypted message, in bytes.
|
||||
PK_PAD_LEN -- the number of bytes added in padding for public-key
|
||||
encryption, in bytes. (The largest number of bytes that can be encrypted
|
||||
in a single public-key operation is therefore PK_ENC_LEN-PK_PAD_LEN.)
|
||||
|
||||
DH_LEN -- the number of bytes used to represent a member of the
|
||||
Diffie-Hellman group.
|
||||
DH_SEC_LEN -- the number of bytes used in a Diffie-Hellman private key (x).
|
||||
|
||||
HASH_LEN -- the length of the hash function's output, in bytes.
|
||||
|
||||
CELL_LEN -- The length of a Tor cell, in bytes.
|
||||
|
||||
0.3. Ciphers
|
||||
|
||||
For a stream cipher, we use 128-bit AES in counter mode, with an IV of all
|
||||
0 bytes.
|
||||
|
||||
For a public-key cipher, we use RSA with 1024-bit keys and a fixed
|
||||
exponent of 65537. We use OAEP padding, with SHA1 as its digest
|
||||
function. (For OAEP padding, see
|
||||
ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf)
|
||||
|
||||
For Diffie-Hellman, we use a generator (g) of 2. For the modulus (p), the
|
||||
1024-bit safe prime from rfc2409, (section 6.2) whose hex representation
|
||||
is:
|
||||
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E08"
|
||||
"8A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B"
|
||||
"302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9"
|
||||
"A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE6"
|
||||
"49286651ECE65381FFFFFFFFFFFFFFFF"
|
||||
|
||||
As an optimization, implementations SHOULD choose DH private keys (x) of
|
||||
320 bits. Implementations that do this MUST never use any DH key more
|
||||
than once.
|
||||
|
||||
All "hashes" are 20-byte SHA1 cryptographic digests.
|
||||
For a hash function, we use SHA1.
|
||||
|
||||
KEY_LEN=16.
|
||||
DH_LEN=128; DH_GROUP_LEN=40.
|
||||
PK_ENC_LEN=128; PK_PAD_LEN=42.
|
||||
HASH_LEN=20.
|
||||
|
||||
When we refer to "the hash of a public key", we mean the SHA1 hash of the
|
||||
DER encoding of an ASN.1 RSA public key (as specified in PKCS.1).
|
||||
|
||||
All "random" values should be generated with a cryptographically strong
|
||||
random number generator, unless otherwise noted.
|
||||
|
||||
The "hybrid encryption" of a byte sequence M with a public key PK is
|
||||
computed as follows:
|
||||
1. If M is less than PK_ENC_LEN-PK_PAD_LEN, pad and encrypt M with PK.
|
||||
2. Otherwise, generate a KEY_LEN byte random key K.
|
||||
Let M1 = the first PK_ENC_LEN-PK_PAD_LEN-KEY_LEN bytes of M,
|
||||
and let M2 = the rest of M.
|
||||
Pad and encrypt K|M1 with PK. Encrypt M2 with our stream cipher,
|
||||
using the key K. Concatenate these encrypted values.
|
||||
(Note that this "hybrid encryption" approach does not prevent an attacker
|
||||
from adding or removing bytes to the end of M.)
|
||||
|
||||
0.4. Other parameter values
|
||||
|
||||
CELL_LEN=512
|
||||
|
||||
1. System overview
|
||||
|
||||
Onion Routing is a distributed overlay network designed to anonymize
|
||||
@ -74,7 +128,7 @@ when do we rotate which keys (tls, link, etc)?
|
||||
support "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" if it is available.
|
||||
Implementations MAY support other ciphersuites, but MUST NOT
|
||||
support any suite without ephemeral keys, symmetric keys of at
|
||||
least 128 bits, and digests of at least 160 bits.
|
||||
least KEY_LEN bits, and digests of at least HASH_LEN bits.
|
||||
|
||||
An OP or OR always sends a two-certificate chain, consisting of a
|
||||
certificate using a short-term connection key and a second, self-
|
||||
@ -95,7 +149,7 @@ when do we rotate which keys (tls, link, etc)?
|
||||
|
||||
Once a TLS connection is established, the two sides send cells
|
||||
(specified below) to one another. Cells are sent serially. All
|
||||
cells are 512 bytes long. Cells may be sent embedded in TLS
|
||||
cells are CELL_LEN bytes long. Cells may be sent embedded in TLS
|
||||
records of any size or divided across TLS records, but the framing
|
||||
of TLS records MUST NOT leak information about the type or contents
|
||||
of the cells.
|
||||
@ -116,8 +170,8 @@ when do we rotate which keys (tls, link, etc)?
|
||||
|
||||
CircID [2 bytes]
|
||||
Command [1 byte]
|
||||
Payload (padded with 0 bytes) [509 bytes]
|
||||
[Total size: 512 bytes]
|
||||
Payload (padded with 0 bytes) [CELL_LEN-3 bytes]
|
||||
[Total size: CELL_LEN bytes]
|
||||
|
||||
The CircID field determines which circuit, if any, the cell is
|
||||
associated with.
|
||||
@ -168,41 +222,33 @@ when do we rotate which keys (tls, link, etc)?
|
||||
|
||||
The payload for a CREATE cell is an 'onion skin', which consists
|
||||
of the first step of the DH handshake data (also known as g^x).
|
||||
|
||||
The data is encrypted to Bob's PK as follows: Suppose Bob's PK
|
||||
modulus is L octets long. If the data to be encrypted is shorter
|
||||
than L-42, then it is encrypted directly (with OAEP padding: see
|
||||
ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf). If the
|
||||
data is at least as long as L-42, then a randomly generated 16-byte
|
||||
symmetric key is prepended to the data, after which the first L-16-42
|
||||
bytes of the data are encrypted with Bob's PK; and the rest of the
|
||||
data is encrypted with the symmetric key.
|
||||
|
||||
So in this case, the onion skin can be thought of as:
|
||||
RSA-encrypted:
|
||||
OAEP padding [42 bytes]
|
||||
Symmetric key [16 bytes]
|
||||
First part of g^x [70 bytes]
|
||||
This value is hybrid-encrypted (see 0.3) to Bob's public key, giving
|
||||
an onion-skin of:
|
||||
PK-encrypted:
|
||||
Padding padding [PK_PAD_LEN bytes]
|
||||
Symmetric key [KEY_LEN bytes]
|
||||
First part of g^x [PK_ENC_LEN-PK_PAD_LEN-KEY_LEN bytes]
|
||||
Symmetrically encrypted:
|
||||
Second part of g^x [58 bytes]
|
||||
Second part of g^x [DH_LEN-(PK_ENC_LEN-PK_PAD_LEN-KEY_LEN)
|
||||
bytes]
|
||||
|
||||
The relay payload for an EXTEND relay cell consists of:
|
||||
Address [4 bytes]
|
||||
Port [2 bytes]
|
||||
Onion skin [186 bytes]
|
||||
Identity fingerprint [20 bytes]
|
||||
Onion skin [DH_LEN+KEY_LEN+PK_PAD_LEN bytes]
|
||||
Identity fingerprint [HASH_LEN bytes]
|
||||
|
||||
The port and address field denote the IPV4 address and port of the next
|
||||
onion router in the circuit; the public key hash is the SHA1 hash of the
|
||||
PKCS#1 ASN1 encoding of the next onion router's identity (signing) key.
|
||||
(Including this hash allows the extending OR verify that it is indeed
|
||||
connected to the correct target OR, and prevents certain man-in-the-middle
|
||||
attacks.)
|
||||
onion router in the circuit; the public key hash is the hash of the PKCS#1
|
||||
ASN1 encoding of the next onion router's identity (signing) key. (See 0.3
|
||||
above.) (Including this hash allows the extending OR verify that it is
|
||||
indeed connected to the correct target OR, and prevents certain
|
||||
man-in-the-middle attacks.)
|
||||
|
||||
The payload for a CREATED cell, or the relay payload for an
|
||||
EXTENDED cell, contains:
|
||||
DH data (g^y) [128 bytes]
|
||||
Derivative key data (KH) [20 bytes] <see 4.2 below>
|
||||
DH data (g^y) [DH_LEN bytes]
|
||||
Derivative key data (KH) [HASH_LEN bytes] <see 4.2 below>
|
||||
|
||||
The CircID for a CREATE cell is an arbitrarily chosen 2-byte integer,
|
||||
selected by the node (OP or OR) that sends the CREATE cell. To prevent
|
||||
@ -232,12 +278,12 @@ when do we rotate which keys (tls, link, etc)?
|
||||
|
||||
A CREATE_FAST cell contains:
|
||||
|
||||
Key material (X) [20 bytes]
|
||||
Key material (X) [HASH_LEN bytes]
|
||||
|
||||
A CREATED_FAST cell contains:
|
||||
|
||||
Key material (Y) [20 bytes]
|
||||
Derivative key data [20 bytes] (See 4.2 below)
|
||||
Key material (Y) [HASH_LEN bytes]
|
||||
Derivative key data [HASH_LEN bytes] (See 4.2 below)
|
||||
|
||||
The values of X and Y must be generated randomly.
|
||||
|
||||
@ -251,7 +297,7 @@ when do we rotate which keys (tls, link, etc)?
|
||||
and server MUST verify that the received g^x or g^y value is not degenerate;
|
||||
that is, it must be strictly greater than 1 and strictly less than p-1
|
||||
where p is the DH modulus. Implementations MUST NOT complete a handshake
|
||||
with degenerate keys. Implementions MAY discard other "weak" g^x values.
|
||||
with degenerate keys. Implementations MAY discard other "weak" g^x values.
|
||||
|
||||
(Discarding degenerate keys is critical for security; if bad keys are not
|
||||
discarded, an attacker can substitute the server's CREATED cell's g^y with
|
||||
@ -268,12 +314,15 @@ when do we rotate which keys (tls, link, etc)?
|
||||
If CREATE_FAST is used, the client and server base their key material on
|
||||
K0=X|Y.
|
||||
|
||||
From the base key material K0, they compute 100 bytes of derivative
|
||||
key data as K = SHA1(K0 | [00]) | SHA1(K0 | [01]) | ... SHA1(K0 |
|
||||
[04]) where "00" is a single octet whose value is zero, [01] is a
|
||||
single octet whose value is one, etc. The first 20 bytes of K form
|
||||
KH, bytes 21-40 form the forward digest Df, 41-60 form the backward
|
||||
digest Db, 61-76 form Kf, and 77-92 form Kb.
|
||||
From the base key material K0, they compute KEY_LEN*2+HASH_LEN*3 bytes of
|
||||
derivative key data as
|
||||
K = H(K0 | [00]) | H(K0 | [01]) | H(K0 | [02]) | ...
|
||||
|
||||
|
||||
The first HASH_LEN bytes of K form KH; the next HASH_LEN form the forward
|
||||
digest Df; the next HASH_LEN 41-60 form the backward digest Db; the next
|
||||
KEY_LEN 61-76 form Kf, and the final KEY_LEN form Kb. Excess bytes from K
|
||||
are discarded.
|
||||
|
||||
KH is used in the handshake response to demonstrate knowledge of the
|
||||
computed shared key. Df is used to seed the integrity-checking hash
|
||||
@ -399,7 +448,7 @@ when do we rotate which keys (tls, link, etc)?
|
||||
|
||||
Otherwise, if the OR is not at the OP edge of the circuit (that is,
|
||||
either an 'exit node' or a non-edge node), it de/encrypts the payload
|
||||
with AES/CTR, as follows:
|
||||
with the stream cipher, as follows:
|
||||
'Forward' relay cell (same direction as CREATE):
|
||||
Use Kf as key; decrypt.
|
||||
'Back' relay cell (opposite direction from CREATE):
|
||||
@ -415,7 +464,7 @@ when do we rotate which keys (tls, link, etc)?
|
||||
sends a DESTROY cell to tear down the circuit.
|
||||
|
||||
When a relay cell arrives at an OP, the OP decrypts the payload
|
||||
with AES/CTR as follows:
|
||||
with the stream cipher as follows:
|
||||
OP receives data cell:
|
||||
For I=N...1,
|
||||
Decrypt with Kb_I. If the payload is recognized (see
|
||||
@ -438,7 +487,7 @@ when do we rotate which keys (tls, link, etc)?
|
||||
StreamID [2 bytes]
|
||||
Digest [4 bytes]
|
||||
Length [2 bytes]
|
||||
Data [498 bytes]
|
||||
Data [CELL_LEN-14 bytes]
|
||||
|
||||
The relay commands are:
|
||||
1 -- RELAY_BEGIN [forward]
|
||||
@ -461,7 +510,7 @@ when do we rotate which keys (tls, link, etc)?
|
||||
|
||||
The 'recognized' field in any unencrypted relay payload is always set
|
||||
to zero; the 'digest' field is computed as the first four bytes of
|
||||
the running SHA-1 digest of all the bytes that have been destined for
|
||||
the running digest of all the bytes that have been destined for
|
||||
this hop of the circuit or originated from this hop of the circuit,
|
||||
seeded from Df or Db respectively (obtained in section 4.2 above),
|
||||
and including this RELAY cell's entire payload (taken with the digest
|
||||
@ -763,7 +812,7 @@ The items' formats are as follows:
|
||||
|
||||
"fingerprint"
|
||||
|
||||
A fingerprint (20 byte SHA1 hash of asn1 encoded public key, encoded
|
||||
A fingerprint (a HASH_LEN-byte of asn1 encoded public key, encoded
|
||||
in hex, with a single space after every 4 characters) for this router's
|
||||
identity key.
|
||||
|
||||
@ -801,7 +850,7 @@ The items' formats are as follows:
|
||||
|
||||
"router-signature" NL Signature NL
|
||||
|
||||
The "SIGNATURE" object contains a signature of the PKCS1-padded SHA1
|
||||
The "SIGNATURE" object contains a signature of the PKCS1-padded
|
||||
hash of the entire router descriptor, taken from the beginning of the
|
||||
"router" line, through the newline after the "router-signature" line.
|
||||
The router descriptor is invalid unless the signature is performed
|
||||
@ -909,7 +958,7 @@ descriptors, and a single "directory-signature" item.
|
||||
|
||||
"directory-signature" nickname-of-dirserver NL Signature
|
||||
|
||||
The signature is computed by computing the SHA-1 hash of the
|
||||
The signature is computed by computing the digest of the
|
||||
directory, from the characters "signed-directory", through the newline
|
||||
after "directory-signature". This digest is then padded with PKCS.1,
|
||||
and signed with the directory server's signing key.
|
||||
@ -981,6 +1030,8 @@ B.1. ... but which will require backward-incompatible change
|
||||
- Circuit IDs should be longer.
|
||||
- IPv6 everywhere.
|
||||
- Maybe, keys should be longer.
|
||||
- Maybe, key-length should be adjustable. How to do this without
|
||||
making anonymity suck?
|
||||
- Drop backward compatibility.
|
||||
- We should use a 128-bit subgroup of our DH prime.
|
||||
- Handshake should use HMAC.
|
||||
|
Loading…
Reference in New Issue
Block a user