// Copyright (c) 2018, The Tor Project, Inc. // Copyright (c) 2018, isis agora lovecruft // See LICENSE for licensing information //! 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 // wrappers in /src/common/crypto_rand.c, which call into OpenSSL, system // libraries, and make syscalls. #[cfg(not(test))] mod internal { use std::u64; use rand_core::CryptoRng; use rand_core::Error; use rand_core::RngCore; 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; use tor_log::LogDomain; use tor_log::LogSeverity; /// Largest strong entropy request permitted. // // C_RUST_COUPLED: `MAX_STRONGEST_RAND_SIZE` /src/common/crypto_rand.c const MAX_STRONGEST_RAND_SIZE: usize = 256; /// A wrapper around OpenSSL's RNG. pub struct TorRng { // 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 TorRng {} impl TorRng { // C_RUST_COUPLED: `crypto_seed_rng()` /src/common/crypto_rand.c #[allow(dead_code)] pub fn new() -> Self { if !c_tor_crypto_seed_rng() { tor_log_msg!(LogSeverity::Warn, LogDomain::General, "TorRng::from_seed()", "The RNG could not be seeded!"); } // XXX also log success at info level —isis TorRng{ _unused: [0u8; 0] } } } impl RngCore for TorRng { // 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]) { 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)] pub 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); c_tor_crypto_strongest_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)) } } } // For testing, we expose a pure-Rust implementation. #[cfg(test)] mod internal { // 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 // module. pub use self::internal::*;