rust: Expose crypto_rand() as an impl of rand_core::RngCore.

This commit is contained in:
Isis Lovecruft 2018-05-02 22:12:38 +00:00
parent b5013e841c
commit 94dcd38a14
No known key found for this signature in database
GPG Key ID: B8938BC5E86C046F
2 changed files with 63 additions and 21 deletions

View File

@ -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::<tor_weak_rng_t>(), 0usize,
concat!("Size of: ", stringify!(tor_weak_rng_t)));
assert_eq!(::std::mem::align_of::<tor_weak_rng_t>(), 1usize,
concat!("Alignment of ", stringify!(tor_weak_rng_t)));
}
}

View File

@ -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