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