aws_lc_rs/
rand.rs

1// Copyright 2015-2016 Brian Smith.
2// SPDX-License-Identifier: ISC
3// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4// SPDX-License-Identifier: Apache-2.0 OR ISC
5
6//! Cryptographic pseudo-random number generation.
7//!
8//! An application should create a single `SystemRandom` and then use it for
9//! all randomness generation. Functions that generate random bytes should take
10//! a `&dyn SecureRandom` parameter instead of instantiating their own. Besides
11//! being more efficient, this also helps document where non-deterministic
12//! (random) outputs occur. Taking a reference to a `SecureRandom` also helps
13//! with testing techniques like fuzzing, where it is useful to use a
14//! (non-secure) deterministic implementation of `SecureRandom` so that results
15//! can be replayed. Following this pattern also may help with sandboxing
16//! (seccomp filters on Linux in particular). See `SystemRandom`'s
17//! documentation for more details.
18
19//! # Example
20//! ```
21//! use aws_lc_rs::{rand, rand::SecureRandom};
22//!
23//! //  Using `rand::fill`
24//! let mut rand_bytes = [0u8; 32];
25//! rand::fill(&mut rand_bytes).unwrap();
26//!
27//! // Using `SystemRandom`
28//! let rng = rand::SystemRandom::new();
29//! rng.fill(&mut rand_bytes).unwrap();
30//!
31//! // Using `rand::generate`
32//! let random_array = rand::generate(&rng).unwrap();
33//! let more_rand_bytes: [u8; 64] = random_array.expose();
34//! ```
35use crate::aws_lc::RAND_bytes;
36use crate::error::Unspecified;
37use crate::fips::indicator_check;
38use core::fmt::Debug;
39
40/// A secure random number generator.
41pub trait SecureRandom: sealed::SecureRandom {
42    /// Fills `dest` with random bytes.
43    ///
44    /// # Errors
45    /// `error::Unspecified` if unable to fill `dest`.
46    fn fill(&self, dest: &mut [u8]) -> Result<(), Unspecified>;
47}
48
49impl<T> SecureRandom for T
50where
51    T: sealed::SecureRandom,
52{
53    #[inline]
54    fn fill(&self, dest: &mut [u8]) -> Result<(), Unspecified> {
55        self.fill_impl(dest)
56    }
57}
58
59/// A random value constructed from a `SecureRandom` that hasn't been exposed
60/// through any safe Rust interface.
61///
62/// Intentionally does not implement any traits other than `Sized`.
63pub struct Random<T: RandomlyConstructable>(T);
64
65impl<T: RandomlyConstructable> Random<T> {
66    /// Expose the random value.
67    #[inline]
68    pub fn expose(self) -> T {
69        self.0
70    }
71}
72
73/// Generate the new random value using `rng`.
74///
75/// # Errors
76/// `error::Unspecified` if unable to fill buffer.
77#[inline]
78pub fn generate<T: RandomlyConstructable>(
79    rng: &dyn SecureRandom,
80) -> Result<Random<T>, Unspecified> {
81    let mut r = T::zero();
82    rng.fill(r.as_mut_bytes())?;
83    Ok(Random(r))
84}
85
86pub(crate) mod sealed {
87    use crate::error;
88
89    pub trait SecureRandom: core::fmt::Debug {
90        /// Fills `dest` with random bytes.
91        fn fill_impl(&self, dest: &mut [u8]) -> Result<(), error::Unspecified>;
92    }
93
94    pub trait RandomlyConstructable: Sized {
95        fn zero() -> Self;
96        // `Default::default()`
97        fn as_mut_bytes(&mut self) -> &mut [u8]; // `AsMut<[u8]>::as_mut`
98    }
99
100    impl<const T: usize> RandomlyConstructable for [u8; T] {
101        #[inline]
102        fn zero() -> Self {
103            [0; T]
104        }
105
106        #[inline]
107        fn as_mut_bytes(&mut self) -> &mut [u8] {
108            &mut self[..]
109        }
110    }
111}
112
113/// A type that can be returned by `aws_lc_rs::rand::generate()`.
114pub trait RandomlyConstructable: sealed::RandomlyConstructable {}
115
116impl<T> RandomlyConstructable for T where T: sealed::RandomlyConstructable {}
117
118/// A secure random number generator where the random values come from the
119/// underlying *AWS-LC* libcrypto.
120///
121/// A single `SystemRandom` may be shared across multiple threads safely.
122//
123// # FIPS
124// Use this implementation for retrieving random bytes.
125#[derive(Clone, Debug)]
126pub struct SystemRandom(());
127
128const SYSTEM_RANDOM: SystemRandom = SystemRandom(());
129
130impl SystemRandom {
131    /// Constructs a new `SystemRandom`.
132    #[inline]
133    #[must_use]
134    pub fn new() -> Self {
135        Self::default()
136    }
137}
138
139impl Default for SystemRandom {
140    fn default() -> Self {
141        SYSTEM_RANDOM
142    }
143}
144
145impl sealed::SecureRandom for SystemRandom {
146    #[inline]
147    fn fill_impl(&self, dest: &mut [u8]) -> Result<(), Unspecified> {
148        fill(dest)
149    }
150}
151
152/// Fills `dest` with random bytes.
153///
154// # FIPS
155// Use this for retrieving random bytes or [`SystemRandom`].
156//
157/// # Errors
158/// `error::Unspecified` if unable to fill `dest`.
159pub fn fill(dest: &mut [u8]) -> Result<(), Unspecified> {
160    if 1 != indicator_check!(unsafe { RAND_bytes(dest.as_mut_ptr(), dest.len()) }) {
161        return Err(Unspecified);
162    }
163    Ok(())
164}
165
166#[cfg(test)]
167mod tests {
168    use crate::rand;
169    use core::array::IntoIter;
170
171    use crate::rand::{generate, SecureRandom, SystemRandom};
172
173    #[test]
174    fn test_secure_random_fill() {
175        // Collect enough random values so that the assertions below should never fail again
176        let mut random_array = [0u8; 1009];
177        let rng = SystemRandom::new();
178        rng.fill(&mut random_array).unwrap();
179
180        let (mean, variance) = mean_variance(&mut random_array.into_iter());
181        assert!((106f64..150f64).contains(&mean), "Mean: {mean}");
182        assert!(variance > 8f64);
183        println!("Mean: {mean} Variance: {variance}");
184    }
185
186    #[test]
187    fn test_rand_fill() {
188        // Collect enough random values so that the assertions below should never fail again
189        let mut random_array = [0u8; 1009];
190        rand::fill(&mut random_array).unwrap();
191
192        let (mean, variance) = mean_variance(&mut random_array.into_iter());
193        assert!((106f64..150f64).contains(&mean), "Mean: {mean}");
194        assert!(variance > 8f64);
195        println!("Mean: {mean} Variance: {variance}");
196    }
197
198    #[test]
199    fn test_randomly_constructable() {
200        let rando = SystemRandom::new();
201        let random_array = generate(&rando).unwrap();
202        // Collect enough random values so that the assertions below should never fail again
203        let random_array: [u8; 1009] = random_array.expose();
204        let (mean, variance) = mean_variance(&mut random_array.into_iter());
205        assert!((106f64..150f64).contains(&mean), "Mean: {mean}");
206        assert!(variance > 8f64);
207        println!("Mean: {mean} Variance: {variance}");
208    }
209
210    fn mean_variance<T: Into<f64>, const N: usize>(iterable: &mut IntoIter<T, N>) -> (f64, f64) {
211        let iter = iterable;
212        let mean: Option<T> = iter.next();
213        let mut mean = mean.unwrap().into();
214        let mut var_squared = 0f64;
215        let mut count = 1f64;
216        for value in iter.by_ref() {
217            count += 1f64;
218            let value = value.into();
219            let prev_mean = mean;
220            mean = prev_mean + (value - prev_mean) / count;
221            var_squared =
222                var_squared + ((value - prev_mean) * (value - mean) - var_squared) / count;
223        }
224
225        (mean, var_squared.sqrt())
226    }
227}