Argparse是 Python 标准库中推荐的命令行解析模块。该模块会自动生成提示信息,且在用户给程序传入非法参数时报错。

刚好最近在看optee的sign_encrypt.py,以它为例介绍python的argparse命令解析模块。

脚本参见:optee_os/scripts/sign_encrypt.py at master · OP-TEE/optee_os · GitHub

#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-2-Clause
#
# Copyright (c) 2015, 2017, 2019, Linaro Limited
#import sys
import mathsig_tee_alg = {'TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256': 0x70414930,'TEE_ALG_RSASSA_PKCS1_V1_5_SHA256': 0x70004830}enc_tee_alg = {'TEE_ALG_AES_GCM': 0x40000810}enc_key_type = {'SHDR_ENC_KEY_DEV_SPECIFIC': 0x0,'SHDR_ENC_KEY_CLASS_WIDE': 0x1}TEE_ATTR_RSA_MODULUS = 0xD0000130
TEE_ATTR_RSA_PUBLIC_EXPONENT = 0xD0000230SHDR_BOOTSTRAP_TA = 1
SHDR_ENCRYPTED_TA = 2
SHDR_SUBKEY = 3
SHDR_MAGIC = 0x4f545348
SHDR_SIZE = 20
SK_HDR_SIZE = 20
EHDR_SIZE = 12
UUID_SIZE = 16
# Use 12 bytes for nonce per recommendation
NONCE_SIZE = 12
TAG_SIZE = 16def value_to_key(db, val):for k, v in db.items():if v == val:return kdef uuid_v5_sha512(namespace_bytes, name):from cryptography.hazmat.primitives import hashesfrom uuid import UUIDh = hashes.Hash(hashes.SHA512())h.update(namespace_bytes + bytes(name, 'utf-8'))digest = h.finalize()return UUID(bytes=digest[:16], version=5)def name_img_to_str(name_img):return name_img.decode().split('\x00', 1)[0]def uuid_parse(s):from uuid import UUIDreturn UUID(s)def int_parse(str):return int(str, 0)def get_args():import argparseimport textwrapclass OnlyOne(argparse.Action):def __call__(self, parser, namespace, values, option_string=None):a = self.dest + '_assigned'if getattr(namespace, a, False):raise argparse.ArgumentError(self, 'Can only be given once')setattr(namespace, a, True)setattr(namespace, self.dest, values)def arg_add_uuid(parser):parser.add_argument('--uuid', required=True, type=uuid_parse,help='String UUID of the TA')def arg_add_key(parser):parser.add_argument('--key', required=True, help='''Name of signing and verification key file (PEM format) or anAmazon Resource Name (arn:) of an AWS KMS asymmetric key.At least public key for the commands digest, stitch, andverify, else a private key''')def arg_add_enc_key(parser):parser.add_argument('--enc-key', required=False, help='Encryption key string')def arg_add_enc_key_type(parser):parser.add_argument('--enc-key-type', required=False,default='SHDR_ENC_KEY_DEV_SPECIFIC',choices=list(enc_key_type.keys()), help='''Encryption key type,Defaults to SHDR_ENC_KEY_DEV_SPECIFIC.''')def arg_add_ta_version(parser):parser.add_argument('--ta-version', required=False, type=int_parse, default=0, help='''TA version stored as a 32-bit unsigned integer and used forrollback protection of TA install in the secure database.Defaults to 0.''')def arg_add_sig(parser):parser.add_argument('--sig', required=True, dest='sigf',help='Name of signature input file, defaults to <UUID>.sig')def arg_add_dig(parser):parser.add_argument('--dig', required=True, dest='digf',help='Name of digest output file, defaults to <UUID>.dig')def arg_add_in(parser):parser.add_argument('--in', required=False, dest='inf', help='''Name of application input file, defaults to<UUID>.stripped.elf''')def arg_add_out(parser):parser.add_argument('--out', required=True, dest='outf',help='Name of application output file, defaults to <UUID>.ta')def arg_add_algo(parser):parser.add_argument('--algo', required=False, choices=list(sig_tee_alg.keys()),default='TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256', help='''The hash and signature algorithm.Defaults to TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256.''')def arg_add_subkey(parser):parser.add_argument('--subkey', action=OnlyOne, help='Name of subkey input file')def arg_add_name(parser):parser.add_argument('--name',help='Input name for subspace of a subkey')def arg_add_subkey_uuid_in(parser):parser.add_argument('--in', required=True, dest='inf',help='Name of subkey input file')def arg_add_max_depth(parser):parser.add_argument('--max-depth', required=False, type=int_parse, help='''Max depth of subkeys below this subkey''')def arg_add_name_size(parser):parser.add_argument('--name-size', required=True, type=int_parse, help='''Size of (unsigned) input name for subspace of a subkey.Set to 0 to create an identity subkey (a subkey havingthe same UUID as the next subkey or TA)''')def arg_add_subkey_version(parser):parser.add_argument('--subkey-version', required=False, type=int_parse, default=0,help='Subkey version used for rollback protection')def arg_add_subkey_in(parser):parser.add_argument('--in', required=True, dest='inf', help='''Name of PEM file with the public key of the new subkey''')def arg_add_subkey_out(parser):parser.add_argument('--out', required=True, dest='outf',help='Name of subkey output file')def get_outf_default(parsed):return str(parsed.uuid) + '.ta'def get_inf_default(parsed):return str(parsed.uuid) + '.stripped.elf'def get_sigf_default(parsed):return str(parsed.uuid) + '.sig'def get_digf_default(parsed):return str(parsed.uuid) + '.dig'def assign_default_value(parsed, attr, func):if hasattr(parsed, attr) and getattr(parsed, attr) is None:setattr(parsed, attr, func(parsed))parser = argparse.ArgumentParser(description='Sign and encrypt (optional) a Trusted Application ' +' for OP-TEE.',usage='%(prog)s <command> ...',epilog='<command> -h for detailed help')subparsers = parser.add_subparsers(title='valid commands, with possible aliases in ()',dest='command', metavar='')parser_sign_enc = subparsers.add_parser('sign-enc', prog=parser.prog + ' sign-enc',help='Generate signed and optionally encrypted loadable TA image file')parser_sign_enc.set_defaults(func=command_sign_enc)arg_add_uuid(parser_sign_enc)arg_add_ta_version(parser_sign_enc)arg_add_in(parser_sign_enc)arg_add_out(parser_sign_enc)arg_add_key(parser_sign_enc)arg_add_subkey(parser_sign_enc)arg_add_name(parser_sign_enc)arg_add_enc_key(parser_sign_enc)arg_add_enc_key_type(parser_sign_enc)arg_add_algo(parser_sign_enc)parser_digest = subparsers.add_parser('digest', aliases=['generate-digest'], prog=parser.prog + ' digest',formatter_class=argparse.RawDescriptionHelpFormatter,help='Generate loadable TA binary image digest for offline signing',epilog=textwrap.dedent('''\example offline signing command using OpenSSL for algorithmTEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256:base64 -d <UUID>.dig | \\openssl pkeyutl -sign -inkey <KEYFILE>.pem \\-pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pss \\-pkeyopt rsa_pss_saltlen:digest \\-pkeyopt rsa_mgf1_md:sha256 | \\base64 > <UUID>.sigexample offline signing command using OpenSSL for algorithmTEE_ALG_RSASSA_PKCS1_V1_5_SHA256:base64 -d <UUID>.dig | \\openssl pkeyutl -sign -inkey <KEYFILE>.pem \\-pkeyopt digest:sha256 -pkeyopt rsa_padding_mode:pkcs1 | \\base64 > <UUID>.sig'''))parser_digest.set_defaults(func=command_digest)arg_add_uuid(parser_digest)arg_add_ta_version(parser_digest)arg_add_in(parser_digest)arg_add_key(parser_digest)arg_add_enc_key(parser_digest)arg_add_enc_key_type(parser_digest)arg_add_algo(parser_digest)arg_add_dig(parser_digest)parser_stitch = subparsers.add_parser('stitch', aliases=['stitch-ta'], prog=parser.prog + ' stich',help='Generate loadable signed and encrypted TA binary image file' +' from TA raw image and its signature')parser_stitch.set_defaults(func=command_stitch)arg_add_uuid(parser_stitch)arg_add_ta_version(parser_stitch)arg_add_in(parser_stitch)arg_add_key(parser_stitch)arg_add_out(parser_stitch)arg_add_enc_key(parser_stitch)arg_add_enc_key_type(parser_stitch)arg_add_algo(parser_stitch)arg_add_sig(parser_stitch)parser_verify = subparsers.add_parser('verify', prog=parser.prog + ' verify',help='Verify signed TA binary')parser_verify.set_defaults(func=command_verify)arg_add_uuid(parser_verify)arg_add_in(parser_verify)arg_add_key(parser_verify)parser_display = subparsers.add_parser('display', prog=parser.prog + ' display',help='Parses and displays a signed TA binary')parser_display.set_defaults(func=command_display)arg_add_in(parser_display)parser_subkey_uuid = subparsers.add_parser('subkey-uuid', prog=parser.prog + ' subkey-uuid',help='calculate the UUID of next TA or subkey')parser_subkey_uuid.set_defaults(func=command_subkey_uuid)arg_add_subkey_uuid_in(parser_subkey_uuid)arg_add_name(parser_subkey_uuid)parser_sign_subkey = subparsers.add_parser('sign-subkey', prog=parser.prog + ' sign-subkey',help='Sign a subkey')parser_sign_subkey.set_defaults(func=command_sign_subkey)arg_add_name(parser_sign_subkey)arg_add_subkey_in(parser_sign_subkey)arg_add_uuid(parser_sign_subkey)arg_add_key(parser_sign_subkey)arg_add_subkey_out(parser_sign_subkey)arg_add_max_depth(parser_sign_subkey)arg_add_name_size(parser_sign_subkey)arg_add_subkey(parser_sign_subkey)arg_add_subkey_version(parser_sign_subkey)arg_add_algo(parser_sign_subkey)argv = sys.argv[1:]if (len(argv) > 0 and argv[0][0] == '-' andargv[0] != '-h' and argv[0] != '--help'):# The default sub-command is 'sign-enc' so add it to the parser# if one is missingargv = ['sign-enc'] + argvparsed = parser.parse_args(argv)if parsed.command is None:parser.print_help()sys.exit(1)# Set a few defaults if defined for the current commandassign_default_value(parsed, 'inf', get_inf_default)assign_default_value(parsed, 'outf', get_outf_default)assign_default_value(parsed, 'sigf', get_sigf_default)assign_default_value(parsed, 'digf', get_digf_default)return parseddef load_asymmetric_key_img(data):from cryptography.hazmat.backends import default_backendfrom cryptography.hazmat.primitives.serialization import (load_pem_private_key, load_pem_public_key)try:return load_pem_private_key(data, password=None,backend=default_backend())except ValueError:return load_pem_public_key(data, backend=default_backend())def load_asymmetric_key(arg_key):if arg_key.startswith('arn:'):from sign_helper_kms import _RSAPrivateKeyInKMSreturn _RSAPrivateKeyInKMS(arg_key)else:with open(arg_key, 'rb') as f:return load_asymmetric_key_img(f.read())class BinaryImage:def __init__(self, arg_inf, arg_key):from cryptography.hazmat.primitives import hashes# Exactly what inf is holding isn't determined a this stageif isinstance(arg_inf, str):with open(arg_inf, 'rb') as f:self.inf = f.read()else:self.inf = arg_infif arg_key is None:self.key = Noneelse:if isinstance(arg_key, str):self.key = load_asymmetric_key(arg_key)else:self.key = arg_keyself.sig_size = math.ceil(self.key.key_size / 8)self.chosen_hash = hashes.SHA256()self.hash_size = self.chosen_hash.digest_sizedef __pack_img(self, img_type, sign_algo):import structself.sig_algo = sign_algoself.img_type = img_typeself.shdr = struct.pack('<IIIIHH', SHDR_MAGIC, img_type, len(self.img),sig_tee_alg[sign_algo], self.hash_size,self.sig_size)def __calc_digest(self):from cryptography.hazmat.backends import default_backendfrom cryptography.hazmat.primitives import hashesh = hashes.Hash(self.chosen_hash, default_backend())h.update(self.shdr)if hasattr(self, 'ta_uuid'):h.update(self.ta_uuid)h.update(self.ta_version)if hasattr(self, 'ehdr'):h.update(self.ehdr)h.update(self.nonce)h.update(self.tag)h.update(self.img)return h.finalize()def encrypt_ta(self, enc_key, key_type, sig_algo, uuid, ta_version):from cryptography.hazmat.primitives.ciphers.aead import AESGCMimport structimport osself.img = self.infcipher = AESGCM(bytes.fromhex(enc_key))self.nonce = os.urandom(NONCE_SIZE)out = cipher.encrypt(self.nonce, self.img, None)self.ciphertext = out[:-TAG_SIZE]# Authentication Tag is always the last bytesself.tag = out[-TAG_SIZE:]enc_algo = enc_tee_alg['TEE_ALG_AES_GCM']flags = enc_key_type[key_type]self.ehdr = struct.pack('<IIHH', enc_algo, flags, len(self.nonce),len(self.tag))self.__pack_img(SHDR_ENCRYPTED_TA, sig_algo)self.ta_uuid = uuid.bytesself.ta_version = struct.pack('<I', ta_version)self.img_digest = self.__calc_digest()def set_bootstrap_ta(self, sig_algo, uuid, ta_version):import structself.img = self.infself.__pack_img(SHDR_BOOTSTRAP_TA, sig_algo)self.ta_uuid = uuid.bytesself.ta_version = struct.pack('<I', ta_version)self.img_digest = self.__calc_digest()def set_subkey(self, sign_algo, name, uuid, subkey_version, max_depth,name_size):from cryptography.hazmat.primitives.asymmetric import rsaimport structself.subkey_name = namesubkey_key = load_asymmetric_key_img(self.inf)if isinstance(subkey_key, rsa.RSAPrivateKey):subkey_pkey = subkey_key.public_key()else:subkey_pkey = subkey_keyif max_depth is None:if hasattr(self, 'previous_max_depth'):if self.previous_max_depth <= 0:logger.error('Max depth of previous subkey is {}, '.format(self.previous_max_depth) +'cannot use a smaller value')sys.exit(1)max_depth = self.previous_max_depth - 1else:max_depth = 0else:if (hasattr(self, 'previous_max_depth') andmax_depth >= getattr(self, 'previous_max_depth')):logger.error('Max depth of previous subkey is {} '.format(self.previous_max_depth) +'and the next value must be smaller')sys.exit(1)def int_to_bytes(x: int) -> bytes:return x.to_bytes((x.bit_length() + 8) // 8, 'big')n_bytes = int_to_bytes(subkey_pkey.public_numbers().n)e_bytes = int_to_bytes(subkey_pkey.public_numbers().e)attrs_end_offs = 16 + 5 * 4 + 2 * 3 * 4shdr_subkey = struct.pack('<IIIIIIIIIII',name_size, subkey_version,max_depth, sig_tee_alg[sign_algo], 2,TEE_ATTR_RSA_MODULUS,attrs_end_offs, len(n_bytes),TEE_ATTR_RSA_PUBLIC_EXPONENT,attrs_end_offs + len(n_bytes),len(e_bytes))self.img = uuid.bytes + shdr_subkey + n_bytes + e_bytesself.__pack_img(SHDR_SUBKEY, sign_algo)self.img_digest = self.__calc_digest()def parse(self):from cryptography.hazmat.primitives.asymmetric import rsaimport structoffs = 0self.shdr = self.inf[offs:offs + SHDR_SIZE][magic, img_type, img_size, algo_value, hash_size,sig_size] = struct.unpack('<IIIIHH', self.shdr)offs += SHDR_SIZEif magic != SHDR_MAGIC:raise Exception("Unexpected magic: 0x{:08x}".format(magic))if algo_value not in sig_tee_alg.values():raise Exception('Unrecognized algorithm: 0x{:08x}'.format(algo_value))self.sig_algo = value_to_key(sig_tee_alg, algo_value)if hash_size != self.hash_size:raise Exception("Unexpected digest len: {}".format(hash_size))self.img_digest = self.inf[offs:offs + hash_size]offs += hash_sizeself.sig = self.inf[offs:offs + sig_size]offs += sig_sizeif img_type == SHDR_BOOTSTRAP_TA or img_type == SHDR_ENCRYPTED_TA:self.ta_uuid = self.inf[offs:offs + UUID_SIZE]offs += UUID_SIZEself.ta_version = self.inf[offs:offs + 4]offs += 4if img_type == SHDR_ENCRYPTED_TA:self.ehdr = self.inf[offs: offs + EHDR_SIZE]offs += EHDR_SIZE[enc_algo, flags, nonce_len,tag_len] = struct.unpack('<IIHH', self.ehdr)if enc_value not in enc_tee_alg.values():raise Exception('Unrecognized encrypt algorithm: 0x{:08x}'.format(enc_value))if nonce_len != 12:raise Exception("Unexpected nonce len: {}".format(nonce_len))self.nonce = self.inf[offs:offs + nonce_len]offs += nonce_lenif tag_len != 16:raise Exception("Unexpected tag len: {}".format(tag_len))self.tag = self.inf[-tag_len:]self.ciphertext = self.inf[offs:-tag_len]if len(self.ciphertext) != img_size:raise Exception("Unexpected ciphertext size: ","got {}, expected {}".format(len(self.ciphertext), img_size))self.img = self.ciphertextelse:self.img = self.inf[offs:]if len(self.img) != img_size:raise Exception("Unexpected img size: got {}, expected {}".format(len(self.img), img_size))elif img_type == SHDR_SUBKEY:subkey_offs = offsself.uuid = self.inf[offs:offs + UUID_SIZE]offs += UUID_SIZEself.subkey_hdr = self.inf[offs:offs + SK_HDR_SIZE][self.name_size, self.subkey_version, self.max_depth, self.algo,self.attr_count] = struct.unpack('<IIIII', self.subkey_hdr)offs += len(self.subkey_hdr)self.attr = self.inf[offs:offs + img_size -UUID_SIZE - len(self.subkey_hdr)]offs += len(self.attr)self.name_img = self.inf[offs:offs + self.name_size]offs += self.name_sizeself.next_inf = self.inf[offs:]def find_attr(attr):if self.attr_count <= 0:return Nonefor n in range(self.attr_count):o = subkey_offs + UUID_SIZE + SK_HDR_SIZE + n * 12[attr_value, attr_offs,attr_len] = struct.unpack('<III', self.inf[o: o + 12])if attr_value == attr:o = subkey_offs + attr_offsreturn self.inf[o:o + attr_len]return Nonen_bytes = find_attr(TEE_ATTR_RSA_MODULUS)e_bytes = find_attr(TEE_ATTR_RSA_PUBLIC_EXPONENT)e = int.from_bytes(e_bytes, 'big')n = int.from_bytes(n_bytes, 'big')self.subkey_key = rsa.RSAPublicNumbers(e, n).public_key()self.img = self.inf[subkey_offs:offs - self.name_size]if len(self.img) != img_size:raise Exception("Unexpected img size: got {}, expected {}".format(len(self.img), img_size))else:raise Exception("Unsupported image type: {}".format(img_type))def display(self):import binasciiimport structimport uuiddef display_ta():nonlocal offsta_uuid = self.inf[offs:offs + UUID_SIZE]print(' struct shdr_bootstrap_ta')print('  uuid:       {}'.format(uuid.UUID(bytes=ta_uuid)))offs += UUID_SIZE[ta_version] = struct.unpack('<I', self.inf[offs:offs + 4])print('  ta_version: {}'.format(ta_version))offs += 4if img_type == SHDR_ENCRYPTED_TA:ehdr = self.inf[offs: offs + EHDR_SIZE]offs += EHDR_SIZE[enc_algo, flags, nonce_len,tag_len] = struct.unpack('<IIHH', ehdr)print(' struct shdr_encrypted_ta')enc_algo_name = 'Unkown'if enc_algo in enc_tee_alg.values():enc_algo_name = value_to_key(enc_tee_alg, enc_algo)print('  enc_algo:   0x{:08x} ({})'.format(enc_algo, enc_algo_name))if enc_algo not in enc_tee_alg.values():raise Exception('Unrecognized encrypt algorithm: 0x{:08x}'.format(enc_value))flags_name = 'Unkown'if flags in enc_key_type.values():flags_name = value_to_key(enc_key_type, flags)print('  flags:      0x{:x} ({})'.format(flags, flags_name))print('  iv_size:    {} (bytes)'.format(nonce_len))if nonce_len != NONCE_SIZE:raise Exception("Unexpected nonce len: {}".format(nonce_len))nonce = self.inf[offs:offs + nonce_len]print('  iv:         {}'.format(binascii.hexlify(nonce).decode('ascii')))offs += nonce_lenprint('  tag_size:   {} (bytes)'.format(tag_len))if tag_len != TAG_SIZE:raise Exception("Unexpected tag len: {}".format(tag_len))tag = self.inf[-tag_len:]print('  tag:        {}'.format(binascii.hexlify(tag).decode('ascii')))ciphertext = self.inf[offs:-tag_len]print(' TA offset:  {} (0x{:x}) bytes'.format(offs, offs))print(' TA size:    {} (0x{:x}) bytes'.format(len(ciphertext), len(ciphertext)))if len(ciphertext) != img_size:raise Exception("Unexpected ciphertext size: ","got {}, expected {}".format(len(ciphertext), img_size))offs += tag_lenelse:img = self.inf[offs:]print(' TA offset:  {} (0x{:x}) bytes'.format(offs, offs))print(' TA size:    {} (0x{:x}) bytes'.format(len(img), len(img)))if len(img) != img_size:raise Exception("Unexpected img size: got {}, expected {}".format(len(img), img_size))offs += img_sizeoffs = 0while offs < len(self.inf):if offs > 0:# name_size is the previous subkey headername_img = self.inf[offs:offs + name_size]print('  next name:  "{}"'.format(name_img_to_str(name_img)))offs += name_sizeprint('Next header at offset: {} (0x{:x})'.format(offs, offs))shdr = self.inf[offs:offs + SHDR_SIZE][magic, img_type, img_size, algo_value, hash_size,sig_size] = struct.unpack('<IIIIHH', shdr)offs += SHDR_SIZEif magic != SHDR_MAGIC:Exception("Unexpected magic: 0x{:08x}".format(magic))img_type_name = 'Unknown'if img_type == SHDR_BOOTSTRAP_TA:print('Bootstrap TA')img_type_name = 'SHDR_BOOTSTRAP_TA'if img_type == SHDR_ENCRYPTED_TA:print('Encrypted TA')img_type_name = 'SHDR_ENCRYPTED_TA'if img_type == SHDR_SUBKEY:print('Subkey')img_type_name = 'SHDR_SUBKEY'algo_name = 'Unknown'if algo_value in sig_tee_alg.values():algo_name = value_to_key(sig_tee_alg, algo_value)print(' struct shdr')print('  magic:      0x{:08x}'.format(magic))print('  img_type:   {} ({})'.format(img_type, img_type_name))print('  img_size:   {} bytes'.format(img_size))print('  algo:       0x{:08x} ({})'.format(algo_value, algo_name))print('  hash_size:  {} bytes'.format(hash_size))print('  sig_size:   {} bytes'.format(sig_size))if algo_value not in sig_tee_alg.values():raise Exception('Unrecognized algorithm: 0x{:08x}'.format(algo_value))if hash_size != self.hash_size:raise Exception("Unexpected digest len: {}".format(hash_size))img_digest = self.inf[offs:offs + hash_size]print('  hash:       {}'.format(binascii.hexlify(img_digest).decode('ascii')))offs += hash_sizesig = self.inf[offs:offs + sig_size]offs += sig_sizeif img_type == SHDR_BOOTSTRAP_TA or img_type == SHDR_ENCRYPTED_TA:display_ta()elif img_type == SHDR_SUBKEY:img_uuid = self.inf[offs:offs + UUID_SIZE]img_subkey = self.inf[offs + UUID_SIZE:offs + UUID_SIZE + SK_HDR_SIZE][name_size, subkey_version, max_depth, algo,attr_count] = struct.unpack('<IIIII', img_subkey)if algo not in sig_tee_alg.values():raise Exception('Unrecognized algorithm: 0x{:08x}'.format(algo))algo_name = value_to_key(sig_tee_alg, algo)print(' struct shdr_subkey')print('  uuid:       {}'.format(uuid.UUID(bytes=img_uuid)))print('  name_size:  {}'.format(name_size))print('  subkey_version: {}'.format(subkey_version))print('  max_depth:  {}'.format(max_depth))print('  algo:       0x{:08x} ({})'.format(algo, algo_name))print('  attr_count: {}'.format(attr_count))offs += img_sizeelse:raise Exception("Unsupported image type: {}".format(img_type))def decrypt_ta(enc_key):from cryptography.hazmat.primitives.ciphers.aead import AESGCMcipher = AESGCM(bytes.fromhex(enc_key))self.img = cipher.decrypt(self.nonce, self.ciphertext, None)def __get_padding(self):from cryptography.hazmat.primitives.asymmetric import paddingif self.sig_algo == 'TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256':pad = padding.PSS(mgf=padding.MGF1(self.chosen_hash),salt_length=self.hash_size)elif self.sig_algo == 'TEE_ALG_RSASSA_PKCS1_V1_5_SHA256':pad = padding.PKCS1v15()return paddef sign(self):from cryptography.hazmat.primitives.asymmetric import utilsfrom cryptography.hazmat.primitives.asymmetric import rsaif not isinstance(self.key, rsa.RSAPrivateKey):logger.error('Provided key cannot be used for signing, ' +'please use offline-signing mode.')sys.exit(1)else:self.sig = self.key.sign(self.img_digest, self.__get_padding(),utils.Prehashed(self.chosen_hash))if len(self.sig) != self.sig_size:raise Exception(("Actual signature length is not equal to ","the computed one: {} != {}").format(len(self.sig), self.sig_size))def add_signature(self, sigf):import base64with open(sigf, 'r') as f:self.sig = base64.b64decode(f.read())if len(self.sig) != self.sig_size:raise Exception(("Actual signature length is not equal to ","the expected one: {} != {}").format(len(self.sig), self.sig_size))def verify_signature(self):from cryptography.hazmat.primitives.asymmetric import utilsfrom cryptography.hazmat.primitives.asymmetric import rsafrom cryptography import exceptionsif isinstance(self.key, rsa.RSAPrivateKey):pkey = self.key.public_key()else:pkey = self.keytry:pkey.verify(self.sig, self.img_digest, self.__get_padding(),utils.Prehashed(self.chosen_hash))except exceptions.InvalidSignature:logger.error('Verification failed, ignoring given signature.')sys.exit(1)def verify_digest(self):if self.img_digest != self.__calc_digest():raise Exception('Hash digest does not match')def verify_uuid(self, uuid):if self.ta_uuid != uuid.bytes:raise Exception('UUID does not match')def add_subkey(self, subkey_file, name):sk_image = BinaryImage(subkey_file, None)self.subkey_img = sk_image.infsk_image.parse()if not hasattr(sk_image, 'next_inf'):logger.error('Invalid subkey file')sys.exit(1)while len(sk_image.next_inf) > 0:sk_image = BinaryImage(sk_image.next_inf, None)sk_image.parse()if name is None:name = ''self.previous_max_depth = sk_image.max_depthself.name_img = str.encode(name).ljust(sk_image.name_size, b'\0')def write(self, outf):with open(outf, 'wb') as f:if hasattr(self, 'subkey_img'):f.write(self.subkey_img)f.write(self.name_img)f.write(self.shdr)f.write(self.img_digest)f.write(self.sig)if hasattr(self, 'ta_uuid'):f.write(self.ta_uuid)f.write(self.ta_version)if hasattr(self, 'ehdr'):f.write(self.ehdr)f.write(self.nonce)f.write(self.tag)f.write(self.ciphertext)else:f.write(self.img)def load_ta_image(args):ta_image = BinaryImage(args.inf, args.key)if args.enc_key:ta_image.encrypt_ta(args.enc_key, args.enc_key_type,args.algo, args.uuid, args.ta_version)else:ta_image.set_bootstrap_ta(args.algo, args.uuid, args.ta_version)return ta_imagedef command_sign_enc(args):ta_image = load_ta_image(args)if args.subkey:ta_image.add_subkey(args.subkey, args.name)ta_image.sign()ta_image.write(args.outf)logger.info('Successfully signed application.')def command_sign_subkey(args):image = BinaryImage(args.inf, args.key)if args.subkey:image.add_subkey(args.subkey, args.name)image.set_subkey(args.algo, args.name, args.uuid, args.subkey_version,args.max_depth, args.name_size)image.sign()image.write(args.outf)logger.info('Successfully signed subkey.')def command_digest(args):import base64ta_image = load_ta_image(args)with open(args.digf, 'wb+') as digfile:digfile.write(base64.b64encode(ta_image.img_digest))def command_stitch(args):ta_image = load_ta_image(args)ta_image.add_signature(args.sigf)ta_image.verify_signature()ta_image.write(args.outf)logger.info('Successfully applied signature.')def command_verify(args):import uuidimage = BinaryImage(args.inf, args.key)next_uuid = Nonemax_depth = -1while True:image.parse()if hasattr(image, 'subkey_hdr'):  # Subkeyprint('Subkey UUID: {}'.format(uuid.UUID(bytes=image.uuid)))image.verify_signature()image.verify_digest()if next_uuid:if uuid.UUID(bytes=image.uuid) != next_uuid:raise Exception('UUID {} does not match {}'.format(uuid.UUID(bytes=image.uuid),next_uuid))if max_depth >= 0:if image.max_depth < 0 or image.max_depth >= max_depth:raise Exception('Invalid max_depth {} not less than {}'.format(image.max_depth, max_depth))max_depth = image.max_depthif len(image.next_inf) == 0:logger.info('Subkey is correctly verified.')returnif image.name_size > 0:next_uuid = uuid_v5_sha512(image.uuid,name_img_to_str(image.name_img))else:next_uuid = image.uuidimage = BinaryImage(image.next_inf, image.subkey_key)else:  # TAprint('TA UUID: {}'.format(uuid.UUID(bytes=image.ta_uuid)))if next_uuid:if uuid.UUID(bytes=image.ta_uuid) != next_uuid:raise Exception('UUID {} does not match {}'.format(uuid.UUID(bytes=image.ta_uuid),next_uuid))if hasattr(image, 'ciphertext'):if args.enc_key is None:logger.error('--enc_key needed to decrypt TA')sys.exit(1)image.decrypt_ta(args.enc_key)image.verify_signature()image.verify_digest()image.verify_uuid(args.uuid)logger.info('Trusted application is correctly verified.')returndef command_display(args):ta_image = BinaryImage(args.inf, None)ta_image.display()def command_subkey_uuid(args):import uuidsk_image = BinaryImage(args.inf, None)sk_image.parse()if not hasattr(sk_image, 'next_inf'):logger.error('Invalid subkey file')sys.exit(1)print('Subkey UUID: {}'.format(uuid.UUID(bytes=sk_image.uuid)))while len(sk_image.next_inf) > 0:sk_image = BinaryImage(sk_image.next_inf, None)sk_image.parse()print('Subkey UUID: {}'.format(uuid.UUID(bytes=sk_image.uuid)))if args.name:if len(args.name) > sk_image.name_size:logger.error('Length of name ({}) '.format(len(args.name)) +'is larger than max name size ({})'.format(sk_image.name_size))sys.exit(1)print('Next subkey UUID: {}'.format(uuid_v5_sha512(sk_image.uuid, args.name)))else:print('Next subkey UUID unchanged: {}'.format(uuid.UUID(bytes=sk_image.uuid)))def main():import loggingimport osglobal loggerlogging.basicConfig()logger = logging.getLogger(os.path.basename(__file__))args = get_args()args.func(args)if __name__ == "__main__":main()

