Beispiel #1
0
def main():
    # List all connected KeepKeys on USB
    devices = HidTransport.enumerate()

    # Check whether we found any
    if len(devices) == 0:
        print('No KeepKey found')
        return

    # Use first connected device
    transport = HidTransport(devices[0])

    # Creates object for manipulating KeepKey
    client = KeepKeyClient(transport)

    # Print out KeepKey's features and settings
    print(client.features)

    # Get the first address of first BIP44 account
    # (should be the same address as shown in KeepKey wallet Chrome extension)
    mpath = "44'/0'/0'/0"
    bip32_path = client.expand_path(mpath)

    print bip32.serialize(client.get_public_node(bip32_path).node, 0x043587CF)

    for i in range(11):
        child_path = '%s%s' % ("44'/0'/0'/0/", str(i))
        address = client.get_address('tDash', client.expand_path(child_path))
        print 'tDASH address:', child_path, address

    client.close()
Beispiel #2
0
class KeepKeyClient(HardwareWalletClient):

    # device is an HID device that has already been opened.
    def __init__(self, device, path):
        super(KeepKeyClient, self).__init__(device)
        device.close()
        devices = HidTransport.enumerate()
        self.client = None
        for d in devices:
            if d[0] == path:
                transport = HidTransport(d)
                self.client = KeepKey(transport)
                break

        # if it wasn't able to find a client, throw an error
        if not self.client:
            raise IOError("no Device")

    # Must return a dict with the xpub
    # Retrieves the public key at the specified BIP 32 derivation path
    def get_pubkey_at_path(self, path):
        expanded_path = self.client.expand_path(path)
        output = self.client.get_public_node(expanded_path)
        print({'xpub':output.xpub})
        return

    # Must return a hex string with the signed transaction
    # The tx must be in the combined unsigned transaction format
    def sign_tx(self, tx):
        raise NotImplementedError('The HardwareWalletClient base class does not '
            'implement this method')

    # Must return a base64 encoded string with the signed message
    # The message can be any string
    def sign_message(self, message):
        raise NotImplementedError('The HardwareWalletClient base class does not '
            'implement this method')

    # Setup a new device
    def setup_device(self):
        raise NotImplementedError('The HardwareWalletClient base class does not '
            'implement this method')

    # Wipe this device
    def wipe_device(self):
        raise NotImplementedError('The HardwareWalletClient base class does not '
            'implement this method')
