use crate::Digest;
use crate::hmac::hmac_multi;
use alloc::vec;
#[inline]
fn l_bits(out_len: usize) -> [u8; 4] {
((out_len as u32).wrapping_mul(8)).to_be_bytes()
}
pub fn counter<H: Digest>(kdk: &[u8], label: &[u8], context: &[u8], out: &mut [u8]) {
let hlen = H::OUTPUT_LEN;
let l = l_bits(out.len());
let mut ki = vec![0u8; hlen];
let mut offset = 0;
let mut i: u32 = 1;
while offset < out.len() {
hmac_multi::<H>(kdk, &[&i.to_be_bytes(), label, &[0x00], context, &l], &mut ki);
let take = core::cmp::min(hlen, out.len() - offset);
out[offset..offset + take].copy_from_slice(&ki[..take]);
offset += take;
i += 1;
}
}
pub fn feedback<H: Digest>(kdk: &[u8], label: &[u8], context: &[u8], iv: &[u8], out: &mut [u8]) {
let hlen = H::OUTPUT_LEN;
let l = l_bits(out.len());
let mut k = vec![0u8; hlen]; let mut prev: &[u8] = iv; let mut offset = 0;
let mut i: u32 = 1;
while offset < out.len() {
let mut ki = vec![0u8; hlen];
hmac_multi::<H>(kdk, &[prev, &i.to_be_bytes(), label, &[0x00], context, &l], &mut ki);
k = ki;
let take = core::cmp::min(hlen, out.len() - offset);
out[offset..offset + take].copy_from_slice(&k[..take]);
offset += take;
i += 1;
prev = &k;
}
}
pub fn double_pipeline<H: Digest>(kdk: &[u8], label: &[u8], context: &[u8], out: &mut [u8]) {
let hlen = H::OUTPUT_LEN;
let l = l_bits(out.len());
let mut a = vec![0u8; hlen];
let mut ki = vec![0u8; hlen];
let mut offset = 0;
let mut i: u32 = 1;
while offset < out.len() {
if i == 1 {
hmac_multi::<H>(kdk, &[label, &[0x00], context, &l], &mut a);
} else {
let a_prev = a.clone();
hmac_multi::<H>(kdk, &[&a_prev], &mut a);
}
hmac_multi::<H>(kdk, &[&a, &i.to_be_bytes(), label, &[0x00], context, &l], &mut ki);
let take = core::cmp::min(hlen, out.len() - offset);
out[offset..offset + take].copy_from_slice(&ki[..take]);
offset += take;
i += 1;
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::sha2::Sha256;
use alloc::vec::Vec;
fn hx(h: &str) -> Vec<u8> {
(0..h.len())
.step_by(2)
.map(|i| u8::from_str_radix(&h[i..i + 2], 16).unwrap())
.collect()
}
#[test]
fn counter_sha256_smoke() {
let kdk = hx("00112233445566778899aabbccddeeff");
let mut out = [0u8; 32];
counter::<Sha256>(&kdk, b"label", b"context", &mut out);
assert_eq!(
out[..],
hx("0221984163d8ce7453e80fe3d91b9f262bf7d316fd29aeb415d6ae903adae919")[..]
);
}
}