libsignal_protocol/
hkdf.rs

1use crate::{
2    context::ContextInner,
3    errors::{FromInternalErrorCode, InternalError},
4    raw_ptr::Raw,
5    Context,
6};
7use failure::Error;
8use std::{ptr, rc::Rc};
9
10/// Context for a HMAC-based Key Derivation Function.
11#[derive(Debug, Clone)]
12pub struct HMACBasedKeyDerivationFunction {
13    pub(crate) raw: Raw<sys::hkdf_context>,
14    ctx: Rc<ContextInner>,
15}
16
17impl HMACBasedKeyDerivationFunction {
18    pub(crate) fn new(
19        version: i32,
20        ctx: &Context,
21    ) -> Result<HMACBasedKeyDerivationFunction, Error> {
22        unsafe {
23            let mut raw = ptr::null_mut();
24            sys::hkdf_create(&mut raw, version as _, ctx.raw())
25                .into_result()?;
26
27            Ok(HMACBasedKeyDerivationFunction {
28                raw: Raw::from_ptr(raw),
29                ctx: Rc::clone(&ctx.0),
30            })
31        }
32    }
33
34    /// Derive a new secret by cryptographically "stretching" the provided
35    /// information to the expected length.
36    pub fn derive_secrets(
37        &self,
38        secret_length: usize,
39        input_key_material: &[u8],
40        salt: &[u8],
41        info: &[u8],
42    ) -> Result<Vec<u8>, Error> {
43        unsafe {
44            let mut secret = ptr::null_mut();
45            let prk_len = sys::hkdf_derive_secrets(
46                self.raw.as_ptr(),
47                &mut secret,
48                input_key_material.as_ptr(),
49                input_key_material.len(),
50                salt.as_ptr(),
51                salt.len(),
52                info.as_ptr(),
53                info.len(),
54                secret_length,
55            );
56
57            if prk_len < 0 {
58                return Err(InternalError::from_error_code(prk_len as i32)
59                    .unwrap_or(InternalError::Unknown)
60                    .into());
61            }
62
63            // Note: I'm not 100% sure this is sound. `secret` was allocated
64            // using malloc, but the allocator used to free our Vec is
65            // unspecified...
66            let secret = std::slice::from_raw_parts_mut(secret, secret_length);
67            Ok(Vec::from(Box::from_raw(secret)))
68        }
69    }
70}