Ejemplo n.º 1
0
    def get_aes_key_impl(cls, pin_pubkey, pin_secret, aes_pin_data_key):
        # Load the data from the pubkey
        pin_pubkey_hash = bytes(sha256(pin_pubkey))
        saved_hps, saved_key, counter = cls._load_pin_fields(
            pin_pubkey_hash, pin_pubkey, aes_pin_data_key)

        # Check that the pin provided matches that saved
        hash_pin_secret = sha256(pin_secret)
        if compare_digest(saved_hps, hash_pin_secret):
            # pin-secret matches - correct pin
            if counter != 0:
                # Zero the 'bad guess counter'
                cls._save_pin_fields(pin_pubkey_hash, saved_hps, saved_key,
                                     pin_pubkey, aes_pin_data_key)

            # return the saved key
            return saved_key

        # user provided wrong pin
        if counter >= 2:
            # pin failed 3 times, overwrite and then remove secret
            cls._save_pin_fields(pin_pubkey_hash, saved_hps,
                                 bytearray(AES_KEY_LEN_256), pin_pubkey,
                                 aes_pin_data_key)
            cls.storage.remove(pin_pubkey_hash)
            raise Exception("Too many attempts")
        else:
            # increment counter
            cls._save_pin_fields(pin_pubkey_hash, saved_hps, saved_key,
                                 pin_pubkey, aes_pin_data_key, counter + 1)
            raise Exception("Invalid PIN")
Ejemplo n.º 2
0
    def set_pin(cls, cke, payload, aes_pin_data_key):
        pin_secret, entropy, pin_pubkey = cls._extract_fields(cke, payload)

        # Make a new aes-key to persist from our and client entropy
        our_random = os.urandom(32)
        new_key = hmac_sha256(our_random, entropy)

        # Persist the pin fields
        pin_pubkey_hash = bytes(sha256(pin_pubkey))
        hash_pin_secret = sha256(pin_secret)
        saved_key = cls._save_pin_fields(pin_pubkey_hash, hash_pin_secret,
                                         new_key, pin_pubkey, aes_pin_data_key)

        # Combine saved key with (not persisted) pin-secret
        return cls.make_client_aes_key(pin_secret, saved_key)
Ejemplo n.º 3
0
    def new_static_client_keys(cls):
        private_key, public_key = PINClientECDH.generate_ec_key_pair()

        # Cache the pinfile for this client key so we can ensure it is removed
        pinfile = bytes(sha256(public_key))
        cls.pinfiles.add(bytes(pinfile))

        # Return the keys and the pin-filename
        return private_key, public_key, pinfile
Ejemplo n.º 4
0
    def handshake(self, e_ecdh_server_public_key, static_server_signature):
        ec_sig_verify(self.static_server_public_key,
                      sha256(e_ecdh_server_public_key), EC_FLAG_ECDSA,
                      static_server_signature)

        # Store the ecdh server public key (ske)
        self.ecdh_server_public_key = e_ecdh_server_public_key

        # Cache the shared secrets
        self.generate_shared_secrets(e_ecdh_server_public_key)
Ejemplo n.º 5
0
    def new_keys(cls):
        # USE ECDH class just because it's convenient way to make key pairs
        sig_priv, sig_pub = E_ECDH.generate_ec_key_pair()
        _, cke = E_ECDH.generate_ec_key_pair()

        # add the pin_pubkey_hash to the set
        pin_pubkey_hash = bytes(sha256(sig_pub))
        cls.pinfiles.add(pin_pubkey_hash)

        return sig_priv, sig_pub, cke, pin_pubkey_hash
Ejemplo n.º 6
0
    def _extract_fields(cls, cke, data):
        assert len(data) == (2 * SHA256_LEN) + EC_SIGNATURE_RECOVERABLE_LEN

        # secret + entropy + sig
        pin_secret = data[:SHA256_LEN]
        entropy = data[SHA256_LEN:SHA256_LEN + SHA256_LEN]
        sig = data[SHA256_LEN + SHA256_LEN:]

        # We know mesage the signature is for, so can recover the public key
        signed_msg = sha256(cke + pin_secret + entropy)
        client_public_key = ec_sig_to_public_key(signed_msg, sig)

        return pin_secret, entropy, client_public_key
Ejemplo n.º 7
0
    def file_static_client_keys(cls):
        pubfile = open(client_public_key, 'rb')
        public_key = pubfile.read()
        pubfile.close()

        privfile = open(client_private_key, 'rb')
        private_key = privfile.read()
        privfile.close()

        # Cache the pinfile for this client key so we can ensure it is removed
        pinfile = bytes(sha256(public_key))
        #cls.pinfiles.add(bytes(pinfile))

        # Return the keys and the pin-filename
        return private_key, public_key, pinfile
