diff --git a/src/errors.rs b/src/errors.rs index 27559556..2a69b38e 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -40,6 +40,9 @@ pub enum Error { /// Invalid coefficient. InvalidCoefficient, + /// Modulus too small. + ModulusTooSmall, + /// Modulus too large. ModulusTooLarge, @@ -94,6 +97,7 @@ impl core::fmt::Display for Error { Error::InvalidModulus => write!(f, "invalid modulus"), Error::InvalidExponent => write!(f, "invalid exponent"), Error::InvalidCoefficient => write!(f, "invalid coefficient"), + Error::ModulusTooSmall => write!(f, "modulus too small"), Error::ModulusTooLarge => write!(f, "modulus too large"), Error::PublicExponentTooSmall => write!(f, "public exponent too small"), Error::PublicExponentTooLarge => write!(f, "public exponent too large"), diff --git a/src/key.rs b/src/key.rs index f2eadc35..9c2aae44 100644 --- a/src/key.rs +++ b/src/key.rs @@ -272,19 +272,62 @@ impl RsaPrivateKey { /// Default exponent for RSA keys. const EXP: u64 = 65537; - /// Generate a new Rsa key pair of the given bit size using the passed in `rng`. - pub fn new(rng: &mut R, bit_size: usize) -> Result { - Self::new_with_exp(rng, bit_size, BoxedUint::from(Self::EXP)) + /// Minimum size of the modulus `n` in bits. Currently only applies to keygen. + const MIN_SIZE: u32 = 1024; + + /// Generate a new RSA key pair with a modulus of the given bit size using the passed in `rng`. + /// + /// # Errors + /// - If `bit_size` is lower than the minimum 1024-bits. + pub fn new(rng: &mut R, bit_size: usize) -> Result { + Self::new_with_exp(rng, bit_size, Self::EXP.into()) + } + + /// Generate a new RSA key pair of the given bit size. + /// + /// #⚠️Warning: Hazmat! + /// This version does not apply minimum key size checks, and as such may generate keys + /// which are insecure! + #[cfg(feature = "hazmat")] + pub fn new_unchecked(rng: &mut R, bit_size: usize) -> Result { + Self::new_with_exp_unchecked(rng, bit_size, Self::EXP.into()) } /// Generate a new RSA key pair of the given bit size and the public exponent /// using the passed in `rng`. /// - /// Unless you have specific needs, you should use `RsaPrivateKey::new` instead. + /// Unless you have specific needs, you should use [`RsaPrivateKey::new`] instead. pub fn new_with_exp( rng: &mut R, bit_size: usize, exp: BoxedUint, + ) -> Result { + if bit_size < Self::MIN_SIZE as usize { + return Err(Error::ModulusTooSmall); + } + + let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?; + RsaPrivateKey::from_components( + components.n.get(), + components.e, + components.d, + components.primes, + ) + } + + /// Generate a new RSA key pair of the given bit size and the public exponent + /// using the passed in `rng`. + /// + /// Unless you have specific needs, you should use [`RsaPrivateKey::new`] instead. + /// + /// #⚠️Warning: Hazmat! + /// This version does not apply minimum key size checks, and as such may generate keys + /// which are insecure! + #[cfg(feature = "hazmat")] + pub fn new_with_exp_unchecked( + rng: &mut R, + bit_size: usize, + exp: BoxedUint, ) -> Result { let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?; RsaPrivateKey::from_components( @@ -821,13 +864,13 @@ mod tests { } #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use serde_test::{assert_tokens, Configure, Token}; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let priv_key = RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"); + let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"); let priv_tokens = [Token::Str(concat!( "3056020100300d06092a864886f70d010101050004423040020100020900a", diff --git a/src/oaep/decrypting_key.rs b/src/oaep/decrypting_key.rs index 70d759bf..ba873899 100644 --- a/src/oaep/decrypting_key.rs +++ b/src/oaep/decrypting_key.rs @@ -98,7 +98,7 @@ where #[cfg(test)] mod tests { #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use super::*; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; @@ -107,7 +107,7 @@ mod tests { let mut rng = ChaCha8Rng::from_seed([42; 32]); let decrypting_key = DecryptingKey::::new( - RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"), + RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"), ); let tokens = [ diff --git a/src/oaep/encrypting_key.rs b/src/oaep/encrypting_key.rs index 60524a21..ee069029 100644 --- a/src/oaep/encrypting_key.rs +++ b/src/oaep/encrypting_key.rs @@ -73,14 +73,15 @@ where mod tests { #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use super::*; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use serde_test::{assert_tokens, Configure, Token}; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"); + let priv_key = + crate::RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"); let encrypting_key = EncryptingKey::::new(priv_key.to_public_key()); let tokens = [ diff --git a/src/pkcs1v15/decrypting_key.rs b/src/pkcs1v15/decrypting_key.rs index f5c36922..1f00d2c1 100644 --- a/src/pkcs1v15/decrypting_key.rs +++ b/src/pkcs1v15/decrypting_key.rs @@ -56,15 +56,16 @@ impl ZeroizeOnDrop for DecryptingKey {} #[cfg(test)] mod tests { #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use super::*; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use serde_test::{assert_tokens, Configure, Token}; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let decrypting_key = - DecryptingKey::new(RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key")); + let decrypting_key = DecryptingKey::new( + RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"), + ); let tokens = [ Token::Struct { diff --git a/src/pkcs1v15/encrypting_key.rs b/src/pkcs1v15/encrypting_key.rs index 0999f88b..f8eef213 100644 --- a/src/pkcs1v15/encrypting_key.rs +++ b/src/pkcs1v15/encrypting_key.rs @@ -30,14 +30,15 @@ impl RandomizedEncryptor for EncryptingKey { #[cfg(test)] mod tests { #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use super::*; + use crate::RsaPrivateKey; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use serde_test::{assert_tokens, Configure, Token}; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"); + let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"); let encrypting_key = EncryptingKey::new(priv_key.to_public_key()); let tokens = [ diff --git a/src/pkcs1v15/signing_key.rs b/src/pkcs1v15/signing_key.rs index 2bb6e72b..222b202a 100644 --- a/src/pkcs1v15/signing_key.rs +++ b/src/pkcs1v15/signing_key.rs @@ -319,15 +319,16 @@ where #[cfg(test)] mod tests { #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use super::*; + use crate::RsaPrivateKey; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use serde_test::{assert_tokens, Configure, Token}; use sha2::Sha256; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"); + let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"); let signing_key = SigningKey::::new(priv_key); let tokens = [Token::Str(concat!( diff --git a/src/pkcs1v15/verifying_key.rs b/src/pkcs1v15/verifying_key.rs index f6150c93..f2f1cf0d 100644 --- a/src/pkcs1v15/verifying_key.rs +++ b/src/pkcs1v15/verifying_key.rs @@ -241,15 +241,16 @@ where #[cfg(test)] mod tests { #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use super::*; + use crate::RsaPrivateKey; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use serde_test::{assert_tokens, Configure, Token}; use sha2::Sha256; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"); + let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"); let pub_key = priv_key.to_public_key(); let verifying_key = VerifyingKey::::new(pub_key); diff --git a/src/pss/blinded_signing_key.rs b/src/pss/blinded_signing_key.rs index 518f0f47..d3439cfb 100644 --- a/src/pss/blinded_signing_key.rs +++ b/src/pss/blinded_signing_key.rs @@ -279,7 +279,7 @@ where #[cfg(test)] mod tests { #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use super::*; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; @@ -288,7 +288,7 @@ mod tests { let mut rng = ChaCha8Rng::from_seed([42; 32]); let signing_key = BlindedSigningKey::::new( - RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"), + RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"), ); let tokens = [Token::Str(concat!( diff --git a/src/pss/signing_key.rs b/src/pss/signing_key.rs index 637c5144..d66a0574 100644 --- a/src/pss/signing_key.rs +++ b/src/pss/signing_key.rs @@ -312,15 +312,16 @@ where #[cfg(test)] mod tests { #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use super::*; + use crate::RsaPrivateKey; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use serde_test::{assert_tokens, Configure, Token}; use sha2::Sha256; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"); + let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"); let signing_key = SigningKey::::new(priv_key); let tokens = [Token::Str(concat!( diff --git a/src/pss/verifying_key.rs b/src/pss/verifying_key.rs index 9303885d..9294330e 100644 --- a/src/pss/verifying_key.rs +++ b/src/pss/verifying_key.rs @@ -236,15 +236,16 @@ where #[cfg(test)] mod tests { #[test] - #[cfg(feature = "serde")] + #[cfg(all(feature = "hazmat", feature = "serde"))] fn test_serde() { use super::*; + use crate::RsaPrivateKey; use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng}; use serde_test::{assert_tokens, Configure, Token}; use sha2::Sha256; let mut rng = ChaCha8Rng::from_seed([42; 32]); - let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"); + let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"); let pub_key = priv_key.to_public_key(); let verifying_key = VerifyingKey::::new(pub_key); diff --git a/tests/proptests.rs b/tests/proptests.rs index eaeeebea..17533ab4 100644 --- a/tests/proptests.rs +++ b/tests/proptests.rs @@ -1,5 +1,7 @@ //! Property-based tests. +#![cfg(feature = "hazmat")] + use proptest::prelude::*; use rand_chacha::ChaCha8Rng; use rand_core::SeedableRng; @@ -14,7 +16,7 @@ prop_compose! { // WARNING: do *NOT* copy and paste this code. It's insecure and optimized for test speed. fn private_key()(seed in any::<[u8; 32]>()) -> RsaPrivateKey { let mut rng = ChaCha8Rng::from_seed(seed); - RsaPrivateKey::new(&mut rng, 512).unwrap() + RsaPrivateKey::new_unchecked(&mut rng, 512).unwrap() } }