ECC: generate values in range of order by rejection

When generating private key and nonce for ECDSA, use rejection sampling.
Note: SP uses this algorithm
This commit is contained in:
Sean Parkinson
2023-11-30 11:37:01 +10:00
parent 6125e595bb
commit 21f53f37a1
7 changed files with 217 additions and 18 deletions

View File

@ -92,6 +92,12 @@ Possible ECC enable options:
* Enables implementations that protect data that is in
* encrypted memory.
* default: off
* WOLFSSL_ECC_GEN_REJECT_SAMPLING
* Enables generation of scalar (private key and ECDSA
* nonce) to be performed using reject sampling algorithm.
* Use this when CPU state can be closely observered by
* attacker.
* default: off
*/
/*
@ -5135,6 +5141,7 @@ int wc_ecc_point_is_at_infinity(ecc_point* p)
int wc_ecc_gen_k(WC_RNG* rng, int size, mp_int* k, mp_int* order)
{
#ifndef WC_NO_RNG
#ifndef WOLFSSL_ECC_GEN_REJECT_SAMPLING
int err;
byte buf[ECC_MAXSIZE_GEN];
@ -5176,6 +5183,54 @@ int wc_ecc_gen_k(WC_RNG* rng, int size, mp_int* k, mp_int* order)
#endif
return err;
#else
int err;
byte buf[ECC_MAXSIZE_GEN];
int bits;
if ((rng == NULL) || (size < 0) || (size + 8 > ECC_MAXSIZE_GEN) ||
(k == NULL) || (order == NULL)) {
return BAD_FUNC_ARG;
}
/* Get actual bit count of order. */
bits = mp_count_bits(order);
size = (bits + 7) >> 3;
/* generate number in range of order through rejection sampling. */
/* see section A.2.2 and A.4.2 in FIPS 186-5 */
do {
/* A.2.2 step 3: make up random string */
err = wc_RNG_GenerateBlock(rng, buf, (word32)size);
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Add("wc_ecc_gen_k buf", buf, size);
#endif
/* Generated multiple of 8 bits but now make it size of order. */
if ((bits & 0x7) > 0) {
buf[0] &= (1 << (bits & 0x7)) - 1;
}
/* A.2.2 step 4: convert to integer. */
/* A.4.2 step 3: Convert the bit string to integer x. */
if (err == 0) {
err = mp_read_unsigned_bin(k, buf, (word32)size);
}
/* A.4.2 step 4, 5: x must be in range [1, n-1] */
if ((err == MP_OKAY) && !mp_iszero(k) &&
(mp_cmp_ct(k, order, order->used) == MP_LT)) {
break;
}
}
while (err == MP_OKAY);
ForceZero(buf, ECC_MAXSIZE_GEN);
#ifdef WOLFSSL_CHECK_MEM_ZERO
wc_MemZero_Check(buf, ECC_MAXSIZE_GEN);
#endif
return err;
#endif
#else
(void)rng;
(void)size;

View File

