From 0b235582a310bd16ac0b017673fc72b69d407f61 Mon Sep 17 00:00:00 2001 From: Paul Adelsbach Date: Mon, 20 Jul 2026 12:40:30 -0700 Subject: [PATCH] Curve25519 crypto cb full --- tests/api/test_curve25519.c | 63 ++++++++++++++++++++++++++++++ tests/api/test_curve25519.h | 2 + tests/swdev/swdev.c | 22 +++++++++++ wolfcrypt/src/cryptocb.c | 61 +++++++++++++++++++++++++++++ wolfcrypt/src/curve25519.c | 73 +++++++++++++++++++++++++++++------ wolfcrypt/src/fe_operations.c | 4 +- wolfssl/wolfcrypt/cryptocb.h | 21 ++++++++++ wolfssl/wolfcrypt/types.h | 4 +- 8 files changed, 235 insertions(+), 15 deletions(-) diff --git a/tests/api/test_curve25519.c b/tests/api/test_curve25519.c index d2a67d59d13..d1557370a25 100644 --- a/tests/api/test_curve25519.c +++ b/tests/api/test_curve25519.c @@ -576,6 +576,69 @@ int test_wc_curve25519_make_pub(void) return EXPECT_RESULT(); } /* END test_wc_curve25519_make_pub */ +/* + * Positive cross-check of the make_pub, generic and keygen paths (and the + * crypto-callback dispatch for each under WOLF_CRYPTO_CB_ONLY_CURVE25519): + * a public key from make_pub or from generic against base point 9 must match + * the make_key public point, and a shared secret must round trip. + */ +int test_wc_curve25519_make_pub_generic(void) +{ + EXPECT_DECLS; +#if defined(HAVE_CURVE25519) && defined(HAVE_CURVE25519_SHARED_SECRET) + curve25519_key keyA; + curve25519_key keyB; + WC_RNG rng; + byte pubM[CURVE25519_KEYSIZE]; + byte pubG[CURVE25519_KEYSIZE]; + const byte base9[CURVE25519_KEYSIZE] = { 9 }; + byte genAB[CURVE25519_KEYSIZE]; + byte ssAB[CURVE25519_KEYSIZE]; + byte ssBA[CURVE25519_KEYSIZE]; + word32 ssABLen = (word32)sizeof(ssAB); + word32 ssBALen = (word32)sizeof(ssBA); + + XMEMSET(&rng, 0, sizeof(WC_RNG)); + + ExpectIntEQ(wc_curve25519_init(&keyA), 0); + ExpectIntEQ(wc_curve25519_init(&keyB), 0); + ExpectIntEQ(wc_InitRng(&rng), 0); + + ExpectIntEQ(wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, &keyA), 0); + ExpectIntEQ(wc_curve25519_make_key(&rng, CURVE25519_KEYSIZE, &keyB), 0); + + /* make_pub from the private scalar must match the keygen public point */ + ExpectIntEQ(wc_curve25519_make_pub((int)sizeof(pubM), pubM, + (int)sizeof(keyA.k), keyA.k), 0); + ExpectBufEQ(pubM, keyA.p.point, CURVE25519_KEYSIZE); + + /* generic against base point 9 is the same operation as make_pub */ + ExpectIntEQ(wc_curve25519_generic((int)sizeof(pubG), pubG, + (int)sizeof(keyA.k), keyA.k, (int)sizeof(base9), base9), 0); + ExpectBufEQ(pubG, pubM, CURVE25519_KEYSIZE); + + /* generic against B's public point must equal the A-B shared secret, + * proving generic actually uses the supplied base point */ + ExpectIntEQ(wc_curve25519_generic((int)sizeof(genAB), genAB, + (int)sizeof(keyA.k), keyA.k, + (int)sizeof(keyB.p.point), keyB.p.point), 0); + ExpectIntEQ(wc_curve25519_shared_secret_ex(&keyA, &keyB, ssAB, &ssABLen, + EC25519_LITTLE_ENDIAN), 0); + ExpectBufEQ(genAB, ssAB, CURVE25519_KEYSIZE); + + /* shared secret must agree both ways, proving the generated keys are + * mutually consistent (a degenerate result is rejected by shared_secret) */ + ExpectIntEQ(wc_curve25519_shared_secret_ex(&keyB, &keyA, ssBA, &ssBALen, + EC25519_LITTLE_ENDIAN), 0); + ExpectBufEQ(ssBA, ssAB, CURVE25519_KEYSIZE); + + DoExpectIntEQ(wc_FreeRng(&rng), 0); + wc_curve25519_free(&keyA); + wc_curve25519_free(&keyB); +#endif + return EXPECT_RESULT(); +} /* END test_wc_curve25519_make_pub_generic */ + /* * Testing test_wc_curve25519_export_public_ex */ diff --git a/tests/api/test_curve25519.h b/tests/api/test_curve25519.h index 8fb4ecdf783..f9b41f6bbca 100644 --- a/tests/api/test_curve25519.h +++ b/tests/api/test_curve25519.h @@ -33,6 +33,7 @@ int test_wc_curve25519_shared_secret_ex(void); int test_wc_curve25519_shared_secret_zero_check(void); int test_wc_curve25519_shared_secret_ex_kat(void); int test_wc_curve25519_make_pub(void); +int test_wc_curve25519_make_pub_generic(void); int test_wc_curve25519_export_public_ex(void); int test_wc_curve25519_export_private_raw_ex(void); int test_wc_curve25519_import_private_raw_ex(void); @@ -57,6 +58,7 @@ int test_wc_curve25519_nonblock(void); TEST_DECL_GROUP("curve25519", test_wc_curve25519_shared_secret_zero_check),\ TEST_DECL_GROUP("curve25519", test_wc_curve25519_shared_secret_ex_kat), \ TEST_DECL_GROUP("curve25519", test_wc_curve25519_make_pub), \ + TEST_DECL_GROUP("curve25519", test_wc_curve25519_make_pub_generic), \ TEST_DECL_GROUP("curve25519", test_wc_curve25519_export_public_ex), \ TEST_DECL_GROUP("curve25519", test_wc_curve25519_export_private_raw_ex), \ TEST_DECL_GROUP("curve25519", test_wc_curve25519_import_private_raw_ex), \ diff --git a/tests/swdev/swdev.c b/tests/swdev/swdev.c index ae612d5456f..f5163626ed2 100644 --- a/tests/swdev/swdev.c +++ b/tests/swdev/swdev.c @@ -336,6 +336,24 @@ static int swdev_curve25519(wc_CryptoInfo* info) info->pk.curve25519.outlen, info->pk.curve25519.endian); } #endif /* HAVE_CURVE25519_SHARED_SECRET */ + +static int swdev_curve25519_make_pub(wc_CryptoInfo* info) +{ + return wc_curve25519_make_pub((int)info->pk.curve25519makepub.pubSz, + info->pk.curve25519makepub.pub, + (int)info->pk.curve25519makepub.privSz, + info->pk.curve25519makepub.priv); +} + +static int swdev_curve25519_generic(wc_CryptoInfo* info) +{ + return wc_curve25519_generic((int)info->pk.curve25519generic.pubSz, + info->pk.curve25519generic.pub, + (int)info->pk.curve25519generic.privSz, + info->pk.curve25519generic.priv, + (int)info->pk.curve25519generic.basepointSz, + info->pk.curve25519generic.basepoint); +} #endif /* HAVE_CURVE25519 */ #ifndef NO_SHA256 @@ -992,6 +1010,10 @@ WC_SWDEV_EXPORT int wc_SwDev_Callback(int devId, wc_CryptoInfo* info, case WC_PK_TYPE_CURVE25519: return swdev_curve25519(info); #endif + case WC_PK_TYPE_CURVE25519_MAKE_PUB: + return swdev_curve25519_make_pub(info); + case WC_PK_TYPE_CURVE25519_GENERIC: + return swdev_curve25519_generic(info); #endif /* HAVE_CURVE25519 */ default: return CRYPTOCB_UNAVAILABLE; diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index cb155e0c1e9..849f5e19762 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -1078,6 +1078,67 @@ int wc_CryptoCb_Curve25519(curve25519_key* private_key, return wc_CryptoCb_TranslateErrorCode(ret); } + +int wc_CryptoCb_Curve25519MakePub(int public_size, byte* pub, + int private_size, const byte* priv) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (pub == NULL || priv == NULL) + return ret; + + /* try the find callback first, else grab the first registered device */ + dev = wc_CryptoCb_FindDevice(INVALID_DEVID, WC_ALGO_TYPE_PK); + if (dev == NULL || dev->cb == NULL) + dev = wc_CryptoCb_FindDeviceByIndex(0); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_CURVE25519_MAKE_PUB; + cryptoInfo.pk.curve25519makepub.pub = pub; + cryptoInfo.pk.curve25519makepub.pubSz = (word32)public_size; + cryptoInfo.pk.curve25519makepub.priv = priv; + cryptoInfo.pk.curve25519makepub.privSz = (word32)private_size; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} + +int wc_CryptoCb_Curve25519Generic(int public_size, byte* pub, + int private_size, const byte* priv, int basepoint_size, + const byte* basepoint) +{ + int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); + CryptoCb* dev; + + if (pub == NULL || priv == NULL || basepoint == NULL) + return ret; + + /* try the find callback first, else grab the first registered device */ + dev = wc_CryptoCb_FindDevice(INVALID_DEVID, WC_ALGO_TYPE_PK); + if (dev == NULL || dev->cb == NULL) + dev = wc_CryptoCb_FindDeviceByIndex(0); + if (dev && dev->cb) { + wc_CryptoInfo cryptoInfo; + XMEMSET(&cryptoInfo, 0, sizeof(cryptoInfo)); + cryptoInfo.algo_type = WC_ALGO_TYPE_PK; + cryptoInfo.pk.type = WC_PK_TYPE_CURVE25519_GENERIC; + cryptoInfo.pk.curve25519generic.pub = pub; + cryptoInfo.pk.curve25519generic.pubSz = (word32)public_size; + cryptoInfo.pk.curve25519generic.priv = priv; + cryptoInfo.pk.curve25519generic.privSz = (word32)private_size; + cryptoInfo.pk.curve25519generic.basepoint = basepoint; + cryptoInfo.pk.curve25519generic.basepointSz = (word32)basepoint_size; + + ret = dev->cb(dev->devId, &cryptoInfo, dev->ctx); + } + + return wc_CryptoCb_TranslateErrorCode(ret); +} #endif /* HAVE_CURVE25519 */ #ifdef HAVE_ED25519 diff --git a/wolfcrypt/src/curve25519.c b/wolfcrypt/src/curve25519.c index 0260f07baba..bdc808f9612 100644 --- a/wolfcrypt/src/curve25519.c +++ b/wolfcrypt/src/curve25519.c @@ -86,10 +86,13 @@ const curve25519_set_type curve25519_sets[] = { } }; -#if (!defined(WOLFSSL_CURVE25519_USE_ED25519) && \ +/* base point is only referenced by the software scalar-mult paths, which are + * compiled out under WOLF_CRYPTO_CB_ONLY_CURVE25519 */ +#if !defined(WOLF_CRYPTO_CB_ONLY_CURVE25519) && \ + ((!defined(WOLFSSL_CURVE25519_USE_ED25519) && \ !(defined(CURVED25519_X64) || (defined(WOLFSSL_ARMASM) && \ defined(__aarch64__)))) || defined(WOLFSSL_CURVE25519_BLINDING) || \ - defined(WC_X25519_NONBLOCK) + defined(WC_X25519_NONBLOCK)) static const word32 kCurve25519BasePoint[CURVE25519_KEYSIZE/sizeof(word32)] = { #ifdef BIG_ENDIAN_ORDER 0x09000000 @@ -165,6 +168,16 @@ int wc_curve25519_make_pub(int public_size, byte* pub, int private_size, if (ret != 0) return ret; +#ifdef WOLF_CRYPTO_CB + ret = wc_CryptoCb_Curve25519MakePub(public_size, pub, private_size, priv); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when unavailable */ +#endif + +#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519 + return NO_VALID_DEVID; +#else #ifdef FREESCALE_LTC_ECC /* input basepoint on Weierstrass curve */ ret = nxp_ltc_curve25519(&wc_pub, priv, basepoint, kLTC_Weierstrass); @@ -229,6 +242,7 @@ int wc_curve25519_make_pub(int public_size, byte* pub, int private_size, #endif return ret; +#endif /* WOLF_CRYPTO_CB_ONLY_CURVE25519 */ } #ifdef WOLFSSL_CURVE25519_BLINDING @@ -236,6 +250,7 @@ int wc_curve25519_make_pub(int public_size, byte* pub, int private_size, #ifndef WOLFSSL_CURVE25519_BLINDING_RAND_CNT #define WOLFSSL_CURVE25519_BLINDING_RAND_CNT 10 #endif +#ifndef WOLF_CRYPTO_CB_ONLY_CURVE25519 static int curve25519_smul_blind(byte* rp, const byte* n, const byte* p, WC_RNG* rng) { @@ -293,6 +308,7 @@ static int curve25519_smul_blind(byte* rp, const byte* n, const byte* p, return ret; } +#endif /* !WOLF_CRYPTO_CB_ONLY_CURVE25519 */ #endif int wc_curve25519_make_pub_blind(int public_size, byte* pub, int private_size, @@ -322,6 +338,16 @@ int wc_curve25519_make_pub_blind(int public_size, byte* pub, int private_size, if (ret != 0) return ret; +#ifdef WOLF_CRYPTO_CB + ret = wc_CryptoCb_Curve25519MakePub(public_size, pub, private_size, priv); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when unavailable */ +#endif + +#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519 + return NO_VALID_DEVID; +#else #ifdef FREESCALE_LTC_ECC /* input basepoint on Weierstrass curve */ ret = nxp_ltc_curve25519(&wc_pub, priv, basepoint, kLTC_Weierstrass); @@ -341,6 +367,7 @@ int wc_curve25519_make_pub_blind(int public_size, byte* pub, int private_size, } return ret; +#endif /* WOLF_CRYPTO_CB_ONLY_CURVE25519 */ } #endif @@ -359,7 +386,6 @@ int wc_curve25519_generic(int public_size, byte* pub, * nxp_ltc_curve25519_GetBasePoint() */ return WC_HW_E; #else -#ifndef WOLFSSL_CURVE25519_BLINDING int ret; if ((public_size != CURVE25519_KEYSIZE) || @@ -375,6 +401,17 @@ int wc_curve25519_generic(int public_size, byte* pub, if (ret != 0) return ret; +#ifdef WOLF_CRYPTO_CB + ret = wc_CryptoCb_Curve25519Generic(public_size, pub, private_size, priv, + basepoint_size, basepoint); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when unavailable */ +#endif + +#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519 + return NO_VALID_DEVID; +#elif !defined(WOLFSSL_CURVE25519_BLINDING) fe_init(); SAVE_VECTOR_REGISTERS(return _svr_ret;); @@ -385,15 +422,16 @@ int wc_curve25519_generic(int public_size, byte* pub, return ret; #else - WC_RNG rng; - int ret; + { + WC_RNG rng; - ret = wc_InitRng(&rng); - if (ret == 0) { - ret = wc_curve25519_generic_blind(public_size, pub, private_size, priv, - basepoint_size, basepoint, &rng); + ret = wc_InitRng(&rng); + if (ret == 0) { + ret = wc_curve25519_generic_blind(public_size, pub, private_size, + priv, basepoint_size, basepoint, &rng); - wc_FreeRng(&rng); + wc_FreeRng(&rng); + } } return ret; @@ -436,11 +474,23 @@ int wc_curve25519_generic_blind(int public_size, byte* pub, if (ret != 0) return ret; +#ifdef WOLF_CRYPTO_CB + ret = wc_CryptoCb_Curve25519Generic(public_size, pub, private_size, priv, + basepoint_size, basepoint); + if (ret != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + return ret; + /* fall-through when unavailable */ +#endif + +#ifdef WOLF_CRYPTO_CB_ONLY_CURVE25519 + return NO_VALID_DEVID; +#else fe_init(); ret = curve25519_smul_blind(pub, priv, basepoint, rng); return ret; +#endif /* WOLF_CRYPTO_CB_ONLY_CURVE25519 */ #endif /* FREESCALE_LTC_ECC */ } #endif @@ -1208,7 +1258,8 @@ int wc_curve25519_init_ex(curve25519_key* key, void* heap, int devId) #endif (void)heap; /* if needed for XMALLOC/XFREE in future */ - #ifndef FREESCALE_LTC_ECC + /* field math is implemented in the callback in crypto cb only */ + #if !defined(FREESCALE_LTC_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_CURVE25519) fe_init(); #endif diff --git a/wolfcrypt/src/fe_operations.c b/wolfcrypt/src/fe_operations.c index d80bc01e4a3..b3a80673e32 100644 --- a/wolfcrypt/src/fe_operations.c +++ b/wolfcrypt/src/fe_operations.c @@ -23,9 +23,7 @@ /* Based On Daniel J Bernstein's curve25519 Public Domain ref10 work. */ -/* under WOLF_CRYPTO_CB_ONLY_ED25519 the callback device does all Ed25519 - * field math, so Ed25519 alone no longer pulls this file in */ -#if defined(HAVE_CURVE25519) || \ +#if (defined(HAVE_CURVE25519) && !defined(WOLF_CRYPTO_CB_ONLY_CURVE25519)) || \ (defined(HAVE_ED25519) && !defined(WOLF_CRYPTO_CB_ONLY_ED25519)) #if !defined(CURVE25519_SMALL) && !defined(ED25519_SMALL) diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index 8d2e587e542..3b87a63f90a 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -282,6 +282,20 @@ typedef struct wc_CryptoInfo { word32* outlen; int endian; } curve25519; + struct { + byte* pub; + word32 pubSz; + const byte* priv; + word32 privSz; + } curve25519makepub; + struct { + byte* pub; + word32 pubSz; + const byte* priv; + word32 privSz; + const byte* basepoint; + word32 basepointSz; + } curve25519generic; #endif #ifdef HAVE_ED25519 struct { @@ -819,6 +833,13 @@ WOLFSSL_LOCAL int wc_CryptoCb_Curve25519Gen(WC_RNG* rng, int keySize, WOLFSSL_LOCAL int wc_CryptoCb_Curve25519(curve25519_key* private_key, curve25519_key* public_key, byte* out, word32* outlen, int endian); + +WOLFSSL_LOCAL int wc_CryptoCb_Curve25519MakePub(int public_size, byte* pub, + int private_size, const byte* priv); + +WOLFSSL_LOCAL int wc_CryptoCb_Curve25519Generic(int public_size, byte* pub, + int private_size, const byte* priv, int basepoint_size, + const byte* basepoint); #endif /* HAVE_CURVE25519 */ #ifdef HAVE_ED25519 diff --git a/wolfssl/wolfcrypt/types.h b/wolfssl/wolfcrypt/types.h index af98e43ba30..b0fba149493 100644 --- a/wolfssl/wolfcrypt/types.h +++ b/wolfssl/wolfcrypt/types.h @@ -1623,8 +1623,10 @@ enum wc_PkType { WC_PK_TYPE_EC_CHECK_PUB_KEY = 35, WC_PK_TYPE_ED25519_MAKE_PUB = 36, WC_PK_TYPE_ED25519_CHECK_KEY = 37, + WC_PK_TYPE_CURVE25519_MAKE_PUB = 38, + WC_PK_TYPE_CURVE25519_GENERIC = 39, #undef _WC_PK_TYPE_MAX - #define _WC_PK_TYPE_MAX WC_PK_TYPE_ED25519_CHECK_KEY + #define _WC_PK_TYPE_MAX WC_PK_TYPE_CURVE25519_GENERIC WC_PK_TYPE_MAX = _WC_PK_TYPE_MAX };