[git] GCRYPT - branch, master, updated. libgcrypt-1.5.0-326-g164eb8c
by Werner Koch
cvs at cvs.gnupg.org
Wed Oct 23 14:10:01 CEST 2013
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".
The branch, master has been updated
via 164eb8c85d773ef4f0939115ec45f5e4b47c1700 (commit)
via 45f6e6268bfdc4b608beaba6b7086b2286e33c71 (commit)
from 98674fdaa30ab22a3ac86ca05d688b5b6112895d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 164eb8c85d773ef4f0939115ec45f5e4b47c1700
Author: Werner Koch <wk at gnupg.org>
Date: Wed Oct 23 14:08:29 2013 +0200
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 at gnupg.org>
diff --git a/cipher/Makefile.am b/cipher/Makefile.am
index 3d8149a..e6b1745 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 0be1f2c..0a95b95 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 0000000..70dfe38
--- /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 0000000..72103e9
--- /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 0000000..1ebfd39
--- /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 2774718..dca0423 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 739a650..69cfbd2 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
commit 45f6e6268bfdc4b608beaba6b7086b2286e33c71
Author: Werner Koch <wk at gnupg.org>
Date: Wed Oct 23 11:41:37 2013 +0200
mpi: Fix scanning of negative SSH formats and add more tests.
* mpi/mpicoder.c (gcry_mpi_scan): Fix sign setting for SSH format.
* tests/t-convert.c (negative_zero): Test all formats.
(check_formats): Add tests for PGP and scan tests for SSH and USG.
* src/gcrypt.h.in (mpi_is_neg): Fix macro.
* mpi/mpi-scan.c (_gcry_mpi_getbyte, _gcry_mpi_putbyte): Comment out
these unused functions.
Signed-off-by: Werner Koch <wk at gnupg.org>
diff --git a/mpi/mpi-scan.c b/mpi/mpi-scan.c
index 2473cd9..e27f7fa 100644
--- a/mpi/mpi-scan.c
+++ b/mpi/mpi-scan.c
@@ -31,79 +31,79 @@
*
* FIXME: This code is VERY ugly!
*/
-int
-_gcry_mpi_getbyte( gcry_mpi_t a, unsigned idx )
-{
- int i, j;
- unsigned n;
- mpi_ptr_t ap;
- mpi_limb_t limb;
+/* int */
+/* _gcry_mpi_getbyte( gcry_mpi_t a, unsigned idx ) */
+/* { */
+/* int i, j; */
+/* unsigned n; */
+/* mpi_ptr_t ap; */
+/* mpi_limb_t limb; */
- ap = a->d;
- for(n=0,i=0; i < a->nlimbs; i++ ) {
- limb = ap[i];
- for( j=0; j < BYTES_PER_MPI_LIMB; j++, n++ )
- if( n == idx )
- return (limb >> j*8) & 0xff;
- }
- return -1;
-}
+/* ap = a->d; */
+/* for(n=0,i=0; i < a->nlimbs; i++ ) { */
+/* limb = ap[i]; */
+/* for( j=0; j < BYTES_PER_MPI_LIMB; j++, n++ ) */
+/* if( n == idx ) */
+/* return (limb >> j*8) & 0xff; */
+/* } */
+/* return -1; */
+/* } */
/****************
* Put a value at position IDX into A. idx counts from lsb to msb
*/
-void
-_gcry_mpi_putbyte( gcry_mpi_t a, unsigned idx, int xc )
-{
- int i, j;
- unsigned n;
- mpi_ptr_t ap;
- mpi_limb_t limb, c;
+/* void */
+/* _gcry_mpi_putbyte( gcry_mpi_t a, unsigned idx, int xc ) */
+/* { */
+/* int i, j; */
+/* unsigned n; */
+/* mpi_ptr_t ap; */
+/* mpi_limb_t limb, c; */
- c = xc & 0xff;
- ap = a->d;
- for(n=0,i=0; i < a->alloced; i++ ) {
- limb = ap[i];
- for( j=0; j < BYTES_PER_MPI_LIMB; j++, n++ )
- if( n == idx ) {
- #if BYTES_PER_MPI_LIMB == 4
- if( j == 0 )
- limb = (limb & 0xffffff00) | c;
- else if( j == 1 )
- limb = (limb & 0xffff00ff) | (c<<8);
- else if( j == 2 )
- limb = (limb & 0xff00ffff) | (c<<16);
- else
- limb = (limb & 0x00ffffff) | (c<<24);
- #elif BYTES_PER_MPI_LIMB == 8
- if( j == 0 )
- limb = (limb & 0xffffffffffffff00) | c;
- else if( j == 1 )
- limb = (limb & 0xffffffffffff00ff) | (c<<8);
- else if( j == 2 )
- limb = (limb & 0xffffffffff00ffff) | (c<<16);
- else if( j == 3 )
- limb = (limb & 0xffffffff00ffffff) | (c<<24);
- else if( j == 4 )
- limb = (limb & 0xffffff00ffffffff) | (c<<32);
- else if( j == 5 )
- limb = (limb & 0xffff00ffffffffff) | (c<<40);
- else if( j == 6 )
- limb = (limb & 0xff00ffffffffffff) | (c<<48);
- else
- limb = (limb & 0x00ffffffffffffff) | (c<<56);
- #else
- #error please enhance this function, its ugly - i know.
- #endif
- if( a->nlimbs <= i )
- a->nlimbs = i+1;
- ap[i] = limb;
- return;
- }
- }
- abort(); /* index out of range */
-}
+/* c = xc & 0xff; */
+/* ap = a->d; */
+/* for(n=0,i=0; i < a->alloced; i++ ) { */
+/* limb = ap[i]; */
+/* for( j=0; j < BYTES_PER_MPI_LIMB; j++, n++ ) */
+/* if( n == idx ) { */
+/* #if BYTES_PER_MPI_LIMB == 4 */
+/* if( j == 0 ) */
+/* limb = (limb & 0xffffff00) | c; */
+/* else if( j == 1 ) */
+/* limb = (limb & 0xffff00ff) | (c<<8); */
+/* else if( j == 2 ) */
+/* limb = (limb & 0xff00ffff) | (c<<16); */
+/* else */
+/* limb = (limb & 0x00ffffff) | (c<<24); */
+/* #elif BYTES_PER_MPI_LIMB == 8 */
+/* if( j == 0 ) */
+/* limb = (limb & 0xffffffffffffff00) | c; */
+/* else if( j == 1 ) */
+/* limb = (limb & 0xffffffffffff00ff) | (c<<8); */
+/* else if( j == 2 ) */
+/* limb = (limb & 0xffffffffff00ffff) | (c<<16); */
+/* else if( j == 3 ) */
+/* limb = (limb & 0xffffffff00ffffff) | (c<<24); */
+/* else if( j == 4 ) */
+/* limb = (limb & 0xffffff00ffffffff) | (c<<32); */
+/* else if( j == 5 ) */
+/* limb = (limb & 0xffff00ffffffffff) | (c<<40); */
+/* else if( j == 6 ) */
+/* limb = (limb & 0xff00ffffffffffff) | (c<<48); */
+/* else */
+/* limb = (limb & 0x00ffffffffffffff) | (c<<56); */
+/* #else */
+/* #error please enhance this function, its ugly - i know. */
+/* #endif */
+/* if( a->nlimbs <= i ) */
+/* a->nlimbs = i+1; */
+/* ap[i] = limb; */
+/* return; */
+/* } */
+/* } */
+/* abort(); /\* index out of range *\/ */
+/* } */
/****************
diff --git a/mpi/mpicoder.c b/mpi/mpicoder.c
index 1d2c87e..b598521 100644
--- a/mpi/mpicoder.c
+++ b/mpi/mpicoder.c
@@ -519,8 +519,8 @@ gcry_mpi_scan (struct gcry_mpi **ret_mpi, enum gcry_mpi_format format,
: mpi_alloc ((n+BYTES_PER_MPI_LIMB-1)/BYTES_PER_MPI_LIMB);
if (n)
{
- a->sign = !!(*s & 0x80);
_gcry_mpi_set_buffer( a, s, n, 0 );
+ a->sign = !!(*s & 0x80);
if (a->sign)
{
onecompl (a);
diff --git a/src/gcrypt.h.in b/src/gcrypt.h.in
index 948202d..2742556 100644
--- a/src/gcrypt.h.in
+++ b/src/gcrypt.h.in
@@ -771,7 +771,7 @@ gcry_mpi_t _gcry_mpi_get_const (int no);
#define mpi_neg( w, u) gcry_mpi_neg( (w), (u) )
#define mpi_cmp( u, v ) gcry_mpi_cmp( (u), (v) )
#define mpi_cmp_ui( u, v ) gcry_mpi_cmp_ui( (u), (v) )
-#define mpi_is_neg( a ) gcry_mpi_is_new ((a))
+#define mpi_is_neg( a ) gcry_mpi_is_neg ((a))
#define mpi_add_ui(w,u,v) gcry_mpi_add_ui((w),(u),(v))
#define mpi_add(w,u,v) gcry_mpi_add ((w),(u),(v))
diff --git a/tests/t-convert.c b/tests/t-convert.c
index d44c439..072bf32 100644
--- a/tests/t-convert.c
+++ b/tests/t-convert.c
@@ -153,15 +153,18 @@ negative_zero (void)
void *bufaddr = &buf;
struct { const char *name; enum gcry_mpi_format format; } fmts[] =
{
- /* { "STD", GCRYMPI_FMT_STD }, */
- /* { "PGP", GCRYMPI_FMT_PGP }, */
- /* { "SSH", GCRYMPI_FMT_SSH }, */
- /* { "HEX", GCRYMPI_FMT_HEX }, */
+ { "STD", GCRYMPI_FMT_STD },
+ { "PGP", GCRYMPI_FMT_PGP },
+ { "SSH", GCRYMPI_FMT_SSH },
+ { "HEX", GCRYMPI_FMT_HEX },
{ "USG", GCRYMPI_FMT_USG },
{ NULL, 0 }
};
int i;
+ if (debug)
+ show ("negative zero printing\n");
+
a = gcry_mpi_new (0);
for (i=0; fmts[i].name; i++)
{
@@ -205,52 +208,63 @@ check_formats (void)
const char *ssh;
size_t usglen;
const char *usg;
+ size_t pgplen;
+ const char *pgp;
} a;
} data[] = {
{ 0, { "00",
0, "",
4, "\x00\x00\x00\x00",
- 0, "" }
+ 0, "",
+ 2, "\x00\x00"}
},
{ 1, { "01",
1, "\x01",
5, "\x00\x00\x00\x01\x01",
- 1, "\x01" }
+ 1, "\x01",
+ 3, "\x00\x01\x01" }
},
{ 2, { "02",
1, "\x02",
5, "\x00\x00\x00\x01\x02",
- 1, "\x02", }
+ 1, "\x02",
+ 3, "\x00\x02\x02" }
},
{ 127, { "7F",
1, "\x7f",
5, "\x00\x00\x00\x01\x7f",
- 1, "\x7f" }
+ 1, "\x7f",
+ 3, "\x00\x07\x7f" }
},
{ 128, { "0080",
2, "\x00\x80",
6, "\x00\x00\x00\x02\x00\x80",
- 1, "\x80" }
+ 1, "\x80",
+ 3, "\x00\x08\x80" }
},
{ 129, { "0081",
2, "\x00\x81",
6, "\x00\x00\x00\x02\x00\x81",
- 1, "\x81" }
+ 1, "\x81",
+ 3, "\x00\x08\x81" }
},
{ 255, { "00FF",
2, "\x00\xff",
6, "\x00\x00\x00\x02\x00\xff",
- 1, "\xff" }
+ 1, "\xff",
+ 3, "\x00\x08\xff" }
},
{ 256, { "0100",
2, "\x01\x00",
6, "\x00\x00\x00\x02\x01\x00",
- 2, "\x01\x00" }
+ 2, "\x01\x00",
+ 4, "\x00\x09\x01\x00" }
},
{ 257, { "0101",
2, "\x01\x01",
6, "\x00\x00\x00\x02\x01\x01",
- 2, "\x01\x01" }
+ 2, "\x01\x01",
+ 4, "\x00\x09\x01\x01" }
},
{ -1, { "-01",
1, "\xff",
@@ -295,17 +309,20 @@ check_formats (void)
{ 65535, { "00FFFF",
3, "\x00\xff\xff",
7, "\x00\x00\x00\x03\x00\xff\xff",
- 2, "\xff\xff" }
+ 2, "\xff\xff",
+ 4, "\x00\x10\xff\xff" }
},
{ 65536, { "010000",
3, "\x01\00\x00",
7, "\x00\x00\x00\x03\x01\x00\x00",
- 3, "\x01\x00\x00" }
+ 3, "\x01\x00\x00",
+ 5, "\x00\x11\x01\x00\x00 "}
},
{ 65537, { "010001",
3, "\x01\00\x01",
7, "\x00\x00\x00\x03\x01\x00\x01",
- 3, "\x01\x00\x01" }
+ 3, "\x01\x00\x01",
+ 5, "\x00\x11\x01\x00\x01" }
},
{ -65537, { "-010001",
3, "\xfe\xff\xff",
@@ -410,6 +427,29 @@ check_formats (void)
}
gcry_free (buf);
}
+
+ err = gcry_mpi_aprint (GCRYMPI_FMT_PGP, bufaddr, &buflen, a);
+ if (gcry_mpi_is_neg (a))
+ {
+ if (gpg_err_code (err) != GPG_ERR_INV_ARG)
+ fail ("error printing value %d as %s: %s\n",
+ data[idx].value, "PGP", "Expected error not returned");
+ }
+ else if (err)
+ fail ("error printing value %d as %s: %s\n",
+ data[idx].value, "PGP", gpg_strerror (err));
+ else
+ {
+ if (buflen != data[idx].a.pgplen
+ || memcmp (buf, data[idx].a.pgp, data[idx].a.pgplen))
+ {
+ fail ("error printing value %d as %s: %s\n",
+ data[idx].value, "PGP", "wrong result");
+ showhex ("expected:", data[idx].a.pgp, data[idx].a.pgplen);
+ showhex (" got:", buf, buflen);
+ }
+ gcry_free (buf);
+ }
}
@@ -460,38 +500,62 @@ check_formats (void)
gcry_mpi_release (b);
}
- err = gcry_mpi_aprint (GCRYMPI_FMT_SSH, bufaddr, &buflen, a);
+ err = gcry_mpi_scan (&b, GCRYMPI_FMT_SSH,
+ data[idx].a.ssh, data[idx].a.sshlen, &buflen);
if (err)
- fail ("error printing value %d as %s: %s\n",
+ fail ("error scanning value %d as %s: %s\n",
data[idx].value, "SSH", gpg_strerror (err));
else
{
- if (buflen != data[idx].a.sshlen
- || memcmp (buf, data[idx].a.ssh, data[idx].a.sshlen))
+ if (gcry_mpi_cmp (a, b) || data[idx].a.sshlen != buflen)
{
- fail ("error printing value %d as %s: %s\n",
- data[idx].value, "SSH", "wrong result");
- showhex ("expected:", data[idx].a.ssh, data[idx].a.sshlen);
- showhex (" got:", buf, buflen);
+ fail ("error scanning value %d from %s: %s (%u)\n",
+ data[idx].value, "SSH", "wrong result", buflen);
+ showmpi ("expected:", a);
+ showmpi (" got:", b);
}
- gcry_free (buf);
+ gcry_mpi_release (b);
}
- err = gcry_mpi_aprint (GCRYMPI_FMT_USG, bufaddr, &buflen, a);
+ err = gcry_mpi_scan (&b, GCRYMPI_FMT_USG,
+ data[idx].a.usg, data[idx].a.usglen, &buflen);
if (err)
- fail ("error printing value %d as %s: %s\n",
+ fail ("error scanning value %d as %s: %s\n",
data[idx].value, "USG", gpg_strerror (err));
else
{
- if (buflen != data[idx].a.usglen
- || memcmp (buf, data[idx].a.usg, data[idx].a.usglen))
+ if (gcry_mpi_is_neg (a))
+ gcry_mpi_neg (b, b);
+ if (gcry_mpi_cmp (a, b) || data[idx].a.usglen != buflen)
{
- fail ("error printing value %d as %s: %s\n",
- data[idx].value, "USG", "wrong result");
- showhex ("expected:", data[idx].a.usg, data[idx].a.usglen);
- showhex (" got:", buf, buflen);
+ fail ("error scanning value %d from %s: %s (%u)\n",
+ data[idx].value, "USG", "wrong result", buflen);
+ showmpi ("expected:", a);
+ showmpi (" got:", b);
+ }
+ gcry_mpi_release (b);
+ }
+
+ /* Negative values are not supported by PGP, thus we don't have
+ an samples. */
+ if (!gcry_mpi_is_neg (a))
+ {
+ err = gcry_mpi_scan (&b, GCRYMPI_FMT_PGP,
+ data[idx].a.pgp, data[idx].a.pgplen, &buflen);
+ if (err)
+ fail ("error scanning value %d as %s: %s\n",
+ data[idx].value, "PGP", gpg_strerror (err));
+ else
+ {
+ if (gcry_mpi_cmp (a, b) || data[idx].a.pgplen != buflen)
+ {
+ fail ("error scanning value %d from %s: %s (%u)\n",
+ data[idx].value, "PGP", "wrong result", buflen);
+ showmpi ("expected:", a);
+ showmpi (" got:", b);
+ }
+ gcry_mpi_release (b);
}
- gcry_free (buf);
}
}
-----------------------------------------------------------------------
Summary of changes:
cipher/Makefile.am | 1 +
cipher/ecc-common.h | 31 ++
cipher/ecc-ecdsa.c | 235 +++++++++++
cipher/ecc-eddsa.c | 681 ++++++++++++++++++++++++++++++++
cipher/ecc-gost.c | 233 +++++++++++
cipher/ecc.c | 1077 +--------------------------------------------------
configure.ac | 3 +-
mpi/mpi-scan.c | 132 +++----
mpi/mpicoder.c | 2 +-
src/gcrypt.h.in | 2 +-
tests/t-convert.c | 132 +++++--
11 files changed, 1361 insertions(+), 1168 deletions(-)
create mode 100644 cipher/ecc-ecdsa.c
create mode 100644 cipher/ecc-eddsa.c
create mode 100644 cipher/ecc-gost.c
hooks/post-receive
--
The GNU crypto library
http://git.gnupg.org
_______________________________________________
Gnupg-commits mailing list
Gnupg-commits at gnupg.org
http://lists.gnupg.org/mailman/listinfo/gnupg-commits
More information about the Gcrypt-devel
mailing list