use std::{
ops::{Deref, DerefMut},
pin::Pin,
};
use openssl::rand::rand_bytes;
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::error::CryptoError;
#[derive(Debug, Eq, PartialEq, Clone, Hash)]
pub struct Secret<const LENGTH: usize>(Pin<Box<[u8; LENGTH]>>);
impl<const LENGTH: usize> Secret<LENGTH> {
#[must_use]
#[expect(unsafe_code)]
pub fn new() -> Self {
let data = vec![0_u8; LENGTH].into_boxed_slice();
let data = unsafe { Box::from_raw(Box::into_raw(data).cast::<[u8; LENGTH]>()) };
Self(Pin::new(data))
}
pub fn new_random() -> Result<Self, CryptoError> {
let mut secret = Self::new();
rand_bytes(&mut secret)?;
Ok(secret)
}
pub fn to_unprotected_bytes(&self, dest: &mut [u8; LENGTH]) {
dest.copy_from_slice(self);
}
pub fn from_unprotected_bytes(bytes: &mut [u8; LENGTH]) -> Self {
let mut secret = Self::new();
secret.copy_from_slice(bytes.as_slice());
bytes.zeroize();
secret
}
}
impl<const LENGTH: usize> Default for Secret<LENGTH> {
fn default() -> Self {
Self::new()
}
}
impl<const LENGTH: usize> Deref for Secret<LENGTH> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&*self.0
}
}
impl<const LENGTH: usize> DerefMut for Secret<LENGTH> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut *self.0
}
}
impl<const LENGTH: usize> Zeroize for Secret<LENGTH> {
fn zeroize(&mut self) {
self.0.deref_mut().zeroize();
}
}
impl<const LENGTH: usize> Drop for Secret<LENGTH> {
fn drop(&mut self) {
self.zeroize();
}
}
impl<const LENGTH: usize> ZeroizeOnDrop for Secret<LENGTH> {}