From f0a51bbdbd50e03a43914c9ee912c451b6ad82e5 Mon Sep 17 00:00:00 2001
From: Karel Miko <karel.miko@gmail.com>
Date: Sun, 17 Jun 2018 12:54:01 +0200
Subject: [PATCH] ecc_sign_hash blinding CVE-2018-12437

---
 makefile                   |  2 +-
 makefile.icc               |  2 +-
 makefile.msvc              |  2 +-
 makefile.shared            |  2 +-
 makefile.unix              |  2 +-
 src/math/rand_bn.c         | 75 ++++++++++++++++++++++++++++++++++++++
 src/pk/ecc/ecc_sign_hash.c | 19 ++++++----
 7 files changed, 91 insertions(+), 13 deletions(-)
 create mode 100644 src/math/rand_bn.c

diff --git a/makefile b/makefile
index 883e51d..aa38cd5 100644
--- a/makefile
+++ b/makefile
@@ -142,7 +142,7 @@ src/mac/pmac/pmac_shift_xor.o src/mac/pmac/pmac_test.o src/mac/xcbc/xcbc_done.o
 src/mac/xcbc/xcbc_file.o src/mac/xcbc/xcbc_init.o src/mac/xcbc/xcbc_memory.o \
 src/mac/xcbc/xcbc_memory_multi.o src/mac/xcbc/xcbc_process.o src/mac/xcbc/xcbc_test.o \
 src/math/fp/ltc_ecc_fp_mulmod.o src/math/gmp_desc.o src/math/ltm_desc.o src/math/multi.o \
-src/math/rand_prime.o src/math/tfm_desc.o src/misc/base64/base64_decode.o \
+src/math/rand_bn.o src/math/rand_prime.o src/math/tfm_desc.o src/misc/base64/base64_decode.o \
 src/misc/base64/base64_encode.o src/misc/burn_stack.o src/misc/crypt/crypt_argchk.o \
 src/misc/crypt/crypt.o src/misc/crypt/crypt_cipher_descriptor.o src/misc/crypt/crypt_cipher_is_valid.o \
 src/misc/crypt/crypt_find_cipher_any.o src/misc/crypt/crypt_find_cipher.o \
diff --git a/makefile.icc b/makefile.icc
index c1ff163..a431010 100644
--- a/makefile.icc
+++ b/makefile.icc
@@ -128,7 +128,7 @@ src/mac/pmac/pmac_shift_xor.o src/mac/pmac/pmac_test.o src/mac/xcbc/xcbc_done.o
 src/mac/xcbc/xcbc_file.o src/mac/xcbc/xcbc_init.o src/mac/xcbc/xcbc_memory.o \
 src/mac/xcbc/xcbc_memory_multi.o src/mac/xcbc/xcbc_process.o src/mac/xcbc/xcbc_test.o \
 src/math/fp/ltc_ecc_fp_mulmod.o src/math/gmp_desc.o src/math/ltm_desc.o src/math/multi.o \
-src/math/rand_prime.o src/math/tfm_desc.o src/misc/base64/base64_decode.o \
+src/math/rand_bn.o src/math/rand_prime.o src/math/tfm_desc.o src/misc/base64/base64_decode.o \
 src/misc/base64/base64_encode.o src/misc/burn_stack.o src/misc/crypt/crypt_argchk.o \
 src/misc/crypt/crypt.o src/misc/crypt/crypt_cipher_descriptor.o src/misc/crypt/crypt_cipher_is_valid.o \
 src/misc/crypt/crypt_find_cipher_any.o src/misc/crypt/crypt_find_cipher.o \
diff --git a/makefile.msvc b/makefile.msvc
index 7f41ad9..19a50fc 100644
--- a/makefile.msvc
+++ b/makefile.msvc
@@ -38,7 +38,7 @@ src/mac/pmac/pmac_shift_xor.obj src/mac/pmac/pmac_test.obj src/mac/xcbc/xcbc_don
 src/mac/xcbc/xcbc_file.obj src/mac/xcbc/xcbc_init.obj src/mac/xcbc/xcbc_memory.obj \
 src/mac/xcbc/xcbc_memory_multi.obj src/mac/xcbc/xcbc_process.obj src/mac/xcbc/xcbc_test.obj \
 src/math/fp/ltc_ecc_fp_mulmod.obj src/math/gmp_desc.obj src/math/ltm_desc.obj src/math/multi.obj \
