Skip to content

Commit

Permalink
Convert ed25519 to Rust (#8697)
Browse files Browse the repository at this point in the history
  • Loading branch information
alex authored Apr 10, 2023
1 parent d5db3d4 commit f5c750d
Show file tree
Hide file tree
Showing 11 changed files with 320 additions and 218 deletions.
65 changes: 28 additions & 37 deletions src/cryptography/hazmat/backends/openssl/backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@
_Ed448PrivateKey,
_Ed448PublicKey,
)
from cryptography.hazmat.backends.openssl.ed25519 import (
_Ed25519PrivateKey,
_Ed25519PublicKey,
)
from cryptography.hazmat.backends.openssl.hashes import _HashContext
from cryptography.hazmat.backends.openssl.hmac import _HMACContext
from cryptography.hazmat.backends.openssl.poly1305 import (
Expand Down Expand Up @@ -641,7 +637,9 @@ def _evp_pkey_to_private_key(
return _DHPrivateKey(self, dh_cdata, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None):
# EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL
return _Ed25519PrivateKey(self, evp_pkey)
return rust_openssl.ed25519.private_key_from_ptr(
int(self._ffi.cast("uintptr_t", evp_pkey))
)
elif key_type == getattr(self._lib, "EVP_PKEY_X448", None):
# EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL
return rust_openssl.x448.private_key_from_ptr(
Expand Down Expand Up @@ -702,7 +700,9 @@ def _evp_pkey_to_public_key(self, evp_pkey) -> PublicKeyTypes:
return _DHPublicKey(self, dh_cdata, evp_pkey)
elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None):
# EVP_PKEY_ED25519 is not present in CRYPTOGRAPHY_IS_LIBRESSL
return _Ed25519PublicKey(self, evp_pkey)
return rust_openssl.ed25519.public_key_from_ptr(
int(self._ffi.cast("uintptr_t", evp_pkey))
)
elif key_type == getattr(self._lib, "EVP_PKEY_X448", None):
# EVP_PKEY_X448 is not present in CRYPTOGRAPHY_IS_LIBRESSL
return rust_openssl.x448.public_key_from_ptr(
Expand Down Expand Up @@ -1049,6 +1049,21 @@ def _ossl2cert(self, x509_ptr: typing.Any) -> x509.Certificate:
self.openssl_assert(res == 1)
return x509.load_der_x509_certificate(self._read_mem_bio(bio))

def _key2ossl(self, key: PKCS12PrivateKeyTypes) -> typing.Any:
data = key.private_bytes(
serialization.Encoding.DER,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption(),
)
mem_bio = self._bytes_to_bio(data)

evp_pkey = self._lib.d2i_PrivateKey_bio(
mem_bio.bio,
self._ffi.NULL,
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
return self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)

def _load_key(
self, openssl_read_func, data, password, unsafe_skip_rsa_key_validation
) -> PrivateKeyTypes:
Expand Down Expand Up @@ -1848,38 +1863,15 @@ def ed25519_supported(self) -> bool:
def ed25519_load_public_bytes(
self, data: bytes
) -> ed25519.Ed25519PublicKey:
utils._check_bytes("data", data)

if len(data) != ed25519._ED25519_KEY_SIZE:
raise ValueError("An Ed25519 public key is 32 bytes long")

evp_pkey = self._lib.EVP_PKEY_new_raw_public_key(
self._lib.NID_ED25519, self._ffi.NULL, data, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)

return _Ed25519PublicKey(self, evp_pkey)
return rust_openssl.ed25519.from_public_bytes(data)

def ed25519_load_private_bytes(
self, data: bytes
) -> ed25519.Ed25519PrivateKey:
if len(data) != ed25519._ED25519_KEY_SIZE:
raise ValueError("An Ed25519 private key is 32 bytes long")

utils._check_byteslike("data", data)
data_ptr = self._ffi.from_buffer(data)
evp_pkey = self._lib.EVP_PKEY_new_raw_private_key(
self._lib.NID_ED25519, self._ffi.NULL, data_ptr, len(data)
)
self.openssl_assert(evp_pkey != self._ffi.NULL)
evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free)

return _Ed25519PrivateKey(self, evp_pkey)
return rust_openssl.ed25519.from_private_bytes(data)

def ed25519_generate_key(self) -> ed25519.Ed25519PrivateKey:
evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED25519)
return _Ed25519PrivateKey(self, evp_pkey)
return rust_openssl.ed25519.generate_key()

def ed448_supported(self) -> bool:
if self._fips_enabled:
Expand Down Expand Up @@ -2207,15 +2199,14 @@ def serialize_key_and_certificates_to_pkcs12(
with self._zeroed_null_terminated_buf(password) as password_buf:
with self._zeroed_null_terminated_buf(name) as name_buf:
ossl_cert = self._cert2ossl(cert) if cert else self._ffi.NULL
if key is not None:
evp_pkey = key._evp_pkey # type: ignore[union-attr]
else:
evp_pkey = self._ffi.NULL
ossl_pkey = (
self._key2ossl(key) if key is not None else self._ffi.NULL
)

p12 = self._lib.PKCS12_create(
password_buf,
name_buf,
evp_pkey,
ossl_pkey,
ossl_cert,
sk_x509,
nid_key,
Expand Down
163 changes: 0 additions & 163 deletions src/cryptography/hazmat/backends/openssl/ed25519.py

This file was deleted.

10 changes: 8 additions & 2 deletions src/cryptography/hazmat/bindings/_rust/openssl/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@

import typing

from cryptography.hazmat.bindings._rust.openssl import x448, x25519
from cryptography.hazmat.bindings._rust.openssl import ed25519, x448, x25519

__all__ = ["openssl_version", "raise_openssl_error", "x448", "x25519"]
__all__ = [
"openssl_version",
"raise_openssl_error",
"ed25519",
"x448",
"x25519",
]

def openssl_version() -> int: ...
def raise_openssl_error() -> typing.NoReturn: ...
Expand Down
14 changes: 14 additions & 0 deletions src/cryptography/hazmat/bindings/_rust/openssl/ed25519.pyi
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# This file is dual licensed under the terms of the Apache License, Version
# 2.0, and the BSD License. See the LICENSE file in the root of this repository
# for complete details.

from cryptography.hazmat.primitives.asymmetric import ed25519

class Ed25519PrivateKey: ...
class Ed25519PublicKey: ...

def generate_key() -> ed25519.Ed25519PrivateKey: ...
def private_key_from_ptr(ptr: int) -> ed25519.Ed25519PrivateKey: ...
def public_key_from_ptr(ptr: int) -> ed25519.Ed25519PublicKey: ...
def from_private_bytes(data: bytes) -> ed25519.Ed25519PrivateKey: ...
def from_public_bytes(data: bytes) -> ed25519.Ed25519PublicKey: ...
19 changes: 11 additions & 8 deletions src/cryptography/hazmat/primitives/asymmetric/ed25519.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import abc

from cryptography.exceptions import UnsupportedAlgorithm, _Reasons
from cryptography.hazmat.bindings._rust import openssl as rust_openssl
from cryptography.hazmat.primitives import _serialization

_ED25519_KEY_SIZE = 32
Expand Down Expand Up @@ -36,14 +37,12 @@ def public_bytes(
The serialized bytes of the public key.
"""

@abc.abstractmethod
def public_bytes_raw(self) -> bytes:
"""
The raw bytes of the public key.
Equivalent to public_bytes(Raw, Raw).
"""
return self.public_bytes(
_serialization.Encoding.Raw, _serialization.PublicFormat.Raw
)

@abc.abstractmethod
def verify(self, signature: bytes, data: bytes) -> None:
Expand All @@ -58,6 +57,10 @@ def __eq__(self, other: object) -> bool:
"""


if hasattr(rust_openssl, "ed25519"):
Ed25519PublicKey.register(rust_openssl.ed25519.Ed25519PublicKey)


class Ed25519PrivateKey(metaclass=abc.ABCMeta):
@classmethod
def generate(cls) -> Ed25519PrivateKey:
Expand Down Expand Up @@ -100,19 +103,19 @@ def private_bytes(
The serialized bytes of the private key.
"""

@abc.abstractmethod
def private_bytes_raw(self) -> bytes:
"""
The raw bytes of the private key.
Equivalent to private_bytes(Raw, Raw, NoEncryption()).
"""
return self.private_bytes(
_serialization.Encoding.Raw,
_serialization.PrivateFormat.Raw,
_serialization.NoEncryption(),
)

@abc.abstractmethod
def sign(self, data: bytes) -> bytes:
"""
Signs the data.
"""


if hasattr(rust_openssl, "x25519"):
Ed25519PrivateKey.register(rust_openssl.ed25519.Ed25519PrivateKey)
Loading

0 comments on commit f5c750d

Please sign in to comment.