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}