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 = "keygen")]
27use crate::algorithms::generate::generate_multi_prime_key_with_exp;
28#[cfg(feature = "alloc")]
29use crate::algorithms::rsa::{
30    compute_modulus, compute_private_exponent_carmicheal, compute_private_exponent_euler_totient,
31    recover_primes,
32};
33
34#[cfg(feature = "alloc")]
35use crate::dummy_rng::DummyRng;
36use crate::errors::{Error, Result};
37use crate::traits::keys::PublicKeyParts;
38use crate::traits::keys::{PrivateKeyParts, RawPrivateKeyConstructible};
39use crate::traits::{
40    modular::ModulusParams, NonZero, PaddingScheme, SignatureScheme, UnsignedModularInt,
41};
42
43/// Represents the public part of an RSA key.
44#[derive(Debug, Clone)]
45pub struct GenericRsaPublicKey<T, M>
46where
47    T: UnsignedModularInt,
48    M: ModulusParams<Modulus = T>,
49{
50    /// Modulus: product of prime numbers `p` and `q`
51    n: NonZero<T>,
52    /// Public exponent: power to which a plaintext message is raised in
53    /// order to encrypt it.
54    ///
55    /// Typically `0x10001` (`65537`)
56    e: T,
57
58    n_params: M,
59}
60
61/// Boxed RSA public key alias used by the `alloc` code path. Equivalent to
62/// `GenericRsaPublicKey<BoxedUint, BoxedMontyParams>`.
63#[cfg(feature = "alloc")]
64pub type RsaPublicKey = GenericRsaPublicKey<BoxedUint, BoxedMontyParams>;
65
66impl<T, M> Eq for GenericRsaPublicKey<T, M>
67where
68    T: UnsignedModularInt + Eq,
69    M: ModulusParams<Modulus = T>,
70{
71}
72
73impl<T, M> PartialEq for GenericRsaPublicKey<T, M>
74where
75    T: UnsignedModularInt + PartialEq,
76    M: ModulusParams<Modulus = T>,
77{
78    #[inline]
79    fn eq(&self, other: &GenericRsaPublicKey<T, M>) -> bool {
80        self.n == other.n && self.e == other.e
81    }
82}
83
84impl<T, M> Hash for GenericRsaPublicKey<T, M>
85where
86    T: UnsignedModularInt,
87    M: ModulusParams<Modulus = T>,
88{
89    fn hash<H: Hasher>(&self, state: &mut H) {
90        // Domain separator for RSA private keys
91        state.write(b"RsaPublicKey");
92        // TODO(tarcieri): to match the `PartialEq` impl we should strip leading zeros
93        state.write(self.n.as_ref().to_be_bytes().as_ref());
94        state.write(self.e.to_be_bytes().as_ref());
95    }
96}
97
98/// Generic RSA private key — heapless-compatible value type.
99///
100/// Holds the public components plus the secret exponent `d` — the raw
101/// `(n, e, d)` form. `primes` and the `precomputed` CRT values are
102/// alloc-gated; key generation is behind the `keygen` feature.
103pub struct GenericRsaPrivateKey<T, M>
104where
105    T: UnsignedModularInt + Zeroize,
106    M: ModulusParams<Modulus = T>,
107{
108    /// Public components of the private key.
109    pubkey_components: GenericRsaPublicKey<T, M>,
110    /// Private exponent.
111    d: T,
112    /// Prime factors of N (≥ 2 elements when populated), empty when
113    /// constructed without primes.
114    #[cfg(feature = "alloc")]
115    pub(crate) primes: alloc::vec::Vec<T>,
116    /// Precomputed CRT values, when available; `None` on the raw path.
117    #[cfg(feature = "alloc")]
118    pub(crate) precomputed: Option<PrecomputedValues<T, M>>,
119}
120
121// Manual `Clone`: the `M::MontgomeryForm: Clone` bound is only needed
122// when the `precomputed` field exists (alloc on). Keep it off the
123// no-alloc variant so backends without a `Clone` MontgomeryForm
124// still build.
125#[cfg(feature = "alloc")]
126impl<T, M> Clone for GenericRsaPrivateKey<T, M>
127where
128    T: UnsignedModularInt + Zeroize + Clone,
129    M: ModulusParams<Modulus = T> + Clone,
130    M::MontgomeryForm: Clone,
131{
132    fn clone(&self) -> Self {
133        Self {
134            pubkey_components: self.pubkey_components.clone(),
135            d: self.d.clone(),
136            primes: self.primes.clone(),
137            precomputed: self.precomputed.clone(),
138        }
139    }
140}
141
142#[cfg(not(feature = "alloc"))]
143impl<T, M> Clone for GenericRsaPrivateKey<T, M>
144where
145    T: UnsignedModularInt + Zeroize + Clone,
146    M: ModulusParams<Modulus = T> + Clone,
147{
148    fn clone(&self) -> Self {
149        Self {
150            pubkey_components: self.pubkey_components.clone(),
151            d: self.d.clone(),
152        }
153    }
154}
155
156// Manual `Debug` — never print `d`, so `{:?}` can't leak private material.
157impl<T, M> fmt::Debug for GenericRsaPrivateKey<T, M>
158where
159    T: UnsignedModularInt + Zeroize,
160    M: ModulusParams<Modulus = T>,
161    GenericRsaPublicKey<T, M>: fmt::Debug,
162{
163    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164        f.debug_struct("GenericRsaPrivateKey")
165            .field("pubkey_components", &self.pubkey_components)
166            .field("d", &"...")
167            .finish()
168    }
169}
170
171// Raw `(public_key, d)` constructor — gated on
172// [`RawPrivateKeyConstructible`], which `BoxedUint` doesn't impl, so it's
173// unreachable on the `RsaPrivateKey` alias. Alloc callers must use the
174// validated `from_components` / `from_p_q` / `from_primes` paths so empty
175// `primes` can't leak into CRT-aware APIs as a `primes[0]` panic.
176impl<T, M> GenericRsaPrivateKey<T, M>
177where
178    T: UnsignedModularInt + Zeroize + RawPrivateKeyConstructible,
179    M: ModulusParams<Modulus = T>,
180{
181    /// Construct from an already-built public key and the private
182    /// exponent `d`. No validation and no CRT precompute — the caller
183    /// owns the `e·d ≡ 1 mod λ(n)` relationship. For validated keys use
184    /// the alloc-side [`RsaPrivateKey::from_components`].
185    pub fn from_public_and_d(pubkey_components: GenericRsaPublicKey<T, M>, d: T) -> Self {
186        Self {
187            pubkey_components,
188            d,
189            #[cfg(feature = "alloc")]
190            primes: alloc::vec::Vec::new(),
191            #[cfg(feature = "alloc")]
192            precomputed: None,
193        }
194    }
195}
196
197impl<T, M> GenericRsaPrivateKey<T, M>
198where
199    T: UnsignedModularInt + Zeroize,
200    M: ModulusParams<Modulus = T>,
201{
202    /// Borrow the public-key components.
203    pub fn as_public(&self) -> &GenericRsaPublicKey<T, M> {
204        &self.pubkey_components
205    }
206}
207
208impl<T, M> PublicKeyParts<T> for GenericRsaPrivateKey<T, M>
209where
210    T: UnsignedModularInt + Zeroize,
211    M: ModulusParams<Modulus = T>,
212{
213    type MontyParams = M;
214
215    fn n(&self) -> &NonZero<T> {
216        self.pubkey_components.n()
217    }
218
219    fn e(&self) -> &T {
220        self.pubkey_components.e()
221    }
222
223    fn n_params(&self) -> &Self::MontyParams {
224        self.pubkey_components.n_params()
225    }
226}
227
228impl<T, M> PrivateKeyParts<T> for GenericRsaPrivateKey<T, M>
229where
230    T: UnsignedModularInt + Zeroize,
231    M: ModulusParams<Modulus = T>,
232{
233    fn d(&self) -> &T {
234        &self.d
235    }
236
237    #[cfg(feature = "alloc")]
238    fn primes(&self) -> &[T] {
239        &self.primes
240    }
241
242    #[cfg(feature = "alloc")]
243    fn dp(&self) -> Option<&T> {
244        self.precomputed.as_ref().map(|p| &p.dp)
245    }
246
247    #[cfg(feature = "alloc")]
248    fn dq(&self) -> Option<&T> {
249        self.precomputed.as_ref().map(|p| &p.dq)
250    }
251
252    #[cfg(feature = "alloc")]
253    fn qinv(&self) -> Option<&<Self::MontyParams as ModulusParams>::MontgomeryForm> {
254        self.precomputed.as_ref().map(|p| &p.qinv)
255    }
256
257    #[cfg(feature = "alloc")]
258    fn p_params(&self) -> Option<&Self::MontyParams> {
259        self.precomputed.as_ref().map(|p| &p.p_params)
260    }
261
262    #[cfg(feature = "alloc")]
263    fn q_params(&self) -> Option<&Self::MontyParams> {
264        self.precomputed.as_ref().map(|p| &p.q_params)
265    }
266}
267
268// `Zeroize` on the type; `Drop` delegates so the wipe lives in one place.
269// Everything except the pubkey components is secret.
270impl<T, M> Zeroize for GenericRsaPrivateKey<T, M>
271where
272    T: UnsignedModularInt + Zeroize,
273    M: ModulusParams<Modulus = T>,
274{
275    fn zeroize(&mut self) {
276        self.d.zeroize();
277        #[cfg(feature = "alloc")]
278        self.primes.zeroize();
279        #[cfg(feature = "alloc")]
280        self.precomputed.zeroize();
281    }
282}
283
284impl<T, M> Drop for GenericRsaPrivateKey<T, M>
285where
286    T: UnsignedModularInt + Zeroize,
287    M: ModulusParams<Modulus = T>,
288{
289    fn drop(&mut self) {
290        self.zeroize();
291    }
292}
293
294impl<T, M> ZeroizeOnDrop for GenericRsaPrivateKey<T, M>
295where
296    T: UnsignedModularInt + Zeroize,
297    M: ModulusParams<Modulus = T>,
298{
299}
300
301/// Boxed RSA private key alias used by the `alloc` code path.
302///
303/// `from_public_and_d` is unreachable through this alias — `BoxedUint`
304/// doesn't impl [`RawPrivateKeyConstructible`]:
305///
306/// ```compile_fail
307/// use rsa_heapless::RsaPrivateKey;
308/// fn must_not_compile(pub_key: rsa_heapless::RsaPublicKey, d: crypto_bigint::BoxedUint) {
309///     let _: RsaPrivateKey = RsaPrivateKey::from_public_and_d(pub_key, d);
310/// }
311/// ```
312#[cfg(feature = "alloc")]
313pub type RsaPrivateKey = GenericRsaPrivateKey<BoxedUint, BoxedMontyParams>;
314
315#[cfg(feature = "alloc")]
316impl Eq for RsaPrivateKey {}
317#[cfg(feature = "alloc")]
318impl PartialEq for RsaPrivateKey {
319    #[inline]
320    fn eq(&self, other: &RsaPrivateKey) -> bool {
321        self.pubkey_components == other.pubkey_components
322            && self.d == other.d
323            && self.primes == other.primes
324    }
325}
326
327#[cfg(feature = "alloc")]
328impl AsRef<RsaPublicKey> for RsaPrivateKey {
329    fn as_ref(&self) -> &RsaPublicKey {
330        &self.pubkey_components
331    }
332}
333
334#[cfg(feature = "alloc")]
335impl Hash for RsaPrivateKey {
336    fn hash<H: Hasher>(&self, state: &mut H) {
337        // Domain separator for RSA private keys
338        state.write(b"RsaPrivateKey");
339        Hash::hash(&self.pubkey_components, state);
340    }
341}
342
343#[cfg(feature = "alloc")]
344pub(crate) struct PrecomputedValues<T, M>
345where
346    T: UnsignedModularInt,
347    M: ModulusParams<Modulus = T>,
348{
349    /// D mod (P-1)
350    pub(crate) dp: T,
351    /// D mod (Q-1)
352    pub(crate) dq: T,
353    /// Q^-1 mod P
354    pub(crate) qinv: M::MontgomeryForm,
355
356    /// Montgomery params for `p`
357    pub(crate) p_params: M,
358    /// Montgomery params for `q`
359    pub(crate) q_params: M,
360}
361
362// Manual `Clone` — `#[derive]` wouldn't add the `M::MontgomeryForm: Clone`
363// bound, only `T: Clone` / `M: Clone`.
364#[cfg(feature = "alloc")]
365impl<T, M> Clone for PrecomputedValues<T, M>
366where
367    T: UnsignedModularInt + Clone,
368    M: ModulusParams<Modulus = T> + Clone,
369    M::MontgomeryForm: Clone,
370{
371    fn clone(&self) -> Self {
372        Self {
373            dp: self.dp.clone(),
374            dq: self.dq.clone(),
375            qinv: self.qinv.clone(),
376            p_params: self.p_params.clone(),
377            q_params: self.q_params.clone(),
378        }
379    }
380}
381
382#[cfg(feature = "alloc")]
383impl<T, M> ZeroizeOnDrop for PrecomputedValues<T, M>
384where
385    T: UnsignedModularInt,
386    M: ModulusParams<Modulus = T>,
387{
388}
389
390#[cfg(feature = "alloc")]
391impl<T, M> Zeroize for PrecomputedValues<T, M>
392where
393    T: UnsignedModularInt + Zeroize,
394    M: ModulusParams<Modulus = T>,
395{
396    fn zeroize(&mut self) {
397        self.dp.zeroize();
398        self.dq.zeroize();
399        // KNOWN GAP: `qinv`/`p_params`/`q_params` aren't wiped — the trait
400        // doesn't require `Zeroize` and upstream `BoxedMontyForm` /
401        // `BoxedMontyParams` don't impl it yet. Enable when they do:
402        // self.qinv.zeroize();
403        // self.p_params.zeroize();
404        // self.q_params.zeroize();
405    }
406}
407
408// Drop-check requires the bounds match the struct exactly. `Zeroize`
409// is a supertrait of `UnsignedModularInt`, so `self.zeroize()`
410// resolves here without an explicit bound.
411#[cfg(feature = "alloc")]
412impl<T, M> Drop for PrecomputedValues<T, M>
413where
414    T: UnsignedModularInt,
415    M: ModulusParams<Modulus = T>,
416{
417    fn drop(&mut self) {
418        self.zeroize();
419    }
420}
421
422#[cfg(feature = "alloc")]
423impl From<RsaPrivateKey> for GenericRsaPublicKey<BoxedUint, BoxedMontyParams> {
424    fn from(private_key: RsaPrivateKey) -> Self {
425        (&private_key).into()
426    }
427}
428
429#[cfg(feature = "alloc")]
430impl From<&RsaPrivateKey> for GenericRsaPublicKey<BoxedUint, BoxedMontyParams> {
431    fn from(private_key: &RsaPrivateKey) -> Self {
432        let public_key: &dyn PublicKeyParts<BoxedUint, MontyParams = BoxedMontyParams> =
433            private_key;
434        GenericRsaPublicKey {
435            n: public_key.n().clone(),
436            e: public_key.e().clone(),
437            n_params: public_key.n_params().clone(),
438        }
439    }
440}
441
442impl<T, M> PublicKeyParts<T> for GenericRsaPublicKey<T, M>
443where
444    T: UnsignedModularInt,
445    M: ModulusParams<Modulus = T>,
446{
447    type MontyParams = M;
448
449    fn n(&self) -> &NonZero<T> {
450        &self.n
451    }
452
453    fn e(&self) -> &T {
454        &self.e
455    }
456
457    fn n_params(&self) -> &M {
458        &self.n_params
459    }
460}
461
462impl<T, M> GenericRsaPublicKey<T, M>
463where
464    T: UnsignedModularInt,
465    M: ModulusParams<Modulus = T>,
466{
467    /// Create a public key from already-validated components and modulus parameters.
468    ///
469    /// This is intended for alternate bigint backends that prepare their own
470    /// modular arithmetic context outside the `BoxedUint` constructors.
471    pub fn from_components(n: T, e: T, n_params: M) -> Result<Self> {
472        let n = NonZero::new(n).ok_or(Error::InvalidModulus)?;
473        Ok(Self { n, e, n_params })
474    }
475}
476
477impl<T, M> GenericRsaPublicKey<T, M>
478where
479    T: UnsignedModularInt,
480    M: ModulusParams<Modulus = T>,
481{
482    /// Encrypt the given message.
483    #[cfg(feature = "alloc")]
484    pub fn encrypt<R: CryptoRng + ?Sized, P: PaddingScheme>(
485        &self,
486        rng: &mut R,
487        padding: P,
488        msg: &[u8],
489    ) -> Result<Vec<u8>>
490    where
491        M: crate::traits::modular::CtModulusParams,
492    {
493        padding.encrypt(rng, self, msg)
494    }
495
496    /// Verify a signed message.
497    ///
498    /// `hashed` must be the result of hashing the input using the hashing function
499    /// passed in through `hash`.
500    ///
501    /// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
502    pub fn verify<S: SignatureScheme>(&self, scheme: S, hashed: &[u8], sig: &[u8]) -> Result<()> {
503        scheme.verify(self, hashed, sig)
504    }
505}
506
507#[cfg(feature = "alloc")]
508impl GenericRsaPublicKey<BoxedUint, BoxedMontyParams> {
509    /// Minimum value of the public exponent `e`.
510    pub const MIN_PUB_EXPONENT: u64 = 2;
511
512    /// Maximum value of the public exponent `e`.
513    ///
514    /// Very large public exponents are a potential denial-of-service vector (a.k.a. "RSADoS")
515    /// because they increase the amount of work required for e.g. signature verification. See:
516    ///
517    /// <https://www.imperialviolet.org/2012/03/17/rsados.html>
518    ///
519    /// The particular constant below has been chosen to align with *ring* where this value was
520    /// selected based on the history of this particular issue, API compatibility concerns, and
521    /// benchmark-driven evaluation. See RustCrypto/RSA#155.
522    ///
523    /// If for some reason you have a legitimate reason to use keys with public exponents larger
524    /// than this value, use the special APIs:
525    ///
526    /// - [`RsaPublicKey::new_with_large_exp`]
527    /// - [`RsaPrivateKey::from_components_with_large_exponent`]
528    pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1;
529
530    /// Maximum size of the modulus `n` in bits.
531    pub const MAX_SIZE: usize = 8192;
532
533    /// Create a new public key from its components.
534    ///
535    /// This function accepts public keys with a modulus size up to 8192-bits,
536    /// i.e. [`RsaPublicKey::MAX_SIZE`].
537    pub fn new(n: BoxedUint, e: BoxedUint) -> Result<Self> {
538        Self::new_with_max_size(n, e, Self::MAX_SIZE)
539    }
540
541    /// Create a new public key from its components.
542    pub fn new_with_max_size(n: BoxedUint, e: BoxedUint, max_size: usize) -> Result<Self> {
543        check_public_with_max_size(&n, &e, Some(max_size))?;
544
545        let n_odd = CryptoOdd::new(n.clone())
546            .into_option()
547            .ok_or(Error::InvalidModulus)?;
548        let n_params = BoxedMontyParams::new(n_odd);
549        let n = NonZero::new(n).expect("checked above");
550
551        Ok(Self { n, e, n_params })
552    }
553
554    /// Create a new public key, bypassing checks around the modulus and public
555    /// exponent size.
556    ///
557    /// This method is not recommended, and only intended for unusual use cases.
558    /// Most applications should use [`RsaPublicKey::new`] or
559    /// [`RsaPublicKey::new_with_max_size`] instead.
560    pub fn new_unchecked(n: BoxedUint, e: BoxedUint) -> Self {
561        let n_odd = CryptoOdd::new(n.clone()).expect("n must be odd");
562        let n_params = BoxedMontyParams::new(n_odd);
563        let n = NonZero::new(n).expect("odd numbers are non zero");
564
565        Self { n, e, n_params }
566    }
567}
568
569#[cfg(feature = "alloc")]
570impl GenericRsaPrivateKey<BoxedUint, BoxedMontyParams> {
571    /// Default exponent for RSA keys.
572    const EXP: u64 = 65537;
573
574    /// Minimum size of the modulus `n` in bits. Currently only applies to keygen.
575    const MIN_SIZE: u32 = 1024;
576
577    /// Generate a new RSA key pair with a modulus of the given bit size using the passed in `rng`.
578    ///
579    /// # Errors
580    /// - If `bit_size` is lower than the minimum 1024-bits.
581    #[cfg(feature = "keygen")]
582    pub fn new<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
583        Self::new_with_exp(rng, bit_size, Self::EXP.into())
584    }
585
586    /// Generate a new RSA key pair of the given bit size.
587    ///
588    /// #⚠️Warning: Hazmat!
589    /// This version does not apply minimum key size checks, and as such may generate keys
590    /// which are insecure!
591    #[cfg(all(feature = "hazmat", feature = "keygen"))]
592    pub fn new_unchecked<R: CryptoRng + ?Sized>(rng: &mut R, bit_size: usize) -> Result<Self> {
593        Self::new_with_exp_unchecked(rng, bit_size, Self::EXP.into())
594    }
595
596    /// Generate a new RSA key pair of the given bit size and the public exponent
597    /// using the passed in `rng`.
598    ///
599    /// Unless you have specific needs, you should use [`RsaPrivateKey::new`] instead.
600    #[cfg(feature = "keygen")]
601    pub fn new_with_exp<R: CryptoRng + ?Sized>(
602        rng: &mut R,
603        bit_size: usize,
604        exp: BoxedUint,
605    ) -> Result<RsaPrivateKey> {
606        if bit_size < Self::MIN_SIZE as usize {
607            return Err(Error::ModulusTooSmall);
608        }
609
610        let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?;
611        RsaPrivateKey::from_components(
612            components.n.get(),
613            components.e,
614            components.d,
615            components.primes,
616        )
617    }
618
619    /// Generate a new RSA key pair of the given bit size and the public exponent
620    /// using the passed in `rng`.
621    ///
622    /// Unless you have specific needs, you should use [`RsaPrivateKey::new`] instead.
623    ///
624    /// #⚠️Warning: Hazmat!
625    /// This version does not apply minimum key size checks, and as such may generate keys
626    /// which are insecure!
627    #[cfg(all(feature = "hazmat", feature = "keygen"))]
628    pub fn new_with_exp_unchecked<R: CryptoRng + ?Sized>(
629        rng: &mut R,
630        bit_size: usize,
631        exp: BoxedUint,
632    ) -> Result<RsaPrivateKey> {
633        let components = generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)?;
634        RsaPrivateKey::from_components(
635            components.n.get(),
636            components.e,
637            components.d,
638            components.primes,
639        )
640    }
641
642    /// Private helper function that constructs an RSA key pair from components
643    /// WITHOUT performing any validation or precomputation.
644    ///
645    /// This is the shared implementation used by `from_components` and
646    /// `from_components_with_large_exponent`.
647    ///
648    /// Callers are responsible for:
649    /// 1. Validating the key (to ensure precomputation won't fail)
650    /// 2. Calling precompute() after validation
651    fn from_components_inner(
652        n: BoxedUint,
653        e: BoxedUint,
654        d: BoxedUint,
655        mut primes: Vec<BoxedUint>,
656    ) -> Result<RsaPrivateKey> {
657        let n = CryptoOdd::new(n)
658            .into_option()
659            .ok_or(Error::InvalidModulus)?;
660
661        // The modulus may come in padded with zeros, shorten it
662        // to ensure optimal performance of arithmetic operations.
663        let n_bits = n.bits_vartime();
664        let n = n.resize_unchecked(n_bits);
665
666        let n_params = BoxedMontyParams::new(n.clone());
667        let n_c = NonZero::new(n.get()).ok_or(Error::InvalidModulus)?;
668
669        match primes.len() {
670            0 => {
671                // Recover `p` and `q` from `d`.
672                // See method in Appendix C.2: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
673                let n_for_recovery =
674                    CryptoNonZero::new(n_c.as_ref().clone()).expect("modulus is non-zero");
675                let (p, q) = recover_primes(&n_for_recovery, &e, &d)?;
676                primes.push(p);
677                primes.push(q);
678            }
679            1 => return Err(Error::NprimesTooSmall),
680            _ => {
681                // Check that the product of primes matches the modulus.
682                // This also ensures that `bit_precision` of each prime is <= that of the modulus,
683                // and `bit_precision` of their product is >= that of the modulus.
684                if primes
685                    .iter()
686                    .fold(BoxedUint::one(), |acc, p| acc.concatenating_mul(&p))
687                    != n_c.as_ref()
688                {
689                    return Err(Error::InvalidModulus);
690                }
691            }
692        }
693
694        // The primes may come in padded with zeros too, so we need to shorten them as well.
695        let primes = primes
696            .into_iter()
697            .map(|p| {
698                let p_bits = p.bits();
699                p.resize_unchecked(p_bits)
700            })
701            .collect();
702
703        let k = RsaPrivateKey {
704            pubkey_components: RsaPublicKey {
705                n: n_c,
706                e,
707                n_params,
708            },
709            d,
710            primes,
711            precomputed: None,
712        };
713
714        Ok(k)
715    }
716
717    /// Constructs an RSA key pair from individual components, accepting exponents outside
718    /// the normal size bounds.
719    ///
720    /// See [`RsaPrivateKey::from_components`] for an explanation on the parameters.
721    ///
722    /// # ⚠️ Warning: Hazmat!
723    ///
724    /// This method accepts public exponents outside the standard bounds (2 ≤ e ≤ 2^33-1),
725    /// but still performs full cryptographic validation to ensure the key is mathematically
726    /// correct (i.e., verifies that de ≡ 1 mod λ(n)).
727    ///
728    /// **Note:** This method is dangerous as it can be used as a DOS vector if used with
729    /// untrusted input https://www.imperialviolet.org/2012/03/17/rsados.html
730    ///
731    /// This is intended for interoperating with systems that use non-standard exponents
732    /// or loading legacy keys. Use [`RsaPrivateKey::from_components`] for standard key
733    /// construction.
734    #[cfg(all(feature = "hazmat", feature = "alloc"))]
735    pub fn from_components_with_large_exponent(
736        n: BoxedUint,
737        e: BoxedUint,
738        d: BoxedUint,
739        primes: Vec<BoxedUint>,
740    ) -> Result<RsaPrivateKey> {
741        let mut k = Self::from_components_inner(n, e, d, primes)?;
742
743        // Validate everything except exponent size bounds (to ensure precompute can't fail)
744        validate_skip_exponent_size(&k)?;
745
746        // Precompute when possible, ignore error otherwise.
747        k.precompute().ok();
748
749        Ok(k)
750    }
751
752    /// Constructs an RSA key pair from individual components:
753    ///
754    /// - `n`: RSA modulus
755    /// - `e`: public exponent (i.e. encrypting exponent)
756    /// - `d`: private exponent (i.e. decrypting exponent)
757    /// - `primes`: prime factors of `n`: typically two primes `p` and `q`. More than two primes can
758    ///   be provided for multiprime RSA, however this is generally not recommended. If no `primes`
759    ///   are provided, a prime factor recovery algorithm will be employed to attempt to recover the
760    ///   factors (as described in [NIST SP 800-56B Revision 2] Appendix C.2). This algorithm only
761    ///   works if there are just two prime factors `p` and `q` (as opposed to multiprime), and `e`
762    ///   is between 2^16 and 2^256.
763    ///
764    ///  [NIST SP 800-56B Revision 2]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
765    pub fn from_components(
766        n: BoxedUint,
767        e: BoxedUint,
768        d: BoxedUint,
769        primes: Vec<BoxedUint>,
770    ) -> Result<RsaPrivateKey> {
771        let mut k = Self::from_components_inner(n, e, d, primes)?;
772
773        // Always validate the key, to ensure precompute can't fail
774        k.validate()?;
775
776        // Precompute when possible, ignore error otherwise.
777        k.precompute().ok();
778
779        Ok(k)
780    }
781
782    /// Constructs an RSA key pair from its two primes p and q.
783    ///
784    /// This will rebuild the private exponent and the modulus.
785    ///
786    /// Private exponent will be rebuilt using the method defined in
787    /// [NIST 800-56B Section 6.2.1](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf#page=47).
788    pub fn from_p_q(
789        p: BoxedUint,
790        q: BoxedUint,
791        public_exponent: BoxedUint,
792    ) -> Result<RsaPrivateKey> {
793        if p == q {
794            return Err(Error::InvalidPrime);
795        }
796
797        let d = compute_private_exponent_carmicheal(&p, &q, &public_exponent)?;
798        let primes = vec![p, q];
799        let n = compute_modulus(&primes);
800
801        Self::from_components(n.get(), public_exponent, d, primes)
802    }
803
804    /// Constructs an RSA key pair from its primes.
805    ///
806    /// This will rebuild the private exponent and the modulus.
807    pub fn from_primes(
808        primes: Vec<BoxedUint>,
809        public_exponent: BoxedUint,
810    ) -> Result<RsaPrivateKey> {
811        if primes.len() < 2 {
812            return Err(Error::NprimesTooSmall);
813        }
814
815        // Makes sure that the primes are pairwise unequal.
816        for (i, prime1) in primes.iter().enumerate() {
817            for prime2 in primes.iter().take(i) {
818                if prime1 == prime2 {
819                    return Err(Error::InvalidPrime);
820                }
821            }
822        }
823
824        let n = compute_modulus(&primes);
825        let d = compute_private_exponent_euler_totient(&primes, &public_exponent)?;
826
827        Self::from_components(n.get(), public_exponent, d, primes)
828    }
829
830    /// Get the public key from the private key.
831    ///
832    /// Specific alternative to [`AsRef::as_ref`].
833    pub fn as_public_key(&self) -> &RsaPublicKey {
834        &self.pubkey_components
835    }
836
837    /// Get the public key from the private key, cloning `n` and `e`.
838    ///
839    /// Generally this is not needed since `RsaPrivateKey` implements the `PublicKey` trait,
840    /// but it can occasionally be useful to discard the private information entirely.
841    pub fn to_public_key(&self) -> RsaPublicKey {
842        self.pubkey_components.clone()
843    }
844
845    /// Performs some calculations to speed up private key operations.
846    pub fn precompute(&mut self) -> Result<()> {
847        if self.precomputed.is_some() {
848            return Ok(());
849        }
850
851        let d = &self.d;
852        let p = self.primes[0].clone();
853        let q = self.primes[1].clone();
854
855        let p_odd = CryptoOdd::new(p.clone())
856            .into_option()
857            .ok_or(Error::InvalidPrime)?;
858        let p_params = BoxedMontyParams::new(p_odd);
859        let q_odd = CryptoOdd::new(q.clone())
860            .into_option()
861            .ok_or(Error::InvalidPrime)?;
862        let q_params = BoxedMontyParams::new(q_odd);
863
864        let x = CryptoNonZero::new(p.wrapping_sub(BoxedUint::one()))
865            .into_option()
866            .ok_or(Error::InvalidPrime)?;
867        let dp = d.rem_vartime(&x);
868
869        let x = CryptoNonZero::new(q.wrapping_sub(BoxedUint::one()))
870            .into_option()
871            .ok_or(Error::InvalidPrime)?;
872        let dq = d.rem_vartime(&x);
873
874        // Note that since `p` and `q` may have different `bits_precision`,
875        // so we have to equalize them to calculate the remainder.
876        let q_mod_p = match p.bits_precision().cmp(&q.bits_precision()) {
877            Ordering::Less => {
878                let p_wide = CryptoNonZero::new(p.clone())
879                    .expect("`p` is non-zero")
880                    .resize_unchecked(q.bits_precision());
881                (&q % p_wide).resize_unchecked(p.bits_precision())
882            }
883            Ordering::Greater => {
884                (&q).resize_unchecked(p.bits_precision())
885                    % &CryptoNonZero::new(p.clone()).expect("`p` is non-zero")
886            }
887            Ordering::Equal => &q % CryptoNonZero::new(p.clone()).expect("`p` is non-zero"),
888        };
889
890        let q_mod_p = BoxedMontyForm::new(q_mod_p, &p_params);
891        let qinv = q_mod_p.invert().into_option().ok_or(Error::InvalidPrime)?;
892
893        debug_assert_eq!(dp.bits_precision(), p.bits_precision());
894        debug_assert_eq!(dq.bits_precision(), q.bits_precision());
895        debug_assert_eq!(qinv.bits_precision(), p.bits_precision());
896        debug_assert_eq!(p_params.bits_precision(), p.bits_precision());
897        debug_assert_eq!(q_params.bits_precision(), q.bits_precision());
898
899        self.precomputed = Some(PrecomputedValues {
900            dp,
901            dq,
902            qinv,
903            p_params,
904            q_params,
905        });
906
907        Ok(())
908    }
909
910    /// Clears precomputed values by setting to None
911    pub fn clear_precomputed(&mut self) {
912        self.precomputed = None;
913    }
914
915    /// Compute CRT coefficient: `(1/q) mod p`.
916    pub fn crt_coefficient(&self) -> Option<BoxedUint> {
917        let p = &self.primes[0];
918        let q = &self.primes[1];
919        // TODO: maybe store primes as `NonZero`?
920        Option::from(q.invert_mod(&CryptoNonZero::new(p.clone()).expect("prime")))
921    }
922
923    /// Performs basic sanity checks on the key.
924    /// Returns `Ok(())` if everything is good, otherwise an appropriate error.
925    pub fn validate(&self) -> Result<()> {
926        check_public(self)?;
927        validate_private_key_parts(self)?;
928        Ok(())
929    }
930
931    /// Decrypt the given message.
932    pub fn decrypt<P: PaddingScheme>(&self, padding: P, ciphertext: &[u8]) -> Result<Vec<u8>> {
933        padding.decrypt(Option::<&mut DummyRng>::None, self, ciphertext)
934    }
935
936    /// Decrypt the given message.
937    ///
938    /// Uses `rng` to blind the decryption process.
939    pub fn decrypt_blinded<R: CryptoRng + ?Sized, P: PaddingScheme>(
940        &self,
941        rng: &mut R,
942        padding: P,
943        ciphertext: &[u8],
944    ) -> Result<Vec<u8>> {
945        padding.decrypt(Some(rng), self, ciphertext)
946    }
947
948    /// Sign the given digest.
949    pub fn sign<S: SignatureScheme>(&self, padding: S, digest_in: &[u8]) -> Result<Vec<u8>> {
950        padding.sign(Option::<&mut DummyRng>::None, self, digest_in)
951    }
952
953    /// Sign the given digest using the provided `rng`, which is used in the
954    /// following ways depending on the [`SignatureScheme`]:
955    ///
956    /// - [`Pkcs1v15Sign`][`crate::Pkcs1v15Sign`] padding: uses the RNG
957    ///   to mask the private key operation with random blinding, which helps
958    ///   mitigate sidechannel attacks.
959    /// - [`Pss`][`crate::Pss`] always requires randomness. Use
960    ///   [`Pss::new`][`crate::Pss::new`] for a standard RSASSA-PSS signature, or
961    ///   [`Pss::new_blinded`][`crate::Pss::new_blinded`] for RSA-BSSA blind
962    ///   signatures.
963    pub fn sign_with_rng<R: CryptoRng + ?Sized, S: SignatureScheme>(
964        &self,
965        rng: &mut R,
966        padding: S,
967        digest_in: &[u8],
968    ) -> Result<Vec<u8>> {
969        padding.sign(Some(rng), self, digest_in)
970    }
971}
972
973/// Check that the public key is well formed and has an exponent within acceptable bounds.
974#[inline]
975#[cfg(feature = "alloc")]
976pub fn check_public(public_key: &impl PublicKeyParts<BoxedUint>) -> Result<()> {
977    check_public_with_max_size(public_key.n().as_ref(), public_key.e(), None)
978}
979
980/// Check that the public key is well formed and has an exponent within acceptable bounds.
981#[inline]
982#[cfg(feature = "alloc")]
983fn check_public_with_max_size(n: &BoxedUint, e: &BoxedUint, max_size: Option<usize>) -> Result<()> {
984    if let Some(max_size) = max_size {
985        if n.bits_vartime() as usize > max_size {
986            return Err(Error::ModulusTooLarge);
987        }
988    }
989
990    check_public_skip_exponent_size(n, e)?;
991
992    if e < &BoxedUint::from(RsaPublicKey::MIN_PUB_EXPONENT) {
993        return Err(Error::PublicExponentTooSmall);
994    }
995
996    if e > &BoxedUint::from(RsaPublicKey::MAX_PUB_EXPONENT) {
997        return Err(Error::PublicExponentTooLarge);
998    }
999
1000    Ok(())
1001}
1002
1003/// Check that the public key is well formed, skipping exponent size bounds checks.
1004///
1005/// This is used internally by both public validation functions and hazmat APIs.
1006#[inline]
1007#[cfg(feature = "alloc")]
1008fn check_public_skip_exponent_size(n: &BoxedUint, e: &BoxedUint) -> Result<()> {
1009    if e >= n || n.is_even().into() || n.is_zero().into() {
1010        return Err(Error::InvalidModulus);
1011    }
1012
1013    if e.is_even().into() {
1014        return Err(Error::InvalidExponent);
1015    }
1016
1017    // Skip exponent size bounds checks
1018    Ok(())
1019}
1020
1021/// Helper function that validates the private key structure and cryptographic correctness.
1022///
1023/// This performs the structural and mathematical validation checks that are common to both
1024/// `validate()` and `validate_skip_exponent_size()`.
1025#[cfg(feature = "alloc")]
1026fn validate_private_key_parts(key: &RsaPrivateKey) -> Result<()> {
1027    // Check that Πprimes == n.
1028    let mut m = BoxedUint::one_with_precision(key.pubkey_components.n.bits_precision());
1029    let one = BoxedUint::one();
1030    for prime in &key.primes {
1031        // Any primes ≤ 1 will cause divide-by-zero panics later.
1032        if prime <= &one {
1033            return Err(Error::InvalidPrime);
1034        }
1035        m = m.wrapping_mul(prime);
1036    }
1037    if m != *key.pubkey_components.n.as_ref() {
1038        return Err(Error::InvalidModulus);
1039    }
1040
1041    // Check that de ≡ 1 mod p-1, for each prime.
1042    // This implies that e is coprime to each p-1 as e has a multiplicative
1043    // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) =
1044    // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1
1045    // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required.
1046    let de = key.d.concatenating_mul(&key.pubkey_components.e);
1047
1048    for prime in &key.primes {
1049        let x = CryptoNonZero::new(prime.wrapping_sub(BoxedUint::one())).unwrap();
1050        let congruence = de.rem_vartime(&x);
1051        if !bool::from(congruence.is_one()) {
1052            return Err(Error::InvalidExponent);
1053        }
1054    }
1055
1056    Ok(())
1057}
1058
1059/// Validate the private key structure and cryptographic correctness,
1060/// skipping only the exponent size bounds checks.
1061///
1062/// This performs all the same checks as `RsaPrivateKey::validate()` except
1063/// it doesn't verify that the exponent is within the standard bounds.
1064#[cfg(all(feature = "hazmat", feature = "alloc"))]
1065fn validate_skip_exponent_size(key: &RsaPrivateKey) -> Result<()> {
1066    // Check public key properties (without exponent size checks)
1067    check_public_skip_exponent_size(key.pubkey_components.n.as_ref(), &key.pubkey_components.e)?;
1068
1069    // Perform common private key validation
1070    validate_private_key_parts(key)?;
1071
1072    Ok(())
1073}
1074
1075#[cfg(feature = "serde")]
1076impl Serialize for RsaPublicKey {
1077    fn serialize<S>(&self, serializer: S) -> core::prelude::v1::Result<S::Ok, S::Error>
1078    where
1079        S: serdect::serde::Serializer,
1080    {
1081        let der = self.to_public_key_der().map_err(ser::Error::custom)?;
1082        serdect::slice::serialize_hex_lower_or_bin(&der, serializer)
1083    }
1084}
1085
1086#[cfg(feature = "serde")]
1087impl<'de> Deserialize<'de> for RsaPublicKey {
1088    fn deserialize<D>(deserializer: D) -> core::prelude::v1::Result<Self, D::Error>
1089    where
1090        D: serdect::serde::Deserializer<'de>,
1091    {
1092        let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
1093        Self::from_public_key_der(&der_bytes).map_err(de::Error::custom)
1094    }
1095}
1096
1097#[cfg(feature = "serde")]
1098impl Serialize for RsaPrivateKey {
1099    fn serialize<S>(&self, serializer: S) -> core::prelude::v1::Result<S::Ok, S::Error>
1100    where
1101        S: ser::Serializer,
1102    {
1103        let der = self.to_pkcs8_der().map_err(ser::Error::custom)?;
1104        serdect::slice::serialize_hex_lower_or_bin(&der.as_bytes(), serializer)
1105    }
1106}
1107
1108#[cfg(feature = "serde")]
1109impl<'de> Deserialize<'de> for RsaPrivateKey {
1110    fn deserialize<D>(deserializer: D) -> core::prelude::v1::Result<Self, D::Error>
1111    where
1112        D: de::Deserializer<'de>,
1113    {
1114        let der_bytes = serdect::slice::deserialize_hex_or_bin_vec(deserializer)?;
1115        Self::from_pkcs8_der(&der_bytes).map_err(de::Error::custom)
1116    }
1117}
1118
1119#[cfg(test)]
1120#[cfg(feature = "alloc")]
1121mod tests {
1122    use super::*;
1123    use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
1124    use crate::traits::{PrivateKeyParts, PublicKeyParts};
1125
1126    use hex_literal::hex;
1127    use rand::rngs::ChaCha8Rng;
1128    use rand_core::SeedableRng;
1129
1130    #[cfg(feature = "encoding")]
1131    use pkcs8::DecodePrivateKey;
1132
1133    #[test]
1134    fn test_from_into() {
1135        let raw_n = BoxedUint::from(101u64);
1136        let n_odd = CryptoOdd::new(raw_n.clone()).unwrap();
1137        let private_key = RsaPrivateKey {
1138            pubkey_components: RsaPublicKey {
1139                n: NonZero::new(raw_n.clone()).unwrap(),
1140                e: BoxedUint::from(200u64),
1141                n_params: BoxedMontyParams::new(n_odd),
1142            },
1143            d: BoxedUint::from(123u64),
1144            primes: vec![],
1145            precomputed: None,
1146        };
1147        let public_key: RsaPublicKey = private_key.into();
1148
1149        let n_limbs: &[u64] = PublicKeyParts::n(&public_key).as_ref().as_ref();
1150        assert_eq!(n_limbs, &[101u64]);
1151        assert_eq!(PublicKeyParts::e(&public_key), &BoxedUint::from(200u64));
1152        assert_eq!(PublicKeyParts::e_bytes(&public_key), [200].into());
1153        assert_eq!(PublicKeyParts::n_bytes(&public_key), [101].into());
1154    }
1155
1156    fn test_key_basics(private_key: &RsaPrivateKey) {
1157        private_key.validate().expect("invalid private key");
1158
1159        assert!(
1160            PrivateKeyParts::d(private_key) < PublicKeyParts::n(private_key).as_ref(),
1161            "private exponent too large"
1162        );
1163
1164        let pub_key: RsaPublicKey = private_key.clone().into();
1165        let m = BoxedUint::from(42u64);
1166        let c = rsa_encrypt(&pub_key, &m).expect("encryption successful");
1167
1168        let m2 = rsa_decrypt_and_check::<ChaCha8Rng>(private_key, None, &c)
1169            .expect("unable to decrypt without blinding");
1170        assert_eq!(m, m2);
1171        let mut rng = ChaCha8Rng::from_seed([42; 32]);
1172        let m3 = rsa_decrypt_and_check(private_key, Some(&mut rng), &c)
1173            .expect("unable to decrypt with blinding");
1174        assert_eq!(m, m3);
1175    }
1176
1177    macro_rules! key_generation {
1178        ($name:ident, $multi:expr, $size:expr) => {
1179            #[cfg(feature = "keygen")]
1180            #[test]
1181            fn $name() {
1182                let mut rng = ChaCha8Rng::from_seed([42; 32]);
1183                let exp = BoxedUint::from(RsaPrivateKey::EXP);
1184
1185                for _ in 0..10 {
1186                    let components =
1187                        generate_multi_prime_key_with_exp(&mut rng, $multi, $size, exp.clone())
1188                            .unwrap();
1189                    let private_key = RsaPrivateKey::from_components(
1190                        components.n.get(),
1191                        components.e,
1192                        components.d,
1193                        components.primes,
1194                    )
1195                    .unwrap();
1196                    assert_eq!(PublicKeyParts::n(&private_key).bits(), $size);
1197
1198                    test_key_basics(&private_key);
1199                }
1200            }
1201        };
1202    }
1203
1204    key_generation!(key_generation_128, 2, 128);
1205    key_generation!(key_generation_1024, 2, 1024);
1206
1207    key_generation!(key_generation_multi_3_256, 3, 256);
1208
1209    key_generation!(key_generation_multi_4_64, 4, 64);
1210
1211    key_generation!(key_generation_multi_5_64, 5, 64);
1212    key_generation!(key_generation_multi_8_576, 8, 576);
1213    key_generation!(key_generation_multi_16_1024, 16, 1024);
1214
1215    #[test]
1216    fn test_negative_decryption_value() {
1217        let bits = 128;
1218        let private_key = RsaPrivateKey::from_components(
1219            BoxedUint::from_le_slice(
1220                &[
1221                    99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180,
1222                ],
1223                bits,
1224            )
1225            .unwrap(),
1226            BoxedUint::from_le_slice(&[1, 0, 1, 0, 0, 0, 0, 0], 64).unwrap(),
1227            BoxedUint::from_le_slice(
1228                &[
1229                    81, 163, 254, 144, 171, 159, 144, 42, 244, 133, 51, 249, 28, 12, 63, 65,
1230                ],
1231                bits,
1232            )
1233            .unwrap(),
1234            vec![
1235                BoxedUint::from_le_slice(&[105, 101, 60, 173, 19, 153, 3, 192], bits / 2).unwrap(),
1236                BoxedUint::from_le_slice(&[235, 65, 160, 134, 32, 136, 6, 241], bits / 2).unwrap(),
1237            ],
1238        )
1239        .unwrap();
1240
1241        for _ in 0..1000 {
1242            test_key_basics(&private_key);
1243        }
1244    }
1245
1246    #[test]
1247    #[cfg(all(feature = "hazmat", feature = "serde", feature = "keygen"))]
1248    fn test_serde() {
1249        use rand::rngs::ChaCha8Rng;
1250        use rand_core::SeedableRng;
1251        use serde_test::{assert_tokens, Configure, Token};
1252
1253        let mut rng = ChaCha8Rng::from_seed([42; 32]);
1254        let priv_key = RsaPrivateKey::new_unchecked(&mut rng, 64).expect("failed to generate key");
1255
1256        let priv_tokens = [Token::Str(concat!(
1257            "3056020100300d06092a864886f70d010101050004423040020100020900a",
1258            "b240c3361d02e370203010001020811e54a15259d22f9020500ceff5cf302",
1259            "0500d3a7aaad020500ccaddf17020500cb529d3d020500bb526d6f"
1260        ))];
1261        assert_tokens(&priv_key.clone().readable(), &priv_tokens);
1262
1263        let priv_tokens = [Token::Str(
1264            "3024300d06092a864886f70d01010105000313003010020900ab240c3361d02e370203010001",
1265        )];
1266        assert_tokens(
1267            &RsaPublicKey::from(priv_key.clone()).readable(),
1268            &priv_tokens,
1269        );
1270    }
1271
1272    #[test]
1273    fn invalid_coeff_private_key_regression() {
1274        use base64ct::{Base64, Encoding};
1275
1276        let n = Base64::decode_vec(
1277            "wC8GyQvTCZOK+iiBR5fGQCmzRCTWX9TQ3aRG5gGFk0wB6EFoLMAyEEqeG3gS8xhA\
1278             m2rSWYx9kKufvNat3iWlbSRVqkcbpVAYlj2vTrpqDpJl+6u+zxFYoUEBevlJJkAh\
1279             l8EuCccOA30fVpcfRvXPTtvRd3yFT9E9EwZljtgSI02w7gZwg7VIxaGeajh5Euz6\
1280             ZVQZ+qNRKgXrRC7gPRqVyI6Dt0Jc+Su5KBGNn0QcPDzOahWha1ieaeMkFisZ9mdp\
1281             sJoZ4tw5eicLaUomKzALHXQVt+/rcZSrCd6/7uUo11B/CYBM4UfSpwXaL88J9AE6\
1282             A5++no9hmJzaF2LLp+Qwx4yY3j9TDutxSAjsraxxJOGZ3XyA9nG++Ybt3cxZ5fP7\
1283             ROjxCfROBmVv5dYn0O9OBIqYeCH6QraNpZMadlLNIhyMv8Y+P3r5l/PaK4VJaEi5\
1284             pPosnEPawp0W0yZDzmjk2z1LthaRx0aZVrAjlH0Rb/6goLUQ9qu1xsDtQVVpN4A8\
1285             9ZUmtTWORnnJr0+595eHHxssd2gpzqf4bPjNITdAEuOCCtpvyi4ls23zwuzryUYj\
1286             cUOEnsXNQ+DrZpLKxdtsD/qNV/j1hfeyBoPllC3cV+6bcGOFcVGbjYqb+Kw1b0+j\
1287             L69RSKQqgmS+qYqr8c48nDRxyq3QXhR8qtzUwBFSLVk=",
1288        )
1289        .unwrap();
1290        let e = Base64::decode_vec("AQAB").unwrap();
1291        let d = Base64::decode_vec(
1292            "qQazSQ+FRN7nVK1bRsROMRB8AmsDwLVEHivlz1V3Td2Dr+oW3YUMgxedhztML1Id\
1293             QJPq/ad6qErJ6yRFNySVIjDaxzBTOEoB1eHa1btOnBJWb8rVvvjaorixvJ6Tn3i4\
1294             EuhsvVy9DoR1k4rGj3qSIiFjUVvLRDAbLyhpGgEfsr0Z577yJmTC5E8JLRMOKX8T\
1295             mxsk3jPVpsgd65Hu1s8S/ZmabwuHCf9SkdMeY/1bd/9i7BqqJeeDLE4B5x1xcC3z\
1296             3scqDUTzqGO+vZPhjgprPDRlBamVwgenhr7KwCn8iaLamFinRVwOAag8BeBqOJj7\
1297             lURiOsKQa9FIX1kdFUS1QMQxgtPycLjkbvCJjriqT7zWKsmJ7l8YLs6Wmm9/+QJR\
1298             wNCEVdMTXKfCP1cJjudaiskEQThfUldtgu8gUDNYbQ/Filb2eKfiX4h1TiMxZqUZ\
1299             HVZyb9nShbQoXJ3vj/MGVF0QM8TxhXM8r2Lv9gDYU5t9nQlUMLhs0jVjai48jHAB\
1300             bFNyH3sEcOmJOIwJrCXw1dzG7AotwyaEVUHOmL04TffmwCFfnyrLjbFgnyOeoyII\
1301             BYjcY7QFRm/9nupXMTH5hZ2qrHfCJIp0KK4tNBdQqmnHapFl5l6Le1s4qBS5bEIz\
1302             jitobLvAFm9abPlDGfxmY6mlrMK4+nytwF9Ct7wc1AE=",
1303        )
1304        .unwrap();
1305        let primes = [
1306            Base64::decode_vec(
1307                "9kQWEAzsbzOcdPa+s5wFfw4XDd7bB1q9foZ31b1+TNjGNxbSBCFlDF1q98vwpV6n\
1308                 M8bWDh/wtbNoETSQDgpEnYOQ26LWEw6YY1+q1Q2GGEFceYUf+Myk8/vTc8TN6Zw0\
1309                 bKZBWy10Qo8h7xk4JpzuI7NcxvjJYTkS9aErFxi3vVH0aiZC0tmfaCqr8a2rJxyV\
1310                 wqreRpOjwAWrotMsf2wGsF4ofx5ScoFy5GB5fJkkdOrW1LyTvZAUCX3cstPr19+T\
1311                 NC5zZOk7WzZatnCkN5H5WzalWtZuu0oVL205KPOa3R8V2yv5e6fm0v5fTmqSuvjm\
1312                 aMJLXCN4QJkmIzojO99ckQ==",
1313            )
1314            .unwrap(),
1315            Base64::decode_vec(
1316                "x8exdMjVA2CiI+Thx7loHtVcevoeE2sZ7btRVAvmBqo+lkHwxb7FHRnWvuj6eJSl\
1317                 D2f0T50EewIhhiW3R9BmktCk7hXjbSCnC1u9Oxc1IAUm/7azRqyfCMx43XhLxpD+\
1318                 xkBCpWkKDLxGczsRwTuaP3lKS3bSdBrNlGmdblubvVBIq4YZ2vXVlnYtza0cS+dg\
1319                 CK7BGTqUsrCUd/ZbIvwcwZkZtpkhj1KQfto9X/0OMurBzAqbkeq1cyRHXHkOfN/q\
1320                 bUIIRqr9Ii7Eswf9Vk8xp2O1Nt8nzcYS9PFD12M5eyaeFEkEYfpNMNGuTzp/31oq\
1321                 VjbpoCxS6vuWAZyADxhISQ==",
1322            )
1323            .unwrap(),
1324            Base64::decode_vec(
1325                "is7d0LY4HoXszlC2NO7gejkq7XqL4p1W6hZJPYTNx+r37t1CC2n3Vvzg6kNdpRix\
1326                 DhIpXVTLjN9O7UO/XuqSumYKJIKoP52eb4Tg+a3hw5Iz2Zsb5lUTNSLgkQSBPAf7\
1327                 1LHxbL82JL4g1nBUog8ae60BwnVArThKY4EwlJguGNw09BAU4lwf6csDl/nX2vfV\
1328                 wiAloYpeZkHL+L8m+bueGZM5KE2jEz+7ztZCI+T+E5i69rZEYDjx0lfLKlEhQlCW\
1329                 3HbCPELqXgNJJkRfi6MP9kXa9lSfnZmoT081RMvqonB/FUa4HOcKyCrw9XZEtnbN\
1330                 CIdbitfDVEX+pSSD7596wQ==",
1331            )
1332            .unwrap(),
1333            Base64::decode_vec(
1334                "GPs0injugfycacaeIP5jMa/WX55VEnKLDHom4k6WlfDF4L4gIGoJdekcPEUfxOI5\
1335                 faKvHyFwRP1wObkPoRBDM0qZxRfBl4zEtpvjHrd5MibSyJkM8+J0BIKk/nSjbRIG\
1336                 eb3hV5O56PvGB3S0dKhCUnuVObiC+ne7izplsD4OTG70l1Yud33UFntyoMxrxGYL\
1337                 USqhBMmZfHquJg4NOWOzKNY/K+EcHDLj1Kjvkcgv9Vf7ocsVxvpFdD9uGPceQ6kw\
1338                 RDdEl6mb+6FDgWuXVyqR9+904oanEIkbJ7vfkthagLbEf57dyG6nJlqh5FBZWxGI\
1339                 R72YGypPuAh7qnnqXXjY2Q==",
1340            )
1341            .unwrap(),
1342            Base64::decode_vec(
1343                "CUWC+hRWOT421kwRllgVjy6FYv6jQUcgDNHeAiYZnf5HjS9iK2ki7v8G5dL/0f+Y\
1344                 f+NhE/4q8w4m8go51hACrVpP1p8GJDjiT09+RsOzITsHwl+ceEKoe56ZW6iDHBLl\
1345                 rNw5/MtcYhKpjNU9KJ2udm5J/c9iislcjgckrZG2IB8ADgXHMEByZ5DgaMl4AKZ1\
1346                 Gx8/q6KftTvmOT5rNTMLi76VN5KWQcDWK/DqXiOiZHM7Nr4dX4me3XeRgABJyNR8\
1347                 Fqxj3N1+HrYLe/zs7LOaK0++F9Ul3tLelhrhsvLxei3oCZkF9A/foD3on3luYA+1\
1348                 cRcxWpSY3h2J4/22+yo4+Q==",
1349            )
1350            .unwrap(),
1351        ];
1352
1353        let e = BoxedUint::from_be_slice(&e, 64).unwrap();
1354
1355        let bits = 4096;
1356        let n = BoxedUint::from_be_slice(&n, bits).unwrap();
1357        let d = BoxedUint::from_be_slice(&d, bits).unwrap();
1358        let primes = primes
1359            .iter()
1360            .map(|p| BoxedUint::from_be_slice(p, bits / 2).unwrap())
1361            .collect();
1362        let res = RsaPrivateKey::from_components(n, e, d, primes);
1363        assert_eq!(res, Err(Error::InvalidModulus));
1364    }
1365
1366    #[test]
1367    fn reject_oversized_private_key() {
1368        // -----BEGIN PUBLIC KEY-----
1369        // MIIEKjANBgkqhkiG9w0BAQEFAAOCBBcAMIIEEgKCBAkAqQn6O7pd9ioQJEOwS2sh
1370        // nD2bM3+PaLovro+OKOE9t7jxrp+b9Xq81oeT6zN5u5yPewa+V08ZsAJQEbF9D5AM
1371        // UZkHZc/sW/XAItC8CojQhHoCQfjOXZpONmGsQxnSJNgwLV5TDVKUApbQIPzIm9yD
1372        // wOvl1yXIypaRINHzthz36ysHmaHlNVZZQ40BHVkOiUd+ws7W9U9vHN0QcaSHC8lH
1373        // UEqb/Iyb0FSmZs+qbm4NXyaI90oloAFftOnt8VFbHfT/TXS0VwMyescxFsuvcuTr
1374        // Xx8EYc9TuJThW22wBAFOK6SpftgtZ6i4WJqk0F8JrTwZ3TyhzKsPRwe8KeNmtmqY
1375        // oaGiPj9lUOc928QzOyTETVd8pV7UpnaOe9Q4WHL0QmnXn61pCu4qpoLuK8jB+IO7
1376        // xifRZHj3PMfsjJurZ4MF57LgpSrI60ekYNh1o6ViXODHQuzGxzTaF3n/7GITDBQX
1377        // DRTlGuQH77hykxFqPclRGI0wxECPKasxpzjhiaTua9eipKedXB+o5XFyosnDt/X4
1378        // Ygqxj/q2/18LPuQgFLqWRzsHd4TdVQyiq9xCmzIoGUjAPz1Q8cjIXRpUnp2rZQjE
1379        // SCLeTjewrGNbjSMDUhdF5M2OBRmn7Q8XHHCUxT9fY/BZeydeE54KvEdEkomxkbXo
1380        // hHKEmbWeEdhp78h04/xW364p1Nu9Y49w7gtO+9nmwKcpNJq32M6Qb0d2dQ3wJ0oI
1381        // I9ml+n/DTna+IIwwbI8UOFEI4KZQzZaqmNv3TzGmpnocHK7eMyEtAUeQZUIGrPmr
1382        // FQEmKZn9rkgr/2Hw8T20q7e0lE65Is69vTP2wXm17B5zKFYska41jJoZ6jIpbMOt
1383        // uVPZV3SoGYM39Z4Ax3JaGZE0L/dQ6lJJhdFUACFIQXwNWqzd7srnvbym4hLqoPuM
1384        // hjkUtTcv6YODEk7LB2FLDcymmH/zCL3w4VSi4+HyZZ13gM7Cz8WmkX4H+jeL0+Ja
1385        // QyG1CzqV/HA78vUpJv/bb/J1+X1i/1HltLeTjteY4rBhVT1cxBoVBGQaCwindAs+
1386        // Fjcp+8cAK+/3pMQghnkrGHzrx9YIYoOGXs4vQIMGngYaTa7aXAaft4fWjg4EeSjd
1387        // rZwqqrPNuUcEuneFP9RPffj8f3vkhqCFgoVBfVM7ontu2d2nRu/hhAkgT13Uc68J
1388        // dM2imBvHAo6DDUt6msWCAMOAEXYuO7aA+n3eettnBqtECoQAoCJdCHCebjIploMB
1389        // XMLXyseGtLK9arI48hDvcxSlf7/1lkBB6LgNQmQJ7925TDipiYQIZ63f4d5Z2JCp
1390        // W0vUkwzrH4iPb2hy+TBQSOw1kvjLyG/lHWjzDQa60xxVW9u59DxQueHsNEMHUORD
1391        // 1oFXvFLe/AllAgMBAAE=
1392        // -----END PUBLIC KEY-----
1393
1394        let n = BoxedUint::from_be_slice(
1395            &hex!(
1396                "a909fa3bba5df62a102443b04b6b219c3d9b337f8f68ba2fae8f8e28e13db7b8
1397                 f1ae9f9bf57abcd68793eb3379bb9c8f7b06be574f19b0025011b17d0f900c51
1398                 990765cfec5bf5c022d0bc0a88d0847a0241f8ce5d9a4e3661ac4319d224d830
1399                 2d5e530d52940296d020fcc89bdc83c0ebe5d725c8ca969120d1f3b61cf7eb2b
1400                 0799a1e5355659438d011d590e89477ec2ced6f54f6f1cdd1071a4870bc94750
1401                 4a9bfc8c9bd054a666cfaa6e6e0d5f2688f74a25a0015fb4e9edf1515b1df4ff
1402                 4d74b45703327ac73116cbaf72e4eb5f1f0461cf53b894e15b6db004014e2ba4
1403                 a97ed82d67a8b8589aa4d05f09ad3c19dd3ca1ccab0f4707bc29e366b66a98a1
1404                 a1a23e3f6550e73ddbc4333b24c44d577ca55ed4a6768e7bd4385872f44269d7
1405                 9fad690aee2aa682ee2bc8c1f883bbc627d16478f73cc7ec8c9bab678305e7b2
1406                 e0a52ac8eb47a460d875a3a5625ce0c742ecc6c734da1779ffec62130c14170d
1407                 14e51ae407efb87293116a3dc951188d30c4408f29ab31a738e189a4ee6bd7a2
1408                 a4a79d5c1fa8e57172a2c9c3b7f5f8620ab18ffab6ff5f0b3ee42014ba96473b
1409                 077784dd550ca2abdc429b32281948c03f3d50f1c8c85d1a549e9dab6508c448
1410                 22de4e37b0ac635b8d2303521745e4cd8e0519a7ed0f171c7094c53f5f63f059
1411                 7b275e139e0abc47449289b191b5e884728499b59e11d869efc874e3fc56dfae
1412                 29d4dbbd638f70ee0b4efbd9e6c0a729349ab7d8ce906f4776750df0274a0823
1413                 d9a5fa7fc34e76be208c306c8f14385108e0a650cd96aa98dbf74f31a6a67a1c
1414                 1caede33212d014790654206acf9ab1501262999fdae482bff61f0f13db4abb7
1415                 b4944eb922cebdbd33f6c179b5ec1e7328562c91ae358c9a19ea32296cc3adb9
1416                 53d95774a8198337f59e00c7725a1991342ff750ea524985d154002148417c0d
1417                 5aacddeecae7bdbca6e212eaa0fb8c863914b5372fe98383124ecb07614b0dcc
1418                 a6987ff308bdf0e154a2e3e1f2659d7780cec2cfc5a6917e07fa378bd3e25a43
1419                 21b50b3a95fc703bf2f52926ffdb6ff275f97d62ff51e5b4b7938ed798e2b061
1420                 553d5cc41a1504641a0b08a7740b3e163729fbc7002beff7a4c42086792b187c
1421                 ebc7d6086283865ece2f4083069e061a4daeda5c069fb787d68e0e047928ddad
1422                 9c2aaab3cdb94704ba77853fd44f7df8fc7f7be486a0858285417d533ba27b6e
1423                 d9dda746efe18409204f5dd473af0974cda2981bc7028e830d4b7a9ac58200c3
1424                 8011762e3bb680fa7dde7adb6706ab440a8400a0225d08709e6e32299683015c
1425                 c2d7cac786b4b2bd6ab238f210ef7314a57fbff5964041e8b80d426409efddb9
1426                 4c38a989840867addfe1de59d890a95b4bd4930ceb1f888f6f6872f9305048ec
1427                 3592f8cbc86fe51d68f30d06bad31c555bdbb9f43c50b9e1ec34430750e443d6
1428                 8157bc52defc0965"
1429            ),
1430            8256,
1431        )
1432        .unwrap();
1433
1434        let e = BoxedUint::from(65_537u64);
1435
1436        assert_eq!(
1437            RsaPublicKey::new(n, e).err().unwrap(),
1438            Error::ModulusTooLarge
1439        );
1440    }
1441
1442    #[test]
1443    #[cfg(feature = "encoding")]
1444    fn build_key_from_primes() {
1445        const RSA_2048_PRIV_DER: &[u8] = include_bytes!("../tests/examples/pkcs8/rsa2048-priv.der");
1446        let ref_key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap();
1447        assert_eq!(ref_key.validate(), Ok(()));
1448
1449        let primes = PrivateKeyParts::primes(&ref_key).to_vec();
1450
1451        let exp = PublicKeyParts::e(&ref_key);
1452        let key = RsaPrivateKey::from_primes(primes, exp.clone())
1453            .expect("failed to import key from primes");
1454        assert_eq!(key.validate(), Ok(()));
1455
1456        assert_eq!(PublicKeyParts::n(&key), PublicKeyParts::n(&ref_key));
1457
1458        assert_eq!(PrivateKeyParts::dp(&key), PrivateKeyParts::dp(&ref_key));
1459        assert_eq!(PrivateKeyParts::dq(&key), PrivateKeyParts::dq(&ref_key));
1460
1461        assert_eq!(PrivateKeyParts::d(&key), PrivateKeyParts::d(&ref_key));
1462    }
1463
1464    #[test]
1465    #[cfg(feature = "encoding")]
1466    fn build_key_from_p_q() {
1467        const RSA_2048_SP800_PRIV_DER: &[u8] =
1468            include_bytes!("../tests/examples/pkcs8/rsa2048-sp800-56b-priv.der");
1469        let ref_key = RsaPrivateKey::from_pkcs8_der(RSA_2048_SP800_PRIV_DER).unwrap();
1470        assert_eq!(ref_key.validate(), Ok(()));
1471
1472        let primes = PrivateKeyParts::primes(&ref_key).to_vec();
1473        let exp = PublicKeyParts::e(&ref_key);
1474
1475        let key = RsaPrivateKey::from_p_q(primes[0].clone(), primes[1].clone(), exp.clone())
1476            .expect("failed to import key from primes");
1477        assert_eq!(key.validate(), Ok(()));
1478
1479        assert_eq!(PublicKeyParts::n(&key), PublicKeyParts::n(&ref_key));
1480
1481        assert_eq!(PrivateKeyParts::dp(&key), PrivateKeyParts::dp(&ref_key));
1482        assert_eq!(PrivateKeyParts::dq(&key), PrivateKeyParts::dq(&ref_key));
1483
1484        assert_eq!(PrivateKeyParts::d(&key), PrivateKeyParts::d(&ref_key));
1485    }
1486
1487    #[test]
1488    #[cfg(all(feature = "hazmat", feature = "keygen"))]
1489    fn test_from_components_with_large_exponent() {
1490        // Test that from_components_with_large_exponent accepts exponents outside normal bounds
1491        // while from_components would reject them
1492
1493        use rand::rngs::ChaCha8Rng;
1494        use rand_core::SeedableRng;
1495
1496        let mut rng = ChaCha8Rng::from_seed([42; 32]);
1497
1498        // Use an exponent larger than the normal maximum (2^33 - 1)
1499        let large_e = BoxedUint::from((1u64 << 34) + 1); // 2^34 + 1 (odd number)
1500
1501        // Generate a key with this large exponent
1502        let components =
1503            generate_multi_prime_key_with_exp(&mut rng, 2, 1024, large_e.clone()).unwrap();
1504
1505        // Extract components
1506        let n = components.n.get().clone();
1507        let d = components.d;
1508        let primes = components.primes;
1509
1510        // from_components should fail with PublicExponentTooLarge
1511        let result =
1512            RsaPrivateKey::from_components(n.clone(), large_e.clone(), d.clone(), primes.clone());
1513        assert!(result.is_err());
1514        assert_eq!(result.unwrap_err(), Error::PublicExponentTooLarge);
1515
1516        // from_components_with_large_exponent should succeed
1517        let key_with_large_exp = RsaPrivateKey::from_components_with_large_exponent(
1518            n.clone(),
1519            large_e.clone(),
1520            d.clone(),
1521            primes.clone(),
1522        );
1523        assert!(key_with_large_exp.is_ok());
1524
1525        let key_with_large_exp = key_with_large_exp.unwrap();
1526        assert_eq!(PublicKeyParts::e(&key_with_large_exp), &large_e);
1527        assert_eq!(PublicKeyParts::n(&key_with_large_exp).as_ref(), &n);
1528        assert_eq!(PrivateKeyParts::d(&key_with_large_exp), &d);
1529
1530        // Verify that the key is still cryptographically valid (de ≡ 1 mod λ(n))
1531        // by checking that validation with skip_exponent_size passes
1532        assert!(validate_skip_exponent_size(&key_with_large_exp).is_ok());
1533    }
1534
1535    #[test]
1536    #[cfg(all(feature = "hazmat", feature = "keygen"))]
1537    fn test_from_components_with_small_exponent() {
1538        // Test that from_components_with_large_exponent accepts exponents below normal minimum
1539        // (despite the name, it works for any non-standard exponent size)
1540
1541        use rand::rngs::ChaCha8Rng;
1542        use rand_core::SeedableRng;
1543
1544        let mut rng = ChaCha8Rng::from_seed([43; 32]);
1545
1546        // Use an exponent smaller than the normal minimum (2)
1547        let small_e = BoxedUint::from(1u64); // This is odd, which is required
1548
1549        // Generate a key with this small exponent
1550        let components =
1551            generate_multi_prime_key_with_exp(&mut rng, 2, 1024, small_e.clone()).unwrap();
1552
1553        // Extract components
1554        let n = components.n.get().clone();
1555        let d = components.d;
1556        let primes = components.primes;
1557
1558        // from_components should fail
1559        let result =
1560            RsaPrivateKey::from_components(n.clone(), small_e.clone(), d.clone(), primes.clone());
1561        assert!(result.is_err());
1562
1563        // from_components_with_large_exponent should succeed
1564        let key_with_small_exp = RsaPrivateKey::from_components_with_large_exponent(
1565            n.clone(),
1566            small_e.clone(),
1567            d.clone(),
1568            primes,
1569        );
1570        assert!(key_with_small_exp.is_ok());
1571
1572        let key_with_small_exp = key_with_small_exp.unwrap();
1573        assert_eq!(PublicKeyParts::e(&key_with_small_exp), &small_e);
1574
1575        // Verify that the key is cryptographically valid
1576        assert!(validate_skip_exponent_size(&key_with_small_exp).is_ok());
1577    }
1578
1579    /// Regression test for CVE-2026-21895 / GHSA-9c48-w39g-hm26.
1580    ///
1581    /// Loading a secret key whose prime factor is `1` must be rejected with
1582    /// `Error::InvalidPrime` rather than panicking via a divide-by-zero in
1583    /// the validation/precompute path.
1584    ///
1585    /// Adapted from the test added in upstream commit 2926c91bef (PR #624);
1586    /// the original used `num-bigint` `BigUint` types, this version uses
1587    /// `crypto-bigint` `BoxedUint` and goes through
1588    /// `from_components_with_large_exponent` so the small (out-of-range) `e`
1589    /// can be supplied verbatim from the original test.
1590    #[test]
1591    #[cfg(feature = "hazmat")]
1592    fn test_key_invalid_primes() {
1593        let e = RsaPrivateKey::from_components_with_large_exponent(
1594            BoxedUint::from(239u64),
1595            BoxedUint::from(185u64),
1596            BoxedUint::from(0u64),
1597            vec![BoxedUint::from(1u64), BoxedUint::from(239u64)],
1598        )
1599        .unwrap_err();
1600        assert_eq!(e, Error::InvalidPrime);
1601    }
1602}