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
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