Merge pull request #5 from danielinux/ecc-sign-verify-raw

[ECC] Added ecc_sign_raw and ecc_verify_raw + test cases
pull/6/head
David Garske 2019-04-16 12:43:58 -07:00 committed by GitHub
commit fda3889766
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 104 additions and 1 deletions

View File

@ -59,6 +59,11 @@ ffi.cdef(
typedef unsigned char byte;
typedef unsigned int word32;
typedef struct { ...; } mp_int;
int mp_init (mp_int * a);
int mp_to_unsigned_bin (mp_int * a, unsigned char *b);
int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
typedef struct { ...; } wc_Sha;
@ -96,6 +101,7 @@ ffi.cdef(
int wc_HmacFinal(Hmac*, byte*);
typedef struct { ...; } Aes;
int wc_AesSetKey(Aes*, const byte*, word32, const byte*, int);
@ -172,6 +178,12 @@ ffi.cdef(
const byte* hash, word32 hashlen,
int* stat, ecc_key* key);
int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng,
ecc_key* key, mp_int *r, mp_int *s);
int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash,
word32 hashlen, int* res, ecc_key* key);
typedef struct {...; } ed25519_key;
int wc_ed25519_init(ed25519_key* ed25519);

View File

@ -530,6 +530,42 @@ class EccPublic(_Ecc):
return status[0] == 1
def verify_raw(self, R, S, data):
"""
Verifies signature from its raw elements **R** and **S**, 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]")
mpR = _ffi.new("mp_int[1]")
mpS = _ffi.new("mp_int[1]")
ret = _lib.mp_init(mpR)
if ret != 0: # pragma: no cover
raise WolfCryptError("wolfCrypt error (%d)" % ret)
ret = _lib.mp_init(mpS)
if ret != 0: # pragma: no cover
raise WolfCryptError("wolfCrypt error (%d)" % ret)
ret = _lib.mp_read_unsigned_bin(mpR, R, len(R))
if ret != 0: # pragma: no cover
raise WolfCryptError("wolfCrypt error (%d)" % ret)
ret = _lib.mp_read_unsigned_bin(mpS, S, len(S))
if ret != 0: # pragma: no cover
raise WolfCryptError("wolfCrypt error (%d)" % ret)
ret = _lib.wc_ecc_verify_hash_ex(mpR, mpS,
data, len(data),
status, self.native_object)
if ret < 0:
raise WolfCryptError("Verify error (%d)" % ret)
return status[0] == 1
class EccPrivate(EccPublic):
@classmethod
@ -650,6 +686,43 @@ class EccPrivate(EccPublic):
return _ffi.buffer(signature, signature_size[0])[:]
def sign_raw(self, plaintext, rng=Random()):
"""
Signs **plaintext**, using the private key data in the object.
Returns the signature in its two raw components r, s
"""
plaintext = t2b(plaintext)
R = _ffi.new("mp_int[1]");
S = _ffi.new("mp_int[1]");
R_bin = _ffi.new("unsigned char[%d]" % self.size )
S_bin = _ffi.new("unsigned char[%d]" % self.size )
ret = _lib.mp_init(R)
if ret != 0: # pragma: no cover
raise WolfCryptError("wolfCrypt error (%d)" % ret)
ret = _lib.mp_init(S)
if ret != 0: # pragma: no cover
raise WolfCryptError("wolfCrypt error (%d)" % ret)
ret = _lib.wc_ecc_sign_hash_ex(plaintext, len(plaintext),
rng.native_object,
self.native_object,
R, S)
if ret != 0: # pragma: no cover
raise WolfCryptError("Signature error (%d)" % ret)
ret = _lib.mp_to_unsigned_bin(R, R_bin)
if ret != 0: # pragma: no cover
raise WolfCryptError("wolfCrypt error (%d)" % ret)
ret = _lib.mp_to_unsigned_bin(S, S_bin)
if ret != 0: # pragma: no cover
raise WolfCryptError("wolfCrypt error (%d)" % ret)
return _ffi.buffer(R_bin, self.size)[:], _ffi.buffer(S_bin, self.size)[:]
class _Ed25519(object): # pylint: disable=too-few-public-methods
def __init__(self):
self.native_object = _ffi.new("ed25519_key *")
@ -735,6 +808,7 @@ class Ed25519Public(_Ed25519):
return status[0] == 1
class Ed25519Private(Ed25519Public):
def __init__(self, key=None, pub=None):
_Ed25519.__init__(self)

View File

@ -349,6 +349,23 @@ def test_ecc_sign_verify(ecc_private, ecc_public):
with pytest.raises(WolfCryptError):
ecc_x963.import_x963(ecc_public.export_x963()[:-1])
def test_ecc_sign_verify_raw(ecc_private, ecc_public):
plaintext = "Everyone gets Friday off."
# normal usage, sign with private, verify with public
r,s = ecc_private.sign_raw(plaintext)
assert len(r) + len(s) <= 2 * ecc_private.size
assert ecc_public.verify_raw(r, s, plaintext)
# invalid signature
ret = ecc_public.verify_raw(r, s[:-1], plaintext)
assert ret == False
# private object holds both private and public info, so it can also verify
# using the known public key.
assert ecc_private.verify_raw(r, s, plaintext)
def test_ecc_make_shared_secret():
a = EccPrivate.make_key(32)