From 9cbfde382824056dd7ec4e45daf243b03d49acac Mon Sep 17 00:00:00 2001
From: Simo Sorce <simo@redhat.com>
Date: Thu, 8 Nov 2018 11:15:59 -0500
Subject: [PATCH] Add side-channel silent RSA root function

Signed-off-by: Simo Sorce <simo@redhat.com>
---
 Makefile.in            |   1 +
 rsa-internal.h         |  50 +++++++++++++++
 rsa-sec-compute-root.c | 139 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 190 insertions(+)
 create mode 100644 rsa-internal.h
 create mode 100644 rsa-sec-compute-root.c

diff --git a/Makefile.in b/Makefile.in
index 6a0c13ec..7740d717 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -147,6 +147,7 @@ hogweed_SOURCES = sexp.c sexp-format.c \
 		  pkcs1-rsa-sha256.c pkcs1-rsa-sha512.c \
 		  pss.c pss-mgf1.c \
 		  rsa.c rsa-sign.c rsa-sign-tr.c rsa-verify.c \
+		  rsa-sec-compute-root.c \
 		  rsa-pkcs1-sign.c rsa-pkcs1-sign-tr.c rsa-pkcs1-verify.c \
 		  rsa-md5-sign.c rsa-md5-sign-tr.c rsa-md5-verify.c \
 		  rsa-sha1-sign.c rsa-sha1-sign-tr.c rsa-sha1-verify.c \
