rsa_heapless/
key.rs

1use core::hash::{Hash, Hasher};
2use num_integer::Integer;
3use num_traits::{FromPrimitive, One, ToPrimitive};
4use rand_core::CryptoRngCore;
5use zeroize::{Zeroize, ZeroizeOnDrop};
6#[cfg(feature = "serde")]
7use {
8    serdect::serde::{de, ser, Deserialize, Serialize},
9};
10
11
12use crate::traits::{modular::MontyParams, UnsignedModularInt, modular::MontyForm};
13
14use crate::algorithms::rsa::{
15    compute_modulus, compute_private_exponent_carmicheal, compute_private_exponent_euler_totient,
16    recover_primes,
17};
18
19use crate::dummy_rng::DummyRng;
20use crate::errors::{Error, Result};
21use crate::traits::keys::{CrtValue, PrivateKeyParts, PublicKeyParts};
22use crate::traits::{PaddingScheme, SignatureScheme};
23
24/// Represents the public part of an RSA key.
25#[derive(Debug, Clone)]
26pub struct RsaPublicKey<T>
27where
28    T: UnsignedModularInt,
29{
30    /// Modulus: product of prime numbers `p` and `q`
31    n: T,
32    /// Public exponent: power to which a plaintext message is raised in
33    /// order to encrypt it.
34    ///
35    /// Typically `0x10001` (`65537`)
36    e: T,
37
38    n_params: MontyParams<T>,
39}
40
41impl<T: UnsignedModularInt> Eq for RsaPublicKey<T> {}
42
43impl<T: UnsignedModularInt> PartialEq for RsaPublicKey<T> {
44    #[inline]
45    fn eq(&self, other: &RsaPublicKey<T>) -> bool {
46        self.n == other.n && self.e == other.e
47    }
48}
49
50impl<T: UnsignedModularInt> Hash for RsaPublicKey<T> {
51    fn hash<H: Hasher>(&self, state: &mut H) {
52        // Domain separator for RSA private keys
53        state.write(b"RsaPublicKey");
54        todo!()
55    }
56}
57
58/// Represents a whole RSA key, public and private parts.
59#[derive(Debug, Clone)]
60pub struct RsaPrivateKey<T>
61where
62    T: UnsignedModularInt,
63{
64    /// Public components of the private key.
65    pubkey_components: RsaPublicKey<T>,
66    /// Private exponent
67    pub(crate) d: T,
68    /// Prime factors of N, contains >= 2 elements.
69    pub(crate) primes: [T; 4],
70    /// precomputed values to speed up private operations
71    pub(crate) precomputed: Option<PrecomputedValues<T>>,
72}
73
74impl<T: UnsignedModularInt> Eq for RsaPrivateKey<T> {}
75impl<T: UnsignedModularInt> PartialEq for RsaPrivateKey<T> {
76    #[inline]
77    fn eq(&self, other: &Self) -> bool {
78        self.pubkey_components == other.pubkey_components
79            && self.d == other.d
80            && self.primes == other.primes
81    }
82}
83
84impl<T: UnsignedModularInt> AsRef<RsaPublicKey<T>> for RsaPrivateKey<T> {
85    fn as_ref(&self) -> &RsaPublicKey<T> {
86        &self.pubkey_components
87    }
88}
89
90impl<T: UnsignedModularInt> Hash for RsaPrivateKey<T> {
91    fn hash<H: Hasher>(&self, state: &mut H) {
92        // Domain separator for RSA private keys
93        state.write(b"RsaPrivateKey");
94        Hash::hash(&self.pubkey_components, state);
95    }
96}
97
98impl<T: UnsignedModularInt> Drop for RsaPrivateKey<T> {
99    fn drop(&mut self) {
100        self.d.zeroize();
101        self.primes.zeroize();
102        self.precomputed.zeroize();
103    }
104}
105
106impl<T: UnsignedModularInt> ZeroizeOnDrop for RsaPrivateKey<T> {}
107
108#[derive(Debug, Clone)]
109pub(crate) struct PrecomputedValues<T: Zeroize + UnsignedModularInt> {
110    /// D mod (P-1)
111    pub(crate) dp: T,
112    /// D mod (Q-1)
113    pub(crate) dq: T,
114    /// Q^-1 mod P
115    pub(crate) qinv: MontyForm<T>,
116
117    /// Montgomery params for `p`
118    pub(crate) p_params: MontyParams<T>,
119    /// Montgomery params for `q`
120    pub(crate) q_params: MontyParams<T>,
121}
122
123impl<T: Zeroize + UnsignedModularInt> ZeroizeOnDrop for PrecomputedValues<T> {}
124
125impl<T: Zeroize + UnsignedModularInt> Zeroize for PrecomputedValues<T> {
126    fn zeroize(&mut self) {
127        self.dp.zeroize();
128        self.dq.zeroize();
129        // TODO: once these have landed in crypto-bigint
130        // self.p_params.zeroize();
131        // self.q_params.zeroize();
132    }
133}
134
135impl<T: UnsignedModularInt> Drop for PrecomputedValues<T> {
136    fn drop(&mut self) {
137        self.zeroize();
138    }
139}
140
141impl<T: UnsignedModularInt> From<RsaPrivateKey<T>> for RsaPublicKey<T> {
142    fn from(private_key: RsaPrivateKey<T>) -> Self {
143        todo!()
144    }
145}
146
147impl<T: UnsignedModularInt> From<&RsaPrivateKey<T>> for RsaPublicKey<T> {
148    fn from(private_key: &RsaPrivateKey<T>) -> Self {
149        let n = PublicKeyParts::n(private_key);
150        let e = PublicKeyParts::e(private_key);
151        let n_params = PublicKeyParts::n_params(private_key);
152        RsaPublicKey {
153            n: n.clone(),
154            e: e.clone(),
155            n_params: n_params.clone(),
156        }
157    }
158}
159
160impl<T: UnsignedModularInt> PublicKeyParts<T> for RsaPublicKey<T> {
161    fn n(&self) -> &T {
162        &self.n
163    }
164
165    fn e(&self) -> &T {
166        &self.e
167    }
168    fn n_params(&self) -> &MontyParams<T> {
169        todo!()
170    }
171}
172
173impl<T: UnsignedModularInt + Clone> RsaPublicKey<T> {
174    /// Encrypt the given message.
175    pub fn encrypt<R: CryptoRngCore, P: PaddingScheme<T>>(
176        &self,
177        rng: &mut R,
178        padding: P,
179        msg: &[u8],
180        storage: &mut [u8],
181    ) -> Result<()> {
182        padding.encrypt(rng, self, msg, storage).map(|_| ())
183    }
184
185    /// Verify a signed message.
186    ///
187    /// `hashed` must be the result of hashing the input using the hashing function
188    /// passed in through `hash`.
189    ///
190    /// If the message is valid `Ok(())` is returned, otherwise an `Err` indicating failure.
191    pub fn verify<S: SignatureScheme<T>>(
192        &self,
193        scheme: S,
194        hashed: &[u8],
195        sig: &[u8],
196    ) -> Result<()> {
197        scheme.verify(self, hashed, sig)
198    }
199}
200
201impl<T: UnsignedModularInt> RsaPublicKey<T> {
202    /// Minimum value of the public exponent `e`.
203    pub const MIN_PUB_EXPONENT: u64 = 2;
204
205    /// Maximum value of the public exponent `e`.
206    pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1;
207
208    /// Maximum size of the modulus `n` in bits.
209    pub const MAX_SIZE: usize = 4096;
210
211    /// Create a new public key from its components.
212    ///
213    /// This function accepts public keys with a modulus size up to 4096-bits,
214    /// i.e. [`RsaPublicKey::MAX_SIZE`].
215    pub fn new(n: T, e: T) -> Result<Self> {
216        Self::new_with_max_size(n, e, Self::MAX_SIZE)
217    }
218
219    /// Create a new public key from its components.
220    pub fn new_with_max_size(n: T, e: T, max_size: usize) -> Result<Self> {
221        check_public_with_max_size(&n, &e, max_size)?;
222
223        let n_odd = n.clone();
224        let n_params = MontyParams::new(n_odd);
225
226        Ok(Self { n, e, n_params })
227    }
228
229    /// Create a new public key, bypassing checks around the modulus and public
230    /// exponent size.
231    ///
232    /// This method is not recommended, and only intended for unusual use cases.
233    /// Most applications should use [`RsaPublicKey::new`] or
234    /// [`RsaPublicKey::new_with_max_size`] instead.
235    pub fn new_unchecked(n: T, e: T) -> Self {
236        todo!()
237    }
238}
239
240impl<T: UnsignedModularInt> PublicKeyParts<T> for RsaPrivateKey<T> {
241    fn n(&self) -> &T {
242        &self.pubkey_components.n
243    }
244
245    fn e(&self) -> &T {
246        &self.pubkey_components.e
247    }
248
249    fn n_params(&self) -> &MontyParams<T> {
250        todo!()
251    }
252}
253
254impl<T: UnsignedModularInt> RsaPrivateKey<T> {
255    /// Default exponent for RSA keys.
256    const EXP: u64 = 65537;
257
258    /// Generate a new Rsa key pair of the given bit size using the passed in `rng`.
259    pub fn new<R: CryptoRngCore>(rng: &mut R, bit_size: usize) -> Result<RsaPrivateKey<T>> {
260        todo!()
261    }
262
263    /// Generate a new RSA key pair of the given bit size and the public exponent
264    /// using the passed in `rng`.
265    ///
266    /// Unless you have specific needs, you should use `RsaPrivateKey::new` instead.
267    pub fn new_with_exp<R: CryptoRngCore>(
268        rng: &mut R,
269        bit_size: usize,
270        exp: T,
271    ) -> Result<RsaPrivateKey<T>> {
272        todo!()
273    }
274
275    /// Constructs an RSA key pair from individual components:
276    ///
277    /// - `n`: RSA modulus
278    /// - `e`: public exponent (i.e. encrypting exponent)
279    /// - `d`: private exponent (i.e. decrypting exponent)
280    /// - `primes`: prime factors of `n`: typically two primes `p` and `q`. More than two primes can
281    ///   be provided for multiprime RSA, however this is generally not recommended. If no `primes`
282    ///   are provided, a prime factor recovery algorithm will be employed to attempt to recover the
283    ///   factors (as described in [NIST SP 800-56B Revision 2] Appendix C.2). This algorithm only
284    ///   works if there are just two prime factors `p` and `q` (as opposed to multiprime), and `e`
285    ///   is between 2^16 and 2^256.
286    ///
287    ///  [NIST SP 800-56B Revision 2]: https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf
288    pub fn from_components(n: T, e: T, d: T, mut primes: [T; 4]) -> Result<Self> {
289        todo!("")
290    }
291
292    /// Constructs an RSA key pair from its two primes p and q.
293    ///
294    /// This will rebuild the private exponent and the modulus.
295    ///
296    /// Private exponent will be rebuilt using the method defined in
297    /// [NIST 800-56B Section 6.2.1](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-56Br2.pdf#page=47).
298    pub fn from_p_q(p: T, q: T, public_exponent: T) -> Result<Self> {
299        if p == q {
300            return Err(Error::InvalidPrime);
301        }
302        todo!()
303    }
304
305    /// Constructs an RSA key pair from its primes.
306    ///
307    /// This will rebuild the private exponent and the modulus.
308    pub fn from_primes(primes: [T; 4], public_exponent: T) -> Result<Self> {
309        if primes.len() < 2 {
310            return Err(Error::NprimesTooSmall);
311        }
312
313        // Makes sure that the primes are pairwise unequal.
314        for (i, prime1) in primes.iter().enumerate() {
315            for prime2 in primes.iter().take(i) {
316                if prime1 == prime2 {
317                    return Err(Error::InvalidPrime);
318                }
319            }
320        }
321        todo!()
322    }
323
324    /// Get the public key from the private key, cloning `n` and `e`.
325    ///
326    /// Generally this is not needed since `RsaPrivateKey` implements the `PublicKey` trait,
327    /// but it can occasionally be useful to discard the private information entirely.
328    pub fn to_public_key(&self) -> RsaPublicKey<T> {
329        self.pubkey_components.clone()
330    }
331
332    /// Performs some calculations to speed up private key operations.
333    pub fn precompute(&mut self) -> Result<()> {
334        if self.precomputed.is_some() {
335            return Ok(());
336        }
337        todo!()
338    }
339
340    /// Clears precomputed values by setting to None
341    pub fn clear_precomputed(&mut self) {
342        self.precomputed = None;
343    }
344
345    /// Compute CRT coefficient: `(1/q) mod p`.
346    pub fn crt_coefficient(&self) -> Option<T> {
347        todo!()
348    }
349
350    /// Performs basic sanity checks on the key.
351    /// Returns `Ok(())` if everything is good, otherwise an appropriate error.
352    pub fn validate(&self) -> Result<()> {
353        check_public(self)?;
354
355        // Check that Πprimes == n.
356        let mut m = T::one();
357        for prime in &self.primes {
358            // Any primes ≤ 1 will cause divide-by-zero panics later.
359            if *prime < T::one() {
360                return Err(Error::InvalidPrime);
361            }
362            m = m * *prime;
363        }
364        if m != self.pubkey_components.n {
365            return Err(Error::InvalidModulus);
366        }
367
368        // Check that de ≡ 1 mod p-1, for each prime.
369        // This implies that e is coprime to each p-1 as e has a multiplicative
370        // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) =
371        // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1
372        // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required.
373        let mut de = *self.e();
374        de = de * self.d;
375        for prime in &self.primes {
376            let congruence: T = de % (*prime - T::one());
377            if !congruence.is_one() {
378                return Err(Error::InvalidExponent);
379            }
380        }
381
382        Ok(())
383    }
384
385    /// Decrypt the given message.
386    pub fn decrypt<P: PaddingScheme<T>>(&self, padding: P, ciphertext: &[u8], storage: &mut [u8]) -> Result<&[u8]> {
387        todo!()
388    }
389
390    /// Decrypt the given message.
391    ///
392    /// Uses `rng` to blind the decryption process.
393    pub fn decrypt_blinded<R: CryptoRngCore, P: PaddingScheme<T>>(
394        &self,
395        rng: &mut R,
396        padding: P,
397        ciphertext: &[u8],
398        storage: &mut [u8],
399    ) -> Result<&[u8]> {
400        todo!()
401    }
402
403    /// Sign the given digest.
404    pub fn sign<S: SignatureScheme<T>>(&self, padding: S, digest_in: &[u8], storage: &mut [u8]) -> Result<&[u8]> {
405        todo!()
406    }
407
408    /// Sign the given digest using the provided `rng`, which is used in the
409    /// following ways depending on the [`SignatureScheme`]:
410    ///
411    /// - [`Pkcs1v15Sign`][`crate::Pkcs1v15Sign`] padding: uses the RNG
412    ///   to mask the private key operation with random blinding, which helps
413    ///   mitigate sidechannel attacks.
414    /// - [`Pss`][`crate::Pss`] always requires randomness. Use
415    ///   [`Pss::new`][`crate::Pss::new`] for a standard RSASSA-PSS signature, or
416    ///   [`Pss::new_blinded`][`crate::Pss::new_blinded`] for RSA-BSSA blind
417    ///   signatures.
418    pub fn sign_with_rng<R: CryptoRngCore, S: SignatureScheme<T>>(
419        &self,
420        rng: &mut R,
421        padding: S,
422        digest_in: &[u8],
423        storage: &mut [u8],
424    ) -> Result<&[u8]> {
425        todo!()
426    }
427}
428
429impl<T: UnsignedModularInt> PrivateKeyParts<T> for RsaPrivateKey<T> {
430    fn d(&self) -> &T {
431        &self.d
432    }
433
434    fn primes(&self) -> &[T] {
435        &self.primes
436    }
437
438    fn dp(&self) -> Option<&T> {
439        self.precomputed.as_ref().map(|p| &p.dp)
440    }
441
442    fn dq(&self) -> Option<&T> {
443        self.precomputed.as_ref().map(|p| &p.dq)
444    }
445
446    fn qinv(&self) -> Option<&MontyForm<T>> {
447        todo!()
448    }
449
450    fn crt_values(&self) -> Option<&[CrtValue<T>]> {
451        /* for some reason the standard self.precomputed.as_ref().map() doesn't work */
452        if let Some(p) = &self.precomputed {
453            todo!()
454        } else {
455            None
456        }
457    }
458
459    fn p_params(&self) -> Option<&MontyParams<T>> {
460        todo!()
461    }
462
463    fn q_params(&self) -> Option<&MontyParams<T>> {
464        todo!()
465    }
466    
467}
468
469/// Check that the public key is well formed and has an exponent within acceptable bounds.
470#[inline]
471pub fn check_public<T>(public_key: &impl PublicKeyParts<T>) -> Result<()>
472where
473    T: UnsignedModularInt,
474{
475        check_public_with_max_size(public_key.n(), public_key.e(), RsaPublicKey::<T>::MAX_SIZE)
476}
477
478/// Check that the public key is well formed and has an exponent within acceptable bounds.
479#[inline]
480fn check_public_with_max_size<T>(n: &T, e: &T, max_size: usize) -> Result<()>
481where
482    T: UnsignedModularInt,
483{
484    if n.bits_precision() as usize > max_size {
485        return Err(Error::ModulusTooLarge);
486    }
487
488    if e >= n || n.is_even().into() || n.is_zero().into() {
489        return Err(Error::InvalidModulus);
490    }
491
492    if e.is_even().into() {
493        return Err(Error::InvalidExponent);
494    }
495
496    // I want to use num_traits::FromPrimitive here for conversion
497
498    if e < &T::from(RsaPublicKey::<T>::MIN_PUB_EXPONENT).unwrap() {
499        return Err(Error::PublicExponentTooSmall);
500    }
501
502    if e > &T::from(RsaPublicKey::<T>::MAX_PUB_EXPONENT).unwrap() {
503        return Err(Error::PublicExponentTooLarge);
504    }
505
506    Ok(())
507}
508
509#[cfg(feature = "serde")]
510impl<T> Serialize for RsaPublicKey<T>
511where
512    T: UnsignedModularInt,
513{
514    fn serialize<S>(&self, serializer: S) -> core::prelude::v1::Result<S::Ok, S::Error>
515    where
516        S: serdect::serde::Serializer,
517    {
518        todo!()
519    }
520}
521
522#[cfg(feature = "serde")]
523impl<'de, T> Deserialize<'de> for RsaPublicKey<T>
524where
525    T: UnsignedModularInt,
526{
527    fn deserialize<D>(deserializer: D) -> core::prelude::v1::Result<Self, D::Error>
528    where
529        D: serdect::serde::Deserializer<'de>,
530    {
531        todo!()
532    }
533}
534
535#[cfg(feature = "serde")]
536impl<T> Serialize for RsaPrivateKey<T>
537where
538    T: UnsignedModularInt,
539{
540    fn serialize<S>(&self, serializer: S) -> core::prelude::v1::Result<S::Ok, S::Error>
541    where
542        S: ser::Serializer,
543    {
544        todo!()
545    }
546}
547
548#[cfg(feature = "serde")]
549impl<'de, T> Deserialize<'de> for RsaPrivateKey<T>
550where
551    T: UnsignedModularInt,
552{
553    fn deserialize<D>(deserializer: D) -> core::prelude::v1::Result<Self, D::Error>
554    where
555        D: de::Deserializer<'de>,
556    {
557        todo!()
558    }
559}
560
561#[cfg(test)]
562mod tests {
563    use super::*;
564    use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
565    use crate::traits::{PrivateKeyParts, PublicKeyParts};
566
567    use hex_literal::hex;
568    use num_traits::{FromPrimitive, ToPrimitive};
569    use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
570
571    #[test]
572    #[ignore]
573    fn test_from_into() {
574        todo!()
575    }
576
577    fn test_key_basics<T>(private_key: &RsaPrivateKey<T>)
578    where
579        T: UnsignedModularInt,
580    {
581        private_key.validate().expect("invalid private key");
582
583        assert!(
584            PrivateKeyParts::d(private_key) < PublicKeyParts::n(private_key),
585            "private exponent too large"
586        );
587
588        todo!()
589    }
590
591    macro_rules! key_generation {
592        ($name:ident, $multi:expr, $size:expr) => {
593            #[test]
594            #[ignore]
595            fn $name() {
596                todo!()
597            }
598        };
599    }
600
601    key_generation!(key_generation_128, 2, 128);
602    key_generation!(key_generation_1024, 2, 1024);
603
604    key_generation!(key_generation_multi_3_256, 3, 256);
605
606    key_generation!(key_generation_multi_4_64, 4, 64);
607
608    key_generation!(key_generation_multi_5_64, 5, 64);
609    key_generation!(key_generation_multi_8_576, 8, 576);
610    // TODO: reenable, currently slow
611    // key_generation!(key_generation_multi_16_1024, 16, 1024);
612
613    #[test]
614    #[ignore]
615    fn test_negative_decryption_value() {
616        todo!()
617    }
618
619    #[test]
620    #[cfg(feature = "serde")]
621    fn test_serde() {
622        use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
623        use serde_test::{assert_tokens, Configure, Token};
624
625        let mut rng = ChaCha8Rng::from_seed([42; 32]);
626        /* TODO:
627        let priv_key = RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
628
629        let priv_tokens = [Token::Str(
630            "3054020100300d06092a864886f70d01010105000440303e020100020900c9269f2f225eb38d020301000102086ecdc49f528812a1020500d2aaa725020500f46fc249020500887e253902046b4851e1020423806864",
631        )];
632        assert_tokens(&priv_key.clone().readable(), &priv_tokens);
633
634        let priv_tokens = [Token::Str(
635            "3024300d06092a864886f70d01010105000313003010020900c9269f2f225eb38d0203010001",
636        )];
637        assert_tokens(
638            &RsaPublicKey::from(priv_key.clone()).readable(),
639            &priv_tokens,
640        );
641        */
642    }
643
644    #[test]
645    #[ignore]
646    fn invalid_coeff_private_key_regression() {
647        use base64ct::{Base64, Encoding};
648
649        let n = Base64::decode_vec(
650            "wC8GyQvTCZOK+iiBR5fGQCmzRCTWX9TQ3aRG5gGFk0wB6EFoLMAyEEqeG3gS8xhA\
651             m2rSWYx9kKufvNat3iWlbSRVqkcbpVAYlj2vTrpqDpJl+6u+zxFYoUEBevlJJkAh\
652             l8EuCccOA30fVpcfRvXPTtvRd3yFT9E9EwZljtgSI02w7gZwg7VIxaGeajh5Euz6\
653             ZVQZ+qNRKgXrRC7gPRqVyI6Dt0Jc+Su5KBGNn0QcPDzOahWha1ieaeMkFisZ9mdp\
654             sJoZ4tw5eicLaUomKzALHXQVt+/rcZSrCd6/7uUo11B/CYBM4UfSpwXaL88J9AE6\
655             A5++no9hmJzaF2LLp+Qwx4yY3j9TDutxSAjsraxxJOGZ3XyA9nG++Ybt3cxZ5fP7\
656             ROjxCfROBmVv5dYn0O9OBIqYeCH6QraNpZMadlLNIhyMv8Y+P3r5l/PaK4VJaEi5\
657             pPosnEPawp0W0yZDzmjk2z1LthaRx0aZVrAjlH0Rb/6goLUQ9qu1xsDtQVVpN4A8\
658             9ZUmtTWORnnJr0+595eHHxssd2gpzqf4bPjNITdAEuOCCtpvyi4ls23zwuzryUYj\
659             cUOEnsXNQ+DrZpLKxdtsD/qNV/j1hfeyBoPllC3cV+6bcGOFcVGbjYqb+Kw1b0+j\
660             L69RSKQqgmS+qYqr8c48nDRxyq3QXhR8qtzUwBFSLVk=",
661        )
662        .unwrap();
663        let e = Base64::decode_vec("AQAB").unwrap();
664        let d = Base64::decode_vec(
665            "qQazSQ+FRN7nVK1bRsROMRB8AmsDwLVEHivlz1V3Td2Dr+oW3YUMgxedhztML1Id\
666             QJPq/ad6qErJ6yRFNySVIjDaxzBTOEoB1eHa1btOnBJWb8rVvvjaorixvJ6Tn3i4\
667             EuhsvVy9DoR1k4rGj3qSIiFjUVvLRDAbLyhpGgEfsr0Z577yJmTC5E8JLRMOKX8T\
668             mxsk3jPVpsgd65Hu1s8S/ZmabwuHCf9SkdMeY/1bd/9i7BqqJeeDLE4B5x1xcC3z\
669             3scqDUTzqGO+vZPhjgprPDRlBamVwgenhr7KwCn8iaLamFinRVwOAag8BeBqOJj7\
670             lURiOsKQa9FIX1kdFUS1QMQxgtPycLjkbvCJjriqT7zWKsmJ7l8YLs6Wmm9/+QJR\
671             wNCEVdMTXKfCP1cJjudaiskEQThfUldtgu8gUDNYbQ/Filb2eKfiX4h1TiMxZqUZ\
672             HVZyb9nShbQoXJ3vj/MGVF0QM8TxhXM8r2Lv9gDYU5t9nQlUMLhs0jVjai48jHAB\
673             bFNyH3sEcOmJOIwJrCXw1dzG7AotwyaEVUHOmL04TffmwCFfnyrLjbFgnyOeoyII\
674             BYjcY7QFRm/9nupXMTH5hZ2qrHfCJIp0KK4tNBdQqmnHapFl5l6Le1s4qBS5bEIz\
675             jitobLvAFm9abPlDGfxmY6mlrMK4+nytwF9Ct7wc1AE=",
676        )
677        .unwrap();
678        let primes = [
679            Base64::decode_vec(
680                "9kQWEAzsbzOcdPa+s5wFfw4XDd7bB1q9foZ31b1+TNjGNxbSBCFlDF1q98vwpV6n\
681                 M8bWDh/wtbNoETSQDgpEnYOQ26LWEw6YY1+q1Q2GGEFceYUf+Myk8/vTc8TN6Zw0\
682                 bKZBWy10Qo8h7xk4JpzuI7NcxvjJYTkS9aErFxi3vVH0aiZC0tmfaCqr8a2rJxyV\
683                 wqreRpOjwAWrotMsf2wGsF4ofx5ScoFy5GB5fJkkdOrW1LyTvZAUCX3cstPr19+T\
684                 NC5zZOk7WzZatnCkN5H5WzalWtZuu0oVL205KPOa3R8V2yv5e6fm0v5fTmqSuvjm\
685                 aMJLXCN4QJkmIzojO99ckQ==",
686            )
687            .unwrap(),
688            Base64::decode_vec(
689                "x8exdMjVA2CiI+Thx7loHtVcevoeE2sZ7btRVAvmBqo+lkHwxb7FHRnWvuj6eJSl\
690                 D2f0T50EewIhhiW3R9BmktCk7hXjbSCnC1u9Oxc1IAUm/7azRqyfCMx43XhLxpD+\
691                 xkBCpWkKDLxGczsRwTuaP3lKS3bSdBrNlGmdblubvVBIq4YZ2vXVlnYtza0cS+dg\
692                 CK7BGTqUsrCUd/ZbIvwcwZkZtpkhj1KQfto9X/0OMurBzAqbkeq1cyRHXHkOfN/q\
693                 bUIIRqr9Ii7Eswf9Vk8xp2O1Nt8nzcYS9PFD12M5eyaeFEkEYfpNMNGuTzp/31oq\
694                 VjbpoCxS6vuWAZyADxhISQ==",
695            )
696            .unwrap(),
697            Base64::decode_vec(
698                "is7d0LY4HoXszlC2NO7gejkq7XqL4p1W6hZJPYTNx+r37t1CC2n3Vvzg6kNdpRix\
699                 DhIpXVTLjN9O7UO/XuqSumYKJIKoP52eb4Tg+a3hw5Iz2Zsb5lUTNSLgkQSBPAf7\
700                 1LHxbL82JL4g1nBUog8ae60BwnVArThKY4EwlJguGNw09BAU4lwf6csDl/nX2vfV\
701                 wiAloYpeZkHL+L8m+bueGZM5KE2jEz+7ztZCI+T+E5i69rZEYDjx0lfLKlEhQlCW\
702                 3HbCPELqXgNJJkRfi6MP9kXa9lSfnZmoT081RMvqonB/FUa4HOcKyCrw9XZEtnbN\
703                 CIdbitfDVEX+pSSD7596wQ==",
704            )
705            .unwrap(),
706            Base64::decode_vec(
707                "GPs0injugfycacaeIP5jMa/WX55VEnKLDHom4k6WlfDF4L4gIGoJdekcPEUfxOI5\
708                 faKvHyFwRP1wObkPoRBDM0qZxRfBl4zEtpvjHrd5MibSyJkM8+J0BIKk/nSjbRIG\
709                 eb3hV5O56PvGB3S0dKhCUnuVObiC+ne7izplsD4OTG70l1Yud33UFntyoMxrxGYL\
710                 USqhBMmZfHquJg4NOWOzKNY/K+EcHDLj1Kjvkcgv9Vf7ocsVxvpFdD9uGPceQ6kw\
711                 RDdEl6mb+6FDgWuXVyqR9+904oanEIkbJ7vfkthagLbEf57dyG6nJlqh5FBZWxGI\
712                 R72YGypPuAh7qnnqXXjY2Q==",
713            )
714            .unwrap(),
715            Base64::decode_vec(
716                "CUWC+hRWOT421kwRllgVjy6FYv6jQUcgDNHeAiYZnf5HjS9iK2ki7v8G5dL/0f+Y\
717                 f+NhE/4q8w4m8go51hACrVpP1p8GJDjiT09+RsOzITsHwl+ceEKoe56ZW6iDHBLl\
718                 rNw5/MtcYhKpjNU9KJ2udm5J/c9iislcjgckrZG2IB8ADgXHMEByZ5DgaMl4AKZ1\
719                 Gx8/q6KftTvmOT5rNTMLi76VN5KWQcDWK/DqXiOiZHM7Nr4dX4me3XeRgABJyNR8\
720                 Fqxj3N1+HrYLe/zs7LOaK0++F9Ul3tLelhrhsvLxei3oCZkF9A/foD3on3luYA+1\
721                 cRcxWpSY3h2J4/22+yo4+Q==",
722            )
723            .unwrap(),
724        ];
725
726        todo!()
727    }
728
729    #[test]
730    #[ignore]
731    fn reject_oversized_private_key() {
732        // -----BEGIN PUBLIC KEY-----
733        // MIIEIjANBgkqhkiG9w0BAQEFAAOCBA8AMIIECgKCBAEAkMBiB8qsNVXAsJR6Xoto
734        // H1r2rtZl/xzUK2tIfy99aPE489u+5tLxCQhQf+a89158vSDpr2/xwgK8w9u0Xpu2
735        // m7XRKjVMS0Y6UIINFoeTc87rVXT92Scr47kNVcGmSFXez4BSDpS+LKpWwXN+0AQu
736        // +cmcfdtsx2862iEbqQvq4PwKGQJOdOR0yldH8O4yeJK/buvIOXRHjb++vtQND/xi
737        // bFGAcd9WJqvaOG7tclhbZ277mbO6ER+y9Lj7AyO8ywybWqNeHaVPHMysPhT7HUWI
738        // 17m59i1OpuVwwEnvzDQQEUf9d5hUmkLYb5qQzuf6Ddnx/04QJCKAgkhyr9CXgnV6
739        // vEZ3PKtpicCHRxk7eqTEmgBlgwqH5vflRFV1iywQMXJnuRhzWOQaXl/vb8v4HIvF
740        // 4TatEZKqfzpbyScLIiYbPEAhHXKdZMd2zY8hkSbicifePApAZmuNpAxxJDZzphh7
741        // r4lD6t8MPT/RUAdtrZfihqaBhduFI6YeVIy6emg05M6YWvlUyer7nYGaPRS1JqD4
742        // 0v7xOtme5I8Qw6APiFPXhTqBK3occr7TgGb3V3lpC8Eq+esNHrji98R1fITkFXJW
743        // KdFcTWjBghPxiobUzMCFUrPIDJcWXeBzrARAryU+hXjEiFfzluXrps0B7RJQ/rLD
744        // LXeTn4vovUeHQVHa7YfoyWMy9pfqeVC+56LBK7SEIAvL0I3lrq5vIv+ZIuOAdbVg
745        // JiRy8DneCOk2LP3RnA8M0HSevYW93DiC+4h/l4ntjjiOfi6yRVOZ8WbVyXZ/83j4
746        // 6+pGWgvi0uMyb+btgOXjBQv7bGqdyHMc5Lqk5bF7ExETx51vKQMYCV4351caS6aX
747        // q16lYZATHgbTADEAZHdroDMJB+HMQaze9O6qU5ZO8wxxAjw89xry0dnoOQD/yA4H
748        // 7CRCo9vVDpV2hqIvHY9RI2T7cek28kmQpKvNvvK+ovmM138dHKViWULHk0fBRt7m
749        // 4wQ+tiL2PmJ/Tr8g1gVhM6S9D1XdE9z0KeDnODCWn1Q8sx2G2ah4ynnYQURDWcwO
750        // McAoP6bdJ7cCt+4F2tEsMPf4S/EwlnjvuNoQjvztxCPahYe9EnyggtQXyHJveIn7
751        // gDJsP6b93VB6x4QbLy5ch4DUhqDWginuKVeo7CTgDkq03j/IEaS1BHwreSDQceny
752        // +bYWONwV+4TMpGytKOHvU5288kmHbyZHdXuaXk8LLqbnqr30fa6Cbp4llCi9sH5a
753        // Kmi5jxQfVTe+elkMs7oVsLsVgkZS6NqPcOuEckAFijNqG223+IJoqvifCzO5Bdcs
754        // JTOLE+YaUYc8LUJwIaPykgcXmtMvQjeT8MCQ3aAlzkHfDpSvvICrXtqbGiaKolU6
755        // mQIDAQAB
756        // -----END PUBLIC KEY-----
757
758        let n = hex!(
759                "
760            90c06207caac3555c0b0947a5e8b681f5af6aed665ff1cd42b6b487f2f7d68f1
761            38f3dbbee6d2f10908507fe6bcf75e7cbd20e9af6ff1c202bcc3dbb45e9bb69b
762            b5d12a354c4b463a50820d16879373ceeb5574fdd9272be3b90d55c1a64855de
763            cf80520e94be2caa56c1737ed0042ef9c99c7ddb6cc76f3ada211ba90beae0fc
764            0a19024e74e474ca5747f0ee327892bf6eebc83974478dbfbebed40d0ffc626c
765            518071df5626abda386eed72585b676efb99b3ba111fb2f4b8fb0323bccb0c9b
766            5aa35e1da54f1cccac3e14fb1d4588d7b9b9f62d4ea6e570c049efcc34101147
767            fd7798549a42d86f9a90cee7fa0dd9f1ff4e10242280824872afd09782757abc
768            46773cab6989c08747193b7aa4c49a0065830a87e6f7e54455758b2c10317267
769            b9187358e41a5e5fef6fcbf81c8bc5e136ad1192aa7f3a5bc9270b22261b3c40
770            211d729d64c776cd8f219126e27227de3c0a40666b8da40c71243673a6187baf
771            8943eadf0c3d3fd150076dad97e286a68185db8523a61e548cba7a6834e4ce98
772            5af954c9eafb9d819a3d14b526a0f8d2fef13ad99ee48f10c3a00f8853d7853a
773            812b7a1c72bed38066f75779690bc12af9eb0d1eb8e2f7c4757c84e415725629
774            d15c4d68c18213f18a86d4ccc08552b3c80c97165de073ac0440af253e8578c4
775            8857f396e5eba6cd01ed1250feb2c32d77939f8be8bd47874151daed87e8c963
776            32f697ea7950bee7a2c12bb484200bcbd08de5aeae6f22ff9922e38075b56026
777            2472f039de08e9362cfdd19c0f0cd0749ebd85bddc3882fb887f9789ed8e388e
778            7e2eb2455399f166d5c9767ff378f8ebea465a0be2d2e3326fe6ed80e5e3050b
779            fb6c6a9dc8731ce4baa4e5b17b131113c79d6f290318095e37e7571a4ba697ab
780            5ea56190131e06d300310064776ba0330907e1cc41acdef4eeaa53964ef30c71
781            023c3cf71af2d1d9e83900ffc80e07ec2442a3dbd50e957686a22f1d8f512364
782            fb71e936f24990a4abcdbef2bea2f98cd77f1d1ca5625942c79347c146dee6e3
783            043eb622f63e627f4ebf20d6056133a4bd0f55dd13dcf429e0e73830969f543c
784            b31d86d9a878ca79d841444359cc0e31c0283fa6dd27b702b7ee05dad12c30f7
785            f84bf1309678efb8da108efcedc423da8587bd127ca082d417c8726f7889fb80
786            326c3fa6fddd507ac7841b2f2e5c8780d486a0d68229ee2957a8ec24e00e4ab4
787            de3fc811a4b5047c2b7920d071e9f2f9b61638dc15fb84cca46cad28e1ef539d
788            bcf249876f2647757b9a5e4f0b2ea6e7aabdf47dae826e9e259428bdb07e5a2a
789            68b98f141f5537be7a590cb3ba15b0bb15824652e8da8f70eb847240058a336a
790            1b6db7f88268aaf89f0b33b905d72c25338b13e61a51873c2d427021a3f29207
791            179ad32f423793f0c090dda025ce41df0e94afbc80ab5eda9b1a268aa2553a99"
792        );
793
794        todo!()
795    }
796
797    #[test]
798    #[ignore]
799    fn build_key_from_primes() {
800        const RSA_2048_PRIV_DER: &[u8] = include_bytes!("../tests/examples/pkcs8/rsa2048-priv.der");
801        todo!()
802    }
803
804    #[test]
805    #[ignore]
806    fn build_key_from_p_q() {
807        const RSA_2048_SP800_PRIV_DER: &[u8] =
808            include_bytes!("../tests/examples/pkcs8/rsa2048-sp800-56b-priv.der");
809        todo!()
810    }
811}