一、一些基本用法使用示例

1、创建ArgumentParser解析器对象

parser = argparse.ArgumentParser(description='Sign and encrypt (optional) a Trusted Application ' +' for OP-TEE.',usage='%(prog)s <command> ...',epilog='<command> -h for detailed help')

ArgumentParser 对象的参数有:

prog -- 程序的名称(默认:sys.argv[0])
usage -- 描述程序用途的字符串(默认值:从添加到解析器的参数生成)
description -- 在参数帮助文档之前显示的文本(默认值:无)。这个参数简要描述这个程序做什么以及怎么做。
epilog -- 在参数帮助文档之后显示的文本(默认值:无)
parents -- 一个 ArgumentParser 对象的列表,它们的参数也应包含在内
formatter_class -- 用于自定义帮助文档输出格式的类
prefix_chars -- 可选参数的前缀字符集合(默认值:’-’)
fromfile_prefix_chars -- 当需要从文件中读取其他参数时,用于标识文件名的前缀字符集合(默认值:None)
argument_default -- 参数的全局默认值(默认值: None)
conflict_handler -- 解决冲突选项的策略(通常是不必要的)
add_help -- 为解析器添加一个 -h/--help 选项(默认值: True)
allow_abbrev -- 如果缩写是无歧义的,则允许缩写长选项 (默认值:True)