Ejemplo n.º 8
0
    def test_save_and_load_pin_fields(self):
        # Reinitialise keys and secret
        _, _, _, pinfile = self.new_keys()
        pin_secret, key_in = self.new_pin_secret(), self.new_entropy()
        hps_in = sha256(pin_secret)
        count_in = 5

        # Trying to read non-existent file throws (and does not create file)
        self.assertFalse(PINDb.storage.exists(pinfile))
        with self.assertRaises((FileNotFoundError, Exception)) as _:
            PINDb._load_pin_fields(pinfile, None, None)
        self.assertFalse(PINDb.storage.exists(pinfile))

        user_id = os.urandom(32)
        aes_pin = bytes(os.urandom(32))

        # Save some data - check new file created
        new_key = PINDb._save_pin_fields(pinfile, hps_in, key_in, user_id,
                                         aes_pin, count_in)
        self.assertTrue(PINDb.storage.exists(pinfile))

        # Atm the 'new key' returned should be the one passed in
        self.assertEqual(new_key, key_in)

        # Read file back in - ensure fields the same
        hps_out, key_out, count_out = PINDb._load_pin_fields(
            pinfile, user_id, aes_pin)
        self.assertEqual(hps_out, hps_in)
        self.assertEqual(key_out, key_in)
        self.assertEqual(count_out, count_in)

        # Ensure we can set zero the count of an existing file
        count_in = 0
        new_key = PINDb._save_pin_fields(pinfile, hps_in, key_in, user_id,
                                         aes_pin, count_in)
        hps_out, key_out, count_out = PINDb._load_pin_fields(
            pinfile, user_id, aes_pin)
        self.assertEqual(hps_out, hps_in)
        self.assertEqual(key_out, key_in)
        self.assertEqual(count_out, count_in)

        # Ensure we can't decrypt the pin with the wrong aes_key, hmac won't match
        bad_aes = os.urandom(32)
        with self.assertRaises(AssertionError) as _:
            PINDb._load_pin_fields(pinfile, user_id, bad_aes)
Ejemplo n.º 9
0
    def server_call(self, private_key, client, endpoint, pin_secret, entropy):
        # Make and encrypt the payload (ie. pin secret)
        ske, cke = client.get_key_exchange()
        sig = ec_sig_from_bytes(private_key,
                                sha256(cke + pin_secret + entropy),
                                EC_FLAG_ECDSA | EC_FLAG_RECOVERABLE)
        payload = pin_secret + entropy + sig

        encrypted, hmac = client.encrypt_request_payload(payload)

        # Make call and parse response
        urldata = {
            'ske': b2h(ske),
            'cke': b2h(cke),
            'encrypted_data': b2h(encrypted),
            'hmac_encrypted_data': b2h(hmac)
        }
        response = self.post(endpoint, urldata)
        encrypted = h2b(response['encrypted_key'])
        hmac = h2b(response['hmac'])

        # Return decrypted payload
        return client.decrypt_response_payload(encrypted, hmac)
Ejemplo n.º 10
0
# Create the contact and calculate the asset id (Needed for asset registry!)
contract = json.dumps(
    {
        'name': name,
        'ticker': ticker,
        'precision': precision,
        'entity': {
            'domain': domain
        },
        'issuer_pubkey': issuer_pubkey,
        'version': version
    },
    separators=(',', ':'),
    sort_keys=True)
contract_hash = wally.hex_from_bytes(wally.sha256(contract.encode('ascii')))
a = wally.hex_from_bytes(
    wally.hex_to_bytes(prev_tx)[::-1]) + wally.hex_from_bytes(
        struct.pack('<L', int(prev_vout)))
a = wally.hex_from_bytes(wally.sha256d(wally.hex_to_bytes(a)))
b = a + contract_hash
merkle = wally.hex_from_bytes(wally.sha256_midstate(wally.hex_to_bytes(b)))
c = merkle + '0000000000000000000000000000000000000000000000000000000000000000'
merkle = wally.hex_from_bytes(
    wally.sha256_midstate(wally.hex_to_bytes(c))[::-1])
res['asset_id'] = merkle
res['contract'] = contract
res['contract_hash'] = contract_hash

# Create the rawissuance transaction
contract_hash_rev = wally.hex_from_bytes(
Ejemplo n.º 11
0
def witness(script_bin):
    # PUSH(OP_0 PUSH(sha256(script_bin)))
    return _b('220020') + sha256(script_bin)
Ejemplo n.º 12
0
                                entropy)

    def set_pin(self, private_key, pin_secret, entropy):
        # Create new ephemeral client, initiate handshake, and make call
        client = self.new_client_handshake()
        return self.server_call(private_key, client, 'set_pin', pin_secret,
                                entropy)


