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