use zeroize::{Zeroize, ZeroizeOnDrop};
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct SecretVec(Vec<u8>);
impl SecretVec {
pub fn new(data: Vec<u8>) -> Self {
Self(data)
}
pub fn with_capacity(capacity: usize) -> Self {
Self(Vec::with_capacity(capacity))
}
pub fn zero(len: usize) -> Self {
Self(vec![0u8; len])
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn as_slice(&self) -> &[u8] {
&self.0
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
pub fn into_inner(mut self) -> Vec<u8> {
std::mem::take(&mut self.0)
}
pub fn extend_from_slice(&mut self, data: &[u8]) {
self.0.extend_from_slice(data);
}
}
impl From<Vec<u8>> for SecretVec {
fn from(data: Vec<u8>) -> Self {
Self::new(data)
}
}
impl AsRef<[u8]> for SecretVec {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl AsMut<[u8]> for SecretVec {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl std::fmt::Debug for SecretVec {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SecretVec([REDACTED {} bytes])", self.0.len())
}
}
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct SecretArray<const N: usize>([u8; N]);
impl<const N: usize> SecretArray<N> {
pub fn new(data: [u8; N]) -> Self {
Self(data)
}
pub fn zero() -> Self {
Self([0u8; N])
}
pub fn as_slice(&self) -> &[u8] {
&self.0
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
&mut self.0
}
pub const fn len(&self) -> usize {
N
}
pub const fn is_empty(&self) -> bool {
N == 0
}
}
impl<const N: usize> From<[u8; N]> for SecretArray<N> {
fn from(data: [u8; N]) -> Self {
Self::new(data)
}
}
impl<const N: usize> AsRef<[u8]> for SecretArray<N> {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl<const N: usize> AsMut<[u8]> for SecretArray<N> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.0
}
}
impl<const N: usize> std::fmt::Debug for SecretArray<N> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "SecretArray([REDACTED {} bytes])", N)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_secret_vec_basic() {
let secret = SecretVec::new(vec![1, 2, 3, 4]);
assert_eq!(secret.len(), 4);
assert!(!secret.is_empty());
assert_eq!(secret.as_slice(), &[1, 2, 3, 4]);
}
#[test]
fn test_secret_vec_zero() {
let secret = SecretVec::zero(32);
assert_eq!(secret.len(), 32);
assert_eq!(secret.as_slice(), &[0u8; 32]);
}
#[test]
fn test_secret_vec_debug() {
let secret = SecretVec::new(vec![1, 2, 3]);
let debug_str = format!("{:?}", secret);
assert!(debug_str.contains("REDACTED"));
assert!(!debug_str.contains("1"));
}
#[test]
fn test_secret_array_basic() {
let secret = SecretArray::new([1, 2, 3, 4]);
assert_eq!(secret.len(), 4);
assert_eq!(secret.as_slice(), &[1, 2, 3, 4]);
}
#[test]
fn test_secret_array_zero() {
let secret = SecretArray::<32>::zero();
assert_eq!(secret.len(), 32);
assert_eq!(secret.as_slice(), &[0u8; 32]);
}
#[test]
fn test_secret_array_debug() {
let secret = SecretArray::new([1, 2, 3]);
let debug_str = format!("{:?}", secret);
assert!(debug_str.contains("REDACTED"));
assert!(!debug_str.contains("1"));
}
#[test]
fn test_extend_from_slice() {
let mut secret = SecretVec::new(vec![1, 2]);
secret.extend_from_slice(&[3, 4]);
assert_eq!(secret.as_slice(), &[1, 2, 3, 4]);
}
}