diff --git a/cipher/ecc-ecdh.c b/cipher/ecc-ecdh.c index 13d7e715..f89ede72 100644 --- a/cipher/ecc-ecdh.c +++ b/cipher/ecc-ecdh.c @@ -1,153 +1,184 @@ /* ecc-ecdh.c - Elliptic Curve Diffie-Hellman key agreement * Copyright (C) 2019 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 . * SPDX-License-Identifier: LGPL-2.1+ */ #include #include #include #include #include #include "g10lib.h" #include "mpi.h" #include "cipher.h" #include "context.h" #include "ec-context.h" #include "ecc-common.h" #define ECC_CURVE25519_BYTES 32 #define ECC_CURVE448_BYTES 56 static gpg_err_code_t prepare_ec (mpi_ec_t *r_ec, const char *name) { int flags = 0; if (!strcmp (name, "Curve25519")) flags = PUBKEY_FLAG_DJB_TWEAK; return _gcry_mpi_ec_internal_new (r_ec, &flags, "ecc_mul_point", NULL, name); } unsigned int _gcry_ecc_get_algo_keylen (int curveid) { unsigned int len = 0; if (curveid == GCRY_ECC_CURVE25519) len = ECC_CURVE25519_BYTES; else if (curveid == GCRY_ECC_CURVE448) len = ECC_CURVE448_BYTES; return len; } gpg_err_code_t _gcry_ecc_curve_mul_point (const char *curve, unsigned char *result, const unsigned char *scalar, const unsigned char *point) { unsigned int nbits; unsigned int nbytes; gpg_err_code_t err; gcry_mpi_t mpi_k = NULL; mpi_ec_t ec = NULL; mpi_point_struct Q = { NULL, NULL, NULL }; gcry_mpi_t x = NULL; unsigned int len; unsigned char *buf; err = prepare_ec (&ec, curve); if (err) return err; nbits = ec->nbits; nbytes = (nbits + 7)/8; if (ec->model == MPI_EC_MONTGOMERY) mpi_k = _gcry_mpi_set_opaque_copy (NULL, scalar, nbytes*8); else if (ec->model == MPI_EC_WEIERSTRASS) { mpi_k = mpi_new (nbytes*8); _gcry_mpi_set_buffer (mpi_k, scalar, nbytes, 0); } else { err = GPG_ERR_UNKNOWN_CURVE; goto leave; } - x = mpi_new (nbits); point_init (&Q); if (point) { gcry_mpi_t mpi_u = _gcry_mpi_set_opaque_copy (NULL, point, nbytes*8); mpi_point_struct P; point_init (&P); if (ec->model == MPI_EC_MONTGOMERY) err = _gcry_ecc_mont_decodepoint (mpi_u, ec, &P); else if (ec->model == MPI_EC_WEIERSTRASS) err = _gcry_ecc_sec_decodepoint (mpi_u, ec, &P); else err = GPG_ERR_UNKNOWN_CURVE; _gcry_mpi_release (mpi_u); if (err) goto leave; _gcry_mpi_ec_mul_point (&Q, mpi_k, &P, ec); point_free (&P); } else _gcry_mpi_ec_mul_point (&Q, mpi_k, ec->G, ec); - _gcry_mpi_ec_get_affine (x, NULL, &Q, ec); + x = mpi_new (nbits); + if (ec->model == MPI_EC_WEIERSTRASS) + { + gcry_mpi_t y = mpi_new (nbits); - buf = _gcry_mpi_get_buffer (x, nbytes, &len, NULL); - if (!buf) - err = gpg_err_code_from_syserror (); + _gcry_mpi_ec_get_affine (x, y, &Q, ec); + + buf = _gcry_ecc_ec2os_buf (x, y, ec->p, &len); + if (!buf) + { + err = gpg_err_code_from_syserror (); + _gcry_mpi_release (y); + } + else + { + if (len != 1 + 2*nbytes) + { + err = GPG_ERR_INV_ARG; + _gcry_mpi_release (y); + } + else + { + /* (x,y) in SEC1 point encoding. */ + memcpy (result, buf, nbytes); + xfree (buf); + _gcry_mpi_release (y); + } + } + } else { - memcpy (result, buf, nbytes); - xfree (buf); + _gcry_mpi_ec_get_affine (x, NULL, &Q, ec); + buf = _gcry_mpi_get_buffer (x, nbytes, &len, NULL); + if (!buf) + err = gpg_err_code_from_syserror (); + else + { + /* x in little endian. */ + memcpy (result, buf, nbytes); + xfree (buf); + } } + _gcry_mpi_release (x); leave: - _gcry_mpi_release (x); point_free (&Q); _gcry_mpi_release (mpi_k); _gcry_mpi_ec_free (ec); return err; } gpg_err_code_t _gcry_ecc_mul_point (int curveid, unsigned char *result, const unsigned char *scalar, const unsigned char *point) { const char *curve; if (curveid == GCRY_ECC_CURVE25519) curve = "Curve25519"; else if (curveid == GCRY_ECC_CURVE448) curve = "X448"; else return gpg_error (GPG_ERR_UNKNOWN_CURVE); return _gcry_ecc_curve_mul_point (curve, result, scalar, point); }