1mod decrypting_key;
8mod encrypting_key;
9
10pub use self::{decrypting_key::DecryptingKey, encrypting_key::EncryptingKey};
11
12use alloc::boxed::Box;
13use alloc::vec::Vec;
14use core::fmt;
15use crypto_bigint::BoxedUint;
16
17use digest::{Digest, FixedOutputReset};
18use rand_core::TryCryptoRng;
19
20use crate::algorithms::oaep::*;
21use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad};
22use crate::algorithms::rsa::{rsa_decrypt_and_check, rsa_encrypt};
23use crate::errors::{Error, Result};
24use crate::key::{self, RsaPrivateKey, RsaPublicKey};
25use crate::traits::{PaddingScheme, PublicKeyParts};
26
27pub struct Oaep<D, MGD = D> {
39 pub digest: D,
41
42 pub mgf_digest: MGD,
44
45 pub label: Option<Box<[u8]>>,
47}
48
49impl<D> Default for Oaep<D>
50where
51 D: Digest + FixedOutputReset,
52{
53 fn default() -> Self {
54 Self::new()
55 }
56}
57
58impl<D> Oaep<D>
59where
60 D: Digest + FixedOutputReset,
61{
62 pub fn new() -> Self {
83 Self {
84 digest: D::new(),
85 mgf_digest: D::new(),
86 label: None,
87 }
88 }
89
90 pub fn new_with_label<S: Into<Box<[u8]>>>(label: S) -> Self {
92 Self {
93 digest: D::new(),
94 mgf_digest: D::new(),
95 label: Some(label.into()),
96 }
97 }
98}
99
100impl<D, MGD> Oaep<D, MGD>
101where
102 D: Digest + FixedOutputReset,
103 MGD: Digest + FixedOutputReset,
104{
105 pub fn new_with_mgf_hash() -> Self {
127 Self {
128 digest: D::new(),
129 mgf_digest: MGD::new(),
130 label: None,
131 }
132 }
133
134 pub fn new_with_mgf_hash_and_label<S: Into<Box<[u8]>>>(label: S) -> Self {
136 Self {
137 digest: D::new(),
138 mgf_digest: MGD::new(),
139 label: Some(label.into()),
140 }
141 }
142}
143
144impl<D, MGD> PaddingScheme for Oaep<D, MGD>
145where
146 D: Digest + FixedOutputReset,
147 MGD: Digest + FixedOutputReset,
148{
149 fn decrypt<Rng: TryCryptoRng + ?Sized>(
150 mut self,
151 rng: Option<&mut Rng>,
152 priv_key: &RsaPrivateKey,
153 ciphertext: &[u8],
154 ) -> Result<Vec<u8>> {
155 decrypt(
156 rng,
157 priv_key,
158 ciphertext,
159 &mut self.digest,
160 &mut self.mgf_digest,
161 self.label,
162 )
163 }
164
165 fn encrypt<Rng: TryCryptoRng + ?Sized>(
166 mut self,
167 rng: &mut Rng,
168 pub_key: &RsaPublicKey,
169 msg: &[u8],
170 ) -> Result<Vec<u8>> {
171 encrypt(
172 rng,
173 pub_key,
174 msg,
175 &mut self.digest,
176 &mut self.mgf_digest,
177 self.label,
178 )
179 }
180}
181
182impl<D, MGD> fmt::Debug for Oaep<D, MGD> {
183 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184 f.debug_struct("OAEP")
185 .field("digest", &"...")
186 .field("mgf_digest", &"...")
187 .field("label", &self.label)
188 .finish()
189 }
190}
191
192#[inline]
200fn encrypt<R, D, MGD>(
201 rng: &mut R,
202 pub_key: &RsaPublicKey,
203 msg: &[u8],
204 digest: &mut D,
205 mgf_digest: &mut MGD,
206 label: Option<Box<[u8]>>,
207) -> Result<Vec<u8>>
208where
209 R: TryCryptoRng + ?Sized,
210 D: Digest + FixedOutputReset,
211 MGD: Digest + FixedOutputReset,
212{
213 key::check_public(pub_key)?;
214
215 let em = oaep_encrypt(rng, msg, digest, mgf_digest, label, pub_key.size())?;
216
217 let int = BoxedUint::from_be_slice(&em, pub_key.n_bits_precision())?;
218 uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size())
219}
220
221fn encrypt_digest<R, D, MGD>(
229 rng: &mut R,
230 pub_key: &RsaPublicKey,
231 msg: &[u8],
232 label: Option<Box<[u8]>>,
233) -> Result<Vec<u8>>
234where
235 R: TryCryptoRng + ?Sized,
236 D: Digest,
237 MGD: Digest + FixedOutputReset,
238{
239 key::check_public(pub_key)?;
240
241 let em = oaep_encrypt_digest::<_, D, MGD>(rng, msg, label, pub_key.size())?;
242
243 let int = BoxedUint::from_be_slice(&em, pub_key.n_bits_precision())?;
244 uint_to_be_pad(rsa_encrypt(pub_key, &int)?, pub_key.size())
245}
246
247#[inline]
260fn decrypt<R, D, MGD>(
261 rng: Option<&mut R>,
262 priv_key: &RsaPrivateKey,
263 ciphertext: &[u8],
264 digest: &mut D,
265 mgf_digest: &mut MGD,
266 label: Option<Box<[u8]>>,
267) -> Result<Vec<u8>>
268where
269 R: TryCryptoRng + ?Sized,
270 D: Digest + FixedOutputReset,
271 MGD: Digest + FixedOutputReset,
272{
273 if ciphertext.len() != priv_key.size() {
274 return Err(Error::Decryption);
275 }
276
277 let ciphertext = BoxedUint::from_be_slice(ciphertext, priv_key.n_bits_precision())?;
278
279 let em = rsa_decrypt_and_check(priv_key, rng, &ciphertext)?;
280 let mut em = uint_to_zeroizing_be_pad(em, priv_key.size())?;
281
282 oaep_decrypt(&mut em, digest, mgf_digest, label, priv_key.size())
283}
284
285#[inline]
298fn decrypt_digest<R, D, MGD>(
299 rng: Option<&mut R>,
300 priv_key: &RsaPrivateKey,
301 ciphertext: &[u8],
302 label: Option<Box<[u8]>>,
303) -> Result<Vec<u8>>
304where
305 R: TryCryptoRng + ?Sized,
306 D: Digest,
307 MGD: Digest + FixedOutputReset,
308{
309 key::check_public(priv_key)?;
310
311 if ciphertext.len() != priv_key.size() {
312 return Err(Error::Decryption);
313 }
314
315 let ciphertext = BoxedUint::from_be_slice(ciphertext, priv_key.n_bits_precision())?;
316 let em = rsa_decrypt_and_check(priv_key, rng, &ciphertext)?;
317 let mut em = uint_to_zeroizing_be_pad(em, priv_key.size())?;
318
319 oaep_decrypt_digest::<D, MGD>(&mut em, label, priv_key.size())
320}
321
322#[cfg(test)]
323mod tests {
324 use crate::key::{RsaPrivateKey, RsaPublicKey};
325 use crate::oaep::{DecryptingKey, EncryptingKey, Oaep};
326 use crate::traits::PublicKeyParts;
327 use crate::traits::{Decryptor, RandomizedDecryptor, RandomizedEncryptor};
328
329 use crypto_bigint::BoxedUint;
330 use digest::{Digest, FixedOutputReset};
331 use rand::rngs::ChaCha8Rng;
332 use rand_core::{Rng, SeedableRng};
333 use sha1::Sha1;
334 use sha2::{Sha224, Sha256, Sha384, Sha512};
335 use sha3::{Sha3_256, Sha3_384, Sha3_512};
336
337 fn get_private_key() -> RsaPrivateKey {
338 RsaPrivateKey::from_components(
367 BoxedUint::from_be_hex("d397b84d98a4c26138ed1b695a8106ead91d553bf06041b62d3fdc50a041e222b8f4529689c1b82c5e71554f5dd69fa2f4b6158cf0dbeb57811a0fc327e1f28e74fe74d3bc166c1eabdc1b8b57b934ca8be5b00b4f29975bcc99acaf415b59bb28a6782bb41a2c3c2976b3c18dbadef62f00c6bb226640095096c0cc60d22fe7ef987d75c6a81b10d96bf292028af110dc7cc1bbc43d22adab379a0cd5d8078cc780ff5cd6209dea34c922cf784f7717e428d75b5aec8ff30e5f0141510766e2e0ab8d473c84e8710b2b98227c3db095337ad3452f19e2b9bfbccdd8148abf6776fa552775e6e75956e45229ae5a9c46949bab1e622f0e48f56524a84ed3483b", 2048).unwrap(),
368 BoxedUint::from(65_537u64),
369 BoxedUint::from_be_hex("c4e70c689162c94c660828191b52b4d8392115df486a9adbe831e458d73958320dc1b755456e93701e9702d76fb0b92f90e01d1fe248153281fe79aa9763a92fae69d8d7ecd144de29fa135bd14f9573e349e45031e3b76982f583003826c552e89a397c1a06bd2163488630d92e8c2bb643d7abef700da95d685c941489a46f54b5316f62b5d2c3a7f1bbd134cb37353a44683fdc9d95d36458de22f6c44057fe74a0a436c4308f73f4da42f35c47ac16a7138d483afc91e41dc3a1127382e0c0f5119b0221b4fc639d6b9c38177a6de9b526ebd88c38d7982c07f98a0efd877d508aae275b946915c02e2e1106d175d74ec6777f5e80d12c053d9c7be1e341", 2048).unwrap(),
370 vec![
371 BoxedUint::from_be_hex("f827bbf3a41877c7cc59aebf42ed4b29c32defcb8ed96863d5b090a05a8930dd624a21c9dcf9838568fdfa0df65b8462a5f2ac913d6c56f975532bd8e78fb07bd405ca99a484bcf59f019bbddcb3933f2bce706300b4f7b110120c5df9018159067c35da3061a56c8635a52b54273b31271b4311f0795df6021e6355e1a42e61", 1024).unwrap(),
372 BoxedUint::from_be_hex("da4817ce0089dd36f2ade6a3ff410c73ec34bf1b4f6bda38431bfede11cef1f7f6efa70e5f8063a3b1f6e17296ffb15feefa0912a0325b8d1fd65a559e717b5b961ec345072e0ec5203d03441d29af4d64054a04507410cf1da78e7b6119d909ec66e6ad625bf995b279a4b3c5be7d895cd7c5b9c4c497fde730916fcdb4e41b", 1024).unwrap()
373 ],
374 ).unwrap()
375 }
376
377 #[test]
378 fn test_encrypt_decrypt_oaep() {
379 let priv_key = get_private_key();
380 do_test_encrypt_decrypt_oaep::<Sha1>(&priv_key);
381 do_test_encrypt_decrypt_oaep::<Sha224>(&priv_key);
382 do_test_encrypt_decrypt_oaep::<Sha256>(&priv_key);
383 do_test_encrypt_decrypt_oaep::<Sha384>(&priv_key);
384 do_test_encrypt_decrypt_oaep::<Sha512>(&priv_key);
385 do_test_encrypt_decrypt_oaep::<Sha3_256>(&priv_key);
386 do_test_encrypt_decrypt_oaep::<Sha3_384>(&priv_key);
387 do_test_encrypt_decrypt_oaep::<Sha3_512>(&priv_key);
388
389 do_test_oaep_with_different_hashes::<Sha1, Sha1>(&priv_key);
390 do_test_oaep_with_different_hashes::<Sha224, Sha1>(&priv_key);
391 do_test_oaep_with_different_hashes::<Sha256, Sha1>(&priv_key);
392 do_test_oaep_with_different_hashes::<Sha384, Sha1>(&priv_key);
393 do_test_oaep_with_different_hashes::<Sha512, Sha1>(&priv_key);
394 do_test_oaep_with_different_hashes::<Sha3_256, Sha1>(&priv_key);
395 do_test_oaep_with_different_hashes::<Sha3_384, Sha1>(&priv_key);
396 do_test_oaep_with_different_hashes::<Sha3_512, Sha1>(&priv_key);
397 }
398
399 fn get_label(rng: &mut ChaCha8Rng) -> Option<Box<[u8]>> {
400 let mut buf = [0u8; 32];
401 rng.fill_bytes(&mut buf);
402
403 if rng.next_u32() % 2 == 0 {
404 Some(buf.into())
405 } else {
406 None
407 }
408 }
409
410 fn do_test_encrypt_decrypt_oaep<D: Digest + FixedOutputReset>(prk: &RsaPrivateKey) {
411 let mut rng = ChaCha8Rng::from_seed([42; 32]);
412
413 let k = prk.size();
414
415 for i in 1..8 {
416 let mut input = vec![0u8; i * 8];
417 rng.fill_bytes(&mut input);
418
419 if input.len() > k - 11 {
420 input = input[0..k - 11].to_vec();
421 }
422 let label = get_label(&mut rng);
423
424 let pub_key: RsaPublicKey = prk.into();
425
426 let ciphertext = if let Some(ref label) = label {
427 let padding = Oaep::<D>::new_with_label(label.clone());
428 pub_key.encrypt(&mut rng, padding, &input).unwrap()
429 } else {
430 let padding = Oaep::<D>::new();
431 pub_key.encrypt(&mut rng, padding, &input).unwrap()
432 };
433
434 assert_ne!(input, ciphertext);
435 let blind: bool = rng.next_u32() < (1 << 31);
436
437 let padding = if let Some(label) = label {
438 Oaep::<D>::new_with_label::<Box<[u8]>>(label)
439 } else {
440 Oaep::<D>::new()
441 };
442
443 let plaintext = if blind {
444 prk.decrypt(padding, &ciphertext).unwrap()
445 } else {
446 prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
447 };
448
449 assert_eq!(input, plaintext);
450 }
451 }
452
453 fn do_test_oaep_with_different_hashes<
454 D: Digest + FixedOutputReset,
455 U: Digest + FixedOutputReset,
456 >(
457 prk: &RsaPrivateKey,
458 ) {
459 let mut rng = ChaCha8Rng::from_seed([42; 32]);
460
461 let k = prk.size();
462
463 for i in 1..8 {
464 let mut input = vec![0u8; i * 8];
465 rng.fill_bytes(&mut input);
466
467 if input.len() > k - 11 {
468 input = input[0..k - 11].to_vec();
469 }
470 let label = get_label(&mut rng);
471
472 let pub_key: RsaPublicKey = prk.into();
473
474 let ciphertext = if let Some(ref label) = label {
475 let padding = Oaep::<D, U>::new_with_mgf_hash_and_label::<_>(label.clone());
476 pub_key.encrypt(&mut rng, padding, &input).unwrap()
477 } else {
478 let padding = Oaep::<D, U>::new_with_mgf_hash();
479 pub_key.encrypt(&mut rng, padding, &input).unwrap()
480 };
481
482 assert_ne!(input, ciphertext);
483 let blind: bool = rng.next_u32() < (1 << 31);
484
485 let padding = if let Some(label) = label {
486 Oaep::<D, U>::new_with_mgf_hash_and_label::<_>(label)
487 } else {
488 Oaep::<D, U>::new_with_mgf_hash()
489 };
490
491 let plaintext = if blind {
492 prk.decrypt(padding, &ciphertext).unwrap()
493 } else {
494 prk.decrypt_blinded(&mut rng, padding, &ciphertext).unwrap()
495 };
496
497 assert_eq!(input, plaintext);
498 }
499 }
500
501 #[test]
502 fn test_decrypt_oaep_invalid_hash() {
503 let mut rng = ChaCha8Rng::from_seed([42; 32]);
504 let priv_key = get_private_key();
505 let pub_key: RsaPublicKey = (&priv_key).into();
506 let ciphertext = pub_key
507 .encrypt(&mut rng, Oaep::<Sha1>::new(), "a_plain_text".as_bytes())
508 .unwrap();
509 assert!(
510 priv_key
511 .decrypt_blinded(
512 &mut rng,
513 Oaep::<Sha1>::new_with_label::<_>("label".as_bytes()),
514 &ciphertext,
515 )
516 .is_err(),
517 "decrypt should have failed on hash verification"
518 );
519 }
520
521 #[test]
522 fn test_encrypt_decrypt_oaep_traits() {
523 let priv_key = get_private_key();
524 do_test_encrypt_decrypt_oaep_traits::<Sha1>(&priv_key);
525 do_test_encrypt_decrypt_oaep_traits::<Sha224>(&priv_key);
526 do_test_encrypt_decrypt_oaep_traits::<Sha256>(&priv_key);
527 do_test_encrypt_decrypt_oaep_traits::<Sha384>(&priv_key);
528 do_test_encrypt_decrypt_oaep_traits::<Sha512>(&priv_key);
529 do_test_encrypt_decrypt_oaep_traits::<Sha3_256>(&priv_key);
530 do_test_encrypt_decrypt_oaep_traits::<Sha3_384>(&priv_key);
531 do_test_encrypt_decrypt_oaep_traits::<Sha3_512>(&priv_key);
532
533 do_test_oaep_with_different_hashes_traits::<Sha1, Sha1>(&priv_key);
534 do_test_oaep_with_different_hashes_traits::<Sha224, Sha1>(&priv_key);
535 do_test_oaep_with_different_hashes_traits::<Sha256, Sha1>(&priv_key);
536 do_test_oaep_with_different_hashes_traits::<Sha384, Sha1>(&priv_key);
537 do_test_oaep_with_different_hashes_traits::<Sha512, Sha1>(&priv_key);
538 do_test_oaep_with_different_hashes_traits::<Sha3_256, Sha1>(&priv_key);
539 do_test_oaep_with_different_hashes_traits::<Sha3_384, Sha1>(&priv_key);
540 do_test_oaep_with_different_hashes_traits::<Sha3_512, Sha1>(&priv_key);
541 }
542
543 fn do_test_encrypt_decrypt_oaep_traits<D: Digest + FixedOutputReset>(prk: &RsaPrivateKey) {
544 do_test_oaep_with_different_hashes_traits::<D, D>(prk);
545 }
546
547 fn do_test_oaep_with_different_hashes_traits<D: Digest, MGD: Digest + FixedOutputReset>(
548 prk: &RsaPrivateKey,
549 ) {
550 let mut rng = ChaCha8Rng::from_seed([42; 32]);
551
552 let k = prk.size();
553
554 for i in 1..8 {
555 let mut input = vec![0u8; i * 8];
556 rng.fill_bytes(&mut input);
557
558 if input.len() > k - 11 {
559 input = input[0..k - 11].to_vec();
560 }
561 let label = get_label(&mut rng);
562
563 let pub_key: RsaPublicKey = prk.into();
564
565 let ciphertext = if let Some(ref label) = label {
566 let encrypting_key =
567 EncryptingKey::<D, MGD>::new_with_label(pub_key, label.clone());
568 encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap()
569 } else {
570 let encrypting_key = EncryptingKey::<D, MGD>::new(pub_key);
571 encrypting_key.encrypt_with_rng(&mut rng, &input).unwrap()
572 };
573
574 assert_ne!(input, ciphertext);
575 let blind: bool = rng.next_u32() < (1 << 31);
576
577 let decrypting_key = if let Some(ref label) = label {
578 DecryptingKey::<D, MGD>::new_with_label(prk.clone(), label.clone())
579 } else {
580 DecryptingKey::<D, MGD>::new(prk.clone())
581 };
582
583 let plaintext = if blind {
584 decrypting_key.decrypt(&ciphertext).unwrap()
585 } else {
586 decrypting_key
587 .decrypt_with_rng(&mut rng, &ciphertext)
588 .unwrap()
589 };
590
591 assert_eq!(input, plaintext);
592 }
593 }
594
595 #[test]
596 fn test_decrypt_oaep_invalid_hash_traits() {
597 let mut rng = ChaCha8Rng::from_seed([42; 32]);
598 let priv_key = get_private_key();
599 let pub_key: RsaPublicKey = (&priv_key).into();
600 let encrypting_key = EncryptingKey::<Sha1>::new(pub_key);
601 let decrypting_key = DecryptingKey::<Sha1>::new_with_label(priv_key, "label".as_bytes());
602 let ciphertext = encrypting_key
603 .encrypt_with_rng(&mut rng, "a_plain_text".as_bytes())
604 .unwrap();
605 assert!(
606 decrypting_key
607 .decrypt_with_rng(&mut rng, &ciphertext)
608 .is_err(),
609 "decrypt should have failed on hash verification"
610 );
611 }
612}