コード例 #1
0
ファイル: test_common.py プロジェクト: mstarecek/spsdk
def test_counter():
    """Test of Counter."""
    # simple counter with nonce only
    cntr = Counter(bytes([0] * 16))
    assert cntr.value == bytes([0] * 16)

    # counter with nonce and counter encoded as little endian
    cntr = Counter(bytes([0] * 16), ctr_value=0x01234567, ctr_byteorder_encoding="little")
    assert cntr.value == bytes([0] * 12 + [0x67, 0x45, 0x23, 0x01])

    # counter with nonce and counter encoded as little endian
    cntr = Counter(bytes([0] * 16), ctr_value=0x01234567)
    assert cntr.value == bytes([0] * 12 + [0x67, 0x45, 0x23, 0x01])

    # counter with nonce and counter encoded as big endian
    cntr = Counter(bytes([0] * 16), ctr_value=1, ctr_byteorder_encoding="big")
    assert cntr.value == bytes([0] * 15 + [1])

    # increment
    cntr.increment()
    assert cntr.value == bytes([0] * 15 + [2])
    cntr.increment(2)
    assert cntr.value == bytes([0] * 15 + [4])
    cntr.increment(256)
    assert cntr.value == bytes([0] * 14 + [1, 4])
コード例 #2
0
def test_invalid_header_hmac(data_dir):
    cs = CertSectionV2(_create_cert_block_v2(data_dir))
    dek = crypto_backend().random_bytes(32)
    mac = crypto_backend().random_bytes(32)
    nonce = crypto_backend().random_bytes(16)
    valid_data = cs.export(dek, mac, Counter(nonce))
    invalid_data = valid_data
    invalid_data = bytearray(invalid_data)
    invalid_data[0:32] = bytearray(32)
    with pytest.raises(SPSDKError, match="HMAC"):
        CertSectionV2.parse(invalid_data, 0, dek, mac, Counter(nonce))
コード例 #3
0
def test_invalid_header_flag(data_dir):
    cs = CertSectionV2(_create_cert_block_v2(data_dir))
    cs._header.address += 1
    dek = crypto_backend().random_bytes(32)
    mac = crypto_backend().random_bytes(32)
    nonce = crypto_backend().random_bytes(16)
    valid_data = cs.export(dek, mac, Counter(nonce))
    with pytest.raises(SPSDKError, match="Mark"):
        CertSectionV2.parse(data=valid_data,
                            mac=mac,
                            dek=dek,
                            counter=Counter(nonce))
コード例 #4
0
def test_certificate_section_v2(data_dir: str) -> None:
    with pytest.raises(AssertionError):
        CertSectionV2(None)

    cs = CertSectionV2(_create_cert_block_v2(data_dir))
    dek = crypto_backend().random_bytes(32)
    mac = crypto_backend().random_bytes(32)
    nonce = crypto_backend().random_bytes(16)
    data = cs.export(dek, mac, Counter(nonce))
    assert data
    assert CertSectionV2.parse(data, 0, dek, mac, Counter(nonce))

    with pytest.raises(Exception):
        CertSectionV2.parse(data, 0, dek,
                            crypto_backend().random_bytes(32), Counter(nonce))
コード例 #5
0
    def encrypt_block(self, key: bytes, start_addr: int, data: bytes) -> bytes:
        """Encrypt block located in any FAC region.

        :param key: user for encryption
        :param start_addr: start address of the data
        :param data: binary block to be encrypted; the block size must be BEE_ENCR_BLOCK_SIZE
        :return: encrypted block if it is inside any FAC region; untouched block if it is not in any FAC region
        :raises SPSDKError: When incorrect length of binary block
        :raises SPSDKError: When encryption mode different from AES/CTR provided
        :raises SPSDKError: When invalid length of key
        :raises SPSDKError: When invalid range of region
        """
        if len(data) != BEE_ENCR_BLOCK_SIZE:
            raise SPSDKError(
                "Incorrect length of binary block to be encrypted")
        if self._start_addr <= start_addr < self._end_addr:
            if self.mode != BeeProtectRegionBlockAesMode.CTR:
                raise SPSDKError("only AES/CTR encryption mode supported now")
            if len(key) != 16:
                raise SPSDKError("Invalid length of key")
            for fac in self.fac_regions:
                if fac.start_addr <= start_addr < fac.end_addr:
                    if start_addr + len(data) > fac.end_addr:
                        raise SPSDKError("Invalid range of region")
                    cntr_key = Counter(
                        self.counter,
                        ctr_value=start_addr >> 4,
                        ctr_byteorder_encoding="big",
                    )
                    return crypto_backend().aes_ctr_encrypt(
                        key, data, cntr_key.value)
        return data
