use core::fmt;
use core::ops::{Deref, DerefMut};
use rand::{CryptoRng, RngCore};
use zeroize::Zeroize;
use crate::error::{validate, Result};
use crate::types::sealed::Sealed;
use crate::types::{
ByteSerializable, ConstantTimeEq, FixedSize, RandomGeneration, SecureZeroingType,
};
#[derive(Clone, Zeroize)]
pub struct Salt<const N: usize> {
data: [u8; N],
}
impl<const N: usize> Sealed for Salt<N> {}
impl<const N: usize> Salt<N> {
pub fn new(data: [u8; N]) -> Self {
Self { data }
}
pub fn from_slice(slice: &[u8]) -> Result<Self> {
validate::length("Salt::from_slice", slice.len(), N)?;
let mut data = [0u8; N];
data.copy_from_slice(slice);
Ok(Self { data })
}
pub fn zeroed() -> Self {
Self { data: [0u8; N] }
}
pub fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let mut data = [0u8; N];
rng.fill_bytes(&mut data);
Self { data }
}
pub fn random_with_size<R: RngCore + CryptoRng>(rng: &mut R, size: usize) -> Result<Self> {
validate::length("Salt::random_with_size", size, N)?;
Ok(Self::random(rng))
}
pub fn size() -> usize {
N
}
pub fn len(&self) -> usize {
N
}
pub fn is_empty(&self) -> bool {
N == 0
}
}
impl<const N: usize> AsRef<[u8]> for Salt<N> {
fn as_ref(&self) -> &[u8] {
&self.data
}
}
impl<const N: usize> AsMut<[u8]> for Salt<N> {
fn as_mut(&mut self) -> &mut [u8] {
&mut self.data
}
}
impl<const N: usize> Deref for Salt<N> {
type Target = [u8; N];
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<const N: usize> DerefMut for Salt<N> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<const N: usize> PartialEq for Salt<N> {
fn eq(&self, other: &Self) -> bool {
self.data == other.data
}
}
impl<const N: usize> Eq for Salt<N> {}
impl<const N: usize> fmt::Debug for Salt<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Salt<{}>", N)
}
}
impl<const N: usize> ConstantTimeEq for Salt<N> {
fn ct_eq(&self, other: &Self) -> bool {
dcrypt_internal::constant_time::ct_eq(self.data, other.data)
}
}
impl<const N: usize> RandomGeneration for Salt<N> {
fn random<R: RngCore + CryptoRng>(rng: &mut R) -> Result<Self> {
Ok(Self::random(rng))
}
}
impl<const N: usize> SecureZeroingType for Salt<N> {
fn zeroed() -> Self {
Self::zeroed()
}
}
impl<const N: usize> FixedSize for Salt<N> {
fn size() -> usize {
N
}
}
impl<const N: usize> ByteSerializable for Salt<N> {
fn to_bytes(&self) -> Vec<u8> {
self.data.to_vec()
}
fn from_bytes(bytes: &[u8]) -> Result<Self> {
Self::from_slice(bytes)
}
}
pub const RECOMMENDED_MIN_SIZE: usize = 16;
pub type Salt8 = Salt<8>;
pub type Salt16 = Salt<16>;
pub type Salt32 = Salt<32>;
pub trait Pbkdf2Compatible: Sealed {}
impl Pbkdf2Compatible for Salt<16> {}
impl Pbkdf2Compatible for Salt<24> {}
impl Pbkdf2Compatible for Salt<32> {}
impl Pbkdf2Compatible for Salt<64> {}
pub trait Argon2Compatible: Sealed {}
impl Argon2Compatible for Salt<8> {}
impl Argon2Compatible for Salt<16> {}
impl Argon2Compatible for Salt<24> {}
impl Argon2Compatible for Salt<32> {}
impl Argon2Compatible for Salt<64> {}
pub trait HkdfCompatible: Sealed {}
impl HkdfCompatible for Salt<16> {}
impl HkdfCompatible for Salt<24> {}
impl HkdfCompatible for Salt<32> {}
impl HkdfCompatible for Salt<64> {}