dcrypt_common/security/
memory.rs1use dcrypt_api::Result;
7
8#[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#[cfg(any(feature = "std", feature = "alloc"))]
20pub type CleanupFn<T> = Box<dyn FnOnce(&mut T)>;
21
22pub trait SecureOperation<T> {
27 fn execute_secure(self) -> Result<T>;
34
35 fn clear_sensitive_data(&mut self);
40}
41
42pub trait SecureOperationExt: Sized {
44 type Output;
45
46 fn execute_with_cleanup<F>(self, cleanup: F) -> Result<Self::Output>
48 where
49 F: FnOnce();
50}
51
52#[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 pub fn new(initial_state: T) -> Self {
66 Self {
67 state: initial_state,
68 cleanup_fns: Vec::new(),
69 }
70 }
71
72 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 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(), }
90 }
91
92 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 for cleanup in self.cleanup_fns.into_iter().rev() {
102 cleanup(&mut state);
103 }
104
105 result
106 }
107}
108
109pub trait SecureCompare: Sized {
114 fn secure_eq(&self, other: &Self) -> bool;
116
117 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
145pub mod barrier {
147 use core::sync::atomic::{compiler_fence, fence, Ordering};
148
149 #[inline(always)]
151 pub fn compiler_fence_seq_cst() {
152 compiler_fence(Ordering::SeqCst);
153 }
154
155 #[inline(always)]
157 pub fn memory_fence_seq_cst() {
158 fence(Ordering::SeqCst);
159 }
160
161 #[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#[cfg(feature = "alloc")]
173pub mod alloc {
174 use super::*;
175 use zeroize::Zeroize;
176
177 pub fn secure_alloc<T: Default + Zeroize + Clone>(size: usize) -> Result<Vec<T>> {
183 Ok(vec![T::default(); size])
186 }
187
188 pub fn secure_free<T: Zeroize>(mut data: Vec<T>) {
190 for item in data.iter_mut() {
192 item.zeroize();
193 }
194 }
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 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}