Skip to main content

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 as rust_alloc;
14
15#[cfg(all(not(feature = "std"), feature = "alloc"))]
16use rust_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    #[cfg(all(not(feature = "std"), feature = "alloc"))]
178    use super::rust_alloc::vec;
179
180    /// Allocate memory for sensitive data with appropriate protections
181    ///
182    /// Note: This is a placeholder for platform-specific secure allocation.
183    /// In a real implementation, this might use mlock() on Unix systems
184    /// or VirtualLock() on Windows.
185    pub fn secure_alloc<T: Default + Zeroize + Clone>(size: usize) -> Result<Vec<T>> {
186        // For now, just use regular allocation
187        // TODO: Implement platform-specific secure allocation
188        Ok(vec![T::default(); size])
189    }
190
191    /// Free memory and ensure it's zeroized
192    pub fn secure_free<T: Zeroize>(mut data: Vec<T>) {
193        // Zeroize the data
194        for item in data.iter_mut() {
195            item.zeroize();
196        }
197        // Let the vector be dropped normally
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204    use zeroize::Zeroize;
205
206    #[cfg(all(not(feature = "std"), feature = "alloc"))]
207    use super::rust_alloc::vec;
208
209    #[cfg(any(feature = "std", feature = "alloc"))]
210    struct TestOperation {
211        secret: Vec<u8>,
212        result: Option<Vec<u8>>,
213    }
214
215    #[cfg(any(feature = "std", feature = "alloc"))]
216    impl SecureOperation<Vec<u8>> for TestOperation {
217        fn execute_secure(mut self) -> Result<Vec<u8>> {
218            // Simulate some operation
219            self.result = Some(self.secret.iter().map(|&b| b ^ 0xFF).collect());
220            let result = self.result.clone().unwrap();
221            self.clear_sensitive_data();
222            Ok(result)
223        }
224
225        fn clear_sensitive_data(&mut self) {
226            self.secret.zeroize();
227            if let Some(ref mut result) = self.result {
228                result.zeroize();
229            }
230            self.result = None;
231        }
232    }
233
234    #[test]
235    #[cfg(any(feature = "std", feature = "alloc"))]
236    fn test_secure_operation() {
237        let op = TestOperation {
238            secret: vec![1, 2, 3, 4],
239            result: None,
240        };
241
242        let result = op.execute_secure().unwrap();
243        assert_eq!(result, vec![254, 253, 252, 251]);
244    }
245
246    #[test]
247    fn test_secure_compare() {
248        let a = [1u8, 2, 3, 4];
249        let b = [1u8, 2, 3, 4];
250        let c = [1u8, 2, 3, 5];
251
252        assert!(a.secure_eq(&b));
253        assert!(!a.secure_eq(&c));
254    }
255
256    #[test]
257    fn test_memory_barriers() {
258        use barrier::*;
259
260        let result = with_barriers(|| {
261            let mut x = 42;
262            x += 1;
263            x
264        });
265
266        assert_eq!(result, 43);
267    }
268}