aes256ctr_poly1305aes/lib.rs
1//! [`Aes256CtrPoly1305Aes`] is an [Authenticated Encryption with Associated Data
2//! (AEAD)][2] cipher amenable to fast, constant-time implementations in software,
3//! based on the [AES256-CTR][3] stream cipher and the [Poly1305-AES MAC] [4]
4//! which uses the [Poly1305][5] universal hash function in combination with the
5//! [AES-128][6] block cipher.
6//!
7//! A lot code is copied from the [chacha20poly1305 crate][7]
8//!
9//! This crate contains pure Rust implementations of [`Aes256CtrPoly1305Aes`]
10//! (with optional AVX2 acceleration) as well as the following variants thereof:
11//!
12//! All implementations contained in the crate are designed to execute in
13//! constant time, either by relying on hardware intrinsics (i.e. AVX2 on
14//! x86/x86_64), or using a portable implementation which is only constant time
15//! on processors which implement constant-time multiplication.
16//!
17//! It is not suitable for use on processors with a variable-time multiplication
18//! operation (e.g. short circuit on multiply-by-zero / multiply-by-one, such as
19//! certain 32-bit PowerPC CPUs and some non-ARM microcontrollers).
20//!
21//! # Usage
22//!
23//! ```
24//! # #[cfg(feature = "alloc")]
25//! # {
26//! use aes256ctr_poly1305aes::{Aes256CtrPoly1305Aes, Key, Nonce};
27//! use aes256ctr_poly1305aes::aead::Aead;
28//!
29//! // 64 bytes key
30//! let key = Key::from_slice(b"This is an example of a very secret key. Keep it always secret!!");
31//! let cipher = Aes256CtrPoly1305Aes::new(key);
32//!
33//! let nonce = Nonce::from_slice(b"my unique nonce!"); // 16-bytes; unique per message
34//!
35//! let ciphertext = cipher.encrypt(nonce, b"plaintext message".as_ref())
36//! .expect("encryption failure!"); // NOTE: handle this error to avoid panics!
37//! let plaintext = cipher.decrypt(nonce, ciphertext.as_ref())
38//! .expect("decryption failure!"); // NOTE: handle this error to avoid panics!
39//!
40//! assert_eq!(&plaintext, b"plaintext message");
41//! # }
42//! ```
43//!
44//! ## In-place Usage (eliminates `alloc` requirement)
45//!
46//! This crate has an optional `alloc` feature which can be disabled in e.g.
47//! microcontroller environments that don't have a heap.
48//!
49//! The [`AeadInPlace::encrypt_in_place`] and [`AeadInPlace::decrypt_in_place`]
50//! methods accept any type that impls the [`aead::Buffer`] trait which
51//! contains the plaintext for encryption or ciphertext for decryption.
52//!
53//! Note that if you enable the `heapless` feature of this crate,
54//! you will receive an impl of [`aead::Buffer`] for `heapless::Vec`
55//! (re-exported from the [`aead`] crate as [`aead::heapless::Vec`]),
56//! which can then be passed as the `buffer` parameter to the in-place encrypt
57//! and decrypt methods:
58//!
59//! ```
60//! # #[cfg(feature = "heapless")]
61//! # {
62//! use aes256ctr_poly1305aes::{Aes256CtrPoly1305Aes, Key, Nonce};
63//! use aes256ctr_poly1305aes::aead::{AeadInPlace, NewAead};
64//! use aes256ctr_poly1305aes::aead::heapless::Vec;
65//!
66//! // 64 bytes key
67//! let key = Key::from_slice(b"This is an example of a very secret key. Keep it always secret!!");
68//! let cipher = Aes256CtrPoly1305Aes::new(key);
69//!
70//! let nonce = Nonce::from_slice(b"my unique nonce!"); // 16-bytes; unique per message
71//!
72//! let mut buffer: Vec<u8, 128> = Vec::new();
73//! buffer.extend_from_slice(b"plaintext message");
74//!
75//! // Encrypt `buffer` in-place, replacing the plaintext contents with ciphertext
76//! cipher.encrypt_in_place(nonce, b"", &mut buffer).expect("encryption failure!");
77//!
78//! // `buffer` now contains the message ciphertext
79//! assert_ne!(&buffer, b"plaintext message");
80//!
81//! // Decrypt `buffer` in-place, replacing its ciphertext context with the original plaintext
82//! cipher.decrypt_in_place(nonce, b"", &mut buffer).expect("decryption failure!");
83//! assert_eq!(&buffer, b"plaintext message");
84//! # }
85//! ```
86//!
87//! [1]: https://tools.ietf.org/html/rfc8439
88//! [2]: https://en.wikipedia.org/wiki/Authenticated_encryption
89//! [3]: https://docs.rs/aes/latest/aes/struct.Aes256Ctr.html
90//! [4]: https://cr.yp.to/mac/poly1305-20050329.pdf
91//! [5]: https://github.com/RustCrypto/universal-hashes/tree/master/poly1305
92//! [6]: https://docs.rs/aes/latest/aes/struct.Aes128.html
93//! [7]: https://crates.io/crates/chacha20poly1305
94
95#![no_std]
96#![cfg_attr(docsrs, feature(doc_cfg))]
97#![doc(
98 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
99 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
100)]
101#![warn(missing_docs, rust_2018_idioms)]
102
103mod cipher;
104
105pub use aead;
106
107use self::cipher::Cipher;
108use aead::{
109 consts::{U0, U16, U32, U64},
110 generic_array::GenericArray,
111 AeadCore, AeadInPlace, Error, KeyInit,
112};
113use ctr::Ctr64BE;
114use zeroize::Zeroize;
115
116use ::cipher::{BlockEncrypt, KeyIvInit};
117use aes::{Aes128, Aes256};
118use poly1305::Poly1305;
119
120type Aes256Ctr = Ctr64BE<Aes256>;
121
122/// Key type (512-bits/64-bytes).
123///
124/// Implemented as an alias for [`GenericArray`].
125pub type Key = GenericArray<u8, U64>;
126
127/// Nonce type (128-bits/16-bytes).
128///
129/// Implemented as an alias for [`GenericArray`].
130pub type Nonce = GenericArray<u8, U16>;
131
132/// Poly1305 tag.
133///
134/// Implemented as an alias for [`GenericArray`].
135pub type Tag = GenericArray<u8, U16>;
136
137/// Authenticated Encryption with Additional Data (AEAD) using AES256-CTR and Poly1305-AES.
138///
139/// See the [toplevel documentation](index.html) for a usage example.
140#[derive(Clone, Debug)]
141pub struct Aes256CtrPoly1305Aes {
142 /// Secret key for Aes256Ctr
143 aes256ctr_key: GenericArray<u8, U32>,
144
145 /// Secret key for Aes128r
146 aes128_key: GenericArray<u8, U16>,
147
148 /// Secret value r for Poly1305
149 poly1305_r: GenericArray<u8, U16>,
150}
151
152impl Aes256CtrPoly1305Aes {
153 fn cipher_from_nonce(&self, nonce: &aead::Nonce<Self>) -> Cipher<Aes256Ctr> {
154 // Derive Poly1305 key from r and AES_k(nonce)
155 let mut mac_key = poly1305::Key::default();
156 mac_key[0..16].copy_from_slice(&self.poly1305_r);
157
158 let mut block = *nonce;
159 Aes128::new(&self.aes128_key).encrypt_block(&mut block);
160 mac_key[16..32].copy_from_slice(&block);
161 block.zeroize();
162
163 let cipher = Cipher::new(
164 <Aes256Ctr as KeyIvInit>::new(&self.aes256ctr_key, nonce),
165 Poly1305::new(&mac_key),
166 );
167 mac_key.zeroize();
168 cipher
169 }
170
171 /// New AEAD using AES256-CTR and Poly1305-AES from the given 64-byte key.
172 /// The first 32 bytes are used as key for AES256-CTR.
173 /// The following 16 bytes are used as key for the AES128 used in Poly1305-AES.
174 /// The last 16 bytes are used as r in Poly1305-AES.
175 pub fn new(key: &Key) -> Self {
176 Self {
177 aes256ctr_key: GenericArray::clone_from_slice(&key[0..32]),
178 aes128_key: GenericArray::clone_from_slice(&key[32..48]),
179 poly1305_r: GenericArray::clone_from_slice(&key[48..64]),
180 }
181 }
182}
183
184impl AeadCore for Aes256CtrPoly1305Aes {
185 type NonceSize = U16;
186 type TagSize = U16;
187 type CiphertextOverhead = U0;
188}
189
190impl AeadInPlace for Aes256CtrPoly1305Aes {
191 fn encrypt_in_place_detached(
192 &self,
193 nonce: &aead::Nonce<Self>,
194 associated_data: &[u8],
195 buffer: &mut [u8],
196 ) -> Result<Tag, Error> {
197 self.cipher_from_nonce(nonce)
198 .encrypt_in_place_detached(associated_data, buffer)
199 }
200
201 fn decrypt_in_place_detached(
202 &self,
203 nonce: &aead::Nonce<Self>,
204 associated_data: &[u8],
205 buffer: &mut [u8],
206 tag: &Tag,
207 ) -> Result<(), Error> {
208 self.cipher_from_nonce(nonce)
209 .decrypt_in_place_detached(associated_data, buffer, tag)
210 }
211}
212
213impl Drop for Aes256CtrPoly1305Aes {
214 fn drop(&mut self) {
215 self.aes256ctr_key.as_mut_slice().zeroize();
216 self.aes128_key.as_mut_slice().zeroize();
217 self.poly1305_r.as_mut_slice().zeroize();
218 }
219}