Skip to content
Snippets Groups Projects
Commit 4c5a4472 authored by Simo Sorce's avatar Simo Sorce Committed by Niels Möller
Browse files

Use side-channel silent root for rsa signatures


Signed-off-by: default avatarSimo Sorce <simo@redhat.com>
parent f7350548
No related branches found
No related tags found
No related merge requests found
...@@ -36,8 +36,15 @@ ...@@ -36,8 +36,15 @@
# include "config.h" # include "config.h"
#endif #endif
#include <assert.h>
#include "gmp-glue.h"
#include "rsa.h" #include "rsa.h"
#include "rsa-internal.h"
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#if NETTLE_USE_MINI_GMP
/* Blinds m, by computing c = m r^e (mod n), for a random r. Also /* Blinds m, by computing c = m r^e (mod n), for a random r. Also
returns the inverse (ri), for use by rsa_unblind. */ returns the inverse (ri), for use by rsa_unblind. */
static void static void
...@@ -118,3 +125,248 @@ rsa_compute_root_tr(const struct rsa_public_key *pub, ...@@ -118,3 +125,248 @@ rsa_compute_root_tr(const struct rsa_public_key *pub,
return res; return res;
} }
int
rsa_sec_compute_root_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
mp_limb_t *x, const mp_limb_t *m, size_t mn)
{
mpz_t mz;
mpz_t xz;
int res;
mpz_init(mz);
mpz_init(xz);
mpn_copyi(mpz_limbs_write(mz, mn), m, mn);
mpz_limbs_finish(mz, mn);
res = rsa_compute_root_tr(pub, key, random_ctx, random, xz, mz);
if (res)
mpz_limbs_copy(x, xz, mpz_size(pub->n));
mpz_clear(mz);
mpz_clear(xz);
return res;
}
#else
/* Blinds m, by computing c = m r^e (mod n), for a random r. Also
returns the inverse (ri), for use by rsa_unblind. */
static void
rsa_sec_blind (const struct rsa_public_key *pub,
void *random_ctx, nettle_random_func *random,
mp_limb_t *c, mp_limb_t *ri, const mp_limb_t *m,
mp_size_t mn)
{
const mp_limb_t *ep = mpz_limbs_read (pub->e);
const mp_limb_t *np = mpz_limbs_read (pub->n);
mp_bitcnt_t ebn = mpz_sizeinbase (pub->e, 2);
mp_size_t nn = mpz_size (pub->n);
size_t itch;
size_t i2;
mp_limb_t *scratch;
TMP_GMP_DECL (tp, mp_limb_t);
TMP_GMP_DECL (rp, mp_limb_t);
TMP_GMP_DECL (r, uint8_t);
TMP_GMP_ALLOC (rp, nn);
TMP_GMP_ALLOC (r, nn * sizeof(mp_limb_t));
/* c = m*(r^e) mod n */
itch = mpn_sec_powm_itch(nn, ebn, nn);
i2 = mpn_sec_mul_itch(nn, mn);
itch = MAX(itch, i2);
i2 = mpn_sec_div_r_itch(nn + mn, nn);
itch = MAX(itch, i2);
i2 = mpn_sec_invert_itch(nn);
itch = MAX(itch, i2);
TMP_GMP_ALLOC (tp, nn + mn + itch);
scratch = tp + nn + mn;
/* ri = r^(-1) */
do
{
random(random_ctx, nn * sizeof(mp_limb_t), (uint8_t *)r);
mpn_set_base256(rp, nn, r, nn * sizeof(mp_limb_t));
mpn_copyi(tp, rp, nn);
/* invert r */
}
while (!mpn_sec_invert (ri, tp, np, nn, 2 * nn * GMP_NUMB_BITS, scratch));
mpn_sec_powm (c, rp, nn, ep, ebn, np, nn, scratch);
/* normally mn == nn, but m can be smaller in some cases */
mpn_sec_mul (tp, c, nn, m, mn, scratch);
mpn_sec_div_r (tp, nn + mn, np, nn, scratch);
mpn_copyi(c, tp, nn);
TMP_GMP_FREE (r);
TMP_GMP_FREE (rp);
TMP_GMP_FREE (tp);
}
/* m = c ri mod n */
static void
rsa_sec_unblind (const struct rsa_public_key *pub,
mp_limb_t *x, mp_limb_t *ri, const mp_limb_t *c)
{
const mp_limb_t *np = mpz_limbs_read (pub->n);
mp_size_t nn = mpz_size (pub->n);
size_t itch;
size_t i2;
mp_limb_t *scratch;
TMP_GMP_DECL(tp, mp_limb_t);
itch = mpn_sec_mul_itch(nn, nn);
i2 = mpn_sec_div_r_itch(nn + nn, nn);
itch = MAX(itch, i2);
TMP_GMP_ALLOC (tp, nn + nn + itch);
scratch = tp + nn + nn;
mpn_sec_mul (tp, c, nn, ri, nn, scratch);
mpn_sec_div_r (tp, nn + nn, np, nn, scratch);
mpn_copyi(x, tp, nn);
TMP_GMP_FREE (tp);
}
static int
sec_equal(const mp_limb_t *a, const mp_limb_t *b, size_t limbs)
{
volatile mp_limb_t z = 0;
for (size_t i = 0; i < limbs; i++)
{
z |= (a[i] ^ b[i]);
}
return z == 0;
}
static int
rsa_sec_check_root(const struct rsa_public_key *pub,
const mp_limb_t *x, const mp_limb_t *m)
{
mp_size_t nn = mpz_size (pub->n);
mp_size_t ebn = mpz_sizeinbase (pub->e, 2);
const mp_limb_t *np = mpz_limbs_read (pub->n);
const mp_limb_t *ep = mpz_limbs_read (pub->e);
int ret;
mp_size_t itch;
mp_limb_t *scratch;
TMP_GMP_DECL(tp, mp_limb_t);
itch = mpn_sec_powm_itch (nn, ebn, nn);
TMP_GMP_ALLOC (tp, nn + itch);
scratch = tp + nn;
mpn_sec_powm(tp, x, nn, ep, ebn, np, nn, scratch);
ret = sec_equal(tp, m, nn);
TMP_GMP_FREE (tp);
return ret;
}
static void
cnd_mpn_zero (int cnd, volatile mp_ptr rp, mp_size_t n)
{
volatile mp_limb_t c;
while (--n >= 0)
{
c = rp[n];
c &= ((mp_limb_t)cnd - 1);
rp[n] = c;
}
}
/* Checks for any errors done in the RSA computation. That avoids
* attacks which rely on faults on hardware, or even software MPI
* implementation.
* This version is side-channel silent even in case of error,
* the destination buffer is always overwritten */
int
rsa_sec_compute_root_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
mp_limb_t *x, const mp_limb_t *m, size_t mn)
{
TMP_GMP_DECL (c, mp_limb_t);
TMP_GMP_DECL (ri, mp_limb_t);
TMP_GMP_DECL (scratch, mp_limb_t);
size_t key_limb_size;
int ret;
key_limb_size = NETTLE_OCTET_SIZE_TO_LIMB_SIZE(key->size);
/* mpz_powm_sec handles only odd moduli. If p, q or n is even, the
key is invalid and rejected by rsa_private_key_prepare. However,
some applications, notably gnutls, don't use this function, and
we don't want an invalid key to lead to a crash down inside
mpz_powm_sec. So do an additional check here. */
if (mpz_even_p (pub->n) || mpz_even_p (key->p) || mpz_even_p (key->q))
{
mpn_zero(x, key_limb_size);
return 0;
}
assert(mpz_size(pub->n) == key_limb_size);
assert(mn <= key_limb_size);
TMP_GMP_ALLOC (c, key_limb_size);
TMP_GMP_ALLOC (ri, key_limb_size);
TMP_GMP_ALLOC (scratch, _rsa_sec_compute_root_itch(key));
rsa_sec_blind (pub, random_ctx, random, x, ri, m, mn);
_rsa_sec_compute_root(key, c, x, scratch);
ret = rsa_sec_check_root(pub, c, x);
rsa_sec_unblind(pub, x, ri, c);
cnd_mpn_zero(1 - ret, x, key_limb_size);
TMP_GMP_FREE (scratch);
TMP_GMP_FREE (ri);
TMP_GMP_FREE (c);
return ret;
}
/* Checks for any errors done in the RSA computation. That avoids
* attacks which rely on faults on hardware, or even software MPI
* implementation.
* This version is maintained for API compatibility reasons. It
* is not completely side-channel silent. There are conditionals
* in buffer copying both in case of success or error.
*/
int
rsa_compute_root_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
mpz_t x, const mpz_t m)
{
TMP_GMP_DECL (l, mp_limb_t);
int res;
mp_size_t l_size = NETTLE_OCTET_SIZE_TO_LIMB_SIZE(key->size);
TMP_GMP_ALLOC (l, l_size);
res = rsa_sec_compute_root_tr (pub, key, random_ctx, random, l,
mpz_limbs_read(m), mpz_size(m));
if (res) {
mp_limb_t *xp = mpz_limbs_write (x, l_size);
mpn_copyi (xp, l, l_size);
mpz_limbs_finish (x, l_size);
}
TMP_GMP_FREE (l);
return res;
}
#endif
...@@ -90,6 +90,7 @@ extern "C" { ...@@ -90,6 +90,7 @@ extern "C" {
#define rsa_decrypt_tr nettle_rsa_decrypt_tr #define rsa_decrypt_tr nettle_rsa_decrypt_tr
#define rsa_compute_root nettle_rsa_compute_root #define rsa_compute_root nettle_rsa_compute_root
#define rsa_compute_root_tr nettle_rsa_compute_root_tr #define rsa_compute_root_tr nettle_rsa_compute_root_tr
#define rsa_sec_compute_root_tr _nettle_rsa_sec_compute_root_tr
#define rsa_generate_keypair nettle_rsa_generate_keypair #define rsa_generate_keypair nettle_rsa_generate_keypair
#define rsa_keypair_to_sexp nettle_rsa_keypair_to_sexp #define rsa_keypair_to_sexp nettle_rsa_keypair_to_sexp
#define rsa_keypair_from_sexp_alist nettle_rsa_keypair_from_sexp_alist #define rsa_keypair_from_sexp_alist nettle_rsa_keypair_from_sexp_alist
...@@ -436,6 +437,14 @@ rsa_compute_root_tr(const struct rsa_public_key *pub, ...@@ -436,6 +437,14 @@ rsa_compute_root_tr(const struct rsa_public_key *pub,
void *random_ctx, nettle_random_func *random, void *random_ctx, nettle_random_func *random,
mpz_t x, const mpz_t m); mpz_t x, const mpz_t m);
/* Safe side-channel silent variant, using RSA blinding, and checking the
* result after CRT. */
int
rsa_sec_compute_root_tr(const struct rsa_public_key *pub,
const struct rsa_private_key *key,
void *random_ctx, nettle_random_func *random,
mp_limb_t *x, const mp_limb_t *m, size_t mn);
/* Key generation */ /* Key generation */
/* Note that the key structs must be initialized first. */ /* Note that the key structs must be initialized first. */
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment