1*4edd96e6SJens Wiklander#!/usr/bin/env python3 2*4edd96e6SJens Wiklander# SPDX-License-Identifier: BSD-2-Clause 3*4edd96e6SJens Wiklander# 4*4edd96e6SJens Wiklander# Copyright (c) 2023, Linaro Limited 5*4edd96e6SJens Wiklander# 6*4edd96e6SJens Wiklander 7*4edd96e6SJens Wiklanderimport sys 8*4edd96e6SJens Wiklander 9*4edd96e6SJens Wiklander 10*4edd96e6SJens Wiklanderdef hex_parse(str): 11*4edd96e6SJens Wiklander try: 12*4edd96e6SJens Wiklander h = bytes.fromhex(str) 13*4edd96e6SJens Wiklander except ValueError as e: 14*4edd96e6SJens Wiklander try: 15*4edd96e6SJens Wiklander # Try to pad with a '0' nibble in front 16*4edd96e6SJens Wiklander h = bytes.fromhex('0' + str) 17*4edd96e6SJens Wiklander print('Odd number of nibbles in hexadecimal string', 18*4edd96e6SJens Wiklander file=sys.stderr) 19*4edd96e6SJens Wiklander raise e 20*4edd96e6SJens Wiklander except ValueError: 21*4edd96e6SJens Wiklander raise e 22*4edd96e6SJens Wiklander return h 23*4edd96e6SJens Wiklander 24*4edd96e6SJens Wiklander 25*4edd96e6SJens Wiklanderdef get_args(): 26*4edd96e6SJens Wiklander import argparse 27*4edd96e6SJens Wiklander import textwrap 28*4edd96e6SJens Wiklander 29*4edd96e6SJens Wiklander parser = argparse.ArgumentParser( 30*4edd96e6SJens Wiklander allow_abbrev=False, 31*4edd96e6SJens Wiklander description='''Derive an RPMB key from the Hardware Unique Key used 32*4edd96e6SJens Wiklander by OP-TEE and the CID of the RPMB.''', 33*4edd96e6SJens Wiklander epilog='''Note that the derived key matches what the 34*4edd96e6SJens Wiklander __huk_subkey_derive() would produce. If huk_subkey_derive() 35*4edd96e6SJens Wiklander is overridden to call another function, please don't use 36*4edd96e6SJens Wiklander this script''') 37*4edd96e6SJens Wiklander 38*4edd96e6SJens Wiklander parser.add_argument('--quiet', action='store_true', default=False, 39*4edd96e6SJens Wiklander help='''Gives only the hexstring of the RPMB key as 40*4edd96e6SJens Wiklander output, intended for scripting''') 41*4edd96e6SJens Wiklander parser.add_argument('--testkey', action='store_true', default=False, 42*4edd96e6SJens Wiklander help='''Outputs the hardcoded test key''') 43*4edd96e6SJens Wiklander parser.add_argument('--huk', type=hex_parse, 44*4edd96e6SJens Wiklander help='''Hardware Unique Key (16 bytes), as returned 45*4edd96e6SJens Wiklander by the platform specific function 46*4edd96e6SJens Wiklander tee_otp_get_hw_unique_key() in OP-TEE''') 47*4edd96e6SJens Wiklander parser.add_argument('--cid', type=hex_parse, help='CID (16 bytes)') 48*4edd96e6SJens Wiklander parser.add_argument('--compat', action='store_true', default=False, 49*4edd96e6SJens Wiklander help='''Generates a backwards compatible key, 50*4edd96e6SJens Wiklander only to be used if OP-TEE is build with 51*4edd96e6SJens Wiklander CFG_CORE_HUK_SUBKEY_COMPAT=y''') 52*4edd96e6SJens Wiklander 53*4edd96e6SJens Wiklander return parser.parse_args() 54*4edd96e6SJens Wiklander 55*4edd96e6SJens Wiklander 56*4edd96e6SJens Wiklanderdef derive_key(huk, cid, compat): 57*4edd96e6SJens Wiklander import struct 58*4edd96e6SJens Wiklander from cryptography.hazmat.primitives import hashes, hmac 59*4edd96e6SJens Wiklander 60*4edd96e6SJens Wiklander # Prepare the CID and Clear the PRV (Product revision) and CRC (CRC7 61*4edd96e6SJens Wiklander # checksum) fields as OP-TEE does. 62*4edd96e6SJens Wiklander data = bytearray(cid) 63*4edd96e6SJens Wiklander data[9] = 0 64*4edd96e6SJens Wiklander data[15] = 0 65*4edd96e6SJens Wiklander 66*4edd96e6SJens Wiklander # This is how __huk_subkey_derive() is implemented, if huk_subkey_derive() 67*4edd96e6SJens Wiklander # is overridden the key derived here may not match what OP-TEE is using 68*4edd96e6SJens Wiklander # 69*4edd96e6SJens Wiklander # HUK is as tee_otp_get_hw_unique_key() in OP-TEE returns it 70*4edd96e6SJens Wiklander h = hmac.HMAC(huk, hashes.SHA256()) 71*4edd96e6SJens Wiklander if not compat: 72*4edd96e6SJens Wiklander usage_word = struct.pack('<I', 0) 73*4edd96e6SJens Wiklander h.update(usage_word) 74*4edd96e6SJens Wiklander h.update(data) 75*4edd96e6SJens Wiklander return h.finalize() 76*4edd96e6SJens Wiklander 77*4edd96e6SJens Wiklander 78*4edd96e6SJens Wiklanderdef main(): 79*4edd96e6SJens Wiklander args = get_args() 80*4edd96e6SJens Wiklander 81*4edd96e6SJens Wiklander if args.testkey: 82*4edd96e6SJens Wiklander if args.cid or args.huk or args.compat: 83*4edd96e6SJens Wiklander print('--cid, --huk, or --compat ' 84*4edd96e6SJens Wiklander 'cannot be given together with --testkey') 85*4edd96e6SJens Wiklander sys.exit(1) 86*4edd96e6SJens Wiklander # The test key hardcoded in OP-TEE 87*4edd96e6SJens Wiklander key = bytes.fromhex('''D3 EB 3E C3 6E 33 4C 9F 88*4edd96e6SJens Wiklander 98 8C E2 C0 B8 59 54 61 89*4edd96e6SJens Wiklander 0D 2B CF 86 64 84 4D F2 90*4edd96e6SJens Wiklander AB 56 E6 C6 1B B7 01 E4''') 91*4edd96e6SJens Wiklander else: 92*4edd96e6SJens Wiklander if not args.cid: 93*4edd96e6SJens Wiklander print('--cid is required without --testkey') 94*4edd96e6SJens Wiklander sys.exit(1) 95*4edd96e6SJens Wiklander 96*4edd96e6SJens Wiklander if not args.huk: 97*4edd96e6SJens Wiklander print('--huk is required without --testkey') 98*4edd96e6SJens Wiklander sys.exit(1) 99*4edd96e6SJens Wiklander 100*4edd96e6SJens Wiklander if len(args.cid) != 16: 101*4edd96e6SJens Wiklander print(f'Invalid CID length, expected 16 bytes got {len(args.cid)}', 102*4edd96e6SJens Wiklander file=sys.stderr) 103*4edd96e6SJens Wiklander sys.exit(1) 104*4edd96e6SJens Wiklander 105*4edd96e6SJens Wiklander if len(args.huk) != 16: 106*4edd96e6SJens Wiklander print(f'Invalid HUK length, expected 16 bytes got {len(args.huk)}', 107*4edd96e6SJens Wiklander file=sys.stderr) 108*4edd96e6SJens Wiklander sys.exit(1) 109*4edd96e6SJens Wiklander 110*4edd96e6SJens Wiklander if not args.quiet: 111*4edd96e6SJens Wiklander print(f'HUK: {args.huk.hex()} length {len(args.huk)}') 112*4edd96e6SJens Wiklander print(f'RPMB CID: {args.cid.hex()} length {len(args.cid)}') 113*4edd96e6SJens Wiklander 114*4edd96e6SJens Wiklander key = derive_key(args.huk, args.cid, args.compat) 115*4edd96e6SJens Wiklander 116*4edd96e6SJens Wiklander if args.quiet: 117*4edd96e6SJens Wiklander print(key.hex()) 118*4edd96e6SJens Wiklander else: 119*4edd96e6SJens Wiklander print(f'RPMB key: {key.hex()}') 120*4edd96e6SJens Wiklander print(f' length {len(key)}') 121*4edd96e6SJens Wiklander if args.testkey: 122*4edd96e6SJens Wiklander print(''' 123*4edd96e6SJens Wiklander********************************************************************* 124*4edd96e6SJens Wiklander*** Please note that the test key should only be used for testing *** 125*4edd96e6SJens Wiklander*** purposes since it's well known and the same for all devices. *** 126*4edd96e6SJens Wiklander*********************************************************************''') 127*4edd96e6SJens Wiklander else: 128*4edd96e6SJens Wiklander print(''' 129*4edd96e6SJens WiklanderPlease take care to double-check the provided input since writing the RPMB 130*4edd96e6SJens Wiklanderkey is an irreversible step.''') 131*4edd96e6SJens Wiklander 132*4edd96e6SJens Wiklander 133*4edd96e6SJens Wiklanderif __name__ == "__main__": 134*4edd96e6SJens Wiklander main() 135