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::*;