예제 #1
0
def verify_signature_files(signature_files:Sequence[str], threshold:int=None) -> bool:
    
    # Get data from signature share file
    
    parties_ids = []
    signature_shares = {}
    master_pubkey = None
    msg = None
    derivation_index = None
    for sig_file in signature_files:
        in_data = {}
        try:
            in_file = open(sig_file, "r")
            in_data = json.load(in_file)
            in_file.close()
        except:
            raise GenVerErrorBasic(f'Reading key file {sig_file}')
            
        try:
            # Verify same master pubkey
            curr_master_pubkey = bytes.fromhex(in_data['master_pubkey'])
            if master_pubkey:
                if not master_pubkey == curr_master_pubkey:
                    raise GenVerErrorBasic(f'Different master pubkey in different files')
            else:
                master_pubkey = curr_master_pubkey

            # Verify same message
            curr_msg = in_data['message']
            if msg:
                if not msg == curr_msg:
                    raise GenVerErrorBasic(f'Different messages in different files')
            else:
                msg = curr_msg

            # Verify same derivation indx
            curr_index = in_data['derivation_index']
            if derivation_index:
                if not derivation_index == curr_index:
                    raise GenVerErrorBasic(f'Different derivation index in different files')
            else:
                derivation_index = curr_index

            curr_id = int(in_data['signer_id'])
            parties_ids.append(curr_id)
            signature_shares[curr_id] = bytes.fromhex(in_data['signature'])
        except:
            raise GenVerErrorBasic(f'Parsing key file {sig_file}')

    msg_str = msg['payload']
    if msg['hex']:
        try:
            msg_bytes = bytes.fromhex(msg['payload'])
        except:
            raise GenVerErrorBasic(f'Message string is not hex')
    else:
        msg_bytes = bytes(msg_str, 'ascii')
    
    # Convert signature shares to G2 elements to later interpolate on
    G2_signature_shares = {}
    for id, sig in signature_shares.items():
        try:
            G2_signature_shares[id] = bls_conv.signature_to_G2(sig)
        except:
            raise GenVerErrorBasic(f'Invalid encoding of signature for id {id}')
        
    if not threshold:
        threshold = len(parties_ids)

    der_path = index_to_path(derivation_index)
    derived_pubkey_address = bls_conv.G1_to_pubkey(derive_public_child(master_pubkey, der_path))
    
    print(f'Verifying signing threshold {threshold} out of {len(parties_ids)} parties')
    print("Message:", colored(msg_str, "green"))
    print("Public Key:", colored(derived_pubkey_address.hex(), "green"))
    
    # Verify joining threshold singature shares gives a valid signature
    auth_signature = b''
    for auth_ids in itertools.combinations(parties_ids, threshold):
        auth_signature = bls_conv.G2_to_signature(_interpolate_in_group({id : G2_signature_shares[id] for id in auth_ids}, bls_curve.G2))

        if not bls_basic.Verify(derived_pubkey_address, msg_bytes, auth_signature):
            raise GenVerErrorBasic(f'Failed verification of combined signature for id {auth_ids}.')
    
    print("Signature:", colored(auth_signature.hex(), "green"))
    print(colored("Success!", "green"))
    
    return True
예제 #2
0
def test_verify(pubkey, message, signature, result):
    assert G2Basic.Verify(pubkey, message, signature) == result
