From 7b115fdf934da4e83185a1a0191eeec171c45fc8 Mon Sep 17 00:00:00 2001 From: Evgeni Margolis Date: Sun, 20 Sep 2015 22:47:39 -0700 Subject: [PATCH] Updated and generalized random number generation function (uECC_generate_random_int). This function is also used internally. In the new implementation when the random number is outside of the requested range it is corrected by subtraction instead of requesting new random number. --- uECC.c | 127 +++++++++++++++++++++++------------------------------ uECC_vli.h | 7 ++- 2 files changed, 60 insertions(+), 74 deletions(-) diff --git a/uECC.c b/uECC.c index 4d4ee8f..0173e84 100644 --- a/uECC.c +++ b/uECC.c @@ -4,7 +4,7 @@ #include "uECC_vli.h" #ifndef uECC_RNG_MAX_TRIES - #define uECC_RNG_MAX_TRIES 64 + #define uECC_RNG_MAX_TRIES 4 #endif #if uECC_SUPPORTS_secp160r1 @@ -789,15 +789,6 @@ static uECC_word_t EccPoint_compute_public_key(uECC_word_t *result, uECC_word_t *p2[2] = {tmp1, tmp2}; uECC_word_t carry; - /* Make sure the private key is in the range [1, n-1]. */ - if (uECC_vli_isZero(private, curve->num_words)) { - return 0; - } - - if (uECC_vli_cmp(curve->n, private, BITS_TO_WORDS(curve->num_n_bits)) != 1) { - 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(private, tmp1, tmp2, curve); @@ -853,19 +844,37 @@ uECC_VLI_API void uECC_vli_bytesToNative(uECC_word_t *native, #endif /* uECC_WORD_SIZE */ -/* Generate a random integer with num_bits bits. The remaining high bits - in the buffer (if any) are zeroed. */ -static cmpresult_t generate_random_int(uECC_word_t *random, - wordcount_t num_words, - wordcount_t num_bits) { - if (!g_rng_function || !g_rng_function((uint8_t *)random, num_words * uECC_WORD_SIZE)) { +/* Generates a random integer in the range 0 < random < top. + Both, random and top, have num_words words. */ +uECC_VLI_API int uECC_generate_random_int(uECC_word_t *random, + const uECC_word_t *top, + wordcount_t num_words) { + uECC_word_t random1[uECC_MAX_WORDS]; + uECC_word_t random2[uECC_MAX_WORDS]; + uECC_word_t *p2[2] = {random1, random2}; + uECC_word_t borrow; + uECC_word_t mask = (uECC_word_t)-1; + uECC_word_t tries; + bitcount_t num_bits = uECC_vli_numBits(top, num_words); + + if (!g_rng_function) { return 0; } - if (num_words * uECC_WORD_SIZE * 8 > num_bits) { - uECC_word_t mask = (uECC_word_t)-1; - random[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { + if (g_rng_function((uint8_t *)random1, num_words * uECC_WORD_SIZE)) { + + random1[num_words - 1] &= mask >> ((bitcount_t)(num_words * uECC_WORD_SIZE * 8 - num_bits)); + + borrow = uECC_vli_sub(random2, random1, top, num_words); + + if (!uECC_vli_isZero(p2[!borrow], num_words)) { + uECC_vli_set(random, p2[!borrow], num_words); + return 1; + } + } } - return 1; + return 0; } int uECC_make_key(uint8_t *public_key, @@ -874,9 +883,9 @@ int uECC_make_key(uint8_t *public_key, uECC_word_t private[uECC_MAX_WORDS]; uECC_word_t public[uECC_MAX_WORDS * 2]; uECC_word_t tries; - + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!generate_random_int(private, BITS_TO_WORDS(curve->num_n_bits), curve->num_n_bits)) { + if (!uECC_generate_random_int(private, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { return 0; } @@ -900,14 +909,13 @@ int uECC_shared_secret(const uint8_t *public_key, uECC_word_t tmp[uECC_MAX_WORDS]; uECC_word_t *p2[2] = {private, tmp}; uECC_word_t *initial_Z = 0; - uECC_word_t tries; uECC_word_t carry; wordcount_t num_words = curve->num_words; + wordcount_t num_bytes = curve->num_bytes; uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); - uECC_vli_bytesToNative(public, public_key, curve->num_bytes); - uECC_vli_bytesToNative( - public + num_words, public_key + curve->num_bytes, curve->num_bytes); + uECC_vli_bytesToNative(public, public_key, num_bytes); + uECC_vli_bytesToNative(public + num_words, 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. */ @@ -916,21 +924,14 @@ int uECC_shared_secret(const uint8_t *public_key, /* 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) { - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!generate_random_int(p2[carry], num_words, curve->num_bytes * 8)) { - return 0; - } - - if (!uECC_vli_isZero(p2[carry], num_words) && - uECC_vli_cmp(curve->p, p2[carry], num_words) == 1) { - initial_Z = p2[carry]; - break; - } + if (!uECC_generate_random_int(p2[carry], curve->p, num_words)) { + return 0; } + initial_Z = p2[carry]; } EccPoint_mult(public, public, p2[!carry], initial_Z, curve->num_n_bits + 1, curve); - uECC_vli_nativeToBytes(secret, curve->num_bytes, public); + uECC_vli_nativeToBytes(secret, num_bytes, public); return !EccPoint_isZero(public, curve); } @@ -997,6 +998,16 @@ int uECC_compute_public_key(const uint8_t *private_key, uint8_t *public_key, uEC uECC_vli_bytesToNative(private, private_key, BITS_TO_BYTES(curve->num_n_bits)); + /* Make sure the private key is in the range [1, n-1]. */ + if (uECC_vli_isZero(private, BITS_TO_WORDS(curve->num_n_bits))) { + return 0; + } + + if (uECC_vli_cmp(curve->n, private, BITS_TO_WORDS(curve->num_n_bits)) != 1) { + return 0; + } + + /* Compute public key. */ if (!EccPoint_compute_public_key(public, private, curve)) { return 0; } @@ -1065,25 +1076,17 @@ static int uECC_sign_with_k(const uint8_t *private_key, return 0; } - /* Attempt to get a random number to prevent side channel analysis of k. */ + /* If an RNG function was specified, get a random number + to prevent side channel analysis of k. */ if (!g_rng_function) { uECC_vli_clear(tmp, num_n_words); tmp[0] = 1; } else { - uECC_word_t tries; - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!generate_random_int(tmp, num_n_words, num_n_bits)) { - return 0; - } - - if (!uECC_vli_isZero(tmp, num_n_words) && - uECC_vli_cmp(curve->n, tmp, num_n_words) == 1) { - goto got_random; - } + if (!uECC_generate_random_int(tmp, curve->n, num_n_words)) { + return 0; } - return 0; } -got_random: + /* Prevent side channel analysis of uECC_vli_modInv() to determine bits of k / the private key by premultiplying by a random number */ uECC_vli_modMult(k, k, tmp, curve->n, num_n_words); /* k' = rand * k */ @@ -1114,11 +1117,9 @@ int uECC_sign(const uint8_t *private_key, uECC_Curve curve) { uECC_word_t k[uECC_MAX_WORDS]; uECC_word_t tries; - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; - + for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!generate_random_int(k, num_n_words, num_n_bits)) { + if (!uECC_generate_random_int(k, curve->n, BITS_TO_WORDS(curve->num_n_bits))) { return 0; } @@ -1418,22 +1419,4 @@ void uECC_point_mult(uECC_word_t *result, EccPoint_mult(result, point, p2[!carry], 0, curve->num_n_bits + 1, curve); } -int uECC_generate_random_int(uECC_word_t *random, uECC_Curve curve) { - wordcount_t num_n_words = BITS_TO_WORDS(curve->num_n_bits); - bitcount_t num_n_bits = curve->num_n_bits; - uECC_word_t tries; - - for (tries = 0; tries < uECC_RNG_MAX_TRIES; ++tries) { - if (!generate_random_int(random, num_n_words, num_n_bits)) { - return 0; - } - - if (!uECC_vli_isZero(random, num_n_words) && - uECC_vli_cmp(curve->n, random, num_n_words) == 1) { - return 1; - } - } - return 0; -} - #endif /* uECC_ENABLE_VLI_API */ diff --git a/uECC_vli.h b/uECC_vli.h index 55bb385..1168d99 100644 --- a/uECC_vli.h +++ b/uECC_vli.h @@ -155,8 +155,11 @@ void uECC_point_mult(uECC_word_t *result, const uECC_word_t *scalar, uECC_Curve curve); -/* Generates a random integer r in the range 0 < r < curve->n */ -int uECC_generate_random_int(uECC_word_t *random, uECC_Curve curve); +/* Generates a random integer in the range 0 < random < top. + Both, random and top, have num_words words. */ +int uECC_generate_random_int(uECC_word_t *random, + const uECC_word_t *top, + wordcount_t num_words); #endif /* uECC_ENABLE_VLI_API */