#!/usr/bin/env python3 ''' sign an ArduPilot APJ firmware with a private key ''' import sys import struct import json, base64, zlib try: import monocypher except ImportError: print("Please install monocypher with: python3 -m pip install pymonocypher") sys.exit(1) key_len = 32 sig_len = 64 sig_version = 30437 descriptor = b'\x41\xa3\xe5\xf2\x65\x69\x92\x07' if len(sys.argv) < 3: print("Usage: make_secure_fw.py APJ_FILE PRIVATE_KEYFILE") sys.exit(1) def to_unsigned(i): '''convert a possibly signed integer to unsigned''' if i < 0: i += 2**32 return i apj_file = sys.argv[1] key_file = sys.argv[2] # open apj file apj = open(apj_file, 'r').read() # decode json in apj d = json.loads(apj) # get image data img = zlib.decompress(base64.b64decode(d['image'])) img_len = len(img) def decode_key(ktype, key): ktype += "_KEYV1:" if not key.startswith(ktype): print("Invalid key type") sys.exit(1) return base64.b64decode(key[len(ktype):]) key = decode_key("PRIVATE", open(key_file, 'r').read()) if len(key) != key_len: print("Bad key length %u" % len(key)) sys.exit(1) offset = img.find(descriptor) if offset == -1: print("No APP_DESCRIPTOR found") sys.exit(1) offset += 8 desc_len = 92 flash1 = img[:offset] flash2 = img[offset+desc_len:] flash12 = flash1 + flash2 signature = monocypher.signature_sign(key, flash12) if len(signature) != sig_len: print("Bad signature length %u should be %u" % (len(signature), sig_len)) sys.exit(1) # pack signature in 4 bytes length, 8 byte signature version and 64 byte # signature. We have a signature version to allow for changes to signature # system in the future desc = struct.pack("