diff --git a/src/hkdf.rs b/src/hkdf.rs new file mode 100644 index 0000000..cc7e5b3 --- /dev/null +++ b/src/hkdf.rs @@ -0,0 +1,89 @@ +use crate::cvt; +use crate::error::ErrorStack; +use crate::md::MdRef; +use foreign_types::ForeignTypeRef; +use openssl_macros::corresponds; + +/// Computes HKDF (as specified by RFC 5869). +/// +/// HKDF is an Extract-and-Expand algorithm. It does not do any key stretching, +/// and as such, is not suited to be used alone to generate a key from a +/// password. +#[corresponds(HKDF)] +#[inline] +pub fn hkdf( + out_key: &mut [u8], + md: &MdRef, + secret: &[u8], + salt: &[u8], + info: &[u8], +) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::HKDF( + out_key.as_mut_ptr(), + out_key.len(), + md.as_ptr(), + secret.as_ptr(), + secret.len(), + salt.as_ptr(), + salt.len(), + info.as_ptr(), + info.len(), + ))?; + } + + Ok(()) +} + +/// Computes a HKDF PRK (as specified by RFC 5869). +/// +/// WARNING: This function orders the inputs differently from RFC 5869 +/// specification. Double-check which parameter is the secret/IKM and which is +/// the salt when using. +#[corresponds(HKDF_extract)] +#[inline] +pub fn hkdf_extract<'a>( + out_key: &'a mut [u8], + md: &MdRef, + secret: &[u8], + salt: &[u8], +) -> Result<&'a [u8], ErrorStack> { + let mut out_len = out_key.len(); + unsafe { + cvt(ffi::HKDF_extract( + out_key.as_mut_ptr(), + &mut out_len, + md.as_ptr(), + secret.as_ptr(), + secret.len(), + salt.as_ptr(), + salt.len(), + ))?; + } + + Ok(&out_key[..out_len]) +} + +/// Computes a HKDF OKM (as specified by RFC 5869). +#[corresponds(HKDF_expand)] +#[inline] +pub fn hkdf_expand( + out_key: &mut [u8], + md: &MdRef, + prk: &[u8], + info: &[u8], +) -> Result<(), ErrorStack> { + unsafe { + cvt(ffi::HKDF_expand( + out_key.as_mut_ptr(), + out_key.len(), + md.as_ptr(), + prk.as_ptr(), + prk.len(), + info.as_ptr(), + info.len(), + ))?; + } + + Ok(()) +}