123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920 |
- /*
- This file is part of GNUnet.
- Copyright (C) 2012, 2013, 2015 GNUnet e.V.
- GNUnet is free software: you can redistribute it and/or modify it
- under the terms of the GNU Affero General Public License as published
- by the Free Software Foundation, either version 3 of the License,
- or (at your option) any later version.
- GNUnet 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
- Affero General Public License for more details.
- You should have received a copy of the GNU Affero General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: AGPL3.0-or-later
- */
- /**
- * @file util/crypto_ecc.c
- * @brief public key cryptography (ECC) with libgcrypt
- * @author Christian Grothoff
- * @author Florian Dold
- */
- #include "platform.h"
- #include <gcrypt.h>
- #include <sodium.h>
- #include "gnunet_crypto_lib.h"
- #include "gnunet_strings_lib.h"
- #include "benchmark.h"
- #define EXTRA_CHECKS 0
- /**
- * IMPLEMENTATION NOTICE:
- *
- * ECDSA: We use a non-standard curve for ECDSA: Ed25519.
- * For performance reasons, we use cryptographic operations from
- * libsodium wherever we can get away with it, even though libsodium
- * itself does not support ECDSA.
- * This is why the sign and verifiy functionality from libgcrypt is
- * required and used.
- *
- * EdDSA: We use a standard EdDSA construction.
- * (We still use libgcrypt for hashing and RNG, but not EC)
- *
- * ECDHE: For both EdDSA and ECDSA keys, we use libsodium for
- * ECDHE due to performance benefits over libgcrypt.
- */
- /**
- * Name of the curve we are using. Note that we have hard-coded
- * structs that use 256 bits, so using a bigger curve will require
- * changes that break stuff badly. The name of the curve given here
- * must be agreed by all peers and be supported by libgcrypt.
- */
- #define CURVE "Ed25519"
- #define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
- #define LOG_STRERROR(kind, syscall) \
- GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
- #define LOG_STRERROR_FILE(kind, syscall, filename) \
- GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
- /**
- * Log an error message at log-level 'level' that indicates
- * a failure of the command 'cmd' with the message given
- * by gcry_strerror(rc).
- */
- #define LOG_GCRY(level, cmd, rc) \
- do \
- { \
- LOG (level, \
- _ ("`%s' failed at %s:%d with error: %s\n"), \
- cmd, \
- __FILE__, \
- __LINE__, \
- gcry_strerror (rc)); \
- } while (0)
- /**
- * Extract values from an S-expression.
- *
- * @param array where to store the result(s)
- * @param sexp S-expression to parse
- * @param topname top-level name in the S-expression that is of interest
- * @param elems names of the elements to extract
- * @return 0 on success
- */
- static int
- key_from_sexp (gcry_mpi_t *array,
- gcry_sexp_t sexp,
- const char *topname,
- const char *elems)
- {
- gcry_sexp_t list;
- gcry_sexp_t l2;
- unsigned int idx;
- list = gcry_sexp_find_token (sexp, topname, 0);
- if (! list)
- return 1;
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- if (! list)
- return 2;
- idx = 0;
- for (const char *s = elems; *s; s++, idx++)
- {
- l2 = gcry_sexp_find_token (list, s, 1);
- if (! l2)
- {
- for (unsigned int i = 0; i < idx; i++)
- {
- gcry_free (array[i]);
- array[i] = NULL;
- }
- gcry_sexp_release (list);
- return 3; /* required parameter not found */
- }
- array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (l2);
- if (! array[idx])
- {
- for (unsigned int i = 0; i < idx; i++)
- {
- gcry_free (array[i]);
- array[i] = NULL;
- }
- gcry_sexp_release (list);
- return 4; /* required parameter is invalid */
- }
- }
- gcry_sexp_release (list);
- return 0;
- }
- /**
- * Convert the given private key from the network format to the
- * S-expression that can be used by libgcrypt.
- *
- * @param priv private key to decode
- * @return NULL on error
- */
- static gcry_sexp_t
- decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
- {
- gcry_sexp_t result;
- int rc;
- uint8_t d[32];
- for (size_t i = 0; i<32; i++)
- d[i] = priv->d[31 - i];
- rc = gcry_sexp_build (&result,
- NULL,
- "(private-key(ecc(curve \"" CURVE "\")"
- "(d %b)))",
- 32,
- d);
- if (0 != rc)
- {
- LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
- GNUNET_assert (0);
- }
- #if EXTRA_CHECKS
- if (0 != (rc = gcry_pk_testkey (result)))
- {
- LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
- GNUNET_assert (0);
- }
- #endif
- return result;
- }
- void
- GNUNET_CRYPTO_ecdsa_key_get_public (
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
- struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
- {
- BENCHMARK_START (ecdsa_key_get_public);
- crypto_scalarmult_ed25519_base_noclamp (pub->q_y, priv->d);
- BENCHMARK_END (ecdsa_key_get_public);
- }
- void
- GNUNET_CRYPTO_eddsa_key_get_public (
- const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
- struct GNUNET_CRYPTO_EddsaPublicKey *pub)
- {
- unsigned char pk[crypto_sign_PUBLICKEYBYTES];
- unsigned char sk[crypto_sign_SECRETKEYBYTES];
- BENCHMARK_START (eddsa_key_get_public);
- GNUNET_assert (0 == crypto_sign_seed_keypair (pk, sk, priv->d));
- GNUNET_memcpy (pub->q_y, pk, crypto_sign_PUBLICKEYBYTES);
- sodium_memzero (sk, crypto_sign_SECRETKEYBYTES);
- BENCHMARK_END (eddsa_key_get_public);
- }
- void
- GNUNET_CRYPTO_ecdhe_key_get_public (
- const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
- struct GNUNET_CRYPTO_EcdhePublicKey *pub)
- {
- BENCHMARK_START (ecdhe_key_get_public);
- GNUNET_assert (0 == crypto_scalarmult_base (pub->q_y, priv->d));
- BENCHMARK_END (ecdhe_key_get_public);
- }
- char *
- GNUNET_CRYPTO_ecdsa_public_key_to_string (
- const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
- {
- char *pubkeybuf;
- size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
- char *end;
- if (keylen % 5 > 0)
- keylen += 5 - keylen % 5;
- keylen /= 5;
- pubkeybuf = GNUNET_malloc (keylen + 1);
- end =
- GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
- sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
- pubkeybuf,
- keylen);
- if (NULL == end)
- {
- GNUNET_free (pubkeybuf);
- return NULL;
- }
- *end = '\0';
- return pubkeybuf;
- }
- char *
- GNUNET_CRYPTO_eddsa_public_key_to_string (
- const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
- {
- char *pubkeybuf;
- size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
- char *end;
- if (keylen % 5 > 0)
- keylen += 5 - keylen % 5;
- keylen /= 5;
- pubkeybuf = GNUNET_malloc (keylen + 1);
- end =
- GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
- sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
- pubkeybuf,
- keylen);
- if (NULL == end)
- {
- GNUNET_free (pubkeybuf);
- return NULL;
- }
- *end = '\0';
- return pubkeybuf;
- }
- char *
- GNUNET_CRYPTO_eddsa_private_key_to_string (
- const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
- {
- char *privkeybuf;
- size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
- char *end;
- if (keylen % 5 > 0)
- keylen += 5 - keylen % 5;
- keylen /= 5;
- privkeybuf = GNUNET_malloc (keylen + 1);
- end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
- sizeof(
- struct GNUNET_CRYPTO_EddsaPrivateKey),
- privkeybuf,
- keylen);
- if (NULL == end)
- {
- GNUNET_free (privkeybuf);
- return NULL;
- }
- *end = '\0';
- return privkeybuf;
- }
- char *
- GNUNET_CRYPTO_ecdsa_private_key_to_string (
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
- {
- char *privkeybuf;
- size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey)) * 8;
- char *end;
- if (keylen % 5 > 0)
- keylen += 5 - keylen % 5;
- keylen /= 5;
- privkeybuf = GNUNET_malloc (keylen + 1);
- end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
- sizeof(
- struct GNUNET_CRYPTO_EcdsaPrivateKey),
- privkeybuf,
- keylen);
- if (NULL == end)
- {
- GNUNET_free (privkeybuf);
- return NULL;
- }
- *end = '\0';
- return privkeybuf;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_ecdsa_public_key_from_string (
- const char *enc,
- size_t enclen,
- struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
- {
- size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
- if (keylen % 5 > 0)
- keylen += 5 - keylen % 5;
- keylen /= 5;
- if (enclen != keylen)
- return GNUNET_SYSERR;
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (enc,
- enclen,
- pub,
- sizeof(
- struct GNUNET_CRYPTO_EcdsaPublicKey)))
- return GNUNET_SYSERR;
- return GNUNET_OK;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_eddsa_public_key_from_string (
- const char *enc,
- size_t enclen,
- struct GNUNET_CRYPTO_EddsaPublicKey *pub)
- {
- size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
- if (keylen % 5 > 0)
- keylen += 5 - keylen % 5;
- keylen /= 5;
- if (enclen != keylen)
- return GNUNET_SYSERR;
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (enc,
- enclen,
- pub,
- sizeof(
- struct GNUNET_CRYPTO_EddsaPublicKey)))
- return GNUNET_SYSERR;
- return GNUNET_OK;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_eddsa_private_key_from_string (
- const char *enc,
- size_t enclen,
- struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
- {
- size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
- if (keylen % 5 > 0)
- keylen += 5 - keylen % 5;
- keylen /= 5;
- if (enclen != keylen)
- return GNUNET_SYSERR;
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (enc,
- enclen,
- priv,
- sizeof(
- struct GNUNET_CRYPTO_EddsaPrivateKey)))
- return GNUNET_SYSERR;
- #if CRYPTO_BUG
- if (GNUNET_OK != check_eddsa_key (priv))
- {
- GNUNET_break (0);
- return GNUNET_OK;
- }
- #endif
- return GNUNET_OK;
- }
- void
- GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
- {
- memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
- }
- void
- GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
- {
- memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey));
- }
- void
- GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
- {
- memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey));
- }
- void
- GNUNET_CRYPTO_ecdhe_key_create (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
- {
- BENCHMARK_START (ecdhe_key_create);
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
- pk,
- sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
- BENCHMARK_END (ecdhe_key_create);
- }
- void
- GNUNET_CRYPTO_ecdsa_key_create (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
- {
- BENCHMARK_START (ecdsa_key_create);
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
- pk,
- sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
- pk->d[0] &= 248;
- pk->d[31] &= 127;
- pk->d[31] |= 64;
- BENCHMARK_END (ecdsa_key_create);
- }
- void
- GNUNET_CRYPTO_eddsa_key_create (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
- {
- BENCHMARK_START (eddsa_key_create);
- /*
- * We do not clamp for EdDSA, since all functions that use the private key do
- * their own clamping (just like in libsodium). What we call "private key"
- * here, actually corresponds to the seed in libsodium.
- *
- * (Contrast this to ECDSA, where functions using the private key can't clamp
- * due to properties needed for GNS. That is a worse/unsafer API, but
- * required for the GNS constructions to work.)
- */
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
- pk,
- sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
- BENCHMARK_END (eddsa_key_create);
- }
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *
- GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
- {
- /**
- * 'anonymous' pseudonym (global static, d=1, public key = G
- * (generator).
- */
- static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
- static int once;
- if (once)
- return &anonymous;
- GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
- sizeof(anonymous.d),
- GCRYMPI_CONST_ONE);
- anonymous.d[0] &= 248;
- anonymous.d[31] &= 127;
- anonymous.d[31] |= 64;
- once = 1;
- return &anonymous;
- }
- /**
- * Convert the data specified in the given purpose argument to an
- * S-expression suitable for signature operations.
- *
- * @param purpose data to convert
- * @return converted s-expression
- */
- static gcry_sexp_t
- data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
- {
- gcry_sexp_t data;
- int rc;
- /* See #5398 */
- #if 1
- struct GNUNET_HashCode hc;
- GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
- if (0 != (rc = gcry_sexp_build (&data,
- NULL,
- "(data(flags rfc6979)(hash %s %b))",
- "sha512",
- (int) sizeof(hc),
- &hc)))
- {
- LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
- return NULL;
- }
- #else
- if (0 != (rc = gcry_sexp_build (&data,
- NULL,
- "(data(flags rfc6979)(hash %s %b))",
- "sha512",
- ntohl (purpose->size),
- purpose)))
- {
- LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
- return NULL;
- }
- #endif
- return data;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_ecdsa_sign_ (
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
- const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- struct GNUNET_CRYPTO_EcdsaSignature *sig)
- {
- gcry_sexp_t priv_sexp;
- gcry_sexp_t sig_sexp;
- gcry_sexp_t data;
- int rc;
- gcry_mpi_t rs[2];
- BENCHMARK_START (ecdsa_sign);
- priv_sexp = decode_private_ecdsa_key (priv);
- data = data_to_ecdsa_value (purpose);
- if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
- {
- LOG (GNUNET_ERROR_TYPE_WARNING,
- _ ("ECC signing failed at %s:%d: %s\n"),
- __FILE__,
- __LINE__,
- gcry_strerror (rc));
- gcry_sexp_release (data);
- gcry_sexp_release (priv_sexp);
- return GNUNET_SYSERR;
- }
- gcry_sexp_release (priv_sexp);
- gcry_sexp_release (data);
- /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
- 'signature' */
- if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
- {
- GNUNET_break (0);
- gcry_sexp_release (sig_sexp);
- return GNUNET_SYSERR;
- }
- gcry_sexp_release (sig_sexp);
- GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof(sig->r), rs[0]);
- GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof(sig->s), rs[1]);
- gcry_mpi_release (rs[0]);
- gcry_mpi_release (rs[1]);
- BENCHMARK_END (ecdsa_sign);
- return GNUNET_OK;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_eddsa_sign_ (
- const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
- const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
- struct GNUNET_CRYPTO_EddsaSignature *sig)
- {
- size_t mlen = ntohl (purpose->size);
- unsigned char sk[crypto_sign_SECRETKEYBYTES];
- unsigned char pk[crypto_sign_PUBLICKEYBYTES];
- int res;
- BENCHMARK_START (eddsa_sign);
- GNUNET_assert (0 == crypto_sign_seed_keypair (pk, sk, priv->d));
- res = crypto_sign_detached ((uint8_t *) sig,
- NULL,
- (uint8_t *) purpose,
- mlen,
- sk);
- BENCHMARK_END (eddsa_sign);
- return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_ecdsa_verify_ (
- uint32_t purpose,
- const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
- const struct GNUNET_CRYPTO_EcdsaSignature *sig,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
- {
- gcry_sexp_t data;
- gcry_sexp_t sig_sexpr;
- gcry_sexp_t pub_sexpr;
- int rc;
- BENCHMARK_START (ecdsa_verify);
- if (purpose != ntohl (validate->purpose))
- return GNUNET_SYSERR; /* purpose mismatch */
- /* build s-expression for signature */
- if (0 != (rc = gcry_sexp_build (&sig_sexpr,
- NULL,
- "(sig-val(ecdsa(r %b)(s %b)))",
- (int) sizeof(sig->r),
- sig->r,
- (int) sizeof(sig->s),
- sig->s)))
- {
- LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
- return GNUNET_SYSERR;
- }
- data = data_to_ecdsa_value (validate);
- if (0 != (rc = gcry_sexp_build (&pub_sexpr,
- NULL,
- "(public-key(ecc(curve " CURVE ")(q %b)))",
- (int) sizeof(pub->q_y),
- pub->q_y)))
- {
- gcry_sexp_release (data);
- gcry_sexp_release (sig_sexpr);
- return GNUNET_SYSERR;
- }
- rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
- gcry_sexp_release (pub_sexpr);
- gcry_sexp_release (data);
- gcry_sexp_release (sig_sexpr);
- if (0 != rc)
- {
- LOG (GNUNET_ERROR_TYPE_INFO,
- _ ("ECDSA signature verification failed at %s:%d: %s\n"),
- __FILE__,
- __LINE__,
- gcry_strerror (rc));
- BENCHMARK_END (ecdsa_verify);
- return GNUNET_SYSERR;
- }
- BENCHMARK_END (ecdsa_verify);
- return GNUNET_OK;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_eddsa_verify_ (
- uint32_t purpose,
- const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
- const struct GNUNET_CRYPTO_EddsaSignature *sig,
- const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
- {
- const unsigned char *m = (const void *) validate;
- size_t mlen = ntohl (validate->size);
- const unsigned char *s = (const void *) sig;
- int res;
- if (purpose != ntohl (validate->purpose))
- return GNUNET_SYSERR; /* purpose mismatch */
- BENCHMARK_START (eddsa_verify);
- res = crypto_sign_verify_detached (s, m, mlen, pub->q_y);
- BENCHMARK_END (eddsa_verify);
- return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
- const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
- struct GNUNET_HashCode *key_material)
- {
- uint8_t p[crypto_scalarmult_BYTES];
- if (0 != crypto_scalarmult (p, priv->d, pub->q_y))
- return GNUNET_SYSERR;
- GNUNET_CRYPTO_hash (p, crypto_scalarmult_BYTES, key_material);
- return GNUNET_OK;
- }
- /**
- * Derive the 'h' value for key derivation, where
- * 'h = H(l,P)'.
- *
- * @param pub public key for deriviation
- * @param label label for deriviation
- * @param context additional context to use for HKDF of 'h';
- * typically the name of the subsystem/application
- * @return h value
- */
- static gcry_mpi_t
- derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
- const char *label,
- const char *context)
- {
- gcry_mpi_t h;
- struct GNUNET_HashCode hc;
- static const char *const salt = "key-derivation";
- GNUNET_CRYPTO_kdf (&hc,
- sizeof(hc),
- salt,
- strlen (salt),
- pub,
- sizeof(*pub),
- label,
- strlen (label),
- context,
- strlen (context),
- NULL,
- 0);
- GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
- return h;
- }
- struct GNUNET_CRYPTO_EcdsaPrivateKey *
- GNUNET_CRYPTO_ecdsa_private_key_derive (
- const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
- const char *label,
- const char *context)
- {
- struct GNUNET_CRYPTO_EcdsaPublicKey pub;
- struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
- uint8_t dc[32];
- gcry_mpi_t h;
- gcry_mpi_t x;
- gcry_mpi_t d;
- gcry_mpi_t n;
- gcry_ctx_t ctx;
- GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
- n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
- GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
- h = derive_h (&pub, label, context);
- /* Convert to big endian for libgcrypt */
- for (size_t i = 0; i < 32; i++)
- dc[i] = priv->d[31 - i];
- GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc));
- d = gcry_mpi_new (256);
- gcry_mpi_mulm (d, h, x, n);
- gcry_mpi_release (h);
- gcry_mpi_release (x);
- gcry_mpi_release (n);
- gcry_ctx_release (ctx);
- ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
- GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
- /* Convert to big endian for libgcrypt */
- for (size_t i = 0; i < 32; i++)
- ret->d[i] = dc[31 - i];
- sodium_memzero (dc, sizeof(dc));
- gcry_mpi_release (d);
- return ret;
- }
- void
- GNUNET_CRYPTO_ecdsa_public_key_derive (
- const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
- const char *label,
- const char *context,
- struct GNUNET_CRYPTO_EcdsaPublicKey *result)
- {
- gcry_ctx_t ctx;
- gcry_mpi_t q_y;
- gcry_mpi_t h;
- gcry_mpi_t n;
- gcry_mpi_t h_mod_n;
- gcry_mpi_point_t q;
- gcry_mpi_point_t v;
- GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
- /* obtain point 'q' from original public key. The provided 'q' is
- compressed thus we first store it in the context and then get it
- back as a (decompresssed) point. */
- q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
- GNUNET_assert (NULL != q_y);
- GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
- gcry_mpi_release (q_y);
- q = gcry_mpi_ec_get_point ("q", ctx, 0);
- GNUNET_assert (q);
- /* calculate h_mod_n = h % n */
- h = derive_h (pub, label, context);
- n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
- h_mod_n = gcry_mpi_new (256);
- gcry_mpi_mod (h_mod_n, h, n);
- /* calculate v = h_mod_n * q */
- v = gcry_mpi_point_new (0);
- gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
- gcry_mpi_release (h_mod_n);
- gcry_mpi_release (h);
- gcry_mpi_release (n);
- gcry_mpi_point_release (q);
- /* convert point 'v' to public key that we return */
- GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
- gcry_mpi_point_release (v);
- q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
- GNUNET_assert (q_y);
- GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
- gcry_mpi_release (q_y);
- gcry_ctx_release (ctx);
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
- const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
- struct GNUNET_HashCode *key_material)
- {
- struct GNUNET_HashCode hc;
- uint8_t a[crypto_scalarmult_SCALARBYTES];
- uint8_t p[crypto_scalarmult_BYTES];
- GNUNET_CRYPTO_hash (priv,
- sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
- &hc);
- memcpy (a, &hc, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
- if (0 != crypto_scalarmult (p, a, pub->q_y))
- return GNUNET_SYSERR;
- GNUNET_CRYPTO_hash (p,
- crypto_scalarmult_BYTES,
- key_material);
- return GNUNET_OK;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
- const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
- struct GNUNET_HashCode *key_material)
- {
- uint8_t p[crypto_scalarmult_BYTES];
- BENCHMARK_START (ecdsa_ecdh);
- if (0 != crypto_scalarmult (p, priv->d, pub->q_y))
- return GNUNET_SYSERR;
- GNUNET_CRYPTO_hash (p,
- crypto_scalarmult_BYTES,
- key_material);
- BENCHMARK_END (ecdsa_ecdh);
- return GNUNET_OK;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
- const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
- struct GNUNET_HashCode *key_material)
- {
- uint8_t p[crypto_scalarmult_BYTES];
- uint8_t curve25510_pk[crypto_scalarmult_BYTES];
- if (0 != crypto_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y))
- return GNUNET_SYSERR;
- if (0 != crypto_scalarmult (p, priv->d, curve25510_pk))
- return GNUNET_SYSERR;
- GNUNET_CRYPTO_hash (p, crypto_scalarmult_BYTES, key_material);
- return GNUNET_OK;
- }
- enum GNUNET_GenericReturnValue
- GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
- const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
- struct GNUNET_HashCode *key_material)
- {
- uint8_t p[crypto_scalarmult_BYTES];
- uint8_t curve25510_pk[crypto_scalarmult_BYTES];
- if (0 != crypto_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y))
- return GNUNET_SYSERR;
- if (0 != crypto_scalarmult (p, priv->d, curve25510_pk))
- return GNUNET_SYSERR;
- GNUNET_CRYPTO_hash (p, crypto_scalarmult_BYTES, key_material);
- return GNUNET_OK;
- }
- /* end of crypto_ecc.c */
|