1use hmac::Mac;
5
6pub const HKDF_CONTEXT_KEY_IDENTIFIER: u8 = 1;
9pub const HKDF_CONTEXT_PER_FILE_ENC_KEY: u8 = 2;
10pub const HKDF_CONTEXT_DIRHASH_KEY: u8 = 5;
11pub const HKDF_CONTEXT_IV_INO_LBLK_32_KEY: u8 = 6;
12pub const HKDF_CONTEXT_INODE_HASH_KEY: u8 = 7;
13
14pub fn fscrypt_hkdf<const L: usize>(
18 initial_key_material: &[u8],
19 info: &[u8],
20 context: u8,
21) -> [u8; L] {
22 let mut out = [0u8; L];
23 let mut fscrypt_info = Vec::with_capacity(9 + info.len());
24 fscrypt_info.extend_from_slice(b"fscrypt\0");
25 fscrypt_info.push(context);
26 debug_assert_eq!(fscrypt_info.len(), 9);
27 fscrypt_info.extend_from_slice(info);
28 hkdf::<L>(initial_key_material, &fscrypt_info, &mut out);
29 out
30}
31
32pub fn hkdf<const L: usize>(initial_key_material: &[u8], info: &[u8], out: &mut [u8; L]) {
38 const HASH_LEN: usize = 64;
39 let mut hmac = hmac::Hmac::<sha2::Sha512>::new_from_slice(&[0; HASH_LEN]).unwrap();
41 hmac.update(initial_key_material);
42 let prk = hmac.finalize().into_bytes();
43 let mut last = [].as_slice();
45 let mut out = out.as_mut_slice();
46 let mut i = 1;
47 loop {
48 let mut hmac = hmac::Hmac::<sha2::Sha512>::new_from_slice(&prk).unwrap();
49 hmac.update(&last);
50 hmac.update(&info);
51 hmac.update(&[i as u8]);
52 let val = hmac.finalize().into_bytes();
53 if out.len() < HASH_LEN {
54 out.copy_from_slice(&val.as_slice()[..out.len()]);
55 break;
56 }
57 out[..HASH_LEN].copy_from_slice(&val.as_slice());
58 (last, out) = out.split_at_mut(HASH_LEN);
59 i += 1;
60 }
61}