gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-exchange] branch master updated: copy (un)blinding logic from GNU


From: gnunet
Subject: [taler-exchange] branch master updated: copy (un)blinding logic from GNUnet
Date: Fri, 04 Dec 2020 12:26:00 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository exchange.

The following commit(s) were added to refs/heads/master by this push:
     new 82813b33 copy (un)blinding logic from GNUnet
82813b33 is described below

commit 82813b337cf02ed2306c13a53893814f629bc2f3
Author: Florian Dold <florian@dold.me>
AuthorDate: Fri Dec 4 12:25:58 2020 +0100

    copy (un)blinding logic from GNUnet
---
 src/util/crypto.c | 410 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 407 insertions(+), 3 deletions(-)

diff --git a/src/util/crypto.c b/src/util/crypto.c
index 1b829c9f..dcff5fd2 100644
--- a/src/util/crypto.c
+++ b/src/util/crypto.c
@@ -36,7 +36,7 @@
  * FIXME: Can we define some macro for this in configure.ac
  * to detect the version?
  */
-#define USE_GNUNET_RSA_BLINDING 1
+#define USE_GNUNET_RSA_BLINDING 0
 
 
 /**
@@ -394,6 +394,281 @@ TALER_refresh_get_commitment (struct 
TALER_RefreshCommitmentP *rc,
 }
 
 
+#if ! USE_GNUNET_RSA_BLINDING
+
+
+/**
+ * The private information of an RSA key pair.
+ *
+ * FIXME: This declaration is evil, as it defines
+ * an opaque struct that is "owned" by GNUnet.
+ */
+struct GNUNET_CRYPTO_RsaPrivateKey
+{
+  /**
+   * Libgcrypt S-expression for the RSA private key.
+   */
+  gcry_sexp_t sexp;
+};
+
+
+/**
+ * The public information of an RSA key pair.
+ *
+ * FIXME: This declaration is evil, as it defines
+ * an opaque struct that is "owned" by GNUnet.
+ */
+struct GNUNET_CRYPTO_RsaPublicKey
+{
+  /**
+   * Libgcrypt S-expression for the RSA public key.
+   */
+  gcry_sexp_t sexp;
+};
+
+/**
+ * @brief an RSA signature
+ *
+ * FIXME: This declaration is evil, as it defines
+ * an opaque struct that is "owned" by GNUnet.
+ */
+struct GNUNET_CRYPTO_RsaSignature
+{
+  /**
+   * Libgcrypt S-expression for the RSA signature.
+   */
+  gcry_sexp_t sexp;
+};
+
+/**
+ * @brief RSA blinding key
+ */
+struct RsaBlindingKey
+{
+  /**
+   * Random value used for blinding.
+   */
+  gcry_mpi_t r;
+};
+
+
+/**
+ * Destroy a blinding key
+ *
+ * @param bkey the blinding key to destroy
+ */
+static void
+rsa_blinding_key_free (struct RsaBlindingKey *bkey)
+{
+  gcry_mpi_release (bkey->r);
+  GNUNET_free (bkey);
+}
+
+
+/**
+ * Extract values from an S-expression.
+ *
+ * @param array where to store the result(s)
+ * @param sexp S-expression to parse
+ * @param topname top-level name in the S-expression that is of interest
+ * @param elems names of the elements to extract
+ * @return 0 on success
+ */
+static int
+key_from_sexp (gcry_mpi_t *array,
+               gcry_sexp_t sexp,
+               const char *topname,
+               const char *elems)
+{
+  gcry_sexp_t list;
+  gcry_sexp_t l2;
+  const char *s;
+  unsigned int idx;
+
+  if (! (list = gcry_sexp_find_token (sexp, topname, 0)))
+    return 1;
+  l2 = gcry_sexp_cadr (list);
+  gcry_sexp_release (list);
+  list = l2;
+  if (! list)
+    return 2;
+  idx = 0;
+  for (s = elems; *s; s++, idx++)
+  {
+    if (! (l2 = gcry_sexp_find_token (list, s, 1)))
+    {
+      for (unsigned int i = 0; i < idx; i++)
+      {
+        gcry_free (array[i]);
+        array[i] = NULL;
+      }
+      gcry_sexp_release (list);
+      return 3;                 /* required parameter not found */
+    }
+    array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+    gcry_sexp_release (l2);
+    if (! array[idx])
+    {
+      for (unsigned int i = 0; i < idx; i++)
+      {
+        gcry_free (array[i]);
+        array[i] = NULL;
+      }
+      gcry_sexp_release (list);
+      return 4;                 /* required parameter is invalid */
+    }
+  }
+  gcry_sexp_release (list);
+  return 0;
+}
+
+
+/**
+ * Test for malicious RSA key.
+ *
+ * Assuming n is an RSA modulous and r is generated using a call to
+ * GNUNET_CRYPTO_kdf_mod_mpi, if gcd(r,n) != 1 then n must be a
+ * malicious RSA key designed to deanomize the user.
+ *
+ * @param r KDF result
+ * @param n RSA modulus
+ * @return True if gcd(r,n) = 1, False means RSA key is malicious
+ */
+static int
+rsa_gcd_validate (gcry_mpi_t r, gcry_mpi_t n)
+{
+  gcry_mpi_t g;
+  int t;
+
+  g = gcry_mpi_new (0);
+  t = gcry_mpi_gcd (g, r, n);
+  gcry_mpi_release (g);
+  return t;
+}
+
+
+/**
+ * Computes a full domain hash seeded by the given public key.
+ * This gives a measure of provable security to the Taler exchange
+ * against one-more forgery attacks.  See:
+ *   https://eprint.iacr.org/2001/002.pdf
+ *   http://www.di.ens.fr/~pointche/Documents/Papers/2001_fcA.pdf
+ *
+ * @param hash initial hash of the message to sign
+ * @param pkey the public key of the signer
+ * @param rsize If not NULL, the number of bytes actually stored in buffer
+ * @return MPI value set to the FDH, NULL if RSA key is malicious
+ */
+static gcry_mpi_t
+rsa_full_domain_hash (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
+                      const struct GNUNET_HashCode *hash)
+{
+  gcry_mpi_t r, n;
+  void *xts;
+  size_t xts_len;
+  int ok;
+
+  /* Extract the composite n from the RSA public key */
+  GNUNET_assert (0 == key_from_sexp (&n, pkey->sexp, "rsa", "n"));
+  /* Assert that it at least looks like an RSA key */
+  GNUNET_assert (0 == gcry_mpi_get_flag (n, GCRYMPI_FLAG_OPAQUE));
+
+  /* We key with the public denomination key as a homage to RSA-PSS by  *
+  * Mihir Bellare and Phillip Rogaway.  Doing this lowers the degree   *
+  * of the hypothetical polyomial-time attack on RSA-KTI created by a  *
+  * polynomial-time one-more forgary attack.  Yey seeding!             */
+  xts_len = GNUNET_CRYPTO_rsa_public_key_encode (pkey, &xts);
+
+  GNUNET_CRYPTO_kdf_mod_mpi (&r,
+                             n,
+                             xts, xts_len,
+                             hash, sizeof(*hash),
+                             "RSA-FDA FTpsW!");
+  GNUNET_free (xts);
+
+  ok = rsa_gcd_validate (r, n);
+  gcry_mpi_release (n);
+  if (ok)
+    return r;
+  gcry_mpi_release (r);
+  return NULL;
+}
+
+
+/**
+ * Create a blinding key
+ *
+ * @param len length of the key in bits (i.e. 2048)
+ * @param bks pre-secret to use to derive the blinding key
+ * @return the newly created blinding key, NULL if RSA key is malicious
+ */
+static struct RsaBlindingKey *
+rsa_blinding_key_derive (const struct GNUNET_CRYPTO_RsaPublicKey *pkey,
+                         const struct GNUNET_CRYPTO_RsaBlindingKeySecret *bks)
+{
+  char *xts = "Blinding KDF extractor HMAC key";  /* Trusts bks' randomness 
more */
+  struct RsaBlindingKey *blind;
+  gcry_mpi_t n;
+
+  blind = GNUNET_new (struct RsaBlindingKey);
+  GNUNET_assert (NULL != blind);
+
+  /* Extract the composite n from the RSA public key */
+  GNUNET_assert (0 == key_from_sexp (&n, pkey->sexp, "rsa", "n"));
+  /* Assert that it at least looks like an RSA key */
+  GNUNET_assert (0 == gcry_mpi_get_flag (n, GCRYMPI_FLAG_OPAQUE));
+
+  GNUNET_CRYPTO_kdf_mod_mpi (&blind->r,
+                             n,
+                             xts, strlen (xts),
+                             bks, sizeof(*bks),
+                             "Blinding KDF");
+  if (0 == rsa_gcd_validate (blind->r, n))
+  {
+    GNUNET_free (blind);
+    blind = NULL;
+  }
+
+  gcry_mpi_release (n);
+  return blind;
+}
+
+
+/**
+ * Print an MPI to a newly created buffer
+ *
+ * @param v MPI to print.
+ * @param[out] newly allocated buffer containing the result
+ * @return number of bytes stored in @a buffer
+ */
+static size_t
+numeric_mpi_alloc_n_print (gcry_mpi_t v,
+                           char **buffer)
+{
+  size_t n;
+  char *b;
+  size_t rsize;
+
+  gcry_mpi_print (GCRYMPI_FMT_USG,
+                  NULL,
+                  0,
+                  &n,
+                  v);
+  b = GNUNET_malloc (n);
+  GNUNET_assert (0 ==
+                 gcry_mpi_print (GCRYMPI_FMT_USG,
+                                 (unsigned char *) b,
+                                 n,
+                                 &rsize,
+                                 v));
+  *buffer = b;
+  return n;
+}
+
+
+#endif /* ! USE_GNUNET_RSA_BLINDING */
+
+
 /**
  * Blinds the given message with the given blinding key
  *
@@ -418,7 +693,67 @@ TALER_rsa_blind (const struct GNUNET_HashCode *hash,
                                   buf,
                                   buf_size);
 #else
-# error "FIXME: implement"
+  struct RsaBlindingKey *bkey;
+  gcry_mpi_t data;
+  gcry_mpi_t ne[2];
+  gcry_mpi_t r_e;
+  gcry_mpi_t data_r_e;
+  int ret;
+
+  GNUNET_assert (buf != NULL);
+  GNUNET_assert (buf_size != NULL);
+  ret = key_from_sexp (ne, pkey->sexp, "public-key", "ne");
+  if (0 != ret)
+    ret = key_from_sexp (ne, pkey->sexp, "rsa", "ne");
+  if (0 != ret)
+  {
+    GNUNET_break (0);
+    *buf = NULL;
+    *buf_size = 0;
+    return 0;
+  }
+
+  data = rsa_full_domain_hash (pkey, hash);
+  if (NULL == data)
+    goto rsa_gcd_validate_failure;
+
+  bkey = rsa_blinding_key_derive (pkey, bks);
+  if (NULL == bkey)
+  {
+    gcry_mpi_release (data);
+    goto rsa_gcd_validate_failure;
+  }
+
+  r_e = gcry_mpi_new (0);
+  gcry_mpi_powm (r_e,
+                 bkey->r,
+                 ne[1],
+                 ne[0]);
+  data_r_e = gcry_mpi_new (0);
+  gcry_mpi_mulm (data_r_e,
+                 data,
+                 r_e,
+                 ne[0]);
+  gcry_mpi_release (data);
+  gcry_mpi_release (ne[0]);
+  gcry_mpi_release (ne[1]);
+  gcry_mpi_release (r_e);
+  rsa_blinding_key_free (bkey);
+
+  *buf_size = numeric_mpi_alloc_n_print (data_r_e,
+                                         (char **) buf);
+  gcry_mpi_release (data_r_e);
+
+  return GNUNET_YES;
+
+rsa_gcd_validate_failure:
+  /* We know the RSA key is malicious here, so warn the wallet. */
+  /* GNUNET_break_op (0); */
+  gcry_mpi_release (ne[0]);
+  gcry_mpi_release (ne[1]);
+  *buf = NULL;
+  *buf_size = 0;
+  return GNUNET_NO;
 #endif
 }
 
