Esempio n. 1
0
def find_name_index(name_address, master_privkey_hex, max_tries=25, start=0):
    """
    Given a name's device-specific address and device-specific master key,
    find index from which it was derived.

    Return the index on success
    Return None on failure.
    """

    hdwallet = HDWallet(master_privkey_hex)
    for i in xrange(start, max_tries):
        child_privkey = hdwallet.get_child_privkey(index=i)
        child_pubkey = get_pubkey_hex(child_privkey)

        child_addresses = [
            keylib.public_key_to_address(
                keylib.key_formatting.compress(child_pubkey)),
            keylib.public_key_to_address(
                keylib.key_formatting.decompress(child_pubkey))
        ]

        if str(name_address) in child_addresses:
            return i

    return None
    def get_master_address(self):
        if self.master_address is not None:
            return self.master_address

        hex_privkey = self.get_master_privkey()
        hex_pubkey = get_pubkey_hex(hex_privkey)
        return virtualchain.address_reencode(keylib.public_key_to_address(hex_pubkey))
Esempio n. 3
0
    def get_master_address(self):
        if self.master_address is not None:
            return self.master_address

        hex_privkey = self.get_master_privkey()
        hex_pubkey = get_pubkey_hex(hex_privkey)
        return keylib.public_key_to_address(hex_pubkey)
Esempio n. 4
0
    def get_master_address(self):
        if self.master_address is not None:
            return self.master_address

        hex_privkey = self.get_master_privkey()
        hex_pubkey = get_pubkey_hex(hex_privkey)
        return virtualchain.address_reencode(
            keylib.public_key_to_address(hex_pubkey))
Esempio n. 5
0
    def get_child_address(self, index=0):
        """
        @index is the child index

        Returns:
        child address for given @index
        """

        if self.child_addresses is not None:
            return self.child_addresses[index]

        hex_privkey = self.get_child_privkey(index)
        hex_pubkey = get_pubkey_hex(hex_privkey)
        return keylib.public_key_to_address(hex_pubkey)
    def get_child_address(self, index=0):
        """
        @index is the child index

        Returns:
        child address for given @index
        """

        if self.child_addresses is not None:
            return self.child_addresses[index]

        # force decompressed...
        hex_privkey = self.get_child_privkey(index)
        hex_pubkey = get_pubkey_hex(hex_privkey)
        return virtualchain.address_reencode(keylib.public_key_to_address(hex_pubkey))
Esempio n. 7
0
    def get_child_address(self, index=0):
        """
        @index is the child index

        Returns:
        child address for given @index
        """

        if self.child_addresses is not None:
            return self.child_addresses[index]

        # force decompressed...
        hex_privkey = self.get_child_privkey(index)
        hex_pubkey = get_pubkey_hex(hex_privkey)
        return virtualchain.address_reencode(
            keylib.public_key_to_address(hex_pubkey))
