linux_kcapi/random.rs
1//! Random generation using linux kernel Crypto Api.
2//!
3//! [NIST SP800-90]: https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final
4
5use crate::err::Error;
6use crate::internal::KcApi;
7
8/// Type of Random number Generator
9#[derive(Clone)]
10pub enum RngType {
11 /// CPU Time Jitter Based Non-Physical True Random Number Generator (see [CPU-Jitter-NPTRNG.pdf](http://www.chronox.de/jent/doc/CPU-Jitter-NPTRNG.pdf))
12 JitterEntropy,
13 /// HMAC_DRBG based on SHA-256 without prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
14 DrbgNoprHmacSha256,
15 /// HMAC_DRBG based on SHA-384 without prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
16 DrbgNoprHmacSha384,
17 /// HMAC_DRBG based on SHA-512 without prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
18 DrbgNoprHmacSha512,
19 /// Hash_DRBG based on SHA-256 without prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
20 DrbgNoprSha256,
21 /// Hash_DRBG based on SHA-384 without prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
22 DrbgNoprSha384,
23 /// Hash_DRBG based on SHA-512 without prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
24 DrbgNoprSha512,
25 /// CTR_DRBG based on AES with 128 bits keys without prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
26 DrbgNoprCtrAes128,
27 /// CTR_DRBG based on AES with 192 bits keys without prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
28 DrbgNoprCtrAes192,
29 /// CTR_DRBG based on AES with 256 bits keys without prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
30 DrbgNoprCtrAes256,
31 /// HMAC_DRBG based on SHA-256 **with** prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
32 DrbgPrHmacSha256,
33 /// HMAC_DRBG based on SHA-384 **with** prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
34 DrbgPrHmacSha384,
35 /// HMAC_DRBG based on SHA-512 **with** prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
36 DrbgPrHmacSha512,
37
38 /// Hash_DRBG based on SHA-256 **with** prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
39 DrbgPrSha256,
40 /// Hash_DRBG based on SHA-384 **with** prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
41 DrbgPrSha384,
42 /// Hash_DRBG based on SHA-512 **with** prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
43 DrbgPrSha512,
44 /// CTR_DRBG based on AES with 128 bits keys **with** prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
45 DrbgPrCtrAes128,
46 /// CTR_DRBG based on AES with 192 bits keys **with** prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
47 DrbgPrCtrAes192,
48 /// CTR_DRBG based on AES with 256 bits keys **with** prediction resistance as specified in [NIST SP800-90A-rev1](https://csrc.nist.gov/publications/detail/sp/800-90a/rev-1/final)
49 DrbgPrCtrAes256,
50}
51
52impl RngType {
53 #[allow(clippy::unused_self)]
54 #[must_use]
55 /// Get type str to be used as type with `AF_ALG` sockets
56 pub fn get_type(&self) -> &'static str {
57 "rng"
58 }
59
60 #[must_use]
61 /// Get name str to be used as type with `AF_ALG` sockets
62 pub fn get_name(&self) -> &'static str {
63 match self {
64 Self::JitterEntropy => "jitterentropy_rng",
65 Self::DrbgNoprHmacSha256 => "drbg_nopr_hmac_sha256",
66 Self::DrbgNoprHmacSha384 => "drbg_nopr_hmac_sha384",
67 Self::DrbgNoprHmacSha512 => "drbg_nopr_hmac_sha512",
68 Self::DrbgNoprSha256 => "drbg_nopr_sha256",
69 Self::DrbgNoprSha384 => "drbg_nopr_sha384",
70 Self::DrbgNoprSha512 => "drbg_nopr_sha512",
71 Self::DrbgNoprCtrAes128 => "drbg_nopr_ctr_aes128",
72 Self::DrbgNoprCtrAes192 => "drbg_nopr_ctr_aes192",
73 Self::DrbgNoprCtrAes256 => "drbg_nopr_ctr_aes256",
74 Self::DrbgPrHmacSha256 => "drbg_pr_hmac_sha256",
75 Self::DrbgPrHmacSha384 => "drbg_pr_hmac_sha384",
76 Self::DrbgPrHmacSha512 => "drbg_pr_hmac_sha512",
77 Self::DrbgPrSha256 => "drbg_pr_sha256",
78 Self::DrbgPrSha384 => "drbg_pr_sha384",
79 Self::DrbgPrSha512 => "drbg_pr_sha512",
80 Self::DrbgPrCtrAes128 => "drbg_pr_ctr_aes128",
81 Self::DrbgPrCtrAes192 => "drbg_pr_ctr_aes192",
82 Self::DrbgPrCtrAes256 => "drbg_pr_ctr_aes256",
83 }
84 }
85
86 #[must_use]
87 /// Whether this random generator has prediction restistance
88 pub fn has_prediction_resistance(&self) -> bool {
89 match self {
90 Self::DrbgNoprHmacSha256
91 | Self::DrbgNoprHmacSha384
92 | Self::DrbgNoprHmacSha512
93 | Self::DrbgNoprSha256
94 | Self::DrbgNoprSha384
95 | Self::DrbgNoprSha512
96 | Self::DrbgNoprCtrAes128
97 | Self::DrbgNoprCtrAes192
98 | Self::DrbgNoprCtrAes256 => false,
99 Self::JitterEntropy
100 | Self::DrbgPrHmacSha256
101 | Self::DrbgPrHmacSha384
102 | Self::DrbgPrHmacSha512
103 | Self::DrbgPrSha256
104 | Self::DrbgPrSha384
105 | Self::DrbgPrSha512
106 | Self::DrbgPrCtrAes128
107 | Self::DrbgPrCtrAes192
108 | Self::DrbgPrCtrAes256 => true,
109 }
110 }
111}
112
113/// Random Generator.
114///
115/// If the `rand_trait` feature is enabled, it implements the [`rand_core::RngCore`](https://rust-random.github.io/rand/rand_core/trait.RngCore.html)
116/// and [`rand_core::CryptoRng`](https://rust-random.github.io/rand/rand_core/trait.CryptoRng.html) traits.
117///
118/// # Sample usage
119///
120/// ```
121/// # use linux_kcapi::Error;
122/// use linux_kcapi::{RngType, Rng};
123///
124/// # fn get_random_bytes() -> Result<(), Error> {
125/// # let seed = [0_u8; 32];
126/// # let zero = [0_u8; 32];
127/// # let mut data = [0_u8; 32];
128/// # let mut data2 = [0_u8; 32];
129/// let rng = Rng::new(RngType::DrbgPrHmacSha256, &seed)?;
130/// rng.get_bytes(&mut data)?;
131/// assert_ne!(zero, data);
132/// rng.get_bytes(&mut data2)?;
133/// assert_ne!(data, data2);
134/// # Ok(())
135/// # }
136/// ```
137pub struct Rng {
138 api: KcApi,
139 name: RngType
140}
141
142impl Rng {
143 /// Create a new random generator.
144 /// # Errors
145 /// - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys) in case of low level error
146 pub fn new<T>(rng: RngType, seed: &T) -> Result<Self, Error>
147 where
148 T: AsRef<[u8]> + Clone,
149 {
150 let mut ret = Self {
151 api: KcApi::new(rng.get_type(), rng.get_name())?,
152 name: rng
153 };
154 ret.api.set_key(seed)?;
155 ret.api.init()?;
156 Ok(ret)
157 }
158
159 #[must_use]
160 /// Get Rng type
161 pub fn name(&self) -> RngType {
162 self.name.clone()
163 }
164
165
166 /// fill destination with random bytes
167 /// # Errors
168 /// - [`Error::Incomplete`](../enum.Error.html#variant.Incomplete) if destination was not totally filled
169 /// - [`Error::Sys(Errno)`](../enum.Error.html#variant.Sys) in case of low level error
170 pub fn get_bytes(&self, dest: &mut [u8]) -> Result<(), Error> {
171 let sz = self.api.read(dest)?;
172 if sz == dest.len() {
173 Ok(())
174 } else {
175 Err(Error::Incomplete)
176 }
177 }
178}
179
180#[cfg(feature = "rand_trait")]
181/// Only available with `"rand_trait"` feature
182///
183/// # Panic
184/// `next_u32`, `next_u64` and `fill_bytes` will panic in case of error
185impl rand_core::RngCore for Rng {
186 fn next_u32(&mut self) -> u32 {
187 let mut dest = [0_u8; 4];
188 self.fill_bytes(&mut dest);
189 u32::from_le_bytes(dest)
190 }
191
192 fn next_u64(&mut self) -> u64 {
193 let mut dest = [0_u8; 8];
194 self.fill_bytes(&mut dest);
195 u64::from_le_bytes(dest)
196 }
197
198 fn fill_bytes(&mut self, dest: &mut [u8]) {
199 if let Err(e) = self.try_fill_bytes(dest) {
200 panic!("fill_bytes error : {}", e);
201 }
202 }
203
204 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
205 // The kernel generates at most 128 bytes in one call.
206 let chunks = dest.chunks_mut(128);
207 for chunk in chunks {
208 if let Err(e) = self.get_bytes(chunk) {
209 return Err(e.into());
210 }
211 }
212 Ok(())
213 }
214}
215
216#[cfg(feature = "rand_trait")]
217/// Only available with `"rand_trait"` feature
218impl rand_core::CryptoRng for Rng {}
219
220#[cfg(test)]
221mod tests {
222 use super::*;
223
224 static RNG_TYPES: &[RngType] = &[
225 RngType::DrbgNoprHmacSha256,
226 RngType::DrbgNoprHmacSha384,
227 RngType::DrbgNoprHmacSha512,
228 // RngType::DrbgNoprSha256,
229 // RngType::DrbgNoprSha384,
230 // RngType::DrbgNoprSha512,
231 // RngType::DrbgNoprCtrAes128,
232 // RngType::DrbgNoprCtrAes192,
233 // RngType::DrbgNoprCtrAes256,
234 RngType::JitterEntropy,
235 RngType::DrbgPrHmacSha256,
236 RngType::DrbgPrHmacSha384,
237 RngType::DrbgPrHmacSha512,
238 // RngType::DrbgPrSha256,
239 // RngType::DrbgPrSha384,
240 // RngType::DrbgPrSha512,
241 // RngType::DrbgPrCtrAes128,
242 // RngType::DrbgPrCtrAes192,
243 // RngType::DrbgPrCtrAes256,
244 ];
245
246 #[test]
247 fn new() {
248 for rng in RNG_TYPES {
249 let seed = [0_u8; 32];
250 assert!(Rng::new(rng.clone(), &seed).is_ok());
251 }
252 }
253
254 #[test]
255 fn bad() {
256 let seed = [0_u8; 32];
257 let e = Rng::new(RngType::DrbgPrCtrAes256, &seed);
258 if let Err(ee) = e {
259 println!("{}", ee);
260 }
261 }
262
263 #[test]
264 fn get_random_bytes() -> Result<(), Error> {
265 for rng_type in RNG_TYPES {
266 let seed = [0_u8; 32];
267 let zero = [0_u8; 32];
268 let mut data = [0_u8; 32];
269 let mut data2 = [0_u8; 32];
270 let rng = Rng::new(rng_type.clone(), &seed)?;
271 rng.get_bytes(&mut data)?;
272 assert_ne!(zero, data);
273 rng.get_bytes(&mut data2)?;
274 assert_ne!(data, data2);
275 }
276 Ok(())
277 }
278}