Skip to main content

rsa/
key.rs

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/// Represents the public part of an RSA key.
45#[derive(Debug, Clone)]
46pub struct GenericRsaPublicKey<T, M>
47where
48    T: UnsignedModularInt,
49    M: ModulusParams<Modulus = T>,
50{
51    /// Modulus: product of prime numbers `p` and `q`
52    n: NonZero<T>,
53    /// Public exponent: power to which a plaintext message is raised in
54    /// order to encrypt it.
55    ///
56    /// Typically `0x10001` (`65537`)
57    e: T,
58
59    n_params: M,
60}
61
62/// Boxed RSA public key alias used by the `alloc` code path. Equivalent to
63/// `GenericRsaPublicKey<BoxedUint, BoxedMontyParams>`.
64#[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        // Domain separator for RSA private keys
92        state.write(b"RsaPublicKey");
93        // TODO(tarcieri): to match the `PartialEq` impl we should strip leading zeros
94        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/// Represents a whole RSA key, public and private parts.
100#[cfg(feature = "private-key")]
101#[derive(Clone)]
102pub struct RsaPrivateKey {
103    /// Public components of the private key.
104    pubkey_components: RsaPublicKey,
105    /// Private exponent
106    pub(crate) d: BoxedUint,
107    /// Prime factors of N, contains >= 2 elements.
108    pub(crate) primes: Vec<BoxedUint>,
109    /// Precomputed values to speed up private operations
110    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        // Domain separator for RSA private keys
153        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    /// D mod (P-1)
174    pub(crate) dp: BoxedUint,
175    /// D mod (Q-1)
176    pub(crate) dq: BoxedUint,
177    /// Q^-1 mod P
178    pub(crate) qinv: BoxedMontyForm,
179
180    /// Montgomery params for `p`
181    pub(crate) p_params: BoxedMontyParams,
182    /// Montgomery params for `q`
183    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        // TODO: once these have landed in crypto-bigint
195        // self.p_params.zeroize();
196        // self.q_params.zeroize();
197    }
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    /// Create a public key from already-validated components and modulus parameters.
253    ///
254    /// This is intended for alternate bigint backends that prepare their own
255    /// modular arithmetic context outside the `BoxedUint` constructors.
256    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    /// Encrypt the given message.
268    #[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    /// Verify a signed message.
279    ///
280    /// `hashed` must be the result of hashing the input using the hashing function
281    /// passed in through `hash`.
282    ///
283    /// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
284    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    /// Minimum value of the public exponent `e`.
292    pub const MIN_PUB_EXPONENT: u64 = 2;
293
294    /// Maximum value of the public exponent `e`.
295    ///
296    /// Very large public exponents are a potential denial-of-service vector (a.k.a. "RSADoS")
297    /// because they increase the amount of work required for e.g. signature verification. See:
298    ///
299    /// <https://www.imperialviolet.org/2012/03/17/rsados.html>
300    ///
301    /// The particular constant below has been chosen to align with *ring* where this value was
302    /// selected based on the history of this particular issue, API compatibility concerns, and
303    /// benchmark-driven evaluation. See RustCrypto/RSA#155.
304    ///
305    /// If for some reason you have a legitimate reason to use keys with public exponents larger
306    /// than this value, use the special APIs:
307    ///
308    /// - [`RsaPublicKey::new_with_large_exp`]
309    /// - [`RsaPrivateKey::from_components_with_large_exponent`]
310    pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1;
311
312    /// Maximum size of the modulus `n` in bits.
313    pub const MAX_SIZE: usize = 8192;
314
315    /// Create a new public key from its components.
316    ///
317    /// This function accepts public keys with a modulus size up to 8192-bits,
318    /// i.e. [`RsaPublicKey::MAX_SIZE`].
319    pub fn new(n: BoxedUint, e: BoxedUint) -> Result<Self> {
320        Self::new_with_max_size(n, e, Self::MAX_SIZE)
321    }
322
323    /// Create a new public key from its components.
324    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    /// Create a new public key, bypassing checks around the modulus and public
337    /// exponent size.
338    ///
339    /// This method is not recommended, and only intended for unusual use cases.
340    /// Most applications should use [`RsaPublicKey::new`] or
341    /// [`RsaPublicKey::new_with_max_size`] instead.
342    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    /// Default exponent for RSA keys.
371    const EXP: u64 = 65537;
372
373    /// Minimum size of the modulus `n` in bits. Currently only applies to keygen.
374    const MIN_SIZE: u32 = 1024;
375
376    /// Generate a new RSA key pair with a modulus of the given bit size using the passed in `rng`.
377    ///
378    /// # Errors
379    /// - If `bit_size` is lower than the minimum 1024-bits.
380    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    /// Generate a new RSA key pair of the given bit size.
385    ///
386    /// #⚠️Warning: Hazmat!
387    /// This version does not apply minimum key size checks, and as such may generate keys
388    /// which are insecure!
389    #[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    /// Generate a new RSA key pair of the given bit size and the public exponent
395    /// using the passed in `rng`.
396    ///
397    /// Unless you have specific needs, you should use [`RsaPrivateKey::new`] instead.
398    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    /// Generate a new RSA key pair of the given bit size and the public exponent
417    /// using the passed in `rng`.
418    ///
419    /// Unless you have specific needs, you should use [`RsaPrivateKey::new`] instead.
420    ///
421    /// #⚠️Warning: Hazmat!
422    /// This version does not apply minimum key size checks, and as such may generate keys
423    /// which are insecure!
424    #[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    /// Private helper function that constructs an RSA key pair from components
440    /// WITHOUT performing any validation or precomputation.
441    ///
442    /// This is the shared implementation used by `from_components` and
443    /// `from_components_with_large_exponent`.
444    ///
445    /// Callers are responsible for:
446    /// 1. Validating the key (to ensure precomputation won't fail)
447    /// 2. Calling precompute() after validation
448    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        // The modulus may come in padded with zeros, shorten it
459        // to ensure optimal performance of arithmetic operations.
460        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                // Recover `p` and `q` from `d`.
469                // See method in Appendix C.2: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
470                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                // Check that the product of primes matches the modulus.
479                // This also ensures that `bit_precision` of each prime is <= that of the modulus,
480                // and `bit_precision` of their product is >= that of the modulus.
481                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        // The primes may come in padded with zeros too, so we need to shorten them as well.
492        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    /// Constructs an RSA key pair from individual components, accepting exponents outside
515    /// the normal size bounds.
516    ///
517    /// See [`RsaPrivateKey::from_components`] for an explanation on the parameters.
518    ///
519    /// # ⚠️ Warning: Hazmat!
520    ///
521    /// This method accepts public exponents outside the standard bounds (2 ≤ e ≤ 2^33-1),
522    /// but still performs full cryptographic validation to ensure the key is mathematically
523    /// correct (i.e., verifies that de ≡ 1 mod λ(n)).
524    ///
525    /// **Note:** This method is dangerous as it can be used as a DOS vector if used with
526    /// untrusted input https://www.imperialviolet.org/2012/03/17/rsados.html
527    ///
528    /// This is intended for interoperating with systems that use non-standard exponents
529    /// or loading legacy keys. Use [`RsaPrivateKey::from_components`] for standard key
530    /// construction.
531    #[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 everything except exponent size bounds (to ensure precompute can't fail)
541        validate_skip_exponent_size(&k)?;
542
543        // Precompute when possible, ignore error otherwise.
544        k.precompute().ok();
545
546        Ok(k)
547    }
548
549    /// Constructs an RSA key pair from individual components:
550    ///
551    /// - `n`: RSA modulus
552    /// - `e`: public exponent (i.e. encrypting exponent)
553    /// - `d`: private exponent (i.e. decrypting exponent)
554    /// - `primes`: prime factors of `n`: typically two primes `p` and `q`. More than two primes can
555    ///   be provided for multiprime RSA, however this is generally not recommended. If no `primes`
556    ///   are provided, a prime factor recovery algorithm will be employed to attempt to recover the
557    ///   factors (as described in [NIST SP 800-56B Revision 2] Appendix C.2). This algorithm only
558    ///   works if there are just two prime factors `p` and `q` (as opposed to multiprime), and `e`
559    ///   is between 2^16 and 2^256.
560    ///
561    ///  [NIST SP 800-56B Revision 2]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
562    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        // Always validate the key, to ensure precompute can't fail
571        k.validate()?;
572
573        // Precompute when possible, ignore error otherwise.
574        k.precompute().ok();
575
576        Ok(k)
577    }
578
579    /// Constructs an RSA key pair from its two primes p and q.
580    ///
581    /// This will rebuild the private exponent and the modulus.
582    ///
583    /// Private exponent will be rebuilt using the method defined in
584    /// [NIST 800-56B Section 6.2.1](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf#page=47).
585    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    /// Constructs an RSA key pair from its primes.
602    ///
603    /// This will rebuild the private exponent and the modulus.
604    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        // Makes sure that the primes are pairwise unequal.
613        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    /// Get the public key from the private key.
628    ///
629    /// Specific alternative to [`AsRef::as_ref`].
630    pub fn as_public_key(&self) -> &RsaPublicKey {
631        &self.pubkey_components
632    }
633
634    /// Get the public key from the private key, cloning `n` and `e`.
635    ///
636    /// Generally this is not needed since `RsaPrivateKey` implements the `PublicKey` trait,
637    /// but it can occasionally be useful to discard the private information entirely.
638    pub fn to_public_key(&self) -> RsaPublicKey {
639        self.pubkey_components.clone()
640    }
641
642    /// Performs some calculations to speed up private key operations.
643    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        // Note that since `p` and `q` may have different `bits_precision`,
672        // so we have to equalize them to calculate the remainder.
673        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    /// Clears precomputed values by setting to None
708    pub fn clear_precomputed(&mut self) {
709        self.precomputed = None;
710    }
711
712    /// Compute CRT coefficient: `(1/q) mod p`.
713    pub fn crt_coefficient(&self) -> Option<BoxedUint> {
714        let p = &self.primes[0];
715        let q = &self.primes[1];
716        // TODO: maybe store primes as `NonZero`?
717        Option::from(q.invert_mod(&CryptoNonZero::new(p.clone()).expect("prime")))
718    }
719
720    /// Performs basic sanity checks on the key.
721    /// Returns `Ok(())` if everything is good, otherwise an appropriate error.
722    pub fn validate(&self) -> Result<()> {
723        check_public(self)?;
724        validate_private_key_parts(self)?;
725        Ok(())
726    }
727
728    /// Decrypt the given message.
729    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    /// Decrypt the given message.
734    ///
735    /// Uses `rng` to blind the decryption process.
736    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    /// Sign the given digest.
746    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    /// Sign the given digest using the provided `rng`, which is used in the
751    /// following ways depending on the [`SignatureScheme`]:
752    ///
753    /// - [`Pkcs1v15Sign`][`crate::Pkcs1v15Sign`] padding: uses the RNG
754    ///   to mask the private key operation with random blinding, which helps
755    ///   mitigate sidechannel attacks.
756    /// - [`Pss`][`crate::Pss`] always requires randomness. Use
757    ///   [`Pss::new`][`crate::Pss::new`] for a standard RSASSA-PSS signature, or
758    ///   [`Pss::new_blinded`][`crate::Pss::new_blinded`] for RSA-BSSA blind
759    ///   signatures.
760    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/// Check that the public key is well formed and has an exponent within acceptable bounds.
806#[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/// Check that the public key is well formed and has an exponent within acceptable bounds.
813#[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/// Check that the public key is well formed, skipping exponent size bounds checks.
836///
837/// This is used internally by both public validation functions and hazmat APIs.
838#[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    // Skip exponent size bounds checks
850    Ok(())
851}
852
853/// Helper function that validates the private key structure and cryptographic correctness.
854///
855/// This performs the structural and mathematical validation checks that are common to both
856/// `validate()` and `validate_skip_exponent_size()`.
857#[cfg(feature = "private-key")]
858fn validate_private_key_parts(key: &RsaPrivateKey) -> Result<()> {
859    // Check that Πprimes == n.
860    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        // Any primes ≤ 1 will cause divide-by-zero panics later.
864        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    // Check that de ≡ 1 mod p-1, for each prime.
874    // This implies that e is coprime to each p-1 as e has a multiplicative
875    // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) =
876    // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1
877    // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required.
878    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/// Validate the private key structure and cryptographic correctness,
892/// skipping only the exponent size bounds checks.
893///
894/// This performs all the same checks as `RsaPrivateKey::validate()` except
895/// it doesn't verify that the exponent is within the standard bounds.
896#[cfg(all(feature = "hazmat", feature = "private-key"))]
897fn validate_skip_exponent_size(key: &RsaPrivateKey) -> Result<()> {
898    // Check public key properties (without exponent size checks)
899    check_public_skip_exponent_size(key.pubkey_components.n.as_ref(), &key.pubkey_components.e)?;
900
901    // Perform common private key validation
902    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        // -----BEGIN PUBLIC KEY-----
1206        // MIIEKjANBgkqhkiG9w0BAQEFAAOCBBcAMIIEEgKCBAkAqQn6O7pd9ioQJEOwS2sh
1207        // nD2bM3+PaLovro+OKOE9t7jxrp+b9Xq81oeT6zN5u5yPewa+V08ZsAJQEbF9D5AM
1208        // UZkHZc/sW/XAItC8CojQhHoCQfjOXZpONmGsQxnSJNgwLV5TDVKUApbQIPzIm9yD
1209        // wOvl1yXIypaRINHzthz36ysHmaHlNVZZQ40BHVkOiUd+ws7W9U9vHN0QcaSHC8lH
1210        // UEqb/Iyb0FSmZs+qbm4NXyaI90oloAFftOnt8VFbHfT/TXS0VwMyescxFsuvcuTr
1211        // Xx8EYc9TuJThW22wBAFOK6SpftgtZ6i4WJqk0F8JrTwZ3TyhzKsPRwe8KeNmtmqY
1212        // oaGiPj9lUOc928QzOyTETVd8pV7UpnaOe9Q4WHL0QmnXn61pCu4qpoLuK8jB+IO7
1213        // xifRZHj3PMfsjJurZ4MF57LgpSrI60ekYNh1o6ViXODHQuzGxzTaF3n/7GITDBQX
1214        // DRTlGuQH77hykxFqPclRGI0wxECPKasxpzjhiaTua9eipKedXB+o5XFyosnDt/X4
1215        // Ygqxj/q2/18LPuQgFLqWRzsHd4TdVQyiq9xCmzIoGUjAPz1Q8cjIXRpUnp2rZQjE
1216        // SCLeTjewrGNbjSMDUhdF5M2OBRmn7Q8XHHCUxT9fY/BZeydeE54KvEdEkomxkbXo
1217        // hHKEmbWeEdhp78h04/xW364p1Nu9Y49w7gtO+9nmwKcpNJq32M6Qb0d2dQ3wJ0oI
1218        // I9ml+n/DTna+IIwwbI8UOFEI4KZQzZaqmNv3TzGmpnocHK7eMyEtAUeQZUIGrPmr
1219        // FQEmKZn9rkgr/2Hw8T20q7e0lE65Is69vTP2wXm17B5zKFYska41jJoZ6jIpbMOt
1220        // uVPZV3SoGYM39Z4Ax3JaGZE0L/dQ6lJJhdFUACFIQXwNWqzd7srnvbym4hLqoPuM
1221        // hjkUtTcv6YODEk7LB2FLDcymmH/zCL3w4VSi4+HyZZ13gM7Cz8WmkX4H+jeL0+Ja
1222        // QyG1CzqV/HA78vUpJv/bb/J1+X1i/1HltLeTjteY4rBhVT1cxBoVBGQaCwindAs+
1223        // Fjcp+8cAK+/3pMQghnkrGHzrx9YIYoOGXs4vQIMGngYaTa7aXAaft4fWjg4EeSjd
1224        // rZwqqrPNuUcEuneFP9RPffj8f3vkhqCFgoVBfVM7ontu2d2nRu/hhAkgT13Uc68J
1225        // dM2imBvHAo6DDUt6msWCAMOAEXYuO7aA+n3eettnBqtECoQAoCJdCHCebjIploMB
1226        // XMLXyseGtLK9arI48hDvcxSlf7/1lkBB6LgNQmQJ7925TDipiYQIZ63f4d5Z2JCp
1227        // W0vUkwzrH4iPb2hy+TBQSOw1kvjLyG/lHWjzDQa60xxVW9u59DxQueHsNEMHUORD
1228        // 1oFXvFLe/AllAgMBAAE=
1229        // -----END PUBLIC KEY-----
1230
1231        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        // Test that from_components_with_large_exponent accepts exponents outside normal bounds
1328        // while from_components would reject them
1329
1330        use rand::rngs::ChaCha8Rng;
1331        use rand_core::SeedableRng;
1332
1333        let mut rng = ChaCha8Rng::from_seed([42; 32]);
1334
1335        // Use an exponent larger than the normal maximum (2^33 - 1)
1336        let large_e = BoxedUint::from((1u64 << 34) + 1); // 2^34 + 1 (odd number)
1337
1338        // Generate a key with this large exponent
1339        let components =
1340            generate_multi_prime_key_with_exp(&mut rng, 2, 1024, large_e.clone()).unwrap();
1341
1342        // Extract components
1343        let n = components.n.get().clone();
1344        let d = components.d;
1345        let primes = components.primes;
1346
1347        // from_components should fail with PublicExponentTooLarge
1348        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        // from_components_with_large_exponent should succeed
1354        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        // Verify that the key is still cryptographically valid (de ≡ 1 mod λ(n))
1368        // by checking that validation with skip_exponent_size passes
1369        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        // Test that from_components_with_large_exponent accepts exponents below normal minimum
1376        // (despite the name, it works for any non-standard exponent size)
1377
1378        use rand::rngs::ChaCha8Rng;
1379        use rand_core::SeedableRng;
1380
1381        let mut rng = ChaCha8Rng::from_seed([43; 32]);
1382
1383        // Use an exponent smaller than the normal minimum (2)
1384        let small_e = BoxedUint::from(1u64); // This is odd, which is required
1385
1386        // Generate a key with this small exponent
1387        let components =
1388            generate_multi_prime_key_with_exp(&mut rng, 2, 1024, small_e.clone()).unwrap();
1389
1390        // Extract components
1391        let n = components.n.get().clone();
1392        let d = components.d;
1393        let primes = components.primes;
1394
1395        // from_components should fail
1396        let result =
1397            RsaPrivateKey::from_components(n.clone(), small_e.clone(), d.clone(), primes.clone());
1398        assert!(result.is_err());
1399
1400        // from_components_with_large_exponent should succeed
1401        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        // Verify that the key is cryptographically valid
1413        assert!(validate_skip_exponent_size(&key_with_small_exp).is_ok());
1414    }
1415
1416    /// Regression test for CVE-2026-21895 / GHSA-9c48-w39g-hm26.
1417    ///
1418    /// Loading a secret key whose prime factor is `1` must be rejected with
1419    /// `Error::InvalidPrime` rather than panicking via a divide-by-zero in
1420    /// the validation/precompute path.
1421    ///
1422    /// Adapted from the test added in upstream commit 2926c91bef (PR #624);
1423    /// the original used `num-bigint` `BigUint` types, this version uses
1424    /// `crypto-bigint` `BoxedUint` and goes through
1425    /// `from_components_with_large_exponent` so the small (out-of-range) `e`
1426    /// can be supplied verbatim from the original test.
1427    #[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}