ecc: Fix recomputing of Q for Ed25519.
authorWerner Koch <wk@gnupg.org>
Mon, 30 Sep 2013 18:17:05 +0000 (20:17 +0200)
committerWerner Koch <wk@gnupg.org>
Mon, 30 Sep 2013 18:44:50 +0000 (20:44 +0200)
* cipher/ecc-misc.c (reverse_buffer): New.
(_gcry_ecc_compute_public): Add ED255519 specific code.
* cipher/ecc.c (sign_eddsa): Allocate DIGEST in secure memory.  Get
rid of HASH_D.
* tests/t-mpi-point.c (context_param): Test recomputing of Q for
Ed25519.

Signed-off-by: Werner Koch <wk@gnupg.org>
cipher/ecc-misc.c
cipher/ecc.c
tests/t-mpi-point.c

index 1dc0480..d89971f 100644 (file)
@@ -234,22 +234,96 @@ _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value)
 }
 
 
+static void
+reverse_buffer (unsigned char *buffer, unsigned int length)
+{
+  unsigned int tmp, i;
+
+  for (i=0; i < length/2; i++)
+    {
+      tmp = buffer[i];
+      buffer[i] = buffer[length-1-i];
+      buffer[length-1-i] = tmp;
+    }
+}
+
+
 /* Compute the public key from the the context EC.  Obviously a
    requirement is that the secret key is available in EC.  On success
-   Q is returned; on error NULL.  If Q is NULL a newly allocated pint
+   Q is returned; on error NULL.  If Q is NULL a newly allocated point
    is returned.  */
 mpi_point_t
 _gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec)
 {
+  int rc;
+
   if (!ec->d || !ec->G || !ec->p || !ec->a)
     return NULL;
   if (ec->model == MPI_EC_TWISTEDEDWARDS && !ec->b)
     return NULL;
 
-  if (!Q)
-    Q = gcry_mpi_point_new (0);
-  if (!Q)
-    return NULL;
-  _gcry_mpi_ec_mul_point (Q, ec->d, ec->G, ec);
+  switch (ec->dialect)
+    {
+    case ECC_DIALECT_ED25519:
+      {
+        gcry_mpi_t a;
+        unsigned char *rawmpi = NULL;
+        unsigned int rawmpilen;
+        unsigned char *digest;
+        gcry_buffer_t hvec[2];
+        int b = (ec->nbits+7)/8;
+
+        gcry_assert (b >= 32);
+        digest = gcry_calloc_secure (2, b);
+        if (!digest)
+          return NULL;
+        memset (hvec, 0, sizeof hvec);
+
+        rawmpi = _gcry_mpi_get_buffer (ec->d, 0, &rawmpilen, NULL);
+        if (!rawmpi)
+          return NULL;
+        memset (digest, 0, b);
+        hvec[0].data = digest;
+        hvec[0].off = 0;
+        hvec[0].len = b > rawmpilen? b - rawmpilen : 0;
+        hvec[1].data = rawmpi;
+        hvec[1].off = 0;
+        hvec[1].len = rawmpilen;
+        /* FIXME: Put and take the hash algo from the context.  */
+        rc = _gcry_md_hash_buffers (GCRY_MD_SHA512, 0, digest, hvec, 2);
+        gcry_free (rawmpi);
+        if (rc)
+          {
+            gcry_free (digest);
+            return NULL;
+          }
+
+        /* Compute the A value.  */
+        reverse_buffer (digest, 32);  /* Only the first half of the hash.  */
+        digest[0] = (digest[0] & 0x7f) | 0x40;
+        digest[31] &= 0xf8;
+        a = mpi_snew (0);
+        _gcry_mpi_set_buffer (a, digest, 32, 0);
+        gcry_free (digest);
+
+        /* And finally the public key.  */
+        if (!Q)
+          Q = gcry_mpi_point_new (0);
+        if (Q)
+          _gcry_mpi_ec_mul_point (Q, a, ec->G, ec);
+        mpi_free (a);
+      }
+      break;
+
+    default:
+      {
+        if (!Q)
+          Q = gcry_mpi_point_new (0);
+        if (Q)
+          _gcry_mpi_ec_mul_point (Q, ec->d, ec->G, ec);
+      }
+      break;
+    }
+
   return Q;
 }
