ring/aead/
less_safe_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 AUTHOR DISCLAIMS ALL WARRANTIES
8// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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
15use super::{Aad, Algorithm, KeyInner, Nonce, Tag, UnboundKey, TAG_LEN};
16use crate::{cpu, error};
17use core::ops::RangeFrom;
18
19/// Immutable keys for use in situations where `OpeningKey`/`SealingKey` and
20/// `NonceSequence` cannot reasonably be used.
21///
22/// Prefer to use `OpeningKey`/`SealingKey` and `NonceSequence` when practical.
23#[derive(Clone)]
24pub struct LessSafeKey {
25    inner: KeyInner,
26    algorithm: &'static Algorithm,
27}
28
29impl LessSafeKey {
30    /// Constructs a `LessSafeKey`.
31    #[inline]
32    pub fn new(key: UnboundKey) -> Self {
33        key.into_inner()
34    }
35
36    pub(super) fn new_(
37        algorithm: &'static Algorithm,
38        key_bytes: &[u8],
39        cpu_features: cpu::Features,
40    ) -> Result<Self, error::Unspecified> {
41        Ok(Self {
42            inner: algorithm.new_key(key_bytes, cpu_features)?,
43            algorithm,
44        })
45    }
46
47    /// Like [open_in_place](Self::open_in_place), except the authentication tag is
48    /// passed separately.
49    #[inline]
50    pub fn open_in_place_separate_tag<'in_out, A>(
51        &self,
52        nonce: Nonce,
53        aad: Aad<A>,
54        tag: Tag,
55        in_out: &'in_out mut [u8],
56        ciphertext: RangeFrom<usize>,
57    ) -> Result<&'in_out mut [u8], error::Unspecified>
58    where
59        A: AsRef<[u8]>,
60    {
61        let aad = Aad::from(aad.as_ref());
62        self.algorithm.open_within(
63            &self.inner,
64            nonce,
65            aad,
66            tag,
67            in_out,
68            ciphertext,
69            cpu::features(),
70        )
71    }
72
73    /// Like [`super::OpeningKey::open_in_place()`], except it accepts an
74    /// arbitrary nonce.
75    ///
76    /// `nonce` must be unique for every use of the key to open data.
77    #[inline]
78    pub fn open_in_place<'in_out, A>(
79        &self,
80        nonce: Nonce,
81        aad: Aad<A>,
82        in_out: &'in_out mut [u8],
83    ) -> Result<&'in_out mut [u8], error::Unspecified>
84    where
85        A: AsRef<[u8]>,
86    {
87        self.open_within(nonce, aad, in_out, 0..)
88    }
89
90    /// Like [`super::OpeningKey::open_within()`], except it accepts an
91    /// arbitrary nonce.
92    ///
93    /// `nonce` must be unique for every use of the key to open data.
94    #[inline]
95    pub fn open_within<'in_out, A>(
96        &self,
97        nonce: Nonce,
98        aad: Aad<A>,
99        in_out: &'in_out mut [u8],
100        ciphertext_and_tag: RangeFrom<usize>,
101    ) -> Result<&'in_out mut [u8], error::Unspecified>
102    where
103        A: AsRef<[u8]>,
104    {
105        let tag_offset = in_out
106            .len()
107            .checked_sub(TAG_LEN)
108            .ok_or(error::Unspecified)?;
109
110        // Split the tag off the end of `in_out`.
111        let (in_out, received_tag) = in_out.split_at_mut(tag_offset);
112        let received_tag = (*received_tag).try_into()?;
113        let ciphertext = ciphertext_and_tag;
114
115        self.open_in_place_separate_tag(nonce, aad, received_tag, in_out, ciphertext)
116    }
117
118    /// Like [`super::SealingKey::seal_in_place_append_tag()`], except it
119    /// accepts an arbitrary nonce.
120    ///
121    /// `nonce` must be unique for every use of the key to seal data.
122    #[inline]
123    pub fn seal_in_place_append_tag<A, InOut>(
124        &self,
125        nonce: Nonce,
126        aad: Aad<A>,
127        in_out: &mut InOut,
128    ) -> Result<(), error::Unspecified>
129    where
130        A: AsRef<[u8]>,
131        InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
132    {
133        self.seal_in_place_separate_tag(nonce, aad, in_out.as_mut())
134            .map(|tag| in_out.extend(tag.as_ref()))
135    }
136
137    /// Like `super::SealingKey::seal_in_place_separate_tag()`, except it
138    /// accepts an arbitrary nonce.
139    ///
140    /// `nonce` must be unique for every use of the key to seal data.
141    #[inline]
142    pub fn seal_in_place_separate_tag<A>(
143        &self,
144        nonce: Nonce,
145        aad: Aad<A>,
146        in_out: &mut [u8],
147    ) -> Result<Tag, error::Unspecified>
148    where
149        A: AsRef<[u8]>,
150    {
151        self.algorithm.seal(
152            &self.inner,
153            nonce,
154            Aad::from(aad.as_ref()),
155            in_out,
156            cpu::features(),
157        )
158    }
159
160    /// The key's AEAD algorithm.
161    #[inline]
162    pub fn algorithm(&self) -> &'static Algorithm {
163        self.algorithm
164    }
165
166    pub(super) fn fmt_debug(
167        &self,
168        type_name: &'static str,
169        f: &mut core::fmt::Formatter,
170    ) -> Result<(), core::fmt::Error> {
171        f.debug_struct(type_name)
172            .field("algorithm", &self.algorithm())
173            .finish()
174    }
175}
176
177impl core::fmt::Debug for LessSafeKey {
178    fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
179        self.fmt_debug("LessSafeKey", f)
180    }
181}