use std::{convert::TryInto, ffi::CString};
use crate::{KcapiError, KcapiResult, ACCESS_HEURISTIC, INIT_AIO};
pub const ECC_CURVE_NIST_P192: u64 = kcapi_sys::ECC_CURVE_NIST_P192 as u64;
pub const ECC_CURVE_NIST_P256: u64 = kcapi_sys::ECC_CURVE_NIST_P256 as u64;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct KcapiKPP {
handle: *mut kcapi_sys::kcapi_handle,
pub outsize: usize,
pub algorithm: String,
}
impl KcapiKPP {
pub fn new(algorithm: &str, flags: u32) -> KcapiResult<Self> {
let mut handle = Box::into_raw(Box::new(crate::kcapi_handle { _unused: [0u8; 0] }))
as *mut kcapi_sys::kcapi_handle;
let alg = CString::new(algorithm).expect("Failed to create CString");
unsafe {
let ret = kcapi_sys::kcapi_kpp_init(&mut handle as *mut _, alg.as_ptr(), flags);
if ret < 0 {
return Err(KcapiError {
code: ret,
message: format!(
"Failed to initialize kpp handle for algorithm '{}'",
algorithm
),
});
}
}
Ok(KcapiKPP {
algorithm: algorithm.to_string(),
handle,
outsize: 0,
})
}
pub fn dh_setparam_pkcs3(&mut self, pkcs3: Vec<u8>) -> KcapiResult<()> {
unsafe {
let ret = kcapi_sys::kcapi_kpp_dh_setparam_pkcs3(
self.handle,
pkcs3.as_ptr(),
pkcs3.len() as u32,
);
if ret < 0 {
return Err(KcapiError {
code: ret,
message: format!(
"Failed to set DH PKCS#3 parameters for algorithm '{}'",
self.algorithm
),
});
}
}
Ok(())
}
pub fn ecdh_setcurve(&mut self, curve_id: u64) -> KcapiResult<()> {
unsafe {
let ret = kcapi_sys::kcapi_kpp_ecdh_setcurve(
self.handle,
curve_id as ::std::os::raw::c_ulong,
);
if ret < 0 {
return Err(KcapiError {
code: ret,
message: format!(
"Failed to set ECC curve {} for algorithm '{}'",
curve_id, self.algorithm
),
});
}
}
Ok(())
}
pub fn setkey(&mut self, key: Vec<u8>) -> KcapiResult<()> {
unsafe {
let ret = kcapi_sys::kcapi_kpp_setkey(self.handle, key.as_ptr(), key.len() as u32);
if ret < 0 {
return Err(KcapiError {
code: ret,
message: format!("Failed to set key for algorithm '{}'", self.algorithm),
});
}
self.outsize = ret.try_into().expect("Failed to convert i32 into usize");
}
Ok(())
}
pub fn keygen(&self, access: u32) -> KcapiResult<Vec<u8>> {
let mut pubkey = vec![0u8; self.outsize];
let ret: kcapi_sys::ssize_t;
unsafe {
ret = kcapi_sys::kcapi_kpp_keygen(
self.handle,
pubkey.as_mut_ptr(),
pubkey.len() as kcapi_sys::size_t,
access as ::std::os::raw::c_int,
);
if ret < 0 {
return Err(KcapiError {
code: ret.try_into().expect("failed to convert i64 into i32"),
message: format!(
"Failed to generate public key for algorithm '{}'",
self.algorithm
),
});
}
}
pubkey.truncate(ret as usize);
Ok(pubkey)
}
pub fn ssgen(&self, pubkey: Vec<u8>, access: u32) -> KcapiResult<Vec<u8>> {
let mut ss = vec![0u8; self.outsize];
let ret: kcapi_sys::ssize_t;
unsafe {
ret = kcapi_sys::kcapi_kpp_ssgen(
self.handle,
pubkey.as_ptr(),
pubkey.len() as kcapi_sys::size_t,
ss.as_mut_ptr(),
ss.len() as kcapi_sys::size_t,
access as ::std::os::raw::c_int,
);
if ret < 0 {
return Err(KcapiError {
code: ret.try_into().expect("failed to convert i64 into i32"),
message: format!(
"Failed to generate shared secret for algorithm '{}'",
self.algorithm
),
});
}
}
ss.truncate(ret as usize);
Ok(ss)
}
}
impl Drop for KcapiKPP {
fn drop(&mut self) {
unsafe {
kcapi_sys::kcapi_kpp_destroy(self.handle);
}
}
}
pub fn ecdh_ephemeral_keygen(curve_id: u64) -> KcapiResult<(KcapiKPP, Vec<u8>)> {
let mut kpp = KcapiKPP::new("ecdh", !INIT_AIO)?;
kpp.ecdh_setcurve(curve_id)?;
kpp.setkey(Vec::new())?;
let pubkey = kpp.keygen(ACCESS_HEURISTIC)?;
Ok((kpp, pubkey))
}