dryoc/
dryocbox.rs

1//! # Public-key authenticated encryption
2//!
3//! [`DryocBox`] implements libsodium's public-key authenticated encryption,
4//! also known as a _box_. This implementation uses X25519 for key derivation,
5//! the XSalsa20 stream cipher, and Poly1305 for message authentication.
6//!
7//! You should use a [`DryocBox`] when you want to:
8//!
9//! * exchange messages between two parties
10//! * authenticate the messages with public keys, rather than a pre-shared
11//!   secret
12//! * avoid secret sharing between parties
13//!
14//! The public keys of the sender and recipient must be known ahead of time, but
15//! the sender's secret key can be used once and discarded, if desired. The
16//! [`DryocBox::seal`] and corresponding [`DryocBox::unseal`] functions do just
17//! this, by generating an ephemeral secret key, deriving a nonce, and including
18//! the sender's public key in the box.
19//!
20//! If the `serde` feature is enabled, the [`serde::Deserialize`] and
21//! [`serde::Serialize`] traits will be implemented for [`DryocBox`].
22//!
23//! ## Rustaceous API example
24//!
25//! ```
26//! use dryoc::dryocbox::*;
27//!
28//! // Randomly generate sender/recipient keypairs. Under normal circumstances, the
29//! // sender would only know the recipient's public key, and the recipient would
30//! // only know the sender's public key.
31//! let sender_keypair = KeyPair::gen();
32//! let recipient_keypair = KeyPair::gen();
33//!
34//! // Randomly generate a nonce
35//! let nonce = Nonce::gen();
36//!
37//! let message = b"All that glitters is not gold";
38//!
39//! // Encrypt the message into a Vec<u8>-based box.
40//! let dryocbox = DryocBox::encrypt_to_vecbox(
41//!     message,
42//!     &nonce,
43//!     &recipient_keypair.public_key,
44//!     &sender_keypair.secret_key,
45//! )
46//! .expect("unable to encrypt");
47//!
48//! // Convert into a libsodium compatible box as a Vec<u8>
49//! let sodium_box = dryocbox.to_vec();
50//!
51//! // Load the libsodium box into a DryocBox
52//! let dryocbox = DryocBox::from_bytes(&sodium_box).expect("failed to read box");
53//!
54//! // Decrypt the same box back to the original message, with the sender/recipient
55//! // keypairs flipped.
56//! let decrypted = dryocbox
57//!     .decrypt_to_vec(
58//!         &nonce,
59//!         &sender_keypair.public_key,
60//!         &recipient_keypair.secret_key,
61//!     )
62//!     .expect("unable to decrypt");
63//!
64//! assert_eq!(message, decrypted.as_slice());
65//! ```
66//!
67//! ## Sealed box example
68//!
69//! ```
70//! use dryoc::dryocbox::*;
71//!
72//! let recipient_keypair = KeyPair::gen();
73//! let message = b"Now is the winter of our discontent.";
74//!
75//! let dryocbox = DryocBox::seal_to_vecbox(message, &recipient_keypair.public_key.clone())
76//!     .expect("unable to seal");
77//!
78//! let decrypted = dryocbox
79//!     .unseal_to_vec(&recipient_keypair)
80//!     .expect("unable to unseal");
81//!
82//! assert_eq!(message, decrypted.as_slice());
83//! ```
84//!
85//! ## Additional resources
86//!
87//! * See <https://libsodium.gitbook.io/doc/public-key_cryptography/authenticated_encryption>
88//!   for additional details on crypto boxes
89//! * For secret-key based encryption, see
90//!   [`DryocSecretBox`](crate::dryocsecretbox)
91//! * For stream encryption, see [`DryocStream`](crate::dryocstream)
92//! * See the [protected] mod for an example using the protected memory features
93//!   with [`DryocBox`]
94
95#[cfg(feature = "serde")]
96use serde::{Deserialize, Serialize};
97use subtle::ConstantTimeEq;
98use zeroize::Zeroize;
99
100use crate::constants::{
101    CRYPTO_BOX_BEFORENMBYTES, CRYPTO_BOX_MACBYTES, CRYPTO_BOX_NONCEBYTES,
102    CRYPTO_BOX_PUBLICKEYBYTES, CRYPTO_BOX_SEALBYTES, CRYPTO_BOX_SECRETKEYBYTES,
103};
104use crate::error::*;
105pub use crate::types::*;
106
107/// Stack-allocated public key for authenticated public-key boxes.
108pub type PublicKey = StackByteArray<CRYPTO_BOX_PUBLICKEYBYTES>;
109/// Stack-allocated secret key for authenticated public-key boxes.
110pub type SecretKey = StackByteArray<CRYPTO_BOX_SECRETKEYBYTES>;
111/// Stack-allocated nonce for authenticated public-key boxes.
112pub type Nonce = StackByteArray<CRYPTO_BOX_NONCEBYTES>;
113/// Stack-allocated message authentication code for authenticated public-key
114/// boxes.
115pub type Mac = StackByteArray<CRYPTO_BOX_MACBYTES>;
116/// Stack-allocated public/secret keypair for authenticated public-key
117/// boxes.
118pub type KeyPair = crate::keypair::KeyPair<PublicKey, SecretKey>;
119
120#[cfg(any(feature = "nightly", all(doc, not(doctest))))]
121#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "nightly")))]
122pub mod protected {
123    //! #  Protected memory type aliases for [`DryocBox`]
124    //!
125    //! This mod provides re-exports of type aliases for protected memory usage
126    //! with [`DryocBox`]. These type aliases are provided for convenience.
127    //!
128    //! ## Example
129    //!
130    //! ```
131    //! use dryoc::dryocbox::DryocBox;
132    //! use dryoc::dryocbox::protected::*;
133    //!
134    //! // Generate a random sender and recipient keypair, into locked, readonly
135    //! // memory.
136    //! let sender_keypair = LockedROKeyPair::gen_readonly_locked_keypair().expect("keypair");
137    //! let recipient_keypair = LockedROKeyPair::gen_readonly_locked_keypair().expect("keypair");
138    //!
139    //! // Generate a random nonce, into locked, readonly memory.
140    //! let nonce = Nonce::gen_readonly_locked().expect("nonce failed");
141    //!
142    //! // Read message into locked, readonly memory.
143    //! let message = HeapBytes::from_slice_into_readonly_locked(b"Secret message from Santa Claus")
144    //!     .expect("message failed");
145    //!
146    //! // Encrypt message into a locked box.
147    //! let dryocbox: LockedBox = DryocBox::encrypt(
148    //!     &message,
149    //!     &nonce,
150    //!     &recipient_keypair.public_key,
151    //!     &sender_keypair.secret_key,
152    //! )
153    //! .expect("encrypt failed");
154    //!
155    //! // Decrypt message into locked bytes.
156    //! let decrypted: LockedBytes = dryocbox
157    //!     .decrypt(
158    //!         &nonce,
159    //!         &sender_keypair.public_key,
160    //!         &recipient_keypair.secret_key,
161    //!     )
162    //!     .expect("decrypt failed");
163    //!
164    //! assert_eq!(message.as_slice(), decrypted.as_slice());
165    //! ```
166    use super::*;
167    pub use crate::protected::*;
168
169    /// Heap-allocated, page-aligned public key for authenticated public-key
170    /// boxes, for use with protected memory.
171    pub type PublicKey = HeapByteArray<CRYPTO_BOX_PUBLICKEYBYTES>;
172    /// Heap-allocated, page-aligned secret key for authenticated public-key
173    /// boxes, for use with protected memory.
174    pub type SecretKey = HeapByteArray<CRYPTO_BOX_SECRETKEYBYTES>;
175    /// Heap-allocated, page-aligned nonce for authenticated public-key
176    /// boxes, for use with protected memory.
177    pub type Nonce = HeapByteArray<CRYPTO_BOX_NONCEBYTES>;
178    /// Heap-allocated, page-aligned message authentication code for
179    /// authenticated public-key boxes, for use with protected memory.
180    pub type Mac = HeapByteArray<CRYPTO_BOX_MACBYTES>;
181
182    /// Heap-allocated, page-aligned public/secret keypair for
183    /// authenticated public-key boxes, for use with protected memory.
184    pub type LockedKeyPair = crate::keypair::KeyPair<Locked<PublicKey>, Locked<SecretKey>>;
185    /// Heap-allocated, page-aligned public/secret keypair for
186    /// authenticated public-key boxes, for use with protected memory.
187    pub type LockedROKeyPair = crate::keypair::KeyPair<LockedRO<PublicKey>, LockedRO<SecretKey>>;
188    /// Locked [DryocBox], provided as a type alias for convenience.
189    pub type LockedBox = DryocBox<Locked<PublicKey>, Locked<Mac>, LockedBytes>;
190}
191
192#[cfg_attr(
193    feature = "serde",
194    derive(Zeroize, Clone, Debug, Serialize, Deserialize)
195)]
196#[cfg_attr(not(feature = "serde"), derive(Zeroize, Clone, Debug))]
197/// A libsodium public-key authenticated encrypted box.
198///
199/// Refer to [crate::dryocbox] for sample usage.
200pub struct DryocBox<
201    EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
202    Mac: ByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
203    Data: Bytes + Zeroize,
204> {
205    ephemeral_pk: Option<EphemeralPublicKey>,
206    tag: Mac,
207    data: Data,
208}
209
210/// [Vec]-based authenticated public-key box.
211pub type VecBox = DryocBox<PublicKey, Mac, Vec<u8>>;
212
213impl<
214    EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
215    Mac: NewByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
216    Data: NewBytes + ResizableBytes + Zeroize,
217> DryocBox<EphemeralPublicKey, Mac, Data>
218{
219    /// Encrypts a message using `sender_secret_key` for `recipient_public_key`,
220    /// and returns a new [DryocBox] with ciphertext and tag.
221    pub fn encrypt<
222        Message: Bytes + ?Sized,
223        Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
224        RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES>,
225        SenderSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES>,
226    >(
227        message: &Message,
228        nonce: &Nonce,
229        recipient_public_key: &RecipientPublicKey,
230        sender_secret_key: &SenderSecretKey,
231    ) -> Result<Self, Error> {
232        use crate::classic::crypto_box::crypto_box_detached;
233
234        let mut dryocbox = Self {
235            ephemeral_pk: None,
236            tag: Mac::new_byte_array(),
237            data: Data::new_bytes(),
238        };
239
240        dryocbox.data.resize(message.as_slice().len(), 0);
241
242        crypto_box_detached(
243            dryocbox.data.as_mut_slice(),
244            dryocbox.tag.as_mut_array(),
245            message.as_slice(),
246            nonce.as_array(),
247            recipient_public_key.as_array(),
248            sender_secret_key.as_array(),
249        );
250
251        Ok(dryocbox)
252    }
253
254    /// Encrypts a message using `precalc_secret_key`,
255    /// and returns a new [DryocBox] with ciphertext and tag.
256    pub fn precalc_encrypt<
257        PrecalcSecretKey: ByteArray<CRYPTO_BOX_BEFORENMBYTES> + Zeroize,
258        Message: Bytes + ?Sized,
259        Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
260    >(
261        message: &Message,
262        nonce: &Nonce,
263        precalc_secret_key: &PrecalcSecretKey,
264    ) -> Result<Self, Error> {
265        use crate::classic::crypto_box::crypto_box_detached_afternm;
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_afternm(
276            dryocbox.data.as_mut_slice(),
277            dryocbox.tag.as_mut_array(),
278            message.as_slice(),
279            nonce.as_array(),
280            precalc_secret_key.as_array(),
281        );
282
283        Ok(dryocbox)
284    }
285}
286
287impl<
288    EphemeralPublicKey: NewByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
289    Mac: NewByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
290    Data: NewBytes + ResizableBytes + Zeroize,
291> DryocBox<EphemeralPublicKey, Mac, Data>
292{
293    /// Encrypts a message for `recipient_public_key`, using an ephemeral secret
294    /// key and nonce. Returns a new [DryocBox] with ciphertext, tag, and
295    /// ephemeral public key.
296    pub fn seal<
297        Message: Bytes + ?Sized,
298        RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES>,
299    >(
300        message: &Message,
301        recipient_public_key: &RecipientPublicKey,
302    ) -> Result<Self, Error> {
303        use crate::classic::crypto_box::{
304            crypto_box_detached, crypto_box_keypair, crypto_box_seal_nonce,
305        };
306
307        let mut nonce = Nonce::new_byte_array();
308        let (epk, esk) = crypto_box_keypair();
309        crypto_box_seal_nonce(nonce.as_mut_array(), &epk, recipient_public_key.as_array());
310
311        let mut pk = EphemeralPublicKey::new_byte_array();
312        pk.copy_from_slice(&epk);
313
314        let mut dryocbox = Self {
315            ephemeral_pk: Some(pk),
316            tag: Mac::new_byte_array(),
317            data: Data::new_bytes(),
318        };
319
320        dryocbox.data.resize(message.as_slice().len(), 0);
321
322        crypto_box_detached(
323            dryocbox.data.as_mut_slice(),
324            dryocbox.tag.as_mut_array(),
325            message.as_slice(),
326            nonce.as_array(),
327            recipient_public_key.as_array(),
328            &esk,
329        );
330
331        Ok(dryocbox)
332    }
333}
334
335impl<
336    'a,
337    EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + std::convert::TryFrom<&'a [u8]> + Zeroize,
338    Mac: ByteArray<CRYPTO_BOX_MACBYTES> + std::convert::TryFrom<&'a [u8]> + Zeroize,
339    Data: Bytes + From<&'a [u8]> + Zeroize,
340> DryocBox<EphemeralPublicKey, Mac, Data>
341{
342    /// Initializes a [`DryocBox`] from a slice. Expects the first
343    /// [`CRYPTO_BOX_MACBYTES`] bytes to contain the message authentication tag,
344    /// with the remaining bytes containing the encrypted message.
345    pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, Error> {
346        if bytes.len() < CRYPTO_BOX_MACBYTES {
347            Err(dryoc_error!(format!(
348                "bytes of len {} less than expected minimum of {}",
349                bytes.len(),
350                CRYPTO_BOX_MACBYTES
351            )))
352        } else {
353            let (tag, data) = bytes.split_at(CRYPTO_BOX_MACBYTES);
354            Ok(Self {
355                ephemeral_pk: None,
356                tag: Mac::try_from(tag).map_err(|_e| dryoc_error!("invalid tag"))?,
357                data: Data::from(data),
358            })
359        }
360    }
361
362    /// Initializes a sealed [`DryocBox`] from a slice. Expects the first
363    /// [`CRYPTO_BOX_PUBLICKEYBYTES`] bytes to contain the ephemeral public key,
364    /// the next [`CRYPTO_BOX_MACBYTES`] bytes to be the message authentication
365    /// tag, with the remaining bytes containing the encrypted message.
366    pub fn from_sealed_bytes(bytes: &'a [u8]) -> Result<Self, Error> {
367        if bytes.len() < CRYPTO_BOX_SEALBYTES {
368            Err(dryoc_error!(format!(
369                "bytes of len {} less than expected minimum of {}",
370                bytes.len(),
371                CRYPTO_BOX_SEALBYTES
372            )))
373        } else {
374            let (seal, data) = bytes.split_at(CRYPTO_BOX_SEALBYTES);
375            let (epk, tag) = seal.split_at(CRYPTO_BOX_PUBLICKEYBYTES);
376            Ok(Self {
377                ephemeral_pk: Some(
378                    EphemeralPublicKey::try_from(epk)
379                        .map_err(|_e| dryoc_error!("invalid ephemeral public key"))?,
380                ),
381                tag: Mac::try_from(tag).map_err(|_e| dryoc_error!("invalid tag"))?,
382                data: Data::from(data),
383            })
384        }
385    }
386}
387
388impl<
389    EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
390    Mac: ByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
391    Data: Bytes + Zeroize,
392> DryocBox<EphemeralPublicKey, Mac, Data>
393{
394    /// Returns a new box with `tag`, `data` and (optional) `ephemeral_pk`,
395    /// consuming each.
396    pub fn from_parts(tag: Mac, data: Data, ephemeral_pk: Option<EphemeralPublicKey>) -> Self {
397        Self {
398            ephemeral_pk,
399            tag,
400            data,
401        }
402    }
403
404    /// Copies `self` into a new [`Vec`]
405    pub fn to_vec(&self) -> Vec<u8> {
406        self.to_bytes()
407    }
408
409    /// Moves the tag, data, and (optional) ephemeral public key out of this
410    /// instance, returning them as a tuple.
411    pub fn into_parts(self) -> (Mac, Data, Option<EphemeralPublicKey>) {
412        (self.tag, self.data, self.ephemeral_pk)
413    }
414
415    /// Decrypts this box using `nonce`, `recipient_secret_key`, and
416    /// `sender_public_key`, returning the decrypted message upon success.
417    pub fn decrypt<
418        Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
419        SenderPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES>,
420        RecipientSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES>,
421        Output: ResizableBytes + NewBytes,
422    >(
423        &self,
424        nonce: &Nonce,
425        sender_public_key: &SenderPublicKey,
426        recipient_secret_key: &RecipientSecretKey,
427    ) -> Result<Output, Error> {
428        use crate::classic::crypto_box::*;
429
430        let mut message = Output::new_bytes();
431        message.resize(self.data.as_slice().len(), 0);
432
433        crypto_box_open_detached(
434            message.as_mut_slice(),
435            self.tag.as_array(),
436            self.data.as_slice(),
437            nonce.as_array(),
438            sender_public_key.as_array(),
439            recipient_secret_key.as_array(),
440        )?;
441
442        Ok(message)
443    }
444
445    /// Decrypts this box using `nonce`, `precalc_secret_key`, and
446    /// `sender_public_key`, returning the decrypted message upon success.
447    pub fn precalc_decrypt<
448        PrecalcSecretKey: ByteArray<CRYPTO_BOX_BEFORENMBYTES> + Zeroize,
449        Nonce: ByteArray<CRYPTO_BOX_NONCEBYTES>,
450        Output: ResizableBytes + NewBytes,
451    >(
452        &self,
453        nonce: &Nonce,
454        precalc_secret_key: &PrecalcSecretKey,
455    ) -> Result<Output, Error> {
456        use crate::classic::crypto_box::crypto_box_open_detached_afternm;
457
458        let mut message = Output::new_bytes();
459        message.resize(self.data.as_slice().len(), 0);
460
461        crypto_box_open_detached_afternm(
462            message.as_mut_slice(),
463            self.tag.as_array(),
464            self.data.as_slice(),
465            nonce.as_array(),
466            precalc_secret_key.as_array(),
467        )?;
468
469        Ok(message)
470    }
471
472    /// Decrypts this sealed box using `recipient_secret_key`, and
473    /// returning the decrypted message upon success.
474    pub fn unseal<
475        RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
476        RecipientSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES> + Zeroize,
477        Output: ResizableBytes + NewBytes + Zeroize,
478    >(
479        &self,
480        recipient_keypair: &crate::keypair::KeyPair<RecipientPublicKey, RecipientSecretKey>,
481    ) -> Result<Output, Error> {
482        use crate::classic::crypto_box::*;
483
484        match &self.ephemeral_pk {
485            Some(epk) => {
486                let mut nonce = Nonce::new_byte_array();
487                crypto_box_seal_nonce(
488                    nonce.as_mut_array(),
489                    epk.as_array(),
490                    recipient_keypair.public_key.as_array(),
491                );
492
493                let mut message = Output::new_bytes();
494                message.resize(self.data.as_slice().len(), 0);
495
496                crypto_box_open_detached(
497                    message.as_mut_slice(),
498                    self.tag.as_array(),
499                    self.data.as_slice(),
500                    nonce.as_array(),
501                    epk.as_array(),
502                    recipient_keypair.secret_key.as_array(),
503                )?;
504
505                Ok(message)
506            }
507            None => Err(dryoc_error!(
508                "ephemeral public key is missing, cannot unseal"
509            )),
510        }
511    }
512
513    /// Copies `self` into the target. Can be used with protected memory.
514    pub fn to_bytes<Bytes: NewBytes + ResizableBytes>(&self) -> Bytes {
515        let mut data = Bytes::new_bytes();
516        match &self.ephemeral_pk {
517            Some(epk) => {
518                data.resize(epk.len() + self.tag.len() + self.data.len(), 0);
519                let s = data.as_mut_slice();
520                s[..CRYPTO_BOX_PUBLICKEYBYTES].copy_from_slice(epk.as_slice());
521                s[CRYPTO_BOX_PUBLICKEYBYTES..CRYPTO_BOX_SEALBYTES]
522                    .copy_from_slice(self.tag.as_slice());
523                s[CRYPTO_BOX_SEALBYTES..].copy_from_slice(self.data.as_slice());
524            }
525            None => {
526                data.resize(self.tag.len() + self.data.len(), 0);
527                let s = data.as_mut_slice();
528                s[..CRYPTO_BOX_MACBYTES].copy_from_slice(self.tag.as_slice());
529                s[CRYPTO_BOX_MACBYTES..].copy_from_slice(self.data.as_slice());
530            }
531        }
532        data
533    }
534}
535
536impl DryocBox<PublicKey, Mac, Vec<u8>> {
537    /// Encrypts a message using `sender_secret_key` for `recipient_public_key`,
538    /// and returns a new [DryocBox] with ciphertext and tag.
539    pub fn encrypt_to_vecbox<
540        Message: Bytes + ?Sized,
541        SecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES>,
542    >(
543        message: &Message,
544        nonce: &Nonce,
545        recipient_public_key: &PublicKey,
546        sender_secret_key: &SecretKey,
547    ) -> Result<Self, Error> {
548        Self::encrypt(message, nonce, recipient_public_key, sender_secret_key)
549    }
550
551    /// Encrypts a message using `precalc_secret_key`,
552    /// and returns a new [DryocBox] with ciphertext and tag.
553    pub fn precalc_encrypt_to_vecbox<
554        Message: Bytes + ?Sized,
555        PrecalcSecretKey: ByteArray<CRYPTO_BOX_BEFORENMBYTES> + Zeroize,
556    >(
557        message: &Message,
558        nonce: &Nonce,
559        precalc_secret_key: &PrecalcSecretKey,
560    ) -> Result<Self, Error> {
561        Self::precalc_encrypt(message, nonce, precalc_secret_key)
562    }
563
564    /// Encrypts a message for `recipient_public_key`, using an ephemeral secret
565    /// key and nonce, and returns a new [DryocBox] with the ciphertext,
566    /// ephemeral public key, and tag.
567    pub fn seal_to_vecbox<Message: Bytes + ?Sized>(
568        message: &Message,
569        recipient_public_key: &PublicKey,
570    ) -> Result<Self, Error> {
571        Self::seal(message, recipient_public_key)
572    }
573
574    /// Decrypts this box using `nonce`, `recipient_secret_key` and
575    /// `sender_public_key`, returning the decrypted message upon success.
576    pub fn decrypt_to_vec<SecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES>>(
577        &self,
578        nonce: &Nonce,
579        sender_public_key: &PublicKey,
580        recipient_secret_key: &SecretKey,
581    ) -> Result<Vec<u8>, Error> {
582        self.decrypt(nonce, sender_public_key, recipient_secret_key)
583    }
584
585    /// Decrypts this box using `nonce` and
586    /// `precalc_secret_key`, returning the decrypted message upon
587    /// success.
588    pub fn precalc_decrypt_to_vec<
589        PrecalcSecretKey: ByteArray<CRYPTO_BOX_BEFORENMBYTES> + Zeroize,
590    >(
591        &self,
592        nonce: &Nonce,
593        precalc_secret_key: &PrecalcSecretKey,
594    ) -> Result<Vec<u8>, Error> {
595        self.precalc_decrypt(nonce, precalc_secret_key)
596    }
597
598    /// Decrypts this sealed box using `recipient_secret_key`, returning the
599    /// decrypted message upon success.
600    pub fn unseal_to_vec<
601        RecipientPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
602        RecipientSecretKey: ByteArray<CRYPTO_BOX_SECRETKEYBYTES> + Zeroize,
603    >(
604        &self,
605        recipient_keypair: &crate::keypair::KeyPair<RecipientPublicKey, RecipientSecretKey>,
606    ) -> Result<Vec<u8>, Error> {
607        self.unseal(recipient_keypair)
608    }
609}
610
611impl<
612    'a,
613    EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
614    Mac: ByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
615    Data: Bytes + ResizableBytes + From<&'a [u8]> + Zeroize,
616> DryocBox<EphemeralPublicKey, Mac, Data>
617{
618    /// Returns a new box with `data` and `tag`, with data copied from `input`
619    /// and `tag` consumed. The ephemeral public key is assumed not to be
620    /// present.
621    pub fn new_with_data_and_mac(tag: Mac, input: &'a [u8]) -> Self {
622        Self {
623            ephemeral_pk: None,
624            tag,
625            data: input.into(),
626        }
627    }
628
629    /// Returns a new sealed box with `ephemeral_pk`, `data` and `tag`, where
630    /// data copied from `input` and `ephemeral_pk` & `tag` are consumed.
631    pub fn new_with_epk_data_and_mac(
632        ephemeral_pk: EphemeralPublicKey,
633        tag: Mac,
634        input: &'a [u8],
635    ) -> Self {
636        Self {
637            ephemeral_pk: Some(ephemeral_pk),
638            tag,
639            data: input.into(),
640        }
641    }
642}
643
644impl<
645    EphemeralPublicKey: ByteArray<CRYPTO_BOX_PUBLICKEYBYTES> + Zeroize,
646    Mac: ByteArray<CRYPTO_BOX_MACBYTES> + Zeroize,
647    Data: Bytes + Zeroize,
648> PartialEq<DryocBox<EphemeralPublicKey, Mac, Data>> for DryocBox<EphemeralPublicKey, Mac, Data>
649{
650    fn eq(&self, other: &Self) -> bool {
651        if let Some(our_epk) = &self.ephemeral_pk {
652            if let Some(their_epk) = &other.ephemeral_pk {
653                self.tag.as_slice().ct_eq(other.tag.as_slice()).unwrap_u8() == 1
654                    && self
655                        .data
656                        .as_slice()
657                        .ct_eq(other.data.as_slice())
658                        .unwrap_u8()
659                        == 1
660                    && our_epk.as_slice().ct_eq(their_epk.as_slice()).unwrap_u8() == 1
661            } else {
662                false
663            }
664        } else if other.ephemeral_pk.is_none() {
665            self.tag.as_slice().ct_eq(other.tag.as_slice()).unwrap_u8() == 1
666                && self
667                    .data
668                    .as_slice()
669                    .ct_eq(other.data.as_slice())
670                    .unwrap_u8()
671                    == 1
672        } else {
673            false
674        }
675    }
676}
677
678#[cfg(test)]
679mod tests {
680    use super::*;
681    use crate::precalc::PrecalcSecretKey;
682
683    #[test]
684    fn test_dryocbox_vecbox() {
685        for i in 0..20 {
686            use base64::Engine as _;
687            use base64::engine::general_purpose;
688            use sodiumoxide::crypto::box_;
689            use sodiumoxide::crypto::box_::{Nonce as SONonce, PublicKey, SecretKey};
690
691            let keypair_sender = KeyPair::gen();
692            let keypair_recipient = KeyPair::gen();
693            let keypair_sender_copy = keypair_sender.clone();
694            let keypair_recipient_copy = keypair_recipient.clone();
695            let nonce = Nonce::gen();
696            let words = vec!["hello1".to_string(); i];
697            let message = words.join(" :D ");
698            let message_copy = message.clone();
699            let dryocbox = DryocBox::encrypt_to_vecbox(
700                message.as_bytes(),
701                &nonce,
702                &keypair_recipient.public_key,
703                &keypair_sender.secret_key,
704            )
705            .unwrap();
706
707            let ciphertext = dryocbox.to_vec();
708
709            let so_ciphertext = box_::seal(
710                message_copy.as_bytes(),
711                &SONonce::from_slice(&nonce).unwrap(),
712                &PublicKey::from_slice(&keypair_recipient_copy.public_key).unwrap(),
713                &SecretKey::from_slice(&keypair_sender_copy.secret_key).unwrap(),
714            );
715
716            assert_eq!(
717                general_purpose::STANDARD.encode(&ciphertext),
718                general_purpose::STANDARD.encode(&so_ciphertext)
719            );
720
721            let keypair_sender = keypair_sender_copy.clone();
722            let keypair_recipient = keypair_recipient_copy.clone();
723
724            let m = dryocbox
725                .decrypt_to_vec(
726                    &nonce,
727                    &keypair_sender.public_key,
728                    &keypair_recipient.secret_key,
729                )
730                .expect("hmm");
731            let so_m = box_::open(
732                &ciphertext,
733                &SONonce::from_slice(&nonce).unwrap(),
734                &PublicKey::from_slice(&keypair_recipient_copy.public_key).unwrap(),
735                &SecretKey::from_slice(&keypair_sender_copy.secret_key).unwrap(),
736            )
737            .expect("HMMM");
738
739            assert_eq!(m, message_copy.as_bytes());
740            assert_eq!(m, so_m);
741        }
742    }
743
744    #[test]
745    fn test_decrypt_failure() {
746        for i in 0..20 {
747            use base64::Engine as _;
748            use base64::engine::general_purpose;
749            use sodiumoxide::crypto::box_;
750            use sodiumoxide::crypto::box_::{
751                Nonce as SONonce, PublicKey as SOPublicKey, SecretKey as SOSecretKey,
752            };
753
754            let keypair_sender = KeyPair::gen();
755            let keypair_recipient = KeyPair::gen();
756            let keypair_sender_copy = keypair_sender.clone();
757            let keypair_recipient_copy = keypair_recipient.clone();
758            let nonce = Nonce::gen();
759            let words = vec!["hello1".to_string(); i];
760            let message = words.join(" :D ");
761            let message_copy = message.clone();
762            let dryocbox = DryocBox::encrypt_to_vecbox(
763                message.as_bytes(),
764                &nonce,
765                &keypair_recipient.public_key,
766                &keypair_sender.secret_key,
767            )
768            .unwrap();
769
770            let ciphertext = dryocbox.to_vec();
771
772            let so_ciphertext = box_::seal(
773                message_copy.as_bytes(),
774                &SONonce::from_slice(&nonce).unwrap(),
775                &SOPublicKey::from_slice(&keypair_recipient_copy.public_key).unwrap(),
776                &SOSecretKey::from_slice(&keypair_sender_copy.secret_key).unwrap(),
777            );
778
779            assert_eq!(
780                general_purpose::STANDARD.encode(&ciphertext),
781                general_purpose::STANDARD.encode(&so_ciphertext)
782            );
783
784            let invalid_key = KeyPair::gen();
785            let invalid_key_copy_1 = invalid_key.clone();
786            let invalid_key_copy_2 = invalid_key.clone();
787
788            DryocBox::decrypt::<Nonce, PublicKey, SecretKey, Vec<u8>>(
789                &dryocbox,
790                &nonce,
791                &invalid_key_copy_1.public_key,
792                &invalid_key_copy_2.secret_key,
793            )
794            .expect_err("hmm");
795            box_::open(
796                &ciphertext,
797                &SONonce::from_slice(&nonce).unwrap(),
798                &SOPublicKey::from_slice(&invalid_key.public_key).unwrap(),
799                &SOSecretKey::from_slice(&invalid_key.secret_key).unwrap(),
800            )
801            .expect_err("HMMM");
802        }
803    }
804
805    #[test]
806    fn test_decrypt_failure_empty() {
807        for _ in 0..20 {
808            use crate::keypair::*;
809
810            let invalid_key = KeyPair::gen();
811            let invalid_key_copy_1 = invalid_key.clone();
812            let invalid_key_copy_2 = invalid_key.clone();
813            let nonce = Nonce::gen();
814
815            let dryocbox: VecBox =
816                DryocBox::from_bytes(b"trollolllololololollollolololololol").expect("ok");
817            DryocBox::decrypt::<
818                Nonce,
819                crate::classic::crypto_box::PublicKey,
820                crate::classic::crypto_box::SecretKey,
821                Vec<u8>,
822            >(
823                &dryocbox,
824                &nonce,
825                &invalid_key_copy_1.public_key,
826                &invalid_key_copy_2.secret_key,
827            )
828            .expect_err("hmm");
829        }
830    }
831
832    #[test]
833    fn test_copy() {
834        for _ in 0..20 {
835            use std::convert::TryFrom;
836
837            use crate::rng::*;
838
839            let mut data1: Vec<u8> = vec![0u8; 1024];
840            copy_randombytes(data1.as_mut_slice());
841            let data1_copy = data1.clone();
842
843            let dryocbox: VecBox = DryocBox::from_bytes(&data1).expect("ok");
844            assert_eq!(dryocbox.data.as_slice(), &data1_copy[CRYPTO_BOX_MACBYTES..]);
845            assert_eq!(dryocbox.tag.as_slice(), &data1_copy[..CRYPTO_BOX_MACBYTES]);
846
847            let data1 = data1_copy.clone();
848            let (tag, data) = data1.split_at(CRYPTO_BOX_MACBYTES);
849            let dryocbox: VecBox =
850                DryocBox::new_with_data_and_mac(Mac::try_from(tag).expect("mac"), data);
851            assert_eq!(dryocbox.data.as_slice(), &data1_copy[CRYPTO_BOX_MACBYTES..]);
852            assert_eq!(dryocbox.tag.as_array(), &data1_copy[..CRYPTO_BOX_MACBYTES]);
853        }
854    }
855
856    #[test]
857    fn test_dryocbox_seal_vecbox() {
858        for i in 0..20 {
859            use sodiumoxide::crypto::box_::{PublicKey as SOPublicKey, SecretKey as SOSecretKey};
860            use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305;
861
862            let keypair_recipient = KeyPair::gen();
863            let words = vec!["hello1".to_string(); i];
864            let message = words.join(" :D ");
865            let message_copy = message.clone();
866            let dryocbox =
867                DryocBox::seal_to_vecbox(message.as_bytes(), &keypair_recipient.public_key)
868                    .unwrap();
869
870            let ciphertext = dryocbox.to_vec();
871
872            let m = dryocbox.unseal_to_vec(&keypair_recipient).expect("hmm");
873            let so_m = curve25519blake2bxsalsa20poly1305::open(
874                ciphertext.as_slice(),
875                &SOPublicKey::from_slice(keypair_recipient.public_key.as_slice()).unwrap(),
876                &SOSecretKey::from_slice(keypair_recipient.secret_key.as_slice()).unwrap(),
877            )
878            .unwrap();
879
880            assert_eq!(m, message_copy.as_bytes());
881            assert_eq!(m, so_m);
882        }
883    }
884
885    #[test]
886    fn test_dryocbox_unseal_vecbox() {
887        for i in 0..20 {
888            use sodiumoxide::crypto::box_::PublicKey as SOPublicKey;
889            use sodiumoxide::crypto::sealedbox::curve25519blake2bxsalsa20poly1305;
890
891            let keypair_recipient = KeyPair::gen();
892            let words = vec!["hello1".to_string(); i];
893            let message = words.join(" :D ");
894
895            let ciphertext = curve25519blake2bxsalsa20poly1305::seal(
896                message.as_bytes(),
897                &SOPublicKey::from_slice(keypair_recipient.public_key.as_slice()).unwrap(),
898            );
899
900            let dryocbox =
901                DryocBox::from_sealed_bytes(&ciphertext).expect("from sealed bytes failed");
902
903            let m = dryocbox.unseal_to_vec(&keypair_recipient).expect("hmm");
904
905            assert_eq!(m, message.as_bytes());
906        }
907    }
908
909    #[test]
910    fn test_precalc_encrypt_decrypt() {
911        let keypair_sender = KeyPair::gen();
912        let keypair_recipient = KeyPair::gen();
913        let nonce = Nonce::gen();
914
915        let message = b"To be, or not to be, that is the question:";
916        let precalc_secret_key = PrecalcSecretKey::precalculate(
917            &keypair_sender.secret_key,
918            &keypair_recipient.public_key,
919        );
920
921        let dryocbox: VecBox = DryocBox::precalc_encrypt(message, &nonce, &precalc_secret_key)
922            .expect("unable to encrypt");
923
924        let decrypted: Vec<u8> = dryocbox
925            .precalc_decrypt(&nonce, &precalc_secret_key)
926            .expect("unable to decrypt");
927
928        assert_eq!(message, decrypted.as_slice());
929    }
930
931    #[test]
932    fn test_precalc_encrypt_to_vecbox_decrypt_to_vecbox() {
933        let keypair_sender = KeyPair::gen();
934        let keypair_recipient = KeyPair::gen();
935        let nonce = Nonce::gen();
936
937        let message = b"All the world's a stage, and all the men and women merely players:";
938        let precalc_secret_key = PrecalcSecretKey::precalculate(
939            &keypair_sender.secret_key,
940            &keypair_recipient.public_key,
941        );
942
943        let dryocbox = DryocBox::precalc_encrypt_to_vecbox(message, &nonce, &precalc_secret_key)
944            .expect("unable to encrypt");
945
946        let decrypted = dryocbox
947            .precalc_decrypt_to_vec(&nonce, &precalc_secret_key)
948            .expect("unable to decrypt");
949
950        assert_eq!(message, decrypted.as_slice());
951    }
952
953    #[test]
954    fn test_precalc_encrypt_decrypt_with_different_messages() {
955        let keypair_sender = KeyPair::gen();
956        let keypair_recipient = KeyPair::gen();
957        let nonce = Nonce::gen();
958
959        let messages: Vec<&[u8]> = vec![
960            b"Now is the winter of our discontent, made glorious summer by this sun of York;",
961            b"Friends, Romans, countrymen, lend me your ears; I come to bury Caesar, not to praise him.",
962            b"A horse! a horse! my kingdom for a horse!",
963            b"Good night, good night! parting is such sweet sorrow, that I shall say good night till it be morrow.",
964        ];
965
966        let precalc_secret_key = PrecalcSecretKey::precalculate(
967            &keypair_sender.secret_key,
968            &keypair_recipient.public_key,
969        );
970
971        for message in &messages {
972            let dryocbox: VecBox = DryocBox::precalc_encrypt(message, &nonce, &precalc_secret_key)
973                .expect("unable to encrypt");
974
975            let decrypted: Vec<u8> = dryocbox
976                .precalc_decrypt(&nonce, &precalc_secret_key)
977                .expect("unable to decrypt");
978
979            assert_eq!(*message, decrypted.as_slice());
980        }
981    }
982
983    #[test]
984    fn test_precalc_encrypt_to_vecbox_decrypt_to_vecbox_with_different_messages() {
985        let keypair_sender = KeyPair::gen();
986        let keypair_recipient = KeyPair::gen();
987        let nonce = Nonce::gen();
988
989        let messages: Vec<&[u8]> = vec![
990            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.",
991            b"Some are born great, some achieve greatness, and some have greatness thrust upon them.",
992            b"The lady doth protest too much, methinks.",
993            b"What's in a name? That which we call a rose by any other name would smell as sweet.",
994        ];
995
996        let precalc_secret_key = PrecalcSecretKey::precalculate(
997            &keypair_sender.secret_key,
998            &keypair_recipient.public_key,
999        );
1000
1001        for message in &messages {
1002            let dryocbox =
1003                DryocBox::precalc_encrypt_to_vecbox(message, &nonce, &precalc_secret_key)
1004                    .expect("unable to encrypt");
1005
1006            let decrypted = dryocbox
1007                .precalc_decrypt_to_vec(&nonce, &precalc_secret_key)
1008                .expect("unable to decrypt");
1009
1010            assert_eq!(*message, decrypted.as_slice());
1011        }
1012    }
1013}