diff options
author | Werner Koch <wk@gnupg.org> | 2013-09-30 20:17:05 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2013-09-30 20:44:50 +0200 |
commit | c325adb8f5092b80a626bd3bb5e49cf7f3a29fc8 (patch) | |
tree | 256b90ac9ca14a4c6838ac4d361a1da0742dac75 /cipher/ecc-misc.c | |
parent | d69a13d3d1c14ad6a6aa7cd349d6d2dfb152d422 (diff) | |
download | libgcrypt-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.c | 86 |
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; } |