add support for curve 25519 and Ed25519 in OpenSSH

refactor curve25519 and Ed25519 code
fix warning in PEM_xxx_mem_xxx functions
This commit is contained in:
Ludovic FLAMENT
2015-08-01 18:28:18 +02:00
parent e363848ecc
commit 409126a97c
15 changed files with 888 additions and 204 deletions

View File

@ -733,6 +733,11 @@ AC_ARG_ENABLE([curve25519],
) )
if test "$ENABLED_OPENSSH" = "yes"
then
ENABLED_CURVE25519="yes"
fi
if test "$ENABLED_CURVE25519" = "small" if test "$ENABLED_CURVE25519" = "small"
then then
AM_CFLAGS="$AM_CFLAGS -DCURVED25519_SMALL" 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" if test "$ENABLED_ED25519" = "small"
then then
AM_CFLAGS="$AM_CFLAGS -DCURVED25519_SMALL" AM_CFLAGS="$AM_CFLAGS -DCURVED25519_SMALL"

3
cyassl/openssl/ec25519.h Normal file
View File

@ -0,0 +1,3 @@
/* ec25519.h */
#include <wolfssl/openssl/ec25519.h>

3
cyassl/openssl/ed25519.h Normal file
View File

@ -0,0 +1,3 @@
/* ed25519.h */
#include <wolfssl/openssl/ed25519.h>

View File

@ -13,6 +13,8 @@ nobase_include_HEADERS+= \
cyassl/openssl/ecdsa.h \ cyassl/openssl/ecdsa.h \
cyassl/openssl/ecdh.h \ cyassl/openssl/ecdh.h \
cyassl/openssl/ec.h \ cyassl/openssl/ec.h \
cyassl/openssl/ec25519.h \
cyassl/openssl/ed25519.h \
cyassl/openssl/engine.h \ cyassl/openssl/engine.h \
cyassl/openssl/err.h \ cyassl/openssl/err.h \
cyassl/openssl/evp.h \ cyassl/openssl/evp.h \

323
src/ssl.c
View File

