Merge pull request #6512 from SparkiDev/math_enc_mem_exptmod

Math, Encrypted Memory: mod exp fix
This commit is contained in:
David Garske
2023-06-15 19:52:41 -07:00
committed by GitHub
2 changed files with 441 additions and 0 deletions

View File

@ -5104,6 +5104,51 @@ int sp_copy(const sp_int* a, sp_int* r)
}
#endif
#if ((defined(WOLFSSL_SP_MATH_ALL) && ((!defined(WOLFSSL_RSA_VERIFY_ONLY) && \
!defined(WOLFSSL_RSA_PUBLIC_ONLY)) || !defined(NO_DH))) || \
defined(OPENSSL_ALL)) && defined(WC_PROTECT_ENCRYPTED_MEM)
/* Copy 2 numbers into two results based on y. Copy a fixed number of digits.
*
* Constant time implementation.
* When y is 0, r1 = a2 and r2 = a1.
* When y is 1, r1 = a1 and r2 = a2.
*
* @param [in] a1 First number to copy.
* @param [in] a2 Second number to copy.
* @param [out] r1 First result number to copy into.
* @param [out] r2 Second result number to copy into.
* @param [in] y Indicates which number goes into which result number.
* @param [in] used Number of digits to copy.
*/
static void _sp_copy_2_ct(const sp_int* a1, const sp_int* a2, sp_int* r1,
sp_int* r2, int y, unsigned int used)
{
unsigned int i;
/* Copy data - constant time. */
for (i = 0; i < used; i++) {
r1->dp[i] = (a1->dp[i] & ((sp_digit)wc_off_on_addr[y ])) +
(a2->dp[i] & ((sp_digit)wc_off_on_addr[y^1]));
r2->dp[i] = (a1->dp[i] & ((sp_digit)wc_off_on_addr[y^1])) +
(a2->dp[i] & ((sp_digit)wc_off_on_addr[y ]));
}
/* Copy used. */
r1->used = (a1->used & ((int)wc_off_on_addr[y ])) +
(a2->used & ((int)wc_off_on_addr[y^1]));
r2->used = (a1->used & ((int)wc_off_on_addr[y^1])) +
(a2->used & ((int)wc_off_on_addr[y ]));
#ifdef WOLFSSL_SP_INT_NEGATIVE
/* Copy sign. */
r1->sign = (a1->sign & ((int)wc_off_on_addr[y ])) +
(a2->sign & ((int)wc_off_on_addr[y^1]));
r2->sign = (a1->sign & ((int)wc_off_on_addr[y^1])) +
(a2->sign & ((int)wc_off_on_addr[y ]));
#endif
}
#endif
#if defined(WOLFSSL_SP_MATH_ALL) || (defined(HAVE_ECC) && defined(FP_ECC))
/* Initializes r and copies in value from a.
*
@ -12483,6 +12528,9 @@ int sp_invmod_mont_ct(const sp_int* a, const sp_int* m, sp_int* r,
#if (defined(WOLFSSL_SP_MATH_ALL) && !defined(WOLFSSL_RSA_VERIFY_ONLY) && \
!defined(WOLFSSL_RSA_PUBLIC_ONLY)) || !defined(NO_DH) || \
defined(OPENSSL_ALL)
#ifndef WC_PROTECT_ENCRYPTED_MEM
/* Internal. Exponentiates b to the power of e modulo m into r: r = b ^ e mod m
* Process the exponent one bit at a time.
* Is constant time and can be cache attack resistant.
@ -12614,6 +12662,105 @@ static int _sp_exptmod_ex(const sp_int* b, const sp_int* e, int bits,
FREE_SP_INT_ARRAY(t, NULL);
return err;
}
#else
/* Internal. Exponentiates b to the power of e modulo m into r: r = b ^ e mod m
* Process the exponent one bit at a time with base in Montgomery form.
* Is constant time and cache attack resistant.
*
* Based on work by Marc Joye, Sung-Ming Yen, "The Montgomery Powering Ladder",
* Cryptographic Hardware and Embedded Systems, CHES 2002
*
* Algorithm:
* b: base, e: exponent, m: modulus, r: result, bits: #bits to use
* 1. t[1] = b mod m.
* 2. t[0] = 1
* 3. For i in (bits-1)...0
* 3.1. y = e[i]
* 3.2. t[2] = t[0] * t[1]
* 3.3. t[3] = t[y] ^ 2
* 3.4. t[y] = t[3], t[y^1] = t[2]
* 4. r = t[0]
*
* @param [in] b SP integer that is the base.
* @param [in] e SP integer that is the exponent.
* @param [in] bits Number of bits in exponent to use. May be greater than
* count of bits in e.
* @param [in] m SP integer that is the modulus.
* @param [out] r SP integer to hold result.
*
* @return MP_OKAY on success.
* @return MP_MEM when dynamic memory allocation fails.
*/
static int _sp_exptmod_ex(const sp_int* b, const sp_int* e, int bits,
const sp_int* m, sp_int* r)
{
int err = MP_OKAY;
int done = 0;
DECL_SP_INT_ARRAY(t, m->used * 2 + 1, 4);
/* Allocate temporaries. */
ALLOC_SP_INT_ARRAY(t, m->used * 2 + 1, 4, err, NULL);
if (err == MP_OKAY) {
/* Initialize temporaries. */
_sp_init_size(t[0], m->used * 2 + 1);
_sp_init_size(t[1], m->used * 2 + 1);
_sp_init_size(t[2], m->used * 2 + 1);
_sp_init_size(t[3], m->used * 2 + 1);
/* 1. Ensure base is less than modulus. */
if (_sp_cmp_abs(b, m) != MP_LT) {
err = sp_mod(b, m, t[1]);
/* Handle base == modulus. */
if ((err == MP_OKAY) && sp_iszero(t[1])) {
_sp_set(r, 0);
done = 1;
}
}
else {
/* Copy base into working variable. */
err = sp_copy(b, t[1]);
}
}
if ((!done) && (err == MP_OKAY)) {
int i;
/* 2. t[0] = 1 */
_sp_set(t[0], 1);
/* 3. For i in (bits-1)...0 */
for (i = bits - 1; (err == MP_OKAY) && (i >= 0); i--) {
/* 3.1. y = e[i] */
int y = (e->dp[i >> SP_WORD_SHIFT] >> (i & SP_WORD_MASK)) & 1;
/* 3.2. t[2] = t[0] * t[1] */
err = sp_mulmod(t[0], t[1], m, t[2]);
/* 3.3. t[3] = t[y] ^ 2 */
if (err == MP_OKAY) {
_sp_copy((sp_int*)(((size_t)t[0] & sp_off_on_addr[y^1]) +
((size_t)t[1] & sp_off_on_addr[y ])),
t[3]);
err = sp_sqrmod(t[3], m, t[3]);
}
/* 3.4. t[y] = t[3], t[y^1] = t[2] */
if (err == MP_OKAY) {
_sp_copy_2_ct(t[2], t[3], t[0], t[1], y, m->used);
}
}
}
if ((!done) && (err == MP_OKAY)) {
/* 4. r = t[0] */
err = sp_copy(t[0], r);
}
FREE_SP_INT_ARRAY(t, NULL);
return err;
}
#endif /* WC_PROTECT_ENCRYPTED_MEM */
#endif
#if (defined(WOLFSSL_SP_MATH_ALL) && ((!defined(WOLFSSL_RSA_VERIFY_ONLY) && \
@ -12621,6 +12768,9 @@ static int _sp_exptmod_ex(const sp_int* b, const sp_int* e, int bits,
defined(OPENSSL_ALL)
#ifndef WC_NO_HARDEN
#if !defined(WC_NO_CACHE_RESISTANT)
#ifndef WC_PROTECT_ENCRYPTED_MEM
/* Internal. Exponentiates b to the power of e modulo m into r: r = b ^ e mod m
* Process the exponent one bit at a time with base in Montgomery form.
* Is constant time and cache attack resistant.
@ -12759,6 +12909,130 @@ static int _sp_exptmod_mont_ex(const sp_int* b, const sp_int* e, int bits,
FREE_SP_INT_ARRAY(t, NULL);
return err;
}
#else
/* Internal. Exponentiates b to the power of e modulo m into r: r = b ^ e mod m
* Process the exponent one bit at a time with base in Montgomery form.
* Is constant time and cache attack resistant.
*
* Based on work by Marc Joye, Sung-Ming Yen, "The Montgomery Powering Ladder",
* Cryptographic Hardware and Embedded Systems, CHES 2002
*
* Algorithm:
* b: base, e: exponent, m: modulus, r: result, bits: #bits to use
* 1. t[1] = b mod m.
* 2. t[0] = ToMont(1)
* 3. t[1] = ToMont(t[1])
* 4. For i in (bits-1)...0
* 4.1. y = e[i]
* 4.2. t[2] = t[0] * t[1]
* 4.3. t[3] = t[y] ^ 2
* 4.4. t[y] = t[3], t[y^1] = t[2]
* 5. t[0] = FromMont(t[0])
* 6. r = t[0]
*
* @param [in] b SP integer that is the base.
* @param [in] e SP integer that is the exponent.
* @param [in] bits Number of bits in exponent to use. May be greater than
* count of bits in e.
* @param [in] m SP integer that is the modulus.
* @param [out] r SP integer to hold result.
*
* @return MP_OKAY on success.
* @return MP_MEM when dynamic memory allocation fails.
*/
static int _sp_exptmod_mont_ex(const sp_int* b, const sp_int* e, int bits,
const sp_int* m, sp_int* r)
{
int err = MP_OKAY;
int done = 0;
DECL_SP_INT_ARRAY(t, m->used * 2 + 1, 4);
/* Allocate temporaries. */
ALLOC_SP_INT_ARRAY(t, m->used * 2 + 1, 4, err, NULL);
if (err == MP_OKAY) {
/* Initialize temporaries. */
_sp_init_size(t[0], m->used * 2 + 1);
_sp_init_size(t[1], m->used * 2 + 1);
_sp_init_size(t[2], m->used * 2 + 1);
_sp_init_size(t[3], m->used * 2 + 1);
/* 1. Ensure base is less than modulus. */
if (_sp_cmp_abs(b, m) != MP_LT) {
err = sp_mod(b, m, t[1]);
/* Handle base == modulus. */
if ((err == MP_OKAY) && sp_iszero(t[1])) {
_sp_set(r, 0);
done = 1;
}
}
else {
/* Copy base into working variable. */
err = sp_copy(b, t[1]);
}
}
if ((!done) && (err == MP_OKAY)) {
int i;
sp_int_digit mp;
/* Calculate Montgomery multiplier for reduction. */
_sp_mont_setup(m, &mp);
/* 2. t[0] = ToMont(1)
* Calculate 1 in Montgomery form.
*/
err = sp_mont_norm(t[0], m);
if (err == MP_OKAY) {
/* 3. t[1] = ToMont(t[1])
* Convert base to Montgomery form.
*/
err = sp_mulmod(t[1], t[0], m, t[1]);
}
/* 4. For i in (bits-1)...0 */
for (i = bits - 1; (err == MP_OKAY) && (i >= 0); i--) {
/* 4.1. y = e[i] */
int y = (e->dp[i >> SP_WORD_SHIFT] >> (i & SP_WORD_MASK)) & 1;
/* 4.2. t[2] = t[0] * t[1] */
err = sp_mul(t[0], t[1], t[2]);
if (err == MP_OKAY) {
err = _sp_mont_red(t[2], m, mp);
}
/* 4.3. t[3] = t[y] ^ 2 */
if (err == MP_OKAY) {
_sp_copy((sp_int*)(((size_t)t[0] & sp_off_on_addr[y^1]) +
((size_t)t[1] & sp_off_on_addr[y ])),
t[3]);
err = sp_sqr(t[3], t[3]);
}
if (err == MP_OKAY) {
err = _sp_mont_red(t[3], m, mp);
}
/* 4.4. t[y] = t[3], t[y^1] = t[2] */
if (err == MP_OKAY) {
_sp_copy_2_ct(t[2], t[3], t[0], t[1], y, m->used);
}
}
if (err == MP_OKAY) {
/* 5. t[0] = FromMont(t[0]) */
err = _sp_mont_red(t[0], m, mp);
/* Reduction implementation returns number to range: 0..m-1. */
}
}
if ((!done) && (err == MP_OKAY)) {
/* 6. r = t[0] */
err = sp_copy(t[0], r);
}
FREE_SP_INT_ARRAY(t, NULL);
return err;
}
#endif /* WC_PROTECT_ENCRYPTED_MEM */
#else
#ifdef SP_ALLOC

View File

@ -1977,6 +1977,8 @@ int fp_exptmod_nb(exptModNb_t* nb, fp_int* G, fp_int* X, fp_int* P, fp_int* Y)
#endif /* WC_RSA_NONBLOCK */
#ifndef WC_PROTECT_ENCRYPTED_MEM
/* timing resistant montgomery ladder based exptmod
Based on work by Marc Joye, Sung-Ming Yen, "The Montgomery Powering Ladder",
Cryptographic Hardware and Embedded Systems, CHES 2002
@ -2159,6 +2161,171 @@ static int _fp_exptmod_ct(fp_int * G, fp_int * X, int digits, fp_int * P,
return err;
}
#else
/* Copy from a1 and a2 into r1 and r2 based on y in constant time.
* When y is 1, r1 = a1 and r2 = a2.
* When y is 0, r1 = a2 and r2 = a1.
* Always copy size digits as that is the maximum size for a1 and a2.
*/
static void fp_copy_2_ct(fp_int* a1, fp_int* a2, fp_int* r1, fp_int* r2, int y,
int size)
{
int i;
/* Copy data - constant time. */
for (i = 0; i < size; i++) {
r1->dp[i] = (a1->dp[i] & ((fp_digit)wc_off_on_addr[y ])) +
(a2->dp[i] & ((fp_digit)wc_off_on_addr[y^1]));
r2->dp[i] = (a1->dp[i] & ((fp_digit)wc_off_on_addr[y^1])) +
(a2->dp[i] & ((fp_digit)wc_off_on_addr[y ]));
}
/* Copy used. */
r1->used = (a1->used & ((int)wc_off_on_addr[y ])) +
(a2->used & ((int)wc_off_on_addr[y^1]));
r2->used = (a1->used & ((int)wc_off_on_addr[y^1])) +
(a2->used & ((int)wc_off_on_addr[y ]));
/* Copy sign. */
r1->sign = (a1->sign & ((int)wc_off_on_addr[y ])) +
(a2->sign & ((int)wc_off_on_addr[y^1]));
r2->sign = (a1->sign & ((int)wc_off_on_addr[y^1])) +
(a2->sign & ((int)wc_off_on_addr[y ]));
}
/* timing resistant montgomery ladder based exptmod
Based on work by Marc Joye, Sung-Ming Yen, "The Montgomery Powering Ladder",
Cryptographic Hardware and Embedded Systems, CHES 2002
*/
static int _fp_exptmod_ct(fp_int * G, fp_int * X, int digits, fp_int * P,
fp_int * Y)
{
#ifndef WOLFSSL_SMALL_STACK
fp_int R[4]; /* need a temp for cache resistance */
#else
fp_int *R;
#endif
fp_digit buf, mp;
int err, bitcnt, digidx, y;
/* now setup montgomery */
if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) {
return err;
}
#ifdef WOLFSSL_SMALL_STACK
R = (fp_int*)XMALLOC(sizeof(fp_int) * 4, NULL, DYNAMIC_TYPE_BIGINT);
if (R == NULL)
return FP_MEM;
#endif
fp_init(&R[0]);
fp_init(&R[1]);
fp_init(&R[2]);
fp_init(&R[3]);
/* now we need R mod m */
err = fp_montgomery_calc_normalization (&R[0], P);
if (err != FP_OKAY) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(R, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
/* now set R[0][1] to G * R mod m */
if (fp_cmp_mag(P, G) != FP_GT) {
/* G > P so we reduce it first */
err = fp_mod(G, P, &R[1]);
if (err != FP_OKAY) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(R, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
} else {
fp_copy(G, &R[1]);
}
err = fp_mulmod (&R[1], &R[0], P, &R[1]);
if (err != FP_OKAY) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(R, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
/* for j = t-1 downto 0 do
r_!k = R0*R1; r_k = r_k^2
*/
/* set initial mode and bit cnt */
bitcnt = 1;
buf = 0;
digidx = digits - 1;
for (;;) {
/* grab next digit as required */
if (--bitcnt == 0) {
/* if digidx == -1 we are out of digits so break */
if (digidx == -1) {
break;
}
/* read next digit and reset bitcnt */
buf = X->dp[digidx--];
bitcnt = (int)DIGIT_BIT;
}
/* grab the next msb from the exponent */
y = (int)(buf >> (DIGIT_BIT - 1)) & 1;
buf <<= (fp_digit)1;
/* do ops */
err = fp_mul(&R[0], &R[1], &R[2]);
if (err != FP_OKAY) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(R, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
err = fp_montgomery_reduce(&R[2], P, mp);
if (err != FP_OKAY) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(R, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
/* instead of using R[y] for sqr, which leaks key bit to cache monitor,
* use R[3] as temp, make sure address calc is constant, keep
* &R[0] and &R[1] in cache */
fp_copy((fp_int*) ( ((wc_ptr_t)&R[0] & wc_off_on_addr[y^1]) +
((wc_ptr_t)&R[1] & wc_off_on_addr[y]) ),
&R[3]);
err = fp_sqr(&R[3], &R[3]);
if (err != FP_OKAY) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(R, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
err = fp_montgomery_reduce(&R[3], P, mp);
if (err != FP_OKAY) {
#ifdef WOLFSSL_SMALL_STACK
XFREE(R, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
fp_copy_2_ct(&R[2], &R[3], &R[0], &R[1], y, P->used);
}
err = fp_montgomery_reduce(&R[0], P, mp);
fp_copy(&R[0], Y);
#ifdef WOLFSSL_SMALL_STACK
XFREE(R, NULL, DYNAMIC_TYPE_BIGINT);
#endif
return err;
}
#endif /* WC_PROTECT_ENCRYPTED_MEM */
#endif /* TFM_TIMING_RESISTANT */
/* y = g**x (mod b)