1#[cfg(feature = "alloc")]
110use alloc::vec::Vec;
111
112#[cfg(feature = "serde")]
113use serde::{Deserialize, Serialize};
114use zeroize::{Zeroize, Zeroizing};
115
116use crate::constants::{
117 CRYPTO_BOX_BEFORENMBYTES, CRYPTO_BOX_MACBYTES, CRYPTO_BOX_NONCEBYTES,
118 CRYPTO_BOX_PUBLICKEYBYTES, CRYPTO_BOX_SEALBYTES, CRYPTO_BOX_SECRETKEYBYTES,
119};
120use crate::error::*;
121use crate::types::*;
122use crate::utils::{ct_eq_bytes, split_prefix};
123
124pub type PublicKey = StackByteArray<CRYPTO_BOX_PUBLICKEYBYTES>;
126pub type SecretKey = StackByteArray<CRYPTO_BOX_SECRETKEYBYTES>;
128pub type Nonce = StackByteArray<CRYPTO_BOX_NONCEBYTES>;
130pub type Mac = StackByteArray<CRYPTO_BOX_MACBYTES>;
133pub type StackKeyPair = crate::keypair::KeyPair<PublicKey, SecretKey>;
136
137#[cfg(any(
138 all(feature = "protected", any(unix, windows)),
139 all(doc, not(doctest), feature = "std")
140))]
141#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "protected")))]
142pub mod protected {
143 use super::*;
186 pub use crate::protected::*;
187
188 pub type PublicKey = HeapByteArray<CRYPTO_BOX_PUBLICKEYBYTES>;
191 pub type SecretKey = HeapByteArray<CRYPTO_BOX_SECRETKEYBYTES>;
194 pub type Nonce = HeapByteArray<CRYPTO_BOX_NONCEBYTES>;
197 pub type Mac = HeapByteArray<CRYPTO_BOX_MACBYTES>;
200
201 pub type LockedKeyPair = crate::keypair::KeyPair<Locked<PublicKey>, Locked<SecretKey>>;
204 pub type LockedROKeyPair = crate::keypair::KeyPair<LockedRO<PublicKey>, LockedRO<SecretKey>>;
207 pub type LockedBox = DryocBox<Locked<PublicKey>, Locked<Mac>, LockedBytes>;
209}
210
211#[derive(Zeroize, Clone, Debug)]
212#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
213pub struct DryocBox<
217 EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
218 Mac: ByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
219 Data: Bytes + Zeroize,
220> {
221 ephemeral_pk: Option<EphemeralPublicKey>,
222 tag: Mac,
223 data: Data,
224}
225
226#[cfg(feature = "alloc")]
228pub type VecBox = DryocBox<PublicKey, Mac, Vec<u8>>;
229
230#[cfg(feature = "wincode_0_6")]
231impl_wincode_schema!(VecBox {
232 ephemeral_pk: Option<[u8; CRYPTO_BOX_PUBLICKEYBYTES]> = (
233 src => &src.ephemeral_pk.as_ref().map(|epk| *epk.as_array()),
234 epk => epk.map(Into::into)
235 ),
236 tag: [u8; CRYPTO_BOX_MACBYTES] = (src => src.tag.as_array(), tag => tag.into()),
237 data: Vec<u8> = (src => &src.data, data => data),
238});
239
240impl<
241 EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
242 Mac: NewByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
243 Data: NewBytes + ResizableBytes + Zeroize,
244> DryocBox<EphemeralPublicKey, Mac, Data>
245{
246 pub fn encrypt<
255 Message: Bytes + ?Sized,
256 Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
257 RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES>,
258 SenderSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES>,
259 >(
260 message: &Message,
261 nonce: &Nonce,
262 recipient_public_key: &RecipientPublicKey,
263 sender_secret_key: &SenderSecretKey,
264 ) -> Result<Self, Error> {
265 use crate::classic::crypto_box::crypto_box_detached;
266
267 let mut dryocbox = Self {
268 ephemeral_pk: None,
269 tag: Mac::new_byte_array(),
270 data: Data::new_bytes(),
271 };
272
273 dryocbox.data.resize(message.as_slice().len(), 0);
274
275 crypto_box_detached(
276 dryocbox.data.as_mut_slice(),
277 dryocbox.tag.as_mut_array(),
278 message.as_slice(),
279 nonce.as_array(),
280 recipient_public_key.as_array(),
281 sender_secret_key.as_array(),
282 )?;
283
284 Ok(dryocbox)
285 }
286
287 pub fn precalc_encrypt<
295 Message: Bytes + ?Sized,
296 Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
297 PrecalcSecretKey: ByteArray<CRYPTO_BOX_BEFORENMBYTES> + Zeroize,
298 >(
299 message: &Message,
300 nonce: &Nonce,
301 precalc_secret_key: &PrecalcSecretKey,
302 ) -> Result<Self, Error> {
303 use crate::classic::crypto_box::crypto_box_detached_afternm;
304
305 let mut dryocbox = Self {
306 ephemeral_pk: None,
307 tag: Mac::new_byte_array(),
308 data: Data::new_bytes(),
309 };
310
311 dryocbox.data.resize(message.as_slice().len(), 0);
312
313 crypto_box_detached_afternm(
314 dryocbox.data.as_mut_slice(),
315 dryocbox.tag.as_mut_array(),
316 message.as_slice(),
317 nonce.as_array(),
318 precalc_secret_key.as_array(),
319 )?;
320
321 Ok(dryocbox)
322 }
323}
324
325impl<
326 EphemeralPublicKey: NewByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
327 Mac: NewByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
328 Data: NewBytes + ResizableBytes + Zeroize,
329> DryocBox<EphemeralPublicKey, Mac, Data>
330{
331 pub fn seal<
346 Message: Bytes + ?Sized,
347 RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES>,
348 >(
349 message: &Message,
350 recipient_public_key: &RecipientPublicKey,
351 ) -> Result<Self, Error> {
352 use crate::classic::crypto_box::{
353 crypto_box_detached, crypto_box_keypair, crypto_box_seal_nonce,
354 };
355
356 let mut nonce = Nonce::new_byte_array();
357 let (epk, esk) = crypto_box_keypair();
358 let esk = Zeroizing::new(esk);
359 crypto_box_seal_nonce(nonce.as_mut_array(), &epk, recipient_public_key.as_array());
360
361 let mut pk = EphemeralPublicKey::new_byte_array();
362 pk.copy_from_slice(&epk);
363
364 let mut dryocbox = Self {
365 ephemeral_pk: Some(pk),
366 tag: Mac::new_byte_array(),
367 data: Data::new_bytes(),
368 };
369
370 dryocbox.data.resize(message.as_slice().len(), 0);
371
372 crypto_box_detached(
373 dryocbox.data.as_mut_slice(),
374 dryocbox.tag.as_mut_array(),
375 message.as_slice(),
376 nonce.as_array(),
377 recipient_public_key.as_array(),
378 &esk,
379 )?;
380
381 Ok(dryocbox)
382 }
383}
384
385impl<
386 'a,
387 EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + core::convert::TryFrom<&'a [u8]> + Zeroize,
388 Mac: ByteArray<CRYPTO_BOX_MACBYTES> + core::convert::TryFrom<&'a [u8]> + Zeroize,
389 Data: Bytes + From<&'a [u8]> + Zeroize,
390> DryocBox<EphemeralPublicKey, Mac, Data>
391{
392 pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, Error> {
401 let (tag, data) = split_prefix(bytes, CRYPTO_BOX_MACBYTES, ErrorContext::Box)?;
402 Ok(Self {
403 ephemeral_pk: None,
404 tag: Mac::try_from(tag)
405 .map_err(|_| Error::invalid_encoding(ErrorContext::AuthenticationTag))?,
406 data: Data::from(data),
407 })
408 }
409
410 pub fn from_sealed_bytes(bytes: &'a [u8]) -> Result<Self, Error> {
421 validate_length!(min CRYPTO_BOX_SEALBYTES, bytes.len(), crate::ErrorContext::SealedBox);
422
423 let (seal, data) = bytes.split_at(CRYPTO_BOX_SEALBYTES);
424 let (epk, tag) = seal.split_at(CRYPTO_BOX_PUBLICKEYBYTES);
425 Ok(Self {
426 ephemeral_pk: Some(
427 EphemeralPublicKey::try_from(epk)
428 .map_err(|_| Error::invalid_key(crate::ErrorContext::EphemeralPublicKey))?,
429 ),
430 tag: Mac::try_from(tag)
431 .map_err(|_| Error::invalid_encoding(crate::ErrorContext::AuthenticationTag))?,
432 data: Data::from(data),
433 })
434 }
435}
436
437impl<
438 EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
439 Mac: ByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
440 Data: Bytes + Zeroize,
441> DryocBox<EphemeralPublicKey, Mac, Data>
442{
443 #[must_use]
447 pub fn from_parts(ephemeral_pk: Option<EphemeralPublicKey>, tag: Mac, data: Data) -> Self {
448 Self {
449 ephemeral_pk,
450 tag,
451 data,
452 }
453 }
454
455 pub fn ephemeral_pk(&self) -> Option<&EphemeralPublicKey> {
458 self.ephemeral_pk.as_ref()
459 }
460
461 pub fn tag(&self) -> &Mac {
463 &self.tag
464 }
465
466 pub fn data(&self) -> &Data {
468 &self.data
469 }
470
471 #[cfg(feature = "alloc")]
473 #[must_use]
474 pub fn to_vec(&self) -> Vec<u8> {
475 self.to_bytes()
476 }
477
478 #[must_use]
481 pub fn into_parts(self) -> (Option<EphemeralPublicKey>, Mac, Data) {
482 (self.ephemeral_pk, self.tag, self.data)
483 }
484
485 pub fn decrypt<
495 Output: ResizableBytes + NewBytes,
496 Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
497 SenderPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES>,
498 RecipientSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES>,
499 >(
500 &self,
501 nonce: &Nonce,
502 sender_public_key: &SenderPublicKey,
503 recipient_secret_key: &RecipientSecretKey,
504 ) -> Result<Output, Error> {
505 use crate::classic::crypto_box::*;
506
507 let mut message = Output::new_bytes();
508 message.resize(self.data.as_slice().len(), 0);
509
510 crypto_box_open_detached(
511 message.as_mut_slice(),
512 self.data.as_slice(),
513 self.tag.as_array(),
514 nonce.as_array(),
515 sender_public_key.as_array(),
516 recipient_secret_key.as_array(),
517 )?;
518
519 Ok(message)
520 }
521
522 pub fn precalc_decrypt<
531 Output: ResizableBytes + NewBytes,
532 Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
533 PrecalcSecretKey: ByteArray<CRYPTO_BOX_BEFORENMBYTES> + Zeroize,
534 >(
535 &self,
536 nonce: &Nonce,
537 precalc_secret_key: &PrecalcSecretKey,
538 ) -> Result<Output, Error> {
539 use crate::classic::crypto_box::crypto_box_open_detached_afternm;
540
541 let mut message = Output::new_bytes();
542 message.resize(self.data.as_slice().len(), 0);
543
544 crypto_box_open_detached_afternm(
545 message.as_mut_slice(),
546 self.data.as_slice(),
547 self.tag.as_array(),
548 nonce.as_array(),
549 precalc_secret_key.as_array(),
550 )?;
551
552 Ok(message)
553 }
554
555 pub fn open<
565 Output: ResizableBytes + NewBytes + Zeroize,
566 RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
567 RecipientSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES> + Zeroize,
568 >(
569 &self,
570 recipient_keypair: &crate::keypair::KeyPair<RecipientPublicKey, RecipientSecretKey>,
571 ) -> Result<Output, Error> {
572 use crate::classic::crypto_box::*;
573
574 match &self.ephemeral_pk {
575 Some(epk) => {
576 let mut nonce = Nonce::new_byte_array();
577 crypto_box_seal_nonce(
578 nonce.as_mut_array(),
579 epk.as_array(),
580 recipient_keypair.public_key.as_array(),
581 );
582
583 let mut message = Output::new_bytes();
584 message.resize(self.data.as_slice().len(), 0);
585
586 crypto_box_open_detached(
587 message.as_mut_slice(),
588 self.data.as_slice(),
589 self.tag.as_array(),
590 nonce.as_array(),
591 epk.as_array(),
592 recipient_keypair.secret_key.as_array(),
593 )?;
594
595 Ok(message)
596 }
597 None => Err(Error::missing_data(crate::ErrorContext::EphemeralPublicKey)),
598 }
599 }
600
601 #[must_use]
603 pub fn to_bytes<Bytes: NewBytes + ResizableBytes>(&self) -> Bytes {
604 match &self.ephemeral_pk {
605 Some(epk) => {
606 let mut data = Bytes::new_bytes();
607 data.resize(CRYPTO_BOX_SEALBYTES + self.data.len(), 0);
608 let s = data.as_mut_slice();
609 s[..CRYPTO_BOX_PUBLICKEYBYTES].copy_from_slice(epk.as_array());
610 s[CRYPTO_BOX_PUBLICKEYBYTES..CRYPTO_BOX_SEALBYTES]
611 .copy_from_slice(self.tag.as_array());
612 s[CRYPTO_BOX_SEALBYTES..].copy_from_slice(self.data.as_slice());
613 data
614 }
615 None => concat_bytes(self.tag.as_array(), self.data.as_slice()),
616 }
617 }
618}
619
620#[cfg(feature = "alloc")]
621impl DryocBox<PublicKey, Mac, Vec<u8>> {
622 pub fn encrypt_to_vecbox<
630 Message: Bytes + ?Sized,
631 Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
632 RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES>,
633 SenderSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES>,
634 >(
635 message: &Message,
636 nonce: &Nonce,
637 recipient_public_key: &RecipientPublicKey,
638 sender_secret_key: &SenderSecretKey,
639 ) -> Result<Self, Error> {
640 Self::encrypt(message, nonce, recipient_public_key, sender_secret_key)
641 }
642
643 pub fn precalc_encrypt_to_vecbox<
651 Message: Bytes + ?Sized,
652 Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
653 PrecalcSecretKey: ByteArray<CRYPTO_BOX_BEFORENMBYTES> + Zeroize,
654 >(
655 message: &Message,
656 nonce: &Nonce,
657 precalc_secret_key: &PrecalcSecretKey,
658 ) -> Result<Self, Error> {
659 Self::precalc_encrypt(message, nonce, precalc_secret_key)
660 }
661
662 pub fn seal_to_vecbox<
676 Message: Bytes + ?Sized,
677 RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES>,
678 >(
679 message: &Message,
680 recipient_public_key: &RecipientPublicKey,
681 ) -> Result<Self, Error> {
682 Self::seal(message, recipient_public_key)
683 }
684
685 pub fn decrypt_to_vec<
694 Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
695 SenderPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES>,
696 RecipientSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES>,
697 >(
698 &self,
699 nonce: &Nonce,
700 sender_public_key: &SenderPublicKey,
701 recipient_secret_key: &RecipientSecretKey,
702 ) -> Result<Vec<u8>, Error> {
703 self.decrypt(nonce, sender_public_key, recipient_secret_key)
704 }
705
706 pub fn precalc_decrypt_to_vec<
715 Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
716 PrecalcSecretKey: ByteArray<CRYPTO_BOX_BEFORENMBYTES> + Zeroize,
717 >(
718 &self,
719 nonce: &Nonce,
720 precalc_secret_key: &PrecalcSecretKey,
721 ) -> Result<Vec<u8>, Error> {
722 self.precalc_decrypt(nonce, precalc_secret_key)
723 }
724
725 pub fn open_to_vec<
734 RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
735 RecipientSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES> + Zeroize,
736 >(
737 &self,
738 recipient_keypair: &crate::keypair::KeyPair<RecipientPublicKey, RecipientSecretKey>,
739 ) -> Result<Vec<u8>, Error> {
740 self.open(recipient_keypair)
741 }
742}
743
744impl<
745 EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
746 Mac: ByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
747 Data: Bytes + Zeroize,
748> PartialEq<DryocBox<EphemeralPublicKey, Mac, Data>> for DryocBox<EphemeralPublicKey, Mac, Data>
749{
750 fn eq(&self, other: &Self) -> bool {
751 if let Some(our_epk) = &self.ephemeral_pk {
752 if let Some(their_epk) = &other.ephemeral_pk {
753 ct_eq_bytes(self.tag.as_slice(), other.tag.as_slice())
754 && ct_eq_bytes(self.data.as_slice(), other.data.as_slice())
755 && ct_eq_bytes(our_epk.as_slice(), their_epk.as_slice())
756 } else {
757 false
758 }
759 } else if other.ephemeral_pk.is_none() {
760 ct_eq_bytes(self.tag.as_slice(), other.tag.as_slice())
761 && ct_eq_bytes(self.data.as_slice(), other.data.as_slice())
762 } else {
763 false
764 }
765 }
766}
767
768#[cfg(all(test, feature = "alloc"))]
769mod tests {
770 use super::*;
771 use crate::constants::CRYPTO_BOX_SEEDBYTES;
772 use crate::precalc::PrecalcSecretKey;
773 use crate::test_prelude::*;
774
775 #[test]
776 fn open_requires_an_ephemeral_public_key() {
777 let box_without_ephemeral_key =
778 VecBox::from_bytes(&[0u8; CRYPTO_BOX_MACBYTES]).expect("a regular box should parse");
779 let recipient_keypair = StackKeyPair::generate();
780
781 let error = box_without_ephemeral_key
782 .open::<Vec<u8>, _, _>(&recipient_keypair)
783 .expect_err("a regular box cannot be opened as a sealed box");
784 assert!(matches!(
785 error,
786 Error::MissingData {
787 context: crate::ErrorContext::EphemeralPublicKey,
788 }
789 ));
790 }
791
792 const ALICE_SK: &str = "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a";
797 const ALICE_PK: &str = "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a";
798 const BOB_SK: &str = "5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb";
799 const BOB_PK: &str = "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f";
800 const SHARED_KEY: &str = "1b27556473e985d462cd51197a9a46c76009549eac6474f206c4ee0844f68389";
801 const NONCE: &str = "69696ee955b62b73cd62bda875fc73d68219e0036b7a0b37";
802 const MESSAGE: &str = concat!(
803 "be075fc53c81f2d5cf141316ebeb0c7b5228c52a4c62cbd44b66849b64244ffce5ecbaaf33bd751a1ac728d4",
804 "5e6c61296cdc3c01233561f41db66cce314adb310e3be8250c46f06dceea3a7fa1348057e2f6556ad6b1318a",
805 "024a838f21af1fde048977eb48f59ffd4924ca1c60902e52f0a089bc76897040e082f937763848645e0705",
806 );
807 const BOXED: &str = concat!(
808 "f3ffc7703f9400e52a7dfb4b3d3305d98e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c5",
809 "31a1186ac0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738b48eeee314a7cc8a",
810 "b932164548e526ae90224368517acfeabd6bb3732bc0e9da99832b61ca01b6de56244a9e88d5f9b37973f622",
811 "a43d14a6599b1f654cb45a74e355a5",
812 );
813
814 fn array<const N: usize>(hex: &str) -> StackByteArray<N> {
815 StackByteArray::try_from(hex::decode(hex).expect("hex").as_slice()).expect("length")
816 }
817
818 struct NaclVector {
819 alice: StackKeyPair,
820 bob: StackKeyPair,
821 nonce: Nonce,
822 message: Vec<u8>,
823 boxed: Vec<u8>,
824 }
825
826 fn nacl_vector() -> NaclVector {
827 NaclVector {
828 alice: StackKeyPair::from_slices(
829 &hex::decode(ALICE_PK).expect("hex"),
830 &hex::decode(ALICE_SK).expect("hex"),
831 )
832 .expect("alice keypair"),
833 bob: StackKeyPair::from_slices(
834 &hex::decode(BOB_PK).expect("hex"),
835 &hex::decode(BOB_SK).expect("hex"),
836 )
837 .expect("bob keypair"),
838 nonce: array(NONCE),
839 message: hex::decode(MESSAGE).expect("hex"),
840 boxed: hex::decode(BOXED).expect("hex"),
841 }
842 }
843
844 #[test]
845 fn nacl_vector_encrypts_to_known_bytes_and_decrypts_with_swapped_keys() {
846 let v = nacl_vector();
847 assert_eq!(
848 StackKeyPair::from_secret_key(v.alice.secret_key.clone()).public_key,
849 v.alice.public_key
850 );
851 assert_eq!(
852 StackKeyPair::from_secret_key(v.bob.secret_key.clone()).public_key,
853 v.bob.public_key
854 );
855
856 let dryocbox = DryocBox::encrypt_to_vecbox(
857 &v.message,
858 &v.nonce,
859 &v.bob.public_key,
860 &v.alice.secret_key,
861 )
862 .expect("encrypt failed");
863 assert_eq!(dryocbox.to_vec(), v.boxed);
864 assert_eq!(dryocbox.tag.as_slice(), &v.boxed[..CRYPTO_BOX_MACBYTES]);
865 assert_eq!(dryocbox.data, v.boxed[CRYPTO_BOX_MACBYTES..]);
866 assert!(dryocbox.ephemeral_pk.is_none());
867
868 let parsed = VecBox::from_bytes(&v.boxed).expect("known-good box should parse");
869 assert_eq!(parsed, dryocbox);
870 assert_eq!(
871 parsed
872 .decrypt_to_vec(&v.nonce, &v.alice.public_key, &v.bob.secret_key)
873 .expect("decrypt failed"),
874 v.message
875 );
876
877 let reverse = DryocBox::encrypt_to_vecbox(
881 &v.message,
882 &v.nonce,
883 &v.alice.public_key,
884 &v.bob.secret_key,
885 )
886 .expect("encrypt failed");
887 assert_eq!(reverse.to_vec(), v.boxed);
888 }
889
890 #[test]
891 fn nacl_vector_precalculated_key_and_ciphertext_match() {
892 let v = nacl_vector();
893 let expected_key: StackByteArray<CRYPTO_BOX_BEFORENMBYTES> = array(SHARED_KEY);
894
895 let alice_side = PrecalcSecretKey::precalculate(&v.bob.public_key, &v.alice.secret_key)
896 .expect("precalculation failed");
897 let bob_side = v
898 .bob
899 .precalculate(&v.alice.public_key)
900 .expect("precalculation failed");
901 assert_eq!(alice_side.as_array(), expected_key.as_array());
902 assert_eq!(alice_side, bob_side);
903
904 let dryocbox = DryocBox::precalc_encrypt_to_vecbox(&v.message, &v.nonce, &alice_side)
905 .expect("encrypt failed");
906 assert_eq!(dryocbox.to_vec(), v.boxed);
907
908 let parsed = VecBox::from_bytes(&v.boxed).expect("parse");
909 assert_eq!(
910 parsed
911 .precalc_decrypt_to_vec(&v.nonce, &bob_side)
912 .expect("decrypt failed"),
913 v.message
914 );
915 assert_eq!(
917 parsed
918 .decrypt_to_vec(&v.nonce, &v.alice.public_key, &v.bob.secret_key)
919 .expect("decrypt failed"),
920 v.message
921 );
922 }
923
924 #[test]
925 fn tampering_and_wrong_keys_are_rejected_and_the_box_stays_usable() {
926 let v = nacl_vector();
927 let dryocbox = VecBox::from_bytes(&v.boxed).expect("parse");
928 let precalc = v.bob.precalculate(&v.alice.public_key).expect("precalc");
929 let stranger = StackKeyPair::from_seed(&[9u8; CRYPTO_BOX_SEEDBYTES]);
930
931 assert!(matches!(
933 dryocbox.decrypt_to_vec(&v.nonce, &stranger.public_key, &v.bob.secret_key),
934 Err(Error::AuthenticationFailed)
935 ));
936 assert!(matches!(
938 dryocbox.decrypt_to_vec(&v.nonce, &v.alice.public_key, &stranger.secret_key),
939 Err(Error::AuthenticationFailed)
940 ));
941 assert!(
943 dryocbox
944 .decrypt_to_vec(&v.nonce, &PublicKey::default(), &v.bob.secret_key)
945 .is_err()
946 );
947
948 let mut wrong_nonce = v.nonce.clone();
949 wrong_nonce[0] ^= 1;
950 assert!(matches!(
951 dryocbox.decrypt_to_vec(&wrong_nonce, &v.alice.public_key, &v.bob.secret_key),
952 Err(Error::AuthenticationFailed)
953 ));
954 assert!(matches!(
955 dryocbox.precalc_decrypt_to_vec(&wrong_nonce, &precalc),
956 Err(Error::AuthenticationFailed)
957 ));
958
959 for index in [
960 0,
961 CRYPTO_BOX_MACBYTES - 1,
962 CRYPTO_BOX_MACBYTES,
963 v.boxed.len() - 1,
964 ] {
965 let mut tampered = v.boxed.clone();
966 tampered[index] ^= 0x80;
967 let tampered = VecBox::from_bytes(&tampered).expect("parse");
968 assert!(matches!(
969 tampered.decrypt_to_vec(&v.nonce, &v.alice.public_key, &v.bob.secret_key),
970 Err(Error::AuthenticationFailed)
971 ));
972 assert!(matches!(
973 tampered.precalc_decrypt_to_vec(&v.nonce, &precalc),
974 Err(Error::AuthenticationFailed)
975 ));
976 }
977
978 let mut wrong_precalc = precalc.clone();
979 wrong_precalc.as_mut_array()[0] ^= 1;
980 assert!(matches!(
981 dryocbox.precalc_decrypt_to_vec(&v.nonce, &wrong_precalc),
982 Err(Error::AuthenticationFailed)
983 ));
984
985 assert_eq!(dryocbox.to_vec(), v.boxed);
987 assert_eq!(
988 dryocbox
989 .decrypt_to_vec(&v.nonce, &v.alice.public_key, &v.bob.secret_key)
990 .expect("decrypt"),
991 v.message
992 );
993 }
994
995 #[test]
996 fn encrypt_rejects_low_order_recipient_key() {
997 let v = nacl_vector();
998 let mut identity = PublicKey::default();
999 identity[0] = 1;
1000 for low_order in [PublicKey::default(), identity] {
1001 assert!(
1002 DryocBox::encrypt_to_vecbox(&v.message, &v.nonce, &low_order, &v.alice.secret_key)
1003 .is_err()
1004 );
1005 assert!(PrecalcSecretKey::precalculate(&low_order, &v.alice.secret_key).is_err());
1006 }
1007 }
1008
1009 #[test]
1010 fn from_bytes_and_from_sealed_bytes_require_their_prefixes() {
1011 for len in 0..CRYPTO_BOX_MACBYTES {
1012 assert!(matches!(
1013 VecBox::from_bytes(&vec![0u8; len]),
1014 Err(Error::InvalidLength {
1015 context: crate::ErrorContext::Box,
1016 actual,
1017 ..
1018 }) if actual == len
1019 ));
1020 }
1021 for len in [0, CRYPTO_BOX_PUBLICKEYBYTES, CRYPTO_BOX_SEALBYTES - 1] {
1022 assert!(matches!(
1023 VecBox::from_sealed_bytes(&vec![0u8; len]),
1024 Err(Error::InvalidLength {
1025 context: crate::ErrorContext::SealedBox,
1026 actual,
1027 ..
1028 }) if actual == len
1029 ));
1030 }
1031
1032 let empty_sealed =
1033 VecBox::from_sealed_bytes(&[0x5au8; CRYPTO_BOX_SEALBYTES]).expect("empty sealed box");
1034 assert!(empty_sealed.data.is_empty());
1035 assert_eq!(
1036 empty_sealed.ephemeral_pk.as_ref().map(|epk| epk.as_slice()),
1037 Some(&[0x5au8; CRYPTO_BOX_PUBLICKEYBYTES][..])
1038 );
1039 }
1040
1041 #[test]
1042 fn sealed_wire_format_is_ephemeral_key_then_tag_then_ciphertext() {
1043 let epk: PublicKey = array(ALICE_PK);
1044 let tag: Mac = array(&NONCE[..CRYPTO_BOX_MACBYTES * 2]);
1045 let data = hex::decode(MESSAGE).expect("hex");
1046
1047 let mut expected = epk.to_vec();
1048 expected.extend_from_slice(tag.as_slice());
1049 expected.extend_from_slice(&data);
1050
1051 let sealed = VecBox::from_parts(Some(epk.clone()), tag.clone(), data.clone());
1052 assert_eq!(sealed.to_vec(), expected);
1053 let reparsed = VecBox::from_sealed_bytes(&expected).expect("parse");
1054 assert_eq!(reparsed, sealed);
1055 let (parsed_epk, parsed_tag, parsed_data) = reparsed.into_parts();
1056 assert_eq!(parsed_tag, tag);
1057 assert_eq!(parsed_data, data);
1058 assert_eq!(parsed_epk.as_ref(), Some(&epk));
1059
1060 let regular = VecBox::from_parts(None, tag, data);
1063 assert_eq!(regular.to_vec(), &expected[CRYPTO_BOX_PUBLICKEYBYTES..]);
1064 }
1065
1066 #[test]
1067 fn sealed_box_authenticates_recipient_and_contents() {
1068 let v = nacl_vector();
1069 let sealed = DryocBox::seal_to_vecbox(&v.message, &v.bob.public_key).expect("seal");
1070 assert_eq!(sealed.open_to_vec(&v.bob).expect("open"), v.message);
1071
1072 let wrong_recipient = sealed.open_to_vec(&v.alice);
1073 assert!(matches!(wrong_recipient, Err(Error::AuthenticationFailed)));
1074
1075 let bytes = sealed.to_vec();
1076 for index in [
1077 0,
1078 CRYPTO_BOX_PUBLICKEYBYTES,
1079 CRYPTO_BOX_SEALBYTES,
1080 bytes.len() - 1,
1081 ] {
1082 let mut tampered = bytes.clone();
1083 tampered[index] ^= 0x80;
1084 let tampered = VecBox::from_sealed_bytes(&tampered).expect("parse");
1085 assert!(tampered.open_to_vec(&v.bob).is_err());
1086 }
1087 assert_eq!(
1088 VecBox::from_sealed_bytes(&bytes)
1089 .expect("parse")
1090 .open_to_vec(&v.bob)
1091 .expect("open"),
1092 v.message
1093 );
1094 }
1095
1096 #[test]
1097 fn test_precalc_encrypt_decrypt() {
1098 let keypair_sender = StackKeyPair::generate();
1099 let keypair_recipient = StackKeyPair::generate();
1100 let nonce = Nonce::generate();
1101
1102 let message = b"To be, or not to be, that is the question:";
1103 let precalc_secret_key = PrecalcSecretKey::precalculate(
1104 &keypair_recipient.public_key,
1105 &keypair_sender.secret_key,
1106 )
1107 .expect("precalculation failed");
1108
1109 let dryocbox: VecBox = DryocBox::precalc_encrypt(message, &nonce, &precalc_secret_key)
1110 .expect("unable to encrypt");
1111
1112 let decrypted: Vec<u8> = dryocbox
1113 .precalc_decrypt(&nonce, &precalc_secret_key)
1114 .expect("unable to decrypt");
1115
1116 assert_eq!(message, decrypted.as_slice());
1117 }
1118
1119 #[test]
1120 fn test_precalc_encrypt_to_vecbox_decrypt_to_vecbox() {
1121 let keypair_sender = StackKeyPair::generate();
1122 let keypair_recipient = StackKeyPair::generate();
1123 let nonce = Nonce::generate();
1124
1125 let message = b"All the world's a stage, and all the men and women merely players:";
1126 let precalc_secret_key = PrecalcSecretKey::precalculate(
1127 &keypair_recipient.public_key,
1128 &keypair_sender.secret_key,
1129 )
1130 .expect("precalculation failed");
1131
1132 let dryocbox = DryocBox::precalc_encrypt_to_vecbox(message, &nonce, &precalc_secret_key)
1133 .expect("unable to encrypt");
1134
1135 let decrypted = dryocbox
1136 .precalc_decrypt_to_vec(&nonce, &precalc_secret_key)
1137 .expect("unable to decrypt");
1138
1139 assert_eq!(message, decrypted.as_slice());
1140 }
1141
1142 #[test]
1143 fn test_precalc_encrypt_decrypt_with_different_messages() {
1144 let keypair_sender = StackKeyPair::generate();
1145 let keypair_recipient = StackKeyPair::generate();
1146 let nonce = Nonce::generate();
1147
1148 let messages: Vec<&[u8]> = vec![
1149 b"Now is the winter of our discontent, made glorious summer by this sun of York;",
1150 b"Friends, Romans, countrymen, lend me your ears; I come to bury Caesar, not to praise him.",
1151 b"A horse! a horse! my kingdom for a horse!",
1152 b"Good night, good night! parting is such sweet sorrow, that I shall say good night till it be morrow.",
1153 ];
1154
1155 let precalc_secret_key = PrecalcSecretKey::precalculate(
1156 &keypair_recipient.public_key,
1157 &keypair_sender.secret_key,
1158 )
1159 .expect("precalculation failed");
1160
1161 for message in &messages {
1162 let dryocbox: VecBox = DryocBox::precalc_encrypt(message, &nonce, &precalc_secret_key)
1163 .expect("unable to encrypt");
1164
1165 let decrypted: Vec<u8> = dryocbox
1166 .precalc_decrypt(&nonce, &precalc_secret_key)
1167 .expect("unable to decrypt");
1168
1169 assert_eq!(*message, decrypted.as_slice());
1170 }
1171 }
1172
1173 #[test]
1174 fn test_precalc_encrypt_to_vecbox_decrypt_to_vecbox_with_different_messages() {
1175 let keypair_sender = StackKeyPair::generate();
1176 let keypair_recipient = StackKeyPair::generate();
1177 let nonce = Nonce::generate();
1178
1179 let messages: Vec<&[u8]> = vec![
1180 b"Out, out brief candle! Life's but a walking shadow, a poor player that struts and frets his hour upon the stage and then is heard no more.",
1181 b"Some are born great, some achieve greatness, and some have greatness thrust upon them.",
1182 b"The lady doth protest too much, methinks.",
1183 b"What's in a name? That which we call a rose by any other name would smell as sweet.",
1184 ];
1185
1186 let precalc_secret_key = PrecalcSecretKey::precalculate(
1187 &keypair_recipient.public_key,
1188 &keypair_sender.secret_key,
1189 )
1190 .expect("precalculation failed");
1191
1192 for message in &messages {
1193 let dryocbox =
1194 DryocBox::precalc_encrypt_to_vecbox(message, &nonce, &precalc_secret_key)
1195 .expect("unable to encrypt");
1196
1197 let decrypted = dryocbox
1198 .precalc_decrypt_to_vec(&nonce, &precalc_secret_key)
1199 .expect("unable to decrypt");
1200
1201 assert_eq!(*message, decrypted.as_slice());
1202 }
1203 }
1204
1205 #[cfg(dryoc_native_tests)]
1206 mod native_tests {
1207 use super::*;
1208 use crate::native_test_util as sodium;
1209
1210 #[test]
1211 fn nacl_vector_matches_libsodium_box_and_beforenm() {
1212 let v = nacl_vector();
1213 let so_boxed =
1214 sodium::box_easy(&v.message, &v.nonce, &v.bob.public_key, &v.alice.secret_key);
1215 assert_eq!(so_boxed, v.boxed);
1216
1217 let precalc = v.alice.precalculate(&v.bob.public_key).expect("precalc");
1218 let so_precalc = sodium::box_beforenm(&v.bob.public_key, &v.alice.secret_key)
1219 .expect("libsodium beforenm");
1220 assert_eq!(precalc.as_slice(), so_precalc.as_slice());
1221 }
1222
1223 #[test]
1224 fn libsodium_regular_and_precomputed_boxes_decrypt_with_rustaceous() {
1225 let v = nacl_vector();
1226 let so_precalc = sodium::box_beforenm(&v.bob.public_key, &v.alice.secret_key)
1227 .expect("libsodium beforenm");
1228 let precalc = v.bob.precalculate(&v.alice.public_key).expect("precalc");
1229
1230 for len in [0, 1, 15, 16, 17, 63, 64, 65, v.message.len()] {
1231 let plaintext = &v.message[..len];
1232
1233 let so_boxed =
1234 sodium::box_easy(plaintext, &v.nonce, &v.bob.public_key, &v.alice.secret_key);
1235 let dryocbox = VecBox::from_bytes(&so_boxed).expect("sodium box should parse");
1236 assert_eq!(
1237 dryocbox
1238 .decrypt_to_vec(&v.nonce, &v.alice.public_key, &v.bob.secret_key)
1239 .expect("decrypt failed"),
1240 plaintext
1241 );
1242 assert_eq!(
1243 dryocbox
1244 .precalc_decrypt_to_vec(&v.nonce, &precalc)
1245 .expect("precalc decrypt failed"),
1246 plaintext
1247 );
1248
1249 let so_afternm = sodium::box_easy_afternm(plaintext, &v.nonce, &so_precalc);
1250 assert_eq!(so_afternm, so_boxed);
1251 let dryocbox =
1252 VecBox::from_bytes(&so_afternm).expect("sodium afternm box should parse");
1253 assert_eq!(
1254 dryocbox
1255 .precalc_decrypt_to_vec(&v.nonce, &precalc)
1256 .expect("precalc decrypt failed"),
1257 plaintext
1258 );
1259
1260 let precalc_box =
1261 DryocBox::precalc_encrypt_to_vecbox(plaintext, &v.nonce, &precalc)
1262 .expect("precalc encrypt failed");
1263 assert_eq!(
1264 sodium::box_open_easy_afternm(&precalc_box.to_vec(), &v.nonce, &so_precalc)
1265 .expect("sodium open_precomputed failed"),
1266 plaintext
1267 );
1268 assert_eq!(
1269 sodium::box_open_easy(
1270 &precalc_box.to_vec(),
1271 &v.nonce,
1272 &v.alice.public_key,
1273 &v.bob.secret_key
1274 )
1275 .expect("sodium open failed"),
1276 plaintext
1277 );
1278 }
1279 }
1280
1281 #[test]
1282 fn libsodium_sealed_box_rejects_wrong_recipient_and_modification() {
1283 let v = nacl_vector();
1284 let ciphertext = sodium::box_seal(&v.message, &v.bob.public_key);
1285 let sealed = VecBox::from_sealed_bytes(&ciphertext).expect("parse");
1286 assert_eq!(sealed.open_to_vec(&v.bob).expect("open"), v.message);
1287 assert!(matches!(
1288 sealed.open_to_vec(&v.alice),
1289 Err(Error::AuthenticationFailed)
1290 ));
1291
1292 for index in [0, CRYPTO_BOX_PUBLICKEYBYTES, CRYPTO_BOX_SEALBYTES] {
1293 let mut tampered = ciphertext.clone();
1294 tampered[index] ^= 0x80;
1295 assert!(
1296 VecBox::from_sealed_bytes(&tampered)
1297 .expect("parse")
1298 .open_to_vec(&v.bob)
1299 .is_err()
1300 );
1301 }
1302 }
1303
1304 #[test]
1305 fn test_dryocbox_vecbox() {
1306 for i in 0..20 {
1307 use base64::Engine as _;
1308 use base64::engine::general_purpose;
1309
1310 let keypair_sender = StackKeyPair::generate();
1311 let keypair_recipient = StackKeyPair::generate();
1312 let keypair_sender_copy = keypair_sender.clone();
1313 let keypair_recipient_copy = keypair_recipient.clone();
1314 let nonce = Nonce::generate();
1315 let words = vec!["hello1".to_string(); i];
1316 let message = words.join(" :D ");
1317 let message_copy = message.clone();
1318 let dryocbox = DryocBox::encrypt_to_vecbox(
1319 message.as_bytes(),
1320 &nonce,
1321 &keypair_recipient.public_key,
1322 &keypair_sender.secret_key,
1323 )
1324 .unwrap();
1325
1326 let ciphertext = dryocbox.to_vec();
1327
1328 let so_ciphertext = sodium::box_easy(
1329 message_copy.as_bytes(),
1330 &nonce,
1331 &keypair_recipient_copy.public_key,
1332 &keypair_sender_copy.secret_key,
1333 );
1334
1335 assert_eq!(
1336 general_purpose::STANDARD.encode(&ciphertext),
1337 general_purpose::STANDARD.encode(&so_ciphertext)
1338 );
1339
1340 let keypair_sender = keypair_sender_copy.clone();
1341 let keypair_recipient = keypair_recipient_copy.clone();
1342
1343 let m = dryocbox
1344 .decrypt_to_vec(
1345 &nonce,
1346 &keypair_sender.public_key,
1347 &keypair_recipient.secret_key,
1348 )
1349 .expect("hmm");
1350 let so_m = sodium::box_open_easy(
1351 &ciphertext,
1352 &nonce,
1353 &keypair_recipient_copy.public_key,
1354 &keypair_sender_copy.secret_key,
1355 )
1356 .expect("HMMM");
1357
1358 assert_eq!(m, message_copy.as_bytes());
1359 assert_eq!(m, so_m);
1360 }
1361 }
1362
1363 #[test]
1364 fn test_decrypt_failure() {
1365 for i in 0..20 {
1366 use base64::Engine as _;
1367 use base64::engine::general_purpose;
1368
1369 let keypair_sender = StackKeyPair::generate();
1370 let keypair_recipient = StackKeyPair::generate();
1371 let keypair_sender_copy = keypair_sender.clone();
1372 let keypair_recipient_copy = keypair_recipient.clone();
1373 let nonce = Nonce::generate();
1374 let words = vec!["hello1".to_string(); i];
1375 let message = words.join(" :D ");
1376 let message_copy = message.clone();
1377 let dryocbox = DryocBox::encrypt_to_vecbox(
1378 message.as_bytes(),
1379 &nonce,
1380 &keypair_recipient.public_key,
1381 &keypair_sender.secret_key,
1382 )
1383 .unwrap();
1384
1385 let ciphertext = dryocbox.to_vec();
1386
1387 let so_ciphertext = sodium::box_easy(
1388 message_copy.as_bytes(),
1389 &nonce,
1390 &keypair_recipient_copy.public_key,
1391 &keypair_sender_copy.secret_key,
1392 );
1393
1394 assert_eq!(
1395 general_purpose::STANDARD.encode(&ciphertext),
1396 general_purpose::STANDARD.encode(&so_ciphertext)
1397 );
1398
1399 let invalid_key = StackKeyPair::generate();
1400 let invalid_key_copy_1 = invalid_key.clone();
1401 let invalid_key_copy_2 = invalid_key.clone();
1402
1403 DryocBox::decrypt::<Vec<u8>, Nonce, PublicKey, SecretKey>(
1404 &dryocbox,
1405 &nonce,
1406 &invalid_key_copy_1.public_key,
1407 &invalid_key_copy_2.secret_key,
1408 )
1409 .expect_err("hmm");
1410 sodium::box_open_easy(
1411 &ciphertext,
1412 &nonce,
1413 &invalid_key.public_key,
1414 &invalid_key.secret_key,
1415 )
1416 .expect_err("HMMM");
1417 }
1418 }
1419
1420 #[test]
1421 fn test_dryocbox_seal_vecbox() {
1422 for i in 0..20 {
1423 let keypair_recipient = StackKeyPair::generate();
1424 let words = vec!["hello1".to_string(); i];
1425 let message = words.join(" :D ");
1426 let message_copy = message.clone();
1427 let dryocbox =
1428 DryocBox::seal_to_vecbox(message.as_bytes(), &keypair_recipient.public_key)
1429 .unwrap();
1430
1431 let ciphertext = dryocbox.to_vec();
1432
1433 let m = dryocbox.open_to_vec(&keypair_recipient).expect("hmm");
1434 let so_m = sodium::box_seal_open(
1435 ciphertext.as_slice(),
1436 keypair_recipient.public_key.as_slice(),
1437 keypair_recipient.secret_key.as_slice(),
1438 )
1439 .unwrap();
1440
1441 assert_eq!(m, message_copy.as_bytes());
1442 assert_eq!(m, so_m);
1443 }
1444 }
1445
1446 #[test]
1447 fn test_dryocbox_open_vecbox() {
1448 for i in 0..20 {
1449 let keypair_recipient = StackKeyPair::generate();
1450 let words = vec!["hello1".to_string(); i];
1451 let message = words.join(" :D ");
1452
1453 let ciphertext =
1454 sodium::box_seal(message.as_bytes(), keypair_recipient.public_key.as_slice());
1455
1456 let dryocbox =
1457 DryocBox::from_sealed_bytes(&ciphertext).expect("from sealed bytes failed");
1458
1459 let m = dryocbox.open_to_vec(&keypair_recipient).expect("hmm");
1460
1461 assert_eq!(m, message.as_bytes());
1462 }
1463 }
1464 }
1465}