b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
| 3 | import argparse |
| 4 | import re |
| 5 | import struct |
| 6 | import subprocess |
| 7 | import zlib |
| 8 | |
| 9 | |
| 10 | def main(): |
| 11 | parser = argparse.ArgumentParser() |
| 12 | parser.add_argument('--input-file', type=str, required=True) |
| 13 | parser.add_argument('--output-file', type=str, required=True) |
| 14 | parser.add_argument('--model', type=str, required=True) |
| 15 | parser.add_argument('--region', type=str, required=True) |
| 16 | parser.add_argument('--version', type=str, required=True) |
| 17 | parser.add_argument('--hw-id-list', type=str) |
| 18 | parser.add_argument('--model-list', type=str) |
| 19 | parser.add_argument('--encryption-block-size', type=str, required=True) |
| 20 | parser.add_argument('--openssl-bin', type=str, required=True) |
| 21 | parser.add_argument('--key', type=str, required=True) |
| 22 | parser.add_argument('--iv', type=str, required=True) |
| 23 | args = parser.parse_args() |
| 24 | |
| 25 | assert re.match(r'V[0-9]\.[0-9]\.[0-9]\.[0-9]', |
| 26 | args.version), 'Version must start with Vx.x.x.x' |
| 27 | encryption_block_size = int(args.encryption_block_size, 0) |
| 28 | assert (encryption_block_size > 0 and encryption_block_size % 16 == |
| 29 | 0), 'Encryption block size must be a multiple of the AES block size (16)' |
| 30 | |
| 31 | hw_id_list = args.hw_id_list.split(';') if args.hw_id_list else [] |
| 32 | model_list = args.model_list.split(';') if args.model_list else [] |
| 33 | hw_info = ';'.join(hw_id_list + model_list) |
| 34 | |
| 35 | image = open(args.input_file, 'rb').read() |
| 36 | image_enc = [] |
| 37 | for i in range(0, len(image), encryption_block_size): |
| 38 | chunk = image[i:i + encryption_block_size] |
| 39 | chunk += b'\x00' * ((-len(chunk)) % 16) # pad to AES block size (16) |
| 40 | res = subprocess.run([ |
| 41 | args.openssl_bin, |
| 42 | 'enc', |
| 43 | '-aes-256-cbc', |
| 44 | '-nosalt', |
| 45 | '-nopad', |
| 46 | '-K', args.key, |
| 47 | '-iv', args.iv |
| 48 | ], |
| 49 | check=True, input=chunk, stdout=subprocess.PIPE) |
| 50 | image_enc.append(res.stdout) |
| 51 | image_enc = b''.join(image_enc) |
| 52 | |
| 53 | image_with_header = struct.pack( |
| 54 | '>32s32s64s64sIBBB13s200s100s12sII', |
| 55 | args.model.encode('ascii'), |
| 56 | args.region.encode('ascii'), |
| 57 | args.version.encode('ascii'), |
| 58 | b'Thu Jan 1 00:00:00 1970', # static date for reproducibility |
| 59 | 0, # product hw model |
| 60 | 0, # model index |
| 61 | len(hw_id_list), |
| 62 | len(model_list), |
| 63 | b'', # reserved |
| 64 | hw_info.encode('ascii'), |
| 65 | b'', # reserved |
| 66 | b'encrpted_img', |
| 67 | len(image_enc), |
| 68 | encryption_block_size, |
| 69 | ) + image_enc |
| 70 | |
| 71 | checksum = zlib.crc32(image_with_header, 0xffffffff) ^ 0xffffffff |
| 72 | |
| 73 | with open(args.output_file, 'wb') as outfile: |
| 74 | outfile.write(image_with_header) |
| 75 | outfile.write(struct.pack('>I', checksum)) |
| 76 | |
| 77 | |
| 78 | if __name__ == "__main__": |
| 79 | main() |