From ef238283d55fff7b4ae8601013596f5639a56988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 4 Nov 2019 11:19:30 +0100 Subject: [PATCH] Add ECCPoint_mult_safer() function This avoids the need for each calling site to manually regularize the scalar and randomize coordinates, which makes for simpler safe use and saves 50 bytes of code size in the library. --- include/tinycrypt/ecc.h | 14 ++++++++++++++ tinycrypt/ecc.c | 41 ++++++++++++++++++++++++++++++++++++++++- tinycrypt/ecc_dh.c | 32 +++----------------------------- tinycrypt/ecc_dsa.c | 23 ++++------------------- 4 files changed, 61 insertions(+), 49 deletions(-) diff --git a/include/tinycrypt/ecc.h b/include/tinycrypt/ecc.h index 9c53f3e7e..3996cd4b2 100644 --- a/include/tinycrypt/ecc.h +++ b/include/tinycrypt/ecc.h @@ -309,6 +309,20 @@ void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, const uECC_word_t * scalar, const uECC_word_t * initial_Z, bitcount_t num_bits, uECC_Curve curve); +/* + * @brief Point multiplication algorithm using Montgomery's ladder with co-Z + * coordinates. See http://eprint.iacr.org/2011/338.pdf. + * Uses scalar regularization and coordinate randomization (if a global RNG + * function is set) in order to protect against some side channel attacks. + * @note Result may overlap point. + * @param result OUT -- returns scalar*point + * @param point IN -- elliptic curve point + * @param scalar IN -- scalar + * @param curve IN -- elliptic curve + */ +int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point, + const uECC_word_t * scalar, uECC_Curve curve); + /* * @brief Constant-time comparison to zero - secure way to compare long integers * @param vli IN -- very long integer diff --git a/tinycrypt/ecc.c b/tinycrypt/ecc.c index f7a6f0665..91bec5604 100644 --- a/tinycrypt/ecc.c +++ b/tinycrypt/ecc.c @@ -65,6 +65,7 @@ #if defined(MBEDTLS_USE_TINYCRYPT) #include +#include "mbedtls/platform_util.h" #include /* IMPORTANT: Make sure a cryptographically-secure PRNG is set and the platform @@ -873,7 +874,7 @@ static void XYcZ_addC_rnd(uECC_word_t * X1, uECC_word_t * Y1, void EccPoint_mult(uECC_word_t * result, const uECC_word_t * point, const uECC_word_t * scalar, const uECC_word_t * initial_Z, - bitcount_t num_bits, uECC_Curve curve) + bitcount_t num_bits, uECC_Curve curve) { /* R0 and R1 */ uECC_word_t Rx[2][NUM_ECC_WORDS]; @@ -936,6 +937,44 @@ uECC_word_t regularize_k(const uECC_word_t * const k, uECC_word_t *k0, return carry; } +int EccPoint_mult_safer(uECC_word_t * result, const uECC_word_t * point, + const uECC_word_t * scalar, uECC_Curve curve) +{ + uECC_word_t tmp[NUM_ECC_WORDS]; + uECC_word_t s[NUM_ECC_WORDS]; + uECC_word_t *k2[2] = {tmp, s}; + wordcount_t num_words = curve->num_words; + bitcount_t num_n_bits = curve->num_n_bits; + uECC_word_t carry; + uECC_word_t *initial_Z = 0; + int r; + + /* Regularize the bitcount for the private key so that attackers cannot use a + * side channel attack to learn the number of leading zeros. */ + carry = regularize_k(scalar, tmp, s, curve); + + /* If an RNG function was specified, get a random initial Z value to + * protect against side-channel attacks such as Template SPA */ + if (g_rng_function) { + if (!uECC_generate_random_int(k2[carry], curve->p, num_words)) { + r = 0; + goto clear_and_out; + } + initial_Z = k2[carry]; + } + + EccPoint_mult(result, point, k2[!carry], initial_Z, num_n_bits + 1, curve); + r = 1; + +clear_and_out: + /* erasing temporary buffer used to store secret: */ + mbedtls_platform_zeroize(k2, sizeof(k2)); + mbedtls_platform_zeroize(tmp, sizeof(tmp)); + mbedtls_platform_zeroize(s, sizeof(s)); + + return r; +} + uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, uECC_word_t *private_key, uECC_Curve curve) diff --git a/tinycrypt/ecc_dh.c b/tinycrypt/ecc_dh.c index 853c50dca..52208ad9d 100644 --- a/tinycrypt/ecc_dh.c +++ b/tinycrypt/ecc_dh.c @@ -72,12 +72,6 @@ #include #include "mbedtls/platform_util.h" -#if default_RNG_defined -static uECC_RNG_Function g_rng_function = &default_CSPRNG; -#else -static uECC_RNG_Function g_rng_function = 0; -#endif - int uECC_make_key_with_d(uint8_t *public_key, uint8_t *private_key, unsigned int *d, uECC_Curve curve) { @@ -160,11 +154,6 @@ int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, uECC_word_t _public[NUM_ECC_WORDS * 2]; uECC_word_t _private[NUM_ECC_WORDS]; - - uECC_word_t tmp[NUM_ECC_WORDS]; - uECC_word_t *p2[2] = {_private, tmp}; - uECC_word_t *initial_Z = 0; - uECC_word_t carry; wordcount_t num_words = curve->num_words; wordcount_t num_bytes = curve->num_bytes; int r; @@ -186,30 +175,15 @@ int uECC_shared_secret(const uint8_t *public_key, const uint8_t *private_key, public_key + num_bytes, num_bytes); - /* Regularize the bitcount for the private key so that attackers cannot use a - * side channel attack to learn the number of leading zeros. */ - carry = regularize_k(_private, _private, tmp, curve); - - /* If an RNG function was specified, try to get a random initial Z value to - * improve protection against side-channel attacks. */ - if (g_rng_function) { - if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { - r = 0; - goto clear_and_out; - } - initial_Z = p2[carry]; - } - - EccPoint_mult(_public, _public, p2[!carry], initial_Z, curve->num_n_bits + 1, - curve); + r = EccPoint_mult_safer(_public, _public, _private, curve); + if (r == 0) + goto clear_and_out; uECC_vli_nativeToBytes(secret, num_bytes, _public); r = !EccPoint_isZero(_public, curve); clear_and_out: /* erasing temporary buffer used to store secret: */ - mbedtls_platform_zeroize(p2, sizeof(p2)); - mbedtls_platform_zeroize(tmp, sizeof(tmp)); mbedtls_platform_zeroize(_private, sizeof(_private)); return r; diff --git a/tinycrypt/ecc_dsa.c b/tinycrypt/ecc_dsa.c index e8c0e0b2b..8462860c6 100644 --- a/tinycrypt/ecc_dsa.c +++ b/tinycrypt/ecc_dsa.c @@ -114,13 +114,11 @@ int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, uECC_word_t tmp[NUM_ECC_WORDS]; uECC_word_t s[NUM_ECC_WORDS]; - uECC_word_t *k2[2] = {tmp, s}; uECC_word_t p[NUM_ECC_WORDS * 2]; - uECC_word_t *initial_Z = 0; - uECC_word_t carry; wordcount_t num_words = curve->num_words; wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; + int r; + /* Make sure 0 < k < curve_n */ if (uECC_vli_isZero(k, num_words) || @@ -128,21 +126,8 @@ int uECC_sign_with_k(const uint8_t *private_key, const uint8_t *message_hash, return 0; } - /* Regularize the bitcount for the private key so that attackers cannot use a - * side channel attack to learn the number of leading zeros. */ - carry = regularize_k(k, tmp, s, curve); - - /* If an RNG function was specified, get a random initial Z value to - * protect against side-channel attacks such as Template SPA */ - if (g_rng_function) { - if (!uECC_generate_random_int(k2[carry], curve->p, num_words)) { - return 0; - } - initial_Z = k2[carry]; - } - - EccPoint_mult(p, curve->G, k2[!carry], initial_Z, num_n_bits + 1, curve); - if (uECC_vli_isZero(p, num_words)) { + r = EccPoint_mult_safer(p, curve->G, k, curve); + if (r == 0 || uECC_vli_isZero(p, num_words)) { return 0; }