Esempio n. 8
0
def parse_mutable_data_v2(mutable_data_json_txt,
                          public_key_hex,
                          public_key_hash=None,
                          data_hash=None,
                          raw=False):
    """
    Version 2 parser
    Parse a piece of mutable data back into the serialized payload.
    Verify that it was signed by the given public key, or the public key hash.
    If neither are given, then verify that it has the given hash.
    Return the data on success
    Return None on error
    """

    pubk_hex = None
    sig_b64 = None
    data_txt = None
    original_data_txt = None

    if not raw:
        # format: bsk2.pubkey.sigb64.data_len:data,
        parts = mutable_data_json_txt.split(".", 3)
        if len(parts) != 4:
            log.debug("Malformed data: {}".format(mutable_data_json_txt))
            return None

        if parts[0] != 'bsk2':
            log.debug("Not v2 data")
            return None

        pubk_hex = str(parts[1])
        sig_b64 = str(parts[2])
        data_txt = str(parts[3])

        # basic sanity checks
        if not re.match('^[0-9a-fA-F]+$', pubk_hex):
            log.debug("Not a v2 mutable datum: Invalid public key")
            return None

        if not re.match(schemas.OP_BASE64_PATTERN_SECTION, sig_b64):
            log.debug("Not a v2 mutable datum: Invalid signature data")
            return None

        try:
            sig_bin = base64.b64decode(sig_b64)
        except:
            log.error("Incorrect base64-encoding")
            return None

        # data_txt must be a netstring (format: 'len(payload):payload,')
        serialized_len = len(data_txt)
        original_data_txt = data_txt[:]
        data_txt = parse_data_payload(data_txt)
        if data_txt is None:
            log.debug(
                "Invalid data payload of {} bytes".format(serialized_len))
            return None

    else:
        data_txt = mutable_data_json_txt
        original_data_txt = mutable_data_json_txt

    # shortcut: if hash is given, we're done
    if data_hash is not None:
        dh = hash_data_payload(str(data_txt))
        if dh == data_hash:
            # done!
            log.debug("Verified with hash {}".format(data_hash))
            return data_txt

        else:
            log.debug(
                "Hash mismatch: expected {}, got {}\noriginal_data_text ({}): '{}'\nlen(original_data_text): {}\nparsed payload: '{}'\nhash_data_payload: {}"
                .format(data_hash, dh, type(original_data_txt),
                        original_data_txt, len(original_data_txt),
                        parse_data_payload(original_data_txt),
                        hash_data_payload(data_txt)))

    # validate
    if keylib.key_formatting.get_pubkey_format(pubk_hex) == 'hex_compressed':
        pubk_hex = keylib.key_formatting.decompress(pubk_hex)

    if public_key_hex is not None:
        # make sure uncompressed
        given_pubkey_hex = str(public_key_hex)
        if keylib.key_formatting.get_pubkey_format(
                given_pubkey_hex) == 'hex_compressed':
            given_pubkey_hex = keylib.key_formatting.decompress(
                given_pubkey_hex)

        log.debug("Try verify with {}".format(pubk_hex))

        if given_pubkey_hex == pubk_hex:
            if verify_data_payload(data_txt, pubk_hex, sig_b64):
                log.debug(
                    "Verified payload with public key {}".format(pubk_hex))
                return data_txt
            else:
                log.debug("Signature failed")

        else:
            log.debug("Public key mismatch: {} != {}".format(
                given_pubkey_hex, pubk_hex))

    if public_key_hash is not None:
        pubkey_hash = keylib.address_formatting.bin_hash160_to_address(
            keylib.address_formatting.address_to_bin_hash160(
                str(public_key_hash), ),
            version_byte=0)

        log.debug("Try verify with {}".format(pubkey_hash))

        pubk_compressed = keylib.key_formatting.compress(pubk_hex)
        pubk_uncompressed = keylib.key_formatting.decompress(pubk_hex)

        if keylib.public_key_to_address(
                pubk_compressed
        ) == pubkey_hash or keylib.public_key_to_address(
                pubk_uncompressed) == pubkey_hash:
            if verify_data_payload(data_txt, pubk_hex, sig_b64):
                log.debug(
                    "Verified payload with public key hash {} ({})".format(
                        pubk_hex, pubkey_hash))
                return data_txt
            else:
                log.debug("Signature failed with pubkey hash")

        else:
            log.debug("Public key hash mismatch")

    log.debug("Failed to verify v2 mutable datum")
    return None
Esempio n. 9
0
 def test_public_key_to_address_uncompressed(self):
     address = public_key_to_address(self.ref['uncompressed_public_key'])
     self.assertEqual(address, self.ref['uncompressed_address'])
Esempio n. 10
0
def parse_mutable_data_v2(mutable_data_json_txt, public_key_hex, public_key_hash=None, data_hash=None):
    """
    Version 2 parser
    Parse a piece of mutable data back into the serialized payload.
    Verify that it was signed by the given public key, or the public key hash.
    If neither are given, then verify that it has the given hash.
    Return the data on success
    Return None on error
    """

    parts = mutable_data_json_txt.split(".", 2)
    if len(parts) != 3:
        log.debug("Malformed data: {}".format(mutable_data_json_txt))
        return None 

    pubk_hex = str(parts[0])
    sig_b64 = str(parts[1])
    data_txt = str(parts[2])

    if not re.match('^[0-9a-fA-F]+$', pubk_hex):
        log.debug("Not a v2 mutable datum: Invalid public key")
        return None 

    if not re.match(schemas.OP_BASE64_PATTERN_SECTION, sig_b64):
        log.debug("Not a v2 mutable datum: Invalid signature data")
        return None

    # shortcut: if hash is given, we're done 
    if data_hash is not None:
        dh = hashlib.sha256(data_txt.encode('utf-8')).hexdigest()
        if dh == data_hash:
            # done!
            log.debug("Verified with hash {}".format(data_hash))
            return data_txt

        else:
            log.debug("Hash mismatch: expected {}, got {}".format(data_hash, dh))

    # validate 
    if keylib.key_formatting.get_pubkey_format(pubk_hex) == 'hex_compressed':
        pubk_hex = keylib.key_formatting.decompress(pubk_hex)

    try:
        sig_bin = base64.b64decode(sig_b64)
    except:
        log.error("Incorrect base64-encoding")
        return None

    if public_key_hex is not None:
        # make sure uncompressed
        given_pubkey_hex = str(public_key_hex)
        if keylib.key_formatting.get_pubkey_format(given_pubkey_hex) == 'hex_compressed':
            given_pubkey_hex = keylib.key_formatting.decompress(given_pubkey_hex)

        log.debug("Try verify with {}".format(pubk_hex))

        if given_pubkey_hex == pubk_hex:
            if verify_raw_data(data_txt, pubk_hex, sig_bin):
                log.debug("Verified with public key {}".format(pubk_hex))
                return data_txt
            else:
                log.debug("Signature failed")

        else:
            log.debug("Public key mismatch: {} != {}".format(given_pubkey_hex, pubk_hex))

    if public_key_hash is not None:
        pubkey_hash = keylib.address_formatting.bin_hash160_to_address(
                keylib.address_formatting.address_to_bin_hash160(
                    str(public_key_hash),
                ),
                version_byte=0
        )

        log.debug("Try verify with {}".format(pubkey_hash))

        if keylib.public_key_to_address(pubk_hex) == pubkey_hash:
            if verify_raw_data(data_txt, pubk_hex, sig_bin):
                log.debug("Verified with public key hash {} ({})".format(pubk_hex, pubkey_hash))
                return data_txt
            else:
                log.debug("Signature failed with pubkey hash")

        else:
            log.debug("Public key hash mismatch")

    log.debug("Failed to verify v2 mutable datum")
    return None
