Skip to main content

aea_tools/
cluster_header.rs

1use crate::segment_info::SegmentInfo;
2use anyhow::Result;
3use std::io::Read;
4
5// https://theapplewiki.com/wiki/Apple_Encrypted_Archive#Cluster_header
6#[derive(Clone)]
7pub struct ClusterHeader {
8    // Encrypted: (checksum_length+8)*segments_per_cluster
9    // Unencrypted: segment_size*segments_per_cluster
10    pub segment_info: Vec<SegmentInfo>,
11    pub next_cluster_hmac: [u8; 32],
12    // 32*segments_per_cluster
13    pub segment_hmacs: Vec<[u8; 32]>,
14}
15
16impl ClusterHeader {
17    pub fn decode<R: Read + Unpin>(
18        reader: &mut R,
19        chek: &[u8; 80],
20        expected_hmac: &[u8; 32],
21        segments_per_cluster: [u8; 4],
22    ) -> Result<Self> {
23        let encrypted_segment_info_size =
24            (32 + 8) * u32::from_le_bytes(segments_per_cluster) as usize;
25        let segment_hmacs_size = 32 * u32::from_le_bytes(segments_per_cluster) as usize;
26
27        let mut encrypted_segment_info = vec![0u8; encrypted_segment_info_size];
28        let mut next_cluster_hmac = [0u8; 32];
29        let mut segment_hmacs = vec![0u8; segment_hmacs_size];
30        reader.read_exact(&mut encrypted_segment_info)?;
31        reader.read_exact(&mut next_cluster_hmac)?;
32        reader.read_exact(&mut segment_hmacs)?;
33
34        let segment_info = SegmentInfo::decrypt_segment_info(
35            &next_cluster_hmac,
36            &segment_hmacs,
37            encrypted_segment_info,
38            chek,
39            expected_hmac,
40        )?;
41
42        let segment_hmacs = segment_hmacs
43            .chunks_exact(32)
44            .map(|chunk| {
45                let mut hmac = [0u8; 32];
46                hmac.copy_from_slice(chunk);
47                hmac
48            })
49            .collect::<Vec<_>>();
50
51        Ok(Self {
52            segment_info,
53            next_cluster_hmac,
54            segment_hmacs,
55        })
56    }
57
58    pub fn encoded_len(&self) -> usize {
59        (32 + 8) * self.segment_info.len() + 32 + 32 * self.segment_info.len()
60    }
61}