3535from cryptography .hazmat .backends .openssl .ec import (
3636 _EllipticCurvePrivateKey , _EllipticCurvePublicKey
3737)
38+ from cryptography .hazmat .backends .openssl .ed25519 import (
39+ _Ed25519PrivateKey , _Ed25519PublicKey
40+ )
3841from cryptography .hazmat .backends .openssl .encode_asn1 import (
3942 _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS ,
4043 _CRL_EXTENSION_ENCODE_HANDLERS , _EXTENSION_ENCODE_HANDLERS ,
@@ -1935,6 +1938,13 @@ def x25519_load_public_bytes(self, data):
19351938 backend .openssl_assert (res == 1 )
19361939 return _X25519PublicKey (self , evp_pkey )
19371940
1941+ def _generic_25519_load_private_bytes (self , prefix , data , key_cls ):
1942+ bio = self ._bytes_to_bio (prefix + data )
1943+ evp_pkey = backend ._lib .d2i_PrivateKey_bio (bio .bio , self ._ffi .NULL )
1944+ self .openssl_assert (evp_pkey != self ._ffi .NULL )
1945+ evp_pkey = self ._ffi .gc (evp_pkey , self ._lib .EVP_PKEY_free )
1946+ return key_cls (self , evp_pkey )
1947+
19381948 def x25519_load_private_bytes (self , data ):
19391949 # OpenSSL only has facilities for loading PKCS8 formatted private
19401950 # keys using the algorithm identifiers specified in
@@ -1950,35 +1960,66 @@ def x25519_load_private_bytes(self, data):
19501960 # contains an OCTET STRING of length 32! So the last two bytes here
19511961 # are \x04\x20, which is an OCTET STRING of length 32.
19521962 pkcs8_prefix = b'0.\x02 \x01 \x00 0\x05 \x06 \x03 +en\x04 "\x04 '
1953- bio = self ._bytes_to_bio (pkcs8_prefix + data )
1954- evp_pkey = backend ._lib .d2i_PrivateKey_bio (bio .bio , self ._ffi .NULL )
1955- self .openssl_assert (evp_pkey != self ._ffi .NULL )
1956- evp_pkey = self ._ffi .gc (evp_pkey , self ._lib .EVP_PKEY_free )
1957- self .openssl_assert (
1958- self ._lib .EVP_PKEY_id (evp_pkey ) == self ._lib .EVP_PKEY_X25519
1963+ return self ._generic_25519_load_private_bytes (
1964+ pkcs8_prefix , data , _X25519PrivateKey
19591965 )
1960- return _X25519PrivateKey (self , evp_pkey )
19611966
1962- def x25519_generate_key (self ):
1963- evp_pkey_ctx = self ._lib .EVP_PKEY_CTX_new_id (
1964- self ._lib .NID_X25519 , self ._ffi .NULL
1965- )
1967+ def _generic_25519_generate_key (self , nid , keycls ):
1968+ evp_pkey_ctx = self ._lib .EVP_PKEY_CTX_new_id (nid , self ._ffi .NULL )
19661969 self .openssl_assert (evp_pkey_ctx != self ._ffi .NULL )
1967- evp_pkey_ctx = self ._ffi .gc (
1968- evp_pkey_ctx , self ._lib .EVP_PKEY_CTX_free
1969- )
1970+ evp_pkey_ctx = self ._ffi .gc (evp_pkey_ctx , self ._lib .EVP_PKEY_CTX_free )
19701971 res = self ._lib .EVP_PKEY_keygen_init (evp_pkey_ctx )
19711972 self .openssl_assert (res == 1 )
19721973 evp_ppkey = self ._ffi .new ("EVP_PKEY **" )
19731974 res = self ._lib .EVP_PKEY_keygen (evp_pkey_ctx , evp_ppkey )
19741975 self .openssl_assert (res == 1 )
19751976 self .openssl_assert (evp_ppkey [0 ] != self ._ffi .NULL )
19761977 evp_pkey = self ._ffi .gc (evp_ppkey [0 ], self ._lib .EVP_PKEY_free )
1977- return _X25519PrivateKey (self , evp_pkey )
1978+ return keycls (self , evp_pkey )
1979+
1980+ def x25519_generate_key (self ):
1981+ return self ._generic_25519_generate_key (
1982+ self ._lib .NID_X25519 , _X25519PrivateKey
1983+ )
19781984
19791985 def x25519_supported (self ):
19801986 return self ._lib .CRYPTOGRAPHY_OPENSSL_110_OR_GREATER
19811987
1988+ def ed25519_supported (self ):
1989+ return self ._lib .CRYPTOGRAPHY_OPENSSL_111_OR_GREATER
1990+
1991+ def ed25519_load_public_bytes (self , data ):
1992+ pkcs8_prefix = b'0.\x02 \x01 \x00 0\x05 \x06 \x03 +ep\x04 "\x04 '
1993+ bio = self ._bytes_to_bio (pkcs8_prefix + data )
1994+ evp_pkey = backend ._lib .d2i_PUBKEY_bio (bio .bio , self ._ffi .NULL )
1995+ self .openssl_assert (evp_pkey != self ._ffi .NULL )
1996+ evp_pkey = self ._ffi .gc (evp_pkey , self ._lib .EVP_PKEY_free )
1997+ return _Ed25519PublicKey (self , evp_pkey )
1998+
1999+ def ed25519_load_private_bytes (self , data ):
2000+ # OpenSSL only has facilities for loading PKCS8 formatted private
2001+ # keys using the algorithm identifiers specified in
2002+ # https://tools.ietf.org/html/draft-ietf-curdle-pkix-03.
2003+ # This is the standard PKCS8 prefix for a 32 byte Ed25519 key.
2004+ # The form is:
2005+ # 0:d=0 hl=2 l= 46 cons: SEQUENCE
2006+ # 2:d=1 hl=2 l= 1 prim: INTEGER :00
2007+ # 5:d=1 hl=2 l= 5 cons: SEQUENCE
2008+ # 7:d=2 hl=2 l= 3 prim: OBJECT :1.3.101.112
2009+ # 12:d=1 hl=2 l= 34 prim: OCTET STRING (the key)
2010+ # Of course there's a bit more complexity. In reality OCTET STRING
2011+ # contains an OCTET STRING of length 32! So the last two bytes here
2012+ # are \x04\x20, which is an OCTET STRING of length 32.
2013+ pkcs8_prefix = b'0.\x02 \x01 \x00 0\x05 \x06 \x03 +ep\x04 "\x04 '
2014+ return self ._generic_25519_load_private_bytes (
2015+ pkcs8_prefix , data , _Ed25519PrivateKey
2016+ )
2017+
2018+ def ed25519_generate_key (self ):
2019+ return self ._generic_25519_generate_key (
2020+ self ._lib .NID_ED25519 , _Ed25519PrivateKey
2021+ )
2022+
19822023 def derive_scrypt (self , key_material , salt , length , n , r , p ):
19832024 buf = self ._ffi .new ("unsigned char[]" , length )
19842025 res = self ._lib .EVP_PBE_scrypt (
0 commit comments