bitwarden_crypto/keys/
shareable_key.rs1use std::pin::Pin;
2
3use generic_array::GenericArray;
4use hmac::Mac;
5use typenum::{U32, U64};
6use zeroize::{Zeroize, Zeroizing};
7
8use super::Aes256CbcHmacKey;
9use crate::util::{hkdf_expand, PbkdfSha256Hmac};
10
11pub fn derive_shareable_key(
16 secret: Zeroizing<[u8; 16]>,
17 name: &str,
18 info: Option<&str>,
19) -> Aes256CbcHmacKey {
20 let res = Zeroizing::new(
22 PbkdfSha256Hmac::new_from_slice(format!("bitwarden-{}", name).as_bytes())
23 .expect("hmac new_from_slice should not fail")
24 .chain_update(secret)
25 .finalize()
26 .into_bytes(),
27 );
28
29 let mut key: Pin<Box<GenericArray<u8, U64>>> =
30 hkdf_expand(&res, info).expect("Input is a valid size");
31 let enc_key = Box::pin(GenericArray::<u8, U32>::clone_from_slice(&key[..32]));
32 let mac_key = Box::pin(GenericArray::<u8, U32>::clone_from_slice(&key[32..]));
33 key.zeroize();
34 Aes256CbcHmacKey { enc_key, mac_key }
35}
36
37#[cfg(test)]
38mod tests {
39 use zeroize::Zeroizing;
40
41 use super::derive_shareable_key;
42 use crate::SymmetricCryptoKey;
43
44 #[test]
45 fn test_derive_shareable_key() {
46 let key = derive_shareable_key(Zeroizing::new(*b"&/$%F1a895g67HlX"), "test_key", None);
47 assert_eq!(SymmetricCryptoKey::Aes256CbcHmacKey(key).to_base64(), "4PV6+PcmF2w7YHRatvyMcVQtI7zvCyssv/wFWmzjiH6Iv9altjmDkuBD1aagLVaLezbthbSe+ktR+U6qswxNnQ==");
48
49 let key = derive_shareable_key(
50 Zeroizing::new(*b"67t9b5g67$%Dh89n"),
51 "test_key",
52 Some("test"),
53 );
54 assert_eq!(SymmetricCryptoKey::Aes256CbcHmacKey(key).to_base64(), "F9jVQmrACGx9VUPjuzfMYDjr726JtL300Y3Yg+VYUnVQtQ1s8oImJ5xtp1KALC9h2nav04++1LDW4iFD+infng==");
55 }
56}