1use alloc::vec::Vec;
2use core::ops::Deref;
3use num_bigint::traits::ModInverse;
4use num_bigint::Sign::Plus;
5use num_bigint::{BigInt, BigUint};
6use num_traits::{One, ToPrimitive};
7use rand_core::{CryptoRng, RngCore};
8#[cfg(feature = "serde")]
9use serde_crate::{Deserialize, Serialize};
10use zeroize::Zeroize;
11
12use crate::algorithms::{generate_multi_prime_key, generate_multi_prime_key_with_exp};
13use crate::dummy_rng::DummyRng;
14use crate::errors::{Error, Result};
15
16use crate::padding::PaddingScheme;
17use crate::raw::{DecryptionPrimitive, EncryptionPrimitive};
18use crate::{oaep, pkcs1v15, pss};
19
20pub trait PublicKeyParts {
22 fn n(&self) -> &BigUint;
24
25 fn e(&self) -> &BigUint;
27
28 fn size(&self) -> usize {
31 (self.n().bits() + 7) / 8
32 }
33}
34
35pub trait PrivateKey: DecryptionPrimitive + PublicKeyParts {}
36
37#[derive(Debug, Clone, Hash, PartialEq, Eq)]
39#[cfg_attr(
40 feature = "serde",
41 derive(Serialize, Deserialize),
42 serde(crate = "serde_crate")
43)]
44pub struct RsaPublicKey {
45 n: BigUint,
46 e: BigUint,
47}
48
49#[derive(Debug, Clone)]
51#[cfg_attr(
52 feature = "serde",
53 derive(Serialize, Deserialize),
54 serde(crate = "serde_crate")
55)]
56pub struct RsaPrivateKey {
57 pubkey_components: RsaPublicKey,
59 pub(crate) d: BigUint,
61 pub(crate) primes: Vec<BigUint>,
63 #[cfg_attr(feature = "serde", serde(skip))]
65 pub(crate) precomputed: Option<PrecomputedValues>,
66}
67
68impl PartialEq for RsaPrivateKey {
69 #[inline]
70 fn eq(&self, other: &RsaPrivateKey) -> bool {
71 self.pubkey_components == other.pubkey_components
72 && self.d == other.d
73 && self.primes == other.primes
74 }
75}
76
77impl Eq for RsaPrivateKey {}
78
79impl Zeroize for RsaPrivateKey {
80 fn zeroize(&mut self) {
81 self.d.zeroize();
82 for prime in self.primes.iter_mut() {
83 prime.zeroize();
84 }
85 self.primes.clear();
86 if self.precomputed.is_some() {
87 self.precomputed.take().unwrap().zeroize();
88 }
89 }
90}
91
92impl Drop for RsaPrivateKey {
93 fn drop(&mut self) {
94 self.zeroize();
95 }
96}
97
98impl Deref for RsaPrivateKey {
99 type Target = RsaPublicKey;
100 fn deref(&self) -> &RsaPublicKey {
101 &self.pubkey_components
102 }
103}
104
105#[derive(Debug, Clone)]
106pub(crate) struct PrecomputedValues {
107 pub(crate) dp: BigUint,
109 pub(crate) dq: BigUint,
111 pub(crate) qinv: BigInt,
113
114 pub(crate) crt_values: Vec<CRTValue>,
119}
120
121impl Zeroize for PrecomputedValues {
122 fn zeroize(&mut self) {
123 self.dp.zeroize();
124 self.dq.zeroize();
125 self.qinv.zeroize();
126 for val in self.crt_values.iter_mut() {
127 val.zeroize();
128 }
129 self.crt_values.clear();
130 }
131}
132
133impl Drop for PrecomputedValues {
134 fn drop(&mut self) {
135 self.zeroize();
136 }
137}
138
139#[derive(Debug, Clone)]
141pub(crate) struct CRTValue {
142 pub(crate) exp: BigInt,
144 pub(crate) coeff: BigInt,
146 pub(crate) r: BigInt,
148}
149
150impl Zeroize for CRTValue {
151 fn zeroize(&mut self) {
152 self.exp.zeroize();
153 self.coeff.zeroize();
154 self.r.zeroize();
155 }
156}
157
158impl From<RsaPrivateKey> for RsaPublicKey {
159 fn from(private_key: RsaPrivateKey) -> Self {
160 (&private_key).into()
161 }
162}
163
164impl From<&RsaPrivateKey> for RsaPublicKey {
165 fn from(private_key: &RsaPrivateKey) -> Self {
166 let n = private_key.n.clone();
167 let e = private_key.e.clone();
168
169 RsaPublicKey { n, e }
170 }
171}
172
173pub trait PublicKey: EncryptionPrimitive + PublicKeyParts {
175 fn encrypt<R: RngCore + CryptoRng>(
177 &self,
178 rng: &mut R,
179 padding: PaddingScheme,
180 msg: &[u8],
181 ) -> Result<Vec<u8>>;
182
183 fn verify(&self, padding: PaddingScheme, hashed: &[u8], sig: &[u8]) -> Result<()>;
188}
189
190impl PublicKeyParts for RsaPublicKey {
191 fn n(&self) -> &BigUint {
192 &self.n
193 }
194
195 fn e(&self) -> &BigUint {
196 &self.e
197 }
198}
199
200impl PublicKey for RsaPublicKey {
201 fn encrypt<R: RngCore + CryptoRng>(
202 &self,
203 rng: &mut R,
204 padding: PaddingScheme,
205 msg: &[u8],
206 ) -> Result<Vec<u8>> {
207 match padding {
208 PaddingScheme::PKCS1v15Encrypt => pkcs1v15::encrypt(rng, self, msg),
209 PaddingScheme::OAEP {
210 mut digest,
211 mut mgf_digest,
212 label,
213 } => oaep::encrypt(rng, self, msg, &mut *digest, &mut *mgf_digest, label),
214 _ => Err(Error::InvalidPaddingScheme),
215 }
216 }
217
218 fn verify(&self, padding: PaddingScheme, hashed: &[u8], sig: &[u8]) -> Result<()> {
219 match padding {
220 PaddingScheme::PKCS1v15Sign { hash_len, prefix } => {
221 if let Some(hash_len) = hash_len {
222 if hashed.len() != hash_len {
223 return Err(Error::InputNotHashed);
224 }
225 }
226 pkcs1v15::verify(self, prefix.as_ref(), hashed, sig)
227 }
228 PaddingScheme::PSS { mut digest, .. } => pss::verify(self, hashed, sig, &mut *digest),
229 _ => Err(Error::InvalidPaddingScheme),
230 }
231 }
232}
233
234impl RsaPublicKey {
235 pub const MIN_PUB_EXPONENT: u64 = 2;
237
238 pub const MAX_PUB_EXPONENT: u64 = (1 << 33) - 1;
240
241 pub const MAX_SIZE: usize = 4096;
243
244 pub fn new(n: BigUint, e: BigUint) -> Result<Self> {
249 Self::new_with_max_size(n, e, Self::MAX_SIZE)
250 }
251
252 pub fn new_with_max_size(n: BigUint, e: BigUint, max_size: usize) -> Result<Self> {
254 let k = Self { n, e };
255 check_public_with_max_size(&k, max_size)?;
256 Ok(k)
257 }
258
259 pub fn new_unchecked(n: BigUint, e: BigUint) -> Self {
266 Self { n, e }
267 }
268}
269
270impl PublicKeyParts for RsaPrivateKey {
271 fn n(&self) -> &BigUint {
272 &self.n
273 }
274
275 fn e(&self) -> &BigUint {
276 &self.e
277 }
278}
279
280impl PrivateKey for RsaPrivateKey {}
281
282impl RsaPrivateKey {
283 pub fn new<R: RngCore + CryptoRng>(rng: &mut R, bit_size: usize) -> Result<RsaPrivateKey> {
285 generate_multi_prime_key(rng, 2, bit_size)
286 }
287
288 pub fn new_with_exp<R: RngCore + CryptoRng>(
293 rng: &mut R,
294 bit_size: usize,
295 exp: &BigUint,
296 ) -> Result<RsaPrivateKey> {
297 generate_multi_prime_key_with_exp(rng, 2, bit_size, exp)
298 }
299
300 pub fn from_components(
302 n: BigUint,
303 e: BigUint,
304 d: BigUint,
305 primes: Vec<BigUint>,
306 ) -> Result<RsaPrivateKey> {
307 if primes.len() < 2 {
310 return Err(Error::NprimesTooSmall);
311 }
312
313 let mut k = RsaPrivateKey {
314 pubkey_components: RsaPublicKey { n, e },
315 d,
316 primes,
317 precomputed: None,
318 };
319
320 let _ = k.precompute();
322
323 Ok(k)
324 }
325
326 pub fn to_public_key(&self) -> RsaPublicKey {
331 self.pubkey_components.clone()
332 }
333
334 pub fn precompute(&mut self) -> Result<()> {
336 if self.precomputed.is_some() {
337 return Ok(());
338 }
339
340 let dp = &self.d % (&self.primes[0] - BigUint::one());
341 let dq = &self.d % (&self.primes[1] - BigUint::one());
342 let qinv = self.primes[1]
343 .clone()
344 .mod_inverse(&self.primes[0])
345 .ok_or(Error::InvalidPrime)?;
346
347 let mut r: BigUint = &self.primes[0] * &self.primes[1];
348 let crt_values: Vec<CRTValue> = {
349 let mut values = Vec::with_capacity(self.primes.len() - 2);
350 for prime in &self.primes[2..] {
351 let res = CRTValue {
352 exp: BigInt::from_biguint(Plus, &self.d % (prime - BigUint::one())),
353 r: BigInt::from_biguint(Plus, r.clone()),
354 coeff: BigInt::from_biguint(
355 Plus,
356 r.clone()
357 .mod_inverse(prime)
358 .ok_or(Error::InvalidCoefficient)?
359 .to_biguint()
360 .unwrap(),
361 ),
362 };
363 r *= prime;
364
365 values.push(res);
366 }
367 values
368 };
369
370 self.precomputed = Some(PrecomputedValues {
371 dp,
372 dq,
373 qinv,
374 crt_values,
375 });
376
377 Ok(())
378 }
379
380 pub fn clear_precomputed(&mut self) {
382 self.precomputed = None;
383 }
384
385 pub fn dp(&self) -> Option<&BigUint> {
387 self.precomputed.as_ref().map(|p| &p.dp)
388 }
389
390 pub fn dq(&self) -> Option<&BigUint> {
392 self.precomputed.as_ref().map(|p| &p.dq)
393 }
394
395 pub fn qinv(&self) -> Option<&BigInt> {
397 self.precomputed.as_ref().map(|p| &p.qinv)
398 }
399
400 pub fn d(&self) -> &BigUint {
402 &self.d
403 }
404
405 pub fn primes(&self) -> &[BigUint] {
407 &self.primes
408 }
409
410 pub fn crt_coefficient(&self) -> Option<BigUint> {
412 (&self.primes[1]).mod_inverse(&self.primes[0])?.to_biguint()
413 }
414
415 pub fn validate(&self) -> Result<()> {
418 check_public(self)?;
419
420 let mut m = BigUint::one();
422 for prime in &self.primes {
423 if *prime < BigUint::one() {
425 return Err(Error::InvalidPrime);
426 }
427 m *= prime;
428 }
429 if m != self.n {
430 return Err(Error::InvalidModulus);
431 }
432
433 let mut de = self.e.clone();
439 de *= self.d.clone();
440 for prime in &self.primes {
441 let congruence: BigUint = &de % (prime - BigUint::one());
442 if !congruence.is_one() {
443 return Err(Error::InvalidExponent);
444 }
445 }
446
447 Ok(())
448 }
449
450 pub fn decrypt(&self, padding: PaddingScheme, ciphertext: &[u8]) -> Result<Vec<u8>> {
452 match padding {
453 PaddingScheme::PKCS1v15Encrypt => {
455 pkcs1v15::decrypt::<DummyRng, _>(None, self, ciphertext)
456 }
457 PaddingScheme::OAEP {
458 mut digest,
459 mut mgf_digest,
460 label,
461 } => oaep::decrypt::<DummyRng, _>(
462 None,
463 self,
464 ciphertext,
465 &mut *digest,
466 &mut *mgf_digest,
467 label,
468 ),
469 _ => Err(Error::InvalidPaddingScheme),
470 }
471 }
472
473 pub fn decrypt_blinded<R: RngCore + CryptoRng>(
477 &self,
478 rng: &mut R,
479 padding: PaddingScheme,
480 ciphertext: &[u8],
481 ) -> Result<Vec<u8>> {
482 match padding {
483 PaddingScheme::PKCS1v15Encrypt => pkcs1v15::decrypt(Some(rng), self, ciphertext),
484 PaddingScheme::OAEP {
485 mut digest,
486 mut mgf_digest,
487 label,
488 } => oaep::decrypt(
489 Some(rng),
490 self,
491 ciphertext,
492 &mut *digest,
493 &mut *mgf_digest,
494 label,
495 ),
496 _ => Err(Error::InvalidPaddingScheme),
497 }
498 }
499
500 pub fn sign(&self, padding: PaddingScheme, digest_in: &[u8]) -> Result<Vec<u8>> {
502 match padding {
503 PaddingScheme::PKCS1v15Sign { hash_len, prefix } => {
505 if let Some(hash_len) = hash_len {
506 if digest_in.len() != hash_len {
507 return Err(Error::InputNotHashed);
508 }
509 }
510 pkcs1v15::sign::<DummyRng, _>(None, self, prefix.as_ref(), digest_in)
511 }
512 _ => Err(Error::InvalidPaddingScheme),
513 }
514 }
515
516 pub fn sign_with_rng<R: RngCore + CryptoRng>(
520 &self,
521 rng: &mut R,
522 padding: PaddingScheme,
523 digest_in: &[u8],
524 ) -> Result<Vec<u8>> {
525 match padding {
526 PaddingScheme::PSS {
527 mut digest,
528 salt_len,
529 } => pss::sign::<R, _>(rng, false, self, digest_in, salt_len, &mut *digest),
530 _ => Err(Error::InvalidPaddingScheme),
531 }
532 }
533
534 pub fn sign_blinded<R: RngCore + CryptoRng>(
538 &self,
539 rng: &mut R,
540 padding: PaddingScheme,
541 digest_in: &[u8],
542 ) -> Result<Vec<u8>> {
543 match padding {
544 PaddingScheme::PKCS1v15Sign { hash_len, prefix } => {
545 if let Some(hash_len) = hash_len {
546 if digest_in.len() != hash_len {
547 return Err(Error::InputNotHashed);
548 }
549 }
550 pkcs1v15::sign(Some(rng), self, prefix.as_ref(), digest_in)
551 }
552 PaddingScheme::PSS {
553 mut digest,
554 salt_len,
555 } => pss::sign::<R, _>(rng, true, self, digest_in, salt_len, &mut *digest),
556 _ => Err(Error::InvalidPaddingScheme),
557 }
558 }
559}
560
561#[inline]
563pub fn check_public(public_key: &impl PublicKeyParts) -> Result<()> {
564 check_public_with_max_size(public_key, RsaPublicKey::MAX_SIZE)
565}
566
567#[inline]
569fn check_public_with_max_size(public_key: &impl PublicKeyParts, max_size: usize) -> Result<()> {
570 if public_key.n().bits() > max_size {
571 return Err(Error::ModulusTooLarge);
572 }
573
574 let e = public_key
575 .e()
576 .to_u64()
577 .ok_or(Error::PublicExponentTooLarge)?;
578
579 if e < RsaPublicKey::MIN_PUB_EXPONENT {
580 return Err(Error::PublicExponentTooSmall);
581 }
582
583 if e > RsaPublicKey::MAX_PUB_EXPONENT {
584 return Err(Error::PublicExponentTooLarge);
585 }
586
587 Ok(())
588}
589
590#[cfg(test)]
591mod tests {
592 use super::*;
593 use crate::internals;
594
595 use alloc::string::String;
596 use digest::{Digest, DynDigest};
597 use hex_literal::hex;
598 use num_traits::{FromPrimitive, ToPrimitive};
599 use rand_chacha::{
600 rand_core::{RngCore, SeedableRng},
601 ChaCha8Rng,
602 };
603 use sha1::Sha1;
604 use sha2::{Sha224, Sha256, Sha384, Sha512};
605 use sha3::{Sha3_256, Sha3_384, Sha3_512};
606
607 #[test]
608 fn test_from_into() {
609 let private_key = RsaPrivateKey {
610 pubkey_components: RsaPublicKey {
611 n: BigUint::from_u64(100).unwrap(),
612 e: BigUint::from_u64(200).unwrap(),
613 },
614 d: BigUint::from_u64(123).unwrap(),
615 primes: vec![],
616 precomputed: None,
617 };
618 let public_key: RsaPublicKey = private_key.into();
619
620 assert_eq!(public_key.n().to_u64(), Some(100));
621 assert_eq!(public_key.e().to_u64(), Some(200));
622 }
623
624 fn test_key_basics(private_key: &RsaPrivateKey) {
625 private_key.validate().expect("invalid private key");
626
627 assert!(
628 private_key.d() < private_key.n(),
629 "private exponent too large"
630 );
631
632 let pub_key: RsaPublicKey = private_key.clone().into();
633 let m = BigUint::from_u64(42).expect("invalid 42");
634 let c = internals::encrypt(&pub_key, &m);
635 let m2 = internals::decrypt::<ChaCha8Rng>(None, private_key, &c)
636 .expect("unable to decrypt without blinding");
637 assert_eq!(m, m2);
638 let mut rng = ChaCha8Rng::from_seed([42; 32]);
639 let m3 = internals::decrypt(Some(&mut rng), private_key, &c)
640 .expect("unable to decrypt with blinding");
641 assert_eq!(m, m3);
642 }
643
644 macro_rules! key_generation {
645 ($name:ident, $multi:expr, $size:expr) => {
646 #[test]
647 fn $name() {
648 let mut rng = ChaCha8Rng::from_seed([42; 32]);
649
650 for _ in 0..10 {
651 let private_key = if $multi == 2 {
652 RsaPrivateKey::new(&mut rng, $size).expect("failed to generate key")
653 } else {
654 generate_multi_prime_key(&mut rng, $multi, $size).unwrap()
655 };
656 assert_eq!(private_key.n().bits(), $size);
657
658 test_key_basics(&private_key);
659 }
660 }
661 };
662 }
663
664 key_generation!(key_generation_128, 2, 128);
665 key_generation!(key_generation_1024, 2, 1024);
666
667 key_generation!(key_generation_multi_3_256, 3, 256);
668
669 key_generation!(key_generation_multi_4_64, 4, 64);
670
671 key_generation!(key_generation_multi_5_64, 5, 64);
672 key_generation!(key_generation_multi_8_576, 8, 576);
673 key_generation!(key_generation_multi_16_1024, 16, 1024);
674
675 #[test]
676 fn test_impossible_keys() {
677 let mut rng = ChaCha8Rng::from_seed([42; 32]);
678 for i in 0..32 {
679 let _ = RsaPrivateKey::new(&mut rng, i).is_err();
680 let _ = generate_multi_prime_key(&mut rng, 3, i);
681 let _ = generate_multi_prime_key(&mut rng, 4, i);
682 let _ = generate_multi_prime_key(&mut rng, 5, i);
683 }
684 }
685
686 #[test]
687 fn test_negative_decryption_value() {
688 let private_key = RsaPrivateKey::from_components(
689 BigUint::from_bytes_le(&[
690 99, 192, 208, 179, 0, 220, 7, 29, 49, 151, 75, 107, 75, 73, 200, 180,
691 ]),
692 BigUint::from_bytes_le(&[1, 0, 1]),
693 BigUint::from_bytes_le(&[
694 81, 163, 254, 144, 171, 159, 144, 42, 244, 133, 51, 249, 28, 12, 63, 65,
695 ]),
696 vec![
697 BigUint::from_bytes_le(&[105, 101, 60, 173, 19, 153, 3, 192]),
698 BigUint::from_bytes_le(&[235, 65, 160, 134, 32, 136, 6, 241]),
699 ],
700 )
701 .unwrap();
702
703 for _ in 0..1000 {
704 test_key_basics(&private_key);
705 }
706 }
707
708 #[test]
709 #[cfg(feature = "serde")]
710 fn test_serde() {
711 use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
712 use serde_test::{assert_tokens, Token};
713
714 let mut rng = ChaCha8Rng::from_seed([42; 32]);
715 let priv_key = RsaPrivateKey::new(&mut rng, 64).expect("failed to generate key");
716
717 let priv_tokens = [
718 Token::Struct {
719 name: "RsaPrivateKey",
720 len: 3,
721 },
722 Token::Str("pubkey_components"),
723 Token::Struct {
724 name: "RsaPublicKey",
725 len: 2,
726 },
727 Token::Str("n"),
728 Token::Seq { len: Some(2) },
729 Token::U32(3814409919),
730 Token::U32(3429654832),
731 Token::SeqEnd,
732 Token::Str("e"),
733 Token::Seq { len: Some(1) },
734 Token::U32(65537),
735 Token::SeqEnd,
736 Token::StructEnd,
737 Token::Str("d"),
738 Token::Seq { len: Some(2) },
739 Token::U32(1482162201),
740 Token::U32(1675500232),
741 Token::SeqEnd,
742 Token::Str("primes"),
743 Token::Seq { len: Some(2) },
744 Token::Seq { len: Some(1) },
745 Token::U32(4133289821),
746 Token::SeqEnd,
747 Token::Seq { len: Some(1) },
748 Token::U32(3563808971),
749 Token::SeqEnd,
750 Token::SeqEnd,
751 Token::StructEnd,
752 ];
753 assert_tokens(&priv_key, &priv_tokens);
754
755 let priv_tokens = [
756 Token::Struct {
757 name: "RsaPublicKey",
758 len: 2,
759 },
760 Token::Str("n"),
761 Token::Seq { len: Some(2) },
762 Token::U32(3814409919),
763 Token::U32(3429654832),
764 Token::SeqEnd,
765 Token::Str("e"),
766 Token::Seq { len: Some(1) },
767 Token::U32(65537),
768 Token::SeqEnd,
769 Token::StructEnd,
770 ];
771 assert_tokens(&RsaPublicKey::from(priv_key), &priv_tokens);
772 }
773
774 #[test]
775 fn invalid_coeff_private_key_regression() {
776 use base64ct::{Base64, Encoding};
777
778 let n = Base64::decode_vec("wC8GyQvTCZOK+iiBR5fGQCmzRCTWX9TQ3aRG5gGFk0wB6EFoLMAyEEqeG3gS8xhAm2rSWYx9kKufvNat3iWlbSRVqkcbpVAYlj2vTrpqDpJl+6u+zxFYoUEBevlJJkAhl8EuCccOA30fVpcfRvXPTtvRd3yFT9E9EwZljtgSI02w7gZwg7VIxaGeajh5Euz6ZVQZ+qNRKgXrRC7gPRqVyI6Dt0Jc+Su5KBGNn0QcPDzOahWha1ieaeMkFisZ9mdpsJoZ4tw5eicLaUomKzALHXQVt+/rcZSrCd6/7uUo11B/CYBM4UfSpwXaL88J9AE6A5++no9hmJzaF2LLp+Qwx4yY3j9TDutxSAjsraxxJOGZ3XyA9nG++Ybt3cxZ5fP7ROjxCfROBmVv5dYn0O9OBIqYeCH6QraNpZMadlLNIhyMv8Y+P3r5l/PaK4VJaEi5pPosnEPawp0W0yZDzmjk2z1LthaRx0aZVrAjlH0Rb/6goLUQ9qu1xsDtQVVpN4A89ZUmtTWORnnJr0+595eHHxssd2gpzqf4bPjNITdAEuOCCtpvyi4ls23zwuzryUYjcUOEnsXNQ+DrZpLKxdtsD/qNV/j1hfeyBoPllC3cV+6bcGOFcVGbjYqb+Kw1b0+jL69RSKQqgmS+qYqr8c48nDRxyq3QXhR8qtzUwBFSLVk=").unwrap();
779 let e = Base64::decode_vec("AQAB").unwrap();
780 let d = Base64::decode_vec("qQazSQ+FRN7nVK1bRsROMRB8AmsDwLVEHivlz1V3Td2Dr+oW3YUMgxedhztML1IdQJPq/ad6qErJ6yRFNySVIjDaxzBTOEoB1eHa1btOnBJWb8rVvvjaorixvJ6Tn3i4EuhsvVy9DoR1k4rGj3qSIiFjUVvLRDAbLyhpGgEfsr0Z577yJmTC5E8JLRMOKX8Tmxsk3jPVpsgd65Hu1s8S/ZmabwuHCf9SkdMeY/1bd/9i7BqqJeeDLE4B5x1xcC3z3scqDUTzqGO+vZPhjgprPDRlBamVwgenhr7KwCn8iaLamFinRVwOAag8BeBqOJj7lURiOsKQa9FIX1kdFUS1QMQxgtPycLjkbvCJjriqT7zWKsmJ7l8YLs6Wmm9/+QJRwNCEVdMTXKfCP1cJjudaiskEQThfUldtgu8gUDNYbQ/Filb2eKfiX4h1TiMxZqUZHVZyb9nShbQoXJ3vj/MGVF0QM8TxhXM8r2Lv9gDYU5t9nQlUMLhs0jVjai48jHABbFNyH3sEcOmJOIwJrCXw1dzG7AotwyaEVUHOmL04TffmwCFfnyrLjbFgnyOeoyIIBYjcY7QFRm/9nupXMTH5hZ2qrHfCJIp0KK4tNBdQqmnHapFl5l6Le1s4qBS5bEIzjitobLvAFm9abPlDGfxmY6mlrMK4+nytwF9Ct7wc1AE=").unwrap();
781 let primes = vec![
782 Base64::decode_vec("9kQWEAzsbzOcdPa+s5wFfw4XDd7bB1q9foZ31b1+TNjGNxbSBCFlDF1q98vwpV6nM8bWDh/wtbNoETSQDgpEnYOQ26LWEw6YY1+q1Q2GGEFceYUf+Myk8/vTc8TN6Zw0bKZBWy10Qo8h7xk4JpzuI7NcxvjJYTkS9aErFxi3vVH0aiZC0tmfaCqr8a2rJxyVwqreRpOjwAWrotMsf2wGsF4ofx5ScoFy5GB5fJkkdOrW1LyTvZAUCX3cstPr19+TNC5zZOk7WzZatnCkN5H5WzalWtZuu0oVL205KPOa3R8V2yv5e6fm0v5fTmqSuvjmaMJLXCN4QJkmIzojO99ckQ==").unwrap(),
783 Base64::decode_vec("x8exdMjVA2CiI+Thx7loHtVcevoeE2sZ7btRVAvmBqo+lkHwxb7FHRnWvuj6eJSlD2f0T50EewIhhiW3R9BmktCk7hXjbSCnC1u9Oxc1IAUm/7azRqyfCMx43XhLxpD+xkBCpWkKDLxGczsRwTuaP3lKS3bSdBrNlGmdblubvVBIq4YZ2vXVlnYtza0cS+dgCK7BGTqUsrCUd/ZbIvwcwZkZtpkhj1KQfto9X/0OMurBzAqbkeq1cyRHXHkOfN/qbUIIRqr9Ii7Eswf9Vk8xp2O1Nt8nzcYS9PFD12M5eyaeFEkEYfpNMNGuTzp/31oqVjbpoCxS6vuWAZyADxhISQ==").unwrap(),
784 Base64::decode_vec("is7d0LY4HoXszlC2NO7gejkq7XqL4p1W6hZJPYTNx+r37t1CC2n3Vvzg6kNdpRixDhIpXVTLjN9O7UO/XuqSumYKJIKoP52eb4Tg+a3hw5Iz2Zsb5lUTNSLgkQSBPAf71LHxbL82JL4g1nBUog8ae60BwnVArThKY4EwlJguGNw09BAU4lwf6csDl/nX2vfVwiAloYpeZkHL+L8m+bueGZM5KE2jEz+7ztZCI+T+E5i69rZEYDjx0lfLKlEhQlCW3HbCPELqXgNJJkRfi6MP9kXa9lSfnZmoT081RMvqonB/FUa4HOcKyCrw9XZEtnbNCIdbitfDVEX+pSSD7596wQ==").unwrap(),
785 Base64::decode_vec("GPs0injugfycacaeIP5jMa/WX55VEnKLDHom4k6WlfDF4L4gIGoJdekcPEUfxOI5faKvHyFwRP1wObkPoRBDM0qZxRfBl4zEtpvjHrd5MibSyJkM8+J0BIKk/nSjbRIGeb3hV5O56PvGB3S0dKhCUnuVObiC+ne7izplsD4OTG70l1Yud33UFntyoMxrxGYLUSqhBMmZfHquJg4NOWOzKNY/K+EcHDLj1Kjvkcgv9Vf7ocsVxvpFdD9uGPceQ6kwRDdEl6mb+6FDgWuXVyqR9+904oanEIkbJ7vfkthagLbEf57dyG6nJlqh5FBZWxGIR72YGypPuAh7qnnqXXjY2Q==").unwrap(),
786 Base64::decode_vec("CUWC+hRWOT421kwRllgVjy6FYv6jQUcgDNHeAiYZnf5HjS9iK2ki7v8G5dL/0f+Yf+NhE/4q8w4m8go51hACrVpP1p8GJDjiT09+RsOzITsHwl+ceEKoe56ZW6iDHBLlrNw5/MtcYhKpjNU9KJ2udm5J/c9iislcjgckrZG2IB8ADgXHMEByZ5DgaMl4AKZ1Gx8/q6KftTvmOT5rNTMLi76VN5KWQcDWK/DqXiOiZHM7Nr4dX4me3XeRgABJyNR8Fqxj3N1+HrYLe/zs7LOaK0++F9Ul3tLelhrhsvLxei3oCZkF9A/foD3on3luYA+1cRcxWpSY3h2J4/22+yo4+Q==").unwrap(),
787 ];
788
789 RsaPrivateKey::from_components(
790 BigUint::from_bytes_be(&n),
791 BigUint::from_bytes_be(&e),
792 BigUint::from_bytes_be(&d),
793 primes.iter().map(|p| BigUint::from_bytes_be(p)).collect(),
794 )
795 .unwrap();
796 }
797
798 #[test]
799 fn reject_oversized_private_key() {
800 let n = BigUint::from_bytes_be(&hex!(
827 "
828 90c06207caac3555c0b0947a5e8b681f5af6aed665ff1cd42b6b487f2f7d68f1
829 38f3dbbee6d2f10908507fe6bcf75e7cbd20e9af6ff1c202bcc3dbb45e9bb69b
830 b5d12a354c4b463a50820d16879373ceeb5574fdd9272be3b90d55c1a64855de
831 cf80520e94be2caa56c1737ed0042ef9c99c7ddb6cc76f3ada211ba90beae0fc
832 0a19024e74e474ca5747f0ee327892bf6eebc83974478dbfbebed40d0ffc626c
833 518071df5626abda386eed72585b676efb99b3ba111fb2f4b8fb0323bccb0c9b
834 5aa35e1da54f1cccac3e14fb1d4588d7b9b9f62d4ea6e570c049efcc34101147
835 fd7798549a42d86f9a90cee7fa0dd9f1ff4e10242280824872afd09782757abc
836 46773cab6989c08747193b7aa4c49a0065830a87e6f7e54455758b2c10317267
837 b9187358e41a5e5fef6fcbf81c8bc5e136ad1192aa7f3a5bc9270b22261b3c40
838 211d729d64c776cd8f219126e27227de3c0a40666b8da40c71243673a6187baf
839 8943eadf0c3d3fd150076dad97e286a68185db8523a61e548cba7a6834e4ce98
840 5af954c9eafb9d819a3d14b526a0f8d2fef13ad99ee48f10c3a00f8853d7853a
841 812b7a1c72bed38066f75779690bc12af9eb0d1eb8e2f7c4757c84e415725629
842 d15c4d68c18213f18a86d4ccc08552b3c80c97165de073ac0440af253e8578c4
843 8857f396e5eba6cd01ed1250feb2c32d77939f8be8bd47874151daed87e8c963
844 32f697ea7950bee7a2c12bb484200bcbd08de5aeae6f22ff9922e38075b56026
845 2472f039de08e9362cfdd19c0f0cd0749ebd85bddc3882fb887f9789ed8e388e
846 7e2eb2455399f166d5c9767ff378f8ebea465a0be2d2e3326fe6ed80e5e3050b
847 fb6c6a9dc8731ce4baa4e5b17b131113c79d6f290318095e37e7571a4ba697ab
848 5ea56190131e06d300310064776ba0330907e1cc41acdef4eeaa53964ef30c71
849 023c3cf71af2d1d9e83900ffc80e07ec2442a3dbd50e957686a22f1d8f512364
850 fb71e936f24990a4abcdbef2bea2f98cd77f1d1ca5625942c79347c146dee6e3
851 043eb622f63e627f4ebf20d6056133a4bd0f55dd13dcf429e0e73830969f543c
852 b31d86d9a878ca79d841444359cc0e31c0283fa6dd27b702b7ee05dad12c30f7
853 f84bf1309678efb8da108efcedc423da8587bd127ca082d417c8726f7889fb80
854 326c3fa6fddd507ac7841b2f2e5c8780d486a0d68229ee2957a8ec24e00e4ab4
855 de3fc811a4b5047c2b7920d071e9f2f9b61638dc15fb84cca46cad28e1ef539d
856 bcf249876f2647757b9a5e4f0b2ea6e7aabdf47dae826e9e259428bdb07e5a2a
857 68b98f141f5537be7a590cb3ba15b0bb15824652e8da8f70eb847240058a336a
858 1b6db7f88268aaf89f0b33b905d72c25338b13e61a51873c2d427021a3f29207
859 179ad32f423793f0c090dda025ce41df0e94afbc80ab5eda9b1a268aa2553a99"
860 ));
861
862 let e = BigUint::from_u64(65537).unwrap();
863
864 assert_eq!(
865 RsaPublicKey::new(n, e).err().unwrap(),
866 Error::ModulusTooLarge
867 );
868 }
869
870 fn get_private_key() -> RsaPrivateKey {
871 RsaPrivateKey::from_components(
900 BigUint::parse_bytes(b"00d397b84d98a4c26138ed1b695a8106ead91d553bf06041b62d3fdc50a041e222b8f4529689c1b82c5e71554f5dd69fa2f4b6158cf0dbeb57811a0fc327e1f28e74fe74d3bc166c1eabdc1b8b57b934ca8be5b00b4f29975bcc99acaf415b59bb28a6782bb41a2c3c2976b3c18dbadef62f00c6bb226640095096c0cc60d22fe7ef987d75c6a81b10d96bf292028af110dc7cc1bbc43d22adab379a0cd5d8078cc780ff5cd6209dea34c922cf784f7717e428d75b5aec8ff30e5f0141510766e2e0ab8d473c84e8710b2b98227c3db095337ad3452f19e2b9bfbccdd8148abf6776fa552775e6e75956e45229ae5a9c46949bab1e622f0e48f56524a84ed3483b", 16).unwrap(),
901 BigUint::from_u64(65537).unwrap(),
902 BigUint::parse_bytes(b"00c4e70c689162c94c660828191b52b4d8392115df486a9adbe831e458d73958320dc1b755456e93701e9702d76fb0b92f90e01d1fe248153281fe79aa9763a92fae69d8d7ecd144de29fa135bd14f9573e349e45031e3b76982f583003826c552e89a397c1a06bd2163488630d92e8c2bb643d7abef700da95d685c941489a46f54b5316f62b5d2c3a7f1bbd134cb37353a44683fdc9d95d36458de22f6c44057fe74a0a436c4308f73f4da42f35c47ac16a7138d483afc91e41dc3a1127382e0c0f5119b0221b4fc639d6b9c38177a6de9b526ebd88c38d7982c07f98a0efd877d508aae275b946915c02e2e1106d175d74ec6777f5e80d12c053d9c7be1e341", 16).unwrap(),
903 vec![
904 BigUint::parse_bytes(b"00f827bbf3a41877c7cc59aebf42ed4b29c32defcb8ed96863d5b090a05a8930dd624a21c9dcf9838568fdfa0df65b8462a5f2ac913d6c56f975532bd8e78fb07bd405ca99a484bcf59f019bbddcb3933f2bce706300b4f7b110120c5df9018159067c35da3061a56c8635a52b54273b31271b4311f0795df6021e6355e1a42e61",16).unwrap(),
905 BigUint::parse_bytes(b"00da4817ce0089dd36f2ade6a3ff410c73ec34bf1b4f6bda38431bfede11cef1f7f6efa70e5f8063a3b1f6e17296ffb15feefa0912a0325b8d1fd65a559e717b5b961ec345072e0ec5203d03441d29af4d64054a04507410cf1da78e7b6119d909ec66e6ad625bf995b279a4b3c5be7d895cd7c5b9c4c497fde730916fcdb4e41b", 16).unwrap()
906 ],
907 ).unwrap()
908 }
909
910 #[test]
911 fn test_encrypt_decrypt_oaep() {
912 let priv_key = get_private_key();
913 do_test_encrypt_decrypt_oaep::<Sha1>(&priv_key);
914 do_test_encrypt_decrypt_oaep::<Sha224>(&priv_key);
915 do_test_encrypt_decrypt_oaep::<Sha256>(&priv_key);
916 do_test_encrypt_decrypt_oaep::<Sha384>(&priv_key);
917 do_test_encrypt_decrypt_oaep::<Sha512>(&priv_key);
918 do_test_encrypt_decrypt_oaep::<Sha3_256>(&priv_key);
919 do_test_encrypt_decrypt_oaep::<Sha3_384>(&priv_key);
920 do_test_encrypt_decrypt_oaep::<Sha3_512>(&priv_key);
921
922 do_test_oaep_with_different_hashes::<Sha1, Sha1>(&priv_key);
923 do_test_oaep_with_different_hashes::<Sha224, Sha1>(&priv_key);
924 do_test_oaep_with_different_hashes::<Sha256, Sha1>(&priv_key);
925 do_test_oaep_with_different_hashes::<Sha384, Sha1>(&priv_key);
926 do_test_oaep_with_different_hashes::<Sha512, Sha1>(&priv_key);
927 do_test_oaep_with_different_hashes::<Sha3_256, Sha1>(&priv_key);
928 do_test_oaep_with_different_hashes::<Sha3_384, Sha1>(&priv_key);
929 do_test_oaep_with_different_hashes::<Sha3_512, Sha1>(&priv_key);
930 }
931
932 fn get_label(rng: &mut ChaCha8Rng) -> Option<String> {
933 const GEN_ASCII_STR_CHARSET: &[u8; 64] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
934 abcdefghijklmnopqrstuvwxyz\
935 0123456789=+";
936
937 let mut buf = [0u8; 32];
938 rng.fill_bytes(&mut buf);
939 if buf[0] < (1 << 7) {
940 for v in buf.iter_mut() {
941 *v = GEN_ASCII_STR_CHARSET[(*v >> 2) as usize];
942 }
943 Some(core::str::from_utf8(&buf).unwrap().to_string())
944 } else {
945 None
946 }
947 }
948
949 fn do_test_encrypt_decrypt_oaep<D: 'static + Digest + DynDigest + Send + Sync>(
950 prk: &RsaPrivateKey,
951 ) {
952 let mut rng = ChaCha8Rng::from_seed([42; 32]);
953
954 let k = prk.size();
955
956 for i in 1..8 {
957 let mut input = vec![0u8; i * 8];
958 rng.fill_bytes(&mut input);
959
960 if input.len() > k - 11 {
961 input = input[0..k - 11].to_vec();
962 }
963 let label = get_label(&mut rng);
964
965 let pub_key: RsaPublicKey = prk.into();
966
967 let ciphertext = if let Some(ref label) = label {
968 let padding = PaddingScheme::new_oaep_with_label::<D, _>(label);
969 pub_key.encrypt(&mut rng, padding, &input).unwrap()
970 } else {
971 let padding = PaddingScheme::new_oaep::<D>();
972 pub_key.encrypt(&mut rng, padding, &input).unwrap()
973 };
974
975 assert_ne!(input, ciphertext);
976 let blind: bool = rng.next_u32() < (1 << 31);
977
978 let padding = if let Some(ref label) = label {
979 PaddingScheme::new_oaep_with_label::<D, _>(label)
980 } else {
981 PaddingScheme::new_oaep::<D>()
982 };
983
984 let plaintext = if blind {
985 prk.decrypt(padding, &ciphertext).unwrap()
986 } else {
987 prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
988 };
989
990 assert_eq!(input, plaintext);
991 }
992 }
993
994 fn do_test_oaep_with_different_hashes<
995 D: 'static + Digest + DynDigest + Send + Sync,
996 U: 'static + Digest + DynDigest + Send + Sync,
997 >(
998 prk: &RsaPrivateKey,
999 ) {
1000 let mut rng = ChaCha8Rng::from_seed([42; 32]);
1001
1002 let k = prk.size();
1003
1004 for i in 1..8 {
1005 let mut input = vec![0u8; i * 8];
1006 rng.fill_bytes(&mut input);
1007
1008 if input.len() > k - 11 {
1009 input = input[0..k - 11].to_vec();
1010 }
1011 let label = get_label(&mut rng);
1012
1013 let pub_key: RsaPublicKey = prk.into();
1014
1015 let ciphertext = if let Some(ref label) = label {
1016 let padding = PaddingScheme::new_oaep_with_mgf_hash_with_label::<D, U, _>(label);
1017 pub_key.encrypt(&mut rng, padding, &input).unwrap()
1018 } else {
1019 let padding = PaddingScheme::new_oaep_with_mgf_hash::<D, U>();
1020 pub_key.encrypt(&mut rng, padding, &input).unwrap()
1021 };
1022
1023 assert_ne!(input, ciphertext);
1024 let blind: bool = rng.next_u32() < (1 << 31);
1025
1026 let padding = if let Some(ref label) = label {
1027 PaddingScheme::new_oaep_with_mgf_hash_with_label::<D, U, _>(label)
1028 } else {
1029 PaddingScheme::new_oaep_with_mgf_hash::<D, U>()
1030 };
1031
1032 let plaintext = if blind {
1033 prk.decrypt(padding, &ciphertext).unwrap()
1034 } else {
1035 prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
1036 };
1037
1038 assert_eq!(input, plaintext);
1039 }
1040 }
1041 #[test]
1042 fn test_decrypt_oaep_invalid_hash() {
1043 let mut rng = ChaCha8Rng::from_seed([42; 32]);
1044 let priv_key = get_private_key();
1045 let pub_key: RsaPublicKey = (&priv_key).into();
1046 let ciphertext = pub_key
1047 .encrypt(
1048 &mut rng,
1049 PaddingScheme::new_oaep::<Sha1>(),
1050 "a_plain_text".as_bytes(),
1051 )
1052 .unwrap();
1053 assert!(
1054 priv_key
1055 .decrypt_blinded(
1056 &mut rng,
1057 PaddingScheme::new_oaep_with_label::<Sha1, _>("label"),
1058 &ciphertext,
1059 )
1060 .is_err(),
1061 "decrypt should have failed on hash verification"
1062 );
1063 }
1064}