Exemple #1
0
    def generate(
            public_key,
            encryption_alg="AES-PMAC-SIV",
            digest_alg=hashes.SHA256(),
            salt=None,
            csrng=os.urandom,
    ):
        """
        Generate an XSTREAM encryptor object with a random ephemeral key

        :param public_key: 32-byte X25519 public key (i.e. compressed Montgomery-u coordinate)
        :param encryption_alg: symmetric encryption algorithm to use with STREAM (default "AES-PMAC-SIV")
        :param digest_alg: digest algorithm to use with HKDF (default "SHA256")
        :param salt: (optional) salt value to pass to HKDF (default None)
        :param csrng: (optional) secure random number generator used to generate ephemeral key (default os.urandom)
        :return: STREAM encryptor and ephemeral public key
        """
        ephemeral_scalar = X25519PrivateKey._from_private_bytes(
            csrng(X25519_KEY_SIZE))

        symmetric_key = kdf(
            private_key=ephemeral_scalar,
            public_key=X25519PublicKey.from_public_bytes(public_key),
            digest_alg=digest_alg,
            length=SYMMETRIC_KEY_SIZE,
            salt=salt)

        enc = Encryptor(encryption_alg, symmetric_key, NONCE)
        return enc, ephemeral_scalar.public_key().public_bytes()
Exemple #2
0
    def __init__(self,
                 private_key,
                 ephemeral_public,
                 encryption_alg="AES-PMAC-SIV",
                 digest_alg=hashes.SHA256(),
                 salt=None):
        """
        Create an XSTREAM decryptor object using our private key and an ephemeral public key

        :param private_key: 32-byte X25519 private key (i.e. private scalar)
        :param ephemeral_public: 32-byte X25519 ephemeral public key from XSTREAM encryption
        :param encryption_alg: symmetric encryption algorithm to use with STREAM (default "AES-PMAC-SIV")
        :param digest_alg: digest algorithm to use with HKDF (default "SHA256")
        :param salt: (optional) salt value to pass to HKDF (default None)
        """

        # Perform an X25519 elliptic curve Diffie-Hellman operation and use
        # the resulting shared secret to derive a symmetric key (using HKDF)
        symmetric_key = kdf(
            private_key=X25519PrivateKey._from_private_bytes(private_key),
            public_key=X25519PublicKey.from_public_bytes(ephemeral_public),
            digest_alg=digest_alg,
            length=SYMMETRIC_KEY_SIZE,
            salt=salt)

        super(Decryptor, self).__init__(encryption_alg, symmetric_key, NONCE)
Exemple #3
0
 def test_rfc7748(self, vector, backend):
     private = binascii.unhexlify(vector["input_scalar"])
     public = binascii.unhexlify(vector["input_u"])
     shared_key = binascii.unhexlify(vector["output_u"])
     private_key = X25519PrivateKey._from_private_bytes(private)
     public_key = X25519PublicKey.from_public_bytes(public)
     computed_shared_key = private_key.exchange(public_key)
     assert computed_shared_key == shared_key
Exemple #4
0
    def test_rfc7748_1000_iteration(self, backend):
        old_private = private = public = binascii.unhexlify(
            b"090000000000000000000000000000000000000000000000000000000000"
            b"0000")
        shared_key = binascii.unhexlify(
            b"684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d9953"
            b"2c51")
        private_key = X25519PrivateKey._from_private_bytes(private)
        public_key = X25519PublicKey.from_public_bytes(public)
        for _ in range(1000):
            computed_shared_key = private_key.exchange(public_key)
            private_key = X25519PrivateKey._from_private_bytes(
                computed_shared_key)
            public_key = X25519PublicKey.from_public_bytes(old_private)
            old_private = computed_shared_key

        assert computed_shared_key == shared_key
Exemple #5
0
 def test_rfc7748(self, vector, backend):
     private = binascii.unhexlify(vector["input_scalar"])
     public = binascii.unhexlify(vector["input_u"])
     shared_key = binascii.unhexlify(vector["output_u"])
     private_key = X25519PrivateKey._from_private_bytes(private)
     public_key = X25519PublicKey.from_public_bytes(public)
     computed_shared_key = private_key.exchange(public_key)
     assert computed_shared_key == shared_key
Exemple #6
0
    def test_rfc7748_1000_iteration(self, backend):
        old_private = private = public = binascii.unhexlify(
            b"090000000000000000000000000000000000000000000000000000000000"
            b"0000"
        )
        shared_key = binascii.unhexlify(
            b"684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d9953"
            b"2c51"
        )
        private_key = X25519PrivateKey._from_private_bytes(private)
        public_key = X25519PublicKey.from_public_bytes(public)
        for _ in range(1000):
            computed_shared_key = private_key.exchange(public_key)
            private_key = X25519PrivateKey._from_private_bytes(
                computed_shared_key
            )
            public_key = X25519PublicKey.from_public_bytes(old_private)
            old_private = computed_shared_key

        assert computed_shared_key == shared_key
Exemple #7
0
 def test_null_shared_key_raises_error(self, backend):
     """
     The vector used here is taken from wycheproof's x25519 test vectors
     """
     public = binascii.unhexlify(
         "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157")
     private = binascii.unhexlify(
         "78f1e8edf14481b389448dac8f59c70b038e7cf92ef2c7eff57a72466e115296")
     private_key = X25519PrivateKey._from_private_bytes(private)
     public_key = X25519PublicKey.from_public_bytes(public)
     with pytest.raises(ValueError):
         private_key.exchange(public_key)
Exemple #8
0
 def test_null_shared_key_raises_error(self, backend):
     """
     The vector used here is taken from wycheproof's x25519 test vectors
     """
     public = binascii.unhexlify(
         "5f9c95bca3508c24b1d0b1559c83ef5b04445cc4581c8e86d8224eddd09f1157"
     )
     private = binascii.unhexlify(
         "78f1e8edf14481b389448dac8f59c70b038e7cf92ef2c7eff57a72466e115296"
     )
     private_key = X25519PrivateKey._from_private_bytes(
         private
     )
     public_key = X25519PublicKey.from_public_bytes(public)
     with pytest.raises(ValueError):
         private_key.exchange(public_key)
Exemple #9
0
def test_x25519(backend, wycheproof):
    assert list(wycheproof.testgroup.items()) == [("curve", "curve25519")]

    private_key = X25519PrivateKey._from_private_bytes(
        binascii.unhexlify(wycheproof.testcase["private"]))
    public_key = X25519PublicKey.from_public_bytes(
        binascii.unhexlify(wycheproof.testcase["public"]))

    assert wycheproof.valid or wycheproof.acceptable

    expected = binascii.unhexlify(wycheproof.testcase["shared"])
    if expected == b"\x00" * 32:
        assert wycheproof.acceptable
        # OpenSSL returns an error on all zeros shared key
        with pytest.raises(ValueError):
            private_key.exchange(public_key)
    else:
        assert private_key.exchange(public_key) == expected
Exemple #10
0
 def test_public_bytes(self, private_bytes, public_bytes, backend):
     private_key = X25519PrivateKey._from_private_bytes(private_bytes)
     assert private_key.public_key().public_bytes() == public_bytes
     public_key = X25519PublicKey.from_public_bytes(public_bytes)
     assert public_key.public_bytes() == public_bytes
Exemple #11
0
 def test_public_bytes(self, private_bytes, public_bytes, backend):
     private_key = X25519PrivateKey._from_private_bytes(private_bytes)
     assert private_key.public_key().public_bytes() == public_bytes
     public_key = X25519PublicKey.from_public_bytes(public_bytes)
     assert public_key.public_bytes() == public_bytes