extern crate alloc;
use alloc::vec;
use alloc::vec::Vec;
use crate::error::WolfCryptError;
const WC_FFDHE_2048: i32 = 256;
const WC_FFDHE_3072: i32 = 257;
const WC_FFDHE_4096: i32 = 258;
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FfdheGroup {
Ffdhe2048,
Ffdhe3072,
Ffdhe4096,
}
impl FfdheGroup {
fn wc_name(self) -> i32 {
match self {
FfdheGroup::Ffdhe2048 => WC_FFDHE_2048,
FfdheGroup::Ffdhe3072 => WC_FFDHE_3072,
FfdheGroup::Ffdhe4096 => WC_FFDHE_4096,
}
}
fn byte_size(self) -> usize {
match self {
FfdheGroup::Ffdhe2048 => 256,
FfdheGroup::Ffdhe3072 => 384,
FfdheGroup::Ffdhe4096 => 512,
}
}
}
pub struct DhSecret {
ctx: *mut core::ffi::c_void,
group_sz: usize,
}
unsafe impl Send for DhSecret {}
impl Drop for DhSecret {
fn drop(&mut self) {
if !self.ctx.is_null() {
unsafe { wolfcrypt_rs::wolfcrypt_dh_free(self.ctx) };
}
}
}
impl DhSecret {
pub fn generate(group: FfdheGroup) -> Result<Self, WolfCryptError> {
let ctx =
unsafe { wolfcrypt_rs::wolfcrypt_dh_new(group.wc_name(), group.byte_size() as u32) };
if ctx.is_null() {
return Err(WolfCryptError::ALLOC_FAILED);
}
let rc = unsafe { wolfcrypt_rs::wolfcrypt_dh_generate_keypair(ctx) };
if rc != 0 {
unsafe { wolfcrypt_rs::wolfcrypt_dh_free(ctx) };
return Err(WolfCryptError::Ffi {
code: rc,
func: "wolfcrypt_dh_generate_keypair",
});
}
Ok(Self {
ctx,
group_sz: group.byte_size(),
})
}
pub fn generate_ffdhe2048() -> Result<Self, WolfCryptError> {
Self::generate(FfdheGroup::Ffdhe2048)
}
pub fn public_key_bytes(&self) -> Result<Vec<u8>, WolfCryptError> {
let mut buf = vec![0u8; self.group_sz];
let mut len = self.group_sz as u32;
let rc =
unsafe { wolfcrypt_rs::wolfcrypt_dh_public_key(self.ctx, buf.as_mut_ptr(), &mut len) };
if rc != 0 {
return Err(WolfCryptError::Ffi {
code: rc,
func: "wolfcrypt_dh_public_key",
});
}
buf.truncate(len as usize);
Ok(buf)
}
pub fn size(&self) -> usize {
self.group_sz
}
pub fn compute_shared_secret(
&self,
peer_pub_bytes: &[u8],
) -> Result<zeroize::Zeroizing<Vec<u8>>, WolfCryptError> {
let mut secret = vec![0u8; self.group_sz];
let mut sz = self.group_sz as u32;
let rc = unsafe {
wolfcrypt_rs::wolfcrypt_dh_agree(
self.ctx,
peer_pub_bytes.as_ptr(),
peer_pub_bytes.len() as u32,
secret.as_mut_ptr(),
&mut sz,
)
};
if rc != 0 {
return Err(WolfCryptError::Ffi {
code: rc,
func: "wolfcrypt_dh_agree",
});
}
secret.truncate(sz as usize);
Ok(zeroize::Zeroizing::new(secret))
}
}