Exemple #1
0
def test_sign_msg_microsd_good(sign_on_microsd, master_xpub, msg, path, addr_vs_path, addr_fmt=AF_CLASSIC):

    # cases we expect to work
    sig, addr = sign_on_microsd(msg, path)

    raw = b64decode(sig)
    assert 40 <= len(raw) <= 65

    if addr_fmt != AF_CLASSIC:
        # TODO
        # - need bech32 decoder here
        # - pycoin can't do signature decode
        if addr_fmt & AFC_BECH32:
            assert '1' in addr
        return

    if path is None:
        path = 'm'

    if "'" not in path and 'p' not in path:
        # check expected addr was used
        mk = BIP32Node.from_wallet_key(master_xpub)
        sk = mk.subkey_for_path(path[2:])

        addr_vs_path(addr, path, addr_fmt)
    
        # verify signature
        assert verify_message(sk, sig, message=msg) == True
    else:
        # just verify signature
        assert verify_message(addr, sig, message=msg) == True
Exemple #2
0
def test_sign_msg_good(dev, need_keypress, msg, path, addr_fmt, addr_vs_path):

    msg = msg.encode('ascii')
    dev.send_recv(CCProtocolPacker.sign_message(msg, path, addr_fmt=addr_fmt),
                  timeout=None)

    need_keypress('y')

    done = None
    while done == None:
        time.sleep(0.050)
        done = dev.send_recv(CCProtocolPacker.get_signed_msg(), timeout=None)

    assert len(done) == 2, done

    addr, raw = done
    sig = str(b64encode(raw), 'ascii').replace('\n', '')

    assert 40 <= len(raw) <= 65

    if addr_fmt != AF_CLASSIC:
        # TODO
        # - need bech32 decoder here
        # - pycoin can't do signature decode
        if addr_fmt & AFC_BECH32:
            assert '1' in addr
        return

    # check expected addr was used
    sk = addr_vs_path(addr, path, addr_fmt)

    # verify signature
    assert verify_message(sk, sig, message=msg.decode('ascii')) == True
    assert verify_message(addr, sig, message=msg.decode('ascii')) == True
Exemple #3
0
    def mitm_verify(self, sig, expected_xpub):
        # First try with Pycoin
        try:
            from pycoin.key.BIP32Node import BIP32Node
            from pycoin.contrib.msg_signing import verify_message
            from pycoin.encoding import from_bytes_32
            from base64 import b64encode

            mk = BIP32Node.from_wallet_key(expected_xpub)
            return verify_message(mk,
                                  b64encode(sig),
                                  msg_hash=from_bytes_32(self.session_key))
        except ImportError:
            pass

        # If Pycoin is not available, do it using ecdsa
        from ecdsa import BadSignatureError, SECP256k1, VerifyingKey
        pubkey, chaincode = decode_xpub(expected_xpub)
        vk = VerifyingKey.from_string(get_pubkey_string(pubkey),
                                      curve=SECP256k1)
        try:
            ok = vk.verify_digest(sig[1:], self.session_key)
        except BadSignatureError:
            ok = False

        return ok
Exemple #4
0
def test_sign_msg_microsd_good(sign_on_microsd, msg, path, addr_vs_path,
                               addr_fmt):

    # cases we expect to work
    sig, addr = sign_on_microsd(msg, path)

    raw = b64decode(sig)
    assert 40 <= len(raw) <= 65

    if addr_fmt != AF_CLASSIC:
        # TODO
        # - need bech32 decoder here
        # - pycoin can't do signature decode
        if addr_fmt & AFC_BECH32:
            assert '1' in addr
        return

    if path is None:
        path = 'm'

    # check expected addr was used
    sk = addr_vs_path(addr, path, addr_fmt)

    if addr_fmt == AF_P2WPKH:
        assert addr.startswith('tb1q')

    # verify signature
    assert verify_message(sk, sig, message=msg) == True
