lib_q_aead/security/memory.rs
1//! Secure memory handling and zeroization
2//!
3//! This module provides secure memory management functions including:
4//! - Automatic zeroization of sensitive data
5//! - Secure memory allocation and deallocation
6//! - Memory barrier operations
7//! - Secure memory copying and comparison
8
9use core::ptr;
10
11/// Secure memory zeroization
12///
13/// Securely zeros a memory region to prevent sensitive data from remaining
14/// in memory after use. This function uses compiler barriers to prevent
15/// optimization that might skip the zeroing.
16///
17/// # Arguments
18/// * `data` - Memory region to zero
19///
20/// # Security
21/// This function uses compiler barriers to ensure the zeroing operation
22/// is not optimized away by the compiler.
23pub fn secure_zero<T>(data: &mut T) {
24 let size = size_of_val(data);
25 let ptr = data as *mut T as *mut u8;
26
27 unsafe {
28 ptr::write_bytes(ptr, 0, size);
29 }
30 // Compiler barrier to prevent optimization
31 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
32}
33
34/// Secure zeroization of a slice
35///
36/// Securely zeros a slice of memory to prevent sensitive data from remaining
37/// in memory after use.
38///
39/// # Arguments
40/// * `data` - Slice to zero
41///
42/// # Security
43/// This function uses compiler barriers to ensure the zeroing operation
44/// is not optimized away by the compiler.
45pub fn secure_zero_slice(data: &mut [u8]) {
46 for byte in data.iter_mut() {
47 *byte = 0;
48 }
49
50 // Compiler barrier to prevent optimization
51 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
52}
53
54/// Secure memory copy
55///
56/// Securely copies memory from source to destination, ensuring that
57/// sensitive data is properly handled.
58///
59/// # Arguments
60/// * `dst` - Destination memory
61/// * `src` - Source memory
62///
63/// # Security
64/// This function uses secure memory operations to prevent data leakage.
65pub fn secure_copy<T>(dst: &mut T, src: &T) {
66 let size = size_of_val(src);
67 let dst_ptr = dst as *mut T as *mut u8;
68 let src_ptr = src as *const T as *const u8;
69
70 unsafe {
71 ptr::copy_nonoverlapping(src_ptr, dst_ptr, size);
72 }
73 // Compiler barrier to prevent optimization
74 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
75}
76
77/// Secure memory copy for slices
78///
79/// Securely copies memory from source slice to destination slice.
80///
81/// # Arguments
82/// * `dst` - Destination slice
83/// * `src` - Source slice
84///
85/// # Panics
86/// Panics if the slices have different lengths.
87///
88/// # Security
89/// This function uses secure memory operations to prevent data leakage.
90pub fn secure_copy_slice(dst: &mut [u8], src: &[u8]) {
91 assert_eq!(dst.len(), src.len());
92
93 for (d, s) in dst.iter_mut().zip(src.iter()) {
94 *d = *s;
95 }
96
97 // Compiler barrier to prevent optimization
98 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
99}
100
101/// Secure memory move
102///
103/// Securely moves memory from source to destination, zeroing the source
104/// after the move to prevent data leakage.
105///
106/// # Arguments
107/// * `dst` - Destination memory
108/// * `src` - Source memory
109///
110/// # Security
111/// This function securely moves data and zeroes the source to prevent
112/// sensitive data from remaining in memory.
113pub fn secure_move<T>(dst: &mut T, src: &mut T) {
114 secure_copy(dst, src);
115 secure_zero(src);
116}
117
118/// Secure memory move for slices
119///
120/// Securely moves memory from source slice to destination slice, zeroing
121/// the source after the move.
122///
123/// # Arguments
124/// * `dst` - Destination slice
125/// * `src` - Source slice
126///
127/// # Panics
128/// Panics if the slices have different lengths.
129///
130/// # Security
131/// This function securely moves data and zeroes the source to prevent
132/// sensitive data from remaining in memory.
133pub fn secure_move_slice(dst: &mut [u8], src: &mut [u8]) {
134 secure_copy_slice(dst, src);
135 secure_zero_slice(src);
136}
137
138/// Secure memory comparison
139///
140/// Securely compares two memory regions in constant time to prevent
141/// timing attacks.
142///
143/// # Arguments
144/// * `a` - First memory region
145/// * `b` - Second memory region
146///
147/// # Returns
148/// * `true` if the regions are equal, `false` otherwise
149///
150/// # Security
151/// This function performs the comparison in constant time to prevent
152/// timing attacks.
153pub fn secure_compare<T>(a: &T, b: &T) -> bool {
154 let size = size_of_val(a);
155 let a_ptr = a as *const T as *const u8;
156 let b_ptr = b as *const T as *const u8;
157
158 let mut result = 0u8;
159
160 unsafe {
161 for i in 0..size {
162 result |= *a_ptr.add(i) ^ *b_ptr.add(i);
163 }
164 }
165
166 result == 0
167}
168
169/// Secure memory comparison for slices
170///
171/// Securely compares two slices in constant time to prevent timing attacks.
172///
173/// # Arguments
174/// * `a` - First slice
175/// * `b` - Second slice
176///
177/// # Returns
178/// * `true` if the slices are equal, `false` otherwise
179///
180/// # Security
181/// This function performs the comparison in constant time to prevent
182/// timing attacks.
183pub fn secure_compare_slice(a: &[u8], b: &[u8]) -> bool {
184 if a.len() != b.len() {
185 return false;
186 }
187
188 let mut result = 0u8;
189 for (x, y) in a.iter().zip(b.iter()) {
190 result |= x ^ y;
191 }
192
193 result == 0
194}
195
196/// Secure memory allocation with enhanced security features
197///
198/// Allocates memory securely with proper alignment, zeroing, and protection.
199/// Implements secure memory allocation best practices including:
200/// - Proper alignment for security-sensitive data
201/// - Memory zeroing to prevent data leakage
202/// - Compiler barriers to prevent optimization
203/// - Memory protection where available
204///
205/// # Arguments
206/// * `size` - Size of memory to allocate
207/// * `alignment` - Memory alignment (defaults to cache line size for security)
208///
209/// # Returns
210/// * `Some(ptr)` if allocation succeeds, `None` otherwise
211///
212/// # Security
213/// This function allocates memory securely and zeros it to prevent
214/// data leakage from previous allocations. Uses cache-line alignment
215/// to prevent side-channel attacks through cache timing.
216#[cfg(feature = "alloc")]
217pub fn secure_alloc(size: usize) -> Option<*mut u8> {
218 secure_alloc_aligned(size, 64) // Default to cache line alignment
219}
220
221/// Secure memory allocation with custom alignment
222#[cfg(feature = "alloc")]
223pub fn secure_alloc_aligned(size: usize, alignment: usize) -> Option<*mut u8> {
224 use alloc::alloc::{
225 Layout,
226 alloc,
227 };
228
229 if size == 0 {
230 return None;
231 }
232
233 // Ensure alignment is a power of 2
234 let alignment = if alignment == 0 || !alignment.is_power_of_two() {
235 64 // Default to cache line alignment
236 } else {
237 alignment
238 };
239
240 let layout = Layout::from_size_align(size, alignment).ok()?;
241 let ptr = unsafe { alloc(layout) };
242
243 if ptr.is_null() {
244 return None;
245 }
246
247 // Zero the allocated memory with secure zeroing
248 secure_zero_raw(ptr, size);
249
250 // Memory barrier to ensure zeroing completes before use
251 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
252
253 Some(ptr)
254}
255
256/// Secure zeroing of raw memory
257#[cfg(feature = "alloc")]
258fn secure_zero_raw(ptr: *mut u8, size: usize) {
259 if ptr.is_null() || size == 0 {
260 return;
261 }
262
263 unsafe {
264 // Use volatile writes to prevent compiler optimization
265 let mut current = ptr;
266 for _ in 0..size {
267 ptr::write_volatile(current, 0);
268 current = current.add(1);
269 }
270 }
271
272 // Compiler barrier to prevent optimization
273 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
274}
275
276/// Secure memory deallocation with enhanced security
277///
278/// Deallocates memory securely by zeroing it before deallocation.
279/// Implements secure deallocation best practices including:
280/// - Secure zeroing before deallocation
281/// - Multiple passes of zeroing for sensitive data
282/// - Compiler barriers to prevent optimization
283/// - Proper layout reconstruction for deallocation
284///
285/// # Arguments
286/// * `ptr` - Pointer to memory to deallocate
287/// * `size` - Size of memory to deallocate
288///
289/// # Safety
290/// This function is unsafe because it:
291/// - Takes a raw pointer that must be valid for the given size
292/// - The pointer must have been allocated with the same allocator
293/// - The size must match the size used for allocation
294///
295/// # Security
296/// This function securely deallocates memory by zeroing it first
297/// to prevent data leakage.
298#[cfg(feature = "alloc")]
299pub unsafe fn secure_dealloc(ptr: *mut u8, size: usize) {
300 unsafe { secure_dealloc_aligned(ptr, size, 64) } // Default to cache line alignment
301}
302
303/// Secure memory deallocation with custom alignment
304///
305/// # Safety
306///
307/// - `ptr` must be a valid pointer returned by a previous allocation
308/// - `size` must be the same size that was used for the original allocation
309/// - `alignment` must be the same alignment that was used for the original allocation
310/// - The memory must not be accessed after this function returns
311#[cfg(feature = "alloc")]
312pub unsafe fn secure_dealloc_aligned(ptr: *mut u8, size: usize, alignment: usize) {
313 if ptr.is_null() || size == 0 {
314 return;
315 }
316
317 // Ensure alignment is a power of 2
318 let alignment = if alignment == 0 || !alignment.is_power_of_two() {
319 64 // Default to cache line alignment
320 } else {
321 alignment
322 };
323
324 // Secure zeroing with multiple passes for sensitive data
325 secure_zero_raw(ptr, size);
326
327 // Additional pass with pattern to ensure zeroing
328 unsafe {
329 let mut current = ptr;
330 for _ in 0..size {
331 ptr::write_volatile(current, 0xFF);
332 current = current.add(1);
333 }
334 }
335
336 // Final zeroing pass
337 secure_zero_raw(ptr, size);
338
339 // Memory barrier to ensure all zeroing completes
340 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
341
342 use alloc::alloc::{
343 Layout,
344 dealloc,
345 };
346 let layout = Layout::from_size_align(size, alignment).unwrap();
347 unsafe {
348 dealloc(ptr, layout);
349 }
350}
351
352/// Memory barrier
353///
354/// Inserts a memory barrier to prevent reordering of memory operations.
355/// This is useful for ensuring that sensitive operations complete
356/// before other operations begin.
357///
358/// # Security
359/// This function prevents memory reordering that could lead to
360/// timing attacks or other side-channel vulnerabilities.
361pub fn memory_barrier() {
362 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
363}
364
365/// Secure memory fill
366///
367/// Securely fills a memory region with a specific value.
368///
369/// # Arguments
370/// * `data` - Memory region to fill
371/// * `value` - Value to fill with
372///
373/// # Security
374/// This function uses secure memory operations to prevent data leakage.
375pub fn secure_fill<T>(data: &mut T, value: u8) {
376 let size = size_of_val(data);
377 let ptr = data as *mut T as *mut u8;
378
379 unsafe {
380 ptr::write_bytes(ptr, value, size);
381 // Compiler barrier to prevent optimization
382 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
383 }
384}
385
386/// Secure memory fill for slices
387///
388/// Securely fills a slice with a specific value.
389///
390/// # Arguments
391/// * `data` - Slice to fill
392/// * `value` - Value to fill with
393///
394/// # Security
395/// This function uses secure memory operations to prevent data leakage.
396pub fn secure_fill_slice(data: &mut [u8], value: u8) {
397 for byte in data.iter_mut() {
398 *byte = value;
399 }
400
401 // Compiler barrier to prevent optimization
402 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
403}
404
405/// Secure memory XOR
406///
407/// Securely XORs two memory regions and stores the result in the first.
408///
409/// # Arguments
410/// * `a` - First memory region (modified in place)
411/// * `b` - Second memory region
412///
413/// # Panics
414/// Panics if the memory regions have different sizes.
415///
416/// # Security
417/// This function uses secure memory operations to prevent data leakage.
418pub fn secure_xor<T>(a: &mut T, b: &T) {
419 let size = size_of_val(a);
420 assert_eq!(size, size_of_val(b));
421
422 let a_ptr = a as *mut T as *mut u8;
423 let b_ptr = b as *const T as *const u8;
424
425 unsafe {
426 for i in 0..size {
427 *a_ptr.add(i) ^= *b_ptr.add(i);
428 }
429 // Compiler barrier to prevent optimization
430 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
431 }
432}
433
434/// Secure memory XOR for slices
435///
436/// Securely XORs two slices and stores the result in the first.
437///
438/// # Arguments
439/// * `a` - First slice (modified in place)
440/// * `b` - Second slice
441///
442/// # Panics
443/// Panics if the slices have different lengths.
444///
445/// # Security
446/// This function uses secure memory operations to prevent data leakage.
447pub fn secure_xor_slice(a: &mut [u8], b: &[u8]) {
448 assert_eq!(a.len(), b.len());
449
450 for (x, y) in a.iter_mut().zip(b.iter()) {
451 *x ^= *y;
452 }
453
454 // Compiler barrier to prevent optimization
455 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
456}
457
458#[cfg(test)]
459mod tests {
460 use super::*;
461
462 #[test]
463 fn test_secure_zero() {
464 let mut data = [1, 2, 3, 4, 5];
465 secure_zero(&mut data);
466 assert_eq!(data, [0, 0, 0, 0, 0]);
467 }
468
469 #[test]
470 fn test_secure_zero_slice() {
471 let mut data = [1, 2, 3, 4, 5];
472 secure_zero_slice(&mut data);
473 assert_eq!(data, [0, 0, 0, 0, 0]);
474 }
475
476 #[test]
477 fn test_secure_copy() {
478 let src = [1, 2, 3, 4, 5];
479 let mut dst = [0; 5];
480 secure_copy(&mut dst, &src);
481 assert_eq!(dst, src);
482 }
483
484 #[test]
485 fn test_secure_copy_slice() {
486 let src = [1, 2, 3, 4, 5];
487 let mut dst = [0; 5];
488 secure_copy_slice(&mut dst, &src);
489 assert_eq!(dst, src);
490 }
491
492 #[test]
493 fn test_secure_move() {
494 let mut src = [1, 2, 3, 4, 5];
495 let mut dst = [0; 5];
496 secure_move(&mut dst, &mut src);
497 assert_eq!(dst, [1, 2, 3, 4, 5]);
498 assert_eq!(src, [0, 0, 0, 0, 0]);
499 }
500
501 #[test]
502 fn test_secure_move_slice() {
503 let mut src = [1, 2, 3, 4, 5];
504 let mut dst = [0; 5];
505 secure_move_slice(&mut dst, &mut src);
506 assert_eq!(dst, [1, 2, 3, 4, 5]);
507 assert_eq!(src, [0, 0, 0, 0, 0]);
508 }
509
510 #[test]
511 fn test_secure_compare() {
512 let a = [1, 2, 3, 4, 5];
513 let b = [1, 2, 3, 4, 5];
514 let c = [1, 2, 3, 4, 6];
515
516 assert!(secure_compare(&a, &b));
517 assert!(!secure_compare(&a, &c));
518 }
519
520 #[test]
521 fn test_secure_compare_slice() {
522 let a = [1, 2, 3, 4, 5];
523 let b = [1, 2, 3, 4, 5];
524 let c = [1, 2, 3, 4, 6];
525
526 assert!(secure_compare_slice(&a, &b));
527 assert!(!secure_compare_slice(&a, &c));
528 }
529
530 #[test]
531 fn test_secure_fill() {
532 let mut data = [0u8; 5];
533 secure_fill(&mut data, 42);
534 assert_eq!(data, [42, 42, 42, 42, 42]);
535 }
536
537 #[test]
538 fn test_secure_fill_slice() {
539 let mut data = [0; 5];
540 secure_fill_slice(&mut data, 42);
541 assert_eq!(data, [42, 42, 42, 42, 42]);
542 }
543
544 #[test]
545 fn test_secure_xor() {
546 let mut a = [0b1010, 0b1100, 0b1111];
547 let b = [0b1100, 0b1010, 0b0000];
548 secure_xor(&mut a, &b);
549 assert_eq!(a, [0b0110, 0b0110, 0b1111]);
550 }
551
552 #[test]
553 fn test_secure_xor_slice() {
554 let mut a = [0b1010, 0b1100, 0b1111];
555 let b = [0b1100, 0b1010, 0b0000];
556 secure_xor_slice(&mut a, &b);
557 assert_eq!(a, [0b0110, 0b0110, 0b1111]);
558 }
559
560 #[test]
561 fn test_memory_barrier() {
562 // This test just ensures the function doesn't panic
563 memory_barrier();
564 }
565}