ring/aead/
opening_key.rs

1// Copyright 2015-2021 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]: https://eprint.iacr.org/2000/025.pdf
22//! [`crypto.cipher.AEAD`]: https://golang.org/pkg/crypto/cipher/#AEAD
23
24use super::{Aad, Algorithm, BoundKey, LessSafeKey, NonceSequence, UnboundKey};
25use crate::error;
26use core::ops::RangeFrom;
27
28/// An AEAD key for authenticating and decrypting ("opening"), bound to a nonce
29/// sequence.
30///
31/// Intentionally not `Clone` or `Copy` since cloning would allow duplication
32/// of the nonce sequence.
33pub struct OpeningKey<N: NonceSequence> {
34    key: LessSafeKey,
35    nonce_sequence: N,
36}
37
38impl<N: NonceSequence> BoundKey<N> for OpeningKey<N> {
39    fn new(key: UnboundKey, nonce_sequence: N) -> Self {
40        Self {
41            key: key.into_inner(),
42            nonce_sequence,
43        }
44    }
45
46    #[inline]
47    fn algorithm(&self) -> &'static Algorithm {
48        self.key.algorithm()
49    }
50}
51
52impl<N: NonceSequence> core::fmt::Debug for OpeningKey<N> {
53    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
54        self.key.fmt_debug("OpeningKey", f)
55    }
56}
57
58impl<N: NonceSequence> OpeningKey<N> {
59    /// Authenticates and decrypts (“opens”) data in place.
60    ///
61    /// `aad` is the additional authenticated data (AAD), if any.
62    ///
63    /// On input, `in_out` must be the ciphertext followed by the tag. When
64    /// `open_in_place()` returns `Ok(plaintext)`, the input ciphertext
65    /// has been overwritten by the plaintext; `plaintext` will refer to the
66    /// plaintext without the tag.
67    ///
68    /// When `open_in_place()` returns `Err(..)`, `in_out` may have been
69    /// overwritten in an unspecified way.
70    #[inline]
71    pub fn open_in_place<'in_out, A>(
72        &mut self,
73        aad: Aad<A>,
74        in_out: &'in_out mut [u8],
75    ) -> Result<&'in_out mut [u8], error::Unspecified>
76    where
77        A: AsRef<[u8]>,
78    {
79        self.key
80            .open_in_place(self.nonce_sequence.advance()?, aad, in_out)
81    }
82
83    /// Authenticates and decrypts (“opens”) data in place, with a shift.
84    ///
85    /// `aad` is the additional authenticated data (AAD), if any.
86    ///
87    /// On input, `in_out[ciphertext_and_tag]` must be the ciphertext followed
88    /// by the tag. When `open_within()` returns `Ok(plaintext)`, the plaintext
89    /// will be at `in_out[0..plaintext.len()]`. In other words, the following
90    /// two code fragments are equivalent for valid values of
91    /// `ciphertext_and_tag`, except `open_within` will often be more efficient:
92    ///
93    ///
94    /// ```skip
95    /// let plaintext = key.open_within(aad, in_out, cipertext_and_tag)?;
96    /// ```
97    ///
98    /// ```skip
99    /// let ciphertext_and_tag_len = in_out[ciphertext_and_tag].len();
100    /// in_out.copy_within(ciphertext_and_tag, 0);
101    /// let plaintext = key.open_in_place(aad, &mut in_out[..ciphertext_and_tag_len])?;
102    /// ```
103    ///
104    /// Similarly, `key.open_within(aad, in_out, 0..)` is equivalent to
105    /// `key.open_in_place(aad, in_out)`.
106    ///
107    ///  When `open_in_place()` returns `Err(..)`, `in_out` may have been
108    /// overwritten in an unspecified way.
109    ///
110    /// The shifting feature is useful in the case where multiple packets are
111    /// being reassembled in place. Consider this example where the peer has
112    /// sent the message “Split stream reassembled in place” split into
113    /// three sealed packets:
114    ///
115    /// ```ascii-art
116    ///                 Packet 1                  Packet 2                 Packet 3
117    /// Input:  [Header][Ciphertext][Tag][Header][Ciphertext][Tag][Header][Ciphertext][Tag]
118    ///                      |         +--------------+                        |
119    ///               +------+   +-----+    +----------------------------------+
120    ///               v          v          v
121    /// Output: [Plaintext][Plaintext][Plaintext]
122    ///        “Split stream reassembled in place”
123    /// ```
124    ///
125    /// This reassembly can be accomplished with three calls to `open_within()`.
126    #[inline]
127    pub fn open_within<'in_out, A>(
128        &mut self,
129        aad: Aad<A>,
130        in_out: &'in_out mut [u8],
131        ciphertext_and_tag: RangeFrom<usize>,
132    ) -> Result<&'in_out mut [u8], error::Unspecified>
133    where
134        A: AsRef<[u8]>,
135    {
136        self.key.open_within(
137            self.nonce_sequence.advance()?,
138            aad,
139            in_out,
140            ciphertext_and_tag,
141        )
142    }
143}