@ -4780,7 +4780,7 @@ static void _sp_mont_setup(const sp_int* m, sp_int_digit* rho);
/* Determine when mp_add_d is required. */
#if !defined(NO_PWDBASED) || defined(WOLFSSL_KEY_GEN) || !defined(NO_DH) || \
!defined(NO_DSA) || (defined(HAVE_ECC) && defined(HAVE_COMP_KEY)) || \
!defined(NO_DSA) || defined(HAVE_ECC) || \
(!defined(NO_RSA) && !defined(WOLFSSL_RSA_VERIFY_ONLY)) || \
defined(OPENSSL_EXTRA)
#define WOLFSSL_SP_ADD_D
@ -5327,8 +5327,8 @@ int sp_abs(const sp_int* a, sp_int* r)
(!defined(NO_RSA) && !defined(WOLFSSL_RSA_VERIFY_ONLY))
/* Compare absolute value of two multi-precision numbers.
*
* @param [in] a SP integer.
* @param [in] b SP integer.
* @param [in] a SP integer.
* @param [in] b SP integer.
*
* @return MP_GT when a is greater than b.
* @return MP_LT when a is less than b.
@ -5373,8 +5373,8 @@ static int _sp_cmp_abs(const sp_int* a, const sp_int* b)
*
* Pointers are compared such that NULL is less than not NULL.
*
* @param [in] a SP integer.
* @param [in] b SP integer.
* @param [in] a SP integer.
* @param [in] b SP integer.
*
* @return MP_GT when a is greater than b.
* @return MP_LT when a is less than b.
@ -5413,8 +5413,8 @@ int sp_cmp_mag(const sp_int* a, const sp_int* b)
*
* Assumes a and b are not NULL.
*
* @param [in] a SP integer.
* @param [in] a SP integer.
* @param [in] a SP integer.
* @param [in] b SP integer.
*
* @return MP_GT when a is greater than b.
* @return MP_LT when a is less than b.
@ -5457,8 +5457,8 @@ static int _sp_cmp(const sp_int* a, const sp_int* b)
*
* Pointers are compared such that NULL is less than not NULL.
*
* @param [in] a SP integer.
* @param [in] a SP integer.
* @param [in] a SP integer.
* @param [in] b SP integer.
*
* @return MP_GT when a is greater than b.
* @return MP_LT when a is less than b.
@ -5490,6 +5490,80 @@ int sp_cmp(const sp_int* a, const sp_int* b)
}
#endif
#if defined(HAVE_ECC) && !defined(WC_NO_RNG) && \
defined(WOLFSSL_ECC_GEN_REJECT_SAMPLING)
/* Compare two multi-precision numbers in constant time.
*
* Assumes a and b are not NULL.
* Assumes a and b are positive.
*
* @param [in] a SP integer.
* @param [in] b SP integer.
* @param [in] n Number of digits to compare.
*
* @return MP_GT when a is greater than b.
* @return MP_LT when a is less than b.
* @return MP_EQ when a is equals b.
*/
static int _sp_cmp_ct(const sp_int* a, const sp_int* b, unsigned int n)
{
int ret = MP_EQ;
int i;
int mask = -1;
for (i = n - 1; i >= 0; i--) {
sp_int_digit ad = a->dp[i] & ((sp_int_digit)0 - (i < (int)a->used));
sp_int_digit bd = b->dp[i] & ((sp_int_digit)0 - (i < (int)b->used));
ret |= mask & ((0 - (ad < bd)) & MP_LT);
mask &= 0 - (ret == MP_EQ);
ret |= mask & ((0 - (ad > bd)) & MP_GT);
mask &= 0 - (ret == MP_EQ);
}
return ret;
}
/* Compare two multi-precision numbers in constant time.
*
* Pointers are compared such that NULL is less than not NULL.
* Assumes a and b are positive.
* Assumes a and b have n digits set at sometime.
*
* @param [in] a SP integer.
* @param [in] b SP integer.
* @param [in] n Number of digits to compare.
*
* @return MP_GT when a is greater than b.
* @return MP_LT when a is less than b.
* @return MP_EQ when a is equals b.
*/
int sp_cmp_ct(const sp_int* a, const sp_int* b, unsigned int n)
{
int ret;
/* Check pointers first. Both NULL returns equal. */
if (a == b) {
ret = MP_EQ;
}
/* Nothing is smaller than something. */
else if (a == NULL) {
ret = MP_LT;
}
/* Something is larger than nothing. */
else if (b == NULL) {
ret = MP_GT;
}
else
{
/* Compare values - a and b are not NULL. */
ret = _sp_cmp_ct(a, b, n);
}
return ret;
}
#endif /* HAVE_ECC && !WC_NO_RNG && WOLFSSL_ECC_GEN_REJECT_SAMPLING */
/*************************
* Bit check/set functions
*************************/
@ -7673,10 +7747,6 @@ int sp_submod(const sp_int* a, const sp_int* b, const sp_int* m, sp_int* r)
}
#endif /* WOLFSSL_SP_MATH_ALL */
#if (defined(WOLFSSL_SP_MATH_ALL) && defined(HAVE_ECC)) || \
(defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_HAVE_SP_DH) || \
defined(WOLFCRYPT_HAVE_ECCSI) || defined(WOLFCRYPT_HAVE_SAKKE) || \
defined(OPENSSL_ALL))
/* Constant time clamping/
*
* @param [in, out] a SP integer to clamp.
@ -7693,7 +7763,6 @@ static void sp_clamp_ct(sp_int* a)
}
a->used = used;
}
#endif
#if defined(WOLFSSL_SP_MATH_ALL) && defined(HAVE_ECC)
/* Add two value and reduce: r = (a + b) % m
@ -14362,7 +14431,8 @@ int sp_div_2d(const sp_int* a, int e, sp_int* r, sp_int* rem)
}
#endif /* WOLFSSL_SP_MATH_ALL && !WOLFSSL_RSA_VERIFY_ONLY */
#if defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_VERIFY_ONLY)
#if (defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_VERIFY_ONLY)) || \
defined(HAVE_ECC)
/* The bottom e bits: r = a & ((1 << e) - 1)
*
* @param [in] a SP integer to reduce.
@ -14432,7 +14502,7 @@ int sp_mod_2d(const sp_int* a, int e, sp_int* r)
return err;
}
#endif /* WOLFSSL_SP_MATH_ALL && !WOLFSSL_RSA_VERIFY_ONLY */
#endif /* (WOLFSSL_SP_MATH_ALL && !WOLFSSL_RSA_VERIFY_ONLY)) || HAVE_ECC */
#if (defined(WOLFSSL_SP_MATH_ALL) && (!defined(WOLFSSL_RSA_VERIFY_ONLY) || \
!defined(NO_DH))) || defined(OPENSSL_ALL)
@ -17771,7 +17841,7 @@ int sp_read_unsigned_bin(sp_int* a, const byte* in, word32 inSz)
#endif /* LITTLE_ENDIAN_ORDER */
}
#endif
sp_clamp(a);
sp_clamp_ct(a);
}
return err;

