use core::sync::atomic::{compiler_fence, Ordering};
pub fn secure_zero_memory(data: &mut [u8]) {
for byte in data.iter_mut() {
unsafe {
core::ptr::write_volatile(byte, 0);
}
}
compiler_fence(Ordering::SeqCst);
}
pub trait Zeroize {
fn zeroize(&mut self);
}
impl Zeroize for [u8] {
fn zeroize(&mut self) {
secure_zero_memory(self);
}
}
impl Zeroize for Vec<u8> {
fn zeroize(&mut self) {
secure_zero_memory(self.as_mut_slice());
}
}
impl<const N: usize> Zeroize for [u8; N] {
fn zeroize(&mut self) {
secure_zero_memory(self.as_mut_slice());
}
}
impl<const N: usize> Zeroize for [i64; N] {
fn zeroize(&mut self) {
let ptr = self.as_mut_ptr() as *mut u8;
let bytes =
unsafe { core::slice::from_raw_parts_mut(ptr, N * core::mem::size_of::<i64>()) };
secure_zero_memory(bytes);
}
}
impl<const N: usize> Zeroize for [i8; N] {
fn zeroize(&mut self) {
let ptr = self.as_mut_ptr() as *mut u8;
let bytes = unsafe { core::slice::from_raw_parts_mut(ptr, N * core::mem::size_of::<i8>()) };
secure_zero_memory(bytes);
}
}
impl<const N: usize> Zeroize for [u32; N] {
fn zeroize(&mut self) {
let ptr = self.as_mut_ptr() as *mut u8;
let bytes =
unsafe { core::slice::from_raw_parts_mut(ptr, N * core::mem::size_of::<u32>()) };
secure_zero_memory(bytes);
}
}
impl Zeroize for String {
fn zeroize(&mut self) {
unsafe {
for byte in self.as_mut_vec().iter_mut() {
core::ptr::write_volatile(byte, 0);
}
}
compiler_fence(Ordering::SeqCst);
}
}
pub struct Zeroizing<T: Zeroize>(pub T);
impl<T: Zeroize> Zeroizing<T> {
pub fn new(data: T) -> Self {
Self(data)
}
}
impl<T: Zeroize> core::ops::Deref for Zeroizing<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T: Zeroize> core::ops::DerefMut for Zeroizing<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<T: Zeroize> Drop for Zeroizing<T> {
fn drop(&mut self) {
self.0.zeroize();
}
}
impl<T: Zeroize + Clone> Clone for Zeroizing<T> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}