Exemple #5
0
def test_against_myself():
    """
    Test code that verifies against ourselves only. Useful but not so great.
    """
    from pycoin.contrib.msg_signing import (parse_signed_message, sign_message,
                                            verify_message)
    from pycoin.encoding import bitcoin_address_to_hash160_sec_with_prefix
    from pycoin.encoding import wif_to_tuple_of_secret_exponent_compressed

    for wif, right_addr in [
        ('L4gXBvYrXHo59HLeyem94D9yLpRkURCHmCwQtPuWW9m6o1X8p8sp',
         '1LsPb3D1o1Z7CzEt1kv5QVxErfqzXxaZXv'),
        ('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss',
         '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN'),
    ]:
        se, comp = wif_to_tuple_of_secret_exponent_compressed(wif)

        k = Key(secret_exponent=se, is_compressed=comp)
        assert k.address() == right_addr

        vk = Key(public_pair=k.public_pair(), is_compressed=comp)
        assert vk.address() == right_addr

        h160, pubpre = bitcoin_address_to_hash160_sec_with_prefix(right_addr)
        vk2 = Key(hash160=h160)
        assert vk2.address() == right_addr

        for i in range(1, 30, 10):
            msg = 'test message %s' % ('A' * i)
            sig = sign_message(k, msg, verbose=1)
            assert right_addr in sig

            # check parsing works
            m, a, s = parse_signed_message(sig)
            assert m == msg, m
            assert a == right_addr, a

            sig2 = sign_message(k, msg, verbose=0)
            assert sig2 in sig, (sig, sig2)

            assert s == sig2, s

            ok = verify_message(k, sig2, msg)
            assert ok

            ok = verify_message(k, sig2.encode('ascii'), msg)
            assert ok
def test_against_myself():
    """
    Test code that verifies against ourselves only. Useful but not so great.
    """
    from pycoin.contrib.msg_signing import (
            parse_signed_message, sign_message, verify_message)
    from pycoin.encoding import bitcoin_address_to_hash160_sec_with_prefix
    from pycoin.encoding import wif_to_tuple_of_secret_exponent_compressed

    for wif, right_addr in [
                    ('L4gXBvYrXHo59HLeyem94D9yLpRkURCHmCwQtPuWW9m6o1X8p8sp',
                     '1LsPb3D1o1Z7CzEt1kv5QVxErfqzXxaZXv'),
                    ('5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss',
                     '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN'),
                ]:
        se, comp = wif_to_tuple_of_secret_exponent_compressed(wif)

        k = Key(secret_exponent=se, is_compressed=comp)
        assert k.address() == right_addr

        vk = Key(public_pair=k.public_pair(), is_compressed=comp)
        assert vk.address() == right_addr

        h160, pubpre = bitcoin_address_to_hash160_sec_with_prefix(right_addr)
        vk2 = Key(hash160=h160)
        assert vk2.address() == right_addr

        for i in range(1, 30, 10):
            msg = 'test message %s' % ('A'*i)
            sig = sign_message(k, msg, verbose=1)
            assert right_addr in sig

            # check parsing works
            m, a, s = parse_signed_message(sig)
            assert m == msg, m
            assert a == right_addr, a

            sig2 = sign_message(k, msg, verbose=0)
            assert sig2 in sig, (sig, sig2)

            assert s == sig2, s

            ok = verify_message(k, sig2, msg)
            assert ok

            ok = verify_message(k, sig2.encode('ascii'), msg)
            assert ok
def test_sign_msg_good(dev, need_keypress, master_xpub, msg, path, addr_fmt,
                       addr_vs_path):

    msg = msg.encode('ascii')
    dev.send_recv(CCProtocolPacker.sign_message(msg, path, addr_fmt=addr_fmt),
                  timeout=None)

    need_keypress('y')

    done = None
    while done == None:
        time.sleep(0.050)
        done = dev.send_recv(CCProtocolPacker.get_signed_msg(), timeout=None)

    assert len(done) == 2, done

    addr, raw = done
    sig = str(b64encode(raw), 'ascii').replace('\n', '')

    assert 40 <= len(raw) <= 65

    if addr_fmt != AF_CLASSIC:
        # TODO
        # - need bech32 decoder here
        # - pycoin can't do signature decode
        if addr_fmt & AFC_BECH32:
            assert '1' in addr
        return

    if "'" not in path and 'p' not in path:
        # check expected addr was used
        mk = BIP32Node.from_wallet_key(master_xpub)
        sk = mk.subkey_for_path(path[2:])

        addr_vs_path(addr, path, addr_fmt)

        # verify signature
        assert verify_message(sk, sig, message=msg.decode('ascii')) == True
    else:
        # just verify signature
        assert verify_message(addr, sig, message=msg.decode('ascii')) == True