View File

@ -4859,6 +4859,12 @@ int mp_div_2d(fp_int* a, int b, fp_int* c, fp_int* d)
return MP_OKAY;
}
int mp_mod_2d(fp_int* a, int b, fp_int* c)
{
fp_mod_2d(a, b, c);
return MP_OKAY;
}
/* copy (src = a) to (dst = b) */
void fp_copy(const fp_int *a, fp_int *b)
{

View File

@ -46040,6 +46040,67 @@ static wc_test_ret_t mp_test_cmp(mp_int* a, mp_int* b)
return WC_TEST_RET_ENC_NC;
#endif
#if defined(HAVE_ECC) && !defined(WC_NO_RNG) && \
defined(WOLFSSL_ECC_GEN_REJECT_SAMPLING)
mp_zero(a);
mp_zero(b);
ret = mp_cmp_ct(a, b, 1);
if (ret != MP_EQ)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_cmp_ct(a, a, a->used);
if (ret != MP_EQ)
return WC_TEST_RET_ENC_EC(ret);
#ifdef WOLFSSL_SP_MATH_ALL
ret = mp_cmp_ct(a, NULL, a->used);
if (ret != MP_GT)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_cmp_ct(NULL, a, a->used);
if (ret != MP_LT)
return WC_TEST_RET_ENC_EC(ret);
#endif
mp_read_radix(a, "1", MP_RADIX_HEX);
ret = mp_cmp_ct(a, b, 1);
if (ret != MP_GT)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_cmp_ct(b, a, 1);
if (ret != MP_LT)
return WC_TEST_RET_ENC_EC(ret);
mp_read_radix(a, "0123456789abcdef0123456789abcdef", MP_RADIX_HEX);
ret = mp_cmp_ct(a, b, a->used);
if (ret != MP_GT)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_cmp_ct(b, a, a->used);
if (ret != MP_LT)
return WC_TEST_RET_ENC_EC(ret);
mp_read_radix(b, "1123456789abcdef0123456789abcdef", MP_RADIX_HEX);
ret = mp_cmp_ct(b, a, a->used);
if (ret != MP_GT)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_cmp_ct(a, b, a->used);
if (ret != MP_LT)
return WC_TEST_RET_ENC_EC(ret);
mp_read_radix(b, "0123456789abcdef0123456789abcdf0", MP_RADIX_HEX);
ret = mp_cmp_ct(b, a, a->used);
if (ret != MP_GT)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_cmp_ct(a, b, a->used);
if (ret != MP_LT)
return WC_TEST_RET_ENC_EC(ret);
mp_read_radix(b, "0123456789abcdf0", MP_RADIX_HEX);
ret = mp_cmp_ct(a, b, a->used);
if (ret != MP_GT)
return WC_TEST_RET_ENC_EC(ret);
ret = mp_cmp_ct(b, a, a->used);
if (ret != MP_LT)
return WC_TEST_RET_ENC_EC(ret);
#endif
return 0;
}

