1use crate::bytes::{le_u16, le_u32, le_u64, read_guid, slice_owned};
10
11const FVE_SIGNATURE: &[u8; 8] = b"-FVE-FS-";
12
13pub const ENTRY_TYPE_VMK: u16 = 0x0002;
15pub const ENTRY_TYPE_FVEK: u16 = 0x0003;
17pub const ENTRY_TYPE_VOLUME_HEADER: u16 = 0x000f;
19
20pub const VALUE_TYPE_AES_CCM: u16 = 0x0005;
22pub const VALUE_TYPE_STRETCH: u16 = 0x0003;
24pub const VALUE_TYPE_VMK: u16 = 0x0008;
26
27pub const PROTECTION_PASSWORD: u16 = 0x2000;
29
30#[derive(Debug, Clone, PartialEq, Eq)]
33pub struct MetadataEntry {
34 pub entry_type: u16,
36 pub value_type: u16,
38 pub version: u16,
40 pub data: Vec<u8>,
42}
43
44impl MetadataEntry {
45 #[must_use]
52 pub fn parse_sequence(data: &[u8]) -> Vec<MetadataEntry> {
53 let mut out = Vec::new();
54 let mut pos = 0usize;
55 while pos + 8 <= data.len() {
56 let size = le_u16(data, pos) as usize;
57 if size < 8 || pos + size > data.len() {
58 break;
59 }
60 out.push(MetadataEntry {
61 entry_type: le_u16(data, pos + 2),
62 value_type: le_u16(data, pos + 4),
63 version: le_u16(data, pos + 6),
64 data: slice_owned(data, pos + 8, size - 8),
65 });
66 pos += size;
67 }
68 out
69 }
70
71 #[must_use]
73 pub fn nested(&self, offset: usize) -> Vec<MetadataEntry> {
74 let start = offset.min(self.data.len());
75 Self::parse_sequence(&self.data[start..])
76 }
77
78 #[must_use]
80 pub fn is_vmk(&self) -> bool {
81 self.entry_type == ENTRY_TYPE_VMK && self.value_type == VALUE_TYPE_VMK
82 }
83
84 #[must_use]
87 pub fn protection_type(&self) -> Option<u16> {
88 self.is_vmk().then(|| le_u16(&self.data, 26))
89 }
90}
91
92#[derive(Debug, Clone)]
96pub struct FveMetadata {
97 pub encryption_method: u16,
99 pub volume_guid: [u8; 16],
101 pub creation_time: u64,
103 pub entries: Vec<MetadataEntry>,
105 pub encrypted_volume_size: u64,
108 pub volume_header_offset: u64,
110 pub volume_header_size: u64,
112 pub metadata_offsets: [u64; 3],
114 pub metadata_size: u32,
116}
117
118impl FveMetadata {
119 #[must_use]
124 pub fn parse(block: &[u8], bytes_per_sector: u16) -> Option<FveMetadata> {
125 if block.get(0..8) != Some(FVE_SIGNATURE.as_slice()) {
126 return None;
127 }
128
129 let encrypted_volume_size = le_u64(block, 16);
130 let num_volume_header_sectors = le_u32(block, 28);
131 let metadata_offsets = [le_u64(block, 32), le_u64(block, 40), le_u64(block, 48)];
132 let block_volume_header_offset = le_u64(block, 56);
133
134 let mh = 64usize;
136 let metadata_size = le_u32(block, mh);
137 let volume_guid = read_guid(block, mh + 16);
138 let encryption_method = le_u16(block, mh + 36);
139 let creation_time = le_u64(block, mh + 40);
140
141 let entries_start = mh + 48;
143 let entries_end = (mh + metadata_size as usize).min(block.len());
144 let entries = if entries_end > entries_start {
145 MetadataEntry::parse_sequence(&block[entries_start..entries_end])
146 } else {
147 Vec::new()
148 };
149
150 let mut volume_header_offset = block_volume_header_offset;
153 let mut volume_header_size =
154 u64::from(num_volume_header_sectors) * u64::from(bytes_per_sector);
155 if let Some(e) = entries
156 .iter()
157 .find(|e| e.entry_type == ENTRY_TYPE_VOLUME_HEADER)
158 {
159 let bo = le_u64(&e.data, 0);
160 let bs = le_u64(&e.data, 8);
161 if bo != 0 {
162 volume_header_offset = bo;
163 }
164 if bs != 0 {
165 volume_header_size = bs;
166 }
167 }
168
169 Some(FveMetadata {
170 encryption_method,
171 volume_guid,
172 creation_time,
173 entries,
174 encrypted_volume_size,
175 volume_header_offset,
176 volume_header_size,
177 metadata_offsets,
178 metadata_size,
179 })
180 }
181
182 pub fn vmk_entries(&self) -> impl Iterator<Item = &MetadataEntry> {
184 self.entries.iter().filter(|e| e.is_vmk())
185 }
186
187 #[must_use]
189 pub fn protector_types(&self) -> Vec<u16> {
190 self.vmk_entries()
191 .filter_map(MetadataEntry::protection_type)
192 .collect()
193 }
194
195 #[must_use]
197 pub fn fvek_entry(&self) -> Option<&MetadataEntry> {
198 self.entries
199 .iter()
200 .find(|e| e.entry_type == ENTRY_TYPE_FVEK && e.value_type == VALUE_TYPE_AES_CCM)
201 }
202}
203
204#[cfg(test)]
205mod tests {
206 use super::*;
207
208 fn entry_bytes(entry_type: u16, value_type: u16, version: u16, data: &[u8]) -> Vec<u8> {
209 let size = (8 + data.len()) as u16;
210 let mut v = Vec::new();
211 v.extend_from_slice(&size.to_le_bytes());
212 v.extend_from_slice(&entry_type.to_le_bytes());
213 v.extend_from_slice(&value_type.to_le_bytes());
214 v.extend_from_slice(&version.to_le_bytes());
215 v.extend_from_slice(data);
216 v
217 }
218
219 #[test]
220 fn parse_sequence_splits_entries() {
221 let mut buf = Vec::new();
222 buf.extend(entry_bytes(0x000f, 0x000f, 1, &[1, 2, 3, 4]));
223 buf.extend(entry_bytes(ENTRY_TYPE_VMK, VALUE_TYPE_VMK, 1, &[9; 20]));
224 let entries = MetadataEntry::parse_sequence(&buf);
225 assert_eq!(entries.len(), 2);
226 assert_eq!(entries[0].entry_type, 0x000f);
227 assert_eq!(entries[0].data, vec![1, 2, 3, 4]);
228 assert!(entries[1].is_vmk());
229 }
230
231 #[test]
232 fn parse_sequence_stops_on_lying_size() {
233 let mut buf = entry_bytes(1, 2, 1, &[]);
235 buf.extend_from_slice(&[0, 0, 0, 0, 0, 0, 0, 0]); let entries = MetadataEntry::parse_sequence(&buf);
237 assert_eq!(entries.len(), 1);
238 }
239
240 #[test]
241 fn parse_sequence_stops_on_oversize() {
242 let mut buf = Vec::new();
244 buf.extend_from_slice(&100u16.to_le_bytes());
245 buf.extend_from_slice(&[0u8; 6]);
246 assert!(MetadataEntry::parse_sequence(&buf).is_empty());
247 }
248
249 fn build_block(entries: &[Vec<u8>]) -> Vec<u8> {
250 let mut entry_bytes = Vec::new();
251 for e in entries {
252 entry_bytes.extend_from_slice(e);
253 }
254 let metadata_size = 48 + entry_bytes.len();
255 let mut block = vec![0u8; 64 + metadata_size];
256 block[0..8].copy_from_slice(FVE_SIGNATURE);
257 block[10..12].copy_from_slice(&2u16.to_le_bytes()); block[16..24].copy_from_slice(&0x0400_0000u64.to_le_bytes()); block[28..32].copy_from_slice(&16u32.to_le_bytes()); block[56..64].copy_from_slice(&0x0211_0800u64.to_le_bytes()); block[64..68].copy_from_slice(&(metadata_size as u32).to_le_bytes());
263 block[64 + 16..64 + 32].copy_from_slice(&[0xAB; 16]); block[64 + 36..64 + 38].copy_from_slice(&0x8000u16.to_le_bytes()); block[64 + 40..64 + 48].copy_from_slice(&130_461_864_497_281_120u64.to_le_bytes());
266 block[64 + 48..].copy_from_slice(&entry_bytes);
267 block
268 }
269
270 #[test]
271 fn parse_full_block() {
272 let mut vh_data = Vec::new();
274 vh_data.extend_from_slice(&0x0211_0800u64.to_le_bytes()); vh_data.extend_from_slice(&0x0051_5a00u64.to_le_bytes()); let vh = entry_bytes(
277 ENTRY_TYPE_VOLUME_HEADER,
278 ENTRY_TYPE_VOLUME_HEADER,
279 1,
280 &vh_data,
281 );
282
283 let mut vmk_data = vec![0u8; 28];
284 vmk_data[26..28].copy_from_slice(&PROTECTION_PASSWORD.to_le_bytes());
285 let vmk = entry_bytes(ENTRY_TYPE_VMK, VALUE_TYPE_VMK, 1, &vmk_data);
286
287 let block = build_block(&[vh, vmk]);
288 let m = FveMetadata::parse(&block, 512).unwrap();
289 assert_eq!(m.encryption_method, 0x8000);
290 assert_eq!(m.volume_guid, [0xAB; 16]);
291 assert_eq!(m.creation_time, 130_461_864_497_281_120);
292 assert_eq!(m.encrypted_volume_size, 0x0400_0000);
293 assert_eq!(m.volume_header_offset, 0x0211_0800);
294 assert_eq!(m.volume_header_size, 0x0051_5a00); assert_eq!(m.entries.len(), 2);
296 assert_eq!(m.protector_types(), vec![PROTECTION_PASSWORD]);
297 }
298
299 #[test]
300 fn parse_returns_none_without_signature() {
301 let block = vec![0u8; 128];
302 assert!(FveMetadata::parse(&block, 512).is_none());
303 }
304
305 #[test]
306 fn volume_header_size_falls_back_to_sector_count() {
307 let block = build_block(&[]);
309 let m = FveMetadata::parse(&block, 512).unwrap();
310 assert_eq!(m.volume_header_size, 16 * 512);
311 assert_eq!(m.volume_header_offset, 0x0211_0800);
312 }
313
314 #[test]
315 fn truncated_block_does_not_panic() {
316 let mut block = build_block(&[]);
317 block.truncate(70);
318 let _ = FveMetadata::parse(&block, 512);
319 }
320}