Compressed binary file internals

This article describes the structure of the zephyr.signed.bin file when image compression is enabled. You do not need to know these details to use the image compression subsystem, but they can be beneficial if you want to use them for verification or custom integration purposes.

For an example, see the following structure of the file:

LZMA header

LZMA Header

The Lempel-Ziv-Markov chain Algorithm (LZMA) header is crucial for files compressed using the LZMA method. It contains metadata essential for decompression. The lzma2_header encodes compression parameters using two bytes.

Calculating compression parameters

Compression parameters can be calculated, retrieved, or changed depending on your needs. For details, see the following sections.

Default values

Compression parameters have the following default values:

  • dict_size: 131072
  • pb: 2
  • lc: 3
  • lp: 1

Adjusting dictionary size

You can calculate the dict_size using the following method:

unsigned int i = 0;

for (i = 0; i < 40; i++) {
    if (raw_dict_size <= (((uint32_t)2 | ((i) & 1)) << ((i) / 2 + 11))) {
        break;
    }
}
dict_size = (uint8_t)i;

With this method, dict_size can have one of the following values:

Hex ValueSize
0x004096
0x016144
0x028192
0x0312288
0x0416384
0x0524576
0x0632768
0x0749152
0x0865536
0x0998304
0x0a131072
0x0b196608
0x0c262144
0x0d393216
0x0e524288
0x0f786432
0x101048576
0x111572864
0x122097152
0x133145728
0x144194304
0x156291456
0x168388608
0x1712582912
0x1816777216
0x1925165824
0x1a33554432
0x1b50331648
0x1c67108864
0x1d100663296
0x1e134217728
0x1f201326592
0x20268435456
0x21402653184
0x22536870912
0x23805306368
0x241073741824
0x251610612736
0x262147483648
0x273221225472

Calculating literal context, literal pos, and pos bits

The second byte of the lzma2_header carries the following parameters:

  • lc, which specifies a number of literal context bits

  • lp, which specifies a number of literal pos bits

  • pb, which specifies a number of pos bits

    These parameters are encoded with the following formula:

    pb_lp_lc = (uint8_t)((pb * 5 + lp) * 9 + lc);
    

    To decode these values from the combined pb_lp_lc byte, run the following code:

    lc = pb_lp_lc % 9;
    pb_lp_lc /= 9;
    pb = pb_lp_lc / 5;
    lp = pb_lp_lc % 5;
    

Extracting LZMA stream from image

To extract and decompress the LZMA stream from the image, follow these steps:

  1. Determine the offset of the compressed stream by adding the lzma2_header size and the value stored under image_header.ih_hdr_size. For the size of the compressed stream, see image_header.ih_img_size.
  2. If the compressed stream is isolated and stored in a file named raw.lzma, you can perform decompression using the following commands:
  • Without an ARM thumb filter:

    unlzma --lzma2 --format=raw --suffix=.lzma raw.lzma
    
  • With an ARM thumb filter:

    unlzma --armthumb --lzma2 --format=raw --suffix=.lzma raw.lzma
    

Once the command is executed you will see a newly created file named raw, which is identical to the image before compression.

TLVs

The following Type-Length-Values (TLVs) are used in the context of decompressed images:

  • DECOMP_SIZE (0x70): Specifies the size of the decompressed image.
  • DECOMP_SHA (0x71): Contains the hash of the decompressed image.
  • DECOMP_SIGNATURE (0x72): Holds the signature of either the hash or the entire image.

These TLVs are placed in the protected TLV section, ensuring they are included in the hashing and signature calculations during the verification process. The process for choosing the type of cryptographic signature and hash algorithm used for securing the image is the same, regardless of whether the image has undergone compression.

Sample

For practical implementation, you can find a simple stand-alone verification program under the following path bootloader/mcuboot/samples/compression_test/independent_cmp.c

This program demonstrates how to independently verify the integrity and authenticity of a decompressed image using the specified TLVs.