mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-14 07:03:44 +01:00
469051f650
I started this repository a while ago to work on documentation for Tor's internals. It needs substantial revision, but first, let's get it copied into Tor's repository. These files are copied, "warts and all", from the tor-guts.git repo, commit de1e34259178b09861c0dea319c760fa80d0099a. Part of 31819.
170 lines
7.1 KiB
Markdown
170 lines
7.1 KiB
Markdown
|
|
## Lower-level cryptography functionality in Tor ##
|
|
|
|
Generally speaking, Tor code shouldn't be calling OpenSSL (or any
|
|
other crypto library) directly. Instead, we should indirect through
|
|
one of the functions in src/common/crypto\*.c or src/common/tortls.c.
|
|
|
|
Cryptography functionality that's available is described below.
|
|
|
|
### RNG facilities ###
|
|
|
|
The most basic RNG capability in Tor is the crypto_rand() family of
|
|
functions. These currently use OpenSSL's RAND_() backend, but may use
|
|
something faster in the future.
|
|
|
|
In addition to crypto_rand(), which fills in a buffer with random
|
|
bytes, we also have functions to produce random integers in certain
|
|
ranges; to produce random hostnames; to produce random doubles, etc.
|
|
|
|
When you're creating a long-term cryptographic secret, you might want
|
|
to use crypto_strongest_rand() instead of crypto_rand(). It takes the
|
|
operating system's entropy source and combines it with output from
|
|
crypto_rand(). This is a pure paranoia measure, but it might help us
|
|
someday.
|
|
|
|
You can use smartlist_choose() to pick a random element from a smartlist
|
|
and smartlist_shuffle() to randomize the order of a smartlist. Both are
|
|
potentially a bit slow.
|
|
|
|
### Cryptographic digests and related functions ###
|
|
|
|
We treat digests as separate types based on the length of their
|
|
outputs. We support one 160-bit digest (SHA1), two 256-bit digests
|
|
(SHA256 and SHA3-256), and two 512-bit digests (SHA512 and SHA3-512).
|
|
|
|
You should not use SHA1 for anything new.
|
|
|
|
The crypto_digest\*() family of functions manipulates digests. You
|
|
can either compute a digest of a chunk of memory all at once using
|
|
crypto_digest(), crypto_digest256(), or crypto_digest512(). Or you
|
|
can create a crypto_digest_t object with
|
|
crypto_digest{,256,512}_new(), feed information to it in chunks using
|
|
crypto_digest_add_bytes(), and then extract the final digest using
|
|
crypto_digest_get_digest(). You can copy the state of one of these
|
|
objects using crypto_digest_dup() or crypto_digest_assign().
|
|
|
|
We support the HMAC hash-based message authentication code
|
|
instantiated using SHA256. See crypto_hmac_sha256. (You should not
|
|
add any HMAC users with SHA1, and HMAC is not necessary with SHA3.)
|
|
|
|
We also support the SHA3 cousins, SHAKE128 and SHAKE256. Unlike
|
|
digests, these are extendable output functions (or XOFs) where you can
|
|
get any amount of output. Use the crypto_xof_\*() functions to access
|
|
these.
|
|
|
|
We have several ways to derive keys from cryptographically strong secret
|
|
inputs (like diffie-hellman outputs). The old
|
|
crypto_expand_key_material-TAP() performs an ad-hoc KDF based on SHA1 -- you
|
|
shouldn't use it for implementing anything but old versions of the Tor
|
|
protocol. You can use HKDF-SHA256 (as defined in RFC5869) for more modern
|
|
protocols. Also consider SHAKE256.
|
|
|
|
If your input is potentially weak, like a password or passphrase, use a salt
|
|
along with the secret_to_key() functions as defined in crypto_s2k.c. Prefer
|
|
scrypt over other hashing methods when possible. If you're using a password
|
|
to encrypt something, see the "boxed file storage" section below.
|
|
|
|
Finally, in order to store objects in hash tables, Tor includes the
|
|
randomized SipHash 2-4 function. Call it via the siphash24g() function in
|
|
src/ext/siphash.h whenever you're creating a hashtable whose keys may be
|
|
manipulated by an attacker in order to DoS you with collisions.
|
|
|
|
|
|
### Stream ciphers ###
|
|
|
|
You can create instances of a stream cipher using crypto_cipher_new().
|
|
These are stateful objects of type crypto_cipher_t. Note that these
|
|
objects only support AES-128 right now; a future version should add
|
|
support for AES-128 and/or ChaCha20.
|
|
|
|
You can encrypt/decrypt with crypto_cipher_encrypt or
|
|
crypto_cipher_decrypt. The crypto_cipher_crypt_inplace function performs
|
|
an encryption without a copy.
|
|
|
|
Note that sensible people should not use raw stream ciphers; they should
|
|
probably be using some kind of AEAD. Sorry.
|
|
|
|
### Public key functionality ###
|
|
|
|
We support four public key algorithms: DH1024, RSA, Curve25519, and
|
|
Ed25519.
|
|
|
|
We support DH1024 over two prime groups. You access these via the
|
|
crypto_dh_\*() family of functions.
|
|
|
|
We support RSA in many bit sizes for signing and encryption. You access
|
|
it via the crypto_pk_*() family of functions. Note that a crypto_pk_t
|
|
may or may not include a private key. See the crypto_pk_* functions in
|
|
crypto.c for a full list of functions here.
|
|
|
|
For Curve25519 functionality, see the functions and types in
|
|
crypto_curve25519.c. Curve25519 is generally suitable for when you need
|
|
a secure fast elliptic-curve diffie hellman implementation. When
|
|
designing new protocols, prefer it over DH in Z_p.
|
|
|
|
For Ed25519 functionality, see the functions and types in
|
|
crypto_ed25519.c. Ed25519 is a generally suitable as a secure fast
|
|
elliptic curve signature method. For new protocols, prefer it over RSA
|
|
signatures.
|
|
|
|
### Metaformats for storage ###
|
|
|
|
When OpenSSL manages the storage of some object, we use whatever format
|
|
OpenSSL provides -- typically, some kind of PEM-wrapped base 64 encoding
|
|
that starts with "----- BEGIN CRYPTOGRAPHIC OBJECT ----".
|
|
|
|
When we manage the storage of some cryptographic object, we prefix the
|
|
object with 32-byte NUL-padded prefix in order to avoid accidental
|
|
object confusion; see the crypto_read_tagged_contents_from_file() and
|
|
crypto_write_tagged_contents_to_file() functions for manipulating
|
|
these. The prefix is "== type: tag ==", where type describes the object
|
|
and its encoding, and tag indicates which one it is.
|
|
|
|
### Boxed-file storage ###
|
|
|
|
When managing keys, you frequently want to have some way to write a
|
|
secret object to disk, encrypted with a passphrase. The crypto_pwbox
|
|
and crypto_unpwbox functions do so in a way that's likely to be
|
|
readable by future versions of Tor.
|
|
|
|
### Certificates ###
|
|
|
|
We have, alas, several certificate types in Tor.
|
|
|
|
The tor_x509_cert_t type represents an X.509 certificate. This document
|
|
won't explain X.509 to you -- possibly, no document can. (OTOH, Peter
|
|
Gutmann's "x.509 style guide", though severely dated, does a good job of
|
|
explaining how awful x.509 can be.) Do not introduce any new usages of
|
|
X.509. Right now we only use it in places where TLS forces us to do so.
|
|
|
|
The authority_cert_t type is used only for directory authority keys. It
|
|
has a medium-term signing key (which the authorities actually keep
|
|
online) signed by a long-term identity key (which the authority operator
|
|
had really better be keeping offline). Don't use it for any new kind of
|
|
certificate.
|
|
|
|
For new places where you need a certificate, consider tor_cert_t: it
|
|
represents a typed and dated _something_ signed by an Ed25519 key. The
|
|
format is described in tor-spec. Unlike x.509, you can write it on a
|
|
napkin.
|
|
|
|
(Additionally, the Tor directory design uses a fairly wide variety of
|
|
documents that include keys and which are signed by keys. You can
|
|
consider these documents to be an additional kind of certificate if you
|
|
want.)
|
|
|
|
### TLS ###
|
|
|
|
Tor's TLS implementation is more tightly coupled to OpenSSL than we'd
|
|
prefer. You can read most of it in tortls.c.
|
|
|
|
Unfortunately, TLS's state machine and our requirement for nonblocking
|
|
IO support means that using TLS in practice is a bit hairy, since
|
|
logical writes can block on a physical reads, and vice versa.
|
|
|
|
If you are lucky, you will never have to look at the code here.
|
|
|
|
|
|
|