diff --git a/.github/workflows/crypto-common.yml b/.github/workflows/crypto-common.yml index 3d93597e..3d7b5142 100644 --- a/.github/workflows/crypto-common.yml +++ b/.github/workflows/crypto-common.yml @@ -41,10 +41,11 @@ jobs: targets: ${{ matrix.target }} - run: cargo build --target ${{ matrix.target }} - minimal-versions: - uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master - with: - working-directory: ${{ github.workflow }} + # TODO(tarcieri): re-enable when `getrandom` has a crate release with `sys_rng` + # minimal-versions: + # uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master + # with: + # working-directory: ${{ github.workflow }} test: runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 773cb084..3ca9a67b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -212,12 +212,12 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "getrandom" version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +source = "git+https://github.com/rust-random/getrandom#6cbbcb4a434f918a9a54bede9694f8138df2856d" dependencies = [ "cfg-if", "libc", "r-efi", + "rand_core", "wasip2", ] diff --git a/Cargo.toml b/Cargo.toml index f89b4edc..408b9a7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,3 +16,5 @@ members = [ [patch.crates-io] digest = { path = "digest" } signature = { path = "signature" } + +getrandom = { git = "https://github.com/rust-random/getrandom" } diff --git a/crypto-common/CHANGELOG.md b/crypto-common/CHANGELOG.md index 8f7460b4..662e027a 100644 --- a/crypto-common/CHANGELOG.md +++ b/crypto-common/CHANGELOG.md @@ -8,12 +8,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## 0.2.0 (UNRELEASED) ### Added - Sealed `BlockSizes` trait implemented for types from `U1` to `U255` +- `Generate` trait ([#2096]) ### Changed - `BlockUser::BlockSize` is now bounded by the `BlockSizes` trait - Edition changed to 2024 and MSRV bumped to 1.85 ([#1759]) +### Removed +- `generate_*` and `try_generate_*` methods from KeyInit and KeyIvInit traits. + See the newly added Generate trait for replacement ([#2096]) + [#1759]: https://github.com/RustCrypto/traits/pull/1759 +[#2096]: https://github.com/RustCrypto/traits/pull/2096 ## 0.1.7 (2025-11-12) ### Changed diff --git a/crypto-common/Cargo.toml b/crypto-common/Cargo.toml index 58491d63..6b670749 100644 --- a/crypto-common/Cargo.toml +++ b/crypto-common/Cargo.toml @@ -16,11 +16,11 @@ description = "Common cryptographic traits" hybrid-array = "0.4" # optional dependencies -getrandom = { version = "0.3", optional = true, default-features = false } +getrandom = { version = "0.3", optional = true, features = ["sys_rng"] } rand_core = { version = "0.10.0-rc-2", optional = true } [features] -getrandom = ["dep:getrandom"] +getrandom = ["rand_core", "dep:getrandom"] rand_core = ["dep:rand_core"] zeroize = ["hybrid-array/zeroize"] diff --git a/crypto-common/src/generate.rs b/crypto-common/src/generate.rs new file mode 100644 index 00000000..bc302328 --- /dev/null +++ b/crypto-common/src/generate.rs @@ -0,0 +1,86 @@ +use hybrid_array::{Array, ArraySize}; +use rand_core::{CryptoRng, TryCryptoRng}; + +#[cfg(feature = "getrandom")] +use crate::RngError; + +/// Secure random generation. +pub trait Generate: Sized { + /// Generate random key using the provided [`TryCryptoRng`]. + fn try_from_rng(rng: &mut R) -> Result; + + /// Generate random key using the provided [`CryptoRng`]. + fn from_rng(rng: &mut R) -> Self { + let Ok(ret) = Self::try_from_rng(rng); + ret + } + + /// Randomly generate a value of this type using the system's ambient cryptographically secure + /// random number generator. + /// + /// # Errors + /// Returns [`RngError`] in the event the system's ambient RNG experiences an internal failure. + #[cfg(feature = "getrandom")] + fn try_generate() -> Result { + Self::try_from_rng(&mut getrandom::SysRng) + } + + /// Randomly generate a value of this type using the system's ambient cryptographically secure + /// random number generator. + /// + /// # Panics + /// This method will panic in the event the system's ambient RNG experiences an internal + /// failure. + /// + /// This shouldn't happen on most modern operating systems. + #[cfg(feature = "getrandom")] + fn generate() -> Self { + Self::try_generate().expect("RNG failure") + } +} + +impl Generate for u32 { + #[inline] + fn try_from_rng(rng: &mut R) -> Result { + rng.try_next_u32() + } +} + +impl Generate for u64 { + #[inline] + fn try_from_rng(rng: &mut R) -> Result { + rng.try_next_u64() + } +} + +impl Generate for [u8; N] { + #[inline] + fn try_from_rng(rng: &mut R) -> Result { + let mut ret = [0u8; N]; + rng.try_fill_bytes(&mut ret)?; + Ok(ret) + } +} + +impl Generate for Array { + #[inline] + fn try_from_rng(rng: &mut R) -> Result { + let mut ret = Self::default(); + rng.try_fill_bytes(&mut ret)?; + Ok(ret) + } +} + +impl Generate for Array { + #[inline] + fn try_from_rng(rng: &mut R) -> Result { + Self::try_from_fn(|_| rng.try_next_u32()) + } +} + +impl Generate for Array { + #[inline] + fn try_from_rng(rng: &mut R) -> Result { + Self::try_from_fn(|_| rng.try_next_u64()) + } +} diff --git a/crypto-common/src/lib.rs b/crypto-common/src/lib.rs index bb6d4758..929f660c 100644 --- a/crypto-common/src/lib.rs +++ b/crypto-common/src/lib.rs @@ -12,24 +12,24 @@ /// Hazardous materials. pub mod hazmat; -#[cfg(feature = "getrandom")] -pub use getrandom; - +/// Secure random generation. #[cfg(feature = "rand_core")] -pub use rand_core; +mod generate; pub use hybrid_array as array; pub use hybrid_array::typenum; +#[cfg(feature = "rand_core")] +pub use {generate::Generate, rand_core}; +#[cfg(feature = "getrandom")] +pub use {getrandom, getrandom::Error as RngError}; + use core::fmt; use hybrid_array::{ Array, ArraySize, typenum::{Diff, Sum, Unsigned}, }; -#[cfg(feature = "rand_core")] -use rand_core::{CryptoRng, TryCryptoRng}; - /// Block on which [`BlockSizeUser`] implementors operate. pub type Block = Array::BlockSize>; @@ -178,35 +178,6 @@ pub trait KeyInit: KeySizeUser + Sized { .map(Self::new) .map_err(|_| InvalidLength) } - - /// Generate random key using the operating system's secure RNG. - #[cfg(feature = "getrandom")] - #[inline] - fn generate_key() -> Result, getrandom::Error> { - let mut key = Key::::default(); - getrandom::fill(&mut key)?; - Ok(key) - } - - /// Generate random key using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn generate_key_with_rng(rng: &mut R) -> Key { - let mut key = Key::::default(); - rng.fill_bytes(&mut key); - key - } - - /// Generate random key using the provided [`TryCryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn try_generate_key_with_rng( - rng: &mut R, - ) -> Result, R::Error> { - let mut key = Key::::default(); - rng.try_fill_bytes(&mut key)?; - Ok(key) - } } /// Types which can be initialized from key and initialization vector (nonce). @@ -234,93 +205,6 @@ pub trait KeyIvInit: KeySizeUser + IvSizeUser + Sized { let iv = <&Iv>::try_from(iv).map_err(|_| InvalidLength)?; Ok(Self::new(key, iv)) } - - /// Generate random key using the operating system's secure RNG. - #[cfg(feature = "getrandom")] - #[inline] - fn generate_key() -> Result, getrandom::Error> { - let mut key = Key::::default(); - getrandom::fill(&mut key)?; - Ok(key) - } - - /// Generate random key using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn generate_key_with_rng(rng: &mut R) -> Key { - let mut key = Key::::default(); - rng.fill_bytes(&mut key); - key - } - - /// Generate random key using the provided [`TryCryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn try_generate_key_with_rng( - rng: &mut R, - ) -> Result, R::Error> { - let mut key = Key::::default(); - rng.try_fill_bytes(&mut key)?; - Ok(key) - } - - /// Generate random IV using the operating system's secure RNG. - #[cfg(feature = "getrandom")] - #[inline] - fn generate_iv() -> Result, getrandom::Error> { - let mut iv = Iv::::default(); - getrandom::fill(&mut iv)?; - Ok(iv) - } - - /// Generate random IV using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn generate_iv_with_rng(rng: &mut R) -> Iv { - let mut iv = Iv::::default(); - rng.fill_bytes(&mut iv); - iv - } - - /// Generate random IV using the provided [`TryCryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn try_generate_iv_with_rng( - rng: &mut R, - ) -> Result, R::Error> { - let mut iv = Iv::::default(); - rng.try_fill_bytes(&mut iv)?; - Ok(iv) - } - - /// Generate random key and IV using the operating system's secure RNG. - #[cfg(feature = "getrandom")] - #[inline] - fn generate_key_iv() -> Result<(Key, Iv), getrandom::Error> { - let key = Self::generate_key()?; - let iv = Self::generate_iv()?; - Ok((key, iv)) - } - - /// Generate random key and IV using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn generate_key_iv_with_rng(rng: &mut R) -> (Key, Iv) { - let key = Self::generate_key_with_rng(rng); - let iv = Self::generate_iv_with_rng(rng); - (key, iv) - } - - /// Generate random key and IV using the provided [`TryCryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn try_generate_key_iv_with_rng( - rng: &mut R, - ) -> Result<(Key, Iv), R::Error> { - let key = Self::try_generate_key_with_rng(rng)?; - let iv = Self::try_generate_iv_with_rng(rng)?; - Ok((key, iv)) - } } /// Types which can be initialized from another type (usually block ciphers). @@ -345,35 +229,6 @@ pub trait InnerIvInit: InnerUser + IvSizeUser + Sized { let iv = <&Iv>::try_from(iv).map_err(|_| InvalidLength)?; Ok(Self::inner_iv_init(inner, iv)) } - - /// Generate random IV using the operating system's secure RNG. - #[cfg(feature = "getrandom")] - #[inline] - fn generate_iv() -> Result, getrandom::Error> { - let mut iv = Iv::::default(); - getrandom::fill(&mut iv)?; - Ok(iv) - } - - /// Generate random IV using the provided [`CryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn generate_iv_with_rng(rng: &mut R) -> Iv { - let mut iv = Iv::::default(); - rng.fill_bytes(&mut iv); - iv - } - - /// Generate random IV using the provided [`TryCryptoRng`]. - #[cfg(feature = "rand_core")] - #[inline] - fn try_generate_iv_with_rng( - rng: &mut R, - ) -> Result, R::Error> { - let mut iv = Iv::::default(); - rng.try_fill_bytes(&mut iv)?; - Ok(iv) - } } /// Trait for loading current IV state.