680 lines
20 KiB
Rust
680 lines
20 KiB
Rust
// Copyright 2015-2016 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 self::block::{Block, BLOCK_LEN};
|
|
use crate::{constant_time, cpu, error, hkdf, polyfill};
|
|
use core::ops::RangeFrom;
|
|
|
|
pub use self::{
|
|
aes_gcm::{AES_128_GCM, AES_256_GCM},
|
|
chacha20_poly1305::CHACHA20_POLY1305,
|
|
nonce::{Nonce, NONCE_LEN},
|
|
};
|
|
|
|
/// 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;
|
|
}
|
|
|
|
/// An AEAD key for authenticating and decrypting ("opening"), bound to a nonce
|
|
/// sequence.
|
|
///
|
|
/// Intentionally not `Clone` or `Copy` since cloning would allow duplication
|
|
/// of the nonce sequence.
|
|
pub struct OpeningKey<N: NonceSequence> {
|
|
key: UnboundKey,
|
|
nonce_sequence: N,
|
|
}
|
|
|
|
impl<N: NonceSequence> BoundKey<N> for OpeningKey<N> {
|
|
fn new(key: UnboundKey, nonce_sequence: N) -> Self {
|
|
Self {
|
|
key,
|
|
nonce_sequence,
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn algorithm(&self) -> &'static Algorithm {
|
|
self.key.algorithm
|
|
}
|
|
}
|
|
|
|
impl<N: NonceSequence> core::fmt::Debug for OpeningKey<N> {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
|
|
f.debug_struct("OpeningKey")
|
|
.field("algorithm", &self.algorithm())
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl<N: NonceSequence> OpeningKey<N> {
|
|
/// Authenticates and decrypts (“opens”) data in place.
|
|
///
|
|
/// `aad` is the additional authenticated data (AAD), if any.
|
|
///
|
|
/// On input, `in_out` must be the ciphertext followed by the tag. When
|
|
/// `open_in_place()` returns `Ok(plaintext)`, the input ciphertext
|
|
/// has been overwritten by the plaintext; `plaintext` will refer to the
|
|
/// plaintext without the tag.
|
|
///
|
|
/// When `open_in_place()` returns `Err(..)`, `in_out` may have been
|
|
/// overwritten in an unspecified way.
|
|
#[inline]
|
|
pub fn 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]>,
|
|
{
|
|
self.open_within(aad, in_out, 0..)
|
|
}
|
|
|
|
/// Authenticates and decrypts (“opens”) data in place, with a shift.
|
|
///
|
|
/// `aad` is the additional authenticated data (AAD), if any.
|
|
///
|
|
/// On input, `in_out[ciphertext_and_tag]` must be the ciphertext followed
|
|
/// by the tag. When `open_within()` returns `Ok(plaintext)`, the plaintext
|
|
/// will be at `in_out[0..plaintext.len()]`. In other words, the following
|
|
/// two code fragments are equivalent for valid values of
|
|
/// `ciphertext_and_tag`, except `open_within` will often be more efficient:
|
|
///
|
|
///
|
|
/// ```skip
|
|
/// let plaintext = key.open_within(aad, in_out, cipertext_and_tag)?;
|
|
/// ```
|
|
///
|
|
/// ```skip
|
|
/// let ciphertext_and_tag_len = in_out[ciphertext_and_tag].len();
|
|
/// in_out.copy_within(ciphertext_and_tag, 0);
|
|
/// let plaintext = key.open_in_place(aad, &mut in_out[..ciphertext_and_tag_len])?;
|
|
/// ```
|
|
///
|
|
/// Similarly, `key.open_within(aad, in_out, 0..)` is equivalent to
|
|
/// `key.open_in_place(aad, in_out)`.
|
|
///
|
|
/// When `open_in_place()` returns `Err(..)`, `in_out` may have been
|
|
/// overwritten in an unspecified way.
|
|
///
|
|
/// The shifting feature is useful in the case where multiple packets are
|
|
/// being reassembled in place. Consider this example where the peer has
|
|
/// sent the message “Split stream reassembled in place” split into
|
|
/// three sealed packets:
|
|
///
|
|
/// ```ascii-art
|
|
/// Packet 1 Packet 2 Packet 3
|
|
/// Input: [Header][Ciphertext][Tag][Header][Ciphertext][Tag][Header][Ciphertext][Tag]
|
|
/// | +--------------+ |
|
|
/// +------+ +-----+ +----------------------------------+
|
|
/// v v v
|
|
/// Output: [Plaintext][Plaintext][Plaintext]
|
|
/// “Split stream reassembled in place”
|
|
/// ```
|
|
///
|
|
/// This reassembly be accomplished with three calls to `open_within()`.
|
|
#[inline]
|
|
pub fn 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]>,
|
|
{
|
|
open_within_(
|
|
&self.key,
|
|
self.nonce_sequence.advance()?,
|
|
aad,
|
|
in_out,
|
|
ciphertext_and_tag,
|
|
)
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn 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> {
|
|
fn open_within<'in_out>(
|
|
key: &UnboundKey,
|
|
nonce: Nonce,
|
|
aad: Aad<&[u8]>,
|
|
in_out: &'in_out mut [u8],
|
|
ciphertext_and_tag: RangeFrom<usize>,
|
|
) -> Result<&'in_out mut [u8], error::Unspecified> {
|
|
let in_prefix_len = ciphertext_and_tag.start;
|
|
let ciphertext_and_tag_len = in_out
|
|
.len()
|
|
.checked_sub(in_prefix_len)
|
|
.ok_or(error::Unspecified)?;
|
|
let ciphertext_len = ciphertext_and_tag_len
|
|
.checked_sub(TAG_LEN)
|
|
.ok_or(error::Unspecified)?;
|
|
check_per_nonce_max_bytes(key.algorithm, ciphertext_len)?;
|
|
let (in_out, received_tag) = in_out.split_at_mut(in_prefix_len + ciphertext_len);
|
|
let Tag(calculated_tag) = (key.algorithm.open)(
|
|
&key.inner,
|
|
nonce,
|
|
aad,
|
|
in_prefix_len,
|
|
in_out,
|
|
key.cpu_features,
|
|
);
|
|
if constant_time::verify_slices_are_equal(calculated_tag.as_ref(), received_tag).is_err() {
|
|
// Zero out the plaintext so that it isn't accidentally leaked or used
|
|
// after verification fails. It would be safest if we could check the
|
|
// tag before decrypting, but some `open` implementations interleave
|
|
// authentication with decryption for performance.
|
|
for b in &mut in_out[..ciphertext_len] {
|
|
*b = 0;
|
|
}
|
|
return Err(error::Unspecified);
|
|
}
|
|
// `ciphertext_len` is also the plaintext length.
|
|
Ok(&mut in_out[..ciphertext_len])
|
|
}
|
|
|
|
open_within(
|
|
key,
|
|
nonce,
|
|
Aad::from(aad.as_ref()),
|
|
in_out,
|
|
ciphertext_and_tag,
|
|
)
|
|
}
|
|
|
|
/// An AEAD key for encrypting and signing ("sealing"), bound to a nonce
|
|
/// sequence.
|
|
///
|
|
/// Intentionally not `Clone` or `Copy` since cloning would allow duplication
|
|
/// of the nonce sequence.
|
|
pub struct SealingKey<N: NonceSequence> {
|
|
key: UnboundKey,
|
|
nonce_sequence: N,
|
|
}
|
|
|
|
impl<N: NonceSequence> BoundKey<N> for SealingKey<N> {
|
|
fn new(key: UnboundKey, nonce_sequence: N) -> Self {
|
|
Self {
|
|
key,
|
|
nonce_sequence,
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn algorithm(&self) -> &'static Algorithm {
|
|
self.key.algorithm
|
|
}
|
|
}
|
|
|
|
impl<N: NonceSequence> core::fmt::Debug for SealingKey<N> {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
|
|
f.debug_struct("SealingKey")
|
|
.field("algorithm", &self.algorithm())
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl<N: NonceSequence> SealingKey<N> {
|
|
/// Deprecated. Renamed to `seal_in_place_append_tag()`.
|
|
#[deprecated(note = "Renamed to `seal_in_place_append_tag`.")]
|
|
#[inline]
|
|
pub fn 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>,
|
|
{
|
|
self.seal_in_place_append_tag(aad, in_out)
|
|
}
|
|
|
|
/// Encrypts and signs (“seals”) data in place, appending the tag to the
|
|
/// resulting ciphertext.
|
|
///
|
|
/// `key.seal_in_place_append_tag(aad, in_out)` is equivalent to:
|
|
///
|
|
/// ```skip
|
|
/// key.seal_in_place_separate_tag(aad, in_out.as_mut())
|
|
/// .map(|tag| in_out.extend(tag.as_ref()))
|
|
/// ```
|
|
#[inline]
|
|
pub fn 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>,
|
|
{
|
|
self.seal_in_place_separate_tag(aad, in_out.as_mut())
|
|
.map(|tag| in_out.extend(tag.as_ref()))
|
|
}
|
|
|
|
/// Encrypts and signs (“seals”) data in place.
|
|
///
|
|
/// `aad` is the additional authenticated data (AAD), if any. This is
|
|
/// authenticated but not encrypted. The type `A` could be a byte slice
|
|
/// `&[u8]`, a byte array `[u8; N]` for some constant `N`, `Vec<u8>`, etc.
|
|
/// If there is no AAD then use `Aad::empty()`.
|
|
///
|
|
/// The plaintext is given as the input value of `in_out`. `seal_in_place()`
|
|
/// will overwrite the plaintext with the ciphertext and return the tag.
|
|
/// For most protocols, the caller must append the tag to the ciphertext.
|
|
/// The tag will be `self.algorithm.tag_len()` bytes long.
|
|
#[inline]
|
|
pub fn seal_in_place_separate_tag<A>(
|
|
&mut self,
|
|
aad: Aad<A>,
|
|
in_out: &mut [u8],
|
|
) -> Result<Tag, error::Unspecified>
|
|
where
|
|
A: AsRef<[u8]>,
|
|
{
|
|
seal_in_place_separate_tag_(
|
|
&self.key,
|
|
self.nonce_sequence.advance()?,
|
|
Aad::from(aad.as_ref()),
|
|
in_out,
|
|
)
|
|
}
|
|
}
|
|
|
|
#[inline]
|
|
fn seal_in_place_separate_tag_(
|
|
key: &UnboundKey,
|
|
nonce: Nonce,
|
|
aad: Aad<&[u8]>,
|
|
in_out: &mut [u8],
|
|
) -> Result<Tag, error::Unspecified> {
|
|
check_per_nonce_max_bytes(key.algorithm, in_out.len())?;
|
|
Ok((key.algorithm.seal)(
|
|
&key.inner,
|
|
nonce,
|
|
aad,
|
|
in_out,
|
|
key.cpu_features,
|
|
))
|
|
}
|
|
|
|
/// 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: AsRef<[u8]>>(A);
|
|
|
|
impl<A: AsRef<[u8]>> Aad<A> {
|
|
/// Construct the `Aad` from the given bytes.
|
|
#[inline]
|
|
pub fn from(aad: A) -> Self {
|
|
Aad(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([])
|
|
}
|
|
}
|
|
|
|
/// An AEAD key without a designated role or nonce sequence.
|
|
pub struct UnboundKey {
|
|
inner: KeyInner,
|
|
algorithm: &'static Algorithm,
|
|
cpu_features: cpu::Features,
|
|
}
|
|
|
|
impl core::fmt::Debug for UnboundKey {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
|
|
f.debug_struct("UnboundKey")
|
|
.field("algorithm", &self.algorithm)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::large_enum_variant, variant_size_differences)]
|
|
enum KeyInner {
|
|
AesGcm(aes_gcm::Key),
|
|
ChaCha20Poly1305(chacha20_poly1305::Key),
|
|
}
|
|
|
|
impl UnboundKey {
|
|
/// Constructs an `UnboundKey`.
|
|
///
|
|
/// Fails if `key_bytes.len() != algorithm.key_len()`.
|
|
pub fn new(
|
|
algorithm: &'static Algorithm,
|
|
key_bytes: &[u8],
|
|
) -> Result<Self, error::Unspecified> {
|
|
let cpu_features = cpu::features();
|
|
Ok(Self {
|
|
inner: (algorithm.init)(key_bytes, cpu_features)?,
|
|
algorithm,
|
|
cpu_features,
|
|
})
|
|
}
|
|
|
|
/// The key's AEAD algorithm.
|
|
#[inline]
|
|
pub fn algorithm(&self) -> &'static Algorithm {
|
|
self.algorithm
|
|
}
|
|
}
|
|
|
|
impl From<hkdf::Okm<'_, &'static Algorithm>> for UnboundKey {
|
|
fn from(okm: hkdf::Okm<&'static Algorithm>) -> Self {
|
|
let mut key_bytes = [0; MAX_KEY_LEN];
|
|
let key_bytes = &mut key_bytes[..okm.len().key_len];
|
|
let algorithm = *okm.len();
|
|
okm.fill(key_bytes).unwrap();
|
|
Self::new(algorithm, key_bytes).unwrap()
|
|
}
|
|
}
|
|
|
|
impl hkdf::KeyType for &'static Algorithm {
|
|
#[inline]
|
|
fn len(&self) -> usize {
|
|
self.key_len()
|
|
}
|
|
}
|
|
|
|
/// Immutable keys for use in situations where `OpeningKey`/`SealingKey` and
|
|
/// `NonceSequence` cannot reasonably be used.
|
|
///
|
|
/// Prefer to use `OpeningKey`/`SealingKey` and `NonceSequence` when practical.
|
|
pub struct LessSafeKey {
|
|
key: UnboundKey,
|
|
}
|
|
|
|
impl LessSafeKey {
|
|
/// Constructs a `LessSafeKey` from an `UnboundKey`.
|
|
pub fn new(key: UnboundKey) -> Self {
|
|
Self { key }
|
|
}
|
|
|
|
/// Like [`OpeningKey::open_in_place()`], except it accepts an arbitrary nonce.
|
|
///
|
|
/// `nonce` must be unique for every use of the key to open data.
|
|
#[inline]
|
|
pub fn 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]>,
|
|
{
|
|
self.open_within(nonce, aad, in_out, 0..)
|
|
}
|
|
|
|
/// Like [`OpeningKey::open_within()`], except it accepts an arbitrary nonce.
|
|
///
|
|
/// `nonce` must be unique for every use of the key to open data.
|
|
#[inline]
|
|
pub fn 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]>,
|
|
{
|
|
open_within_(&self.key, nonce, aad, in_out, ciphertext_and_tag)
|
|
}
|
|
|
|
/// Deprecated. Renamed to `seal_in_place_append_tag()`.
|
|
#[deprecated(note = "Renamed to `seal_in_place_append_tag`.")]
|
|
#[inline]
|
|
pub fn 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>,
|
|
{
|
|
self.seal_in_place_append_tag(nonce, aad, in_out)
|
|
}
|
|
|
|
/// Like [`SealingKey::seal_in_place_append_tag()`], except it accepts an
|
|
/// arbitrary nonce.
|
|
///
|
|
/// `nonce` must be unique for every use of the key to seal data.
|
|
#[inline]
|
|
pub fn 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>,
|
|
{
|
|
self.seal_in_place_separate_tag(nonce, aad, in_out.as_mut())
|
|
.map(|tag| in_out.extend(tag.as_ref()))
|
|
}
|
|
|
|
/// Like `SealingKey::seal_in_place_separate_tag()`, except it accepts an
|
|
/// arbitrary nonce.
|
|
///
|
|
/// `nonce` must be unique for every use of the key to seal data.
|
|
#[inline]
|
|
pub fn seal_in_place_separate_tag<A>(
|
|
&self,
|
|
nonce: Nonce,
|
|
aad: Aad<A>,
|
|
in_out: &mut [u8],
|
|
) -> Result<Tag, error::Unspecified>
|
|
where
|
|
A: AsRef<[u8]>,
|
|
{
|
|
seal_in_place_separate_tag_(&self.key, nonce, Aad::from(aad.as_ref()), in_out)
|
|
}
|
|
|
|
/// The key's AEAD algorithm.
|
|
#[inline]
|
|
pub fn algorithm(&self) -> &'static Algorithm {
|
|
&self.key.algorithm
|
|
}
|
|
}
|
|
|
|
impl core::fmt::Debug for LessSafeKey {
|
|
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
|
|
f.debug_struct("LessSafeKey")
|
|
.field("algorithm", self.algorithm())
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
/// 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],
|
|
cpu_features: cpu::Features,
|
|
) -> Tag,
|
|
open: fn(
|
|
key: &KeyInner,
|
|
nonce: Nonce,
|
|
aad: Aad<&[u8]>,
|
|
in_prefix_len: usize,
|
|
in_out: &mut [u8],
|
|
cpu_features: cpu::Features,
|
|
) -> 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 = BLOCK_LEN;
|
|
|
|
/// The maximum length of a tag for the algorithms in this module.
|
|
pub const MAX_TAG_LEN: usize = TAG_LEN;
|
|
|
|
fn check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), error::Unspecified> {
|
|
if polyfill::u64_from_usize(in_out_len) > alg.max_input_len {
|
|
return Err(error::Unspecified);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
#[derive(Clone, Copy)]
|
|
enum Direction {
|
|
Opening { in_prefix_len: usize },
|
|
Sealing,
|
|
}
|
|
|
|
mod aes;
|
|
mod aes_gcm;
|
|
mod block;
|
|
mod chacha;
|
|
mod chacha20_poly1305;
|
|
pub mod chacha20_poly1305_openssh;
|
|
mod counter;
|
|
mod gcm;
|
|
mod iv;
|
|
mod nonce;
|
|
mod poly1305;
|
|
pub mod quic;
|
|
mod shift;
|