Exemple #8
0
    def mitm_verify(self, sig, expected_xpub):
        # replace this with your own library, as needed.
        try:
            from pycoin.key.BIP32Node import BIP32Node
            from pycoin.contrib.msg_signing import verify_message
            from pycoin.encoding import from_bytes_32
            from base64 import b64encode
        except ImportError:
            raise RuntimeError("Missing pycoin for signature checking")

        mk = BIP32Node.from_wallet_key(expected_xpub)
        ok = verify_message(mk,
                            b64encode(sig),
                            msg_hash=from_bytes_32(self.session_key))

        return ok
Exemple #9
0
def test_change_outs(fake_txn, start_sign, end_sign, cap_story, dev, num_outs, master_xpub,
                        act_outs, segwit, out_style, visualized, add_xpub, num_ins=3):
    # create a TXN which has change outputs, which shouldn't be shown to user, and also not fail.
    xp = dev.master_xpub

    couts = num_outs if act_outs == -1 else num_ins-act_outs
    psbt = fake_txn(num_ins, num_outs, xp, segwit_in=segwit,
                        outstyles=[out_style], change_outputs=range(couts), add_xpub=add_xpub)

    open('debug/change.psbt', 'wb').write(psbt)

    # should be able to sign, but get warning
    if not visualized:
        start_sign(psbt, False)

        time.sleep(.1)
        title, story = cap_story()
        print(repr(story))

        assert title == "OK TO SEND?"
    else:
        # use new feature to have Coldcard return the 'visualization' of transaction
        start_sign(psbt, False, stxn_flags=visualized)
        story = end_sign(accept=None, expect_txn=False)

        story = story.decode('ascii')

        if (visualized & STXN_SIGNED):
            # last line should be signature, using 'm' over the rest
            from pycoin.contrib.msg_signing import verify_message
            from pycoin.key.BIP32Node import BIP32Node

            #def verify_message(key_or_address, signature, message=None, msg_hash=None, netcode=None):

            assert story[-1] == '\n'
            last_nl = story[:-1].rindex('\n')
            msg, sig = story[0:last_nl+1], story[last_nl:]
            wallet = BIP32Node.from_wallet_key(master_xpub)
            assert verify_message(wallet, sig, message=msg) == True
            story = msg

    assert 'Network fee' in story

    if couts < num_outs:
        assert '- to address -' in story
    else:
        assert 'Consolidating' in story

    if couts == 1:
        assert "- to address -" in story
    else:
        assert "- to addresses -" in story

    val, addrs = parse_change_back(story)
    assert val > 0          # hard to calc here
    assert len(addrs) == couts
    if out_style == 'p2pkh':
        assert all((i[0] in 'mn') for i in addrs)
    elif out_style == 'p2wpkh':
        assert set(i[0:4] for i in addrs) == {'tb1q'}
    elif out_style == 'p2wpkh-p2sh':
        assert set(i[0] for i in addrs) == {'2'}
