aboutsummaryrefslogtreecommitdiff
path: root/src/rust/crypto/rand/rng.rs
blob: 644a5c20b1660ebc199b972891b05f1602679220 (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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright (c) 2018-2019, 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::impls::next_u32_via_fill;
    use rand_core::impls::next_u64_via_fill;
    use rand_core::CryptoRng;
    use rand_core::Error;
    use rand_core::RngCore;

    use external::c_tor_crypto_rand;
    use external::c_tor_crypto_seed_rng;
    use external::c_tor_crypto_strongest_rand;

    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 counterpart.
        _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 counterpart.
        _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_crate::ChaChaRng as TorRng;
    pub use rand_crate::ChaChaRng as TorStrongestRng;
}

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