use crate::hash::hmac_sha256;
use crate::internal_alloc::Vec;
use noxtls_core::{Error, Result};
#[derive(Debug, Clone)]
pub struct HmacDrbgSha256 {
k: [u8; 32],
v: [u8; 32],
reseed_counter: u64,
}
impl HmacDrbgSha256 {
pub fn new(entropy: &[u8], nonce: &[u8], personalization: &[u8]) -> Result<Self> {
if entropy.len() < 16 {
return Err(Error::InvalidLength(
"drbg entropy input must be at least 16 bytes",
));
}
let mut drbg = Self {
k: [0_u8; 32],
v: [0x01_u8; 32],
reseed_counter: 1,
};
let mut seed = Vec::with_capacity(entropy.len() + nonce.len() + personalization.len());
seed.extend_from_slice(entropy);
seed.extend_from_slice(nonce);
seed.extend_from_slice(personalization);
drbg.update(Some(&seed));
Ok(drbg)
}
pub fn reseed(&mut self, entropy: &[u8], additional_input: &[u8]) -> Result<()> {
if entropy.len() < 16 {
return Err(Error::InvalidLength(
"drbg entropy input must be at least 16 bytes",
));
}
let mut seed = Vec::with_capacity(entropy.len() + additional_input.len());
seed.extend_from_slice(entropy);
seed.extend_from_slice(additional_input);
self.update(Some(&seed));
self.reseed_counter = 1;
Ok(())
}
pub fn generate(&mut self, out_len: usize, additional_input: &[u8]) -> Result<Vec<u8>> {
if out_len == 0 {
return Ok(Vec::new());
}
if self.reseed_counter > 1_000_000 {
return Err(Error::StateError("drbg reseed required"));
}
if !additional_input.is_empty() {
self.update(Some(additional_input));
}
let mut out = Vec::with_capacity(out_len);
while out.len() < out_len {
self.v = hmac_sha256(&self.k, &self.v);
out.extend_from_slice(&self.v);
}
out.truncate(out_len);
self.update(if additional_input.is_empty() {
None
} else {
Some(additional_input)
});
self.reseed_counter += 1;
Ok(out)
}
fn update(&mut self, provided_data: Option<&[u8]>) {
let mut msg = Vec::with_capacity(self.v.len() + 1 + provided_data.map_or(0, <[u8]>::len));
msg.extend_from_slice(&self.v);
msg.push(0x00);
if let Some(data) = provided_data {
msg.extend_from_slice(data);
}
self.k = hmac_sha256(&self.k, &msg);
self.v = hmac_sha256(&self.k, &self.v);
if let Some(data) = provided_data {
let mut msg = Vec::with_capacity(self.v.len() + 1 + data.len());
msg.extend_from_slice(&self.v);
msg.push(0x01);
msg.extend_from_slice(data);
self.k = hmac_sha256(&self.k, &msg);
self.v = hmac_sha256(&self.k, &self.v);
}
}
}