mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2025-08-04 05:04:41 +02:00
Refactor to combine ECC-CDH with existing “wc_ecc_shared_secret()” and use flag to perform cofactor computation on private key. Added new API “wc_ecc_set_flags()” and flag “WC_ECC_FLAG_COFACTOR” to indicate key should use cofactor. Added NIST CAVS test vector for ECC CDH Primitive with P-256.
This commit is contained in:
@@ -2579,6 +2579,29 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point,
|
|||||||
int err;
|
int err;
|
||||||
ecc_point* result = NULL;
|
ecc_point* result = NULL;
|
||||||
word32 x = 0;
|
word32 x = 0;
|
||||||
|
mp_int* k = &private_key->k;
|
||||||
|
#ifdef HAVE_ECC_CDH
|
||||||
|
mp_int k_lcl;
|
||||||
|
|
||||||
|
/* if cofactor flag has been set */
|
||||||
|
if (private_key->flags & WC_ECC_FLAG_COFACTOR) {
|
||||||
|
int cofactor = private_key->dp->cofactor;
|
||||||
|
/* only perform cofactor calc if not equal to 1 */
|
||||||
|
if (cofactor != 1) {
|
||||||
|
k = &k_lcl;
|
||||||
|
if (mp_init(k) != MP_OKAY)
|
||||||
|
return MEMORY_E;
|
||||||
|
/* multiple cofactor times private key "k" */
|
||||||
|
err = mp_set_int(k, cofactor);
|
||||||
|
if (err == MP_OKAY)
|
||||||
|
err = mp_mul(k, &private_key->k, k);
|
||||||
|
if (err != MP_OKAY) {
|
||||||
|
mp_clear(k);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* make new point */
|
/* make new point */
|
||||||
result = wc_ecc_new_point_h(private_key->heap);
|
result = wc_ecc_new_point_h(private_key->heap);
|
||||||
@@ -2586,7 +2609,7 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point,
|
|||||||
return MEMORY_E;
|
return MEMORY_E;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = wc_ecc_mulmod_ex(&private_key->k, point, result,
|
err = wc_ecc_mulmod_ex(k, point, result,
|
||||||
curve->Af, curve->prime, 1, private_key->heap);
|
curve->Af, curve->prime, 1, private_key->heap);
|
||||||
if (err == MP_OKAY) {
|
if (err == MP_OKAY) {
|
||||||
x = mp_unsigned_bin_size(curve->prime);
|
x = mp_unsigned_bin_size(curve->prime);
|
||||||
@@ -2603,6 +2626,10 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point,
|
|||||||
*outlen = x;
|
*outlen = x;
|
||||||
|
|
||||||
wc_ecc_del_point_h(result, private_key->heap);
|
wc_ecc_del_point_h(result, private_key->heap);
|
||||||
|
#ifdef HAVE_ECC_CDH
|
||||||
|
if (k == &k_lcl)
|
||||||
|
mp_clear(k);
|
||||||
|
#endif
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -2695,121 +2722,6 @@ int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point,
|
|||||||
#endif /* HAVE_ECC_DHE */
|
#endif /* HAVE_ECC_DHE */
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_ECC_CDH
|
|
||||||
/*
|
|
||||||
Elliptic Curve Cryptography Cofactor Diffie-Hellman (ECC CDH)
|
|
||||||
|
|
||||||
A shared secret Z is computed using the domain parameters:
|
|
||||||
(q, FR, a, b{, SEED}, G, n, h), the other party’s public key,
|
|
||||||
and one’s own private key.
|
|
||||||
|
|
||||||
Input:
|
|
||||||
1. (q, FR, a, b{, SEED}, G, n, h): Domain parameters,
|
|
||||||
2. dA : One’s own private key, and
|
|
||||||
3. QB : The other party’s public key.
|
|
||||||
*/
|
|
||||||
|
|
||||||
int wc_ecc_cdh_ex(ecc_key* private_key, ecc_point* public_point,
|
|
||||||
byte* out, word32 *outlen)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
int cofactor;
|
|
||||||
ecc_point* result = NULL;
|
|
||||||
mp_int k_lcl;
|
|
||||||
mp_int* k;
|
|
||||||
word32 x = 0;
|
|
||||||
DECLARE_CURVE_SPECS(2)
|
|
||||||
|
|
||||||
if (private_key == NULL || public_point == NULL || out == NULL ||
|
|
||||||
outlen == NULL) {
|
|
||||||
return BAD_FUNC_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* type valid? */
|
|
||||||
if (private_key->type != ECC_PRIVATEKEY) {
|
|
||||||
return ECC_BAD_ARG_E;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* load curve info */
|
|
||||||
cofactor = private_key->dp->cofactor;
|
|
||||||
err = wc_ecc_curve_load(private_key->dp, &curve,
|
|
||||||
(ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF));
|
|
||||||
if (err != MP_OKAY) {
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* multiple cofactor times private key "k" */
|
|
||||||
if (cofactor != 1) {
|
|
||||||
k = &k_lcl;
|
|
||||||
if (mp_init(k) != MP_OKAY) {
|
|
||||||
return MEMORY_E;
|
|
||||||
}
|
|
||||||
|
|
||||||
mp_set_int(k, cofactor);
|
|
||||||
mp_mul(k, &private_key->k, k);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
k = &private_key->k;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* make new point */
|
|
||||||
result = wc_ecc_new_point_h(private_key->heap);
|
|
||||||
if (result == NULL) {
|
|
||||||
return MEMORY_E;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* multiple public and private points */
|
|
||||||
err = wc_ecc_mulmod_ex(k, public_point, result,
|
|
||||||
curve->Af, curve->prime, 1, private_key->heap);
|
|
||||||
if (err == MP_OKAY) {
|
|
||||||
x = mp_unsigned_bin_size(curve->prime);
|
|
||||||
if (*outlen < x) {
|
|
||||||
err = BUFFER_E;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* return output */
|
|
||||||
if (err == MP_OKAY) {
|
|
||||||
XMEMSET(out, 0, x);
|
|
||||||
err = mp_to_unsigned_bin(result->x,
|
|
||||||
out + (x - mp_unsigned_bin_size(result->x)));
|
|
||||||
}
|
|
||||||
*outlen = x;
|
|
||||||
|
|
||||||
/* clean up */
|
|
||||||
wc_ecc_del_point_h(result, private_key->heap);
|
|
||||||
if (cofactor != 1) {
|
|
||||||
mp_clear(k);
|
|
||||||
}
|
|
||||||
wc_ecc_curve_free(curve);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int wc_ecc_cdh(ecc_key* private_key, ecc_key* public_key,
|
|
||||||
byte* out, word32* outlen)
|
|
||||||
{
|
|
||||||
if (private_key == NULL || public_key == NULL) {
|
|
||||||
return BAD_FUNC_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify domain params supplied */
|
|
||||||
if (wc_ecc_is_valid_idx(private_key->idx) == 0 ||
|
|
||||||
wc_ecc_is_valid_idx(public_key->idx) == 0) {
|
|
||||||
return ECC_BAD_ARG_E;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Verify curve id matches */
|
|
||||||
if (private_key->dp->id != public_key->dp->id) {
|
|
||||||
return ECC_BAD_ARG_E;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wc_ecc_cdh_ex(private_key, &public_key->pubkey, out, outlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* HAVE_ECC_CDH */
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef WOLFSSL_ATECC508A
|
#ifndef WOLFSSL_ATECC508A
|
||||||
/* return 1 if point is at infinity, 0 if not, < 0 on error */
|
/* return 1 if point is at infinity, 0 if not, < 0 on error */
|
||||||
int wc_ecc_point_is_at_infinity(ecc_point* p)
|
int wc_ecc_point_is_at_infinity(ecc_point* p)
|
||||||
@@ -3141,6 +3053,14 @@ int wc_ecc_init(ecc_key* key)
|
|||||||
return wc_ecc_init_ex(key, NULL, INVALID_DEVID);
|
return wc_ecc_init_ex(key, NULL, INVALID_DEVID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wc_ecc_set_flags(ecc_key* key, word32 flags)
|
||||||
|
{
|
||||||
|
if (key == NULL) {
|
||||||
|
return BAD_FUNC_ARG;
|
||||||
|
}
|
||||||
|
key->flags |= flags;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_ECC_SIGN
|
#ifdef HAVE_ECC_SIGN
|
||||||
|
|
||||||
|
@@ -8198,6 +8198,56 @@ static int ecc_test_vector(int keySize)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_ECC_CDH
|
||||||
|
static int ecc_test_cdh_vectors(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
ecc_key pub_key, priv_key;
|
||||||
|
byte sharedA[32] = {0}, sharedB[32] = {0};
|
||||||
|
word32 x;
|
||||||
|
mp_int z;
|
||||||
|
|
||||||
|
const char* QCAVSx = "700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287";
|
||||||
|
const char* QCAVSy = "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac";
|
||||||
|
const char* dIUT = "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534";
|
||||||
|
const char* QIUTx = "ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230";
|
||||||
|
const char* QIUTy = "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141";
|
||||||
|
const char* ZIUT = "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b";
|
||||||
|
|
||||||
|
/* setup private and public keys */
|
||||||
|
wc_ecc_init(&pub_key);
|
||||||
|
wc_ecc_init(&priv_key);
|
||||||
|
wc_ecc_set_flags(&pub_key, WC_ECC_FLAG_COFACTOR);
|
||||||
|
wc_ecc_set_flags(&priv_key, WC_ECC_FLAG_COFACTOR);
|
||||||
|
ret = wc_ecc_import_raw(&pub_key, QCAVSx, QCAVSy, NULL, "SECP256R1");
|
||||||
|
if (ret != 0)
|
||||||
|
goto done;
|
||||||
|
ret = wc_ecc_import_raw(&priv_key, QIUTx, QIUTy, dIUT, "SECP256R1");
|
||||||
|
if (ret != 0)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
/* compute ECC Cofactor shared secret */
|
||||||
|
x = sizeof(sharedA);
|
||||||
|
ret = wc_ecc_shared_secret(&priv_key, &pub_key, sharedA, &x);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read in expected Z */
|
||||||
|
mp_init(&z);
|
||||||
|
mp_read_radix(&z, ZIUT, 16);
|
||||||
|
mp_to_unsigned_bin(&z, sharedB);
|
||||||
|
mp_clear(&z);
|
||||||
|
|
||||||
|
/* compare results */
|
||||||
|
if (XMEMCMP(sharedA, sharedB, x)) {
|
||||||
|
ERROR_OUT(-1007, done);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif /* HAVE_ECC_CDH */
|
||||||
#endif /* HAVE_ECC_VECTOR_TEST */
|
#endif /* HAVE_ECC_VECTOR_TEST */
|
||||||
|
|
||||||
#ifdef WOLFSSL_KEY_GEN
|
#ifdef WOLFSSL_KEY_GEN
|
||||||
@@ -8344,14 +8394,18 @@ static int ecc_test_curve_size(WC_RNG* rng, int keySize, int testVerifyCount,
|
|||||||
#endif /* HAVE_ECC_DHE */
|
#endif /* HAVE_ECC_DHE */
|
||||||
|
|
||||||
#ifdef HAVE_ECC_CDH
|
#ifdef HAVE_ECC_CDH
|
||||||
|
/* add cofactor flag */
|
||||||
|
wc_ecc_set_flags(&userA, WC_ECC_FLAG_COFACTOR);
|
||||||
|
wc_ecc_set_flags(&userB, WC_ECC_FLAG_COFACTOR);
|
||||||
|
|
||||||
x = sizeof(sharedA);
|
x = sizeof(sharedA);
|
||||||
ret = wc_ecc_cdh(&userA, &userB, sharedA, &x);
|
ret = wc_ecc_shared_secret(&userA, &userB, sharedA, &x);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
y = sizeof(sharedB);
|
y = sizeof(sharedB);
|
||||||
ret = wc_ecc_cdh(&userB, &userA, sharedB, &y);
|
ret = wc_ecc_shared_secret(&userB, &userA, sharedB, &y);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
@@ -8360,6 +8414,10 @@ static int ecc_test_curve_size(WC_RNG* rng, int keySize, int testVerifyCount,
|
|||||||
|
|
||||||
if (XMEMCMP(sharedA, sharedB, x))
|
if (XMEMCMP(sharedA, sharedB, x))
|
||||||
ERROR_OUT(-1007, done);
|
ERROR_OUT(-1007, done);
|
||||||
|
|
||||||
|
/* remove cofactor flag */
|
||||||
|
wc_ecc_set_flags(&userA, 0);
|
||||||
|
wc_ecc_set_flags(&userB, 0);
|
||||||
#endif /* HAVE_ECC_CDH */
|
#endif /* HAVE_ECC_CDH */
|
||||||
|
|
||||||
#ifdef HAVE_ECC_KEY_EXPORT
|
#ifdef HAVE_ECC_KEY_EXPORT
|
||||||
@@ -8598,6 +8656,13 @@ int ecc_test(void)
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_ECC_CDH
|
||||||
|
ret = ecc_test_cdh_vectors();
|
||||||
|
if (ret != 0) {
|
||||||
|
printf("ecc_test_cdh_vectors failed! %d\n", ret);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
done:
|
done:
|
||||||
wc_FreeRng(&rng);
|
wc_FreeRng(&rng);
|
||||||
|
|
||||||
|
@@ -248,6 +248,13 @@ typedef struct {
|
|||||||
#endif
|
#endif
|
||||||
} ecc_point;
|
} ecc_point;
|
||||||
|
|
||||||
|
/* ECC Flags */
|
||||||
|
enum {
|
||||||
|
WC_ECC_FLAG_NONE = 0x00,
|
||||||
|
#ifdef HAVE_ECC_CDH
|
||||||
|
WC_ECC_FLAG_COFACTOR = 0x01,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
/* An ECC Key */
|
/* An ECC Key */
|
||||||
typedef struct ecc_key {
|
typedef struct ecc_key {
|
||||||
@@ -256,6 +263,7 @@ typedef struct ecc_key {
|
|||||||
this curve if -1, this key is using user supplied
|
this curve if -1, this key is using user supplied
|
||||||
curve in dp */
|
curve in dp */
|
||||||
int state;
|
int state;
|
||||||
|
word32 flags;
|
||||||
const ecc_set_type* dp; /* domain parameters, either points to NIST
|
const ecc_set_type* dp; /* domain parameters, either points to NIST
|
||||||
curves (idx >= 0) or user supplied */
|
curves (idx >= 0) or user supplied */
|
||||||
void* heap; /* heap hint */
|
void* heap; /* heap hint */
|
||||||
@@ -302,15 +310,6 @@ int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point,
|
|||||||
#define wc_ecc_shared_secret_ssh wc_ecc_shared_secret_ex /* For backwards compat */
|
#define wc_ecc_shared_secret_ssh wc_ecc_shared_secret_ex /* For backwards compat */
|
||||||
#endif /* HAVE_ECC_DHE */
|
#endif /* HAVE_ECC_DHE */
|
||||||
|
|
||||||
#ifdef HAVE_ECC_CDH
|
|
||||||
WOLFSSL_API
|
|
||||||
int wc_ecc_cdh(ecc_key* private_key, ecc_key* public_key,
|
|
||||||
byte* out, word32* outlen);
|
|
||||||
WOLFSSL_API
|
|
||||||
int wc_ecc_cdh_ex(ecc_key* private_key, ecc_point* public_point,
|
|
||||||
byte* out, word32 *outlen);
|
|
||||||
#endif /* HAVE_ECC_CDH */
|
|
||||||
|
|
||||||
#ifdef HAVE_ECC_SIGN
|
#ifdef HAVE_ECC_SIGN
|
||||||
WOLFSSL_API
|
WOLFSSL_API
|
||||||
int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
|
int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,
|
||||||
@@ -336,6 +335,8 @@ int wc_ecc_init_ex(ecc_key* key, void* heap, int devId);
|
|||||||
WOLFSSL_API
|
WOLFSSL_API
|
||||||
void wc_ecc_free(ecc_key* key);
|
void wc_ecc_free(ecc_key* key);
|
||||||
WOLFSSL_API
|
WOLFSSL_API
|
||||||
|
int wc_ecc_set_flags(ecc_key* key, word32 flags);
|
||||||
|
WOLFSSL_API
|
||||||
void wc_ecc_fp_free(void);
|
void wc_ecc_fp_free(void);
|
||||||
|
|
||||||
WOLFSSL_API
|
WOLFSSL_API
|
||||||
|
Reference in New Issue
Block a user