Esempio n. 11
0
def parse_mutable_data(mutable_data_json_txt,
                       public_key,
                       public_key_hash=None,
                       data_hash=None,
                       bsk_version=None,
                       return_public_key=False):
    """
    Given the serialized JSON for a piece of mutable data,
    parse it into a JSON document.  Verify that it was
    signed by public_key's or public_key_hash's private key.

    Try to verify with both keys, if given.

    Returns:
    * the parsed JSON dict on success (if a profile)
    * the raw data (otherwise)
    * the dict {'data': ..., 'public_key': ...} (if return_public_key is True)

    Return None on error
    """

    # newer version?
    if mutable_data_json_txt.startswith("bsk2.") or bsk_version == 2:
        raw = False
        if not mutable_data_json_txt.startswith("bsk2."):
            # raw data; will authenticate with data hash
            raw = True
            if data_hash is None:
                log.error(
                    "Corrupt data: data text does not start with 'bsk2.', and no data hash given"
                )
                return None

        return parse_mutable_data_v2(mutable_data_json_txt,
                                     public_key,
                                     public_key_hash=public_key_hash,
                                     data_hash=data_hash,
                                     raw=raw,
                                     return_public_key=return_public_key)

    # legacy parser
    assert public_key is not None or public_key_hash is not None, 'Need a public key or public key hash'

    mutable_data_jwt = None
    try:
        mutable_data_jwt = json.loads(mutable_data_json_txt)
        assert isinstance(mutable_data_jwt, (dict, list))
    except:
        # TODO: Check use of catchall exception handler
        log.error('Invalid JSON')
        return None

    mutable_data_json = None

    # try pubkey, if given
    if public_key is not None:
        mutable_data_json = blockstack_profiles.get_profile_from_tokens(
            mutable_data_jwt, str(public_key))

        if len(mutable_data_json) > 0:
            if return_public_key:
                return {
                    'data': mutable_data_json,
                    'public_key': str(public_key)
                }
            else:
                return mutable_data_json

        msg = 'Failed to verify with public key "{}"'
        log.warn(msg.format(public_key))

    # try pubkey address
    if public_key_hash is not None:
        # NOTE: these should always have version byte 0
        # TODO: use jsontokens directly
        public_key_hash_0 = keylib.address_formatting.bin_hash160_to_address(
            keylib.address_formatting.address_to_bin_hash160(
                str(public_key_hash)),
            version_byte=0)

        mutable_data_json = blockstack_profiles.get_profile_from_tokens(
            mutable_data_jwt, public_key_hash_0)

        if len(mutable_data_json) > 0:
            log.debug('Verified with {}'.format(public_key_hash))
            if return_public_key:
                profile_token = jsontokens.decode_token(
                    mutable_data_jwt[0]['token'])
                issuer_public_key = profile_token['payload']['issuer'][
                    'publicKey']

                # use the one that corresponds to the address
                ret_pubkey = None
                if virtualchain.address_reencode(
                        keylib.public_key_to_address(
                            keylib.key_formatting.compress(
                                str(issuer_public_key)))
                ) == virtualchain.address_reencode(str(public_key_hash)):
                    ret_pubkey = keylib.key_formatting.compress(
                        issuer_public_key)
                elif virtualchain.address_reencode(
                        keylib.public_key_to_address(
                            keylib.key_formatting.decompress(
                                str(issuer_public_key)))
                ) == virtualchain.address_reencode(str(public_key_hash)):
                    ret_pubkey = keylib.key_formatting.decompress(
                        issuer_public_key)
                else:
                    raise Exception(
                        "BUG: public key {} does not match {}".format(
                            issuer_public_key, public_key_hash))

                return {'data': mutable_data_json, 'public_key': ret_pubkey}

            else:
                return mutable_data_json

        msg = 'Failed to verify with public key hash "{}" ("{}")'
        log.warn(msg.format(public_key_hash, public_key_hash_0))

    # try sha256 hash
    if data_hash is not None:
        log.error("Verifying profiles by hash it not supported")

    return None