コード例 #6
0
def test_boot_section_v2():
    boot_section = BootSectionV2(0, CmdErase(address=0, length=100000),
                                 CmdLoad(address=0, data=b"0123456789"),
                                 CmdReset())

    assert boot_section.uid == 0
    assert not boot_section.is_last
    assert boot_section.hmac_count == 1
    assert boot_section.raw_size == 144

    dek = crypto_backend().random_bytes(32)
    mac = crypto_backend().random_bytes(32)
    nonce = crypto_backend().random_bytes(16)
    data = boot_section.export(dek, mac, Counter(nonce))
    assert data
    assert BootSectionV2.parse(data, 0, False, dek, mac, Counter(nonce))

    with pytest.raises(SPSDKError,
                       match="Invalid type of dek, should be bytes"):
        BootSectionV2.parse(data=data,
                            offset=0,
                            plain_sect=False,
                            dek=4,
                            mac=mac,
                            counter=Counter(nonce))

    with pytest.raises(SPSDKError,
                       match="Invalid type of mac, should be bytes"):
        BootSectionV2.parse(data=data,
                            offset=0,
                            plain_sect=False,
                            dek=dek,
                            mac=4,
                            counter=Counter(nonce))

    with pytest.raises(SPSDKError, match="Invalid type of counter"):
        BootSectionV2.parse(data=data,
                            offset=0,
                            plain_sect=False,
                            dek=dek,
                            mac=mac,
                            counter=5)

    with pytest.raises(SPSDKError):
        assert BootSectionV2.parse(data, 0, False, dek,
                                   crypto_backend().random_bytes(32),
                                   Counter(nonce))
コード例 #7
0
def test_invalid_export_cert_section_v2(data_dir):
    cs = CertSectionV2(_create_cert_block_v2(data_dir))
    dek = crypto_backend().random_bytes(16)
    mac = crypto_backend().random_bytes(16)
    nonce = crypto_backend().random_bytes(16)
    cs.HMAC_SIZE = 137
    with pytest.raises(SPSDKError, match="Invalid size"):
        cs.export(dek, mac, Counter(nonce))
コード例 #8
0
    def export(self, padding: Optional[bytes] = None) -> bytes:
        """Serialize image object.

        :param padding: header padding (8 bytes) for testing purpose; None to use random values (recommended)
        :return: exported bytes
        :raises SPSDKError: Raised when there are no boot sections or is not signed or private keys are missing
        :raises SPSDKError: Raised when there is invalid dek or mac
        :raises SPSDKError: Raised when certificate data is not present
        :raises SPSDKError: Raised when there is invalid certificate block
        :raises SPSDKError: Raised when there is invalid length of exported data
        """
        if len(self.dek) != 32 or len(self.mac) != 32:
            raise SPSDKError("Invalid dek or mac")
        # validate params
        if not self._boot_sections:
            raise SPSDKError("No boot section")
        if self.signed and (self._cert_section is None):
            raise SPSDKError(
                "Certificate section is required for signed images")
        # update internals
        self.update()
        # Add Image Header data
        data = self._header.export(padding=padding)
        # Add Image Header HMAC data
        data += crypto_backend().hmac(self.mac, data)
        # Add DEK and MAC keys
        data += crypto_backend().aes_key_wrap(self.kek, self.dek + self.mac)
        # Add Padding
        data += padding if padding else crypto_backend().random_bytes(8)
        # Add Certificates data
        if not self._header.nonce:
            raise SPSDKError("There is no nonce in the header")
        counter = Counter(self._header.nonce)
        counter.increment(calc_cypher_block_count(len(data)))
        if self._cert_section is not None:
            cert_sect_bin = self._cert_section.export(dek=self.dek,
                                                      mac=self.mac,
                                                      counter=counter)
            counter.increment(calc_cypher_block_count(len(cert_sect_bin)))
            data += cert_sect_bin
        # Add Boot Sections data
        for sect in self._boot_sections:
            data += sect.export(dek=self.dek, mac=self.mac, counter=counter)
        # Add Signature data
        if self.signed:
            private_key_pem_data = self.private_key_pem_data
            if private_key_pem_data is None:
                raise SPSDKError(
                    "Private key not assigned, cannot sign the image")
            certificate_block = self.cert_block
            if not ((certificate_block is not None) and certificate_block.
                    verify_private_key(private_key_pem_data)):
                raise SPSDKError("Invalid certificate block")
            data += crypto_backend().rsa_sign(private_key_pem_data, data)
        if len(data) != self.raw_size:
            raise SPSDKError("Invalid length of exported data")
        return data
