use crate::types::Random;
use openssl::symm::{encrypt, Cipher};
use std::io::Error;
pub const CUSTOMIZATION_STRING_LENGTH: usize = 48;
const AES256_KEY_LENGTH: usize = 32;
const AES256_V_LENGTH: usize = 16;
pub struct Aes256CtrDrbg {
key: [u8; AES256_KEY_LENGTH],
v: [u8; AES256_V_LENGTH],
reseed_counter: i32,
}
impl Aes256CtrDrbg {
pub fn new(entropy_input: &[u8], personalization_string: Option<&[u8]>) -> Aes256CtrDrbg {
let mut seed_material: [u8; CUSTOMIZATION_STRING_LENGTH] = [0; CUSTOMIZATION_STRING_LENGTH];
seed_material.clone_from_slice(&entropy_input[..CUSTOMIZATION_STRING_LENGTH]);
if let Some(p_string) = personalization_string {
array_xor_in_place!(seed_material, p_string)
}
let mut ctr_drbg = Aes256CtrDrbg {
key: [0; AES256_KEY_LENGTH],
v: [0; AES256_V_LENGTH],
reseed_counter: 1
};
ctr_drbg.update(Some(&seed_material));
ctr_drbg
}
fn update(&mut self, provided_data: Option<&[u8]>) {
let encryptor_iter = (0..CUSTOMIZATION_STRING_LENGTH / 16)
.flat_map(|_| {
self.inc_v();
encrypt(Cipher::aes_256_ecb(), &self.key, None, &self.v)
.unwrap()
.into_iter()
.take(16)
});
let mut temp: [u8; CUSTOMIZATION_STRING_LENGTH] = array_init::from_iter(encryptor_iter).unwrap();
if let Some(data) = provided_data {
array_xor_in_place!(temp, data)
}
self.key.clone_from_slice(&temp[..32]);
self.v.clone_from_slice(&temp[32..48]);
}
fn inc_v(&mut self) {
for v in self.v.iter_mut().rev() {
match *v {
0xff => { *v = 0x00; },
_ => {
*v += 1;
break;
}
};
}
}
fn randombytes(&mut self, dest: &mut [u8], len: usize) -> Result<(), openssl::error::ErrorStack> {
let mut block = [0u8; 16];
let mut i = 0usize;
let mut xlen = len;
while xlen > 0 {
self.inc_v();
block.copy_from_slice(&encrypt(Cipher::aes_256_ecb(), &self.key, None, &self.v)?[..16]);
if xlen > 15 {
dest[i..i + 16].copy_from_slice(&block);
i += 16;
xlen -= 16;
} else {
dest[i..i + xlen as usize].copy_from_slice(&block[..xlen as usize]);
xlen = 0;
}
}
self.update(None);
self.reseed_counter += 1;
Ok(())
}
}
impl rand_core::RngCore for Aes256CtrDrbg {
fn next_u32(&mut self) -> u32 {
rand_core::impls::next_u32_via_fill(self)
}
fn next_u64(&mut self) -> u64 {
rand_core::impls::next_u64_via_fill(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.try_fill_bytes(dest).unwrap();
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> {
self.randombytes(dest, dest.len()).map_err(|e| rand_core::Error::new(Error::from(e)))
}
}
impl rand_core::CryptoRng for Aes256CtrDrbg { }
impl Random for Aes256CtrDrbg { }