From ce2aaefb333c64c9f487b40ee7bd1e0427db8755 Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 29 Jan 2025 21:41:31 +1000 Subject: [PATCH] Curve25519: add blinding when using private key XOR in random value to scalar and perform special scalar multiplication. --- tests/api.c | 3 + wolfcrypt/src/curve25519.c | 141 ++++++++++++++++++++++++++++++ wolfcrypt/src/fe_operations.c | 85 ++++++++++++++---- wolfcrypt/test/test.c | 15 +++- wolfssl/wolfcrypt/curve25519.h | 20 +++++ wolfssl/wolfcrypt/fe_operations.h | 4 + 6 files changed, 248 insertions(+), 20 deletions(-) diff --git a/tests/api.c b/tests/api.c index b941ea01ee..cd131a8895 100644 --- a/tests/api.c +++ b/tests/api.c @@ -24923,6 +24923,9 @@ static int test_wc_curve25519_shared_secret_ex(void) int endian = EC25519_BIG_ENDIAN; ExpectIntEQ(wc_curve25519_init(&private_key), 0); +#ifdef WOLFSSL_CURVE25519_BLINDING + ExpectIntEQ(wc_curve25519_set_rng(&private_key, &rng), 0); +#endif ExpectIntEQ(wc_curve25519_init(&public_key), 0); ExpectIntEQ(wc_InitRng(&rng), 0); diff --git a/wolfcrypt/src/curve25519.c b/wolfcrypt/src/curve25519.c index 81d2de9698..5a3c2b668b 100644 --- a/wolfcrypt/src/curve25519.c +++ b/wolfcrypt/src/curve25519.c @@ -155,6 +155,75 @@ int wc_curve25519_make_pub(int public_size, byte* pub, int private_size, return ret; } +#ifdef WOLFSSL_CURVE25519_BLINDING +#ifndef FREESCALE_LTC_ECC +static int curve25519_smul_blind(byte* rp, const byte* n, const byte* p, + WC_RNG* rng) +{ + int ret; + byte a[CURVE25519_KEYSIZE]; + byte n_a[CURVE25519_KEYSIZE]; + int i; + + SAVE_VECTOR_REGISTERS(return _svr_ret;); + + /* Generate 253 random bits. */ + ret = wc_RNG_GenerateBlock(rng, a, sizeof(a)); + if (ret != 0) + return ret; + a[CURVE25519_KEYSIZE-1] &= 0x7f; + /* k' = k ^ 2k ^ a */ + n_a[0] = n[0] ^ (n[0] << 1) ^ a[0]; + for (i = 1; i < CURVE25519_KEYSIZE; i++) { + n_a[i] = n[i] ^ (n[i] << 1) ^ (n[i-1] >> 7) ^ a[i]; + } + /* Scalar multiple blinded scalar with blinding value. */ + ret = curve25519_blind(rp, n_a, a, p); + + RESTORE_VECTOR_REGISTERS(); + + return ret; +} +#endif + +int wc_curve25519_make_pub_blind(int public_size, byte* pub, int private_size, + const byte* priv, WC_RNG* rng) +{ + int ret; +#ifdef FREESCALE_LTC_ECC + const ECPoint* basepoint = nxp_ltc_curve25519_GetBasePoint(); + ECPoint wc_pub; +#endif + + if ( (public_size != CURVE25519_KEYSIZE) || + (private_size != CURVE25519_KEYSIZE)) { + return ECC_BAD_ARG_E; + } + if ((pub == NULL) || (priv == NULL)) { + return ECC_BAD_ARG_E; + } + + /* check clamping */ + ret = curve25519_priv_clamp_check(priv); + if (ret != 0) + return ret; + +#ifdef FREESCALE_LTC_ECC + /* input basepoint on Weierstrass curve */ + ret = nxp_ltc_curve25519(&wc_pub, priv, basepoint, kLTC_Weierstrass); + if (ret == 0) { + XMEMCPY(pub, wc_pub.point, CURVE25519_KEYSIZE); + } +#else + fe_init(); + + ret = curve25519_smul_blind(pub, priv, (byte*)kCurve25519BasePoint, rng); +#endif + + return ret; +} +#endif + /* compute the public key from an existing private key, with supplied basepoint, * using bare vectors. * @@ -197,6 +266,51 @@ int wc_curve25519_generic(int public_size, byte* pub, #endif /* FREESCALE_LTC_ECC */ } +#ifdef WOLFSSL_CURVE25519_BLINDING +/* compute the public key from an existing private key, with supplied basepoint, + * using bare vectors. + * + * return value is propagated from curve25519() (0 on success), + * and the byte vectors are little endian. + */ +int wc_curve25519_generic_blind(int public_size, byte* pub, + int private_size, const byte* priv, + int basepoint_size, const byte* basepoint, + WC_RNG* rng) +{ +#ifdef FREESCALE_LTC_ECC + /* unsupported with NXP LTC, only supports single basepoint with + * nxp_ltc_curve25519_GetBasePoint() */ + return WC_HW_E; +#else + int ret; + + if ((public_size != CURVE25519_KEYSIZE) || + (private_size != CURVE25519_KEYSIZE) || + (basepoint_size != CURVE25519_KEYSIZE)) { + return ECC_BAD_ARG_E; + } + if ((pub == NULL) || (priv == NULL) || (basepoint == NULL)) + return ECC_BAD_ARG_E; + + /* check clamping */ + ret = curve25519_priv_clamp_check(priv); + if (ret != 0) + return ret; + + fe_init(); + + SAVE_VECTOR_REGISTERS(return _svr_ret;); + + ret = curve25519_smul_blind(pub, priv, basepoint, rng); + + RESTORE_VECTOR_REGISTERS(); + + return ret; +#endif /* FREESCALE_LTC_ECC */ +} +#endif + /* generate a new private key, as a bare vector. * * return value is propagated from wc_RNG_GenerateBlock(() (0 on success), @@ -250,8 +364,14 @@ int wc_curve25519_make_key(WC_RNG* rng, int keysize, curve25519_key* key) ret = wc_curve25519_make_priv(rng, keysize, key->k); if (ret == 0) { key->privSet = 1; +#ifdef WOLFSSL_CURVE25519_BLINDING + ret = wc_curve25519_make_pub_blind((int)sizeof(key->p.point), + key->p.point, (int)sizeof(key->k), + key->k, rng); +#else ret = wc_curve25519_make_pub((int)sizeof(key->p.point), key->p.point, (int)sizeof(key->k), key->k); +#endif key->pubSet = (ret == 0); } #endif @@ -322,7 +442,12 @@ int wc_curve25519_shared_secret_ex(curve25519_key* private_key, { SAVE_VECTOR_REGISTERS(return _svr_ret;); +#ifndef WOLFSSL_CURVE25519_BLINDING ret = curve25519(o.point, private_key->k, public_key->p.point); +#else + ret = curve25519_smul_blind(o.point, private_key->k, public_key->p.point, + private_key->rng); +#endif RESTORE_VECTOR_REGISTERS(); } @@ -379,8 +504,14 @@ int wc_curve25519_export_public_ex(curve25519_key* key, byte* out, /* calculate public if missing */ if (!key->pubSet) { +#ifdef WOLFSSL_CURVE25519_BLINDING + ret = wc_curve25519_make_pub_blind((int)sizeof(key->p.point), + key->p.point, (int)sizeof(key->k), + key->k, key->rng); +#else ret = wc_curve25519_make_pub((int)sizeof(key->p.point), key->p.point, (int)sizeof(key->k), key->k); +#endif key->pubSet = (ret == 0); } /* export public point with endianness */ @@ -739,6 +870,16 @@ void wc_curve25519_free(curve25519_key* key) #endif } +#ifdef WOLFSSL_CURVE25519_BLINDING +int wc_curve25519_set_rng(curve25519_key* key, WC_RNG* rng) +{ + if (key == NULL) + return BAD_FUNC_ARG; + key->rng = rng; + return 0; +} +#endif + /* get key size */ int wc_curve25519_size(curve25519_key* key) { diff --git a/wolfcrypt/src/fe_operations.c b/wolfcrypt/src/fe_operations.c index 97647de022..ba82100310 100644 --- a/wolfcrypt/src/fe_operations.c +++ b/wolfcrypt/src/fe_operations.c @@ -130,9 +130,6 @@ void fe_init(void) !defined(FREESCALE_LTC_ECC) int curve25519(byte* q, const byte* n, const byte* p) { -#if 0 - unsigned char e[32]; -#endif fe x1 = {0}; fe x2 = {0}; fe z2 = {0}; @@ -143,17 +140,6 @@ int curve25519(byte* q, const byte* n, const byte* p) int pos = 0; unsigned int swap = 0; - /* 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); fe_0(z2); @@ -163,11 +149,7 @@ int curve25519(byte* q, const byte* n, const byte* p) swap = 0; for (pos = 254;pos >= 0;--pos) { unsigned int b; -#if 0 - b = e[pos / 8] >> (pos & 7); -#else b = n[pos / 8] >> (pos & 7); -#endif b &= 1; swap ^= b; fe_cswap(x2,x3,(int)swap); @@ -203,6 +185,73 @@ int curve25519(byte* q, const byte* n, const byte* p) return 0; } + +#ifdef WOLFSSL_CURVE25519_BLINDING +int curve25519_blind(byte* q, const byte* n, const byte* mask, const byte* p) +{ + fe x1 = {0}; + fe x2 = {0}; + fe z2 = {0}; + fe x3 = {0}; + fe z3 = {0}; + fe tmp0 = {0}; + fe tmp1 = {0}; + int pos = 0; + unsigned int b; + + fe_frombytes(x1,p); + fe_1(x2); + fe_0(z2); + fe_copy(x3,x1); + fe_1(z3); + + /* mask_bits[252] */ + b = mask[31] >> 7; + b &= 1; + fe_cswap(x2,x3,(int)b); + fe_cswap(z2,z3,(int)b); + for (pos = 255;pos >= 1;--pos) { + b = n[pos / 8] >> (pos & 7); + b &= 1; + fe_cswap(x2,x3,(int)b); + fe_cswap(z2,z3,(int)b); + + /* montgomery */ + fe_sub(tmp0,x3,z3); + fe_sub(tmp1,x2,z2); + fe_add(x2,x2,z2); + fe_add(z2,x3,z3); + fe_mul(z3,tmp0,x2); + fe_mul(z2,z2,tmp1); + fe_sq(tmp0,tmp1); + fe_sq(tmp1,x2); + fe_add(x3,z3,z2); + fe_sub(z2,z3,z2); + fe_mul(x2,tmp1,tmp0); + fe_sub(tmp1,tmp1,tmp0); + fe_sq(z2,z2); + fe_mul121666(z3,tmp1); + fe_sq(x3,x3); + fe_add(tmp0,tmp0,z3); + fe_mul(z3,x1,z2); + fe_mul(z2,tmp1,tmp0); + + b = mask[(pos-1) / 8] >> ((pos-1) & 7); + b &= 1; + fe_cswap(x2,x3,(int)b); + fe_cswap(z2,z3,(int)b); + } + b = n[0] & 1; + fe_cswap(x2,x3,(int)b); + fe_cswap(z2,z3,(int)b); + + fe_invert(z2,z2); + fe_mul(x2,x2,z2); + fe_tobytes(q,x2); + + return 0; +} +#endif #endif /* HAVE_CURVE25519 && !CURVE25519_SMALL && !FREESCALE_LTC_ECC */ diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index 6301a24d9b..f974d969ec 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -34706,7 +34706,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t ecc_test_buffers(void) #else #define X25519_TEST_CNT 1 #endif -static wc_test_ret_t curve25519_overflow_test(void) +static wc_test_ret_t curve25519_overflow_test(WC_RNG* rng) { /* secret key for party a */ byte sa[X25519_TEST_CNT][32] = { @@ -34824,6 +34824,10 @@ static wc_test_ret_t curve25519_overflow_test(void) curve25519_key userA; wc_curve25519_init_ex(&userA, HEAP_HINT, devId); +#ifdef WOLFSSL_CURVE25519_BLINDING + wc_curve25519_set_rng(&userA, rng); +#endif + (void)rng; for (i = 0; i < X25519_TEST_CNT; i++) { if (wc_curve25519_import_private_raw(sa[i], sizeof(sa[i]), pb[i], @@ -35302,6 +35306,10 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) wc_curve25519_init_ex(userB, HEAP_HINT, devId); wc_curve25519_init_ex(pubKey, HEAP_HINT, devId); #endif +#ifdef WOLFSSL_CURVE25519_BLINDING + wc_curve25519_set_rng(userA, &rng); + wc_curve25519_set_rng(userB, &rng); +#endif /* make curve25519 keys */ ret = wc_curve25519_make_key(&rng, 32, userA); @@ -35399,6 +35407,9 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) wc_curve25519_free(userB); wc_curve25519_init_ex(userB, HEAP_HINT, devId); +#ifdef WOLFSSL_CURVE25519_BLINDING + wc_curve25519_set_rng(userB, &rng); +#endif ret = wc_curve25519_make_key(&rng, 32, userB); if (ret != 0) @@ -35421,7 +35432,7 @@ WOLFSSL_TEST_SUBROUTINE wc_test_ret_t curve25519_test(void) if (XMEMCMP(sharedA, sharedB, x)) ERROR_OUT(WC_TEST_RET_ENC_NC, cleanup); - ret = curve25519_overflow_test(); + ret = curve25519_overflow_test(&rng); if (ret != 0) goto cleanup; ret = curve25519_check_public_test(); diff --git a/wolfssl/wolfcrypt/curve25519.h b/wolfssl/wolfcrypt/curve25519.h index ec736a02e0..79fb6d9af3 100644 --- a/wolfssl/wolfcrypt/curve25519.h +++ b/wolfssl/wolfcrypt/curve25519.h @@ -91,6 +91,9 @@ struct curve25519_key { int devId; #endif void *heap; +#ifdef WOLFSSL_CURVE25519_BLINDING + WC_RNG* rng; +#endif #ifdef WOLFSSL_SE050 word32 keyId; byte keyIdSet; @@ -109,11 +112,23 @@ enum { WOLFSSL_API int wc_curve25519_make_pub(int public_size, byte* pub, int private_size, const byte* priv); +#ifdef WOLFSSL_CURVE25519_BLINDING +WOLFSSL_API +int wc_curve25519_make_pub_blind(int public_size, byte* pub, int private_size, + const byte* priv, WC_RNG* rng); +#endif WOLFSSL_API int wc_curve25519_generic(int public_size, byte* pub, int private_size, const byte* priv, int basepoint_size, const byte* basepoint); +#ifdef WOLFSSL_CURVE25519_BLINDING +WOLFSSL_API +int wc_curve25519_generic_blind(int public_size, byte* pub, + int private_size, const byte* priv, + int basepoint_size, const byte* basepoint, + WC_RNG* rng); +#endif WOLFSSL_API int wc_curve25519_make_priv(WC_RNG* rng, int keysize, byte* priv); @@ -139,6 +154,11 @@ int wc_curve25519_init_ex(curve25519_key* key, void* heap, int devId); WOLFSSL_API void wc_curve25519_free(curve25519_key* key); +#ifdef WOLFSSL_CURVE25519_BLINDING +WOLFSSL_API +int wc_curve25519_set_rng(curve25519_key* key, WC_RNG* rng); +#endif + #ifndef WC_NO_CONSTRUCTORS WOLFSSL_API curve25519_key* wc_curve25519_new(void* heap, int devId, int *result_code); diff --git a/wolfssl/wolfcrypt/fe_operations.h b/wolfssl/wolfcrypt/fe_operations.h index 8b4ce304ea..ebc22d5ac9 100644 --- a/wolfssl/wolfcrypt/fe_operations.h +++ b/wolfssl/wolfcrypt/fe_operations.h @@ -76,6 +76,10 @@ Bounds on each t[i] vary depending on context. WOLFSSL_LOCAL void fe_init(void); WOLFSSL_LOCAL int curve25519(byte * q, const byte * n, const byte * p); +#ifdef WOLFSSL_CURVE25519_BLINDING +WOLFSSL_LOCAL int curve25519_blind(byte * q, const byte * n, const byte* mask, + const byte * p); +#endif #endif /* default to be faster but take more memory */