-src/math/rand_prime.obj src/math/tfm_desc.obj src/misc/base64/base64_decode.obj \
+src/math/rand_bn.obj src/math/rand_prime.obj src/math/tfm_desc.obj src/misc/base64/base64_decode.obj \
 src/misc/base64/base64_encode.obj src/misc/burn_stack.obj src/misc/crypt/crypt_argchk.obj \
 src/misc/crypt/crypt.obj src/misc/crypt/crypt_cipher_descriptor.obj src/misc/crypt/crypt_cipher_is_valid.obj \
 src/misc/crypt/crypt_find_cipher_any.obj src/misc/crypt/crypt_find_cipher.obj \
diff --git a/makefile.shared b/makefile.shared
index eb889cd..7d523b8 100644
--- a/makefile.shared
+++ b/makefile.shared
@@ -133,7 +133,7 @@ src/mac/pmac/pmac_shift_xor.o src/mac/pmac/pmac_test.o src/mac/xcbc/xcbc_done.o
 src/mac/xcbc/xcbc_file.o src/mac/xcbc/xcbc_init.o src/mac/xcbc/xcbc_memory.o \
 src/mac/xcbc/xcbc_memory_multi.o src/mac/xcbc/xcbc_process.o src/mac/xcbc/xcbc_test.o \
 src/math/fp/ltc_ecc_fp_mulmod.o src/math/gmp_desc.o src/math/ltm_desc.o src/math/multi.o \
-src/math/rand_prime.o src/math/tfm_desc.o src/misc/base64/base64_decode.o \
+src/math/rand_bn.o src/math/rand_prime.o src/math/tfm_desc.o src/misc/base64/base64_decode.o \
 src/misc/base64/base64_encode.o src/misc/burn_stack.o src/misc/crypt/crypt_argchk.o \
 src/misc/crypt/crypt.o src/misc/crypt/crypt_cipher_descriptor.o src/misc/crypt/crypt_cipher_is_valid.o \
 src/misc/crypt/crypt_find_cipher_any.o src/misc/crypt/crypt_find_cipher.o \
diff --git a/makefile.unix b/makefile.unix
index bb8f29c..657fe9b 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -74,7 +74,7 @@ src/mac/pmac/pmac_shift_xor.o src/mac/pmac/pmac_test.o src/mac/xcbc/xcbc_done.o
 src/mac/xcbc/xcbc_file.o src/mac/xcbc/xcbc_init.o src/mac/xcbc/xcbc_memory.o \
 src/mac/xcbc/xcbc_memory_multi.o src/mac/xcbc/xcbc_process.o src/mac/xcbc/xcbc_test.o \
 src/math/fp/ltc_ecc_fp_mulmod.o src/math/gmp_desc.o src/math/ltm_desc.o src/math/multi.o \
-src/math/rand_prime.o src/math/tfm_desc.o src/misc/base64/base64_decode.o \
+src/math/rand_bn.o src/math/rand_prime.o src/math/tfm_desc.o src/misc/base64/base64_decode.o \
 src/misc/base64/base64_encode.o src/misc/burn_stack.o src/misc/crypt/crypt_argchk.o \
 src/misc/crypt/crypt.o src/misc/crypt/crypt_cipher_descriptor.o src/misc/crypt/crypt_cipher_is_valid.o \
 src/misc/crypt/crypt_find_cipher_any.o src/misc/crypt/crypt_find_cipher.o \