Beispiel #3
0
class KeepkeyClient(HardwareWalletClient):
    def __init__(self, path, password=''):
        super(KeepkeyClient, self).__init__(path, password)
        devices = HidTransport.enumerate()
        transport = HidTransport((path.encode(), None))
        self.client = KeepKey(transport)

        # if it wasn't able to find a client, throw an error
        if not self.client:
            raise IOError("no Device")

        self.password = password
        os.environ['PASSPHRASE'] = password

    # Must return a dict with the xpub
    # Retrieves the public key at the specified BIP 32 derivation path
    def get_pubkey_at_path(self, path):
        path = path.replace('h', '\'')
        path = path.replace('H', '\'')
        expanded_path = self.client.expand_path(path)
        output = self.client.get_public_node(expanded_path)
        if self.is_testnet:
            return {'xpub': xpub_main_2_test(output.xpub)}
        else:
            return {'xpub': output.xpub}

    # Must return a hex string with the signed transaction
    # The tx must be in the combined unsigned transaction format
    def sign_tx(self, tx):

        # Get this devices master key fingerprint
        master_key = self.client.get_public_node([0])
        master_fp = get_xpub_fingerprint(master_key.xpub)

        # Prepare inputs
        inputs = []
        for psbt_in, txin in zip(tx.inputs, tx.tx.vin):
            txinputtype = proto.TxInputType()

            # Set the input stuff
            txinputtype.prev_hash = ser_uint256(txin.prevout.hash)[::-1]
            txinputtype.prev_index = txin.prevout.n
            txinputtype.sequence = txin.nSequence

            # Detrermine spend type
            if psbt_in.non_witness_utxo:
                txinputtype.script_type = 0
            elif psbt_in.witness_utxo:
                # Check if the output is p2sh
                if psbt_in.witness_utxo.is_p2sh():
                    txinputtype.script_type = 3
                else:
                    txinputtype.script_type = 4

            # Check for 1 key
            if len(psbt_in.hd_keypaths) == 1:
                # Is this key ours
                pubkey = list(psbt_in.hd_keypaths.keys())[0]
                fp = psbt_in.hd_keypaths[pubkey][0]
                keypath = psbt_in.hd_keypaths[pubkey][1:]
                if fp == master_fp:
                    # Set the keypath
                    txinputtype.address_n.extend(keypath)

            # Check for multisig (more than 1 key)
            elif len(psbt_in.hd_keypaths) > 1:
                raise TypeError("Cannot sign multisig yet")
            else:
                raise TypeError("All inputs must have a key for this device")

            # Set the amount
            if psbt_in.non_witness_utxo:
                txinputtype.amount = psbt_in.non_witness_utxo.vout[
                    txin.prevout.n].nValue
            elif psbt_in.witness_utxo:
                txinputtype.amount = psbt_in.witness_utxo.nValue

            # append to inputs
            inputs.append(txinputtype)

        # address version byte
        if self.is_testnet:
            p2pkh_version = b'\x6f'
            p2sh_version = b'\xc4'
        else:
            p2pkh_version = b'\x00'
            p2sh_version = b'\x05'

        # prepare outputs
        outputs = []
        for out in tx.tx.vout:
            txoutput = proto.TxOutputType()
            txoutput.amount = out.nValue
            if out.is_p2pkh():
                txoutput.address = to_address(out.scriptPubKey[3:23],
                                              p2pkh_version)
                txoutput.script_type = 0
            elif out.is_p2sh():
                txoutput.address = to_address(out.scriptPubKey[2:22],
                                              p2sh_version)
                txoutput.script_type = 1
            else:
                # TODO: Figure out what to do here. for now, just break
                break

            # append to outputs
            outputs.append(txoutput)
            logging.debug(txoutput)

        # Sign the transaction
        self.client.set_tx_api(TxAPIPSBT(tx))
        if self.is_testnet:
            signed_tx = self.client.sign_tx("Testnet", inputs, outputs,
                                            tx.tx.nVersion, tx.tx.nLockTime)
        else:
            signed_tx = self.client.sign_tx("Bitcoin", inputs, outputs,
                                            tx.tx.nVersion, tx.tx.nLockTime)

        signatures = signed_tx[0]
        logging.debug(binascii.hexlify(signed_tx[1]))
        for psbt_in in tx.inputs:
            for pubkey, sig in zip(psbt_in.hd_keypaths.keys(), signatures):
                fp = psbt_in.hd_keypaths[pubkey][0]
                keypath = psbt_in.hd_keypaths[pubkey][1:]
                if fp == master_fp:
                    psbt_in.partial_sigs[pubkey] = sig + b'\x01'

        return {'psbt': tx.serialize()}

    # Must return a base64 encoded string with the signed message
    # The message can be any string
    def sign_message(self, message, keypath):
        raise NotImplementedError(
            'The KeepKey does not currently implement signmessage')

    # Display address of specified type on the device. Only supports single-key based addresses.
    def display_address(self, keypath, p2sh_p2wpkh, bech32):
        raise NotImplementedError(
            'The KeepKey does not currently implement displayaddress')

    # Setup a new device
    def setup_device(self, label='', passphrase=''):
        if self.client.features.initialized:
            raise DeviceAlreadyInitError(
                'Device is already initialized. Use wipe first and try again')
        self.client.reset_device(False, 256, bool(self.password), True, label,
                                 'english')
        return {'success': True}

    # Wipe this device
    def wipe_device(self):
        self.client.wipe_device()
        return {'success': True}

    # Restore device from mnemonic or xprv
    def restore_device(self, label=''):
        self.client.recovery_device(False, 24, bool(self.password), True,
                                    label, 'english')
        return {'success': True}

    # Begin backup process
    def backup_device(self, label='', passphrase=''):
        raise UnavailableActionError(
            'The Keepkey does not support creating a backup via software')

    # Close the device
    def close(self):
        self.client.close()
