1#[cfg(feature = "alloc")]
2use alloc::vec::Vec;
3use core::cmp::Ordering;
4use core::fmt;
5use core::hash::{Hash, Hasher};
6
7#[cfg(feature = "alloc")]
8use crypto_bigint::Resize as _;
9#[cfg(feature = "alloc")]
10use crypto_bigint::{
11 modular::{BoxedMontyForm, BoxedMontyParams},
12 BoxedUint, ConcatenatingMul, Integer,
13};
14#[cfg(feature = "alloc")]
15use crypto_bigint::{NonZero as CryptoNonZero, Odd as CryptoOdd};
16
17use rand_core::CryptoRng;
18use zeroize::{Zeroize, ZeroizeOnDrop};
19#[cfg(feature = "serde")]
20use {
21 pkcs8::{DecodePrivateKey, EncodePrivateKey},
22 serdect::serde::{de, ser, Deserialize, Serialize},
23 spki::{DecodePublicKey, EncodePublicKey},
24};
25
26#[cfg(feature = "private-key")]
27use crate::algorithms::generate::generate_multi_prime_key_with_exp;
28#[cfg(feature = "private-key")]
29use crate::algorithms::rsa::{
30 compute_modulus, compute_private_exponent_carmicheal, compute_private_exponent_euler_totient,
31 recover_primes,
32};
33
34#[cfg(feature = "private-key")]
35use crate::dummy_rng::DummyRng;
36use crate::errors::{Error, Result};
37use crate::traits::keys::PublicKeyParts;
38#[cfg(feature = "private-key")]
39use crate::traits::keys::{CrtValue, PrivateKeyParts};
40use crate::traits::{
41 modular::ModulusParams, NonZero, PaddingScheme, SignatureScheme, UnsignedModularInt,
42};
43
44#[derive(Debug, Clone)]
46pub struct GenericRsaPublicKey<T, M>
47where
48 T: UnsignedModularInt,
49 M: ModulusParams<Modulus = T>,
50{
51 n: NonZero<T>,
53 e: T,
58
59 n_params: M,
60}
61
62#[cfg(feature = "alloc")]
65pub type RsaPublicKey = GenericRsaPublicKey<BoxedUint, BoxedMontyParams>;
66
67impl<T, M> Eq for GenericRsaPublicKey<T, M>
68where
69 T: UnsignedModularInt + Eq,
70 M: ModulusParams<Modulus = T>,
71{
72}
73
74impl<T, M> PartialEq for GenericRsaPublicKey<T, M>
75where
76 T: UnsignedModularInt + PartialEq,
77 M: ModulusParams<Modulus = T>,
78{
79 #[inline]
80 fn eq(&self, other: &GenericRsaPublicKey<T, M>) -> bool {
81 self.n == other.n && self.e == other.e
82 }
83}
84
85impl<T, M> Hash for GenericRsaPublicKey<T, M>
86where
87 T: UnsignedModularInt,
88 M: ModulusParams<Modulus = T>,
89{
90 fn hash<H: Hasher>(&self, state: &mut H) {
91 state.write(b"RsaPublicKey");
93 state.write(self.n.as_ref().to_be_bytes().as_ref());
95 state.write(self.e.to_be_bytes().as_ref());
96 }
97}
98
99#[cfg(feature = "private-key")]
101#[derive(Clone)]
102pub struct RsaPrivateKey {
103 pubkey_components: RsaPublicKey,
105 pub(crate) d: BoxedUint,
107 pub(crate) primes: Vec<BoxedUint>,
109 pub(crate) precomputed: Option<PrecomputedValues>,
111}
112
113#[cfg(feature = "private-key")]
114impl fmt::Debug for RsaPrivateKey {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 let precomputed = if self.precomputed.is_some() {
117 "Some(...)"
118 } else {
119 "None"
120 };
121 f.debug_struct("RsaPrivateKey")
122 .field("pubkey_components", &self.pubkey_components)
123 .field("d", &"...")
124 .field("primes", &"&[...]")
125 .field("precomputed", &precomputed)
126 .finish()
127 }
128}
129
130#[cfg(feature = "private-key")]
131impl Eq for RsaPrivateKey {}
132#[cfg(feature = "private-key")]
133impl PartialEq for RsaPrivateKey {
134 #[inline]
135 fn eq(&self, other: &RsaPrivateKey) -> bool {
136 self.pubkey_components == other.pubkey_components
137 && self.d == other.d
138 && self.primes == other.primes
139 }
140}
141
142#[cfg(feature = "private-key")]
143impl AsRef<RsaPublicKey> for RsaPrivateKey {
144 fn as_ref(&self) -> &RsaPublicKey {
145 &self.pubkey_components
146 }
147}
148
149#[cfg(feature = "private-key")]
150impl Hash for RsaPrivateKey {
151 fn hash<H: Hasher>(&self, state: &mut H) {
152 state.write(b"RsaPrivateKey");
154 Hash::hash(&self.pubkey_components, state);
155 }
156}
157
158#[cfg(feature = "private-key")]
159impl Drop for RsaPrivateKey {
160 fn drop(&mut self) {
161 self.d.zeroize();
162 self.primes.zeroize();
163 self.precomputed.zeroize();
164 }
165}
166
167#[cfg(feature = "private-key")]
168impl ZeroizeOnDrop for RsaPrivateKey {}
169
170#[cfg(feature = "private-key")]
171#[derive(Clone)]
172pub(crate) struct PrecomputedValues {
173 pub(crate) dp: BoxedUint,
175 pub(crate) dq: BoxedUint,
177 pub(crate) qinv: BoxedMontyForm,
179
180 pub(crate) p_params: BoxedMontyParams,
182 pub(crate) q_params: BoxedMontyParams,
184}
185
186#[cfg(feature = "private-key")]
187impl ZeroizeOnDrop for PrecomputedValues {}
188
189#[cfg(feature = "private-key")]
190impl Zeroize for PrecomputedValues {
191 fn zeroize(&mut self) {
192 self.dp.zeroize();
193 self.dq.zeroize();
194 }
198}
199
200#[cfg(feature = "private-key")]
201impl Drop for PrecomputedValues {
202 fn drop(&mut self) {
203 self.zeroize();
204 }
205}
206
207#[cfg(feature = "private-key")]
208impl From<RsaPrivateKey> for GenericRsaPublicKey<BoxedUint, BoxedMontyParams> {
209 fn from(private_key: RsaPrivateKey) -> Self {
210 (&private_key).into()
211 }
212}
213
214#[cfg(feature = "private-key")]
215impl From<&RsaPrivateKey> for GenericRsaPublicKey<BoxedUint, BoxedMontyParams> {
216 fn from(private_key: &RsaPrivateKey) -> Self {
217 let public_key: &dyn PublicKeyParts<BoxedUint, MontyParams = BoxedMontyParams> =
218 private_key;
219 GenericRsaPublicKey {
220 n: public_key.n().clone(),
221 e: public_key.e().clone(),
222 n_params: public_key.n_params().clone(),
223 }
224 }
225}
226
227impl<T, M> PublicKeyParts<T> for GenericRsaPublicKey<T, M>
228where
229 T: UnsignedModularInt,
230 M: ModulusParams<Modulus = T>,
231{
232 type MontyParams = M;
233
234 fn n(&self) -> &NonZero<T> {
235 &self.n
236 }
237
238 fn e(&self) -> &T {
239 &self.e
240 }
241
242 fn n_params(&self) -> &M {
243 &self.n_params
244 }
245}
246
247impl<T, M> GenericRsaPublicKey<T, M>
248where
249 T: UnsignedModularInt,
250 M: ModulusParams<Modulus = T>,
251{
252 pub fn from_components(n: T, e: T, n_params: M) -> Result<Self> {
257 let n = NonZero::new(n).ok_or(Error::InvalidModulus)?;
258 Ok(Self { n, e, n_params })
259 }
260}
261
262impl<T, M> GenericRsaPublicKey<T, M>
263where
264 T: UnsignedModularInt,
265 M: ModulusParams<Modulus = T>,
266{
267 #[cfg(feature = "alloc")]
269 pub fn encrypt<R: CryptoRng + ?Sized, P: PaddingScheme>(
270 &self,
271 rng: &mut R,
272 padding: P,
273 msg: &[u8],
274 ) -> Result<Vec<u8>> {
275 padding.encrypt(rng, self, msg)
276 }
277
278 pub fn verify<S: SignatureScheme>(&self, scheme: S, hashed: &[u8], sig: &[u8]) -> Result<()> {
285 scheme.verify(self, hashed, sig)
286 }
287}
288
289#[cfg(feature = "alloc")]
290impl GenericRsaPublicKey<BoxedUint, BoxedMontyParams> {
291 pub const MIN_PUB_EXPONENT: u64 = 2;
293
294 pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1;
311
312 pub const MAX_SIZE: usize = 8192;
314
315 pub fn new(n: BoxedUint, e: BoxedUint) -> Result<Self> {
320 Self::new_with_max_size(n, e, Self::MAX_SIZE)
321 }
322
323 pub fn new_with_max_size(n: BoxedUint, e: BoxedUint, max_size: usize) -> Result<Self> {
325 check_public_with_max_size(&n, &e, Some(max_size))?;
326
327 let n_odd = CryptoOdd::new(n.clone())
328 .into_option()
329 .ok_or(Error::InvalidModulus)?;
330 let n_params = BoxedMontyParams::new(n_odd);
331 let n = NonZero::new(n).expect("checked above");
332
333 Ok(Self { n, e, n_params })
334 }
335
336 pub fn new_unchecked(n: BoxedUint, e: BoxedUint) -> Self {
343 let n_odd = CryptoOdd::new(n.clone()).expect("n must be odd");
344 let n_params = BoxedMontyParams::new(n_odd);
345 let n = NonZero::new(n).expect("odd numbers are non zero");
346
347 Self { n, e, n_params }
348 }
349}
350
351#[cfg(feature = "private-key")]
352impl PublicKeyParts<BoxedUint> for RsaPrivateKey {
353 type MontyParams = BoxedMontyParams;
354
355 fn n(&self) -> &NonZero<BoxedUint> {
356 &self.pubkey_components.n
357 }
358
359 fn e(&self) -> &BoxedUint {
360 &self.pubkey_components.e
361 }
362
363 fn n_params(&self) -> &BoxedMontyParams {
364 &self.pubkey_components.n_params
365 }
366}
367
368#[cfg(feature = "private-key")]
369impl RsaPrivateKey {
370 const EXP: u64 = 65537;
372
373 const MIN_SIZE: u32 = 1024;
375
376 pub fn new<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
381 Self::new_with_exp(rng, bit_size, Self::EXP.into())
382 }
383
384 #[cfg(feature = "hazmat")]
390 pub fn new_unchecked<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
391 Self::new_with_exp_unchecked(rng, bit_size, Self::EXP.into())
392 }
393
394 pub fn new_with_exp<R: CryptoRng + ?Sized>(
399 rng: &mut R,
400 bit_size: usize,
401 exp: BoxedUint,
402 ) -> Result<RsaPrivateKey> {
403 if bit_size < Self::MIN_SIZE as usize {
404 return Err(Error::ModulusTooSmall);
405 }
406
407 let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?;
408 RsaPrivateKey::from_components(
409 components.n.get(),
410 components.e,
411 components.d,
412 components.primes,
413 )
414 }
415
416 #[cfg(feature = "hazmat")]
425 pub fn new_with_exp_unchecked<R: CryptoRng + ?Sized>(
426 rng: &mut R,
427 bit_size: usize,
428 exp: BoxedUint,
429 ) -> Result<RsaPrivateKey> {
430 let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?;
431 RsaPrivateKey::from_components(
432 components.n.get(),
433 components.e,
434 components.d,
435 components.primes,
436 )
437 }
438
439 fn from_components_inner(
449 n: BoxedUint,
450 e: BoxedUint,
451 d: BoxedUint,
452 mut primes: Vec<BoxedUint>,
453 ) -> Result<RsaPrivateKey> {
454 let n = CryptoOdd::new(n)
455 .into_option()
456 .ok_or(Error::InvalidModulus)?;
457
458 let n_bits = n.bits_vartime();
461 let n = n.resize_unchecked(n_bits);
462
463 let n_params = BoxedMontyParams::new(n.clone());
464 let n_c = NonZero::new(n.get()).ok_or(Error::InvalidModulus)?;
465
466 match primes.len() {
467 0 => {
468 let n_for_recovery =
471 CryptoNonZero::new(n_c.as_ref().clone()).expect("modulus is non-zero");
472 let (p, q) = recover_primes(&n_for_recovery, &e, &d)?;
473 primes.push(p);
474 primes.push(q);
475 }
476 1 => return Err(Error::NprimesTooSmall),
477 _ => {
478 if primes
482 .iter()
483 .fold(BoxedUint::one(), |acc, p| acc.concatenating_mul(&p))
484 != n_c.as_ref()
485 {
486 return Err(Error::InvalidModulus);
487 }
488 }
489 }
490
491 let primes = primes
493 .into_iter()
494 .map(|p| {
495 let p_bits = p.bits();
496 p.resize_unchecked(p_bits)
497 })
498 .collect();
499
500 let k = RsaPrivateKey {
501 pubkey_components: RsaPublicKey {
502 n: n_c,
503 e,
504 n_params,
505 },
506 d,
507 primes,
508 precomputed: None,
509 };
510
511 Ok(k)
512 }
513
514 #[cfg(all(feature = "hazmat", feature = "private-key"))]
532 pub fn from_components_with_large_exponent(
533 n: BoxedUint,
534 e: BoxedUint,
535 d: BoxedUint,
536 primes: Vec<BoxedUint>,
537 ) -> Result<RsaPrivateKey> {
538 let mut k = Self::from_components_inner(n, e, d, primes)?;
539
540 validate_skip_exponent_size(&k)?;
542
543 k.precompute().ok();
545
546 Ok(k)
547 }
548
549 pub fn from_components(
563 n: BoxedUint,
564 e: BoxedUint,
565 d: BoxedUint,
566 primes: Vec<BoxedUint>,
567 ) -> Result<RsaPrivateKey> {
568 let mut k = Self::from_components_inner(n, e, d, primes)?;
569
570 k.validate()?;
572
573 k.precompute().ok();
575
576 Ok(k)
577 }
578
579 pub fn from_p_q(
586 p: BoxedUint,
587 q: BoxedUint,
588 public_exponent: BoxedUint,
589 ) -> Result<RsaPrivateKey> {
590 if p == q {
591 return Err(Error::InvalidPrime);
592 }
593
594 let d = compute_private_exponent_carmicheal(&p, &q, &public_exponent)?;
595 let primes = vec![p, q];
596 let n = compute_modulus(&primes);
597
598 Self::from_components(n.get(), public_exponent, d, primes)
599 }
600
601 pub fn from_primes(
605 primes: Vec<BoxedUint>,
606 public_exponent: BoxedUint,
607 ) -> Result<RsaPrivateKey> {
608 if primes.len() < 2 {
609 return Err(Error::NprimesTooSmall);
610 }
611
612 for (i, prime1) in primes.iter().enumerate() {
614 for prime2 in primes.iter().take(i) {
615 if prime1 == prime2 {
616 return Err(Error::InvalidPrime);
617 }
618 }
619 }
620
621 let n = compute_modulus(&primes);
622 let d = compute_private_exponent_euler_totient(&primes, &public_exponent)?;
623
624 Self::from_components(n.get(), public_exponent, d, primes)
625 }
626
627 pub fn as_public_key(&self) -> &RsaPublicKey {
631 &self.pubkey_components
632 }
633
634 pub fn to_public_key(&self) -> RsaPublicKey {
639 self.pubkey_components.clone()
640 }
641
642 pub fn precompute(&mut self) -> Result<()> {
644 if self.precomputed.is_some() {
645 return Ok(());
646 }
647
648 let d = &self.d;
649 let p = self.primes[0].clone();
650 let q = self.primes[1].clone();
651
652 let p_odd = CryptoOdd::new(p.clone())
653 .into_option()
654 .ok_or(Error::InvalidPrime)?;
655 let p_params = BoxedMontyParams::new(p_odd);
656 let q_odd = CryptoOdd::new(q.clone())
657 .into_option()
658 .ok_or(Error::InvalidPrime)?;
659 let q_params = BoxedMontyParams::new(q_odd);
660
661 let x = CryptoNonZero::new(p.wrapping_sub(BoxedUint::one()))
662 .into_option()
663 .ok_or(Error::InvalidPrime)?;
664 let dp = d.rem_vartime(&x);
665
666 let x = CryptoNonZero::new(q.wrapping_sub(BoxedUint::one()))
667 .into_option()
668 .ok_or(Error::InvalidPrime)?;
669 let dq = d.rem_vartime(&x);
670
671 let q_mod_p = match p.bits_precision().cmp(&q.bits_precision()) {
674 Ordering::Less => {
675 let p_wide = CryptoNonZero::new(p.clone())
676 .expect("`p` is non-zero")
677 .resize_unchecked(q.bits_precision());
678 (&q % p_wide).resize_unchecked(p.bits_precision())
679 }
680 Ordering::Greater => {
681 (&q).resize_unchecked(p.bits_precision())
682 % &CryptoNonZero::new(p.clone()).expect("`p` is non-zero")
683 }
684 Ordering::Equal => &q % CryptoNonZero::new(p.clone()).expect("`p` is non-zero"),
685 };
686
687 let q_mod_p = BoxedMontyForm::new(q_mod_p, &p_params);
688 let qinv = q_mod_p.invert().into_option().ok_or(Error::InvalidPrime)?;
689
690 debug_assert_eq!(dp.bits_precision(), p.bits_precision());
691 debug_assert_eq!(dq.bits_precision(), q.bits_precision());
692 debug_assert_eq!(qinv.bits_precision(), p.bits_precision());
693 debug_assert_eq!(p_params.bits_precision(), p.bits_precision());
694 debug_assert_eq!(q_params.bits_precision(), q.bits_precision());
695
696 self.precomputed = Some(PrecomputedValues {
697 dp,
698 dq,
699 qinv,
700 p_params,
701 q_params,
702 });
703
704 Ok(())
705 }
706
707 pub fn clear_precomputed(&mut self) {
709 self.precomputed = None;
710 }
711
712 pub fn crt_coefficient(&self) -> Option<BoxedUint> {
714 let p = &self.primes[0];
715 let q = &self.primes[1];
716 Option::from(q.invert_mod(&CryptoNonZero::new(p.clone()).expect("prime")))
718 }
719
720 pub fn validate(&self) -> Result<()> {
723 check_public(self)?;
724 validate_private_key_parts(self)?;
725 Ok(())
726 }
727
728 pub fn decrypt<P: PaddingScheme>(&self, padding: P, ciphertext: &[u8]) -> Result<Vec<u8>> {
730 padding.decrypt(Option::<&mut DummyRng>::None, self, ciphertext)
731 }
732
733 pub fn decrypt_blinded<R: CryptoRng + ?Sized, P: PaddingScheme>(
737 &self,
738 rng: &mut R,
739 padding: P,
740 ciphertext: &[u8],
741 ) -> Result<Vec<u8>> {
742 padding.decrypt(Some(rng), self, ciphertext)
743 }
744
745 pub fn sign<S: SignatureScheme>(&self, padding: S, digest_in: &[u8]) -> Result<Vec<u8>> {
747 padding.sign(Option::<&mut DummyRng>::None, self, digest_in)
748 }
749
750 pub fn sign_with_rng<R: CryptoRng + ?Sized, S: SignatureScheme>(
761 &self,
762 rng: &mut R,
763 padding: S,
764 digest_in: &[u8],
765 ) -> Result<Vec<u8>> {
766 padding.sign(Some(rng), self, digest_in)
767 }
768}
769
770#[cfg(feature = "private-key")]
771impl PrivateKeyParts for RsaPrivateKey {
772 fn d(&self) -> &BoxedUint {
773 &self.d
774 }
775
776 fn primes(&self) -> &[BoxedUint] {
777 &self.primes
778 }
779
780 fn dp(&self) -> Option<&BoxedUint> {
781 self.precomputed.as_ref().map(|p| &p.dp)
782 }
783
784 fn dq(&self) -> Option<&BoxedUint> {
785 self.precomputed.as_ref().map(|p| &p.dq)
786 }
787
788 fn qinv(&self) -> Option<&BoxedMontyForm> {
789 self.precomputed.as_ref().map(|p| &p.qinv)
790 }
791
792 fn crt_values(&self) -> Option<&[CrtValue]> {
793 None
794 }
795
796 fn p_params(&self) -> Option<&BoxedMontyParams> {
797 self.precomputed.as_ref().map(|p| &p.p_params)
798 }
799
800 fn q_params(&self) -> Option<&BoxedMontyParams> {
801 self.precomputed.as_ref().map(|p| &p.q_params)
802 }
803}
804
805#[inline]
807#[cfg(feature = "alloc")]
808pub fn check_public(public_key: &impl PublicKeyParts<BoxedUint>) -> Result<()> {
809 check_public_with_max_size(public_key.n().as_ref(), public_key.e(), None)
810}
811
812#[inline]
814#[cfg(feature = "alloc")]
815fn check_public_with_max_size(n: &BoxedUint, e: &BoxedUint, max_size: Option<usize>) -> Result<()> {
816 if let Some(max_size) = max_size {
817 if n.bits_vartime() as usize > max_size {
818 return Err(Error::ModulusTooLarge);
819 }
820 }
821
822 check_public_skip_exponent_size(n, e)?;
823
824 if e < &BoxedUint::from(RsaPublicKey::MIN_PUB_EXPONENT) {
825 return Err(Error::PublicExponentTooSmall);
826 }
827
828 if e > &BoxedUint::from(RsaPublicKey::MAX_PUB_EXPONENT) {
829 return Err(Error::PublicExponentTooLarge);
830 }
831
832 Ok(())
833}
834
835#[inline]
839#[cfg(feature = "alloc")]
840fn check_public_skip_exponent_size(n: &BoxedUint, e: &BoxedUint) -> Result<()> {
841 if e >= n || n.is_even().into() || n.is_zero().into() {
842 return Err(Error::InvalidModulus);
843 }
844
845 if e.is_even().into() {
846 return Err(Error::InvalidExponent);
847 }
848
849 Ok(())
851}
852
853#[cfg(feature = "private-key")]
858fn validate_private_key_parts(key: &RsaPrivateKey) -> Result<()> {
859 let mut m = BoxedUint::one_with_precision(key.pubkey_components.n.bits_precision());
861 let one = BoxedUint::one();
862 for prime in &key.primes {
863 if prime <= &one {
865 return Err(Error::InvalidPrime);
866 }
867 m = m.wrapping_mul(prime);
868 }
869 if m != *key.pubkey_components.n.as_ref() {
870 return Err(Error::InvalidModulus);
871 }
872
873 let de = key.d.concatenating_mul(&key.pubkey_components.e);
879
880 for prime in &key.primes {
881 let x = CryptoNonZero::new(prime.wrapping_sub(BoxedUint::one())).unwrap();
882 let congruence = de.rem_vartime(&x);
883 if !bool::from(congruence.is_one()) {
884 return Err(Error::InvalidExponent);
885 }
886 }
887
888 Ok(())
889}
890
891#[cfg(all(feature = "hazmat", feature = "private-key"))]
897fn validate_skip_exponent_size(key: &RsaPrivateKey) -> Result<()> {
898 check_public_skip_exponent_size(key.pubkey_components.n.as_ref(), &key.pubkey_components.e)?;
900
901 validate_private_key_parts(key)?;
903
904 Ok(())
905}
906
907#[cfg(feature = "serde")]
908impl Serialize for RsaPublicKey {
909 fn serialize<S>(&self, serializer: S) -> core::prelude::v1::Result<S::Ok, S::Error>
910 where
911 S: serdect::serde::Serializer,
912 {
913 let der = self.to_public_key_der().map_err(ser::Error::custom)?;
914 serdect::slice::serialize_hex_lower_or_bin(&der, serializer)
915 }
916}
917
918#[cfg(feature = "serde")]
919impl<'de> Deserialize<'de> for RsaPublicKey {
920 fn deserialize<D>(deserializer: D) -> core::prelude::v1::Result<Self, D::Error>
921 where
922 D: serdect::serde::Deserializer<'de>,
923 {
924 let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
925 Self::from_public_key_der(&der_bytes).map_err(de::Error::custom)
926 }
927}
928
929#[cfg(feature = "serde")]
930impl Serialize for RsaPrivateKey {
931 fn serialize<S>(&self, serializer: S) -> core::prelude::v1::Result<S::Ok, S::Error>
932 where
933 S: ser::Serializer,
934 {
935 let der = self.to_pkcs8_der().map_err(ser::Error::custom)?;
936 serdect::slice::serialize_hex_lower_or_bin(&der.as_bytes(), serializer)
937 }
938}
939
940#[cfg(feature = "serde")]
941impl<'de> Deserialize<'de> for RsaPrivateKey {
942 fn deserialize<D>(deserializer: D) -> core::prelude::v1::Result<Self, D::Error>
943 where
944 D: de::Deserializer<'de>,
945 {
946 let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
947 Self::from_pkcs8_der(&der_bytes).map_err(de::Error::custom)
948 }
949}
950
951#[cfg(test)]
952#[cfg(all(feature = "alloc", feature = "private-key"))]
953mod tests {
954 use super::*;
955 use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
956 use crate::traits::{PrivateKeyParts, PublicKeyParts};
957
958 use hex_literal::hex;
959 use rand::rngs::ChaCha8Rng;
960 use rand_core::SeedableRng;
961
962 #[cfg(feature = "encoding")]
963 use pkcs8::DecodePrivateKey;
964
965 #[test]
966 fn test_from_into() {
967 let raw_n = BoxedUint::from(101u64);
968 let n_odd = CryptoOdd::new(raw_n.clone()).unwrap();
969 let private_key = RsaPrivateKey {
970 pubkey_components: RsaPublicKey {
971 n: NonZero::new(raw_n.clone()).unwrap(),
972 e: BoxedUint::from(200u64),
973 n_params: BoxedMontyParams::new(n_odd),
974 },
975 d: BoxedUint::from(123u64),
976 primes: vec![],
977 precomputed: None,
978 };
979 let public_key: RsaPublicKey = private_key.into();
980
981 let n_limbs: &[u64] = PublicKeyParts::n(&public_key).as_ref().as_ref();
982 assert_eq!(n_limbs, &[101u64]);
983 assert_eq!(PublicKeyParts::e(&public_key), &BoxedUint::from(200u64));
984 assert_eq!(PublicKeyParts::e_bytes(&public_key), [200].into());
985 assert_eq!(PublicKeyParts::n_bytes(&public_key), [101].into());
986 }
987
988 fn test_key_basics(private_key: &RsaPrivateKey) {
989 private_key.validate().expect("invalid private key");
990
991 assert!(
992 PrivateKeyParts::d(private_key) < PublicKeyParts::n(private_key).as_ref(),
993 "private exponent too large"
994 );
995
996 let pub_key: RsaPublicKey = private_key.clone().into();
997 let m = BoxedUint::from(42u64);
998 let c = rsa_encrypt(&pub_key, &m).expect("encryption successful");
999
1000 let m2 = rsa_decrypt_and_check::<ChaCha8Rng>(private_key, None, &c)
1001 .expect("unable to decrypt without blinding");
1002 assert_eq!(m, m2);
1003 let mut rng = ChaCha8Rng::from_seed([42; 32]);
1004 let m3 = rsa_decrypt_and_check(private_key, Some(&mut rng), &c)
1005 .expect("unable to decrypt with blinding");
1006 assert_eq!(m, m3);
1007 }
1008
1009 macro_rules! key_generation {
1010 ($name:ident, $multi:expr, $size:expr) => {
1011 #[cfg(feature = "private-key")]
1012 #[test]
1013 fn $name() {
1014 let mut rng = ChaCha8Rng::from_seed([42; 32]);
1015 let exp = BoxedUint::from(RsaPrivateKey::EXP);
1016
1017 for _ in 0..10 {
1018 let components =
1019 generate_multi_prime_key_with_exp(&mut rng, $multi, $size, exp.clone())
1020 .unwrap();
1021 let private_key = RsaPrivateKey::from_components(
1022 components.n.get(),
1023 components.e,
1024 components.d,
1025 components.primes,
1026 )
1027 .unwrap();
1028 assert_eq!(PublicKeyParts::n(&private_key).bits(), $size);
1029
1030 test_key_basics(&private_key);
1031 }
1032 }
1033 #[cfg(not(feature = "private-key"))]
1034 #[test]
1035 fn $name() {
1036 todo!("generate_multi_prime_key_with_exp is not implemented yet");
1037 }
1038 };
1039 }
1040
1041 key_generation!(key_generation_128, 2, 128);
1042 key_generation!(key_generation_1024, 2, 1024);
1043
1044 key_generation!(key_generation_multi_3_256, 3, 256);
1045
1046 key_generation!(key_generation_multi_4_64, 4, 64);
1047
1048 key_generation!(key_generation_multi_5_64, 5, 64);
1049 key_generation!(key_generation_multi_8_576, 8, 576);
1050 key_generation!(key_generation_multi_16_1024, 16, 1024);
1051
1052 #[test]
1053 fn test_negative_decryption_value() {
1054 let bits = 128;
1055 let private_key = RsaPrivateKey::from_components(
1056 BoxedUint::from_le_slice(
1057 &[
1058 99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180,
1059 ],
1060 bits,
1061 )
1062 .unwrap(),
1063 BoxedUint::from_le_slice(&[1, 0, 1, 0, 0, 0, 0, 0], 64).unwrap(),
1064 BoxedUint::from_le_slice(
1065 &[
1066 81, 163, 254, 144, 171, 159, 144, 42, 244, 133, 51, 249, 28, 12, 63, 65,
1067 ],
1068 bits,
1069 )
1070 .unwrap(),
1071 vec![
1072 BoxedUint::from_le_slice(&[105, 101, 60, 173, 19, 153, 3, 192], bits / 2).unwrap(),
1073 BoxedUint::from_le_slice(&[235, 65, 160, 134, 32, 136, 6, 241], bits / 2).unwrap(),
1074 ],
1075 )
1076 .unwrap();
1077
1078 for _ in 0..1000 {
1079 test_key_basics(&private_key);
1080 }
1081 }
1082
1083 #[test]
1084 #[cfg(all(feature = "hazmat", feature = "serde"))]
1085 fn test_serde() {
1086 use rand::rngs::ChaCha8Rng;
1087 use rand_core::SeedableRng;
1088 use serde_test::{assert_tokens, Configure, Token};
1089
1090 let mut rng = ChaCha8Rng::from_seed([42; 32]);
1091 let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
1092
1093 let priv_tokens = [Token::Str(concat!(
1094 "3056020100300d06092a864886f70d010101050004423040020100020900a",
1095 "b240c3361d02e370203010001020811e54a15259d22f9020500ceff5cf302",
1096 "0500d3a7aaad020500ccaddf17020500cb529d3d020500bb526d6f"
1097 ))];
1098 assert_tokens(&priv_key.clone().readable(), &priv_tokens);
1099
1100 let priv_tokens = [Token::Str(
1101 "3024300d06092a864886f70d01010105000313003010020900ab240c3361d02e370203010001",
1102 )];
1103 assert_tokens(
1104 &RsaPublicKey::from(priv_key.clone()).readable(),
1105 &priv_tokens,
1106 );
1107 }
1108
1109 #[test]
1110 fn invalid_coeff_private_key_regression() {
1111 use base64ct::{Base64, Encoding};
1112
1113 let n = Base64::decode_vec(
1114 "wC8GyQvTCZOK+iiBR5fGQCmzRCTWX9TQ3aRG5gGFk0wB6EFoLMAyEEqeG3gS8xhA\
1115 m2rSWYx9kKufvNat3iWlbSRVqkcbpVAYlj2vTrpqDpJl+6u+zxFYoUEBevlJJkAh\
1116 l8EuCccOA30fVpcfRvXPTtvRd3yFT9E9EwZljtgSI02w7gZwg7VIxaGeajh5Euz6\
1117 ZVQZ+qNRKgXrRC7gPRqVyI6Dt0Jc+Su5KBGNn0QcPDzOahWha1ieaeMkFisZ9mdp\
1118 sJoZ4tw5eicLaUomKzALHXQVt+/rcZSrCd6/7uUo11B/CYBM4UfSpwXaL88J9AE6\
1119 A5++no9hmJzaF2LLp+Qwx4yY3j9TDutxSAjsraxxJOGZ3XyA9nG++Ybt3cxZ5fP7\
1120 ROjxCfROBmVv5dYn0O9OBIqYeCH6QraNpZMadlLNIhyMv8Y+P3r5l/PaK4VJaEi5\
1121 pPosnEPawp0W0yZDzmjk2z1LthaRx0aZVrAjlH0Rb/6goLUQ9qu1xsDtQVVpN4A8\
1122 9ZUmtTWORnnJr0+595eHHxssd2gpzqf4bPjNITdAEuOCCtpvyi4ls23zwuzryUYj\
1123 cUOEnsXNQ+DrZpLKxdtsD/qNV/j1hfeyBoPllC3cV+6bcGOFcVGbjYqb+Kw1b0+j\
1124 L69RSKQqgmS+qYqr8c48nDRxyq3QXhR8qtzUwBFSLVk=",
1125 )
1126 .unwrap();
1127 let e = Base64::decode_vec("AQAB").unwrap();
1128 let d = Base64::decode_vec(
1129 "qQazSQ+FRN7nVK1bRsROMRB8AmsDwLVEHivlz1V3Td2Dr+oW3YUMgxedhztML1Id\
1130 QJPq/ad6qErJ6yRFNySVIjDaxzBTOEoB1eHa1btOnBJWb8rVvvjaorixvJ6Tn3i4\
1131 EuhsvVy9DoR1k4rGj3qSIiFjUVvLRDAbLyhpGgEfsr0Z577yJmTC5E8JLRMOKX8T\
1132 mxsk3jPVpsgd65Hu1s8S/ZmabwuHCf9SkdMeY/1bd/9i7BqqJeeDLE4B5x1xcC3z\
1133 3scqDUTzqGO+vZPhjgprPDRlBamVwgenhr7KwCn8iaLamFinRVwOAag8BeBqOJj7\
1134 lURiOsKQa9FIX1kdFUS1QMQxgtPycLjkbvCJjriqT7zWKsmJ7l8YLs6Wmm9/+QJR\
1135 wNCEVdMTXKfCP1cJjudaiskEQThfUldtgu8gUDNYbQ/Filb2eKfiX4h1TiMxZqUZ\
1136 HVZyb9nShbQoXJ3vj/MGVF0QM8TxhXM8r2Lv9gDYU5t9nQlUMLhs0jVjai48jHAB\
1137 bFNyH3sEcOmJOIwJrCXw1dzG7AotwyaEVUHOmL04TffmwCFfnyrLjbFgnyOeoyII\
1138 BYjcY7QFRm/9nupXMTH5hZ2qrHfCJIp0KK4tNBdQqmnHapFl5l6Le1s4qBS5bEIz\
1139 jitobLvAFm9abPlDGfxmY6mlrMK4+nytwF9Ct7wc1AE=",
1140 )
1141 .unwrap();
1142 let primes = [
1143 Base64::decode_vec(
1144 "9kQWEAzsbzOcdPa+s5wFfw4XDd7bB1q9foZ31b1+TNjGNxbSBCFlDF1q98vwpV6n\
1145 M8bWDh/wtbNoETSQDgpEnYOQ26LWEw6YY1+q1Q2GGEFceYUf+Myk8/vTc8TN6Zw0\
1146 bKZBWy10Qo8h7xk4JpzuI7NcxvjJYTkS9aErFxi3vVH0aiZC0tmfaCqr8a2rJxyV\
1147 wqreRpOjwAWrotMsf2wGsF4ofx5ScoFy5GB5fJkkdOrW1LyTvZAUCX3cstPr19+T\
1148 NC5zZOk7WzZatnCkN5H5WzalWtZuu0oVL205KPOa3R8V2yv5e6fm0v5fTmqSuvjm\
1149 aMJLXCN4QJkmIzojO99ckQ==",
1150 )
1151 .unwrap(),
1152 Base64::decode_vec(
1153 "x8exdMjVA2CiI+Thx7loHtVcevoeE2sZ7btRVAvmBqo+lkHwxb7FHRnWvuj6eJSl\
1154 D2f0T50EewIhhiW3R9BmktCk7hXjbSCnC1u9Oxc1IAUm/7azRqyfCMx43XhLxpD+\
1155 xkBCpWkKDLxGczsRwTuaP3lKS3bSdBrNlGmdblubvVBIq4YZ2vXVlnYtza0cS+dg\
1156 CK7BGTqUsrCUd/ZbIvwcwZkZtpkhj1KQfto9X/0OMurBzAqbkeq1cyRHXHkOfN/q\
1157 bUIIRqr9Ii7Eswf9Vk8xp2O1Nt8nzcYS9PFD12M5eyaeFEkEYfpNMNGuTzp/31oq\
1158 VjbpoCxS6vuWAZyADxhISQ==",
1159 )
1160 .unwrap(),
1161 Base64::decode_vec(
1162 "is7d0LY4HoXszlC2NO7gejkq7XqL4p1W6hZJPYTNx+r37t1CC2n3Vvzg6kNdpRix\
1163 DhIpXVTLjN9O7UO/XuqSumYKJIKoP52eb4Tg+a3hw5Iz2Zsb5lUTNSLgkQSBPAf7\
1164 1LHxbL82JL4g1nBUog8ae60BwnVArThKY4EwlJguGNw09BAU4lwf6csDl/nX2vfV\
1165 wiAloYpeZkHL+L8m+bueGZM5KE2jEz+7ztZCI+T+E5i69rZEYDjx0lfLKlEhQlCW\
1166 3HbCPELqXgNJJkRfi6MP9kXa9lSfnZmoT081RMvqonB/FUa4HOcKyCrw9XZEtnbN\
1167 CIdbitfDVEX+pSSD7596wQ==",
1168 )
1169 .unwrap(),
1170 Base64::decode_vec(
1171 "GPs0injugfycacaeIP5jMa/WX55VEnKLDHom4k6WlfDF4L4gIGoJdekcPEUfxOI5\
1172 faKvHyFwRP1wObkPoRBDM0qZxRfBl4zEtpvjHrd5MibSyJkM8+J0BIKk/nSjbRIG\
1173 eb3hV5O56PvGB3S0dKhCUnuVObiC+ne7izplsD4OTG70l1Yud33UFntyoMxrxGYL\
1174 USqhBMmZfHquJg4NOWOzKNY/K+EcHDLj1Kjvkcgv9Vf7ocsVxvpFdD9uGPceQ6kw\
1175 RDdEl6mb+6FDgWuXVyqR9+904oanEIkbJ7vfkthagLbEf57dyG6nJlqh5FBZWxGI\
1176 R72YGypPuAh7qnnqXXjY2Q==",
1177 )
1178 .unwrap(),
1179 Base64::decode_vec(
1180 "CUWC+hRWOT421kwRllgVjy6FYv6jQUcgDNHeAiYZnf5HjS9iK2ki7v8G5dL/0f+Y\
1181 f+NhE/4q8w4m8go51hACrVpP1p8GJDjiT09+RsOzITsHwl+ceEKoe56ZW6iDHBLl\
1182 rNw5/MtcYhKpjNU9KJ2udm5J/c9iislcjgckrZG2IB8ADgXHMEByZ5DgaMl4AKZ1\
1183 Gx8/q6KftTvmOT5rNTMLi76VN5KWQcDWK/DqXiOiZHM7Nr4dX4me3XeRgABJyNR8\
1184 Fqxj3N1+HrYLe/zs7LOaK0++F9Ul3tLelhrhsvLxei3oCZkF9A/foD3on3luYA+1\
1185 cRcxWpSY3h2J4/22+yo4+Q==",
1186 )
1187 .unwrap(),
1188 ];
1189
1190 let e = BoxedUint::from_be_slice(&e, 64).unwrap();
1191
1192 let bits = 4096;
1193 let n = BoxedUint::from_be_slice(&n, bits).unwrap();
1194 let d = BoxedUint::from_be_slice(&d, bits).unwrap();
1195 let primes = primes
1196 .iter()
1197 .map(|p| BoxedUint::from_be_slice(p, bits / 2).unwrap())
1198 .collect();
1199 let res = RsaPrivateKey::from_components(n, e, d, primes);
1200 assert_eq!(res, Err(Error::InvalidModulus));
1201 }
1202
1203 #[test]
1204 fn reject_oversized_private_key() {
1205 let n = BoxedUint::from_be_slice(
1232 &hex!(
1233 "a909fa3bba5df62a102443b04b6b219c3d9b337f8f68ba2fae8f8e28e13db7b8
1234 f1ae9f9bf57abcd68793eb3379bb9c8f7b06be574f19b0025011b17d0f900c51
1235 990765cfec5bf5c022d0bc0a88d0847a0241f8ce5d9a4e3661ac4319d224d830
1236 2d5e530d52940296d020fcc89bdc83c0ebe5d725c8ca969120d1f3b61cf7eb2b
1237 0799a1e5355659438d011d590e89477ec2ced6f54f6f1cdd1071a4870bc94750
1238 4a9bfc8c9bd054a666cfaa6e6e0d5f2688f74a25a0015fb4e9edf1515b1df4ff
1239 4d74b45703327ac73116cbaf72e4eb5f1f0461cf53b894e15b6db004014e2ba4
1240 a97ed82d67a8b8589aa4d05f09ad3c19dd3ca1ccab0f4707bc29e366b66a98a1
1241 a1a23e3f6550e73ddbc4333b24c44d577ca55ed4a6768e7bd4385872f44269d7
1242 9fad690aee2aa682ee2bc8c1f883bbc627d16478f73cc7ec8c9bab678305e7b2
1243 e0a52ac8eb47a460d875a3a5625ce0c742ecc6c734da1779ffec62130c14170d
1244 14e51ae407efb87293116a3dc951188d30c4408f29ab31a738e189a4ee6bd7a2
1245 a4a79d5c1fa8e57172a2c9c3b7f5f8620ab18ffab6ff5f0b3ee42014ba96473b
1246 077784dd550ca2abdc429b32281948c03f3d50f1c8c85d1a549e9dab6508c448
1247 22de4e37b0ac635b8d2303521745e4cd8e0519a7ed0f171c7094c53f5f63f059
1248 7b275e139e0abc47449289b191b5e884728499b59e11d869efc874e3fc56dfae
1249 29d4dbbd638f70ee0b4efbd9e6c0a729349ab7d8ce906f4776750df0274a0823
1250 d9a5fa7fc34e76be208c306c8f14385108e0a650cd96aa98dbf74f31a6a67a1c
1251 1caede33212d014790654206acf9ab1501262999fdae482bff61f0f13db4abb7
1252 b4944eb922cebdbd33f6c179b5ec1e7328562c91ae358c9a19ea32296cc3adb9
1253 53d95774a8198337f59e00c7725a1991342ff750ea524985d154002148417c0d
1254 5aacddeecae7bdbca6e212eaa0fb8c863914b5372fe98383124ecb07614b0dcc
1255 a6987ff308bdf0e154a2e3e1f2659d7780cec2cfc5a6917e07fa378bd3e25a43
1256 21b50b3a95fc703bf2f52926ffdb6ff275f97d62ff51e5b4b7938ed798e2b061
1257 553d5cc41a1504641a0b08a7740b3e163729fbc7002beff7a4c42086792b187c
1258 ebc7d6086283865ece2f4083069e061a4daeda5c069fb787d68e0e047928ddad
1259 9c2aaab3cdb94704ba77853fd44f7df8fc7f7be486a0858285417d533ba27b6e
1260 d9dda746efe18409204f5dd473af0974cda2981bc7028e830d4b7a9ac58200c3
1261 8011762e3bb680fa7dde7adb6706ab440a8400a0225d08709e6e32299683015c
1262 c2d7cac786b4b2bd6ab238f210ef7314a57fbff5964041e8b80d426409efddb9
1263 4c38a989840867addfe1de59d890a95b4bd4930ceb1f888f6f6872f9305048ec
1264 3592f8cbc86fe51d68f30d06bad31c555bdbb9f43c50b9e1ec34430750e443d6
1265 8157bc52defc0965"
1266 ),
1267 8256,
1268 )
1269 .unwrap();
1270
1271 let e = BoxedUint::from(65_537u64);
1272
1273 assert_eq!(
1274 RsaPublicKey::new(n, e).err().unwrap(),
1275 Error::ModulusTooLarge
1276 );
1277 }
1278
1279 #[test]
1280 #[cfg(feature = "encoding")]
1281 fn build_key_from_primes() {
1282 const RSA_2048_PRIV_DER: &[u8] = include_bytes!("../tests/examples/pkcs8/rsa2048-priv.der");
1283 let ref_key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap();
1284 assert_eq!(ref_key.validate(), Ok(()));
1285
1286 let primes = PrivateKeyParts::primes(&ref_key).to_vec();
1287
1288 let exp = PublicKeyParts::e(&ref_key);
1289 let key = RsaPrivateKey::from_primes(primes, exp.clone())
1290 .expect("failed to import key from primes");
1291 assert_eq!(key.validate(), Ok(()));
1292
1293 assert_eq!(PublicKeyParts::n(&key), PublicKeyParts::n(&ref_key));
1294
1295 assert_eq!(PrivateKeyParts::dp(&key), PrivateKeyParts::dp(&ref_key));
1296 assert_eq!(PrivateKeyParts::dq(&key), PrivateKeyParts::dq(&ref_key));
1297
1298 assert_eq!(PrivateKeyParts::d(&key), PrivateKeyParts::d(&ref_key));
1299 }
1300
1301 #[test]
1302 #[cfg(feature = "encoding")]
1303 fn build_key_from_p_q() {
1304 const RSA_2048_SP800_PRIV_DER: &[u8] =
1305 include_bytes!("../tests/examples/pkcs8/rsa2048-sp800-56b-priv.der");
1306 let ref_key = RsaPrivateKey::from_pkcs8_der(RSA_2048_SP800_PRIV_DER).unwrap();
1307 assert_eq!(ref_key.validate(), Ok(()));
1308
1309 let primes = PrivateKeyParts::primes(&ref_key).to_vec();
1310 let exp = PublicKeyParts::e(&ref_key);
1311
1312 let key = RsaPrivateKey::from_p_q(primes[0].clone(), primes[1].clone(), exp.clone())
1313 .expect("failed to import key from primes");
1314 assert_eq!(key.validate(), Ok(()));
1315
1316 assert_eq!(PublicKeyParts::n(&key), PublicKeyParts::n(&ref_key));
1317
1318 assert_eq!(PrivateKeyParts::dp(&key), PrivateKeyParts::dp(&ref_key));
1319 assert_eq!(PrivateKeyParts::dq(&key), PrivateKeyParts::dq(&ref_key));
1320
1321 assert_eq!(PrivateKeyParts::d(&key), PrivateKeyParts::d(&ref_key));
1322 }
1323
1324 #[test]
1325 #[cfg(feature = "hazmat")]
1326 fn test_from_components_with_large_exponent() {
1327 use rand::rngs::ChaCha8Rng;
1331 use rand_core::SeedableRng;
1332
1333 let mut rng = ChaCha8Rng::from_seed([42; 32]);
1334
1335 let large_e = BoxedUint::from((1u64 << 34) + 1); let components =
1340 generate_multi_prime_key_with_exp(&mut rng, 2, 1024, large_e.clone()).unwrap();
1341
1342 let n = components.n.get().clone();
1344 let d = components.d;
1345 let primes = components.primes;
1346
1347 let result =
1349 RsaPrivateKey::from_components(n.clone(), large_e.clone(), d.clone(), primes.clone());
1350 assert!(result.is_err());
1351 assert_eq!(result.unwrap_err(), Error::PublicExponentTooLarge);
1352
1353 let key_with_large_exp = RsaPrivateKey::from_components_with_large_exponent(
1355 n.clone(),
1356 large_e.clone(),
1357 d.clone(),
1358 primes.clone(),
1359 );
1360 assert!(key_with_large_exp.is_ok());
1361
1362 let key_with_large_exp = key_with_large_exp.unwrap();
1363 assert_eq!(PublicKeyParts::e(&key_with_large_exp), &large_e);
1364 assert_eq!(PublicKeyParts::n(&key_with_large_exp).as_ref(), &n);
1365 assert_eq!(PrivateKeyParts::d(&key_with_large_exp), &d);
1366
1367 assert!(validate_skip_exponent_size(&key_with_large_exp).is_ok());
1370 }
1371
1372 #[test]
1373 #[cfg(feature = "hazmat")]
1374 fn test_from_components_with_small_exponent() {
1375 use rand::rngs::ChaCha8Rng;
1379 use rand_core::SeedableRng;
1380
1381 let mut rng = ChaCha8Rng::from_seed([43; 32]);
1382
1383 let small_e = BoxedUint::from(1u64); let components =
1388 generate_multi_prime_key_with_exp(&mut rng, 2, 1024, small_e.clone()).unwrap();
1389
1390 let n = components.n.get().clone();
1392 let d = components.d;
1393 let primes = components.primes;
1394
1395 let result =
1397 RsaPrivateKey::from_components(n.clone(), small_e.clone(), d.clone(), primes.clone());
1398 assert!(result.is_err());
1399
1400 let key_with_small_exp = RsaPrivateKey::from_components_with_large_exponent(
1402 n.clone(),
1403 small_e.clone(),
1404 d.clone(),
1405 primes,
1406 );
1407 assert!(key_with_small_exp.is_ok());
1408
1409 let key_with_small_exp = key_with_small_exp.unwrap();
1410 assert_eq!(PublicKeyParts::e(&key_with_small_exp), &small_e);
1411
1412 assert!(validate_skip_exponent_size(&key_with_small_exp).is_ok());
1414 }
1415
1416 #[test]
1428 #[cfg(feature = "hazmat")]
1429 fn test_key_invalid_primes() {
1430 let e = RsaPrivateKey::from_components_with_large_exponent(
1431 BoxedUint::from(239u64),
1432 BoxedUint::from(185u64),
1433 BoxedUint::from(0u64),
1434 vec![BoxedUint::from(1u64), BoxedUint::from(239u64)],
1435 )
1436 .unwrap_err();
1437 assert_eq!(e, Error::InvalidPrime);
1438 }
1439}