• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 use super::{Aad, Algorithm, KeyInner, Nonce, Tag, UnboundKey, TAG_LEN};
16 use crate::{constant_time, cpu, error, polyfill};
17 use 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)]
24 pub struct LessSafeKey {
25     inner: KeyInner,
26     algorithm: &'static Algorithm,
27 }
28 
29 impl LessSafeKey {
30     /// Constructs a `LessSafeKey`.
31     #[inline]
new(key: UnboundKey) -> Self32     pub fn new(key: UnboundKey) -> Self {
33         key.into_inner()
34     }
35 
new_( algorithm: &'static Algorithm, key_bytes: &[u8], ) -> Result<Self, error::Unspecified>36     pub(super) fn new_(
37         algorithm: &'static Algorithm,
38         key_bytes: &[u8],
39     ) -> Result<Self, error::Unspecified> {
40         let cpu_features = cpu::features();
41         Ok(Self {
42             inner: (algorithm.init)(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]
open_in_place_separate_tag<'in_out, A>( &self, nonce: Nonce, aad: Aad<A>, tag: Tag, in_out: &'in_out mut [u8], ciphertext: RangeFrom<usize>, ) -> Result<&'in_out mut [u8], error::Unspecified> where A: AsRef<[u8]>,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         open_within_(self, nonce, aad, tag, in_out, ciphertext)
63     }
64 
65     /// Like [`super::OpeningKey::open_in_place()`], except it accepts an
66     /// arbitrary nonce.
67     ///
68     /// `nonce` must be unique for every use of the key to open data.
69     #[inline]
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]>,70     pub fn open_in_place<'in_out, A>(
71         &self,
72         nonce: Nonce,
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.open_within(nonce, aad, in_out, 0..)
80     }
81 
82     /// Like [`super::OpeningKey::open_within()`], except it accepts an
83     /// arbitrary nonce.
84     ///
85     /// `nonce` must be unique for every use of the key to open data.
86     #[inline]
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]>,87     pub fn open_within<'in_out, A>(
88         &self,
89         nonce: Nonce,
90         aad: Aad<A>,
91         in_out: &'in_out mut [u8],
92         ciphertext_and_tag: RangeFrom<usize>,
93     ) -> Result<&'in_out mut [u8], error::Unspecified>
94     where
95         A: AsRef<[u8]>,
96     {
97         let tag_offset = in_out
98             .len()
99             .checked_sub(TAG_LEN)
100             .ok_or(error::Unspecified)?;
101 
102         // Split the tag off the end of `in_out`.
103         let (in_out, received_tag) = in_out.split_at_mut(tag_offset);
104         let received_tag = (*received_tag).try_into()?;
105         let ciphertext = ciphertext_and_tag;
106 
107         self.open_in_place_separate_tag(nonce, aad, received_tag, in_out, ciphertext)
108     }
109 
110     /// Like [`super::SealingKey::seal_in_place_append_tag()`], except it
111     /// accepts an arbitrary nonce.
112     ///
113     /// `nonce` must be unique for every use of the key to seal data.
114     #[inline]
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>,115     pub fn seal_in_place_append_tag<A, InOut>(
116         &self,
117         nonce: Nonce,
118         aad: Aad<A>,
119         in_out: &mut InOut,
120     ) -> Result<(), error::Unspecified>
121     where
122         A: AsRef<[u8]>,
123         InOut: AsMut<[u8]> + for<'in_out> Extend<&'in_out u8>,
124     {
125         self.seal_in_place_separate_tag(nonce, aad, in_out.as_mut())
126             .map(|tag| in_out.extend(tag.as_ref()))
127     }
128 
129     /// Like `super::SealingKey::seal_in_place_separate_tag()`, except it
130     /// accepts an arbitrary nonce.
131     ///
132     /// `nonce` must be unique for every use of the key to seal data.
133     #[inline]
seal_in_place_separate_tag<A>( &self, nonce: Nonce, aad: Aad<A>, in_out: &mut [u8], ) -> Result<Tag, error::Unspecified> where A: AsRef<[u8]>,134     pub fn seal_in_place_separate_tag<A>(
135         &self,
136         nonce: Nonce,
137         aad: Aad<A>,
138         in_out: &mut [u8],
139     ) -> Result<Tag, error::Unspecified>
140     where
141         A: AsRef<[u8]>,
142     {
143         seal_in_place_separate_tag_(self, nonce, Aad::from(aad.as_ref()), in_out)
144     }
145 
146     /// The key's AEAD algorithm.
147     #[inline]
algorithm(&self) -> &'static Algorithm148     pub fn algorithm(&self) -> &'static Algorithm {
149         self.algorithm
150     }
151 
fmt_debug( &self, type_name: &'static str, f: &mut core::fmt::Formatter, ) -> Result<(), core::fmt::Error>152     pub(super) fn fmt_debug(
153         &self,
154         type_name: &'static str,
155         f: &mut core::fmt::Formatter,
156     ) -> Result<(), core::fmt::Error> {
157         f.debug_struct(type_name)
158             .field("algorithm", &self.algorithm())
159             .finish()
160     }
161 }
162 
open_within_<'in_out>( key: &LessSafeKey, nonce: Nonce, aad: Aad<&[u8]>, received_tag: Tag, in_out: &'in_out mut [u8], src: RangeFrom<usize>, ) -> Result<&'in_out mut [u8], error::Unspecified>163 fn open_within_<'in_out>(
164     key: &LessSafeKey,
165     nonce: Nonce,
166     aad: Aad<&[u8]>,
167     received_tag: Tag,
168     in_out: &'in_out mut [u8],
169     src: RangeFrom<usize>,
170 ) -> Result<&'in_out mut [u8], error::Unspecified> {
171     let ciphertext_len = in_out.get(src.clone()).ok_or(error::Unspecified)?.len();
172     check_per_nonce_max_bytes(key.algorithm, ciphertext_len)?;
173 
174     let Tag(calculated_tag) = (key.algorithm.open)(&key.inner, nonce, aad, in_out, src);
175 
176     if constant_time::verify_slices_are_equal(calculated_tag.as_ref(), received_tag.as_ref())
177         .is_err()
178     {
179         // Zero out the plaintext so that it isn't accidentally leaked or used
180         // after verification fails. It would be safest if we could check the
181         // tag before decrypting, but some `open` implementations interleave
182         // authentication with decryption for performance.
183         for b in &mut in_out[..ciphertext_len] {
184             *b = 0;
185         }
186         return Err(error::Unspecified);
187     }
188 
189     // `ciphertext_len` is also the plaintext length.
190     Ok(&mut in_out[..ciphertext_len])
191 }
192 
193 #[inline]
seal_in_place_separate_tag_( key: &LessSafeKey, nonce: Nonce, aad: Aad<&[u8]>, in_out: &mut [u8], ) -> Result<Tag, error::Unspecified>194 pub(super) fn seal_in_place_separate_tag_(
195     key: &LessSafeKey,
196     nonce: Nonce,
197     aad: Aad<&[u8]>,
198     in_out: &mut [u8],
199 ) -> Result<Tag, error::Unspecified> {
200     check_per_nonce_max_bytes(key.algorithm(), in_out.len())?;
201     Ok((key.algorithm.seal)(&key.inner, nonce, aad, in_out))
202 }
203 
check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), error::Unspecified>204 fn check_per_nonce_max_bytes(alg: &Algorithm, in_out_len: usize) -> Result<(), error::Unspecified> {
205     if polyfill::u64_from_usize(in_out_len) > alg.max_input_len {
206         return Err(error::Unspecified);
207     }
208     Ok(())
209 }
210 
211 impl core::fmt::Debug for LessSafeKey {
fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error>212     fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
213         self.fmt_debug("LessSafeKey", f)
214     }
215 }
216