def sign_message(self, sequence, message, password):
        sig = None
        try:
            message = message.encode('utf8')
            inputPath = self.get_derivation() + "/%d/%d" % sequence
            msg_hash = sha256d(msg_magic(message))
            inputHash = msg_hash.hex()
            hasharray = []
            hasharray.append({'hash': inputHash, 'keypath': inputPath})
            hasharray = json.dumps(hasharray)

            msg = b'{"sign":{"meta":"sign message", "data":%s}}' % hasharray.encode(
                'utf8')

            dbb_client = self.plugin.get_client(self)

            if not dbb_client.is_paired():
                raise Exception(_("Bitbox does not appear to be connected."))

            reply = dbb_client.hid_send_encrypt(msg)
            self.handler.show_message(
                _("Signing message ...") + "\n\n" +
                _("To continue, touch the Digital Bitbox's blinking light for "
                  "3 seconds.") + "\n\n" +
                _("To cancel, briefly touch the blinking light or wait for the timeout."
                  ))
            # Send twice, first returns an echo for smart verification (not implemented)
            reply = dbb_client.hid_send_encrypt(msg)
            self.handler.finished()

            if 'error' in reply:
                raise Exception(reply['error']['message'])

            if 'sign' not in reply:
                raise Exception(_("Bitbox did not sign the message."))

            siginfo = reply['sign'][0]
            compact_sig = bytes.fromhex(siginfo['sig'])
            if 'recid' in siginfo:
                recids = [int(siginfo['recid'], 16)]
            else:
                recids = range(4)
            for recid in recids:
                # firmware > v2.1.1
                message_sig = bytes([recid + 27]) + compact_sig
                try:
                    pubkey = PublicKey.from_signed_message(
                        message_sig, message)
                except Exception:
                    logger.exception(
                        f"If Digital Bitbox signing failed, this may be why")
                    continue
                if pubkey.verify_message(message_sig, message):
                    return message_sig
            raise RuntimeError(
                _("Unable to sign as Bitbox failed to provide a valid signature"
                  ))
        except Exception as e:
            self.give_error(e)
        return sig
Exemple #2
0
    def sign_message(self, sequence, message, password):
        sig = None
        try:
            message = message.encode('utf8')
            inputPath = self.get_derivation() + "/%d/%d" % sequence
            msg_hash = Hash(msg_magic(message))
            inputHash = to_hexstr(msg_hash)
            hasharray = []
            hasharray.append({'hash': inputHash, 'keypath': inputPath})
            hasharray = json.dumps(hasharray)

            msg = b'{"sign":{"meta":"sign message", "data":%s}}' % hasharray.encode(
                'utf8')

            dbb_client = self.plugin.get_client(self)

            if not dbb_client.is_paired():
                raise Exception(_("Could not sign message."))

            reply = dbb_client.hid_send_encrypt(msg)
            self.handler.show_message(
                _("Signing message ...") + "\n\n" +
                _("To continue, touch the Digital Bitbox's blinking light for "
                  "3 seconds.") + "\n\n" +
                _("To cancel, briefly touch the blinking light or wait for the timeout."
                  ))
            # Send twice, first returns an echo for smart verification (not implemented)
            reply = dbb_client.hid_send_encrypt(msg)
            self.handler.finished()

            if 'error' in reply:
                raise Exception(reply['error']['message'])

            if 'sign' not in reply:
                raise Exception(_("Could not sign message."))

            if 'recid' in reply['sign'][0]:
                # firmware > v2.1.1
                sig = (bytes([27 + int(reply['sign'][0]['recid'], 16) + 4]) +
                       binascii.unhexlify(reply['sign'][0]['sig']))
                pk, compressed = pubkey_from_signature(sig, msg_hash)
                pk = point_to_ser(pk.pubkey.point, compressed)
                addr = public_key_to_p2pkh(pk)
                if verify_message(addr, sig, message) is False:
                    raise Exception(_("Could not sign message"))
            elif 'pubkey' in reply['sign'][0]:
                # firmware <= v2.1.1
                for i in range(4):
                    sig = bytes([27 + i + 4]) + binascii.unhexlify(
                        reply['sign'][0]['sig'])
                    try:
                        addr = public_key_to_p2pkh(
                            binascii.unhexlify(reply['sign'][0]['pubkey']))
                        if verify_message(addr, sig, message):
                            break
                    except Exception:
                        continue
                else:
                    raise Exception(_("Could not sign message"))

        except BaseException as e:
            self.give_error(e)
        return sig