1// Copyright 2015-2021 Brian Smith.
2//
3// Permission to use, copy, modify, and/or distribute this software for any
4// purpose with or without fee is hereby granted, provided that the above
5// copyright notice and this permission notice appear in all copies.
6//
7// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
10// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14
15//! Authenticated Encryption with Associated Data (AEAD).
16//!
17//! See [Authenticated encryption: relations among notions and analysis of the
18//! generic composition paradigm][AEAD] for an introduction to the concept of
19//! AEADs.
20//!
21//! [AEAD]: https://eprint.iacr.org/2000/025.pdf
22//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD
23
24use crate::{
25 cpu, error, hkdf,
26 polyfill::{u64_from_usize, usize_from_u64_saturated},
27};
28use core::ops::RangeFrom;
29
30pub use self::{
31 aes_gcm::{AES_128_GCM, AES_256_GCM},
32 chacha20_poly1305::CHACHA20_POLY1305,
33 less_safe_key::LessSafeKey,
34 nonce::{Nonce, NONCE_LEN},
35 opening_key::OpeningKey,
36 sealing_key::SealingKey,
37 unbound_key::UnboundKey,
38};
39
40/// A sequences of unique nonces.
41///
42/// A given `NonceSequence` must never return the same `Nonce` twice from
43/// `advance()`.
44///
45/// A simple counter is a reasonable (but probably not ideal) `NonceSequence`.
46///
47/// Intentionally not `Clone` or `Copy` since cloning would allow duplication
48/// of the sequence.
49pub trait NonceSequence {
50 /// Returns the next nonce in the sequence.
51 ///
52 /// This may fail if "too many" nonces have been requested, where how many
53 /// is too many is up to the implementation of `NonceSequence`. An
54 /// implementation may that enforce a maximum number of records are
55 /// sent/received under a key this way. Once `advance()` fails, it must
56 /// fail for all subsequent calls.
57 fn advance(&mut self) -> Result<Nonce, error::Unspecified>;
58}
59
60/// An AEAD key bound to a nonce sequence.
61pub trait BoundKey<N: NonceSequence>: core::fmt::Debug {
62 /// Constructs a new key from the given `UnboundKey` and `NonceSequence`.
63 fn new(key: UnboundKey, nonce_sequence: N) -> Self;
64
65 /// The key's AEAD algorithm.
66 fn algorithm(&self) -> &'static Algorithm;
67}
68
69/// The additionally authenticated data (AAD) for an opening or sealing
70/// operation. This data is authenticated but is **not** encrypted.
71///
72/// The type `A` could be a byte slice `&[u8]`, a byte array `[u8; N]`
73/// for some constant `N`, `Vec<u8>`, etc.
74#[derive(Clone, Copy)]
75pub struct Aad<A>(A);
76
77impl<A: AsRef<[u8]>> Aad<A> {
78 /// Construct the `Aad` from the given bytes.
79 #[inline]
80 pub fn from(aad: A) -> Self {
81 Self(aad)
82 }
83}
84
85impl<A> AsRef<[u8]> for Aad<A>
86where
87 A: AsRef<[u8]>,
88{
89 fn as_ref(&self) -> &[u8] {
90 self.0.as_ref()
91 }
92}
93
94impl Aad<[u8; 0]> {
95 /// Construct an empty `Aad`.
96 pub fn empty() -> Self {
97 Self::from([])
98 }
99}
100
101impl<A> core::fmt::Debug for Aad<A>
102where
103 A: core::fmt::Debug,
104{
105 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
106 f.debug_tuple(name:"Aad").field(&self.0).finish()
107 }
108}
109
110impl<A> PartialEq for Aad<A>
111where
112 A: PartialEq,
113{
114 #[inline]
115 fn eq(&self, other: &Self) -> bool {
116 self.0.eq(&other.0)
117 }
118}
119
120impl<A> Eq for Aad<A> where A: Eq {}
121
122#[allow(clippy::large_enum_variant, variant_size_differences)]
123#[derive(Clone)]
124enum KeyInner {
125 AesGcm(aes_gcm::Key),
126 ChaCha20Poly1305(chacha20_poly1305::Key),
127}
128
129impl hkdf::KeyType for &'static Algorithm {
130 #[inline]
131 fn len(&self) -> usize {
132 self.key_len()
133 }
134}
135
136/// An AEAD Algorithm.
137pub struct Algorithm {
138 init: fn(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified>,
139
140 seal: fn(
141 key: &KeyInner,
142 nonce: Nonce,
143 aad: Aad<&[u8]>,
144 in_out: &mut [u8],
145 cpu_features: cpu::Features,
146 ) -> Result<Tag, error::Unspecified>,
147 open: fn(
148 key: &KeyInner,
149 nonce: Nonce,
150 aad: Aad<&[u8]>,
151 in_out: &mut [u8],
152 src: RangeFrom<usize>,
153 cpu_features: cpu::Features,
154 ) -> Result<Tag, error::Unspecified>,
155
156 key_len: usize,
157 id: AlgorithmID,
158}
159
160const fn max_input_len(block_len: usize, overhead_blocks_per_nonce: usize) -> usize {
161 // Each of our AEADs use a 32-bit block counter so the maximum is the
162 // largest input that will not overflow the counter.
163 usize_from_u64_saturated(
164 ((1u64 << 32) - u64_from_usize(overhead_blocks_per_nonce)) * u64_from_usize(block_len),
165 )
166}
167
168impl Algorithm {
169 /// The length of the key.
170 #[inline(always)]
171 pub fn key_len(&self) -> usize {
172 self.key_len
173 }
174
175 /// The length of a tag.
176 ///
177 /// See also `MAX_TAG_LEN`.
178 #[inline(always)]
179 pub fn tag_len(&self) -> usize {
180 TAG_LEN
181 }
182
183 /// The length of the nonces.
184 #[inline(always)]
185 pub fn nonce_len(&self) -> usize {
186 NONCE_LEN
187 }
188}
189
190derive_debug_via_id!(Algorithm);
191
192#[derive(Debug, Eq, PartialEq)]
193enum AlgorithmID {
194 AES_128_GCM,
195 AES_256_GCM,
196 CHACHA20_POLY1305,
197}
198
199impl PartialEq for Algorithm {
200 fn eq(&self, other: &Self) -> bool {
201 self.id == other.id
202 }
203}
204
205impl Eq for Algorithm {}
206
207/// A possibly valid authentication tag.
208#[must_use]
209#[repr(C)]
210#[derive(Clone, Copy)]
211pub struct Tag([u8; TAG_LEN]);
212
213impl AsRef<[u8]> for Tag {
214 fn as_ref(&self) -> &[u8] {
215 self.0.as_ref()
216 }
217}
218
219impl TryFrom<&[u8]> for Tag {
220 type Error = error::Unspecified;
221
222 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
223 let raw_tag: [u8; TAG_LEN] = value.try_into().map_err(|_| error::Unspecified)?;
224 Ok(Self::from(raw_tag))
225 }
226}
227
228impl From<[u8; TAG_LEN]> for Tag {
229 #[inline]
230 fn from(value: [u8; TAG_LEN]) -> Self {
231 Self(value)
232 }
233}
234
235const MAX_KEY_LEN: usize = 32;
236
237// All the AEADs we support use 128-bit tags.
238const TAG_LEN: usize = 16;
239
240/// The maximum length of a tag for the algorithms in this module.
241pub const MAX_TAG_LEN: usize = TAG_LEN;
242
243mod aes;
244mod aes_gcm;
245mod block;
246mod chacha;
247mod chacha20_poly1305;
248pub mod chacha20_poly1305_openssh;
249mod gcm;
250mod less_safe_key;
251mod nonce;
252mod opening_key;
253mod poly1305;
254pub mod quic;
255mod sealing_key;
256mod shift;
257mod unbound_key;
258