diff --git a/src/math/rand_bn.c b/src/math/rand_bn.c
new file mode 100644
index 0000000..aa6539c
--- /dev/null
+++ b/src/math/rand_bn.c
@@ -0,0 +1,75 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt.h"
+
+#if defined(LTC_MDSA) || defined(LTC_MECC)
+/**
+  Generate a random number N with given bitlength (note: MSB can be 0)
+*/
+
+int rand_bn_bits(void *N, int bits, prng_state *prng, int wprng)
+{
+   int res, bytes;
+   unsigned char *buf, mask;
+
+   LTC_ARGCHK(N != NULL);
+   LTC_ARGCHK(bits > 1);
+
+   /* check PRNG */
+   if ((res = prng_is_valid(wprng)) != CRYPT_OK) return res;
+
+   bytes = (bits+7) >> 3;
+   mask = 0xff << (8 - bits % 8);
+
+   /* allocate buffer */
+   if ((buf = XCALLOC(1, bytes)) == NULL) return CRYPT_MEM;
+
+   /* generate random bytes */
+   if (prng_descriptor[wprng].read(buf, bytes, prng) != (unsigned long)bytes) {
+      res = CRYPT_ERROR_READPRNG;
+      goto cleanup;
+   }
+   /* mask bits */
+   buf[0] &= ~mask;
+   /* load value */
+   if ((res = mp_read_unsigned_bin(N, buf, bytes)) != CRYPT_OK) goto cleanup;
+
+   res = CRYPT_OK;
+
+cleanup:
+#ifdef LTC_CLEAN_STACK
+   zeromem(buf, bytes);
+#endif
+   XFREE(buf);
+   return res;
+}
+
+/**
+  Generate a random number N in a range: 1 <= N < limit
+*/
+int rand_bn_upto(void *N, void *limit, prng_state *prng, int wprng)
+{
+   int res, bits;
+
+   LTC_ARGCHK(N != NULL);
+   LTC_ARGCHK(limit != NULL);
+
+   bits = mp_count_bits(limit);
+   do {
+     res = rand_bn_bits(N, bits, prng, wprng);
+     if (res != CRYPT_OK) return res;
+   } while (mp_cmp_d(N, 0) != LTC_MP_GT || mp_cmp(N, limit) != LTC_MP_LT);
+
+   return CRYPT_OK;
+}
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */
diff --git a/src/pk/ecc/ecc_sign_hash.c b/src/pk/ecc/ecc_sign_hash.c
index 1263095..eb40ece 100644
--- a/src/pk/ecc/ecc_sign_hash.c
+++ b/src/pk/ecc/ecc_sign_hash.c
@@ -39,7 +39,7 @@ int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
                         prng_state *prng, int wprng, ecc_key *key)
 {
    ecc_key       pubkey;
-   void          *r, *s, *e, *p;
+   void          *r, *s, *e, *p, *b;
    int           err;
 
    LTC_ARGCHK(in     != NULL);
@@ -63,7 +63,7 @@ int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
 
    /* get the hash and load it as a bignum into 'e' */
    /* init the bignums */
-   if ((err = mp_init_multi(&r, &s, &p, &e, NULL)) != CRYPT_OK) { 
+   if ((err = mp_init_multi(&r, &s, &p, &e, &b, NULL)) != CRYPT_OK) {
       return err;
    }
    if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK)                      { goto errnokey; }
@@ -80,13 +80,16 @@ int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
 
       if (mp_iszero(r) == LTC_MP_YES) {
          ecc_free(&pubkey);
-      } else { 
+      } else {
+        if ((err = rand_bn_upto(b, p, prng, wprng)) != CRYPT_OK)          { goto error; } /* b = blinding value */
         /* find s = (e + xr)/k */
-        if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK)            { goto error; } /* k = 1/k */
+	if ((err = mp_mulmod(pubkey.k, b, p, pubkey.k)) != CRYPT_OK)      { goto error; } /* k = kb */
+	if ((err = mp_invmod(pubkey.k, p, pubkey.k)) != CRYPT_OK)         { goto error; } /* k = 1/kb */
         if ((err = mp_mulmod(key->k, r, p, s)) != CRYPT_OK)                  { goto error; } /* s = xr */
-        if ((err = mp_add(e, s, s)) != CRYPT_OK)                             { goto error; } /* s = e +  xr */
-        if ((err = mp_mod(s, p, s)) != CRYPT_OK)                             { goto error; } /* s = e +  xr */
-        if ((err = mp_mulmod(s, pubkey.k, p, s)) != CRYPT_OK)                { goto error; } /* s = (e + xr)/k */
+	if ((err = mp_mulmod(pubkey.k, s, p, s)) != CRYPT_OK)             { goto error; } /* s = xr/kb */
+	if ((err = mp_mulmod(pubkey.k, e, p, e)) != CRYPT_OK)             { goto error; } /* e = e/kb */
+	if ((err = mp_add(e, s, s)) != CRYPT_OK)                          { goto error; } /* s = e/kb + xr/kb */
+	if ((err = mp_mulmod(s, b, p, s)) != CRYPT_OK)                    { goto error; } /* s = b(e/kb + xr/kb) = (e + xr)/k */
         ecc_free(&pubkey);
         if (mp_iszero(s) == LTC_MP_NO) {
            break;
@@ -103,7 +106,7 @@ int ecc_sign_hash(const unsigned char *in,  unsigned long inlen,
 error:
    ecc_free(&pubkey);
 errnokey:
-   mp_clear_multi(r, s, p, e, NULL);
+   mp_clear_multi(r, s, e, b, NULL);
    return err;   
 }
 
-- 
2.17.1

