use crate::{can_cast_i32, can_cast_u32, const_can_cast_i32, const_can_cast_u32, to_u32};
use crate::sealed::AadSealed as Sealed;
use core::num::NonZeroU32;
use core::convert::Infallible;
use crate::buf::InvalidSize;
use crate::error::InvalidIters;
use core::fmt;
non_fips! {
mod hmac;
pub use hmac::hkdf;
pub use hmac::hkdf_into;
}
pub mod pbkdf;
#[doc(inline)]
pub use pbkdf::{pbkdf2, pbkdf2_into, FipsPbkdf2};
non_fips! {
#[doc(inline)]
pub use pbkdf::{pbkdf1, pbkdf1_into};
}
#[doc(inline)]
pub use crate::mac::hmac::algo::{
InsecureKey,
KeySlice,
Sha224, Sha256, Sha384, Sha512,
Sha3_224, Sha3_256, Sha3_384, Sha3_512
};
non_fips! {
#[doc(inline)]
pub use crate::mac::hmac::algo::{
Sha, Md5
};
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct Iters { count: NonZeroU32 }
impl fmt::Display for Iters {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_fmt(format_args!("Iters({})", self.count))
}
}
impl fmt::Debug for Iters {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Self as fmt::Display>::fmt(self, f)
}
}
impl Iters {
pub const fn new(iters: u32) -> Option<Self> {
match NonZeroU32::new(iters) {
Some(count) => Some(Self { count }),
None => None
}
}
pub const unsafe fn new_unchecked(iters: u32) -> Self {
Self { count: NonZeroU32::new_unchecked(iters) }
}
pub const fn is_valid_size(&self) -> bool {
self.get() <= i32::MAX as u32
}
#[inline]
#[must_use]
pub const fn get(&self) -> u32 {
self.count.get()
}
}
impl From<NonZeroU32> for Iters {
#[inline]
fn from(value: NonZeroU32) -> Self {
Self { count: value }
}
}
impl TryFrom<u32> for Iters {
type Error = InvalidIters;
#[inline]
fn try_from(value: u32) -> Result<Self, Self::Error> {
Self::new(value).ok_or(InvalidIters)
}
}
impl TryFrom<usize> for Iters {
type Error = InvalidIters;
#[inline]
fn try_from(value: usize) -> Result<Self, Self::Error> {
to_u32(value).and_then(Self::new).ok_or(InvalidIters)
}
}
pub mod salt {
use super::{InvalidSize, Infallible, Salt, Sealed};
use core::marker::PhantomData;
use core::fmt;
pub trait MinSize : Sealed {
type CreateError;
fn min_size() -> u32;
}
macro_rules! def_sz {
($(
$(#[$meta:meta])*
$name:ident => $sz:literal => $err:ident
),* $(,)?) => {
$(
$(#[$meta])*
pub struct $name;
impl super::Sealed for $name {}
impl MinSize for $name {
type CreateError = $err;
#[inline]
fn min_size() -> u32 {
$sz
}
}
)*
};
}
def_sz! {
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Empty => 0 => Infallible,
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
NonEmpty => 1 => InvalidSize,
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
Min16 => 16 => InvalidSize
}
pub trait NonEmptySize<SZ: MinSize> : Salt<SZ> {}
impl<S: Salt<NonEmpty>> NonEmptySize<NonEmpty> for S {}
impl<S: Salt<Min16>> NonEmptySize<Min16> for S {}
mark_fips! { Min16, Sealed }
#[repr(transparent)]
pub struct Slice<'s, SZ> {
raw: &'s [u8],
_min_size: PhantomData<SZ>
}
impl<'s, SZ: MinSize> Clone for Slice<'s, SZ> {
#[inline]
fn clone(&self) -> Self { Self::create(self.raw) }
}
impl<'s, SZ: MinSize> AsRef<[u8]> for Slice<'s, SZ> {
#[inline]
fn as_ref(&self) -> &[u8] { self.raw }
}
impl<'s, SZ: MinSize> fmt::Debug for Slice<'s, SZ> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("Slice").field(&self.raw).finish()
}
}
macro_rules! impl_salt_for {
($sz:ty => { $item:item }) => {
impl<'s> Slice<'s, $sz> {
$item
}
};
}
impl_salt_for! { Empty => {
pub const fn new(slice: &'s [u8]) -> Result<Self, Infallible> {
Ok(Self::create(slice))
}
}}
impl_salt_for! { NonEmpty => {
pub const fn new(slice: &'s [u8]) -> Result<Self, InvalidSize> {
if !slice.is_empty() {
Ok(Self::create(slice))
} else {
Err(InvalidSize)
}
}
}}
impl_salt_for! { Min16 => {
pub const fn new(slice: &'s [u8]) -> Result<Self, InvalidSize> {
if slice.len() >= 16 {
Ok(Self::create(slice))
} else {
Err(InvalidSize)
}
}
}}
impl<'s, SZ: MinSize> Slice<'s, SZ> {
#[inline]
const fn create(raw: &'s [u8]) -> Self {
Self { raw, _min_size: PhantomData }
}
}
macro_rules! impl_salt_try_from {
($ty:ty) => {
impl<'s> TryFrom<&'s [u8]> for Slice<'s, $ty> {
type Error = <$ty as MinSize>::CreateError;
#[inline]
fn try_from(value: &'s [u8]) -> Result<Self, Self::Error> {
Self::new(value)
}
}
};
}
impl_salt_try_from! { NonEmpty }
impl_salt_try_from! { Min16 }
impl<'s> From<&'s [u8]> for Slice<'s, Empty> {
#[inline]
fn from(value: &'s [u8]) -> Self {
Self::create(value)
}
}
impl<'s> From<&'s [u8; 16]> for Slice<'s, Min16> {
#[inline]
fn from(value: &'s [u8; 16]) -> Self {
Self::create(value)
}
}
impl<'s, SZ: MinSize> Sealed for Slice<'s, SZ> {}
macro_rules! impl_salt_slice {
($for:ident allows $with:ident) => {
impl<'s> Salt<$for> for Slice<'s, $with> {
#[inline]
fn size(&self) -> u32 {
debug_assert!($crate::can_cast_u32(self.raw.len()));
self.raw.len() as u32
}
#[inline]
fn is_valid_size(&self) -> bool {
$crate::can_cast_u32(self.raw.len())
}
#[inline]
fn i_size(&self) -> i32 {
debug_assert!($crate::can_cast_i32(self.raw.len()));
self.raw.len() as i32
}
#[inline]
fn i_is_valid_size(&self) -> bool {
$crate::can_cast_i32(self.raw.len())
}
#[inline]
fn ptr(&self) -> *const u8 {
self.raw.as_ptr()
}
}
};
}
impl_salt_slice! { Empty allows Empty }
impl_salt_slice! { Empty allows NonEmpty }
impl_salt_slice! { Empty allows Min16 }
impl_salt_slice! { NonEmpty allows NonEmpty }
impl_salt_slice! { Min16 allows Min16 }
}
pub trait Salt<SZ: salt::MinSize>: Sealed {
#[doc(hidden)]
#[must_use]
fn size(&self) -> u32;
#[doc(hidden)]
#[must_use]
fn is_valid_size(&self) -> bool;
#[doc(hidden)]
#[must_use]
fn i_size(&self) -> i32;
#[doc(hidden)]
#[must_use]
fn i_is_valid_size(&self) -> bool;
#[doc(hidden)]
#[must_use]
fn ptr(&self) -> *const u8;
}
impl<T: Salt<salt::Min16>> Salt<salt::NonEmpty> for T {
#[inline]
fn size(&self) -> u32 {
<T as Salt<salt::Min16>>::size(self)
}
#[inline]
fn is_valid_size(&self) -> bool {
<T as Salt<salt::Min16>>::is_valid_size(self)
}
#[inline]
fn i_size(&self) -> i32 {
<T as Salt<salt::Min16>>::i_size(self)
}
#[inline]
fn i_is_valid_size(&self) -> bool {
<T as Salt<salt::Min16>>::i_is_valid_size(self)
}
#[inline]
fn ptr(&self) -> *const u8 {
<T as Salt<salt::Min16>>::ptr(self)
}
}
impl Salt<salt::Empty> for &[u8] {
#[inline]
fn size(&self) -> u32 {
debug_assert!(can_cast_u32(self.len()));
self.len() as u32
}
#[inline]
fn is_valid_size(&self) -> bool {
can_cast_u32(self.len())
}
#[inline]
fn i_size(&self) -> i32 {
debug_assert!(can_cast_i32(self.len()));
self.len() as i32
}
#[inline]
fn i_is_valid_size(&self) -> bool {
can_cast_i32(self.len())
}
#[inline]
fn ptr(&self) -> *const u8 {
self.as_ptr()
}
}
impl<const C: usize> Salt<salt::Empty> for [u8; C] {
#[inline]
fn size(&self) -> u32 {
debug_assert!(const_can_cast_u32::<C>());
self.len() as u32
}
#[inline]
fn is_valid_size(&self) -> bool {
const_can_cast_u32::<C>()
}
#[inline]
fn i_size(&self) -> i32 {
debug_assert!(const_can_cast_i32::<C>());
C as i32
}
#[inline]
fn i_is_valid_size(&self) -> bool {
const_can_cast_i32::<C>()
}
#[inline]
fn ptr(&self) -> *const u8 {
self.as_ptr()
}
}
macro_rules! impl_salt_for_sizes {
($constraint:ty => [$($sz:literal),*]) => {
$(
impl Salt<$constraint> for [u8; $sz] {
#[inline]
fn size(&self) -> u32 { $sz }
#[inline]
fn is_valid_size(&self) -> bool { true }
#[inline]
fn i_size(&self) -> i32 { $sz }
#[inline]
fn i_is_valid_size(&self) -> bool { true }
#[inline]
fn ptr(&self) -> *const u8 { self.as_ptr() }
}
impl Salt<$constraint> for &[u8; $sz] {
#[inline]
fn size(&self) -> u32 { $sz }
#[inline]
fn is_valid_size(&self) -> bool { true }
#[inline]
fn i_size(&self) -> i32 { $sz }
#[inline]
fn i_is_valid_size(&self) -> bool { true }
#[inline]
fn ptr(&self) -> *const u8 { self.as_ptr() }
}
)*
};
}
impl_salt_for_sizes! { salt::Min16 => [
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 48, 64
]}
impl_salt_for_sizes! { salt::NonEmpty => [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
]}
impl Salt<salt::Empty> for () {
#[inline]
fn size(&self) -> u32 {
0
}
#[inline]
fn is_valid_size(&self) -> bool {
true
}
#[inline]
fn i_size(&self) -> i32 {
0
}
#[inline]
fn i_is_valid_size(&self) -> bool {
true
}
#[inline]
fn ptr(&self) -> *const u8 {
core::ptr::null()
}
}
impl<T: Salt<salt::Empty>> Salt<salt::Empty> for &T {
#[inline]
fn size(&self) -> u32 {
<T as Salt<salt::Empty>>::size(self)
}
#[inline]
fn is_valid_size(&self) -> bool {
<T as Salt<salt::Empty>>::is_valid_size(self)
}
#[inline]
fn i_size(&self) -> i32 {
<T as Salt<salt::Empty>>::i_size(self)
}
#[inline]
fn i_is_valid_size(&self) -> bool {
<T as Salt<salt::Empty>>::i_is_valid_size(self)
}
#[inline]
fn ptr(&self) -> *const u8 {
<T as Salt<salt::Empty>>::ptr(self)
}
}
impl<T: Salt<salt::Empty>> Salt<salt::Empty> for &mut T {
#[inline]
fn size(&self) -> u32 {
<T as Salt<salt::Empty>>::size(self)
}
#[inline]
fn is_valid_size(&self) -> bool {
<T as Salt<salt::Empty>>::is_valid_size(self)
}
#[inline]
fn i_size(&self) -> i32 {
<T as Salt<salt::Empty>>::i_size(self)
}
#[inline]
fn i_is_valid_size(&self) -> bool {
<T as Salt<salt::Empty>>::i_is_valid_size(self)
}
#[inline]
fn ptr(&self) -> *const u8 {
<T as Salt<salt::Empty>>::ptr(self)
}
}
impl<T: Salt<salt::Empty>> Salt<salt::Empty> for Option<T> {
#[inline]
fn size(&self) -> u32 {
self.as_ref().map_or(0, <T as Salt<salt::Empty>>::size)
}
#[inline]
fn is_valid_size(&self) -> bool {
self.as_ref().map_or(true, <T as Salt<salt::Empty>>::is_valid_size)
}
#[inline]
fn i_size(&self) -> i32 {
self.as_ref().map_or(0, <T as Salt<salt::Empty>>::i_size)
}
#[inline]
fn i_is_valid_size(&self) -> bool {
self.as_ref().map_or(true, <T as Salt<salt::Empty>>::i_is_valid_size)
}
#[inline]
fn ptr(&self) -> *const u8 {
self.as_ref().map_or_else(core::ptr::null, <T as Salt<salt::Empty>>::ptr)
}
}
pub type FipsSaltSlice<'s> = salt::Slice<'s, salt::Min16>;
pub type SaltSlice<'s> = salt::Slice<'s, salt::NonEmpty>;
pub type MaybeSaltSlice<'s> = salt::Slice<'s, salt::Empty>;
#[cfg(not(feature = "allow-non-fips"))]
pub type DynSaltSlice<'s> = FipsSaltSlice<'s>;
#[cfg(feature = "allow-non-fips")]
pub type DynSaltSlice<'s> = SaltSlice<'s>;
impl<T: Salt<salt::Min16>> crate::sealed::FipsSealed for T {}
impl<T: Salt<salt::Min16>> crate::Fips for T {}
#[cfg(test)]
mod foolery {
use core::mem;
use super::*;
#[test]
fn foolery() {
dbg!(mem::size_of::<Option<NonZeroU32>>());
dbg!(mem::size_of::<Option<Iters>>());
dbg!(mem::align_of::<Option<Iters>>());
dbg!(mem::align_of::<Option<NonZeroU32>>());
}
}