use super::KeyDerivationFunction;
use crate::error::{CryptoKitError, Result};
extern "C" {
#[link_name = "hkdf_sha256_derive"]
fn swift_hkdf_sha256_derive(
input_key: *const u8,
input_key_len: i32,
salt: *const u8,
salt_len: i32,
info: *const u8,
info_len: i32,
output_length: i32,
output: *mut u8,
) -> i32;
}
#[allow(non_camel_case_types)]
pub struct HKDF_SHA256;
impl HKDF_SHA256 {
pub fn derive_key(
input_key_material: &[u8],
salt: &[u8],
info: &[u8],
output_length: usize,
) -> Result<Vec<u8>> {
Self::derive(input_key_material, salt, info, output_length)
}
}
impl KeyDerivationFunction for HKDF_SHA256 {
fn derive(
input_key_material: &[u8],
salt: &[u8],
info: &[u8],
output_length: usize,
) -> Result<Vec<u8>> {
if input_key_material.is_empty() {
return Err(CryptoKitError::InvalidInput(
"Input key material cannot be empty".to_string(),
));
}
if output_length == 0 || output_length > 255 * 32 {
return Err(CryptoKitError::InvalidLength);
}
unsafe {
let mut output = vec![0u8; output_length];
let result = swift_hkdf_sha256_derive(
input_key_material.as_ptr(),
input_key_material.len() as i32,
salt.as_ptr(),
salt.len() as i32,
info.as_ptr(),
info.len() as i32,
output_length as i32,
output.as_mut_ptr(),
);
if result == 0 {
Ok(output)
} else {
Err(CryptoKitError::DerivationFailed)
}
}
}
}
pub fn hkdf_sha256_derive(
input_key_material: &[u8],
salt: &[u8],
info: &[u8],
output_length: usize,
) -> Result<Vec<u8>> {
HKDF_SHA256::derive(input_key_material, salt, info, output_length)
}