Skip to content

Commit eb1cca7

Browse files
authored
Add minimum bit_size of 1024 to RsaPrivateKey::new (#576)
Also adds a `hazmat`-gated `RsaPrivateKey::new_unchecked` as an escape hatch. Partial step towards addressing #445.
1 parent f5001d1 commit eb1cca7

12 files changed

+82
-26
lines changed

src/errors.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ pub enum Error {
4040
/// Invalid coefficient.
4141
InvalidCoefficient,
4242

43+
/// Modulus too small.
44+
ModulusTooSmall,
45+
4346
/// Modulus too large.
4447
ModulusTooLarge,
4548

@@ -94,6 +97,7 @@ impl core::fmt::Display for Error {
9497
Error::InvalidModulus => write!(f, "invalid modulus"),
9598
Error::InvalidExponent => write!(f, "invalid exponent"),
9699
Error::InvalidCoefficient => write!(f, "invalid coefficient"),
100+
Error::ModulusTooSmall => write!(f, "modulus too small"),
97101
Error::ModulusTooLarge => write!(f, "modulus too large"),
98102
Error::PublicExponentTooSmall => write!(f, "public exponent too small"),
99103
Error::PublicExponentTooLarge => write!(f, "public exponent too large"),

src/key.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -272,19 +272,62 @@ impl RsaPrivateKey {
272272
/// Default exponent for RSA keys.
273273
const EXP: u64 = 65537;
274274

275-
/// Generate a new Rsa key pair of the given bit size using the passed in `rng`.
276-
pub fn new<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<RsaPrivateKey> {
277-
Self::new_with_exp(rng, bit_size, BoxedUint::from(Self::EXP))
275+
/// Minimum size of the modulus `n` in bits. Currently only applies to keygen.
276+
const MIN_SIZE: u32 = 1024;
277+
278+
/// Generate a new RSA key pair with a modulus of the given bit size using the passed in `rng`.
279+
///
280+
/// # Errors
281+
/// - If `bit_size` is lower than the minimum 1024-bits.
282+
pub fn new<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
283+
Self::new_with_exp(rng, bit_size, Self::EXP.into())
284+
}
285+
286+
/// Generate a new RSA key pair of the given bit size.
287+
///
288+
/// #⚠️Warning: Hazmat!
289+
/// This version does not apply minimum key size checks, and as such may generate keys
290+
/// which are insecure!
291+
#[cfg(feature = "hazmat")]
292+
pub fn new_unchecked<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
293+
Self::new_with_exp_unchecked(rng, bit_size, Self::EXP.into())
278294
}
279295

280296
/// Generate a new RSA key pair of the given bit size and the public exponent
281297
/// using the passed in `rng`.
282298
///
283-
/// Unless you have specific needs, you should use `RsaPrivateKey::new` instead.
299+
/// Unless you have specific needs, you should use [`RsaPrivateKey::new`] instead.
284300
pub fn new_with_exp<R: CryptoRng + ?Sized>(
285301
rng: &mut R,
286302
bit_size: usize,
287303
exp: BoxedUint,
304+
) -> Result<RsaPrivateKey> {
305+
if bit_size < Self::MIN_SIZE as usize {
306+
return Err(Error::ModulusTooSmall);
307+
}
308+
309+
let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?;
310+
RsaPrivateKey::from_components(
311+
components.n.get(),
312+
components.e,
313+
components.d,
314+
components.primes,
315+
)
316+
}
317+
318+
/// Generate a new RSA key pair of the given bit size and the public exponent
319+
/// using the passed in `rng`.
320+
///
321+
/// Unless you have specific needs, you should use [`RsaPrivateKey::new`] instead.
322+
///
323+
/// #⚠️Warning: Hazmat!
324+
/// This version does not apply minimum key size checks, and as such may generate keys
325+
/// which are insecure!
326+
#[cfg(feature = "hazmat")]
327+
pub fn new_with_exp_unchecked<R: CryptoRng + ?Sized>(
328+
rng: &mut R,
329+
bit_size: usize,
330+
exp: BoxedUint,
288331
) -> Result<RsaPrivateKey> {
289332
let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?;
290333
RsaPrivateKey::from_components(
@@ -821,13 +864,13 @@ mod tests {
821864
}
822865

823866
#[test]
824-
#[cfg(feature = "serde")]
867+
#[cfg(all(feature = "hazmat", feature = "serde"))]
825868
fn test_serde() {
826869
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
827870
use serde_test::{assert_tokens, Configure, Token};
828871

829872
let mut rng = ChaCha8Rng::from_seed([42; 32]);
830-
let priv_key = RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
873+
let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
831874

832875
let priv_tokens = [Token::Str(concat!(
833876
"3056020100300d06092a864886f70d010101050004423040020100020900a",

src/oaep/decrypting_key.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ where
9898
#[cfg(test)]
9999
mod tests {
100100
#[test]
101-
#[cfg(feature = "serde")]
101+
#[cfg(all(feature = "hazmat", feature = "serde"))]
102102
fn test_serde() {
103103
use super::*;
104104
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
@@ -107,7 +107,7 @@ mod tests {
107107

108108
let mut rng = ChaCha8Rng::from_seed([42; 32]);
109109
let decrypting_key = DecryptingKey::<Sha256>::new(
110-
RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"),
110+
RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"),
111111
);
112112

113113
let tokens = [

src/oaep/encrypting_key.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,15 @@ where
7373
mod tests {
7474

7575
#[test]
76-
#[cfg(feature = "serde")]
76+
#[cfg(all(feature = "hazmat", feature = "serde"))]
7777
fn test_serde() {
7878
use super::*;
7979
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
8080
use serde_test::{assert_tokens, Configure, Token};
8181

8282
let mut rng = ChaCha8Rng::from_seed([42; 32]);
83-
let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
83+
let priv_key =
84+
crate::RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
8485
let encrypting_key = EncryptingKey::<sha2::Sha256>::new(priv_key.to_public_key());
8586

8687
let tokens = [

src/pkcs1v15/decrypting_key.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,15 +56,16 @@ impl ZeroizeOnDrop for DecryptingKey {}
5656
#[cfg(test)]
5757
mod tests {
5858
#[test]
59-
#[cfg(feature = "serde")]
59+
#[cfg(all(feature = "hazmat", feature = "serde"))]
6060
fn test_serde() {
6161
use super::*;
6262
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
6363
use serde_test::{assert_tokens, Configure, Token};
6464

6565
let mut rng = ChaCha8Rng::from_seed([42; 32]);
66-
let decrypting_key =
67-
DecryptingKey::new(RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"));
66+
let decrypting_key = DecryptingKey::new(
67+
RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"),
68+
);
6869

6970
let tokens = [
7071
Token::Struct {

src/pkcs1v15/encrypting_key.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@ impl RandomizedEncryptor for EncryptingKey {
3030
#[cfg(test)]
3131
mod tests {
3232
#[test]
33-
#[cfg(feature = "serde")]
33+
#[cfg(all(feature = "hazmat", feature = "serde"))]
3434
fn test_serde() {
3535
use super::*;
36+
use crate::RsaPrivateKey;
3637
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
3738
use serde_test::{assert_tokens, Configure, Token};
3839

3940
let mut rng = ChaCha8Rng::from_seed([42; 32]);
40-
let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
41+
let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
4142
let encrypting_key = EncryptingKey::new(priv_key.to_public_key());
4243

4344
let tokens = [

src/pkcs1v15/signing_key.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -319,15 +319,16 @@ where
319319
#[cfg(test)]
320320
mod tests {
321321
#[test]
322-
#[cfg(feature = "serde")]
322+
#[cfg(all(feature = "hazmat", feature = "serde"))]
323323
fn test_serde() {
324324
use super::*;
325+
use crate::RsaPrivateKey;
325326
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
326327
use serde_test::{assert_tokens, Configure, Token};
327328
use sha2::Sha256;
328329

329330
let mut rng = ChaCha8Rng::from_seed([42; 32]);
330-
let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
331+
let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
331332
let signing_key = SigningKey::<Sha256>::new(priv_key);
332333

333334
let tokens = [Token::Str(concat!(

src/pkcs1v15/verifying_key.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,15 +241,16 @@ where
241241
#[cfg(test)]
242242
mod tests {
243243
#[test]
244-
#[cfg(feature = "serde")]
244+
#[cfg(all(feature = "hazmat", feature = "serde"))]
245245
fn test_serde() {
246246
use super::*;
247+
use crate::RsaPrivateKey;
247248
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
248249
use serde_test::{assert_tokens, Configure, Token};
249250
use sha2::Sha256;
250251

251252
let mut rng = ChaCha8Rng::from_seed([42; 32]);
252-
let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
253+
let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
253254
let pub_key = priv_key.to_public_key();
254255
let verifying_key = VerifyingKey::<Sha256>::new(pub_key);
255256

src/pss/blinded_signing_key.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ where
279279
#[cfg(test)]
280280
mod tests {
281281
#[test]
282-
#[cfg(feature = "serde")]
282+
#[cfg(all(feature = "hazmat", feature = "serde"))]
283283
fn test_serde() {
284284
use super::*;
285285
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
@@ -288,7 +288,7 @@ mod tests {
288288

289289
let mut rng = ChaCha8Rng::from_seed([42; 32]);
290290
let signing_key = BlindedSigningKey::<Sha256>::new(
291-
RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key"),
291+
RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key"),
292292
);
293293

294294
let tokens = [Token::Str(concat!(

src/pss/signing_key.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,15 +312,16 @@ where
312312
#[cfg(test)]
313313
mod tests {
314314
#[test]
315-
#[cfg(feature = "serde")]
315+
#[cfg(all(feature = "hazmat", feature = "serde"))]
316316
fn test_serde() {
317317
use super::*;
318+
use crate::RsaPrivateKey;
318319
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
319320
use serde_test::{assert_tokens, Configure, Token};
320321
use sha2::Sha256;
321322

322323
let mut rng = ChaCha8Rng::from_seed([42; 32]);
323-
let priv_key = crate::RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
324+
let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
324325
let signing_key = SigningKey::<Sha256>::new(priv_key);
325326

326327
let tokens = [Token::Str(concat!(

0 commit comments

Comments
 (0)