@@ -443,7 +778,76 @@ TALER_rsa_unblind (const struct GNUNET_CRYPTO_RsaSignature 
*sig,
                                     bks,
                                     pkey);
 #else
-# error "FIXME: implement"
+  struct RsaBlindingKey *bkey;
+  gcry_mpi_t n;
+  gcry_mpi_t s;
+  gcry_mpi_t r_inv;
+  gcry_mpi_t ubsig;
+  int ret;
+  struct GNUNET_CRYPTO_RsaSignature *sret;
+
+  ret = key_from_sexp (&n, pkey->sexp, "public-key", "n");
+  if (0 != ret)
+    ret = key_from_sexp (&n, pkey->sexp, "rsa", "n");
+  if (0 != ret)
+  {
+    GNUNET_break_op (0);
+    return NULL;
+  }
+  ret = key_from_sexp (&s, sig->sexp, "sig-val", "s");
+  if (0 != ret)
+    ret = key_from_sexp (&s, sig->sexp, "rsa", "s");
+  if (0 != ret)
+  {
+    gcry_mpi_release (n);
+    GNUNET_break_op (0);
+    return NULL;
+  }
+
+  bkey = rsa_blinding_key_derive (pkey, bks);
+  if (NULL == bkey)
+  {
+    /* RSA key is malicious since rsa_gcd_validate failed here.
+     * It should have failed during GNUNET_CRYPTO_rsa_blind too though,
+     * so the exchange is being malicious in an unfamilair way, maybe
+     * just trying to crash us.  */
+    GNUNET_break_op (0);
+    gcry_mpi_release (n);
+    gcry_mpi_release (s);
+    return NULL;
+  }
+
+  r_inv = gcry_mpi_new (0);
+  if (1 !=
+      gcry_mpi_invm (r_inv,
+                     bkey->r,
+                     n))
+  {
+    /* We cannot find r mod n, so gcd(r,n) != 1, which should get *
+    * caught above, but we handle it the same here.              */
+    GNUNET_break_op (0);
+    gcry_mpi_release (r_inv);
+    rsa_blinding_key_free (bkey);
+    gcry_mpi_release (n);
+    gcry_mpi_release (s);
+    return NULL;
+  }
+
+  ubsig = gcry_mpi_new (0);
+  gcry_mpi_mulm (ubsig, s, r_inv, n);
+  gcry_mpi_release (n);
+  gcry_mpi_release (r_inv);
+  gcry_mpi_release (s);
+  rsa_blinding_key_free (bkey);
+
+  sret = GNUNET_new (struct GNUNET_CRYPTO_RsaSignature);
+  GNUNET_assert (0 ==
+                 gcry_sexp_build (&sret->sexp,
+                                  NULL,
+                                  "(sig-val (rsa (s %M)))",
+                                  ubsig));
+  gcry_mpi_release (ubsig);
+  return sret;
 #endif
 }
 

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]