[tor-commits] [tor/master] rust: Expose crypto_rand() as an impl of rand_core::RngCore.

nickm at torproject.org nickm at torproject.org
Thu May 3 17:58:40 UTC 2018


commit 94dcd38a1430061a0bb630ad680a41a78262a55c
Author: Isis Lovecruft <isis at torproject.org>
Date:   Wed May 2 22:12:38 2018 +0000

    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::<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)));
-    }
-}
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;
 
@@ -66,6 +67,53 @@ mod internal {
 
         // 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);
 
             c_tor_crypto_strongest_rand(dest);
@@ -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





More information about the tor-commits mailing list