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 /// - After a process is forked, the RNG in the child process is reseeded within 26 /// the next few generated values, depending on the block size of the 27 /// underlying PRNG. For ChaCha and Hc128 this is a maximum of 28 /// 15 `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 /// # Error handling 47 /// 48 /// Although unlikely, reseeding the wrapped PRNG can fail. `ReseedingRng` will 49 /// never panic but try to handle the error intelligently through some 50 /// combination of retrying and delaying reseeding until later. 51 /// If handling the source error fails `ReseedingRng` will continue generating 52 /// data from the wrapped PRNG without reseeding. 53 /// 54 /// Manually calling [`reseed()`] will not have this retry or delay logic, but 55 /// reports the error. 56 /// 57 /// # Example 58 /// 59 /// ``` 60 /// use rand::prelude::*; 61 /// use rand_chacha::ChaCha20Core; // Internal part of ChaChaRng that 62 /// // implements BlockRngCore 63 /// use rand::rngs::OsRng; 64 /// use rand::rngs::adapter::ReseedingRng; 65 /// 66 /// let prng = ChaCha20Core::from_entropy(); 67 /// let mut reseeding_rng = ReseedingRng::new(prng, 0, OsRng); 68 /// 69 /// println!("{}", reseeding_rng.gen::<u64>()); 70 /// 71 /// let mut cloned_rng = reseeding_rng.clone(); 72 /// assert!(reseeding_rng.gen::<u64>() != cloned_rng.gen::<u64>()); 73 /// ``` 74 /// 75 /// [`BlockRngCore`]: rand_core::block::BlockRngCore 76 /// [`ReseedingRng::new`]: ReseedingRng::new 77 /// [`reseed()`]: ReseedingRng::reseed 78 #[derive(Debug)] 79 pub struct ReseedingRng<R, Rsdr>(BlockRng<ReseedingCore<R, Rsdr>>) 80 where 81 R: BlockRngCore + SeedableRng, 82 Rsdr: RngCore; 83 84 impl<R, Rsdr> ReseedingRng<R, Rsdr> 85 where 86 R: BlockRngCore + SeedableRng, 87 Rsdr: RngCore, 88 { 89 /// Create a new `ReseedingRng` from an existing PRNG, combined with a RNG 90 /// to use as reseeder. 91 /// 92 /// `threshold` sets the number of generated bytes after which to reseed the 93 /// PRNG. Set it to zero to never reseed based on the number of generated 94 /// values. new(rng: R, threshold: u64, reseeder: Rsdr) -> Self95 pub fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { 96 ReseedingRng(BlockRng::new(ReseedingCore::new(rng, threshold, reseeder))) 97 } 98 99 /// Reseed the internal PRNG. reseed(&mut self) -> Result<(), Error>100 pub fn reseed(&mut self) -> Result<(), Error> { 101 self.0.core.reseed() 102 } 103 } 104 105 // TODO: this should be implemented for any type where the inner type 106 // implements RngCore, but we can't specify that because ReseedingCore is private 107 impl<R, Rsdr: RngCore> RngCore for ReseedingRng<R, Rsdr> 108 where 109 R: BlockRngCore<Item = u32> + SeedableRng, 110 <R as BlockRngCore>::Results: AsRef<[u32]> + AsMut<[u32]>, 111 { 112 #[inline(always)] next_u32(&mut self) -> u32113 fn next_u32(&mut self) -> u32 { 114 self.0.next_u32() 115 } 116 117 #[inline(always)] next_u64(&mut self) -> u64118 fn next_u64(&mut self) -> u64 { 119 self.0.next_u64() 120 } 121 fill_bytes(&mut self, dest: &mut [u8])122 fn fill_bytes(&mut self, dest: &mut [u8]) { 123 self.0.fill_bytes(dest) 124 } 125 try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>126 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { 127 self.0.try_fill_bytes(dest) 128 } 129 } 130 131 impl<R, Rsdr> Clone for ReseedingRng<R, Rsdr> 132 where 133 R: BlockRngCore + SeedableRng + Clone, 134 Rsdr: RngCore + Clone, 135 { clone(&self) -> ReseedingRng<R, Rsdr>136 fn clone(&self) -> ReseedingRng<R, Rsdr> { 137 // Recreating `BlockRng` seems easier than cloning it and resetting 138 // the index. 139 ReseedingRng(BlockRng::new(self.0.core.clone())) 140 } 141 } 142 143 impl<R, Rsdr> CryptoRng for ReseedingRng<R, Rsdr> 144 where 145 R: BlockRngCore + SeedableRng + CryptoRng, 146 Rsdr: RngCore + CryptoRng, 147 { 148 } 149 150 #[derive(Debug)] 151 struct ReseedingCore<R, Rsdr> { 152 inner: R, 153 reseeder: Rsdr, 154 threshold: i64, 155 bytes_until_reseed: i64, 156 fork_counter: usize, 157 } 158 159 impl<R, Rsdr> BlockRngCore for ReseedingCore<R, Rsdr> 160 where 161 R: BlockRngCore + SeedableRng, 162 Rsdr: RngCore, 163 { 164 type Item = <R as BlockRngCore>::Item; 165 type Results = <R as BlockRngCore>::Results; 166 generate(&mut self, results: &mut Self::Results)167 fn generate(&mut self, results: &mut Self::Results) { 168 let global_fork_counter = fork::get_fork_counter(); 169 if self.bytes_until_reseed <= 0 || self.is_forked(global_fork_counter) { 170 // We get better performance by not calling only `reseed` here 171 // and continuing with the rest of the function, but by directly 172 // returning from a non-inlined function. 173 return self.reseed_and_generate(results, global_fork_counter); 174 } 175 let num_bytes = results.as_ref().len() * size_of::<Self::Item>(); 176 self.bytes_until_reseed -= num_bytes as i64; 177 self.inner.generate(results); 178 } 179 } 180 181 impl<R, Rsdr> ReseedingCore<R, Rsdr> 182 where 183 R: BlockRngCore + SeedableRng, 184 Rsdr: RngCore, 185 { 186 /// Create a new `ReseedingCore`. new(rng: R, threshold: u64, reseeder: Rsdr) -> Self187 fn new(rng: R, threshold: u64, reseeder: Rsdr) -> Self { 188 use ::core::i64::MAX; 189 fork::register_fork_handler(); 190 191 // Because generating more values than `i64::MAX` takes centuries on 192 // current hardware, we just clamp to that value. 193 // Also we set a threshold of 0, which indicates no limit, to that 194 // value. 195 let threshold = if threshold == 0 { 196 MAX 197 } else if threshold <= MAX as u64 { 198 threshold as i64 199 } else { 200 MAX 201 }; 202 203 ReseedingCore { 204 inner: rng, 205 reseeder, 206 threshold: threshold as i64, 207 bytes_until_reseed: threshold as i64, 208 fork_counter: 0, 209 } 210 } 211 212 /// Reseed the internal PRNG. reseed(&mut self) -> Result<(), Error>213 fn reseed(&mut self) -> Result<(), Error> { 214 R::from_rng(&mut self.reseeder).map(|result| { 215 self.bytes_until_reseed = self.threshold; 216 self.inner = result 217 }) 218 } 219 is_forked(&self, global_fork_counter: usize) -> bool220 fn is_forked(&self, global_fork_counter: usize) -> bool { 221 // In theory, on 32-bit platforms, it is possible for 222 // `global_fork_counter` to wrap around after ~4e9 forks. 223 // 224 // This check will detect a fork in the normal case where 225 // `fork_counter < global_fork_counter`, and also when the difference 226 // between both is greater than `isize::MAX` (wrapped around). 227 // 228 // It will still fail to detect a fork if there have been more than 229 // `isize::MAX` forks, without any reseed in between. Seems unlikely 230 // enough. 231 (self.fork_counter.wrapping_sub(global_fork_counter) as isize) < 0 232 } 233 234 #[inline(never)] reseed_and_generate( &mut self, results: &mut <Self as BlockRngCore>::Results, global_fork_counter: usize, )235 fn reseed_and_generate( 236 &mut self, results: &mut <Self as BlockRngCore>::Results, global_fork_counter: usize, 237 ) { 238 #![allow(clippy::if_same_then_else)] // false positive 239 if self.is_forked(global_fork_counter) { 240 info!("Fork detected, reseeding RNG"); 241 } else { 242 trace!("Reseeding RNG (periodic reseed)"); 243 } 244 245 let num_bytes = results.as_ref().len() * size_of::<<R as BlockRngCore>::Item>(); 246 247 if let Err(e) = self.reseed() { 248 warn!("Reseeding RNG failed: {}", e); 249 let _ = e; 250 } 251 self.fork_counter = global_fork_counter; 252 253 self.bytes_until_reseed = self.threshold - num_bytes as i64; 254 self.inner.generate(results); 255 } 256 } 257 258 impl<R, Rsdr> Clone for ReseedingCore<R, Rsdr> 259 where 260 R: BlockRngCore + SeedableRng + Clone, 261 Rsdr: RngCore + Clone, 262 { clone(&self) -> ReseedingCore<R, Rsdr>263 fn clone(&self) -> ReseedingCore<R, Rsdr> { 264 ReseedingCore { 265 inner: self.inner.clone(), 266 reseeder: self.reseeder.clone(), 267 threshold: self.threshold, 268 bytes_until_reseed: 0, // reseed clone on first use 269 fork_counter: self.fork_counter, 270 } 271 } 272 } 273 274 impl<R, Rsdr> CryptoRng for ReseedingCore<R, Rsdr> 275 where 276 R: BlockRngCore + SeedableRng + CryptoRng, 277 Rsdr: RngCore + CryptoRng, 278 { 279 } 280 281 282 #[cfg(all(unix, not(target_os = "emscripten")))] 283 mod fork { 284 use core::sync::atomic::{AtomicUsize, Ordering}; 285 use std::sync::Once; 286 287 // Fork protection 288 // 289 // We implement fork protection on Unix using `pthread_atfork`. 290 // When the process is forked, we increment `RESEEDING_RNG_FORK_COUNTER`. 291 // Every `ReseedingRng` stores the last known value of the static in 292 // `fork_counter`. If the cached `fork_counter` is less than 293 // `RESEEDING_RNG_FORK_COUNTER`, it is time to reseed this RNG. 294 // 295 // If reseeding fails, we don't deal with this by setting a delay, but just 296 // don't update `fork_counter`, so a reseed is attempted as soon as 297 // possible. 298 299 static RESEEDING_RNG_FORK_COUNTER: AtomicUsize = AtomicUsize::new(0); 300 get_fork_counter() -> usize301 pub fn get_fork_counter() -> usize { 302 RESEEDING_RNG_FORK_COUNTER.load(Ordering::Relaxed) 303 } 304 fork_handler()305 extern "C" fn fork_handler() { 306 // Note: fetch_add is defined to wrap on overflow 307 // (which is what we want). 308 RESEEDING_RNG_FORK_COUNTER.fetch_add(1, Ordering::Relaxed); 309 } 310 register_fork_handler()311 pub fn register_fork_handler() { 312 static REGISTER: Once = Once::new(); 313 REGISTER.call_once(|| unsafe { 314 libc::pthread_atfork(None, None, Some(fork_handler)); 315 }); 316 } 317 } 318 319 #[cfg(not(all(unix, not(target_os = "emscripten"))))] 320 mod fork { get_fork_counter() -> usize321 pub fn get_fork_counter() -> usize { 322 0 323 } register_fork_handler()324 pub fn register_fork_handler() {} 325 } 326 327 328 #[cfg(feature = "std_rng")] 329 #[cfg(test)] 330 mod test { 331 use super::ReseedingRng; 332 use crate::rngs::mock::StepRng; 333 use crate::rngs::std::Core; 334 use crate::{Rng, SeedableRng}; 335 336 #[test] test_reseeding()337 fn test_reseeding() { 338 let mut zero = StepRng::new(0, 0); 339 let rng = Core::from_rng(&mut zero).unwrap(); 340 let thresh = 1; // reseed every time the buffer is exhausted 341 let mut reseeding = ReseedingRng::new(rng, thresh, zero); 342 343 // RNG buffer size is [u32; 64] 344 // Debug is only implemented up to length 32 so use two arrays 345 let mut buf = ([0u32; 32], [0u32; 32]); 346 reseeding.fill(&mut buf.0); 347 reseeding.fill(&mut buf.1); 348 let seq = buf; 349 for _ in 0..10 { 350 reseeding.fill(&mut buf.0); 351 reseeding.fill(&mut buf.1); 352 assert_eq!(buf, seq); 353 } 354 } 355 356 #[test] test_clone_reseeding()357 fn test_clone_reseeding() { 358 let mut zero = StepRng::new(0, 0); 359 let rng = Core::from_rng(&mut zero).unwrap(); 360 let mut rng1 = ReseedingRng::new(rng, 32 * 4, zero); 361 362 let first: u32 = rng1.gen(); 363 for _ in 0..10 { 364 let _ = rng1.gen::<u32>(); 365 } 366 367 let mut rng2 = rng1.clone(); 368 assert_eq!(first, rng2.gen::<u32>()); 369 } 370 } 371