dcrypt_common/security/
secret.rs

1//! Secret data types with guaranteed zeroization
2//!
3//! This module provides type-safe wrappers for sensitive data that ensure
4//! proper cleanup and zeroization when the data is no longer needed.
5
6use core::convert::{AsMut, AsRef};
7use core::fmt;
8use core::ops::{Deref, DerefMut};
9use zeroize::{Zeroize, ZeroizeOnDrop};
10
11// Handle Vec import based on features
12#[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
21/// Trait for types that can be securely zeroed and cloned
22pub trait SecureZeroingType: Zeroize + Clone {
23    /// Create a zeroed instance
24    fn zeroed() -> Self;
25
26    /// Create a secure clone that preserves security properties
27    ///
28    /// This method ensures that cloned instances maintain the same
29    /// security guarantees as the original, including proper zeroization.
30    fn secure_clone(&self) -> Self {
31        self.clone() // Default implementation uses regular clone
32    }
33}
34
35/// Fixed-size secret buffer that guarantees zeroization
36///
37/// This type provides:
38/// - Automatic zeroization on drop
39/// - Secure cloning that preserves security properties
40/// - Type-safe size guarantees at compile time
41#[derive(Clone, Zeroize, ZeroizeOnDrop)]
42pub struct SecretBuffer<const N: usize> {
43    data: [u8; N],
44}
45
46impl<const N: usize> SecretBuffer<N> {
47    /// Create a new secret buffer with the given data
48    pub fn new(data: [u8; N]) -> Self {
49        Self { data }
50    }
51
52    /// Create a zeroed secret buffer
53    pub fn zeroed() -> Self {
54        Self { data: [0u8; N] }
55    }
56
57    /// Get the length of the buffer
58    pub fn len(&self) -> usize {
59        N
60    }
61
62    /// Check if the buffer is empty (always false for non-zero N)
63    pub fn is_empty(&self) -> bool {
64        N == 0
65    }
66
67    /// Get a reference to the inner data
68    pub fn as_slice(&self) -> &[u8] {
69        &self.data
70    }
71
72    /// Get a mutable reference to the inner data
73    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) // Fixed: removed .clone() since [u8; N] implements Copy
85    }
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/// Variable-size secret vector that guarantees zeroization
107///
108/// This type provides:
109/// - Automatic zeroization on drop
110/// - Secure cloning that preserves security properties
111/// - Dynamic sizing with secure memory management
112#[cfg(feature = "alloc")]
113#[derive(Clone, Zeroize, ZeroizeOnDrop)]
114pub struct SecretVec {
115    data: Vec<u8>,
116}
117
118#[cfg(feature = "alloc")]
119impl SecretVec {
120    /// Create a new secret vector with the given data
121    pub fn new(data: Vec<u8>) -> Self {
122        Self { data }
123    }
124
125    /// Create a secret vector from a slice
126    pub fn from_slice(slice: &[u8]) -> Self {
127        Self {
128            data: slice.to_vec(),
129        }
130    }
131
132    /// Create an empty secret vector
133    pub fn empty() -> Self {
134        Self { data: Vec::new() }
135    }
136
137    /// Create a secret vector with the specified capacity
138    pub fn with_capacity(capacity: usize) -> Self {
139        Self {
140            data: Vec::with_capacity(capacity),
141        }
142    }
143
144    /// Get the length of the vector
145    pub fn len(&self) -> usize {
146        self.data.len()
147    }
148
149    /// Check if the vector is empty
150    pub fn is_empty(&self) -> bool {
151        self.data.is_empty()
152    }
153
154    /// Get a reference to the inner data
155    pub fn as_slice(&self) -> &[u8] {
156        &self.data
157    }
158
159    /// Get a mutable reference to the inner data
160    pub fn as_mut_slice(&mut self) -> &mut [u8] {
161        &mut self.data
162    }
163
164    /// Extend the vector with additional data
165    pub fn extend_from_slice(&mut self, slice: &[u8]) {
166        self.data.extend_from_slice(slice);
167    }
168
169    /// Resize the vector to the specified length
170    pub fn resize(&mut self, new_len: usize, value: u8) {
171        self.data.resize(new_len, value);
172    }
173
174    /// Truncate the vector to the specified length
175    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
219/// Ephemeral secret that is automatically zeroized after use
220///
221/// This type wraps any type T and ensures it is zeroized when dropped.
222/// It's useful for temporary secrets and intermediate cryptographic values.
223pub struct EphemeralSecret<T: Zeroize> {
224    inner: T,
225}
226
227impl<T: Zeroize> EphemeralSecret<T> {
228    /// Create a new ephemeral secret
229    pub fn new(value: T) -> Self {
230        Self { inner: value }
231    }
232
233    /// Consume the secret and return the inner value
234    ///
235    /// Note: After calling this method, the caller is responsible
236    /// for ensuring the value is properly zeroized.
237    pub fn into_inner(self) -> T {
238        let this = core::mem::ManuallyDrop::new(self);
239        unsafe { core::ptr::read(&this.inner) }
240    }
241}
242
243// Fixed: Implement actual AsRef and AsMut traits instead of methods
244impl<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
294/// Guard type that ensures a value is zeroized when dropped
295///
296/// This is useful for ensuring cleanup happens even in the presence
297/// of early returns or panics.
298pub struct ZeroizeGuard<'a, T: Zeroize> {
299    value: &'a mut T,
300}
301
302impl<'a, T: Zeroize> ZeroizeGuard<'a, T> {
303    /// Create a new zeroize guard for the given value
304    pub fn new(value: &'a mut T) -> Self {
305        Self { value }
306    }
307}
308
309// Fixed: Use lifetime elision instead of explicit lifetimes
310impl<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        // Test mutation
341        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        // Test extend
366        vec.extend_from_slice(&[5, 6]);
367        assert_eq!(vec.as_slice(), &[1, 2, 3, 4, 5, 6]);
368
369        // Test truncate
370        vec.truncate(3);
371        assert_eq!(vec.as_slice(), &[1, 2, 3]);
372
373        // Test resize
374        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        // Test deref
387        let value = secret.0;
388        assert_eq!(value, 42);
389
390        // Test clone
391        let cloned = secret.clone();
392        assert_eq!(cloned.0, 42);
393
394        // Test into_inner
395        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            // Simulate work with the value
405            assert_eq!(&**guard, &[1, 2, 3, 4]);
406        }
407        // Guard should have zeroized the value (which clears the Vec)
408        assert!(value.is_empty());
409    }
410}