Beispiel #4
0
def check_hw_wallet():
    printdbg('checking hw wallet')
    #client = None

    client = None
    signing = False

    if TYPE_HW_WALLET.lower().startswith("keepkey"):
        from keepkeylib.client import KeepKeyClient
        from keepkeylib.transport_hid import HidTransport
        import keepkeylib.ckd_public as bip32

        try:
            devices = HidTransport.enumerate()

        except Exception as e:
            err_msg = str(e.args)
            print_err_exit(get_caller_name(), get_function_name(), err_msg)

        if len(devices) == 0:
            print('===> No HW Wallet found')
            signing = False

        else:

            try:
                print('===> keepkey HW Wallet found')
                transport = HidTransport(devices[0])
                client = KeepKeyClient(transport)
                signing = True

            except Exception as e:
                err_msg = str(e.args)
                print_err_exit(get_caller_name(), get_function_name(), err_msg)

    elif TYPE_HW_WALLET.lower().startswith("trezor"):
        from trezorlib.client import TrezorClient
        from trezorlib.transport_hid import HidTransport
        import trezorlib.ckd_public as bip32

        try:
            devices = HidTransport.enumerate()

        except Exception as e:
            err_msg = str(e.args)
            print_err_exit(get_caller_name(), get_function_name(), err_msg)

        if len(devices) == 0:
            print('===> No HW Wallet found')
            signing = False

        else:
            try:
                print('===> trezor HW Wallet found')
                transport = HidTransport(devices[0])
                client = TrezorClient(transport)
                signing = True

            except Exception as e:
                err_msg = str(e.args)
                print_err_exit(get_caller_name(), get_function_name(), err_msg)

    elif TYPE_HW_WALLET.lower().startswith("ledgernanos"):
        #from btchip.btchip import *
        #from btchip.btchipUtils import *

        try:
            devices = getDongle(False)

        except Exception as e:
            err_msg = str(e.args)
            print_err_exit(get_caller_name(), get_function_name(), err_msg)

        if not devices:
            print('===> No HW Wallet found')
            signing = False

        else:
            try:
                print('===> Ledger nano s HW Wallet found')
                client = btchip(devices)
                signing = True

            except Exception as e:
                err_msg = str(e.args)
                print_err_exit(get_caller_name(), get_function_name(), err_msg)

    if client is not None:

        if TYPE_HW_WALLET.lower().startswith("ledgernanos"):
            pass

        else:
            try:
                wallet_supported_coins = list_coins(client)

            except Exception as e:
                err_msg = str(e.args)
                print_err_exit(get_caller_name(), get_function_name(), err_msg)

            if coin_name not in wallet_supported_coins:
                err_msg = 'only following coins supported by wallet\n\t' + \
                    str(wallet_supported_coins)
                print_err_exit(get_caller_name(), get_function_name(), err_msg)

    else:
        err_msg = "Can't run florijncoinmnb without hw wallet"
        print_err_exit(get_caller_name(), get_function_name(), err_msg)

    if TYPE_HW_WALLET.lower().startswith("ledgernanos"):
        mpath = get_mpath()

        return client, signing, mpath

    else:
        try:
            mpath = get_mpath()
            bip32_path = client.expand_path(mpath)
            xpub = bip32.serialize(
                client.get_public_node(bip32_path).node,
                (0x0488B21E if MAINNET else 0x043587CF))

        except AssertionError as e:
            err_msg = str(e.args)
            print_err_exit(get_caller_name(), get_function_name(), err_msg)

        except Exception as e:
            err_msg = str(e.args)
            print_err_exit(get_caller_name(), get_function_name(), err_msg)

        except KeyboardInterrupt:
            print_err_exit(get_caller_name(), get_function_name(),
                           "KeyboardInterrupt")

    printdbg('check_hw_wallet : signing : %s' % signing)
    printdbg('check_hw_wallet : xpub[:7] : %s' % xpub[:7])
    printdbg('check_hw_wallet : xpub[-7:] : %s' % xpub[-7:])
    printdbg('check_hw_wallet : mpath : %s' % mpath)

    return client, signing, bip32, mpath, xpub