View File

@ -344,6 +344,7 @@ int fast_mp_invmod (mp_int * a, mp_int * b, mp_int * c);
MP_API int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c);
MP_API int mp_cmp_mag (mp_int * a, mp_int * b);
MP_API int mp_cmp (mp_int * a, mp_int * b);
#define mp_cmp_ct(a, b, n) mp_cmp(a, b)
MP_API int mp_cmp_d(mp_int * a, mp_digit b);
MP_API int mp_set (mp_int * a, mp_digit b);
MP_API int mp_is_bit_set (mp_int * a, mp_digit b);

View File

@ -945,6 +945,7 @@ MP_API int sp_abs(const sp_int* a, sp_int* r);
MP_API int sp_cmp_mag(const sp_int* a, const sp_int* b);
#endif
MP_API int sp_cmp(const sp_int* a, const sp_int* b);
MP_API int sp_cmp_ct(const sp_int* a, const sp_int* b, unsigned int n);
MP_API int sp_is_bit_set(const sp_int* a, unsigned int b);
MP_API int sp_count_bits(const sp_int* a);
@ -1030,9 +1031,11 @@ MP_API int sp_exptmod_nct(const sp_int* b, const sp_int* e, const sp_int* m,
#if defined(WOLFSSL_SP_MATH_ALL) || defined(OPENSSL_ALL)
MP_API int sp_div_2d(const sp_int* a, int e, sp_int* r, sp_int* rem);
MP_API int sp_mod_2d(const sp_int* a, int e, sp_int* r);
MP_API int sp_mul_2d(const sp_int* a, int e, sp_int* r);
#endif
#if defined(WOLFSSL_SP_MATH_ALL) || defined(HAVE_ECC) || defined(OPENSSL_ALL)
MP_API int sp_mod_2d(const sp_int* a, int e, sp_int* r);
#endif
MP_API int sp_sqr(const sp_int* a, sp_int* r);
MP_API int sp_sqrmod(const sp_int* a, const sp_int* m, sp_int* r);
@ -1119,6 +1122,7 @@ WOLFSSL_LOCAL void sp_memzero_check(sp_int* sp);
#define mp_cond_swap_ct_ex sp_cond_swap_ct_ex
#define mp_cmp_mag sp_cmp_mag
#define mp_cmp sp_cmp
#define mp_cmp_ct sp_cmp_ct
#define mp_count_bits sp_count_bits
#define mp_cnt_lsb sp_cnt_lsb
#define mp_leading_bit sp_leading_bit

View File

@ -838,6 +838,7 @@ MP_API int mp_2expt(mp_int* a, int b);
MP_API int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
MP_API int mp_cmp(mp_int *a, mp_int *b);
#define mp_cmp_ct(a, b, n) mp_cmp(a, b)
MP_API int mp_cmp_d(mp_int *a, mp_digit b);
MP_API int mp_unsigned_bin_size(const mp_int * a);
@ -908,6 +909,7 @@ MP_API int mp_cond_swap_ct(mp_int* a, mp_int* b, int c, int m);
MP_API int mp_cnt_lsb(fp_int *a);
MP_API int mp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d);
MP_API int mp_mod_2d(fp_int *a, int b, fp_int *c);
MP_API int mp_mod_d(fp_int* a, fp_digit b, fp_digit* c);
MP_API int mp_lshd (mp_int * a, int b);
MP_API int mp_abs(mp_int* a, mp_int* b);