1use super::{Aad, Algorithm, KeyInner, Nonce, Tag, UnboundKey, TAG_LEN};
16use crate::{constant_time, cpu, error, polyfill};
17use core::ops::RangeFrom;
18
19pub struct LessSafeKey {
24 inner: KeyInner,
25 algorithm: &'static Algorithm,
26}
27
28impl LessSafeKey {
29 #[inline]
31 pub fn new(key: UnboundKey) -> Self {
32 key.into_inner()
33 }
34
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 #[inline]
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 #[inline]
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 #[inline]
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 #[inline]
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 #[inline]
123 pub fn algorithm(&self) -> &'static Algorithm {
124 &self.algorithm
125 }
126
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
138fn 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 for b in &mut in_out[..ciphertext_len] {
161 *b = 0;
162 }
163 return Err(error::Unspecified);
164 }
165 Ok(&mut in_out[..ciphertext_len])
167}
168
169#[inline]
170pub(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
180fn 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
187impl core::fmt::Debug for LessSafeKey {
188 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
189 self.fmt_debug("LessSafeKey", f)
190 }
191}