Exemple #10
0
def test_msg_parse():
    """
        Test against real-world signatures found in the wild.
    """

    from pycoin.contrib.msg_signing import parse_signed_message, verify_message
    from pycoin.key import Key

    # Output from brainwallet in "multibit" mode.
    multibit = '''

-----BEGIN BITCOIN SIGNED MESSAGE-----
This is an example of a signed message.
-----BEGIN BITCOIN SIGNATURE-----
Version: Bitcoin-qt (1.0)
Address: 1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN

HCT1esk/TWlF/o9UNzLDANqsPXntkMErf7erIrjH5IBOZP98cNcmWmnW0GpSAi3wbr6CwpUAN4ctNn1T71UBwSc=
-----END BITCOIN SIGNATURE-----

'''
    m, a, s = parse_signed_message(multibit)
    assert m == 'This is an example of a signed message.'
    assert a == '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN'
    assert s == ('HCT1esk/TWlF/o9UNzLDANqsPXntkMErf7erIrjH5IBOZ'
                 'P98cNcmWmnW0GpSAi3wbr6CwpUAN4ctNn1T71UBwSc=')
    ok = verify_message(a, s, m, netcode='BTC')
    assert ok

    # Sampled from: https://www.bitrated.com/u/Bit2c.txt on Sep 3/2014
    bit2c = '''\
Username: Bit2c
Public key: 0396267072e597ad5d043db7c73e13af84a77a7212871f1aade607fb0f2f96e1a8
Public key address: 15etuU8kwLFCBbCNRsgQTvWgrGWY9829ej
URL: https://www.bitrated.com/u/Bit2c

-----BEGIN BITCOIN SIGNED MESSAGE-----
We will try to contact both parties to gather information and evidence, and do my best to make rightful judgement. Evidence may be submitted to us on https://www.bit2c.co.il/home/contact or in a private message to [email protected] or in any agreed way.

https://www.bit2c.co.il
-----BEGIN SIGNATURE-----
15etuU8kwLFCBbCNRsgQTvWgrGWY9829ej
H2utKkquLbyEJamGwUfS9J0kKT4uuMTEr2WX2dPU9YImg4LeRpyjBelrqEqfM4QC8pJ+hVlQgZI5IPpLyRNxvK8=
-----END BITCOIN SIGNED MESSAGE-----
'''
    m, a, s = parse_signed_message(bit2c)
    assert a == '15etuU8kwLFCBbCNRsgQTvWgrGWY9829ej'
    assert s == ('H2utKkquLbyEJamGwUfS9J0kKT4uuMTEr2WX2dPU9YI'
                 'mg4LeRpyjBelrqEqfM4QC8pJ+hVlQgZI5IPpLyRNxvK8=')
    ok = verify_message(a, s, m, netcode='BTC')
    assert ok

    # testnet example
    # Sampled from: http://testnet.bitrated.com/u/bearbin.txt on Sep 3/2014
    # NOTE: Testnet3
    bearbin = '''\
Username: bearbin
Public key: 03fc594c16779054fc5e119c309215c1f40f2ce104b0169cddeb6d20445bd28f67
Public key address: n2D9XsQX1mDpFGgYqsfmePTy61LJFQnXQM
URL: http://testnet.bitrated.com/u/bearbin

-----BEGIN BITCOIN SIGNED MESSAGE-----
Contact
-----------

[email protected] - Email or hangouts (text only).

/u/bearbin on reddit (slow response, not preferred for use with the service, just for contact).

Resolution Guidelines:
-----------------------------

 * Evidence is needed. (e.g. pictures w/ proof that it's you).
 * If anybody fails to respond, money goes to the other person after 2 weeks.
 * Additional terms available on request.

Pricing
----------

 * 0.7% Min 0.003 Max 0.15
 * Payment in advance.
-----BEGIN SIGNATURE-----
n2D9XsQX1mDpFGgYqsfmePTy61LJFQnXQM
IEackZgifpBJs3SqQQ6leUwzvakTZgUKTDuCCn6rVMOQgHlIEzWSYZGQu2H+1chvu68uutzt04cGmsHy/kRIaEc=
-----END BITCOIN SIGNED MESSAGE-----
'''
    m, a, s = parse_signed_message(bearbin)
    assert a == 'n2D9XsQX1mDpFGgYqsfmePTy61LJFQnXQM'
    assert s == ('IEackZgifpBJs3SqQQ6leUwzvakTZgUKTDuCCn6rVMOQgH'
                 'lIEzWSYZGQu2H+1chvu68uutzt04cGmsHy/kRIaEc=')
    ok = verify_message(a, s, m, netcode='XTN')
    assert ok
