#!/usr/bin/env python3 # # Copyright (c) 2020-2022 Shanghai Panchip Microelectronics Co.,Ltd. # # SPDX-License-Identifier: Apache-2.0 # """ PAN1080 Image Encrypt Tool This script is used for encrypting the PAN1080 Image by AES ECB algorithm, which is indispensable for SoC that has enabled the Hardware Secure Flow. @author: limi@panchip.com lihui@panchip.com @change-history: v1.0.0: * (Apr/14/2020) Initial version v1.1.0: * (Apr/13/2022) Add several enhancements for easier use """ import sys import os import binascii from Crypto.Cipher import AES from binascii import b2a_hex from intelhex import IntelHex import yaml #Get from input hex image_start_addr = None image_size = None # Get from input yaml encrypt_flash_offset = None encrypt_key = None expected_image_start_addr = None usage = ''' Usage: CMD Syntax: python %s Notes: 1. Currently the tool only support HEX format file as input image. 2. The tool currently gets "encrypt_flash_offset", "encrypt_key" and "expected_start_addr" from the for checking and encrypting use. 3. Once encryption done, the tool generate 2 output files in the same folder: a hex file and a bin file, and each file has a '_enc' name suffix. e.g. Provided we have a named "path/to/input_file.hex", and a named "path2/to/encrypt_info.yaml", and now we open a cmd prompt and type: python %s path/to/input_file.hex path2/to/encrypt_info.yaml Soon we can find 2 output files in the input image file folder: 1. "path/to/input_file_enc.hex" 2. "path/to/input_file_enc.bin" ''' % (os.path.basename(__file__), os.path.basename(__file__)) # Check input parameters if len(sys.argv) != 3: print(usage) sys.exit(1) # Input image file with Intel HEX format input_hex_image_file = sys.argv[1] # Encrypt information file with YAML format encrypt_info_yaml_file = sys.argv[2] print('Image Encryption start..') print("Input image file: '{:s}'".format(input_hex_image_file)) print("Encrypt information file: '{:s}'".format(encrypt_info_yaml_file)) #------------------ Hex file processing ------------------ ihi = IntelHex(input_hex_image_file) segments = ihi.segments() segment_num = len(segments) # Currently we don't support to parse hex file with multiple segments if segment_num != 1: print("Error: Input file has multiple segments!") sys.exit(1) print("Hex Image Entry Address Info:", ihi.start_addr) for s in segments: image_start_addr = s[0] image_size = s[1]-s[0] print("Hex Segment: {{ start: 0x{:08X}, end: 0x{:08X}, length: 0x{:08X} ({:d}) }}" .format(s[0], s[1]-1, s[1]-s[0], s[1]-s[0])) # Check if the image start address is 256-bytes align if image_start_addr % 256 != 0: print('Error: The start address in hex file is not 256-bytes align!') sys.exit(1) #------------------ Yaml file processing ------------------ with open(encrypt_info_yaml_file, encoding='utf-8') as f: enc_info_list = yaml.safe_load(f) # print(enc_info_list) encrypt_flash_offset = enc_info_list['encrypt_info']['encrypt_flash_offset'] encrypt_key = enc_info_list['encrypt_info']['encrypt_key'] expected_image_start_addr = enc_info_list['image_info']['expected_start_addr'] print('encrypt flash offset: 0x{:X} ({:d})'.format(encrypt_flash_offset, encrypt_flash_offset)) print('encrypt key:', encrypt_key) print('expected image start addr: 0x{:X}'.format(expected_image_start_addr)) # Check if the image start address read from the input HEX file is # same with expected start address read from the input YAML file. if expected_image_start_addr != image_start_addr: print('Error: Start address in input HEX file is not same as expected in encrypt info YAML file!') sys.exit(1) # Check if the encrypt addr is larger than image start address if (encrypt_flash_offset * 256 < image_start_addr or encrypt_flash_offset * 256 + 256 > image_start_addr + image_size): print('Error: Encrypt flash offset is out of image range!') sys.exit(1) #----------------------------- Encrypt params --------------------------- # offset in binary file offset = encrypt_flash_offset - image_start_addr / 256 offset = int(offset) # AES key for the following encrypt flow use key = encrypt_key #------------------------- Processing binary data ---------------------- text_aes = ihi.tobinarray() text_aes_128_1 = b2a_hex(text_aes[( 0+int(offset)*256):( 16+int(offset)*256)]) text_aes_128_2 = b2a_hex(text_aes[( 16+int(offset)*256):( 32+int(offset)*256)]) text_aes_128_3 = b2a_hex(text_aes[( 32+int(offset)*256):( 48+int(offset)*256)]) text_aes_128_4 = b2a_hex(text_aes[( 48+int(offset)*256):( 64+int(offset)*256)]) text_aes_128_5 = b2a_hex(text_aes[( 64+int(offset)*256):( 80+int(offset)*256)]) text_aes_128_6 = b2a_hex(text_aes[( 80+int(offset)*256):( 96+int(offset)*256)]) text_aes_128_7 = b2a_hex(text_aes[( 96+int(offset)*256):(112+int(offset)*256)]) text_aes_128_8 = b2a_hex(text_aes[(112+int(offset)*256):(128+int(offset)*256)]) text_aes_128_9 = b2a_hex(text_aes[(128+int(offset)*256):(144+int(offset)*256)]) text_aes_128_10 = b2a_hex(text_aes[(144+int(offset)*256):(160+int(offset)*256)]) text_aes_128_11 = b2a_hex(text_aes[(160+int(offset)*256):(176+int(offset)*256)]) text_aes_128_12 = b2a_hex(text_aes[(176+int(offset)*256):(192+int(offset)*256)]) text_aes_128_13 = b2a_hex(text_aes[(192+int(offset)*256):(208+int(offset)*256)]) text_aes_128_14 = b2a_hex(text_aes[(208+int(offset)*256):(224+int(offset)*256)]) text_aes_128_15 = b2a_hex(text_aes[(224+int(offset)*256):(240+int(offset)*256)]) text_aes_128_16 = b2a_hex(text_aes[(240+int(offset)*256):(256+int(offset)*256)]) def big_2_small_endian(data): return binascii.hexlify(binascii.unhexlify(data)[::-1]) text_aes_128_1 = big_2_small_endian(text_aes_128_1) text_aes_128_2 = big_2_small_endian(text_aes_128_2) text_aes_128_3 = big_2_small_endian(text_aes_128_3) text_aes_128_4 = big_2_small_endian(text_aes_128_4) text_aes_128_5 = big_2_small_endian(text_aes_128_5) text_aes_128_6 = big_2_small_endian(text_aes_128_6) text_aes_128_7 = big_2_small_endian(text_aes_128_7) text_aes_128_8 = big_2_small_endian(text_aes_128_8) text_aes_128_9 = big_2_small_endian(text_aes_128_9) text_aes_128_10 = big_2_small_endian(text_aes_128_10) text_aes_128_11 = big_2_small_endian(text_aes_128_11) text_aes_128_12 = big_2_small_endian(text_aes_128_12) text_aes_128_13 = big_2_small_endian(text_aes_128_13) text_aes_128_14 = big_2_small_endian(text_aes_128_14) text_aes_128_15 = big_2_small_endian(text_aes_128_15) text_aes_128_16 = big_2_small_endian(text_aes_128_16) def str_2_ascii(string): string_hex = string.zfill(32) # print('string_hex value is:',string_hex) string_ascii = binascii.a2b_hex(string_hex) # print('string_ascii value is: ',string_ascii) return string_ascii def encrypt(key_ascii,text_ascii): # print('key_ascii value is :',key_ascii) # print('text_ascii value is:',text_ascii) mode = AES.MODE_ECB aes = AES.new(key_ascii,mode) en_text = aes.encrypt(text_ascii) # print('en_text value is:',en_text) # encrypt_data = b2a_hex(en_text) # print('encrypt value data is:',encrypt_data) return en_text #------------------------- Encryption Flow ---------------------- text = text_aes_128_1 text_ascii = str_2_ascii(text) #print('text_aes_1 text_ascii value is ',text_ascii) #print('text_aes_1 hex value is',b2a_hex(text_ascii)) key_ascii = str_2_ascii(key) encrypt_text_1 = encrypt(key_ascii,text_ascii) text = text_aes_128_2 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_2 = encrypt(key_ascii,text_ascii) text = text_aes_128_3 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_3 = encrypt(key_ascii,text_ascii) text = text_aes_128_4 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_4 = encrypt(key_ascii,text_ascii) text = text_aes_128_5 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_5 = encrypt(key_ascii,text_ascii) text = text_aes_128_6 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_6 = encrypt(key_ascii,text_ascii) text = text_aes_128_7 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_7 = encrypt(key_ascii,text_ascii) text = text_aes_128_8 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_8 = encrypt(key_ascii,text_ascii) text = text_aes_128_9 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_9 = encrypt(key_ascii,text_ascii) text = text_aes_128_10 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_10 = encrypt(key_ascii,text_ascii) text = text_aes_128_11 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_11 = encrypt(key_ascii,text_ascii) text = text_aes_128_12 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_12 = encrypt(key_ascii,text_ascii) text = text_aes_128_13 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_13 = encrypt(key_ascii,text_ascii) text = text_aes_128_14 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_14 = encrypt(key_ascii,text_ascii) text = text_aes_128_15 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_15 = encrypt(key_ascii,text_ascii) text = text_aes_128_16 text_ascii = str_2_ascii(text) #text_ascii = text key_ascii = str_2_ascii(key) encrypt_text_16 = encrypt(key_ascii,text_ascii) #---------------------------- Re-combine data ----------------------------- encrypt_text_1 = str_2_ascii((big_2_small_endian(b2a_hex(encrypt_text_1)))) encrypt_text_2 = str_2_ascii((big_2_small_endian(b2a_hex(encrypt_text_2)))) encrypt_text_3 = str_2_ascii((big_2_small_endian(b2a_hex(encrypt_text_3)))) encrypt_text_4 = str_2_ascii((big_2_small_endian(b2a_hex(encrypt_text_4)))) encrypt_text_5 = str_2_ascii((big_2_small_endian(b2a_hex(encrypt_text_5)))) encrypt_text_6 = str_2_ascii((big_2_small_endian(b2a_hex(encrypt_text_6)))) encrypt_text_7 = str_2_ascii((big_2_small_endian(b2a_hex(encrypt_text_7)))) encrypt_text_8 = str_2_ascii((big_2_small_endian(b2a_hex(encrypt_text_8)))) encrypt_text_9 = str_2_ascii((big_2_small_endian(b2a_hex(encrypt_text_9)))) encrypt_text_10 = str_2_ascii(big_2_small_endian((b2a_hex(encrypt_text_10)))) encrypt_text_11 = str_2_ascii(big_2_small_endian((b2a_hex(encrypt_text_11)))) encrypt_text_12 = str_2_ascii(big_2_small_endian((b2a_hex(encrypt_text_12)))) encrypt_text_13 = str_2_ascii(big_2_small_endian((b2a_hex(encrypt_text_13)))) encrypt_text_14 = str_2_ascii(big_2_small_endian((b2a_hex(encrypt_text_14)))) encrypt_text_15 = str_2_ascii(big_2_small_endian((b2a_hex(encrypt_text_15)))) encrypt_text_16 = str_2_ascii(big_2_small_endian((b2a_hex(encrypt_text_16)))) text_aes_new = text_aes[0:(0+int(offset)*256)].tobytes() \ + encrypt_text_1 \ + encrypt_text_2 \ + encrypt_text_3 \ + encrypt_text_4 \ + encrypt_text_5 \ + encrypt_text_6 \ + encrypt_text_7 \ + encrypt_text_8 \ + encrypt_text_9 \ + encrypt_text_10 \ + encrypt_text_11 \ + encrypt_text_12 \ + encrypt_text_13 \ + encrypt_text_14 \ + encrypt_text_15 \ + encrypt_text_16 \ + text_aes[(256+int(offset)*256):].tobytes() #---------------------------- Generate output files ----------------------------- iho = IntelHex() iho.frombytes(text_aes_new, image_start_addr) # keep start address (offset) unchanged # Output files name output_bin_file = os.path.splitext(input_hex_image_file)[0] + '_enc.bin' output_hex_file = os.path.splitext(input_hex_image_file)[0] + '_enc.hex' # Generate binrary output file try: iho.tobinfile(output_bin_file) except IOError: e = sys.exc_info()[1] # current exception print("ERROR: Could not write to file: %s: %s" % (output_bin_file, str(e))) sys.exit(1) # Generate Intel Hex output file try: # iho.start_addr = ihi.start_addr # keep start address (entry) unchanged iho.write_hex_file(output_hex_file) except IOError: e = sys.exc_info()[1] # current exception print("ERROR: Could not write to file: %s: %s" % (output_hex_file, str(e))) sys.exit(1) print("Output bin file: '{:s}'".format(output_bin_file)) print("Output hex file: '{:s}'".format(output_hex_file)) print('Image encryption finish!')