@ -48,6 +48,8 @@
#include <wolfssl/openssl/rsa.h> #include <wolfssl/openssl/rsa.h>
#include <wolfssl/openssl/pem.h> #include <wolfssl/openssl/pem.h>
#include <wolfssl/openssl/ec.h> #include <wolfssl/openssl/ec.h>
#include <wolfssl/openssl/ec25519.h>
#include <wolfssl/openssl/ed25519.h>
#include <wolfssl/openssl/ecdsa.h> #include <wolfssl/openssl/ecdsa.h>
#include <wolfssl/openssl/ecdh.h> #include <wolfssl/openssl/ecdh.h>
/* openssl headers end, wolfssl internal headers next */ /* openssl headers end, wolfssl internal headers next */
@ -57,6 +59,8 @@
#include <wolfssl/wolfcrypt/md4.h> #include <wolfssl/wolfcrypt/md4.h>
#include <wolfssl/wolfcrypt/md5.h> #include <wolfssl/wolfcrypt/md5.h>
#include <wolfssl/wolfcrypt/arc4.h> #include <wolfssl/wolfcrypt/arc4.h>
#include <wolfssl/wolfcrypt/curve25519.h>
#include <wolfssl/wolfcrypt/ed25519.h>
#ifdef WOLFSSL_SHA512 #ifdef WOLFSSL_SHA512
#include <wolfssl/wolfcrypt/sha512.h> #include <wolfssl/wolfcrypt/sha512.h>
#endif #endif
@ -12632,8 +12636,7 @@ int wolfSSL_DSA_generate_key(WOLFSSL_DSA* dsa)
return SSL_FAILURE; return SSL_FAILURE;
} }
if (dsa->inSet == 0) if (dsa->inSet == 0) {
{
WOLFSSL_MSG("No DSA internal set, do it"); WOLFSSL_MSG("No DSA internal set, do it");
if (SetDsaInternal(dsa) != SSL_SUCCESS) { 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, int wolfSSL_PEM_write_mem_RSAPrivateKey(RSA* rsa, const EVP_CIPHER* cipher,
unsigned char* passwd, int passwdSz, unsigned char* passwd, int passwdSz,
byte **pem, int *plen) unsigned char **pem, int *plen)
{ {
byte *der, *tmp, *cipherInfo = NULL; byte *der, *tmp, *cipherInfo = NULL;
int der_max_len = 0, derSz = 0; 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, int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* ecc,
const EVP_CIPHER* cipher, const EVP_CIPHER* cipher,
unsigned char* passwd, int passwdSz, unsigned char* passwd, int passwdSz,
byte **pem, int *plen) unsigned char **pem, int *plen)
{ {
byte *der, *tmp, *cipherInfo = NULL; byte *der, *tmp, *cipherInfo = NULL;
int der_max_len = 0, derSz = 0; 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, int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa,
const EVP_CIPHER* cipher, const EVP_CIPHER* cipher,
unsigned char* passwd, int passwdSz, unsigned char* passwd, int passwdSz,
byte **pem, int *plen) unsigned char **pem, int *plen)
{ {
byte *der, *tmp, *cipherInfo = NULL; byte *der, *tmp, *cipherInfo = NULL;
int der_max_len = 0, derSz = 0; 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; return sess->sessionID;
} }
#endif /* OPENSSL_EXTRA and HAVE_STUNNEL */ #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 */

View File

@ -46,94 +46,96 @@ const curve25519_set_type curve25519_sets[] = {
}; };
int wc_curve25519_make_key(RNG* rng, int keysize, curve25519_key* key) int wc_curve25519_make_key(RNG* rng, int keysize, curve25519_key* key)
{ {
unsigned char basepoint[CURVE25519_KEYSIZE] = {9}; unsigned char basepoint[CURVE25519_KEYSIZE] = {9};
unsigned char n[CURVE25519_KEYSIZE]; int ret;
unsigned char p[CURVE25519_KEYSIZE];
int i;
int ret;
if (key == NULL || rng == NULL) if (key == NULL || rng == NULL)
return ECC_BAD_ARG_E; return BAD_FUNC_ARG;
/* currently only a key size of 32 bytes is used */ /* currently only a key size of 32 bytes is used */
if (keysize != CURVE25519_KEYSIZE) if (keysize != CURVE25519_KEYSIZE)
return ECC_BAD_ARG_E; return ECC_BAD_ARG_E;
/* get random number from RNG */ /* random number for private key */
ret = wc_RNG_GenerateBlock(rng, n, keysize); ret = wc_RNG_GenerateBlock(rng, key->k.point, keysize);
if (ret != 0) if (ret != 0)
return ret; return ret;
for (i = 0; i < keysize; ++i) key->k.point[i] = n[i]; /* Clamp the private key */
key->k.point[ 0] &= 248; key->k.point[0] &= 248;
key->k.point[31] &= 127; key->k.point[CURVE25519_KEYSIZE-1] &= 63; /* same &=127 because |=64 after */
key->k.point[31] |= 64; key->k.point[CURVE25519_KEYSIZE-1] |= 64;
/* compute public key */ /* compute public key */
ret = curve25519(p, key->k.point, basepoint); 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 */ return ret;
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;
} }
int wc_curve25519_shared_secret(curve25519_key* private_key, int wc_curve25519_shared_secret(curve25519_key* private_key,
curve25519_key* public_key, curve25519_key* public_key,
byte* out, word32* outlen) byte* out, word32* outlen)
{ {
unsigned char k[CURVE25519_KEYSIZE]; return wc_curve25519_shared_secret_ex(private_key, public_key,
unsigned char p[CURVE25519_KEYSIZE]; 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]; unsigned char o[CURVE25519_KEYSIZE];
int ret = 0; int ret = 0;
int i;
/* sanity check */ /* sanity check */
if (private_key == NULL || public_key == NULL || out == NULL || if (private_key == NULL || public_key == NULL ||
outlen == NULL) out == NULL || outlen == NULL || *outlen < CURVE25519_KEYSIZE)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
/* avoid implementation fingerprinting */ /* avoid implementation fingerprinting */
if (public_key->p.point[0] > 0x7F) if (public_key->p.point[CURVE25519_KEYSIZE-1] > 0x7F)
return ECC_BAD_ARG_E; return ECC_BAD_ARG_E;
XMEMSET(p, 0, sizeof(p)); ret = curve25519(o, private_key->k.point, public_key->p.point);
XMEMSET(k, 0, sizeof(k)); if (ret != 0) {
XMEMSET(out, 0, CURVE25519_KEYSIZE); ForceZero(o, CURVE25519_KEYSIZE);
return ret;
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 , 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; *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)); ForceZero(o, sizeof(o));
return ret; return ret;
} }
/* export curve25519 public key (Big endian)
/* curve25519 uses a serialized string for key representation */ * return 0 on success */
int wc_curve25519_export_public(curve25519_key* key, byte* out, word32* outLen) 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; word32 keySz;
@ -143,30 +145,59 @@ int wc_curve25519_export_public(curve25519_key* key, byte* out, word32* outLen)
/* check size of outgoing key */ /* check size of outgoing key */
keySz = wc_curve25519_size(key); keySz = wc_curve25519_size(key);
/* copy in public key */ /* check and set outgoing key size */
XMEMCPY(out, key->p.point, keySz); if (*outLen < keySz) {
*outLen = keySz;
return ECC_BAD_ARG_E;
}
*outLen = keySz; *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; return 0;
} }
/* import curve25519 public key /* import curve25519 public key (Big endian)
return 0 on success */ * return 0 on success */
int wc_curve25519_import_public(const byte* in, word32 inLen, int wc_curve25519_import_public(const byte* in, word32 inLen,
curve25519_key* key) 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; word32 keySz;
/* sanity check */ /* sanity check */
if (key == NULL || in == NULL) if (key == NULL || in == NULL)
return ECC_BAD_ARG_E; return BAD_FUNC_ARG;
/* check size of incoming keys */ /* check size of incoming keys */
keySz = wc_curve25519_size(key); keySz = wc_curve25519_size(key);
if (inLen != keySz) if (inLen != keySz)
return ECC_BAD_ARG_E; 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]; 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 /* export curve25519 private key only raw (Big endian)
return 0 on success */ * outLen is in/out size
* return 0 on success */
int wc_curve25519_export_private_raw(curve25519_key* key, byte* out, int wc_curve25519_export_private_raw(curve25519_key* key, byte* out,
word32* outLen) 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; word32 keySz;
/* sanity check */ /* sanity check */
if (key == NULL || out == NULL || outLen == NULL) 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); keySz = wc_curve25519_size(key);
if (*outLen < keySz) {
*outLen = keySz;
return ECC_BAD_ARG_E;
}
*outLen = keySz; *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; return 0;
} }
/* curve25519 key pair export (Big or Little endian)
/* curve25519 private key import. * return 0 on success */
Public key to match private key needs to be imported too */ int wc_curve25519_export_key_raw(curve25519_key* key,
int wc_curve25519_import_private_raw(const byte* priv, word32 privSz, byte* priv, word32 *privSz,
const byte* pub, word32 pubSz, curve25519_key* key) byte* pub, word32 *pubSz)
{ {
int ret = 0; return wc_curve25519_export_key_raw_ex(key, priv, privSz,
word32 keySz; pub, pubSz, EC25519_BIG_ENDIAN);
}
/* sanity check */ /* curve25519 key pair export (Big or Little endian)
if (key == NULL || priv == NULL || pub == NULL) * return 0 on success */
return ECC_BAD_ARG_E; 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 */ /* export private part */
keySz = wc_curve25519_size(key); ret = wc_curve25519_export_private_raw_ex(key, priv, privSz, endian);
if (privSz != keySz || pubSz != keySz) if (ret != 0)
return ECC_BAD_ARG_E; return ret;
XMEMCPY(key->k.point, priv, privSz); /* export public part */
XMEMCPY(key->p.point, pub, pubSz); return wc_curve25519_export_public_ex(key, pub, pubSz, endian);
return ret;
} }
/* 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) int wc_curve25519_init(curve25519_key* key)
{ {
word32 keySz;
if (key == NULL) if (key == NULL)
return ECC_BAD_ARG_E; return BAD_FUNC_ARG;
/* currently the format for curve25519 */ /* currently the format for curve25519 */
key->dp = &curve25519_sets[0]; key->dp = &curve25519_sets[0];
keySz = key->dp->size;
XMEMSET(key->k.point, 0, keySz); XMEMSET(key->k.point, 0, key->dp->size);
XMEMSET(key->p.point, 0, keySz); XMEMSET(key->p.point, 0, key->dp->size);
return 0; return 0;
} }
@ -251,7 +378,8 @@ void wc_curve25519_free(curve25519_key* key)
/* get key size */ /* get key size */
int wc_curve25519_size(curve25519_key* key) int wc_curve25519_size(curve25519_key* key)
{ {
if (key == NULL) return 0; if (key == NULL)
return 0;
return key->dp->size; return key->dp->size;
} }

