1use zeroize::{Zeroize, Zeroizing};
48
49use super::crypto_generichash::{
50 crypto_generichash_final, crypto_generichash_init, crypto_generichash_update,
51};
52use crate::classic::crypto_box_impl::*;
53use crate::classic::crypto_secretbox::*;
54use crate::classic::crypto_secretbox_impl::*;
55use crate::constants::*;
56use crate::error::Error;
57use crate::types::*;
58
59pub type Mac = [u8; CRYPTO_BOX_MACBYTES];
61
62pub type Nonce = [u8; CRYPTO_BOX_NONCEBYTES];
64pub type PublicKey = [u8; CRYPTO_BOX_PUBLICKEYBYTES];
66pub type SecretKey = [u8; CRYPTO_BOX_SECRETKEYBYTES];
68
69pub fn crypto_box_keypair_inplace(public_key: &mut PublicKey, secret_key: &mut SecretKey) {
71 crypto_box_curve25519xsalsa20poly1305_keypair_inplace(public_key, secret_key)
72}
73
74pub fn crypto_box_seed_keypair_inplace(
76 public_key: &mut PublicKey,
77 secret_key: &mut SecretKey,
78 seed: &[u8; CRYPTO_BOX_SEEDBYTES],
79) {
80 crypto_box_curve25519xsalsa20poly1305_seed_keypair_inplace(public_key, secret_key, seed)
81}
82
83#[must_use]
86pub fn crypto_box_keypair() -> (PublicKey, SecretKey) {
87 crypto_box_curve25519xsalsa20poly1305_keypair()
88}
89
90#[must_use]
94pub fn crypto_box_seed_keypair(seed: &[u8; CRYPTO_BOX_SEEDBYTES]) -> (PublicKey, SecretKey) {
95 crypto_box_curve25519xsalsa20poly1305_seed_keypair(seed)
96}
97
98pub fn crypto_box_beforenm(public_key: &PublicKey, secret_key: &SecretKey) -> Result<Key, Error> {
107 crypto_box_curve25519xsalsa20poly1305_beforenm(public_key, secret_key)
108}
109
110pub fn crypto_box_detached_afternm(
119 ciphertext: &mut [u8],
120 mac: &mut Mac,
121 message: &[u8],
122 nonce: &Nonce,
123 key: &Key,
124) -> Result<(), Error> {
125 crypto_secretbox_detached(ciphertext, mac, message, nonce, key)
126}
127
128pub fn crypto_box_detached_afternm_inplace(
130 ciphertext: &mut [u8],
131 mac: &mut Mac,
132 nonce: &Nonce,
133 key: &Key,
134) {
135 crypto_secretbox_detached_inplace(ciphertext, mac, nonce, key)
136}
137
138pub fn crypto_box_easy_afternm(
150 ciphertext: &mut [u8],
151 message: &[u8],
152 nonce: &Nonce,
153 key: &Key,
154) -> Result<(), Error> {
155 validate_length!(max CRYPTO_BOX_MESSAGEBYTES_MAX, message.len(), crate::ErrorContext::Message);
156
157 let expected_ciphertext_len = message.len() + CRYPTO_BOX_MACBYTES;
158 validate_length!(
159 exact expected_ciphertext_len,
160 ciphertext.len(),
161 crate::ErrorContext::Ciphertext
162 );
163
164 let (mac, ciphertext) = ciphertext
165 .split_first_chunk_mut::<CRYPTO_BOX_MACBYTES>()
166 .expect("validated ciphertext length");
167 crypto_box_detached_afternm(ciphertext, mac, message, nonce, key)
168}
169
170pub fn crypto_box_detached(
179 ciphertext: &mut [u8],
180 mac: &mut Mac,
181 message: &[u8],
182 nonce: &Nonce,
183 recipient_public_key: &PublicKey,
184 sender_secret_key: &SecretKey,
185) -> Result<(), Error> {
186 let mut key = Zeroizing::new(Key::default());
187 crypto_box_curve25519xsalsa20poly1305_beforenm_into(
188 &mut key,
189 recipient_public_key,
190 sender_secret_key,
191 )?;
192
193 crypto_box_detached_afternm(ciphertext, mac, message, nonce, &key)
194}
195
196pub fn crypto_box_detached_inplace(
202 message: &mut [u8],
203 mac: &mut Mac,
204 nonce: &Nonce,
205 recipient_public_key: &PublicKey,
206 sender_secret_key: &SecretKey,
207) -> Result<(), Error> {
208 let mut key = Zeroizing::new(Key::default());
209 crypto_box_curve25519xsalsa20poly1305_beforenm_into(
210 &mut key,
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 validate_length!(max CRYPTO_BOX_MESSAGEBYTES_MAX, message.len(), crate::ErrorContext::Message);
240 validate_length!(
241 exact message.len() + CRYPTO_BOX_MACBYTES,
242 ciphertext.len(),
243 crate::ErrorContext::Ciphertext
244 );
245
246 let (mac, ciphertext) = ciphertext
247 .split_first_chunk_mut::<CRYPTO_BOX_MACBYTES>()
248 .expect("validated ciphertext length");
249 crypto_box_detached(
250 ciphertext,
251 mac,
252 message,
253 nonce,
254 recipient_public_key,
255 sender_secret_key,
256 )?;
257
258 Ok(())
259}
260
261pub(crate) fn crypto_box_seal_nonce(nonce: &mut Nonce, epk: &PublicKey, rpk: &SecretKey) {
262 let mut state = crypto_generichash_init(None, CRYPTO_BOX_NONCEBYTES).expect("state");
263 crypto_generichash_update(&mut state, epk);
264 crypto_generichash_update(&mut state, rpk);
265 crypto_generichash_final(state, nonce).expect("hash error");
266}
267
268fn crypto_box_seal_ciphertext_len(message_len: usize) -> Result<usize, Error> {
269 message_len
270 .checked_add(CRYPTO_BOX_SEALBYTES)
271 .ok_or(Error::arithmetic_overflow(crate::ErrorContext::SealedBox))
272}
273
274pub fn crypto_box_seal(
293 ciphertext: &mut [u8],
294 message: &[u8],
295 recipient_public_key: &PublicKey,
296) -> Result<(), Error> {
297 let expected_ciphertext_len = crypto_box_seal_ciphertext_len(message.len())?;
298 validate_length!(
299 exact expected_ciphertext_len,
300 ciphertext.len(),
301 crate::ErrorContext::Ciphertext
302 );
303
304 let mut nonce = Nonce::new_byte_array();
305 let (mut epk, esk) = crypto_box_keypair();
306 let esk = Zeroizing::new(esk);
307 crypto_box_seal_nonce(&mut nonce, &epk, recipient_public_key);
308
309 crypto_box_easy(
310 &mut ciphertext[CRYPTO_BOX_PUBLICKEYBYTES..],
311 message,
312 &nonce,
313 recipient_public_key,
314 &esk,
315 )?;
316
317 ciphertext[..CRYPTO_BOX_PUBLICKEYBYTES].copy_from_slice(&epk);
318
319 epk.zeroize();
320 nonce.zeroize();
321
322 Ok(())
323}
324
325pub fn crypto_box_easy_inplace(
344 data: &mut [u8],
345 nonce: &Nonce,
346 recipient_public_key: &PublicKey,
347 sender_secret_key: &SecretKey,
348) -> Result<(), Error> {
349 validate_length!(min CRYPTO_BOX_MACBYTES, data.len(), crate::ErrorContext::Data);
350 validate_length!(
351 max CRYPTO_BOX_MESSAGEBYTES_MAX + CRYPTO_BOX_MACBYTES,
352 data.len(),
353 crate::ErrorContext::Data
354 );
355
356 let mut key = Zeroizing::new(Key::default());
357 crypto_box_curve25519xsalsa20poly1305_beforenm_into(
358 &mut key,
359 recipient_public_key,
360 sender_secret_key,
361 )?;
362
363 data.rotate_right(CRYPTO_BOX_MACBYTES);
364
365 let (mac, data) = data
366 .split_first_chunk_mut::<CRYPTO_BOX_MACBYTES>()
367 .expect("validated data length");
368
369 crypto_box_detached_afternm_inplace(data, mac, nonce, &key);
370
371 Ok(())
372}
373
374pub fn crypto_box_open_detached_afternm(
383 message: &mut [u8],
384 ciphertext: &[u8],
385 mac: &Mac,
386 nonce: &Nonce,
387 key: &Key,
388) -> Result<(), Error> {
389 crypto_secretbox_open_detached(message, ciphertext, mac, nonce, key)
390}
391
392pub fn crypto_box_open_detached_afternm_inplace(
398 data: &mut [u8],
399 mac: &Mac,
400 nonce: &Nonce,
401 key: &Key,
402) -> Result<(), Error> {
403 crypto_secretbox_open_detached_inplace(data, mac, nonce, key)
404}
405
406pub fn crypto_box_open_easy_afternm(
415 message: &mut [u8],
416 ciphertext: &[u8],
417 nonce: &Nonce,
418 key: &Key,
419) -> Result<(), Error> {
420 validate_length!(min CRYPTO_BOX_MACBYTES, ciphertext.len(), crate::ErrorContext::Ciphertext);
421
422 let expected_message_len = ciphertext.len() - CRYPTO_BOX_MACBYTES;
423 validate_length!(
424 exact expected_message_len,
425 message.len(),
426 crate::ErrorContext::Message
427 );
428
429 let (mac, ciphertext) = ciphertext
430 .split_first_chunk::<CRYPTO_BOX_MACBYTES>()
431 .expect("validated ciphertext length");
432 crypto_box_open_detached_afternm(message, ciphertext, mac, nonce, key)
433}
434
435pub fn crypto_box_open_detached(
447 message: &mut [u8],
448 ciphertext: &[u8],
449 mac: &Mac,
450 nonce: &Nonce,
451 sender_public_key: &PublicKey,
452 recipient_secret_key: &SecretKey,
453) -> Result<(), Error> {
454 let mut key = Zeroizing::new(Key::default());
455 crypto_box_curve25519xsalsa20poly1305_beforenm_into(
456 &mut key,
457 sender_public_key,
458 recipient_secret_key,
459 )?;
460
461 crypto_box_open_detached_afternm(message, ciphertext, mac, nonce, &key)?;
462
463 Ok(())
464}
465
466pub fn crypto_box_open_detached_inplace(
475 data: &mut [u8],
476 mac: &Mac,
477 nonce: &Nonce,
478 sender_public_key: &PublicKey,
479 recipient_secret_key: &SecretKey,
480) -> Result<(), Error> {
481 let mut key = Zeroizing::new(Key::default());
482 crypto_box_curve25519xsalsa20poly1305_beforenm_into(
483 &mut key,
484 sender_public_key,
485 recipient_secret_key,
486 )?;
487
488 crypto_box_open_detached_afternm_inplace(data, mac, nonce, &key)?;
489
490 Ok(())
491}
492
493pub fn crypto_box_open_easy(
504 message: &mut [u8],
505 ciphertext: &[u8],
506 nonce: &Nonce,
507 sender_public_key: &PublicKey,
508 recipient_secret_key: &SecretKey,
509) -> Result<(), Error> {
510 validate_length!(min CRYPTO_BOX_MACBYTES, ciphertext.len(), crate::ErrorContext::Ciphertext);
511 validate_length!(
512 exact ciphertext.len() - CRYPTO_BOX_MACBYTES,
513 message.len(),
514 crate::ErrorContext::Message
515 );
516
517 let (mac, ciphertext) = ciphertext
518 .split_first_chunk::<CRYPTO_BOX_MACBYTES>()
519 .expect("validated ciphertext length");
520
521 crypto_box_open_detached(
522 message,
523 ciphertext,
524 mac,
525 nonce,
526 sender_public_key,
527 recipient_secret_key,
528 )
529}
530
531pub fn crypto_box_seal_open(
546 message: &mut [u8],
547 ciphertext: &[u8],
548 recipient_public_key: &PublicKey,
549 recipient_secret_key: &SecretKey,
550) -> Result<(), Error> {
551 validate_length!(min CRYPTO_BOX_SEALBYTES, ciphertext.len(), crate::ErrorContext::Ciphertext);
552 validate_length!(
553 exact ciphertext.len() - CRYPTO_BOX_SEALBYTES,
554 message.len(),
555 crate::ErrorContext::Message
556 );
557
558 let mut nonce = Nonce::new_byte_array();
559 let mut epk = PublicKey::new_byte_array();
560 epk.copy_from_slice(&ciphertext[..CRYPTO_BOX_PUBLICKEYBYTES]);
561
562 crypto_box_seal_nonce(&mut nonce, &epk, recipient_public_key);
563
564 crypto_box_open_easy(
565 message,
566 &ciphertext[CRYPTO_BOX_PUBLICKEYBYTES..],
567 &nonce,
568 &epk,
569 recipient_secret_key,
570 )
571}
572
573pub fn crypto_box_open_easy_inplace(
591 data: &mut [u8],
592 nonce: &Nonce,
593 sender_public_key: &PublicKey,
594 recipient_secret_key: &SecretKey,
595) -> Result<(), Error> {
596 validate_length!(min CRYPTO_BOX_MACBYTES, data.len(), crate::ErrorContext::Data);
597
598 let (mac, d) = data
599 .split_first_chunk_mut::<CRYPTO_BOX_MACBYTES>()
600 .expect("validated data length");
601 let mac = &*mac;
602
603 crypto_box_open_detached_inplace(d, mac, nonce, sender_public_key, recipient_secret_key)?;
604
605 data.rotate_left(CRYPTO_BOX_MACBYTES);
606
607 Ok(())
608}
609
610#[cfg(test)]
611mod tests {
612 use super::*;
613 use crate::rng::*;
614 use crate::test_prelude::*;
615
616 #[test]
617 fn test_crypto_box_easy_invalid() {
618 for _ in 0..20 {
619 let (sender_pk, _sender_sk) = crypto_box_keypair();
620 let (_recipient_pk, recipient_sk) = crypto_box_keypair();
621 let nonce = Nonce::generate();
622
623 let mut ciphertext: Vec<u8> = vec![];
624 let message: Vec<u8> = vec![];
625
626 crypto_box_open_easy(&mut ciphertext, &message, &nonce, &sender_pk, &recipient_sk)
627 .expect_err("expected an error");
628 }
629 }
630
631 #[test]
632 fn test_crypto_box_rejects_mismatched_buffers_without_mutation() {
633 let (sender_pk, sender_sk) = crypto_box_keypair();
634 let (recipient_pk, recipient_sk) = crypto_box_keypair();
635 let nonce = Nonce::default();
636 let message = b"buffer length validation";
637
638 for output_len in [
639 message.len() + CRYPTO_BOX_MACBYTES - 1,
640 message.len() + CRYPTO_BOX_MACBYTES + 1,
641 ] {
642 let mut output = vec![0xa5; output_len];
643 let original = output.clone();
644 assert!(
645 crypto_box_easy(&mut output, message, &nonce, &recipient_pk, &sender_sk,).is_err()
646 );
647 assert_eq!(output, original);
648 }
649
650 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_MACBYTES];
651 crypto_box_easy(&mut ciphertext, message, &nonce, &recipient_pk, &sender_sk)
652 .expect("encrypt failed");
653
654 for output_len in [message.len() - 1, message.len() + 1] {
655 let mut output = vec![0xa5; output_len];
656 let original = output.clone();
657 assert!(
658 crypto_box_open_easy(&mut output, &ciphertext, &nonce, &sender_pk, &recipient_sk,)
659 .is_err()
660 );
661 assert_eq!(output, original);
662 }
663 }
664
665 #[test]
666 fn test_crypto_box_easy_afternm_roundtrip_and_failure_atomicity() {
667 let (sender_public_key, sender_secret_key) = crypto_box_keypair();
668 let (recipient_public_key, recipient_secret_key) = crypto_box_keypair();
669 let nonce = Nonce::generate();
670 let message = b"precomputed crypto box";
671 let sender_key = crypto_box_beforenm(&recipient_public_key, &sender_secret_key)
672 .expect("sender precalculation failed");
673 let recipient_key = crypto_box_beforenm(&sender_public_key, &recipient_secret_key)
674 .expect("recipient precalculation failed");
675 assert_eq!(sender_key, recipient_key);
676
677 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_MACBYTES];
678 crypto_box_easy_afternm(&mut ciphertext, message, &nonce, &sender_key)
679 .expect("encryption failed");
680 let mut direct_ciphertext = vec![0u8; ciphertext.len()];
681 crypto_box_easy(
682 &mut direct_ciphertext,
683 message,
684 &nonce,
685 &recipient_public_key,
686 &sender_secret_key,
687 )
688 .expect("direct encryption failed");
689 assert_eq!(ciphertext, direct_ciphertext);
690
691 let mut decrypted = vec![0u8; message.len()];
692 crypto_box_open_easy_afternm(&mut decrypted, &ciphertext, &nonce, &recipient_key)
693 .expect("decryption failed");
694 assert_eq!(decrypted, message);
695
696 ciphertext[0] ^= 1;
697 decrypted.fill(0xa5);
698 let original_decrypted = decrypted.clone();
699 assert!(
700 crypto_box_open_easy_afternm(&mut decrypted, &ciphertext, &nonce, &recipient_key)
701 .is_err()
702 );
703 assert_eq!(decrypted, original_decrypted);
704 }
705
706 #[test]
707 fn test_crypto_box_seal_rejects_mismatched_buffers() {
708 let (recipient_public_key, recipient_secret_key) = crypto_box_keypair();
709 let message = b"sealed box buffer validation";
710
711 assert!(matches!(
712 crypto_box_seal_ciphertext_len(usize::MAX),
713 Err(Error::ArithmeticOverflow {
714 context: crate::ErrorContext::SealedBox,
715 })
716 ));
717
718 let mut short_ciphertext = vec![0u8; message.len() + CRYPTO_BOX_SEALBYTES - 1];
719 assert!(matches!(
720 crypto_box_seal(&mut short_ciphertext, message, &recipient_public_key),
721 Err(Error::InvalidLength {
722 context: crate::ErrorContext::Ciphertext,
723 actual,
724 constraint: crate::LengthConstraint::Exact(expected),
725 }) if actual == short_ciphertext.len()
726 && expected == message.len() + CRYPTO_BOX_SEALBYTES
727 ));
728
729 let short_sealed_box = vec![0u8; CRYPTO_BOX_SEALBYTES - 1];
730 assert!(matches!(
731 crypto_box_seal_open(
732 &mut [],
733 &short_sealed_box,
734 &recipient_public_key,
735 &recipient_secret_key,
736 ),
737 Err(Error::InvalidLength {
738 context: crate::ErrorContext::Ciphertext,
739 actual,
740 constraint: crate::LengthConstraint::AtLeast(CRYPTO_BOX_SEALBYTES),
741 }) if actual == short_sealed_box.len()
742 ));
743
744 let sealed_box = vec![0u8; CRYPTO_BOX_SEALBYTES + 1];
745 assert!(matches!(
746 crypto_box_seal_open(
747 &mut [],
748 &sealed_box,
749 &recipient_public_key,
750 &recipient_secret_key,
751 ),
752 Err(Error::InvalidLength {
753 context: crate::ErrorContext::Message,
754 actual: 0,
755 constraint: crate::LengthConstraint::Exact(1),
756 })
757 ));
758 }
759
760 #[test]
761 fn test_crypto_box_rejects_low_order_public_keys() {
762 let (_, secret_key) = crypto_box_keypair();
763 let nonce = Nonce::default();
764 let message = b"message";
765 let mut ciphertext = [0u8; 7];
766 let mut mac = Mac::default();
767 let mut one = PublicKey::default();
768 one[0] = 1;
769
770 for public_key in [PublicKey::default(), one] {
771 assert!(crypto_box_beforenm(&public_key, &secret_key).is_err());
772 assert!(
773 crypto_box_detached(
774 &mut ciphertext,
775 &mut mac,
776 message,
777 &nonce,
778 &public_key,
779 &secret_key,
780 )
781 .is_err()
782 );
783
784 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();
785 let original_data = data.clone();
786 assert!(crypto_box_easy_inplace(&mut data, &nonce, &public_key, &secret_key).is_err());
787 assert_eq!(data, original_data);
788 }
789 }
790
791 #[test]
794 fn test_crypto_box_easy_inplace_invalid() {
795 let (sender_pk, sender_sk) = crypto_box_keypair();
796 let (recipient_pk, recipient_sk) = crypto_box_keypair();
797 let (other_pk, _) = crypto_box_keypair();
798 let nonce = Nonce::generate();
799
800 let mut ciphertext: Vec<u8> = vec![];
801 crypto_box_open_easy_inplace(&mut ciphertext, &nonce, &sender_pk, &recipient_sk)
802 .expect_err("expected an error");
803
804 for len in [CRYPTO_BOX_MACBYTES, CRYPTO_BOX_MACBYTES + 1, 1024] {
805 let mut random = vec![0u8; len];
806 copy_randombytes(&mut random);
807 let original = random.clone();
808 crypto_box_open_easy_inplace(&mut random, &nonce, &sender_pk, &recipient_sk)
809 .expect_err("random bytes must not authenticate");
810 assert_eq!(random, original);
811
812 let mut data = original.clone();
813 crypto_box_easy_inplace(&mut data, &nonce, &recipient_pk, &sender_sk)
814 .expect("encrypt failed");
815 let sealed = data.clone();
816 let mut tampered = sealed.clone();
817 tampered[len - 1] ^= 1;
818 crypto_box_open_easy_inplace(&mut tampered, &nonce, &sender_pk, &recipient_sk)
819 .expect_err("tampered body must not authenticate");
820 assert_eq!(tampered[len - 1], sealed[len - 1] ^ 1);
821 assert_eq!(tampered[..len - 1], sealed[..len - 1]);
822
823 let mut wrong_sender = sealed.clone();
824 crypto_box_open_easy_inplace(&mut wrong_sender, &nonce, &other_pk, &recipient_sk)
825 .expect_err("wrong sender must not authenticate");
826 assert_eq!(wrong_sender, sealed);
827
828 let mut wrong_nonce = sealed.clone();
829 let mut other_nonce = nonce;
830 other_nonce[0] ^= 1;
831 crypto_box_open_easy_inplace(&mut wrong_nonce, &other_nonce, &sender_pk, &recipient_sk)
832 .expect_err("wrong nonce must not authenticate");
833 assert_eq!(wrong_nonce, sealed);
834
835 crypto_box_open_easy_inplace(&mut data, &nonce, &sender_pk, &recipient_sk)
836 .expect("decrypt failed");
837 assert_eq!(
838 data[..len - CRYPTO_BOX_MACBYTES],
839 original[..len - CRYPTO_BOX_MACBYTES]
840 );
841 }
842 }
843
844 #[test]
848 fn test_crypto_box_open_detached_failure_atomicity() {
849 let (sender_pk, sender_sk) = crypto_box_seed_keypair(&[0x41; CRYPTO_BOX_SEEDBYTES]);
850 let (recipient_pk, recipient_sk) = crypto_box_seed_keypair(&[0x42; CRYPTO_BOX_SEEDBYTES]);
851 let nonce = [0x43; CRYPTO_BOX_NONCEBYTES];
852 let message = [0x44; 70];
853 let mut ciphertext = [0u8; 70];
854 let mut mac = Mac::default();
855 crypto_box_detached(
856 &mut ciphertext,
857 &mut mac,
858 &message,
859 &nonce,
860 &recipient_pk,
861 &sender_sk,
862 )
863 .unwrap();
864 let key = crypto_box_beforenm(&sender_pk, &recipient_sk).unwrap();
865 let mut bad_mac = mac;
866 bad_mac[0] ^= 1;
867 let mut low_order = PublicKey::default();
868 low_order[0] = 1;
869
870 let sentinel = [0xa5; 70];
871 let mut output = sentinel;
872 assert!(matches!(
873 crypto_box_open_detached(
874 &mut output,
875 &ciphertext,
876 &bad_mac,
877 &nonce,
878 &sender_pk,
879 &recipient_sk
880 ),
881 Err(Error::AuthenticationFailed)
882 ));
883 assert_eq!(output, sentinel);
884 assert!(matches!(
885 crypto_box_open_detached_afternm(&mut output, &ciphertext, &bad_mac, &nonce, &key),
886 Err(Error::AuthenticationFailed)
887 ));
888 assert_eq!(output, sentinel);
889 assert!(matches!(
890 crypto_box_open_detached(
891 &mut output,
892 &ciphertext,
893 &mac,
894 &nonce,
895 &low_order,
896 &recipient_sk
897 ),
898 Err(Error::InvalidKey { .. })
899 ));
900 assert_eq!(output, sentinel);
901 let mut short_output = [0xa5; 69];
902 assert!(matches!(
903 crypto_box_open_detached(
904 &mut short_output,
905 &ciphertext,
906 &mac,
907 &nonce,
908 &sender_pk,
909 &recipient_sk
910 ),
911 Err(Error::InvalidLength { .. })
912 ));
913 assert_eq!(short_output, [0xa5; 69]);
914
915 let mut data = ciphertext;
916 assert!(
917 crypto_box_open_detached_inplace(
918 &mut data,
919 &bad_mac,
920 &nonce,
921 &sender_pk,
922 &recipient_sk
923 )
924 .is_err()
925 );
926 assert_eq!(data, ciphertext);
927 assert!(
928 crypto_box_open_detached_afternm_inplace(&mut data, &bad_mac, &nonce, &key).is_err()
929 );
930 assert_eq!(data, ciphertext);
931 assert!(
932 crypto_box_open_detached_inplace(&mut data, &mac, &nonce, &low_order, &recipient_sk)
933 .is_err()
934 );
935 assert_eq!(data, ciphertext);
936
937 crypto_box_open_detached(
938 &mut output,
939 &ciphertext,
940 &mac,
941 &nonce,
942 &sender_pk,
943 &recipient_sk,
944 )
945 .unwrap();
946 assert_eq!(output, message);
947 crypto_box_open_detached_inplace(&mut data, &mac, &nonce, &sender_pk, &recipient_sk)
948 .unwrap();
949 assert_eq!(data, message);
950 }
951
952 #[cfg(dryoc_native_tests)]
953 mod native_tests {
954 use super::*;
955
956 #[test]
959 fn test_crypto_box_beforenm_low_order_compatibility() {
960 let (_, secret_key) = crypto_box_seed_keypair(&[0x54; CRYPTO_BOX_SEEDBYTES]);
961
962 for public_key in crate::scalarmult_curve25519::test_vectors::low_order_u_encodings() {
963 assert!(
964 crypto_box_beforenm(&public_key, &secret_key).is_err(),
965 "{public_key:02x?}"
966 );
967 assert!(
968 crate::native_test_util::box_beforenm(&public_key, &secret_key).is_err(),
969 "{public_key:02x?}"
970 );
971 }
972 }
973
974 #[test]
979 fn test_crypto_box_detached_matches_libsodium() {
980 crate::native_test_util::init();
981 let (sender_pk, sender_sk) = crypto_box_seed_keypair(&[0x51; CRYPTO_BOX_SEEDBYTES]);
982 let (recipient_pk, recipient_sk) =
983 crypto_box_seed_keypair(&[0x52; CRYPTO_BOX_SEEDBYTES]);
984 let nonce = [0x53; CRYPTO_BOX_NONCEBYTES];
985
986 let sender_key = crypto_box_beforenm(&recipient_pk, &sender_sk).unwrap();
987 let recipient_key = crypto_box_beforenm(&sender_pk, &recipient_sk).unwrap();
988 assert_eq!(sender_key, recipient_key);
989 let sodium_key = crate::native_test_util::box_beforenm(&recipient_pk, &sender_sk)
990 .expect("libsodium beforenm");
991 assert_eq!(sender_key, sodium_key);
992
993 let mut rng = crate::utils::test_util::XorShift64::new(0x243f_6a88_85a3_08d3);
994 let mut all = Vec::with_capacity(96);
995 while all.len() < 65 {
996 all.extend_from_slice(&rng.next_bytes32());
997 }
998
999 for len in [0usize, 1, 31, 32, 33, 63, 64, 65] {
1000 let message = &all[..len];
1001
1002 let mut ciphertext = vec![0u8; len];
1003 let mut mac = Mac::default();
1004 crypto_box_detached(
1005 &mut ciphertext,
1006 &mut mac,
1007 message,
1008 &nonce,
1009 &recipient_pk,
1010 &sender_sk,
1011 )
1012 .unwrap();
1013
1014 let mut sodium_ciphertext = vec![0u8; len];
1015 let mut sodium_mac = Mac::default();
1016 let result = unsafe {
1017 libsodium_sys::crypto_box_detached(
1018 sodium_ciphertext.as_mut_ptr(),
1019 sodium_mac.as_mut_ptr(),
1020 message.as_ptr(),
1021 len as u64,
1022 nonce.as_ptr(),
1023 recipient_pk.as_ptr(),
1024 sender_sk.as_ptr(),
1025 )
1026 };
1027 assert_eq!(result, 0);
1028 assert_eq!(ciphertext, sodium_ciphertext, "len {len}");
1029 assert_eq!(mac, sodium_mac, "len {len}");
1030
1031 let mut afternm_ciphertext = vec![0u8; len];
1032 let mut afternm_mac = Mac::default();
1033 crypto_box_detached_afternm(
1034 &mut afternm_ciphertext,
1035 &mut afternm_mac,
1036 message,
1037 &nonce,
1038 &sender_key,
1039 )
1040 .unwrap();
1041 assert_eq!(afternm_ciphertext, ciphertext, "afternm len {len}");
1042 assert_eq!(afternm_mac, mac, "afternm len {len}");
1043 let result = unsafe {
1044 libsodium_sys::crypto_box_detached_afternm(
1045 sodium_ciphertext.as_mut_ptr(),
1046 sodium_mac.as_mut_ptr(),
1047 message.as_ptr(),
1048 len as u64,
1049 nonce.as_ptr(),
1050 sodium_key.as_ptr(),
1051 )
1052 };
1053 assert_eq!(result, 0);
1054 assert_eq!(ciphertext, sodium_ciphertext, "sodium afternm len {len}");
1055 assert_eq!(mac, sodium_mac, "sodium afternm len {len}");
1056
1057 let mut data = message.to_vec();
1058 let mut inplace_mac = Mac::default();
1059 crypto_box_detached_inplace(
1060 &mut data,
1061 &mut inplace_mac,
1062 &nonce,
1063 &recipient_pk,
1064 &sender_sk,
1065 )
1066 .unwrap();
1067 assert_eq!(data, ciphertext, "inplace len {len}");
1068 assert_eq!(inplace_mac, mac, "inplace len {len}");
1069 let mut data = message.to_vec();
1070 let mut inplace_mac = Mac::default();
1071 crypto_box_detached_afternm_inplace(
1072 &mut data,
1073 &mut inplace_mac,
1074 &nonce,
1075 &sender_key,
1076 );
1077 assert_eq!(data, ciphertext, "afternm inplace len {len}");
1078 assert_eq!(inplace_mac, mac, "afternm inplace len {len}");
1079
1080 let mut opened = vec![0xa5; len];
1082 crypto_box_open_detached(
1083 &mut opened,
1084 &sodium_ciphertext,
1085 &sodium_mac,
1086 &nonce,
1087 &sender_pk,
1088 &recipient_sk,
1089 )
1090 .unwrap();
1091 assert_eq!(opened, message, "open len {len}");
1092 opened.fill(0xa5);
1093 crypto_box_open_detached_afternm(
1094 &mut opened,
1095 &sodium_ciphertext,
1096 &sodium_mac,
1097 &nonce,
1098 &recipient_key,
1099 )
1100 .unwrap();
1101 assert_eq!(opened, message, "open afternm len {len}");
1102 let mut data = sodium_ciphertext.clone();
1103 crypto_box_open_detached_inplace(
1104 &mut data,
1105 &sodium_mac,
1106 &nonce,
1107 &sender_pk,
1108 &recipient_sk,
1109 )
1110 .unwrap();
1111 assert_eq!(data, message, "open inplace len {len}");
1112 let mut data = sodium_ciphertext.clone();
1113 crypto_box_open_detached_afternm_inplace(
1114 &mut data,
1115 &sodium_mac,
1116 &nonce,
1117 &recipient_key,
1118 )
1119 .unwrap();
1120 assert_eq!(data, message, "open afternm inplace len {len}");
1121
1122 let mut sodium_opened = vec![0xa5; len];
1124 let result = unsafe {
1125 libsodium_sys::crypto_box_open_detached(
1126 sodium_opened.as_mut_ptr(),
1127 ciphertext.as_ptr(),
1128 mac.as_ptr(),
1129 len as u64,
1130 nonce.as_ptr(),
1131 sender_pk.as_ptr(),
1132 recipient_sk.as_ptr(),
1133 )
1134 };
1135 assert_eq!(result, 0, "sodium open len {len}");
1136 assert_eq!(sodium_opened, message, "sodium open len {len}");
1137 sodium_opened.fill(0xa5);
1138 let result = unsafe {
1139 libsodium_sys::crypto_box_open_detached_afternm(
1140 sodium_opened.as_mut_ptr(),
1141 ciphertext.as_ptr(),
1142 mac.as_ptr(),
1143 len as u64,
1144 nonce.as_ptr(),
1145 sodium_key.as_ptr(),
1146 )
1147 };
1148 assert_eq!(result, 0, "sodium open afternm len {len}");
1149 assert_eq!(sodium_opened, message, "sodium open afternm len {len}");
1150 }
1151 }
1152
1153 #[test]
1154 fn test_crypto_box_easy() {
1155 for i in 0..20 {
1156 use base64::Engine as _;
1157 use base64::engine::general_purpose;
1158
1159 use crate::native_test_util::{box_easy, box_open_easy};
1160
1161 let (sender_pk, sender_sk) = crypto_box_keypair();
1162 let (recipient_pk, recipient_sk) = crypto_box_keypair();
1163 let nonce = Nonce::generate();
1164 let words = vec!["hello1".to_string(); i];
1165 let message = words.join(" :D ");
1166 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_MACBYTES];
1167 crypto_box_easy(
1168 &mut ciphertext,
1169 message.as_bytes(),
1170 &nonce,
1171 &recipient_pk,
1172 &sender_sk,
1173 )
1174 .expect("encrypt failed");
1175
1176 let so_ciphertext = box_easy(message.as_bytes(), &nonce, &recipient_pk, &sender_sk);
1177
1178 assert_eq!(
1179 general_purpose::STANDARD_NO_PAD.encode(&ciphertext),
1180 general_purpose::STANDARD_NO_PAD.encode(&so_ciphertext)
1181 );
1182
1183 let mut m = vec![0u8; ciphertext.len() - CRYPTO_BOX_MACBYTES];
1184 crypto_box_open_easy(
1185 &mut m,
1186 ciphertext.as_slice(),
1187 &nonce,
1188 &sender_pk,
1189 &recipient_sk,
1190 )
1191 .expect("decrypt failed");
1192 let so_m = box_open_easy(ciphertext.as_slice(), &nonce, &recipient_pk, &sender_sk)
1193 .unwrap();
1194
1195 assert_eq!(m, message.as_bytes());
1196 assert_eq!(m, so_m);
1197 }
1198 }
1199
1200 #[test]
1201 fn test_crypto_box_easy_inplace() {
1202 for i in 0..20 {
1203 use base64::Engine as _;
1204 use base64::engine::general_purpose;
1205
1206 use crate::native_test_util::{box_easy, box_open_easy};
1207
1208 let (sender_pk, sender_sk) = crypto_box_keypair();
1209 let (recipient_pk, recipient_sk) = crypto_box_keypair();
1210 let nonce = Nonce::generate();
1211 let words = vec!["hello1".to_string(); i];
1212 let message: Vec<u8> = words.join(" :D ").as_bytes().to_vec();
1213 let message_copy = message.clone();
1214
1215 let mut ciphertext = message.clone();
1216 ciphertext.resize(message.len() + CRYPTO_BOX_MACBYTES, 0);
1217 crypto_box_easy_inplace(&mut ciphertext, &nonce, &recipient_pk, &sender_sk)
1218 .expect("encrypt failed");
1219 let so_ciphertext =
1220 box_easy(message_copy.as_slice(), &nonce, &recipient_pk, &sender_sk);
1221
1222 assert_eq!(
1223 general_purpose::STANDARD_NO_PAD.encode(&ciphertext),
1224 general_purpose::STANDARD_NO_PAD.encode(&so_ciphertext)
1225 );
1226
1227 let mut ciphertext_clone = ciphertext.clone();
1228 crypto_box_open_easy_inplace(
1229 &mut ciphertext_clone,
1230 &nonce,
1231 &sender_pk,
1232 &recipient_sk,
1233 )
1234 .expect("decrypt failed");
1235 ciphertext_clone.resize(message.len(), 0);
1236
1237 let so_m = box_open_easy(ciphertext.as_slice(), &nonce, &recipient_pk, &sender_sk)
1238 .expect("decrypt failed");
1239
1240 assert_eq!(
1241 general_purpose::STANDARD_NO_PAD.encode(&ciphertext_clone),
1242 general_purpose::STANDARD_NO_PAD.encode(&message_copy)
1243 );
1244 assert_eq!(
1245 general_purpose::STANDARD_NO_PAD.encode(&so_m),
1246 general_purpose::STANDARD_NO_PAD.encode(&message_copy)
1247 );
1248 }
1249 }
1250
1251 #[test]
1252 #[cfg(feature = "alloc")]
1253 fn test_crypto_box_seed_keypair() {
1254 use base64::Engine as _;
1255 use base64::engine::general_purpose;
1256
1257 use crate::native_test_util::box_seed_keypair;
1258
1259 for _ in 0..10 {
1260 let seed: [u8; CRYPTO_BOX_SEEDBYTES] = randombytes_buf(CRYPTO_BOX_SEEDBYTES)
1261 .try_into()
1262 .expect("seed length");
1263
1264 let (pk, sk) = crypto_box_seed_keypair(&seed);
1265 let (so_pk, so_sk) = box_seed_keypair(&seed);
1266
1267 assert_eq!(
1268 general_purpose::STANDARD_NO_PAD.encode(pk),
1269 general_purpose::STANDARD_NO_PAD.encode(so_pk)
1270 );
1271 assert_eq!(
1272 general_purpose::STANDARD_NO_PAD.encode(sk),
1273 general_purpose::STANDARD_NO_PAD.encode(so_sk)
1274 );
1275 }
1276 }
1277
1278 #[test]
1279 fn test_crypto_box_seal() {
1280 for i in 0..20 {
1281 use crate::native_test_util::box_seal_open;
1282
1283 let (recipient_pk, recipient_sk) = crypto_box_keypair();
1284 let words = vec!["hello1".to_string(); i];
1285 let message = words.join(" :D ");
1286 let mut ciphertext = vec![0u8; message.len() + CRYPTO_BOX_SEALBYTES];
1287 crypto_box_seal(&mut ciphertext, message.as_bytes(), &recipient_pk)
1288 .expect("encrypt failed");
1289
1290 let mut m = vec![0u8; ciphertext.len() - CRYPTO_BOX_SEALBYTES];
1291 crypto_box_seal_open(&mut m, ciphertext.as_slice(), &recipient_pk, &recipient_sk)
1292 .expect("decrypt failed");
1293 let so_m =
1294 box_seal_open(ciphertext.as_slice(), &recipient_pk, &recipient_sk).unwrap();
1295
1296 assert_eq!(m, message.as_bytes());
1297 assert_eq!(m, so_m);
1298 }
1299 }
1300
1301 #[test]
1302 fn test_crypto_box_seal_open() {
1303 for i in 0..20 {
1304 use crate::native_test_util::{box_seal, box_seal_open};
1305
1306 let (recipient_pk, recipient_sk) = crypto_box_keypair();
1307 let words = vec!["hello1".to_string(); i];
1308 let message = words.join(" :D ");
1309 let so_ciphertext = box_seal(message.as_bytes(), &recipient_pk);
1310
1311 let mut m = vec![0u8; so_ciphertext.len() - CRYPTO_BOX_SEALBYTES];
1312 crypto_box_seal_open(
1313 &mut m,
1314 so_ciphertext.as_slice(),
1315 &recipient_pk,
1316 &recipient_sk,
1317 )
1318 .expect("decrypt failed");
1319 let so_m =
1320 box_seal_open(so_ciphertext.as_slice(), &recipient_pk, &recipient_sk).unwrap();
1321
1322 assert_eq!(m, message.as_bytes());
1323 assert_eq!(m, so_m);
1324 }
1325 }
1326 }
1327}