exit_on_error -- 确定发生错误时 ArgumentParser 是否退出并显示错误信息

2、调用add_argument() 方法添加参数

添加参数是由add_argument() 方法完成的,它指定 ArgumentParser对象如何获取命令行字符串并将其转换为对象。这些信息将会在 parse_args() 调用时被存储和使用。例如:

    def arg_add_uuid(parser):parser.add_argument('--uuid', required=True, type=uuid_parse,help='String UUID of the TA')def arg_add_key(parser):parser.add_argument('--key', required=True, help='''Name of signing and verification key file (PEM format) or anAmazon Resource Name (arn:) of an AWS KMS asymmetric key.At least public key for the commands digest, stitch, andverify, else a private key''')def arg_add_enc_key(parser):parser.add_argument('--enc-key', required=False, help='Encryption key string')def arg_add_enc_key_type(parser):parser.add_argument('--enc-key-type', required=False,default='SHDR_ENC_KEY_DEV_SPECIFIC',choices=list(enc_key_type.keys()), help='''Encryption key type,Defaults to SHDR_ENC_KEY_DEV_SPECIFIC.''')def arg_add_ta_version(parser):parser.add_argument('--ta-version', required=False, type=int_parse, default=0, help='''TA version stored as a 32-bit unsigned integer and used forrollback protection of TA install in the secure database.Defaults to 0.''')def arg_add_sig(parser):parser.add_argument('--sig', required=True, dest='sigf',help='Name of signature input file, defaults to <UUID>.sig')def arg_add_dig(parser):parser.add_argument('--dig', required=True, dest='digf',help='Name of digest output file, defaults to <UUID>.dig')def arg_add_in(parser):parser.add_argument('--in', required=False, dest='inf', help='''Name of application input file, defaults to<UUID>.stripped.elf''')def arg_add_out(parser):parser.add_argument('--out', required=True, dest='outf',help='Name of application output file, defaults to <UUID>.ta')def arg_add_algo(parser):parser.add_argument('--algo', required=False, choices=list(sig_tee_alg.keys()),default='TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256', help='''The hash and signature algorithm.Defaults to TEE_ALG_RSASSA_PKCS1_PSS_MGF1_SHA256.''')def arg_add_subkey(parser):parser.add_argument('--subkey', action=OnlyOne, help='Name of subkey input file')def arg_add_name(parser):parser.add_argument('--name',help='Input name for subspace of a subkey')def arg_add_subkey_uuid_in(parser):parser.add_argument('--in', required=True, dest='inf',help='Name of subkey input file')def arg_add_max_depth(parser):parser.add_argument('--max-depth', required=False, type=int_parse, help='''Max depth of subkeys below this subkey''')def arg_add_name_size(parser):parser.add_argument('--name-size', required=True, type=int_parse, help='''Size of (unsigned) input name for subspace of a subkey.Set to 0 to create an identity subkey (a subkey havingthe same UUID as the next subkey or TA)''')def arg_add_subkey_version(parser):parser.add_argument('--subkey-version', required=False, type=int_parse, default=0,help='Subkey version used for rollback protection')def arg_add_subkey_in(parser):parser.add_argument('--in', required=True, dest='inf', help='''Name of PEM file with the public key of the new subkey''')def arg_add_subkey_out(parser):parser.add_argument('--out', required=True, dest='outf',help='Name of subkey output file')

