1 // Copyright (c) 2018-2019, The Tor Project, Inc.
2 // Copyright (c) 2018, isis agora lovecruft
3 // See LICENSE for licensing information
4 
5 //! Bindings to external (P)RNG interfaces and utilities in
6 //! src/common/crypto_rand.[ch].
7 //!
8 //! We wrap our C implementations in src/common/crypto_rand.[ch] here in order
9 //! to provide wrappers with native Rust types, and then provide more Rusty
10 //! types and and trait implementations in src/rust/crypto/rand/.
11 
12 use std::time::Duration;
13 
14 use libc::c_double;
15 use libc::c_int;
16 use libc::size_t;
17 use libc::time_t;
18 use libc::uint8_t;
19 
20 extern "C" {
crypto_seed_rng() -> c_int21     fn crypto_seed_rng() -> c_int;
crypto_rand(out: *mut uint8_t, out_len: size_t)22     fn crypto_rand(out: *mut uint8_t, out_len: size_t);
crypto_strongest_rand(out: *mut uint8_t, out_len: size_t)23     fn crypto_strongest_rand(out: *mut uint8_t, out_len: size_t);
crypto_rand_time_range(min: time_t, max: time_t) -> time_t24     fn crypto_rand_time_range(min: time_t, max: time_t) -> time_t;
crypto_rand_double() -> c_double25     fn crypto_rand_double() -> c_double;
26 }
27 
28 /// Seed OpenSSL's random number generator with bytes from the operating
29 /// system.
30 ///
31 /// # Returns
32 ///
33 /// `true` on success; `false` on failure.
c_tor_crypto_seed_rng() -> bool34 pub fn c_tor_crypto_seed_rng() -> bool {
35     let ret: c_int;
36 
37     unsafe {
38         ret = crypto_seed_rng();
39     }
40     match ret {
41         0 => return true,
42         _ => return false,
43     }
44 }
45 
46 /// Fill the bytes of `dest` with random data.
c_tor_crypto_rand(dest: &mut [u8])47 pub fn c_tor_crypto_rand(dest: &mut [u8]) {
48     unsafe {
49         crypto_rand(dest.as_mut_ptr(), dest.len() as size_t);
50     }
51 }
52 
53 /// Fill the bytes of `dest` with "strong" random data by hashing
54 /// together randomness obtained from OpenSSL's RNG and the operating
55 /// system.
c_tor_crypto_strongest_rand(dest: &mut [u8])56 pub fn c_tor_crypto_strongest_rand(dest: &mut [u8]) {
57     // We'll let the C side panic if the len is larger than
58     // MAX_STRONGEST_RAND_SIZE, rather than potentially panicking here.  A
59     // paranoid caller should assert on the length of dest *before* calling this
60     // function.
61     unsafe {
62         crypto_strongest_rand(dest.as_mut_ptr(), dest.len() as size_t);
63     }
64 }
65 
66 /// Get a random time, in seconds since the Unix Epoch.
67 ///
68 /// # Returns
69 ///
70 /// A `std::time::Duration` of seconds since the Unix Epoch.
c_tor_crypto_rand_time_range(min: &Duration, max: &Duration) -> Duration71 pub fn c_tor_crypto_rand_time_range(min: &Duration, max: &Duration) -> Duration {
72     let ret: time_t;
73 
74     unsafe {
75         ret = crypto_rand_time_range(min.as_secs() as time_t, max.as_secs() as time_t);
76     }
77 
78     Duration::from_secs(ret as u64)
79 }
80 
81 /// Return a pseudorandom 64-bit float, chosen uniformly from the range [0.0, 1.0).
c_tor_crypto_rand_double() -> f6482 pub fn c_tor_crypto_rand_double() -> f64 {
83     unsafe { crypto_rand_double() }
84 }
85