1use age_core::{
4 format::FileKey,
5 primitives::hkdf,
6 secrecy::{ExposeSecret, SecretBox},
7};
8use rand::{rngs::OsRng, RngCore};
9
10use crate::{
11 error::DecryptError,
12 format::HeaderV1,
13 primitives::{stream::PayloadKey, HmacKey},
14 protocol::Nonce,
15};
16
17const HEADER_KEY_LABEL: &[u8] = b"header";
18const PAYLOAD_KEY_LABEL: &[u8] = b"payload";
19
20pub(crate) fn new_file_key() -> FileKey {
21 FileKey::init_with_mut(|file_key| OsRng.fill_bytes(file_key))
22}
23
24pub(crate) fn mac_key(file_key: &FileKey) -> HmacKey {
25 HmacKey(SecretBox::new(Box::new(hkdf(
26 &[],
27 HEADER_KEY_LABEL,
28 file_key.expose_secret(),
29 ))))
30}
31
32pub(crate) fn v1_payload_key(
33 file_key: &FileKey,
34 header: &HeaderV1,
35 nonce: &Nonce,
36) -> Result<PayloadKey, DecryptError> {
37 header.verify_mac(mac_key(file_key))?;
39
40 Ok(PayloadKey(
42 hkdf(nonce.as_ref(), PAYLOAD_KEY_LABEL, file_key.expose_secret()).into(),
43 ))
44}