diff --git a/rsa-internal.h b/rsa-internal.h
new file mode 100644
index 00000000..4930bb90
--- /dev/null
+++ b/rsa-internal.h
@@ -0,0 +1,50 @@
+/* rsa-internal.h
+
+   The RSA publickey algorithm.
+
+   Copyright (C) 2001, 2002 Niels Möller
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle 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
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef NETTLE_RSA_INTERNAL_H_INCLUDED
+#define NETTLE_RSA_INTERNAL_H_INCLUDED
+
+#include "nettle-types.h"
+
+#define _rsa_sec_compute_root_itch _nettle_rsa_sec_compute_root_itch
+#define _rsa_sec_compute_root _nettle_rsa_sec_compute_root
+
+/* side-channel silent root computation */
+mp_size_t
+_rsa_sec_compute_root_itch(const struct rsa_private_key *key);
+void
+_rsa_sec_compute_root(const struct rsa_private_key *key,
+                      mp_limb_t *rp, const mp_limb_t *mp,
+                      mp_limb_t *scratch);
+
+#endif /* NETTLE_RSA_INTERNAL_H_INCLUDED */
diff --git a/rsa-sec-compute-root.c b/rsa-sec-compute-root.c
new file mode 100644
index 00000000..28856ff5
--- /dev/null
+++ b/rsa-sec-compute-root.c
@@ -0,0 +1,139 @@
+/* rsa-sec-compute-root.c
+
+   Creating RSA signatures, with some additional checks.
+
+   Copyright (C) 2018 Niels Möller
+
+   This file is part of GNU Nettle.
+
+   GNU Nettle is free software: you can redistribute it and/or
+   modify it under the terms of either:
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at your
+       option) any later version.
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at your
+       option) any later version.
+
+   or both in parallel, as here.
+
+   GNU Nettle 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
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see http://www.gnu.org/licenses/.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+
+#include "rsa.h"
+#include "rsa-internal.h"
+#include "gmp-glue.h"
+
+#if !NETTLE_USE_MINI_GMP
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+mp_size_t
+_rsa_sec_compute_root_itch (const struct rsa_private_key *key)
+{
+  mp_size_t nn = NETTLE_OCTET_SIZE_TO_LIMB_SIZE (key->size);
+  mp_size_t pn = mpz_size (key->p);
+  mp_size_t qn = mpz_size (key->q);
+  mp_size_t cn = mpz_size (key->c);
+  mp_size_t itch;
+  mp_size_t i2;
+
+  itch = nn;    /* Sufficient for mpn_sec_add_1 */
+  i2 = mpn_sec_div_r_itch (nn, qn);
+  itch = MAX (itch, i2);
+  i2 = mpn_sec_div_r_itch (nn, pn);
+  itch = MAX (itch, i2);
+  i2 = mpn_sec_powm_itch (qn, mpz_sizeinbase (key->b, 2), qn);
+  itch = MAX (itch, i2);
+  i2 = mpn_sec_powm_itch (pn, mpz_sizeinbase (key->a, 2), pn);
+  itch = MAX (itch, i2);
+  i2 = mpn_sec_div_r_itch (qn, pn);
+  itch = MAX (itch, i2);
+  i2 = mpn_sec_mul_itch (pn, cn);
+  itch = MAX (itch, i2);
+  if (qn > pn)
+    i2 = mpn_sec_mul_itch (qn, pn);
+  else
+    i2 = mpn_sec_mul_itch (pn, qn);
+  itch = MAX (itch, i2);
+  i2 = mpn_sec_div_r_itch (pn + cn, pn);
+  itch = MAX (itch, i2);
+
+  itch += MAX (nn + 1, MAX (pn +cn, qn +cn)) + pn + qn;
+  return itch;
+}
+
+void
+_rsa_sec_compute_root (const struct rsa_private_key *key,
+                       mp_limb_t *rp, const mp_limb_t *mp,
+                       mp_limb_t *scratch)
+{
+  mp_size_t nn = NETTLE_OCTET_SIZE_TO_LIMB_SIZE (key->size);
+
+  /* The common case is pn = qn. This function would be simpler if we
+   * could require that pn >= qn. */
+  const mp_limb_t *pp = mpz_limbs_read (key->p);
+  const mp_limb_t *qp = mpz_limbs_read (key->q);
+
+  mp_size_t cn = mpz_size (key->c);
+  mp_size_t pn = mpz_size (key->p);
+  mp_size_t qn = mpz_size (key->q);
+  mp_size_t tn = nn + 1;
+
+  mp_limb_t *r_mod_p = scratch + MAX (tn, MAX (pn + cn, qn + cn));
+  mp_limb_t *r_mod_q = r_mod_p + pn;
+  mp_limb_t *sp = r_mod_q + qn;
+  mp_limb_t cy;
+
+  assert (pn + qn <= tn);
+  assert (pn <= nn);
+  assert (qn <= nn);
+  assert (cn <= pn);
+
+  /* Compute r_mod_q = m^d % q = (m%q)^b % q */
+  mpn_copyi (scratch, mp, nn);
+  mpn_sec_div_r (scratch, nn, qp, qn, sp);
+  mpn_sec_powm (r_mod_q, scratch, qn, mpz_limbs_read (key->b),
+                mpz_sizeinbase (key->b, 2), qp, qn, sp);
+
+  /* Compute r_mod_p = m^d % p = (m%p)^a % p */
+  mpn_copyi (scratch, mp, nn);
+  mpn_sec_div_r (scratch, nn, pp, pn, sp);
+  mpn_sec_powm (r_mod_p, scratch, pn, mpz_limbs_read (key->a),
+                mpz_sizeinbase (key->a, 2), pp, pn, sp);
+
+  /* Set r_mod_p' = r_mod_p * c % p - r_mod_q * c % p . */
+  mpn_sec_mul (scratch, r_mod_p, pn, mpz_limbs_read (key->c), cn, sp);
+  mpn_sec_div_r (scratch, pn + cn, pp, pn, sp);
+  mpn_copyi (r_mod_p, scratch, pn);
+  mpn_sec_mul (scratch, r_mod_q, qn, mpz_limbs_read (key->c), cn, sp);
+  mpn_sec_div_r (scratch, qn + cn, pp, pn, sp);
+  cy = mpn_sub_n (r_mod_p, r_mod_p, scratch, pn);
+  cnd_add_n (cy, r_mod_p, pp, pn);
+
+  /* Finally, compute x = r_mod_q + q r_mod_p' */
+  if (qn > pn)
+    mpn_sec_mul (scratch, qp, qn, r_mod_p, pn, sp);
+  else
+    mpn_sec_mul (scratch, r_mod_p, pn, qp, qn, sp);
+
+  cy = mpn_add_n (rp, scratch, r_mod_q, qn);
+  mpn_sec_add_1 (rp + qn, scratch + qn, nn - qn, cy, sp);
+}
+#endif
-- 
GitLab