alkali/symmetric/
cipher.rs

1//! Symmetric [Authenticated Encryption](https://en.wikipedia.org/wiki/Authenticated_encryption)
2//! (AE).
3//!
4//! This module corresponds to the [`crypto_secretbox`
5//! API](https://doc.libsodium.org/secret-key_cryptography/secretbox) from Sodium.
6//!
7//! Authenticated encryption is used to encrypt messages, providing assurance to the receiver that
8//! the ciphertext has not been modified in transit by an attacker or transmission error. In
9//! symmetric encryption, all parties who wish to encrypt or decrypt messages must share a single
10//! secret key prior to communication, which is used for both encryption and decryption.
11//!
12//! # Algorithm Details
13//! This authenticated encryption construction uses the [XSalsa20](https://cr.yp.to/snuffle.html)
14//! stream cipher (Salsa20 with an eXtended nonce length) for encryption by default, together with
15//! the [Poly1305](https://en.wikipedia.org/wiki/Poly1305) MAC for authentication. This construction
16//! is exposed in the [`xsalsa20poly1305`] module.
17//!
18//! As an alternative, an implementation which uses [XChaCha20](https://cr.yp.to/chacha.html) as the
19//! stream cipher is also available, exposed as [`xchacha20poly1305`].
20//!
21//! # Security Considerations
22//! For the algorithms in this module, nonces must *never* be used more than once with the same key.
23//! If you supply `None` as the nonce for [`encrypt`] or [`encrypt_detached`], a nonce will be
24//! randomly generated for you, and the chance of nonce-reuse is effectively zero. However, if you
25//! need to specify your own nonces for each message, please ensure a given nonce is never reused:
26//! Random nonce generation with [`generate_nonce`] will probably be your best strategy.
27//!
28//! If many trusted parties have access to the secret key, there is no way to prove which one of
29//! them sent a given message without additional information.
30//!
31//! This construction exposes the length of the plaintext. If this is undesirable, apply padding to
32//! the plaintext prior to encryption via [`util::pad`](crate::util::pad), and remove it following
33//! decryption via [`util::unpad`](crate::util::unpad).
34//!
35//! ## Secret Data
36//! * The encryption/decryption key ([`Key`]) must only be known to parties who should be able to
37//!   both encrypt and decrypt messages
38//!
39//! ## Non-Secret Data
40//! * MACs ([`MAC`]) are not sensitive
41//! * Nonces ([`Nonce`]) are not sensitive
42//!
43//! # Examples
44//! Standard encryption & decryption (uses [`encrypt`] and [`decrypt`]):
45//!
46//! ```rust
47//! use alkali::symmetric::cipher;
48//!
49//! const MESSAGE: &'static str = "Here's a message to encrypt. It can be of any length.";
50//!
51//! // Prior to communication:
52//!
53//! // A random secret key is generated & distributed to all parties:
54//! let key = cipher::Key::generate().unwrap();
55//!
56//!
57//! // ...
58//!
59//!
60//! // Sender side:
61//! // We assume the sender knows `key`.
62//!
63//! // The encrypted message will be `MAC_LENGTH` bytes longer than the original message.
64//! let mut ciphertext = vec![0u8; MESSAGE.as_bytes().len() + cipher::MAC_LENGTH];
65//! // If this function is successful, the ciphertext + a MAC will be stored in `ciphertext`. A
66//! // random nonce will be generated for this message, and returned to be stored in `nonce`. We
67//! // will need this to perform the decryption.
68//! let (_, nonce) = cipher::encrypt(MESSAGE.as_bytes(), &key, None, &mut ciphertext).unwrap();
69//!
70//!
71//! // ...
72//!
73//!
74//! // Receiver side:
75//! // We assume the receiver knows `key`.
76//!
77//! let mut plaintext = vec![0u8; ciphertext.len() - cipher::MAC_LENGTH];
78//! // The `decrypt` function not only decrypts `ciphertext`, but also verifies its authenticity
79//! // using the included MAC. This operation will fail if a forgery is attempted.
80//! cipher::decrypt(&ciphertext, &key, &nonce, &mut plaintext).unwrap();
81//! assert_eq!(&plaintext, MESSAGE.as_bytes());
82//! ```
83//!
84//! Detached encryption & decryption, which stores the MAC separately to the ciphertext (uses
85//! [`encrypt_detached`] and [`decrypt_detached`]):
86//!
87//! ```rust
88//! use alkali::symmetric::cipher;
89//!
90//! const MESSAGE: &'static str = "Another encryption example!";
91//!
92//! // Prior to communication:
93//!
94//! // A random secret key is generated & distributed to all parties:
95//! let key = cipher::Key::generate().unwrap();
96//!
97//!
98//! // ...
99//!
100//!
101//! // Sender side:
102//! // We assume the sender knows `key`.
103//!
104//! // In detached mode, the ciphertext length is identical to the plaintext length.
105//! let mut ciphertext = vec![0u8; MESSAGE.as_bytes().len()];
106//! // The `encrypt_detached` function will return the MAC of the message separately.
107//! let (_, nonce, mac) =
108//!     cipher::encrypt_detached(MESSAGE.as_bytes(), &key, None, &mut ciphertext).unwrap();
109//!
110//!
111//! // ...
112//!
113//!
114//! // Receiver side:
115//! // We assume the receiver knows `key`.
116//!
117//! let mut plaintext = vec![0u8; ciphertext.len()];
118//! // We will need to pass the MAC as another argument to the detached decryption function.
119//! cipher::decrypt_detached(&ciphertext, &mac, &key, &nonce, &mut plaintext);
120//! assert_eq!(&plaintext, MESSAGE.as_bytes());
121//! ```
122
123crate::error_type! {
124    /// Error type returned if something went wrong in the `symmetric::cipher` module.
125    SymmetricCipherError {
126        /// The output buffer is too short to store the ciphertext/plaintext which would result
127        /// from encrypting/decrypting this message.
128        ///
129        /// Each function in this module should provide information in its documentation about the
130        /// output length requirements.
131        OutputInsufficient,
132
133        /// Message too long for use with this cipher.
134        ///
135        /// Beyond a certain point, the keystream of the cipher is exhausted, and it can no longer
136        /// be used to safely encrypt message contents. Therefore, this error is returned if the
137        /// message provided is too long. Messages can be at most [`struct@MESSAGE_LENGTH_MAX`]
138        /// bytes.
139        MessageTooLong,
140
141        /// Indicates decryption of a provided ciphertext failed.
142        ///
143        /// This could indicate an attempted forgery, or transmission error.
144        DecryptionFailed,
145    }
146}
147
148/// Generates the API for a `symmetric::cipher` module with the given functions from Sodium for a
149/// specific implementation.
150macro_rules! cipher_module {
151    (
152        $key_len:expr,      // crypto_secretbox_KEYBYTES
153        $mac_len:expr,      // crypto_secretbox_MACBYTES
154        $nonce_len:expr,    // crypto_secretbox_NONCEBYTES
155        $msg_max:path,      // crypto_secretbox_messagebytes_max
156        $keygen:path,       // crypto_secretbox_keygen
157        $encrypt:path,      // crypto_secretbox_easy
158        $decrypt:path,      // crypto_secretbox_open_easy
159        $encrypt_d:path,    // crypto_secretbox_detached
160        $decrypt_d:path,    // crypto_secretbox_open_detached
161    ) => {
162        use $crate::symmetric::cipher::SymmetricCipherError;
163        use $crate::{assert_not_err, mem, random, require_init, AlkaliError};
164
165        /// The length of a symmetric key used for encryption/decryption, in bytes.
166        pub const KEY_LENGTH: usize = $key_len as usize;
167
168        /// The length of a MAC, in bytes.
169        pub const MAC_LENGTH: usize = $mac_len as usize;
170
171        /// The length of a message nonce, in bytes.
172        pub const NONCE_LENGTH: usize = $nonce_len as usize;
173
174        lazy_static::lazy_static! {
175            /// The maximum message length which can be encrypted with this cipher, in bytes.
176            pub static ref MESSAGE_LENGTH_MAX: usize = unsafe {
177                // SAFETY: This function just returns a constant value, and should always be safe
178                // to call.
179                $msg_max()
180            };
181        }
182
183        mem::hardened_buffer! {
184            /// A secret key for symmetric authenticated encryption.
185            ///
186            /// There are no *technical* constraints on the contents of a key, but it should be
187            /// indistinguishable from random noise. A random key can be securely generated via
188            /// [`Key::generate`].
189            ///
190            /// A secret key must not be made public.
191            ///
192            /// This is a [hardened buffer type](https://docs.rs/alkali#hardened-buffer-types), and
193            /// will be zeroed on drop. A number of other security measures are also taken to
194            /// protect its contents. This type in particular can be thought of as roughly
195            /// equivalent to a `[u8; KEY_LENGTH]`, and implements [`core::ops::Deref`] so it can be
196            /// used like it is an `&[u8]`. This struct uses heap memory while in scope, allocated
197            /// using Sodium's [secure memory
198            /// utilities](https://doc.libsodium.org/memory_management).
199            pub Key(KEY_LENGTH);
200        }
201
202        impl Key<mem::FullAccess> {
203            /// Generate a new, random key for use in symmetric AE.
204            pub fn generate() -> Result<Self, AlkaliError> {
205                require_init()?;
206
207                let mut key = Self::new_empty()?;
208                unsafe {
209                    // SAFETY: This function expects a pointer to a region of memory sufficient to
210                    // store a key. The `Key` type allocates `crypto_secretbox_KEYBYTES`, the length
211                    // of a key for this algorithm. It is therefore valid for writes of the required
212                    // length. The `Key::inner_mut` method simply returns a mutable pointer to the
213                    // struct's backing memory.
214                    $keygen(key.inner_mut().cast());
215                }
216                Ok(key)
217            }
218        }
219
220        /// A MAC (Message Authentication Code), used to authenticate a message.
221        ///
222        /// If using [`encrypt`], the MAC is included in the ciphertext. It is returned separately
223        /// in the [`encrypt_detached`] variant.
224        pub type MAC = [u8; MAC_LENGTH];
225
226        /// A nonce, used to introduce non-determinism into the keystream calculation.
227        ///
228        /// Nonces must never be used for multiple messages with the same key. Ideally, let alkali
229        /// generate a random nonce for every message by specifying `None` as the nonce for
230        /// [`encrypt`]/[`encrypt_detached`].
231        pub type Nonce = [u8; NONCE_LENGTH];
232
233        /// Generate a random nonce for use with the functions throughout this module.
234        ///
235        /// It is vital that a given nonce is never used to encrypt more than one message under the
236        /// same key. The cipher used here has a sufficient nonce size that we can simply generate a
237        /// random nonce for every message we wish to encrypt, and the chances of reusing a nonce
238        /// are essentially zero.
239        ///
240        /// Returns a random nonce, or a [`crate::AlkaliError`] if an error occurred.
241        pub fn generate_nonce() -> Result<Nonce, AlkaliError> {
242            let mut nonce = [0; NONCE_LENGTH];
243            random::fill_random(&mut nonce)?;
244            Ok(nonce)
245        }
246
247        /// Encrypt `message` using the provided `key`, writing the result to `output`.
248        ///
249        /// `message` should be the message to encrypt, and `key` a [`Key`] generated randomly using
250        /// [`Key::generate`].
251        ///
252        /// `nonce` should be a [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) to use in
253        /// the encryption process. It is recommended that this be set to `None`, which will cause
254        /// alkali to randomly generate a nonce for the message. If you specify a custom nonce, it
255        /// is vital the nonce is never used to encrypt more than one message under the same key:
256        /// Nonce reuse destroys the security of the scheme. Nonces are not secret, but will need to
257        /// be communicated to the decrypting party for them to be able to decrypt the message. This
258        /// function will return the nonce used for the encryption of this message.
259        ///
260        /// The encrypted ciphertext will be written to `output`. The ciphertext will be
261        /// [`MAC_LENGTH`] bytes longer than `message`, so `output` must be of sufficient size to
262        /// store at least this many bytes. An error will be returned if `output` is not sufficient
263        /// to store the ciphertext.
264        ///
265        /// If encryption is successful, returns the number of bytes written to `output` (this will
266        /// actually always be `message.len()` + [`MAC_LENGTH`] bytes), and the [`Nonce`] used for
267        /// the encryption process.
268        ///
269        /// # Security Considerations
270        /// Nonces must *never* be used more than once with the same key. You should specify `None`
271        /// for the nonce to use, which will cause a random nonce to be generated for every message,
272        /// unless you have good reason to do otherwise.
273        pub fn encrypt(
274            message: &[u8],
275            key: &Key<impl mem::MprotectReadable>,
276            nonce: Option<&Nonce>,
277            output: &mut [u8],
278        ) -> Result<(usize, Nonce), AlkaliError> {
279            require_init()?;
280
281            let c_len = message.len() + MAC_LENGTH;
282
283            if output.len() < c_len {
284                return Err(SymmetricCipherError::OutputInsufficient.into());
285            } else if message.len() > *MESSAGE_LENGTH_MAX {
286                return Err(SymmetricCipherError::MessageTooLong.into());
287            }
288
289            let nonce = match nonce {
290                Some(&n) => n,
291                None => generate_nonce()?,
292            };
293
294            let encrypt_result = unsafe {
295                // SAFETY: The first argument to this function is the destination to which the
296                // combined MAC + ciphertext will be written. The ciphertext will be of the same
297                // length as the message, and the MAC will always be `crypto_secretbox_MACBYTES`, so
298                // as long as the output pointer is valid for writes of `message.len() +
299                // crypto_secretbox_MACBYTES`, it is valid to use here. We verify this condition
300                // above, and return an error if the output is insufficient. The next two arguments
301                // specify the message to encrypt and its length. We use `message.len()` to specify
302                // the message length, so `message` is definitely valid for reads of this length.
303                // The next argument should be a pointer to the nonce to use for encryption. We have
304                // defined the `Nonce` type to be `crypto_secretbox_NONCEBYTES`, the size of a nonce
305                // for this algorithm, so it is valid for reads of the required length. The final
306                // argument for this function specifies the key with which the message should be
307                // encrypted. We have defined the `Key` type to allocate
308                // `crypto_secretbox_KEYBYTES`, the length of a key for this algorithm, so it is
309                // valid for reads of the required length. The `Key::inner` method simply returns an
310                // immutable pointer to its backing memory.
311                $encrypt(
312                    output.as_mut_ptr(),
313                    message.as_ptr(),
314                    message.len() as libc::c_ulonglong,
315                    nonce.as_ptr(),
316                    key.inner().cast(),
317                )
318            };
319            assert_not_err!(encrypt_result, stringify!($encrypt));
320
321            Ok((c_len, nonce))
322        }
323
324        /// Decrypt `ciphertext` using the provided `key`, writing the result to `output`.
325        ///
326        /// `ciphertext` should be the combined ciphertext + MAC to decrypt (previously encrypted
327        /// using [`encrypt`]). `key` should be the [`Key`] to use to decrypt the message. `nonce`
328        /// should be the [`Nonce`] which was used to encrypt the message.
329        ///
330        /// The decrypted plaintext will be written to `output`. The plaintext will be
331        /// [`MAC_LENGTH`] bytes shorter than `ciphertext`, so `output` must be of sufficient size
332        /// to store at least this many bytes. An error will be returned if `output` is not
333        /// sufficient to store the plaintext.
334        ///
335        /// Decryption will fail if message authentication fails. If decryption is successful, the
336        /// plaintext is written to `output`, and the length of the plaintext will be returned (this
337        /// will always be `ciphertext.len()` - [`MAC_LENGTH`] bytes).
338        pub fn decrypt(
339            ciphertext: &[u8],
340            key: &Key<impl mem::MprotectReadable>,
341            nonce: &Nonce,
342            output: &mut [u8],
343        ) -> Result<usize, AlkaliError> {
344            require_init()?;
345
346            if ciphertext.len() < MAC_LENGTH {
347                return Err(SymmetricCipherError::DecryptionFailed.into());
348            }
349
350            let m_len = ciphertext.len() - MAC_LENGTH;
351
352            if output.len() < m_len {
353                return Err(SymmetricCipherError::OutputInsufficient.into());
354            }
355
356            let decrypt_result = unsafe {
357                // SAFETY: The first argument to this function is the destination to which the
358                // decrypted plaintext will be written. The plaintext will be
359                // `crypto_secretbox_MACBYTES` shorter than the ciphertext, so as long as the output
360                // pointer is valid for writes of `ciphertext.len() - crypto_secretbox_MACBYTES`, it
361                // is valid to use here. We verify this condition above, and return an error if the
362                // output is insufficient. The next two arguments specify the ciphertext to decrypt
363                // and its length. We use `ciphertext.len()` to specify the ciphertext length, so
364                // `ciphertext` is definitely valid for reads of this length. The next argument
365                // should be a pointer to the nonce to use for decryption. We have defined the
366                // `Nonce` type to be `crypto_secretbox_NONCEBYTES`, the size of a nonce for this
367                // algorithm, so it is valid for reads of the required length. The final argument
368                // for this function specifies the key with which the message should be decrypted.
369                // We have defined the `Key` type to allocate `crypto_secretbox_KEYBYTES`, the
370                // length of a key for this algorithm, so it is valid for reads of the required
371                // length. The `Key::inner` method simply returns an immutable pointer to its
372                // backing memory.
373                $decrypt(
374                    output.as_mut_ptr(),
375                    ciphertext.as_ptr(),
376                    ciphertext.len() as libc::c_ulonglong,
377                    nonce.as_ptr(),
378                    key.inner().cast(),
379                )
380            };
381
382            if decrypt_result == 0 {
383                Ok(m_len)
384            } else {
385                Err(SymmetricCipherError::DecryptionFailed.into())
386            }
387        }
388
389        /// Encrypt `message` using the provided `key`, writing the result to `output`, separately
390        /// returning the [`MAC`].
391        ///
392        /// This function is very similar to the [`encrypt`] function. The difference is that the
393        /// standard [`encrypt`] function prepends the Message Authentication Code (MAC, used to
394        /// verify the authenticity of the ciphertext) to the ciphertext output, while this
395        /// function only writes the ciphertext to `output`, and separately returns the MAC.
396        ///
397        /// `message` should be the message to encrypt. `key` should be the [`Key`] to use for
398        /// encryption, generated randomly using [`Key::generate`].
399        ///
400        /// `nonce` should be a [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) to use in
401        /// the encryption process. It is recommended that this be set to `None`, which will cause
402        /// alkali to randomly generate a nonce for the message. If you specify a custom nonce, it
403        /// is vital the nonce is never used to encrypt more than one message under the same key:
404        /// Nonce reuse destroys the security of the scheme. Nonces are not secret, but will need to
405        /// be communicated to the decrypting party for them to be able to decrypt the message. This
406        /// function will return the nonce used for the encryption of this message.
407        ///
408        /// The encrypted ciphertext will be written to `output`. The ciphertext will be the same
409        /// length as `message`, so `output` must be of sufficient size to store at least this many
410        /// bytes. An error will be returned if `output` is not sufficient to store the ciphertext.
411        ///
412        /// If encryption is successful, returns the number of bytes written to `output` (this will
413        /// actually always be `message.len()` bytes), the [`Nonce`] used for the encryption
414        /// process, and the authentication tag for the message (a [`MAC`]).
415        ///
416        /// # Security Considerations
417        /// Nonces must *never* be used more than once with the same key. You should specify `None`
418        /// for the nonce to use, which will cause a random nonce to be generated for every message,
419        /// unless you have good reason to do otherwise.
420        pub fn encrypt_detached(
421            message: &[u8],
422            key: &Key<impl mem::MprotectReadable>,
423            nonce: Option<&Nonce>,
424            output: &mut [u8],
425        ) -> Result<(usize, Nonce, MAC), AlkaliError> {
426            require_init()?;
427
428            if output.len() < message.len() {
429                return Err(SymmetricCipherError::OutputInsufficient.into());
430            } else if message.len() > *MESSAGE_LENGTH_MAX {
431                return Err(SymmetricCipherError::MessageTooLong.into());
432            }
433
434            let nonce = match nonce {
435                Some(&n) => n,
436                None => generate_nonce()?,
437            };
438
439            let mut mac = [0u8; MAC_LENGTH];
440
441            let encrypt_result = unsafe {
442                // SAFETY: The first argument to this function is the destination to which the
443                // ciphertext will be written. The ciphertext will be of the same length as the
444                // message, so as long as the output pointer is valid for writes of `message.len()`,
445                // it is valid to use here. We verify this condition above, and return an error if
446                // the output is insufficient. The next argument is the destination to which the MAC
447                // will be written. We define the `mac` array to be `crypto_secretbox_MACBYTES`, the
448                // length of a MAC for this algorithm, so it is valid for writes of the required
449                // length. The next two arguments specify the message to encrypt and its length. We
450                // use `message.len()` to specify the message length, so `message` is definitely
451                // valid for reads of this length. The next argument should be a pointer to the
452                // nonce to use for encryption. We have defined the `Nonce` type to be
453                // `crypto_secretbox_NONCEBYTES`, the size of a nonce for this algorithm, so it is
454                // valid for reads of the required length. The final argument for this function
455                // specifies the key with which the message should be encrypted. We have defined the
456                // `Key` type to allocate `crypto_secretbox_KEYBYTES`, the length of a key for this
457                // algorithm, so it is valid for reads of the required length. The `Key::inner`
458                // method simply returns an immutable pointer to its backing memory.
459                $encrypt_d(
460                    output.as_mut_ptr(),
461                    mac.as_mut_ptr(),
462                    message.as_ptr(),
463                    message.len() as libc::c_ulonglong,
464                    nonce.as_ptr(),
465                    key.inner().cast(),
466                )
467            };
468            assert_not_err!(encrypt_result, stringify!($encrypt_d));
469
470            Ok((message.len(), nonce, mac))
471        }
472
473        /// Decrypt `ciphertext` using the provided `key`, verifying the detached [`MAC`] and
474        /// writing the result to `output`.
475        ///
476        /// `ciphertext` should be the ciphertext to decrypt, and `mac` the [`MAC`] generated when
477        /// encrypting the ciphertext in detached mode with [`encrypt_detached`]. `key` should be
478        /// the [`Key`] to use to decrypt the message. `nonce` should be the
479        /// [nonce](https://en.wikipedia.org/wiki/Cryptographic_nonce) which was used to encrypt the
480        /// message.
481        ///
482        /// The decrypted plaintext will be written to `output`. The plaintext will be the same
483        /// length as `ciphertext`, so `output` must be of sufficient size to store at least this
484        /// many bytes. An error will be returned if `output` is not sufficient to store the
485        /// plaintext.
486        ///
487        /// Decryption will fail if message authentication fails. If decryption is successful, the
488        /// plaintext is written to `output`, and the length of the plaintext will be returned (this
489        /// will always be `ciphertext.len()` bytes).
490        pub fn decrypt_detached(
491            ciphertext: &[u8],
492            mac: &MAC,
493            key: &Key<impl mem::MprotectReadable>,
494            nonce: &Nonce,
495            output: &mut [u8],
496        ) -> Result<usize, AlkaliError> {
497            require_init()?;
498
499            if output.len() < ciphertext.len() {
500                return Err(SymmetricCipherError::OutputInsufficient.into());
501            }
502
503            let decrypt_result = unsafe {
504                // SAFETY: The first argument to this function is the destination to which the
505                // decrypted plaintext will be written. The plaintext will be the same length as the
506                // ciphertext, so as long as the output pointer is valid for writes of
507                // `ciphertext.len()`, it is valid to use here. We verify this condition above, and
508                // return an error if the output is insufficient. The next three arguments specify
509                // the ciphertext to decrypt, the MAC, and the ciphertext length. We use
510                // `ciphertext.len()` to specify the ciphertext length, so `ciphertext` is
511                // definitely valid for reads of this length. The `MAC` type is defined to be
512                // `crypto_secretbox_MACBYTES`, the length of a MAC for this algorithm, so `mac` is
513                // valid for reads of the required length. The next argument should be a pointer to
514                // the nonce to use for decryption. We have defined the `Nonce` type to be
515                // `crypto_secretbox_NONCEBYTES`, the size of a nonce for this algorithm, so it is
516                // valid for reads of the required length. The final argument for this function
517                // specifies the key with which the message should be decrypted. We have defined the
518                // `Key` type to allocate `crypto_secretbox_KEYBYTES`, the length of a key for this
519                // algorithm, so it is valid for reads of the required length. The `Key::inner`
520                // method simply returns an immutable pointer to its backing memory.
521                $decrypt_d(
522                    output.as_mut_ptr(),
523                    ciphertext.as_ptr(),
524                    mac.as_ptr(),
525                    ciphertext.len() as libc::c_ulonglong,
526                    nonce.as_ptr(),
527                    key.inner().cast(),
528                )
529            };
530
531            if decrypt_result == 0 {
532                Ok(ciphertext.len())
533            } else {
534                Err(SymmetricCipherError::DecryptionFailed.into())
535            }
536        }
537    };
538}
539
540#[allow(unused_macros)]
541macro_rules! cipher_tests {
542    ( $( {
543        msg: $msg:expr,
544        key: $key:expr,
545        nonce: $nonce:expr,
546        c: $c:expr,
547        mac: $mac:expr,
548    }, )* ) => {
549        use super::{
550            decrypt, decrypt_detached, encrypt, encrypt_detached, generate_nonce, Key, MAC_LENGTH,
551        };
552        use $crate::random::fill_random;
553        use $crate::AlkaliError;
554
555        #[test]
556        fn key_generation() -> Result<(), AlkaliError> {
557            let _key = Key::generate()?;
558            Ok(())
559        }
560
561        #[test]
562        fn nonce_generation() -> Result<(), AlkaliError> {
563            let _nonce = generate_nonce()?;
564            Ok(())
565        }
566
567        #[test]
568        fn enc_and_dec() -> Result<(), AlkaliError> {
569            let key = Key::generate()?;
570
571            let mut msg_a = [];
572            let mut msg_b = [0; 16];
573            let mut msg_c = [0; 1024];
574            let mut msg_d = [0; 1 << 18];
575
576            fill_random(&mut msg_b)?;
577            fill_random(&mut msg_c)?;
578            fill_random(&mut msg_d)?;
579
580            let mut c_a = [0; MAC_LENGTH];
581            let mut c_b = [0; 16 + MAC_LENGTH];
582            let mut c_c = [0; 1024 + MAC_LENGTH];
583            let mut c_d = [0; (1 << 18) + MAC_LENGTH];
584
585            let (l_a, nonce_a) = encrypt(&msg_a, &key, None, &mut c_a)?;
586            let (l_b, nonce_b) = encrypt(&msg_b, &key, None, &mut c_b)?;
587            let (l_c, nonce_c) = encrypt(&msg_c, &key, None, &mut c_c)?;
588            let (l_d, nonce_d) = encrypt(&msg_d, &key, None, &mut c_d)?;
589
590            assert_eq!(l_a, MAC_LENGTH);
591            assert_eq!(l_b, 16 + MAC_LENGTH);
592            assert_eq!(l_c, 1024 + MAC_LENGTH);
593            assert_eq!(l_d, (1 << 18) + MAC_LENGTH);
594
595            assert_eq!(decrypt(&c_a, &key, &nonce_a, &mut msg_a)?, 0);
596            assert_eq!(decrypt(&c_b, &key, &nonce_b, &mut msg_b)?, 16);
597            assert_eq!(decrypt(&c_c, &key, &nonce_c, &mut msg_c)?, 1024);
598            assert_eq!(decrypt(&c_d, &key, &nonce_d, &mut msg_d)?, 1 << 18);
599
600            fill_random(&mut c_a)?;
601            fill_random(&mut c_b)?;
602            fill_random(&mut c_c)?;
603            fill_random(&mut c_d)?;
604
605            assert!(decrypt(&c_a, &key, &nonce_a, &mut msg_a).is_err());
606            assert!(decrypt(&c_b, &key, &nonce_b, &mut msg_b).is_err());
607            assert!(decrypt(&c_c, &key, &nonce_c, &mut msg_c).is_err());
608            assert!(decrypt(&c_d, &key, &nonce_d, &mut msg_d).is_err());
609
610            Ok(())
611        }
612
613        #[test]
614        fn enc_and_dec_detached() -> Result<(), AlkaliError> {
615            let key = Key::generate()?;
616
617            let mut msg_a = [];
618            let mut msg_b = [0; 16];
619            let mut msg_c = [0; 1024];
620            let mut msg_d = [0; 1 << 18];
621
622            fill_random(&mut msg_b)?;
623            fill_random(&mut msg_c)?;
624            fill_random(&mut msg_d)?;
625
626            let mut c_a = [];
627            let mut c_b = [0; 16];
628            let mut c_c = [0; 1024];
629            let mut c_d = [0; (1 << 18)];
630
631            let (mut l_a, nonce_a, mut mac_a) = encrypt_detached(&msg_a, &key, None, &mut c_a)?;
632            let (mut l_b, nonce_b, mac_b) = encrypt_detached(&msg_b, &key, None, &mut c_b)?;
633            let (mut l_c, nonce_c, mac_c) = encrypt_detached(&msg_c, &key, None, &mut c_c)?;
634            let (mut l_d, nonce_d, mac_d) = encrypt_detached(&msg_d, &key, None, &mut c_d)?;
635
636            assert_eq!(l_a, 0);
637            assert_eq!(l_b, 16);
638            assert_eq!(l_c, 1024);
639            assert_eq!(l_d, 1 << 18);
640
641            l_a = decrypt_detached(&c_a, &mac_a, &key, &nonce_a, &mut msg_a)?;
642            l_b = decrypt_detached(&c_b, &mac_b, &key, &nonce_b, &mut msg_b)?;
643            l_c = decrypt_detached(&c_c, &mac_c, &key, &nonce_c, &mut msg_c)?;
644            l_d = decrypt_detached(&c_d, &mac_d, &key, &nonce_d, &mut msg_d)?;
645
646            assert_eq!(l_a, 0);
647            assert_eq!(l_b, 16);
648            assert_eq!(l_c, 1024);
649            assert_eq!(l_d, 1 << 18);
650
651            fill_random(&mut mac_a)?;
652            fill_random(&mut c_b)?;
653            fill_random(&mut c_c)?;
654            fill_random(&mut c_d)?;
655
656            assert!(decrypt_detached(&c_a, &mac_a, &key, &nonce_a, &mut msg_a).is_err());
657            assert!(decrypt_detached(&c_b, &mac_b, &key, &nonce_b, &mut msg_b).is_err());
658            assert!(decrypt_detached(&c_c, &mac_c, &key, &nonce_c, &mut msg_c).is_err());
659            assert!(decrypt_detached(&c_d, &mac_d, &key, &nonce_d, &mut msg_d).is_err());
660
661            Ok(())
662        }
663
664        #[test]
665        fn test_vectors() -> Result<(), AlkaliError> {
666            let mut key = Key::new_empty()?;
667            let mut c = [0; 1024];
668            let mut m = [0; 1024];
669
670            $(
671                key.copy_from_slice(&$key);
672                let (l, _) = encrypt(&$msg, &key, Some(&$nonce), &mut c)?;
673                assert_eq!(l, $msg.len() + MAC_LENGTH);
674                assert_eq!(&c[..MAC_LENGTH], &$mac[..]);
675                assert_eq!(&c[MAC_LENGTH..$msg.len() + MAC_LENGTH], &$c[..]);
676                assert_eq!(
677                    decrypt(&c[..$msg.len() + MAC_LENGTH], &key, &$nonce, &mut m)?, $msg.len()
678                );
679                assert_eq!(&m[..$msg.len()], &$msg[..$msg.len()]);
680            )*
681
682            Ok(())
683        }
684
685        #[test]
686        fn test_vectors_detached() -> Result<(), AlkaliError> {
687            let mut key = Key::new_empty()?;
688            let mut c = [0; 1024];
689            let mut m = [0; 1024];
690
691            $(
692                key.copy_from_slice(&$key);
693                let (l, _, mac) = encrypt_detached(&$msg, &key, Some(&$nonce), &mut c)?;
694                assert_eq!(l, $msg.len());
695                assert_eq!(&c[..$msg.len()], &$c[..$msg.len()]);
696                assert_eq!(&mac, &$mac);
697                assert_eq!(decrypt_detached(&c[..$msg.len()], &mac, &key, &$nonce, &mut m)?, $msg.len());
698                assert_eq!(&m[..$msg.len()], &$msg[..$msg.len()]);
699            )*
700
701            Ok(())
702        }
703    };
704}
705
706/// The [XSalsa20](https://cr.yp.to/snuffle.html) cipher with a
707/// [Poly1305](https://en.wikipedia.org/wiki/Poly1305) MAC.
708pub mod xsalsa20poly1305 {
709    use libsodium_sys as sodium;
710
711    cipher_module! {
712        sodium::crypto_secretbox_xsalsa20poly1305_KEYBYTES,
713        sodium::crypto_secretbox_xsalsa20poly1305_MACBYTES,
714        sodium::crypto_secretbox_xsalsa20poly1305_NONCEBYTES,
715        sodium::crypto_secretbox_xsalsa20poly1305_messagebytes_max,
716        sodium::crypto_secretbox_xsalsa20poly1305_keygen,
717        sodium::crypto_secretbox_easy,
718        sodium::crypto_secretbox_open_easy,
719        sodium::crypto_secretbox_detached,
720        sodium::crypto_secretbox_open_detached,
721    }
722
723    #[cfg(test)]
724    mod tests {
725        cipher_tests! [
726            {
727                msg:   [0xbe, 0x07, 0x5f, 0xc5, 0x3c, 0x81, 0xf2, 0xd5, 0xcf, 0x14, 0x13, 0x16,
728                        0xeb, 0xeb, 0x0c, 0x7b, 0x52, 0x28, 0xc5, 0x2a, 0x4c, 0x62, 0xcb, 0xd4,
729                        0x4b, 0x66, 0x84, 0x9b, 0x64, 0x24, 0x4f, 0xfc, 0xe5, 0xec, 0xba, 0xaf,
730                        0x33, 0xbd, 0x75, 0x1a, 0x1a, 0xc7, 0x28, 0xd4, 0x5e, 0x6c, 0x61, 0x29,
731                        0x6c, 0xdc, 0x3c, 0x01, 0x23, 0x35, 0x61, 0xf4, 0x1d, 0xb6, 0x6c, 0xce,
732                        0x31, 0x4a, 0xdb, 0x31, 0x0e, 0x3b, 0xe8, 0x25, 0x0c, 0x46, 0xf0, 0x6d,
733                        0xce, 0xea, 0x3a, 0x7f, 0xa1, 0x34, 0x80, 0x57, 0xe2, 0xf6, 0x55, 0x6a,
734                        0xd6, 0xb1, 0x31, 0x8a, 0x02, 0x4a, 0x83, 0x8f, 0x21, 0xaf, 0x1f, 0xde,
735                        0x04, 0x89, 0x77, 0xeb, 0x48, 0xf5, 0x9f, 0xfd, 0x49, 0x24, 0xca, 0x1c,
736                        0x60, 0x90, 0x2e, 0x52, 0xf0, 0xa0, 0x89, 0xbc, 0x76, 0x89, 0x70, 0x40,
737                        0xe0, 0x82, 0xf9, 0x37, 0x76, 0x38, 0x48, 0x64, 0x5e, 0x07, 0x05],
738                key:   [0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4, 0x62, 0xcd, 0x51, 0x19,
739                        0x7a, 0x9a, 0x46, 0xc7, 0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2,
740                        0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89],
741                nonce: [0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8,
742                        0x75, 0xfc, 0x73, 0xd6, 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37],
743                c:     [0x8e, 0x99, 0x3b, 0x9f, 0x48, 0x68, 0x12, 0x73, 0xc2, 0x96, 0x50, 0xba,
744                        0x32, 0xfc, 0x76, 0xce, 0x48, 0x33, 0x2e, 0xa7, 0x16, 0x4d, 0x96, 0xa4,
745                        0x47, 0x6f, 0xb8, 0xc5, 0x31, 0xa1, 0x18, 0x6a, 0xc0, 0xdf, 0xc1, 0x7c,
746                        0x98, 0xdc, 0xe8, 0x7b, 0x4d, 0xa7, 0xf0, 0x11, 0xec, 0x48, 0xc9, 0x72,
747                        0x71, 0xd2, 0xc2, 0x0f, 0x9b, 0x92, 0x8f, 0xe2, 0x27, 0x0d, 0x6f, 0xb8,
748                        0x63, 0xd5, 0x17, 0x38, 0xb4, 0x8e, 0xee, 0xe3, 0x14, 0xa7, 0xcc, 0x8a,
749                        0xb9, 0x32, 0x16, 0x45, 0x48, 0xe5, 0x26, 0xae, 0x90, 0x22, 0x43, 0x68,
750                        0x51, 0x7a, 0xcf, 0xea, 0xbd, 0x6b, 0xb3, 0x73, 0x2b, 0xc0, 0xe9, 0xda,
751                        0x99, 0x83, 0x2b, 0x61, 0xca, 0x01, 0xb6, 0xde, 0x56, 0x24, 0x4a, 0x9e,
752                        0x88, 0xd5, 0xf9, 0xb3, 0x79, 0x73, 0xf6, 0x22, 0xa4, 0x3d, 0x14, 0xa6,
753                        0x59, 0x9b, 0x1f, 0x65, 0x4c, 0xb4, 0x5a, 0x74, 0xe3, 0x55, 0xa5],
754                mac:   [0xf3, 0xff, 0xc7, 0x70, 0x3f, 0x94, 0x00, 0xe5, 0x2a, 0x7d, 0xfb, 0x4b,
755                        0x3d, 0x33, 0x05, 0xd9],
756            },
757            {
758                msg:   [] as [u8; 0],
759                key:   [0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4, 0x62, 0xcd, 0x51, 0x19,
760                        0x7a, 0x9a, 0x46, 0xc7, 0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2,
761                        0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89],
762                nonce: [0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8,
763                        0x75, 0xfc, 0x73, 0xd6, 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37],
764                c:     [],
765                mac:   [0x25, 0x39, 0x12, 0x1d, 0x8e, 0x23, 0x4e, 0x65, 0x2d, 0x65, 0x1f, 0xa4,
766                        0xc8, 0xcf, 0xf8, 0x80],
767            },
768        ];
769    }
770}
771
772/// The [XChaCha20](https://cr.yp.to/chacha.html) cipher with a
773/// [Poly1305](https://en.wikipedia.org/wiki/Poly1305) MAC.
774#[cfg(not(feature = "minimal"))]
775#[cfg_attr(doc_cfg, doc(cfg(not(feature = "minimal"))))]
776pub mod xchacha20poly1305 {
777    use libsodium_sys as sodium;
778
779    cipher_module! {
780        sodium::crypto_secretbox_xchacha20poly1305_KEYBYTES,
781        sodium::crypto_secretbox_xchacha20poly1305_MACBYTES,
782        sodium::crypto_secretbox_xchacha20poly1305_NONCEBYTES,
783        sodium::crypto_secretbox_xchacha20poly1305_messagebytes_max,
784        sodium::crypto_secretbox_keygen,
785        sodium::crypto_secretbox_xchacha20poly1305_easy,
786        sodium::crypto_secretbox_xchacha20poly1305_open_easy,
787        sodium::crypto_secretbox_xchacha20poly1305_detached,
788        sodium::crypto_secretbox_xchacha20poly1305_open_detached,
789    }
790
791    #[cfg(test)]
792    mod tests {
793        cipher_tests! [
794            {
795                msg:   [0xbe, 0x07, 0x5f, 0xc5, 0x3c, 0x81, 0xf2, 0xd5, 0xcf, 0x14, 0x13, 0x16,
796                        0xeb, 0xeb, 0x0c, 0x7b, 0x52, 0x28, 0xc5, 0x2a, 0x4c, 0x62, 0xcb, 0xd4,
797                        0x4b, 0x66, 0x84, 0x9b, 0x64, 0x24, 0x4f, 0xfc, 0xe5, 0xec, 0xba, 0xaf,
798                        0x33, 0xbd, 0x75, 0x1a, 0x1a, 0xc7, 0x28, 0xd4, 0x5e, 0x6c, 0x61, 0x29,
799                        0x6c, 0xdc, 0x3c, 0x01, 0x23, 0x35, 0x61, 0xf4, 0x1d, 0xb6, 0x6c, 0xce,
800                        0x31, 0x4a, 0xdb, 0x31, 0x0e, 0x3b, 0xe8, 0x25, 0x0c, 0x46, 0xf0, 0x6d,
801                        0xce, 0xea, 0x3a, 0x7f, 0xa1, 0x34, 0x80, 0x57, 0xe2, 0xf6, 0x55, 0x6a,
802                        0xd6, 0xb1, 0x31, 0x8a, 0x02, 0x4a, 0x83, 0x8f, 0x21, 0xaf, 0x1f, 0xde,
803                        0x04, 0x89, 0x77, 0xeb, 0x48, 0xf5, 0x9f, 0xfd, 0x49, 0x24, 0xca, 0x1c,
804                        0x60, 0x90, 0x2e, 0x52, 0xf0, 0xa0, 0x89, 0xbc, 0x76, 0x89, 0x70, 0x40,
805                        0xe0, 0x82, 0xf9, 0x37, 0x76, 0x38, 0x48, 0x64, 0x5e, 0x07, 0x05],
806                key:   [0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4, 0x62, 0xcd, 0x51, 0x19,
807                        0x7a, 0x9a, 0x46, 0xc7, 0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2,
808                        0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89],
809                nonce: [0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8,
810                        0x75, 0xfc, 0x73, 0xd6, 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37],
811                c:     [0xbf, 0x8a, 0xf3, 0x19, 0x85, 0x85, 0xe5, 0x5d, 0x9c, 0xb0, 0x7e, 0xdc,
812                        0xd1, 0xe5, 0xa6, 0x95, 0x26, 0x54, 0x7f, 0xbd, 0x0f, 0x2c, 0x64, 0x2e,
813                        0x9e, 0xe9, 0x6e, 0x19, 0x46, 0x20, 0x31, 0xf1, 0x03, 0x2f, 0x1c, 0xd8,
814                        0x62, 0xbb, 0x95, 0x29, 0x00, 0x10, 0x3c, 0x06, 0xac, 0x16, 0x34, 0x4d,
815                        0x7f, 0x9c, 0x9d, 0xf0, 0xfe, 0xaa, 0xf5, 0xa7, 0x33, 0xde, 0xa7, 0xea,
816                        0x2d, 0xf7, 0x0a, 0x61, 0x99, 0x36, 0xfc, 0xc5, 0x50, 0x1d, 0xe7, 0x5c,
817                        0x5d, 0x11, 0x2e, 0x8a, 0xbd, 0x75, 0x73, 0xc4, 0x61, 0xad, 0xa2, 0x9e,
818                        0xc0, 0x16, 0xd1, 0x31, 0xaa, 0x55, 0x78, 0x04, 0x32, 0x00, 0x11, 0xff,
819                        0x6d, 0x94, 0x09, 0x25, 0x81, 0xce, 0xea, 0x1b, 0xad, 0x3c, 0xf0, 0xd6,
820                        0x51, 0x93, 0x88, 0x02, 0xca, 0x86, 0x7c, 0xd5, 0x2b, 0xbe, 0x50, 0xc2,
821                        0xda, 0x11, 0x61, 0xcb, 0x09, 0x51, 0x44, 0x07, 0x60, 0x99, 0x20],
822                mac:   [0x0c, 0x61, 0xfc, 0xff, 0xbc, 0x3f, 0xc8, 0xd3, 0xaa, 0x74, 0x64, 0xb9,
823                        0x1a, 0xb3, 0x53, 0x74],
824            },
825            {
826                msg:   [] as [u8; 0],
827                key:   [0x1b, 0x27, 0x55, 0x64, 0x73, 0xe9, 0x85, 0xd4, 0x62, 0xcd, 0x51, 0x19,
828                        0x7a, 0x9a, 0x46, 0xc7, 0x60, 0x09, 0x54, 0x9e, 0xac, 0x64, 0x74, 0xf2,
829                        0x06, 0xc4, 0xee, 0x08, 0x44, 0xf6, 0x83, 0x89],
830                nonce: [0x69, 0x69, 0x6e, 0xe9, 0x55, 0xb6, 0x2b, 0x73, 0xcd, 0x62, 0xbd, 0xa8,
831                        0x75, 0xfc, 0x73, 0xd6, 0x82, 0x19, 0xe0, 0x03, 0x6b, 0x7a, 0x0b, 0x37],
832                c:     [],
833                mac:   [0x89, 0x46, 0xd8, 0xf1, 0x8f, 0x31, 0x34, 0x65, 0xc8, 0x62, 0xa0, 0x87,
834                        0x82, 0x64, 0x82, 0x48],
835            },
836        ];
837    }
838}
839
840pub use xsalsa20poly1305::*;