File libgcrypt-CVE-2024-2236_01.patch of Package libgcrypt.39918
From a611e3a25d61505698e2bb38ec2db38bc6a74820 Mon Sep 17 00:00:00 2001
From: NIIBE Yutaka <gniibe@fsij.org>
Date: Tue, 10 May 2022 15:44:19 +0900
Subject: [PATCH] mpi: Fix for 64-bit for _gcry_mpih_cmp_ui.
* mpi/mpih-const-time.c (_gcry_mpih_cmp_ui): Compare 64-bit
value correctly.
--
Reported-by: Guido Vranken <guidovranken@gmail.com>
GnuPG-bug-id: 5970
Signed-off-by: NIIBE Yutaka <gniibe@fsij.org>
---
mpi/mpih-const-time.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
Index: libgcrypt-1.8.2/cipher/rsa-common.c
===================================================================
--- libgcrypt-1.8.2.orig/cipher/rsa-common.c
+++ libgcrypt-1.8.2/cipher/rsa-common.c
@@ -27,6 +27,7 @@
#include "mpi.h"
#include "cipher.h"
#include "pubkey-internal.h"
+#include "const-time.h"
/* Turn VALUE into an octet string and store it in an allocated buffer
@@ -161,6 +162,35 @@ _gcry_rsa_pkcs1_encode_for_enc (gcry_mpi
}
+/*
+ * <--len-->
+ * DST-------v v-------------SRC
+ * [.................]
+ * <---- buflen --->
+ *
+ * Copy the memory area SRC with LEN into another memory area DST.
+ * Conditions met:
+ * the address SRC > DST
+ * DST + BUFLEN == SRC + LEN.
+ *
+ * Memory access doesn't depends on LEN, but always done independently,
+ * sliding memory area by 1, 2, 4 ... until done.
+ */
+static void
+memmov_independently (void *dst, const void *src, size_t len, size_t buflen)
+{
+ size_t offset = (size_t)((char *)src - (char *)dst);
+ size_t shift;
+
+ (void)len; /* No dependency. */
+ for (shift = 1; shift < buflen; shift <<= 1)
+ {
+ ct_memmov_cond (dst, (char *)dst + shift, buflen - shift, (offset&1));
+ offset >>= 1;
+ }
+}
+
+
/* Decode a plaintext in VALUE assuming pkcs#1 block type 2 padding.
NBITS is the size of the secret key. On success the result is
stored as a newly allocated buffer at R_RESULT and its valid length at
@@ -172,7 +202,9 @@ _gcry_rsa_pkcs1_decode_for_enc (unsigned
gcry_error_t err;
unsigned char *frame = NULL;
size_t nframe = (nbits+7) / 8;
- size_t n;
+ size_t n, n0;
+ unsigned int failed = 0;
+ unsigned int not_found = 1;
*r_result = NULL;
@@ -203,33 +235,31 @@ _gcry_rsa_pkcs1_decode_for_enc (unsigned
n = 0;
if (!frame[0])
n++;
- if (frame[n++] != 0x02)
- {
- xfree (frame);
- return GPG_ERR_ENCODING_PROBLEM; /* Wrong block type. */
- }
+ failed |= ct_not_equal_byte (frame[n++], 0x02);
- /* Skip the non-zero random bytes and the terminating zero byte. */
- for (; n < nframe && frame[n] != 0x00; n++)
- ;
- if (n+1 >= nframe)
+ /* Find the terminating zero byte. */
+ n0 = n;
+ for (; n < nframe; n++)
{
- xfree (frame);
- return GPG_ERR_ENCODING_PROBLEM; /* No zero byte. */
+ not_found &= ct_not_equal_byte (frame[n], 0x00);
+ n0 += not_found;
}
- n++; /* Skip the zero byte. */
+
+ failed |= not_found;
+ 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. */
- memmove (frame, frame + n, nframe - n);
+ memmov_independently (frame, frame + n0, nframe - n0, nframe);
+
*r_result = frame;
- *r_resultlen = nframe - n;
+ *r_resultlen = nframe - n0;
if (DBG_CIPHER)
log_printhex ("value extracted from PKCS#1 block type 2 encoded data",
*r_result, *r_resultlen);
- return 0;
+ return (0U - failed) & GPG_ERR_ENCODING_PROBLEM;
}
@@ -616,7 +646,8 @@ _gcry_rsa_oaep_decode (unsigned char **r
size_t db_len; /* Length of DB and masked_db. */
size_t nkey = (nbits+7)/8; /* Length of the key in bytes. */
int failed = 0; /* Error indicator. */
- size_t n;
+ size_t n, n1;
+ unsigned int not_found = 1;
*r_result = NULL;
@@ -688,51 +719,43 @@ _gcry_rsa_oaep_decode (unsigned char **r
db_len = nframe - 1 - hlen;
/* Step 3c and 3d: seed = maskedSeed ^ mgf(maskedDB, hlen). */
- if (mgf1 (seed, hlen, masked_db, db_len, algo))
- failed = 1;
+ failed |= (mgf1 (seed, hlen, masked_db, db_len, algo) != 0);
for (n = 0; n < hlen; n++)
seed[n] ^= masked_seed[n];
/* Step 3e and 3f: db = maskedDB ^ mgf(seed, db_len). */
- if (mgf1 (db, db_len, seed, hlen, algo))
- failed = 1;
+ failed |= (mgf1 (db, db_len, seed, hlen, algo) != 0);
for (n = 0; n < db_len; n++)
db[n] ^= masked_db[n];
/* Step 3g: Check lhash, an possible empty padding string terminated
by 0x01 and the first byte of EM being 0. */
- if (memcmp (lhash, db, hlen))
- failed = 1;
- for (n = hlen; n < db_len; n++)
- if (db[n] == 0x01)
- break;
- if (n == db_len)
- failed = 1;
- if (frame[0])
- failed = 1;
+ failed |= ct_not_memequal (lhash, db, hlen);
+ for (n = n1 = hlen; n < db_len; n++)
+ {
+ not_found &= ct_not_equal_byte (db[n], 0x01);
+ n1 += not_found;
+ }
+ failed |= not_found;
+ failed |= ct_not_equal_byte (frame[0], 0x00);
xfree (lhash);
xfree (frame);
- if (failed)
- {
- xfree (seed);
- return GPG_ERR_ENCODING_PROBLEM;
- }
/* Step 4: Output M. */
/* To avoid an extra allocation we reuse the seed buffer. The only
caller of this function will anyway free the result soon. */
- n++;
- memmove (seed, db + n, db_len - n);
+ n1 += !not_found;
+ memmov_independently (seed, db + n1, db_len - n1, nframe - 1);
*r_result = seed;
- *r_resultlen = db_len - n;
+ *r_resultlen = db_len - n1;
seed = NULL;
if (DBG_CIPHER)
log_printhex ("value extracted from OAEP encoded data",
*r_result, *r_resultlen);
- return 0;
+ return (0U - failed) & GPG_ERR_ENCODING_PROBLEM;
}
Index: libgcrypt-1.8.2/cipher/rsa.c
===================================================================
--- libgcrypt-1.8.2.orig/cipher/rsa.c
+++ libgcrypt-1.8.2/cipher/rsa.c
@@ -33,6 +33,7 @@
#include "mpi.h"
#include "cipher.h"
#include "pubkey-internal.h"
+#include "const-time.h"
typedef struct
@@ -1425,7 +1426,7 @@ static gcry_err_code_t
rsa_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
- gpg_err_code_t rc;
+ gpg_err_code_t rc, rc_sexp;
struct pk_encoding_ctx ctx;
gcry_sexp_t l1 = NULL;
gcry_mpi_t data = NULL;
@@ -1433,7 +1434,8 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_
gcry_mpi_t plain = NULL;
unsigned char *unpad = NULL;
size_t unpadlen = 0;
-
+ gcry_sexp_t result = NULL;
+ gcry_sexp_t dummy = NULL;
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
rsa_get_nbits (keyparms));
@@ -1498,8 +1500,12 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_
rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain);
mpi_free (plain);
plain = NULL;
- if (!rc)
- rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+ rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad);
+ *r_plain = sexp_null_cond (result, ct_is_not_zero (rc));
+ dummy = sexp_null_cond (result, ct_is_zero (rc));
+ sexp_release (dummy);
+ rc = ct_ulong_select (rc_sexp, rc,
+ ct_is_zero (rc) & ct_is_not_zero (rc_sexp));
break;
case PUBKEY_ENC_OAEP:
@@ -1508,8 +1514,12 @@ rsa_decrypt (gcry_sexp_t *r_plain, gcry_
plain, ctx.label, ctx.labellen);
mpi_free (plain);
plain = NULL;
- if (!rc)
- rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+ rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad);
+ *r_plain = sexp_null_cond (result, ct_is_not_zero (rc));
+ dummy = sexp_null_cond (result, ct_is_zero (rc));
+ sexp_release (dummy);
+ rc = ct_ulong_select (rc_sexp, rc,
+ ct_is_zero (rc) & ct_is_not_zero (rc_sexp));
break;
default:
Index: libgcrypt-1.8.2/src/Makefile.am
===================================================================
--- libgcrypt-1.8.2.orig/src/Makefile.am
+++ libgcrypt-1.8.2/src/Makefile.am
@@ -61,6 +61,7 @@ libgcrypt_la_SOURCES = \
stdmem.c stdmem.h secmem.c secmem.h \
mpi.h missing-string.c fips.c \
hmac256.c hmac256.h context.c context.h \
+ const-time.h const-time.c \
ec-context.h
EXTRA_libgcrypt_la_SOURCES = hwf-x86.c hwf-arm.c
Index: libgcrypt-1.8.2/src/const-time.c
===================================================================
--- /dev/null
+++ libgcrypt-1.8.2/src/const-time.c
@@ -0,0 +1,78 @@
+/* const-time.c - Constant-time functions
+ * Copyright (C) 2023 g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "g10lib.h"
+#include "const-time.h"
+
+/*
+ * Compare byte arrays of length LEN, return 1 if it's not same,
+ * 0, otherwise.
+ */
+unsigned int
+_gcry_ct_not_memequal (const void *b1, const void *b2, size_t len)
+{
+ const byte *a = b1;
+ const byte *b = b2;
+ int ab, ba;
+ size_t i;
+
+ /* Constant-time compare. */
+ for (i = 0, ab = 0, ba = 0; i < len; i++)
+ {
+ /* If a[i] != b[i], either ab or ba will be negative. */
+ ab |= a[i] - b[i];
+ ba |= b[i] - a[i];
+ }
+
+ /* 'ab | ba' is negative when buffers are not equal, extract sign bit. */
+ return ((unsigned int)(ab | ba) >> (sizeof(unsigned int) * 8 - 1)) & 1;
+}
+
+/*
+ * Compare byte arrays of length LEN, return 0 if it's not same,
+ * 1, otherwise.
+ */
+unsigned int
+_gcry_ct_memequal (const void *b1, const void *b2, size_t len)
+{
+ return _gcry_ct_not_memequal (b1, b2, len) ^ 1;
+}
+
+/*
+ * Copy LEN bytes from memory area SRC to memory area DST, when
+ * OP_ENABLED=1. When DST <= SRC, the memory areas may overlap. When
+ * DST > SRC, the memory areas must not overlap.
+ */
+void
+_gcry_ct_memmov_cond (void *dst, const void *src, size_t len,
+ unsigned long op_enable)
+{
+ /* Note: dual mask with AND/OR used for EM leakage mitigation */
+ unsigned char mask1 = ct_ulong_gen_mask(op_enable);
+ unsigned char mask2 = ct_ulong_gen_inv_mask(op_enable);
+ unsigned char *b_dst = dst;
+ const unsigned char *b_src = src;
+ size_t i;
+
+ for (i = 0; i < len; i++)
+ b_dst[i] = (b_dst[i] & mask2) | (b_src[i] & mask1);
+}
Index: libgcrypt-1.8.2/src/const-time.h
===================================================================
--- /dev/null
+++ libgcrypt-1.8.2/src/const-time.h
@@ -0,0 +1,167 @@
+/* const-time.h - Constant-time functions
+ * Copyright (C) 2023 g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef GCRY_CONST_TIME_H
+#define GCRY_CONST_TIME_H
+
+#include "types.h"
+
+
+#define ct_not_memequal _gcry_ct_not_memequal
+#define ct_memequal _gcry_ct_memequal
+#define ct_memmov_cond _gcry_ct_memmov_cond
+
+
+#ifndef HAVE_GCC_ASM_VOLATILE_MEMORY
+extern volatile unsigned int _gcry_ct_vzero;
+extern volatile unsigned int _gcry_ct_vone;
+#endif
+
+
+/*
+ * 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.
+ */
+static inline unsigned int
+ct_not_equal_byte (unsigned char b0, unsigned char b1)
+{
+ unsigned int diff;
+
+ diff = b0;
+ diff ^= b1;
+
+ return (0U - diff) >> (sizeof (unsigned int)*8 - 1);
+}
+
+/* Compare byte-arrays of length LEN, return 1 if it's not same, 0
+ otherwise. We use pointer of void *, so that it can be used with
+ any structure. */
+unsigned int _gcry_ct_not_memequal (const void *b1, const void *b2, size_t len);
+
+/* Compare byte-arrays of length LEN, return 0 if it's not same, 1
+ otherwise. We use pointer of void *, so that it can be used with
+ any structure. */
+unsigned int _gcry_ct_memequal (const void *b1, const void *b2, size_t len);
+
+/*
+ * Return all bits set if A is 1 and return 0 otherwise.
+ */
+#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY
+# define DEFINE_CT_TYPE_GEN_MASK(name, type) \
+ static inline type \
+ ct_##name##_gen_mask (unsigned long op_enable) \
+ { \
+ type mask = -(type)op_enable; \
+ asm volatile ("\n" : "+r" (mask) :: "memory"); \
+ return mask; \
+ }
+#else
+# define DEFINE_CT_TYPE_GEN_MASK(name, type) \
+ static inline type \
+ ct_##name##_gen_mask (unsigned long op_enable) \
+ { \
+ type mask = (type)_gcry_ct_vzero - (type)op_enable; \
+ return mask; \
+ }
+#endif
+DEFINE_CT_TYPE_GEN_MASK(uintptr, uintptr_t)
+DEFINE_CT_TYPE_GEN_MASK(ulong, unsigned long)
+
+/*
+ * Return all bits set if A is 0 and return 1 otherwise.
+ */
+#ifdef HAVE_GCC_ASM_VOLATILE_MEMORY
+# define DEFINE_CT_TYPE_GEN_INV_MASK(name, type) \
+ static inline type \
+ ct_##name##_gen_inv_mask (unsigned long op_enable) \
+ { \
+ type mask = (type)op_enable - (type)1; \
+ asm volatile ("\n" : "+r" (mask) :: "memory"); \
+ return mask; \
+ }
+#else
+# define DEFINE_CT_TYPE_GEN_INV_MASK(name, type) \
+ static inline type \
+ ct_##name##_gen_inv_mask (unsigned long op_enable) \
+ { \
+ type mask = (type)op_enable - (type)_gcry_ct_vone; \
+ return mask; \
+ }
+#endif
+DEFINE_CT_TYPE_GEN_INV_MASK(uintptr, uintptr_t)
+DEFINE_CT_TYPE_GEN_INV_MASK(ulong, unsigned long)
+
+/*
+ * 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 = ct_##name##_gen_inv_mask(op_enable); \
+ type mask_a = ct_##name##_gen_mask(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
+ */
+static inline gcry_sexp_t
+sexp_null_cond (gcry_sexp_t w, unsigned long op_enable)
+{
+ uintptr_t o = ct_uintptr_select((uintptr_t)NULL, (uintptr_t)w, op_enable);
+ return (gcry_sexp_t)(void *)o;
+}
+
+/*
+ * Copy LEN bytes from memory area SRC to memory area DST, when
+ * OP_ENABLED=1. When DST <= SRC, the memory areas may overlap. When
+ * DST > SRC, the memory areas must not overlap.
+ */
+void _gcry_ct_memmov_cond (void *dst, const void *src, size_t len,
+ unsigned long op_enable);
+
+#endif /*GCRY_CONST_TIME_H*/
Index: libgcrypt-1.8.2/cipher/elgamal.c
===================================================================
--- libgcrypt-1.8.2.orig/cipher/elgamal.c
+++ libgcrypt-1.8.2/cipher/elgamal.c
@@ -31,6 +31,7 @@
#include "mpi.h"
#include "cipher.h"
#include "pubkey-internal.h"
+#include "const-time.h"
/* Blinding is used to mitigate side-channel attacks. You may undef
@@ -872,7 +873,7 @@ elg_encrypt (gcry_sexp_t *r_ciph, gcry_s
static gcry_err_code_t
elg_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
{
- gpg_err_code_t rc;
+ gpg_err_code_t rc, rc_sexp;
struct pk_encoding_ctx ctx;
gcry_sexp_t l1 = NULL;
gcry_mpi_t data_a = NULL;
@@ -881,6 +882,8 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_
gcry_mpi_t plain = NULL;
unsigned char *unpad = NULL;
size_t unpadlen = 0;
+ gcry_sexp_t result = NULL;
+ gcry_sexp_t dummy = NULL;
_gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
elg_get_nbits (keyparms));
@@ -928,18 +931,28 @@ elg_decrypt (gcry_sexp_t *r_plain, gcry_
{
case PUBKEY_ENC_PKCS1:
rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, ctx.nbits, plain);
- mpi_free (plain); plain = NULL;
- if (!rc)
- rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+ mpi_free (plain);
+ plain = NULL;
+ rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad);
+ *r_plain = sexp_null_cond (result, ct_is_not_zero (rc));
+ dummy = sexp_null_cond (result, ct_is_zero (rc));
+ sexp_release (dummy);
+ 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;
- if (!rc)
- rc = sexp_build (r_plain, NULL, "(value %b)", (int)unpadlen, unpad);
+ mpi_free (plain);
+ plain = NULL;
+ rc_sexp = sexp_build (&result, NULL, "(value %b)", (int)unpadlen, unpad);
+ *r_plain = sexp_null_cond (result, ct_is_not_zero (rc));
+ dummy = sexp_null_cond (result, ct_is_zero (rc));
+ sexp_release (dummy);
+ rc = ct_ulong_select (rc_sexp, rc,
+ ct_is_zero (rc) & ct_is_not_zero (rc_sexp));
break;
default:
Index: libgcrypt-1.8.2/cipher/bufhelp.h
===================================================================
--- libgcrypt-1.8.2.orig/cipher/bufhelp.h
+++ libgcrypt-1.8.2/cipher/bufhelp.h
@@ -22,6 +22,7 @@
#include "g10lib.h"
#include "bithelp.h"
+#include "const-time.h"
#undef BUFHELP_UNALIGNED_ACCESS
@@ -288,15 +289,7 @@ buf_xor_n_copy(void *_dst_xor, void *_sr
static inline int
buf_eq_const(const void *_a, const void *_b, size_t len)
{
- const byte *a = _a;
- const byte *b = _b;
- size_t diff, i;
-
- /* Constant-time compare. */
- for (i = 0, diff = 0; i < len; i++)
- diff -= !!(a[i] - b[i]);
-
- return !diff;
+ return ct_memequal (_a, _b, len);
}
Index: libgcrypt-1.8.2/mpi/mpiutil.c
===================================================================
--- libgcrypt-1.8.2.orig/mpi/mpiutil.c
+++ libgcrypt-1.8.2/mpi/mpiutil.c
@@ -27,6 +27,7 @@
#include "g10lib.h"
#include "mpi-internal.h"
#include "mod-source-info.h"
+#include "const-time.h"
/* Constants allocated right away at startup. */
static gcry_mpi_t constants[MPI_NUMBER_OF_CONSTANTS];
@@ -496,25 +497,33 @@ _gcry_mpi_set (gcry_mpi_t w, gcry_mpi_t
gcry_mpi_t
_gcry_mpi_set_cond (gcry_mpi_t w, const gcry_mpi_t u, unsigned long set)
{
+ /* Note: dual mask with AND/OR used for EM leakage mitigation */
+ mpi_limb_t mask1 = ct_limb_gen_mask(set);
+ mpi_limb_t mask2 = ct_limb_gen_inv_mask(set);
mpi_size_t i;
mpi_size_t nlimbs = u->alloced;
- mpi_limb_t mask = ((mpi_limb_t)0) - set;
- mpi_limb_t x;
+ mpi_limb_t xu;
+ mpi_limb_t xw;
+ mpi_limb_t *uu = u->d;
+ mpi_limb_t *uw = w->d;
if (w->alloced != u->alloced)
log_bug ("mpi_set_cond: different sizes\n");
for (i = 0; i < nlimbs; i++)
{
- x = mask & (w->d[i] ^ u->d[i]);
- w->d[i] = w->d[i] ^ x;
+ xu = uu[i];
+ xw = uw[i];
+ uw[i] = (xw & mask2) | (xu & mask1);
}
- x = mask & (w->nlimbs ^ u->nlimbs);
- w->nlimbs = w->nlimbs ^ x;
-
- x = mask & (w->sign ^ u->sign);
- w->sign = w->sign ^ x;
+ xu = u->nlimbs;
+ xw = w->nlimbs;
+ w->nlimbs = (xw & mask2) | (xu & mask1);
+
+ xu = u->sign;
+ xw = w->sign;
+ w->sign = (xw & mask2) | (xu & mask1);
return w;
}
@@ -586,11 +595,16 @@ _gcry_mpi_swap (gcry_mpi_t a, gcry_mpi_t
void
_gcry_mpi_swap_cond (gcry_mpi_t a, gcry_mpi_t b, unsigned long swap)
{
+ /* Note: dual mask with AND/OR used for EM leakage mitigation */
+ mpi_limb_t mask1 = ct_limb_gen_mask(swap);
+ mpi_limb_t mask2 = ct_limb_gen_inv_mask(swap);
mpi_size_t i;
mpi_size_t nlimbs;
- mpi_limb_t mask = ((mpi_limb_t)0) - swap;
- mpi_limb_t x;
-
+ mpi_limb_t *ua = a->d;
+ mpi_limb_t *ub = b->d;
+ mpi_limb_t xa;
+ mpi_limb_t xb;
+
if (a->alloced > b->alloced)
nlimbs = b->alloced;
else
@@ -600,18 +614,22 @@ _gcry_mpi_swap_cond (gcry_mpi_t a, gcry_
for (i = 0; i < nlimbs; i++)
{
- x = mask & (a->d[i] ^ b->d[i]);
- a->d[i] = a->d[i] ^ x;
- b->d[i] = b->d[i] ^ x;
+ xa = ua[i];
+ xb = ub[i];
+ ua[i] = (xa & mask2) | (xb & mask1);
+ ub[i] = (xa & mask1) | (xb & mask2);
}
- x = mask & (a->nlimbs ^ b->nlimbs);
- a->nlimbs = a->nlimbs ^ x;
- b->nlimbs = b->nlimbs ^ x;
-
- x = mask & (a->sign ^ b->sign);
- a->sign = a->sign ^ x;
- b->sign = b->sign ^ x;
+ xa = a->nlimbs;
+ xb = b->nlimbs;
+ a->nlimbs = (xa & mask2) | (xb & mask1);
+ b->nlimbs = (xa & mask1) | (xb & mask2);
+
+ xa = a->sign;
+ xb = b->sign;
+ a->sign = (xa & mask2) | (xb & mask1);
+ b->sign = (xa & mask1) | (xb & mask2);
+
}
Index: libgcrypt-1.8.2/mpi/mpi-internal.h
===================================================================
--- libgcrypt-1.8.2.orig/mpi/mpi-internal.h
+++ libgcrypt-1.8.2/mpi/mpi-internal.h
@@ -50,6 +50,7 @@
#endif /*BITS_PER_MPI_LIMB*/
#include "mpi.h"
+#include "const-time.h"
/* If KARATSUBA_THRESHOLD is not already defined, define it to a
* value which is good on most machines. */
@@ -61,6 +62,9 @@
#define KARATSUBA_THRESHOLD 16
#endif
+DEFINE_CT_TYPE_GEN_MASK(limb, mpi_limb_t)
+DEFINE_CT_TYPE_GEN_INV_MASK(limb, mpi_limb_t)
+
/* The code can't handle KARATSUBA_THRESHOLD smaller than 2. */
#if KARATSUBA_THRESHOLD < 2
#undef KARATSUBA_THRESHOLD