chacha20_poly1305_stream/
lib.rs

1// Copyright 2016 chacha20-poly1305-aead Developers
2// Copyright 2016 chacha20-poly1305-stream Developers
3//
4// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
5// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
6// http://opensource.org/licenses/MIT>, at your option. This file may not be
7// copied, modified, or distributed except according to those terms.
8
9//! A pure Rust implementation of the ChaCha20-Poly1305 AEAD from RFC 7539.
10//!
11//! An Authenticated Encryption with Associated Data (AEAD) mode
12//! encrypts data and generates an authentication tag, or decrypts data
13//! and verifies an authentication tag, as a single operation. The tag
14//! can also validate additional authenticated data (AAD) which is not
15//! included in the cyphertext, for instance a plaintext header.
16//!
17//! The ChaCha20-Poly1305 AEAD uses a 256-bit (32-byte) key, and a
18//! 96-bit (12-byte) nonce. For each key, a given nonce should be used
19//! only once, otherwise the encryption and authentication can be
20//! broken. One way to prevent reuse is for the nonce to contain a
21//! sequence number.
22//!
23//! The amount of data that can be encrypted in a single call is 2^32 - 1
24//! blocks of 64 bytes, slightly less than 256 GiB.
25
26#![warn(missing_docs)]
27
28#![cfg_attr(feature = "clippy", feature(plugin))]
29#![cfg_attr(feature = "clippy", plugin(clippy))]
30#![cfg_attr(feature = "clippy", warn(clippy_pedantic))]
31
32#![cfg_attr(all(feature = "bench", test), feature(test))]
33#![cfg_attr(feature = "simd", feature(platform_intrinsics, repr_simd))]
34#![cfg_attr(feature = "simd_opt", feature(cfg_target_feature))]
35
36extern crate constant_time_eq;
37#[cfg(all(feature = "bench", test))]
38extern crate test;
39
40pub use stream_decryptor::ChaCha20Poly1305StreamDecryptor;
41pub use stream_encryptor::ChaCha20Poly1305StreamEncryptor;
42
43mod as_bytes;
44
45mod simdty;
46mod simdint;
47mod simdop;
48mod simd_opt;
49mod simd;
50
51mod chacha20;
52mod poly1305;
53// mod aead;
54mod stream_util;
55mod stream_encryptor;
56mod stream_decryptor;
57
58/// ChaCha20Policy Encrypt
59pub fn chacha20_poly1305_encrypt(key: &[u8], nonce: &[u8], message: &[u8]) -> Result<Vec<u8>, String> {
60    chacha20_poly1305_aad_encrypt(key, nonce, &[], message)
61}
62
63/// ChaCha20Policy Decrypt
64pub fn chacha20_poly1305_decrypt(key: &[u8], nonce: &[u8], message: &[u8]) -> Result<Vec<u8>, String> {
65    chacha20_poly1305_aad_decrypt(key, nonce, &[], message)
66}
67
68/// ChaCha20Policy Encrypt with AAD
69pub fn chacha20_poly1305_aad_encrypt(key: &[u8], nonce: &[u8], aad: &[u8], message: &[u8]) -> Result<Vec<u8>, String> {
70    let mut encryptor = ChaCha20Poly1305StreamEncryptor::new(key, nonce)?;
71    if !aad.is_empty() { encryptor.init_adata(aad); }
72    let mut b1 = encryptor.update(message);
73    let (last_block, tag) = encryptor.finalize();
74    b1.extend_from_slice(&last_block);
75    b1.extend_from_slice(&tag);
76    Ok(b1)
77}
78
79/// ChaCha20Policy Decrypt with AAD
80pub fn chacha20_poly1305_aad_decrypt(key: &[u8], nonce: &[u8], aad: &[u8], message: &[u8]) -> Result<Vec<u8>, String> {
81    let mut decryptor = ChaCha20Poly1305StreamDecryptor::new(key, nonce)?;
82    if !aad.is_empty() { decryptor.init_adata(aad); }
83    let mut b1 = decryptor.update(message);
84    let last_block = decryptor.finalize()?;
85    b1.extend_from_slice(&last_block);
86    Ok(b1)
87}
88
89/// Runs the self-test for ChaCha20, Poly1305
90#[cold]
91pub fn selftest() {
92    chacha20::selftest();
93    poly1305::selftest();
94}
95
96#[test]
97fn test_enc_dec() {
98    let key = [0u8; 32];
99    let nonce = [0u8; 12];
100    let aad = b"hello world";
101    let plaintext = [0u8; 1000];
102
103    let ciphertext = chacha20_poly1305_aad_encrypt(&key, &nonce, aad, &plaintext).unwrap();
104
105    let mut output = vec![];
106    let mut plaintext = plaintext.to_vec();
107    let tag = chacha20_poly1305_aead::encrypt(
108        &key, &nonce, &aad[..], &mut plaintext, &mut output).unwrap();
109    output.extend_from_slice(&tag);
110
111    assert_eq!(ciphertext, output);
112
113    let plaintext_decrypted = chacha20_poly1305_aad_decrypt(&key, &nonce, aad, &ciphertext).unwrap();
114    assert_eq!(plaintext, plaintext_decrypted);
115}
116
117#[test]
118fn test_rfc_7539() {
119    let key = hex::decode(
120        "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f").unwrap();
121    let nonce = hex::decode("070000004041424344454647").unwrap();
122    let aad = hex::decode("50515253c0c1c2c3c4c5c6c7").unwrap();
123    let plaintext = hex::decode(
124        "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f6620\
125        2739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666\
126        f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e").unwrap();
127
128    let expected_ciphertext = hex::decode(
129        "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca\
130        9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091\
131        b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116").unwrap();
132    let expected_tag = hex::decode("1ae10b594f09e26a7e902ecbd0600691").unwrap();
133
134    let mut encryptor = ChaCha20Poly1305StreamEncryptor::new(&key, &nonce).unwrap();
135    encryptor.init_adata(&aad);
136    let mut ciphertext = encryptor.update(&plaintext);
137    let (last_block, tag) = encryptor.finalize();
138    ciphertext.extend_from_slice(&last_block);
139
140    assert_eq!(expected_ciphertext, ciphertext);
141    assert_eq!(expected_tag, tag);
142}