use core::{convert::TryInto, marker::PhantomData, ptr};
use std::mem::size_of;
use std::num::NonZeroUsize;
use cryptoki_sys::{
CK_ATTRIBUTE, CK_ATTRIBUTE_PTR, CK_DERIVED_KEY, CK_DERIVED_KEY_PTR, CK_INVALID_HANDLE,
CK_OBJECT_HANDLE, CK_OBJECT_HANDLE_PTR, CK_PRF_DATA_PARAM, CK_PRF_DATA_PARAM_PTR,
CK_SP800_108_BYTE_ARRAY, CK_SP800_108_COUNTER, CK_SP800_108_COUNTER_FORMAT,
CK_SP800_108_DKM_LENGTH, CK_SP800_108_DKM_LENGTH_FORMAT, CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS,
CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS, CK_SP800_108_FEEDBACK_KDF_PARAMS,
CK_SP800_108_ITERATION_VARIABLE, CK_SP800_108_KDF_PARAMS, CK_ULONG,
};
use crate::object::{Attribute, ObjectHandle};
use super::MechanismType;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Endianness {
Little,
Big,
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct KbkdfCounterFormat(CK_SP800_108_COUNTER_FORMAT);
impl KbkdfCounterFormat {
pub fn new(endianness: Endianness, width_in_bits: NonZeroUsize) -> Self {
Self(CK_SP800_108_COUNTER_FORMAT {
bLittleEndian: (endianness == Endianness::Little).into(),
ulWidthInBits: width_in_bits
.get()
.try_into()
.expect("bit width of KBKDF internal counter does not fit in CK_ULONG"),
})
}
}
#[derive(Debug, Clone, Copy)]
pub enum KbkdfDkmLengthMethod {
SumOfKeys,
SumOfSegments,
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct KbkdfDkmLengthFormat(CK_SP800_108_DKM_LENGTH_FORMAT);
impl KbkdfDkmLengthFormat {
pub fn new(
dkm_length_method: KbkdfDkmLengthMethod,
endianness: Endianness,
width_in_bits: NonZeroUsize,
) -> Self {
Self(CK_SP800_108_DKM_LENGTH_FORMAT {
dkmLengthMethod: match dkm_length_method {
KbkdfDkmLengthMethod::SumOfKeys => CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS,
KbkdfDkmLengthMethod::SumOfSegments => CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS,
},
bLittleEndian: (endianness == Endianness::Little).into(),
ulWidthInBits: width_in_bits
.get()
.try_into()
.expect("bit width of KBKDF DKM length value does not fit in CK_ULONG"),
})
}
}
#[derive(Debug, Clone, Copy)]
pub enum PrfDataParamType<'a> {
IterationVariable(Option<&'a KbkdfCounterFormat>),
Counter(&'a KbkdfCounterFormat),
DkmLength(&'a KbkdfDkmLengthFormat),
ByteArray(&'a [u8]),
}
#[derive(Debug, Clone, Copy)]
#[repr(transparent)]
pub struct PrfDataParam<'a> {
inner: CK_PRF_DATA_PARAM,
_marker: PhantomData<&'a [u8]>,
}
impl<'a> PrfDataParam<'a> {
pub fn new(type_: PrfDataParamType<'a>) -> Self {
Self {
inner: match type_ {
PrfDataParamType::IterationVariable(None) => CK_PRF_DATA_PARAM {
type_: CK_SP800_108_ITERATION_VARIABLE,
pValue: ptr::null_mut(),
ulValueLen: 0,
},
PrfDataParamType::IterationVariable(Some(counter_format)) => CK_PRF_DATA_PARAM {
type_: CK_SP800_108_ITERATION_VARIABLE,
pValue: counter_format as *const _ as *mut _,
ulValueLen: size_of::<CK_SP800_108_COUNTER_FORMAT>() as CK_ULONG,
},
PrfDataParamType::Counter(counter_format) => CK_PRF_DATA_PARAM {
type_: CK_SP800_108_COUNTER,
pValue: counter_format as *const _ as *mut _,
ulValueLen: size_of::<CK_SP800_108_COUNTER_FORMAT>() as CK_ULONG,
},
PrfDataParamType::DkmLength(dkm_length_format) => CK_PRF_DATA_PARAM {
type_: CK_SP800_108_DKM_LENGTH,
pValue: dkm_length_format as *const _ as *mut _,
ulValueLen: size_of::<CK_SP800_108_DKM_LENGTH_FORMAT>() as CK_ULONG,
},
PrfDataParamType::ByteArray(data) => CK_PRF_DATA_PARAM {
type_: CK_SP800_108_BYTE_ARRAY,
pValue: data.as_ptr() as *mut _,
ulValueLen: data
.len()
.try_into()
.expect("length of PRF data parameter does not fit in CK_ULONG"),
},
},
_marker: PhantomData,
}
}
}
#[derive(Debug)]
pub struct DerivedKey {
template: Box<[CK_ATTRIBUTE]>,
handle: CK_OBJECT_HANDLE,
}
impl DerivedKey {
pub fn new(template: &[Attribute]) -> Self {
let template: Box<[CK_ATTRIBUTE]> = template.iter().map(Into::into).collect();
Self {
template,
handle: CK_INVALID_HANDLE,
}
}
pub fn handle(&self) -> Option<ObjectHandle> {
if self.handle == CK_INVALID_HANDLE {
None
} else {
Some(ObjectHandle::new(self.handle))
}
}
}
impl From<&mut DerivedKey> for CK_DERIVED_KEY {
fn from(value: &mut DerivedKey) -> Self {
CK_DERIVED_KEY {
pTemplate: value.template.as_ptr() as CK_ATTRIBUTE_PTR,
ulAttributeCount: value
.template
.len()
.try_into()
.expect("number of attributes in template does not fit in CK_ULONG"),
phKey: &mut value.handle as CK_OBJECT_HANDLE_PTR,
}
}
}
#[derive(Debug)]
pub struct KbkdfParams<'a> {
_additional_derived_keys: Option<Box<[CK_DERIVED_KEY]>>,
inner: CK_SP800_108_KDF_PARAMS,
_marker: PhantomData<&'a mut [u8]>,
}
impl<'a> KbkdfParams<'a> {
pub fn new(
prf_mechanism: MechanismType,
prf_data_params: &'a [PrfDataParam<'a>],
additional_derived_keys: Option<&'a mut [DerivedKey]>,
) -> Self {
let mut additional_derived_keys = additional_derived_keys.map(|keys| {
keys.iter_mut()
.map(Into::into)
.collect::<Box<[CK_DERIVED_KEY]>>()
});
let inner = CK_SP800_108_KDF_PARAMS {
prfType: prf_mechanism.into(),
ulNumberOfDataParams: prf_data_params
.len()
.try_into()
.expect("number of PRF data parameters does not fit in CK_ULONG"),
pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR,
ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| {
keys.len()
.try_into()
.expect("number of additional derived keys does not fit in CK_ULONG")
}),
pAdditionalDerivedKeys: additional_derived_keys
.as_mut()
.map_or(ptr::null_mut(), |keys| {
keys.as_mut_ptr() as CK_DERIVED_KEY_PTR
}),
};
Self {
_additional_derived_keys: additional_derived_keys,
inner,
_marker: PhantomData,
}
}
pub(crate) fn inner(&self) -> &CK_SP800_108_KDF_PARAMS {
&self.inner
}
}
#[derive(Debug)]
pub struct KbkdfFeedbackParams<'a> {
_additional_derived_keys: Option<Box<[CK_DERIVED_KEY]>>,
inner: CK_SP800_108_FEEDBACK_KDF_PARAMS,
_marker: PhantomData<&'a mut [u8]>,
}
impl<'a> KbkdfFeedbackParams<'a> {
pub fn new(
prf_mechanism: MechanismType,
prf_data_params: &'a [PrfDataParam<'a>],
iv: Option<&'a [u8]>,
additional_derived_keys: Option<&'a mut [DerivedKey]>,
) -> Self {
let mut additional_derived_keys = additional_derived_keys.map(|keys| {
keys.iter_mut()
.map(Into::into)
.collect::<Box<[CK_DERIVED_KEY]>>()
});
let inner = CK_SP800_108_FEEDBACK_KDF_PARAMS {
prfType: prf_mechanism.into(),
ulNumberOfDataParams: prf_data_params
.len()
.try_into()
.expect("number of PRF data parameters does not fit in CK_ULONG"),
pDataParams: prf_data_params.as_ptr() as CK_PRF_DATA_PARAM_PTR,
ulIVLen: iv.map_or(0, |iv| {
iv.len()
.try_into()
.expect("IV length does not fit in CK_ULONG")
}),
pIV: iv.map_or(ptr::null_mut(), |iv| iv.as_ptr() as *mut _),
ulAdditionalDerivedKeys: additional_derived_keys.as_ref().map_or(0, |keys| {
keys.len()
.try_into()
.expect("number of additional derived keys does not fit in CK_ULONG")
}),
pAdditionalDerivedKeys: additional_derived_keys
.as_mut()
.map_or(ptr::null_mut(), |keys| {
keys.as_mut_ptr() as CK_DERIVED_KEY_PTR
}),
};
Self {
_additional_derived_keys: additional_derived_keys,
inner,
_marker: PhantomData,
}
}
pub(crate) fn inner(&self) -> &CK_SP800_108_FEEDBACK_KDF_PARAMS {
&self.inner
}
}