use core::ptr;
pub fn secure_zero<T>(data: &mut T) {
let size = size_of_val(data);
let ptr = data as *mut T as *mut u8;
unsafe {
ptr::write_bytes(ptr, 0, size);
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
pub fn secure_zero_slice(data: &mut [u8]) {
for byte in data.iter_mut() {
*byte = 0;
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
pub fn secure_copy<T>(dst: &mut T, src: &T) {
let size = size_of_val(src);
let dst_ptr = dst as *mut T as *mut u8;
let src_ptr = src as *const T as *const u8;
unsafe {
ptr::copy_nonoverlapping(src_ptr, dst_ptr, size);
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
pub fn secure_copy_slice(dst: &mut [u8], src: &[u8]) {
assert_eq!(dst.len(), src.len());
for (d, s) in dst.iter_mut().zip(src.iter()) {
*d = *s;
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
pub fn secure_move<T>(dst: &mut T, src: &mut T) {
secure_copy(dst, src);
secure_zero(src);
}
pub fn secure_move_slice(dst: &mut [u8], src: &mut [u8]) {
secure_copy_slice(dst, src);
secure_zero_slice(src);
}
pub fn secure_compare<T>(a: &T, b: &T) -> bool {
let size = size_of_val(a);
let a_ptr = a as *const T as *const u8;
let b_ptr = b as *const T as *const u8;
let mut result = 0u8;
unsafe {
for i in 0..size {
result |= *a_ptr.add(i) ^ *b_ptr.add(i);
}
}
result == 0
}
pub fn secure_compare_slice(a: &[u8], b: &[u8]) -> bool {
if a.len() != b.len() {
return false;
}
let mut result = 0u8;
for (x, y) in a.iter().zip(b.iter()) {
result |= x ^ y;
}
result == 0
}
#[cfg(feature = "alloc")]
pub fn secure_alloc(size: usize) -> Option<*mut u8> {
secure_alloc_aligned(size, 64) }
#[cfg(feature = "alloc")]
pub fn secure_alloc_aligned(size: usize, alignment: usize) -> Option<*mut u8> {
use alloc::alloc::{
Layout,
alloc,
};
if size == 0 {
return None;
}
let alignment = if alignment == 0 || !alignment.is_power_of_two() {
64 } else {
alignment
};
let layout = Layout::from_size_align(size, alignment).ok()?;
let ptr = unsafe { alloc(layout) };
if ptr.is_null() {
return None;
}
secure_zero_raw(ptr, size);
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
Some(ptr)
}
#[cfg(feature = "alloc")]
fn secure_zero_raw(ptr: *mut u8, size: usize) {
if ptr.is_null() || size == 0 {
return;
}
unsafe {
let mut current = ptr;
for _ in 0..size {
ptr::write_volatile(current, 0);
current = current.add(1);
}
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
#[cfg(feature = "alloc")]
pub unsafe fn secure_dealloc(ptr: *mut u8, size: usize) {
unsafe { secure_dealloc_aligned(ptr, size, 64) } }
#[cfg(feature = "alloc")]
pub unsafe fn secure_dealloc_aligned(ptr: *mut u8, size: usize, alignment: usize) {
if ptr.is_null() || size == 0 {
return;
}
let alignment = if alignment == 0 || !alignment.is_power_of_two() {
64 } else {
alignment
};
secure_zero_raw(ptr, size);
unsafe {
let mut current = ptr;
for _ in 0..size {
ptr::write_volatile(current, 0xFF);
current = current.add(1);
}
}
secure_zero_raw(ptr, size);
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
use alloc::alloc::{
Layout,
dealloc,
};
let layout = Layout::from_size_align(size, alignment).unwrap();
unsafe {
dealloc(ptr, layout);
}
}
pub fn memory_barrier() {
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
pub fn secure_fill<T>(data: &mut T, value: u8) {
let size = size_of_val(data);
let ptr = data as *mut T as *mut u8;
unsafe {
ptr::write_bytes(ptr, value, size);
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
}
pub fn secure_fill_slice(data: &mut [u8], value: u8) {
for byte in data.iter_mut() {
*byte = value;
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
pub fn secure_xor<T>(a: &mut T, b: &T) {
let size = size_of_val(a);
assert_eq!(size, size_of_val(b));
let a_ptr = a as *mut T as *mut u8;
let b_ptr = b as *const T as *const u8;
unsafe {
for i in 0..size {
*a_ptr.add(i) ^= *b_ptr.add(i);
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
}
pub fn secure_xor_slice(a: &mut [u8], b: &[u8]) {
assert_eq!(a.len(), b.len());
for (x, y) in a.iter_mut().zip(b.iter()) {
*x ^= *y;
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_secure_zero() {
let mut data = [1, 2, 3, 4, 5];
secure_zero(&mut data);
assert_eq!(data, [0, 0, 0, 0, 0]);
}
#[test]
fn test_secure_zero_slice() {
let mut data = [1, 2, 3, 4, 5];
secure_zero_slice(&mut data);
assert_eq!(data, [0, 0, 0, 0, 0]);
}
#[test]
fn test_secure_copy() {
let src = [1, 2, 3, 4, 5];
let mut dst = [0; 5];
secure_copy(&mut dst, &src);
assert_eq!(dst, src);
}
#[test]
fn test_secure_copy_slice() {
let src = [1, 2, 3, 4, 5];
let mut dst = [0; 5];
secure_copy_slice(&mut dst, &src);
assert_eq!(dst, src);
}
#[test]
fn test_secure_move() {
let mut src = [1, 2, 3, 4, 5];
let mut dst = [0; 5];
secure_move(&mut dst, &mut src);
assert_eq!(dst, [1, 2, 3, 4, 5]);
assert_eq!(src, [0, 0, 0, 0, 0]);
}
#[test]
fn test_secure_move_slice() {
let mut src = [1, 2, 3, 4, 5];
let mut dst = [0; 5];
secure_move_slice(&mut dst, &mut src);
assert_eq!(dst, [1, 2, 3, 4, 5]);
assert_eq!(src, [0, 0, 0, 0, 0]);
}
#[test]
fn test_secure_compare() {
let a = [1, 2, 3, 4, 5];
let b = [1, 2, 3, 4, 5];
let c = [1, 2, 3, 4, 6];
assert!(secure_compare(&a, &b));
assert!(!secure_compare(&a, &c));
}
#[test]
fn test_secure_compare_slice() {
let a = [1, 2, 3, 4, 5];
let b = [1, 2, 3, 4, 5];
let c = [1, 2, 3, 4, 6];
assert!(secure_compare_slice(&a, &b));
assert!(!secure_compare_slice(&a, &c));
}
#[test]
fn test_secure_fill() {
let mut data = [0u8; 5];
secure_fill(&mut data, 42);
assert_eq!(data, [42, 42, 42, 42, 42]);
}
#[test]
fn test_secure_fill_slice() {
let mut data = [0; 5];
secure_fill_slice(&mut data, 42);
assert_eq!(data, [42, 42, 42, 42, 42]);
}
#[test]
fn test_secure_xor() {
let mut a = [0b1010, 0b1100, 0b1111];
let b = [0b1100, 0b1010, 0b0000];
secure_xor(&mut a, &b);
assert_eq!(a, [0b0110, 0b0110, 0b1111]);
}
#[test]
fn test_secure_xor_slice() {
let mut a = [0b1010, 0b1100, 0b1111];
let b = [0b1100, 0b1010, 0b0000];
secure_xor_slice(&mut a, &b);
assert_eq!(a, [0b0110, 0b0110, 0b1111]);
}
#[test]
fn test_memory_barrier() {
memory_barrier();
}
}