ECC: better protection when using encrypted memory

Added new ECC scalar multiplication implementation.
This commit is contained in:
Sean Parkinson
2021-12-16 08:49:54 +10:00
parent bd7e19b8fe
commit 0b2b218de7

View File

@ -87,6 +87,11 @@ Possible ECC enable options:
* the variant macro is used the bits2octets operation on
* the hash is removed.
* default: off
*
* WC_PROTECT_ENCRYPTED_MEM:
* Enables implementations that protect data that is in
* encrypted memory.
* default: off
*/
/*
@ -2762,6 +2767,7 @@ static int wc_ecc_gen_z(WC_RNG* rng, int size, ecc_point* p,
return err;
}
#ifndef WC_PROTECT_ENCRYPTED_MEM
#define M_POINTS 3
/* Joye double-add ladder.
@ -2925,6 +2931,183 @@ static int ecc_mulmod(const mp_int* k, ecc_point* P, ecc_point* Q,
return err;
}
#else
/* Number of points to allocate for use during scalar multiplication. */
#define M_POINTS 5
/* Last of the points is used as a temporary during calculations. */
#define TMP_IDX M_POINTS - 1
static void mp_cond_swap_into_ct(mp_int* ra, mp_int* rb, mp_int* a, mp_int* b,
int digits, int m)
{
int i;
#if !defined(WOLFSSL_SP_MATH_ALL) || defined(WOLFSSL_SP_INT_NEGATIVE)
/* Only using positive numbers in ECC operations. */
ra->sign = 0;
rb->sign = 0;
#endif
/* Don't store 0 when mask is 0, it will be in a register. */
ra->used = (int)(((a->used ^ b->used) & ((mp_digit)0 - (m & 1))) ^ a->used);
rb->used = (int)(((a->used ^ b->used) & ((mp_digit)0 - (m & 1))) ^ b->used);
for (i = 0; i < digits; i++) {
ra->dp[i] = ((a->dp[i] ^ b->dp[i]) & ((mp_digit)0 - (m & 1))) ^
a->dp[i];
rb->dp[i] = ((a->dp[i] ^ b->dp[i]) & ((mp_digit)0 - (m & 1))) ^
b->dp[i];
}
}
static void ecc_cond_swap_into_ct(ecc_point* ra, ecc_point* rb, ecc_point* a,
ecc_point* b, int digits, int m)
{
/* Conditionally swap each ordinate. */
mp_cond_swap_into_ct(ra->x, rb->x, a->x, b->x, digits, m);
mp_cond_swap_into_ct(ra->y, rb->y, a->y, b->y, digits, m);
mp_cond_swap_into_ct(ra->z, rb->z, a->z, b->z, digits, m);
}
/* Joye double-add ladder.
* "Highly Regular Right-to-Left Algorithms for Scalar Multiplication"
* by Marc Joye (2007)
*
* Algorithm 1':
* Input: P element of curve, k = (k[t-1],..., k[0]) base 2
* Output: Q = kP
* 1: R[0] = P; R[1] = P
* 2: for j = 1 to t-1 do
* 3: b = 1 - k[j]; R[b] = 2*R[b] + R[k[j]]
* 4: end for
* 5: b = k[0]; R[b] = R[b] - P
* 6: return R[0]
*
* Assumes: k < order.
*/
static int ecc_mulmod(const mp_int* k, ecc_point* P, ecc_point* Q,
ecc_point** R, mp_int* a, mp_int* modulus, mp_digit mp, WC_RNG* rng)
{
int err = MP_OKAY;
int bytes = (mp_count_bits(modulus) + 7) / 8;
int i;
int j = 1;
int cnt;
int t = 0;
mp_int* kt = R[TMP_IDX]->x;
/* First bit always 1 (fix at end) and swap equals first bit */
register int swap = 1;
/* Which pair of points has current value. R[0,1] or R[2,3] */
int set = 0;
int infinity;
/* Step 1: R[0] = P; R[1] = P */
/* R[0] = P */
if (err == MP_OKAY)
err = mp_copy(P->x, R[0]->x);
if (err == MP_OKAY)
err = mp_copy(P->y, R[0]->y);
if (err == MP_OKAY)
err = mp_copy(P->z, R[0]->z);
/* R[1] = P */
if (err == MP_OKAY)
err = mp_copy(P->x, R[1]->x);
if (err == MP_OKAY)
err = mp_copy(P->y, R[1]->y);
if (err == MP_OKAY)
err = mp_copy(P->z, R[1]->z);
/* Randomize z ordinates to obfuscate timing. */
if ((err == MP_OKAY) && (rng != NULL))
err = wc_ecc_gen_z(rng, bytes, R[0], modulus, mp, R[TMP_IDX]->x,
R[TMP_IDX]->y);
if ((err == MP_OKAY) && (rng != NULL))
err = wc_ecc_gen_z(rng, bytes, R[1], modulus, mp, R[TMP_IDX]->x,
R[TMP_IDX]->y);
if (err == MP_OKAY) {
/* Order could be one greater than the size of the modulus. */
t = mp_count_bits(modulus) + 1;
err = mp_copy(k, kt);
}
if (err == MP_OKAY) {
err = mp_grow(kt, modulus->used + 1);
}
/* Step 2: for j = 1 to t-1 do */
for (i = 1, j = 0, cnt = 0; (err == MP_OKAY) && (i < t); i++) {
if (++cnt == DIGIT_BIT) {
j++;
cnt = 0;
}
/* Step 3: b = 1 - k[j]; R[b] = 2*R[b] + R[k[j]] */
/* Swap R[0] and R[1] if other index is needed. */
/* Ensure 'swap' changes when shifted word is 0. */
swap += (kt->dp[j] >> cnt) + 2;
ecc_cond_swap_into_ct(R[(2 - set) + 0], R[(2 - set) + 1],
R[set + 0], R[set + 1], modulus->used, swap);
/* Change to operate on set copied into. */
set = 2 - set;
/* Ensure 'swap' changes to a previously unseen value. */
swap += (kt->dp[j] >> cnt) + swap;
err = ecc_projective_dbl_point_safe(R[set + 0], R[set + 0], a, modulus,
mp);
if (err == MP_OKAY) {
err = ecc_projective_add_point_safe(R[set + 0], R[set + 1],
R[set + 0], a, modulus, mp, &infinity);
}
}
/* Step 4: end for */
/* Swap back if last bit is 0. */
/* Ensure 'swap' changes. */
swap += 1;
if (err == MP_OKAY) {
ecc_cond_swap_into_ct(R[(2 - set) + 0], R[(2 - set) + 1],
R[set + 0], R[set + 1], modulus->used, swap);
set = 2 - set;
}
/* Step 5: b = k[0]; R[b] = R[b] - P */
/* R[TMP_IDX] = -P */
if (err == MP_OKAY)
err = mp_copy(P->x, R[TMP_IDX]->x);
if (err == MP_OKAY)
err = mp_sub(modulus, P->y, R[TMP_IDX]->y);
if (err == MP_OKAY)
err = mp_copy(P->z, R[TMP_IDX]->z);
/* Subtract point by adding negative. */
if (err == MP_OKAY) {
/* Swap R[0] and R[1], if necessary, to operate on the one we want.
* Last bit of k->dp[0] is being used to make decision to swap.
*/
ecc_cond_swap_into_ct(R[(2 - set) + 0], R[(2 - set) + 1],
R[set + 0], R[set + 1], modulus->used,
(int)k->dp[0]);
set = 2 - set;
err = ecc_projective_add_point_safe(R[set + 0], R[TMP_IDX], R[set + 0],
a, modulus, mp, &infinity);
/* Swap back if necessary. */
if (err == MP_OKAY) {
ecc_cond_swap_into_ct(R[(2 - set) + 0], R[(2 - set) + 1],
R[set + 0], R[set + 1], modulus->used,
(int)k->dp[0]);
set = 2 - set;
}
}
/* Step 6: return R[0] */
if (err == MP_OKAY)
err = mp_copy(R[set + 0]->x, Q->x);
if (err == MP_OKAY)
err = mp_copy(R[set + 0]->y, Q->y);
if (err == MP_OKAY)
err = mp_copy(R[set + 0]->z, Q->z);
return err;
}
#endif
#endif
/* Convert the point to montgomery form.