Skip to content

Commit b462f53

Browse files
committed
crypto-common: Generate trait
Replaces all of the previous RNG functionality with a `Generate` trait which has the same basic shape as the existing methods, but allows types to impl only `try_from_rng` and receive provided versions of all of the other methods: - `generate`: infallible generation using system RNG with panic on error - `try_generate`: fallible version of above with RNG error `Result`s - `from_rng`: infallible generation with RNG parameter that panics on error The `generate` and `try_generate` methods are available when the `getrandom` feature is enabled. Impls are provided for `hybrid_array::Array<u8, U>`. 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(); The trait is also intended to be impl'd by consuming crates for other key generation use cases, e.g. `RsaPrivateKey`, `dsa::SigningKey`, `ecdsa::SigningKey`, or KEM decapsulation keys.
1 parent b8679f5 commit b462f53

File tree

4 files changed

+139
-152
lines changed

4 files changed

+139
-152
lines changed

crypto-common/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ getrandom = { version = "0.3", optional = true, default-features = false }
2020
rand_core = { version = "0.10.0-rc-2", optional = true }
2121

2222
[features]
23-
getrandom = ["dep:getrandom"]
23+
getrandom = ["rand_core", "dep:getrandom"]
2424
rand_core = ["dep:rand_core"]
2525
zeroize = ["hybrid-array/zeroize"]
2626

crypto-common/src/generate.rs

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

crypto-common/src/lib.rs

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

15-
#[cfg(feature = "getrandom")]
16-
pub use getrandom;
15+
/// Secure random generation using the system's ambient RNG
16+
#[cfg(feature = "rand_core")]
17+
mod generate;
1718

1819
#[cfg(feature = "rand_core")]
19-
pub use rand_core;
20+
pub use {generate::Generate, rand_core};
21+
22+
#[cfg(feature = "getrandom")]
23+
pub use {generate::RngError, getrandom};
2024

2125
pub use hybrid_array as array;
2226
pub use hybrid_array::typenum;
@@ -27,9 +31,6 @@ use hybrid_array::{
2731
typenum::{Diff, Sum, Unsigned},
2832
};
2933

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

@@ -178,35 +179,6 @@ pub trait KeyInit: KeySizeUser + Sized {
178179
.map(Self::new)
179180
.map_err(|_| InvalidLength)
180181
}
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-
}
210182
}
211183

212184
/// Types which can be initialized from key and initialization vector (nonce).
@@ -234,93 +206,6 @@ pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized {
234206
let iv = <&Iv<Self>>::try_from(iv).map_err(|_| InvalidLength)?;
235207
Ok(Self::new(key, iv))
236208
}
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-
}
324209
}
325210

326211
/// Types which can be initialized from another type (usually block ciphers).
@@ -345,35 +230,6 @@ pub trait InnerIvInit: InnerUser + IvSizeUser + Sized {
345230
let iv = <&Iv<Self>>::try_from(iv).map_err(|_| InvalidLength)?;
346231
Ok(Self::inner_iv_init(inner, iv))
347232
}
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-
}
377233
}
378234

379235
/// Trait for loading current IV state.

0 commit comments

Comments
 (0)