コード例 #9
0
def test_boot_section_v2_invalid_export():
    boot_section = BootSectionV2(0, CmdErase(address=0, length=100000),
                                 CmdLoad(address=0, data=b"0123456789"),
                                 CmdReset())
    dek = 32
    mac = 4
    nonce = crypto_backend().random_bytes(16)
    with pytest.raises(SPSDKError,
                       match="Invalid type of dek, should be bytes"):
        boot_section.export(dek, mac, Counter(nonce))
    dek = crypto_backend().random_bytes(32)
    with pytest.raises(SPSDKError,
                       match="Invalid type of mac, should be bytes"):
        boot_section.export(dek, mac, Counter(nonce))
    counter = 5
    mac = crypto_backend().random_bytes(32)
    with pytest.raises(SPSDKError, match="Invalid type of counter"):
        boot_section.export(dek, mac, counter)
コード例 #10
0
def test_boot_section_v2():
    boot_section = BootSectionV2(0, CmdErase(address=0, length=100000),
                                 CmdLoad(address=0, data=b'0123456789'),
                                 CmdReset())

    assert boot_section.uid == 0
    assert not boot_section.is_last
    assert boot_section.hmac_count == 1
    assert boot_section.raw_size == 144

    dek = crypto_backend().random_bytes(32)
    mac = crypto_backend().random_bytes(32)
    nonce = crypto_backend().random_bytes(16)
    data = boot_section.export(dek, mac, Counter(nonce))
    assert data
    assert BootSectionV2.parse(data, 0, False, dek, mac, Counter(nonce))

    with pytest.raises(Exception):
        assert BootSectionV2.parse(data, 0, False, dek,
                                   crypto_backend().random_bytes(32),
                                   Counter(nonce))
コード例 #11
0
ファイル: bee.py プロジェクト: AdrianCano-01/spsdk
    def encrypt_block(self, key: bytes, start_addr: int, data: bytes) -> bytes:
        """Encrypt block located in any FAC region.

        :param key: user for encryption
        :param start_addr: start address of the data
        :param data: binary block to be encrypted; the block size must be BEE_ENCR_BLOCK_SIZE
        :return: encrypted block if it is inside any FAC region; untouched block if it is not in any FAC region
        """
        assert len(data) == BEE_ENCR_BLOCK_SIZE
        if self._start_addr <= start_addr < self._end_addr:
            assert self.mode == BeeProtectRegionBlockAesMode.CTR, 'only AES/CTR encryption mode supported now'
            assert len(key) == 16
            for fac in self.fac_regions:
                if fac.start_addr <= start_addr < fac.end_addr:
                    assert start_addr + len(data) <= fac.end_addr
                    cntr_key = Counter(self.counter,
                                       ctr_value=start_addr >> 4,
                                       ctr_byteorder_encoding='big')
                    return crypto_backend().aes_ctr_encrypt(
                        key, data, cntr_key.value)
        return data
