1 | // Copyright 2015-2016 Brian Smith. |
2 | // |
3 | // Permission to use, copy, modify, and/or distribute this software for any |
4 | // purpose with or without fee is hereby granted, provided that the above |
5 | // copyright notice and this permission notice appear in all copies. |
6 | // |
7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | |
15 | //! Cryptographic pseudo-random number generation. |
16 | //! |
17 | //! *ring* functions that generate random bytes take a `&dyn SecureRandom` |
18 | //! parameter to make it clear which functions are non-deterministic. |
19 | |
20 | use crate::error; |
21 | |
22 | /// A secure random number generator. |
23 | pub trait SecureRandom: sealed::SecureRandom { |
24 | /// Fills `dest` with random bytes. |
25 | fn fill(&self, dest: &mut [u8]) -> Result<(), error::Unspecified>; |
26 | } |
27 | |
28 | impl<T> SecureRandom for T |
29 | where |
30 | T: sealed::SecureRandom, |
31 | { |
32 | #[inline (always)] |
33 | fn fill(&self, dest: &mut [u8]) -> Result<(), error::Unspecified> { |
34 | self.fill_impl(dest) |
35 | } |
36 | } |
37 | |
38 | /// A random value constructed from a `SecureRandom` that hasn't been exposed |
39 | /// through any safe Rust interface. |
40 | /// |
41 | /// Intentionally does not implement any traits other than `Sized`. |
42 | pub struct Random<T: RandomlyConstructable>(T); |
43 | |
44 | impl<T: RandomlyConstructable> Random<T> { |
45 | /// Expose the random value. |
46 | #[inline ] |
47 | pub fn expose(self) -> T { |
48 | self.0 |
49 | } |
50 | } |
51 | |
52 | /// Generate the new random value using `rng`. |
53 | #[inline ] |
54 | pub fn generate<T: RandomlyConstructable>( |
55 | rng: &dyn SecureRandom, |
56 | ) -> Result<Random<T>, error::Unspecified> |
57 | where |
58 | T: RandomlyConstructable, |
59 | { |
60 | let mut r: T = T::zero(); |
61 | rng.fill(dest:r.as_mut_bytes())?; |
62 | Ok(Random(r)) |
63 | } |
64 | |
65 | pub(crate) mod sealed { |
66 | use crate::error; |
67 | |
68 | pub trait SecureRandom: core::fmt::Debug { |
69 | /// Fills `dest` with random bytes. |
70 | fn fill_impl(&self, dest: &mut [u8]) -> Result<(), error::Unspecified>; |
71 | } |
72 | |
73 | pub trait RandomlyConstructable: Sized { |
74 | fn zero() -> Self; // `Default::default()` |
75 | fn as_mut_bytes(&mut self) -> &mut [u8]; // `AsMut<[u8]>::as_mut` |
76 | } |
77 | |
78 | impl<const N: usize> RandomlyConstructable for [u8; N] { |
79 | #[inline ] |
80 | fn zero() -> Self { |
81 | [0; N] |
82 | } |
83 | |
84 | #[inline ] |
85 | fn as_mut_bytes(&mut self) -> &mut [u8] { |
86 | &mut self[..] |
87 | } |
88 | } |
89 | } |
90 | |
91 | /// A type that can be returned by `ring::rand::generate()`. |
92 | pub trait RandomlyConstructable: self::sealed::RandomlyConstructable {} |
93 | impl<T> RandomlyConstructable for T where T: self::sealed::RandomlyConstructable {} |
94 | |
95 | /// A secure random number generator where the random values come directly |
96 | /// from the operating system. |
97 | /// |
98 | /// "Directly from the operating system" here presently means "whatever the |
99 | /// `getrandom` crate does" but that may change in the future. That roughly |
100 | /// means calling libc's `getrandom` function or whatever is analogous to that; |
101 | /// see the `getrandom` crate's documentation for more info. |
102 | /// |
103 | /// A single `SystemRandom` may be shared across multiple threads safely. |
104 | /// |
105 | /// `new()` is guaranteed to always succeed and to have low latency; it won't |
106 | /// try to open or read from a file or do similar things. The first call to |
107 | /// `fill()` may block a substantial amount of time since any and all |
108 | /// initialization is deferred to it. Therefore, it may be a good idea to call |
109 | /// `fill()` once at a non-latency-sensitive time to minimize latency for |
110 | /// future calls. |
111 | #[derive (Clone, Debug)] |
112 | pub struct SystemRandom(()); |
113 | |
114 | impl SystemRandom { |
115 | /// Constructs a new `SystemRandom`. |
116 | #[inline (always)] |
117 | pub fn new() -> Self { |
118 | Self(()) |
119 | } |
120 | } |
121 | |
122 | impl crate::sealed::Sealed for SystemRandom {} |
123 | |
124 | // Use the `getrandom` crate whenever it is using the environment's (operating |
125 | // system's) CSPRNG. Avoid using it on targets where it uses the `rdrand` |
126 | // implementation. |
127 | #[cfg (any( |
128 | all(feature = "less-safe-getrandom-custom-or-rdrand" , target_os = "none" ), |
129 | target_os = "aix" , |
130 | target_os = "android" , |
131 | target_os = "dragonfly" , |
132 | target_os = "freebsd" , |
133 | target_os = "haiku" , |
134 | target_os = "hermit" , |
135 | target_os = "illumos" , |
136 | target_os = "ios" , |
137 | target_os = "linux" , |
138 | target_os = "macos" , |
139 | target_os = "netbsd" , |
140 | target_os = "openbsd" , |
141 | target_os = "redox" , |
142 | target_os = "solaris" , |
143 | target_os = "tvos" , |
144 | target_os = "vita" , |
145 | target_os = "windows" , |
146 | all( |
147 | target_arch = "wasm32" , |
148 | any( |
149 | target_os = "wasi" , |
150 | all(target_os = "unknown" , feature = "wasm32_unknown_unknown_js" ) |
151 | ) |
152 | ), |
153 | ))] |
154 | impl sealed::SecureRandom for SystemRandom { |
155 | #[inline (always)] |
156 | fn fill_impl(&self, dest: &mut [u8]) -> Result<(), error::Unspecified> { |
157 | getrandom::getrandom(dest).map_err(|_| error::Unspecified) |
158 | } |
159 | } |
160 | |