From 94dcd38a1430061a0bb630ad680a41a78262a55c Mon Sep 17 00:00:00 2001 From: Isis Lovecruft Date: Wed, 2 May 2018 22:12:38 +0000 Subject: [PATCH] rust: Expose crypto_rand() as an impl of rand_core::RngCore. --- src/rust/external/crypto_rand.rs | 30 +++++++----------- src/rust/rand/rng.rs | 54 ++++++++++++++++++++++++++++++-- 2 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/rust/external/crypto_rand.rs b/src/rust/external/crypto_rand.rs index 19b9ab281..af1ade016 100644 --- a/src/rust/external/crypto_rand.rs +++ b/src/rust/external/crypto_rand.rs @@ -11,23 +11,18 @@ use std::time::Duration; -use libc::c_char; use libc::c_double; use libc::c_int; -use libc::c_uint; -use libc::c_void; use libc::size_t; use libc::time_t; use libc::uint8_t; -use libc::uint64_t; extern "C" { fn crypto_seed_rng() -> c_int; + fn crypto_rand(out: *mut uint8_t, out_len: size_t); fn crypto_strongest_rand(out: *mut uint8_t, out_len: size_t); fn crypto_rand_time_range(min: time_t, max: time_t) -> time_t; fn crypto_rand_double() -> c_double; - // fn crypto_random_hostname(min_rand_len: c_int, max_rand_len: c_int, - // prefix: *const c_char, suffix: *const c_char) -> *mut c_char; } /// Seed OpenSSL's random number generator with bytes from the operating @@ -48,7 +43,16 @@ pub fn c_tor_crypto_seed_rng() -> bool { } } -/// Fill the bytes of `dest` with strong random data. +/// Fill the bytes of `dest` with random data. +pub fn c_tor_crypto_rand(dest: &mut [u8]) { + unsafe { + crypto_rand(dest.as_mut_ptr(), dest.len() as size_t); + } +} + +/// Fill the bytes of `dest` with "strong" random data by hashing +/// together randomness obtained from OpenSSL's RNG and the operating +/// system. pub fn c_tor_crypto_strongest_rand(dest: &mut [u8]) { // We'll let the C side panic if the len is larger than // MAX_STRONGEST_RAND_SIZE, rather than potentially panicking here. A @@ -81,15 +85,3 @@ pub fn c_tor_crypto_rand_double() -> f64 { } } -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn test_layout_tor_weak_rng_t() { - assert_eq!(::std::mem::size_of::(), 0usize, - concat!("Size of: ", stringify!(tor_weak_rng_t))); - assert_eq!(::std::mem::align_of::(), 1usize, - concat!("Alignment of ", stringify!(tor_weak_rng_t))); - } -} diff --git a/src/rust/rand/rng.rs b/src/rust/rand/rng.rs index ea234492e..cfd96c961 100644 --- a/src/rust/rand/rng.rs +++ b/src/rust/rand/rng.rs @@ -2,7 +2,7 @@ // Copyright (c) 2018, isis agora lovecruft // See LICENSE for licensing information -//! Wrappers for Tor's random number generator to provide implementations of +//! Wrappers for Tor's random number generators to provide implementations of //! `rand_core` traits. // This is the real implementation, in use in production, which calls into our C @@ -18,6 +18,7 @@ mod internal { use rand_core::impls::next_u32_via_fill; use rand_core::impls::next_u64_via_fill; + use external::c_tor_crypto_rand; use external::c_tor_crypto_strongest_rand; use external::c_tor_crypto_seed_rng; @@ -64,6 +65,53 @@ mod internal { next_u64_via_fill(self) } + // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c + fn fill_bytes(&mut self, dest: &mut [u8]) { + c_tor_crypto_rand(dest); + } + + // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + Ok(self.fill_bytes(dest)) + } + } + + /// A CSPRNG which hashes together randomness from OpenSSL's RNG and entropy + /// obtained from the operating system. + pub struct TorStrongestRng { + // This private, zero-length field forces the struct to be treated the + // same as its opaque C couterpart. + _unused: [u8; 0], + } + + /// Mark `TorRng` as being suitable for cryptographic purposes. + impl CryptoRng for TorStrongestRng {} + + impl TorStrongestRng { + // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c + #[allow(dead_code)] + fn new() -> Self { + if !c_tor_crypto_seed_rng() { + tor_log_msg!(LogSeverity::Warn, LogDomain::General, + "TorStrongestRng::from_seed()", + "The RNG could not be seeded!"); + } + // XXX also log success at info level —isis + TorStrongestRng{ _unused: [0u8; 0] } + } + } + + impl RngCore for TorStrongestRng { + // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c + fn next_u32(&mut self) -> u32 { + next_u32_via_fill(self) + } + + // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c + fn next_u64(&mut self) -> u64 { + next_u64_via_fill(self) + } + // C_RUST_COUPLED: `crypto_strongest_rand()` /src/common/crypto_rand.c fn fill_bytes(&mut self, dest: &mut [u8]) { debug_assert!(dest.len() <= MAX_STRONGEST_RAND_SIZE); @@ -81,7 +129,9 @@ mod internal { // For testing, we expose a pure-Rust implementation. #[cfg(test)] mod internal { - pub use rand::EntropyRng as TorRng; + // It doesn't matter if we pretend ChaCha is a CSPRNG in tests. + pub use rand::ChaChaRng as TorRng; + pub use rand::ChaChaRng as TorStrongestRng; } // Finally, expose the public functionality of whichever appropriate internal