コード例 #12
0
    def parse(cls,
              data: bytes,
              offset: int = 0,
              kek: bytes = bytes()) -> "BootImageV20":
        """Parse image from bytes.

        :param data: Raw data of parsed image
        :param offset: The offset of input data
        :param kek: The Key for unwrapping DEK and MAC keys (required)
        :return: parsed image object
        :raise Exception: raised when header is in wrong format
        :raise Exception: raised when there is invalid header version
        :raise Exception: raised when signature is incorrect
        :raises SPSDKError: Raised when kek is empty
        :raises Exception: raised when header's nonce is not present
        """
        if not kek:
            raise SPSDKError("kek cannot be empty")
        index = offset
        header_raw_data = data[index:index + ImageHeaderV2.SIZE]
        index += ImageHeaderV2.SIZE
        header_mac_data = data[index:index + cls.HEADER_MAC_SIZE]
        index += cls.HEADER_MAC_SIZE
        key_blob = data[index:index + cls.KEY_BLOB_SIZE]
        index += cls.KEY_BLOB_SIZE
        key_blob_unwrap = crypto_backend().aes_key_unwrap(kek, key_blob[:-8])
        dek = key_blob_unwrap[:32]
        mac = key_blob_unwrap[32:]
        header_mac_data_calc = crypto_backend().hmac(mac, header_raw_data)
        if header_mac_data != header_mac_data_calc:
            raise Exception()
        # Parse Header
        header = ImageHeaderV2.parse(header_raw_data)
        if header.version != "2.0":
            raise Exception(
                f"Invalid Header Version: {header.version} instead 2.0")
        image_size = header.image_blocks * 16
        # Initialize counter
        if not header.nonce:
            raise SPSDKError("Header's nonce not present")
        counter = Counter(header.nonce)
        counter.increment(calc_cypher_block_count(index - offset))
        # ...
        signed = header.flags == 0x08
        adv_params = SBV2xAdvancedParams(dek=dek,
                                         mac=mac,
                                         nonce=header.nonce,
                                         timestamp=header.timestamp)
        obj = cls(
            signed,
            kek=kek,
            product_version=str(header.product_version),
            component_version=str(header.component_version),
            build_number=header.build_number,
            advanced_params=adv_params,
        )
        # Parse Certificate section
        if header.flags == 0x08:
            cert_sect = CertSectionV2.parse(data,
                                            index,
                                            dek=dek,
                                            mac=mac,
                                            counter=counter)
            obj._cert_section = cert_sect
            index += cert_sect.raw_size
            # Check Signature
            if not cert_sect.cert_block.verify_data(
                    data[offset + image_size:],
                    data[offset:offset + image_size]):
                raise Exception()
        # Parse Boot Sections
        while index < (image_size + offset):
            boot_section = BootSectionV2.parse(data,
                                               index,
                                               dek=dek,
                                               mac=mac,
                                               counter=counter)
            obj.add_boot_section(boot_section)
            index += boot_section.raw_size
        return obj
コード例 #13
0
ファイル: test_common.py プロジェクト: mstarecek/spsdk
def test_counter_invalid():
    with pytest.raises(SPSDKError, match="Wrong byte order"):
        Counter(nonce=bytes(16), ctr_byteorder_encoding="BIG")
