Skip to content

Commit 44f54a4

Browse files
committed
crypto-common: FromRng and Generate traits
Replaces all of the previous RNG functionality with traits which map to either a parameterized RNG (using traits from `rand_core`) or the system's ambient RNG (using `getrandom`). Both traits support fallible and infallible operation, with the infallible version provided by the trait. We had previously discussed putting something like this in `hybrid-array`, but I opted not to for a few reasons: 1. Ideally we'd get rid of `hybrid-array` and switch to sufficiently powerful const generics instead, so really it's better if it doesn't have functionality that's equivalent to core arrays 2. Having traits provides a common API for random generation which is reusable across many different types. This implementation provides impls for `hybrid-array` (for `u8`, `u32`, and `u64`), but also core arrays of `[u8; N]` and the core `u32` and `u64` types. 3. The traits are further reusable for a whole host of types in consuming crates, notably `SecretKey`/`SigningKey` types, or KEM decapsulation keys. With this approach we can generate things like symmetric keys and IVs like: type Aes256CbcEnc = cbc::Encryptor<aes::Aes256>; let key = Key::<Aes256CbcEnc>::generate(); let iv = Iv::<Aes256CbcEnc>::generate();
1 parent b8679f5 commit 44f54a4

File tree

3 files changed

+144
-150
lines changed

3 files changed

+144
-150
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
use hybrid_array::{Array, ArraySize};
2+
use rand_core::{CryptoRng, TryCryptoRng};
3+
4+
/// Secure random generation using a provided RNG which impls traits from the [`rand_core`] crate.
5+
pub trait FromCryptoRng: Sized {
6+
/// Generate random key using the provided [`CryptoRng`].
7+
fn from_rng<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
8+
let Ok(ret) = Self::try_from_rng(rng);
9+
ret
10+
}
11+
12+
/// Generate random key using the provided [`TryCryptoRng`].
13+
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error>;
14+
}
15+
16+
impl FromCryptoRng for u32 {
17+
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
18+
rng.try_next_u32()
19+
}
20+
}
21+
22+
impl FromCryptoRng for u64 {
23+
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
24+
rng.try_next_u64()
25+
}
26+
}
27+
28+
impl<const N: usize> FromCryptoRng for [u8; N] {
29+
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
30+
let mut ret = [0u8; N];
31+
rng.try_fill_bytes(&mut ret)?;
32+
Ok(ret)
33+
}
34+
}
35+
36+
impl<U: ArraySize> FromCryptoRng for Array<u8, U> {
37+
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
38+
let mut ret = Self::default();
39+
rng.try_fill_bytes(&mut ret)?;
40+
Ok(ret)
41+
}
42+
}
43+
44+
impl<U: ArraySize> FromCryptoRng for Array<u32, U> {
45+
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
46+
Self::try_from_fn(|_| rng.try_next_u32())
47+
}
48+
}
49+
50+
impl<U: ArraySize> FromCryptoRng for Array<u64, U> {
51+
fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
52+
Self::try_from_fn(|_| rng.try_next_u64())
53+
}
54+
}

crypto-common/src/generate.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use core::fmt;
2+
use hybrid_array::{Array, ArraySize};
3+
4+
/// Secure random generation using the system's ambient RNG.
5+
pub trait Generate: Sized {
6+
/// Randomly generate a value of this type using the system's ambient cryptographically secure
7+
/// random number generator.
8+
///
9+
/// # Panics
10+
/// This method will panic in the event the system's ambient RNG experiences an internal
11+
/// failure.
12+
///
13+
/// This shouldn't happen on most modern operating systems.
14+
fn generate() -> Self {
15+
Self::try_generate().expect("RNG failure")
16+
}
17+
18+
/// Randomly generate a value of this type using the system's ambient cryptographically secure
19+
/// random number generator.
20+
///
21+
/// # Errors
22+
/// Returns [`RngError`] in the event the system's ambient RNG experiences an internal failure.
23+
fn try_generate() -> Result<Self, RngError>;
24+
}
25+
26+
/// Errors occurring internally within the system's ambient cryptographically secure RNG.
27+
// TODO(tarcieri): switch to `getrandom::Error` when it impls `core::error::Error`?
28+
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
29+
pub struct RngError(getrandom::Error);
30+
31+
impl fmt::Display for RngError {
32+
#[inline]
33+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
34+
write!(f, "{}", &self.0)
35+
}
36+
}
37+
38+
impl core::error::Error for RngError {}
39+
40+
impl Generate for u32 {
41+
fn try_generate() -> Result<Self, RngError> {
42+
getrandom::u32().map_err(RngError)
43+
}
44+
}
45+
46+
impl Generate for u64 {
47+
fn try_generate() -> Result<Self, RngError> {
48+
getrandom::u64().map_err(RngError)
49+
}
50+
}
51+
52+
impl<const N: usize> Generate for [u8; N] {
53+
fn try_generate() -> Result<Self, RngError> {
54+
let mut ret = [0u8; N];
55+
getrandom::fill(&mut ret).map_err(RngError)?;
56+
Ok(ret)
57+
}
58+
}
59+
60+
impl<U: ArraySize> Generate for Array<u8, U> {
61+
fn try_generate() -> Result<Self, RngError> {
62+
let mut ret = Self::default();
63+
getrandom::fill(&mut ret).map_err(RngError)?;
64+
Ok(ret)
65+
}
66+
}
67+
68+
impl<U: ArraySize> Generate for Array<u32, U> {
69+
fn try_generate() -> Result<Self, RngError> {
70+
Self::try_from_fn(|_| u32::try_generate())
71+
}
72+
}
73+
74+
impl<U: ArraySize> Generate for Array<u64, U> {
75+
fn try_generate() -> Result<Self, RngError> {
76+
Self::try_from_fn(|_| u64::try_generate())
77+
}
78+
}