Esempio n. 12
0
 def test_public_key_to_address_2(self):
     public_key = "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"
     address = public_key_to_address(public_key)
     reference_address = "1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm"
     self.assertEqual(address, reference_address)
Esempio n. 13
0
 def test_public_key_to_address(self):
     public_key = "030589ee559348bd6a7325994f9c8eff12bd5d73cc683142bd0dd1a17abc99b0dc"
     address = public_key_to_address(public_key)
     reference_address = "1KbUJ4x8epz6QqxkmZbTc4f79JbWWz6g37"
     self.assertEqual(address, reference_address)
Esempio n. 14
0
 def test_public_key_to_address_2(self):
     public_key = "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"
     address = public_key_to_address(public_key)
     reference_address = "1EHNa6Q4Jz2uvNExL497mE43ikXhwF6kZm"
     self.assertEqual(address, reference_address)
Esempio n. 15
0
 def test_public_key_to_address(self):
     public_key = "030589ee559348bd6a7325994f9c8eff12bd5d73cc683142bd0dd1a17abc99b0dc"
     address = public_key_to_address(public_key)
     reference_address = "1KbUJ4x8epz6QqxkmZbTc4f79JbWWz6g37"
     self.assertEqual(address, reference_address)
Esempio n. 16
0
def get_compressed_and_decompressed_private_key_info(privkey_info):
    """
    Get the compressed and decompressed versions of private keys and addresses
    Return {'compressed_addr': ..., 'compressed_private_key_info': ..., 'decompressed_addr': ..., 'decompressed_private_key_info': ...} on success
    """
    if virtualchain.is_multisig(
            privkey_info) or virtualchain.btc_is_multisig_segwit(privkey_info):

        # get both compressed and decompressed addresses
        privkeys = privkey_info['private_keys']
        m, _ = virtualchain.parse_multisig_redeemscript(
            privkey_info['redeem_script'])
        privkeys_hex = [ecdsa_private_key(pk).to_hex() for pk in privkeys]

        decompressed_privkeys = map(
            lambda pk: pk if len(pk) == 64 else pk[:-2], privkeys_hex)
        compressed_privkeys = map(
            lambda pk: pk
            if len(pk) == 66 and pk[:-2] == '01' else pk, privkeys_hex)

        decompressed_multisig = virtualchain.make_multisig_info(
            m, decompressed_privkeys, compressed=True)
        compressed_multisig = virtualchain.make_multisig_info(
            m, compressed_privkeys, compressed=False)

        decompressed_addr = virtualchain.address_reencode(
            decompressed_multisig['address'])
        compressed_addr = virtualchain.address_reencode(
            compressed_multisig['address'])

        return {
            'decompressed_private_key_info': decompressed_multisig,
            'compressed_private_key_info': compressed_multisig,
            'compressed_addr': compressed_addr,
            'decompressed_addr': decompressed_addr
        }

    elif virtualchain.is_singlesig(
            privkey_info) or virtualchain.btc_is_singlesig_segwit(
                privkey_info):

        pk = virtualchain.get_singlesig_privkey(privkey_info)

        # get both compressed and decompressed addresses
        compressed_pk = None
        decompressed_pk = None
        if len(pk) == 66 and pk.endswith('01'):
            compressed_pk = pk
            decompressed_pk = pk[:-2]
        else:
            compressed_pk = pk
            decompressed_pk = pk + '01'

        compressed_pubk = ecdsa_private_key(
            compressed_pk).public_key().to_hex()
        decompressed_pubk = ecdsa_private_key(
            decompressed_pk).public_key().to_hex()

        compressed_addr = virtualchain.address_reencode(
            keylib.public_key_to_address(compressed_pubk))
        decompressed_addr = virtualchain.address_reencode(
            keylib.public_key_to_address(decompressed_pubk))

        return {
            'decompressed_private_key_info': decompressed_pk,
            'compressed_private_key_info': compressed_pk,
            'compressed_addr': compressed_addr,
            'decompressed_addr': decompressed_addr
        }

    else:
        raise ValueError("Invalid key bundle")