base64_ng/v2/secret/
exposure.rs1use super::super::bounded::BufferLengthError;
4
5pub struct ExposedSecret<'a> {
11 bytes: &'a [u8],
12}
13
14impl<'a> ExposedSecret<'a> {
15 pub(super) const fn new(bytes: &'a [u8]) -> Self {
16 Self { bytes }
17 }
18
19 #[must_use]
21 pub const fn as_bytes(&self) -> &[u8] {
22 self.bytes
23 }
24
25 #[must_use]
27 pub const fn len(&self) -> usize {
28 self.bytes.len()
29 }
30
31 #[must_use]
33 pub const fn is_empty(&self) -> bool {
34 self.bytes.is_empty()
35 }
36}
37
38impl AsRef<[u8]> for ExposedSecret<'_> {
39 fn as_ref(&self) -> &[u8] {
40 self.bytes
41 }
42}
43
44impl core::ops::Deref for ExposedSecret<'_> {
45 type Target = [u8];
46
47 fn deref(&self) -> &Self::Target {
48 self.bytes
49 }
50}
51
52redacted_formatting!(ExposedSecret<'_>, "ExposedSecret");
53
54pub struct ExposedSecretMut<'a> {
58 pub(super) bytes: &'a mut [u8],
59}
60
61impl ExposedSecretMut<'_> {
62 #[must_use]
64 pub fn as_bytes(&self) -> &[u8] {
65 self.bytes
66 }
67
68 #[must_use]
70 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
71 self.bytes
72 }
73
74 #[must_use]
76 pub fn len(&self) -> usize {
77 self.bytes.len()
78 }
79
80 #[must_use]
82 pub fn is_empty(&self) -> bool {
83 self.bytes.is_empty()
84 }
85}
86
87impl AsRef<[u8]> for ExposedSecretMut<'_> {
88 fn as_ref(&self) -> &[u8] {
89 self.bytes
90 }
91}
92
93impl AsMut<[u8]> for ExposedSecretMut<'_> {
94 fn as_mut(&mut self) -> &mut [u8] {
95 self.bytes
96 }
97}
98
99impl core::ops::Deref for ExposedSecretMut<'_> {
100 type Target = [u8];
101
102 fn deref(&self) -> &Self::Target {
103 self.bytes
104 }
105}
106
107impl core::ops::DerefMut for ExposedSecretMut<'_> {
108 fn deref_mut(&mut self) -> &mut Self::Target {
109 self.bytes
110 }
111}
112
113redacted_formatting!(ExposedSecretMut<'_>, "ExposedSecretMut");
114
115pub struct SecretInput<'a> {
121 bytes: &'a [u8],
122}
123
124impl<'a> SecretInput<'a> {
125 #[must_use]
127 pub const fn new(bytes: &'a [u8]) -> Self {
128 Self { bytes }
129 }
130
131 #[must_use]
133 pub const fn expose_secret(&self) -> ExposedSecret<'_> {
134 ExposedSecret::new(self.bytes)
135 }
136
137 #[must_use]
139 pub const fn len(&self) -> usize {
140 self.bytes.len()
141 }
142
143 #[must_use]
145 pub const fn is_empty(&self) -> bool {
146 self.bytes.is_empty()
147 }
148
149 pub(crate) const fn classified_bytes(&self) -> &[u8] {
150 self.bytes
151 }
152}
153
154redacted_formatting!(SecretInput<'_>, "SecretInput");
155
156pub struct SecretOutput<'a> {
162 storage: &'a mut [u8],
163 len: usize,
164}
165
166impl<'a> SecretOutput<'a> {
167 pub fn from_initialized(storage: &'a mut [u8], len: usize) -> Result<Self, BufferLengthError> {
171 let capacity = storage.len();
172 if len > capacity {
173 crate::wipe_bytes(storage);
174 return Err(BufferLengthError::new(len, capacity));
175 }
176 crate::wipe_tail(storage, len);
177 Ok(Self { storage, len })
178 }
179
180 #[must_use]
182 pub fn empty(storage: &'a mut [u8]) -> Self {
183 crate::wipe_bytes(storage);
184 Self { storage, len: 0 }
185 }
186
187 #[must_use]
189 pub fn expose_secret(&self) -> ExposedSecret<'_> {
190 ExposedSecret::new(&self.storage[..self.len])
191 }
192
193 #[must_use]
195 pub fn expose_secret_mut(&mut self) -> ExposedSecretMut<'_> {
196 ExposedSecretMut {
197 bytes: &mut self.storage[..self.len],
198 }
199 }
200
201 #[must_use = "declassification transfers cleanup responsibility to the caller"]
206 pub fn declassify(mut self) -> DeclassifiedOutput<'a> {
207 let storage = core::mem::take(&mut self.storage);
208 let len = self.len;
209 self.len = 0;
210 DeclassifiedOutput { storage, len }
211 }
212
213 #[must_use]
215 pub const fn len(&self) -> usize {
216 self.len
217 }
218
219 #[must_use]
221 pub fn capacity(&self) -> usize {
222 self.storage.len()
223 }
224
225 #[must_use]
227 pub const fn is_empty(&self) -> bool {
228 self.len == 0
229 }
230
231 pub fn clear(&mut self) {
233 crate::wipe_bytes(self.storage);
234 self.len = 0;
235 }
236}
237
238impl Drop for SecretOutput<'_> {
239 fn drop(&mut self) {
240 self.clear();
241 }
242}
243
244redacted_formatting!(SecretOutput<'_>, "SecretOutput");
245
246pub struct DeclassifiedOutput<'a> {
250 storage: &'a mut [u8],
251 len: usize,
252}
253
254impl<'a> DeclassifiedOutput<'a> {
255 #[must_use]
257 pub fn as_bytes(&self) -> &[u8] {
258 &self.storage[..self.len]
259 }
260
261 #[must_use]
263 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
264 &mut self.storage[..self.len]
265 }
266
267 #[must_use]
269 pub const fn len(&self) -> usize {
270 self.len
271 }
272
273 #[must_use]
275 pub const fn is_empty(&self) -> bool {
276 self.len == 0
277 }
278
279 #[must_use]
281 pub fn into_parts(self) -> (&'a mut [u8], usize) {
282 (self.storage, self.len)
283 }
284}
285
286impl AsRef<[u8]> for DeclassifiedOutput<'_> {
287 fn as_ref(&self) -> &[u8] {
288 self.as_bytes()
289 }
290}
291
292impl AsMut<[u8]> for DeclassifiedOutput<'_> {
293 fn as_mut(&mut self) -> &mut [u8] {
294 self.as_bytes_mut()
295 }
296}