1pub const SALT_LEN: usize = 64;
17pub const HEADER_LEN: usize = 448;
19pub const VOLUME_HEADER_LEN: usize = SALT_LEN + HEADER_LEN;
21pub const NORMAL_HEADER_OFFSET: u64 = 0;
23pub const HIDDEN_HEADER_OFFSET: u64 = 65_536;
25pub const MAGIC_VERA: &[u8; 4] = b"VERA";
27pub const MAGIC_TRUE: &[u8; 4] = b"TRUE";
29
30fn be_u32(d: &[u8], o: usize) -> u32 {
31 let mut b = [0u8; 4];
32 if let Some(s) = d.get(o..o + 4) {
33 b.copy_from_slice(s);
34 }
35 u32::from_be_bytes(b)
36}
37
38fn be_u64(d: &[u8], o: usize) -> u64 {
39 let mut b = [0u8; 8];
40 if let Some(s) = d.get(o..o + 8) {
41 b.copy_from_slice(s);
42 }
43 u64::from_be_bytes(b)
44}
45
46#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum Flavor {
49 VeraCrypt,
51 TrueCrypt,
53}
54
55#[derive(Debug, Clone)]
57pub struct VeraHeader {
58 pub flavor: Flavor,
60 pub version: u16,
62 pub encrypted_area_start: u64,
64 pub encrypted_area_size: u64,
66 pub volume_size: u64,
68 pub hidden_size: u64,
70 pub sector_size: u32,
72 pub master_keys: [u8; 256],
74}
75
76impl VeraHeader {
77 #[must_use]
81 pub fn validate(dec: &[u8]) -> Option<VeraHeader> {
82 if dec.len() < HEADER_LEN {
83 return None;
84 }
85 let flavor = match dec.get(0..4)? {
86 m if m == MAGIC_VERA => Flavor::VeraCrypt,
87 m if m == MAGIC_TRUE => Flavor::TrueCrypt,
88 _ => return None,
89 };
90 if be_u32(dec, 8) != crc32fast::hash(dec.get(192..448)?) {
92 return None;
93 }
94 if be_u32(dec, 188) != crc32fast::hash(dec.get(0..188)?) {
95 return None;
96 }
97 let mut master_keys = [0u8; 256];
98 master_keys.copy_from_slice(dec.get(192..448)?);
99 Some(VeraHeader {
100 flavor,
101 version: (be_u32(dec, 4) >> 16) as u16,
102 encrypted_area_start: be_u64(dec, 44),
103 encrypted_area_size: be_u64(dec, 52),
104 volume_size: be_u64(dec, 36),
105 hidden_size: be_u64(dec, 28),
106 sector_size: be_u32(dec, 64),
107 master_keys,
108 })
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 fn valid_header(magic: &[u8; 4]) -> [u8; HEADER_LEN] {
119 let mut dec = [0u8; HEADER_LEN];
120 dec[0..4].copy_from_slice(magic);
121 dec[4..6].copy_from_slice(&5u16.to_be_bytes()); dec[28..36].copy_from_slice(&4096u64.to_be_bytes()); dec[36..44].copy_from_slice(&1_048_576u64.to_be_bytes()); dec[44..52].copy_from_slice(&131_072u64.to_be_bytes()); dec[52..60].copy_from_slice(&36_864u64.to_be_bytes()); dec[64..68].copy_from_slice(&512u32.to_be_bytes()); for (i, b) in dec[192..448].iter_mut().enumerate() {
128 *b = (i as u8) ^ 0x5a; }
130 let crc_mk = crc32fast::hash(&dec[192..448]);
131 dec[8..12].copy_from_slice(&crc_mk.to_be_bytes());
132 let crc_hdr = crc32fast::hash(&dec[0..188]);
133 dec[188..192].copy_from_slice(&crc_hdr.to_be_bytes());
134 dec
135 }
136
137 #[test]
138 fn validates_vera_and_true_magic() {
139 let v = VeraHeader::validate(&valid_header(MAGIC_VERA)).expect("VERA header");
140 assert_eq!(v.flavor, Flavor::VeraCrypt);
141 assert_eq!(v.version, 5);
142 assert_eq!(v.encrypted_area_start, 131_072);
143 assert_eq!(v.encrypted_area_size, 36_864);
144 assert_eq!(v.volume_size, 1_048_576);
145 assert_eq!(v.hidden_size, 4096);
146 assert_eq!(v.sector_size, 512);
147
148 let t = VeraHeader::validate(&valid_header(MAGIC_TRUE)).expect("TRUE header");
149 assert_eq!(t.flavor, Flavor::TrueCrypt);
150 }
151
152 #[test]
153 fn rejects_short_input() {
154 assert!(VeraHeader::validate(&[0u8; HEADER_LEN - 1]).is_none());
155 }
156
157 #[test]
158 fn rejects_bad_magic() {
159 let mut dec = valid_header(MAGIC_VERA);
160 dec[0] = b'X'; assert!(VeraHeader::validate(&dec).is_none());
162 }
163
164 #[test]
165 fn rejects_master_key_crc_mismatch() {
166 let mut dec = valid_header(MAGIC_VERA);
167 dec[400] ^= 0xff; assert!(VeraHeader::validate(&dec).is_none());
169 }
170
171 #[test]
172 fn rejects_header_field_crc_mismatch() {
173 let mut dec = valid_header(MAGIC_VERA);
174 dec[64] ^= 0xff; assert!(VeraHeader::validate(&dec).is_none());
176 }
177}