コード例 #14
0
    def export(self,
               padding: Optional[bytes] = None,
               dbg_info: Optional[List[str]] = None) -> bytes:
        """Serialize image object.

        :param padding: header padding (8 bytes) for testing purpose; None to use random values (recommended)
        :param dbg_info: optional list, where debug info is exported in text form
        :return: exported bytes
        :raise ValueError: raised when there is no boot section to be added
        :raise ValueError: raise when certificate is not assigned
        :raise ValueError: raise when private key is not assigned
        """
        # validate params
        if not self._boot_sections:
            raise ValueError("At least one Boot Section must be added")
        if self.cert_block is None:
            raise ValueError('Certificate is not assigned')
        if self.private_key_pem_data is None:
            raise ValueError('Private key not assigned, cannot sign the image')
        # Update internals
        if dbg_info is not None:
            dbg_info.append('[sb_file]')
        bs_dbg_info: Optional[List[str]] = list() if dbg_info else None
        self.update()
        # Export Boot Sections
        bs_data = bytes()
        # TODO: implement helper method for get key size in bytes. Now is working only with internal backend
        bs_offset = (ImageHeaderV2.SIZE + self.HEADER_MAC_SIZE +
                     self.KEY_BLOB_SIZE + self.cert_block.raw_size +
                     self.cert_block.signature_size)
        assert self._header.nonce
        counter = Counter(self._header.nonce,
                          calc_cypher_block_count(bs_offset))
        for sect in self._boot_sections:
            bs_data += sect.export(dek=self.dek,
                                   mac=self.mac,
                                   counter=counter,
                                   dbg_info=bs_dbg_info)
        # Export Header
        signed_data = self._header.export(padding=padding)
        if dbg_info:
            dbg_info.append('[header]')
            dbg_info.append(signed_data.hex())
        #  Add HMAC data
        first_bs_hmac_count = self._boot_sections[0].hmac_count
        hmac_data = bs_data[CmdHeader.SIZE:CmdHeader.SIZE +
                            (first_bs_hmac_count * 32) + 32]
        hmac = crypto_backend().hmac(self.mac, hmac_data)
        signed_data += hmac
        if dbg_info:
            dbg_info.append('[hmac]')
            dbg_info.append(hmac.hex())
        # Add KeyBlob data
        key_blob = crypto_backend().aes_key_wrap(self.kek, self.dek + self.mac)
        key_blob += b'\00' * (self.KEY_BLOB_SIZE - len(key_blob))
        signed_data += key_blob
        if dbg_info:
            dbg_info.append('[key_blob]')
            dbg_info.append(key_blob.hex())
        # Add Certificates data
        signed_data += self.cert_block.export()
        if dbg_info:
            dbg_info.append('[cert_block]')
            dbg_info.append(self.cert_block.export().hex())
        # Add Signature data
        assert self.cert_block.verify_private_key(
            self.private_key_pem_data
        )  # verify private key matches certificate
        signature = crypto_backend().rsa_sign(self.private_key_pem_data,
                                              signed_data)
        if dbg_info:
            dbg_info.append('[signature]')
            dbg_info.append(signature.hex())
            dbg_info.append('[boot_sections]')
            assert bs_dbg_info
            dbg_info.extend(bs_dbg_info)
        return signed_data + signature + bs_data
コード例 #15
0
    def export(self,
               padding: Optional[bytes] = None,
               dbg_info: Optional[List[str]] = None) -> bytes:
        """Serialize image object.

        :param padding: header padding (8 bytes) for testing purpose; None to use random values (recommended)
        :param dbg_info: optional list, where debug info is exported in text form
        :return: exported bytes
        :raises SPSDKError: Raised when there is no boot section to be added
        :raises SPSDKError: Raised when certificate is not assigned
        :raises SPSDKError: Raised when private key is not assigned
        :raises SPSDKError: Raised when private header's nonce is invalid
        :raises SPSDKError: Raised when private key does not match certificate
        :raises SPSDKError: Raised when there is no debug info
        """
        # validate params
        if not self._boot_sections:
            raise SPSDKError("At least one Boot Section must be added")
        if self.cert_block is None:
            raise SPSDKError("Certificate is not assigned")
        if self.private_key_pem_data is None:
            raise SPSDKError("Private key not assigned, cannot sign the image")
        # Update internals
        if dbg_info is not None:
            dbg_info.append("[sb_file]")
        bs_dbg_info: Optional[List[str]] = list() if dbg_info else None
        self.update()
        # Export Boot Sections
        bs_data = bytes()
        # TODO: implement helper method for get key size in bytes. Now is working only with internal backend
        bs_offset = (ImageHeaderV2.SIZE + self.HEADER_MAC_SIZE +
                     self.KEY_BLOB_SIZE + self.cert_block.raw_size +
                     self.cert_block.signature_size)
        if self.header.flags & self.FLAGS_SHA_PRESENT_BIT:
            bs_offset += self.SHA_256_SIZE

        if not self._header.nonce:
            raise SPSDKError("Invalid header's nonce")
        counter = Counter(self._header.nonce,
                          calc_cypher_block_count(bs_offset))
        for sect in self._boot_sections:
            bs_data += sect.export(dek=self.dek,
                                   mac=self.mac,
                                   counter=counter,
                                   dbg_info=bs_dbg_info)
        # Export Header
        signed_data = self._header.export(padding=padding)
        if dbg_info:
            dbg_info.append("[header]")
            dbg_info.append(signed_data.hex())
        #  Add HMAC data
        first_bs_hmac_count = self._boot_sections[0].hmac_count
        hmac_data = bs_data[CmdHeader.SIZE:CmdHeader.SIZE +
                            (first_bs_hmac_count * 32) + 32]
        hmac = crypto_backend().hmac(self.mac, hmac_data)
        signed_data += hmac
        if dbg_info:
            dbg_info.append("[hmac]")
            dbg_info.append(hmac.hex())
        # Add KeyBlob data
        key_blob = crypto_backend().aes_key_wrap(self.kek, self.dek + self.mac)
        key_blob += b"\00" * (self.KEY_BLOB_SIZE - len(key_blob))
        signed_data += key_blob
        if dbg_info:
            dbg_info.append("[key_blob]")
            dbg_info.append(key_blob.hex())
        # Add Certificates data
        signed_data += self.cert_block.export()
        if dbg_info:
            dbg_info.append("[cert_block]")
            dbg_info.append(self.cert_block.export().hex())
        # Add SHA-256 of Bootable sections if requested
        if self.header.flags & self.FLAGS_SHA_PRESENT_BIT:
            signed_data += internal_backend.hash(bs_data)
        # Add Signature data
        if not self.cert_block.verify_private_key(self.private_key_pem_data):
            raise SPSDKError("Private key does not match certificate")
        signature = crypto_backend().rsa_sign(self.private_key_pem_data,
                                              signed_data)
        if dbg_info:
            dbg_info.append("[signature]")
            dbg_info.append(signature.hex())
            dbg_info.append("[boot_sections]")
            if not bs_dbg_info:
                raise SPSDKError("No debug information")
            dbg_info.extend(bs_dbg_info)
        return signed_data + signature + bs_data
