def msg_authenticate_genkey(app_id: bytes, keyhandle: bytes, pathformat: str): from apps.common import seed # unpack the keypath from the first half of keyhandle keybuf = keyhandle[:32] keypath = ustruct.unpack(pathformat, keybuf) # check high bit for hardened keys for i in keypath: if not i & HARDENED: if __debug__: log.warning(__name__, "invalid key path") return None # derive the signing key nodepath = [_U2F_KEY_PATH] + list(keypath) node = seed.derive_node_without_passphrase(nodepath, "nist256p1") # second half of keyhandle is a hmac of app_id and keypath keybase = hmac.Hmac(node.private_key(), app_id, hashlib.sha256) keybase.update(keybuf) keybase = keybase.digest() # verify the hmac if keybase != keyhandle[32:]: if __debug__: log.warning(__name__, "invalid key handle") return None return node
def msg_authenticate_genkey(app_id: bytes, keyhandle: bytes): from apps.common import seed # unpack the keypath from the first half of keyhandle keybuf = keyhandle[:32] keypath = ustruct.unpack('>8L', keybuf) # check high bit for hardened keys for i in keypath: if not i & 0x80000000: log.warning(__name__, 'invalid key path') return None # derive the signing key nodepath = [_U2F_KEY_PATH] + list(keypath) node = seed.get_root_without_passphrase('nist256p1') node.derive_path(nodepath) # second half of keyhandle is a hmac of app_id and keypath keybase = hmac.Hmac(node.private_key(), app_id, hashlib.sha256) keybase.update(keybuf) keybase = keybase.digest() # verify the hmac if keybase != keyhandle[32:]: log.warning(__name__, 'invalid key handle') return None return node
def _node_from_key_handle(rp_id_hash: bytes, keyhandle: bytes, pathformat: str) -> Optional[bip32.HDNode]: # unpack the keypath from the first half of keyhandle keypath = keyhandle[:32] path = ustruct.unpack(pathformat, keypath) # check high bit for hardened keys for i in path: if not i & HARDENED: if __debug__: log.warning(__name__, "invalid key path") return None # derive the signing key nodepath = [_U2F_KEY_PATH] + list(path) node = seed.derive_node_without_passphrase(nodepath, "nist256p1") # second half of keyhandle is a hmac of rp_id_hash and keypath mac = hmac.Hmac(node.private_key(), rp_id_hash, hashlib.sha256) mac.update(keypath) # verify the hmac if not utils.consteq(mac.digest(), keyhandle[32:]): if __debug__: log.warning(__name__, "invalid key handle") return None return node
def msg_register_sign(challenge: bytes, app_id: bytes) -> bytes: from apps.common import seed # derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' keypath = [0x80000000 | random.uniform(0xf0000000) for _ in range(0, 8)] nodepath = [_U2F_KEY_PATH] + keypath # prepare signing key from random path, compute decompressed public key node = seed.get_root_without_passphrase('nist256p1') node.derive_path(nodepath) pubkey = nist256p1.publickey(node.private_key(), False) # first half of keyhandle is keypath keybuf = ustruct.pack('>8L', *keypath) # second half of keyhandle is a hmac of app_id and keypath keybase = hmac.Hmac(node.private_key(), app_id, hashlib.sha256) keybase.update(keybuf) keybase = keybase.digest() # hash the request data together with keyhandle and pubkey dig = hashlib.sha256() dig.update(b'\x00') # uint8_t reserved; dig.update(app_id) # uint8_t appId[32]; dig.update(challenge) # uint8_t chal[32]; dig.update(keybuf) # uint8_t keyHandle[64]; dig.update(keybase) dig.update(pubkey) # uint8_t pubKey[65]; dig = dig.digest() # sign the digest and convert to der sig = nist256p1.sign(_U2F_ATT_PRIV_KEY, dig, False) sig = der.encode_seq((sig[1:33], sig[33:])) # pack to a response buf, resp = make_struct( resp_cmd_register( len(keybuf) + len(keybase), len(_U2F_ATT_CERT), len(sig))) resp.registerId = _U2F_REGISTER_ID utils.memcpy(resp.pubKey, 0, pubkey, 0, len(pubkey)) resp.keyHandleLen = len(keybuf) + len(keybase) utils.memcpy(resp.keyHandle, 0, keybuf, 0, len(keybuf)) utils.memcpy(resp.keyHandle, len(keybuf), keybase, 0, len(keybase)) utils.memcpy(resp.cert, 0, _U2F_ATT_CERT, 0, len(_U2F_ATT_CERT)) utils.memcpy(resp.sig, 0, sig, 0, len(sig)) resp.status = _SW_NO_ERROR return buf
def generate_key_handle(self) -> None: # derivation path is m/U2F'/r'/r'/r'/r'/r'/r'/r'/r' path = [HARDENED | random.uniform(0x80000000) for _ in range(0, 8)] nodepath = [_U2F_KEY_PATH] + path # prepare signing key from random path, compute decompressed public key self.node = seed.derive_node_without_passphrase(nodepath, "nist256p1") # first half of keyhandle is keypath keypath = ustruct.pack("<8L", *path) # second half of keyhandle is a hmac of rp_id_hash and keypath mac = hmac.Hmac(self.node.private_key(), self.rp_id_hash, hashlib.sha256) mac.update(keypath) self.id = keypath + mac.digest()
def get_identifier(script_pubkey: bytes, keychain: Keychain) -> bytes: # k = Key(m/"SLIP-0019"/"Ownership identification key") node = keychain.derive_slip21(_OWNERSHIP_ID_KEY_PATH) # id = HMAC-SHA256(key = k, msg = scriptPubKey) return hmac.Hmac(node.key(), script_pubkey, hashlib.sha256).digest()