summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2013-10-23 14:08:29 +0200
committerWerner Koch <wk@gnupg.org>2013-10-23 14:08:29 +0200
commit164eb8c85d773ef4f0939115ec45f5e4b47c1700 (patch)
tree5051b857c0d076627db8be12d5038e07758c2429
parent45f6e6268bfdc4b608beaba6b7086b2286e33c71 (diff)
downloadlibgcrypt-164eb8c85d773ef4f0939115ec45f5e4b47c1700.tar.gz
ecc: Refactor ecc.c
* cipher/ecc-ecdsa.c, cipher/ecc-eddsa.c, cipher/ecc-gost.c: New. * cipher/Makefile.am (EXTRA_libcipher_la_SOURCES): Add new files. * configure.ac (GCRYPT_PUBKEY_CIPHERS): Add new files. * cipher/ecc.c (point_init, point_free): Move to ecc-common.h. (sign_ecdsa): Move to ecc-ecdsa.c as _gcry_ecc_ecdsa_sign. (verify_ecdsa): Move to ecc-ecdsa.c as _gcry_ecc_ecdsa_verify. (sign_gost): Move to ecc-gots.c as _gcry_ecc_gost_sign. (verify_gost): Move to ecc-gost.c as _gcry_ecc_gost_verify. (sign_eddsa): Move to ecc-eddsa.c as _gcry_ecc_eddsa_sign. (verify_eddsa): Move to ecc-eddsa.c as _gcry_ecc_eddsa_verify. (eddsa_generate_key): Move to ecc-eddsa.c as _gcry_ecc_eddsa_genkey. (reverse_buffer): Move to ecc-eddsa.c. (eddsa_encodempi, eddsa_encode_x_y): Ditto. (_gcry_ecc_eddsa_encodepoint, _gcry_ecc_eddsa_decodepoint): Ditto. -- This change should make it easier to add new ECC algorithms. Signed-off-by: Werner Koch <wk@gnupg.org>
-rw-r--r--cipher/Makefile.am1
-rw-r--r--cipher/ecc-common.h31
-rw-r--r--cipher/ecc-ecdsa.c235
-rw-r--r--cipher/ecc-eddsa.c681
-rw-r--r--cipher/ecc-gost.c233
-rw-r--r--cipher/ecc.c1077
-rw-r--r--configure.ac3
7 files changed, 1195 insertions, 1066 deletions
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 3d8149a5..e6b1745d 100644
--- a/cipher/Makefile.am
+++ b/cipher/Makefile.am
@@ -62,6 +62,7 @@ des.c \
dsa.c \
elgamal.c \
ecc.c ecc-curves.c ecc-misc.c ecc-common.h \
+ecc-ecdsa.c ecc-eddsa.c ecc-gost.c \
idea.c \
gost28147.c gost.h \
gostr3411-94.c \
diff --git a/cipher/ecc-common.h b/cipher/ecc-common.h
index 0be1f2c3..0a95b95f 100644
--- a/cipher/ecc-common.h
+++ b/cipher/ecc-common.h
@@ -61,6 +61,9 @@ point_set (mpi_point_t d, mpi_point_t s)
mpi_set (d->z, s->z);
}
+#define point_init(a) _gcry_mpi_point_init ((a))
+#define point_free(a) _gcry_mpi_point_free_parts ((a))
+
/*-- ecc-curves.c --*/
gpg_err_code_t _gcry_ecc_fill_in_curve (unsigned int nbits,
@@ -85,6 +88,15 @@ gcry_error_t _gcry_ecc_os2ec (mpi_point_t result, gcry_mpi_t value);
mpi_point_t _gcry_ecc_compute_public (mpi_point_t Q, mpi_ec_t ec);
/*-- ecc.c --*/
+
+/*-- ecc-ecdsa.c --*/
+gpg_err_code_t _gcry_ecc_ecdsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
+ gcry_mpi_t r, gcry_mpi_t s,
+ int flags, int hashalgo);
+gpg_err_code_t _gcry_ecc_ecdsa_verify (gcry_mpi_t input, ECC_public_key *pkey,
+ gcry_mpi_t r, gcry_mpi_t s);
+
+/*-- ecc-eddsa.c --*/
gpg_err_code_t _gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ctx,
gcry_mpi_t x, gcry_mpi_t y,
unsigned char **r_buffer,
@@ -94,5 +106,24 @@ gpg_err_code_t _gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx,
unsigned char **r_encpk,
unsigned int *r_encpklen);
+gpg_err_code_t _gcry_ecc_eddsa_genkey (ECC_secret_key *sk,
+ elliptic_curve_t *E,
+ mpi_ec_t ctx,
+ gcry_random_level_t random_level);
+gpg_err_code_t _gcry_ecc_eddsa_sign (gcry_mpi_t input,
+ ECC_secret_key *sk,
+ gcry_mpi_t r_r, gcry_mpi_t s,
+ int hashalgo, gcry_mpi_t pk);
+gpg_err_code_t _gcry_ecc_eddsa_verify (gcry_mpi_t input,
+ ECC_public_key *pk,
+ gcry_mpi_t r, gcry_mpi_t s,
+ int hashalgo, gcry_mpi_t pkmpi);
+
+/*-- ecc-gost.c --*/
+gpg_err_code_t _gcry_ecc_gost_sign (gcry_mpi_t input, ECC_secret_key *skey,
+ gcry_mpi_t r, gcry_mpi_t s);
+gpg_err_code_t _gcry_ecc_gost_verify (gcry_mpi_t input, ECC_public_key *pkey,
+ gcry_mpi_t r, gcry_mpi_t s);
+
#endif /*GCRY_ECC_COMMON_H*/
diff --git a/cipher/ecc-ecdsa.c b/cipher/ecc-ecdsa.c
new file mode 100644
index 00000000..70dfe38d
--- /dev/null
+++ b/cipher/ecc-ecdsa.c
@@ -0,0 +1,235 @@
+/* ecc-ecdsa.c - Elliptic Curve ECDSA signatures
+ * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "context.h"
+#include "ec-context.h"
+#include "pubkey-internal.h"
+#include "ecc-common.h"
+
+
+/* Compute an ECDSA signature.
+ * Return the signature struct (r,s) from the message hash. The caller
+ * must have allocated R and S.
+ */
+gpg_err_code_t
+_gcry_ecc_ecdsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
+ gcry_mpi_t r, gcry_mpi_t s,
+ int flags, int hashalgo)
+{
+ gpg_err_code_t err = 0;
+ int extraloops = 0;
+ gcry_mpi_t k, dr, sum, k_1, x;
+ mpi_point_struct I;
+ gcry_mpi_t hash;
+ const void *abuf;
+ unsigned int abits, qbits;
+ mpi_ec_t ctx;
+
+ if (DBG_CIPHER)
+ log_mpidump ("ecdsa sign hash ", input );
+
+ qbits = mpi_get_nbits (skey->E.n);
+
+ /* Convert the INPUT into an MPI if needed. */
+ if (mpi_is_opaque (input))
+ {
+ abuf = gcry_mpi_get_opaque (input, &abits);
+ err = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG,
+ abuf, (abits+7)/8, NULL));
+ if (err)
+ return err;
+ if (abits > qbits)
+ gcry_mpi_rshift (hash, hash, abits - qbits);
+ }
+ else
+ hash = input;
+
+
+ k = NULL;
+ dr = mpi_alloc (0);
+ sum = mpi_alloc (0);
+ k_1 = mpi_alloc (0);
+ x = mpi_alloc (0);
+ point_init (&I);
+
+ ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
+ skey->E.p, skey->E.a, skey->E.b);
+
+ /* Two loops to avoid R or S are zero. This is more of a joke than
+ a real demand because the probability of them being zero is less
+ than any hardware failure. Some specs however require it. */
+ do
+ {
+ do
+ {
+ mpi_free (k);
+ k = NULL;
+ if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo)
+ {
+ /* Use Pornin's method for deterministic DSA. If this
+ flag is set, it is expected that HASH is an opaque
+ MPI with the to be signed hash. That hash is also
+ used as h1 from 3.2.a. */
+ if (!mpi_is_opaque (input))
+ {
+ err = GPG_ERR_CONFLICT;
+ goto leave;
+ }
+
+ abuf = gcry_mpi_get_opaque (input, &abits);
+ err = _gcry_dsa_gen_rfc6979_k (&k, skey->E.n, skey->d,
+ abuf, (abits+7)/8,
+ hashalgo, extraloops);
+ if (err)
+ goto leave;
+ extraloops++;
+ }
+ else
+ k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM);
+
+ _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx);
+ if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx))
+ {
+ if (DBG_CIPHER)
+ log_debug ("ecc sign: Failed to get affine coordinates\n");
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+ mpi_mod (r, x, skey->E.n); /* r = x mod n */
+ }
+ while (!mpi_cmp_ui (r, 0));
+
+ mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */
+ mpi_addm (sum, hash, dr, skey->E.n); /* sum = hash + (d*r) mod n */
+ mpi_invm (k_1, k, skey->E.n); /* k_1 = k^(-1) mod n */
+ mpi_mulm (s, k_1, sum, skey->E.n); /* s = k^(-1)*(hash+(d*r)) mod n */
+ }
+ while (!mpi_cmp_ui (s, 0));
+
+ if (DBG_CIPHER)
+ {
+ log_mpidump ("ecdsa sign result r ", r);
+ log_mpidump ("ecdsa sign result s ", s);
+ }
+
+ leave:
+ _gcry_mpi_ec_free (ctx);
+ point_free (&I);
+ mpi_free (x);
+ mpi_free (k_1);
+ mpi_free (sum);
+ mpi_free (dr);
+ mpi_free (k);
+
+ if (hash != input)
+ mpi_free (hash);
+
+ return err;
+}
+
+
+/* Verify an ECDSA signature.
+ * Check if R and S verifies INPUT.
+ */
+gpg_err_code_t
+_gcry_ecc_ecdsa_verify (gcry_mpi_t input, ECC_public_key *pkey,
+ gcry_mpi_t r, gcry_mpi_t s)
+{
+ gpg_err_code_t err = 0;
+ gcry_mpi_t h, h1, h2, x;
+ mpi_point_struct Q, Q1, Q2;
+ mpi_ec_t ctx;
+
+ if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) )
+ return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */
+ if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) )
+ return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */
+
+ h = mpi_alloc (0);
+ h1 = mpi_alloc (0);
+ h2 = mpi_alloc (0);
+ x = mpi_alloc (0);
+ point_init (&Q);
+ point_init (&Q1);
+ point_init (&Q2);
+
+ ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
+ pkey->E.p, pkey->E.a, pkey->E.b);
+
+ /* h = s^(-1) (mod n) */
+ mpi_invm (h, s, pkey->E.n);
+ /* h1 = hash * s^(-1) (mod n) */
+ mpi_mulm (h1, input, h, pkey->E.n);
+ /* Q1 = [ hash * s^(-1) ]G */
+ _gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx);
+ /* h2 = r * s^(-1) (mod n) */
+ mpi_mulm (h2, r, h, pkey->E.n);
+ /* Q2 = [ r * s^(-1) ]Q */
+ _gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx);
+ /* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */
+ _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx);
+
+ if (!mpi_cmp_ui (Q.z, 0))
+ {
+ if (DBG_CIPHER)
+ log_debug ("ecc verify: Rejected\n");
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+ if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx))
+ {
+ if (DBG_CIPHER)
+ log_debug ("ecc verify: Failed to get affine coordinates\n");
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+ mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */
+ if (mpi_cmp (x, r)) /* x != r */
+ {
+ if (DBG_CIPHER)
+ {
+ log_mpidump (" x", x);
+ log_mpidump (" r", r);
+ log_mpidump (" s", s);
+ }
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+
+ leave:
+ _gcry_mpi_ec_free (ctx);
+ point_free (&Q2);
+ point_free (&Q1);
+ point_free (&Q);
+ mpi_free (x);
+ mpi_free (h2);
+ mpi_free (h1);
+ mpi_free (h);
+ return err;
+}
diff --git a/cipher/ecc-eddsa.c b/cipher/ecc-eddsa.c
new file mode 100644
index 00000000..72103e96
--- /dev/null
+++ b/cipher/ecc-eddsa.c
@@ -0,0 +1,681 @@
+/* ecc-eddsa.c - Elliptic Curve EdDSA signatures
+ * Copyright (C) 2013 g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "context.h"
+#include "ec-context.h"
+#include "ecc-common.h"
+
+
+
+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;
+ }
+}
+
+
+
+/* Encode MPI using the EdDSA scheme. MINLEN specifies the required
+ length of the buffer in bytes. On success 0 is returned an a
+ malloced buffer with the encoded point is stored at R_BUFFER; the
+ length of this buffer is stored at R_BUFLEN. */
+static gpg_err_code_t
+eddsa_encodempi (gcry_mpi_t mpi, unsigned int minlen,
+ unsigned char **r_buffer, unsigned int *r_buflen)
+{
+ unsigned char *rawmpi;
+ unsigned int rawmpilen;
+
+ rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL);
+ if (!rawmpi)
+ return gpg_err_code_from_syserror ();
+
+ *r_buffer = rawmpi;
+ *r_buflen = rawmpilen;
+ return 0;
+}
+
+
+/* Encode (X,Y) using the EdDSA scheme. MINLEN is the required length
+ in bytes for the result. On success 0 is returned and a malloced
+ buffer with the encoded point is stored at R_BUFFER; the length of
+ this buffer is stored at R_BUFLEN. */
+static gpg_err_code_t
+eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int minlen,
+ unsigned char **r_buffer, unsigned int *r_buflen)
+{
+ unsigned char *rawmpi;
+ unsigned int rawmpilen;
+
+ rawmpi = _gcry_mpi_get_buffer (y, minlen, &rawmpilen, NULL);
+ if (!rawmpi)
+ return gpg_err_code_from_syserror ();
+ if (mpi_test_bit (x, 0) && rawmpilen)
+ rawmpi[rawmpilen - 1] |= 0x80; /* Set sign bit. */
+
+ *r_buffer = rawmpi;
+ *r_buflen = rawmpilen;
+ return 0;
+}
+
+/* Encode POINT using the EdDSA scheme. X and Y are either scratch
+ variables supplied by the caller or NULL. CTX is the usual
+ context. On success 0 is returned and a malloced buffer with the
+ encoded point is stored at R_BUFFER; the length of this buffer is
+ stored at R_BUFLEN. */
+gpg_err_code_t
+_gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec,
+ gcry_mpi_t x_in, gcry_mpi_t y_in,
+ unsigned char **r_buffer, unsigned int *r_buflen)
+{
+ gpg_err_code_t rc;
+ gcry_mpi_t x, y;
+
+ x = x_in? x_in : mpi_new (0);
+ y = y_in? y_in : mpi_new (0);
+
+ if (_gcry_mpi_ec_get_affine (x, y, point, ec))
+ {
+ log_error ("eddsa_encodepoint: Failed to get affine coordinates\n");
+ rc = GPG_ERR_INTERNAL;
+ }
+ else
+ rc = eddsa_encode_x_y (x, y, ec->nbits/8, r_buffer, r_buflen);
+
+ if (!x_in)
+ mpi_free (x);
+ if (!y_in)
+ mpi_free (y);
+ return rc;
+}
+
+
+/* Decode the EdDSA style encoded PK and set it into RESULT. CTX is
+ the usual curve context. If R_ENCPK is not NULL, the encoded PK is
+ stored at that address; this is a new copy to be released by the
+ caller. In contrast to the supplied PK, this is not an MPI and
+ thus guarnateed to be properly padded. R_ENCPKLEN received the
+ length of that encoded key. */
+gpg_err_code_t
+_gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result,
+ unsigned char **r_encpk, unsigned int *r_encpklen)
+{
+ gpg_err_code_t rc;
+ unsigned char *rawmpi;
+ unsigned int rawmpilen;
+ gcry_mpi_t yy, t, x, p1, p2, p3;
+ int sign;
+
+ if (mpi_is_opaque (pk))
+ {
+ const unsigned char *buf;
+
+ buf = gcry_mpi_get_opaque (pk, &rawmpilen);
+ if (!buf)
+ return GPG_ERR_INV_OBJ;
+ rawmpilen = (rawmpilen + 7)/8;
+
+ /* First check whether the public key has been given in standard
+ uncompressed format. No need to recover x in this case.
+ Detection is easy: The size of the buffer will be odd and the
+ first byte be 0x04. */
+ if (rawmpilen > 1 && buf[0] == 0x04 && (rawmpilen%2))
+ {
+ gcry_mpi_t y;
+
+ rc = gcry_mpi_scan (&x, GCRYMPI_FMT_STD,
+ buf+1, (rawmpilen-1)/2, NULL);
+ if (rc)
+ return rc;
+ rc = gcry_mpi_scan (&y, GCRYMPI_FMT_STD,
+ buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2, NULL);
+ if (rc)
+ {
+ mpi_free (x);
+ return rc;
+ }
+
+ if (r_encpk)
+ {
+ rc = eddsa_encode_x_y (x, y, ctx->nbits/8, r_encpk, r_encpklen);
+ if (rc)
+ {
+ mpi_free (x);
+ mpi_free (y);
+ return rc;
+ }
+ }
+ mpi_snatch (result->x, x);
+ mpi_snatch (result->y, y);
+ mpi_set_ui (result->z, 1);
+ return 0;
+ }
+
+ /* EdDSA compressed point. */
+ rawmpi = gcry_malloc (rawmpilen? rawmpilen:1);
+ if (!rawmpi)
+ return gpg_err_code_from_syserror ();
+ memcpy (rawmpi, buf, rawmpilen);
+ reverse_buffer (rawmpi, rawmpilen);
+ }
+ else
+ {
+ /* Note: Without using an opaque MPI it is not reliable possible
+ to find out whether the public key has been given in
+ uncompressed format. Thus we expect EdDSA format here. */
+ rawmpi = _gcry_mpi_get_buffer (pk, ctx->nbits/8, &rawmpilen, NULL);
+ if (!rawmpi)
+ return gpg_err_code_from_syserror ();
+ }
+
+ if (rawmpilen)
+ {
+ sign = !!(rawmpi[0] & 0x80);
+ rawmpi[0] &= 0x7f;
+ }
+ else
+ sign = 0;
+ _gcry_mpi_set_buffer (result->y, rawmpi, rawmpilen, 0);
+ if (r_encpk)
+ {
+ /* Revert to little endian. */
+ if (sign && rawmpilen)
+ rawmpi[0] |= 0x80;
+ reverse_buffer (rawmpi, rawmpilen);
+ *r_encpk = rawmpi;
+ if (r_encpklen)
+ *r_encpklen = rawmpilen;
+ }
+ else
+ gcry_free (rawmpi);
+
+ /* Now recover X. */
+ /* t = (y^2-1) · ((b*y^2+1)^{p-2} mod p) */
+ x = mpi_new (0);
+ yy = mpi_new (0);
+ mpi_mul (yy, result->y, result->y);
+ t = mpi_copy (yy);
+ mpi_mul (t, t, ctx->b);
+ mpi_add_ui (t, t, 1);
+ p2 = mpi_copy (ctx->p);
+ mpi_sub_ui (p2, p2, 2);
+ mpi_powm (t, t, p2, ctx->p);
+
+ mpi_sub_ui (yy, yy, 1);
+ mpi_mul (t, yy, t);
+
+ /* x = t^{(p+3)/8} mod p */
+ p3 = mpi_copy (ctx->p);
+ mpi_add_ui (p3, p3, 3);
+ mpi_fdiv_q (p3, p3, mpi_const (MPI_C_EIGHT));
+ mpi_powm (x, t, p3, ctx->p);
+
+ /* (x^2 - t) % p != 0 ? x = (x*(2^{(p-1)/4} mod p)) % p */
+ mpi_mul (yy, x, x);
+ mpi_subm (yy, yy, t, ctx->p);
+ if (mpi_cmp_ui (yy, 0))
+ {
+ p1 = mpi_copy (ctx->p);
+ mpi_sub_ui (p1, p1, 1);
+ mpi_fdiv_q (p1, p1, mpi_const (MPI_C_FOUR));
+ mpi_powm (yy, mpi_const (MPI_C_TWO), p1, ctx->p);
+ mpi_mulm (x, x, yy, ctx->p);
+ }
+ else
+ p1 = NULL;
+
+ /* is_odd(x) ? x = p-x */
+ if (mpi_test_bit (x, 0))
+ mpi_sub (x, ctx->p, x);
+
+ /* lowbit(x) != highbit(input) ? x = p-x */
+ if (mpi_test_bit (x, 0) != sign)
+ mpi_sub (x, ctx->p, x);
+
+ mpi_set (result->x, x);
+ mpi_set_ui (result->z, 1);
+
+ gcry_mpi_release (x);
+ gcry_mpi_release (yy);
+ gcry_mpi_release (t);
+ gcry_mpi_release (p3);
+ gcry_mpi_release (p2);
+ gcry_mpi_release (p1);
+
+ return 0;
+}
+
+
+/* Ed25519 version of the key generation. */
+gpg_err_code_t
+_gcry_ecc_eddsa_genkey (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
+ gcry_random_level_t random_level)
+{
+ gpg_err_code_t rc;
+ int b = 256/8; /* The only size we currently support. */
+ gcry_mpi_t a, x, y;
+ mpi_point_struct Q;
+ char *dbuf;
+ size_t dlen;
+ gcry_buffer_t hvec[1];
+ unsigned char *hash_d = NULL;
+
+ point_init (&Q);
+ memset (hvec, 0, sizeof hvec);
+
+ a = mpi_snew (0);
+ x = mpi_new (0);
+ y = mpi_new (0);
+
+ /* Generate a secret. */
+ hash_d = gcry_malloc_secure (2*b);
+ if (!hash_d)
+ {
+ rc = gpg_error_from_syserror ();
+ goto leave;
+ }
+ dlen = b;
+ dbuf = gcry_random_bytes_secure (dlen, random_level);
+
+ /* Compute the A value. */
+ hvec[0].data = dbuf;
+ hvec[0].len = dlen;
+ rc = _gcry_md_hash_buffers (GCRY_MD_SHA512, 0, hash_d, hvec, 1);
+ if (rc)
+ goto leave;
+ sk->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8);
+ dbuf = NULL;
+ 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);
+ gcry_free (hash_d); hash_d = NULL;
+ /* log_printmpi ("ecgen a", a); */
+
+ /* Compute Q. */
+ _gcry_mpi_ec_mul_point (&Q, a, &E->G, ctx);
+ if (DBG_CIPHER)
+ log_printpnt ("ecgen pk", &Q, ctx);
+
+ /* Copy the stuff to the key structures. */
+ sk->E.model = E->model;
+ sk->E.dialect = E->dialect;
+ sk->E.p = mpi_copy (E->p);
+ sk->E.a = mpi_copy (E->a);
+ sk->E.b = mpi_copy (E->b);
+ point_init (&sk->E.G);
+ point_set (&sk->E.G, &E->G);
+ sk->E.n = mpi_copy (E->n);
+ point_init (&sk->Q);
+ point_set (&sk->Q, &Q);
+
+ leave:
+ gcry_mpi_release (a);
+ gcry_mpi_release (x);
+ gcry_mpi_release (y);
+ gcry_free (hash_d);
+ return rc;
+}
+
+
+/* Compute an EdDSA signature. See:
+ * [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja
+ * Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security
+ * signatures. Journal of Cryptographic Engineering 2 (2012), 77-89.
+ * Document ID: a1a62a2f76d23f65d622484ddd09caf8.
+ * URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26.
+ *
+ * Despite that this function requires the specification of a hash
+ * algorithm, we only support what has been specified by the paper.
+ * This may change in the future. Note that we don't check the used
+ * curve; the user is responsible to use Ed25519.
+ *
+ * Return the signature struct (r,s) from the message hash. The caller
+ * must have allocated R_R and S.
+ */
+gpg_err_code_t
+_gcry_ecc_eddsa_sign (gcry_mpi_t input, ECC_secret_key *skey,
+ gcry_mpi_t r_r, gcry_mpi_t s, int hashalgo, gcry_mpi_t pk)
+{
+ int rc;
+ mpi_ec_t ctx = NULL;
+ int b;
+ unsigned int tmp;
+ unsigned char *digest;
+ gcry_buffer_t hvec[3];
+ const void *mbuf;
+ size_t mlen;
+ unsigned char *rawmpi = NULL;
+ unsigned int rawmpilen;
+ unsigned char *encpk = NULL; /* Encoded public key. */
+ unsigned int encpklen;
+ mpi_point_struct I; /* Intermediate value. */
+ mpi_point_struct Q; /* Public key. */
+ gcry_mpi_t a, x, y, r;
+
+ memset (hvec, 0, sizeof hvec);
+
+ if (!mpi_is_opaque (input))
+ return GPG_ERR_INV_DATA;
+ if (hashalgo != GCRY_MD_SHA512)
+ return GPG_ERR_DIGEST_ALGO;
+
+ /* Initialize some helpers. */
+ point_init (&I);
+ point_init (&Q);
+ a = mpi_snew (0);
+ x = mpi_new (0);
+ y = mpi_new (0);
+ 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+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 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;
+ }
+ 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, digest, hvec, 2);
+ gcry_free (rawmpi); rawmpi = NULL;
+ if (rc)
+ goto leave;
+
+ /* 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. */
+ if (pk)
+ {
+ rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_printhex ("* e_pk", encpk, encpklen);
+ if (!_gcry_mpi_ec_curve_point (&Q, ctx))
+ {
+ rc = GPG_ERR_BROKEN_PUBKEY;
+ goto leave;
+ }
+ }
+ else
+ {
+ _gcry_mpi_ec_mul_point (&Q, a, &skey->E.G, ctx);
+ rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, &encpk, &encpklen);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_printhex (" e_pk", encpk, encpklen);
+ }
+
+ /* Compute R. */
+ mbuf = gcry_mpi_get_opaque (input, &tmp);
+ mlen = (tmp +7)/8;
+ if (DBG_CIPHER)
+ log_printhex (" m", mbuf, mlen);
+
+ hvec[0].data = digest;
+ hvec[0].off = 32;
+ hvec[0].len = 32;
+ hvec[1].data = (char*)mbuf;
+ hvec[1].len = mlen;
+ rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
+ if (rc)
+ goto leave;
+ reverse_buffer (digest, 64);
+ if (DBG_CIPHER)
+ log_printhex (" r", digest, 64);
+ _gcry_mpi_set_buffer (r, digest, 64, 0);
+ _gcry_mpi_ec_mul_point (&I, r, &skey->E.G, ctx);
+ if (DBG_CIPHER)
+ log_printpnt (" r", &I, ctx);
+
+ /* Convert R into affine coordinates and apply encoding. */
+ rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, &rawmpi, &rawmpilen);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_printhex (" e_r", rawmpi, rawmpilen);
+
+ /* S = r + a * H(encodepoint(R) + encodepoint(pk) + m) mod n */
+ hvec[0].data = rawmpi; /* (this is R) */
+ hvec[0].off = 0;
+ hvec[0].len = rawmpilen;
+ hvec[1].data = encpk;
+ hvec[1].off = 0;
+ hvec[1].len = encpklen;
+ hvec[2].data = (char*)mbuf;
+ hvec[2].off = 0;
+ hvec[2].len = mlen;
+ rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
+ if (rc)
+ goto leave;
+
+ /* No more need for RAWMPI thus we now transfer it to R_R. */
+ gcry_mpi_set_opaque (r_r, rawmpi, rawmpilen*8);
+ rawmpi = NULL;
+
+ reverse_buffer (digest, 64);
+ if (DBG_CIPHER)
+ log_printhex (" H(R+)", digest, 64);
+ _gcry_mpi_set_buffer (s, digest, 64, 0);
+ mpi_mulm (s, s, a, skey->E.n);
+ mpi_addm (s, s, r, skey->E.n);
+ rc = eddsa_encodempi (s, b, &rawmpi, &rawmpilen);
+ if (rc)
+ goto leave;
+ if (DBG_CIPHER)
+ log_printhex (" e_s", rawmpi, rawmpilen);
+ gcry_mpi_set_opaque (s, rawmpi, rawmpilen*8);
+ rawmpi = NULL;
+
+ rc = 0;
+
+ leave:
+ gcry_mpi_release (a);
+ 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);
+ gcry_free (encpk);
+ gcry_free (rawmpi);
+ return rc;
+}
+
+
+/* Verify an EdDSA signature. See sign_eddsa for the reference.
+ * Check if R_IN and S_IN verifies INPUT. PKEY has the curve
+ * parameters and PK is the EdDSA style encoded public key.
+ */
+gpg_err_code_t
+_gcry_ecc_eddsa_verify (gcry_mpi_t input, ECC_public_key *pkey,
+ gcry_mpi_t r_in, gcry_mpi_t s_in, int hashalgo,
+ gcry_mpi_t pk)
+{
+ int rc;
+ mpi_ec_t ctx = NULL;
+ int b;
+ unsigned int tmp;
+ mpi_point_struct Q; /* Public key. */
+ unsigned char *encpk = NULL; /* Encoded public key. */
+ unsigned int encpklen;
+ const void *mbuf, *rbuf;
+ unsigned char *tbuf = NULL;
+ size_t mlen, rlen;
+ unsigned int tlen;
+ unsigned char digest[64];
+ gcry_buffer_t hvec[3];
+ gcry_mpi_t h, s;
+ mpi_point_struct Ia, Ib;
+
+ if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in))
+ return GPG_ERR_INV_DATA;
+ if (hashalgo != GCRY_MD_SHA512)
+ return GPG_ERR_DIGEST_ALGO;
+
+ point_init (&Q);
+ point_init (&Ia);
+ point_init (&Ib);
+ h = mpi_new (0);
+ s = mpi_new (0);
+
+ ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
+ pkey->E.p, pkey->E.a, pkey->E.b);
+ b = ctx->nbits/8;
+ if (b != 256/8)
+ return GPG_ERR_INTERNAL; /* We only support 256 bit. */
+
+ /* Decode and check the public key. */
+ rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen);
+ if (rc)
+ goto leave;
+ if (!_gcry_mpi_ec_curve_point (&Q, ctx))
+ {
+ rc = GPG_ERR_BROKEN_PUBKEY;
+ goto leave;
+ }
+ if (DBG_CIPHER)
+ log_printhex (" e_pk", encpk, encpklen);
+ if (encpklen != b)
+ {
+ rc = GPG_ERR_INV_LENGTH;
+ goto leave;
+ }
+
+ /* Convert the other input parameters. */
+ mbuf = gcry_mpi_get_opaque (input, &tmp);
+ mlen = (tmp +7)/8;
+ if (DBG_CIPHER)
+ log_printhex (" m", mbuf, mlen);
+ rbuf = gcry_mpi_get_opaque (r_in, &tmp);
+ rlen = (tmp +7)/8;
+ if (DBG_CIPHER)
+ log_printhex (" r", rbuf, rlen);
+ if (rlen != b)
+ {
+ rc = GPG_ERR_INV_LENGTH;
+ goto leave;
+ }
+
+ /* h = H(encodepoint(R) + encodepoint(pk) + m) */
+ hvec[0].data = (char*)rbuf;
+ hvec[0].off = 0;
+ hvec[0].len = rlen;
+ hvec[1].data = encpk;
+ hvec[1].off = 0;
+ hvec[1].len = encpklen;
+ hvec[2].data = (char*)mbuf;
+ hvec[2].off = 0;
+ hvec[2].len = mlen;
+ rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
+ if (rc)
+ goto leave;
+ reverse_buffer (digest, 64);
+ if (DBG_CIPHER)
+ log_printhex (" H(R+)", digest, 64);
+ _gcry_mpi_set_buffer (h, digest, 64, 0);
+
+ /* According to the paper the best way for verification is:
+ encodepoint(sG - h·Q) = encodepoint(r)
+ because we don't need to decode R. */
+ {
+ void *sbuf;
+ unsigned int slen;
+
+ sbuf = _gcry_mpi_get_opaque_copy (s_in, &tmp);
+ slen = (tmp +7)/8;
+ reverse_buffer (sbuf, slen);
+ if (DBG_CIPHER)
+ log_printhex (" s", sbuf, slen);
+ _gcry_mpi_set_buffer (s, sbuf, slen, 0);
+ gcry_free (sbuf);
+ if (slen != b)
+ {
+ rc = GPG_ERR_INV_LENGTH;
+ goto leave;
+ }
+ }
+
+ _gcry_mpi_ec_mul_point (&Ia, s, &pkey->E.G, ctx);
+ _gcry_mpi_ec_mul_point (&Ib, h, &Q, ctx);
+ _gcry_mpi_neg (Ib.x, Ib.x);
+ _gcry_mpi_ec_add_points (&Ia, &Ia, &Ib, ctx);
+ rc = _gcry_ecc_eddsa_encodepoint (&Ia, ctx, s, h, &tbuf, &tlen);
+ if (rc)
+ goto leave;
+ if (tlen != rlen || memcmp (tbuf, rbuf, tlen))
+ {
+ rc = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+
+ rc = 0;
+
+ leave:
+ gcry_free (encpk);
+ gcry_free (tbuf);
+ _gcry_mpi_ec_free (ctx);
+ gcry_mpi_release (s);
+ gcry_mpi_release (h);
+ point_free (&Ia);
+ point_free (&Ib);
+ point_free (&Q);
+ return rc;
+}
diff --git a/cipher/ecc-gost.c b/cipher/ecc-gost.c
new file mode 100644
index 00000000..1ebfd392
--- /dev/null
+++ b/cipher/ecc-gost.c
@@ -0,0 +1,233 @@
+/* ecc-gots.c - Elliptic Curve GOST signatures
+ * Copyright (C) 2007, 2008, 2010, 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Dmitry Eremin-Solenikov
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "g10lib.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "context.h"
+#include "ec-context.h"
+#include "ecc-common.h"
+
+
+/* Compute an GOST R 34.10-01/-12 signature.
+ * Return the signature struct (r,s) from the message hash. The caller
+ * must have allocated R and S.
+ */
+gpg_err_code_t
+_gcry_ecc_gost_sign (gcry_mpi_t input, ECC_secret_key *skey,
+ gcry_mpi_t r, gcry_mpi_t s)
+{
+ gpg_err_code_t err = 0;
+ gcry_mpi_t k, dr, sum, ke, x, e;
+ mpi_point_struct I;
+ gcry_mpi_t hash;
+ const void *abuf;
+ unsigned int abits, qbits;
+ mpi_ec_t ctx;
+
+ if (DBG_CIPHER)
+ log_mpidump ("gost sign hash ", input );
+
+ qbits = mpi_get_nbits (skey->E.n);
+
+ /* Convert the INPUT into an MPI if needed. */
+ if (mpi_is_opaque (input))
+ {
+ abuf = gcry_mpi_get_opaque (input, &abits);
+ err = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG,
+ abuf, (abits+7)/8, NULL));
+ if (err)
+ return err;
+ if (abits > qbits)
+ gcry_mpi_rshift (hash, hash, abits - qbits);
+ }
+ else
+ hash = input;
+
+
+ k = NULL;
+ dr = mpi_alloc (0);
+ sum = mpi_alloc (0);
+ ke = mpi_alloc (0);
+ e = mpi_alloc (0);
+ x = mpi_alloc (0);
+ point_init (&I);
+
+ ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
+ skey->E.p, skey->E.a, skey->E.b);
+
+ mpi_mod (e, input, skey->E.n); /* e = hash mod n */
+
+ if (!mpi_cmp_ui (e, 0))
+ mpi_set_ui (e, 1);
+
+ /* Two loops to avoid R or S are zero. This is more of a joke than
+ a real demand because the probability of them being zero is less
+ than any hardware failure. Some specs however require it. */
+ do
+ {
+ do
+ {
+ mpi_free (k);
+ k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM);
+
+ _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx);
+ if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx))
+ {
+ if (DBG_CIPHER)
+ log_debug ("ecc sign: Failed to get affine coordinates\n");
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+ mpi_mod (r, x, skey->E.n); /* r = x mod n */
+ }
+ while (!mpi_cmp_ui (r, 0));
+ mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */
+ mpi_mulm (ke, k, e, skey->E.n); /* ke = k*e mod n */
+ mpi_addm (s, ke, dr, skey->E.n); /* sum = (k*e+ d*r) mod n */
+ }
+ while (!mpi_cmp_ui (s, 0));
+
+ if (DBG_CIPHER)
+ {
+ log_mpidump ("gost sign result r ", r);
+ log_mpidump ("gost sign result s ", s);
+ }
+
+ leave:
+ _gcry_mpi_ec_free (ctx);
+ point_free (&I);
+ mpi_free (x);
+ mpi_free (e);
+ mpi_free (ke);
+ mpi_free (sum);
+ mpi_free (dr);
+ mpi_free (k);
+
+ if (hash != input)
+ mpi_free (hash);
+
+ return err;
+}
+
+
+/* Verify a GOST R 34.10-01/-12 signature.
+ * Check if R and S verifies INPUT.
+ */
+gpg_err_code_t
+_gcry_ecc_gost_verify (gcry_mpi_t input, ECC_public_key *pkey,
+ gcry_mpi_t r, gcry_mpi_t s)
+{
+ gpg_err_code_t err = 0;
+ gcry_mpi_t e, x, z1, z2, v, rv, zero;
+ mpi_point_struct Q, Q1, Q2;
+ mpi_ec_t ctx;
+
+ if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) )
+ return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */
+ if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) )
+ return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */
+
+ x = mpi_alloc (0);
+ e = mpi_alloc (0);
+ z1 = mpi_alloc (0);
+ z2 = mpi_alloc (0);
+ v = mpi_alloc (0);
+ rv = mpi_alloc (0);
+ zero = mpi_alloc (0);
+
+ point_init (&Q);
+ point_init (&Q1);
+ point_init (&Q2);
+
+ ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
+ pkey->E.p, pkey->E.a, pkey->E.b);
+
+ mpi_mod (e, input, pkey->E.n); /* e = hash mod n */
+ if (!mpi_cmp_ui (e, 0))
+ mpi_set_ui (e, 1);
+ mpi_invm (v, e, pkey->E.n); /* v = e^(-1) (mod n) */
+ mpi_mulm (z1, s, v, pkey->E.n); /* z1 = s*v (mod n) */
+ mpi_mulm (rv, r, v, pkey->E.n); /* rv = s*v (mod n) */
+ mpi_subm (z2, zero, rv, pkey->E.n); /* z2 = -r*v (mod n) */
+
+ _gcry_mpi_ec_mul_point (&Q1, z1, &pkey->E.G, ctx);
+/* log_mpidump ("Q1.x", Q1.x); */
+/* log_mpidump ("Q1.y", Q1.y); */
+/* log_mpidump ("Q1.z", Q1.z); */
+ _gcry_mpi_ec_mul_point (&Q2, z2, &pkey->Q, ctx);
+/* log_mpidump ("Q2.x", Q2.x); */
+/* log_mpidump ("Q2.y", Q2.y); */
+/* log_mpidump ("Q2.z", Q2.z); */
+ _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx);
+/* log_mpidump (" Q.x", Q.x); */
+/* log_mpidump (" Q.y", Q.y); */
+/* log_mpidump (" Q.z", Q.z); */
+
+ if (!mpi_cmp_ui (Q.z, 0))
+ {
+ if (DBG_CIPHER)
+ log_debug ("ecc verify: Rejected\n");
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+ if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx))
+ {
+ if (DBG_CIPHER)
+ log_debug ("ecc verify: Failed to get affine coordinates\n");
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+ mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */
+ if (mpi_cmp (x, r)) /* x != r */
+ {
+ if (DBG_CIPHER)
+ {
+ log_mpidump (" x", x);
+ log_mpidump (" r", r);
+ log_mpidump (" s", s);
+ log_debug ("ecc verify: Not verified\n");
+ }
+ err = GPG_ERR_BAD_SIGNATURE;
+ goto leave;
+ }
+ if (DBG_CIPHER)
+ log_debug ("ecc verify: Accepted\n");
+
+ leave:
+ _gcry_mpi_ec_free (ctx);
+ point_free (&Q2);
+ point_free (&Q1);
+ point_free (&Q);
+ mpi_free (zero);
+ mpi_free (rv);
+ mpi_free (v);
+ mpi_free (z2);
+ mpi_free (z1);
+ mpi_free (x);
+ mpi_free (e);
+ return err;
+}
diff --git a/cipher/ecc.c b/cipher/ecc.c
index 27747182..dca04234 100644
--- a/cipher/ecc.c
+++ b/cipher/ecc.c
@@ -81,19 +81,10 @@ static void (*progress_cb) (void *, const char*, int, int, int);
static void *progress_cb_data;
-#define point_init(a) _gcry_mpi_point_init ((a))
-#define point_free(a) _gcry_mpi_point_free_parts ((a))
-
/* Local prototypes. */
static void test_keys (ECC_secret_key * sk, unsigned int nbits);
static int check_secret_key (ECC_secret_key * sk);
-static gpg_err_code_t sign_ecdsa (gcry_mpi_t input, ECC_secret_key *skey,
- gcry_mpi_t r, gcry_mpi_t s,
- int flags, int hashalgo);
-static gpg_err_code_t verify_ecdsa (gcry_mpi_t input, ECC_public_key *pkey,
- gcry_mpi_t r, gcry_mpi_t s);
-
static gcry_mpi_t gen_y_2 (gcry_mpi_t x, elliptic_curve_t * base);
static unsigned int ecc_get_nbits (gcry_sexp_t parms);
@@ -261,10 +252,10 @@ test_keys (ECC_secret_key *sk, unsigned int nbits)
gcry_mpi_randomize (test, nbits, GCRY_WEAK_RANDOM);
- if (sign_ecdsa (test, sk, r, s, 0, 0) )
+ if (_gcry_ecc_ecdsa_sign (test, sk, r, s, 0, 0) )
log_fatal ("ECDSA operation: sign failed\n");
- if (verify_ecdsa (test, &pk, r, s))
+ if (_gcry_ecc_ecdsa_verify (test, &pk, r, s))
{
log_fatal ("ECDSA operation: sign, verify failed\n");
}
@@ -389,1052 +380,6 @@ check_secret_key (ECC_secret_key * sk)
}
-/* Compute an ECDSA signature.
- * Return the signature struct (r,s) from the message hash. The caller
- * must have allocated R and S.
- */
-static gpg_err_code_t
-sign_ecdsa (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s,
- int flags, int hashalgo)
-{
- gpg_err_code_t err = 0;
- int extraloops = 0;
- gcry_mpi_t k, dr, sum, k_1, x;
- mpi_point_struct I;
- gcry_mpi_t hash;
- const void *abuf;
- unsigned int abits, qbits;
- mpi_ec_t ctx;
-
- if (DBG_CIPHER)
- log_mpidump ("ecdsa sign hash ", input );
-
- qbits = mpi_get_nbits (skey->E.n);
-
- /* Convert the INPUT into an MPI if needed. */
- if (mpi_is_opaque (input))
- {
- abuf = gcry_mpi_get_opaque (input, &abits);
- err = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG,
- abuf, (abits+7)/8, NULL));
- if (err)
- return err;
- if (abits > qbits)
- gcry_mpi_rshift (hash, hash, abits - qbits);
- }
- else
- hash = input;
-
-
- k = NULL;
- dr = mpi_alloc (0);
- sum = mpi_alloc (0);
- k_1 = mpi_alloc (0);
- x = mpi_alloc (0);
- point_init (&I);
-
- ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
- skey->E.p, skey->E.a, skey->E.b);
-
- /* Two loops to avoid R or S are zero. This is more of a joke than
- a real demand because the probability of them being zero is less
- than any hardware failure. Some specs however require it. */
- do
- {
- do
- {
- mpi_free (k);
- k = NULL;
- if ((flags & PUBKEY_FLAG_RFC6979) && hashalgo)
- {
- /* Use Pornin's method for deterministic DSA. If this
- flag is set, it is expected that HASH is an opaque
- MPI with the to be signed hash. That hash is also
- used as h1 from 3.2.a. */
- if (!mpi_is_opaque (input))
- {
- err = GPG_ERR_CONFLICT;
- goto leave;
- }
-
- abuf = gcry_mpi_get_opaque (input, &abits);
- err = _gcry_dsa_gen_rfc6979_k (&k, skey->E.n, skey->d,
- abuf, (abits+7)/8,
- hashalgo, extraloops);
- if (err)
- goto leave;
- extraloops++;
- }
- else
- k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM);
-
- _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx);
- if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx))
- {
- if (DBG_CIPHER)
- log_debug ("ecc sign: Failed to get affine coordinates\n");
- err = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- mpi_mod (r, x, skey->E.n); /* r = x mod n */
- }
- while (!mpi_cmp_ui (r, 0));
-
- mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */
- mpi_addm (sum, hash, dr, skey->E.n); /* sum = hash + (d*r) mod n */
- mpi_invm (k_1, k, skey->E.n); /* k_1 = k^(-1) mod n */
- mpi_mulm (s, k_1, sum, skey->E.n); /* s = k^(-1)*(hash+(d*r)) mod n */
- }
- while (!mpi_cmp_ui (s, 0));
-
- if (DBG_CIPHER)
- {
- log_mpidump ("ecdsa sign result r ", r);
- log_mpidump ("ecdsa sign result s ", s);
- }
-
- leave:
- _gcry_mpi_ec_free (ctx);
- point_free (&I);
- mpi_free (x);
- mpi_free (k_1);
- mpi_free (sum);
- mpi_free (dr);
- mpi_free (k);
-
- if (hash != input)
- mpi_free (hash);
-
- return err;
-}
-
-
-/* Verify an ECDSA signature.
- * Check if R and S verifies INPUT.
- */
-static gpg_err_code_t
-verify_ecdsa (gcry_mpi_t input, ECC_public_key *pkey,
- gcry_mpi_t r, gcry_mpi_t s)
-{
- gpg_err_code_t err = 0;
- gcry_mpi_t h, h1, h2, x;
- mpi_point_struct Q, Q1, Q2;
- mpi_ec_t ctx;
-
- if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) )
- return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */
- if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) )
- return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */
-
- h = mpi_alloc (0);
- h1 = mpi_alloc (0);
- h2 = mpi_alloc (0);
- x = mpi_alloc (0);
- point_init (&Q);
- point_init (&Q1);
- point_init (&Q2);
-
- ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
- pkey->E.p, pkey->E.a, pkey->E.b);
-
- /* h = s^(-1) (mod n) */
- mpi_invm (h, s, pkey->E.n);
- /* h1 = hash * s^(-1) (mod n) */
- mpi_mulm (h1, input, h, pkey->E.n);
- /* Q1 = [ hash * s^(-1) ]G */
- _gcry_mpi_ec_mul_point (&Q1, h1, &pkey->E.G, ctx);
- /* h2 = r * s^(-1) (mod n) */
- mpi_mulm (h2, r, h, pkey->E.n);
- /* Q2 = [ r * s^(-1) ]Q */
- _gcry_mpi_ec_mul_point (&Q2, h2, &pkey->Q, ctx);
- /* Q = ([hash * s^(-1)]G) + ([r * s^(-1)]Q) */
- _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx);
-
- if (!mpi_cmp_ui (Q.z, 0))
- {
- if (DBG_CIPHER)
- log_debug ("ecc verify: Rejected\n");
- err = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx))
- {
- if (DBG_CIPHER)
- log_debug ("ecc verify: Failed to get affine coordinates\n");
- err = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */
- if (mpi_cmp (x, r)) /* x != r */
- {
- if (DBG_CIPHER)
- {
- log_mpidump (" x", x);
- log_mpidump (" r", r);
- log_mpidump (" s", s);
- }
- err = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
-
- leave:
- _gcry_mpi_ec_free (ctx);
- point_free (&Q2);
- point_free (&Q1);
- point_free (&Q);
- mpi_free (x);
- mpi_free (h2);
- mpi_free (h1);
- mpi_free (h);
- return err;
-}
-
-/* Compute an GOST R 34.10-01/-12 signature.
- * Return the signature struct (r,s) from the message hash. The caller
- * must have allocated R and S.
- */
-static gpg_err_code_t
-sign_gost (gcry_mpi_t input, ECC_secret_key *skey, gcry_mpi_t r, gcry_mpi_t s)
-{
- gpg_err_code_t err = 0;
- gcry_mpi_t k, dr, sum, ke, x, e;
- mpi_point_struct I;
- gcry_mpi_t hash;
- const void *abuf;
- unsigned int abits, qbits;
- mpi_ec_t ctx;
-
- if (DBG_CIPHER)
- log_mpidump ("gost sign hash ", input );
-
- qbits = mpi_get_nbits (skey->E.n);
-
- /* Convert the INPUT into an MPI if needed. */
- if (mpi_is_opaque (input))
- {
- abuf = gcry_mpi_get_opaque (input, &abits);
- err = gpg_err_code (gcry_mpi_scan (&hash, GCRYMPI_FMT_USG,
- abuf, (abits+7)/8, NULL));
- if (err)
- return err;
- if (abits > qbits)
- gcry_mpi_rshift (hash, hash, abits - qbits);
- }
- else
- hash = input;
-
-
- k = NULL;
- dr = mpi_alloc (0);
- sum = mpi_alloc (0);
- ke = mpi_alloc (0);
- e = mpi_alloc (0);
- x = mpi_alloc (0);
- point_init (&I);
-
- ctx = _gcry_mpi_ec_p_internal_new (skey->E.model, skey->E.dialect,
- skey->E.p, skey->E.a, skey->E.b);
-
- mpi_mod (e, input, skey->E.n); /* e = hash mod n */
-
- if (!mpi_cmp_ui (e, 0))
- mpi_set_ui (e, 1);
-
- /* Two loops to avoid R or S are zero. This is more of a joke than
- a real demand because the probability of them being zero is less
- than any hardware failure. Some specs however require it. */
- do
- {
- do
- {
- mpi_free (k);
- k = _gcry_dsa_gen_k (skey->E.n, GCRY_STRONG_RANDOM);
-
- _gcry_mpi_ec_mul_point (&I, k, &skey->E.G, ctx);
- if (_gcry_mpi_ec_get_affine (x, NULL, &I, ctx))
- {
- if (DBG_CIPHER)
- log_debug ("ecc sign: Failed to get affine coordinates\n");
- err = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- mpi_mod (r, x, skey->E.n); /* r = x mod n */
- }
- while (!mpi_cmp_ui (r, 0));
- mpi_mulm (dr, skey->d, r, skey->E.n); /* dr = d*r mod n */
- mpi_mulm (ke, k, e, skey->E.n); /* ke = k*e mod n */
- mpi_addm (s, ke, dr, skey->E.n); /* sum = (k*e+ d*r) mod n */
- }
- while (!mpi_cmp_ui (s, 0));
-
- if (DBG_CIPHER)
- {
- log_mpidump ("gost sign result r ", r);
- log_mpidump ("gost sign result s ", s);
- }
-
- leave:
- _gcry_mpi_ec_free (ctx);
- point_free (&I);
- mpi_free (x);
- mpi_free (e);
- mpi_free (ke);
- mpi_free (sum);
- mpi_free (dr);
- mpi_free (k);
-
- if (hash != input)
- mpi_free (hash);
-
- return err;
-}
-
-/* Verify a GOST R 34.10-01/-12 signature.
- * Check if R and S verifies INPUT.
- */
-static gpg_err_code_t
-verify_gost (gcry_mpi_t input, ECC_public_key *pkey,
- gcry_mpi_t r, gcry_mpi_t s)
-{
- gpg_err_code_t err = 0;
- gcry_mpi_t e, x, z1, z2, v, rv, zero;
- mpi_point_struct Q, Q1, Q2;
- mpi_ec_t ctx;
-
- if( !(mpi_cmp_ui (r, 0) > 0 && mpi_cmp (r, pkey->E.n) < 0) )
- return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < r < n failed. */
- if( !(mpi_cmp_ui (s, 0) > 0 && mpi_cmp (s, pkey->E.n) < 0) )
- return GPG_ERR_BAD_SIGNATURE; /* Assertion 0 < s < n failed. */
-
- x = mpi_alloc (0);
- e = mpi_alloc (0);
- z1 = mpi_alloc (0);
- z2 = mpi_alloc (0);
- v = mpi_alloc (0);
- rv = mpi_alloc (0);
- zero = mpi_alloc (0);
-
- point_init (&Q);
- point_init (&Q1);
- point_init (&Q2);
-
- ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
- pkey->E.p, pkey->E.a, pkey->E.b);
-
- mpi_mod (e, input, pkey->E.n); /* e = hash mod n */
- if (!mpi_cmp_ui (e, 0))
- mpi_set_ui (e, 1);
- mpi_invm (v, e, pkey->E.n); /* v = e^(-1) (mod n) */
- mpi_mulm (z1, s, v, pkey->E.n); /* z1 = s*v (mod n) */
- mpi_mulm (rv, r, v, pkey->E.n); /* rv = s*v (mod n) */
- mpi_subm (z2, zero, rv, pkey->E.n); /* z2 = -r*v (mod n) */
-
- _gcry_mpi_ec_mul_point (&Q1, z1, &pkey->E.G, ctx);
-/* log_mpidump ("Q1.x", Q1.x); */
-/* log_mpidump ("Q1.y", Q1.y); */
-/* log_mpidump ("Q1.z", Q1.z); */
- _gcry_mpi_ec_mul_point (&Q2, z2, &pkey->Q, ctx);
-/* log_mpidump ("Q2.x", Q2.x); */
-/* log_mpidump ("Q2.y", Q2.y); */
-/* log_mpidump ("Q2.z", Q2.z); */
- _gcry_mpi_ec_add_points (&Q, &Q1, &Q2, ctx);
-/* log_mpidump (" Q.x", Q.x); */
-/* log_mpidump (" Q.y", Q.y); */
-/* log_mpidump (" Q.z", Q.z); */
-
- if (!mpi_cmp_ui (Q.z, 0))
- {
- if (DBG_CIPHER)
- log_debug ("ecc verify: Rejected\n");
- err = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- if (_gcry_mpi_ec_get_affine (x, NULL, &Q, ctx))
- {
- if (DBG_CIPHER)
- log_debug ("ecc verify: Failed to get affine coordinates\n");
- err = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- mpi_mod (x, x, pkey->E.n); /* x = x mod E_n */
- if (mpi_cmp (x, r)) /* x != r */
- {
- if (DBG_CIPHER)
- {
- log_mpidump (" x", x);
- log_mpidump (" r", r);
- log_mpidump (" s", s);
- log_debug ("ecc verify: Not verified\n");
- }
- err = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
- if (DBG_CIPHER)
- log_debug ("ecc verify: Accepted\n");
-
- leave:
- _gcry_mpi_ec_free (ctx);
- point_free (&Q2);
- point_free (&Q1);
- point_free (&Q);
- mpi_free (zero);
- mpi_free (rv);
- mpi_free (v);
- mpi_free (z2);
- mpi_free (z1);
- mpi_free (x);
- mpi_free (e);
- return err;
-}
-
-
-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;
- }
-}
-
-
-/* Encode MPI using the EdDSA scheme. MINLEN specifies the required
- length of the buffer in bytes. On success 0 is returned an a
- malloced buffer with the encoded point is stored at R_BUFFER; the
- length of this buffer is stored at R_BUFLEN. */
-static gpg_err_code_t
-eddsa_encodempi (gcry_mpi_t mpi, unsigned int minlen,
- unsigned char **r_buffer, unsigned int *r_buflen)
-{
- unsigned char *rawmpi;
- unsigned int rawmpilen;
-
- rawmpi = _gcry_mpi_get_buffer (mpi, minlen, &rawmpilen, NULL);
- if (!rawmpi)
- return gpg_err_code_from_syserror ();
-
- *r_buffer = rawmpi;
- *r_buflen = rawmpilen;
- return 0;
-}
-
-
-/* Encode (X,Y) using the EdDSA scheme. MINLEN is the required length
- in bytes for the result. On success 0 is returned and a malloced
- buffer with the encoded point is stored at R_BUFFER; the length of
- this buffer is stored at R_BUFLEN. */
-static gpg_err_code_t
-eddsa_encode_x_y (gcry_mpi_t x, gcry_mpi_t y, unsigned int minlen,
- unsigned char **r_buffer, unsigned int *r_buflen)
-{
- unsigned char *rawmpi;
- unsigned int rawmpilen;
-
- rawmpi = _gcry_mpi_get_buffer (y, minlen, &rawmpilen, NULL);
- if (!rawmpi)
- return gpg_err_code_from_syserror ();
- if (mpi_test_bit (x, 0) && rawmpilen)
- rawmpi[rawmpilen - 1] |= 0x80; /* Set sign bit. */
-
- *r_buffer = rawmpi;
- *r_buflen = rawmpilen;
- return 0;
-}
-
-/* Encode POINT using the EdDSA scheme. X and Y are either scratch
- variables supplied by the caller or NULL. CTX is the usual
- context. On success 0 is returned and a malloced buffer with the
- encoded point is stored at R_BUFFER; the length of this buffer is
- stored at R_BUFLEN. */
-gpg_err_code_t
-_gcry_ecc_eddsa_encodepoint (mpi_point_t point, mpi_ec_t ec,
- gcry_mpi_t x_in, gcry_mpi_t y_in,
- unsigned char **r_buffer, unsigned int *r_buflen)
-{
- gpg_err_code_t rc;
- gcry_mpi_t x, y;
-
- x = x_in? x_in : mpi_new (0);
- y = y_in? y_in : mpi_new (0);
-
- if (_gcry_mpi_ec_get_affine (x, y, point, ec))
- {
- log_error ("eddsa_encodepoint: Failed to get affine coordinates\n");
- rc = GPG_ERR_INTERNAL;
- }
- else
- rc = eddsa_encode_x_y (x, y, ec->nbits/8, r_buffer, r_buflen);
-
- if (!x_in)
- mpi_free (x);
- if (!y_in)
- mpi_free (y);
- return rc;
-}
-
-
-/* Decode the EdDSA style encoded PK and set it into RESULT. CTX is
- the usual curve context. If R_ENCPK is not NULL, the encoded PK is
- stored at that address; this is a new copy to be released by the
- caller. In contrast to the supplied PK, this is not an MPI and
- thus guarnateed to be properly padded. R_ENCPKLEN received the
- length of that encoded key. */
-gpg_err_code_t
-_gcry_ecc_eddsa_decodepoint (gcry_mpi_t pk, mpi_ec_t ctx, mpi_point_t result,
- unsigned char **r_encpk, unsigned int *r_encpklen)
-{
- gpg_err_code_t rc;
- unsigned char *rawmpi;
- unsigned int rawmpilen;
- gcry_mpi_t yy, t, x, p1, p2, p3;
- int sign;
-
- if (mpi_is_opaque (pk))
- {
- const unsigned char *buf;
-
- buf = gcry_mpi_get_opaque (pk, &rawmpilen);
- if (!buf)
- return GPG_ERR_INV_OBJ;
- rawmpilen = (rawmpilen + 7)/8;
-
- /* First check whether the public key has been given in standard
- uncompressed format. No need to recover x in this case.
- Detection is easy: The size of the buffer will be odd and the
- first byte be 0x04. */
- if (rawmpilen > 1 && buf[0] == 0x04 && (rawmpilen%2))
- {
- gcry_mpi_t y;
-
- rc = gcry_mpi_scan (&x, GCRYMPI_FMT_STD,
- buf+1, (rawmpilen-1)/2, NULL);
- if (rc)
- return rc;
- rc = gcry_mpi_scan (&y, GCRYMPI_FMT_STD,
- buf+1+(rawmpilen-1)/2, (rawmpilen-1)/2, NULL);
- if (rc)
- {
- mpi_free (x);
- return rc;
- }
-
- if (r_encpk)
- {
- rc = eddsa_encode_x_y (x, y, ctx->nbits/8, r_encpk, r_encpklen);
- if (rc)
- {
- mpi_free (x);
- mpi_free (y);
- return rc;
- }
- }
- mpi_snatch (result->x, x);
- mpi_snatch (result->y, y);
- mpi_set_ui (result->z, 1);
- return 0;
- }
-
- /* EdDSA compressed point. */
- rawmpi = gcry_malloc (rawmpilen? rawmpilen:1);
- if (!rawmpi)
- return gpg_err_code_from_syserror ();
- memcpy (rawmpi, buf, rawmpilen);
- reverse_buffer (rawmpi, rawmpilen);
- }
- else
- {
- /* Note: Without using an opaque MPI it is not reliable possible
- to find out whether the public key has been given in
- uncompressed format. Thus we expect EdDSA format here. */
- rawmpi = _gcry_mpi_get_buffer (pk, ctx->nbits/8, &rawmpilen, NULL);
- if (!rawmpi)
- return gpg_err_code_from_syserror ();
- }
-
- if (rawmpilen)
- {
- sign = !!(rawmpi[0] & 0x80);
- rawmpi[0] &= 0x7f;
- }
- else
- sign = 0;
- _gcry_mpi_set_buffer (result->y, rawmpi, rawmpilen, 0);
- if (r_encpk)
- {
- /* Revert to little endian. */
- if (sign && rawmpilen)
- rawmpi[0] |= 0x80;
- reverse_buffer (rawmpi, rawmpilen);
- *r_encpk = rawmpi;
- if (r_encpklen)
- *r_encpklen = rawmpilen;
- }
- else
- gcry_free (rawmpi);
-
- /* Now recover X. */
- /* t = (y^2-1) · ((b*y^2+1)^{p-2} mod p) */
- x = mpi_new (0);
- yy = mpi_new (0);
- mpi_mul (yy, result->y, result->y);
- t = mpi_copy (yy);
- mpi_mul (t, t, ctx->b);
- mpi_add_ui (t, t, 1);
- p2 = mpi_copy (ctx->p);
- mpi_sub_ui (p2, p2, 2);
- mpi_powm (t, t, p2, ctx->p);
-
- mpi_sub_ui (yy, yy, 1);
- mpi_mul (t, yy, t);
-
- /* x = t^{(p+3)/8} mod p */
- p3 = mpi_copy (ctx->p);
- mpi_add_ui (p3, p3, 3);
- mpi_fdiv_q (p3, p3, mpi_const (MPI_C_EIGHT));
- mpi_powm (x, t, p3, ctx->p);
-
- /* (x^2 - t) % p != 0 ? x = (x*(2^{(p-1)/4} mod p)) % p */
- mpi_mul (yy, x, x);
- mpi_subm (yy, yy, t, ctx->p);
- if (mpi_cmp_ui (yy, 0))
- {
- p1 = mpi_copy (ctx->p);
- mpi_sub_ui (p1, p1, 1);
- mpi_fdiv_q (p1, p1, mpi_const (MPI_C_FOUR));
- mpi_powm (yy, mpi_const (MPI_C_TWO), p1, ctx->p);
- mpi_mulm (x, x, yy, ctx->p);
- }
- else
- p1 = NULL;
-
- /* is_odd(x) ? x = p-x */
- if (mpi_test_bit (x, 0))
- mpi_sub (x, ctx->p, x);
-
- /* lowbit(x) != highbit(input) ? x = p-x */
- if (mpi_test_bit (x, 0) != sign)
- mpi_sub (x, ctx->p, x);
-
- mpi_set (result->x, x);
- mpi_set_ui (result->z, 1);
-
- gcry_mpi_release (x);
- gcry_mpi_release (yy);
- gcry_mpi_release (t);
- gcry_mpi_release (p3);
- gcry_mpi_release (p2);
- gcry_mpi_release (p1);
-
- return 0;
-}
-
-
-/* Ed25519 version of the key generation. */
-static gpg_err_code_t
-eddsa_generate_key (ECC_secret_key *sk, elliptic_curve_t *E, mpi_ec_t ctx,
- gcry_random_level_t random_level)
-{
- gpg_err_code_t rc;
- int b = 256/8; /* The only size we currently support. */
- gcry_mpi_t a, x, y;
- mpi_point_struct Q;
- char *dbuf;
- size_t dlen;
- gcry_buffer_t hvec[1];
- unsigned char *hash_d = NULL;
-
- point_init (&Q);
- memset (hvec, 0, sizeof hvec);
-
- a = mpi_snew (0);
- x = mpi_new (0);
- y = mpi_new (0);
-
- /* Generate a secret. */
- hash_d = gcry_malloc_secure (2*b);
- if (!hash_d)
- {
- rc = gpg_error_from_syserror ();
- goto leave;
- }
- dlen = b;
- dbuf = gcry_random_bytes_secure (dlen, random_level);
-
- /* Compute the A value. */
- hvec[0].data = dbuf;
- hvec[0].len = dlen;
- rc = _gcry_md_hash_buffers (GCRY_MD_SHA512, 0, hash_d, hvec, 1);
- if (rc)
- goto leave;
- sk->d = _gcry_mpi_set_opaque (NULL, dbuf, dlen*8);
- dbuf = NULL;
- 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);
- gcry_free (hash_d); hash_d = NULL;
- /* log_printmpi ("ecgen a", a); */
-
- /* Compute Q. */
- _gcry_mpi_ec_mul_point (&Q, a, &E->G, ctx);
- if (DBG_CIPHER)
- log_printpnt ("ecgen pk", &Q, ctx);
-
- /* Copy the stuff to the key structures. */
- sk->E.model = E->model;
- sk->E.dialect = E->dialect;
- sk->E.p = mpi_copy (E->p);
- sk->E.a = mpi_copy (E->a);
- sk->E.b = mpi_copy (E->b);
- point_init (&sk->E.G);
- point_set (&sk->E.G, &E->G);
- sk->E.n = mpi_copy (E->n);
- point_init (&sk->Q);
- point_set (&sk->Q, &Q);
-
- leave:
- gcry_mpi_release (a);
- gcry_mpi_release (x);
- gcry_mpi_release (y);
- gcry_free (hash_d);
- return rc;
-}
-
-
-/* Compute an EdDSA signature. See:
- * [ed25519] 23pp. (PDF) Daniel J. Bernstein, Niels Duif, Tanja
- * Lange, Peter Schwabe, Bo-Yin Yang. High-speed high-security
- * signatures. Journal of Cryptographic Engineering 2 (2012), 77-89.
- * Document ID: a1a62a2f76d23f65d622484ddd09caf8.
- * URL: http://cr.yp.to/papers.html#ed25519. Date: 2011.09.26.
- *
- * Despite that this function requires the specification of a hash
- * algorithm, we only support what has been specified by the paper.
- * This may change in the future. Note that we don't check the used
- * curve; the user is responsible to use Ed25519.
- *
- * Return the signature struct (r,s) from the message hash. The caller
- * must have allocated R_R and S.
- */
-static gpg_err_code_t
-sign_eddsa (gcry_mpi_t input, ECC_secret_key *skey,
- gcry_mpi_t r_r, gcry_mpi_t s, int hashalgo, gcry_mpi_t pk)
-{
- int rc;
- mpi_ec_t ctx = NULL;
- int b;
- unsigned int tmp;
- unsigned char *digest;
- gcry_buffer_t hvec[3];
- const void *mbuf;
- size_t mlen;
- unsigned char *rawmpi = NULL;
- unsigned int rawmpilen;
- unsigned char *encpk = NULL; /* Encoded public key. */
- unsigned int encpklen;
- mpi_point_struct I; /* Intermediate value. */
- mpi_point_struct Q; /* Public key. */
- gcry_mpi_t a, x, y, r;
-
- memset (hvec, 0, sizeof hvec);
-
- if (!mpi_is_opaque (input))
- return GPG_ERR_INV_DATA;
- if (hashalgo != GCRY_MD_SHA512)
- return GPG_ERR_DIGEST_ALGO;
-
- /* Initialize some helpers. */
- point_init (&I);
- point_init (&Q);
- a = mpi_snew (0);
- x = mpi_new (0);
- y = mpi_new (0);
- 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+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 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;
- }
- 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, digest, hvec, 2);
- gcry_free (rawmpi); rawmpi = NULL;
- if (rc)
- goto leave;
-
- /* 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. */
- if (pk)
- {
- rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen);
- if (rc)
- goto leave;
- if (DBG_CIPHER)
- log_printhex ("* e_pk", encpk, encpklen);
- if (!_gcry_mpi_ec_curve_point (&Q, ctx))
- {
- rc = GPG_ERR_BROKEN_PUBKEY;
- goto leave;
- }
- }
- else
- {
- _gcry_mpi_ec_mul_point (&Q, a, &skey->E.G, ctx);
- rc = _gcry_ecc_eddsa_encodepoint (&Q, ctx, x, y, &encpk, &encpklen);
- if (rc)
- goto leave;
- if (DBG_CIPHER)
- log_printhex (" e_pk", encpk, encpklen);
- }
-
- /* Compute R. */
- mbuf = gcry_mpi_get_opaque (input, &tmp);
- mlen = (tmp +7)/8;
- if (DBG_CIPHER)
- log_printhex (" m", mbuf, mlen);
-
- hvec[0].data = digest;
- hvec[0].off = 32;
- hvec[0].len = 32;
- hvec[1].data = (char*)mbuf;
- hvec[1].len = mlen;
- rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 2);
- if (rc)
- goto leave;
- reverse_buffer (digest, 64);
- if (DBG_CIPHER)
- log_printhex (" r", digest, 64);
- _gcry_mpi_set_buffer (r, digest, 64, 0);
- _gcry_mpi_ec_mul_point (&I, r, &skey->E.G, ctx);
- if (DBG_CIPHER)
- log_printpnt (" r", &I, ctx);
-
- /* Convert R into affine coordinates and apply encoding. */
- rc = _gcry_ecc_eddsa_encodepoint (&I, ctx, x, y, &rawmpi, &rawmpilen);
- if (rc)
- goto leave;
- if (DBG_CIPHER)
- log_printhex (" e_r", rawmpi, rawmpilen);
-
- /* S = r + a * H(encodepoint(R) + encodepoint(pk) + m) mod n */
- hvec[0].data = rawmpi; /* (this is R) */
- hvec[0].off = 0;
- hvec[0].len = rawmpilen;
- hvec[1].data = encpk;
- hvec[1].off = 0;
- hvec[1].len = encpklen;
- hvec[2].data = (char*)mbuf;
- hvec[2].off = 0;
- hvec[2].len = mlen;
- rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
- if (rc)
- goto leave;
-
- /* No more need for RAWMPI thus we now transfer it to R_R. */
- gcry_mpi_set_opaque (r_r, rawmpi, rawmpilen*8);
- rawmpi = NULL;
-
- reverse_buffer (digest, 64);
- if (DBG_CIPHER)
- log_printhex (" H(R+)", digest, 64);
- _gcry_mpi_set_buffer (s, digest, 64, 0);
- mpi_mulm (s, s, a, skey->E.n);
- mpi_addm (s, s, r, skey->E.n);
- rc = eddsa_encodempi (s, b, &rawmpi, &rawmpilen);
- if (rc)
- goto leave;
- if (DBG_CIPHER)
- log_printhex (" e_s", rawmpi, rawmpilen);
- gcry_mpi_set_opaque (s, rawmpi, rawmpilen*8);
- rawmpi = NULL;
-
- rc = 0;
-
- leave:
- gcry_mpi_release (a);
- 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);
- gcry_free (encpk);
- gcry_free (rawmpi);
- return rc;
-}
-
-
-/* Verify an EdDSA signature. See sign_eddsa for the reference.
- * Check if R_IN and S_IN verifies INPUT. PKEY has the curve
- * parameters and PK is the EdDSA style encoded public key.
- */
-static gpg_err_code_t
-verify_eddsa (gcry_mpi_t input, ECC_public_key *pkey,
- gcry_mpi_t r_in, gcry_mpi_t s_in, int hashalgo, gcry_mpi_t pk)
-{
- int rc;
- mpi_ec_t ctx = NULL;
- int b;
- unsigned int tmp;
- mpi_point_struct Q; /* Public key. */
- unsigned char *encpk = NULL; /* Encoded public key. */
- unsigned int encpklen;
- const void *mbuf, *rbuf;
- unsigned char *tbuf = NULL;
- size_t mlen, rlen;
- unsigned int tlen;
- unsigned char digest[64];
- gcry_buffer_t hvec[3];
- gcry_mpi_t h, s;
- mpi_point_struct Ia, Ib;
-
- if (!mpi_is_opaque (input) || !mpi_is_opaque (r_in) || !mpi_is_opaque (s_in))
- return GPG_ERR_INV_DATA;
- if (hashalgo != GCRY_MD_SHA512)
- return GPG_ERR_DIGEST_ALGO;
-
- point_init (&Q);
- point_init (&Ia);
- point_init (&Ib);
- h = mpi_new (0);
- s = mpi_new (0);
-
- ctx = _gcry_mpi_ec_p_internal_new (pkey->E.model, pkey->E.dialect,
- pkey->E.p, pkey->E.a, pkey->E.b);
- b = ctx->nbits/8;
- if (b != 256/8)
- return GPG_ERR_INTERNAL; /* We only support 256 bit. */
-
- /* Decode and check the public key. */
- rc = _gcry_ecc_eddsa_decodepoint (pk, ctx, &Q, &encpk, &encpklen);
- if (rc)
- goto leave;
- if (!_gcry_mpi_ec_curve_point (&Q, ctx))
- {
- rc = GPG_ERR_BROKEN_PUBKEY;
- goto leave;
- }
- if (DBG_CIPHER)
- log_printhex (" e_pk", encpk, encpklen);
- if (encpklen != b)
- {
- rc = GPG_ERR_INV_LENGTH;
- goto leave;
- }
-
- /* Convert the other input parameters. */
- mbuf = gcry_mpi_get_opaque (input, &tmp);
- mlen = (tmp +7)/8;
- if (DBG_CIPHER)
- log_printhex (" m", mbuf, mlen);
- rbuf = gcry_mpi_get_opaque (r_in, &tmp);
- rlen = (tmp +7)/8;
- if (DBG_CIPHER)
- log_printhex (" r", rbuf, rlen);
- if (rlen != b)
- {
- rc = GPG_ERR_INV_LENGTH;
- goto leave;
- }
-
- /* h = H(encodepoint(R) + encodepoint(pk) + m) */
- hvec[0].data = (char*)rbuf;
- hvec[0].off = 0;
- hvec[0].len = rlen;
- hvec[1].data = encpk;
- hvec[1].off = 0;
- hvec[1].len = encpklen;
- hvec[2].data = (char*)mbuf;
- hvec[2].off = 0;
- hvec[2].len = mlen;
- rc = _gcry_md_hash_buffers (hashalgo, 0, digest, hvec, 3);
- if (rc)
- goto leave;
- reverse_buffer (digest, 64);
- if (DBG_CIPHER)
- log_printhex (" H(R+)", digest, 64);
- _gcry_mpi_set_buffer (h, digest, 64, 0);
-
- /* According to the paper the best way for verification is:
- encodepoint(sG - h·Q) = encodepoint(r)
- because we don't need to decode R. */
- {
- void *sbuf;
- unsigned int slen;
-
- sbuf = _gcry_mpi_get_opaque_copy (s_in, &tmp);
- slen = (tmp +7)/8;
- reverse_buffer (sbuf, slen);
- if (DBG_CIPHER)
- log_printhex (" s", sbuf, slen);
- _gcry_mpi_set_buffer (s, sbuf, slen, 0);
- gcry_free (sbuf);
- if (slen != b)
- {
- rc = GPG_ERR_INV_LENGTH;
- goto leave;
- }
- }
-
- _gcry_mpi_ec_mul_point (&Ia, s, &pkey->E.G, ctx);
- _gcry_mpi_ec_mul_point (&Ib, h, &Q, ctx);
- _gcry_mpi_neg (Ib.x, Ib.x);
- _gcry_mpi_ec_add_points (&Ia, &Ia, &Ib, ctx);
- rc = _gcry_ecc_eddsa_encodepoint (&Ia, ctx, s, h, &tbuf, &tlen);
- if (rc)
- goto leave;
- if (tlen != rlen || memcmp (tbuf, rbuf, tlen))
- {
- rc = GPG_ERR_BAD_SIGNATURE;
- goto leave;
- }
-
- rc = 0;
-
- leave:
- gcry_free (encpk);
- gcry_free (tbuf);
- _gcry_mpi_ec_free (ctx);
- gcry_mpi_release (s);
- gcry_mpi_release (h);
- point_free (&Ia);
- point_free (&Ib);
- point_free (&Q);
- return rc;
-}
-
-
/*********************************************
************** interface ******************
@@ -1540,7 +485,7 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
rc = nist_generate_key (&sk, &E, ctx, random_level, nbits);
}
else
- rc = eddsa_generate_key (&sk, &E, ctx, random_level);
+ rc = _gcry_ecc_eddsa_genkey (&sk, &E, ctx, random_level);
break;
default:
rc = GPG_ERR_INTERNAL;
@@ -1830,21 +775,22 @@ ecc_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_data, gcry_sexp_t keyparms)
if ((ctx.flags & PUBKEY_FLAG_EDDSA))
{
/* EdDSA requires the public key. */
- rc = sign_eddsa (data, &sk, sig_r, sig_s, ctx.hash_algo, mpi_q);
+ rc = _gcry_ecc_eddsa_sign (data, &sk, sig_r, sig_s, ctx.hash_algo, mpi_q);
if (!rc)
rc = gcry_sexp_build (r_sig, NULL,
"(sig-val(eddsa(r%M)(s%M)))", sig_r, sig_s);
}
else if ((ctx.flags & PUBKEY_FLAG_GOST))
{
- rc = sign_gost (data, &sk, sig_r, sig_s);
+ rc = _gcry_ecc_gost_sign (data, &sk, sig_r, sig_s);
if (!rc)
rc = gcry_sexp_build (r_sig, NULL,
"(sig-val(gost(r%M)(s%M)))", sig_r, sig_s);
}
else
{
- rc = sign_ecdsa (data, &sk, sig_r, sig_s, ctx.flags, ctx.hash_algo);
+ rc = _gcry_ecc_ecdsa_sign (data, &sk, sig_r, sig_s,
+ ctx.flags, ctx.hash_algo);
if (!rc)
rc = gcry_sexp_build (r_sig, NULL,
"(sig-val(ecdsa(r%M)(s%M)))", sig_r, sig_s);
@@ -1990,7 +936,8 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
*/
if ((sigflags & PUBKEY_FLAG_EDDSA))
{
- rc = verify_eddsa (data, &pk, sig_r, sig_s, ctx.hash_algo, mpi_q);
+ rc = _gcry_ecc_eddsa_verify (data, &pk, sig_r, sig_s,
+ ctx.hash_algo, mpi_q);
}
else if ((sigflags & PUBKEY_FLAG_GOST))
{
@@ -1999,7 +946,7 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
if (rc)
goto leave;
- rc = verify_gost (data, &pk, sig_r, sig_s);
+ rc = _gcry_ecc_gost_verify (data, &pk, sig_r, sig_s);
}
else
{
@@ -2024,12 +971,12 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
if (abits > qbits)
gcry_mpi_rshift (a, a, abits - qbits);
- rc = verify_ecdsa (a, &pk, sig_r, sig_s);
+ rc = _gcry_ecc_ecdsa_verify (a, &pk, sig_r, sig_s);
gcry_mpi_release (a);
}
}
else
- rc = verify_ecdsa (data, &pk, sig_r, sig_s);
+ rc = _gcry_ecc_ecdsa_verify (data, &pk, sig_r, sig_s);
}
leave:
diff --git a/configure.ac b/configure.ac
index 739a6504..69cfbd23 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1583,7 +1583,8 @@ fi
LIST_MEMBER(ecc, $enabled_pubkey_ciphers)
if test "$found" = "1" ; then
GCRYPT_PUBKEY_CIPHERS="$GCRYPT_PUBKEY_CIPHERS \
- ecc.lo ecc-curves.lo ecc-misc.lo"
+ ecc.lo ecc-curves.lo ecc-misc.lo \
+ ecc-ecdsa.lo ecc-eddsa.lo ecc-gost.lo"
AC_DEFINE(USE_ECC, 1, [Defined if this module should be included])
fi