aboutsummaryrefslogtreecommitdiff
path: root/src/rust/rand/rng.rs
blob: ea234492ebb7841466566ee01dc7a5fb7f1070cd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright (c) 2018, The Tor Project, Inc.
// Copyright (c) 2018, isis agora lovecruft
// See LICENSE for licensing information

//! Wrappers for Tor's random number generator 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_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)]
        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]) {
            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 {
    pub use rand::EntropyRng as TorRng;
}

// Finally, expose the public functionality of whichever appropriate internal
// module.
pub use self::internal::*;