1#[cfg(feature = "alloc")]
4use super::SecretVec;
5use super::{SecretArray, SecretInput, SecretOutput};
6use crate::v2::{
7 Base64, Codec, Progress,
8 secret_encoder::{SecretEncodeError, SecretEncoderState, require_disjoint},
9};
10
11pub struct SecretArrayEncoder<const CAP: usize> {
16 state: SecretEncoderState,
17 output: [u8; CAP],
18}
19
20impl<const CAP: usize> SecretArrayEncoder<CAP> {
21 const CAPACITY_ASSERT: () = enforce_stack_capacity::<CAP>();
22
23 pub fn new<S: Codec>(
25 codec: &Base64<S>,
26 maximum_input_len: usize,
27 ) -> Result<Self, SecretEncodeError> {
28 const { enforce_stack_capacity::<CAP>() }
29 let () = Self::CAPACITY_ASSERT;
30 Ok(Self {
31 state: SecretEncoderState::new(codec.settings(), maximum_input_len, CAP)?,
32 output: [0; CAP],
33 })
34 }
35
36 pub fn update(&mut self, input: &SecretInput<'_>) -> Result<Progress, SecretEncodeError> {
38 if let Err(error) = require_disjoint(input.classified_bytes(), &self.output) {
39 self.state.latch_external_failure();
40 self.fail_storage();
41 return Err(error);
42 }
43 match self
44 .state
45 .update(input.classified_bytes(), &mut self.output)
46 {
47 Ok(progress) => Ok(progress),
48 Err(error) => {
49 self.fail_storage();
50 Err(error)
51 }
52 }
53 }
54
55 pub fn finish(mut self) -> Result<SecretArray<CAP>, SecretEncodeError> {
57 let written = match self.state.finish(&mut self.output) {
58 Ok(written) => written,
59 Err(error) => {
60 self.fail_storage();
61 return Err(error);
62 }
63 };
64 let output = core::mem::replace(&mut self.output, [0; CAP]);
65 SecretArray::from_frame(output, written).map_err(|error| SecretEncodeError::OutputFull {
66 required: error.length(),
67 available: error.capacity(),
68 })
69 }
70
71 pub fn encode<S: Codec>(
73 codec: &Base64<S>,
74 input: &SecretInput<'_>,
75 ) -> Result<SecretArray<CAP>, SecretEncodeError> {
76 let mut encoder = Self::new(codec, input.len())?;
77 encoder.update(input)?;
78 encoder.finish()
79 }
80
81 #[must_use]
83 pub const fn state(&self) -> &SecretEncoderState {
84 &self.state
85 }
86
87 fn fail_storage(&mut self) {
88 crate::wipe_bytes(&mut self.output);
89 }
90
91 #[cfg(test)]
92 pub(crate) const fn storage_for_test(&self) -> &[u8; CAP] {
93 &self.output
94 }
95}
96
97#[allow(clippy::manual_assert)]
98const fn enforce_stack_capacity<const CAP: usize>() {
99 if CAP > crate::v2::secret_encoder::MAX_SECRET_STACK_ENCODED {
100 panic!("SecretArrayEncoder encoded capacity exceeds 1368-byte stack limit");
101 }
102}
103
104impl<const CAP: usize> Drop for SecretArrayEncoder<CAP> {
105 fn drop(&mut self) {
106 self.fail_storage();
107 }
108}
109
110impl<const CAP: usize> core::fmt::Debug for SecretArrayEncoder<CAP> {
111 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
112 formatter
113 .debug_struct("SecretArrayEncoder")
114 .field("output", &"<redacted>")
115 .field("state", &self.state)
116 .finish_non_exhaustive()
117 }
118}
119
120pub struct SecretEncoder<'a> {
122 state: SecretEncoderState,
123 output: Option<&'a mut [u8]>,
124}
125
126impl<'a> SecretEncoder<'a> {
127 pub fn new<S: Codec>(
129 codec: &Base64<S>,
130 maximum_input_len: usize,
131 output: &'a mut [u8],
132 ) -> Result<Self, SecretEncodeError> {
133 let state = SecretEncoderState::new(codec.settings(), maximum_input_len, output.len())?;
134 crate::wipe_bytes(output);
135 Ok(Self {
136 state,
137 output: Some(output),
138 })
139 }
140
141 pub fn update(&mut self, input: &SecretInput<'_>) -> Result<Progress, SecretEncodeError> {
143 let output = self
144 .output
145 .as_deref_mut()
146 .ok_or(SecretEncodeError::Failed)?;
147 if let Err(error) = require_disjoint(input.classified_bytes(), output) {
148 self.state.latch_external_failure();
149 crate::wipe_bytes(output);
150 return Err(error);
151 }
152 match self.state.update(input.classified_bytes(), output) {
153 Ok(progress) => Ok(progress),
154 Err(error) => {
155 crate::wipe_bytes(output);
156 Err(error)
157 }
158 }
159 }
160
161 pub fn finish(mut self) -> Result<SecretOutput<'a>, SecretEncodeError> {
163 let Some(output) = self.output.take() else {
164 return Err(SecretEncodeError::Failed);
165 };
166 let written = match self.state.finish(output) {
167 Ok(written) => written,
168 Err(error) => {
169 crate::wipe_bytes(output);
170 return Err(error);
171 }
172 };
173 let available = output.len();
174 SecretOutput::from_initialized(output, written).map_err(|_| SecretEncodeError::OutputFull {
175 required: written,
176 available,
177 })
178 }
179
180 #[must_use]
182 pub const fn state(&self) -> &SecretEncoderState {
183 &self.state
184 }
185
186 fn fail_storage(&mut self) {
187 if let Some(output) = self.output.as_deref_mut() {
188 crate::wipe_bytes(output);
189 }
190 }
191}
192
193impl Drop for SecretEncoder<'_> {
194 fn drop(&mut self) {
195 self.fail_storage();
196 }
197}
198
199impl core::fmt::Debug for SecretEncoder<'_> {
200 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
201 formatter
202 .debug_struct("SecretEncoder")
203 .field("output", &"<redacted>")
204 .field("state", &self.state)
205 .finish_non_exhaustive()
206 }
207}
208
209#[cfg(feature = "alloc")]
211pub struct SecretVecEncoder {
212 state: SecretEncoderState,
213 output: alloc::vec::Vec<u8>,
214}
215
216#[cfg(feature = "alloc")]
217impl SecretVecEncoder {
218 pub fn new<S: Codec>(
220 codec: &Base64<S>,
221 maximum_input_len: usize,
222 ) -> Result<Self, SecretEncodeError> {
223 let padded = codec.settings().encode_padding() == crate::v2::EncodePadding::Padded;
224 let required = crate::checked_encoded_len(maximum_input_len, padded)
225 .ok_or(SecretEncodeError::LengthOverflow)?;
226 let output = allocate_zeroed(required)?;
227 Ok(Self {
228 state: SecretEncoderState::new(codec.settings(), maximum_input_len, required)?,
229 output,
230 })
231 }
232
233 pub fn update(&mut self, input: &SecretInput<'_>) -> Result<Progress, SecretEncodeError> {
235 if let Err(error) = require_disjoint(input.classified_bytes(), &self.output) {
236 self.state.latch_external_failure();
237 self.fail_storage();
238 return Err(error);
239 }
240 match self
241 .state
242 .update(input.classified_bytes(), &mut self.output)
243 {
244 Ok(progress) => Ok(progress),
245 Err(error) => {
246 self.fail_storage();
247 Err(error)
248 }
249 }
250 }
251
252 pub fn finish(mut self) -> Result<SecretVec, SecretEncodeError> {
254 let written = match self.state.finish(&mut self.output) {
255 Ok(written) => written,
256 Err(error) => {
257 self.fail_storage();
258 return Err(error);
259 }
260 };
261 let output = core::mem::take(&mut self.output);
262 Ok(SecretVec::from_frame(output, written))
263 }
264
265 pub fn encode<S: Codec>(
267 codec: &Base64<S>,
268 input: &SecretInput<'_>,
269 ) -> Result<SecretVec, SecretEncodeError> {
270 let mut encoder = Self::new(codec, input.len())?;
271 encoder.update(input)?;
272 encoder.finish()
273 }
274
275 #[must_use]
277 pub const fn state(&self) -> &SecretEncoderState {
278 &self.state
279 }
280
281 #[cfg(test)]
282 pub(crate) fn allocation_snapshot(&self) -> (*const u8, usize) {
283 (self.output.as_ptr(), self.output.capacity())
284 }
285
286 fn fail_storage(&mut self) {
287 crate::wipe_bytes(&mut self.output);
288 }
289}
290
291#[cfg(feature = "alloc")]
292impl Drop for SecretVecEncoder {
293 fn drop(&mut self) {
294 self.fail_storage();
295 }
296}
297
298#[cfg(feature = "alloc")]
299impl core::fmt::Debug for SecretVecEncoder {
300 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
301 formatter
302 .debug_struct("SecretVecEncoder")
303 .field("output", &"<redacted>")
304 .field("state", &self.state)
305 .finish_non_exhaustive()
306 }
307}
308
309#[cfg(feature = "alloc")]
310fn allocate_zeroed(capacity: usize) -> Result<alloc::vec::Vec<u8>, SecretEncodeError> {
311 let mut bytes = alloc::vec::Vec::new();
312 bytes
313 .try_reserve_exact(capacity)
314 .map_err(|_| SecretEncodeError::AllocationFailed)?;
315 bytes.resize(capacity, 0);
316 Ok(bytes)
317}
318
319impl<S: Codec> Base64<S> {
320 pub fn encode_secret_array<const CAP: usize>(
322 &self,
323 input: &SecretInput<'_>,
324 ) -> Result<SecretArray<CAP>, SecretEncodeError> {
325 SecretArrayEncoder::encode(self, input)
326 }
327
328 pub fn encode_secret_into<'a>(
330 &self,
331 input: &SecretInput<'_>,
332 output: &'a mut [u8],
333 ) -> Result<SecretOutput<'a>, SecretEncodeError> {
334 require_disjoint(input.classified_bytes(), output)?;
335 let mut encoder = SecretEncoder::new(self, input.len(), output)?;
336 encoder.update(input)?;
337 encoder.finish()
338 }
339
340 #[cfg(feature = "alloc")]
342 pub fn encode_secret_vec(
343 &self,
344 input: &SecretInput<'_>,
345 ) -> Result<SecretVec, SecretEncodeError> {
346 SecretVecEncoder::encode(self, input)
347 }
348}