cryptoxide/
chacha20poly1305.rs

1//! ChaCha20Poly1305 is an authenticated symmetric stream cipher based on chacha20 and poly1305.
2//!
3//! the specification of chacha20poly1305 is available at [RFC8439][1] and it follows general principle related to [AEAD][2].
4//!
5//! This module provides 2 interfaces:
6//!
7//! * the one shot interface [`ChaCha20Poly1305`]
8//! * the incremental interfaces, using [`Context`], [`ContextEncryption`] and [`ContextDecryption`]
9//!
10//! The incremental interfaces should be used when you are streaming data or that
11//! you need more control over the memory usage, as the one-shot interface
12//! expects one single call with slices parameter.
13//!
14//! # Examples
15//!
16//! Encrypting using the one-shot interface:
17//!
18//! ```
19//! use cryptoxide::chacha20poly1305::ChaCha20Poly1305;
20//!
21//! let key : [u8; 16] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
22//! let nonce : [u8; 12] = [1,2,3,4,5,6,7,8,9,10,11,12];
23//! let aad : [u8; 0] = [];
24//! let input : &[u8; 12] = b"hello world!";
25//! let mut out : [u8; 12+16] = [0u8; 12+16];
26//! let mut tag : [u8; 16] = [0u8; 16];
27//!
28//! // create a new cipher
29//! let mut cipher = ChaCha20Poly1305::new(&key, &nonce, &aad);
30//!
31//! // encrypt the msg and append the tag at the end
32//! cipher.encrypt(input, &mut out[0..12], &mut tag);
33//! out[12..].copy_from_slice(&tag);
34//! ```
35//!
36//! Encrypting using the incremental interfaces:
37//!
38//! ```
39//! use cryptoxide::chacha20poly1305::Context;
40//!
41//! let key : [u8; 16] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
42//! let nonce : [u8; 12] = [1,2,3,4,5,6,7,8,9,10,11,12];
43//! let mut context = Context::<20>::new(&key, &nonce);
44//!
45//! // Add incrementally 2 slices of data
46//! context.add_data(b"authenticated");
47//! context.add_data(b"data");
48//!
49//! let mut encrypted_input = [0u8; 10+16];
50//! let mut context = context.to_encryption();
51//!
52//! // Encrypt incrementally 2 slices and append the encrypted data to the output buffer
53//! context.encrypt(b"hello", &mut encrypted_input[0..5]);
54//! context.encrypt(b"world", &mut encrypted_input[5..10]);
55//!
56//! // Finalize the context, and append the tag to the end of the output buffer
57//! let tag = context.finalize();
58//! encrypted_input[10..26].copy_from_slice(&tag.0);
59//! ```
60//!
61//! [1]: https://tools.ietf.org/html/rfc8439
62//! [2]: https://en.wikipedia.org/wiki/Authenticated_encryption
63
64// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
65// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
66// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
67// option. This file may not be copied, modified, or distributed
68// except according to those terms.
69
70use crate::chacha20::ChaCha;
71use crate::constant_time::{Choice, CtEqual};
72use crate::cryptoutil::write_u64_le;
73use crate::mac::Mac;
74use crate::poly1305::Poly1305;
75use core::convert::TryFrom;
76
77/// Chacha20Poly1305 Incremental Context for Authenticated Data (AAD)
78///
79/// The initial context set the key and nonce, and the authenticated data (if any),
80/// then it needs to converted either to a [`ContextEncryption`] or [`ContextDecryption`]
81/// using the [`Context::to_encryption`] or [`Context::to_decryption`] methods (respectively).
82///
83/// ```
84/// use cryptoxide::chacha20poly1305::Context;
85///
86/// let key : [u8; 16] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
87/// let nonce : [u8; 12] = [1,2,3,4,5,6,7,8,9,10,11,12];
88/// let mut context = Context::<20>::new(&key, &nonce);
89///
90/// // Add incrementally 2 slices of data
91/// context.add_data(b"authenticated");
92/// context.add_data(b"data");
93///
94/// let mut encrypted_input = [0u8; 10+16];
95/// let mut context = context.to_encryption();
96///
97/// // Encrypt incrementally 2 slices and append the encrypted data to the output buffer
98/// context.encrypt(b"hello", &mut encrypted_input[0..5]);
99/// context.encrypt(b"world", &mut encrypted_input[5..10]);
100///
101/// // Finalize the context, and append the tag to the end of the output buffer
102/// let tag = context.finalize();
103/// encrypted_input[10..26].copy_from_slice(&tag.0);
104/// ```
105#[derive(Clone)]
106pub struct Context<const ROUNDS: usize> {
107    cipher: ChaCha<ROUNDS>,
108    mac: Poly1305,
109    aad_len: u64,
110    data_len: u64,
111}
112
113/// ChaCha20Poly1305 Incremental Context for encryption
114#[derive(Clone)]
115pub struct ContextEncryption<const ROUNDS: usize>(Context<ROUNDS>);
116
117/// ChaCha20Poly1305 Incremental Context for decryption
118#[derive(Clone)]
119pub struct ContextDecryption<const ROUNDS: usize>(Context<ROUNDS>);
120
121/// ChaCha20Poly1305 Authenticated Tag (128 bits)
122#[derive(Debug, Clone)]
123pub struct Tag(pub [u8; 16]);
124
125impl CtEqual for &Tag {
126    fn ct_eq(self, other: Self) -> Choice {
127        self.0.ct_eq(&other.0)
128    }
129    fn ct_ne(self, b: Self) -> Choice {
130        self.ct_eq(b).negate()
131    }
132}
133
134impl PartialEq for Tag {
135    fn eq(&self, other: &Self) -> bool {
136        self.ct_eq(other).is_true()
137    }
138}
139
140impl Eq for Tag {}
141
142impl<const ROUNDS: usize> Context<ROUNDS> {
143    /// Create a new context given the key and nonce.
144    ///
145    /// ```
146    /// use cryptoxide::chacha20poly1305::Context;
147    ///
148    /// let key : [u8; 16] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
149    /// let nonce : [u8; 12] = [1,2,3,4,5,6,7,8,9,10,11,12];
150    /// let context = Context::<20>::new(&key, &nonce);
151    /// ```
152    pub fn new(key: &[u8], nonce: &[u8; 12]) -> Self {
153        assert!(key.len() == 16 || key.len() == 32);
154        let mut cipher = ChaCha::new(key, nonce);
155        let mut mac_key = [0u8; 64];
156        let zero_key = [0u8; 64];
157        cipher.process(&zero_key, &mut mac_key);
158
159        let mac = Poly1305::new(<&[u8; 32]>::try_from(&mac_key[..32]).unwrap());
160        Context {
161            cipher: cipher,
162            mac: mac,
163            aad_len: 0,
164            data_len: 0,
165        }
166    }
167
168    fn add_encrypted(&mut self, encrypted: &[u8]) {
169        self.mac.input(encrypted);
170        self.data_len += encrypted.len() as u64;
171    }
172
173    /// Add Authenticated Data to the MAC Context
174    ///
175    /// This can be called multiple times
176    pub fn add_data(&mut self, aad: &[u8]) {
177        self.aad_len += aad.len() as u64;
178        self.mac.input(aad);
179    }
180
181    /// Finish authenticated part and move to the encryption phase
182    pub fn to_encryption(mut self) -> ContextEncryption<ROUNDS> {
183        pad16(&mut self.mac, self.aad_len);
184        ContextEncryption(self)
185    }
186
187    /// Finish authenticated part and move to the decryption phase
188    pub fn to_decryption(mut self) -> ContextDecryption<ROUNDS> {
189        pad16(&mut self.mac, self.aad_len);
190        ContextDecryption(self)
191    }
192}
193
194fn finalize_raw<const ROUNDS: usize>(inner: &mut Context<ROUNDS>) -> [u8; 16] {
195    let mut len_buf = [0u8; 16];
196    pad16(&mut inner.mac, inner.data_len);
197    write_u64_le(&mut len_buf[0..8], inner.aad_len);
198    write_u64_le(&mut len_buf[8..16], inner.data_len);
199    inner.mac.input(&len_buf);
200    inner.mac.raw_result(&mut len_buf);
201    len_buf
202}
203
204impl<const ROUNDS: usize> ContextEncryption<ROUNDS> {
205    /// Encrypt input in place
206    pub fn encrypt_mut(&mut self, buf: &mut [u8]) {
207        self.0.cipher.process_mut(buf);
208        self.0.add_encrypted(buf);
209    }
210
211    /// Encrypt the input slice to the output slice
212    ///
213    /// The number of bytes written to the output is
214    /// equal to the number of bytes as input.
215    ///
216    /// Panics:
217    ///     if input and output are of different size
218    pub fn encrypt(&mut self, input: &[u8], output: &mut [u8]) {
219        assert_eq!(input.len(), output.len());
220        self.0.cipher.process(input, output);
221        self.0.add_encrypted(output);
222    }
223
224    /// Finalize the encryption context and return the tag
225    #[must_use]
226    pub fn finalize(mut self) -> Tag {
227        let tag = finalize_raw(&mut self.0);
228        Tag(tag)
229    }
230}
231
232/// Whether or not, the decryption was succesful related to the expected tag
233#[derive(Debug, Clone, PartialEq, Eq)]
234pub enum DecryptionResult {
235    /// The tag matched, the data has been verified as not tempered
236    Match,
237    /// The tag mismatched, which imply that some data is incorrect or has been tempered
238    MisMatch,
239}
240
241impl<const ROUNDS: usize> ContextDecryption<ROUNDS> {
242    /// Decrypt input in place
243    pub fn decrypt_mut(&mut self, buf: &mut [u8]) {
244        self.0.add_encrypted(buf);
245        self.0.cipher.process_mut(buf);
246    }
247
248    /// Decrypt the input to the output slice
249    ///
250    /// Panics:
251    ///     if input and output are of different size
252    pub fn decrypt(&mut self, input: &[u8], output: &mut [u8]) {
253        assert_eq!(input.len(), output.len());
254        self.0.add_encrypted(input);
255        self.0.cipher.process(input, output);
256    }
257
258    /// Finalize the decryption context and check that the tag match the expected value
259    ///
260    #[must_use = "if the result is not checked, then the data will not be verified against tempering"]
261    pub fn finalize(mut self, expected_tag: &Tag) -> DecryptionResult {
262        let got_tag = Tag(finalize_raw(&mut self.0));
263        if &got_tag == expected_tag {
264            DecryptionResult::Match
265        } else {
266            DecryptionResult::MisMatch
267        }
268    }
269}
270
271/// A ChaCha20+Poly1305 Context
272#[derive(Clone)]
273pub struct ChaChaPoly1305<const ROUNDS: usize> {
274    finished: bool,
275    context: Context<ROUNDS>,
276}
277
278fn pad16(mac: &mut Poly1305, len: u64) {
279    if (len % 16) != 0 {
280        let padding = [0u8; 15];
281        let sz = 16 - (len % 16) as usize;
282        mac.input(&padding[0..sz]);
283    }
284}
285
286/// Type alias to the common ChaChaPoly1305 with 20 rounds ChaCha
287pub type ChaCha20Poly1305 = ChaChaPoly1305<20>;
288
289impl<const ROUNDS: usize> ChaChaPoly1305<ROUNDS> {
290    /// Create a new ChaCha20Poly1305
291    ///
292    /// * key needs to be 16 or 32 bytes
293    /// * nonce needs to be 12 bytes
294    ///
295    pub fn new(key: &[u8], nonce: &[u8; 12], aad: &[u8]) -> Self {
296        let mut context = Context::new(key, nonce);
297        context.add_data(aad);
298        ChaChaPoly1305 {
299            context: context,
300            finished: false,
301        }
302    }
303
304    /// Encrypt input buffer to output buffer, and write an authenticated tag to out_tag.
305    ///
306    /// Output buffer need to be the same size as the input buffer
307    /// Out_tag mutable slice need to 16 bytes exactly.
308    ///
309    /// Example: Encrypt a simple "hello world" message with chacha20poly1305 AEAD
310    /// using a 64 bits nonce and a 128 bits keys, and arrange the output data
311    /// in the format : ENCRYPTED_MSG | AEAD_TAG
312    ///
313    /// ```
314    /// use cryptoxide::chacha20poly1305::ChaCha20Poly1305;
315    ///
316    /// let key : [u8; 16] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
317    /// let nonce : [u8; 12] = [1,2,3,4,5,6,7,8,9,10,11,12];
318    /// let aad : [u8; 0] = [];
319    /// let input : &[u8; 12] = b"hello world!";
320    /// let mut out : [u8; 12+16] = [0u8; 12+16];
321    /// let mut tag : [u8; 16] = [0u8; 16];
322    ///
323    /// // create a new cipher
324    /// let mut cipher = ChaCha20Poly1305::new(&key, &nonce, &aad);
325    ///
326    /// // encrypt the msg and append the tag at the end
327    /// cipher.encrypt(input, &mut out[0..12], &mut tag);
328    /// out[12..].copy_from_slice(&tag);
329    /// ```
330    pub fn encrypt(&mut self, input: &[u8], output: &mut [u8], out_tag: &mut [u8]) {
331        assert!(input.len() == output.len());
332        assert!(!self.finished);
333        assert!(out_tag.len() == 16);
334
335        self.finished = true;
336
337        let mut ctx = self.context.clone().to_encryption();
338        ctx.encrypt(input, output);
339
340        let Tag(tag) = ctx.finalize();
341        out_tag.copy_from_slice(&tag[..])
342    }
343
344    /// Decrypt the input to the output buffer
345    ///
346    /// if the calculated tag during decryption doesn't match
347    /// the tag in parameter, then the function return False
348    ///
349    /// Example: Decrypt a simple message with chacha20poly1305 AEAD
350    /// using a 64 bits nonce and a 128 bits keys where the first 12 bytes
351    /// are the encrypted message and the tag is the last 16 bytes. if the
352    /// cipher message has been tempered, a panic is raised (in the example):
353    ///
354    /// ```
355    /// use cryptoxide::chacha20poly1305::ChaCha20Poly1305;
356    ///
357    /// let key : [u8; 16] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
358    /// let nonce : [u8; 12] = [1,2,3,4,5,6,7,8,9,10,11,12];
359    /// let aad : [u8; 0] = [];
360    /// let ae_msg : [u8; 12+16] = [108, 82, 26, 254, 225, 35, 236, 248, 197, 246, 224, 48, 26, 63, 45, 5, 196, 47, 207, 128, 34, 182, 149, 185, 193, 73, 147, 29];
361    /// let mut decrypt_msg : [u8; 12] = [0u8; 12];
362    ///
363    /// // create a new cipher
364    /// let mut cipher = ChaCha20Poly1305::new(&key, &nonce, &aad);
365    ///
366    /// // encrypt the msg and append the tag at the end
367    /// if !cipher.decrypt(&ae_msg[0..12], &mut decrypt_msg, &ae_msg[12..]) {
368    ///     panic!("encrypted message has been tempered")
369    /// }
370    /// assert_eq!(&decrypt_msg, b"hello world!");
371    ///
372    /// ```
373    pub fn decrypt(&mut self, input: &[u8], output: &mut [u8], tag: &[u8]) -> bool {
374        assert!(tag.len() == 16);
375        assert!(input.len() == output.len());
376        assert!(!self.finished);
377
378        self.finished = true;
379
380        let mut tag_data = [0u8; 16];
381        tag_data.copy_from_slice(tag);
382
383        let mut ctx = self.context.clone().to_decryption();
384
385        ctx.decrypt(input, output);
386        ctx.finalize(&Tag(tag_data)) == DecryptionResult::Match
387    }
388}
389
390#[cfg(test)]
391mod test {
392    use super::ChaCha20Poly1305;
393
394    struct TestVector {
395        key: [u8; 32],
396        nonce: [u8; 12],
397        tag: [u8; 16],
398        plain_text: &'static [u8],
399        cipher_text: &'static [u8],
400        aad: &'static [u8],
401    }
402
403    fn test_vector(v: &TestVector) {
404        let mut tag = [0u8; 16];
405        let mut ciphertext = vec![0u8; v.cipher_text.len()];
406
407        let mut context = ChaCha20Poly1305::new(&v.key, &v.nonce, &v.aad);
408        let mut dcontext = context.clone();
409
410        // test encryption
411        context.encrypt(&v.plain_text, &mut ciphertext, &mut tag[..]);
412
413        assert_eq!(&ciphertext[..], &v.cipher_text[..]);
414        assert_eq!(&tag[..], &v.tag[..]);
415
416        // test decryption
417        let mut output = vec![0u8; v.plain_text.len()];
418        assert_eq!(dcontext.decrypt(&ciphertext, &mut output, &v.tag[..]), true);
419
420        assert_eq!(&output[..], &v.plain_text[..]);
421    }
422
423    #[test]
424    fn test_vectors() {
425        let tests = [
426            // RFC 7539 section 2.8.2.
427            TestVector {
428                key: [
429                    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c,
430                    0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
431                    0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
432                ],
433                nonce: [
434                    0x07, 0x00, 0x00, 0x00, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
435                ],
436                plain_text: &[
437                    0x4c, 0x61, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x65,
438                    0x6e, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68,
439                    0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x27, 0x39,
440                    0x39, 0x3a, 0x20, 0x49, 0x66, 0x20, 0x49, 0x20, 0x63, 0x6f, 0x75, 0x6c, 0x64,
441                    0x20, 0x6f, 0x66, 0x66, 0x65, 0x72, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x6f, 0x6e,
442                    0x6c, 0x79, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x74, 0x69, 0x70, 0x20, 0x66, 0x6f,
443                    0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x75, 0x74, 0x75, 0x72, 0x65, 0x2c,
444                    0x20, 0x73, 0x75, 0x6e, 0x73, 0x63, 0x72, 0x65, 0x65, 0x6e, 0x20, 0x77, 0x6f,
445                    0x75, 0x6c, 0x64, 0x20, 0x62, 0x65, 0x20, 0x69, 0x74, 0x2e,
446                ],
447                aad: &[
448                    0x50, 0x51, 0x52, 0x53, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
449                ],
450                cipher_text: &[
451                    0xd3, 0x1a, 0x8d, 0x34, 0x64, 0x8e, 0x60, 0xdb, 0x7b, 0x86, 0xaf, 0xbc, 0x53,
452                    0xef, 0x7e, 0xc2, 0xa4, 0xad, 0xed, 0x51, 0x29, 0x6e, 0x08, 0xfe, 0xa9, 0xe2,
453                    0xb5, 0xa7, 0x36, 0xee, 0x62, 0xd6, 0x3d, 0xbe, 0xa4, 0x5e, 0x8c, 0xa9, 0x67,
454                    0x12, 0x82, 0xfa, 0xfb, 0x69, 0xda, 0x92, 0x72, 0x8b, 0x1a, 0x71, 0xde, 0x0a,
455                    0x9e, 0x06, 0x0b, 0x29, 0x05, 0xd6, 0xa5, 0xb6, 0x7e, 0xcd, 0x3b, 0x36, 0x92,
456                    0xdd, 0xbd, 0x7f, 0x2d, 0x77, 0x8b, 0x8c, 0x98, 0x03, 0xae, 0xe3, 0x28, 0x09,
457                    0x1b, 0x58, 0xfa, 0xb3, 0x24, 0xe4, 0xfa, 0xd6, 0x75, 0x94, 0x55, 0x85, 0x80,
458                    0x8b, 0x48, 0x31, 0xd7, 0xbc, 0x3f, 0xf4, 0xde, 0xf0, 0x8e, 0x4b, 0x7a, 0x9d,
459                    0xe5, 0x76, 0xd2, 0x65, 0x86, 0xce, 0xc6, 0x4b, 0x61, 0x16,
460                ],
461                tag: [
462                    0x1a, 0xe1, 0x0b, 0x59, 0x4f, 0x09, 0xe2, 0x6a, 0x7e, 0x90, 0x2e, 0xcb, 0xd0,
463                    0x60, 0x06, 0x91,
464                ],
465            },
466            // RFC 7539 section A.5.
467            TestVector {
468                key: [
469                    0x1c, 0x92, 0x40, 0xa5, 0xeb, 0x55, 0xd3, 0x8a, 0xf3, 0x33, 0x88, 0x86, 0x04,
470                    0xf6, 0xb5, 0xf0, 0x47, 0x39, 0x17, 0xc1, 0x40, 0x2b, 0x80, 0x09, 0x9d, 0xca,
471                    0x5c, 0xbc, 0x20, 0x70, 0x75, 0xc0,
472                ],
473                nonce: [
474                    0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
475                ],
476                tag: [
477                    0xee, 0xad, 0x9d, 0x67, 0x89, 0x0c, 0xbb, 0x22, 0x39, 0x23, 0x36, 0xfe, 0xa1,
478                    0x85, 0x1f, 0x38,
479                ],
480                plain_text: &[
481                    0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44, 0x72, 0x61, 0x66,
482                    0x74, 0x73, 0x20, 0x61, 0x72, 0x65, 0x20, 0x64, 0x72, 0x61, 0x66, 0x74, 0x20,
483                    0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x76, 0x61, 0x6c,
484                    0x69, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x61, 0x20, 0x6d, 0x61, 0x78, 0x69,
485                    0x6d, 0x75, 0x6d, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x69, 0x78, 0x20, 0x6d, 0x6f,
486                    0x6e, 0x74, 0x68, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x61, 0x79, 0x20,
487                    0x62, 0x65, 0x20, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x2c, 0x20, 0x72,
488                    0x65, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x2c, 0x20, 0x6f, 0x72, 0x20, 0x6f,
489                    0x62, 0x73, 0x6f, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x6f,
490                    0x74, 0x68, 0x65, 0x72, 0x20, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, 0x6e, 0x74,
491                    0x73, 0x20, 0x61, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x74, 0x69, 0x6d, 0x65,
492                    0x2e, 0x20, 0x49, 0x74, 0x20, 0x69, 0x73, 0x20, 0x69, 0x6e, 0x61, 0x70, 0x70,
493                    0x72, 0x6f, 0x70, 0x72, 0x69, 0x61, 0x74, 0x65, 0x20, 0x74, 0x6f, 0x20, 0x75,
494                    0x73, 0x65, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x2d, 0x44,
495                    0x72, 0x61, 0x66, 0x74, 0x73, 0x20, 0x61, 0x73, 0x20, 0x72, 0x65, 0x66, 0x65,
496                    0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6d, 0x61, 0x74, 0x65, 0x72, 0x69, 0x61,
497                    0x6c, 0x20, 0x6f, 0x72, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x69, 0x74, 0x65, 0x20,
498                    0x74, 0x68, 0x65, 0x6d, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x74, 0x68,
499                    0x61, 0x6e, 0x20, 0x61, 0x73, 0x20, 0x2f, 0xe2, 0x80, 0x9c, 0x77, 0x6f, 0x72,
500                    0x6b, 0x20, 0x69, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73,
501                    0x2e, 0x2f, 0xe2, 0x80, 0x9d,
502                ],
503                cipher_text: &[
504                    0x64, 0xa0, 0x86, 0x15, 0x75, 0x86, 0x1a, 0xf4, 0x60, 0xf0, 0x62, 0xc7, 0x9b,
505                    0xe6, 0x43, 0xbd, 0x5e, 0x80, 0x5c, 0xfd, 0x34, 0x5c, 0xf3, 0x89, 0xf1, 0x08,
506                    0x67, 0x0a, 0xc7, 0x6c, 0x8c, 0xb2, 0x4c, 0x6c, 0xfc, 0x18, 0x75, 0x5d, 0x43,
507                    0xee, 0xa0, 0x9e, 0xe9, 0x4e, 0x38, 0x2d, 0x26, 0xb0, 0xbd, 0xb7, 0xb7, 0x3c,
508                    0x32, 0x1b, 0x01, 0x00, 0xd4, 0xf0, 0x3b, 0x7f, 0x35, 0x58, 0x94, 0xcf, 0x33,
509                    0x2f, 0x83, 0x0e, 0x71, 0x0b, 0x97, 0xce, 0x98, 0xc8, 0xa8, 0x4a, 0xbd, 0x0b,
510                    0x94, 0x81, 0x14, 0xad, 0x17, 0x6e, 0x00, 0x8d, 0x33, 0xbd, 0x60, 0xf9, 0x82,
511                    0xb1, 0xff, 0x37, 0xc8, 0x55, 0x97, 0x97, 0xa0, 0x6e, 0xf4, 0xf0, 0xef, 0x61,
512                    0xc1, 0x86, 0x32, 0x4e, 0x2b, 0x35, 0x06, 0x38, 0x36, 0x06, 0x90, 0x7b, 0x6a,
513                    0x7c, 0x02, 0xb0, 0xf9, 0xf6, 0x15, 0x7b, 0x53, 0xc8, 0x67, 0xe4, 0xb9, 0x16,
514                    0x6c, 0x76, 0x7b, 0x80, 0x4d, 0x46, 0xa5, 0x9b, 0x52, 0x16, 0xcd, 0xe7, 0xa4,
515                    0xe9, 0x90, 0x40, 0xc5, 0xa4, 0x04, 0x33, 0x22, 0x5e, 0xe2, 0x82, 0xa1, 0xb0,
516                    0xa0, 0x6c, 0x52, 0x3e, 0xaf, 0x45, 0x34, 0xd7, 0xf8, 0x3f, 0xa1, 0x15, 0x5b,
517                    0x00, 0x47, 0x71, 0x8c, 0xbc, 0x54, 0x6a, 0x0d, 0x07, 0x2b, 0x04, 0xb3, 0x56,
518                    0x4e, 0xea, 0x1b, 0x42, 0x22, 0x73, 0xf5, 0x48, 0x27, 0x1a, 0x0b, 0xb2, 0x31,
519                    0x60, 0x53, 0xfa, 0x76, 0x99, 0x19, 0x55, 0xeb, 0xd6, 0x31, 0x59, 0x43, 0x4e,
520                    0xce, 0xbb, 0x4e, 0x46, 0x6d, 0xae, 0x5a, 0x10, 0x73, 0xa6, 0x72, 0x76, 0x27,
521                    0x09, 0x7a, 0x10, 0x49, 0xe6, 0x17, 0xd9, 0x1d, 0x36, 0x10, 0x94, 0xfa, 0x68,
522                    0xf0, 0xff, 0x77, 0x98, 0x71, 0x30, 0x30, 0x5b, 0xea, 0xba, 0x2e, 0xda, 0x04,
523                    0xdf, 0x99, 0x7b, 0x71, 0x4d, 0x6c, 0x6f, 0x2c, 0x29, 0xa6, 0xad, 0x5c, 0xb4,
524                    0x02, 0x2b, 0x02, 0x70, 0x9b,
525                ],
526                aad: &[
527                    0xf3, 0x33, 0x88, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4e, 0x91,
528                ],
529            },
530        ];
531        for tv in tests.iter() {
532            test_vector(&tv)
533        }
534    }
535}
536
537#[cfg(all(test, feature = "with-bench"))]
538mod bench {
539    use super::ChaCha20Poly1305;
540    use test::Bencher;
541
542    #[bench]
543    pub fn chacha20poly1305_10(bh: &mut Bencher) {
544        let input = [1u8; 10];
545        let aad = [3u8; 10];
546        bh.iter(|| {
547            let mut cipher = ChaCha20Poly1305::new(&[0; 32], &[0; 12], &aad);
548            let mut decipher = ChaCha20Poly1305::new(&[0; 32], &[0; 12], &aad);
549
550            let mut output = [0u8; 10];
551            let mut tag = [0u8; 16];
552            let mut output2 = [0u8; 10];
553            cipher.encrypt(&input, &mut output, &mut tag);
554            decipher.decrypt(&output, &mut output2, &tag);
555        });
556        bh.bytes = 10u64;
557    }
558
559    #[bench]
560    pub fn chacha20poly1305_1k(bh: &mut Bencher) {
561        let input = [1u8; 1024];
562        let aad = [3u8; 1024];
563        bh.iter(|| {
564            let mut cipher = ChaCha20Poly1305::new(&[0; 32], &[0; 12], &aad);
565            let mut decipher = ChaCha20Poly1305::new(&[0; 32], &[0; 12], &aad);
566
567            let mut output = [0u8; 1024];
568            let mut tag = [0u8; 16];
569            let mut output2 = [0u8; 1024];
570
571            cipher.encrypt(&input, &mut output, &mut tag);
572            decipher.decrypt(&output, &mut output2, &tag);
573        });
574        bh.bytes = 1024u64;
575    }
576
577    #[bench]
578    pub fn chacha20poly1305_64k(bh: &mut Bencher) {
579        let input = [1u8; 65536];
580        let aad = [3u8; 65536];
581        bh.iter(|| {
582            let mut cipher = ChaCha20Poly1305::new(&[0; 32], &[0; 12], &aad);
583            let mut decipher = ChaCha20Poly1305::new(&[0; 32], &[0; 12], &aad);
584
585            let mut output = [0u8; 65536];
586            let mut tag = [0u8; 16];
587            let mut output2 = [0u8; 65536];
588
589            cipher.encrypt(&input, &mut output, &mut tag);
590            decipher.decrypt(&output, &mut output2, &tag);
591        });
592        bh.bytes = 65536u64;
593    }
594}