Skip to main content

aea_tools/
root_header.rs

1use crate::{crypto::aes_aead_decrypt, prologue::AeaPrologue};
2use anyhow::Result;
3use sha2::Sha256;
4
5pub enum RootHeaderEnum {
6    Unencrypted(RootHeader),
7    Encrypted([u8; 48]),
8}
9
10pub struct RootHeader {
11    pub raw_size: [u8; 8],
12    pub container_size: [u8; 8],
13    pub segment_size: [u8; 4],
14    pub segments_per_cluster: [u8; 4],
15    pub compression_algorithm: [u8; 1],
16    pub checksum_algorithm: [u8; 1],
17    // 22 bytes of padding
18}
19
20impl RootHeader {
21    // https://theapplewiki.com/wiki/Apple_Encrypted_Archive#Decrypting_root_header
22    pub fn decrypt_root_header(
23        prologue: &AeaPrologue,
24        amk: &[u8; 32],
25    ) -> Result<Option<RootHeader>> {
26        let root_header_encrypted = match &prologue.root_header {
27            RootHeaderEnum::Encrypted(data) => data,
28            RootHeaderEnum::Unencrypted(_) => return Ok(None),
29        };
30
31        let hk_rhek = hkdf::Hkdf::<Sha256>::new(None, amk);
32        let mut rhek = [0u8; 80];
33        hk_rhek
34            .expand(b"AEA_RHEK", &mut rhek)
35            .map_err(|_| anyhow::anyhow!("RHEK expand fail"))?;
36
37        let mut ad = Vec::new();
38        ad.extend_from_slice(&prologue.first_cluster_hmac);
39        ad.extend_from_slice(&prologue.auth_data);
40
41        let decrypted_header =
42            aes_aead_decrypt(&rhek, root_header_encrypted, &ad, &prologue.root_hmac)?;
43
44        let root_header = RootHeader::from_decrypted_data(&decrypted_header);
45        Ok(Some(root_header))
46    }
47
48    pub fn from_decrypted_data(data: &[u8]) -> Self {
49        let mut raw_size = [0u8; 8];
50        raw_size.copy_from_slice(&data[0..8]);
51
52        let mut container_size = [0u8; 8];
53        container_size.copy_from_slice(&data[8..16]);
54
55        let mut segment_size = [0u8; 4];
56        segment_size.copy_from_slice(&data[16..20]);
57
58        let mut segments_per_cluster = [0u8; 4];
59        segments_per_cluster.copy_from_slice(&data[20..24]);
60
61        let compression_algorithm = data[24];
62        let checksum_algorithm = data[25];
63
64        Self {
65            raw_size,
66            container_size,
67            segment_size,
68            segments_per_cluster,
69            compression_algorithm: [compression_algorithm],
70            checksum_algorithm: [checksum_algorithm],
71        }
72    }
73}