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