Exemple #11
0
def test_msg_parse():
    """
        Test against real-world signatures found in the wild.
    """

    from pycoin.contrib.msg_signing import parse_signed_message, verify_message
    from pycoin.key import Key

    # Output from brainwallet in "multibit" mode.
    multibit = """

-----BEGIN BITCOIN SIGNED MESSAGE-----
This is an example of a signed message.
-----BEGIN BITCOIN SIGNATURE-----
Version: Bitcoin-qt (1.0)
Address: 1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN

HCT1esk/TWlF/o9UNzLDANqsPXntkMErf7erIrjH5IBOZP98cNcmWmnW0GpSAi3wbr6CwpUAN4ctNn1T71UBwSc=
-----END BITCOIN SIGNATURE-----

"""
    m, a, s = parse_signed_message(multibit)
    assert m == "This is an example of a signed message."
    assert a == "1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN"
    assert s == ("HCT1esk/TWlF/o9UNzLDANqsPXntkMErf7erIrjH5IBOZ" "P98cNcmWmnW0GpSAi3wbr6CwpUAN4ctNn1T71UBwSc=")
    ok = verify_message(a, s, m, netcode="BTC")
    assert ok

    # Sampled from: https://www.bitrated.com/u/Bit2c.txt on Sep 3/2014
    bit2c = """\
Username: Bit2c
Public key: 0396267072e597ad5d043db7c73e13af84a77a7212871f1aade607fb0f2f96e1a8
Public key address: 15etuU8kwLFCBbCNRsgQTvWgrGWY9829ej
URL: https://www.bitrated.com/u/Bit2c

-----BEGIN BITCOIN SIGNED MESSAGE-----
We will try to contact both parties to gather information and evidence, and do my best to make rightful judgement. Evidence may be submitted to us on https://www.bit2c.co.il/home/contact or in a private message to [email protected] or in any agreed way.

https://www.bit2c.co.il
-----BEGIN SIGNATURE-----
15etuU8kwLFCBbCNRsgQTvWgrGWY9829ej
H2utKkquLbyEJamGwUfS9J0kKT4uuMTEr2WX2dPU9YImg4LeRpyjBelrqEqfM4QC8pJ+hVlQgZI5IPpLyRNxvK8=
-----END BITCOIN SIGNED MESSAGE-----
"""
    m, a, s = parse_signed_message(bit2c)
    assert a == "15etuU8kwLFCBbCNRsgQTvWgrGWY9829ej"
    assert s == ("H2utKkquLbyEJamGwUfS9J0kKT4uuMTEr2WX2dPU9YI" "mg4LeRpyjBelrqEqfM4QC8pJ+hVlQgZI5IPpLyRNxvK8=")
    ok = verify_message(a, s, m, netcode="BTC")
    assert ok

    # testnet example
    # Sampled from: http://testnet.bitrated.com/u/bearbin.txt on Sep 3/2014
    # NOTE: Testnet3
    bearbin = """\
Username: bearbin
Public key: 03fc594c16779054fc5e119c309215c1f40f2ce104b0169cddeb6d20445bd28f67
Public key address: n2D9XsQX1mDpFGgYqsfmePTy61LJFQnXQM
URL: http://testnet.bitrated.com/u/bearbin

-----BEGIN BITCOIN SIGNED MESSAGE-----
Contact
-----------

[email protected] - Email or hangouts (text only).

/u/bearbin on reddit (slow response, not preferred for use with the service, just for contact).

Resolution Guidelines:
-----------------------------

 * Evidence is needed. (e.g. pictures w/ proof that it's you).
 * If anybody fails to respond, money goes to the other person after 2 weeks.
 * Additional terms available on request.

Pricing
----------

 * 0.7% Min 0.003 Max 0.15
 * Payment in advance.
-----BEGIN SIGNATURE-----
n2D9XsQX1mDpFGgYqsfmePTy61LJFQnXQM
IEackZgifpBJs3SqQQ6leUwzvakTZgUKTDuCCn6rVMOQgHlIEzWSYZGQu2H+1chvu68uutzt04cGmsHy/kRIaEc=
-----END BITCOIN SIGNED MESSAGE-----
"""
    m, a, s = parse_signed_message(bearbin)
    assert a == "n2D9XsQX1mDpFGgYqsfmePTy61LJFQnXQM"
    assert s == ("IEackZgifpBJs3SqQQ6leUwzvakTZgUKTDuCCn6rVMOQgH" "lIEzWSYZGQu2H+1chvu68uutzt04cGmsHy/kRIaEc=")
    ok = verify_message(a, s, m, netcode="XTN")
    assert ok