if __name__ == '__main__':
    test = PinServerClient()
    # Make ourselves a static key pair for this logical client
    priv_key, _, _ = test.file_static_client_keys()

    # The 'correct' client pin
    pin_secret = bytes(sha256(b'pippo'))

    # Make a new client and set the pin secret to get a new aes key
    aeskey_s = test.set_pin(priv_key, pin_secret, test.new_entropy())
    if not len(aeskey_s) == AES_KEY_LEN_256:
        print('dimension!')

    iv = priv_key[0:16]
    encrypted = aes.AES(aeskey_s).encrypt_ctr(b'Attack at dawn', iv)
    iv = priv_key[0:16]
    print(aes.AES(aeskey_s).decrypt_ctr(encrypted, iv))
    print('---')

    # Get key with a new client, with the correct pin secret (new entropy)
    for attempt in range(5):
        aeskey_g = test.get_pin(priv_key, pin_secret, test.new_entropy())
Ejemplo n.º 13
0
    def _sign_with_static_key(cls, msg):
        cls._load_private_key()

        hashed = sha256(msg)
        return ec_sig_from_bytes(cls.STATIC_SERVER_PRIVATE_KEY, hashed,
                                 EC_FLAG_ECDSA)
Ejemplo n.º 14
0
 def make_payload(signing_key, cke, secret_in, entropy_in):
     # Build the expected payload
     sig = ec_sig_from_bytes(signing_key,
                             sha256(cke + secret_in + entropy_in),
                             EC_FLAG_ECDSA | EC_FLAG_RECOVERABLE)
     return secret_in + entropy_in + sig
Ejemplo n.º 15
0
 def get_shared_nonce(self, pubkey: bytes, script: bytes) -> bytes:
     our_privkey = self.get_private_blinding_key(script)
     nonce = wally.sha256(wally.ecdh(pubkey, our_privkey))
     return nonce
Ejemplo n.º 16
0
def issuer(asset_amount, asset_address, token_amount, token_address,
           issuer_pubkey, name, ticker, precision, domain):
    data = {}
    version = 0  # don't change
    blind = False
    feerate = 0.00003000

    asset_amount = int(asset_amount) / 10**(8 - int(precision))
    token_amount = int(token_amount) / 10**(8 - int(precision))

    # Create funded base tx
    base = host.call('createrawtransaction', [], [{'data': '00'}])
    funded = host.call('fundrawtransaction', base, {'feeRate': feerate})

    # Create the contact and calculate the asset id (Needed for asset registry!)
    contract = json.dumps(
        {
            'name': name,
            'ticker': ticker,
            'precision': int(precision),
            'entity': {
                'domain': domain
            },
            'issuer_pubkey': issuer_pubkey,
            'version': version
        },
        separators=(',', ':'),
        sort_keys=True)
    contract_hash = wally.hex_from_bytes(wally.sha256(
        contract.encode('ascii')))
    data['contract'] = contract

    # Create the rawissuance transaction
    contract_hash_rev = wally.hex_from_bytes(
        wally.hex_to_bytes(contract_hash)[::-1])
    rawissue = host.call('rawissueasset', funded['hex'],
                         [{
                             'asset_amount': asset_amount,
                             'asset_address': asset_address,
                             'token_amount': token_amount,
                             'token_address': token_address,
                             'blind': blind,
                             'contract_hash': contract_hash_rev
                         }])

    # Blind the transaction
    blind = host.call('blindrawtransaction', rawissue[0]['hex'], True, [],
                      False)

    # Sign transaction
    signed = host.call('signrawtransactionwithwallet', blind)
    decoded = host.call('decoderawtransaction', signed['hex'])
    data['asset_id'] = decoded['vin'][0]['issuance']['asset']

    # Test transaction
    test = host.call('testmempoolaccept', [signed['hex']])
    if test[0]['allowed'] is True:
        txid = host.call('sendrawtransaction', signed['hex'])
        data['txid'] = txid
        data['registry'] = json.dumps({
            'asset_id': data['asset_id'],
            'contract': json.loads(data['contract'])
        })

    return data
Ejemplo n.º 17
0
import sys

b2h = wally.hex_from_bytes

if (len(sys.argv) != 2):
    print("Use " + sys.argv[0] + " minikey")
    exit()

minikey = sys.argv[1]

PREFIX = int('80', 16)  # wif prv
VERSION = int('39', 16)  # address
CA_PREFIX = wally.WALLY_CA_PREFIX_LIQUID  # 0c, confidential address

# check minikey is valid
minikey_checksum = b2h(wally.sha256((minikey + '?').encode()))
assert minikey_checksum[:
                        2] == '00', 'Invalid minikey, incorrect checksum: {}'.format(
                            minikey_checksum)

# compute private key
private_key = wally.sha256(minikey.encode())

# check that private_key is valid
wally.ec_private_key_verify(private_key)

# compute private key in WIF format
private_key_wif = wally.wif_from_bytes(private_key, PREFIX,
                                       wally.WALLY_WIF_FLAG_COMPRESSED)

# compute blinding key
Ejemplo n.º 18
0
 def witness_program(self):
     return wally.sha256(self.witness_script)