Adding support for ed448
parent
e5a2bbe738
commit
e3968d1932
|
@ -68,3 +68,4 @@ venv_*
|
|||
|
||||
# code editor preferences
|
||||
.vscode
|
||||
.tags
|
||||
|
|
|
@ -24,7 +24,7 @@ __uri__ = "https://github.com/wolfssl/wolfcrypt-py"
|
|||
|
||||
# When bumping the C library version, reset the POST count to 0
|
||||
|
||||
__wolfssl_version__ = "v4.1.0-stable"
|
||||
__wolfssl_version__ = "v5.0.0-stable"
|
||||
|
||||
# We're using implicit post releases [PEP 440] to bump package version
|
||||
# while maintaining the C library version intact for better reference.
|
||||
|
@ -32,7 +32,7 @@ __wolfssl_version__ = "v4.1.0-stable"
|
|||
#
|
||||
# MAJOR.MINOR.BUILD-POST
|
||||
|
||||
__version__ = "4.1.0-0"
|
||||
__version__ = "5.0.0-0"
|
||||
|
||||
__author__ = "wolfSSL Inc."
|
||||
__email__ = "info@wolfssl.com"
|
||||
|
|
|
@ -62,6 +62,7 @@ RSA_BLINDING_ENABLED = 1
|
|||
ECC_TIMING_RESISTANCE_ENABLED = 1
|
||||
ECC_ENABLED = 1
|
||||
ED25519_ENABLED = 1
|
||||
ED448_ENABLED = 1
|
||||
KEYGEN_ENABLED = 1
|
||||
CHACHA_ENABLED = 1
|
||||
PWDBASED_ENABLED = 0
|
||||
|
@ -86,6 +87,7 @@ if featureDetection:
|
|||
RSA_BLINDING_ENABLED = 1 if '#define WC_RSA_BLINDING' in optionsHeaderStr else 0
|
||||
ECC_ENABLED = 1 if '#define HAVE_ECC' in optionsHeaderStr else 0
|
||||
ED25519_ENABLED = 1 if '#define HAVE_ED25519' in optionsHeaderStr else 0
|
||||
ED448_ENABLED = 1 if '#define HAVE_ED448' in optionsHeaderStr else 0
|
||||
KEYGEN_ENABLED = 1 if '#define WOLFSSL_KEY_GEN' in optionsHeaderStr else 0
|
||||
PWDBASED_ENABLED = 0 if '#define NO_PWDBASED' in optionsHeaderStr else 1
|
||||
ERROR_STRINGS_ENABLED = 0 if '#define NO_ERROR_STRINGS' in optionsHeaderStr else 1
|
||||
|
@ -128,6 +130,7 @@ ffibuilder.set_source(
|
|||
#include <wolfssl/wolfcrypt/rsa.h>
|
||||
#include <wolfssl/wolfcrypt/ecc.h>
|
||||
#include <wolfssl/wolfcrypt/ed25519.h>
|
||||
#include <wolfssl/wolfcrypt/ed448.h>
|
||||
#include <wolfssl/wolfcrypt/curve25519.h>
|
||||
|
||||
int MPAPI_ENABLED = """ + str(MPAPI_ENABLED) + """;
|
||||
|
@ -145,6 +148,7 @@ ffibuilder.set_source(
|
|||
int ECC_TIMING_RESISTANCE_ENABLED = """ + str(ECC_TIMING_RESISTANCE_ENABLED) + """;
|
||||
int ECC_ENABLED = """ + str(ECC_ENABLED) + """;
|
||||
int ED25519_ENABLED = """ + str(ED25519_ENABLED) + """;
|
||||
int ED448_ENABLED = """ + str(ED448_ENABLED) + """;
|
||||
int KEYGEN_ENABLED = """ + str(KEYGEN_ENABLED) + """;
|
||||
int PWDBASED_ENABLED = """ + str(PWDBASED_ENABLED) + """;
|
||||
int FIPS_ENABLED = """ + str(FIPS_ENABLED) + """;
|
||||
|
@ -171,6 +175,7 @@ _cdef = """
|
|||
extern int ECC_TIMING_RESISTANCE_ENABLED;
|
||||
extern int ECC_ENABLED;
|
||||
extern int ED25519_ENABLED;
|
||||
extern int ED448_ENABLED;
|
||||
extern int KEYGEN_ENABLED;
|
||||
extern int PWDBASED_ENABLED;
|
||||
extern int FIPS_ENABLED;
|
||||
|
@ -403,6 +408,43 @@ if ED25519_ENABLED:
|
|||
int wc_ed25519_priv_size(ed25519_key* key);
|
||||
"""
|
||||
|
||||
if ED448_ENABLED:
|
||||
_cdef += """
|
||||
typedef struct {...; } ed448_key;
|
||||
|
||||
int wc_ed448_init(ed448_key* ed448);
|
||||
void wc_ed448_free(ed448_key* ed448);
|
||||
|
||||
int wc_ed448_make_key(WC_RNG* rng, int keysize, ed448_key* key);
|
||||
int wc_ed448_make_public(ed448_key* key, unsigned char* pubKey,
|
||||
word32 pubKeySz);
|
||||
int wc_ed448_size(ed448_key* key);
|
||||
int wc_ed448_sig_size(ed448_key* key);
|
||||
int wc_ed448_sign_msg(const byte* in, word32 inlen, byte* out,
|
||||
word32 *outlen, ed448_key* key, byte* ctx,
|
||||
word32 ctx_len);
|
||||
int wc_ed448_verify_msg(const byte* sig, word32 siglen, const byte* msg,
|
||||
word32 msglen, int* stat, ed448_key* key, byte *ctx,
|
||||
word32 ctx_len);
|
||||
int wc_Ed448PrivateKeyDecode(const byte*, word32*, ed448_key*, word32);
|
||||
int wc_Ed448KeyToDer(ed448_key*, byte* output, word32 inLen);
|
||||
|
||||
int wc_Ed448PublicKeyDecode(const byte*, word32*, ed448_key*, word32);
|
||||
int wc_Ed448PublicKeyToDer(ed448_key*, byte* output,
|
||||
word32 inLen, int with_AlgCurve);
|
||||
|
||||
int wc_ed448_import_public(const byte* in, word32 inLen, ed448_key* key);
|
||||
int wc_ed448_import_private_only(const byte* priv, word32 privSz, ed448_key* key);
|
||||
int wc_ed448_import_private_key(const byte* priv, word32 privSz, const byte* pub, word32 pubSz, ed448_key* key);
|
||||
int wc_ed448_export_public(ed448_key*, byte* out, word32* outLen);
|
||||
int wc_ed448_export_private_only(ed448_key* key, byte* out, word32* outLen);
|
||||
int wc_ed448_export_private(ed448_key* key, byte* out, word32* outLen);
|
||||
int wc_ed448_export_key(ed448_key* key, byte* priv, word32 *privSz, byte* pub, word32 *pubSz);
|
||||
int wc_ed448_check_key(ed448_key* key);
|
||||
int wc_ed448_pub_size(ed448_key* key);
|
||||
int wc_ed448_priv_size(ed448_key* key);
|
||||
"""
|
||||
|
||||
if PWDBASED_ENABLED:
|
||||
_cdef += """
|
||||
int wc_PBKDF2(byte* output, const byte* passwd, int pLen,
|
||||
|
|
|
@ -164,6 +164,7 @@ def make_flags(prefix):
|
|||
flags.append("--enable-rsa")
|
||||
flags.append("--enable-ecc")
|
||||
flags.append("--enable-ed25519")
|
||||
flags.append("--enable-ed448")
|
||||
flags.append("--enable-curve25519")
|
||||
flags.append("--enable-keygen")
|
||||
|
||||
|
|
|
@ -1057,3 +1057,205 @@ if _lib.ED25519_ENABLED:
|
|||
raise WolfCryptError("Signature error (%d)" % ret)
|
||||
|
||||
return _ffi.buffer(signature, signature_size[0])[:]
|
||||
|
||||
if _lib.ED448_ENABLED:
|
||||
class _Ed448(object): # pylint: disable=too-few-public-methods
|
||||
def __init__(self):
|
||||
self.native_object = _ffi.new("ed448_key *")
|
||||
ret = _lib.wc_ed448_init(self.native_object)
|
||||
if ret < 0: # pragma: no cover
|
||||
raise WolfCryptError("Invalid key error (%d)" % ret)
|
||||
|
||||
# making sure _lib.wc_ed448_free outlives ed448_key instances
|
||||
_delete = _lib.wc_ed448_free
|
||||
|
||||
def __del__(self):
|
||||
if self.native_object:
|
||||
self._delete(self.native_object)
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return _lib.wc_ed448_size(self.native_object)
|
||||
|
||||
@property
|
||||
def max_signature_size(self):
|
||||
return _lib.wc_ed448_sig_size(self.native_object)
|
||||
|
||||
|
||||
class Ed448Public(_Ed448):
|
||||
def __init__(self, key=None):
|
||||
_Ed448.__init__(self)
|
||||
|
||||
if key:
|
||||
self.decode_key(key)
|
||||
|
||||
def decode_key(self, key):
|
||||
"""
|
||||
Decodes an ED448 public key
|
||||
"""
|
||||
key = t2b(key)
|
||||
if (len(key) < _lib.wc_ed448_pub_size(self.native_object)):
|
||||
raise WolfCryptError("Key decode error: key too short")
|
||||
|
||||
idx = _ffi.new("word32*")
|
||||
idx[0] = 0
|
||||
ret = _lib.wc_ed448_import_public(key, len(key),
|
||||
self.native_object)
|
||||
if ret < 0:
|
||||
raise WolfCryptError("Key decode error (%d)" % ret)
|
||||
if self.size <= 0: # pragma: no cover
|
||||
raise WolfCryptError("Key decode error (%d)" % self.size)
|
||||
if self.max_signature_size <= 0: # pragma: no cover
|
||||
raise WolfCryptError(
|
||||
"Key decode error (%d)" % self.max_signature_size)
|
||||
|
||||
def encode_key(self):
|
||||
"""
|
||||
Encodes the ED448 public key
|
||||
|
||||
Returns the encoded key.
|
||||
"""
|
||||
key = _ffi.new("byte[%d]" % (self.size * 4))
|
||||
size = _ffi.new("word32[1]")
|
||||
|
||||
size[0] = _lib.wc_ed448_pub_size(self.native_object)
|
||||
|
||||
ret = _lib.wc_ed448_export_public(self.native_object, key, size)
|
||||
if ret != 0: # pragma: no cover
|
||||
raise WolfCryptError("Key encode error (%d)" % ret)
|
||||
|
||||
return _ffi.buffer(key, size[0])[:]
|
||||
|
||||
def verify(self, signature, data, ctx=None):
|
||||
"""
|
||||
Verifies **signature**, using the public key data in the object.
|
||||
|
||||
Returns **True** in case of a valid signature, otherwise **False**.
|
||||
"""
|
||||
data = t2b(data)
|
||||
status = _ffi.new("int[1]")
|
||||
ctx_buf = _ffi.NULL
|
||||
ctx_buf_len = 0
|
||||
if ctx != None:
|
||||
ctx_buf = t2b(ctx)
|
||||
ctx_buf_len = len(ctx_buf)
|
||||
|
||||
ret = _lib.wc_ed448_verify_msg(signature, len(signature),
|
||||
data, len(data), status,
|
||||
self.native_object, ctx_buf,
|
||||
ctx_buf_len)
|
||||
|
||||
if ret < 0:
|
||||
raise WolfCryptError("Verify error (%d)" % ret)
|
||||
|
||||
return status[0] == 1
|
||||
|
||||
|
||||
|
||||
class Ed448Private(Ed448Public):
|
||||
def __init__(self, key=None, pub=None):
|
||||
_Ed448.__init__(self)
|
||||
|
||||
if key and not pub:
|
||||
self.decode_key(key)
|
||||
if key and pub:
|
||||
self.decode_key(key,pub)
|
||||
|
||||
@classmethod
|
||||
def make_key(cls, size, rng=Random()):
|
||||
"""
|
||||
Generates a new key pair of desired length **size**.
|
||||
"""
|
||||
ed448 = cls()
|
||||
|
||||
ret = _lib.wc_ed448_make_key(rng.native_object, size,
|
||||
ed448.native_object)
|
||||
if ret < 0:
|
||||
raise WolfCryptError("Key generation error (%d)" % ret)
|
||||
|
||||
return ed448
|
||||
|
||||
def decode_key(self, key, pub = None):
|
||||
"""
|
||||
Decodes an ED448 private + pub key
|
||||
"""
|
||||
key = t2b(key)
|
||||
|
||||
if (len(key) < _lib.wc_ed448_priv_size(self.native_object)/2):
|
||||
raise WolfCryptError("Key decode error: key too short")
|
||||
|
||||
idx = _ffi.new("word32*")
|
||||
idx[0] = 0
|
||||
if pub:
|
||||
ret = _lib.wc_ed448_import_private_key(key, len(key), pub,
|
||||
len(pub), self.native_object);
|
||||
if ret < 0:
|
||||
raise WolfCryptError("Key decode error (%d)" % ret)
|
||||
else:
|
||||
ret = _lib.wc_ed448_import_private_only(key, len(key),
|
||||
self.native_object);
|
||||
if ret < 0:
|
||||
raise WolfCryptError("Key decode error (%d)" % ret)
|
||||
pubkey = _ffi.new("byte[%d]" % (self.size * 4))
|
||||
ret = _lib.wc_ed448_make_public(self.native_object, pubkey,
|
||||
self.size)
|
||||
if ret < 0:
|
||||
raise WolfCryptError("Public key generate error (%d)" % ret)
|
||||
ret = _lib.wc_ed448_import_public(pubkey, self.size,
|
||||
self.native_object);
|
||||
|
||||
if self.size <= 0: # pragma: no cover
|
||||
raise WolfCryptError("Key decode error (%d)" % self.size)
|
||||
if self.max_signature_size <= 0: # pragma: no cover
|
||||
raise WolfCryptError(
|
||||
"Key decode error (%d)" % self.max_signature_size)
|
||||
|
||||
def encode_key(self):
|
||||
"""
|
||||
Encodes the ED448 private key.
|
||||
|
||||
Returns the encoded key.
|
||||
"""
|
||||
key = _ffi.new("byte[%d]" % (self.size * 4))
|
||||
pubkey = _ffi.new("byte[%d]" % (self.size * 4))
|
||||
size = _ffi.new("word32[1]")
|
||||
|
||||
size[0] = _lib.wc_ed448_priv_size(self.native_object)
|
||||
|
||||
ret = _lib.wc_ed448_export_private_only(self.native_object,
|
||||
key, size)
|
||||
if ret != 0: # pragma: no cover
|
||||
raise WolfCryptError("Private key encode error (%d)" % ret)
|
||||
ret = _lib.wc_ed448_export_public(self.native_object, pubkey,
|
||||
size)
|
||||
if ret != 0: # pragma: no cover
|
||||
raise WolfCryptError("Public key encode error (%d)" % ret)
|
||||
|
||||
return _ffi.buffer(key, size[0])[:], _ffi.buffer(pubkey, size[0])[:]
|
||||
|
||||
def sign(self, plaintext, ctx=None):
|
||||
"""
|
||||
Signs **plaintext**, using the private key data in the object.
|
||||
|
||||
Returns the signature.
|
||||
"""
|
||||
plaintext = t2b(plaintext)
|
||||
signature = _ffi.new("byte[%d]" % self.max_signature_size)
|
||||
|
||||
signature_size = _ffi.new("word32[1]")
|
||||
signature_size[0] = self.max_signature_size
|
||||
ctx_buf = _ffi.NULL
|
||||
ctx_buf_len = 0
|
||||
if (ctx != None):
|
||||
ctx_buf = t2b(ctx)
|
||||
ctx_buf_len = len(ctx_buf)
|
||||
|
||||
ret = _lib.wc_ed448_sign_msg(plaintext, len(plaintext),
|
||||
signature, signature_size,
|
||||
self.native_object, ctx_buf,
|
||||
ctx_buf_len)
|
||||
|
||||
if ret != 0: # pragma: no cover
|
||||
raise WolfCryptError("Signature error (%d)" % ret)
|
||||
|
||||
return _ffi.buffer(signature, signature_size[0])[:]
|
||||
|
|
|
@ -44,6 +44,9 @@ if _lib.ECC_ENABLED:
|
|||
if _lib.ED25519_ENABLED:
|
||||
from wolfcrypt.ciphers import (Ed25519Private, Ed25519Public)
|
||||
|
||||
if _lib.ED448_ENABLED:
|
||||
from wolfcrypt.ciphers import (Ed448Private, Ed448Public)
|
||||
|
||||
from wolfcrypt.ciphers import (
|
||||
MODE_ECB, MODE_CBC, WolfCryptError
|
||||
)
|
||||
|
@ -194,7 +197,19 @@ def vectors():
|
|||
"FC96"
|
||||
)
|
||||
)
|
||||
|
||||
if _lib.ED448_ENABLED:
|
||||
vectorArray[Ed448Private]=TestVector(
|
||||
key=h2b("c2b29804e9a893c9e275cac1f8a3033f3d4b78b79eb427ed359fdeb8"
|
||||
"82d657c129c7930936b181971b795167ad18cabeeb52b59b94f115ad"
|
||||
"59"
|
||||
)
|
||||
)
|
||||
vectorArray[Ed448Public]=TestVector(
|
||||
key=h2b("89fb2b5a5ab67dd317794cc5f1700cace295b043f3ad73a66299e10a"
|
||||
"d3fc0a28289ddd1c641598a354113867a42e82ad844b4d858d92e4e7"
|
||||
"80"
|
||||
)
|
||||
)
|
||||
return vectorArray
|
||||
|
||||
algo_params = []
|
||||
|
@ -570,3 +585,53 @@ if _lib.ED25519_ENABLED:
|
|||
# using the known public key.
|
||||
assert ed25519_private.verify(signature, plaintext)
|
||||
|
||||
if _lib.ED448_ENABLED:
|
||||
@pytest.fixture
|
||||
def ed448_private(vectors):
|
||||
return Ed448Private(vectors[Ed448Private].key, vectors[Ed448Public].key)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def ed448_public(vectors):
|
||||
return Ed448Public(vectors[Ed448Public].key)
|
||||
|
||||
|
||||
def test_new_ed448_raises(vectors):
|
||||
with pytest.raises(WolfCryptError):
|
||||
Ed448Private(vectors[Ed448Private].key[:-1]) # invalid key length
|
||||
|
||||
with pytest.raises(WolfCryptError):
|
||||
Ed448Public(vectors[Ed448Public].key[:-1]) # invalid key length
|
||||
|
||||
with pytest.raises(WolfCryptError): # invalid key size
|
||||
Ed448Private.make_key(1024)
|
||||
|
||||
|
||||
def test_ed448_key_encoding(vectors):
|
||||
priv = Ed448Private()
|
||||
pub = Ed448Public()
|
||||
|
||||
priv.decode_key(vectors[Ed448Private].key)
|
||||
pub.decode_key(vectors[Ed448Public].key)
|
||||
|
||||
assert priv.encode_key()[0] == vectors[Ed448Private].key
|
||||
assert priv.encode_key()[1] == vectors[Ed448Public].key # Automatically re-generated from private-only
|
||||
assert pub.encode_key() == vectors[Ed448Public].key
|
||||
|
||||
|
||||
def test_ed448_sign_verify(ed448_private, ed448_public):
|
||||
plaintext = "Everyone gets Friday off."
|
||||
|
||||
# normal usage, sign with private, verify with public
|
||||
signature = ed448_private.sign(plaintext)
|
||||
|
||||
assert len(signature) <= ed448_private.max_signature_size
|
||||
assert ed448_public.verify(signature, plaintext)
|
||||
|
||||
# invalid signature
|
||||
with pytest.raises(WolfCryptError):
|
||||
ed448_public.verify(signature[:-1], plaintext)
|
||||
|
||||
# private object holds both private and public info, so it can also verify
|
||||
# using the known public key.
|
||||
assert ed448_private.verify(signature, plaintext)
|
||||
|
|
Loading…
Reference in New Issue