dcrypt_common/security/
secret.rs1use core::convert::{AsMut, AsRef};
7use core::fmt;
8use core::ops::{Deref, DerefMut};
9use zeroize::{Zeroize, ZeroizeOnDrop};
10
11#[cfg(all(feature = "alloc", not(feature = "std")))]
13extern crate alloc;
14
15#[cfg(all(feature = "alloc", not(feature = "std")))]
16use alloc::vec::Vec;
17
18#[cfg(feature = "std")]
19use std::vec::Vec;
20
21pub trait SecureZeroingType: Zeroize + Clone {
23 fn zeroed() -> Self;
25
26 fn secure_clone(&self) -> Self {
31 self.clone() }
33}
34
35#[derive(Clone, Zeroize, ZeroizeOnDrop)]
42pub struct SecretBuffer<const N: usize> {
43 data: [u8; N],
44}
45
46impl<const N: usize> SecretBuffer<N> {
47 pub fn new(data: [u8; N]) -> Self {
49 Self { data }
50 }
51
52 pub fn zeroed() -> Self {
54 Self { data: [0u8; N] }
55 }
56
57 pub fn len(&self) -> usize {
59 N
60 }
61
62 pub fn is_empty(&self) -> bool {
64 N == 0
65 }
66
67 pub fn as_slice(&self) -> &[u8] {
69 &self.data
70 }
71
72 pub fn as_mut_slice(&mut self) -> &mut [u8] {
74 &mut self.data
75 }
76}
77
78impl<const N: usize> SecureZeroingType for SecretBuffer<N> {
79 fn zeroed() -> Self {
80 Self::zeroed()
81 }
82
83 fn secure_clone(&self) -> Self {
84 Self::new(self.data) }
86}
87
88impl<const N: usize> AsRef<[u8]> for SecretBuffer<N> {
89 fn as_ref(&self) -> &[u8] {
90 &self.data
91 }
92}
93
94impl<const N: usize> AsMut<[u8]> for SecretBuffer<N> {
95 fn as_mut(&mut self) -> &mut [u8] {
96 &mut self.data
97 }
98}
99
100impl<const N: usize> fmt::Debug for SecretBuffer<N> {
101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
102 write!(f, "SecretBuffer<{}>([REDACTED])", N)
103 }
104}
105
106#[cfg(feature = "alloc")]
113#[derive(Clone, Zeroize, ZeroizeOnDrop)]
114pub struct SecretVec {
115 data: Vec<u8>,
116}
117
118#[cfg(feature = "alloc")]
119impl SecretVec {
120 pub fn new(data: Vec<u8>) -> Self {
122 Self { data }
123 }
124
125 pub fn from_slice(slice: &[u8]) -> Self {
127 Self {
128 data: slice.to_vec(),
129 }
130 }
131
132 pub fn empty() -> Self {
134 Self { data: Vec::new() }
135 }
136
137 pub fn with_capacity(capacity: usize) -> Self {
139 Self {
140 data: Vec::with_capacity(capacity),
141 }
142 }
143
144 pub fn len(&self) -> usize {
146 self.data.len()
147 }
148
149 pub fn is_empty(&self) -> bool {
151 self.data.is_empty()
152 }
153
154 pub fn as_slice(&self) -> &[u8] {
156 &self.data
157 }
158
159 pub fn as_mut_slice(&mut self) -> &mut [u8] {
161 &mut self.data
162 }
163
164 pub fn extend_from_slice(&mut self, slice: &[u8]) {
166 self.data.extend_from_slice(slice);
167 }
168
169 pub fn resize(&mut self, new_len: usize, value: u8) {
171 self.data.resize(new_len, value);
172 }
173
174 pub fn truncate(&mut self, len: usize) {
176 self.data.truncate(len);
177 }
178}
179
180#[cfg(feature = "alloc")]
181impl SecureZeroingType for SecretVec {
182 fn zeroed() -> Self {
183 Self::empty()
184 }
185
186 fn secure_clone(&self) -> Self {
187 Self::new(self.data.clone())
188 }
189}
190
191#[cfg(feature = "alloc")]
192impl AsRef<[u8]> for SecretVec {
193 fn as_ref(&self) -> &[u8] {
194 &self.data
195 }
196}
197
198#[cfg(feature = "alloc")]
199impl AsMut<[u8]> for SecretVec {
200 fn as_mut(&mut self) -> &mut [u8] {
201 &mut self.data
202 }
203}
204
205#[cfg(feature = "alloc")]
206impl From<Vec<u8>> for SecretVec {
207 fn from(data: Vec<u8>) -> Self {
208 Self::new(data)
209 }
210}
211
212#[cfg(feature = "alloc")]
213impl fmt::Debug for SecretVec {
214 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
215 write!(f, "SecretVec(len={}, [REDACTED])", self.data.len())
216 }
217}
218
219pub struct EphemeralSecret<T: Zeroize> {
224 inner: T,
225}
226
227impl<T: Zeroize> EphemeralSecret<T> {
228 pub fn new(value: T) -> Self {
230 Self { inner: value }
231 }
232
233 pub fn into_inner(self) -> T {
238 let this = core::mem::ManuallyDrop::new(self);
239 unsafe { core::ptr::read(&this.inner) }
240 }
241}
242
243impl<T: Zeroize> AsRef<T> for EphemeralSecret<T> {
245 fn as_ref(&self) -> &T {
246 &self.inner
247 }
248}
249
250impl<T: Zeroize> AsMut<T> for EphemeralSecret<T> {
251 fn as_mut(&mut self) -> &mut T {
252 &mut self.inner
253 }
254}
255
256impl<T: Zeroize> Drop for EphemeralSecret<T> {
257 fn drop(&mut self) {
258 self.inner.zeroize();
259 }
260}
261
262impl<T: Zeroize + Clone> Clone for EphemeralSecret<T> {
263 fn clone(&self) -> Self {
264 Self::new(self.inner.clone())
265 }
266}
267
268impl<T: Zeroize + Default> Default for EphemeralSecret<T> {
269 fn default() -> Self {
270 Self::new(T::default())
271 }
272}
273
274impl<T: Zeroize> Deref for EphemeralSecret<T> {
275 type Target = T;
276
277 fn deref(&self) -> &Self::Target {
278 &self.inner
279 }
280}
281
282impl<T: Zeroize> DerefMut for EphemeralSecret<T> {
283 fn deref_mut(&mut self) -> &mut Self::Target {
284 &mut self.inner
285 }
286}
287
288impl<T: Zeroize + fmt::Debug> fmt::Debug for EphemeralSecret<T> {
289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 write!(f, "EphemeralSecret([REDACTED])")
291 }
292}
293
294pub struct ZeroizeGuard<'a, T: Zeroize> {
299 value: &'a mut T,
300}
301
302impl<'a, T: Zeroize> ZeroizeGuard<'a, T> {
303 pub fn new(value: &'a mut T) -> Self {
305 Self { value }
306 }
307}
308
309impl<T: Zeroize> Drop for ZeroizeGuard<'_, T> {
311 fn drop(&mut self) {
312 self.value.zeroize();
313 }
314}
315
316impl<T: Zeroize> Deref for ZeroizeGuard<'_, T> {
317 type Target = T;
318
319 fn deref(&self) -> &Self::Target {
320 self.value
321 }
322}
323
324impl<T: Zeroize> DerefMut for ZeroizeGuard<'_, T> {
325 fn deref_mut(&mut self) -> &mut Self::Target {
326 self.value
327 }
328}
329
330#[cfg(test)]
331mod tests {
332 use super::*;
333
334 #[test]
335 fn test_secret_buffer_basic() {
336 let mut buffer = SecretBuffer::<32>::new([42u8; 32]);
337 assert_eq!(buffer.len(), 32);
338 assert_eq!(buffer.as_slice()[0], 42);
339
340 buffer.as_mut_slice()[0] = 1;
342 assert_eq!(buffer.as_slice()[0], 1);
343 }
344
345 #[test]
346 fn test_secret_buffer_secure_clone() {
347 let buffer = SecretBuffer::<16>::new([0xAA; 16]);
348 let cloned = buffer.secure_clone();
349 assert_eq!(cloned.as_slice(), buffer.as_slice());
350 }
351
352 #[test]
353 fn test_secret_buffer_zeroed() {
354 let zeroed = SecretBuffer::<32>::zeroed();
355 assert_eq!(zeroed.as_slice(), &[0u8; 32]);
356 }
357
358 #[cfg(feature = "alloc")]
359 #[test]
360 fn test_secret_vec_operations() {
361 let mut vec = SecretVec::from_slice(&[1, 2, 3, 4]);
362 assert_eq!(vec.len(), 4);
363 assert_eq!(vec.as_slice(), &[1, 2, 3, 4]);
364
365 vec.extend_from_slice(&[5, 6]);
367 assert_eq!(vec.as_slice(), &[1, 2, 3, 4, 5, 6]);
368
369 vec.truncate(3);
371 assert_eq!(vec.as_slice(), &[1, 2, 3]);
372
373 vec.resize(5, 0xFF);
375 assert_eq!(vec.as_slice(), &[1, 2, 3, 0xFF, 0xFF]);
376 }
377
378 #[test]
379 fn test_ephemeral_secret() {
380 #[derive(Clone, Zeroize)]
381 struct TestSecret(u64);
382
383 let secret = EphemeralSecret::new(TestSecret(42));
384 assert_eq!(secret.0, 42);
385
386 let value = secret.0;
388 assert_eq!(value, 42);
389
390 let cloned = secret.clone();
392 assert_eq!(cloned.0, 42);
393
394 let inner = secret.into_inner();
396 assert_eq!(inner.0, 42);
397 }
398
399 #[test]
400 fn test_zeroize_guard() {
401 let mut value = vec![1u8, 2, 3, 4];
402 {
403 let guard = ZeroizeGuard::new(&mut value);
404 assert_eq!(&**guard, &[1, 2, 3, 4]);
406 }
407 assert!(value.is_empty());
409 }
410}