use std::{convert::TryInto, ffi::CString};
use crate::{KcapiError, KcapiResult, INIT_AIO};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct KcapiRNG {
handle: *mut kcapi_sys::kcapi_handle,
pub algorithm: String,
pub seedsize: usize,
}
impl KcapiRNG {
pub fn new(algorithm: &str) -> 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");
let seedsize: usize;
unsafe {
let ret = kcapi_sys::kcapi_rng_init(&mut handle as *mut _, alg.as_ptr(), !INIT_AIO);
if ret < 0 {
return Err(KcapiError {
code: ret,
message: format!(
"Failed to initialize RNG handle for algorithm '{}'",
algorithm,
),
});
}
seedsize = kcapi_sys::kcapi_rng_seedsize(handle)
.try_into()
.expect("Failed to convert u32 into usize");
}
Ok(KcapiRNG {
handle,
algorithm: algorithm.to_string(),
seedsize,
})
}
pub fn setentropy(&self, mut entropy: Vec<u8>) -> KcapiResult<()> {
unsafe {
let ret = kcapi_sys::kcapi_rng_setentropy(
self.handle,
entropy.as_mut_ptr(),
entropy.len() as u32,
);
if ret < 0 {
return Err(KcapiError {
code: ret,
message: format!(
"Failed to set RNG entropy for algorithm '{}'",
self.algorithm
),
});
}
}
Ok(())
}
pub fn setaddtl(&self, mut entropy: Vec<u8>) -> KcapiResult<()> {
unsafe {
let ret = kcapi_sys::kcapi_rng_setaddtl(
self.handle,
entropy.as_mut_ptr(),
entropy.len() as u32,
);
if ret < 0 {
return Err(KcapiError {
code: ret,
message: format!(
"Failed to set RNG entropy for algorithm '{}'",
self.algorithm
),
});
}
}
Ok(())
}
pub fn seed(&self, mut data: Vec<u8>) -> KcapiResult<()> {
unsafe {
let ret = kcapi_sys::kcapi_rng_seed(self.handle, data.as_mut_ptr(), data.len() as u32);
if ret < 0 {
return Err(KcapiError {
code: ret,
message: format!("Failed to seed RNG for algorithm '{}'", self.algorithm,),
});
}
}
Ok(())
}
pub fn generate(&self, count: usize) -> KcapiResult<Vec<u8>> {
let mut out = vec![0u8; count];
unsafe {
let ret = kcapi_sys::kcapi_rng_generate(
self.handle,
out.as_mut_ptr(),
count as kcapi_sys::size_t,
);
if ret < 0 {
return Err(KcapiError {
code: ret.try_into().expect("failed to convert i64 into i32"),
message: format!(
"Failed to generate random data for algorithm '{}'",
self.algorithm,
),
});
}
}
Ok(out)
}
}
impl Drop for KcapiRNG {
fn drop(&mut self) {
unsafe {
kcapi_sys::kcapi_rng_destroy(self.handle);
}
}
}
pub fn get_bytes(count: usize) -> KcapiResult<Vec<u8>> {
let mut out = vec![0u8; count];
unsafe {
let ret = kcapi_sys::kcapi_rng_get_bytes(out.as_mut_ptr(), count as kcapi_sys::size_t);
if ret < 0 {
return Err(KcapiError {
code: ret.try_into().expect("failed to convert i64 into i32"),
message: format!("Failed to obtain {} bytes from the stdrng", count),
});
}
}
Ok(out)
}