3、使用 parse_args() 解析添加的参数

parse_args() 方法检查命令行,把每个参数转换为适当的类型然后调用相应的操作。

parsed = parser.parse_args(argv)if parsed.command is None:parser.print_help()sys.exit(1)

4、使用add_subparsers()方法去创建子命令

功能比较多的命令端程序常常将功能分解到不同子命令中。

subparsers = parser.add_subparsers(title='valid commands, with possible aliases in ()',dest='command', metavar='')

5、使用add_parser添加子命令

parser_sign_enc = subparsers.add_parser('sign-enc', prog=parser.prog + ' sign-enc',help='Generate signed and optionally encrypted loadable TA image file')arg_add_uuid(parser_sign_enc)
arg_add_ta_version(parser_sign_enc)
arg_add_in(parser_sign_enc)
arg_add_out(parser_sign_enc)
arg_add_key(parser_sign_enc)
arg_add_subkey(parser_sign_enc)
arg_add_name(parser_sign_enc)
arg_add_enc_key(parser_sign_enc)
arg_add_enc_key_type(parser_sign_enc)
arg_add_algo(parser_sign_enc)

6、使用set_defaults()绑定子命令默认函数

argparse提供了一个一个方法set_defaults(),可以将子命令绑定特定的函数。

parser_sign_enc.set_defaults(func=command_sign_enc)