예제 #3
0
def verify_key_file(key_file:str, passphrase:str, rsa_priv_key_file:str=None):
    try:
        in_file = open(key_file, "r")
        data = json.load(in_file)
        in_file.close()
    except:
        raise GenVerErrorBasic(f'Reading key file {key_file}')

    try:
        master_pubkey = bytes.fromhex(data['master_pubkey'])
        integrity_checksum = bytes.fromhex(data['integrity_checksum'])

        threshold = data['threshold']
        my_id = data['key_id']
        parties = data['parties']

        encrypted_private_key_share = bytes.fromhex(parties[f'{my_id}']['encrypted_master_private_key_share'])
        encrypted_integrity_passphrase = bytes.fromhex(parties[f'{my_id}']['encrypted_integrity_passphrase'])

        parties_ids = []
        test_signature_shares = {}
        for id_str, party in parties.items():
            try:
                id = int(id_str)
            except:
                raise GenVerErrorBasic(f'Invalid id {id_str}')
            parties_ids.append(id)
            test_signature_shares[id] = bytes.fromhex(party['test_signature_share'])
        
    except:
        raise GenVerErrorBasic(f'Error parsing key file')

    # If Given RSA private key, use it to get integrity passphrase (if no file, assume integrity passphrase is given)
    master_private_key_share = None
    if rsa_priv_key_file is None:
        integrity_passphrase = bytes(passphrase, 'utf-8')
    else: 
        try:
            in_file = open(rsa_priv_key_file, 'r')
            rsa_key = RSA.importKey(in_file.read(), passphrase=passphrase)
            cipher = PKCS1_OAEP.new(rsa_key)
            in_file.close()
        except:
            raise GenVerErrorBasic(f'Importing RSA key from file {rsa_priv_key_file} (perhaps wrong passphrase)')

        if not rsa_key.has_private():
            raise GenVerErrorBasic(f'Not a private RSA key file {rsa_priv_key_file}')
        
        try:
            master_private_key_share = cipher.decrypt(encrypted_private_key_share)
        except:
            raise GenVerErrorBasic(f'Invalid decryption of private key share from key file')
            
        try:
            integrity_passphrase = cipher.decrypt(encrypted_integrity_passphrase)
        except:
            raise GenVerErrorBasic(f'Invalid decryption of integrity passphrase from key file')

    # Sanity checks

    if threshold > len(parties_ids) or threshold < 1:
        raise GenVerErrorBasic(f'Invalid threhsold {threshold} for ids {parties_ids}')

    if (len(parties_ids) != len(set(parties_ids))):
        raise GenVerErrorBasic(f'Non-unique ids in verification file')
    
    test_derivation_path = _get_test_path()
    derived_public_key = derive_public_child(master_pubkey, test_derivation_path)
    derived_pubkey_address = bls_conv.G1_to_pubkey(derived_public_key)
    test_msg, _ = _get_msg_for_address(derived_pubkey_address)

    # If decrypted master_private_key Verify my own signature wasn't modified by signing again
    if master_private_key_share:
        derived_private_key_share = derive_private_child(master_private_key_share, test_derivation_path, master_pubkey)
        if not test_signature_shares[my_id] == bls_basic.Sign(derived_private_key_share, test_msg):
            raise GenVerErrorBasic(f'Modified signature share for my key id {my_id}')
    else:
        print(colored('No RSA key - not verifying private key share validity!', "cyan"))
    
    # After getting scrypt integrity passphrase validate master pubkey wasn't changed
    computed_checksum = _compute_scrypt_checksum(integrity_passphrase, master_pubkey)

    if not computed_checksum == integrity_checksum:
        raise GenVerErrorBasic(f'Failure in validating master public key integrity checksum (perhaps wrong passphrase)')

    # Convert to group elements to allow interpolation of signatures
    G2_signature_shares = {}
    for id, sig in test_signature_shares.items():
        try:
            G2_signature_shares[id] = bls_conv.signature_to_G2(sig)
        except:
            raise GenVerErrorBasic(f'Invalid encoding of signature shares for id {id}')

    # For each authorized set of the above, combine signature shares and verify

    print(f'Verifying signing threshold {threshold} out of {len(parties_ids)} parties...')
    
    for auth_ids in itertools.combinations(parties_ids, threshold):
        auth_signature = bls_conv.G2_to_signature(_interpolate_in_group({id : G2_signature_shares[id] for id in auth_ids}, bls_curve.G2))
        if not  bls_basic.Verify(derived_pubkey_address, test_msg, auth_signature):
            raise GenVerErrorBasic(f'Failed verification of combined signature for ids {auth_ids}')
    
    # Sanity check: check un-authorized set can't get valid signature (less then threhsold) 
    for auth_ids in itertools.combinations(parties_ids, threshold-1):        
        auth_signature = bls_conv.G2_to_signature(_interpolate_in_group({id : G2_signature_shares[id] for id in auth_ids}, bls_curve.G2))
        if bls_basic.Verify(derived_pubkey_address, test_msg, auth_signature):
            raise GenVerErrorBasic(f'Valid signature for unauthorized ids {auth_ids}')

    print(colored("Success!", "green"))
    return True