aboutsummaryrefslogtreecommitdiff
path: root/src/rust/external/crypto_rand.rs
blob: 703382093c1af63de041e48691d9bac98a1bceff (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
// Copyright (c) 2018-2019, The Tor Project, Inc.
// Copyright (c) 2018, isis agora lovecruft
// See LICENSE for licensing information

//! Bindings to external (P)RNG interfaces and utilities in
//! src/common/crypto_rand.[ch].
//!
//! We wrap our C implementations in src/common/crypto_rand.[ch] here in order
//! to provide wrappers with native Rust types, and then provide more Rusty
//! types and and trait implementations in src/rust/crypto/rand/.

use std::time::Duration;

use libc::c_double;
use libc::c_int;
use libc::size_t;
use libc::time_t;
use libc::uint8_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;
}

/// Seed OpenSSL's random number generator with bytes from the operating
/// system.
///
/// # Returns
///
/// `true` on success; `false` on failure.
pub fn c_tor_crypto_seed_rng() -> bool {
    let ret: c_int;

    unsafe {
        ret = crypto_seed_rng();
    }
    match ret {
        0 => return true,
        _ => return false,
    }
}

/// 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
    // paranoid caller should assert on the length of dest *before* calling this
    // function.
    unsafe {
        crypto_strongest_rand(dest.as_mut_ptr(), dest.len() as size_t);
    }
}

/// Get a random time, in seconds since the Unix Epoch.
///
/// # Returns
///
/// A `std::time::Duration` of seconds since the Unix Epoch.
pub fn c_tor_crypto_rand_time_range(min: &Duration, max: &Duration) -> Duration {
    let ret: time_t;

    unsafe {
        ret = crypto_rand_time_range(min.as_secs() as time_t, max.as_secs() as time_t);
    }

    Duration::from_secs(ret as u64)
}

/// Return a pseudorandom 64-bit float, chosen uniformly from the range [0.0, 1.0).
pub fn c_tor_crypto_rand_double() -> f64 {
    unsafe { crypto_rand_double() }
}