dcrypt_common/security/
memory.rs

1//! Memory safety patterns and secure operations
2//!
3//! This module provides traits and utilities for ensuring memory safety
4//! in cryptographic operations.
5
6use dcrypt_api::Result;
7
8// Handle Vec and Box imports based on features
9#[cfg(feature = "std")]
10use std::{boxed::Box, vec::Vec};
11
12#[cfg(all(not(feature = "std"), feature = "alloc"))]
13extern crate alloc;
14
15#[cfg(all(not(feature = "std"), feature = "alloc"))]
16use alloc::{boxed::Box, vec::Vec};
17
18/// Type alias for cleanup functions used in secure operations
19#[cfg(any(feature = "std", feature = "alloc"))]
20pub type CleanupFn<T> = Box<dyn FnOnce(&mut T)>;
21
22/// Trait for secure cryptographic operations
23///
24/// This trait ensures that sensitive data is properly handled and cleared
25/// after operations complete, whether they succeed or fail.
26pub trait SecureOperation<T> {
27    /// Execute the operation securely
28    ///
29    /// This method should:
30    /// 1. Perform the cryptographic operation
31    /// 2. Clear all sensitive intermediate data
32    /// 3. Return the result or error
33    fn execute_secure(self) -> Result<T>;
34
35    /// Clear all sensitive data associated with this operation
36    ///
37    /// This method is called automatically by `execute_secure` but can
38    /// also be called manually when needed.
39    fn clear_sensitive_data(&mut self);
40}
41
42/// Extension trait for operations that produce a result
43pub trait SecureOperationExt: Sized {
44    type Output;
45
46    /// Execute the operation and ensure cleanup on both success and failure
47    fn execute_with_cleanup<F>(self, cleanup: F) -> Result<Self::Output>
48    where
49        F: FnOnce();
50}
51
52/// Builder pattern for secure operations
53///
54/// This pattern allows for composing operations while maintaining
55/// security guarantees at each step.
56#[cfg(any(feature = "std", feature = "alloc"))]
57pub struct SecureOperationBuilder<T> {
58    state: T,
59    cleanup_fns: Vec<CleanupFn<T>>,
60}
61
62#[cfg(any(feature = "std", feature = "alloc"))]
63impl<T> SecureOperationBuilder<T> {
64    /// Create a new secure operation builder
65    pub fn new(initial_state: T) -> Self {
66        Self {
67            state: initial_state,
68            cleanup_fns: Vec::new(),
69        }
70    }
71
72    /// Add a cleanup function to be called when the operation completes
73    pub fn with_cleanup<F>(mut self, cleanup: F) -> Self
74    where
75        F: FnOnce(&mut T) + 'static,
76    {
77        self.cleanup_fns.push(Box::new(cleanup));
78        self
79    }
80
81    /// Transform the state
82    pub fn transform<U, F>(self, f: F) -> SecureOperationBuilder<U>
83    where
84        F: FnOnce(T) -> U,
85    {
86        SecureOperationBuilder {
87            state: f(self.state),
88            cleanup_fns: Vec::new(), // Cleanup functions don't transfer
89        }
90    }
91
92    /// Build and execute the operation
93    pub fn build<O, F>(self, operation: F) -> Result<O>
94    where
95        F: FnOnce(&mut T) -> Result<O>,
96    {
97        let mut state = self.state;
98        let result = operation(&mut state);
99
100        // Execute cleanup functions regardless of success/failure
101        for cleanup in self.cleanup_fns.into_iter().rev() {
102            cleanup(&mut state);
103        }
104
105        result
106    }
107}
108
109/// Trait for types that can be securely compared
110///
111/// This trait provides constant-time comparison operations to prevent
112/// timing attacks.
113pub trait SecureCompare: Sized {
114    /// Compare two values in constant time
115    fn secure_eq(&self, other: &Self) -> bool;
116
117    /// Compare two values and return a constant-time choice
118    fn secure_cmp(&self, other: &Self) -> subtle::Choice;
119}
120
121impl<const N: usize> SecureCompare for [u8; N] {
122    fn secure_eq(&self, other: &Self) -> bool {
123        use subtle::ConstantTimeEq;
124        bool::from(self.ct_eq(other))
125    }
126
127    fn secure_cmp(&self, other: &Self) -> subtle::Choice {
128        use subtle::ConstantTimeEq;
129        self.ct_eq(other)
130    }
131}
132
133impl SecureCompare for &[u8] {
134    fn secure_eq(&self, other: &Self) -> bool {
135        use subtle::ConstantTimeEq;
136        bool::from(self.ct_eq(other))
137    }
138
139    fn secure_cmp(&self, other: &Self) -> subtle::Choice {
140        use subtle::ConstantTimeEq;
141        self.ct_eq(other)
142    }
143}
144
145/// Memory barrier utilities
146pub mod barrier {
147    use core::sync::atomic::{compiler_fence, fence, Ordering};
148
149    /// Insert a compiler fence to prevent reordering
150    #[inline(always)]
151    pub fn compiler_fence_seq_cst() {
152        compiler_fence(Ordering::SeqCst);
153    }
154
155    /// Insert a full memory fence
156    #[inline(always)]
157    pub fn memory_fence_seq_cst() {
158        fence(Ordering::SeqCst);
159    }
160
161    /// Execute a closure with memory barriers before and after
162    #[inline(always)]
163    pub fn with_barriers<T, F: FnOnce() -> T>(f: F) -> T {
164        compiler_fence_seq_cst();
165        let result = f();
166        compiler_fence_seq_cst();
167        result
168    }
169}
170
171/// Secure allocation utilities
172#[cfg(feature = "alloc")]
173pub mod alloc {
174    use super::*;
175    use zeroize::Zeroize;
176
177    /// Allocate memory for sensitive data with appropriate protections
178    ///
179    /// Note: This is a placeholder for platform-specific secure allocation.
180    /// In a real implementation, this might use mlock() on Unix systems
181    /// or VirtualLock() on Windows.
182    pub fn secure_alloc<T: Default + Zeroize + Clone>(size: usize) -> Result<Vec<T>> {
183        // For now, just use regular allocation
184        // TODO: Implement platform-specific secure allocation
185        Ok(vec![T::default(); size])
186    }
187
188    /// Free memory and ensure it's zeroized
189    pub fn secure_free<T: Zeroize>(mut data: Vec<T>) {
190        // Zeroize the data
191        for item in data.iter_mut() {
192            item.zeroize();
193        }
194        // Let the vector be dropped normally
195    }
196}
197
198#[cfg(test)]
199mod tests {
200    use super::*;
201    use zeroize::Zeroize;
202
203    #[cfg(any(feature = "std", feature = "alloc"))]
204    struct TestOperation {
205        secret: Vec<u8>,
206        result: Option<Vec<u8>>,
207    }
208
209    #[cfg(any(feature = "std", feature = "alloc"))]
210    impl SecureOperation<Vec<u8>> for TestOperation {
211        fn execute_secure(mut self) -> Result<Vec<u8>> {
212            // Simulate some operation
213            self.result = Some(self.secret.iter().map(|&b| b ^ 0xFF).collect());
214            let result = self.result.clone().unwrap();
215            self.clear_sensitive_data();
216            Ok(result)
217        }
218
219        fn clear_sensitive_data(&mut self) {
220            self.secret.zeroize();
221            if let Some(ref mut result) = self.result {
222                result.zeroize();
223            }
224            self.result = None;
225        }
226    }
227
228    #[test]
229    #[cfg(any(feature = "std", feature = "alloc"))]
230    fn test_secure_operation() {
231        let op = TestOperation {
232            secret: vec![1, 2, 3, 4],
233            result: None,
234        };
235
236        let result = op.execute_secure().unwrap();
237        assert_eq!(result, vec![254, 253, 252, 251]);
238    }
239
240    #[test]
241    fn test_secure_compare() {
242        let a = [1u8, 2, 3, 4];
243        let b = [1u8, 2, 3, 4];
244        let c = [1u8, 2, 3, 5];
245
246        assert!(a.secure_eq(&b));
247        assert!(!a.secure_eq(&c));
248    }
249
250    #[test]
251    fn test_memory_barriers() {
252        use barrier::*;
253
254        let result = with_barriers(|| {
255            let mut x = 42;
256            x += 1;
257            x
258        });
259
260        assert_eq!(result, 43);
261    }
262}