综上,sign_encrypt.py脚本有以下8个子命令,对应8个功能点:

sign-enc、digest、stitch、verify、display、subkey_uuid、sign_subkey

即:

$python3 sign_encrypt.py -h
usage: sign_encrypt.py <command> ...Sign and encrypt (optional) a Trusted Application for OP-TEE.options:-h, --help            show this help message and exitvalid commands, with possible aliases in ():sign-enc            Generate signed and optionally encrypted loadable TA image filedigest (generate-digest)Generate loadable TA binary image digest for offline signingstitch (stitch-ta)  Generate loadable signed and encrypted TA binary image file from TA raw image and its signatureverify              Verify signed TA binarydisplay             Parses and displays a signed TA binarysubkey-uuid         calculate the UUID of next TA or subkeysign-subkey         Sign a subkey<command> -h for detailed help

二、参考资料

Argparse 教程 — Python 3.11.4 文档

以optee的sign_encrypt.py为例讲解argparse命令解析模块相关推荐

  1. 操作系统之进程调度——优先权法和轮转法(附上样例讲解)

    操作系统之进程调度--优先权法和轮转法(附上样例讲解) 操作系统之银行家算法-详解流程及案例数据 操作系统之多线程编程-读者优先/写者优先详解 操作系统之存储管理--FIFO算法和LRU算法 操作系统 ...

  2. 优化算法求解复杂约束问题策略(以粒子群算法为例讲解求解复杂约束问题的多种策略)

    优化算法求解复杂约束问题策略(以粒子群算法为例讲解求解复杂约束问题的多种策略)python实现     整个代码文字讲解共17页 提示:专栏解锁后,可以查看该专栏所有文章. 文章目录 策略1:在位置更 ...

  3. ncl如何添加线shp文件_NCL画图个例讲解.pdf

    NCL画图个例讲解 Example 1--XY plots 这个例子介绍了NCL 的基础知识,例如如何开始和结束NCL 脚本,如何创 建和初始化变量,如何创建和绘制XY 坐标图,以及如何设置resou ...

  4. 以VS2017配置fftw 64位为例讲解如何调用第三方库

    最近在使用github上很多项目,然后就会需要配很多依赖包,很多第三方库需要加载进来,以前也经常配一些环境,但是都是看着网上的大佬们的教程一步一步走下来的,只知其然而不知其所以然,这次就配置就遇见了很 ...

  5. php连接数据库比jdbc连接哪个好,MySQL_MySQL为例讲解JDBC数据库连接步骤,1、什么是JDBC?有什么作用? - phpStudy...

    MySQL为例讲解JDBC数据库连接步骤 1.什么是JDBC?有什么作用? Java Data Base Connectivity Java数据库连接协议 是一种用于执行SQL语句的Java API, ...

  6. GNSS控制网数据处理教程-以Trimble Business Center 5.0(TBC)为例讲解

    Trimble Business Center 5.0(TBC)越来越符合国内的规范标准(报表),处理能力强,学习一个容易的,工程上不落伍的GPS数据处理工具软件. 视频教学内容: 题目:GNSS控制 ...

  7. antvg2 环图轮播_在vue项目中引用Antv G2,以饼图为例讲解

    我就废话不多说了,大家还是直接看代码吧~ npm install @antv/g2 --save template内容: js部分: ​//引入G2组件 import G2 from "@a ...

  8. Py之argparse:Python库之argparse(命令行解析)简介、安装、使用方法之详细攻略

    Py之argparse:Python库之argparse(命令行解析)简介.安装.使用方法之详细攻略 导读 python中的命令行解析最简单最原始的方法是使用sys.argv来实现,更高级的可以使用a ...

  9. 简单实例讲解linux的module模块编译步骤

    简单实例讲解linux的module模块编译步骤 (2014-10-24 10:19:17) 标签: module linux 分类:Linux/Unix 本文将直接了当的带你进入linux的模块编译 ...

