diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index f5a9b2d42..73bd6c00d 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -35,6 +35,7 @@ Possible ECC enable options: * HAVE_ECC_SIGN: ECC sign default: on * HAVE_ECC_VERIFY: ECC verify default: on * HAVE_ECC_DHE: ECC build shared secret default: on + * HAVE_ECC_CDH: ECC cofactor DH shared secret default: off * HAVE_ECC_KEY_IMPORT: ECC Key import default: on * HAVE_ECC_KEY_EXPORT: ECC Key export default: on * ECC_SHAMIR: Enables Shamir calc method default: on @@ -2693,6 +2694,122 @@ int wc_ecc_shared_secret_ex(ecc_key* private_key, ecc_point* point, #endif /* !WOLFSSL_ATECC508A */ #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 /* return 1 if point is at infinity, 0 if not, < 0 on error */ int wc_ecc_point_is_at_infinity(ecc_point* p) diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 0f10251df..2935fcb90 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -8343,6 +8343,25 @@ static int ecc_test_curve_size(WC_RNG* rng, int keySize, int testVerifyCount, ERROR_OUT(-1005, done); #endif /* HAVE_ECC_DHE */ +#ifdef HAVE_ECC_CDH + x = sizeof(sharedA); + ret = wc_ecc_cdh(&userA, &userB, sharedA, &x); + if (ret != 0) { + goto done; + } + + y = sizeof(sharedB); + ret = wc_ecc_cdh(&userB, &userA, sharedB, &y); + if (ret != 0) + goto done; + + if (y != x) + ERROR_OUT(-1006, done); + + if (XMEMCMP(sharedA, sharedB, x)) + ERROR_OUT(-1007, done); +#endif /* HAVE_ECC_CDH */ + #ifdef HAVE_ECC_KEY_EXPORT x = sizeof(exportBuf); ret = wc_ecc_export_x963(&userA, exportBuf, &x); diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index ea8b4285f..286647fe5 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -302,6 +302,15 @@ 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 */ #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 WOLFSSL_API int wc_ecc_sign_hash(const byte* in, word32 inlen, byte* out, word32 *outlen,