crypto-common/src/lib.rs

Lines changed: 12 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@
1212
/// Hazardous materials.
1313
pub mod hazmat;
1414

15+
/// Secure random generation using a provided RNG
16+
#[cfg(feature = "rand_core")]
17+
mod from_crypto_rng;
18+
19+
/// Secure random generation using the system's ambient RNG
1520
#[cfg(feature = "getrandom")]
16-
pub use getrandom;
21+
mod generate;
1722

1823
#[cfg(feature = "rand_core")]
19-
pub use rand_core;
24+
pub use {from_crypto_rng::FromCryptoRng, rand_core};
25+
#[cfg(feature = "getrandom")]
26+
pub use {
27+
generate::{Generate, RngError},
28+
getrandom,
29+
};
2030

2131
pub use hybrid_array as array;
2232
pub use hybrid_array::typenum;
@@ -27,9 +37,6 @@ use hybrid_array::{
2737
typenum::{Diff, Sum, Unsigned},
2838
};
2939

30-
#[cfg(feature = "rand_core")]
31-
use rand_core::{CryptoRng, TryCryptoRng};
32-
3340
/// Block on which [`BlockSizeUser`] implementors operate.
3441
pub type Block<B> = Array<u8, <B as BlockSizeUser>::BlockSize>;
3542

@@ -178,35 +185,6 @@ pub trait KeyInit: KeySizeUser + Sized {
178185
.map(Self::new)
179186
.map_err(|_| InvalidLength)
180187
}
181-
182-
/// Generate random key using the operating system's secure RNG.
183-
#[cfg(feature = "getrandom")]
184-
#[inline]
185-
fn generate_key() -> Result<Key<Self>, getrandom::Error> {
186-
let mut key = Key::<Self>::default();
187-
getrandom::fill(&mut key)?;
188-
Ok(key)
189-
}
190-
191-
/// Generate random key using the provided [`CryptoRng`].
192-
#[cfg(feature = "rand_core")]
193-
#[inline]
194-
fn generate_key_with_rng<R: CryptoRng + ?Sized>(rng: &mut R) -> Key<Self> {
195-
let mut key = Key::<Self>::default();
196-
rng.fill_bytes(&mut key);
197-
key
198-
}
199-
200-
/// Generate random key using the provided [`TryCryptoRng`].
201-
#[cfg(feature = "rand_core")]
202-
#[inline]
203-
fn try_generate_key_with_rng<R: TryCryptoRng + ?Sized>(
204-
rng: &mut R,
205-
) -> Result<Key<Self>, R::Error> {
206-
let mut key = Key::<Self>::default();
207-
rng.try_fill_bytes(&mut key)?;
208-
Ok(key)
209-
}
210188
}
211189

