use crate::error::{map_result, Error, Result};
use boring::hash::MessageDigest;
use boring_sys as bffi;
use bytes::{BufMut, BytesMut};
use once_cell::sync::Lazy;
pub(crate) const DIGEST_BLOCK_LEN: usize = bffi::SHA_CBLOCK as _;
#[derive(Clone, Copy, Eq, PartialEq)]
pub(crate) struct Hkdf(MessageDigest);
static SHA256: Lazy<Hkdf> = Lazy::new(|| Hkdf(MessageDigest::sha256()));
static SHA384: Lazy<Hkdf> = Lazy::new(|| Hkdf(MessageDigest::sha384()));
impl Hkdf {
pub(crate) fn sha256() -> Hkdf {
*SHA256
}
pub(crate) fn sha384() -> Hkdf {
*SHA384
}
#[inline]
pub(crate) fn digest_size(self) -> usize {
self.0.size()
}
#[inline]
pub(crate) fn extract(self, salt: &[u8], ikm: &[u8], out: &mut [u8]) -> Result<usize> {
if out.len() < self.digest_size() {
return Err(Error::invalid_input(format!(
"HKDF extract output array invalid size: {}",
out.len()
)));
}
let mut out_len = out.len();
unsafe {
map_result(bffi::HKDF_extract(
out.as_mut_ptr(),
&mut out_len,
self.0.as_ptr(),
ikm.as_ptr(),
ikm.len(),
salt.as_ptr(),
salt.len(),
))?;
Ok(out_len)
}
}
#[inline]
pub(crate) fn expand_label(self, secret: &[u8], label: &[u8], out: &mut [u8]) -> Result<()> {
let label = {
const TLS_VERSION_LABEL: &[u8] = b"tls13 ";
let label_len = TLS_VERSION_LABEL.len() + label.len();
let builder_capacity = label_len + 4;
let mut builder = BytesMut::with_capacity(builder_capacity);
builder.put_u16(out.len() as u16);
builder.put_u8(label_len as u8);
builder.put(TLS_VERSION_LABEL);
builder.put(label);
builder.put_u8(0);
builder
};
self.expand(secret, &label, out)
}
#[inline]
pub(crate) fn expand(&self, prk: &[u8], info: &[u8], out: &mut [u8]) -> Result<()> {
unsafe {
map_result(bffi::HKDF_expand(
out.as_mut_ptr(),
out.len(),
self.0.as_ptr(),
prk.as_ptr(),
prk.len(),
info.as_ptr(),
info.len(),
))?;
}
Ok(())
}
}