コード例 #16
0
    def parse(
        cls,
        data: bytes,
        offset: int = 0,
        kek: bytes = bytes(),
        plain_sections: bool = False,
    ) -> "BootImageV21":
        """Parse image from bytes.

        :param data: Raw data of parsed image
        :param offset: The offset of input data
        :param kek: The Key for unwrapping DEK and MAC keys (required)
        :param plain_sections: Sections are not encrypted; this is used only for debugging,
            not supported by ROM code
        :return: BootImageV21 parsed object
        :raises Exception: raised when header is in incorrect format
        :raises Exception: raised when signature is incorrect
        :raises SPSDKError: Raised when kek is empty
        :raises Exception: raised when header's nonce not present"
        """
        if not kek:
            raise SPSDKError("kek cannot be empty")
        index = offset
        header_raw_data = data[index:index + ImageHeaderV2.SIZE]
        index += ImageHeaderV2.SIZE
        # TODO not used right now: hmac_data = data[index: index + cls.HEADER_MAC_SIZE]
        index += cls.HEADER_MAC_SIZE
        key_blob = data[index:index + cls.KEY_BLOB_SIZE]
        index += cls.KEY_BLOB_SIZE
        key_blob_unwrap = crypto_backend().aes_key_unwrap(kek, key_blob[:-8])
        dek = key_blob_unwrap[:32]
        mac = key_blob_unwrap[32:]
        # Parse Header
        header = ImageHeaderV2.parse(header_raw_data)
        if header.offset_to_certificate_block != (index - offset):
            raise Exception()
        # Parse Certificate Block
        cert_block = CertBlockV2.parse(data, index)
        index += cert_block.raw_size

        # Verify Signature
        signature_index = index
        # The image may containt SHA, in such a case the signature is placed
        # after SHA. Thus we must shift the index by SHA size.
        if header.flags & BootImageV21.FLAGS_SHA_PRESENT_BIT:
            signature_index += BootImageV21.SHA_256_SIZE
        result = cert_block.verify_data(
            data[signature_index:signature_index + cert_block.signature_size],
            data[offset:signature_index],
        )

        if not result:
            raise Exception()
        # Check flags, if 0x8000 bit is set, the SB file contains SHA-256 between
        # certificate and signature.
        if header.flags & BootImageV21.FLAGS_SHA_PRESENT_BIT:
            bootable_section_sha256 = data[index:index +
                                           BootImageV21.SHA_256_SIZE]
            index += BootImageV21.SHA_256_SIZE
        index += cert_block.signature_size
        # Check first Boot Section HMAC
        # TODO: not implemented yet
        # hmac_data_calc = crypto_backend().hmac(mac, data[index + CmdHeader.SIZE: index + CmdHeader.SIZE + ((2) * 32)])
        # if hmac_data != hmac_data_calc:
        #    raise Exception()
        if not header.nonce:
            raise SPSDKError("Header's nonce not present")
        counter = Counter(header.nonce)
        counter.increment(calc_cypher_block_count(index - offset))
        boot_section = BootSectionV2.parse(data,
                                           index,
                                           dek=dek,
                                           mac=mac,
                                           counter=counter,
                                           plain_sect=plain_sections)
        if header.flags & BootImageV21.FLAGS_SHA_PRESENT_BIT:
            computed_bootable_section_sha256 = internal_backend.hash(
                data[index:], algorithm="sha256")

            if bootable_section_sha256 != computed_bootable_section_sha256:
                raise SPSDKError(desc=(
                    "Error: invalid Bootable section SHA."
                    f"Expected {bootable_section_sha256.decode('utf-8')},"
                    f"got {computed_bootable_section_sha256.decode('utf-8')}"))
        adv_params = SBV2xAdvancedParams(dek=dek,
                                         mac=mac,
                                         nonce=header.nonce,
                                         timestamp=header.timestamp)
        obj = cls(
            kek=kek,
            product_version=str(header.product_version),
            component_version=str(header.component_version),
            build_number=header.build_number,
            advanced_params=adv_params,
        )
        obj.cert_block = cert_block
        obj.add_boot_section(boot_section)
        return obj
