diff --git a/mcapi/crypto.c b/mcapi/crypto.c index 9437f1ede..18ec920c3 100644 --- a/mcapi/crypto.c +++ b/mcapi/crypto.c @@ -702,14 +702,32 @@ int CRYPT_ECC_DHE_SharedSecretMake(CRYPT_ECC_CTX* priv, CRYPT_ECC_CTX* pub, { int ret; unsigned int inOut = outSz; +#if defined(ECC_TIMING_RESISTANT) + WC_RNG rng; +#endif if (priv == NULL || pub == NULL || out == NULL || usedSz == NULL) return BAD_FUNC_ARG; +#if defined(ECC_TIMING_RESISTANT) + ret = wc_InitRng(&rng); + if (ret != 0) + return ret; + ret = wc_ecc_set_rng((ecc_key*)priv->holder, &rng); + if (ret != 0) { + wc_FreeRng(&rng); + return ret; + } +#endif + ret = wc_ecc_shared_secret((ecc_key*)priv->holder, (ecc_key*)pub->holder, out, &inOut); *usedSz = inOut; +#if defined(ECC_TIMING_RESISTANT) + wc_FreeRng(&rng); +#endif + return ret; } diff --git a/src/internal.c b/src/internal.c index 936ede2fd..ae6a0e6fe 100644 --- a/src/internal.c +++ b/src/internal.c @@ -4243,7 +4243,13 @@ int EccSharedSecret(WOLFSSL* ssl, ecc_key* priv_key, ecc_key* pub_key, else #endif { - ret = wc_ecc_shared_secret(priv_key, pub_key, out, outlen); +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(priv_key, ssl->rng); + if (ret == 0) +#endif + ret = wc_ecc_shared_secret(priv_key, pub_key, out, outlen); } /* Handle async pending response */ diff --git a/src/tls.c b/src/tls.c index bc09c53ff..175fd0cc6 100644 --- a/src/tls.c +++ b/src/tls.c @@ -7509,6 +7509,15 @@ static int TLSX_KeyShare_ProcessEcc(WOLFSSL* ssl, KeyShareEntry* keyShareEntry) } ssl->ecdhCurveOID = ssl->peerEccKey->dp->oidSum; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(keyShareKey, ssl->rng); + if (ret != 0) { + return ret; + } +#endif + do { #if defined(WOLFSSL_ASYNC_CRYPT) ret = wc_AsyncWait(ret, &keyShareKey->asyncDev, WC_ASYNC_FLAG_CALL_AGAIN); diff --git a/tests/api.c b/tests/api.c index ef0f1912d..78c9e4a84 100644 --- a/tests/api.c +++ b/tests/api.c @@ -19056,6 +19056,14 @@ static int test_wc_ecc_shared_secret (void) ret = wc_ecc_make_key(&rng, keySz, &pubKey); } +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + if (ret == 0) { + ret = wc_ecc_set_rng(&key, &rng); + } +#endif + printf(testingFmt, "wc_ecc_shared_secret()"); if (ret == 0) { ret = wc_ecc_shared_secret(&key, &pubKey, out, &outlen); @@ -20021,6 +20029,17 @@ static int test_wc_ecc_encryptDecrypt (void) } } +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + if (ret == 0) { + ret = wc_ecc_set_rng(&srvKey, &rng); + } + if (ret == 0) { + ret = wc_ecc_set_rng(&cliKey, &rng); + } +#endif + printf(testingFmt, "wc_ecc_encrypt()"); if (ret == 0) { @@ -20353,6 +20372,14 @@ static int test_wc_ecc_shared_secret_ssh (void) printf(testingFmt, "ecc_shared_secret_ssh()"); +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + if (ret == 0) { + ret = wc_ecc_set_rng(&key, &rng); + } +#endif + if (ret == 0) { ret = wc_ecc_shared_secret_ssh(&key, &key2.pubkey, secret, &secretLen); } @@ -22203,6 +22230,7 @@ static void test_wc_PKCS7_EncodeDecodeEnvelopedData (void) { #if defined(HAVE_PKCS7) PKCS7* pkcs7; + WC_RNG rng; word32 tempWrd32 = 0; byte* tmpBytePtr = NULL; const char input[] = "Test data to encode."; @@ -22370,6 +22398,10 @@ static void test_wc_PKCS7_EncodeDecodeEnvelopedData (void) #endif /* END HAVE_ECC */ }; /* END pkcs7EnvelopedVector */ +#ifdef ECC_TIMING_RESISTANT + AssertIntEQ(wc_InitRng(&rng), 0); +#endif + printf(testingFmt, "wc_PKCS7_EncodeEnvelopedData()"); AssertNotNull(pkcs7 = wc_PKCS7_New(HEAP_HINT, devId)); @@ -22379,6 +22411,9 @@ static void test_wc_PKCS7_EncodeDecodeEnvelopedData (void) for (i = 0; i < testSz; i++) { AssertIntEQ(wc_PKCS7_InitWithCert(pkcs7, (testVectors + i)->cert, (word32)(testVectors + i)->certSz), 0); +#ifdef ECC_TIMING_RESISTANT + pkcs7->rng = &rng; +#endif pkcs7->content = (byte*)(testVectors + i)->content; pkcs7->contentSz = (testVectors + i)->contentSz; @@ -22501,6 +22536,10 @@ static void test_wc_PKCS7_EncodeDecodeEnvelopedData (void) } #endif /* HAVE_ECC */ +#ifdef ECC_TIMING_RESISTANT + wc_FreeRng(&rng); +#endif + #endif /* HAVE_PKCS7 */ } /* END test_wc_PKCS7_EncodeEnvelopedData() */ diff --git a/wolfcrypt/benchmark/benchmark.c b/wolfcrypt/benchmark/benchmark.c index 03b38d0f4..bcaae78ba 100644 --- a/wolfcrypt/benchmark/benchmark.c +++ b/wolfcrypt/benchmark/benchmark.c @@ -5311,6 +5311,13 @@ void bench_ecc(int doAsync) } #ifdef HAVE_ECC_DHE +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + for (i = 0; i < BENCH_MAX_PENDING; i++) { + (void)wc_ecc_set_rng(&genKey[i], &gRng); + } +#endif /* ECC Shared Secret */ bench_stats_start(&count, &start); diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 81127a689..3482a4aea 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -1619,8 +1619,13 @@ int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, } /* should we dbl instead? */ - if (err == MP_OKAY) + if (err == MP_OKAY) { +#ifdef ECC_TIMING_RESISTANT + err = mp_submod_ct(modulus, Q->y, modulus, t1); +#else err = mp_sub(modulus, Q->y, t1); +#endif + } if (err == MP_OKAY) { if ( (mp_cmp(P->x, Q->x) == MP_EQ) && (get_digit_count(Q->z) && mp_cmp(P->z, Q->z) == MP_EQ) && @@ -1728,46 +1733,22 @@ int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, /* Y = Y - T1 */ if (err == MP_OKAY) - err = mp_sub(y, t1, y); - if (err == MP_OKAY) { - if (mp_isneg(y)) - err = mp_add(y, modulus, y); - } + err = mp_submod_ct(y, t1, modulus, y); /* T1 = 2T1 */ if (err == MP_OKAY) - err = mp_add(t1, t1, t1); - if (err == MP_OKAY) { - if (mp_cmp(t1, modulus) != MP_LT) - err = mp_sub(t1, modulus, t1); - } + err = mp_addmod_ct(t1, t1, modulus, t1); /* T1 = Y + T1 */ if (err == MP_OKAY) - err = mp_add(t1, y, t1); - if (err == MP_OKAY) { - if (mp_cmp(t1, modulus) != MP_LT) - err = mp_sub(t1, modulus, t1); - } + err = mp_addmod_ct(t1, y, modulus, t1); /* X = X - T2 */ if (err == MP_OKAY) - err = mp_sub(x, t2, x); - if (err == MP_OKAY) { - if (mp_isneg(x)) - err = mp_add(x, modulus, x); - } + err = mp_submod_ct(x, t2, modulus, x); /* T2 = 2T2 */ if (err == MP_OKAY) - err = mp_add(t2, t2, t2); - if (err == MP_OKAY) { - if (mp_cmp(t2, modulus) != MP_LT) - err = mp_sub(t2, modulus, t2); - } + err = mp_addmod_ct(t2, t2, modulus, t2); /* T2 = X + T2 */ if (err == MP_OKAY) - err = mp_add(t2, x, t2); - if (err == MP_OKAY) { - if (mp_cmp(t2, modulus) != MP_LT) - err = mp_sub(t2, modulus, t2); - } + err = mp_addmod_ct(t2, x, modulus, t2); if (err == MP_OKAY) { if (!mp_iszero(Q->z)) { @@ -1816,25 +1797,13 @@ int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, /* X = X - T2 */ if (err == MP_OKAY) - err = mp_sub(x, t2, x); - if (err == MP_OKAY) { - if (mp_isneg(x)) - err = mp_add(x, modulus, x); - } + err = mp_submod_ct(x, t2, modulus, x); /* T2 = T2 - X */ if (err == MP_OKAY) - err = mp_sub(t2, x, t2); - if (err == MP_OKAY) { - if (mp_isneg(t2)) - err = mp_add(t2, modulus, t2); - } + err = mp_submod_ct(t2, x, modulus, t2); /* T2 = T2 - X */ if (err == MP_OKAY) - err = mp_sub(t2, x, t2); - if (err == MP_OKAY) { - if (mp_isneg(t2)) - err = mp_add(t2, modulus, t2); - } + err = mp_submod_ct(t2, x, modulus, t2); /* T2 = T2 * Y */ if (err == MP_OKAY) err = mp_mul(t2, y, t2); @@ -1843,18 +1812,10 @@ int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, /* Y = T2 - T1 */ if (err == MP_OKAY) - err = mp_sub(t2, t1, y); - if (err == MP_OKAY) { - if (mp_isneg(y)) - err = mp_add(y, modulus, y); - } + err = mp_submod_ct(t2, t1, modulus, y); /* Y = Y/2 */ - if (err == MP_OKAY) { - if (mp_isodd(y) == MP_YES) - err = mp_add(y, modulus, y); - } if (err == MP_OKAY) - err = mp_div_2(y, y); + err = mp_div_2_mod_ct(y, modulus, y); #ifdef ALT_ECC_SIZE if (err == MP_OKAY) @@ -2071,11 +2032,7 @@ int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, /* Z = 2Z */ if (err == MP_OKAY) - err = mp_add(z, z, z); - if (err == MP_OKAY) { - if (mp_cmp(z, modulus) != MP_LT) - err = mp_sub(z, modulus, z); - } + err = mp_addmod_ct(z, z, modulus, z); /* Determine if curve "a" should be used in calc */ #ifdef WOLFSSL_CUSTOM_CURVES @@ -2101,25 +2058,13 @@ int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, err = mp_montgomery_reduce(t2, modulus, mp); /* T1 = T2 + T1 */ if (err == MP_OKAY) - err = mp_add(t1, t2, t1); - if (err == MP_OKAY) { - if (mp_cmp(t1, modulus) != MP_LT) - err = mp_sub(t1, modulus, t1); - } + err = mp_addmod_ct(t1, t2, modulus, t1); /* T1 = T2 + T1 */ if (err == MP_OKAY) - err = mp_add(t1, t2, t1); - if (err == MP_OKAY) { - if (mp_cmp(t1, modulus) != MP_LT) - err = mp_sub(t1, modulus, t1); - } + err = mp_addmod_ct(t1, t2, modulus, t1); /* T1 = T2 + T1 */ if (err == MP_OKAY) - err = mp_add(t1, t2, t1); - if (err == MP_OKAY) { - if (mp_cmp(t1, modulus) != MP_LT) - err = mp_sub(t1, modulus, t1); - } + err = mp_addmod_ct(t1, t2, modulus, t1); } else #endif /* WOLFSSL_CUSTOM_CURVES */ @@ -2129,18 +2074,10 @@ int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, /* T2 = X - T1 */ if (err == MP_OKAY) - err = mp_sub(x, t1, t2); - if (err == MP_OKAY) { - if (mp_isneg(t2)) - err = mp_add(t2, modulus, t2); - } + err = mp_submod_ct(x, t1, modulus, t2); /* T1 = X + T1 */ if (err == MP_OKAY) - err = mp_add(t1, x, t1); - if (err == MP_OKAY) { - if (mp_cmp(t1, modulus) != MP_LT) - err = mp_sub(t1, modulus, t1); - } + err = mp_addmod_ct(t1, x, modulus, t1); /* T2 = T1 * T2 */ if (err == MP_OKAY) err = mp_mul(t1, t2, t2); @@ -2149,27 +2086,15 @@ int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, /* T1 = 2T2 */ if (err == MP_OKAY) - err = mp_add(t2, t2, t1); - if (err == MP_OKAY) { - if (mp_cmp(t1, modulus) != MP_LT) - err = mp_sub(t1, modulus, t1); - } + err = mp_addmod_ct(t2, t2, modulus, t1); /* T1 = T1 + T2 */ if (err == MP_OKAY) - err = mp_add(t1, t2, t1); - if (err == MP_OKAY) { - if (mp_cmp(t1, modulus) != MP_LT) - err = mp_sub(t1, modulus, t1); - } + err = mp_addmod_ct(t1, t2, modulus, t1); } /* Y = 2Y */ if (err == MP_OKAY) - err = mp_add(y, y, y); - if (err == MP_OKAY) { - if (mp_cmp(y, modulus) != MP_LT) - err = mp_sub(y, modulus, y); - } + err = mp_addmod_ct(y, y, modulus, y); /* Y = Y * Y */ if (err == MP_OKAY) err = mp_sqr(y, y); @@ -2183,12 +2108,8 @@ int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, err = mp_montgomery_reduce(t2, modulus, mp); /* T2 = T2/2 */ - if (err == MP_OKAY) { - if (mp_isodd(t2) == MP_YES) - err = mp_add(t2, modulus, t2); - } if (err == MP_OKAY) - err = mp_div_2(t2, t2); + err = mp_div_2_mod_ct(t2, modulus, t2); /* Y = Y * X */ if (err == MP_OKAY) @@ -2204,26 +2125,14 @@ int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, /* X = X - Y */ if (err == MP_OKAY) - err = mp_sub(x, y, x); - if (err == MP_OKAY) { - if (mp_isneg(x)) - err = mp_add(x, modulus, x); - } + err = mp_submod_ct(x, y, modulus, x); /* X = X - Y */ if (err == MP_OKAY) - err = mp_sub(x, y, x); - if (err == MP_OKAY) { - if (mp_isneg(x)) - err = mp_add(x, modulus, x); - } + err = mp_submod_ct(x, y, modulus, x); /* Y = Y - X */ if (err == MP_OKAY) - err = mp_sub(y, x, y); - if (err == MP_OKAY) { - if (mp_isneg(y)) - err = mp_add(y, modulus, y); - } + err = mp_submod_ct(y, x, modulus, y); /* Y = Y * T1 */ if (err == MP_OKAY) err = mp_mul(y, t1, y); @@ -2232,11 +2141,7 @@ int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, /* Y = Y - T2 */ if (err == MP_OKAY) - err = mp_sub(y, t2, y); - if (err == MP_OKAY) { - if (mp_isneg(y)) - err = mp_add(y, modulus, y); - } + err = mp_submod_ct(y, t2, modulus, y); #ifdef ALT_ECC_SIZE if (err == MP_OKAY) @@ -2515,181 +2420,24 @@ int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp) #if !defined(FREESCALE_LTC_ECC) && !defined(WOLFSSL_STM32_PKA) -#if !defined(FP_ECC) || !defined(WOLFSSL_SP_MATH) -/** - Perform a point multiplication - k The scalar to multiply by - G The base point - R [out] Destination for kG - a ECC curve parameter a - modulus The modulus of the field the ECC curve is in - map Boolean whether to map back to affine or not - (1==map, 0 == leave in projective) - return MP_OKAY on success -*/ -#ifdef FP_ECC -static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, - mp_int* a, mp_int* modulus, int map, - void* heap) -#else -int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, - mp_int* a, mp_int* modulus, int map, - void* heap) -#endif -{ #ifndef WOLFSSL_SP_MATH + #ifndef ECC_TIMING_RESISTANT - /* size of sliding window, don't change this! */ - #define WINSIZE 4 - #define M_POINTS 8 - int first = 1, bitbuf = 0, bitcpy = 0, j; -#elif defined(WC_NO_CACHE_RESISTANT) - #define M_POINTS 4 -#else - #define M_POINTS 5 -#endif - ecc_point *tG, *M[M_POINTS]; - int i, err; -#ifdef WOLFSSL_SMALL_STACK_CACHE - ecc_key key; -#endif -#ifdef WOLFSSL_SMALL_STACK - mp_int* mu = NULL; -#else - mp_int mu[1]; -#endif - mp_digit mp; - mp_digit buf; - int bitcnt = 0, mode = 0, digidx = 0; +/* size of sliding window, don't change this! */ +#define WINSIZE 4 +#define M_POINTS 8 - if (k == NULL || G == NULL || R == NULL || modulus == NULL) { - return ECC_BAD_ARG_E; - } +static int ecc_mulmod(mp_int* k, ecc_point* tG, ecc_point* R, ecc_point** M, + mp_int* a, mp_int* modulus, mp_digit mp, WC_RNG* rng) +{ + int err = MP_OKAY; + int i; + int first = 1, bitbuf = 0, bitcpy = 0, j; + int bitcnt = 0, mode = 0, digidx = 0; + mp_digit buf; - /* init variables */ - tG = NULL; - XMEMSET(M, 0, sizeof(M)); -#ifdef WOLFSSL_SMALL_STACK - mu = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); - if (mu == NULL) - return MEMORY_E; -#endif -#ifdef WOLFSSL_SMALL_STACK_CACHE - key.t1 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); - key.t2 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); -#ifdef ALT_ECC_SIZE - key.x = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); - key.y = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); - key.z = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); -#endif - if (key.t1 == NULL || key.t2 == NULL -#ifdef ALT_ECC_SIZE - || key.x == NULL || key.y == NULL || key.z == NULL -#endif - ) { -#ifdef ALT_ECC_SIZE - XFREE(key.z, heap, DYNAMIC_TYPE_ECC); - XFREE(key.y, heap, DYNAMIC_TYPE_ECC); - XFREE(key.x, heap, DYNAMIC_TYPE_ECC); -#endif - XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); - XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); - XFREE(mu, heap, DYNAMIC_TYPE_ECC); - return MEMORY_E; - } -#endif /* WOLFSSL_SMALL_STACK_CACHE */ - - /* init montgomery reduction */ - if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { -#ifdef WOLFSSL_SMALL_STACK_CACHE -#ifdef ALT_ECC_SIZE - XFREE(key.z, heap, DYNAMIC_TYPE_ECC); - XFREE(key.y, heap, DYNAMIC_TYPE_ECC); - XFREE(key.x, heap, DYNAMIC_TYPE_ECC); -#endif - XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); - XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); -#endif /* WOLFSSL_SMALL_STACK_CACHE */ -#ifdef WOLFSSL_SMALL_STACK - XFREE(mu, heap, DYNAMIC_TYPE_ECC); -#endif - return err; - } - - if ((err = mp_init(mu)) != MP_OKAY) { -#ifdef WOLFSSL_SMALL_STACK_CACHE -#ifdef ALT_ECC_SIZE - XFREE(key.z, heap, DYNAMIC_TYPE_ECC); - XFREE(key.y, heap, DYNAMIC_TYPE_ECC); - XFREE(key.x, heap, DYNAMIC_TYPE_ECC); -#endif - XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); - XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); -#endif /* WOLFSSL_SMALL_STACK_CACHE */ -#ifdef WOLFSSL_SMALL_STACK - XFREE(mu, heap, DYNAMIC_TYPE_ECC); -#endif - return err; - } - if ((err = mp_montgomery_calc_normalization(mu, modulus)) != MP_OKAY) { - mp_clear(mu); -#ifdef WOLFSSL_SMALL_STACK_CACHE -#ifdef ALT_ECC_SIZE - XFREE(key.z, heap, DYNAMIC_TYPE_ECC); - XFREE(key.y, heap, DYNAMIC_TYPE_ECC); - XFREE(key.x, heap, DYNAMIC_TYPE_ECC); -#endif - XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); - XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); -#endif /* WOLFSSL_SMALL_STACK_CACHE */ -#ifdef WOLFSSL_SMALL_STACK - XFREE(mu, heap, DYNAMIC_TYPE_ECC); -#endif - return err; - } - - /* alloc ram for window temps */ - for (i = 0; i < M_POINTS; i++) { - M[i] = wc_ecc_new_point_h(heap); - if (M[i] == NULL) { - mp_clear(mu); - err = MEMORY_E; goto exit; - } -#ifdef WOLFSSL_SMALL_STACK_CACHE - M[i]->key = &key; -#endif - } - - /* make a copy of G in case R==G */ - tG = wc_ecc_new_point_h(heap); - if (tG == NULL) - err = MEMORY_E; - - /* tG = G and convert to montgomery */ - if (err == MP_OKAY) { - if (mp_cmp_d(mu, 1) == MP_EQ) { - err = mp_copy(G->x, tG->x); - if (err == MP_OKAY) - err = mp_copy(G->y, tG->y); - if (err == MP_OKAY) - err = mp_copy(G->z, tG->z); - } else { - err = mp_mulmod(G->x, mu, modulus, tG->x); - if (err == MP_OKAY) - err = mp_mulmod(G->y, mu, modulus, tG->y); - if (err == MP_OKAY) - err = mp_mulmod(G->z, mu, modulus, tG->z); - } - } - - /* done with mu */ - mp_clear(mu); - -#ifdef WOLFSSL_SMALL_STACK_CACHE - R->key = &key; -#endif -#ifndef ECC_TIMING_RESISTANT + (void)rng; /* calc the M tab, which holds kG for k==8..15 */ /* M[0] == 8G */ @@ -2770,7 +2518,7 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, } if (err != MP_OKAY) break; /* out of first for(;;) */ - /* then add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */ + /* now add, bitbuf will be 8..15 [8..2^WINSIZE] guaranteed */ err = ecc_projective_add_point(R, M[bitbuf-M_POINTS], R, a, modulus, mp); } @@ -2818,7 +2566,54 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, #undef WINSIZE -#else /* ECC_TIMING_RESISTANT */ + return err; +} + +#else + +static int wc_ecc_gen_z(WC_RNG* rng, int size, ecc_point* p, + mp_int* modulus, mp_digit mp, mp_int* tx, mp_int* ty) +{ + int err; + + err = wc_ecc_gen_k(rng, size, ty, modulus); + if (err == MP_OKAY) + err = mp_mul(p->z, ty, p->z); + if (err == MP_OKAY) + err = mp_montgomery_reduce(p->z, modulus, mp); + if (err == MP_OKAY) + err = mp_sqr(ty, tx); + if (err == MP_OKAY) + err = mp_montgomery_reduce(tx, modulus, mp); + if (err == MP_OKAY) + err = mp_mul(ty, tx, ty); + if (err == MP_OKAY) + err = mp_montgomery_reduce(ty, modulus, mp); + if (err == MP_OKAY) + err = mp_mul(p->x, tx, p->x); + if (err == MP_OKAY) + err = mp_montgomery_reduce(p->x, modulus, mp); + if (err == MP_OKAY) + err = mp_mul(p->y, ty, p->y); + if (err == MP_OKAY) + err = mp_montgomery_reduce(p->y, modulus, mp); + + return err; +} + +#if defined(WC_NO_CACHE_RESISTANT) + #define M_POINTS 4 +#else + #define M_POINTS 5 +#endif + +static int ecc_mulmod(mp_int* k, ecc_point* tG, ecc_point* R, ecc_point** M, + mp_int* a, mp_int* modulus, mp_digit mp, WC_RNG* rng) +{ + int err = MP_OKAY; + int i; + int bitcnt = 0, mode = 0, digidx = 0; + mp_digit buf; /* calc the M tab */ /* M[0] == G */ @@ -2832,22 +2627,45 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, /* M[1] == 2G */ if (err == MP_OKAY) err = ecc_projective_dbl_point(tG, M[1], a, modulus, mp); + #ifdef WC_NO_CACHE_RESISTANT if (err == MP_OKAY) err = wc_ecc_copy_point(M[0], M[2]); + if (rng != NULL) { + if (err == MP_OKAY) { + err = wc_ecc_gen_z(rng, (mp_count_bits(modulus) + 7) / 8, M[0], + modulus, mp, M[3]->x, M[3]->y); + } + if (err == MP_OKAY) { + err = wc_ecc_gen_z(rng, (mp_count_bits(modulus) + 7) / 8, M[1], + modulus, mp, M[3]->x, M[3]->y); + } + } #else if (err == MP_OKAY) err = wc_ecc_copy_point(M[0], M[3]); if (err == MP_OKAY) err = wc_ecc_copy_point(M[1], M[4]); + if (rng != NULL) { + if (err == MP_OKAY) { + err = wc_ecc_gen_z(rng, (mp_count_bits(modulus) + 7) / 8, M[3], + modulus, mp, M[2]->x, M[2]->y); + } + if (err == MP_OKAY) { + err = wc_ecc_gen_z(rng, (mp_count_bits(modulus) + 7) / 8, M[4], + modulus, mp, M[2]->x, M[2]->y); + } + } #endif /* setup sliding window */ mode = 0; digidx = get_digit_count(modulus) - 1; - /* The order MAY be 1 bit longer than the modulus. */ - digidx += modulus->dp[digidx] >> (DIGIT_BIT-1); - bitcnt = (mp_count_bits(modulus) + 1) % DIGIT_BIT; + /* The order MAY be 1 bit longer than the modulus. + * k MAY be 1 bit longer than the order. + */ + bitcnt = (mp_count_bits(modulus) + 2) % DIGIT_BIT; + digidx += (bitcnt <= 3); buf = get_digit(k, digidx) << (DIGIT_BIT - bitcnt); bitcnt = (bitcnt + 1) % DIGIT_BIT; digidx -= bitcnt != 1; @@ -2873,10 +2691,10 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, if (mode == 0) { /* timing resistant - dummy operations */ if (err == MP_OKAY) - err = ecc_projective_add_point(M[1], M[2], M[2], a, modulus, + err = ecc_projective_add_point(M[1], M[2], M[3], a, modulus, mp); if (err == MP_OKAY) - err = ecc_projective_dbl_point(M[2], M[3], a, modulus, mp); + err = ecc_projective_dbl_point(M[3], M[2], a, modulus, mp); } else { if (err == MP_OKAY) @@ -2958,8 +2776,186 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, if (err == MP_OKAY) err = mp_copy(M[0]->z, R->z); -#endif /* ECC_TIMING_RESISTANT */ + return err; +} +#endif + +#ifndef WOLFSSL_SP_MATH +/* Convert the point to montogmery form. + * + * @param [in] p Point to convert. + * @param [out] r Point in montgomery form. + * @param [in] modulus Modulus of ordinates. + * @return 0 on success. + * @return -ve on failure. + */ +static int ecc_point_to_mont(ecc_point* p, ecc_point* r, mp_int* modulus, + void* heap) +{ + int err = MP_OKAY; +#ifdef WOLFSSL_SMALL_STACK + mp_int* mu = NULL; +#else + mp_int mu[1]; +#endif + + (void)heap; + +#ifdef WOLFSSL_SMALL_STACK + mu = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + if (mu == NULL) + err = MEMORY_E; +#endif + if (err == MP_OKAY) + err = mp_init(mu); + if (err == MP_OKAY) { + err = mp_montgomery_calc_normalization(mu, modulus); + } + + if (err == MP_OKAY) { + if (mp_cmp_d(mu, 1) == MP_EQ) { + err = mp_copy(p->x, r->x); + if (err == MP_OKAY) + err = mp_copy(p->y, r->y); + if (err == MP_OKAY) + err = mp_copy(p->z, r->z); + } + else { + err = mp_mulmod(p->x, mu, modulus, r->x); + if (err == MP_OKAY) + err = mp_mulmod(p->y, mu, modulus, r->y); + if (err == MP_OKAY) + err = mp_mulmod(p->z, mu, modulus, r->z); + } + } + +#ifdef WOLFSSL_SMALL_STACK + if (mu != NULL) + XFREE(mu, heap, DYNAMIC_TYPE_ECC); +#endif + return err; +} +#endif /* !WOLFSSL_SP_MATH */ + +#ifdef WOLFSSL_SMALL_STACK_CACHE +static int ecc_key_tmp_init(ecc_key* key, void* heap) +{ + int err = MP_OKAY; + + XMEMSET(*key, 0, sizeof(key)); + + key->t1 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + key->t2 = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); +#ifdef ALT_ECC_SIZE + key->x = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + key->y = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); + key->z = (mp_int*)XMALLOC(sizeof(mp_int), heap, DYNAMIC_TYPE_ECC); +#endif + if (key->t1 == NULL || key->t2 == NULL +#ifdef ALT_ECC_SIZE + || key->x == NULL || key->y == NULL || key->z == NULL +#endif + ) { + err = MEMORY_E; + } + + return err; +} + +static void ecc_key_tmp_final(ecc_key* key, void* heap) +{ +#ifdef ALT_ECC_SIZE + if (key->z != NULL) + XFREE(key->z, heap, DYNAMIC_TYPE_ECC); + if (key->y != NULL) + XFREE(key->y, heap, DYNAMIC_TYPE_ECC); + if (key->x != NULL) + XFREE(key->x, heap, DYNAMIC_TYPE_ECC); +#endif + if (key->t2 != NULL) + XFREE(key->t2, heap, DYNAMIC_TYPE_ECC); + if (key.t1 != NULL) + XFREE(key->t1, heap, DYNAMIC_TYPE_ECC); +} +#endif /* WOLFSSL_SMALL_STACK_CACHE */ +#endif /* !WOLFSSL_SP_MATH */ + +#if !defined(WOLFSSL_SP_MATH) || !defined(FP_ECC) +/** + Perform a point multiplication + k The scalar to multiply by + G The base point + R [out] Destination for kG + a ECC curve parameter a + modulus The modulus of the field the ECC curve is in + map Boolean whether to map back to affine or not + (1==map, 0 == leave in projective) + return MP_OKAY on success +*/ +#ifdef FP_ECC +static int normal_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, + mp_int* modulus, WC_RNG* rng, int map, void* heap) +#else +int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, + mp_int* modulus, int map, void* heap) +#endif +#ifndef WOLFSSL_SP_MATH +{ + ecc_point *tG, *M[M_POINTS]; + int i, err; +#ifdef WOLFSSL_SMALL_STACK_CACHE + ecc_key key; +#endif + mp_digit mp; + + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } + + /* init variables */ + tG = NULL; + XMEMSET(M, 0, sizeof(M)); + +#ifdef WOLFSSL_SMALL_STACK_CACHE + err = ecc_key_tmp_init(&key, heap); + if (err != MP_OKAY) + goto exit; + R->key = &key; +#endif /* WOLFSSL_SMALL_STACK_CACHE */ + + /* alloc ram for window temps */ + for (i = 0; i < M_POINTS; i++) { + M[i] = wc_ecc_new_point_h(heap); + if (M[i] == NULL) { + err = MEMORY_E; + goto exit; + } +#ifdef WOLFSSL_SMALL_STACK_CACHE + M[i]->key = &key; +#endif + } + + /* make a copy of G in case R==G */ + tG = wc_ecc_new_point_h(heap); + if (tG == NULL) { + err = MEMORY_E; + goto exit; + } + if ((err = ecc_point_to_mont(G, tG, modulus, heap)) != MP_OKAY) { + goto exit; + } + + /* init montgomery reduction */ + if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { + goto exit; + } + +#ifdef FP_ECC + err = ecc_mulmod(k, tG, R, M, a, modulus, mp, rng); +#else + err = ecc_mulmod(k, tG, R, M, a, modulus, mp, NULL); +#endif /* map R back from projective space */ if (err == MP_OKAY && map) err = ecc_map(R, modulus, mp); @@ -2973,20 +2969,13 @@ exit: } #ifdef WOLFSSL_SMALL_STACK_CACHE R->key = NULL; -#ifdef ALT_ECC_SIZE - XFREE(key.z, heap, DYNAMIC_TYPE_ECC); - XFREE(key.y, heap, DYNAMIC_TYPE_ECC); - XFREE(key.x, heap, DYNAMIC_TYPE_ECC); -#endif - XFREE(key.t2, heap, DYNAMIC_TYPE_ECC); - XFREE(key.t1, heap, DYNAMIC_TYPE_ECC); + ecc_key_tmp_free(&key, heap); #endif /* WOLFSSL_SMALL_STACK_CACHE */ -#ifdef WOLFSSL_SMALL_STACK - XFREE(mu, heap, DYNAMIC_TYPE_ECC); -#endif return err; +} #else +{ if (k == NULL || G == NULL || R == NULL || modulus == NULL) { return ECC_BAD_ARG_E; } @@ -3004,10 +2993,158 @@ exit: } #endif return ECC_BAD_ARG_E; -#endif } +#endif +#endif /* !defined(WOLFSSL_SP_MATH) && !defined(FP_ECC) */ -#endif /* !FP_ECC || !WOLFSSL_SP_MATH */ +#ifndef FP_ECC +/** + Perform a point multiplication + k The scalar to multiply by + G The base point + R [out] Destination for kG + a ECC curve parameter a + modulus The modulus of the field the ECC curve is in + map Boolean whether to map back to affine or not + (1==map, 0 == leave in projective) + return MP_OKAY on success +*/ +int wc_ecc_mulmod_ex2(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, + mp_int* modulus, mp_int* order, WC_RNG* rng, int map, + void* heap) +#ifndef WOLFSSL_SP_MATH +{ + ecc_point *tG, *M[M_POINTS]; + int i, err; +#ifdef WOLFSSL_SMALL_STACK_CACHE + ecc_key key; +#endif + mp_digit mp; +#ifdef ECC_TIMING_RESISTANT + mp_int t; + mp_int o; + mp_digit mask; +#endif + + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } + + /* init variables */ + tG = NULL; + XMEMSET(M, 0, sizeof(M)); + +#ifdef WOLFSSL_SMALL_STACK_CACHE + err = ecc_key_tmp_init(&key, heap); + if (err != MP_OKAY) + goto exit; + R->key = &key; +#endif /* WOLFSSL_SMALL_STACK_CACHE */ + + /* alloc ram for window temps */ + for (i = 0; i < M_POINTS; i++) { + M[i] = wc_ecc_new_point_h(heap); + if (M[i] == NULL) { + err = MEMORY_E; + goto exit; + } +#ifdef WOLFSSL_SMALL_STACK_CACHE + M[i]->key = &key; +#endif + } + + /* make a copy of G in case R==G */ + tG = wc_ecc_new_point_h(heap); + if (tG == NULL) { + err = MEMORY_E; + goto exit; + } + if ((err = ecc_point_to_mont(G, tG, modulus, heap)) != MP_OKAY) { + goto exit; + } + + /* init montgomery reduction */ + if ((err = mp_montgomery_setup(modulus, &mp)) != MP_OKAY) { + goto exit; + } + +#ifdef ECC_TIMING_RESISTANT + if ((err = mp_init(&t)) != MP_OKAY) + goto exit; + if ((err = mp_init(&o)) != MP_OKAY) { + mp_free(&t); + goto exit; + } + + /* Make k at 1 bit longer than order. */ + if (err == MP_OKAY) { + err = mp_add(k, order, &t); + } + if (err == MP_OKAY) { + err = mp_copy(order, &o); + } + if (err == MP_OKAY) { + /* Only add if order + k has same number of bits as order */ + mask = (mp_digit)0 - (mp_count_bits(&t) == mp_count_bits(order)); + for (i = 0; i < o.used; i++) { + o.dp[i] &= mask; + } + err = mp_add(&t, &o, &t); + } + mp_free(&o); + + if (err == MP_OKAY) + err = ecc_mulmod(&t, tG, R, M, a, modulus, mp, rng); + + mp_forcezero(&t); + mp_free(&t); +#else + err = ecc_mulmod(k, tG, R, M, a, modulus, mp, rng); + + (void)order; +#endif + /* map R back from projective space */ + if (err == MP_OKAY && map) + err = ecc_map(R, modulus, mp); + +exit: + + /* done */ + wc_ecc_del_point_h(tG, heap); + for (i = 0; i < M_POINTS; i++) { + wc_ecc_del_point_h(M[i], heap); + } +#ifdef WOLFSSL_SMALL_STACK_CACHE + R->key = NULL; + ecc_key_tmp_free(&key, heap); +#endif /* WOLFSSL_SMALL_STACK_CACHE */ + + return err; +} +#else +{ + if (k == NULL || G == NULL || R == NULL || modulus == NULL) { + return ECC_BAD_ARG_E; + } + + (void)a; + (void)order; + (void)rng; + +#ifndef WOLFSSL_SP_NO_256 + if (mp_count_bits(modulus) == 256) { + return sp_ecc_mulmod_256(k, G, R, map, heap); + } +#endif +#ifdef WOLFSSL_SP_384 + if (mp_count_bits(modulus) == 384) { + return sp_ecc_mulmod_384(k, G, R, map, heap); + } +#endif + return ECC_BAD_ARG_E; +} +#endif /* !WOLFSSL_SP_MATH */ +#endif /* !FP_ECC */ #endif /* !FREESCALE_LTC_ECC && !WOLFSSL_STM32_PKA */ @@ -3616,7 +3753,7 @@ int wc_ecc_shared_secret(ecc_key* private_key, ecc_key* public_key, byte* out, static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point, byte* out, word32* outlen, ecc_curve_spec* curve) { - int err; + int err = MP_OKAY; #ifndef WOLFSSL_SP_MATH ecc_point* result = NULL; word32 x = 0; @@ -3679,9 +3816,23 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point, return MEMORY_E; } - /* Map in a separate call as this should be constant time */ - err = wc_ecc_mulmod_ex(k, point, result, curve->Af, curve->prime, 0, - private_key->heap); +#ifdef ECC_TIMING_RESISTANT + if (private_key->rng == NULL) { + err = MISSING_RNG_E; + } +#endif + + if (err == MP_OKAY) { + /* Map in a separate call as this should be constant time */ +#ifdef ECC_TIMING_RESISTANT + err = wc_ecc_mulmod_ex2(k, point, result, curve->Af, curve->prime, + curve->order, private_key->rng, 0, + private_key->heap); +#else + err = wc_ecc_mulmod_ex2(k, point, result, curve->Af, curve->prime, + curve->order, NULL, 0, private_key->heap); +#endif + } if (err == MP_OKAY) { err = mp_montgomery_setup(curve->prime, &mp); } @@ -3781,7 +3932,7 @@ int wc_ecc_shared_secret_gen(ecc_key* private_key, ecc_point* point, byte* out, word32 *outlen) { int err; - DECLARE_CURVE_SPECS(curve, 2); + DECLARE_CURVE_SPECS(curve, 3); if (private_key == NULL || point == NULL || out == NULL || outlen == NULL) { @@ -3789,9 +3940,9 @@ int wc_ecc_shared_secret_gen(ecc_key* private_key, ecc_point* point, } /* load curve info */ - ALLOC_CURVE_SPECS(2); + ALLOC_CURVE_SPECS(3); err = wc_ecc_curve_load(private_key->dp, &curve, - (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF)); + (ECC_CURVE_FIELD_PRIME | ECC_CURVE_FIELD_AF | ECC_CURVE_FIELD_ORDER)); if (err != MP_OKAY) { FREE_CURVE_SPECS(); return err; @@ -3958,7 +4109,6 @@ static WC_INLINE void wc_ecc_reset(ecc_key* key) key->state = ECC_STATE_NONE; } - /* create the public ECC key from a private key * * key an initialized private key to generate public part from @@ -3972,8 +4122,8 @@ static WC_INLINE void wc_ecc_reset(ecc_key* key) * * returns MP_OKAY on success */ -static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, - ecc_point* pubOut) +static int ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, + ecc_point* pubOut, WC_RNG* rng) { int err = MP_OKAY; #if !defined(WOLFSSL_ATECC508A) && !defined(WOLFSSL_ATECC608A) @@ -3984,6 +4134,8 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, DECLARE_CURVE_SPECS(curve, ECC_CURVE_FIELD_COUNT); #endif /* !WOLFSSL_ATECC508A */ + (void)rng; + if (key == NULL) { return BAD_FUNC_ARG; } @@ -4058,21 +4210,20 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, err = mp_copy(curve->Gx, base->x); if (err == MP_OKAY) err = mp_copy(curve->Gy, base->y); + if (err == MP_OKAY) + err = mp_montgomery_setup(curve->prime, &mp); if (err == MP_OKAY) err = mp_set(base->z, 1); /* make the public key */ if (err == MP_OKAY) { /* Map in a separate call as this should be constant time */ - err = wc_ecc_mulmod_ex(&key->k, base, pub, curve->Af, curve->prime, - 0, key->heap); + err = wc_ecc_mulmod_ex2(&key->k, base, pub, curve->Af, curve->prime, + curve->order, rng, 0, key->heap); if (err == MP_MEM) { err = MEMORY_E; } } - if (err == MP_OKAY) { - err = mp_montgomery_setup(curve->prime, &mp); - } if (err == MP_OKAY) { /* Use constant time map if compiled in */ err = ecc_map_ex(pub, curve->prime, mp, 1); @@ -4131,7 +4282,23 @@ int wc_ecc_make_pub(ecc_key* key, ecc_point* pubOut) { WOLFSSL_ENTER("wc_ecc_make_pub"); - return wc_ecc_make_pub_ex(key, NULL, pubOut); + return ecc_make_pub_ex(key, NULL, pubOut, NULL); +} + +/* create the public ECC key from a private key - mask timing use random z + * + * key an initialized private key to generate public part from + * pubOut [out]ecc_point holding the public key, if NULL then public key part + * is cached in key instead. + * + * + * returns MP_OKAY on success + */ +int wc_ecc_make_pub_ex(ecc_key* key, ecc_point* pubOut, WC_RNG* rng) +{ + WOLFSSL_ENTER("wc_ecc_make_pub"); + + return ecc_make_pub_ex(key, NULL, pubOut, rng); } @@ -4308,7 +4475,7 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id) /* generate public key from k */ if (err == MP_OKAY) - err = wc_ecc_make_pub_ex(key, curve, NULL); + err = ecc_make_pub_ex(key, curve, NULL, rng); if (err == MP_OKAY) key->type = ECC_PRIVATEKEY; @@ -5191,7 +5358,7 @@ int wc_ecc_sign_hash_ex(const byte* in, word32 inlen, WC_RNG* rng, mp_free(key->sign_k); XFREE(key->sign_k, key->heap, DYNAMIC_TYPE_ECC); key->sign_k = NULL; - err = wc_ecc_make_pub_ex(pubkey, curve, NULL); + err = ecc_make_pub_ex(pubkey, curve, NULL, rng); } else #endif @@ -5995,7 +6162,7 @@ int wc_ecc_verify_hash_ex(mp_int *r, mp_int *s, const byte* hash, /* checking if private key with no public part */ if (key->type == ECC_PRIVATEKEY_ONLY) { WOLFSSL_MSG("Verify called with private key, generating public part"); - err = wc_ecc_make_pub_ex(key, NULL, NULL); + err = ecc_make_pub_ex(key, NULL, NULL, NULL); if (err != MP_OKAY) { WOLFSSL_MSG("Unable to extract public key"); return err; @@ -6902,12 +7069,12 @@ static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) int err = MP_OKAY; ecc_point* base = NULL; ecc_point* res = NULL; - DECLARE_CURVE_SPECS(curve, 2); + DECLARE_CURVE_SPECS(curve, 3); if (key == NULL) return BAD_FUNC_ARG; - ALLOC_CURVE_SPECS(2); + ALLOC_CURVE_SPECS(3); res = wc_ecc_new_point_h(key->heap); if (res == NULL) @@ -6938,8 +7105,8 @@ static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) if (err == MP_OKAY) { /* load curve info */ - err = wc_ecc_curve_load(key->dp, &curve, - (ECC_CURVE_FIELD_GX | ECC_CURVE_FIELD_GY)); + err = wc_ecc_curve_load(key->dp, &curve, (ECC_CURVE_FIELD_GX | + ECC_CURVE_FIELD_GY | ECC_CURVE_FIELD_ORDER)); } /* set up base generator */ @@ -6950,8 +7117,15 @@ static int ecc_check_privkey_gen(ecc_key* key, mp_int* a, mp_int* prime) if (err == MP_OKAY) err = mp_set(base->z, 1); +#ifdef ECC_TIMING_RESISTANT if (err == MP_OKAY) - err = wc_ecc_mulmod_ex(&key->k, base, res, a, prime, 1, key->heap); + err = wc_ecc_mulmod_ex2(&key->k, base, res, a, prime, curve->order, + key->rng, 1, key->heap); +#else + if (err == MP_OKAY) + err = wc_ecc_mulmod_ex2(&key->k, base, res, a, prime, curve->order, + NULL, 1, key->heap); +#endif } if (err == MP_OKAY) { @@ -9659,7 +9833,7 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, if (err == MP_OKAY) err = accel_fp_mul(idx, k, R, a, modulus, mp, map); } else { - err = normal_ecc_mulmod(k, G, R, a, modulus, map, heap); + err = normal_ecc_mulmod(k, G, R, a, modulus, NULL, map, heap); } } @@ -9688,6 +9862,164 @@ int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, #endif } +#ifndef WOLFSSL_SP_MATH +static int normal_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, + mp_int* a, mp_int* modulus, mp_int* order, + WC_RNG* rng, int map, void* heap) +{ + int err; + mp_int t; + mp_int o; + mp_digit mask; + int i; + + if ((err = mp_init(&t)) != MP_OKAY) + return err; + if ((err = mp_init(&o)) != MP_OKAY) { + mp_free(&t); + return err; + } + + /* Make k at 1 bit longer than order. */ + if (err == MP_OKAY) { + err = mp_add(k, order, &t); + } + if (err == MP_OKAY) { + err = mp_copy(order, &o); + } + if (err == MP_OKAY) { + /* Only add if order + k has same number of bits as order */ + mask = (mp_digit)0 - (mp_count_bits(&t) == mp_count_bits(order)); + for (i = 0; i < o.used; i++) { + o.dp[i] &= mask; + } + err = mp_add(&t, &o, &t); + } + + if (err == MP_OKAY) { + err = normal_ecc_mulmod(&t, G, R, a, modulus, rng, map, heap); + } + + mp_forcezero(&t); + mp_free(&o); + mp_free(&t); + + return err; +} +#endif /* !WOLFSSL_SP_MATH */ + +/** ECC Fixed Point mulmod global + k The multiplicand + G Base point to multiply + R [out] Destination of product + a ECC curve parameter a + modulus The modulus for the curve + map [boolean] If non-zero maps the point back to affine coordinates, + otherwise it's left in jacobian-montgomery form + return MP_OKAY if successful +*/ +int wc_ecc_mulmod_ex2(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, + mp_int* modulus, mp_int* order, WC_RNG* rng, int map, void* heap) +{ +#ifndef WOLFSSL_SP_MATH + int idx, err = MP_OKAY; + mp_digit mp; + mp_int mu; + int mpSetup = 0; + + if (k == NULL || G == NULL || R == NULL || a == NULL || modulus == NULL || + order == NULL) { + return ECC_BAD_ARG_E; + } + + if (mp_init(&mu) != MP_OKAY) + return MP_INIT_E; + +#ifndef HAVE_THREAD_LS + if (initMutex == 0) { /* extra sanity check if wolfCrypt_Init not called */ + wc_InitMutex(&ecc_fp_lock); + initMutex = 1; + } + + if (wc_LockMutex(&ecc_fp_lock) != 0) + return BAD_MUTEX_E; +#endif /* HAVE_THREAD_LS */ + + /* find point */ + idx = find_base(G); + + /* no entry? */ + if (idx == -1) { + /* find hole and add it */ + idx = find_hole(); + + if (idx >= 0) + err = add_entry(idx, G); + } + if (err == MP_OKAY && idx >= 0) { + /* increment LRU */ + ++(fp_cache[idx].lru_count); + } + + + if (err == MP_OKAY) { + /* if it's 2 build the LUT, if it's higher just use the LUT */ + if (idx >= 0 && fp_cache[idx].lru_count >= 2 && !fp_cache[idx].LUT_set) { + /* compute mp */ + err = mp_montgomery_setup(modulus, &mp); + + if (err == MP_OKAY) { + /* compute mu */ + mpSetup = 1; + err = mp_montgomery_calc_normalization(&mu, modulus); + } + + if (err == MP_OKAY) + /* build the LUT */ + err = build_lut(idx, a, modulus, mp, &mu); + } + } + + if (err == MP_OKAY) { + if (idx >= 0 && fp_cache[idx].LUT_set) { + if (mpSetup == 0) { + /* compute mp */ + err = mp_montgomery_setup(modulus, &mp); + } + if (err == MP_OKAY) + err = accel_fp_mul(idx, k, R, a, modulus, mp, map); + } else { + err = normal_ecc_mulmod_ex(k, G, R, a, modulus, order, rng, map, + heap); + } + } + +#ifndef HAVE_THREAD_LS + wc_UnLockMutex(&ecc_fp_lock); +#endif /* HAVE_THREAD_LS */ + mp_clear(&mu); + + return err; +#else + if (k == NULL || G == NULL || R == NULL || a == NULL || modulus == NULL || + order == NULL) { + return ECC_BAD_ARG_E; + } + +#ifndef WOLFSSL_SP_NO_256 + if (mp_count_bits(modulus) == 256) { + return sp_ecc_mulmod_256(k, G, R, map, heap); + } +#endif +#ifdef WOLFSSL_SP_384 + if (mp_count_bits(modulus) == 384) { + return sp_ecc_mulmod_384(k, G, R, map, heap); + } +#endif + return WC_KEY_SIZE_E; +#endif +} + #ifndef WOLFSSL_SP_MATH /* helper function for freeing the cache ... must be called with the cache mutex locked */ @@ -9753,6 +10085,22 @@ void wc_ecc_fp_free(void) #endif /* FP_ECC */ +#ifdef ECC_TIMING_RESISTANT +int wc_ecc_set_rng(ecc_key* key, WC_RNG* rng) +{ + int err = 0; + + if (key == NULL) { + err = BAD_FUNC_ARG; + } + else { + key->rng = rng; + } + + return err; +} +#endif + #ifdef HAVE_ECC_ENCRYPT diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index d81d84e18..9077cbba8 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -1413,16 +1413,40 @@ int wolfSSL_EVP_PKEY_derive(WOLFSSL_EVP_PKEY_CTX *ctx, unsigned char *key, size_ } if (key) { word32 len32 = (word32)len; +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + WC_RNG rng; + if (wc_InitRng(&rng) != MP_OKAY) { + WOLFSSL_MSG("Init RNG failed"); + return WOLFSSL_FAILURE; + } + ((ecc_key*)ctx->pkey->ecc->internal)->rng = &rng; +#endif if (*keylen < len32) { WOLFSSL_MSG("buffer too short"); +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ((ecc_key*)ctx->pkey->ecc->internal)->rng = NULL; + wc_FreeRng(&rng); +#endif return WOLFSSL_FAILURE; } if (wc_ecc_shared_secret_ssh((ecc_key*)ctx->pkey->ecc->internal, (ecc_point*)ctx->peerKey->ecc->pub_key->internal, key, &len32) != MP_OKAY) { WOLFSSL_MSG("wc_ecc_shared_secret failed"); +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ((ecc_key*)ctx->pkey->ecc->internal)->rng = NULL; + wc_FreeRng(&rng); +#endif return WOLFSSL_FAILURE; } +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + ((ecc_key*)ctx->pkey->ecc->internal)->rng = NULL; + wc_FreeRng(&rng); +#endif len = (int)len32; } *keylen = (size_t)len; diff --git a/wolfcrypt/src/integer.c b/wolfcrypt/src/integer.c index decb1b37e..c7d2c7e34 100644 --- a/wolfcrypt/src/integer.c +++ b/wolfcrypt/src/integer.c @@ -1577,6 +1577,24 @@ int mp_div_2(mp_int * a, mp_int * b) return MP_OKAY; } +/* c = a / 2 (mod b) - constant time (a < b and positive) */ +int mp_div_2_mod_ct(mp_int *a, mp_int *b, mp_int *c) +{ + int res; + + if (mp_isodd(a)) { + res = mp_add(a, b, c); + if (res == MP_OKAY) { + res = mp_div_2(c, c); + } + } + else { + res = mp_div_2(a, c); + } + + return res; +} + /* high level addition (handles signs) */ int mp_add (mp_int * a, mp_int * b, mp_int * c) @@ -2994,6 +3012,32 @@ int mp_addmod(mp_int* a, mp_int* b, mp_int* c, mp_int* d) return res; } +/* d = a - b (mod c) - a < c and b < c and positive */ +int mp_submod_ct(mp_int* a, mp_int* b, mp_int* c, mp_int* d) +{ + int res; + + res = mp_sub(a, b, d); + if (res == MP_OKAY && mp_isneg(d)) { + res = mp_add(d, c, d); + } + + return res; +} + +/* d = a + b (mod c) - a < c and b < c and positive */ +int mp_addmod_ct(mp_int* a, mp_int* b, mp_int* c, mp_int* d) +{ + int res; + + res = mp_add(a, b, d); + if (res == MP_OKAY && mp_cmp(d, c) != MP_LT) { + res = mp_sub(d, c, d); + } + + return res; +} + /* computes b = a*a */ int mp_sqr (mp_int * a, mp_int * b) { diff --git a/wolfcrypt/src/pkcs7.c b/wolfcrypt/src/pkcs7.c index e420cad37..aa0dd65c6 100644 --- a/wolfcrypt/src/pkcs7.c +++ b/wolfcrypt/src/pkcs7.c @@ -5531,7 +5531,7 @@ static int wc_PKCS7_KariGenerateSharedInfo(WC_PKCS7_KARI* kari, int keyWrapOID) /* create key encryption key (KEK) using key wrap algorithm and key encryption * algorithm, place in kari->kek. return 0 on success, <0 on error. */ -static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, +static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, WC_RNG* rng, int keyWrapOID, int keyEncOID) { int ret; @@ -5566,6 +5566,19 @@ static int wc_PKCS7_KariGenerateKEK(WC_PKCS7_KARI* kari, if (secret == NULL) return MEMORY_E; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(kari->senderKey, rng); + if (ret != 0) + return ret; + ret = wc_ecc_set_rng(kari->recipKey, rng); + if (ret != 0) + return ret; +#else + (void)rng; +#endif + if (kari->direction == WC_PKCS7_ENCODE) { ret = wc_ecc_shared_secret(kari->senderKey, kari->recipKey, @@ -5797,7 +5810,7 @@ int wc_PKCS7_AddRecipient_KARI(PKCS7* pkcs7, const byte* cert, word32 certSz, } /* generate KEK (key encryption key) */ - ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapOID, keyAgreeOID); + ret = wc_PKCS7_KariGenerateKEK(kari, pkcs7->rng, keyWrapOID, keyAgreeOID); if (ret != 0) { wc_PKCS7_KariFree(kari); #ifdef WOLFSSL_SMALL_STACK @@ -9397,7 +9410,8 @@ static int wc_PKCS7_DecryptKari(PKCS7* pkcs7, byte* in, word32 inSz, } else { /* create KEK */ - ret = wc_PKCS7_KariGenerateKEK(kari, keyWrapOID, pkcs7->keyAgreeOID); + ret = wc_PKCS7_KariGenerateKEK(kari, pkcs7->rng, keyWrapOID, + pkcs7->keyAgreeOID); if (ret != 0) { wc_PKCS7_KariFree(kari); #ifdef WOLFSSL_SMALL_STACK diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c index 5e6d74ef6..bf128174e 100644 --- a/wolfcrypt/src/tfm.c +++ b/wolfcrypt/src/tfm.c @@ -103,6 +103,26 @@ word32 CheckRunTimeFastMath(void) /* Functions */ +static int fp_cmp_mag_ct(fp_int *a, fp_int *b, int len) +{ + int i; + fp_digit r = FP_EQ; + fp_digit mask = (fp_digit)-1; + + for (i = len - 1; i >= 0; i--) { + /* 0 is placed into unused digits. */ + fp_digit ad = a->dp[i]; + fp_digit bd = b->dp[i]; + + r |= mask & (ad > bd); + mask &= (ad > bd) - 1; + r |= mask & (-(ad < bd)); + mask &= (ad < bd) - 1; + } + + return (int)r; +} + int fp_add(fp_int *a, fp_int *b, fp_int *c) { int sa, sb; @@ -639,7 +659,8 @@ int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d) } /* if a < b then q=0, r = a */ - if (fp_cmp_mag (a, b) == FP_LT) { + if (fp_cmp_mag (a, b) == FP_LT) + { if (d != NULL) { fp_copy (a, d); } @@ -878,6 +899,31 @@ void fp_div_2(fp_int * a, fp_int * b) fp_clamp (b); } +/* c = a / 2 (mod b) - constant time (a < b and positive) */ +int fp_div_2_mod_ct(fp_int *a, fp_int *b, fp_int *c) +{ + fp_word w = 0; + fp_digit mask; + int i; + + mask = 0 - (a->dp[0] & 1); + for (i = 0; i < b->used; i++) { + fp_digit mask_a = 0 - (i < a->used); + + w += b->dp[i] & mask; + w += a->dp[i] & mask_a; + c->dp[i] = (fp_digit)w; + w >>= DIGIT_BIT; + } + c->dp[i] = (fp_digit)w; + c->used = i + 1; + c->sign = FP_ZPOS; + fp_clamp(c); + fp_div_2(c, c); + + return FP_OKAY; +} + /* c = a / 2**b */ void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d) { @@ -1546,6 +1592,54 @@ int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d) return err; } +/* d = a - b (mod c) - constant time (a < c and b < c and positive) */ +int fp_submod_ct(fp_int *a, fp_int *b, fp_int *c, fp_int *d) +{ + fp_word w = 0; + fp_digit mask; + int i; + + mask = 0 - (fp_cmp_mag_ct(a, b, c->used + 1) == FP_LT); + for (i = 0; i < c->used + 1; i++) { + fp_digit mask_a = 0 - (i < a->used); + + w += c->dp[i] & mask; + w += a->dp[i] & mask_a; + d->dp[i] = (fp_digit)w; + w >>= DIGIT_BIT; + } + d->dp[i] = (fp_digit)w; + d->used = i + 1; + d->sign = FP_ZPOS; + fp_clamp(d); + s_fp_sub(d, b, d); + + return FP_OKAY; +} + +/* d = a + b (mod c) - constant time (|a| < c and |b| < c and positive) */ +int fp_addmod_ct(fp_int *a, fp_int *b, fp_int *c, fp_int *d) +{ + fp_word w = 0; + fp_digit mask; + int i; + + s_fp_add(a, b, d); + mask = 0 - (fp_cmp_mag_ct(d, c, c->used + 1) != FP_LT); + for (i = 0; i < c->used; i++) { + w += c->dp[i] & mask; + w = d->dp[i] - w; + d->dp[i] = (fp_digit)w; + w = (w >> DIGIT_BIT)&1; + } + d->dp[i] = 0; + d->used = i; + d->sign = a->sign; + fp_clamp(d); + + return FP_OKAY; +} + #ifdef TFM_TIMING_RESISTANT #ifdef WC_RSA_NONBLOCK @@ -2033,7 +2127,7 @@ static int _fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) fp_copy (&M[1], &M[(word32)(1 << (winsize - 1))]); for (x = 0; x < (winsize - 1); x++) { fp_sqr (&M[(word32)(1 << (winsize - 1))], &M[(word32)(1 << (winsize - 1))]); - err = fp_montgomery_reduce (&M[(word32)(1 << (winsize - 1))], P, mp); + err = fp_montgomery_reduce_ex(&M[(word32)(1 << (winsize - 1))], P, mp, 0); if (err != FP_OKAY) { #ifndef WOLFSSL_NO_MALLOC XFREE(M, NULL, DYNAMIC_TYPE_BIGINT); @@ -2051,7 +2145,7 @@ static int _fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) #endif return err; } - err = fp_montgomery_reduce(&M[x], P, mp); + err = fp_montgomery_reduce_ex(&M[x], P, mp, 0); if (err != FP_OKAY) { #ifndef WOLFSSL_NO_MALLOC XFREE(M, NULL, DYNAMIC_TYPE_BIGINT); @@ -2102,7 +2196,7 @@ static int _fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) #endif return err; } - fp_montgomery_reduce(res, P, mp); + fp_montgomery_reduce_ex(res, P, mp, 0); if (err != FP_OKAY) { #ifndef WOLFSSL_NO_MALLOC XFREE(M, NULL, DYNAMIC_TYPE_BIGINT); @@ -2127,7 +2221,7 @@ static int _fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) #endif return err; } - err = fp_montgomery_reduce(res, P, mp); + err = fp_montgomery_reduce_ex(res, P, mp, 0); if (err != FP_OKAY) { #ifndef WOLFSSL_NO_MALLOC XFREE(M, NULL, DYNAMIC_TYPE_BIGINT); @@ -2144,7 +2238,7 @@ static int _fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) #endif return err; } - err = fp_montgomery_reduce(res, P, mp); + err = fp_montgomery_reduce_ex(res, P, mp, 0); if (err != FP_OKAY) { #ifndef WOLFSSL_NO_MALLOC XFREE(M, NULL, DYNAMIC_TYPE_BIGINT); @@ -2170,7 +2264,7 @@ static int _fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) #endif return err; } - err = fp_montgomery_reduce(res, P, mp); + err = fp_montgomery_reduce_ex(res, P, mp, 0); if (err != FP_OKAY) { #ifndef WOLFSSL_NO_MALLOC XFREE(M, NULL, DYNAMIC_TYPE_BIGINT); @@ -2189,7 +2283,7 @@ static int _fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) #endif return err; } - err = fp_montgomery_reduce(res, P, mp); + err = fp_montgomery_reduce_ex(res, P, mp, 0); if (err != FP_OKAY) { #ifndef WOLFSSL_NO_MALLOC XFREE(M, NULL, DYNAMIC_TYPE_BIGINT); @@ -2206,7 +2300,7 @@ static int _fp_exptmod_nct(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) * to reduce one more time to cancel out the factor * of R. */ - err = fp_montgomery_reduce(res, P, mp); + err = fp_montgomery_reduce_ex(res, P, mp, 0); /* swap res with Y */ fp_copy (res, Y); @@ -3119,6 +3213,7 @@ int fp_cmp_mag(fp_int *a, fp_int *b) return FP_EQ; } + /* sets up the montgomery reduction */ int fp_montgomery_setup(fp_int *a, fp_digit *rho) { @@ -3198,7 +3293,7 @@ static WC_INLINE void innermul8_mulx(fp_digit *c_mulx, fp_digit *cy_mulx, fp_dig } /* computes x/R == x (mod N) via Montgomery Reduction */ -static int fp_montgomery_reduce_mulx(fp_int *a, fp_int *m, fp_digit mp) +static int fp_montgomery_reduce_mulx(fp_int *a, fp_int *m, fp_digit mp, int ct) { #ifndef WOLFSSL_SMALL_STACK fp_digit c[FP_SIZE+1]; @@ -3279,10 +3374,20 @@ static int fp_montgomery_reduce_mulx(fp_int *a, fp_int *m, fp_digit mp) a->used = pa+1; fp_clamp(a); +#ifdef WOLFSSL_MONT_RED_NCT /* if A >= m then A = A - m */ if (fp_cmp_mag (a, m) != FP_LT) { s_fp_sub (a, m, a); } + (void)ct; +#else + if (ct) { + fp_submod_ct(a, m, m, a); + } + else if (fp_cmp_mag (a, m) != FP_LT) { + s_fp_sub (a, m, a); + } +#endif #ifdef WOLFSSL_SMALL_STACK XFREE(c, NULL, DYNAMIC_TYPE_BIGINT); @@ -3292,7 +3397,7 @@ static int fp_montgomery_reduce_mulx(fp_int *a, fp_int *m, fp_digit mp) #endif /* computes x/R == x (mod N) via Montgomery Reduction */ -int fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) +int fp_montgomery_reduce_ex(fp_int *a, fp_int *m, fp_digit mp, int ct) { #ifndef WOLFSSL_SMALL_STACK fp_digit c[FP_SIZE+1]; @@ -3302,7 +3407,7 @@ int fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) fp_digit *_c, *tmpm, mu = 0; int oldused, x, y, pa, err = 0; - IF_HAVE_INTEL_MULX(err = fp_montgomery_reduce_mulx(a, m, mp), return err) ; + IF_HAVE_INTEL_MULX(err=fp_montgomery_reduce_mulx(a, m, mp, ct), return err) ; (void)err; /* bail if too large */ @@ -3330,7 +3435,16 @@ int fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) pa = m->used; /* copy the input */ +#ifdef TFM_TIMING_RESISTANT + if (a->used <= m->used) { + oldused = m->used; + } + else { + oldused = m->used * 2; + } +#else oldused = a->used; +#endif for (x = 0; x < oldused; x++) { c[x] = a->dp[x]; } @@ -3378,10 +3492,20 @@ int fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) a->used = pa+1; fp_clamp(a); +#ifndef WOLFSSL_MONT_RED_CT /* if A >= m then A = A - m */ if (fp_cmp_mag (a, m) != FP_LT) { s_fp_sub (a, m, a); } + (void)ct; +#else + if (ct) { + fp_submod_ct(a, m, m, a); + } + else if (fp_cmp_mag (a, m) != FP_LT) { + s_fp_sub (a, m, a); + } +#endif #ifdef WOLFSSL_SMALL_STACK XFREE(c, NULL, DYNAMIC_TYPE_BIGINT); @@ -3389,6 +3513,11 @@ int fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) return FP_OKAY; } +int fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) +{ + return fp_montgomery_reduce_ex(a, m, mp, 1); +} + int fp_read_unsigned_bin(fp_int *a, const unsigned char *b, int c) { #if defined(ALT_ECC_SIZE) || defined(HAVE_WOLF_BIGINT) @@ -4007,6 +4136,18 @@ int mp_addmod(mp_int *a, mp_int *b, mp_int *c, mp_int *d) return fp_addmod(a, b, c, d); } +/* d = a - b (mod c) - constant time (a < c and b < c) */ +int mp_submod_ct(mp_int *a, mp_int *b, mp_int *c, mp_int *d) +{ + return fp_submod_ct(a, b, c, d); +} + +/* d = a + b (mod c) - constant time (a < c and b < c) */ +int mp_addmod_ct(mp_int *a, mp_int *b, mp_int *c, mp_int *d) +{ + return fp_addmod_ct(a, b, c, d); +} + /* c = a mod b, 0 <= c < b */ #if defined(FREESCALE_LTC_TFM) int wolfcrypt_mp_mod (mp_int * a, mp_int * b, mp_int * c) @@ -5221,6 +5362,11 @@ int mp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) return fp_montgomery_reduce(a, m, mp); } +int mp_montgomery_reduce_ex(fp_int *a, fp_int *m, fp_digit mp, int ct) +{ + return fp_montgomery_reduce_ex(a, m, mp, ct); +} + /* fast math conversion */ int mp_montgomery_setup(fp_int *a, fp_digit *rho) @@ -5234,6 +5380,12 @@ int mp_div_2(fp_int * a, fp_int * b) return MP_OKAY; } +/* c = a / 2 (mod b) - constant time (a < b and positive) */ +int mp_div_2_mod_ct(mp_int *a, mp_int *b, mp_int *c) +{ + return fp_div_2_mod_ct(a, b, c); +} + int mp_init_copy(fp_int * a, fp_int * b) { diff --git a/wolfcrypt/test/test.c b/wolfcrypt/test/test.c index cf17af746..4ecd617b7 100644 --- a/wolfcrypt/test/test.c +++ b/wolfcrypt/test/test.c @@ -18260,7 +18260,7 @@ done: #endif #ifdef HAVE_ECC_CDH -static int ecc_test_cdh_vectors(void) +static int ecc_test_cdh_vectors(WC_RNG* rng) { int ret; ecc_key pub_key, priv_key; @@ -18292,6 +18292,16 @@ static int ecc_test_cdh_vectors(void) if (ret != 0) goto done; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&priv_key, rng); + if (ret != 0) + goto done; +#else + (void)rng; +#endif + /* compute ECC Cofactor shared secret */ x = sizeof(sharedA); do { @@ -18517,6 +18527,14 @@ static int ecc_test_make_pub(WC_RNG* rng) } TEST_SLEEP(); +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&key, rng); + if (ret != 0) + goto done; +#endif + x = sizeof(exportBuf); do { #if defined(WOLFSSL_ASYNC_CRYPT) @@ -18766,6 +18784,17 @@ static int ecc_test_curve_size(WC_RNG* rng, int keySize, int testVerifyCount, } #ifdef HAVE_ECC_DHE +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&userA, rng); + if (ret != 0) + goto done; + ret = wc_ecc_set_rng(&userB, rng); + if (ret != 0) + goto done; +#endif + x = ECC_SHARED_SIZE; do { #if defined(WOLFSSL_ASYNC_CRYPT) @@ -19528,7 +19557,7 @@ done: #endif #ifdef HAVE_ECC_DHE -static int ecc_ssh_test(ecc_key* key) +static int ecc_ssh_test(ecc_key* key, WC_RNG* rng) { int ret; byte out[128]; @@ -19548,6 +19577,16 @@ static int ecc_ssh_test(ecc_key* key) if (ret != BAD_FUNC_ARG) return -9747; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(key, rng); + if (ret != 0) + return -9748; +#else + (void)rng; +#endif + /* Use API. */ ret = 0; do { @@ -19558,7 +19597,7 @@ static int ecc_ssh_test(ecc_key* key) ret = wc_ecc_shared_secret_ssh(key, &key->pubkey, out, &outLen); } while (ret == WC_PENDING_E); if (ret != 0) - return -9748; + return -9749; TEST_SLEEP(); return 0; } @@ -19613,7 +19652,7 @@ static int ecc_def_curve_test(WC_RNG *rng) goto done; #endif #ifdef HAVE_ECC_DHE - ret = ecc_ssh_test(&key); + ret = ecc_ssh_test(&key, rng); if (ret < 0) goto done; #endif @@ -20667,7 +20706,7 @@ int ecc_test(void) } #endif #ifdef HAVE_ECC_CDH - ret = ecc_test_cdh_vectors(); + ret = ecc_test_cdh_vectors(&rng); if (ret != 0) { printf("ecc_test_cdh_vectors failed! %d\n", ret); goto done; @@ -20773,6 +20812,19 @@ int ecc_encrypt_test(void) for (i = 0; i < (int)sizeof(msg); i++) msg[i] = i; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&userA, &rng); + if (ret != 0) { + ret = -10011; goto done; + } + ret = wc_ecc_set_rng(&userB, &rng); + if (ret != 0) { + ret = -10012; goto done; + } +#endif + /* encrypt msg to B */ ret = wc_ecc_encrypt(&userA, &userB, msg, sizeof(msg), out, &outSz, NULL); if (ret != 0) { @@ -20923,6 +20975,15 @@ int ecc_test_buffers(void) { if (ret != 0) return -10015; +#if defined(ECC_TIMING_RESISTANT) && (!defined(HAVE_FIPS) || \ + (!defined(HAVE_FIPS_VERSION) || (HAVE_FIPS_VERSION < 2))) && \ + !defined(HAVE_SELFTEST) + ret = wc_ecc_set_rng(&cliKey, &rng); + if (ret != 0) { + return -10023; + } +#endif + #if defined(HAVE_ECC_ENCRYPT) && defined(HAVE_HKDF) { word32 y; @@ -24856,6 +24917,7 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, byte enveloped[2048]; byte decoded[2048]; PKCS7* pkcs7; + WC_RNG rng; #ifdef PKCS7_OUTPUT_TEST_BUNDLES XFILE pkcs7File; #endif @@ -25012,6 +25074,17 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, testSz = sizeof(testVectors) / sizeof(pkcs7EnvelopedVector); +#ifdef ECC_TIMING_RESISTANT +#ifndef HAVE_FIPS + ret = wc_InitRng_ex(&rng, HEAP_HINT, devId); +#else + ret = wc_InitRng(&rng); +#endif + if (ret != 0) { + return -11760; + } +#endif + for (i = 0; i < testSz; i++) { pkcs7 = wc_PKCS7_New(HEAP_HINT, #ifdef WOLFSSL_ASYNC_CRYPT @@ -25172,6 +25245,9 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, } } +#ifdef ECC_TIMING_RESISTANT + pkcs7->rng = &rng; +#endif /* encode envelopedData */ envelopedSz = wc_PKCS7_EncodeEnvelopedData(pkcs7, enveloped, sizeof(enveloped)); @@ -25233,6 +25309,10 @@ static int pkcs7enveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, pkcs7 = NULL; } +#ifdef ECC_TIMING_RESISTANT + wc_FreeRng(&rng); +#endif + (void)eccCert; (void)eccCertSz; (void)eccPrivKey; @@ -25633,8 +25713,6 @@ static int pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, wc_FreeRng(&rng); return -11806; } - - wc_FreeRng(&rng); } for (i = 0; i < testSz; i++) { @@ -25808,6 +25886,10 @@ static int pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, } } +#ifdef ECC_TIMING_RESISTANT + pkcs7->rng = &rng; +#endif + /* encode envelopedData */ envelopedSz = wc_PKCS7_EncodeAuthEnvelopedData(pkcs7, enveloped, sizeof(enveloped)); @@ -25869,6 +25951,8 @@ static int pkcs7authenveloped_run_vectors(byte* rsaCert, word32 rsaCertSz, pkcs7 = NULL; } + wc_FreeRng(&rng); + #if !defined(HAVE_ECC) || defined(NO_AES) (void)eccCert; (void)eccCertSz; diff --git a/wolfssl/test.h b/wolfssl/test.h index 50ba4a5fc..c3136894b 100644 --- a/wolfssl/test.h +++ b/wolfssl/test.h @@ -2673,6 +2673,13 @@ static WC_INLINE int myEccSharedSecret(WOLFSSL* ssl, ecc_key* otherKey, ret = BAD_FUNC_ARG; } +#if defined(ECC_TIMING_RESISTANT) && !defined(HAVE_FIPS) && \ + !defined(HAVE_SELFTEST) + if (ret == 0) { + ret = wc_ecc_set_rng(privKey, wolfSSL_GetRNG(ssl)); + } +#endif + /* generate shared secret and return it */ if (ret == 0) { ret = wc_ecc_shared_secret(privKey, pubKey, out, outlen); diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 930b96199..a63894bae 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -431,6 +431,9 @@ struct ecc_key { #ifdef WOLFSSL_DSP remote_handle64 handle; #endif +#ifdef ECC_TIMING_RESISTANT + WC_RNG* rng; +#endif #ifdef WC_ECC_NONBLOCK ecc_nb_ctx_t* nb_ctx; #endif @@ -476,6 +479,8 @@ int wc_ecc_make_key_ex(WC_RNG* rng, int keysize, ecc_key* key, int curve_id); WOLFSSL_API int wc_ecc_make_pub(ecc_key* key, ecc_point* pubOut); WOLFSSL_API +int wc_ecc_make_pub_ex(ecc_key* key, ecc_point* pubOut, WC_RNG* rng); +WOLFSSL_API int wc_ecc_check_key(ecc_key* key); WOLFSSL_API int wc_ecc_is_point(ecc_point* ecp, mp_int* a, mp_int* b, mp_int* prime); @@ -545,6 +550,10 @@ WOLFSSL_API void wc_ecc_fp_free(void); WOLFSSL_LOCAL void wc_ecc_fp_init(void); +#ifdef ECC_TIMING_RESISTANT +WOLFSSL_API +int wc_ecc_set_rng(ecc_key* key, WC_RNG* rng); +#endif WOLFSSL_API int wc_ecc_set_curve(ecc_key* key, int keysize, int curve_id); @@ -600,6 +609,10 @@ int wc_ecc_mulmod(mp_int* k, ecc_point *G, ecc_point *R, WOLFSSL_LOCAL int wc_ecc_mulmod_ex(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, mp_int* modulus, int map, void* heap); +WOLFSSL_LOCAL +int wc_ecc_mulmod_ex2(mp_int* k, ecc_point *G, ecc_point *R, mp_int* a, + mp_int* modulus, mp_int* order, WC_RNG* rng, int map, + void* heap); #endif /* !WOLFSSL_ATECC508A */ diff --git a/wolfssl/wolfcrypt/integer.h b/wolfssl/wolfcrypt/integer.h index 03ea908c3..2bd06ae2e 100644 --- a/wolfssl/wolfcrypt/integer.h +++ b/wolfssl/wolfcrypt/integer.h @@ -318,6 +318,7 @@ MP_API int mp_is_bit_set (mp_int * a, mp_digit b); MP_API int mp_mod (mp_int * a, mp_int * b, mp_int * c); MP_API int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d); MP_API int mp_div_2(mp_int * a, mp_int * b); +MP_API int mp_div_2_mod_ct (mp_int* a, mp_int* b, mp_int* c); MP_API int mp_add (mp_int * a, mp_int * b, mp_int * c); int s_mp_add (mp_int * a, mp_int * b, mp_int * c); int s_mp_sub (mp_int * a, mp_int * b, mp_int * c); @@ -332,6 +333,7 @@ MP_API int mp_exptmod_base_2 (mp_int * X, mp_int * P, mp_int * Y); MP_API int mp_montgomery_setup (mp_int * n, mp_digit * rho); int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho); MP_API int mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho); +#define mp_montgomery_reduce_ex(x, n, rho, ct) mp_montgomery_reduce (x, n, rho) MP_API void mp_dr_setup(mp_int *a, mp_digit *d); MP_API int mp_dr_reduce (mp_int * x, mp_int * n, mp_digit k); MP_API int mp_reduce_2k(mp_int *a, mp_int *n, mp_digit d); @@ -355,6 +357,8 @@ MP_API int mp_sqr (mp_int * a, mp_int * b); MP_API int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d); MP_API int mp_submod (mp_int* a, mp_int* b, mp_int* c, mp_int* d); MP_API int mp_addmod (mp_int* a, mp_int* b, mp_int* c, mp_int* d); +MP_API int mp_submod_ct (mp_int* a, mp_int* b, mp_int* c, mp_int* d); +MP_API int mp_addmod_ct (mp_int* a, mp_int* b, mp_int* c, mp_int* d); MP_API int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); MP_API int mp_2expt (mp_int * a, int b); MP_API int mp_set_bit (mp_int * a, int b); diff --git a/wolfssl/wolfcrypt/tfm.h b/wolfssl/wolfcrypt/tfm.h index 2f1324675..ae216fa3f 100644 --- a/wolfssl/wolfcrypt/tfm.h +++ b/wolfssl/wolfcrypt/tfm.h @@ -474,6 +474,9 @@ int fp_mul_2d(fp_int *a, int b, fp_int *c); void fp_2expt (fp_int *a, int b); int fp_mul_2(fp_int *a, fp_int *c); void fp_div_2(fp_int *a, fp_int *c); +/* c = a / 2 (mod b) - constant time (a < b and positive) */ +int fp_div_2_mod_ct(fp_int *a, fp_int *b, fp_int *c); + /* Counts the number of lsbs which are zero before the first zero bit */ int fp_cnt_lsb(fp_int *a); @@ -530,6 +533,12 @@ int fp_submod(fp_int *a, fp_int *b, fp_int *c, fp_int *d); /* d = a + b (mod c) */ int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d); +/* d = a - b (mod c) - constant time (a < c and b < c) */ +int fp_submod_ct(fp_int *a, fp_int *b, fp_int *c, fp_int *d); + +/* d = a + b (mod c) - constant time (a < c and b < c) */ +int fp_addmod_ct(fp_int *a, fp_int *b, fp_int *c, fp_int *d); + /* c = a * a (mod b) */ int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c); @@ -553,6 +562,7 @@ int fp_montgomery_calc_normalization(fp_int *a, fp_int *b); /* computes x/R == x (mod N) via Montgomery Reduction */ int fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp); +int fp_montgomery_reduce_ex(fp_int *a, fp_int *m, fp_digit mp, int ct); /* d = a**b (mod c) */ int fp_exptmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d); @@ -743,6 +753,8 @@ MP_API int mp_mul_d (mp_int * a, mp_digit b, mp_int * c); MP_API int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d); MP_API int mp_submod (mp_int* a, mp_int* b, mp_int* c, mp_int* d); MP_API int mp_addmod (mp_int* a, mp_int* b, mp_int* c, mp_int* d); +MP_API int mp_submod_ct (mp_int* a, mp_int* b, mp_int* c, mp_int* d); +MP_API int mp_addmod_ct (mp_int* a, mp_int* b, mp_int* c, mp_int* d); MP_API int mp_mod(mp_int *a, mp_int *b, mp_int *c); MP_API int mp_invmod(mp_int *a, mp_int *b, mp_int *c); MP_API int mp_invmod_mont_ct(mp_int *a, mp_int *b, mp_int *c, fp_digit mp); @@ -791,8 +803,11 @@ MP_API int mp_radix_size (mp_int * a, int radix, int *size); #ifdef HAVE_ECC MP_API int mp_sqr(fp_int *a, fp_int *b); MP_API int mp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp); + MP_API int mp_montgomery_reduce_ex(fp_int *a, fp_int *m, fp_digit mp, + int ct); MP_API int mp_montgomery_setup(fp_int *a, fp_digit *rho); MP_API int mp_div_2(fp_int * a, fp_int * b); + MP_API int mp_div_2_mod_ct(mp_int *a, mp_int *b, mp_int *c); MP_API int mp_init_copy(fp_int * a, fp_int * b); #endif