1 // Copyright 2018 Developers of the Rand project.
2 // Copyright 2013 The Rust Project Developers.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9 
10 //! A wrapper around another PRNG that reseeds it after it
11 //! generates a certain number of random bytes.
12 
13 use core::mem::size_of;
14 
15 use rand_core::block::{BlockRng, BlockRngCore};
16 use rand_core::{CryptoRng, Error, RngCore, SeedableRng};
17 
18 /// A wrapper around any PRNG that implements [`BlockRngCore`], that adds the
19 /// ability to reseed it.
20 ///
21 /// `ReseedingRng` reseeds the underlying PRNG in the following cases:
22 ///
23 /// - On a manual call to [`reseed()`].
24 /// - After `clone()`, the clone will be reseeded on first use.
25 /// - When a process is forked on UNIX, the RNGs in both the parent and child
26 ///   processes will be reseeded just before the next call to
27 ///   [`BlockRngCore::generate`], i.e. "soon". For ChaCha and Hc128 this is a
28 ///   maximum of fifteen `u32` values before reseeding.
29 /// - After the PRNG has generated a configurable number of random bytes.
30 ///
31 /// # When should reseeding after a fixed number of generated bytes be used?
32 ///
33 /// Reseeding after a fixed number of generated bytes is never strictly
34 /// *necessary*. Cryptographic PRNGs don't have a limited number of bytes they
35 /// can output, or at least not a limit reachable in any practical way. There is
36 /// no such thing as 'running out of entropy'.
37 ///
38 /// Occasionally reseeding can be seen as some form of 'security in depth'. Even
39 /// if in the future a cryptographic weakness is found in the CSPRNG being used,
40 /// or a flaw in the implementation, occasionally reseeding should make
41 /// exploiting it much more difficult or even impossible.
42 ///
43 /// Use [`ReseedingRng::new`] with a `threshold` of `0` to disable reseeding
44 /// after a fixed number of generated bytes.
45 ///
46 /// # Limitations
47 ///
48 /// It is recommended that a `ReseedingRng` (including `ThreadRng`) not be used
49 /// from a fork handler.
50 /// Use `OsRng` or `getrandom`, or defer your use of the RNG until later.
51 ///
52 /// # Error handling
53 ///
54 /// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will
55 /// never panic but try to handle the error intelligently through some
56 /// combination of retrying and delaying reseeding until later.
57 /// If handling the source error fails `ReseedingRng` will continue generating
58 /// data from the wrapped PRNG without reseeding.
59 ///
60 /// Manually calling [`reseed()`] will not have this retry or delay logic, but
61 /// reports the error.
62 ///
63 /// # Example
64 ///
65 /// ```
66 /// use rand::prelude::*;
67 /// use rand_chacha::ChaCha20Core; // Internal part of ChaChaRng that
68 ///                              // implements BlockRngCore
69 /// use rand::rngs::OsRng;
70 /// use rand::rngs::adapter::ReseedingRng;
71 ///
72 /// let prng = ChaCha20Core::from_entropy();
73 /// let mut reseeding_rng = ReseedingRng::new(prng, 0, OsRng);
74 ///
75 /// println!("{}", reseeding_rng.gen::<u64>());
76 ///
77 /// let mut cloned_rng = reseeding_rng.clone();
78 /// assert!(reseeding_rng.gen::<u64>() != cloned_rng.gen::<u64>());
79 /// ```
80 ///
81 /// [`BlockRngCore`]: rand_core::block::BlockRngCore
82 /// [`ReseedingRng::new`]: ReseedingRng::new
83 /// [`reseed()`]: ReseedingRng::reseed
84 #[derive(Debug)]
85 pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>)
86 where
87     R: BlockRngCore + SeedableRng,
88     Rsdr: RngCore;
89 
90 impl<R, Rsdr> ReseedingRng<R, Rsdr>
91 where
92     R: BlockRngCore + SeedableRng,
93     Rsdr: RngCore,
94 {
95     /// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG
96     /// to use as reseeder.
97     ///
98     /// `threshold` sets the number of generated bytes after which to reseed the
99     /// PRNG. Set it to zero to never reseed based on the number of generated
100     /// values.
new(rng: R, threshold: u64, reseeder: Rsdr) -> Self101     pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self {
102         ReseedingRng(BlockRng::new(ReseedingCore::new(rng, threshold, reseeder)))
103     }
104 
105     /// Reseed the internal PRNG.
reseed(&mut self) -> Result<(), Error>106     pub fn reseed(&mut self) -> Result<(), Error> {
107         self.0.core.reseed()
108     }
109 }
110 
111 // TODO: this should be implemented for any type where the inner type
112 // implements RngCore, but we can't specify that because ReseedingCore is private
113 impl<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr>
114 where
115     R: BlockRngCore<Item = u32> + SeedableRng,
116     <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>,
117 {
118     #[inline(always)]
next_u32(&mut self) -> u32119     fn next_u32(&mut self) -> u32 {
120         self.0.next_u32()
121     }
122 
123     #[inline(always)]
next_u64(&mut self) -> u64124     fn next_u64(&mut self) -> u64 {
125         self.0.next_u64()
126     }
127 
fill_bytes(&mut self, dest: &mut [u8])128     fn fill_bytes(&mut self, dest: &mut [u8]) {
129         self.0.fill_bytes(dest)
130     }
131 
try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>132     fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
133         self.0.try_fill_bytes(dest)
134     }
135 }
136 
137 impl<R, Rsdr> Clone for ReseedingRng<R, Rsdr>
138 where
139     R: BlockRngCore + SeedableRng + Clone,
140     Rsdr: RngCore + Clone,
141 {
clone(&self) -> ReseedingRng<R, Rsdr>142     fn clone(&self) -> ReseedingRng<R, Rsdr> {
143         // Recreating `BlockRng` seems easier than cloning it and resetting
144         // the index.
145         ReseedingRng(BlockRng::new(self.0.core.clone()))
146     }
147 }
148 
149 impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr>
150 where
151     R: BlockRngCore + SeedableRng + CryptoRng,
152     Rsdr: RngCore + CryptoRng,
153 {
154 }
155 
156 #[derive(Debug)]
157 struct ReseedingCore<R, Rsdr> {
158     inner: R,
159     reseeder: Rsdr,
160     threshold: i64,
161     bytes_until_reseed: i64,
162     fork_counter: usize,
163 }
164 
165 impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr>
166 where
167     R: BlockRngCore + SeedableRng,
168     Rsdr: RngCore,
169 {
170     type Item = <R as BlockRngCore>::Item;
171     type Results = <R as BlockRngCore>::Results;
172 
generate(&mut self, results: &mut Self::Results)173     fn generate(&mut self, results: &mut Self::Results) {
174         let global_fork_counter = fork::get_fork_counter();
175         if self.bytes_until_reseed <= 0 || self.is_forked(global_fork_counter) {
176             // We get better performance by not calling only `reseed` here
177             // and continuing with the rest of the function, but by directly
178             // returning from a non-inlined function.
179             return self.reseed_and_generate(results, global_fork_counter);
180         }
181         let num_bytes = results.as_ref().len() * size_of::<Self::Item>();
182         self.bytes_until_reseed -= num_bytes as i64;
183         self.inner.generate(results);
184     }
185 }
186 
187 impl<R, Rsdr> ReseedingCore<R, Rsdr>
188 where
189     R: BlockRngCore + SeedableRng,
190     Rsdr: RngCore,
191 {
192     /// Create a new `ReseedingCore`.
new(rng: R, threshold: u64, reseeder: Rsdr) -> Self193     fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self {
194         use ::core::i64::MAX;
195         fork::register_fork_handler();
196 
197         // Because generating more values than `i64::MAX` takes centuries on
198         // current hardware, we just clamp to that value.
199         // Also we set a threshold of 0, which indicates no limit, to that
200         // value.
201         let threshold = if threshold == 0 {
202             MAX
203         } else if threshold <= MAX as u64 {
204             threshold as i64
205         } else {
206             MAX
207         };
208 
209         ReseedingCore {
210             inner: rng,
211             reseeder,
212             threshold: threshold as i64,
213             bytes_until_reseed: threshold as i64,
214             fork_counter: 0,
215         }
216     }
217 
218     /// Reseed the internal PRNG.
reseed(&mut self) -> Result<(), Error>219     fn reseed(&mut self) -> Result<(), Error> {
220         R::from_rng(&mut self.reseeder).map(|result| {
221             self.bytes_until_reseed = self.threshold;
222             self.inner = result
223         })
224     }
225 
is_forked(&self, global_fork_counter: usize) -> bool226     fn is_forked(&self, global_fork_counter: usize) -> bool {
227         // In theory, on 32-bit platforms, it is possible for
228         // `global_fork_counter` to wrap around after ~4e9 forks.
229         //
230         // This check will detect a fork in the normal case where
231         // `fork_counter < global_fork_counter`, and also when the difference
232         // between both is greater than `isize::MAX` (wrapped around).
233         //
234         // It will still fail to detect a fork if there have been more than
235         // `isize::MAX` forks, without any reseed in between. Seems unlikely
236         // enough.
237         (self.fork_counter.wrapping_sub(global_fork_counter) as isize) < 0
238     }
239 
240     #[inline(never)]
reseed_and_generate( &mut self, results: &mut <Self as BlockRngCore>::Results, global_fork_counter: usize, )241     fn reseed_and_generate(
242         &mut self, results: &mut <Self as BlockRngCore>::Results, global_fork_counter: usize,
243     ) {
244         #![allow(clippy::if_same_then_else)] // false positive
245         if self.is_forked(global_fork_counter) {
246             info!("Fork detected, reseeding RNG");
247         } else {
248             trace!("Reseeding RNG (periodic reseed)");
249         }
250 
251         let num_bytes = results.as_ref().len() * size_of::<<R as BlockRngCore>::Item>();
252 
253         if let Err(e) = self.reseed() {
254             warn!("Reseeding RNG failed: {}", e);
255             let _ = e;
256         }
257         self.fork_counter = global_fork_counter;
258 
259         self.bytes_until_reseed = self.threshold - num_bytes as i64;
260         self.inner.generate(results);
261     }
262 }
263 
264 impl<R, Rsdr> Clone for ReseedingCore<R, Rsdr>
265 where
266     R: BlockRngCore + SeedableRng + Clone,
267     Rsdr: RngCore + Clone,
268 {
clone(&self) -> ReseedingCore<R, Rsdr>269     fn clone(&self) -> ReseedingCore<R, Rsdr> {
270         ReseedingCore {
271             inner: self.inner.clone(),
272             reseeder: self.reseeder.clone(),
273             threshold: self.threshold,
274             bytes_until_reseed: 0, // reseed clone on first use
275             fork_counter: self.fork_counter,
276         }
277     }
278 }
279 
280 impl<R, Rsdr> CryptoRng for ReseedingCore<R, Rsdr>
281 where
282     R: BlockRngCore + SeedableRng + CryptoRng,
283     Rsdr: RngCore + CryptoRng,
284 {
285 }
286 
287 
288 #[cfg(all(unix, not(target_os = "emscripten")))]
289 mod fork {
290     use core::sync::atomic::{AtomicUsize, Ordering};
291     use std::sync::Once;
292 
293     // Fork protection
294     //
295     // We implement fork protection on Unix using `pthread_atfork`.
296     // When the process is forked, we increment `RESEEDING_RNG_FORK_COUNTER`.
297     // Every `ReseedingRng` stores the last known value of the static in
298     // `fork_counter`. If the cached `fork_counter` is less than
299     // `RESEEDING_RNG_FORK_COUNTER`, it is time to reseed this RNG.
300     //
301     // If reseeding fails, we don't deal with this by setting a delay, but just
302     // don't update `fork_counter`, so a reseed is attempted as soon as
303     // possible.
304 
305     static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = AtomicUsize::new(0);
306 
get_fork_counter() -> usize307     pub fn get_fork_counter() -> usize {
308         RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed)
309     }
310 
fork_handler()311     extern "C" fn fork_handler() {
312         // Note: fetch_add is defined to wrap on overflow
313         // (which is what we want).
314         RESEEDING_RNG_FORK_COUNTER.fetch_add(1, Ordering::Relaxed);
315     }
316 
register_fork_handler()317     pub fn register_fork_handler() {
318         static REGISTER: Once = Once::new();
319         REGISTER.call_once(|| {
320             // Bump the counter before and after forking (see #1169):
321             let ret = unsafe { libc::pthread_atfork(
322                 Some(fork_handler),
323                 Some(fork_handler),
324                 Some(fork_handler),
325             ) };
326             if ret != 0 {
327                 panic!("libc::pthread_atfork failed with code {}", ret);
328             }
329         });
330     }
331 }
332 
333 #[cfg(not(all(unix, not(target_os = "emscripten"))))]
334 mod fork {
get_fork_counter() -> usize335     pub fn get_fork_counter() -> usize {
336         0
337     }
register_fork_handler()338     pub fn register_fork_handler() {}
339 }
340 
341 
342 #[cfg(feature = "std_rng")]
343 #[cfg(test)]
344 mod test {
345     use super::ReseedingRng;
346     use crate::rngs::mock::StepRng;
347     use crate::rngs::std::Core;
348     use crate::{Rng, SeedableRng};
349 
350     #[test]
test_reseeding()351     fn test_reseeding() {
352         let mut zero = StepRng::new(0, 0);
353         let rng = Core::from_rng(&mut zero).unwrap();
354         let thresh = 1; // reseed every time the buffer is exhausted
355         let mut reseeding = ReseedingRng::new(rng, thresh, zero);
356 
357         // RNG buffer size is [u32; 64]
358         // Debug is only implemented up to length 32 so use two arrays
359         let mut buf = ([0u32; 32], [0u32; 32]);
360         reseeding.fill(&mut buf.0);
361         reseeding.fill(&mut buf.1);
362         let seq = buf;
363         for _ in 0..10 {
364             reseeding.fill(&mut buf.0);
365             reseeding.fill(&mut buf.1);
366             assert_eq!(buf, seq);
367         }
368     }
369 
370     #[test]
test_clone_reseeding()371     fn test_clone_reseeding() {
372         #![allow(clippy::redundant_clone)]
373 
374         let mut zero = StepRng::new(0, 0);
375         let rng = Core::from_rng(&mut zero).unwrap();
376         let mut rng1 = ReseedingRng::new(rng, 32 * 4, zero);
377 
378         let first: u32 = rng1.gen();
379         for _ in 0..10 {
380             let _ = rng1.gen::<u32>();
381         }
382 
383         let mut rng2 = rng1.clone();
384         assert_eq!(first, rng2.gen::<u32>());
385     }
386 }
387