• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015-2016 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]: http://www-cse.ucsd.edu/~mihir/papers/oem.html
22 //! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD
23 
24 use self::block::{Block, BLOCK_LEN};
25 use crate::{constant_time, cpu, error, hkdf, polyfill};
26 use core::ops::RangeFrom;
27 
28 pub use self::{
29     aes_gcm::{AES_128_GCM, AES_256_GCM},
30     chacha20_poly1305::CHACHA20_POLY1305,
31     nonce::{Nonce, NONCE_LEN},
32 };
33 
34 /// A sequences of unique nonces.
35 ///
36 /// A given `NonceSequence` must never return the same `Nonce` twice from
37 /// `advance()`.
38 ///
39 /// A simple counter is a reasonable (but probably not ideal) `NonceSequence`.
40 ///
41 /// Intentionally not `Clone` or `Copy` since cloning would allow duplication
42 /// of the sequence.
43 pub trait NonceSequence {
44     /// Returns the next nonce in the sequence.
45     ///
46     /// This may fail if "too many" nonces have been requested, where how many
47     /// is too many is up to the implementation of `NonceSequence`. An
48     /// implementation may that enforce a maximum number of records are
49     /// sent/received under a key this way. Once `advance()` fails, it must
50     /// fail for all subsequent calls.
advance(&mut self) -> Result<Nonce, error::Unspecified>51     fn advance(&mut self) -> Result<Nonce, error::Unspecified>;
52 }
53 
54 /// An AEAD key bound to a nonce sequence.
55 pub trait BoundKey<N: NonceSequence>: core::fmt::Debug {
56     /// Constructs a new key from the given `UnboundKey` and `NonceSequence`.
new(key: UnboundKey, nonce_sequence: N) -> Self57     fn new(key: UnboundKey, nonce_sequence: N) -> Self;
58 
59     /// The key's AEAD algorithm.
algorithm(&self) -> &'static Algorithm60     fn algorithm(&self) -> &'static Algorithm;
61 }
62 
63 /// An AEAD key for authenticating and decrypting ("opening"), bound to a nonce
64 /// sequence.
65 ///
66 /// Intentionally not `Clone` or `Copy` since cloning would allow duplication
67 /// of the nonce sequence.
68 pub struct OpeningKey<N: NonceSequence> {
69     key: UnboundKey,
70     nonce_sequence: N,
71 }
72 
73 impl<N: NonceSequence> BoundKey<N> for OpeningKey<N> {
new(key: UnboundKey, nonce_sequence: N) -> Self74     fn new(key: UnboundKey, nonce_sequence: N) -> Self {
75         Self {
76             key,
77             nonce_sequence,
78         }
79     }
80 
81     #[inline]
algorithm(&self) -> &'static Algorithm82     fn algorithm(&self) -> &'static Algorithm {
83         self.key.algorithm
84     }
85 }
86 
87 impl<N: NonceSequence> core::fmt::Debug for OpeningKey<N> {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>88     fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
89         f.debug_struct("OpeningKey")
90             .field("algorithm", &self.algorithm())
91             .finish()
92     }
93 }
94 
95 impl<N: NonceSequence> OpeningKey<N> {
96     /// Authenticates and decrypts (“opens”) data in place.
97     ///
98     /// `aad` is the additional authenticated data (AAD), if any.
99     ///
100     /// On input, `in_out` must be the ciphertext followed by the tag. When
101     /// `open_in_place()` returns `Ok(plaintext)`, the input ciphertext
102     /// has been overwritten by the plaintext; `plaintext` will refer to the
103     /// plaintext without the tag.
104     ///
105     /// When `open_in_place()` returns `Err(..)`, `in_out` may have been
106     /// overwritten in an unspecified way.
107     #[inline]
open_in_place<'in_out, A>( &mut self, aad: Aad<A>, in_out: &'in_out mut [u8], ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,108     pub fn open_in_place<'in_out, A>(
109         &mut self,
110         aad: Aad<A>,
111         in_out: &'in_out mut [u8],
112     ) -> Result<&'in_out mut [u8], error::Unspecified>
113     where
114         A: AsRef<[u8]>,
115     {
116         self.open_within(aad, in_out, 0..)
117     }
118 
119     /// Authenticates and decrypts (“opens”) data in place, with a shift.
120     ///
121     /// `aad` is the additional authenticated data (AAD), if any.
122     ///
123     /// On input, `in_out[ciphertext_and_tag]` must be the ciphertext followed
124     /// by the tag. When `open_within()` returns `Ok(plaintext)`, the plaintext
125     /// will be at `in_out[0..plaintext.len()]`. In other words, the following
126     /// two code fragments are equivalent for valid values of
127     /// `ciphertext_and_tag`, except `open_within` will often be more efficient:
128     ///
129     ///
130     /// ```skip
131     /// let plaintext = key.open_within(aad, in_out, cipertext_and_tag)?;
132     /// ```
133     ///
134     /// ```skip
135     /// let ciphertext_and_tag_len = in_out[ciphertext_and_tag].len();
136     /// in_out.copy_within(ciphertext_and_tag, 0);
137     /// let plaintext = key.open_in_place(aad, &mut in_out[..ciphertext_and_tag_len])?;
138     /// ```
139     ///
140     /// Similarly, `key.open_within(aad, in_out, 0..)` is equivalent to
141     /// `key.open_in_place(aad, in_out)`.
142     ///
143     ///  When `open_in_place()` returns `Err(..)`, `in_out` may have been
144     /// overwritten in an unspecified way.
145     ///
146     /// The shifting feature is useful in the case where multiple packets are
147     /// being reassembled in place. Consider this example where the peer has
148     /// sent the message “Split stream reassembled in place” split into
149     /// three sealed packets:
150     ///
151     /// ```ascii-art
152     ///                 Packet 1                  Packet 2                 Packet 3
153     /// Input:  [Header][Ciphertext][Tag][Header][Ciphertext][Tag][Header][Ciphertext][Tag]
154     ///                      |         +--------------+                        |
155     ///               +------+   +-----+    +----------------------------------+
156     ///               v          v          v
157     /// Output: [Plaintext][Plaintext][Plaintext]
158     ///        “Split stream reassembled in place”
159     /// ```
160     ///
161     /// This reassembly be accomplished with three calls to `open_within()`.
162     #[inline]
open_within<'in_out, A>( &mut self, aad: Aad<A>, in_out: &'in_out mut [u8], ciphertext_and_tag: RangeFrom<usize>, ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,163     pub fn open_within<'in_out, A>(
164         &mut self,
165         aad: Aad<A>,
166         in_out: &'in_out mut [u8],
167         ciphertext_and_tag: RangeFrom<usize>,
168     ) -> Result<&'in_out mut [u8], error::Unspecified>
169     where
170         A: AsRef<[u8]>,
171     {
172         open_within_(
173             &self.key,
174             self.nonce_sequence.advance()?,
175             aad,
176             in_out,
177             ciphertext_and_tag,
178         )
179     }
180 }
181 
182 #[inline]
open_within_<'in_out, A: AsRef<[u8]>>( key: &UnboundKey, nonce: Nonce, Aad(aad): Aad<A>, in_out: &'in_out mut [u8], ciphertext_and_tag: RangeFrom<usize>, ) -> Result<&'in_out mut [u8], error::Unspecified>183 fn open_within_<'in_out, A: AsRef<[u8]>>(
184     key: &UnboundKey,
185     nonce: Nonce,
186     Aad(aad): Aad<A>,
187     in_out: &'in_out mut [u8],
188     ciphertext_and_tag: RangeFrom<usize>,
189 ) -> Result<&'in_out mut [u8], error::Unspecified> {
190     fn open_within<'in_out>(
191         key: &UnboundKey,
192         nonce: Nonce,
193         aad: Aad<&[u8]>,
194         in_out: &'in_out mut [u8],
195         ciphertext_and_tag: RangeFrom<usize>,
196     ) -> Result<&'in_out mut [u8], error::Unspecified> {
197         let in_prefix_len = ciphertext_and_tag.start;
198         let ciphertext_and_tag_len = in_out
199             .len()
200             .checked_sub(in_prefix_len)
201             .ok_or(error::Unspecified)?;
202         let ciphertext_len = ciphertext_and_tag_len
203             .checked_sub(TAG_LEN)
204             .ok_or(error::Unspecified)?;
205         check_per_nonce_max_bytes(key.algorithm, ciphertext_len)?;
206         let (in_out, received_tag) = in_out.split_at_mut(in_prefix_len + ciphertext_len);
207         let Tag(calculated_tag) = (key.algorithm.open)(
208             &key.inner,
209             nonce,
210             aad,
211             in_prefix_len,
212             in_out,
213             key.cpu_features,
214         );
215         if constant_time::verify_slices_are_equal(calculated_tag.as_ref(), received_tag).is_err() {
216             // Zero out the plaintext so that it isn't accidentally leaked or used
217             // after verification fails. It would be safest if we could check the
218             // tag before decrypting, but some `open` implementations interleave
219             // authentication with decryption for performance.
220             for b in &mut in_out[..ciphertext_len] {
221                 *b = 0;
222             }
223             return Err(error::Unspecified);
224         }
225         // `ciphertext_len` is also the plaintext length.
226         Ok(&mut in_out[..ciphertext_len])
227     }
228 
229     open_within(
230         key,
231         nonce,
232         Aad::from(aad.as_ref()),
233         in_out,
234         ciphertext_and_tag,
235     )
236 }
237 
238 /// An AEAD key for encrypting and signing ("sealing"), bound to a nonce
239 /// sequence.
240 ///
241 /// Intentionally not `Clone` or `Copy` since cloning would allow duplication
242 /// of the nonce sequence.
243 pub struct SealingKey<N: NonceSequence> {
244     key: UnboundKey,
245     nonce_sequence: N,
246 }
247 
248 impl<N: NonceSequence> BoundKey<N> for SealingKey<N> {
new(key: UnboundKey, nonce_sequence: N) -> Self249     fn new(key: UnboundKey, nonce_sequence: N) -> Self {
250         Self {
251             key,
252             nonce_sequence,
253         }
254     }
255 
256     #[inline]
algorithm(&self) -> &'static Algorithm257     fn algorithm(&self) -> &'static Algorithm {
258         self.key.algorithm
259     }
260 }
261 
262 impl<N: NonceSequence> core::fmt::Debug for SealingKey<N> {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>263     fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
264         f.debug_struct("SealingKey")
265             .field("algorithm", &self.algorithm())
266             .finish()
267     }
268 }
269 
270 impl<N: NonceSequence> SealingKey<N> {
271     /// Deprecated. Renamed to `seal_in_place_append_tag()`.
272     #[deprecated(note = "Renamed to `seal_in_place_append_tag`.")]
273     #[inline]
seal_in_place<A, InOut>( &mut self, aad: Aad<A>, in_out: &mut InOut, ) -> Result<(), error::Unspecified> where A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,274     pub fn seal_in_place<A, InOut>(
275         &mut self,
276         aad: Aad<A>,
277         in_out: &mut InOut,
278     ) -> Result<(), error::Unspecified>
279     where
280         A: AsRef<[u8]>,
281         InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
282     {
283         self.seal_in_place_append_tag(aad, in_out)
284     }
285 
286     /// Encrypts and signs (“seals”) data in place, appending the tag to the
287     /// resulting ciphertext.
288     ///
289     /// `key.seal_in_place_append_tag(aad, in_out)` is equivalent to:
290     ///
291     /// ```skip
292     /// key.seal_in_place_separate_tag(aad, in_out.as_mut())
293     ///     .map(|tag| in_out.extend(tag.as_ref()))
294     /// ```
295     #[inline]
seal_in_place_append_tag<A, InOut>( &mut self, aad: Aad<A>, in_out: &mut InOut, ) -> Result<(), error::Unspecified> where A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,296     pub fn seal_in_place_append_tag<A, InOut>(
297         &mut self,
298         aad: Aad<A>,
299         in_out: &mut InOut,
300     ) -> Result<(), error::Unspecified>
301     where
302         A: AsRef<[u8]>,
303         InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
304     {
305         self.seal_in_place_separate_tag(aad, in_out.as_mut())
306             .map(|tag| in_out.extend(tag.as_ref()))
307     }
308 
309     /// Encrypts and signs (“seals”) data in place.
310     ///
311     /// `aad` is the additional authenticated data (AAD), if any. This is
312     /// authenticated but not encrypted. The type `A` could be a byte slice
313     /// `&[u8]`, a byte array `[u8; N]` for some constant `N`, `Vec<u8>`, etc.
314     /// If there is no AAD then use `Aad::empty()`.
315     ///
316     /// The plaintext is given as the input value of `in_out`. `seal_in_place()`
317     /// will overwrite the plaintext with the ciphertext and return the tag.
318     /// For most protocols, the caller must append the tag to the ciphertext.
319     /// The tag will be `self.algorithm.tag_len()` bytes long.
320     #[inline]
seal_in_place_separate_tag<A>( &mut self, aad: Aad<A>, in_out: &mut [u8], ) -> Result<Tag, error::Unspecified> where A: AsRef<[u8]>,321     pub fn seal_in_place_separate_tag<A>(
322         &mut self,
323         aad: Aad<A>,
324         in_out: &mut [u8],
325     ) -> Result<Tag, error::Unspecified>
326     where
327         A: AsRef<[u8]>,
328     {
329         seal_in_place_separate_tag_(
330             &self.key,
331             self.nonce_sequence.advance()?,
332             Aad::from(aad.as_ref()),
333             in_out,
334         )
335     }
336 }
337 
338 #[inline]
seal_in_place_separate_tag_( key: &UnboundKey, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8], ) -> Result<Tag, error::Unspecified>339 fn seal_in_place_separate_tag_(
340     key: &UnboundKey,
341     nonce: Nonce,
342     aad: Aad<&[u8]>,
343     in_out: &mut [u8],
344 ) -> Result<Tag, error::Unspecified> {
345     check_per_nonce_max_bytes(key.algorithm, in_out.len())?;
346     Ok((key.algorithm.seal)(
347         &key.inner,
348         nonce,
349         aad,
350         in_out,
351         key.cpu_features,
352     ))
353 }
354 
355 /// The additionally authenticated data (AAD) for an opening or sealing
356 /// operation. This data is authenticated but is **not** encrypted.
357 ///
358 /// The type `A` could be a byte slice `&[u8]`, a byte array `[u8; N]`
359 /// for some constant `N`, `Vec<u8>`, etc.
360 pub struct Aad<A: AsRef<[u8]>>(A);
361 
362 impl<A: AsRef<[u8]>> Aad<A> {
363     /// Construct the `Aad` from the given bytes.
364     #[inline]
from(aad: A) -> Self365     pub fn from(aad: A) -> Self {
366         Aad(aad)
367     }
368 }
369 
370 impl<A> AsRef<[u8]> for Aad<A>
371 where
372     A: AsRef<[u8]>,
373 {
as_ref(&self) -> &[u8]374     fn as_ref(&self) -> &[u8] {
375         self.0.as_ref()
376     }
377 }
378 
379 impl Aad<[u8; 0]> {
380     /// Construct an empty `Aad`.
empty() -> Self381     pub fn empty() -> Self {
382         Self::from([])
383     }
384 }
385 
386 /// An AEAD key without a designated role or nonce sequence.
387 pub struct UnboundKey {
388     inner: KeyInner,
389     algorithm: &'static Algorithm,
390     cpu_features: cpu::Features,
391 }
392 
393 impl core::fmt::Debug for UnboundKey {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>394     fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
395         f.debug_struct("UnboundKey")
396             .field("algorithm", &self.algorithm)
397             .finish()
398     }
399 }
400 
401 #[allow(clippy::large_enum_variant, variant_size_differences)]
402 enum KeyInner {
403     AesGcm(aes_gcm::Key),
404     ChaCha20Poly1305(chacha20_poly1305::Key),
405 }
406 
407 impl UnboundKey {
408     /// Constructs an `UnboundKey`.
409     ///
410     /// Fails if `key_bytes.len() != algorithm.key_len()`.
new( algorithm: &'static Algorithm, key_bytes: &[u8], ) -> Result<Self, error::Unspecified>411     pub fn new(
412         algorithm: &'static Algorithm,
413         key_bytes: &[u8],
414     ) -> Result<Self, error::Unspecified> {
415         let cpu_features = cpu::features();
416         Ok(Self {
417             inner: (algorithm.init)(key_bytes, cpu_features)?,
418             algorithm,
419             cpu_features,
420         })
421     }
422 
423     /// The key's AEAD algorithm.
424     #[inline]
algorithm(&self) -> &'static Algorithm425     pub fn algorithm(&self) -> &'static Algorithm {
426         self.algorithm
427     }
428 }
429 
430 impl From<hkdf::Okm<'_, &'static Algorithm>> for UnboundKey {
from(okm: hkdf::Okm<&'static Algorithm>) -> Self431     fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self {
432         let mut key_bytes = [0; MAX_KEY_LEN];
433         let key_bytes = &mut key_bytes[..okm.len().key_len];
434         let algorithm = *okm.len();
435         okm.fill(key_bytes).unwrap();
436         Self::new(algorithm, key_bytes).unwrap()
437     }
438 }
439 
440 impl hkdf::KeyType for &'static Algorithm {
441     #[inline]
len(&self) -> usize442     fn len(&self) -> usize {
443         self.key_len()
444     }
445 }
446 
447 /// Immutable keys for use in situations where `OpeningKey`/`SealingKey` and
448 /// `NonceSequence` cannot reasonably be used.
449 ///
450 /// Prefer to use `OpeningKey`/`SealingKey` and `NonceSequence` when practical.
451 pub struct LessSafeKey {
452     key: UnboundKey,
453 }
454 
455 impl LessSafeKey {
456     /// Constructs a `LessSafeKey` from an `UnboundKey`.
new(key: UnboundKey) -> Self457     pub fn new(key: UnboundKey) -> Self {
458         Self { key }
459     }
460 
461     /// Like [`OpeningKey::open_in_place()`], except it accepts an arbitrary nonce.
462     ///
463     /// `nonce` must be unique for every use of the key to open data.
464     #[inline]
open_in_place<'in_out, A>( &self, nonce: Nonce, aad: Aad<A>, in_out: &'in_out mut [u8], ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,465     pub fn open_in_place<'in_out, A>(
466         &self,
467         nonce: Nonce,
468         aad: Aad<A>,
469         in_out: &'in_out mut [u8],
470     ) -> Result<&'in_out mut [u8], error::Unspecified>
471     where
472         A: AsRef<[u8]>,
473     {
474         self.open_within(nonce, aad, in_out, 0..)
475     }
476 
477     /// Like [`OpeningKey::open_within()`], except it accepts an arbitrary nonce.
478     ///
479     /// `nonce` must be unique for every use of the key to open data.
480     #[inline]
open_within<'in_out, A>( &self, nonce: Nonce, aad: Aad<A>, in_out: &'in_out mut [u8], ciphertext_and_tag: RangeFrom<usize>, ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,481     pub fn open_within<'in_out, A>(
482         &self,
483         nonce: Nonce,
484         aad: Aad<A>,
485         in_out: &'in_out mut [u8],
486         ciphertext_and_tag: RangeFrom<usize>,
487     ) -> Result<&'in_out mut [u8], error::Unspecified>
488     where
489         A: AsRef<[u8]>,
490     {
491         open_within_(&self.key, nonce, aad, in_out, ciphertext_and_tag)
492     }
493 
494     /// Deprecated. Renamed to `seal_in_place_append_tag()`.
495     #[deprecated(note = "Renamed to `seal_in_place_append_tag`.")]
496     #[inline]
seal_in_place<A, InOut>( &self, nonce: Nonce, aad: Aad<A>, in_out: &mut InOut, ) -> Result<(), error::Unspecified> where A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,497     pub fn seal_in_place<A, InOut>(
498         &self,
499         nonce: Nonce,
500         aad: Aad<A>,
501         in_out: &mut InOut,
502     ) -> Result<(), error::Unspecified>
503     where
504         A: AsRef<[u8]>,
505         InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
506     {
507         self.seal_in_place_append_tag(nonce, aad, in_out)
508     }
509 
510     /// Like [`SealingKey::seal_in_place_append_tag()`], except it accepts an
511     /// arbitrary nonce.
512     ///
513     /// `nonce` must be unique for every use of the key to seal data.
514     #[inline]
seal_in_place_append_tag<A, InOut>( &self, nonce: Nonce, aad: Aad<A>, in_out: &mut InOut, ) -> Result<(), error::Unspecified> where A: AsRef<[u8]>, InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,515     pub fn seal_in_place_append_tag<A, InOut>(
516         &self,
517         nonce: Nonce,
518         aad: Aad<A>,
519         in_out: &mut InOut,
520     ) -> Result<(), error::Unspecified>
521     where
522         A: AsRef<[u8]>,
523         InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
524     {
525         self.seal_in_place_separate_tag(nonce, aad, in_out.as_mut())
526             .map(|tag| in_out.extend(tag.as_ref()))
527     }
528 
529     /// Like `SealingKey::seal_in_place_separate_tag()`, except it accepts an
530     /// arbitrary nonce.
531     ///
532     /// `nonce` must be unique for every use of the key to seal data.
533     #[inline]
seal_in_place_separate_tag<A>( &self, nonce: Nonce, aad: Aad<A>, in_out: &mut [u8], ) -> Result<Tag, error::Unspecified> where A: AsRef<[u8]>,534     pub fn seal_in_place_separate_tag<A>(
535         &self,
536         nonce: Nonce,
537         aad: Aad<A>,
538         in_out: &mut [u8],
539     ) -> Result<Tag, error::Unspecified>
540     where
541         A: AsRef<[u8]>,
542     {
543         seal_in_place_separate_tag_(&self.key, nonce, Aad::from(aad.as_ref()), in_out)
544     }
545 
546     /// The key's AEAD algorithm.
547     #[inline]
algorithm(&self) -> &'static Algorithm548     pub fn algorithm(&self) -> &'static Algorithm {
549         &self.key.algorithm
550     }
551 }
552 
553 impl core::fmt::Debug for LessSafeKey {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>554     fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
555         f.debug_struct("LessSafeKey")
556             .field("algorithm", self.algorithm())
557             .finish()
558     }
559 }
560 
561 /// An AEAD Algorithm.
562 pub struct Algorithm {
563     init: fn(key: &[u8], cpu_features: cpu::Features) -> Result<KeyInner, error::Unspecified>,
564 
565     seal: fn(
566         key: &KeyInner,
567         nonce: Nonce,
568         aad: Aad<&[u8]>,
569         in_out: &mut [u8],
570         cpu_features: cpu::Features,
571     ) -> Tag,
572     open: fn(
573         key: &KeyInner,
574         nonce: Nonce,
575         aad: Aad<&[u8]>,
576         in_prefix_len: usize,
577         in_out: &mut [u8],
578         cpu_features: cpu::Features,
579     ) -> Tag,
580 
581     key_len: usize,
582     id: AlgorithmID,
583 
584     /// Use `max_input_len!()` to initialize this.
585     // TODO: Make this `usize`.
586     max_input_len: u64,
587 }
588 
max_input_len(block_len: usize, overhead_blocks_per_nonce: usize) -> u64589 const fn max_input_len(block_len: usize, overhead_blocks_per_nonce: usize) -> u64 {
590     // Each of our AEADs use a 32-bit block counter so the maximum is the
591     // largest input that will not overflow the counter.
592     ((1u64 << 32) - polyfill::u64_from_usize(overhead_blocks_per_nonce))
593         * polyfill::u64_from_usize(block_len)
594 }
595 
596 impl Algorithm {
597     /// The length of the key.
598     #[inline(always)]
key_len(&self) -> usize599     pub fn key_len(&self) -> usize {
600         self.key_len
601     }
602 
603     /// The length of a tag.
604     ///
605     /// See also `MAX_TAG_LEN`.
606     #[inline(always)]
tag_len(&self) -> usize607     pub fn tag_len(&self) -> usize {
608         TAG_LEN
609     }
610 
611     /// The length of the nonces.
612     #[inline(always)]
nonce_len(&self) -> usize613     pub fn nonce_len(&self) -> usize {
614         NONCE_LEN
615     }
616 }
617 
618 derive_debug_via_id!(Algorithm);
619 
620 #[derive(Debug, Eq, PartialEq)]
621 enum AlgorithmID {
622     AES_128_GCM,
623     AES_256_GCM,
624     CHACHA20_POLY1305,
625 }
626 
627 impl PartialEq for Algorithm {
eq(&self, other: &Self) -> bool628     fn eq(&self, other: &Self) -> bool {
629         self.id == other.id
630     }
631 }
632 
633 impl Eq for Algorithm {}
634 
635 /// An authentication tag.
636 #[must_use]
637 #[repr(C)]
638 pub struct Tag([u8; TAG_LEN]);
639 
640 impl AsRef<[u8]> for Tag {
as_ref(&self) -> &[u8]641     fn as_ref(&self) -> &[u8] {
642         self.0.as_ref()
643     }
644 }
645 
646 const MAX_KEY_LEN: usize = 32;
647 
648 // All the AEADs we support use 128-bit tags.
649 const TAG_LEN: usize = BLOCK_LEN;
650 
651 /// The maximum length of a tag for the algorithms in this module.
652 pub const MAX_TAG_LEN: usize = TAG_LEN;
653 
check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), error::Unspecified>654 fn check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), error::Unspecified> {
655     if polyfill::u64_from_usize(in_out_len) > alg.max_input_len {
656         return Err(error::Unspecified);
657     }
658     Ok(())
659 }
660 
661 #[derive(Clone, Copy)]
662 enum Direction {
663     Opening { in_prefix_len: usize },
664     Sealing,
665 }
666 
667 mod aes;
668 mod aes_gcm;
669 mod block;
670 mod chacha;
671 mod chacha20_poly1305;
672 pub mod chacha20_poly1305_openssh;
673 mod counter;
674 mod gcm;
675 mod iv;
676 mod nonce;
677 mod poly1305;
678 pub mod quic;
679 mod shift;
680