From 1de07da61f0c8e9926dcbd68119f73230dae283f Mon Sep 17 00:00:00 2001 From: Sean Parkinson Date: Wed, 18 Mar 2020 11:05:44 +1000 Subject: [PATCH] Constant time EC map to affine for private operations For fast math, use a constant time modular inverse when mapping to affine when operation involves a private key - key gen, calc shared secret, sign. --- wolfcrypt/src/ecc.c | 54 ++++++++++++++++++++++++----- wolfcrypt/src/tfm.c | 75 +++++++++++++++++++++++++++++++++++++++++ wolfssl/wolfcrypt/ecc.h | 1 + wolfssl/wolfcrypt/tfm.h | 2 ++ 4 files changed, 124 insertions(+), 8 deletions(-) diff --git a/wolfcrypt/src/ecc.c b/wolfcrypt/src/ecc.c index 31c4090fc..e5b76b297 100644 --- a/wolfcrypt/src/ecc.c +++ b/wolfcrypt/src/ecc.c @@ -2285,9 +2285,10 @@ int ecc_projective_dbl_point(ecc_point *P, ecc_point *R, mp_int* a, P [in/out] The point to map modulus The modulus of the field the ECC curve is in mp The "b" value from montgomery_setup() + ct Operation should be constant time. return MP_OKAY on success */ -int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp) +int ecc_map_ex(ecc_point* P, mp_int* modulus, mp_digit mp, int ct) { #ifndef WOLFSSL_SP_MATH #ifdef WOLFSSL_SMALL_STACK @@ -2307,6 +2308,8 @@ int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp) mp_int *x, *y, *z; int err; + (void)ct; + if (P == NULL || modulus == NULL) return ECC_BAD_ARG_E; @@ -2402,12 +2405,23 @@ int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp) z = P->z; #endif - /* first map z back to normal */ - err = mp_montgomery_reduce(z, modulus, mp); - /* get 1/z */ - if (err == MP_OKAY) - err = mp_invmod(z, modulus, t1); + if (err == MP_OKAY) { +#if defined(ECC_TIMING_RESISTANT) && defined(USE_FAST_MATH) + if (ct) { + err = mp_invmod_mont_ct(z, modulus, t1, mp); + if (err == MP_OKAY) + err = mp_montgomery_reduce(t1, modulus, mp); + } + else +#endif + { + /* first map z back to normal */ + err = mp_montgomery_reduce(z, modulus, mp); + if (err == MP_OKAY) + err = mp_invmod(z, modulus, t1); + } + } /* get 1/z^2 and 1/z^3 */ if (err == MP_OKAY) @@ -2484,6 +2498,10 @@ done: #endif } +int ecc_map(ecc_point* P, mp_int* modulus, mp_digit mp) +{ + return ecc_map_ex(P, modulus, mp, 0); +} #endif /* !WOLFSSL_SP_MATH || WOLFSSL_PUBLIC_ECC_ADD_DBL */ #if !defined(FREESCALE_LTC_ECC) && !defined(WOLFSSL_STM32_PKA) @@ -3639,6 +3657,8 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point, } #else { + mp_digit mp = 0; + /* make new point */ result = wc_ecc_new_point_h(private_key->heap); if (result == NULL) { @@ -3649,8 +3669,16 @@ static int wc_ecc_shared_secret_gen_sync(ecc_key* private_key, ecc_point* point, return MEMORY_E; } - err = wc_ecc_mulmod_ex(k, point, result, curve->Af, curve->prime, 1, + /* 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); + 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(result, curve->prime, mp, 1); + } if (err == MP_OKAY) { x = mp_unsigned_bin_size(curve->prime); if (*outlen < x || (int)x < mp_unsigned_bin_size(result->x)) { @@ -4008,6 +4036,8 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, err = WC_KEY_SIZE_E; #else { + mp_digit mp; + if (err == MP_OKAY) { base = wc_ecc_new_point_h(key->heap); if (base == NULL) @@ -4023,12 +4053,20 @@ static int wc_ecc_make_pub_ex(ecc_key* key, ecc_curve_spec* curveIn, /* 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, - 1, key->heap); + 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); + } wc_ecc_del_point_h(base, key->heap); } diff --git a/wolfcrypt/src/tfm.c b/wolfcrypt/src/tfm.c index 2fd96bdb2..be84dee25 100644 --- a/wolfcrypt/src/tfm.c +++ b/wolfcrypt/src/tfm.c @@ -1160,6 +1160,75 @@ top: return FP_OKAY; } +#define CT_INV_MOD_PRE_CNT 8 + +/* modulus (b) must be greater than 2 and a prime */ +int fp_invmod_mont_ct(fp_int *a, fp_int *b, fp_int *c, fp_digit mp) +{ + int i, j; +#ifndef WOLFSSL_SMALL_STACK + fp_int t[1], e[1]; + fp_int pre[CT_INV_MOD_PRE_CNT]; +#else + fp_int* t; + fp_int* e; + fp_int* pre; +#endif + +#ifdef WOLFSSL_SMALL_STACK + t = (fp_int*)XMALLOC(sizeof(fp_int) * (2 + CT_INV_MOD_PRE_CNT), NULL, + DYNAMIC_TYPE_BIGINT); + if (t == NULL) + return FP_MEM; + e = t + 1; + pre = t + 2; +#endif + + fp_init(t); + fp_init(e); + + fp_init(&pre[0]); + fp_copy(a, &pre[0]); + for (i = 1; i < CT_INV_MOD_PRE_CNT; i++) { + fp_init(&pre[i]); + fp_sqr(&pre[i-1], &pre[i]); + fp_montgomery_reduce(&pre[i], b, mp); + fp_mul(&pre[i], a, &pre[i]); + fp_montgomery_reduce(&pre[i], b, mp); + } + + fp_sub_d(b, 2, e); + /* Highest bit is always set. */ + for (i = fp_count_bits(e)-2, j = 1; i >= 0; i--, j++) { + if (!fp_is_bit_set(e, i) || j == CT_INV_MOD_PRE_CNT) + break; + } + fp_copy(&pre[j-1], t); + for (j = 0; i >= 0; i--) { + int set = fp_is_bit_set(e, i); + + if ((j == CT_INV_MOD_PRE_CNT) || (!set && j > 0)) { + fp_mul(t, &pre[j-1], t); + fp_montgomery_reduce(t, b, mp); + j = 0; + } + fp_sqr(t, t); + fp_montgomery_reduce(t, b, mp); + j += set; + } + if (j > 0) { + fp_mul(t, &pre[j-1], c); + fp_montgomery_reduce(c, b, mp); + } + else + fp_copy(t, c); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(t, NULL, DYNAMIC_TYPE_BIGINT); +#endif + return FP_OKAY; +} + /* d = a * b (mod c) */ int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d) { @@ -3545,6 +3614,12 @@ int mp_invmod (mp_int * a, mp_int * b, mp_int * c) return fp_invmod(a, b, c); } +/* hac 14.61, pp608 */ +int mp_invmod_mont_ct (mp_int * a, mp_int * b, mp_int * c, mp_digit mp) +{ + return fp_invmod_mont_ct(a, b, c, mp); +} + /* this is a shell function that calls either the normal or Montgomery * exptmod functions. Originally the call to the montgomery code was * embedded in the normal function but that wasted a lot of stack space diff --git a/wolfssl/wolfcrypt/ecc.h b/wolfssl/wolfcrypt/ecc.h index 8741a6d6a..cebba65c6 100644 --- a/wolfssl/wolfcrypt/ecc.h +++ b/wolfssl/wolfcrypt/ecc.h @@ -439,6 +439,7 @@ ECC_API int ecc_mul2add(ecc_point* A, mp_int* kA, ecc_point* C, mp_int* a, mp_int* modulus, void* heap); ECC_API int ecc_map(ecc_point*, mp_int*, mp_digit); +ECC_API int ecc_map_ex(ecc_point*, mp_int*, mp_digit, int ct); ECC_API int ecc_projective_add_point(ecc_point* P, ecc_point* Q, ecc_point* R, mp_int* a, mp_int* modulus, mp_digit mp); ECC_API int ecc_projective_dbl_point(ecc_point* P, ecc_point* R, mp_int* a, diff --git a/wolfssl/wolfcrypt/tfm.h b/wolfssl/wolfcrypt/tfm.h index 961472cff..e8b41248e 100644 --- a/wolfssl/wolfcrypt/tfm.h +++ b/wolfssl/wolfcrypt/tfm.h @@ -535,6 +535,7 @@ int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c); /* c = 1/a (mod b) */ int fp_invmod(fp_int *a, fp_int *b, fp_int *c); +int fp_invmod_mont_ct(fp_int *a, fp_int *b, fp_int *c, fp_digit mp); /* c = (a, b) */ /*int fp_gcd(fp_int *a, fp_int *b, fp_int *c);*/ @@ -743,6 +744,7 @@ 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_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); MP_API int mp_exptmod (mp_int * g, mp_int * x, mp_int * p, mp_int * y); MP_API int mp_exptmod_ex (mp_int * g, mp_int * x, int minDigits, mp_int * p, mp_int * y);