use sha2::{Digest, Sha256};
use crate::error::CryptoError;
pub fn concat_kdf(
z: &[u8],
alg: &[u8],
apu: &[u8],
apv: &[u8],
key_len_bits: u32,
) -> Result<Vec<u8>, CryptoError> {
let key_len_bytes = (key_len_bits / 8) as usize;
let mut hasher = Sha256::new();
hasher.update(1u32.to_be_bytes());
hasher.update(z);
hasher.update((alg.len() as u32).to_be_bytes());
hasher.update(alg);
hasher.update((apu.len() as u32).to_be_bytes());
hasher.update(apu);
hasher.update((apv.len() as u32).to_be_bytes());
hasher.update(apv);
hasher.update(key_len_bits.to_be_bytes());
let hash = hasher.finalize();
Ok(hash[..key_len_bytes].to_vec())
}
pub fn concat_kdf_1pu(
z: &[u8],
alg: &[u8],
apu: &[u8],
apv: &[u8],
key_len_bits: u32,
cc_tag: &[u8],
) -> Result<Vec<u8>, CryptoError> {
concat_kdf_1pu_inner(z, alg, apu, apv, key_len_bits, cc_tag, false)
}
pub fn concat_kdf_1pu_legacy(
z: &[u8],
alg: &[u8],
apu: &[u8],
apv: &[u8],
key_len_bits: u32,
cc_tag: &[u8],
) -> Result<Vec<u8>, CryptoError> {
concat_kdf_1pu_inner(z, alg, apu, apv, key_len_bits, cc_tag, true)
}
fn concat_kdf_1pu_inner(
z: &[u8],
alg: &[u8],
apu: &[u8],
apv: &[u8],
key_len_bits: u32,
cc_tag: &[u8],
legacy_tag_encoding: bool,
) -> Result<Vec<u8>, CryptoError> {
if cc_tag.is_empty() {
return concat_kdf(z, alg, apu, apv, key_len_bits);
}
let key_len_bytes = (key_len_bits / 8) as usize;
let mut hasher = Sha256::new();
hasher.update(1u32.to_be_bytes());
hasher.update(z);
hasher.update((alg.len() as u32).to_be_bytes());
hasher.update(alg);
hasher.update((apu.len() as u32).to_be_bytes());
hasher.update(apu);
hasher.update((apv.len() as u32).to_be_bytes());
hasher.update(apv);
hasher.update(key_len_bits.to_be_bytes());
if !legacy_tag_encoding {
hasher.update((cc_tag.len() as u32).to_be_bytes());
}
hasher.update(cc_tag);
let hash = hasher.finalize();
Ok(hash[..key_len_bytes].to_vec())
}