| // 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]: http://www-cse.ucsd.edu/~mihir/papers/oem.html |
| //! [`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<Nonce, error::Unspecified>; |
| } |
| |
| /// An AEAD key bound to a nonce sequence. |
| pub trait BoundKey<N: NonceSequence>: 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<u8>`, etc. |
| pub struct Aad<A>(A); |
| |
| impl<A: AsRef<[u8]>> Aad<A> { |
| /// Construct the `Aad` from the given bytes. |
| #[inline] |
| pub fn from(aad: A) -> Self { |
| Self(aad) |
| } |
| } |
| |
| impl<A> AsRef<[u8]> for Aad<A> |
| 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<A> Clone for Aad<A> |
| where |
| A: Clone, |
| { |
| #[inline] |
| fn clone(&self) -> Self { |
| Self(self.0.clone()) |
| } |
| } |
| |
| impl<A> Copy for Aad<A> where A: Copy {} |
| |
| impl<A> core::fmt::Debug for Aad<A> |
| 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<A> PartialEq for Aad<A> |
| where |
| A: PartialEq, |
| { |
| #[inline] |
| fn eq(&self, other: &Self) -> bool { |
| self.0.eq(&other.0) |
| } |
| } |
| |
| impl<A> Eq for Aad<A> where A: Eq {} |
| |
| #[allow(clippy::large_enum_variant, variant_size_differences)] |
| 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<KeyInner, error::Unspecified>, |
| |
| 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<usize>, |
| ) -> 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 {} |
| |
| /// An authentication tag. |
| #[must_use] |
| #[repr(C)] |
| pub struct Tag([u8; TAG_LEN]); |
| |
| impl AsRef<[u8]> for Tag { |
| fn as_ref(&self) -> &[u8] { |
| self.0.as_ref() |
| } |
| } |
| |
| 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; |