Ejemplo n.º 1
0
    def secret_key(self, passphrase=None, ed25519_seed=True):
        """
        Creates base58 encoded private key representation
        :param passphrase: encryption phrase for the private key
        :param ed25519_seed: encode seed rather than full key for ed25519 curve (True by default)
        :return: the secret key associated with this key, if available
        """
        if not self.secret_exponent:
            raise ValueError("Secret key not known.")

        if self.curve == b'ed' and ed25519_seed:
            key = pysodium.crypto_sign_sk_to_seed(self.secret_exponent)
        else:
            key = self.secret_exponent

        if passphrase:
            if not ed25519_seed:
                raise NotImplementedError

            salt = pysodium.randombytes(8)
            encryption_key = hashlib.pbkdf2_hmac(
                hash_name="sha512",
                password=scrub_input(passphrase),
                salt=salt,
                iterations=32768,
                dklen=32)
            encrypted_sk = pysodium.crypto_secretbox(msg=key,
                                                     nonce=b'\000' * 24,
                                                     k=encryption_key)
            key = salt + encrypted_sk  # we have to combine salt and encrypted key in order to decrypt later
            prefix = self.curve + b'esk'
        else:
            prefix = self.curve + b'sk'

        return base58_encode(key, prefix).decode()
Ejemplo n.º 2
0
    def sign(self, message, generic=False):
        """
        Sign a raw sequence of bytes
        :param message: sequence of bytes, raw format or hexadecimal notation
        :param generic: do not specify elliptic curve if set to True
        :return: signature in base58 encoding
        """
        message = scrub_input(message)

        if not self.is_secret:
            raise ValueError("Cannot sign without a secret key.")

        # Ed25519
        if self.curve == b"ed":
            digest = pysodium.crypto_generichash(message)
            signature = pysodium.crypto_sign_detached(digest, self._secret_key)
        # Secp256k1
        elif self.curve == b"sp":
            pk = secp256k1.PrivateKey(self._secret_key)
            signature = pk.ecdsa_serialize_compact(
                pk.ecdsa_sign(message, digest=blake2b_32))
        # P256
        elif self.curve == b"p2":
            r, s = sign(msg=message, d=bytes_to_int(self._secret_key), hashfunc=blake2b_32)
            signature = int_to_bytes(r) + int_to_bytes(s)
        else:
            assert False

        if generic:
            prefix = b'sig'
        else:
            prefix = self.curve + b'sig'

        return base58_encode(signature, prefix).decode()
Ejemplo n.º 3
0
    def verify(self, signature, message):
        """ Verify signature, raise exception if it is not valid.

        :param message: sequance of bytes, raw format or hexadecimal notation
        :param signature: a signature in base58 encoding
        :raises: ValueError if signature is not valid
        """
        signature = scrub_input(signature)
        message = scrub_input(message)

        if not self.public_point:
            raise ValueError("Cannot verify without a public key")

        if signature[:3] != b'sig':  # not generic
            if self.curve != signature[:2]:  # "sp", "p2" "ed"
                raise ValueError("Signature and public key curves mismatch.")

        signature = base58_decode(signature)

        # Ed25519
        if self.curve == b"ed":
            digest = pysodium.crypto_generichash(message)
            try:
                pysodium.crypto_sign_verify_detached(signature, digest,
                                                     self.public_point)
            except ValueError:
                raise ValueError('Signature is invalid.')
        # Secp256k1
        elif self.curve == b"sp":
            pk = secp256k1.PublicKey(self.public_point, raw=True)
            sig = pk.ecdsa_deserialize_compact(signature)
            if not pk.ecdsa_verify(message, sig, digest=blake2b_32):
                raise ValueError('Signature is invalid.')
        # P256
        elif self.curve == b"p2":
            pk = fastecdsa.encoding.sec1.SEC1Encoder.decode_public_key(
                self.public_point, curve=fastecdsa.curve.P256)
            r, s = bytes_to_int(signature[:32]), bytes_to_int(signature[32:])
            if not fastecdsa.ecdsa.verify(
                    sig=(r, s), msg=message, Q=pk, hashfunc=blake2b_32):
                raise ValueError('Signature is invalid.')
        else:
            assert False
Ejemplo n.º 4
0
    def from_encoded_key(cls, key, passphrase=''):
        """
        Creates a key object from a base58 encoded key.
        :param key: a public or secret key in base58 encoding
        :param passphrase: the passphrase used if the key provided is an encrypted private key
        """
        key = scrub_input(key)

        curve = key[:2]  # "sp", "p2" "ed"
        if curve not in [b'sp', b'p2', b'ed']:
            raise ValueError("Invalid prefix for a key encoding.")
        if not len(key) in [54, 55, 88, 98]:
            raise ValueError("Invalid length for a key encoding.")

        encrypted = (key[2:3] == b'e')
        public_or_secret = key[3:5] if encrypted else key[2:4]
        if public_or_secret not in [b'pk', b'sk']:
            raise Exception("Invalid prefix for a key encoding.")

        key = base58_decode(key)
        is_secret = (public_or_secret == b'sk')
        if not is_secret:
            return cls.from_public_point(key, curve)

        if encrypted:
            if not passphrase:
                raise ValueError(
                    "Encrypted key provided without a passphrase.")

            salt, encrypted_sk = key[:8], key[8:]
            encryption_key = hashlib.pbkdf2_hmac(
                hash_name="sha512",
                password=scrub_input(passphrase),
                salt=salt,
                iterations=32768,
                dklen=32)
            key = pysodium.crypto_secretbox_open(c=encrypted_sk,
                                                 nonce=b'\000' * 24,
                                                 k=encryption_key)
            del passphrase

        return cls.from_secret_exponent(key, curve)
Ejemplo n.º 5
0
 def test_scrub_input(self, input_data, expected):
     self.assertEqual(expected, scrub_input(input_data))
Ejemplo n.º 6
0
def blake2b_32(v=b''):
    return blake2b(scrub_input(v), digest_size=32)
Ejemplo n.º 7
0
def blake2b_32(v=b''):
    """ Get a BLAKE2B hash of bytes
    """
    return blake2b(scrub_input(v), digest_size=32)