Skip to content

Commit d78109e

Browse files
committed
Minimum modulus size checks
Changes the existing checked APIs to respect a minimum modulus size in addition to a maximum one. Note: several tests fail because of this, so we'll need to go through them and convert to an unchecked API where appropriate (or decide if the test is bogus to begin with)
1 parent 472c98d commit d78109e

File tree

2 files changed

+129
-51
lines changed

2 files changed

+129
-51
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: 125 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use alloc::vec::Vec;
22
use core::cmp::Ordering;
33
use core::fmt;
44
use core::hash::{Hash, Hasher};
5+
use core::ops::Range;
56

67
use crypto_bigint::modular::{BoxedMontyForm, BoxedMontyParams};
78
use crypto_bigint::{BoxedUint, Integer, NonZero, Odd, Resize};
@@ -206,29 +207,37 @@ impl RsaPublicKey {
206207
pub fn verify<S: SignatureScheme>(&self, scheme: S, hashed: &[u8], sig: &[u8]) -> Result<()> {
207208
scheme.verify(self, hashed, sig)
208209
}
209-
}
210210

211-
impl RsaPublicKey {
212211
/// Minimum value of the public exponent `e`.
213212
pub const MIN_PUB_EXPONENT: u64 = 2;
214213

215214
/// Maximum value of the public exponent `e`.
216215
pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1;
217216

218-
/// Maximum size of the modulus `n` in bits.
219-
pub const MAX_SIZE: usize = 4096;
217+
/// Default minimum size of the modulus `n` in bits.
218+
pub const MIN_SIZE: u32 = 1024;
219+
220+
/// Default maximum size of the modulus `n` in bits.
221+
pub const MAX_SIZE: u32 = 4096;
220222

221223
/// Create a new public key from its components.
222224
///
223225
/// This function accepts public keys with a modulus size up to 4096-bits,
224226
/// i.e. [`RsaPublicKey::MAX_SIZE`].
225227
pub fn new(n: BoxedUint, e: BoxedUint) -> Result<Self> {
226-
Self::new_with_max_size(n, e, Self::MAX_SIZE)
228+
Self::new_with_size_limits(n, e, Self::MIN_SIZE..Self::MAX_SIZE)
227229
}
228230

229231
/// Create a new public key from its components.
230-
pub fn new_with_max_size(n: BoxedUint, e: BoxedUint, max_size: usize) -> Result<Self> {
231-
check_public_with_max_size(&n, &e, max_size)?;
232+
///
233+
/// Accepts a third argument which specifies a range of allowed sizes from minimum to maximum
234+
/// in bits, which by default is `1024..4096`.
235+
pub fn new_with_size_limits(
236+
n: BoxedUint,
237+
e: BoxedUint,
238+
size_range_bits: Range<u32>,
239+
) -> Result<Self> {
240+
check_public_with_size_limits(&n, &e, size_range_bits)?;
232241

233242
let n_odd = Odd::new(n.clone())
234243
.into_option()
@@ -239,19 +248,30 @@ impl RsaPublicKey {
239248
Ok(Self { n, e, n_params })
240249
}
241250

251+
/// Deprecated: this has been replaced with [`RsaPublicKey::new_with_size_limits`].
252+
#[deprecated(since = "0.10.0", note = "please use `new_with_size_limits` instead")]
253+
pub fn new_with_max_size(n: BoxedUint, e: BoxedUint, max_size: usize) -> Result<Self> {
254+
Self::new_with_size_limits(n, e, Self::MIN_SIZE..(max_size as u32))
255+
}
256+
242257
/// Create a new public key, bypassing checks around the modulus and public
243258
/// exponent size.
244259
///
245260
/// This method is not recommended, and only intended for unusual use cases.
246261
/// Most applications should use [`RsaPublicKey::new`] or
247-
/// [`RsaPublicKey::new_with_max_size`] instead.
262+
/// [`RsaPublicKey::new_with_size_limits`] instead.
248263
pub fn new_unchecked(n: BoxedUint, e: BoxedUint) -> Self {
249264
let n_odd = Odd::new(n.clone()).expect("n must be odd");
250265
let n_params = BoxedMontyParams::new(n_odd);
251266
let n = NonZero::new(n).expect("odd numbers are non zero");
252267

253268
Self { n, e, n_params }
254269
}
270+
271+
/// Get the size of the modulus `n` in bits.
272+
pub fn bits(&self) -> u32 {
273+
self.n.bits_vartime()
274+
}
255275
}
256276

257277
impl PublicKeyParts for RsaPrivateKey {
@@ -309,6 +329,36 @@ impl RsaPrivateKey {
309329
///
310330
/// [NIST SP 800-56B Revision 2]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
311331
pub fn from_components(
332+
n: BoxedUint,
333+
e: BoxedUint,
334+
d: BoxedUint,
335+
primes: Vec<BoxedUint>,
336+
) -> Result<RsaPrivateKey> {
337+
// The primes may come in padded with zeros too, so we need to shorten them as well.
338+
let primes = primes
339+
.into_iter()
340+
.map(|p| {
341+
let p_bits = p.bits();
342+
p.resize_unchecked(p_bits)
343+
})
344+
.collect();
345+
346+
let mut k = Self::from_components_unchecked(n, e, d, primes)?;
347+
348+
// Always validate the key, to ensure precompute can't fail
349+
k.validate()?;
350+
351+
// Precompute when possible, ignore error otherwise.
352+
k.precompute().ok();
353+
354+
Ok(k)
355+
}
356+
357+
/// Constructs an RSA key pair from individual components. Bypasses checks on the key's
358+
/// validity like the modulus size.
359+
///
360+
/// Please use [`RsaPrivateKey::from_components`] whenever possible.
361+
pub fn from_components_unchecked(
312362
n: BoxedUint,
313363
e: BoxedUint,
314364
d: BoxedUint,
@@ -337,8 +387,8 @@ impl RsaPrivateKey {
337387
1 => return Err(Error::NprimesTooSmall),
338388
_ => {
339389
// Check that the product of primes matches the modulus.
340-
// This also ensures that `bit_precision` of each prime is <= that of the modulus,
341-
// and `bit_precision` of their product is >= that of the modulus.
390+
// This also ensures that `bits_precision` of each prime is <= that of the modulus,
391+
// and `bits_precision` of their product is >= that of the modulus.
342392
if &primes.iter().fold(BoxedUint::one(), |acc, p| acc * p) != n_c.as_ref() {
343393
return Err(Error::InvalidModulus);
344394
}
@@ -354,7 +404,7 @@ impl RsaPrivateKey {
354404
})
355405
.collect();
356406

357-
let mut k = RsaPrivateKey {
407+
Ok(RsaPrivateKey {
358408
pubkey_components: RsaPublicKey {
359409
n: n_c,
360410
e,
@@ -363,15 +413,7 @@ impl RsaPrivateKey {
363413
d,
364414
primes,
365415
precomputed: None,
366-
};
367-
368-
// Always validate the key, to ensure precompute can't fail
369-
k.validate()?;
370-
371-
// Precompute when possible, ignore error otherwise.
372-
k.precompute().ok();
373-
374-
Ok(k)
416+
})
375417
}
376418

377419
/// Constructs an RSA key pair from its two primes p and q.
@@ -584,6 +626,11 @@ impl RsaPrivateKey {
584626
) -> Result<Vec<u8>> {
585627
padding.sign(Some(rng), self, digest_in)
586628
}
629+
630+
/// Get the size of the modulus `n` in bits.
631+
pub fn bits(&self) -> u32 {
632+
self.pubkey_components.bits()
633+
}
587634
}
588635

589636
impl PrivateKeyParts for RsaPrivateKey {
@@ -620,16 +667,30 @@ impl PrivateKeyParts for RsaPrivateKey {
620667
}
621668
}
622669

623-
/// Check that the public key is well formed and has an exponent within acceptable bounds.
670+
/// Check that the public key is well-formed and has an exponent within acceptable bounds.
624671
#[inline]
625672
pub fn check_public(public_key: &impl PublicKeyParts) -> Result<()> {
626-
check_public_with_max_size(public_key.n(), public_key.e(), RsaPublicKey::MAX_SIZE)
673+
check_public_with_size_limits(
674+
public_key.n(),
675+
public_key.e(),
676+
RsaPublicKey::MIN_SIZE..RsaPublicKey::MAX_SIZE,
677+
)
627678
}
628679

629-
/// Check that the public key is well formed and has an exponent within acceptable bounds.
680+
/// Check that the public key is well-formed and has an exponent within acceptable bounds.
630681
#[inline]
631-
fn check_public_with_max_size(n: &BoxedUint, e: &BoxedUint, max_size: usize) -> Result<()> {
632-
if n.bits_vartime() as usize > max_size {
682+
fn check_public_with_size_limits(
683+
n: &BoxedUint,
684+
e: &BoxedUint,
685+
size_range_bits: Range<u32>,
686+
) -> Result<()> {
687+
let modulus_bits = n.bits_vartime();
688+
689+
if modulus_bits < size_range_bits.start {
690+
return Err(Error::ModulusTooSmall);
691+
}
692+
693+
if modulus_bits > size_range_bits.end {
633694
return Err(Error::ModulusTooLarge);
634695
}
635696

@@ -732,7 +793,10 @@ mod tests {
732793
}
733794

734795
fn test_key_basics(private_key: &RsaPrivateKey) {
735-
private_key.validate().expect("invalid private key");
796+
// Some test keys have moduli which are smaller than 1024-bits
797+
if private_key.bits() >= RsaPublicKey::MIN_SIZE {
798+
private_key.validate().expect("invalid private key");
799+
}
736800

737801
assert!(
738802
PrivateKeyParts::d(private_key) < PublicKeyParts::n(private_key).as_ref(),
@@ -778,29 +842,17 @@ mod tests {
778842
};
779843
}
780844

781-
key_generation!(key_generation_128, 2, 128);
782845
key_generation!(key_generation_1024, 2, 1024);
783-
784-
key_generation!(key_generation_multi_3_256, 3, 256);
785-
786-
key_generation!(key_generation_multi_4_64, 4, 64);
787-
788-
key_generation!(key_generation_multi_5_64, 5, 64);
789-
key_generation!(key_generation_multi_8_576, 8, 576);
790846
key_generation!(key_generation_multi_16_1024, 16, 1024);
791847

792848
#[test]
793849
fn test_negative_decryption_value() {
794850
let bits = 128;
795-
let private_key = RsaPrivateKey::from_components(
796-
BoxedUint::from_le_slice(
797-
&[
798-
99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180,
799-
],
800-
bits,
801-
)
802-
.unwrap(),
803-
BoxedUint::from_le_slice(&[1, 0, 1, 0, 0, 0, 0, 0], 64).unwrap(),
851+
let private_key = RsaPrivateKey::from_components_unchecked(
852+
BoxedUint::from_le_slice_vartime(&[
853+
99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180,
854+
]),
855+
BoxedUint::from_le_slice_vartime(&[1, 0, 1, 0, 0, 0, 0, 0]),
804856
BoxedUint::from_le_slice(
805857
&[
806858
81, 163, 254, 144, 171, 159, 144, 42, 244, 133, 51, 249, 28, 12, 63, 65,
@@ -827,21 +879,43 @@ mod tests {
827879
use serde_test::{assert_tokens, Configure, Token};
828880

829881
let mut rng = ChaCha8Rng::from_seed([42; 32]);
830-
let priv_key = RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
882+
let priv_key = RsaPrivateKey::new(&mut rng, 1024).expect("failed to generate key");
831883

832884
let priv_tokens = [Token::Str(concat!(
833-
"3056020100300d06092a864886f70d010101050004423040020100020900a",
834-
"b240c3361d02e370203010001020811e54a15259d22f9020500ceff5cf302",
835-
"0500d3a7aaad020500ccaddf17020500cb529d3d020500bb526d6f"
885+
"30820278020100300d06092a864886f70d0101010500048202623082025e0",
886+
"2010002818100cd1419dc3771354bee0955a90489cce0c98aee6577851358",
887+
"afe386a68bc95287862a1157d5aba8847e8e57b6f2f94748ab7efda3f3c74",
888+
"a6702329397ffe0a8f83e2ef5297aa3d9d883cbeb94ee018fd68e986e08d5",
889+
"b044c15e8170217cd57501d42dd72ef691b2a95bcc090d9bca735bba3ecb8",
890+
"38650f13b1aa36d0f454e37ff020301000102818100935c4248cf3df5c21d",
891+
"c56f5c07faccd129813f5481d189d94c69fdb366f6beeacb2927552a2032f",
892+
"321cd3e92237da40f3fcbfc8df6f9d928b3978c1ec8aab23e857a3ba2db26",
893+
"941ace6ecda8dcb290866a80820b3aa9138179ca867d37825ebcdb48adbe7",
894+
"c397f1e77c4160f0fbf87cc0cd5dff195ac96fd333c0b38384c74c1024100",
895+
"e90ad93c4b19bb40807391b5a9404ce5ea359e7b0556ee25cb2e7455aeb5c",
896+
"af83fc26f34457cdbb173347962c66b6fe0c4686b54dbe0d2c913a7aa924e",
897+
"ff5d67024100e148067566a1fa3aabd0672361be62715516c9d62790b03f4",
898+
"326cc00b2f782e6b64a167689e5c9aebe6a4cf594f3083380fe2a0a7edf1f",
899+
"325e58c523b98199a9024100df15fc8924577892b1a4707b178faf4d751c6",
900+
"91ed928b387486eaafd0ee7866a8916c73fa1b979d1f037ee6fa904563033",
901+
"b4c5f2911e328a3c9f87c0d190d1c7024057461ce26c7141cc6af5608f6f7",
902+
"55f13c2c0024f49a29ef4d321fb9425c1076033ac7e094c20ce4239185b5a",
903+
"246b06795576a178d16fc4d9317db859bfaafa8902410084b2d64651b471b",
904+
"f805af14018db693cdab6059063a6aa4eb8f9ca99b319074b79d7dead3d05",
905+
"68c364978be262d3395aa60541d670f94367babebe7616dbc260"
836906
))];
837907
assert_tokens(&priv_key.clone().readable(), &priv_tokens);
838908

839-
let priv_tokens = [Token::Str(
840-
"3024300d06092a864886f70d01010105000313003010020900ab240c3361d02e370203010001",
841-
)];
909+
let pub_tokens = [Token::Str(concat!(
910+
"30819f300d06092a864886f70d010101050003818d0030818902818100cd1419dc3771354bee",
911+
"0955a90489cce0c98aee6577851358afe386a68bc95287862a1157d5aba8847e8e57b6f2f947",
912+
"48ab7efda3f3c74a6702329397ffe0a8f83e2ef5297aa3d9d883cbeb94ee018fd68e986e08d5",
913+
"b044c15e8170217cd57501d42dd72ef691b2a95bcc090d9bca735bba3ecb838650f13b1aa36d",
914+
"0f454e37ff0203010001",
915+
))];
842916
assert_tokens(
843917
&RsaPublicKey::from(priv_key.clone()).readable(),
844-
&priv_tokens,
918+
&pub_tokens,
845919
);
846920
}
847921

0 commit comments

Comments
 (0)