1use zeroize::{Zeroize, Zeroizing};
44
45use super::crypto_generichash::{
46 crypto_generichash_final, crypto_generichash_init, crypto_generichash_update,
47};
48use crate::classic::crypto_box_impl::*;
49use crate::classic::crypto_secretbox::*;
50use crate::classic::crypto_secretbox_impl::*;
51use crate::constants::*;
52use crate::error::Error;
53use crate::types::*;
54
55pub type Mac = [u8; CRYPTO_BOX_MACBYTES];
57
58pub type Nonce = [u8; CRYPTO_BOX_NONCEBYTES];
60pub type PublicKey = [u8; CRYPTO_BOX_PUBLICKEYBYTES];
62pub type SecretKey = [u8; CRYPTO_BOX_SECRETKEYBYTES];
64
65pub fn crypto_box_keypair_inplace(public_key: &mut PublicKey, secret_key: &mut SecretKey) {
67 crypto_box_curve25519xsalsa20poly1305_keypair_inplace(public_key, secret_key)
68}
69
70pub fn crypto_box_seed_keypair_inplace(
72 public_key: &mut PublicKey,
73 secret_key: &mut SecretKey,
74 seed: &[u8; CRYPTO_BOX_SEEDBYTES],
75) {
76 crypto_box_curve25519xsalsa20poly1305_seed_keypair_inplace(public_key, secret_key, seed)
77}
78
79pub fn crypto_box_keypair() -> (PublicKey, SecretKey) {
82 crypto_box_curve25519xsalsa20poly1305_keypair()
83}
84
85pub fn crypto_box_seed_keypair(seed: &[u8; CRYPTO_BOX_SEEDBYTES]) -> (PublicKey, SecretKey) {
89 crypto_box_curve25519xsalsa20poly1305_seed_keypair(seed)
90}
91
92pub fn crypto_box_beforenm(public_key: &PublicKey, secret_key: &SecretKey) -> Result<Key, Error> {
101 crypto_box_curve25519xsalsa20poly1305_beforenm(public_key, secret_key)
102}
103
104pub fn crypto_box_detached_afternm(
113 ciphertext: &mut [u8],
114 mac: &mut Mac,
115 message: &[u8],
116 nonce: &Nonce,
117 key: &Key,
118) -> Result<(), Error> {
119 crypto_secretbox_detached(ciphertext, mac, message, nonce, key)
120}
121
122pub fn crypto_box_detached_afternm_inplace(
124 ciphertext: &mut [u8],
125 mac: &mut Mac,
126 nonce: &Nonce,
127 key: &Key,
128) {
129 crypto_secretbox_detached_inplace(ciphertext, mac, nonce, key)
130}
131
132pub fn crypto_box_easy_afternm(
144 ciphertext: &mut [u8],
145 message: &[u8],
146 nonce: &Nonce,
147 key: &Key,
148) -> Result<(), Error> {
149 if message.len() > CRYPTO_BOX_MESSAGEBYTES_MAX {
150 return Err(
151 length_error!(crate::ErrorContext::Message, message.len(), max CRYPTO_BOX_MESSAGEBYTES_MAX),
152 );
153 }
154
155 let expected_ciphertext_len = message.len() + CRYPTO_BOX_MACBYTES;
156 if ciphertext.len() != expected_ciphertext_len {
157 return Err(length_error!(
158 crate::ErrorContext::Ciphertext,
159 ciphertext.len(),
160 exact expected_ciphertext_len
161 ));
162 }
163
164 let (mac, ciphertext) = ciphertext.split_at_mut(CRYPTO_BOX_MACBYTES);
165 crypto_box_detached_afternm(
166 ciphertext,
167 MutByteArray::as_mut_array(mac),
168 message,
169 nonce,
170 key,
171 )
172}
173
174pub fn crypto_box_detached(
183 ciphertext: &mut [u8],
184 mac: &mut Mac,
185 message: &[u8],
186 nonce: &Nonce,
187 recipient_public_key: &PublicKey,
188 sender_secret_key: &SecretKey,
189) -> Result<(), Error> {
190 let key = Zeroizing::new(crypto_box_beforenm(
191 recipient_public_key,
192 sender_secret_key,
193 )?);
194
195 crypto_box_detached_afternm(ciphertext, mac, message, nonce, &key)
196}
197
198pub fn crypto_box_detached_inplace(
204 message: &mut [u8],
205 mac: &mut Mac,
206 nonce: &Nonce,
207 recipient_public_key: &PublicKey,
208 sender_secret_key: &SecretKey,
209) -> Result<(), Error> {
210 let key = Zeroizing::new(crypto_box_beforenm(
211 recipient_public_key,
212 sender_secret_key,
213 )?);
214
215 crypto_box_detached_afternm_inplace(message, mac, nonce, &key);
216
217 Ok(())
218}
219pub fn crypto_box_easy(
233 ciphertext: &mut [u8],
234 message: &[u8],
235 nonce: &Nonce,
236 recipient_public_key: &PublicKey,
237 sender_secret_key: &SecretKey,
238) -> Result<(), Error> {
239 if message.len() > CRYPTO_BOX_MESSAGEBYTES_MAX {
240 Err(
241 length_error!(crate::ErrorContext::Message, message.len(), max CRYPTO_BOX_MESSAGEBYTES_MAX),
242 )
243 } else if ciphertext.len() != message.len() + CRYPTO_BOX_MACBYTES {
244 Err(length_error!(
245 crate::ErrorContext::Ciphertext,
246 ciphertext.len(),
247 exact message.len() + CRYPTO_BOX_MACBYTES
248 ))
249 } else {
250 let (mac, ciphertext) = ciphertext.split_at_mut(CRYPTO_BOX_MACBYTES);
251 let mac = MutByteArray::as_mut_array(mac);
252 crypto_box_detached(
253 ciphertext,
254 mac,
255 message,
256 nonce,
257 recipient_public_key,
258 sender_secret_key,
259 )?;
260
261 Ok(())
262 }
263}
264
265pub(crate) fn crypto_box_seal_nonce(nonce: &mut Nonce, epk: &PublicKey, rpk: &SecretKey) {
266 let mut state = crypto_generichash_init(None, CRYPTO_BOX_NONCEBYTES).expect("state");
267 crypto_generichash_update(&mut state, epk);
268 crypto_generichash_update(&mut state, rpk);
269 crypto_generichash_final(state, nonce).expect("hash error");
270}
271
272fn crypto_box_seal_ciphertext_len(message_len: usize) -> Result<usize, Error> {
273 message_len
274 .checked_add(CRYPTO_BOX_SEALBYTES)
275 .ok_or(Error::arithmetic_overflow(crate::ErrorContext::SealedBox))
276}
277
278pub fn crypto_box_seal(
297 ciphertext: &mut [u8],
298 message: &[u8],
299 recipient_public_key: &PublicKey,
300) -> Result<(), Error> {
301 let expected_ciphertext_len = crypto_box_seal_ciphertext_len(message.len())?;
302 if ciphertext.len() != expected_ciphertext_len {
303 Err(length_error!(
304 crate::ErrorContext::Ciphertext,
305 ciphertext.len(),
306 exact expected_ciphertext_len
307 ))
308 } else {
309 let mut nonce = Nonce::new_byte_array();
310 let (mut epk, esk) = crypto_box_keypair();
311 let esk = Zeroizing::new(esk);
312 crypto_box_seal_nonce(&mut nonce, &epk, recipient_public_key);
313
314 crypto_box_easy(
315 &mut ciphertext[CRYPTO_BOX_PUBLICKEYBYTES..],
316 message,
317 &nonce,
318 recipient_public_key,
319 &esk,
320 )?;
321
322 ciphertext[..CRYPTO_BOX_PUBLICKEYBYTES].copy_from_slice(&epk);
323
324 epk.zeroize();
325 nonce.zeroize();
326
327 Ok(())
328 }
329}
330
331pub fn crypto_box_easy_inplace(
350 data: &mut [u8],
351 nonce: &Nonce,
352 recipient_public_key: &PublicKey,
353 sender_secret_key: &SecretKey,
354) -> Result<(), Error> {
355 if data.len() < CRYPTO_BOX_MACBYTES {
356 Err(length_error!(crate::ErrorContext::Data, data.len(), min CRYPTO_BOX_MACBYTES))
357 } else if data.len() - CRYPTO_BOX_MACBYTES > CRYPTO_BOX_MESSAGEBYTES_MAX {
358 Err(length_error!(
359 crate::ErrorContext::Data,
360 data.len(),
361 max CRYPTO_BOX_MESSAGEBYTES_MAX + CRYPTO_BOX_MACBYTES
362 ))
363 } else {
364 let key = Zeroizing::new(crypto_box_beforenm(
365 recipient_public_key,
366 sender_secret_key,
367 )?);
368
369 data.rotate_right(CRYPTO_BOX_MACBYTES);
370
371 let (mac, data) = data.split_at_mut(CRYPTO_BOX_MACBYTES);
372 let mac = MutByteArray::as_mut_array(mac);
373
374 crypto_box_detached_afternm_inplace(data, mac, nonce, &key);
375
376 Ok(())
377 }
378}
379
380pub fn crypto_box_open_detached_afternm(
389 message: &mut [u8],
390 mac: &Mac,
391 ciphertext: &[u8],
392 nonce: &Nonce,
393 key: &Key,
394) -> Result<(), Error> {
395 crypto_secretbox_open_detached(message, mac, ciphertext, nonce, key)
396}
397
398pub fn crypto_box_open_detached_afternm_inplace(
404 data: &mut [u8],
405 mac: &Mac,
406 nonce: &Nonce,
407 key: &Key,
408) -> Result<(), Error> {
409 crypto_secretbox_open_detached_inplace(data, mac, nonce, key)
410}
411
412pub fn crypto_box_open_easy_afternm(
421 message: &mut [u8],
422 ciphertext: &[u8],
423 nonce: &Nonce,
424 key: &Key,
425) -> Result<(), Error> {
426 if ciphertext.len() < CRYPTO_BOX_MACBYTES {
427 return Err(
428 length_error!(crate::ErrorContext::Ciphertext, ciphertext.len(), min CRYPTO_BOX_MACBYTES),
429 );
430 }
431
432 let expected_message_len = ciphertext.len() - CRYPTO_BOX_MACBYTES;
433 if message.len() != expected_message_len {
434 return Err(length_error!(
435 crate::ErrorContext::Message,
436 message.len(),
437 exact expected_message_len
438 ));
439 }
440
441 let (mac, ciphertext) = ciphertext.split_at(CRYPTO_BOX_MACBYTES);
442 crypto_box_open_detached_afternm(message, ByteArray::as_array(mac), ciphertext, nonce, key)
443}
444
445pub fn crypto_box_open_detached(
455 message: &mut [u8],
456 mac: &Mac,
457 ciphertext: &[u8],
458 nonce: &Nonce,
459 recipient_public_key: &PublicKey,
460 sender_secret_key: &SecretKey,
461) -> Result<(), Error> {
462 let key = Zeroizing::new(crypto_box_beforenm(
463 recipient_public_key,
464 sender_secret_key,
465 )?);
466
467 crypto_box_open_detached_afternm(message, mac, ciphertext, nonce, &key)?;
468
469 Ok(())
470}
471
472pub fn crypto_box_open_detached_inplace(
479 data: &mut [u8],
480 mac: &Mac,
481 nonce: &Nonce,
482 recipient_public_key: &PublicKey,
483 sender_secret_key: &SecretKey,
484) -> Result<(), Error> {
485 let key = Zeroizing::new(crypto_box_beforenm(
486 recipient_public_key,
487 sender_secret_key,
488 )?);
489
490 crypto_box_open_detached_afternm_inplace(data, mac, nonce, &key)?;
491
492 Ok(())
493}
494
495pub fn crypto_box_open_easy(
506 message: &mut [u8],
507 ciphertext: &[u8],
508 nonce: &Nonce,
509 sender_public_key: &PublicKey,
510 recipient_secret_key: &SecretKey,
511) -> Result<(), Error> {
512 if ciphertext.len() < CRYPTO_BOX_MACBYTES {
513 Err(
514 length_error!(crate::ErrorContext::Ciphertext, ciphertext.len(), min CRYPTO_BOX_MACBYTES),
515 )
516 } else if message.len() != ciphertext.len() - CRYPTO_BOX_MACBYTES {
517 Err(length_error!(
518 crate::ErrorContext::Message,
519 message.len(),
520 exact ciphertext.len() - CRYPTO_BOX_MACBYTES
521 ))
522 } else {
523 let (mac, ciphertext) = ciphertext.split_at(CRYPTO_BOX_MACBYTES);
524 let mac = ByteArray::as_array(mac);
525
526 crypto_box_open_detached(
527 message,
528 mac,
529 ciphertext,
530 nonce,
531 sender_public_key,
532 recipient_secret_key,
533 )
534 }
535}
536
537pub fn crypto_box_seal_open(
552 message: &mut [u8],
553 ciphertext: &[u8],
554 recipient_public_key: &PublicKey,
555 recipient_secret_key: &SecretKey,
556) -> Result<(), Error> {
557 if ciphertext.len() < CRYPTO_BOX_SEALBYTES {
558 Err(
559 length_error!(crate::ErrorContext::Ciphertext, ciphertext.len(), min CRYPTO_BOX_SEALBYTES),
560 )
561 } else if message.len() != ciphertext.len() - CRYPTO_BOX_SEALBYTES {
562 Err(length_error!(
563 crate::ErrorContext::Message,
564 message.len(),
565 exact ciphertext.len() - CRYPTO_BOX_SEALBYTES
566 ))
567 } else {
568 let mut nonce = Nonce::new_byte_array();
569 let mut epk = PublicKey::new_byte_array();
570 epk.copy_from_slice(&ciphertext[..CRYPTO_BOX_PUBLICKEYBYTES]);
571
572 crypto_box_seal_nonce(&mut nonce, &epk, recipient_public_key);
573
574 crypto_box_open_easy(
575 message,
576 &ciphertext[CRYPTO_BOX_PUBLICKEYBYTES..],
577 &nonce,
578 &epk,
579 recipient_secret_key,
580 )
581 }
582}
583
584pub fn crypto_box_open_easy_inplace(
602 data: &mut [u8],
603 nonce: &Nonce,
604 sender_public_key: &PublicKey,
605 recipient_secret_key: &SecretKey,
606) -> Result<(), Error> {
607 if data.len() < CRYPTO_BOX_MACBYTES {
608 Err(length_error!(crate::ErrorContext::Data, data.len(), min CRYPTO_BOX_MACBYTES))
609 } else {
610 let (mac, d) = data.split_at_mut(CRYPTO_BOX_MACBYTES);
611 let mac = ByteArray::as_array(mac);
612
613 crypto_box_open_detached_inplace(d, mac, nonce, sender_public_key, recipient_secret_key)?;
614
615 data.rotate_left(CRYPTO_BOX_MACBYTES);
616
617 Ok(())
618 }
619}
620
621#[cfg(test)]
622mod tests {
623 use super::*;
624 use crate::rng::*;
625
626 #[test]
627 fn test_crypto_box_easy_invalid() {
628 for _ in 0..20 {
629 let (sender_pk, _sender_sk) = crypto_box_keypair();
630 let (_recipient_pk, recipient_sk) = crypto_box_keypair();
631 let nonce = Nonce::generate();
632
633 let mut ciphertext: Vec<u8> = vec![];
634 let message: Vec<u8> = vec![];
635
636 crypto_box_open_easy(&mut ciphertext, &message, &nonce, &sender_pk, &recipient_sk)
637 .expect_err("expected an error");
638 }
639 }
640
641 #[test]
642 fn test_crypto_box_rejects_mismatched_buffers_without_mutation() {
643 let (sender_pk, sender_sk) = crypto_box_keypair();
644 let (recipient_pk, recipient_sk) = crypto_box_keypair();
645 let nonce = Nonce::default();
646 let message = b"buffer length validation";
647
648 for output_len in [
649 message.len() + CRYPTO_BOX_MACBYTES - 1,
650 message.len() + CRYPTO_BOX_MACBYTES + 1,
651 ] {
652 let mut output = vec![0xa5; output_len];
653 let original = output.clone();
654 assert!(
655 crypto_box_easy(&mut output, message, &nonce, &recipient_pk, &sender_sk,).is_err()
656 );
657 assert_eq!(output, original);
658 }
659
660 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_MACBYTES];
661 crypto_box_easy(&mut ciphertext, message, &nonce, &recipient_pk, &sender_sk)
662 .expect("encrypt failed");
663
664 for output_len in [message.len() - 1, message.len() + 1] {
665 let mut output = vec![0xa5; output_len];
666 let original = output.clone();
667 assert!(
668 crypto_box_open_easy(&mut output, &ciphertext, &nonce, &sender_pk, &recipient_sk,)
669 .is_err()
670 );
671 assert_eq!(output, original);
672 }
673 }
674
675 #[test]
676 fn test_crypto_box_easy_afternm_roundtrip_and_failure_atomicity() {
677 let (sender_public_key, sender_secret_key) = crypto_box_keypair();
678 let (recipient_public_key, recipient_secret_key) = crypto_box_keypair();
679 let nonce = Nonce::generate();
680 let message = b"precomputed crypto box";
681 let sender_key = crypto_box_beforenm(&recipient_public_key, &sender_secret_key)
682 .expect("sender precalculation failed");
683 let recipient_key = crypto_box_beforenm(&sender_public_key, &recipient_secret_key)
684 .expect("recipient precalculation failed");
685 assert_eq!(sender_key, recipient_key);
686
687 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_MACBYTES];
688 crypto_box_easy_afternm(&mut ciphertext, message, &nonce, &sender_key)
689 .expect("encryption failed");
690 let mut direct_ciphertext = vec![0u8; ciphertext.len()];
691 crypto_box_easy(
692 &mut direct_ciphertext,
693 message,
694 &nonce,
695 &recipient_public_key,
696 &sender_secret_key,
697 )
698 .expect("direct encryption failed");
699 assert_eq!(ciphertext, direct_ciphertext);
700
701 let mut decrypted = vec![0u8; message.len()];
702 crypto_box_open_easy_afternm(&mut decrypted, &ciphertext, &nonce, &recipient_key)
703 .expect("decryption failed");
704 assert_eq!(decrypted, message);
705
706 ciphertext[0] ^= 1;
707 decrypted.fill(0xa5);
708 let original_decrypted = decrypted.clone();
709 assert!(
710 crypto_box_open_easy_afternm(&mut decrypted, &ciphertext, &nonce, &recipient_key)
711 .is_err()
712 );
713 assert_eq!(decrypted, original_decrypted);
714 }
715
716 #[test]
717 fn test_crypto_box_seal_rejects_mismatched_buffers() {
718 let (recipient_public_key, recipient_secret_key) = crypto_box_keypair();
719 let message = b"sealed box buffer validation";
720
721 assert!(matches!(
722 crypto_box_seal_ciphertext_len(usize::MAX),
723 Err(Error::ArithmeticOverflow {
724 context: crate::ErrorContext::SealedBox,
725 })
726 ));
727
728 let mut short_ciphertext = vec![0u8; message.len() + CRYPTO_BOX_SEALBYTES - 1];
729 assert!(matches!(
730 crypto_box_seal(&mut short_ciphertext, message, &recipient_public_key),
731 Err(Error::InvalidLength {
732 context: crate::ErrorContext::Ciphertext,
733 actual,
734 constraint: crate::LengthConstraint::Exact(expected),
735 }) if actual == short_ciphertext.len()
736 && expected == message.len() + CRYPTO_BOX_SEALBYTES
737 ));
738
739 let short_sealed_box = vec![0u8; CRYPTO_BOX_SEALBYTES - 1];
740 assert!(matches!(
741 crypto_box_seal_open(
742 &mut [],
743 &short_sealed_box,
744 &recipient_public_key,
745 &recipient_secret_key,
746 ),
747 Err(Error::InvalidLength {
748 context: crate::ErrorContext::Ciphertext,
749 actual,
750 constraint: crate::LengthConstraint::AtLeast(CRYPTO_BOX_SEALBYTES),
751 }) if actual == short_sealed_box.len()
752 ));
753
754 let sealed_box = vec![0u8; CRYPTO_BOX_SEALBYTES + 1];
755 assert!(matches!(
756 crypto_box_seal_open(
757 &mut [],
758 &sealed_box,
759 &recipient_public_key,
760 &recipient_secret_key,
761 ),
762 Err(Error::InvalidLength {
763 context: crate::ErrorContext::Message,
764 actual: 0,
765 constraint: crate::LengthConstraint::Exact(1),
766 })
767 ));
768 }
769
770 #[test]
771 fn test_crypto_box_rejects_low_order_public_keys() {
772 let (_, secret_key) = crypto_box_keypair();
773 let nonce = Nonce::default();
774 let message = b"message";
775 let mut ciphertext = [0u8; 7];
776 let mut mac = Mac::default();
777 let mut one = PublicKey::default();
778 one[0] = 1;
779
780 for public_key in [PublicKey::default(), one] {
781 assert!(crypto_box_beforenm(&public_key, &secret_key).is_err());
782 assert!(
783 crypto_box_detached(
784 &mut ciphertext,
785 &mut mac,
786 message,
787 &nonce,
788 &public_key,
789 &secret_key,
790 )
791 .is_err()
792 );
793
794 let mut data = b"message with tag storage\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0".to_vec();
795 let original_data = data.clone();
796 assert!(crypto_box_easy_inplace(&mut data, &nonce, &public_key, &secret_key).is_err());
797 assert_eq!(data, original_data);
798 }
799 }
800 #[test]
801 fn test_crypto_box_easy_inplace_invalid() {
802 for _ in 0..20 {
803 use base64::Engine as _;
804 use base64::engine::general_purpose;
805
806 let (sender_pk, _sender_sk) = crypto_box_keypair();
807 let (_recipient_pk, recipient_sk) = crypto_box_keypair();
808 let nonce = Nonce::generate();
809
810 let mut ciphertext: Vec<u8> = vec![];
811
812 crypto_box_open_easy_inplace(&mut ciphertext, &nonce, &sender_pk, &recipient_sk)
813 .expect_err("expected an error");
814
815 ciphertext.resize(1024, 0);
816 copy_randombytes(ciphertext.as_mut_slice());
817 let ciphertext_copy = ciphertext.clone();
818
819 crypto_box_open_easy_inplace(&mut ciphertext, &nonce, &sender_pk, &recipient_sk)
820 .expect_err("expected an error");
821
822 assert_eq!(ciphertext.len(), ciphertext_copy.len());
823 assert_eq!(
824 general_purpose::STANDARD_NO_PAD.encode(&ciphertext[0..CRYPTO_BOX_MACBYTES]),
825 general_purpose::STANDARD_NO_PAD.encode(&ciphertext_copy[0..CRYPTO_BOX_MACBYTES])
826 );
827 }
828 }
829
830 #[cfg(dryoc_native_tests)]
831 mod native_tests {
832 use super::*;
833
834 #[test]
835 fn test_crypto_box_beforenm_low_order_compatibility() {
836 let (_, secret_key) = crypto_box_keypair();
837 let mut one = PublicKey::default();
838 one[0] = 1;
839
840 for public_key in [PublicKey::default(), one] {
841 let mut sodium_key = Key::default();
842 let sodium_result = unsafe {
843 libsodium_sys::crypto_box_curve25519xsalsa20poly1305_beforenm(
844 sodium_key.as_mut_ptr(),
845 public_key.as_ptr(),
846 secret_key.as_ptr(),
847 )
848 };
849
850 assert!(crypto_box_beforenm(&public_key, &secret_key).is_err());
851 assert_eq!(sodium_result, -1);
852 }
853 }
854
855 #[test]
856 fn test_crypto_box_easy() {
857 for i in 0..20 {
858 use base64::Engine as _;
859 use base64::engine::general_purpose;
860 use sodiumoxide::crypto::box_;
861 use sodiumoxide::crypto::box_::{Nonce as SONonce, PublicKey, SecretKey};
862
863 let (sender_pk, sender_sk) = crypto_box_keypair();
864 let (recipient_pk, recipient_sk) = crypto_box_keypair();
865 let nonce = Nonce::generate();
866 let words = vec!["hello1".to_string(); i];
867 let message = words.join(" :D ");
868 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_MACBYTES];
869 crypto_box_easy(
870 &mut ciphertext,
871 message.as_bytes(),
872 &nonce,
873 &recipient_pk,
874 &sender_sk,
875 )
876 .expect("encrypt failed");
877
878 let so_ciphertext = box_::seal(
879 message.as_bytes(),
880 &SONonce::from_slice(&nonce).unwrap(),
881 &PublicKey::from_slice(&recipient_pk).unwrap(),
882 &SecretKey::from_slice(&sender_sk).unwrap(),
883 );
884
885 assert_eq!(
886 general_purpose::STANDARD_NO_PAD.encode(&ciphertext),
887 general_purpose::STANDARD_NO_PAD.encode(&so_ciphertext)
888 );
889
890 let mut m = vec![0u8; ciphertext.len() - CRYPTO_BOX_MACBYTES];
891 crypto_box_open_easy(
892 &mut m,
893 ciphertext.as_slice(),
894 &nonce,
895 &sender_pk,
896 &recipient_sk,
897 )
898 .expect("decrypt failed");
899 let so_m = box_::open(
900 ciphertext.as_slice(),
901 &SONonce::from_slice(&nonce).unwrap(),
902 &PublicKey::from_slice(&recipient_pk).unwrap(),
903 &SecretKey::from_slice(&sender_sk).unwrap(),
904 )
905 .unwrap();
906
907 assert_eq!(m, message.as_bytes());
908 assert_eq!(m, so_m);
909 }
910 }
911
912 #[test]
913 fn test_crypto_box_easy_inplace() {
914 for i in 0..20 {
915 use base64::Engine as _;
916 use base64::engine::general_purpose;
917 use sodiumoxide::crypto::box_;
918 use sodiumoxide::crypto::box_::{Nonce as SONonce, PublicKey, SecretKey};
919
920 let (sender_pk, sender_sk) = crypto_box_keypair();
921 let (recipient_pk, recipient_sk) = crypto_box_keypair();
922 let nonce = Nonce::generate();
923 let words = vec!["hello1".to_string(); i];
924 let message: Vec<u8> = words.join(" :D ").as_bytes().to_vec();
925 let message_copy = message.clone();
926
927 let mut ciphertext = message.clone();
928 ciphertext.resize(message.len() + CRYPTO_BOX_MACBYTES, 0);
929 crypto_box_easy_inplace(&mut ciphertext, &nonce, &recipient_pk, &sender_sk)
930 .expect("encrypt failed");
931 let so_ciphertext = box_::seal(
932 message_copy.as_slice(),
933 &SONonce::from_slice(&nonce).unwrap(),
934 &PublicKey::from_slice(&recipient_pk).unwrap(),
935 &SecretKey::from_slice(&sender_sk).unwrap(),
936 );
937
938 assert_eq!(
939 general_purpose::STANDARD_NO_PAD.encode(&ciphertext),
940 general_purpose::STANDARD_NO_PAD.encode(&so_ciphertext)
941 );
942
943 let mut ciphertext_clone = ciphertext.clone();
944 crypto_box_open_easy_inplace(
945 &mut ciphertext_clone,
946 &nonce,
947 &sender_pk,
948 &recipient_sk,
949 )
950 .expect("decrypt failed");
951 ciphertext_clone.resize(message.len(), 0);
952
953 let so_m = box_::open(
954 ciphertext.as_slice(),
955 &SONonce::from_slice(&nonce).unwrap(),
956 &PublicKey::from_slice(&recipient_pk).unwrap(),
957 &SecretKey::from_slice(&sender_sk).unwrap(),
958 )
959 .expect("decrypt failed");
960
961 assert_eq!(
962 general_purpose::STANDARD_NO_PAD.encode(&ciphertext_clone),
963 general_purpose::STANDARD_NO_PAD.encode(&message_copy)
964 );
965 assert_eq!(
966 general_purpose::STANDARD_NO_PAD.encode(&so_m),
967 general_purpose::STANDARD_NO_PAD.encode(&message_copy)
968 );
969 }
970 }
971
972 #[test]
973 fn test_crypto_box_seed_keypair() {
974 use base64::Engine as _;
975 use base64::engine::general_purpose;
976 use sodiumoxide::crypto::box_::{Seed, keypair_from_seed};
977
978 for _ in 0..10 {
979 let seed: [u8; CRYPTO_BOX_SEEDBYTES] = randombytes_buf(CRYPTO_BOX_SEEDBYTES)
980 .try_into()
981 .expect("seed length");
982
983 let (pk, sk) = crypto_box_seed_keypair(&seed);
984 let (so_pk, so_sk) = keypair_from_seed(&Seed::from_slice(&seed).unwrap());
985
986 assert_eq!(
987 general_purpose::STANDARD_NO_PAD.encode(pk),
988 general_purpose::STANDARD_NO_PAD.encode(so_pk.as_ref())
989 );
990 assert_eq!(
991 general_purpose::STANDARD_NO_PAD.encode(sk),
992 general_purpose::STANDARD_NO_PAD.encode(so_sk.as_ref())
993 );
994 }
995 }
996
997 #[test]
998 fn test_crypto_box_seal() {
999 for i in 0..20 {
1000 use sodiumoxide::crypto::box_::{PublicKey, SecretKey};
1001 use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305;
1002
1003 let (recipient_pk, recipient_sk) = crypto_box_keypair();
1004 let words = vec!["hello1".to_string(); i];
1005 let message = words.join(" :D ");
1006 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_SEALBYTES];
1007 crypto_box_seal(&mut ciphertext, message.as_bytes(), &recipient_pk)
1008 .expect("encrypt failed");
1009
1010 let mut m = vec![0u8; ciphertext.len() - CRYPTO_BOX_SEALBYTES];
1011 crypto_box_seal_open(&mut m, ciphertext.as_slice(), &recipient_pk, &recipient_sk)
1012 .expect("decrypt failed");
1013 let so_m = curve25519blake2bxsalsa20poly1305::open(
1014 ciphertext.as_slice(),
1015 &PublicKey::from_slice(&recipient_pk).unwrap(),
1016 &SecretKey::from_slice(&recipient_sk).unwrap(),
1017 )
1018 .unwrap();
1019
1020 assert_eq!(m, message.as_bytes());
1021 assert_eq!(m, so_m);
1022 }
1023 }
1024
1025 #[test]
1026 fn test_crypto_box_seal_open() {
1027 for i in 0..20 {
1028 use sodiumoxide::crypto::box_::{PublicKey, SecretKey};
1029 use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305;
1030
1031 let (recipient_pk, recipient_sk) = crypto_box_keypair();
1032 let words = vec!["hello1".to_string(); i];
1033 let message = words.join(" :D ");
1034 let so_ciphertext = curve25519blake2bxsalsa20poly1305::seal(
1035 message.as_bytes(),
1036 &PublicKey::from_slice(&recipient_pk).unwrap(),
1037 );
1038
1039 let mut m = vec![0u8; so_ciphertext.len() - CRYPTO_BOX_SEALBYTES];
1040 crypto_box_seal_open(
1041 &mut m,
1042 so_ciphertext.as_slice(),
1043 &recipient_pk,
1044 &recipient_sk,
1045 )
1046 .expect("decrypt failed");
1047 let so_m = curve25519blake2bxsalsa20poly1305::open(
1048 so_ciphertext.as_slice(),
1049 &PublicKey::from_slice(&recipient_pk).unwrap(),
1050 &SecretKey::from_slice(&recipient_sk).unwrap(),
1051 )
1052 .unwrap();
1053
1054 assert_eq!(m, message.as_bytes());
1055 assert_eq!(m, so_m);
1056 }
1057 }
1058 }
1059}