dsa: add TryCryptoRng support (#1367)

This renames the previous `generate` methods to
`try_generate_from_rng_with_key_size` and changes them to accept a
`TryCryptoRng`, returning a `Result` with potential RNG errors.

This helps clear the way for implementing the `Generate` trait from
`crypto-common`, which defines its own `generate` method which takes
no parameters, using the system RNG and default key size.
This commit is contained in:
Tony Arcieri
2026-06-02 15:20:32 -06:00
committed by GitHub
parent c97a63150d
commit 275aea5146
11 changed files with 47 additions and 26 deletions
+2 -1
View File
@@ -7,7 +7,8 @@ use std::{fs::File, io::Write};
fn main() {
let mut rng = rand_core::UnwrapErr(SysRng);
let components = Components::generate(&mut rng, KeySize::DSA_2048_256);
let components =
Components::try_generate_from_rng_with_key_size(&mut rng, KeySize::DSA_2048_256).unwrap();
let signing_key = SigningKey::generate(&mut rng, components);
let verifying_key = signing_key.verifying_key();
+2 -1
View File
@@ -5,7 +5,8 @@ use getrandom::{SysRng, rand_core::UnwrapErr};
fn main() {
let mut rng = UnwrapErr(SysRng);
let components = Components::generate(&mut rng, KeySize::DSA_2048_256);
let components =
Components::try_generate_from_rng_with_key_size(&mut rng, KeySize::DSA_2048_256).unwrap();
let signing_key = SigningKey::generate(&mut rng, components);
let _verifying_key = signing_key.verifying_key();
}
+4 -1
View File
@@ -7,8 +7,11 @@ use signature::{RandomizedDigestSigner, SignatureEncoding};
use std::{fs::File, io::Write};
fn main() {
let components =
Components::try_generate_from_rng_with_key_size(&mut SysRng, KeySize::DSA_2048_256)
.unwrap();
let mut rng = UnwrapErr(SysRng);
let components = Components::generate(&mut rng, KeySize::DSA_2048_256);
let signing_key = SigningKey::generate(&mut rng, components);
let verifying_key = signing_key.verifying_key();
+9 -6
View File
@@ -2,13 +2,13 @@
//! Module containing the definition of the common components container
//!
use crate::{size::KeySize, two};
use crate::{generate, size::KeySize, two};
use crypto_bigint::{BoxedUint, NonZero, Odd};
use der::{
self, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, Tag, Writer,
asn1::UintRef,
};
use signature::rand_core::CryptoRng;
use signature::rand_core::TryCryptoRng;
/// The common components of an DSA keypair
///
@@ -87,10 +87,13 @@ impl Components {
}
/// Generate a new pair of common components
pub fn generate<R: CryptoRng + ?Sized>(rng: &mut R, key_size: KeySize) -> Self {
let (p, q, g) = crate::generate::common_components(rng, key_size);
Self::from_components(p.get(), q.get(), g.get())
.expect("[Bug] Newly generated components considered invalid")
pub fn try_generate_from_rng_with_key_size<R: TryCryptoRng + ?Sized>(
rng: &mut R,
key_size: KeySize,
) -> Result<Self, R::Error> {
let (p, q, g) = generate::common_components(rng, key_size)?;
Ok(Self::from_components(p.get(), q.get(), g.get())
.expect("[Bug] Newly generated components considered invalid"))
}
/// DSA prime p
+4 -3
View File
@@ -1,6 +1,6 @@
use crypto_bigint::{BoxedUint, NonZero, Resize};
use crypto_primes::{Flavor, random_prime};
use signature::rand_core::CryptoRng;
use signature::rand_core::{TryCryptoRng, UnwrapErr};
mod components;
mod keypair;
@@ -33,6 +33,7 @@ fn calculate_bounds(size: u32) -> (NonZero<BoxedUint>, NonZero<BoxedUint>) {
///
/// This wrapper function mainly exists to enforce the [`CryptoRng`](rand::CryptoRng) requirement (I might otherwise forget it)
#[inline]
fn generate_prime<R: CryptoRng + ?Sized>(bit_length: u32, rng: &mut R) -> BoxedUint {
random_prime(rng, Flavor::Any, bit_length)
fn generate_prime<R: TryCryptoRng + ?Sized>(bit_length: u32, rng: &mut R) -> BoxedUint {
let mut rng = UnwrapErr(rng);
random_prime(&mut rng, Flavor::Any, bit_length)
}
+11 -6
View File
@@ -8,11 +8,11 @@ use crate::{
two,
};
use crypto_bigint::{
BoxedUint, ConcatenatingMul, NonZero, Odd, RandomBits, Resize,
BoxedUint, ConcatenatingMul, NonZero, Odd, RandomBits, RandomBitsError, Resize,
modular::{BoxedMontyForm, BoxedMontyParams},
};
use crypto_primes::{Flavor, is_prime};
use signature::rand_core::CryptoRng;
use signature::rand_core::TryCryptoRng;
#[cfg(feature = "hazmat")]
use {crate::Components, crypto_bigint::CtOption};
@@ -22,10 +22,11 @@ use {crate::Components, crypto_bigint::CtOption};
/// # Returns
///
/// Tuple of three `BoxedUint`s. Ordered like this `(p, q, g)`
pub(crate) fn common<R: CryptoRng + ?Sized>(
#[allow(clippy::type_complexity, reason = "internal helper")]
pub(crate) fn common<R: TryCryptoRng + ?Sized>(
rng: &mut R,
KeySize { l, n }: KeySize,
) -> (Odd<BoxedUint>, NonZero<BoxedUint>, NonZero<BoxedUint>) {
) -> Result<(Odd<BoxedUint>, NonZero<BoxedUint>, NonZero<BoxedUint>), R::Error> {
// Calculate the lower and upper bounds of p and q
let (p_min, p_max) = calculate_bounds(l);
let (q_min, q_max): (NonZero<_>, _) = calculate_bounds(n);
@@ -41,7 +42,11 @@ pub(crate) fn common<R: CryptoRng + ?Sized>(
// Attempt to find a prime p which has a subgroup of the order q
for _ in 0..4096 {
let m = 'gen_m: loop {
let m = BoxedUint::random_bits(rng, l);
let m = match BoxedUint::try_random_bits(rng, l) {
Ok(m) => m,
Err(RandomBitsError::RandCore(err)) => return Err(err),
Err(other) => unreachable!("[bug] RNG error: {other}"),
};
if m > *p_min && m < *p_max {
break 'gen_m m;
@@ -82,7 +87,7 @@ pub(crate) fn common<R: CryptoRng + ?Sized>(
let q = q.resize(n);
(p, q, g)
Ok((p, q, g))
}
/// Calculate the public component from the common components and the private component
+8 -4
View File
@@ -14,13 +14,17 @@
//!
#![cfg_attr(feature = "hazmat", doc = "```")]
#![cfg_attr(not(feature = "hazmat"), doc = "```ignore")]
//! # use dsa::{KeySize, Components, SigningKey};
//! use getrandom::{SysRng, rand_core::UnwrapErr};
//! # fn main() -> Result<(), core::convert::Infallible> {
//! use dsa::{KeySize, Components, SigningKey};
//!
//! let mut csprng = UnwrapErr(SysRng);
//! let components = Components::generate(&mut csprng, KeySize::DSA_2048_256);
//! # use getrandom::{SysRng, rand_core::UnwrapErr};
//! # let mut csprng = UnwrapErr(SysRng);
//!
//! let components = Components::try_generate_from_rng_with_key_size(&mut csprng, KeySize::DSA_2048_256)?;
//! let signing_key = SigningKey::generate(&mut csprng, components);
//! let verifying_key = signing_key.verifying_key();
//! # Ok(())
//! # }
//! ```
//!
//! Create keypair from existing components
+1 -1
View File
@@ -20,7 +20,7 @@ prop_compose! {
fn private_key()(seed in any::<[u8; 32]>()) -> SigningKey {
let mut rng = ChaCha8Rng::from_seed(seed);
#[allow(deprecated)]
let components = Components::generate(&mut rng, KeySize::DSA_1024_160);
let components = Components::try_generate_from_rng_with_key_size(&mut rng, KeySize::DSA_1024_160).unwrap();
SigningKey::generate(&mut rng, components)
}
}
+2 -1
View File
@@ -34,7 +34,8 @@ const MESSAGE_SIGNATURE_OPENSSL_ASN1: &[u8] = &hex!(
/// Generate a random DSA keypair
fn generate_random_keypair() -> SigningKey {
let mut rng = UnwrapErr(SysRng);
let components = Components::generate(&mut rng, KeySize::DSA_1024_160);
let components =
Components::try_generate_from_rng_with_key_size(&mut rng, KeySize::DSA_1024_160).unwrap();
SigningKey::generate(&mut rng, components)
}
+2 -1
View File
@@ -18,7 +18,8 @@ const OPENSSL_PEM_PRIVATE_KEY: &str = include_str!("pems/private.pem");
fn generate_keypair() -> SigningKey {
let mut rng = UnwrapErr(SysRng);
let components = Components::generate(&mut rng, KeySize::DSA_1024_160);
let components =
Components::try_generate_from_rng_with_key_size(&mut rng, KeySize::DSA_1024_160).unwrap();
SigningKey::generate(&mut rng, components)
}
+2 -1
View File
@@ -21,7 +21,8 @@ const OPENSSL_PEM_PUBLIC_KEY: &str = include_str!("pems/public.pem");
#[cfg(feature = "hazmat")]
fn generate_verifying_key() -> VerifyingKey {
let mut rng = rand_core::UnwrapErr(SysRng);
let components = Components::generate(&mut rng, KeySize::DSA_1024_160);
let components =
Components::try_generate_from_rng_with_key_size(&mut rng, KeySize::DSA_1024_160).unwrap();
let signing_key = SigningKey::generate(&mut rng, components);
signing_key.verifying_key().clone()