index abd501f..a7fb90f 100644 (file)
@@ -909,8 +909,7 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
   mpi_ec_t ctx = NULL;
   int b;
   unsigned int tmp;
-  unsigned char hash_d[64];  /* Fixme: malloc in secure memory */
-  unsigned char digest[64];
+  unsigned char *digest;
   gcry_buffer_t hvec[3];
   const void *mbuf;
   size_t mlen;
@@ -938,37 +937,41 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
   r = mpi_new (0);
   ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
                                      skey->E.p, skey->E.a, skey->E.b);
-  b = ctx->nbits/8;
+  b = (ctx->nbits+7)/8;
   if (b != 256/8)
     return GPG_ERR_INTERNAL; /* We only support 256 bit. */
 
+  digest = gcry_calloc_secure (2, b);
+  if (!digest)
+    {
+      rc = gpg_err_code_from_syserror ();
+      goto leave;
+    }
 
-  /* Hash the secret key.  We clear DIGEST so we can use it to left
-     pad the key with zeroes for hashing.  */
+  /* Hash the secret key.  We clear DIGEST so we can use it as input
+     to left pad the key with zeroes for hashing.  */
   rawmpi = _gcry_mpi_get_buffer (skey->d, 0, &rawmpilen, NULL);
   if (!rawmpi)
     {
       rc = gpg_err_code_from_syserror ();
       goto leave;
     }
-  memset (digest, 0, b);
   hvec[0].data = digest;
   hvec[0].off = 0;
   hvec[0].len = b > rawmpilen? b - rawmpilen : 0;
   hvec[1].data = rawmpi;
   hvec[1].off = 0;
   hvec[1].len = rawmpilen;
-  rc = _gcry_md_hash_buffers (hashalgo, 0, hash_d, hvec, 2);
+  rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
   gcry_free (rawmpi); rawmpi = NULL;
   if (rc)
     goto leave;
 
-  /* Compute the A value (this modifies hash_d).  */
-  reverse_buffer (hash_d, 32);  /* Only the first half of the hash.  */
-  hash_d[0] = (hash_d[0] & 0x7f) | 0x40;
-  hash_d[31] &= 0xf8;
-  _gcry_mpi_set_buffer (a, hash_d, 32, 0);
-  /* log_printmpi ("     a", a); */
+  /* Compute the A value (this modifies DIGEST).  */
+  reverse_buffer (digest, 32);  /* Only the first half of the hash.  */
+  digest[0] = (digest[0] & 0x7f) | 0x40;
+  digest[31] &= 0xf8;
+  _gcry_mpi_set_buffer (a, digest, 32, 0);
 
   /* Compute the public key if it has not been supplied as optional
      parameter.  */
@@ -1001,7 +1004,7 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
   if (DBG_CIPHER)
     log_printhex ("     m", mbuf, mlen);
 
-  hvec[0].data = hash_d;
+  hvec[0].data = digest;
   hvec[0].off  = 32;
   hvec[0].len  = 32;
   hvec[1].data = (char*)mbuf;
@@ -1063,6 +1066,7 @@ sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
   gcry_mpi_release (x);
   gcry_mpi_release (y);
   gcry_mpi_release (r);
+  gcry_free (digest);
   _gcry_mpi_ec_free (ctx);
   point_free (&I);
   point_free (&Q);
index 0641779..5a0b311 100644 (file)
@@ -666,9 +666,17 @@ context_param (void)
                          "Ed25519", ctx);
       get_and_cmp_mpi ("q@eddsa", sample_ed25519_q_eddsa, "Ed25519", ctx);
 
-      /* Delete Q by setting d and the clearing d.  The clearing is
+      /* Set d tosee whether Q is correctly re-computed.  */
+      d = hex2mpi (sample_ed25519_d);
+      err = gcry_mpi_ec_set_mpi ("d", d, ctx);
+      if (err)
+        fail ("setting d for Ed25519 failed: %s\n", gpg_strerror (err));
+      gcry_mpi_release (d);
+      get_and_cmp_mpi ("q", sample_ed25519_q, "Ed25519(recompute Q)", ctx);
+
+      /* Delete Q by setting d and then clearing d.  The clearing is
          required so that we can check whether Q has been cleared and
-         because further tests only expect a public key. */
+         because further tests only expect a public key.  */
       d = hex2mpi (sample_ed25519_d);
       err = gcry_mpi_ec_set_mpi ("d", d, ctx);
       if (err)