amebazii/types/header.rs
1use std::io;
2
3use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
4
5use crate::{
6 error::Error, is_valid_data, read_padding, read_valid_data, util::write_fill, write_data,
7 write_padding,
8};
9
10use super::{
11 enums::{ImageType, SectionType, XipPageRemapSize},
12 BinarySize, DataRefType, DataType, FromStream, ToStream,
13};
14
15/// A struct representing the key block with two public keys:
16/// * an encryption public key and
17/// * a hash public key.
18#[derive(Debug)]
19pub struct KeyBlock {
20 enc_pubkey: [u8; 32], // Encryption public key (32 bytes)
21 hash_pubkey: [u8; 32], // Hash public key (32 bytes)
22}
23
24impl Default for KeyBlock {
25 /// Creates a default `KeyBlock` with both public keys initialized to `[0xFF; 32]`.
26 ///
27 /// # Returns
28 /// - A `KeyBlock` instance with both the encryption and hash public keys set to `0xFF`.
29 fn default() -> Self {
30 KeyBlock {
31 enc_pubkey: [0xFF; 32],
32 hash_pubkey: [0xFF; 32],
33 }
34 }
35}
36
37impl BinarySize for KeyBlock {
38 /// Returns the binary size of the `KeyBlock` in bytes.
39 ///
40 /// Since the struct contains two 32-byte fields (`enc_pubkey` and `hash_pubkey`), the total size is 64 bytes.
41 ///
42 /// # Returns
43 /// - `64`: The size in bytes required to serialize a `KeyBlock`.
44 fn binary_size() -> usize {
45 64
46 }
47}
48
49impl FromStream for KeyBlock {
50 /// Deserializes a `KeyBlock` from a stream.
51 ///
52 /// This method reads 64 bytes (32 bytes for each of the `enc_pubkey` and `hash_pubkey`) from the provided
53 /// reader and populates the `KeyBlock` instance fields accordingly.
54 ///
55 /// # Parameters
56 /// - `reader`: A mutable reference to a reader implementing `io::Read` and `io::Seek`.
57 ///
58 /// # Returns
59 /// - `Ok(())`: If the `KeyBlock` was successfully deserialized.
60 /// - `Err(Error)`: If an error occurs while reading from the stream.
61 fn read_from<R>(&mut self, reader: &mut R) -> Result<(), Error>
62 where
63 R: std::io::Read + std::io::Seek,
64 {
65 reader.read_exact(&mut self.enc_pubkey)?;
66 reader.read_exact(&mut self.hash_pubkey)?;
67 Ok(())
68 }
69}
70
71impl ToStream for KeyBlock {
72 /// Serializes a `KeyBlock` to a stream.
73 ///
74 /// # Parameters
75 /// - `writer`: A mutable reference to a writer implementing `io::Write` and `io::Seek`.
76 ///
77 /// # Returns
78 /// - `Ok(())`: If the `KeyBlock` was successfully written to the stream.
79 /// - `Err(Error)`: If an error occurs while writing to the stream.
80 fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
81 where
82 W: std::io::Write + std::io::Seek,
83 {
84 writer.write_all(&self.enc_pubkey)?;
85 writer.write_all(&self.hash_pubkey)?;
86 Ok(())
87 }
88}
89
90impl KeyBlock {
91 /// Checks if the encryption public key is valid.
92 ///
93 /// # Returns
94 /// - `true` if the encryption public key is valid.
95 /// - `false` if the encryption public key is invalid.
96 pub fn is_enc_pubkey_valid(&self) -> bool {
97 is_valid_data!(&self.enc_pubkey)
98 }
99
100 /// Checks if the hash public key is valid.
101 ///
102 /// # Returns
103 /// - `true` if the hash public key is valid.
104 /// - `false` if the hash public key is invalid.
105 pub fn is_hash_pubkey_valid(&self) -> bool {
106 is_valid_data!(&self.hash_pubkey)
107 }
108
109 /// Retrieves the encryption public key.
110 ///
111 /// # Returns
112 /// - A reference to the encryption public key (32 bytes).
113 pub fn get_enc_pubkey(&self) -> &[u8; 32] {
114 &self.enc_pubkey
115 }
116
117 /// Retrieves the hash public key.
118 ///
119 /// # Returns
120 /// - A reference to the hash public key (32 bytes).
121 pub fn get_hash_pubkey(&self) -> &[u8; 32] {
122 &self.hash_pubkey
123 }
124
125 /// Retrieves a mutable reference to the encryption public key.
126 ///
127 /// # Returns
128 /// - A mutable reference to the encryption public key (32 bytes).
129 pub fn get_enc_pubkey_mut(&mut self) -> &mut [u8; 32] {
130 &mut self.enc_pubkey
131 }
132
133 /// Retrieves a mutable reference to the hash public key.
134 ///
135 /// # Returns
136 /// - A mutable reference to the hash public key (32 bytes).
137 pub fn get_hash_pubkey_mut(&mut self) -> &mut [u8; 32] {
138 &mut self.hash_pubkey
139 }
140}
141
142// --- Generic Header ---
143// According to _create_img_header
144// +---+---+---+---+----+----+----+---+----------+----------------+--------------+---------------+----+----+----+----+
145// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
146// +========+===+===+===+===+====+====+====+===+==========+================+==============+===============+====+====+====+====+
147// | 0x00 | length: u32 | next_offset: u32 | type: u8 | is_encrypt: u8 | pkey_idx: u8 | key_valid: u8 | |
148// +--------+---------------+------------------+----------+----------------+--------------+---------------+-------------------+
149// | 0x10 | | serial: u32 | |
150// +--------+---------------+------------------+------------------------------------------------------------------------------+
151// | 0x20 | key1: bytes[32] |
152// +--------+-----------------------------------------------------------------------------------------------------------------+
153// | 0x40 | key2: bytes[32] |
154// +--------+-----------------------------------------------------------------------------------------------------------------+
155// size: 0x60 = 96 bytes
156
157/// Generic image header.
158///
159/// This struct contains metadata for an image, such as the segment size, offset to the next image header,
160/// the image type, encryption flag, and user keys.
161#[derive(Debug)]
162pub struct ImageHeader {
163 /// The size of the image segment in bytes.
164 ///
165 /// This field specifies the size of the image's data segment, which can be used to determine how much
166 /// data is associated with the current image header.
167 pub segment_size: u32,
168
169 /// Offset to the next image header.
170 ///
171 /// If there is no next image header, this field is set to `None`. Otherwise, it holds the
172 /// byte offset to the next image header.
173 pub next_offset: Option<u32>,
174
175 /// The type of the image.
176 ///
177 /// This field stores the image type, which can represent different image types such as boot images,
178 /// partition tables, etc.
179 pub img_type: ImageType,
180
181 /// Flag indicating whether the image is encrypted.
182 ///
183 /// This boolean flag indicates whether the image is encrypted (`true`) or not (`false`).
184 pub is_encrypt: bool,
185
186 /// The serial number associated with the image. (version number)
187 ///
188 /// This field stores the image's serial number. It is initialized to `0xFFFF_FFFF` by default.
189 pub serial: u32,
190
191 /// User key 1, used for encryption
192 pub user_key1: DataType<32>,
193
194 /// User key 2, used for encryption
195 pub user_key2: DataType<32>,
196}
197
198impl Default for ImageHeader {
199 /// Creates a default `ImageHeader` instance with the following default values:
200 /// - `segment_size`: `0` (default size is zero)
201 /// - `next_offset`: `0xFFFF_FFFF` (indicating no next header) == None
202 /// - `img_type`: `ImageType::Parttab` (default is partition table)
203 /// - `is_encrypt`: `false` (default is no encryption)
204 /// - `serial`: `0xFFFF_FFFF` (default invalid serial number)
205 /// - `user_key1`: `[0xFF; 32]` (default invalid key)
206 /// - `user_key2`: `[0xFF; 32]` (default invalid key)
207 ///
208 /// # Returns
209 /// - A new `ImageHeader` with the default values.
210 fn default() -> Self {
211 ImageHeader {
212 segment_size: 0,
213 next_offset: None, // invalid by default
214 img_type: ImageType::Parttab, // partition table by default
215 is_encrypt: false,
216 serial: 0xFFFF_FFFF,
217 user_key1: None, // invalid by default
218 user_key2: None,
219 }
220 }
221}
222
223impl BinarySize for ImageHeader {
224 /// Returns the binary size of the `ImageHeader` in bytes.
225 #[inline]
226 fn binary_size() -> usize {
227 0x60 // 96 bytes total size
228 }
229}
230
231impl FromStream for ImageHeader {
232 /// Reads an `ImageHeader` from a stream, populating its fields.
233 ///
234 /// # Parameters
235 /// - `reader`: A mutable reference to a reader that implements both `io::Read` and `io::Seek`. This is used
236 /// to read the raw byte data representing the `ImageHeader`.
237 ///
238 /// # Returns
239 /// - `Ok(())`: If the header is successfully read from the stream and all fields are populated.
240 /// - `Err(Error)`: If any errors occur while reading the data from the stream.
241 fn read_from<R>(&mut self, reader: &mut R) -> Result<(), Error>
242 where
243 R: std::io::Read + std::io::Seek,
244 {
245 self.segment_size = reader.read_u32::<LittleEndian>()?;
246
247 let offset = reader.read_u32::<LittleEndian>()?;
248 self.next_offset = if offset != 0xFFFF_FFFF {
249 Some(offset)
250 } else {
251 None
252 };
253
254 self.img_type = ImageType::try_from(reader.read_u8()?)?;
255 self.is_encrypt = reader.read_u8()? != 0;
256
257 // Skip the next byte (reserved - seems to be pkey_index)
258 read_padding!(reader, 1);
259
260 // REVIIST: unused
261 let _flags = reader.read_u8()?;
262
263 read_padding!(reader, 8);
264 self.serial = reader.read_u32::<LittleEndian>()?;
265 read_padding!(reader, 8);
266
267 read_valid_data!(self.user_key1, 32, reader);
268 read_valid_data!(self.user_key2, 32, reader);
269 Ok(())
270 }
271}
272
273impl ToStream for ImageHeader {
274 /// Serializes the `ImageHeader` struct to a stream.
275 ///
276 /// # Parameters
277 /// - `writer`: A mutable reference to a type that implements the `std::io::Write` trait. The data will
278 /// be written to this stream.
279 ///
280 /// # Returns
281 /// - `Ok(())`: If the data is written successfully.
282 /// - `Err(Error)`: If there is an issue writing the data to the stream.
283 fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
284 where
285 W: std::io::Write,
286 {
287 writer.write_u32::<LittleEndian>(self.segment_size)?;
288 writer.write_u32::<LittleEndian>(self.next_offset.unwrap_or(0xFFFF_FFFF))?;
289 writer.write_u8(self.img_type as u8)?;
290 writer.write_u8(self.is_encrypt as u8)?;
291 writer.write_u8(0x00)?;
292
293 // Write the key validity flags (1 byte), combining key1_valid and key2_valid
294 let key1_valid = self.is_key1_valid();
295 let key2_valid = self.is_key2_valid();
296 writer.write_u8((key1_valid as u8) | ((key2_valid as u8) << 1))?;
297
298 write_padding!(writer, 8);
299 writer.write_u32::<LittleEndian>(self.serial)?;
300 write_padding!(writer, 8);
301
302 // If key1 is valid, write user_key1 (32 bytes), otherwise write padding
303 write_data!(writer, self.user_key1, 32);
304 write_data!(writer, self.user_key2, 32);
305 Ok(())
306 }
307}
308
309impl ImageHeader {
310 // ------------------------------------------------------------------------------------
311 // instance methods
312 // ------------------------------------------------------------------------------------
313
314 /// Checks if the first user key (`user_key1`) is valid.
315 ///
316 /// # Returns
317 /// - `true` if `user_key1` is valid (i.e., not all bytes are `0xFF`).
318 /// - `false` if `user_key1` is invalid (i.e., all bytes are `0xFF`).
319 pub fn is_key1_valid(&self) -> bool {
320 match &self.user_key1 {
321 None => false,
322 Some(key) => key.iter().any(|&byte| byte != 0xFF),
323 }
324 }
325
326 /// Checks if the second user key (`user_key2`) is valid.
327 ///
328 /// # Returns
329 /// - `true` if `user_key2` is valid (i.e., not all bytes are `0xFF`).
330 /// - `false` if `user_key2` is invalid (i.e., all bytes are `0xFF`).
331 pub fn is_key2_valid(&self) -> bool {
332 match &self.user_key2 {
333 None => false,
334 Some(key) => key.iter().any(|&byte| byte != 0xFF),
335 }
336 }
337
338 /// Checks if there is a next image header.
339 ///
340 /// The `next_offset` field indicates the offset to the next image header. If the value
341 /// is `0xFFFF_FFFF`, it means there is no next image. This method returns `true` if the
342 /// `next_offset` is not `0xFFFF_FFFF`, indicating there is a next image header.
343 ///
344 /// # Returns
345 /// - `true` if there is a next image (i.e., `next_offset` is not `0xFFFF_FFFF`).
346 /// - `false` if there is no next image (i.e., `next_offset` is `0xFFFF_FFFF`).
347 pub fn has_next(&self) -> bool {
348 self.next_offset.is_some()
349 }
350
351 /// Gets the first user key (`user_key1`).
352 ///
353 /// # Returns
354 /// A reference to the `user_key1` array (32 bytes).
355 pub fn get_user_key1(&self) -> DataRefType<'_, 32> {
356 self.user_key1.as_ref()
357 }
358
359 /// Gets the second user key (`user_key2`).
360 ///
361 /// # Returns
362 /// A reference to the `user_key2` array (32 bytes).
363 pub fn get_user_key2(&self) -> DataRefType<'_, 32> {
364 self.user_key2.as_ref()
365 }
366
367 /// Sets the first user key (`user_key1`) in the image header.
368 ///
369 /// # Arguments
370 ///
371 /// * `key` - A `DataType<32>` representing the new value for `user_key1`.
372 pub fn set_user_key1(&mut self, key: DataType<32>) {
373 self.user_key1 = key;
374 }
375
376 /// Sets the second user key (`user_key2`) in the image header.
377 ///
378 /// # Arguments
379 ///
380 /// * `key` - A `DataType<32>` representing the new value for `user_key2`.
381 pub fn set_user_key2(&mut self, key: DataType<32>) {
382 self.user_key2 = key;
383 }
384}
385
386// --- Sub-Image Header ---
387// Layout
388// +---+---+---+---+----+----+----+---+----------------------+-----------------+-----------------+------------------+----+----+----+----+
389// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
390// +========+===+===+===+===+====+====+====+===+======================+=================+=================+==================+====+====+====+====+
391// | 0x00 | length: u32 | next_offset: u32 | sec_type: u8 | sce_enabled: u8 | xip_pg_size: u8 | xip_sec_size: u8 | |
392// +--------+---------------+------------------+----------------------+-----------------+-----------------+------------------+-------------------+
393// | 0x10 | validpat: bytes[8] | xip_key_iv_valid: u8 | |
394// +--------+----------------------------------+----------------------+--------------------------------------------------------------------------+
395// | 0x20 | xip_key: bytes[16] |
396// +--------+------------------------------------------------------------------------------------------------------------------------------------+
397// | 0x30 | xip_iv: bytes[16] |
398// +--------+------------------------------------------------------------------------------------------------------------------------------------+
399// | 0x40 | alignment: bytes[32] |
400// +--------+------------------------------------------------------------------------------------------------------------------------------------+
401// size: 0x60 = 96 bytes
402
403/// Represents the header of a section in a binary image.
404///
405/// The `SectionHeader` struct contains information about the section's length, type,
406/// offset to the next section, as well as details about encryption, remapping, and
407/// validation. The struct is designed to handle sections in a memory or file layout
408/// where the sections could represent different types of data, such as executable code
409/// (XIP), memory regions (DTCM, ITCM), and more. Fields like `xip_page_size`, `xip_key`,
410/// and `xip_iv` are especially relevant when dealing with Execute-In-Place (XIP) sections.
411#[derive(Debug)]
412pub struct SectionHeader {
413 /// The length of the section in bytes.
414 ///
415 /// This field stores the total size of the section, which may include data and metadata.
416 /// The exact meaning and content depend on the section type (`sect_type`).
417 pub length: u32,
418
419 /// Offset to the next section.
420 ///
421 /// This field indicates the position of the next section in memory. A value of `0xFFFF_FFFF`
422 /// indicates that this is the last section, and no further sections exist.
423 pub next_offset: Option<u32>,
424
425 /// The type of the current section.
426 pub sect_type: SectionType,
427
428 /// Indicates whether Secure Copy Engine (SCE) is enabled for this section.
429 pub sce_enabled: bool,
430
431 /// XIP (Execute-In-Place) page size and remapping setting.
432 ///
433 /// This field indicates the page size used for remapping during XIP operations. The value is an
434 /// integer representing one of three possible values: 0 (16K), 1 (32K), and 2 (64K).
435 pub xip_page_size: XipPageRemapSize,
436
437 /// Block size for XIP remapping.
438 ///
439 /// This field defines the block size used for XIP remapping, typically represented in bytes.
440 /// The default value is `0`, which means that remapping block size is not defined.
441 pub xip_block_size: u8,
442
443 /// A valid pattern used to verify the integrity of the section header.
444 valid_pattern: [u8; 8],
445
446 /// The encryption key used for XIP operations.
447 ///
448 /// This is a 16-byte key used during the XIP process. If encryption is enabled for the section,
449 /// this key is used for decryption. The default value is an array of `0xFF` bytes, indicating an
450 /// invalid key by default.
451 xip_key: DataType<16>,
452
453 /// The initialization vector (IV) used for XIP encryption.
454 ///
455 /// This is a 16-byte initialization vector (IV) used in conjunction with the `xip_key` during XIP
456 /// encryption operations. As with the key, it is initialized to an invalid value of `0xFF` bytes.
457 xip_iv: DataType<16>,
458}
459
460impl BinarySize for SectionHeader {
461 /// Returns the binary size (in bytes) of the `SectionHeader` struct.
462 ///
463 /// # Returns
464 /// Returns the binary size as a constant `usize` value, which is `0x60` (96 bytes).
465 #[inline]
466 fn binary_size() -> usize {
467 return 0x60;
468 }
469}
470
471impl Default for SectionHeader {
472 /// Returns the default `SectionHeader` instance with predefined values.
473 ///
474 /// - `length` set to `0`, representing an empty section.
475 /// - `next_offset` set to `0xFFFF_FFFF`, which indicates the absence of a next section.
476 /// - `sect_type` set to `SectionType::XIP`, as a default section type.
477 /// - `sce_enabled` set to `false` (assuming encryption is not enabled by default).
478 /// - `xip_page_size` set to `XipPageRemapSize::_16K`, the smallest page size for XIP remapping.
479 /// - `xip_block_size` set to `0`, indicating no block size set.
480 /// - `valid_pattern` set to a default validation pattern of increasing values.
481 /// - `xip_key` and `xip_iv` both set to `0xFF`, representing uninitialized keys/IV.
482 ///
483 /// # Returns
484 /// Returns a `SectionHeader` with the default values.
485 fn default() -> SectionHeader {
486 return SectionHeader {
487 length: 0,
488 next_offset: None, // make last as default
489 sect_type: SectionType::XIP,
490 sce_enabled: false, // encrypted currently not supported
491 xip_page_size: XipPageRemapSize::_16K,
492 xip_block_size: 0,
493 valid_pattern: [0, 1, 2, 3, 4, 5, 6, 7],
494 xip_key: None,
495 xip_iv: None,
496 };
497 }
498}
499
500impl FromStream for SectionHeader {
501 /// Reads the `SectionHeader` struct from a stream.
502 ///
503 /// # Error Handling
504 /// This method may return an error if there is an issue with reading from the stream or if
505 /// an invalid value is encountered during deserialization (e.g., an invalid enum value for `sect_type`
506 /// or `xip_page_size`). Any errors encountered during reading from the stream will be propagated as an `Error`.
507 ///
508 /// # Returns
509 /// - `Ok(())` if the `SectionHeader` was successfully read from the stream.
510 /// - `Err(Error)` if there was an issue reading from the stream or an invalid value was encountered.
511 ///
512 /// # Panics
513 /// This function assumes that the binary data is well-formed and follows the expected format. If
514 /// the format is incorrect or the stream is malformed, this function will return an error instead of
515 /// panicking. However, it is still important to handle errors appropriately in calling code.
516 fn read_from<R>(&mut self, reader: &mut R) -> Result<(), Error>
517 where
518 R: std::io::Read + std::io::Seek,
519 {
520 self.length = reader.read_u32::<LittleEndian>()?;
521 self.next_offset = match reader.read_u32::<LittleEndian>()? {
522 0xFFFF_FFFF => None,
523 offset => Some(offset),
524 };
525 self.sect_type = SectionType::try_from(reader.read_u8()?)?;
526 self.sce_enabled = reader.read_u8()? != 0;
527 self.xip_page_size = XipPageRemapSize::try_from(reader.read_u8()?)?;
528 self.xip_block_size = reader.read_u8()?;
529
530 read_padding!(reader, 4);
531 reader.read_exact(&mut self.valid_pattern)?;
532
533 let sce_key_iv_valid = reader.read_u8()? & 0b01 == 1;
534 read_padding!(reader, 7);
535
536 if sce_key_iv_valid {
537 read_valid_data!(self.xip_key, 16, reader);
538 read_valid_data!(self.xip_iv, 16, reader);
539 // Align to 96 bytes (by skipping 32 bytes)
540 read_padding!(reader, 32);
541 } else {
542 self.xip_key = None;
543 self.xip_iv = None;
544 // Align to 96 bytes by skipping 64 bytes if no key/IV is present
545 read_padding!(reader, 64);
546 }
547 Ok(())
548 }
549}
550
551impl ToStream for SectionHeader {
552 /// Serializes the `SectionHeader` struct to a stream.
553 ///
554 /// # Parameters
555 /// - `writer`: A mutable reference to a type that implements the `std::io::Write` trait. The data will
556 /// be written to this stream.
557 ///
558 /// # Returns
559 /// - `Ok(())`: If the data is written successfully.
560 /// - `Err(Error)`: If there is an issue writing the data to the stream.
561 fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
562 where
563 W: io::Write + io::Seek,
564 {
565 writer.write_u32::<LittleEndian>(self.length)?;
566 writer.write_u32::<LittleEndian>(self.next_offset.unwrap_or(0xFFFF_FFFF))?;
567 writer.write_u8(self.sect_type as u8)?;
568 writer.write_u8(self.sce_enabled as u8)?;
569 writer.write_u8(self.xip_page_size as u8)?;
570 writer.write_u8(self.xip_block_size)?;
571
572 write_padding!(writer, 4);
573 writer.write_all(&self.valid_pattern)?;
574 writer.write_u8(self.xip_key_iv_valid() as u8)?;
575 write_padding!(writer, 7);
576
577 write_data!(writer, self.xip_key, 16);
578 write_data!(writer, self.xip_iv, 16);
579 write_padding!(writer, 32);
580 Ok(())
581 }
582}
583
584impl SectionHeader {
585 // ------------------------------------------------------------------------------------
586 // instance methods
587 // ------------------------------------------------------------------------------------
588
589 /// Checks if the section has a next section.
590 ///
591 /// This method checks if the `next_offset` field of the `SectionHeader` is set to the special
592 /// value `0xFFFF_FFFF`, which indicates that there is no next section. If `next_offset` is
593 /// different from this value, it implies that there is a subsequent section, and the method
594 /// returns `true`. Otherwise, it returns `false`, indicating this is the last section.
595 ///
596 /// # Returns
597 /// - `true` if the section has a next section (i.e., `next_offset` is not `0xFFFF_FFFF`).
598 /// - `false` if this is the last section (i.e., `next_offset` is `0xFFFF_FFFF`).
599 pub fn has_next(&self) -> bool {
600 return self.next_offset.is_some();
601 }
602
603 /// Checks if both the `xip_key` and `xip_iv` fields are valid.
604 ///
605 /// This method uses the `is_valid_data!` macro to check the validity of both the `xip_key`
606 /// and `xip_iv` fields. It returns `true` if both fields are valid (i.e., they do not consist
607 /// entirely of `0xFF` bytes). If either field is invalid, it returns `false`.
608 ///
609 /// This method is typically used to determine if the section is encrypted and can be used
610 /// for cryptographic operations.
611 ///
612 /// # Returns
613 /// - `true` if both `xip_key` and `xip_iv` are valid.
614 /// - `false` if either `xip_key` or `xip_iv` is invalid.
615 pub fn xip_key_iv_valid(&self) -> bool {
616 match (&self.xip_key, &self.xip_iv) {
617 (Some(xip_key), Some(xip_iv)) => {
618 return is_valid_data!(xip_key) && is_valid_data!(xip_iv);
619 }
620 _ => return false,
621 }
622 }
623
624 /// Retrieves the XIP key.
625 pub fn get_xip_key(&self) -> DataRefType<'_, 16> {
626 self.xip_key.as_ref()
627 }
628
629 /// Retrieves the XIP IV.
630 pub fn get_xip_iv(&self) -> DataRefType<'_, 16> {
631 self.xip_iv.as_ref()
632 }
633
634 /// Retrieves the valid pattern.
635 pub fn get_valid_pattern(&self) -> &[u8; 8] {
636 &self.valid_pattern
637 }
638
639 pub fn set_xip_iv(&mut self, iv: DataType<16>) {
640 self.xip_iv = iv;
641 }
642
643 pub fn set_xip_key(&mut self, key: DataType<16>) {
644 self.xip_key = key;
645 }
646}
647
648// -- entry header --
649// Layout recovered from
650// - entry_header_t *_create_entry_header(uint length, uint load_address, uint entry_address)
651//
652// +---+---+---+---+----+----+----+----+----+----+-----+----+----+----+----+----+
653// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
654// +========+===+===+===+===+====+====+====+====+====+====+=====+====+====+====+====+====+
655// | 0x00 | length: u32 | load_address: u32 | entry_address: u32 | |
656// +--------+---------------+-------------------+--------------------+-------------------+
657// | 0x10 | |
658// +--------+----------------------------------------------------------------------------+
659// size = 0x20
660
661/// `EntryHeader` represents the header of a specific entry within a binary image.
662/// It includes metadata about the entry, such as its length, load address, and entry point.
663///
664/// This structure is used to describe a segment or block of data that is loaded into memory
665/// at a specified address and contains an entry point that the system can use to jump to
666/// the start of execution.
667///
668/// Fields:
669/// - `length`: The length of the entry in bytes. This defines how much memory the entry occupies.
670/// - `load_address`: The memory address at which the entry is loaded into the system's memory space.
671/// - `entry_address`: The address to which control is transferred when the entry is executed.
672/// By default, it's set to `0xFFFF_FFFF` (None), which indicates an invalid entry address.
673#[derive(Debug)]
674pub struct EntryHeader {
675 /// The length of the entry in bytes.
676 pub length: u32,
677
678 /// The load address in memory where the entry will be loaded.
679 pub load_address: u32,
680
681 /// The entry address, the address to which the system will jump to start execution.
682 /// Defaults to `0xFFFF_FFFF` (None), indicating an invalid address.
683 pub entry_address: Option<u32>,
684}
685
686impl BinarySize for EntryHeader {
687 /// Returns the binary size of the `EntryHeader` struct in bytes.
688 ///
689 /// # Returns
690 /// - `0x20`: The size of the `EntryHeader` struct in bytes.
691 fn binary_size() -> usize {
692 return 0x20;
693 }
694}
695
696impl Default for EntryHeader {
697 /// Returns the default values for the `EntryHeader` struct.
698 ///
699 /// The default values are:
700 /// - `length`: `0` (indicating no data or length of the entry).
701 /// - `load_address`: `0` (indicating the entry is not loaded anywhere).
702 /// - `entry_address`: `0xFFFF_FFFF` (None) (invalid entry address, typically indicating no valid entry).
703 ///
704 /// # Returns
705 /// - `EntryHeader`: A struct with default values.
706 fn default() -> EntryHeader {
707 return EntryHeader {
708 length: 0,
709 load_address: 0,
710 entry_address: None,
711 };
712 }
713}
714
715impl FromStream for EntryHeader {
716 /// Reads an `EntryHeader` from the provided reader (e.g., a file or memory buffer).
717 ///
718 /// # Arguments
719 /// - `reader`: A mutable reference to an object that implements `Read` and `Seek` (e.g., a file or buffer).
720 ///
721 /// # Returns
722 /// - `Ok(())`: If the deserialization is successful.
723 /// - `Err(Error)`: If there is an error reading from the stream, such as an unexpected end of data.
724 fn read_from<R>(&mut self, reader: &mut R) -> Result<(), Error>
725 where
726 R: std::io::Read + std::io::Seek,
727 {
728 self.length = reader.read_u32::<LittleEndian>()?;
729 self.load_address = reader.read_u32::<LittleEndian>()?;
730 self.entry_address = match reader.read_u32::<LittleEndian>()? {
731 0xFFFF_FFFF => None,
732 address => Some(address),
733 };
734 read_padding!(reader, 20);
735 Ok(())
736 }
737}
738
739impl ToStream for EntryHeader {
740 /// Serializes the `EntryHeader` struct to a stream.
741 ///
742 /// # Parameters
743 /// - `writer`: A mutable reference to a type that implements the `std::io::Write` trait. The data will
744 /// be written to this stream.
745 ///
746 /// # Returns
747 /// - `Ok(())`: If the data is written successfully.
748 /// - `Err(Error)`: If there is an issue writing the data to the stream.
749 fn write_to<W>(&self, writer: &mut W) -> Result<(), Error>
750 where
751 W: io::Write + io::Seek,
752 {
753 writer.write_u32::<LittleEndian>(self.length)?;
754 writer.write_u32::<LittleEndian>(self.load_address)?;
755 writer.write_u32::<LittleEndian>(self.entry_address.unwrap_or(0xFFFF_FFFF))?;
756 write_padding!(writer, 20);
757 Ok(())
758 }
759}