* cipher/elgamal.c (elg_decrypt): Replace ! operator with calls to ct_is_not_zero/ct_is_zero/ct_ulong_select. * cipher/rsa-common.c (_gcry_rsa_pkcs1_decode_for_enc): Replace ! operator with call to ct_is_zero. * cipher/rsa.c (rsa_decrypt): Replace ! operator with calls to ct_is_not_zero/ct_is_zero/ct_ulong_select. * src/const-time.c (_gcry_ct_vzero, _gcry_ct_vone): New. * src/const-time.h (_gcry_ct_vzero, _gcry_ct_vone): New. (ct_is_not_zero, ct_is_zero, DEFINE_CT_TYPE_SELECT_FUNC) (ct_uintptr_select, ct_ulong_select): New. (sexp_null_cond): Use ct_uintptr_select. --
Signed-off-by: Jussi Kivilinna <jussi.kivili...@iki.fi> --- cipher/elgamal.c | 22 +++++++++++--------- cipher/rsa-common.c | 2 +- cipher/rsa.c | 16 +++++++-------- src/const-time.c | 8 ++++++++ src/const-time.h | 49 +++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 74 insertions(+), 23 deletions(-) diff --git a/cipher/elgamal.c b/cipher/elgamal.c index 06881cb6..540ecb02 100644 --- a/cipher/elgamal.c +++ b/cipher/elgamal.c @@ -931,26 +931,28 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) { case PUBKEY_ENC_PKCS1: rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain); - mpi_free (plain); plain = NULL; + mpi_free (plain); + plain = NULL; rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad); - *r_plain = sexp_null_cond (result, !!rc); - dummy = sexp_null_cond (result, !rc); + *r_plain = sexp_null_cond (result, ct_is_not_zero (rc)); + dummy = sexp_null_cond (result, ct_is_zero (rc)); sexp_release (dummy); - if (!rc && rc_sexp) - rc = rc_sexp; + rc = ct_ulong_select (rc_sexp, rc, + ct_is_zero (rc) & ct_is_not_zero (rc_sexp)); break; case PUBKEY_ENC_OAEP: rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, ctx.nbits, ctx.hash_algo, plain, ctx.label, ctx.labellen); - mpi_free (plain); plain = NULL; + mpi_free (plain); + plain = NULL; rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad); - *r_plain = sexp_null_cond (result, !!rc); - dummy = sexp_null_cond (result, !rc); + *r_plain = sexp_null_cond (result, ct_is_not_zero (rc)); + dummy = sexp_null_cond (result, ct_is_zero (rc)); sexp_release (dummy); - if (!rc && rc_sexp) - rc = rc_sexp; + rc = ct_ulong_select (rc_sexp, rc, + ct_is_zero (rc) & ct_is_not_zero (rc_sexp)); break; default: diff --git a/cipher/rsa-common.c b/cipher/rsa-common.c index 74eb6341..1920eedd 100644 --- a/cipher/rsa-common.c +++ b/cipher/rsa-common.c @@ -246,7 +246,7 @@ _gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen, } failed |= not_found; - n0 += !not_found; /* Skip the zero byte. */ + n0 += ct_is_zero (not_found); /* Skip the zero byte. */ /* To avoid an extra allocation we reuse the frame buffer. The only caller of this function will anyway free the result soon. */ diff --git a/cipher/rsa.c b/cipher/rsa.c index 383e2474..c7a809f4 100644 --- a/cipher/rsa.c +++ b/cipher/rsa.c @@ -1516,11 +1516,11 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) mpi_free (plain); plain = NULL; rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad); - *r_plain = sexp_null_cond (result, !!rc); - dummy = sexp_null_cond (result, !rc); + *r_plain = sexp_null_cond (result, ct_is_not_zero (rc)); + dummy = sexp_null_cond (result, ct_is_zero (rc)); sexp_release (dummy); - if (!rc && rc_sexp) - rc = rc_sexp; + rc = ct_ulong_select (rc_sexp, rc, + ct_is_zero (rc) & ct_is_not_zero (rc_sexp)); break; case PUBKEY_ENC_OAEP: @@ -1530,11 +1530,11 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms) mpi_free (plain); plain = NULL; rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad); - *r_plain = sexp_null_cond (result, !!rc); - dummy = sexp_null_cond (result,!rc); + *r_plain = sexp_null_cond (result, ct_is_not_zero (rc)); + dummy = sexp_null_cond (result, ct_is_zero (rc)); sexp_release (dummy); - if (!rc && rc_sexp) - rc = rc_sexp; + rc = ct_ulong_select (rc_sexp, rc, + ct_is_zero (rc) & ct_is_not_zero (rc_sexp)); break; default: diff --git a/src/const-time.c b/src/const-time.c index fb787a02..908c0ee9 100644 --- a/src/const-time.c +++ b/src/const-time.c @@ -23,6 +23,14 @@ #include "g10lib.h" #include "const-time.h" + +/* These variables are used to generate masks from conditional operation + * flag parameters. Use of volatile prevents compiler optimizations from + * converting AND-masking to conditional branches. */ +volatile unsigned int _gcry_ct_vzero = 0; +volatile unsigned int _gcry_ct_vone = 1; + + /* * Compare byte arrays of length LEN, return 1 if it's not same, * 0, otherwise. diff --git a/src/const-time.h b/src/const-time.h index 4f14f86b..3a229ddb 100644 --- a/src/const-time.h +++ b/src/const-time.h @@ -23,6 +23,34 @@ #include "types.h" +extern volatile unsigned int _gcry_ct_vzero; +extern volatile unsigned int _gcry_ct_vone; + + +/* + * Return 0 if A is 0 and return 1 otherwise. + */ +static inline unsigned int +ct_is_not_zero (unsigned int a) +{ + /* Sign bit set if A != 0. */ + a = a | (-a); + + return a >> (sizeof(unsigned int) * 8 - 1); +} + +/* + * Return 1 if A is 0 and return 0 otherwise. + */ +static inline unsigned int +ct_is_zero (unsigned int a) +{ + /* Sign bit set if A == 0. */ + a = ~a & ~(-a); + + return a >> (sizeof(unsigned int) * 8 - 1); +} + /* * Return 1 if it's not same, 0 if same. */ @@ -47,6 +75,21 @@ unsigned int ct_not_memequal (const void *b1, const void *b2, size_t len); any structure. */ unsigned int ct_memequal (const void *b1, const void *b2, size_t len); +/* + * Return A when OP_ENABLED=1 + * otherwise, return B + */ +#define DEFINE_CT_TYPE_SELECT_FUNC(name, type) \ + static inline type \ + ct_##name##_select (type a, type b, unsigned long op_enable) \ + { \ + type mask_b = (type)op_enable - (type)_gcry_ct_vone; \ + type mask_a = (type)_gcry_ct_vzero - (type)op_enable; \ + return (mask_a & a) | (mask_b & b); \ + } +DEFINE_CT_TYPE_SELECT_FUNC(uintptr, uintptr_t) +DEFINE_CT_TYPE_SELECT_FUNC(ulong, unsigned long) + /* * Return NULL when OP_ENABLED=1 * otherwise, return W @@ -54,10 +97,8 @@ unsigned int ct_memequal (const void *b1, const void *b2, size_t len); static inline gcry_sexp_t sexp_null_cond (gcry_sexp_t w, unsigned long op_enable) { - static volatile uintptr_t vone = 1; - size_t mask = (uintptr_t)op_enable - vone; - - return (gcry_sexp_t)(void *)((uintptr_t)w & mask); + uintptr_t o = ct_uintptr_select((uintptr_t)NULL, (uintptr_t)w, op_enable); + return (gcry_sexp_t)(void *)o; } /* -- 2.40.1 _______________________________________________ Gcrypt-devel mailing list Gcrypt-devel@gnupg.org https://lists.gnupg.org/mailman/listinfo/gcrypt-devel