summaryrefslogtreecommitdiff
path: root/cipher/ecc-misc.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2013-09-30 20:17:05 +0200
committerWerner Koch <wk@gnupg.org>2013-09-30 20:44:50 +0200
commitc325adb8f5092b80a626bd3bb5e49cf7f3a29fc8 (patch)
tree256b90ac9ca14a4c6838ac4d361a1da0742dac75 /cipher/ecc-misc.c
parentd69a13d3d1c14ad6a6aa7cd349d6d2dfb152d422 (diff)
downloadlibgcrypt-c325adb8f5092b80a626bd3bb5e49cf7f3a29fc8.tar.gz
ecc: Fix recomputing of Q for Ed25519.
* 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>
Diffstat (limited to 'cipher/ecc-misc.c')
-rw-r--r--cipher/ecc-misc.c86
1 files changed, 80 insertions, 6 deletions
diff --git a/cipher/ecc-misc.c b/cipher/ecc-misc.c
index 1dc0480f..d89971f0 100644
--- a/cipher/ecc-misc.c
+++ b/cipher/ecc-misc.c
@@ -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;
}