212190
/// Types which can be initialized from key and initialization vector (nonce).
@@ -234,93 +212,6 @@ pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized {
234212
let iv = <&Iv<Self>>::try_from(iv).map_err(|_| InvalidLength)?;
235213
Ok(Self::new(key, iv))
236214
}
237-
238-
/// Generate random key using the operating system's secure RNG.
239-
#[cfg(feature = "getrandom")]
240-
#[inline]
241-
fn generate_key() -> Result<Key<Self>, getrandom::Error> {
242-
let mut key = Key::<Self>::default();
243-
getrandom::fill(&mut key)?;
244-
Ok(key)
245-
}
246-
247-
/// Generate random key using the provided [`CryptoRng`].
248-
#[cfg(feature = "rand_core")]
249-
#[inline]
250-
fn generate_key_with_rng<R: CryptoRng + ?Sized>(rng: &mut R) -> Key<Self> {
251-
let mut key = Key::<Self>::default();
252-
rng.fill_bytes(&mut key);
253-
key
254-
}
255-
256-
/// Generate random key using the provided [`TryCryptoRng`].
257-
#[cfg(feature = "rand_core")]
258-
#[inline]
259-
fn try_generate_key_with_rng<R: TryCryptoRng + ?Sized>(
260-
rng: &mut R,
261-
) -> Result<Key<Self>, R::Error> {
262-
let mut key = Key::<Self>::default();
263-
rng.try_fill_bytes(&mut key)?;
264-
Ok(key)
265-
}
266-
267-
/// Generate random IV using the operating system's secure RNG.
268-
#[cfg(feature = "getrandom")]
269-
#[inline]
270-
fn generate_iv() -> Result<Iv<Self>, getrandom::Error> {
271-
let mut iv = Iv::<Self>::default();
272-
getrandom::fill(&mut iv)?;
273-
Ok(iv)
274-
}
275-
276-
/// Generate random IV using the provided [`CryptoRng`].
277-
#[cfg(feature = "rand_core")]
278-
#[inline]
279-
fn generate_iv_with_rng<R: CryptoRng + ?Sized>(rng: &mut R) -> Iv<Self> {
280-
let mut iv = Iv::<Self>::default();
281-
rng.fill_bytes(&mut iv);
282-
iv
283-
}
284-
285-
/// Generate random IV using the provided [`TryCryptoRng`].
286-
#[cfg(feature = "rand_core")]
287-
#[inline]
288-
fn try_generate_iv_with_rng<R: TryCryptoRng + ?Sized>(
289-
rng: &mut R,
290-
) -> Result<Iv<Self>, R::Error> {
291-
let mut iv = Iv::<Self>::default();
292-
rng.try_fill_bytes(&mut iv)?;
293-
Ok(iv)
294-
}
295-
296-
/// Generate random key and IV using the operating system's secure RNG.
297-
#[cfg(feature = "getrandom")]
298-
#[inline]
299-
fn generate_key_iv() -> Result<(Key<Self>, Iv<Self>), getrandom::Error> {
300-
let key = Self::generate_key()?;
301-
let iv = Self::generate_iv()?;
302-
Ok((key, iv))
303-
}
304-
305-
/// Generate random key and IV using the provided [`CryptoRng`].
306-
#[cfg(feature = "rand_core")]
307-
#[inline]
308-
fn generate_key_iv_with_rng<R: CryptoRng + ?Sized>(rng: &mut R) -> (Key<Self>, Iv<Self>) {
309-
let key = Self::generate_key_with_rng(rng);
310-
let iv = Self::generate_iv_with_rng(rng);
311-
(key, iv)
312-
}
313-
314-
/// Generate random key and IV using the provided [`TryCryptoRng`].
315-
#[cfg(feature = "rand_core")]
316-
#[inline]
317-
fn try_generate_key_iv_with_rng<R: TryCryptoRng + ?Sized>(
318-
rng: &mut R,
319-
) -> Result<(Key<Self>, Iv<Self>), R::Error> {
320-
let key = Self::try_generate_key_with_rng(rng)?;
321-
let iv = Self::try_generate_iv_with_rng(rng)?;
322-
Ok((key, iv))
323-
}
324215
}
325216

326217
/// Types which can be initialized from another type (usually block ciphers).
@@ -345,35 +236,6 @@ pub trait InnerIvInit: InnerUser + IvSizeUser + Sized {
345236
let iv = <&Iv<Self>>::try_from(iv).map_err(|_| InvalidLength)?;
346237
Ok(Self::inner_iv_init(inner, iv))
347238
}
348-
349-
/// Generate random IV using the operating system's secure RNG.
350-
#[cfg(feature = "getrandom")]
351-
#[inline]
352-
fn generate_iv() -> Result<Iv<Self>, getrandom::Error> {
353-
let mut iv = Iv::<Self>::default();
354-
getrandom::fill(&mut iv)?;
355-
Ok(iv)
356-
}
357-
358-
/// Generate random IV using the provided [`CryptoRng`].
359-
#[cfg(feature = "rand_core")]
360-
#[inline]
361-
fn generate_iv_with_rng<R: CryptoRng + ?Sized>(rng: &mut R) -> Iv<Self> {
362-
let mut iv = Iv::<Self>::default();
363-
rng.fill_bytes(&mut iv);
364-
iv
365-
}
366-
367-
/// Generate random IV using the provided [`TryCryptoRng`].
368-
#[cfg(feature = "rand_core")]
369-
#[inline]
370-
fn try_generate_iv_with_rng<R: TryCryptoRng + ?Sized>(
371-
rng: &mut R,
372-
) -> Result<Iv<Self>, R::Error> {
373-
let mut iv = Iv::<Self>::default();
374-
rng.try_fill_bytes(&mut iv)?;
375-
Ok(iv)
376-
}
377239
}
378240

379241
/// Trait for loading current IV state.

0 commit comments

Comments
 (0)