1diff --git a/src/hkdf.rs b/src/hkdf.rs
2new file mode 100644
3index 0000000..cc7e5b3
4--- /dev/null
5+++ b/src/hkdf.rs
6@@ -0,0 +1,89 @@
7+use crate::cvt;
8+use crate::error::ErrorStack;
9+use crate::md::MdRef;
10+use foreign_types::ForeignTypeRef;
11+use openssl_macros::corresponds;
12+
13+/// Computes HKDF (as specified by RFC 5869).
14+///
15+/// HKDF is an Extract-and-Expand algorithm. It does not do any key stretching,
16+/// and as such, is not suited to be used alone to generate a key from a
17+/// password.
18+#[corresponds(HKDF)]
19+#[inline]
20+pub fn hkdf(
21+    out_key: &mut [u8],
22+    md: &MdRef,
23+    secret: &[u8],
24+    salt: &[u8],
25+    info: &[u8],
26+) -> Result<(), ErrorStack> {
27+    unsafe {
28+        cvt(ffi::HKDF(
29+            out_key.as_mut_ptr(),
30+            out_key.len(),
31+            md.as_ptr(),
32+            secret.as_ptr(),
33+            secret.len(),
34+            salt.as_ptr(),
35+            salt.len(),
36+            info.as_ptr(),
37+            info.len(),
38+        ))?;
39+    }
40+
41+    Ok(())
42+}
43+
44+/// Computes a HKDF PRK (as specified by RFC 5869).
45+///
46+/// WARNING: This function orders the inputs differently from RFC 5869
47+/// specification. Double-check which parameter is the secret/IKM and which is
48+/// the salt when using.
49+#[corresponds(HKDF_extract)]
50+#[inline]
51+pub fn hkdf_extract<'a>(
52+    out_key: &'a mut [u8],
53+    md: &MdRef,
54+    secret: &[u8],
55+    salt: &[u8],
56+) -> Result<&'a [u8], ErrorStack> {
57+    let mut out_len = out_key.len();
58+    unsafe {
59+        cvt(ffi::HKDF_extract(
60+            out_key.as_mut_ptr(),
61+            &mut out_len,
62+            md.as_ptr(),
63+            secret.as_ptr(),
64+            secret.len(),
65+            salt.as_ptr(),
66+            salt.len(),
67+        ))?;
68+    }
69+
70+    Ok(&out_key[..out_len])
71+}
72+
73+/// Computes a HKDF OKM (as specified by RFC 5869).
74+#[corresponds(HKDF_expand)]
75+#[inline]
76+pub fn hkdf_expand(
77+    out_key: &mut [u8],
78+    md: &MdRef,
79+    prk: &[u8],
80+    info: &[u8],
81+) -> Result<(), ErrorStack> {
82+    unsafe {
83+        cvt(ffi::HKDF_expand(
84+            out_key.as_mut_ptr(),
85+            out_key.len(),
86+            md.as_ptr(),
87+            prk.as_ptr(),
88+            prk.len(),
89+            info.as_ptr(),
90+            info.len(),
91+        ))?;
92+    }
93+
94+    Ok(())
95+}
96