コード例 #17
0
    def parse(cls,
              data: bytes,
              offset: int = 0,
              kek: bytes = bytes(),
              plain_sections: bool = False) -> 'BootImageV21':
        """Parse image from bytes.

        :param data: Raw data of parsed image
        :param offset: The offset of input data
        :param kek: The Key for unwrapping DEK and MAC keys (required)
        :param plain_sections: Sections are not encrypted; this is used only for debugging, not supported by ROM code
        :return: BootImageV21 parsed object
        :raise Exception: raised when header is in incorrect format
        :raise Exception: raised when signature is incorrect
        """
        assert kek, 'kek cannot be empty'
        index = offset
        header_raw_data = data[index:index + ImageHeaderV2.SIZE]
        index += ImageHeaderV2.SIZE
        # TODO not used right now: hmac_data = data[index: index + cls.HEADER_MAC_SIZE]
        index += cls.HEADER_MAC_SIZE
        key_blob = data[index:index + cls.KEY_BLOB_SIZE]
        index += cls.KEY_BLOB_SIZE
        key_blob_unwrap = crypto_backend().aes_key_unwrap(kek, key_blob[:-8])
        dek = key_blob_unwrap[:32]
        mac = key_blob_unwrap[32:]
        # Parse Header
        header = ImageHeaderV2.parse(header_raw_data)
        if header.offset_to_certificate_block != (index - offset):
            raise Exception()
        # Parse Certificate Block
        cert_block = CertBlockV2.parse(data, index)
        index += cert_block.raw_size
        # Verify Signature
        if not cert_block.verify_data(
                data[index:index + cert_block.signature_size],
                data[offset:index]):
            raise Exception()
        index += cert_block.signature_size
        # Check first Boot Section HMAC
        # TODO: not implemented yet
        # hmac_data_calc = crypto_backend().hmac(mac, data[index + CmdHeader.SIZE: index + CmdHeader.SIZE + ((2) * 32)])
        # if hmac_data != hmac_data_calc:
        #    raise Exception()
        assert header.nonce
        counter = Counter(header.nonce)
        counter.increment(calc_cypher_block_count(index - offset))
        boot_section = BootSectionV2.parse(data,
                                           index,
                                           dek=dek,
                                           mac=mac,
                                           counter=counter,
                                           plain_sect=plain_sections)
        adv_params = SBV2xAdvancedParams(dek=dek,
                                         mac=mac,
                                         nonce=header.nonce,
                                         timestamp=header.timestamp)
        obj = cls(kek=kek,
                  product_version=str(header.product_version),
                  component_version=str(header.component_version),
                  build_number=header.build_number,
                  advanced_params=adv_params)
        obj.cert_block = cert_block
        obj.add_boot_section(boot_section)
        return obj