#[cfg(feature = "aes-drbg")]
use alloc::format;
#[cfg(feature = "aes-drbg")]
use alloc::string::String;
#[cfg(feature = "aes-drbg")]
use aes::Aes256;
#[cfg(feature = "aes-drbg")]
use aes::cipher::{
Array,
BlockCipherEncrypt,
KeyInit,
};
use rand_core::{
TryCryptoRng,
TryRng,
};
#[cfg(feature = "aes-drbg")]
#[derive(Debug, Clone)]
pub struct Aes256CtrDrbg {
key: [u8; 32],
v: [u8; 16],
reseed_counter: u64,
}
#[cfg(feature = "aes-drbg")]
impl Aes256CtrDrbg {
pub fn instantiate(entropy_input: &[u8; 48]) -> Self {
let mut key = [0u8; 32];
let mut v = [0u8; 16];
Self::ctr_drbg_update(Some(entropy_input), &mut key, &mut v);
Self {
key,
v,
reseed_counter: 1,
}
}
pub fn aes256_ecb(key: &[u8; 32], input: &[u8; 16]) -> [u8; 16] {
let cipher = Aes256::new(&Array::from(*key));
let mut block = Array::from(*input);
cipher.encrypt_block(&mut block);
block.into()
}
fn ctr_drbg_update(provided_data: Option<&[u8; 48]>, key: &mut [u8; 32], v: &mut [u8; 16]) {
let mut temp = [0u8; 48];
for i in 0..3 {
Self::increment_counter(v);
let block = Self::aes256_ecb(key, v);
temp[i * 16..(i + 1) * 16].copy_from_slice(&block);
}
if let Some(data) = provided_data {
for i in 0..48 {
temp[i] ^= data[i];
}
}
key.copy_from_slice(&temp[..32]);
v.copy_from_slice(&temp[32..48]);
}
pub fn increment_counter(v: &mut [u8; 16]) {
for i in (0..16).rev() {
if v[i] == 0xFF {
v[i] = 0x00;
} else {
v[i] += 1;
break;
}
}
}
}
#[cfg(feature = "aes-drbg")]
impl TryRng for Aes256CtrDrbg {
type Error = core::convert::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
let mut bytes = [0u8; 4];
self.try_fill_bytes(&mut bytes)?;
Ok(u32::from_le_bytes(bytes))
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
let mut bytes = [0u8; 8];
self.try_fill_bytes(&mut bytes)?;
Ok(u64::from_le_bytes(bytes))
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
let mut offset = 0;
while offset < dest.len() {
Self::increment_counter(&mut self.v);
let block = Self::aes256_ecb(&self.key, &self.v);
let to_copy = core::cmp::min(16, dest.len() - offset);
dest[offset..offset + to_copy].copy_from_slice(&block[..to_copy]);
offset += to_copy;
}
Self::ctr_drbg_update(None, &mut self.key, &mut self.v);
self.reseed_counter += 1;
Ok(())
}
}
#[cfg(feature = "aes-drbg")]
impl TryCryptoRng for Aes256CtrDrbg {}
#[cfg(feature = "aes-drbg")]
impl Aes256CtrDrbg {
pub fn debug_state(&self) -> String {
format!(
"Key: {:02x?}\nV: {:02x?}\nReseed: {}",
&self.key[..],
&self.v[..],
self.reseed_counter
)
}
}
#[cfg(feature = "aes-drbg")]
pub fn create_aes_ctr_drbg_rng(entropy: [u8; 48]) -> Aes256CtrDrbg {
Aes256CtrDrbg::instantiate(&entropy)
}
#[cfg(not(feature = "aes-drbg"))]
pub struct Aes256CtrDrbg;
#[cfg(not(feature = "aes-drbg"))]
impl Aes256CtrDrbg {
pub fn instantiate(_entropy_input: &[u8; 48]) -> Self {
panic!("AES-CTR-DRBG requires the 'aes-drbg' feature to be enabled");
}
}
#[cfg(not(feature = "aes-drbg"))]
impl TryRng for Aes256CtrDrbg {
type Error = core::convert::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
panic!("AES-CTR-DRBG requires the 'aes-drbg' feature to be enabled");
}
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
panic!("AES-CTR-DRBG requires the 'aes-drbg' feature to be enabled");
}
fn try_fill_bytes(&mut self, _dest: &mut [u8]) -> Result<(), Self::Error> {
panic!("AES-CTR-DRBG requires the 'aes-drbg' feature to be enabled");
}
}
#[cfg(not(feature = "aes-drbg"))]
impl TryCryptoRng for Aes256CtrDrbg {}
#[cfg(not(feature = "aes-drbg"))]
pub fn create_aes_ctr_drbg_rng(_entropy: [u8; 48]) -> Aes256CtrDrbg {
panic!("AES-CTR-DRBG requires the 'aes-drbg' feature to be enabled");
}