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}; |
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 ] |
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 | ) -> 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 ] |
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 ] |
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 ] |
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 ] |
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 ] |
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 ] |
148 | pub fn algorithm(&self) -> &'static Algorithm { |
149 | self.algorithm |
150 | } |
151 | |
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 | |
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: usize = in_out.get(src.clone()).ok_or(err:error::Unspecified)?.len(); |
172 | |
173 | let Tag(calculated_tag: [u8; 16]) = |
174 | (key.algorithm.open)(&key.inner, nonce, aad, in_out, src, cpu::features())?; |
175 | |
176 | if constant_timeResult<(), Unspecified>::verify_slices_are_equal(a:calculated_tag.as_ref(), b: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: &mut u8 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 ] |
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 | (key.algorithm.seal)(&key.inner, nonce, aad, in_out, cpu::features()) |
201 | } |
202 | |
203 | impl core::fmt::Debug for LessSafeKey { |
204 | fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> { |
205 | self.fmt_debug(type_name:"LessSafeKey" , f) |
206 | } |
207 | } |
208 | |