diff options
author | Werner Koch <wk@gnupg.org> | 2013-03-15 14:43:19 +0100 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2013-03-15 14:53:42 +0100 |
commit | 229f3219f80c9369ed9624242c0436ae6d293201 (patch) | |
tree | 1eaa99a11af69b72dc6c96d1222c4d1ffb0c4228 /cipher | |
parent | e005629bd7bebb3e13945645c6e1230b44ab16a2 (diff) | |
download | libgcrypt-229f3219f80c9369ed9624242c0436ae6d293201.tar.gz |
mpi: Add functions to manipulate an EC context.
* src/gcrypt.h.in (gcry_mpi_ec_p_new): Remove.
(gcry_mpi_ec_new): New.
(gcry_mpi_ec_get_mpi): New.
(gcry_mpi_ec_get_point): New.
(gcry_mpi_ec_set_mpi): New.
(gcry_mpi_ec_set_point): New.
* src/visibility.c (gcry_mpi_ec_p_new): Remove.
* mpi/ec.c (_gcry_mpi_ec_p_new): Make it an internal function and
change to return an error code.
(_gcry_mpi_ec_get_mpi): New.
(_gcry_mpi_ec_get_point): New.
(_gcry_mpi_ec_set_mpi): New.
(_gcry_mpi_ec_set_point): New.
* src/mpi.h: Add new prototypes.
* src/ec-context.h: New.
* mpi/ec.c: Include that header.
(mpi_ec_ctx_s): Move to ec-context.h, add new fields, and put some
fields into an inner struct.
(point_copy): New.
* cipher/ecc.c (fill_in_curve): Allow passing NULL for R_NBITS.
(mpi_from_keyparam, point_from_keyparam): New.
(_gcry_mpi_ec_new): New.
* tests/t-mpi-point.c (test-curve): New.
(ec_p_new): New. Use it instead of the removed gcry_mpi_ec_p_new.
(get_and_cmp_mpi, get_and_cmp_point): New.
(context_param): New test.
(basic_ec_math_simplified): New test.
(main): Call new tests.
* src/context.c (_gcry_ctx_get_pointer): Check for a NULL CTX.
--
gcry_mpi_ec_p_new() was a specialized version of the more general new
gcry_mpi_ec_new(). It was added to master only a few days ago, thus
there should be no problem to remove it. A replacement can easily be
written (cf. t-mpi-point.c).
Note that gcry_mpi_ec_set_mpi and gcry_mpi_ec_set_point have not yet
been tested.
Diffstat (limited to 'cipher')
-rw-r--r-- | cipher/ecc.c | 287 |
1 files changed, 284 insertions, 3 deletions
diff --git a/cipher/ecc.c b/cipher/ecc.c index 4efbef45..c95a57af 100644 --- a/cipher/ecc.c +++ b/cipher/ecc.c @@ -46,6 +46,12 @@ - In mpi/ec.c we use mpi_powm for x^2 mod p: Either implement a special case in mpi_powm or check whether mpi_mulm is faster. + + - Split this up into several files. For example the curve + management and gcry_mpi_ec_new are independent of the actual ECDSA + implementation. This will also help to support optimized versions + of some curves. + */ @@ -53,10 +59,13 @@ #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" /* Definition of a curve. */ typedef struct @@ -440,8 +449,8 @@ gen_k (gcry_mpi_t p, int security_level) /* Generate the crypto system setup. This function takes the NAME of a curve or the desired number of bits and stores at R_CURVE the - parameters of the named curve or those of a suitable curve. The - chosen number of bits is stored on R_NBITS. */ + parameters of the named curve or those of a suitable curve. If + R_NBITS is not NULL, the chosen number of bits is stored there. */ static gpg_err_code_t fill_in_curve (unsigned int nbits, const char *name, elliptic_curve_t *curve, unsigned int *r_nbits) @@ -491,7 +500,8 @@ fill_in_curve (unsigned int nbits, const char *name, if (fips_mode () && !domain_parms[idx].fips ) return GPG_ERR_NOT_SUPPORTED; - *r_nbits = domain_parms[idx].nbits; + if (r_nbits) + *r_nbits = domain_parms[idx].nbits; curve->p = scanval (domain_parms[idx].p); curve->a = scanval (domain_parms[idx].a); curve->b = scanval (domain_parms[idx].b); @@ -1689,6 +1699,277 @@ compute_keygrip (gcry_md_hd_t md, gcry_sexp_t keyparam) } + +/* + Low-level API helper functions. + */ + +/* Helper to extract an MPI from key parameters. */ +static gpg_err_code_t +mpi_from_keyparam (gcry_mpi_t *r_a, gcry_sexp_t keyparam, const char *name) +{ + gcry_err_code_t ec = 0; + gcry_sexp_t l1; + + l1 = gcry_sexp_find_token (keyparam, name, 0); + if (l1) + { + *r_a = gcry_sexp_nth_mpi (l1, 1, GCRYMPI_FMT_USG); + gcry_sexp_release (l1); + if (!*r_a) + ec = GPG_ERR_INV_OBJ; + } + return ec; +} + +/* Helper to extract a point from key parameters. If no parameter + with NAME is found, the functions tries to find a non-encoded point + by appending ".x", ".y" and ".z" to NAME. ".z" is in this case + optional and defaults to 1. */ +static gpg_err_code_t +point_from_keyparam (gcry_mpi_point_t *r_a, + gcry_sexp_t keyparam, const char *name) +{ + gcry_err_code_t ec; + gcry_mpi_t a = NULL; + gcry_mpi_point_t point; + + ec = mpi_from_keyparam (&a, keyparam, name); + if (ec) + return ec; + + if (a) + { + point = gcry_mpi_point_new (0); + ec = os2ec (point, a); + if (ec) + { + gcry_mpi_point_release (point); + mpi_free (a); + return ec; + } + } + else + { + char *tmpname; + gcry_mpi_t x = NULL; + gcry_mpi_t y = NULL; + gcry_mpi_t z = NULL; + + tmpname = gcry_malloc (strlen (name) + 2 + 1); + if (!tmpname) + return gpg_err_code_from_syserror (); + strcpy (stpcpy (tmpname, name), ".x"); + ec = mpi_from_keyparam (&x, keyparam, tmpname); + if (ec) + { + gcry_free (tmpname); + return ec; + } + strcpy (stpcpy (tmpname, name), ".y"); + ec = mpi_from_keyparam (&y, keyparam, tmpname); + if (ec) + { + mpi_free (x); + gcry_free (tmpname); + return ec; + } + strcpy (stpcpy (tmpname, name), ".z"); + ec = mpi_from_keyparam (&z, keyparam, tmpname); + if (ec) + { + mpi_free (y); + mpi_free (x); + gcry_free (tmpname); + return ec; + } + if (!z) + z = mpi_set_ui (NULL, 1); + if (x && y) + point = gcry_mpi_point_snatch_set (NULL, x, y, z); + else + { + mpi_free (x); + mpi_free (y); + mpi_free (z); + point = NULL; + } + gcry_free (tmpname); + } + + if (point) + *r_a = point; + return 0; +} + + +/* This function creates a new context for elliptic curve operations. + Either KEYPARAM or CURVENAME must be given. If both are given and + KEYPARAM has no curve parameter CURVENAME is used to add missing + parameters. On success 0 is returned and the new context stored at + R_CTX. On error NULL is stored at R_CTX and an error code is + returned. The context needs to be released using + gcry_ctx_release. */ +gpg_err_code_t +_gcry_mpi_ec_new (gcry_ctx_t *r_ctx, + gcry_sexp_t keyparam, const char *curvename) +{ + gpg_err_code_t errc; + gcry_ctx_t ctx = NULL; + gcry_mpi_t p = NULL; + gcry_mpi_t a = NULL; + gcry_mpi_t b = NULL; + gcry_mpi_point_t G = NULL; + gcry_mpi_t n = NULL; + gcry_mpi_point_t Q = NULL; + gcry_mpi_t d = NULL; + gcry_sexp_t l1; + + *r_ctx = NULL; + + if (keyparam) + { + errc = mpi_from_keyparam (&p, keyparam, "p"); + if (errc) + goto leave; + errc = mpi_from_keyparam (&a, keyparam, "a"); + if (errc) + goto leave; + errc = mpi_from_keyparam (&b, keyparam, "b"); + if (errc) + goto leave; + errc = point_from_keyparam (&G, keyparam, "G"); + if (errc) + goto leave; + errc = mpi_from_keyparam (&n, keyparam, "n"); + if (errc) + goto leave; + errc = point_from_keyparam (&Q, keyparam, "Q"); + if (errc) + goto leave; + errc = mpi_from_keyparam (&d, keyparam, "d"); + if (errc) + goto leave; + } + + + /* Check whether a curve parameter is available and use that to fill + in missing values. If no curve parameter is available try an + optional provided curvename. If only the curvename has been + given use that one. */ + if (keyparam) + l1 = gcry_sexp_find_token (keyparam, "curve", 5); + else + l1 = NULL; + if (l1 || curvename) + { + char *name; + elliptic_curve_t *E; + + if (l1) + { + name = _gcry_sexp_nth_string (l1, 1); + gcry_sexp_release (l1); + if (!name) + { + errc = GPG_ERR_INV_OBJ; /* Name missing or out of core. */ + goto leave; + } + } + else + name = NULL; + + E = gcry_calloc (1, sizeof *E); + if (!E) + { + errc = gpg_err_code_from_syserror (); + gcry_free (name); + goto leave; + } + + errc = fill_in_curve (0, name? name : curvename, E, NULL); + gcry_free (name); + if (errc) + { + gcry_free (E); + goto leave; + } + + if (!p) + { + p = E->p; + E->p = NULL; + } + if (!a) + { + a = E->a; + E->a = NULL; + } + if (!b) + { + b = E->b; + E->b = NULL; + } + if (!G) + { + G = gcry_mpi_point_snatch_set (NULL, E->G.x, E->G.y, E->G.z); + E->G.x = NULL; + E->G.y = NULL; + E->G.z = NULL; + } + if (!n) + { + n = E->n; + E->n = NULL; + } + curve_free (E); + gcry_free (E); + } + + errc = _gcry_mpi_ec_p_new (&ctx, p, a); + if (!errc) + { + mpi_ec_t ec = _gcry_ctx_get_pointer (ctx, CONTEXT_TYPE_EC); + + if (b) + { + ec->b = b; + b = NULL; + } + if (G) + { + ec->G = G; + G = NULL; + } + if (n) + { + ec->n = n; + n = NULL; + } + if (Q) + { + ec->Q = Q; + Q = NULL; + } + if (d) + { + ec->d = d; + d = NULL; + } + + *r_ctx = ctx; + } + + leave: + mpi_free (p); + mpi_free (a); + mpi_free (b); + gcry_mpi_point_release (G); + mpi_free (n); + gcry_mpi_point_release (Q); + mpi_free (d); + return errc; +} |