From 97b9dfe3052f1fe3b14f47fc1326e235f96305b7 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 20 Feb 2019 12:21:05 -0500 Subject: [PATCH 1/3] Add a convenience macro to get a fast one-in-n calculation --- src/lib/crypt_ops/crypto_rand.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h index 6eef22ed4d..bb424fd691 100644 --- a/src/lib/crypt_ops/crypto_rand.h +++ b/src/lib/crypt_ops/crypto_rand.h @@ -68,6 +68,9 @@ unsigned crypto_fast_rng_get_uint(crypto_fast_rng_t *rng, unsigned limit); uint64_t crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit); double crypto_fast_rng_get_double(crypto_fast_rng_t *rng); +#define crypto_fast_rng_one_in_n(rng, n) \ + (0 == (crypto_fast_rng_get_uint((rng), (n)))) + crypto_fast_rng_t *get_thread_fast_rng(void); #ifdef CRYPTO_PRIVATE From b3416476b487304426296173dd177e1277388e48 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Wed, 20 Feb 2019 12:21:23 -0500 Subject: [PATCH 2/3] Remove all uses of weak_rng. I'm not removing the weak_rng code itself yet, since it is possible that we will want to revert one of these. --- changes/ticket29542 | 7 +++++++ src/app/main/main.c | 2 +- src/core/mainloop/cpuworker.c | 7 ++----- src/core/or/relay.c | 14 ++------------ src/core/or/relay.h | 3 --- src/lib/evloop/workqueue.c | 10 +--------- 6 files changed, 13 insertions(+), 30 deletions(-) create mode 100644 changes/ticket29542 diff --git a/changes/ticket29542 b/changes/ticket29542 new file mode 100644 index 0000000000..465a8e31bc --- /dev/null +++ b/changes/ticket29542 @@ -0,0 +1,7 @@ + o Minor features (defense in depth): + - Tor now uses a fast cryptographically strong PRNG even for decisions + that we do not believe are security-sensitive. Previously, for + performance reasons, we had used a trivially predictable linear + congruential generator algorithm for certain load-balancing and + statistical sampling decisions. Now we use our fast RNG in those cases. + Closes ticket 29542. diff --git a/src/app/main/main.c b/src/app/main/main.c index 0ffc27d456..ec15109f6c 100644 --- a/src/app/main/main.c +++ b/src/app/main/main.c @@ -669,7 +669,7 @@ tor_init(int argc, char *argv[]) log_err(LD_BUG, "Unable to initialize OpenSSL. Exiting."); return -1; } - stream_choice_seed_weak_rng(); + if (tor_init_libevent_rng() < 0) { log_warn(LD_NET, "Problem initializing libevent RNG."); } diff --git a/src/core/mainloop/cpuworker.c b/src/core/mainloop/cpuworker.c index e704d55642..436fcd28c3 100644 --- a/src/core/mainloop/cpuworker.c +++ b/src/core/mainloop/cpuworker.c @@ -34,7 +34,6 @@ #include "core/crypto/onion_crypto.h" #include "core/or/or_circuit_st.h" -#include "lib/intmath/weakrng.h" static void queue_pending_tasks(void); @@ -74,8 +73,6 @@ worker_state_free_void(void *arg) static replyqueue_t *replyqueue = NULL; static threadpool_t *threadpool = NULL; -static tor_weak_rng_t request_sample_rng = TOR_WEAK_RNG_INIT; - static int total_pending_tasks = 0; static int max_pending_tasks = 128; @@ -109,7 +106,6 @@ cpu_init(void) /* Total voodoo. Can we make this more sensible? */ max_pending_tasks = get_num_cpus(get_options()) * 64; - crypto_seed_weak_rng(&request_sample_rng); } /** Magic numbers to make sure our cpuworker_requests don't grow any @@ -235,9 +231,10 @@ should_time_request(uint16_t onionskin_type) * sample */ if (onionskins_n_processed[onionskin_type] < 4096) return 1; + /** Otherwise, measure with P=1/128. We avoid doing this for every * handshake, since the measurement itself can take a little time. */ - return tor_weak_random_one_in_n(&request_sample_rng, 128); + return crypto_fast_rng_one_in_n(get_thread_fast_rng(), 128); } /** Return an estimate of how many microseconds we will need for a single diff --git a/src/core/or/relay.c b/src/core/or/relay.c index 706a6e05cb..7f7fa2fe1f 100644 --- a/src/core/or/relay.c +++ b/src/core/or/relay.c @@ -94,8 +94,6 @@ #include "feature/nodelist/routerinfo_st.h" #include "core/or/socks_request_st.h" -#include "lib/intmath/weakrng.h" - static edge_connection_t *relay_lookup_conn(circuit_t *circ, cell_t *cell, cell_direction_t cell_direction, crypt_path_t *layer_hint); @@ -134,9 +132,6 @@ uint64_t stats_n_relay_cells_delivered = 0; * reached (see append_cell_to_circuit_queue()) */ uint64_t stats_n_circ_max_cell_reached = 0; -/** Used to tell which stream to read from first on a circuit. */ -static tor_weak_rng_t stream_choice_rng = TOR_WEAK_RNG_INIT; - /** * Update channel usage state based on the type of relay cell and * circuit properties. @@ -2180,12 +2175,6 @@ circuit_resume_edge_reading(circuit_t *circ, crypt_path_t *layer_hint) circ, layer_hint); } -void -stream_choice_seed_weak_rng(void) -{ - crypto_seed_weak_rng(&stream_choice_rng); -} - /** A helper function for circuit_resume_edge_reading() above. * The arguments are the same, except that conn is the head * of a linked list of edge streams that should each be considered. @@ -2237,7 +2226,8 @@ circuit_resume_edge_reading_helper(edge_connection_t *first_conn, int num_streams = 0; for (conn = first_conn; conn; conn = conn->next_stream) { num_streams++; - if (tor_weak_random_one_in_n(&stream_choice_rng, num_streams)) { + + if (crypto_fast_rng_one_in_n(get_thread_fast_rng(), num_streams)) { chosen_stream = conn; } /* Invariant: chosen_stream has been chosen uniformly at random from diff --git a/src/core/or/relay.h b/src/core/or/relay.h index 044f6be156..ea1b358ffb 100644 --- a/src/core/or/relay.h +++ b/src/core/or/relay.h @@ -94,8 +94,6 @@ const uint8_t *decode_address_from_payload(tor_addr_t *addr_out, int payload_len); void circuit_clear_cell_queue(circuit_t *circ, channel_t *chan); -void stream_choice_seed_weak_rng(void); - circid_t packed_cell_get_circid(const packed_cell_t *cell, int wide_circ_ids); #ifdef RELAY_PRIVATE @@ -126,4 +124,3 @@ STATIC int connection_edge_process_relay_cell(cell_t *cell, circuit_t *circ, #endif /* defined(RELAY_PRIVATE) */ #endif /* !defined(TOR_RELAY_H) */ - diff --git a/src/lib/evloop/workqueue.c b/src/lib/evloop/workqueue.c index b36a02da5e..015b694290 100644 --- a/src/lib/evloop/workqueue.c +++ b/src/lib/evloop/workqueue.c @@ -59,9 +59,6 @@ struct threadpool_s { * p is work[p]. */ work_tailq_t work[WORKQUEUE_N_PRIORITIES]; - /** Weak RNG, used to decide when to ignore priority. */ - tor_weak_rng_t weak_rng; - /** The current 'update generation' of the threadpool. Any thread that is * at an earlier generation needs to run the update function. */ unsigned generation; @@ -238,7 +235,7 @@ worker_thread_extract_next_work(workerthread_t *thread) this_queue = &pool->work[i]; if (!TOR_TAILQ_EMPTY(this_queue)) { queue = this_queue; - if (! tor_weak_random_one_in_n(&pool->weak_rng, + if (! crypto_fast_rng_one_in_n(get_thread_fast_rng(), thread->lower_priority_chance)) { /* Usually we'll just break now, so that we can get out of the loop * and use the queue where we found work. But with a small @@ -555,11 +552,6 @@ threadpool_new(int n_threads, for (i = WORKQUEUE_PRIORITY_FIRST; i <= WORKQUEUE_PRIORITY_LAST; ++i) { TOR_TAILQ_INIT(&pool->work[i]); } - { - unsigned seed; - crypto_rand((void*)&seed, sizeof(seed)); - tor_init_weak_random(&pool->weak_rng, seed); - } pool->new_thread_state_fn = new_thread_state_fn; pool->new_thread_state_arg = arg; From 64f594499a3e8893a6097fa5db7d47962f83d2f5 Mon Sep 17 00:00:00 2001 From: Nick Mathewson Date: Fri, 1 Mar 2019 08:20:54 -0500 Subject: [PATCH 3/3] Document crypto_fast_rng_one_in_n. --- src/lib/crypt_ops/crypto_rand.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/lib/crypt_ops/crypto_rand.h b/src/lib/crypt_ops/crypto_rand.h index bb424fd691..6f09aedf6a 100644 --- a/src/lib/crypt_ops/crypto_rand.h +++ b/src/lib/crypt_ops/crypto_rand.h @@ -68,6 +68,12 @@ unsigned crypto_fast_rng_get_uint(crypto_fast_rng_t *rng, unsigned limit); uint64_t crypto_fast_rng_get_uint64(crypto_fast_rng_t *rng, uint64_t limit); double crypto_fast_rng_get_double(crypto_fast_rng_t *rng); +/** + * Using the fast_rng rng, yield true with probability + * 1/n. Otherwise yield false. + * + * n must not be zero. + **/ #define crypto_fast_rng_one_in_n(rng, n) \ (0 == (crypto_fast_rng_get_uint((rng), (n))))