// 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 super::{Aad, Algorithm, BoundKey, LessSafeKey, NonceSequence, UnboundKey}; use crate::error; use core::ops::RangeFrom; /// 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 { key: LessSafeKey, nonce_sequence: N, } impl BoundKey for OpeningKey { fn new(key: UnboundKey, nonce_sequence: N) -> Self { Self { key: key.into_inner(), nonce_sequence, } } #[inline] fn algorithm(&self) -> &'static Algorithm { self.key.algorithm() } } impl core::fmt::Debug for OpeningKey { fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { self.key.fmt_debug("OpeningKey", f) } } impl OpeningKey { /// 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, in_out: &'in_out mut [u8], ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>, { self.key .open_in_place(self.nonce_sequence.advance()?, aad, in_out) } /// 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 can be accomplished with three calls to `open_within()`. #[inline] pub fn open_within<'in_out, A>( &mut self, aad: Aad, in_out: &'in_out mut [u8], ciphertext_and_tag: RangeFrom, ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>, { self.key.open_within( self.nonce_sequence.advance()?, aad, in_out, ciphertext_and_tag, ) } }