use core::marker::PhantomData;
use wolf_crypto_sys::{
WC_SHA224, WC_SHA256, WC_SHA384, WC_SHA512,
WC_SHA3_224, WC_SHA3_256, WC_SHA3_384, WC_SHA3_512
};
use zeroize::Zeroize;
use crate::sealed::HmacSealed as Sealed;
use crate::sealed::HmacDigestSealed as SealedDigest;
use crate::buf::InvalidSize;
use crate::can_cast_u32;
use crate::Fips;
use core::fmt;
non_fips! {
use wolf_crypto_sys::{WC_MD5, WC_SHA};
}
pub trait KeySz : Sealed {
#[must_use]
fn size() -> u32;
}
pub trait GenericKey : Sealed {
type Size: KeySz;
#[doc(hidden)]
#[must_use]
fn ptr(&self) -> *const u8;
fn size(&self) -> u32;
fn cleanup(self);
}
pub trait HexDigest : SealedDigest + AsRef<[u8]> + AsMut<[u8]> + Copy {
type Digest: Digest;
#[doc(hidden)]
#[must_use]
fn zeroes() -> Self;
}
pub trait Digest : Sealed + AsRef<[u8]> + AsMut<[u8]> + Copy {
type Hex: HexDigest;
#[doc(hidden)]
#[must_use]
fn zeroes() -> Self;
#[must_use]
fn size() -> u32;
#[doc(hidden)]
#[must_use]
fn ptr(&mut self) -> *mut u8;
}
pub trait Hash : Sealed {
type Digest: Digest;
type KeyLen: KeySz;
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result;
#[doc(hidden)]
#[must_use]
fn type_id() -> core::ffi::c_int;
}
macro_rules! make_digest {
($(($name:ident, $sz:literal)),* $(,)?) => {
$(
impl SealedDigest for [u8; crate::ct::hex_encode_len($sz)] {}
impl HexDigest for [u8; crate::ct::hex_encode_len($sz)] {
type Digest = [u8; $sz];
#[inline]
fn zeroes() -> Self {
[0u8; crate::ct::hex_encode_len($sz)]
}
}
impl Sealed for [u8; $sz] {}
impl Digest for [u8; $sz] {
type Hex = [u8; crate::ct::hex_encode_len($sz)];
#[inline]
fn zeroes() -> Self {
[0u8; $sz]
}
#[inline]
fn size() -> u32 {
$sz
}
#[inline]
fn ptr(&mut self) -> *mut u8 {
self.as_mut_ptr()
}
}
#[doc = concat!(
"Generic representation of a ", stringify!($sz), " byte key for `HMAC` or KDFs."
)]
#[doc = ""]
#[doc = "It is strongly recommended that the key length is equivalent "]
#[doc = "to the hash functions digest size. (SHA256 means 256 bit (32 byte) key)."]
pub struct $name;
impl Sealed for $name {}
impl KeySz for $name {
#[inline]
fn size() -> u32 {
Self::SIZE
}
}
impl $name {
pub const SIZE: u32 = $sz;
pub(crate) const USIZE: usize = $sz;
}
impl GenericKey for [u8; $sz] {
type Size = $name;
#[inline]
fn ptr(&self) -> *const u8 {
self.as_ptr()
}
#[inline]
fn size(&self) -> u32 {
<$name>::SIZE
}
#[inline]
fn cleanup(mut self) {
self.zeroize();
}
}
impl Sealed for &[u8; $sz] {}
impl GenericKey for &[u8; $sz] {
type Size = $name;
#[inline]
fn ptr(&self) -> *const u8 {
self.as_ptr()
}
#[inline]
fn size(&self) -> u32 {
<$name>::SIZE
}
#[inline(always)]
fn cleanup(self) {}
}
)*
};
}
#[repr(transparent)]
pub struct KeySlice<'k, SZ: KeySz> {
inner: &'k [u8],
_min_size: PhantomData<SZ>
}
impl<'k, SZ: KeySz> Sealed for KeySlice<'k, SZ> {}
impl<'k, SZ: KeySz> GenericKey for KeySlice<'k, SZ> {
type Size = SZ;
#[inline]
fn ptr(&self) -> *const u8 {
self.inner.as_ptr()
}
#[inline]
fn size(&self) -> u32 {
self.inner.len() as u32
}
#[inline(always)]
fn cleanup(self) {}
}
impl<'k, SZ: KeySz> KeySlice<'k, SZ> {
#[inline]
pub fn new(slice: &'k [u8]) -> Result<Self, InvalidSize> {
if slice.len() < SZ::size() as usize || !can_cast_u32(slice.len()) {
Err(InvalidSize)
} else {
Ok(Self { inner: slice, _min_size: PhantomData })
}
}
}
impl<'k, SZ: KeySz> TryFrom<&'k [u8]> for KeySlice<'k, SZ> {
type Error = InvalidSize;
#[inline]
fn try_from(value: &'k [u8]) -> Result<Self, Self::Error> {
Self::new(value)
}
}
#[repr(transparent)]
pub struct InsecureKey<'k, SZ: KeySz> {
inner: &'k [u8],
_min_size: PhantomData<SZ>
}
impl<'k, SZ: KeySz> InsecureKey<'k, SZ> {
#[cfg(feature = "allow-non-fips")]
const MIN_SIZE: usize = 1;
#[cfg(not(feature = "allow-non-fips"))]
const MIN_SIZE: usize = 14;
#[inline]
#[must_use]
const fn new_predicate(len: usize) -> bool {
(len >= Self::MIN_SIZE) && can_cast_u32(len)
}
pub const fn new(slice: &'k [u8]) -> Result<Self, InvalidSize> {
if Self::new_predicate(slice.len()) {
Ok(Self { inner: slice, _min_size: PhantomData })
} else {
Err(InvalidSize)
}
}
}
impl<'k, SZ: KeySz> Sealed for InsecureKey<'k, SZ> {}
impl<'k, SZ: KeySz> GenericKey for InsecureKey<'k, SZ> {
type Size = SZ;
#[inline]
fn ptr(&self) -> *const u8 {
self.inner.as_ptr()
}
#[inline]
fn size(&self) -> u32 {
self.inner.len() as u32
}
#[inline(always)]
fn cleanup(self) {}
}
impl<'k, SZ: KeySz> TryFrom<&'k [u8]> for InsecureKey<'k, SZ> {
type Error = InvalidSize;
#[inline]
fn try_from(value: &'k [u8]) -> Result<Self, Self::Error> {
Self::new(value)
}
}
macro_rules! make_algo_type {
($((
$(#[$meta:meta])*
$name:ident,
$sz:ident,
$wc_ty:ident
$(, $fips_trait:ident)?
)),* $(,)?) => {
$(
$(#[$meta])*
pub struct $name;
impl Sealed for $name {}
impl $crate::sealed::Sealed for $name {}
$(
impl $crate::sealed::FipsSealed for $name {}
impl $fips_trait for $name {}
)?
impl Hash for $name {
type Digest = [u8; $sz::USIZE];
type KeyLen = $sz;
#[doc = concat!("Writes \"", stringify!($name), "\" to `f`.")]
#[inline]
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(stringify!($name))
}
#[inline]
fn type_id() -> ::core::ffi::c_int {
debug_assert!($wc_ty <= i32::MAX as ::core::ffi::c_uint);
$wc_ty as ::core::ffi::c_int
}
}
impl Sealed for $crate::hash::$name {}
impl Hash for $crate::hash::$name {
type Digest = [u8; $sz::USIZE];
type KeyLen = $sz;
#[doc = concat!("Writes \"", stringify!($name), "\" to `f`.")]
#[inline]
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(stringify!($name))
}
#[inline]
fn type_id() -> ::core::ffi::c_int {
debug_assert!($wc_ty <= i32::MAX as ::core::ffi::c_uint);
$wc_ty as ::core::ffi::c_int
}
}
)*
};
}
#[cfg_attr(docsrs, doc(cfg(feature = "allow-non-fips")))]
#[cfg(feature = "allow-non-fips")]
make_digest! { (U16, 16), (U20, 20) }
make_digest! { (U28, 28), (U32, 32), (U48, 48), (U64, 64) }
#[cfg_attr(docsrs, doc(cfg(feature = "allow-non-fips")))]
#[cfg(feature = "allow-non-fips")]
make_algo_type! {
(
Md5, U16, WC_MD5
),
(
Sha, U20, WC_SHA
)
}
make_algo_type! {
(
Sha224, U28, WC_SHA224, Fips
),
(
Sha256, U32, WC_SHA256, Fips
),
(
Sha384, U48, WC_SHA384, Fips
),
(
Sha512, U64, WC_SHA512, Fips
),
(
Sha3_224, U28, WC_SHA3_224, Fips
),
(
Sha3_256, U32, WC_SHA3_256, Fips
),
(
Sha3_384, U48, WC_SHA3_384, Fips
),
(
Sha3_512, U64, WC_SHA3_512, Fips
)
}