use crate::hash::{noxtls_hmac_sha256, noxtls_hmac_sha256_parts};
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 noxtls_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,
};
drbg.noxtls_update_multi(&[entropy, nonce, personalization]);
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",
));
}
self.noxtls_update_multi(&[entropy, additional_input]);
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.noxtls_update(Some(additional_input));
}
let mut out = Vec::with_capacity(out_len);
while out.len() < out_len {
self.v = noxtls_hmac_sha256(&self.k, &self.v);
out.extend_from_slice(&self.v);
}
out.truncate(out_len);
self.noxtls_update(if additional_input.is_empty() {
None
} else {
Some(additional_input)
});
self.reseed_counter += 1;
Ok(out)
}
fn noxtls_update(&mut self, provided_data: Option<&[u8]>) {
match provided_data {
Some(data) => self.noxtls_update_multi(&[data]),
None => self.noxtls_update_multi(&[]),
}
}
fn noxtls_update_multi(&mut self, provided_data: &[&[u8]]) {
let zero = [0_u8];
let one = [1_u8];
self.k = match provided_data {
[] => noxtls_hmac_sha256_parts(&self.k, &[&self.v[..], &zero]),
[a] => noxtls_hmac_sha256_parts(&self.k, &[&self.v[..], &zero, *a]),
[a, b] => noxtls_hmac_sha256_parts(&self.k, &[&self.v[..], &zero, *a, *b]),
[a, b, c] => noxtls_hmac_sha256_parts(&self.k, &[&self.v[..], &zero, *a, *b, *c]),
_ => {
let mut seed = Vec::new();
for data in provided_data {
seed.extend_from_slice(data);
}
noxtls_hmac_sha256_parts(&self.k, &[&self.v[..], &zero, &seed])
}
};
self.v = noxtls_hmac_sha256(&self.k, &self.v);
if !provided_data.is_empty() {
self.k = match provided_data {
[a] => noxtls_hmac_sha256_parts(&self.k, &[&self.v[..], &one, *a]),
[a, b] => noxtls_hmac_sha256_parts(&self.k, &[&self.v[..], &one, *a, *b]),
[a, b, c] => noxtls_hmac_sha256_parts(&self.k, &[&self.v[..], &one, *a, *b, *c]),
_ => {
let mut seed = Vec::new();
for data in provided_data {
seed.extend_from_slice(data);
}
noxtls_hmac_sha256_parts(&self.k, &[&self.v[..], &one, &seed])
}
};
self.v = noxtls_hmac_sha256(&self.k, &self.v);
}
}
}