// Copyright 2015-2021 Brian Smith. // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice appear in all copies. // // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. //! Authenticated Encryption with Associated Data (AEAD). //! //! See [Authenticated encryption: relations among notions and analysis of the //! generic composition paradigm][AEAD] for an introduction to the concept of //! AEADs. //! //! [AEAD]: https://eprint.iacr.org/2000/025.pdf //! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD use crate::{cpu, error, hkdf, polyfill}; use core::ops::RangeFrom; pub use self::{ aes_gcm::{AES_128_GCM, AES_256_GCM}, chacha20_poly1305::CHACHA20_POLY1305, less_safe_key::LessSafeKey, nonce::{Nonce, NONCE_LEN}, opening_key::OpeningKey, sealing_key::SealingKey, unbound_key::UnboundKey, }; /// A sequences of unique nonces. /// /// A given `NonceSequence` must never return the same `Nonce` twice from /// `advance()`. /// /// A simple counter is a reasonable (but probably not ideal) `NonceSequence`. /// /// Intentionally not `Clone` or `Copy` since cloning would allow duplication /// of the sequence. pub trait NonceSequence { /// Returns the next nonce in the sequence. /// /// This may fail if "too many" nonces have been requested, where how many /// is too many is up to the implementation of `NonceSequence`. An /// implementation may that enforce a maximum number of records are /// sent/received under a key this way. Once `advance()` fails, it must /// fail for all subsequent calls. fn advance(&mut self) -> Result; } /// An AEAD key bound to a nonce sequence. pub trait BoundKey: core::fmt::Debug { /// Constructs a new key from the given `UnboundKey` and `NonceSequence`. fn new(key: UnboundKey, nonce_sequence: N) -> Self; /// The key's AEAD algorithm. fn algorithm(&self) -> &'static Algorithm; } /// The additionally authenticated data (AAD) for an opening or sealing /// operation. This data is authenticated but is **not** encrypted. /// /// The type `A` could be a byte slice `&[u8]`, a byte array `[u8; N]` /// for some constant `N`, `Vec`, etc. #[derive(Clone, Copy)] pub struct Aad(A); impl> Aad { /// Construct the `Aad` from the given bytes. #[inline] pub fn from(aad: A) -> Self { Self(aad) } } impl AsRef<[u8]> for Aad where A: AsRef<[u8]>, { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } impl Aad<[u8; 0]> { /// Construct an empty `Aad`. pub fn empty() -> Self { Self::from([]) } } impl core::fmt::Debug for Aad where A: core::fmt::Debug, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_tuple("Aad").field(&self.0).finish() } } impl PartialEq for Aad where A: PartialEq, { #[inline] fn eq(&self, other: &Self) -> bool { self.0.eq(&other.0) } } impl Eq for Aad where A: Eq {} #[allow(clippy::large_enum_variant, variant_size_differences)] #[derive(Clone)] enum KeyInner { AesGcm(aes_gcm::Key), ChaCha20Poly1305(chacha20_poly1305::Key), } impl hkdf::KeyType for &'static Algorithm { #[inline] fn len(&self) -> usize { self.key_len() } } /// An AEAD Algorithm. pub struct Algorithm { init: fn(key: &[u8], cpu_features: cpu::Features) -> Result, seal: fn(key: &KeyInner, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8]) -> Tag, open: fn( key: &KeyInner, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8], src: RangeFrom, ) -> Tag, key_len: usize, id: AlgorithmID, /// Use `max_input_len!()` to initialize this. // TODO: Make this `usize`. max_input_len: u64, } const fn max_input_len(block_len: usize, overhead_blocks_per_nonce: usize) -> u64 { // Each of our AEADs use a 32-bit block counter so the maximum is the // largest input that will not overflow the counter. ((1u64 << 32) - polyfill::u64_from_usize(overhead_blocks_per_nonce)) * polyfill::u64_from_usize(block_len) } impl Algorithm { /// The length of the key. #[inline(always)] pub fn key_len(&self) -> usize { self.key_len } /// The length of a tag. /// /// See also `MAX_TAG_LEN`. #[inline(always)] pub fn tag_len(&self) -> usize { TAG_LEN } /// The length of the nonces. #[inline(always)] pub fn nonce_len(&self) -> usize { NONCE_LEN } } derive_debug_via_id!(Algorithm); #[derive(Debug, Eq, PartialEq)] enum AlgorithmID { AES_128_GCM, AES_256_GCM, CHACHA20_POLY1305, } impl PartialEq for Algorithm { fn eq(&self, other: &Self) -> bool { self.id == other.id } } impl Eq for Algorithm {} /// A possibly valid authentication tag. #[must_use] #[repr(C)] #[derive(Clone, Copy)] pub struct Tag([u8; TAG_LEN]); impl AsRef<[u8]> for Tag { fn as_ref(&self) -> &[u8] { self.0.as_ref() } } impl TryFrom<&[u8]> for Tag { type Error = error::Unspecified; fn try_from(value: &[u8]) -> Result { let raw_tag: [u8; TAG_LEN] = value.try_into().map_err(|_| error::Unspecified)?; Ok(Self::from(raw_tag)) } } impl From<[u8; TAG_LEN]> for Tag { #[inline] fn from(value: [u8; TAG_LEN]) -> Self { Self(value) } } const MAX_KEY_LEN: usize = 32; // All the AEADs we support use 128-bit tags. const TAG_LEN: usize = 16; /// The maximum length of a tag for the algorithms in this module. pub const MAX_TAG_LEN: usize = TAG_LEN; mod aes; mod aes_gcm; mod block; mod chacha; mod chacha20_poly1305; pub mod chacha20_poly1305_openssh; mod gcm; mod less_safe_key; mod nonce; mod opening_key; mod poly1305; pub mod quic; mod sealing_key; mod shift; mod unbound_key;