View File

@ -38,14 +38,12 @@
#include <wolfcrypt/src/misc.c> #include <wolfcrypt/src/misc.c>
#endif #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) int wc_ed25519_make_key(RNG* rng, int keySz, ed25519_key* key)
{ {
byte az[64]; byte az[ED25519_PRV_KEY_SIZE];
int ret; int ret;
ge_p3 A; ge_p3 A;
@ -56,16 +54,25 @@ int wc_ed25519_make_key(RNG* rng, int keySz, ed25519_key* key)
if (keySz != ED25519_KEY_SIZE) if (keySz != ED25519_KEY_SIZE)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
ret = 0; ret = wc_RNG_GenerateBlock(rng, key->k, ED25519_KEY_SIZE);
ret |= wc_RNG_GenerateBlock(rng, key->k, 32); if (ret != 0)
ret |= wc_Sha512Hash(key->k, 32, az); return ret;
az[0] &= 248; ret = wc_Sha512Hash(key->k, ED25519_KEY_SIZE, az);
az[31] &= 63; 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; az[31] |= 64;
ge_scalarmult_base(&A, az); ge_scalarmult_base(&A, az);
ge_p3_tobytes(key->p, &A); 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; return ret;
} }
@ -75,43 +82,54 @@ int wc_ed25519_make_key(RNG* rng, int keySz, ed25519_key* key)
in contains the message to sign in contains the message to sign
inlen is the length of the message to sign inlen is the length of the message to sign
out is the buffer to write the signature out is the buffer to write the signature
outlen [in/out] input size of out buf outLen [in/out] input size of out buf
output gets set as the final length of out output gets set as the final length of out
key is the ed25519 key to use when signing key is the ed25519 key to use when signing
return 0 on success return 0 on success
*/ */
int wc_ed25519_sign_msg(const byte* in, word32 inlen, byte* out, 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; ge_p3 R;
byte nonce[SHA512_DIGEST_SIZE]; byte nonce[SHA512_DIGEST_SIZE];
byte hram[SHA512_DIGEST_SIZE]; byte hram[SHA512_DIGEST_SIZE];
byte az[64]; byte az[ED25519_PRV_KEY_SIZE];
word32 sigSz;
Sha512 sha; Sha512 sha;
int ret = 0; int ret;
/* sanity check on arguments */ /* 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; return BAD_FUNC_ARG;
/* check and set up out length */ /* check and set up out length */
ret = 0; if (*outLen < ED25519_SIG_SIZE) {
sigSz = wc_ed25519_sig_size(key); *outLen = ED25519_SIG_SIZE;
if (*outlen < sigSz) return BUFFER_E;
return BAD_FUNC_ARG; }
*outlen = sigSz; *outLen = ED25519_SIG_SIZE;
/* step 1: create nonce to use where nonce is r in /* step 1: create nonce to use where nonce is r in
r = H(h_b, ... ,h_2b-1,M) */ 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[0] &= 248;
az[31] &= 63; az[31] &= 63; /* same than az[31] &= 127 because of az[31] |= 64 */
az[31] |= 64; az[31] |= 64;
ret |= wc_InitSha512(&sha);
ret |= wc_Sha512Update(&sha, az + 32, 32); ret = wc_InitSha512(&sha);
ret |= wc_Sha512Update(&sha, in, inlen); if (ret != 0)
ret |= wc_Sha512Final(&sha, nonce); 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); sc_reduce(nonce);
/* step 2: computing R = rB where rB is the scalar multiplication of /* 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 /* step 3: hash R + public key + message getting H(R,A,M) then
creating S = (r + H(R,A,M)a) mod l */ creating S = (r + H(R,A,M)a) mod l */
ret |= wc_InitSha512(&sha); ret = wc_InitSha512(&sha);
ret |= wc_Sha512Update(&sha, out, 32); if (ret != 0)
ret |= wc_Sha512Update(&sha, key->p, 32); return ret;
ret |= wc_Sha512Update(&sha, in, inlen); ret = wc_Sha512Update(&sha, out, ED25519_SIG_SIZE/2);
ret |= wc_Sha512Final(&sha, hram); 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_reduce(hram);
sc_muladd(out + 32, hram, az, nonce); sc_muladd(out + (ED25519_SIG_SIZE/2), hram, az, nonce);
return ret; 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, int wc_ed25519_verify_msg(byte* sig, word32 siglen, const byte* msg,
word32 msglen, int* stat, ed25519_key* key) word32 msglen, int* stat, ed25519_key* key)
{ {
byte rcheck[32]; byte rcheck[ED25519_KEY_SIZE];
byte h[SHA512_DIGEST_SIZE]; byte h[SHA512_DIGEST_SIZE];
ge_p3 A; ge_p3 A;
ge_p2 R; ge_p2 R;
word32 sigSz;
int ret; int ret;
Sha512 sha; 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) if (sig == NULL || msg == NULL || stat == NULL || key == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
ret = 0; /* set verification failed by default */
*stat = 0; *stat = 0;
sigSz = wc_ed25519_size(key);
/* check on basics needed to verify signature */ /* check on basics needed to verify signature */
if (siglen < sigSz) if (siglen < ED25519_SIG_SIZE || (sig[ED25519_SIG_SIZE-1] & 224))
return BAD_FUNC_ARG;
if (sig[63] & 224)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
/* uncompress A (public key), test if valid, and negate it */ /* 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; return BAD_FUNC_ARG;
/* find H(R,A,M) and store it as h */ /* find H(R,A,M) and store it as h */
ret |= wc_InitSha512(&sha); ret = wc_InitSha512(&sha);
ret |= wc_Sha512Update(&sha, sig, 32); if (ret != 0)
ret |= wc_Sha512Update(&sha, key->p, 32); return ret;
ret |= wc_Sha512Update(&sha, msg, msglen); ret = wc_Sha512Update(&sha, sig, ED25519_SIG_SIZE/2);
ret |= wc_Sha512Final(&sha, h); 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); sc_reduce(h);
/* /*
Uses a fast single-signature verification SB = R + H(R,A,M)A becomes Uses a fast single-signature verification SB = R + H(R,A,M)A becomes
SB - H(R,A,M)A saving decompression of R 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); ge_tobytes(rcheck, &R);
/* comparison of R created to R in sig */ /* 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; 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) int wc_ed25519_export_public(ed25519_key* key, byte* out, word32* outLen)
{ {
word32 keySz;
/* sanity check on arguments */ /* sanity check on arguments */
if (key == NULL || out == NULL || outLen == NULL) if (key == NULL || out == NULL || outLen == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
keySz = wc_ed25519_size(key); if (*outLen < ED25519_PUB_KEY_SIZE) {
if (*outLen < keySz) { *outLen = ED25519_PUB_KEY_SIZE;
*outLen = keySz;
return BUFFER_E; 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; 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) int wc_ed25519_import_public(const byte* in, word32 inLen, ed25519_key* key)
{ {
word32 keySz;
int ret; int ret;
/* sanity check on arguments */ /* sanity check on arguments */
if (in == NULL || key == NULL) if (in == NULL || key == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
keySz = wc_ed25519_size(key); if (inLen < ED25519_PUB_KEY_SIZE)
if (inLen < keySz)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
/* compressed prefix according to draft /* compressed prefix according to draft
http://www.ietf.org/id/draft-koch-eddsa-for-openpgp-02.txt */ 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 */ /* 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; return 0;
} }
/* importing uncompressed public key */ /* 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 */ /* 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; return ret;
} }
/* if not specified compressed or uncompressed check key size /* if not specified compressed or uncompressed check key size
if key size is equal to compressed key size copy in key */ if key size is equal to compressed key size copy in key */
if (inLen == keySz) { if (inLen == ED25519_PUB_KEY_SIZE) {
XMEMCPY(key->p, in, keySz); XMEMCPY(key->p, in, ED25519_PUB_KEY_SIZE);
return 0; 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, int wc_ed25519_import_private_key(const byte* priv, word32 privSz,
const byte* pub, word32 pubSz, ed25519_key* key) const byte* pub, word32 pubSz, ed25519_key* key)
{ {
word32 keySz;
int ret; int ret;
/* sanity check on arguments */ /* sanity check on arguments */
if (priv == NULL || pub == NULL || key == NULL) if (priv == NULL || pub == NULL || key == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
keySz = wc_ed25519_size(key);
/* key size check */ /* key size check */
if (privSz < keySz || pubSz < keySz) if (privSz < ED25519_KEY_SIZE || pubSz < ED25519_PUB_KEY_SIZE)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
XMEMCPY(key->k, priv, keySz); /* import public key */
ret = wc_ed25519_import_public(pub, pubSz, 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; return ret;
} }
/* /*
outLen should contain the size of out buffer when input. outLen is than set export private key only (secret part so 32 bytes)
to the final output length. outLen should contain the size of out buffer when input. outLen is than set
returns 0 on success to the final output length.
returns 0 on success
*/ */
int wc_ed25519_export_private_only(ed25519_key* key, byte* out, word32* outLen) int wc_ed25519_export_private_only(ed25519_key* key, byte* out, word32* outLen)
{ {
word32 keySz;
/* sanity checks on arguments */ /* sanity checks on arguments */
if (key == NULL || out == NULL || outLen == NULL) if (key == NULL || out == NULL || outLen == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
keySz = wc_ed25519_size(key); if (*outLen < ED25519_KEY_SIZE) {
if (*outLen < keySz) { *outLen = ED25519_KEY_SIZE;
*outLen = keySz;
return BUFFER_E; return BUFFER_E;
} }
*outLen = keySz;
XMEMCPY(out, key->k, keySz); *outLen = ED25519_KEY_SIZE;
XMEMCPY(out, key->k, ED25519_KEY_SIZE);
return 0; 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) int wc_ed25519_size(ed25519_key* key)
{ {
word32 keySz;
if (key == NULL) if (key == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
keySz = ED25519_KEY_SIZE; return ED25519_KEY_SIZE;
return keySz;
} }
/* 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 */ /* returns the size of signature in bytes */
int wc_ed25519_sig_size(ed25519_key* key) int wc_ed25519_sig_size(ed25519_key* key)
{ {
word32 sigSz;
if (key == NULL) if (key == NULL)
return BAD_FUNC_ARG; return BAD_FUNC_ARG;
sigSz = ED25519_SIG_SIZE; return ED25519_SIG_SIZE;
return sigSz;
} }
#endif /* HAVE_ED25519 */ #endif /* HAVE_ED25519 */

View File

@ -107,8 +107,9 @@ void fe_0(fe h)
int curve25519(byte* q, byte* n, byte* p) int curve25519(byte* q, byte* n, byte* p)
{ {
#if 0
unsigned char e[32]; unsigned char e[32];
unsigned int i; #endif
fe x1; fe x1;
fe x2; fe x2;
fe z2; fe z2;
@ -120,10 +121,16 @@ int curve25519(byte* q, byte* n, byte* p)
unsigned int swap; unsigned int swap;
unsigned int b; unsigned int b;
for (i = 0;i < 32;++i) e[i] = n[i]; /* Clamp already done during key generation and import */
e[0] &= 248; #if 0
e[31] &= 127; {
e[31] |= 64; 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_frombytes(x1,p);
fe_1(x2); fe_1(x2);
@ -133,7 +140,11 @@ int curve25519(byte* q, byte* n, byte* p)
swap = 0; swap = 0;
for (pos = 254;pos >= 0;--pos) { for (pos = 254;pos >= 0;--pos) {
#if 0
b = e[pos / 8] >> (pos & 7); b = e[pos / 8] >> (pos & 7);
#else
b = n[pos / 8] >> (pos & 7);
#endif
b &= 1; b &= 1;
swap ^= b; swap ^= b;
fe_cswap(x2,x3,swap); fe_cswap(x2,x3,swap);

View File

@ -5510,6 +5510,27 @@ int curve25519_test(void)
if (XMEMCMP(ss, sharedB, y)) if (XMEMCMP(ss, sharedB, y))
return -1017; 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 */ /* clean up keys when done */
wc_curve25519_free(&pubKey); wc_curve25519_free(&pubKey);
wc_curve25519_free(&userB); wc_curve25519_free(&userB);

23
wolfssl/openssl/ec25519.h Normal file
View File

@ -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 */

26
wolfssl/openssl/ed25519.h Normal file
View File

@ -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 */

View File

@ -13,6 +13,8 @@ nobase_include_HEADERS+= \
wolfssl/openssl/ecdsa.h \ wolfssl/openssl/ecdsa.h \
wolfssl/openssl/ecdh.h \ wolfssl/openssl/ecdh.h \
wolfssl/openssl/ec.h \ wolfssl/openssl/ec.h \
wolfssl/openssl/ec25519.h \
wolfssl/openssl/ed25519.h \
wolfssl/openssl/engine.h \ wolfssl/openssl/engine.h \
wolfssl/openssl/err.h \ wolfssl/openssl/err.h \
wolfssl/openssl/evp.h \ wolfssl/openssl/evp.h \

View File

@ -28,7 +28,7 @@ int wolfSSL_PEM_write_RSAPrivateKey(FILE *fp, WOLFSSL_RSA *rsa,
WOLFSSL_API WOLFSSL_API
int wolfSSL_PEM_write_mem_RSAPrivateKey(RSA* rsa, const EVP_CIPHER* cipher, int wolfSSL_PEM_write_mem_RSAPrivateKey(RSA* rsa, const EVP_CIPHER* cipher,
unsigned char* passwd, int len, unsigned char* passwd, int len,
byte **pem, int *plen); unsigned char **pem, int *plen);
WOLFSSL_API WOLFSSL_API
WOLFSSL_RSA *wolfSSL_PEM_read_RSAPublicKey(FILE *fp, WOLFSSL_RSA **x, WOLFSSL_RSA *wolfSSL_PEM_read_RSAPublicKey(FILE *fp, WOLFSSL_RSA **x,
pem_password_cb *cb, void *u); pem_password_cb *cb, void *u);
@ -54,7 +54,7 @@ WOLFSSL_API
int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa, int wolfSSL_PEM_write_mem_DSAPrivateKey(WOLFSSL_DSA* dsa,
const EVP_CIPHER* cipher, const EVP_CIPHER* cipher,
unsigned char* passwd, int len, unsigned char* passwd, int len,
byte **pem, int *plen); unsigned char **pem, int *plen);
WOLFSSL_API WOLFSSL_API
int wolfSSL_PEM_write_DSA_PUBKEY(FILE *fp, WOLFSSL_DSA *x); 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, int wolfSSL_PEM_write_mem_ECPrivateKey(WOLFSSL_EC_KEY* key,
const EVP_CIPHER* cipher, const EVP_CIPHER* cipher,
unsigned char* passwd, int len, unsigned char* passwd, int len,
byte **pem, int *plen); unsigned char **pem, int *plen);
WOLFSSL_API WOLFSSL_API
int wolfSSL_PEM_write_EC_PUBKEY(FILE *fp, WOLFSSL_EC_KEY *key); int wolfSSL_PEM_write_EC_PUBKEY(FILE *fp, WOLFSSL_EC_KEY *key);

View File

@ -42,7 +42,8 @@ typedef struct {
} curve25519_set_type; } curve25519_set_type;
/* ECC point */ /* ECC point, the internal structure is Little endian
* the mathematical functions used the endianess */
typedef struct { typedef struct {
byte point[CURVE25519_KEYSIZE]; byte point[CURVE25519_KEYSIZE];
}ECPoint; }ECPoint;
@ -58,6 +59,11 @@ typedef struct {
ECPoint k; /* private key */ ECPoint k; /* private key */
} curve25519_key; } curve25519_key;
enum {
EC25519_LITTLE_ENDIAN=0,
EC25519_BIG_ENDIAN=1
};
WOLFSSL_API WOLFSSL_API
int wc_curve25519_make_key(RNG* rng, int keysize, curve25519_key* key); 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, curve25519_key* public_key,
byte* out, word32* outlen); 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 WOLFSSL_API
int wc_curve25519_init(curve25519_key* key); int wc_curve25519_init(curve25519_key* key);
@ -74,21 +85,49 @@ void wc_curve25519_free(curve25519_key* key);
/* raw key helpers */ /* 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 WOLFSSL_API
int wc_curve25519_import_private_raw(const byte* priv, word32 privSz, int wc_curve25519_import_private_raw(const byte* priv, word32 privSz,
const byte* pub, word32 pubSz, curve25519_key* key); const byte* pub, word32 pubSz, curve25519_key* key);
WOLFSSL_API 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, int wc_curve25519_export_private_raw(curve25519_key* key, byte* out,
word32* outLen); word32* outLen);
WOLFSSL_API
int wc_curve25519_export_private_raw_ex(curve25519_key* key, byte* out,
word32* outLen, int endian);
WOLFSSL_API WOLFSSL_API
int wc_curve25519_import_public(const byte* in, word32 inLen, int wc_curve25519_import_public(const byte* in, word32 inLen,
curve25519_key* key); curve25519_key* key);
WOLFSSL_API
int wc_curve25519_import_public_ex(const byte* in, word32 inLen,
curve25519_key* key, int endian);
WOLFSSL_API WOLFSSL_API
int wc_curve25519_export_public(curve25519_key* key, byte* out, word32* outLen); 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 */ /* size helper */
WOLFSSL_API WOLFSSL_API
int wc_curve25519_size(curve25519_key* key); int wc_curve25519_size(curve25519_key* key);

View File

@ -46,14 +46,17 @@
"-121665/121666", value of d "-121665/121666", value of d
*/ */
#define ED25519_KEY_SIZE 32 #define ED25519_KEY_SIZE 32 /* private key only */
#define ED25519_SIG_SIZE 64 #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 */ /* An ED25519 Key */
typedef struct { typedef struct {
byte p[32]; /* compressed public key */ byte p[ED25519_PUB_KEY_SIZE]; /* compressed public key */
byte k[64]; /* private key : 32 secret -- 32 public */ byte k[ED25519_PRV_KEY_SIZE]; /* private key : 32 secret -- 32 public */
} ed25519_key; } ed25519_key;
@ -78,11 +81,21 @@ WOLFSSL_API
int wc_ed25519_export_public(ed25519_key*, byte* out, word32* outLen); int wc_ed25519_export_public(ed25519_key*, byte* out, word32* outLen);
WOLFSSL_API WOLFSSL_API
int wc_ed25519_export_private_only(ed25519_key* key, byte* out, word32* outLen); 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 */ /* size helper */
WOLFSSL_API WOLFSSL_API
int wc_ed25519_size(ed25519_key* key); int wc_ed25519_size(ed25519_key* key);
WOLFSSL_API 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); int wc_ed25519_sig_size(ed25519_key* key);
#ifdef __cplusplus #ifdef __cplusplus