1use std::mem::size_of;
2
3use crate::{
4 byte_read::ByteReader, error::ParseError, CommonMetadata, MbnHeader, MbnHeaderV6, MbnHeaderV7,
5 Metadata, Result,
6};
7
8#[derive(Clone, Copy, Debug)]
10pub struct Padding {
11 pub content: u8,
13 pub len: usize,
15}
16
17#[derive(Clone, Copy, Debug)]
19pub enum HashEntry {
20 Sha1([u8; 20]),
21 Sha256([u8; 32]),
22 Sha384([u8; 48]),
23}
24
25#[derive(Clone, Debug)]
27pub struct HashTableSegment {
28 pub mbn_header: MbnHeader,
30 pub common_metadata: Option<CommonMetadata>,
32 pub qti_metadata: Option<Metadata>,
34 pub metadata: Option<Metadata>,
36 pub hash_table: Vec<HashEntry>,
38 pub qti_signature: Vec<u8>,
40 pub qti_certificate_chain: Vec<u8>,
42 pub signature: Vec<u8>,
44 pub certificate_chain: Vec<u8>,
46 pub padding: Padding,
48}
49
50impl HashEntry {
51 pub fn as_bytes(&self) -> &[u8] {
53 match self {
54 HashEntry::Sha1(entry) => entry,
55 HashEntry::Sha256(entry) => entry,
56 HashEntry::Sha384(entry) => entry,
57 }
58 }
59}
60
61impl HashTableSegment {
62 pub fn parse(raw: &[u8]) -> Result<Self> {
69 let mut reader = ByteReader::new(raw);
70
71 let mbn_header = reader.read()?;
72
73 let common_metadata = match &mbn_header {
74 MbnHeader::V7(
75 header @ MbnHeaderV7 {
76 common_meta_size: 1..,
77 ..
78 },
79 ) => {
80 if header.common_meta_size != 24 {
81 return Err(ParseError::CommonMetadataNotAligned(
82 header.common_meta_size,
83 ));
84 }
85 Some(reader.read::<CommonMetadata>()?)
86 }
87 _ => None,
88 };
89
90 let qti_metadata = match mbn_header {
91 MbnHeader::V6(MbnHeaderV6 {
92 qti_metadata_size: qti_metadata_size @ 1..,
93 ..
94 })
95 | MbnHeader::V7(MbnHeaderV7 {
96 qti_metadata_size: qti_metadata_size @ 1..,
97 ..
98 }) => match qti_metadata_size {
99 120 => Some(Metadata::Len120(reader.read()?)),
100 224 => Some(Metadata::Len224(reader.read()?)),
101 _ => return Err(ParseError::MetadataNotAligned(qti_metadata_size)),
102 },
103 _ => None,
104 };
105
106 let metadata = match mbn_header {
107 MbnHeader::V6(MbnHeaderV6 {
108 metadata_size: metadata_size @ 1..,
109 ..
110 })
111 | MbnHeader::V7(MbnHeaderV7 {
112 metadata_size: metadata_size @ 1..,
113 ..
114 }) => match metadata_size {
115 120 => Some(Metadata::Len120(reader.read()?)),
116 224 => Some(Metadata::Len224(reader.read()?)),
117 _ => return Err(ParseError::MetadataNotAligned(metadata_size)),
118 },
119 _ => None,
120 };
121
122 let mut hash_table = vec![];
123 let code_size = match &mbn_header {
124 MbnHeader::V3Len40(header) => header.code_size,
125 MbnHeader::V3Len80(header) => header.code_size,
126 MbnHeader::V5(header) => header.code_size,
127 MbnHeader::V6(header) => header.code_size,
128 MbnHeader::V7(header) => header.code_size,
129 };
130
131 let sha_algo = 'algo: {
132 match common_metadata {
133 Some(CommonMetadata {
134 hash_table_algorithm: 2,
135 ..
136 }) => break 'algo "SHA256",
137 Some(CommonMetadata {
138 hash_table_algorithm: 3,
139 ..
140 }) => break 'algo "SHA384",
141 _ => (),
142 };
143
144 if let MbnHeader::V6(_) = &mbn_header {
145 break 'algo "SHA384";
146 }
147
148 let maybe_dummy = reader.peek::<[u8; 20]>(20)?;
149 if maybe_dummy.iter().all(|x| *x == 0) {
150 break 'algo "SHA1";
151 }
152 let maybe_dummy = reader.peek::<[u8; 32]>(32)?;
153 if maybe_dummy.iter().all(|x| *x == 0) {
154 break 'algo "SHA256";
155 }
156 let maybe_dummy = reader.peek::<[u8; 48]>(48)?;
157 if maybe_dummy.iter().all(|x| *x == 0) {
158 break 'algo "SHA384";
159 }
160
161 return Err(ParseError::HashTableNotAligned(code_size));
162 };
163
164 match sha_algo {
165 "SHA1" => {
166 if code_size % 20 != 0 {
167 return Err(ParseError::HashTableNotAligned(code_size));
168 }
169 for _ in 0..code_size / 20 {
170 hash_table.push(HashEntry::Sha1(reader.read()?));
171 }
172 }
173 "SHA256" => {
174 if code_size % 32 != 0 {
175 return Err(ParseError::HashTableNotAligned(code_size));
176 }
177 for _ in 0..code_size / 32 {
178 hash_table.push(HashEntry::Sha256(reader.read()?));
179 }
180 }
181 "SHA384" => {
182 if code_size % 48 != 0 {
183 return Err(ParseError::HashTableNotAligned(code_size));
184 }
185 for _ in 0..code_size / 48 {
186 hash_table.push(HashEntry::Sha384(reader.read()?));
187 }
188 }
189 _ => unreachable!(),
190 };
191
192 let qti_signature = match &mbn_header {
193 MbnHeader::V5(header) => reader.skip(header.qti_signature_size as usize)?,
194 MbnHeader::V6(header) => reader.skip(header.qti_signature_size as usize)?,
195 _ => vec![],
196 };
197
198 let qti_certificate_chain = match &mbn_header {
199 MbnHeader::V5(header) => reader.skip(header.qti_cert_chain_size as usize)?,
200 MbnHeader::V6(header) => reader.skip(header.qti_cert_chain_size as usize)?,
201 _ => vec![],
202 };
203
204 let signature = match &mbn_header {
205 MbnHeader::V3Len40(header) => reader.skip(header.signature_size as usize)?,
206 MbnHeader::V3Len80(header) => reader.skip(header.signature_size as usize)?,
207 MbnHeader::V5(header) => reader.skip(header.signature_size as usize)?,
208 MbnHeader::V6(header) => reader.skip(header.signature_size as usize)?,
209 MbnHeader::V7(header) => reader.skip(header.signature_size as usize)?,
210 };
211
212 let certificate_chain = match &mbn_header {
213 MbnHeader::V3Len40(header) => reader.skip(header.cert_chain_size as usize)?,
214 MbnHeader::V3Len80(header) => reader.skip(header.cert_chain_size as usize)?,
215 MbnHeader::V5(header) => reader.skip(header.cert_chain_size as usize)?,
216 MbnHeader::V6(header) => reader.skip(header.cert_chain_size as usize)?,
217 MbnHeader::V7(header) => reader.skip(header.cert_chain_size as usize)?,
218 };
219
220 let mut padding = Padding {
221 content: 0xFF,
222 len: reader.available(),
223 };
224 if padding.len > 0 {
225 padding.content = reader.read()?;
226 }
227
228 Ok(Self {
229 mbn_header,
230 common_metadata,
231 qti_metadata,
232 metadata,
233 hash_table,
234 qti_signature,
235 qti_certificate_chain,
236 signature,
237 certificate_chain,
238 padding,
239 })
240 }
241
242 pub fn dump<W: std::io::Write>(&self, writer: &mut W, padding: bool) -> Result<()> {
246 writer.write_all(self.mbn_header.as_bytes())?;
247 if let Some(common_metadata) = &self.common_metadata {
248 writer.write_all(common_metadata.as_bytes())?;
249 }
250 if let Some(metadata) = &self.qti_metadata {
251 writer.write_all(metadata.as_bytes())?;
252 }
253 if let Some(metadata) = &self.metadata {
254 writer.write_all(metadata.as_bytes())?;
255 }
256 for hash in &self.hash_table {
257 writer.write_all(hash.as_bytes())?;
258 }
259 writer.write_all(&self.qti_signature)?;
260 writer.write_all(&self.qti_certificate_chain)?;
261 writer.write_all(&self.signature)?;
262 writer.write_all(&self.certificate_chain)?;
263 if padding {
264 let padding = vec![self.padding.content; self.padding.len];
265 writer.write_all(&padding)?;
266 }
267
268 Ok(())
269 }
270
271 pub fn len(&self) -> usize {
273 let mut len = match self.mbn_header {
274 MbnHeader::V3Len40(_) | MbnHeader::V5(_) => 40,
275 MbnHeader::V3Len80(_) => 80,
276 MbnHeader::V6(_) => 48,
277 MbnHeader::V7(_) => 40,
278 };
279
280 if self.qti_metadata.is_some() {
281 len += 120;
282 }
283 if self.metadata.is_some() {
284 len += 120;
285 }
286 len += self.hash_table.len() * 48;
287 len += self.qti_signature.len();
288 len += self.qti_certificate_chain.len();
289 len += self.signature.len();
290 len += self.certificate_chain.len();
291 len += self.padding.len;
292 len
293 }
294
295 pub fn adjust(&mut self, padding_to: usize) {
299 self.mbn_header.adjust_header_version();
300 self.mbn_header.adjust_image_src();
301 match &mut self.mbn_header {
302 MbnHeader::V3Len40(header) => {
303 header.code_size = self
304 .hash_table
305 .iter()
306 .fold(0, |acc, entry| acc + entry.as_bytes().len())
307 as u32;
308 header.signature_size = self.signature.len() as u32;
309 header.cert_chain_size = self.certificate_chain.len() as u32;
310 }
311 MbnHeader::V3Len80(header) => {
312 header.code_size = self
313 .hash_table
314 .iter()
315 .fold(0, |acc, entry| acc + entry.as_bytes().len())
316 as u32;
317 header.signature_size = self.signature.len() as u32;
318 header.cert_chain_size = self.certificate_chain.len() as u32;
319 }
320 MbnHeader::V5(header) => {
321 header.code_size = self
322 .hash_table
323 .iter()
324 .fold(0, |acc, entry| acc + entry.as_bytes().len())
325 as u32;
326 header.qti_signature_size = self.qti_signature.len() as u32;
327 header.qti_cert_chain_size = self.qti_certificate_chain.len() as u32;
328 header.signature_size = self.signature.len() as u32;
329 header.cert_chain_size = self.certificate_chain.len() as u32;
330 }
331 MbnHeader::V6(header) => {
332 header.qti_metadata_size = if let Some(metadata) = &self.qti_metadata {
333 metadata.as_bytes().len() as u32
334 } else {
335 0
336 };
337 header.metadata_size = if let Some(metadata) = &self.metadata {
338 metadata.as_bytes().len() as u32
339 } else {
340 0
341 };
342 header.code_size = self
343 .hash_table
344 .iter()
345 .fold(0, |acc, entry| acc + entry.as_bytes().len())
346 as u32;
347 header.qti_signature_size = self.qti_signature.len() as u32;
348 header.qti_cert_chain_size = self.qti_certificate_chain.len() as u32;
349 header.signature_size = self.signature.len() as u32;
350 header.cert_chain_size = self.certificate_chain.len() as u32;
351 }
352 MbnHeader::V7(header) => {
353 header.common_meta_size = if self.common_metadata.is_some() {
354 size_of::<CommonMetadata>() as u32
355 } else {
356 0
357 };
358 header.qti_metadata_size = if let Some(metadata) = &self.qti_metadata {
359 metadata.as_bytes().len() as u32
360 } else {
361 0
362 };
363 header.metadata_size = if let Some(metadata) = &self.metadata {
364 metadata.as_bytes().len() as u32
365 } else {
366 0
367 };
368 header.code_size = self
369 .hash_table
370 .iter()
371 .fold(0, |acc, entry| acc + entry.as_bytes().len())
372 as u32;
373 header.qti_signature_size = self.qti_signature.len() as u32;
374 header.qti_cert_chain_size = self.qti_certificate_chain.len() as u32;
375 header.signature_size = self.signature.len() as u32;
376 header.cert_chain_size = self.certificate_chain.len() as u32;
377 }
378 }
379 self.mbn_header.adjust_image_size();
380
381 let len_no_padding = self.len() - self.padding.len;
382 if len_no_padding >= padding_to {
383 self.padding.len = 0;
384 } else {
385 self.padding.len = padding_to - len_no_padding;
386 }
387 }
388}