最新文章

  1. python 框架好学吗-python的flask框架难学吗
  2. linux运维、架构之路-MySQL(一)
  3. opencv 通过标定摄像头测量物体大小_视觉激光雷达信息融合与联合标定
  4. 怎样快速识别 英文地址中包含非英文字符_[论文笔记]端到端的场景文本识别算法--CRNN 论文笔记...
  5. webase crud查看所有表_Laravel-Gii 可视化代码生成工具 CRUD +GUI
  6. 董明珠:格力100%不会爆雷 爆雷的白马股不是真正白马股
  7. 【Unity开源项目精选】UniRx:Unity中的响应式编程
  8. java 经典免费教程下载
  9. 解决Lost connection to MySQL server at 'reading initial communication packet', 的方法
  10. 【VRP】基于matlab蚁群算法求解多配送中心的车辆调度问题【含Matlab源码 1098期】
  11. 面试题之GC垃圾回收算法
  12. 盘点一下 在Python中安装包的三种方法
  13. c++字符串逆序输出
  14. HTML两张图片翻转,canvas实现图片镜像翻转的2种方式
  15. SAS首席科学家:如何选择机器学习算法?
  16. 解决Chrome“此网页正试图从未经验证的来源加载脚本”的问题
  17. 理解套间(涉及进程、线程、COM线程模型)(转载)
  18. Python3输出格式化时间yyyy-mm-dd HH:MM:SS
  19. 2019年 十款Mac上必备的实用软件列表
  20. shell sftp 命令大全

热门文章

  1. android7.1 msm8953通过寄存器拉高gpio电平
  2. Zynq7000简介
  3. 用树型模型管理App数字和红点提示
  4. 强制垃圾分类是社会治理的必要手段(转自中国文明网
  5. Arduino NANO -- 那些需要了解的地方
  6. 3d mark android 版本,OMAP继续悲催 实测3D MARK安卓版更新
  7. uni-app px rpx 互相转换
  8. 第二章 希腊化——罗马科学
  9. 5.《程序猿扯淡系列》吃货的理想--健康从吃开始
  10. 漳州职业技术学院工业机器人技术_漳州职业技术学院工业机器人技术专业师生到我司参观交流...