mirror of https://github.com/wolfSSL/wolfssl.git
add support for curve 25519 and Ed25519 in OpenSSH
refactor curve25519 and Ed25519 code fix warning in PEM_xxx_mem_xxx functionspull/113/head
parent
e363848ecc
commit
409126a97c
10
configure.ac
10
configure.ac
|
@ -733,6 +733,11 @@ AC_ARG_ENABLE([curve25519],
|
|||
)
|
||||
|
||||
|
||||
if test "$ENABLED_OPENSSH" = "yes"
|
||||
then
|
||||
ENABLED_CURVE25519="yes"
|
||||
fi
|
||||
|
||||
if test "$ENABLED_CURVE25519" = "small"
|
||||
then
|
||||
AM_CFLAGS="$AM_CFLAGS -DCURVED25519_SMALL"
|
||||
|
@ -758,6 +763,11 @@ AC_ARG_ENABLE([ed25519],
|
|||
)
|
||||
|
||||
|
||||
if test "$ENABLED_OPENSSH" = "yes"
|
||||
then
|
||||
ENABLED_ED25519="yes"
|
||||
fi
|
||||
|
||||
if test "$ENABLED_ED25519" = "small"
|
||||
then
|
||||
AM_CFLAGS="$AM_CFLAGS -DCURVED25519_SMALL"
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
/* ec25519.h */
|
||||
|
||||
#include <wolfssl/openssl/ec25519.h>
|
|
@ -0,0 +1,3 @@
|
|||
/* ed25519.h */
|
||||
|
||||
#include <wolfssl/openssl/ed25519.h>
|
|
@ -13,6 +13,8 @@ nobase_include_HEADERS+= \
|
|||
cyassl/openssl/ecdsa.h \
|
||||
cyassl/openssl/ecdh.h \
|
||||
cyassl/openssl/ec.h \
|
||||
cyassl/openssl/ec25519.h \
|
||||
cyassl/openssl/ed25519.h \
|
||||
cyassl/openssl/engine.h \
|
||||
cyassl/openssl/err.h \
|
||||
cyassl/openssl/evp.h \
|
||||
|
|
323
src/ssl.c
323
src/ssl.c
|
@ -48,6 +48,8 @@
|
|||
#include <wolfssl/openssl/rsa.h>
|
||||
#include <wolfssl/openssl/pem.h>
|
||||
#include <wolfssl/openssl/ec.h>
|
||||
#include <wolfssl/openssl/ec25519.h>
|
||||
#include <wolfssl/openssl/ed25519.h>
|
||||
#include <wolfssl/openssl/ecdsa.h>
|
||||
#include <wolfssl/openssl/ecdh.h>
|
||||
/* openssl headers end, wolfssl internal headers next */
|
||||
|
@ -57,6 +59,8 @@
|
|||
#include <wolfssl/wolfcrypt/md4.h>
|
||||
#include <wolfssl/wolfcrypt/md5.h>
|
||||
#include <wolfssl/wolfcrypt/arc4.h>
|
||||
#include <wolfssl/wolfcrypt/curve25519.h>
|
||||
#include <wolfssl/wolfcrypt/ed25519.h>
|
||||
#ifdef WOLFSSL_SHA512
|
||||
#include <wolfssl/wolfcrypt/sha512.h>
|
||||
#endif
|
||||
|
@ -12632,8 +12636,7 @@ int wolfSSL_DSA_generate_key(WOLFSSL_DSA* dsa)
|
|||
return SSL_FAILURE;
|
||||
}
|
||||
|
||||
if (dsa->inSet == 0)
|
||||
{
|
||||
if (dsa->inSet == 0) {
|
||||
WOLFSSL_MSG("No DSA internal set, do it");
|
||||
|
||||
if (SetDsaInternal(dsa) != SSL_SUCCESS) {
|
||||
|
@ -13493,7 +13496,7 @@ static int EncryptDerKey(byte *der, int *derSz, const EVP_CIPHER* cipher,
|
|||
*/
|
||||
int wolfSSL_PEM_write_mem_RSAPrivateKey(RSA* rsa, const EVP_CIPHER* cipher,
|
||||
unsigned char* passwd, int passwdSz,
|
||||
byte **pem, int *plen)
|
||||
unsigned char **pem, int *plen)
|
||||
{
|
||||
byte *der, *tmp, *cipherInfo = NULL;
|
||||
int der_max_len = 0, derSz = 0;
|
||||
|
@ -14864,7 +14867,7 @@ int wolfSSL_PEM_write_bio_ECPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_EC_KEY* ecc,
|
|||
int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* ecc,
|
||||
const EVP_CIPHER* cipher,
|
||||
unsigned char* passwd, int passwdSz,
|
||||
byte **pem, int *plen)
|
||||
unsigned char **pem, int *plen)
|
||||
{
|
||||
byte *der, *tmp, *cipherInfo = NULL;
|
||||
int der_max_len = 0, derSz = 0;
|
||||
|
@ -15037,7 +15040,7 @@ int wolfSSL_PEM_write_bio_DSAPrivateKey(WOLFSSL_BIO* bio, WOLFSSL_DSA* dsa,
|
|||
int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa,
|
||||
const EVP_CIPHER* cipher,
|
||||
unsigned char* passwd, int passwdSz,
|
||||
byte **pem, int *plen)
|
||||
unsigned char **pem, int *plen)
|
||||
{
|
||||
byte *der, *tmp, *cipherInfo = NULL;
|
||||
int der_max_len = 0, derSz = 0;
|
||||
|
@ -16327,3 +16330,313 @@ const byte* wolfSSL_SESSION_get_id(WOLFSSL_SESSION* sess, unsigned int* idLen)
|
|||
return sess->sessionID;
|
||||
}
|
||||
#endif /* OPENSSL_EXTRA and HAVE_STUNNEL */
|
||||
|
||||
#if defined(OPENSSL_EXTRA) && defined(HAVE_CURVE25519)
|
||||
/* return 1 if success, 0 if error
|
||||
* output keys are little endian format
|
||||
*/
|
||||
int wolfSSL_EC25519_generate_key(unsigned char *priv, unsigned int *privSz,
|
||||
unsigned char *pub, unsigned int *pubSz)
|
||||
{
|
||||
#ifndef WOLFSSL_KEY_GEN
|
||||
WOLFSSL_MSG("No Key Gen built in");
|
||||
return SSL_FAILURE;
|
||||
#else /* WOLFSSL_KEY_GEN */
|
||||
int ret = SSL_FAILURE;
|
||||
int initTmpRng = 0;
|
||||
RNG *rng = NULL;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
RNG *tmpRNG = NULL;
|
||||
#else
|
||||
RNG tmpRNG[1];
|
||||
#endif
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_EC25519_generate_key");
|
||||
|
||||
if (priv == NULL || privSz == NULL || *privSz < CURVE25519_KEYSIZE ||
|
||||
pub == NULL || pubSz == NULL || *pubSz < CURVE25519_KEYSIZE) {
|
||||
WOLFSSL_MSG("Bad arguments");
|
||||
return SSL_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
tmpRNG = (RNG*)XMALLOC(sizeof(RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (tmpRNG == NULL)
|
||||
return SSL_FAILURE;
|
||||
#endif
|
||||
if (wc_InitRng(tmpRNG) == 0) {
|
||||
rng = tmpRNG;
|
||||
initTmpRng = 1;
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("Bad RNG Init, trying global");
|
||||
if (initGlobalRNG == 0)
|
||||
WOLFSSL_MSG("Global RNG no Init");
|
||||
else
|
||||
rng = &globalRNG;
|
||||
}
|
||||
|
||||
if (rng) {
|
||||
curve25519_key key;
|
||||
|
||||
if (wc_curve25519_init(&key) != MP_OKAY)
|
||||
WOLFSSL_MSG("wc_curve25519_init failed");
|
||||
else if (wc_curve25519_make_key(rng, CURVE25519_KEYSIZE, &key)!=MP_OKAY)
|
||||
WOLFSSL_MSG("wc_curve25519_make_key failed");
|
||||
/* export key pair */
|
||||
else if (wc_curve25519_export_key_raw_ex(&key, priv, privSz, pub,
|
||||
pubSz, EC25519_LITTLE_ENDIAN)
|
||||
!= MP_OKAY)
|
||||
WOLFSSL_MSG("wc_curve25519_export_key_raw_ex failed");
|
||||
else
|
||||
ret = SSL_SUCCESS;
|
||||
|
||||
wc_curve25519_free(&key);
|
||||
}
|
||||
|
||||
if (initTmpRng)
|
||||
wc_FreeRng(tmpRNG);
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
#endif /* WOLFSSL_KEY_GEN */
|
||||
}
|
||||
|
||||
/* return 1 if success, 0 if error
|
||||
* input and output keys are little endian format
|
||||
*/
|
||||
int wolfSSL_EC25519_shared_key(unsigned char *shared, unsigned int *sharedSz,
|
||||
const unsigned char *priv, unsigned int privSz,
|
||||
const unsigned char *pub, unsigned int pubSz)
|
||||
{
|
||||
#ifndef WOLFSSL_KEY_GEN
|
||||
WOLFSSL_MSG("No Key Gen built in");
|
||||
return SSL_FAILURE;
|
||||
#else /* WOLFSSL_KEY_GEN */
|
||||
int ret = SSL_FAILURE;
|
||||
curve25519_key privkey, pubkey;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_EC25519_shared_key");
|
||||
|
||||
if (shared == NULL || sharedSz == NULL || *sharedSz < CURVE25519_KEYSIZE ||
|
||||
priv == NULL || privSz < CURVE25519_KEYSIZE ||
|
||||
pub == NULL || pubSz < CURVE25519_KEYSIZE) {
|
||||
WOLFSSL_MSG("Bad arguments");
|
||||
return SSL_FAILURE;
|
||||
}
|
||||
|
||||
/* import private key */
|
||||
if (wc_curve25519_init(&privkey) != MP_OKAY) {
|
||||
WOLFSSL_MSG("wc_curve25519_init privkey failed");
|
||||
return ret;
|
||||
}
|
||||
if (wc_curve25519_import_private_ex(priv, privSz, &privkey,
|
||||
EC25519_LITTLE_ENDIAN) != MP_OKAY) {
|
||||
WOLFSSL_MSG("wc_curve25519_import_private_ex failed");
|
||||
wc_curve25519_free(&privkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* import public key */
|
||||
if (wc_curve25519_init(&pubkey) != MP_OKAY) {
|
||||
WOLFSSL_MSG("wc_curve25519_init pubkey failed");
|
||||
wc_curve25519_free(&privkey);
|
||||
return ret;
|
||||
}
|
||||
if (wc_curve25519_import_public_ex(pub, pubSz, &pubkey,
|
||||
EC25519_LITTLE_ENDIAN) != MP_OKAY) {
|
||||
WOLFSSL_MSG("wc_curve25519_import_public_ex failed");
|
||||
wc_curve25519_free(&privkey);
|
||||
wc_curve25519_free(&pubkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (wc_curve25519_shared_secret_ex(&privkey, &pubkey,
|
||||
shared, sharedSz,
|
||||
EC25519_LITTLE_ENDIAN) != MP_OKAY)
|
||||
WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed");
|
||||
else
|
||||
ret = SSL_SUCCESS;
|
||||
|
||||
wc_curve25519_free(&privkey);
|
||||
wc_curve25519_free(&pubkey);
|
||||
|
||||
return ret;
|
||||
#endif /* WOLFSSL_KEY_GEN */
|
||||
}
|
||||
#endif /* OPENSSL_EXTRA && HAVE_CURVE25519 */
|
||||
|
||||
#if defined(OPENSSL_EXTRA) && defined(HAVE_ED25519)
|
||||
/* return 1 if success, 0 if error
|
||||
* output keys are little endian format
|
||||
*/
|
||||
int wolfSSL_ED25519_generate_key(unsigned char *priv, unsigned int *privSz,
|
||||
unsigned char *pub, unsigned int *pubSz)
|
||||
{
|
||||
#ifndef WOLFSSL_KEY_GEN
|
||||
WOLFSSL_MSG("No Key Gen built in");
|
||||
return SSL_FAILURE;
|
||||
#else /* WOLFSSL_KEY_GEN */
|
||||
int ret = SSL_FAILURE;
|
||||
int initTmpRng = 0;
|
||||
RNG *rng = NULL;
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
RNG *tmpRNG = NULL;
|
||||
#else
|
||||
RNG tmpRNG[1];
|
||||
#endif
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_ED25519_generate_key");
|
||||
|
||||
if (priv == NULL || privSz == NULL || *privSz < ED25519_PRV_KEY_SIZE ||
|
||||
pub == NULL || pubSz == NULL || *pubSz < ED25519_PUB_KEY_SIZE) {
|
||||
WOLFSSL_MSG("Bad arguments");
|
||||
return SSL_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
tmpRNG = (RNG*)XMALLOC(sizeof(RNG), NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (tmpRNG == NULL)
|
||||
return SSL_FATAL_ERROR;
|
||||
#endif
|
||||
if (wc_InitRng(tmpRNG) == 0) {
|
||||
rng = tmpRNG;
|
||||
initTmpRng = 1;
|
||||
}
|
||||
else {
|
||||
WOLFSSL_MSG("Bad RNG Init, trying global");
|
||||
if (initGlobalRNG == 0)
|
||||
WOLFSSL_MSG("Global RNG no Init");
|
||||
else
|
||||
rng = &globalRNG;
|
||||
}
|
||||
|
||||
if (rng) {
|
||||
ed25519_key key;
|
||||
|
||||
if (wc_ed25519_init(&key) != MP_OKAY)
|
||||
WOLFSSL_MSG("wc_ed25519_init failed");
|
||||
else if (wc_ed25519_make_key(rng, ED25519_KEY_SIZE, &key)!=MP_OKAY)
|
||||
WOLFSSL_MSG("wc_ed25519_make_key failed");
|
||||
/* export private key */
|
||||
else if (wc_ed25519_export_key(&key, priv, privSz, pub, pubSz)!=MP_OKAY)
|
||||
WOLFSSL_MSG("wc_ed25519_export_key failed");
|
||||
else
|
||||
ret = SSL_SUCCESS;
|
||||
|
||||
wc_ed25519_free(&key);
|
||||
}
|
||||
|
||||
if (initTmpRng)
|
||||
wc_FreeRng(tmpRNG);
|
||||
|
||||
#ifdef WOLFSSL_SMALL_STACK
|
||||
XFREE(tmpRNG, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
#endif /* WOLFSSL_KEY_GEN */
|
||||
}
|
||||
|
||||
/* return 1 if success, 0 if error
|
||||
* input and output keys are little endian format
|
||||
* priv is a buffer containing private and public part of key
|
||||
*/
|
||||
int wolfSSL_ED25519_sign(const unsigned char *msg, unsigned int msgSz,
|
||||
const unsigned char *priv, unsigned int privSz,
|
||||
unsigned char *sig, unsigned int *sigSz)
|
||||
{
|
||||
#ifndef WOLFSSL_KEY_GEN
|
||||
WOLFSSL_MSG("No Key Gen built in");
|
||||
return SSL_FAILURE;
|
||||
#else /* WOLFSSL_KEY_GEN */
|
||||
ed25519_key key;
|
||||
int ret = SSL_FAILURE;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_ED25519_sign");
|
||||
|
||||
if (priv == NULL || privSz != ED25519_PRV_KEY_SIZE ||
|
||||
msg == NULL || sig == NULL || *sigSz < ED25519_SIG_SIZE) {
|
||||
WOLFSSL_MSG("Bad arguments");
|
||||
return SSL_FAILURE;
|
||||
}
|
||||
|
||||
/* import key */
|
||||
if (wc_ed25519_init(&key) != MP_OKAY) {
|
||||
WOLFSSL_MSG("wc_curve25519_init failed");
|
||||
return ret;
|
||||
}
|
||||
if (wc_ed25519_import_private_key(priv, privSz/2,
|
||||
priv+(privSz/2), ED25519_PUB_KEY_SIZE,
|
||||
&key) != MP_OKAY){
|
||||
WOLFSSL_MSG("wc_ed25519_import_private failed");
|
||||
wc_ed25519_free(&key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (wc_ed25519_sign_msg(msg, msgSz, sig, sigSz, &key) != MP_OKAY)
|
||||
WOLFSSL_MSG("wc_curve25519_shared_secret_ex failed");
|
||||
else
|
||||
ret = SSL_SUCCESS;
|
||||
|
||||
wc_ed25519_free(&key);
|
||||
|
||||
return ret;
|
||||
#endif /* WOLFSSL_KEY_GEN */
|
||||
}
|
||||
|
||||
/* return 1 if success, 0 if error
|
||||
* input and output keys are little endian format
|
||||
* pub is a buffer containing public part of key
|
||||
*/
|
||||
int wolfSSL_ED25519_verify(const unsigned char *msg, unsigned int msgSz,
|
||||
const unsigned char *pub, unsigned int pubSz,
|
||||
const unsigned char *sig, unsigned int sigSz)
|
||||
{
|
||||
#ifndef WOLFSSL_KEY_GEN
|
||||
WOLFSSL_MSG("No Key Gen built in");
|
||||
return SSL_FAILURE;
|
||||
#else /* WOLFSSL_KEY_GEN */
|
||||
ed25519_key key;
|
||||
int ret = SSL_FAILURE, check = 0;
|
||||
|
||||
WOLFSSL_ENTER("wolfSSL_ED25519_verify");
|
||||
|
||||
if (pub == NULL || pubSz != ED25519_PUB_KEY_SIZE ||
|
||||
msg == NULL || sig == NULL || sigSz != ED25519_SIG_SIZE) {
|
||||
WOLFSSL_MSG("Bad arguments");
|
||||
return SSL_FAILURE;
|
||||
}
|
||||
|
||||
/* import key */
|
||||
if (wc_ed25519_init(&key) != MP_OKAY) {
|
||||
WOLFSSL_MSG("wc_curve25519_init failed");
|
||||
return ret;
|
||||
}
|
||||
if (wc_ed25519_import_public(pub, pubSz, &key) != MP_OKAY){
|
||||
WOLFSSL_MSG("wc_ed25519_import_public failed");
|
||||
wc_ed25519_free(&key);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if ((ret = wc_ed25519_verify_msg((byte*)sig, sigSz, msg, msgSz,
|
||||
&check, &key)) != MP_OKAY) {
|
||||
WOLFSSL_MSG("wc_ed25519_verify_msg failed");
|
||||
fprintf(stderr, "err code = %d, sigSz=%d, msgSz=%d\n", ret, sigSz, msgSz);
|
||||
}
|
||||
else if (!check)
|
||||
WOLFSSL_MSG("wc_ed25519_verify_msg failed (signature invalid)");
|
||||
else
|
||||
ret = SSL_SUCCESS;
|
||||
|
||||
wc_ed25519_free(&key);
|
||||
|
||||
return ret;
|
||||
#endif /* WOLFSSL_KEY_GEN */
|
||||
}
|
||||
|
||||
#endif /* OPENSSL_EXTRA && HAVE_ED25519 */
|
||||
|
||||
|
|
|
@ -46,94 +46,96 @@ const curve25519_set_type curve25519_sets[] = {
|
|||
};
|
||||
|
||||
|
||||
|
||||
int wc_curve25519_make_key(RNG* rng, int keysize, curve25519_key* key)
|
||||
{
|
||||
unsigned char basepoint[CURVE25519_KEYSIZE] = {9};
|
||||
unsigned char n[CURVE25519_KEYSIZE];
|
||||
unsigned char p[CURVE25519_KEYSIZE];
|
||||
int i;
|
||||
int ret;
|
||||
unsigned char basepoint[CURVE25519_KEYSIZE] = {9};
|
||||
int ret;
|
||||
|
||||
if (key == NULL || rng == NULL)
|
||||
return ECC_BAD_ARG_E;
|
||||
if (key == NULL || rng == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* currently only a key size of 32 bytes is used */
|
||||
if (keysize != CURVE25519_KEYSIZE)
|
||||
return ECC_BAD_ARG_E;
|
||||
/* currently only a key size of 32 bytes is used */
|
||||
if (keysize != CURVE25519_KEYSIZE)
|
||||
return ECC_BAD_ARG_E;
|
||||
|
||||
/* get random number from RNG */
|
||||
ret = wc_RNG_GenerateBlock(rng, n, keysize);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
/* random number for private key */
|
||||
ret = wc_RNG_GenerateBlock(rng, key->k.point, keysize);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < keysize; ++i) key->k.point[i] = n[i];
|
||||
key->k.point[ 0] &= 248;
|
||||
key->k.point[31] &= 127;
|
||||
key->k.point[31] |= 64;
|
||||
/* Clamp the private key */
|
||||
key->k.point[0] &= 248;
|
||||
key->k.point[CURVE25519_KEYSIZE-1] &= 63; /* same &=127 because |=64 after */
|
||||
key->k.point[CURVE25519_KEYSIZE-1] |= 64;
|
||||
|
||||
/* compute public key */
|
||||
ret = curve25519(p, key->k.point, basepoint);
|
||||
/* compute public key */
|
||||
ret = curve25519(key->p.point, key->k.point, basepoint);
|
||||
if (ret != 0) {
|
||||
ForceZero(key->k.point, keysize);
|
||||
ForceZero(key->p.point, keysize);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* store keys in big endian format */
|
||||
for (i = 0; i < keysize; ++i) n[i] = key->k.point[i];
|
||||
for (i = 0; i < keysize; ++i) {
|
||||
key->p.point[keysize - i - 1] = p[i];
|
||||
key->k.point[keysize - i - 1] = n[i];
|
||||
}
|
||||
|
||||
ForceZero(n, keysize);
|
||||
ForceZero(p, keysize);
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int wc_curve25519_shared_secret(curve25519_key* private_key,
|
||||
curve25519_key* public_key,
|
||||
byte* out, word32* outlen)
|
||||
{
|
||||
unsigned char k[CURVE25519_KEYSIZE];
|
||||
unsigned char p[CURVE25519_KEYSIZE];
|
||||
return wc_curve25519_shared_secret_ex(private_key, public_key,
|
||||
out, outlen, EC25519_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
int wc_curve25519_shared_secret_ex(curve25519_key* private_key,
|
||||
curve25519_key* public_key,
|
||||
byte* out, word32* outlen, int endian)
|
||||
{
|
||||
unsigned char o[CURVE25519_KEYSIZE];
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
/* sanity check */
|
||||
if (private_key == NULL || public_key == NULL || out == NULL ||
|
||||
outlen == NULL)
|
||||
if (private_key == NULL || public_key == NULL ||
|
||||
out == NULL || outlen == NULL || *outlen < CURVE25519_KEYSIZE)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* avoid implementation fingerprinting */
|
||||
if (public_key->p.point[0] > 0x7F)
|
||||
if (public_key->p.point[CURVE25519_KEYSIZE-1] > 0x7F)
|
||||
return ECC_BAD_ARG_E;
|
||||
|
||||
XMEMSET(p, 0, sizeof(p));
|
||||
XMEMSET(k, 0, sizeof(k));
|
||||
XMEMSET(out, 0, CURVE25519_KEYSIZE);
|
||||
|
||||
for (i = 0; i < CURVE25519_KEYSIZE; ++i) {
|
||||
p[i] = public_key->p.point [CURVE25519_KEYSIZE - i - 1];
|
||||
k[i] = private_key->k.point[CURVE25519_KEYSIZE - i - 1];
|
||||
ret = curve25519(o, private_key->k.point, public_key->p.point);
|
||||
if (ret != 0) {
|
||||
ForceZero(o, CURVE25519_KEYSIZE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = curve25519(o , k, p);
|
||||
if (endian == EC25519_BIG_ENDIAN) {
|
||||
int i;
|
||||
/* put shared secret key in Big Endian format */
|
||||
for (i = 0; i < CURVE25519_KEYSIZE; i++)
|
||||
out[i] = o[CURVE25519_KEYSIZE - i -1];
|
||||
}
|
||||
else /* put shared secret key in Little Endian format */
|
||||
XMEMCPY(out, o, CURVE25519_KEYSIZE);
|
||||
|
||||
*outlen = CURVE25519_KEYSIZE;
|
||||
|
||||
for (i = 0; i < CURVE25519_KEYSIZE; ++i) {
|
||||
out[i] = o[CURVE25519_KEYSIZE - i -1];
|
||||
}
|
||||
|
||||
ForceZero(p, sizeof(p));
|
||||
ForceZero(k, sizeof(k));
|
||||
ForceZero(o, sizeof(o));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* curve25519 uses a serialized string for key representation */
|
||||
/* export curve25519 public key (Big endian)
|
||||
* return 0 on success */
|
||||
int wc_curve25519_export_public(curve25519_key* key, byte* out, word32* outLen)
|
||||
{
|
||||
return wc_curve25519_export_public_ex(key, out, outLen, EC25519_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* export curve25519 public key (Big or Little endian)
|
||||
* return 0 on success */
|
||||
int wc_curve25519_export_public_ex(curve25519_key* key, byte* out,
|
||||
word32* outLen, int endian)
|
||||
{
|
||||
word32 keySz;
|
||||
|
||||
|
@ -143,30 +145,59 @@ int wc_curve25519_export_public(curve25519_key* key, byte* out, word32* outLen)
|
|||
/* check size of outgoing key */
|
||||
keySz = wc_curve25519_size(key);
|
||||
|
||||
/* copy in public key */
|
||||
XMEMCPY(out, key->p.point, keySz);
|
||||
/* check and set outgoing key size */
|
||||
if (*outLen < keySz) {
|
||||
*outLen = keySz;
|
||||
return ECC_BAD_ARG_E;
|
||||
}
|
||||
*outLen = keySz;
|
||||
|
||||
if (endian == EC25519_BIG_ENDIAN) {
|
||||
int i;
|
||||
|
||||
/* read keys in Big Endian format */
|
||||
for (i = 0; i < CURVE25519_KEYSIZE; i++)
|
||||
out[i] = key->p.point[CURVE25519_KEYSIZE - i - 1];
|
||||
}
|
||||
else
|
||||
XMEMCPY(out, key->p.point, keySz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* import curve25519 public key
|
||||
return 0 on success */
|
||||
/* import curve25519 public key (Big endian)
|
||||
* return 0 on success */
|
||||
int wc_curve25519_import_public(const byte* in, word32 inLen,
|
||||
curve25519_key* key)
|
||||
{
|
||||
return wc_curve25519_import_public_ex(in, inLen, key, EC25519_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* import curve25519 public key (Big or Little endian)
|
||||
* return 0 on success */
|
||||
int wc_curve25519_import_public_ex(const byte* in, word32 inLen,
|
||||
curve25519_key* key, int endian)
|
||||
{
|
||||
word32 keySz;
|
||||
|
||||
/* sanity check */
|
||||
if (key == NULL || in == NULL)
|
||||
return ECC_BAD_ARG_E;
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* check size of incoming keys */
|
||||
keySz = wc_curve25519_size(key);
|
||||
if (inLen != keySz)
|
||||
return ECC_BAD_ARG_E;
|
||||
|
||||
XMEMCPY(key->p.point, in, inLen);
|
||||
if (endian == EC25519_BIG_ENDIAN) {
|
||||
int i;
|
||||
|
||||
/* read keys in Big Endian format */
|
||||
for (i = 0; i < CURVE25519_KEYSIZE; i++)
|
||||
key->p.point[i] = in[CURVE25519_KEYSIZE - i - 1];
|
||||
}
|
||||
else
|
||||
XMEMCPY(key->p.point, in, inLen);
|
||||
|
||||
key->dp = &curve25519_sets[0];
|
||||
|
||||
|
@ -174,63 +205,159 @@ int wc_curve25519_import_public(const byte* in, word32 inLen,
|
|||
}
|
||||
|
||||
|
||||
/* export curve25519 private key only raw, outLen is in/out size
|
||||
return 0 on success */
|
||||
/* export curve25519 private key only raw (Big endian)
|
||||
* outLen is in/out size
|
||||
* return 0 on success */
|
||||
int wc_curve25519_export_private_raw(curve25519_key* key, byte* out,
|
||||
word32* outLen)
|
||||
{
|
||||
return wc_curve25519_export_private_raw_ex(key, out, outLen,
|
||||
EC25519_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* export curve25519 private key only raw (Big or Little endian)
|
||||
* outLen is in/out size
|
||||
* return 0 on success */
|
||||
int wc_curve25519_export_private_raw_ex(curve25519_key* key, byte* out,
|
||||
word32* outLen, int endian)
|
||||
{
|
||||
word32 keySz;
|
||||
|
||||
/* sanity check */
|
||||
if (key == NULL || out == NULL || outLen == NULL)
|
||||
return ECC_BAD_ARG_E;
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* check size of outgoing buffer */
|
||||
keySz = wc_curve25519_size(key);
|
||||
if (*outLen < keySz) {
|
||||
*outLen = keySz;
|
||||
return ECC_BAD_ARG_E;
|
||||
}
|
||||
*outLen = keySz;
|
||||
XMEMSET(out, 0, keySz);
|
||||
XMEMCPY(out, key->k.point, keySz);
|
||||
|
||||
if (endian == EC25519_BIG_ENDIAN) {
|
||||
int i;
|
||||
|
||||
/* put the key in Big Endian format */
|
||||
for (i = 0; i < CURVE25519_KEYSIZE; i++)
|
||||
out[i] = key->k.point[CURVE25519_KEYSIZE - i - 1];
|
||||
}
|
||||
else
|
||||
XMEMCPY(out, key->k.point, keySz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* curve25519 private key import.
|
||||
Public key to match private key needs to be imported too */
|
||||
int wc_curve25519_import_private_raw(const byte* priv, word32 privSz,
|
||||
const byte* pub, word32 pubSz, curve25519_key* key)
|
||||
/* curve25519 key pair export (Big or Little endian)
|
||||
* return 0 on success */
|
||||
int wc_curve25519_export_key_raw(curve25519_key* key,
|
||||
byte* priv, word32 *privSz,
|
||||
byte* pub, word32 *pubSz)
|
||||
{
|
||||
int ret = 0;
|
||||
word32 keySz;
|
||||
return wc_curve25519_export_key_raw_ex(key, priv, privSz,
|
||||
pub, pubSz, EC25519_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* sanity check */
|
||||
if (key == NULL || priv == NULL || pub == NULL)
|
||||
return ECC_BAD_ARG_E;
|
||||
/* curve25519 key pair export (Big or Little endian)
|
||||
* return 0 on success */
|
||||
int wc_curve25519_export_key_raw_ex(curve25519_key* key,
|
||||
byte* priv, word32 *privSz,
|
||||
byte* pub, word32 *pubSz,
|
||||
int endian)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* check size of incoming keys */
|
||||
keySz = wc_curve25519_size(key);
|
||||
if (privSz != keySz || pubSz != keySz)
|
||||
return ECC_BAD_ARG_E;
|
||||
/* export private part */
|
||||
ret = wc_curve25519_export_private_raw_ex(key, priv, privSz, endian);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
XMEMCPY(key->k.point, priv, privSz);
|
||||
XMEMCPY(key->p.point, pub, pubSz);
|
||||
|
||||
return ret;
|
||||
/* export public part */
|
||||
return wc_curve25519_export_public_ex(key, pub, pubSz, endian);
|
||||
}
|
||||
|
||||
|
||||
/* curve25519 private key import (Big endian)
|
||||
* Public key to match private key needs to be imported too
|
||||
* return 0 on success */
|
||||
int wc_curve25519_import_private_raw(const byte* priv, word32 privSz,
|
||||
const byte* pub, word32 pubSz,
|
||||
curve25519_key* key)
|
||||
{
|
||||
return wc_curve25519_import_private_raw_ex(priv, privSz, pub, pubSz,
|
||||
key, EC25519_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* curve25519 private key import (Big or Little endian)
|
||||
* Public key to match private key needs to be imported too
|
||||
* return 0 on success */
|
||||
int wc_curve25519_import_private_raw_ex(const byte* priv, word32 privSz,
|
||||
const byte* pub, word32 pubSz,
|
||||
curve25519_key* key, int endian)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* import private part */
|
||||
ret = wc_curve25519_import_private_ex(priv, privSz, key, endian);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* import public part */
|
||||
return wc_curve25519_import_public_ex(pub, pubSz, key, endian);
|
||||
}
|
||||
|
||||
/* curve25519 private key import only. (Big endian)
|
||||
* return 0 on success */
|
||||
int wc_curve25519_import_private(const byte* priv, word32 privSz,
|
||||
curve25519_key* key)
|
||||
{
|
||||
return wc_curve25519_import_private_ex(priv, privSz,
|
||||
key, EC25519_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* curve25519 private key import only. (Big or Little endian)
|
||||
* return 0 on success */
|
||||
int wc_curve25519_import_private_ex(const byte* priv, word32 privSz,
|
||||
curve25519_key* key, int endian)
|
||||
{
|
||||
/* sanity check */
|
||||
if (key == NULL || priv == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* check size of incoming keys */
|
||||
if ((int)privSz != wc_curve25519_size(key))
|
||||
return ECC_BAD_ARG_E;
|
||||
|
||||
if (endian == EC25519_BIG_ENDIAN) {
|
||||
int i;
|
||||
|
||||
/* read the key in Big Endian format */
|
||||
for (i = 0; i < CURVE25519_KEYSIZE; i++)
|
||||
key->k.point[i] = priv[CURVE25519_KEYSIZE - i - 1];
|
||||
}
|
||||
else
|
||||
XMEMCPY(key->k.point, priv, privSz);
|
||||
|
||||
key->dp = &curve25519_sets[0];
|
||||
|
||||
/* Clamp the key */
|
||||
key->k.point[0] &= 248;
|
||||
key->k.point[privSz-1] &= 63; /* same &=127 because |=64 after */
|
||||
key->k.point[privSz-1] |= 64;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wc_curve25519_init(curve25519_key* key)
|
||||
{
|
||||
word32 keySz;
|
||||
|
||||
if (key == NULL)
|
||||
return ECC_BAD_ARG_E;
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* currently the format for curve25519 */
|
||||
key->dp = &curve25519_sets[0];
|
||||
keySz = key->dp->size;
|
||||
|
||||
XMEMSET(key->k.point, 0, keySz);
|
||||
XMEMSET(key->p.point, 0, keySz);
|
||||
XMEMSET(key->k.point, 0, key->dp->size);
|
||||
XMEMSET(key->p.point, 0, key->dp->size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -251,7 +378,8 @@ void wc_curve25519_free(curve25519_key* key)
|
|||
/* get key size */
|
||||
int wc_curve25519_size(curve25519_key* key)
|
||||
{
|
||||
if (key == NULL) return 0;
|
||||
if (key == NULL)
|
||||
return 0;
|
||||
|
||||
return key->dp->size;
|
||||
}
|
||||
|
|
|
@ -38,14 +38,12 @@
|
|||
#include <wolfcrypt/src/misc.c>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
generate an ed25519 key pair.
|
||||
returns 0 on success
|
||||
/* generate an ed25519 key pair.
|
||||
* returns 0 on success
|
||||
*/
|
||||
int wc_ed25519_make_key(RNG* rng, int keySz, ed25519_key* key)
|
||||
{
|
||||
byte az[64];
|
||||
byte az[ED25519_PRV_KEY_SIZE];
|
||||
int ret;
|
||||
ge_p3 A;
|
||||
|
||||
|
@ -56,16 +54,25 @@ int wc_ed25519_make_key(RNG* rng, int keySz, ed25519_key* key)
|
|||
if (keySz != ED25519_KEY_SIZE)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
ret = 0;
|
||||
ret |= wc_RNG_GenerateBlock(rng, key->k, 32);
|
||||
ret |= wc_Sha512Hash(key->k, 32, az);
|
||||
az[0] &= 248;
|
||||
az[31] &= 63;
|
||||
ret = wc_RNG_GenerateBlock(rng, key->k, ED25519_KEY_SIZE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Hash(key->k, ED25519_KEY_SIZE, az);
|
||||
if (ret != 0) {
|
||||
ForceZero(key->k, ED25519_KEY_SIZE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* apply clamp */
|
||||
az[0] &= 248;
|
||||
az[31] &= 63; /* same than az[31] &= 127 because of az[31] |= 64 */
|
||||
az[31] |= 64;
|
||||
|
||||
ge_scalarmult_base(&A, az);
|
||||
ge_p3_tobytes(key->p, &A);
|
||||
XMEMMOVE(key->k + 32, key->p, 32);
|
||||
|
||||
/* put public key after private key, on the same buffer */
|
||||
XMEMMOVE(key->k + ED25519_KEY_SIZE, key->p, ED25519_PUB_KEY_SIZE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -75,43 +82,54 @@ int wc_ed25519_make_key(RNG* rng, int keySz, ed25519_key* key)
|
|||
in contains the message to sign
|
||||
inlen is the length of the message to sign
|
||||
out is the buffer to write the signature
|
||||
outlen [in/out] input size of out buf
|
||||
output gets set as the final length of out
|
||||
outLen [in/out] input size of out buf
|
||||
output gets set as the final length of out
|
||||
key is the ed25519 key to use when signing
|
||||
return 0 on success
|
||||
*/
|
||||
int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out,
|
||||
word32 *outlen, ed25519_key* key)
|
||||
word32 *outLen, ed25519_key* key)
|
||||
{
|
||||
ge_p3 R;
|
||||
byte nonce[SHA512_DIGEST_SIZE];
|
||||
byte hram[SHA512_DIGEST_SIZE];
|
||||
byte az[64];
|
||||
word32 sigSz;
|
||||
byte az[ED25519_PRV_KEY_SIZE];
|
||||
Sha512 sha;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
/* sanity check on arguments */
|
||||
if (in == NULL || out == NULL || outlen == NULL || key == NULL)
|
||||
if (in == NULL || out == NULL || outLen == NULL || key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* check and set up out length */
|
||||
ret = 0;
|
||||
sigSz = wc_ed25519_sig_size(key);
|
||||
if (*outlen < sigSz)
|
||||
return BAD_FUNC_ARG;
|
||||
*outlen = sigSz;
|
||||
if (*outLen < ED25519_SIG_SIZE) {
|
||||
*outLen = ED25519_SIG_SIZE;
|
||||
return BUFFER_E;
|
||||
}
|
||||
*outLen = ED25519_SIG_SIZE;
|
||||
|
||||
/* step 1: create nonce to use where nonce is r in
|
||||
r = H(h_b, ... ,h_2b-1,M) */
|
||||
ret |= wc_Sha512Hash(key->k,32,az);
|
||||
ret = wc_Sha512Hash(key->k, ED25519_KEY_SIZE, az);
|
||||
|
||||
/* apply clamp */
|
||||
az[0] &= 248;
|
||||
az[31] &= 63;
|
||||
az[31] &= 63; /* same than az[31] &= 127 because of az[31] |= 64 */
|
||||
az[31] |= 64;
|
||||
ret |= wc_InitSha512(&sha);
|
||||
ret |= wc_Sha512Update(&sha, az + 32, 32);
|
||||
ret |= wc_Sha512Update(&sha, in, inlen);
|
||||
ret |= wc_Sha512Final(&sha, nonce);
|
||||
|
||||
ret = wc_InitSha512(&sha);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Update(&sha, az + ED25519_KEY_SIZE, ED25519_KEY_SIZE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Update(&sha, in, inlen);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Final(&sha, nonce);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
sc_reduce(nonce);
|
||||
|
||||
/* step 2: computing R = rB where rB is the scalar multiplication of
|
||||
|
@ -121,13 +139,24 @@ int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out,
|
|||
|
||||
/* step 3: hash R + public key + message getting H(R,A,M) then
|
||||
creating S = (r + H(R,A,M)a) mod l */
|
||||
ret |= wc_InitSha512(&sha);
|
||||
ret |= wc_Sha512Update(&sha, out, 32);
|
||||
ret |= wc_Sha512Update(&sha, key->p, 32);
|
||||
ret |= wc_Sha512Update(&sha, in, inlen);
|
||||
ret |= wc_Sha512Final(&sha, hram);
|
||||
ret = wc_InitSha512(&sha);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Update(&sha, out, ED25519_SIG_SIZE/2);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Update(&sha, key->p, ED25519_PUB_KEY_SIZE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Update(&sha, in, inlen);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Final(&sha, hram);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
sc_reduce(hram);
|
||||
sc_muladd(out + 32, hram, az, nonce);
|
||||
sc_muladd(out + (ED25519_SIG_SIZE/2), hram, az, nonce);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -143,11 +172,10 @@ int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out,
|
|||
int wc_ed25519_verify_msg(byte* sig, word32 siglen, const byte* msg,
|
||||
word32 msglen, int* stat, ed25519_key* key)
|
||||
{
|
||||
byte rcheck[32];
|
||||
byte rcheck[ED25519_KEY_SIZE];
|
||||
byte h[SHA512_DIGEST_SIZE];
|
||||
ge_p3 A;
|
||||
ge_p2 R;
|
||||
word32 sigSz;
|
||||
int ret;
|
||||
Sha512 sha;
|
||||
|
||||
|
@ -155,14 +183,11 @@ int wc_ed25519_verify_msg(byte* sig, word32 siglen, const byte* msg,
|
|||
if (sig == NULL || msg == NULL || stat == NULL || key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
ret = 0;
|
||||
/* set verification failed by default */
|
||||
*stat = 0;
|
||||
sigSz = wc_ed25519_size(key);
|
||||
|
||||
/* check on basics needed to verify signature */
|
||||
if (siglen < sigSz)
|
||||
return BAD_FUNC_ARG;
|
||||
if (sig[63] & 224)
|
||||
if (siglen < ED25519_SIG_SIZE || (sig[ED25519_SIG_SIZE-1] & 224))
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* uncompress A (public key), test if valid, and negate it */
|
||||
|
@ -170,24 +195,41 @@ int wc_ed25519_verify_msg(byte* sig, word32 siglen, const byte* msg,
|
|||
return BAD_FUNC_ARG;
|
||||
|
||||
/* find H(R,A,M) and store it as h */
|
||||
ret |= wc_InitSha512(&sha);
|
||||
ret |= wc_Sha512Update(&sha, sig, 32);
|
||||
ret |= wc_Sha512Update(&sha, key->p, 32);
|
||||
ret |= wc_Sha512Update(&sha, msg, msglen);
|
||||
ret |= wc_Sha512Final(&sha, h);
|
||||
ret = wc_InitSha512(&sha);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Update(&sha, sig, ED25519_SIG_SIZE/2);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Update(&sha, key->p, ED25519_PUB_KEY_SIZE);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Update(&sha, msg, msglen);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = wc_Sha512Final(&sha, h);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
sc_reduce(h);
|
||||
|
||||
/*
|
||||
Uses a fast single-signature verification SB = R + H(R,A,M)A becomes
|
||||
SB - H(R,A,M)A saving decompression of R
|
||||
*/
|
||||
ret |= ge_double_scalarmult_vartime(&R, h, &A, sig + 32);
|
||||
ret = ge_double_scalarmult_vartime(&R, h, &A, sig + (ED25519_SIG_SIZE/2));
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ge_tobytes(rcheck, &R);
|
||||
|
||||
/* comparison of R created to R in sig */
|
||||
ret |= ConstantCompare(rcheck, sig, 32);
|
||||
ret = ConstantCompare(rcheck, sig, ED25519_SIG_SIZE/2);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
*stat = (ret == 0)? 1: 0;
|
||||
/* set the verification status */
|
||||
*stat = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -222,19 +264,17 @@ void wc_ed25519_free(ed25519_key* key)
|
|||
*/
|
||||
int wc_ed25519_export_public(ed25519_key* key, byte* out, word32* outLen)
|
||||
{
|
||||
word32 keySz;
|
||||
|
||||
/* sanity check on arguments */
|
||||
if (key == NULL || out == NULL || outLen == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
keySz = wc_ed25519_size(key);
|
||||
if (*outLen < keySz) {
|
||||
*outLen = keySz;
|
||||
if (*outLen < ED25519_PUB_KEY_SIZE) {
|
||||
*outLen = ED25519_PUB_KEY_SIZE;
|
||||
return BUFFER_E;
|
||||
}
|
||||
*outLen = keySz;
|
||||
XMEMCPY(out, key->p, keySz);
|
||||
|
||||
*outLen = ED25519_PUB_KEY_SIZE;
|
||||
XMEMCPY(out, key->p, ED25519_PUB_KEY_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -248,37 +288,35 @@ int wc_ed25519_export_public(ed25519_key* key, byte* out, word32* outLen)
|
|||
*/
|
||||
int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key)
|
||||
{
|
||||
word32 keySz;
|
||||
int ret;
|
||||
|
||||
/* sanity check on arguments */
|
||||
if (in == NULL || key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
keySz = wc_ed25519_size(key);
|
||||
|
||||
if (inLen < keySz)
|
||||
if (inLen < ED25519_PUB_KEY_SIZE)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* compressed prefix according to draft
|
||||
http://www.ietf.org/id/draft-koch-eddsa-for-openpgp-02.txt */
|
||||
if (in[0] == 0x40) {
|
||||
if (in[0] == 0x40 && inLen > ED25519_PUB_KEY_SIZE) {
|
||||
/* key is stored in compressed format so just copy in */
|
||||
XMEMCPY(key->p, (in + 1), keySz);
|
||||
XMEMCPY(key->p, (in + 1), ED25519_PUB_KEY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* importing uncompressed public key */
|
||||
if (in[0] == 0x04) {
|
||||
if (in[0] == 0x04 && inLen > 2*ED25519_PUB_KEY_SIZE) {
|
||||
/* pass in (x,y) and store compressed key */
|
||||
ret = ge_compress_key(key->p, (in+1), (in+1+keySz), keySz);
|
||||
ret = ge_compress_key(key->p, in+1,
|
||||
in+1+ED25519_PUB_KEY_SIZE, ED25519_PUB_KEY_SIZE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* if not specified compressed or uncompressed check key size
|
||||
if key size is equal to compressed key size copy in key */
|
||||
if (inLen == keySz) {
|
||||
XMEMCPY(key->p, in, keySz);
|
||||
if (inLen == ED25519_PUB_KEY_SIZE) {
|
||||
XMEMCPY(key->p, in, ED25519_PUB_KEY_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -293,77 +331,129 @@ int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key)
|
|||
int wc_ed25519_import_private_key(const byte* priv, word32 privSz,
|
||||
const byte* pub, word32 pubSz, ed25519_key* key)
|
||||
{
|
||||
word32 keySz;
|
||||
int ret;
|
||||
|
||||
/* sanity check on arguments */
|
||||
if (priv == NULL || pub == NULL || key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
keySz = wc_ed25519_size(key);
|
||||
|
||||
/* key size check */
|
||||
if (privSz < keySz || pubSz < keySz)
|
||||
if (privSz < ED25519_KEY_SIZE || pubSz < ED25519_PUB_KEY_SIZE)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
XMEMCPY(key->k, priv, keySz);
|
||||
/* import public key */
|
||||
ret = wc_ed25519_import_public(pub, pubSz, key);
|
||||
XMEMCPY((key->k + keySz), key->p, keySz);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* make the private key (priv + pub) */
|
||||
XMEMCPY(key->k, priv, ED25519_KEY_SIZE);
|
||||
XMEMCPY(key->k + ED25519_KEY_SIZE, key->p, ED25519_PUB_KEY_SIZE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
outLen should contain the size of out buffer when input. outLen is than set
|
||||
to the final output length.
|
||||
returns 0 on success
|
||||
export private key only (secret part so 32 bytes)
|
||||
outLen should contain the size of out buffer when input. outLen is than set
|
||||
to the final output length.
|
||||
returns 0 on success
|
||||
*/
|
||||
int wc_ed25519_export_private_only(ed25519_key* key, byte* out, word32* outLen)
|
||||
{
|
||||
word32 keySz;
|
||||
|
||||
/* sanity checks on arguments */
|
||||
if (key == NULL || out == NULL || outLen == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
keySz = wc_ed25519_size(key);
|
||||
if (*outLen < keySz) {
|
||||
*outLen = keySz;
|
||||
if (*outLen < ED25519_KEY_SIZE) {
|
||||
*outLen = ED25519_KEY_SIZE;
|
||||
return BUFFER_E;
|
||||
}
|
||||
*outLen = keySz;
|
||||
XMEMCPY(out, key->k, keySz);
|
||||
|
||||
*outLen = ED25519_KEY_SIZE;
|
||||
XMEMCPY(out, key->k, ED25519_KEY_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
export private key, including public part
|
||||
outLen should contain the size of out buffer when input. outLen is than set
|
||||
to the final output length.
|
||||
returns 0 on success
|
||||
*/
|
||||
int wc_ed25519_export_private(ed25519_key* key, byte* out, word32* outLen)
|
||||
{
|
||||
/* sanity checks on arguments */
|
||||
if (key == NULL || out == NULL || outLen == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
/* is the compressed key size in bytes */
|
||||
if (*outLen < ED25519_PRV_KEY_SIZE) {
|
||||
*outLen = ED25519_PRV_KEY_SIZE;
|
||||
return BUFFER_E;
|
||||
}
|
||||
|
||||
*outLen = ED25519_PRV_KEY_SIZE;
|
||||
XMEMCPY(out, key->k, ED25519_PRV_KEY_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* export full private key and public key
|
||||
return 0 on success
|
||||
*/
|
||||
int wc_ed25519_export_key(ed25519_key* key,
|
||||
byte* priv, word32 *privSz,
|
||||
byte* pub, word32 *pubSz)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* export 'full' private part */
|
||||
ret = wc_ed25519_export_private(key, priv, privSz);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* export public part */
|
||||
ret = wc_ed25519_export_public(key, pub, pubSz);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* returns the private key size (secret only) in bytes */
|
||||
int wc_ed25519_size(ed25519_key* key)
|
||||
{
|
||||
word32 keySz;
|
||||
|
||||
if (key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
keySz = ED25519_KEY_SIZE;
|
||||
|
||||
return keySz;
|
||||
return ED25519_KEY_SIZE;
|
||||
}
|
||||
|
||||
/* returns the private key size (secret + public) in bytes */
|
||||
int wc_ed25519_priv_size(ed25519_key* key)
|
||||
{
|
||||
if (key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
return ED25519_PRV_KEY_SIZE;
|
||||
}
|
||||
|
||||
/* returns the compressed key size in bytes (public key) */
|
||||
int wc_ed25519_pub_size(ed25519_key* key)
|
||||
{
|
||||
if (key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
return ED25519_PUB_KEY_SIZE;
|
||||
}
|
||||
|
||||
/* returns the size of signature in bytes */
|
||||
int wc_ed25519_sig_size(ed25519_key* key)
|
||||
{
|
||||
word32 sigSz;
|
||||
|
||||
if (key == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
sigSz = ED25519_SIG_SIZE;
|
||||
|
||||
return sigSz;
|
||||
return ED25519_SIG_SIZE;
|
||||
}
|
||||
|
||||
#endif /* HAVE_ED25519 */
|
||||
|
|
|
@ -107,8 +107,9 @@ void fe_0(fe h)
|
|||
|
||||
int curve25519(byte* q, byte* n, byte* p)
|
||||
{
|
||||
#if 0
|
||||
unsigned char e[32];
|
||||
unsigned int i;
|
||||
#endif
|
||||
fe x1;
|
||||
fe x2;
|
||||
fe z2;
|
||||
|
@ -120,10 +121,16 @@ int curve25519(byte* q, byte* n, byte* p)
|
|||
unsigned int swap;
|
||||
unsigned int b;
|
||||
|
||||
for (i = 0;i < 32;++i) e[i] = n[i];
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
/* Clamp already done during key generation and import */
|
||||
#if 0
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0;i < 32;++i) e[i] = n[i];
|
||||
e[0] &= 248;
|
||||
e[31] &= 127;
|
||||
e[31] |= 64;
|
||||
}
|
||||
#endif
|
||||
|
||||
fe_frombytes(x1,p);
|
||||
fe_1(x2);
|
||||
|
@ -133,7 +140,11 @@ int curve25519(byte* q, byte* n, byte* p)
|
|||
|
||||
swap = 0;
|
||||
for (pos = 254;pos >= 0;--pos) {
|
||||
#if 0
|
||||
b = e[pos / 8] >> (pos & 7);
|
||||
#else
|
||||
b = n[pos / 8] >> (pos & 7);
|
||||
#endif
|
||||
b &= 1;
|
||||
swap ^= b;
|
||||
fe_cswap(x2,x3,swap);
|
||||
|
|
|
@ -5510,6 +5510,27 @@ int curve25519_test(void)
|
|||
if (XMEMCMP(ss, sharedB, y))
|
||||
return -1017;
|
||||
|
||||
/* test with 1 generated key and 1 from known test vector */
|
||||
if (wc_curve25519_import_private_raw(sa, sizeof(sa), pa, sizeof(pa), &userA)
|
||||
!= 0)
|
||||
return -1018;
|
||||
|
||||
if (wc_curve25519_make_key(&rng, 32, &userB) != 0)
|
||||
return -1019;
|
||||
|
||||
if (wc_curve25519_shared_secret(&userA, &userB, sharedA, &x) != 0)
|
||||
return -1020;
|
||||
|
||||
if (wc_curve25519_shared_secret(&userB, &userA, sharedB, &y) != 0)
|
||||
return -1021;
|
||||
|
||||
/* compare shared secret keys to test they are the same */
|
||||
if (y != x)
|
||||
return -1022;
|
||||
|
||||
if (XMEMCMP(sharedA, sharedB, x))
|
||||
return -1023;
|
||||
|
||||
/* clean up keys when done */
|
||||
wc_curve25519_free(&pubKey);
|
||||
wc_curve25519_free(&userB);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
/* ec25519.h */
|
||||
|
||||
#ifndef WOLFSSL_EC25519_H_
|
||||
#define WOLFSSL_EC25519_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
WOLFSSL_API
|
||||
int wolfSSL_EC25519_generate_key(unsigned char *priv, unsigned int *privSz,
|
||||
unsigned char *pub, unsigned int *pubSz);
|
||||
|
||||
WOLFSSL_API
|
||||
int wolfSSL_EC25519_shared_key(unsigned char *shared, unsigned int *sharedSz,
|
||||
const unsigned char *priv, unsigned int privSz,
|
||||
const unsigned char *pub, unsigned int pubSz);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* header */
|
|
@ -0,0 +1,26 @@
|
|||
/* ed25519.h */
|
||||
|
||||
#ifndef WOLFSSL_ED25519_H_
|
||||
#define WOLFSSL_ED25519_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
WOLFSSL_API
|
||||
int wolfSSL_ED25519_generate_key(unsigned char *priv, unsigned int *privSz,
|
||||
unsigned char *pub, unsigned int *pubSz);
|
||||
WOLFSSL_API
|
||||
int wolfSSL_ED25519_sign(const unsigned char *msg, unsigned int msgSz,
|
||||
const unsigned char *priv, unsigned int privSz,
|
||||
unsigned char *sig, unsigned int *sigSz);
|
||||
WOLFSSL_API
|
||||
int wolfSSL_ED25519_verify(const unsigned char *msg, unsigned int msgSz,
|
||||
const unsigned char *pub, unsigned int pubSz,
|
||||
const unsigned char *sig, unsigned int sigSz);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* header */
|
|
@ -13,6 +13,8 @@ nobase_include_HEADERS+= \
|
|||
wolfssl/openssl/ecdsa.h \
|
||||
wolfssl/openssl/ecdh.h \
|
||||
wolfssl/openssl/ec.h \
|
||||
wolfssl/openssl/ec25519.h \
|
||||
wolfssl/openssl/ed25519.h \
|
||||
wolfssl/openssl/engine.h \
|
||||
wolfssl/openssl/err.h \
|
||||
wolfssl/openssl/evp.h \
|
||||
|
|
|
@ -28,7 +28,7 @@ int wolfSSL_PEM_write_RSAPrivateKey(FILE *fp, WOLFSSL_RSA *rsa,
|
|||
WOLFSSL_API
|
||||
int wolfSSL_PEM_write_mem_RSAPrivateKey(RSA* rsa, const EVP_CIPHER* cipher,
|
||||
unsigned char* passwd, int len,
|
||||
byte **pem, int *plen);
|
||||
unsigned char **pem, int *plen);
|
||||
WOLFSSL_API
|
||||
WOLFSSL_RSA *wolfSSL_PEM_read_RSAPublicKey(FILE *fp, WOLFSSL_RSA **x,
|
||||
pem_password_cb *cb, void *u);
|
||||
|
@ -54,7 +54,7 @@ WOLFSSL_API
|
|||
int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa,
|
||||
const EVP_CIPHER* cipher,
|
||||
unsigned char* passwd, int len,
|
||||
byte **pem, int *plen);
|
||||
unsigned char **pem, int *plen);
|
||||
WOLFSSL_API
|
||||
int wolfSSL_PEM_write_DSA_PUBKEY(FILE *fp, WOLFSSL_DSA *x);
|
||||
|
||||
|
@ -73,7 +73,7 @@ WOLFSSL_API
|
|||
int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* key,
|
||||
const EVP_CIPHER* cipher,
|
||||
unsigned char* passwd, int len,
|
||||
byte **pem, int *plen);
|
||||
unsigned char **pem, int *plen);
|
||||
WOLFSSL_API
|
||||
int wolfSSL_PEM_write_EC_PUBKEY(FILE *fp, WOLFSSL_EC_KEY *key);
|
||||
|
||||
|
|
|
@ -42,7 +42,8 @@ typedef struct {
|
|||
} curve25519_set_type;
|
||||
|
||||
|
||||
/* ECC point */
|
||||
/* ECC point, the internal structure is Little endian
|
||||
* the mathematical functions used the endianess */
|
||||
typedef struct {
|
||||
byte point[CURVE25519_KEYSIZE];
|
||||
}ECPoint;
|
||||
|
@ -58,6 +59,11 @@ typedef struct {
|
|||
ECPoint k; /* private key */
|
||||
} curve25519_key;
|
||||
|
||||
enum {
|
||||
EC25519_LITTLE_ENDIAN=0,
|
||||
EC25519_BIG_ENDIAN=1
|
||||
};
|
||||
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_make_key(RNG* rng, int keysize, curve25519_key* key);
|
||||
|
||||
|
@ -66,6 +72,11 @@ int wc_curve25519_shared_secret(curve25519_key* private_key,
|
|||
curve25519_key* public_key,
|
||||
byte* out, word32* outlen);
|
||||
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_shared_secret_ex(curve25519_key* private_key,
|
||||
curve25519_key* public_key,
|
||||
byte* out, word32* outlen, int endian);
|
||||
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_init(curve25519_key* key);
|
||||
|
||||
|
@ -74,21 +85,49 @@ void wc_curve25519_free(curve25519_key* key);
|
|||
|
||||
|
||||
/* raw key helpers */
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_import_private(const byte* priv, word32 privSz,
|
||||
curve25519_key* key);
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_import_private_ex(const byte* priv, word32 privSz,
|
||||
curve25519_key* key, int endian);
|
||||
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_import_private_raw(const byte* priv, word32 privSz,
|
||||
const byte* pub, word32 pubSz, curve25519_key* key);
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_import_private_raw_ex(const byte* priv, word32 privSz,
|
||||
const byte* pub, word32 pubSz,
|
||||
curve25519_key* key, int endian);
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_export_private_raw(curve25519_key* key, byte* out,
|
||||
word32* outLen);
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_export_private_raw_ex(curve25519_key* key, byte* out,
|
||||
word32* outLen, int endian);
|
||||
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_import_public(const byte* in, word32 inLen,
|
||||
curve25519_key* key);
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_import_public_ex(const byte* in, word32 inLen,
|
||||
curve25519_key* key, int endian);
|
||||
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_export_public(curve25519_key* key, byte* out, word32* outLen);
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_export_public_ex(curve25519_key* key, byte* out,
|
||||
word32* outLen, int endian);
|
||||
|
||||
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_export_key_raw(curve25519_key* key,
|
||||
byte* priv, word32 *privSz,
|
||||
byte* pub, word32 *pubSz);
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_export_key_raw_ex(curve25519_key* key,
|
||||
byte* priv, word32 *privSz,
|
||||
byte* pub, word32 *pubSz,
|
||||
int endian);
|
||||
/* size helper */
|
||||
WOLFSSL_API
|
||||
int wc_curve25519_size(curve25519_key* key);
|
||||
|
|
|
@ -46,14 +46,17 @@
|
|||
"-121665/121666", value of d
|
||||
*/
|
||||
|
||||
#define ED25519_KEY_SIZE 32
|
||||
#define ED25519_SIG_SIZE 64
|
||||
#define ED25519_KEY_SIZE 32 /* private key only */
|
||||
#define ED25519_SIG_SIZE 64
|
||||
|
||||
#define ED25519_PUB_KEY_SIZE 32 /* compressed */
|
||||
/* both private and public key */
|
||||
#define ED25519_PRV_KEY_SIZE (ED25519_PUB_KEY_SIZE+ED25519_KEY_SIZE)
|
||||
|
||||
/* An ED25519 Key */
|
||||
typedef struct {
|
||||
byte p[32]; /* compressed public key */
|
||||
byte k[64]; /* private key : 32 secret -- 32 public */
|
||||
byte p[ED25519_PUB_KEY_SIZE]; /* compressed public key */
|
||||
byte k[ED25519_PRV_KEY_SIZE]; /* private key : 32 secret -- 32 public */
|
||||
} ed25519_key;
|
||||
|
||||
|
||||
|
@ -78,11 +81,21 @@ WOLFSSL_API
|
|||
int wc_ed25519_export_public(ed25519_key*, byte* out, word32* outLen);
|
||||
WOLFSSL_API
|
||||
int wc_ed25519_export_private_only(ed25519_key* key, byte* out, word32* outLen);
|
||||
WOLFSSL_API
|
||||
int wc_ed25519_export_private(ed25519_key* key, byte* out, word32* outLen);
|
||||
WOLFSSL_API
|
||||
int wc_ed25519_export_key(ed25519_key* key,
|
||||
byte* priv, word32 *privSz,
|
||||
byte* pub, word32 *pubSz);
|
||||
|
||||
/* size helper */
|
||||
WOLFSSL_API
|
||||
int wc_ed25519_size(ed25519_key* key);
|
||||
WOLFSSL_API
|
||||
int wc_ed25519_priv_size(ed25519_key* key);
|
||||
WOLFSSL_API
|
||||
int wc_ed25519_pub_size(ed25519_key* key);
|
||||
WOLFSSL_API
|
||||
int wc_ed25519_sig_size(ed25519_key* key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
Loading…
Reference in New Issue