2 This file is part of GNUnet.
3 Copyright (C) 2012, 2013, 2015 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @file util/crypto_ecc.c
23 * @brief public key cryptography (ECC) with libgcrypt
24 * @author Christian Grothoff
28 #include "gnunet_crypto_lib.h"
29 #include "gnunet_strings_lib.h"
30 #include "benchmark.h"
32 #define EXTRA_CHECKS 0
35 * Name of the curve we are using. Note that we have hard-coded
36 * structs that use 256 bits, so using a bigger curve will require
37 * changes that break stuff badly. The name of the curve given here
38 * must be agreed by all peers and be supported by libgcrypt.
40 #define CURVE "Ed25519"
42 #define LOG(kind, ...) GNUNET_log_from(kind, "util-crypto-ecc", __VA_ARGS__)
44 #define LOG_STRERROR(kind, syscall) \
45 GNUNET_log_from_strerror(kind, "util-crypto-ecc", syscall)
47 #define LOG_STRERROR_FILE(kind, syscall, filename) \
48 GNUNET_log_from_strerror_file(kind, "util-crypto-ecc", syscall, filename)
51 * Log an error message at log-level 'level' that indicates
52 * a failure of the command 'cmd' with the message given
53 * by gcry_strerror(rc).
55 #define LOG_GCRY(level, cmd, rc) \
59 _("`%s' failed at %s:%d with error: %s\n"), \
68 * Extract values from an S-expression.
70 * @param array where to store the result(s)
71 * @param sexp S-expression to parse
72 * @param topname top-level name in the S-expression that is of interest
73 * @param elems names of the elements to extract
74 * @return 0 on success
77 key_from_sexp(gcry_mpi_t *array,
87 list = gcry_sexp_find_token(sexp, topname, 0);
90 l2 = gcry_sexp_cadr(list);
91 gcry_sexp_release(list);
97 for (s = elems; *s; s++, idx++)
99 l2 = gcry_sexp_find_token(list, s, 1);
102 for (unsigned int i = 0; i < idx; i++)
107 gcry_sexp_release(list);
108 return 3; /* required parameter not found */
110 array[idx] = gcry_sexp_nth_mpi(l2, 1, GCRYMPI_FMT_USG);
111 gcry_sexp_release(l2);
114 for (unsigned int i = 0; i < idx; i++)
119 gcry_sexp_release(list);
120 return 4; /* required parameter is invalid */
123 gcry_sexp_release(list);
129 * Convert the given private key from the network format to the
130 * S-expression that can be used by libgcrypt.
132 * @param priv private key to decode
133 * @return NULL on error
136 decode_private_ecdsa_key(const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
141 rc = gcry_sexp_build(&result,
143 "(private-key(ecc(curve \"" CURVE "\")"
145 (int)sizeof(priv->d),
149 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
153 if (0 != (rc = gcry_pk_testkey(result)))
155 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
164 * Convert the given private key from the network format to the
165 * S-expression that can be used by libgcrypt.
167 * @param priv private key to decode
168 * @return NULL on error
171 decode_private_eddsa_key(const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
176 rc = gcry_sexp_build(&result,
178 "(private-key(ecc(curve \"" CURVE "\")"
179 "(flags eddsa)(d %b)))",
180 (int)sizeof(priv->d),
184 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
188 if (0 != (rc = gcry_pk_testkey(result)))
190 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
199 * Convert the given private key from the network format to the
200 * S-expression that can be used by libgcrypt.
202 * @param priv private key to decode
203 * @return NULL on error
206 decode_private_ecdhe_key(const struct GNUNET_CRYPTO_EcdhePrivateKey *priv)
211 rc = gcry_sexp_build(&result,
213 "(private-key(ecc(curve \"" CURVE "\")"
215 (int)sizeof(priv->d),
219 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
223 if (0 != (rc = gcry_pk_testkey(result)))
225 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
234 * Extract the public key for the given private key.
236 * @param priv the private key
237 * @param pub where to write the public key
240 GNUNET_CRYPTO_ecdsa_key_get_public(
241 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
242 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
248 BENCHMARK_START(ecdsa_key_get_public);
250 sexp = decode_private_ecdsa_key(priv);
251 GNUNET_assert(NULL != sexp);
252 GNUNET_assert(0 == gcry_mpi_ec_new(&ctx, sexp, NULL));
253 gcry_sexp_release(sexp);
254 q = gcry_mpi_ec_get_mpi("q@eddsa", ctx, 0);
255 GNUNET_assert(NULL != q);
256 GNUNET_CRYPTO_mpi_print_unsigned(pub->q_y, sizeof(pub->q_y), q);
258 gcry_ctx_release(ctx);
260 BENCHMARK_END(ecdsa_key_get_public);
265 * Extract the public key for the given private key.
267 * @param priv the private key
268 * @param pub where to write the public key
271 GNUNET_CRYPTO_eddsa_key_get_public(
272 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
273 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
279 BENCHMARK_START(eddsa_key_get_public);
281 sexp = decode_private_eddsa_key(priv);
282 GNUNET_assert(NULL != sexp);
283 GNUNET_assert(0 == gcry_mpi_ec_new(&ctx, sexp, NULL));
284 gcry_sexp_release(sexp);
285 q = gcry_mpi_ec_get_mpi("q@eddsa", ctx, 0);
287 GNUNET_CRYPTO_mpi_print_unsigned(pub->q_y, sizeof(pub->q_y), q);
289 gcry_ctx_release(ctx);
291 BENCHMARK_END(eddsa_key_get_public);
296 * Extract the public key for the given private key.
298 * @param priv the private key
299 * @param pub where to write the public key
302 GNUNET_CRYPTO_ecdhe_key_get_public(
303 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
304 struct GNUNET_CRYPTO_EcdhePublicKey *pub)
310 BENCHMARK_START(ecdhe_key_get_public);
312 sexp = decode_private_ecdhe_key(priv);
313 GNUNET_assert(NULL != sexp);
314 GNUNET_assert(0 == gcry_mpi_ec_new(&ctx, sexp, NULL));
315 gcry_sexp_release(sexp);
316 q = gcry_mpi_ec_get_mpi("q@eddsa", ctx, 0);
318 GNUNET_CRYPTO_mpi_print_unsigned(pub->q_y, sizeof(pub->q_y), q);
320 gcry_ctx_release(ctx);
322 BENCHMARK_END(ecdhe_key_get_public);
327 * Convert a public key to a string.
329 * @param pub key to convert
330 * @return string representing @a pub
333 GNUNET_CRYPTO_ecdsa_public_key_to_string(
334 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
337 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
341 keylen += 5 - keylen % 5;
343 pubkeybuf = GNUNET_malloc(keylen + 1);
345 GNUNET_STRINGS_data_to_string((unsigned char *)pub,
346 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
351 GNUNET_free(pubkeybuf);
360 * Convert a public key to a string.
362 * @param pub key to convert
363 * @return string representing @a pub
366 GNUNET_CRYPTO_eddsa_public_key_to_string(
367 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
370 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
374 keylen += 5 - keylen % 5;
376 pubkeybuf = GNUNET_malloc(keylen + 1);
378 GNUNET_STRINGS_data_to_string((unsigned char *)pub,
379 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
384 GNUNET_free(pubkeybuf);
393 * Convert a private key to a string.
395 * @param priv key to convert
396 * @return string representing @a pub
399 GNUNET_CRYPTO_eddsa_private_key_to_string(
400 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
403 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
407 keylen += 5 - keylen % 5;
409 privkeybuf = GNUNET_malloc(keylen + 1);
410 end = GNUNET_STRINGS_data_to_string((unsigned char *)priv,
412 struct GNUNET_CRYPTO_EddsaPrivateKey),
417 GNUNET_free(privkeybuf);
426 * Convert a private key to a string.
428 * @param priv key to convert
429 * @return string representing @a priv
432 GNUNET_CRYPTO_ecdsa_private_key_to_string(
433 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
436 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey)) * 8;
440 keylen += 5 - keylen % 5;
442 privkeybuf = GNUNET_malloc(keylen + 1);
443 end = GNUNET_STRINGS_data_to_string((unsigned char *)priv,
445 struct GNUNET_CRYPTO_EcdsaPrivateKey),
450 GNUNET_free(privkeybuf);
459 * Convert a string representing a public key to a public key.
461 * @param enc encoded public key
462 * @param enclen number of bytes in @a enc (without 0-terminator)
463 * @param pub where to store the public key
464 * @return #GNUNET_OK on success
467 GNUNET_CRYPTO_ecdsa_public_key_from_string(
470 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
472 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
475 keylen += 5 - keylen % 5;
477 if (enclen != keylen)
478 return GNUNET_SYSERR;
481 GNUNET_STRINGS_string_to_data(enc,
485 struct GNUNET_CRYPTO_EcdsaPublicKey)))
486 return GNUNET_SYSERR;
492 * Convert a string representing a public key to a public key.
494 * @param enc encoded public key
495 * @param enclen number of bytes in @a enc (without 0-terminator)
496 * @param pub where to store the public key
497 * @return #GNUNET_OK on success
500 GNUNET_CRYPTO_eddsa_public_key_from_string(
503 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
505 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
508 keylen += 5 - keylen % 5;
510 if (enclen != keylen)
511 return GNUNET_SYSERR;
514 GNUNET_STRINGS_string_to_data(enc,
518 struct GNUNET_CRYPTO_EddsaPublicKey)))
519 return GNUNET_SYSERR;
525 * Convert a string representing a private key to a private key.
527 * @param enc encoded public key
528 * @param enclen number of bytes in @a enc (without 0-terminator)
529 * @param priv where to store the private key
530 * @return #GNUNET_OK on success
533 GNUNET_CRYPTO_eddsa_private_key_from_string(
536 struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
538 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
541 keylen += 5 - keylen % 5;
543 if (enclen != keylen)
544 return GNUNET_SYSERR;
547 GNUNET_STRINGS_string_to_data(enc,
551 struct GNUNET_CRYPTO_EddsaPrivateKey)))
552 return GNUNET_SYSERR;
554 if (GNUNET_OK != check_eddsa_key(priv))
566 * Clear memory that was used to store a private key.
568 * @param pk location of the key
571 GNUNET_CRYPTO_ecdhe_key_clear(struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
573 memset(pk, 0, sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
579 * Clear memory that was used to store a private key.
581 * @param pk location of the key
584 GNUNET_CRYPTO_ecdsa_key_clear(struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
586 memset(pk, 0, sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey));
592 * Clear memory that was used to store a private key.
594 * @param pk location of the key
597 GNUNET_CRYPTO_eddsa_key_clear(struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
599 memset(pk, 0, sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey));
604 * Create a new private key. Caller must free return value.
606 * @return fresh private key
608 struct GNUNET_CRYPTO_EcdhePrivateKey *
609 GNUNET_CRYPTO_ecdhe_key_create()
611 struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
613 priv = GNUNET_new(struct GNUNET_CRYPTO_EcdhePrivateKey);
614 if (GNUNET_OK != GNUNET_CRYPTO_ecdhe_key_create2(priv))
625 * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
627 * @param[out] pk set to fresh private key;
628 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
631 GNUNET_CRYPTO_ecdhe_key_create2(struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
633 gcry_sexp_t priv_sexp;
634 gcry_sexp_t s_keyparam;
638 BENCHMARK_START(ecdhe_key_create);
640 /* NOTE: For libgcrypt >= 1.7, we do not need the 'eddsa' flag here,
641 but should also be harmless. For libgcrypt < 1.7, using 'eddsa'
642 disables an expensive key testing routine. We do not want to run
643 the expensive check for ECDHE, as we generate TONS of keys to
644 use for a very short time. */
645 if (0 != (rc = gcry_sexp_build(&s_keyparam,
647 "(genkey(ecc(curve \"" CURVE "\")"
648 "(flags eddsa no-keytest)))")))
650 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
651 return GNUNET_SYSERR;
653 if (0 != (rc = gcry_pk_genkey(&priv_sexp, s_keyparam)))
655 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
656 gcry_sexp_release(s_keyparam);
657 return GNUNET_SYSERR;
659 gcry_sexp_release(s_keyparam);
661 if (0 != (rc = gcry_pk_testkey(priv_sexp)))
663 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
664 gcry_sexp_release(priv_sexp);
665 return GNUNET_SYSERR;
668 if (0 != (rc = key_from_sexp(&d, priv_sexp, "private-key", "d")))
670 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
671 gcry_sexp_release(priv_sexp);
672 return GNUNET_SYSERR;
674 gcry_sexp_release(priv_sexp);
675 GNUNET_CRYPTO_mpi_print_unsigned(pk->d, sizeof(pk->d), d);
678 BENCHMARK_END(ecdhe_key_create);
685 * Create a new private key. Caller must free return value.
687 * @return fresh private key
689 struct GNUNET_CRYPTO_EcdsaPrivateKey *
690 GNUNET_CRYPTO_ecdsa_key_create()
692 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
693 gcry_sexp_t priv_sexp;
694 gcry_sexp_t s_keyparam;
698 BENCHMARK_START(ecdsa_key_create);
700 if (0 != (rc = gcry_sexp_build(&s_keyparam,
702 "(genkey(ecc(curve \"" CURVE "\")"
705 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
708 if (0 != (rc = gcry_pk_genkey(&priv_sexp, s_keyparam)))
710 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
711 gcry_sexp_release(s_keyparam);
714 gcry_sexp_release(s_keyparam);
716 if (0 != (rc = gcry_pk_testkey(priv_sexp)))
718 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
719 gcry_sexp_release(priv_sexp);
723 if (0 != (rc = key_from_sexp(&d, priv_sexp, "private-key", "d")))
725 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
726 gcry_sexp_release(priv_sexp);
729 gcry_sexp_release(priv_sexp);
730 priv = GNUNET_new(struct GNUNET_CRYPTO_EcdsaPrivateKey);
731 GNUNET_CRYPTO_mpi_print_unsigned(priv->d, sizeof(priv->d), d);
734 BENCHMARK_END(ecdsa_key_create);
740 * Create a new private key. Caller must free return value.
742 * @return fresh private key
744 struct GNUNET_CRYPTO_EddsaPrivateKey *
745 GNUNET_CRYPTO_eddsa_key_create()
747 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
748 gcry_sexp_t priv_sexp;
749 gcry_sexp_t s_keyparam;
753 BENCHMARK_START(eddsa_key_create);
758 if (0 != (rc = gcry_sexp_build(&s_keyparam,
760 "(genkey(ecc(curve \"" CURVE "\")"
763 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
766 if (0 != (rc = gcry_pk_genkey(&priv_sexp, s_keyparam)))
768 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
769 gcry_sexp_release(s_keyparam);
772 gcry_sexp_release(s_keyparam);
774 if (0 != (rc = gcry_pk_testkey(priv_sexp)))
776 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
777 gcry_sexp_release(priv_sexp);
781 if (0 != (rc = key_from_sexp(&d, priv_sexp, "private-key", "d")))
783 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
784 gcry_sexp_release(priv_sexp);
787 gcry_sexp_release(priv_sexp);
788 priv = GNUNET_new(struct GNUNET_CRYPTO_EddsaPrivateKey);
789 GNUNET_CRYPTO_mpi_print_unsigned(priv->d, sizeof(priv->d), d);
793 if (GNUNET_OK != check_eddsa_key(priv))
801 BENCHMARK_END(eddsa_key_create);
808 * Get the shared private key we use for anonymous users.
810 * @return "anonymous" private key
812 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
813 GNUNET_CRYPTO_ecdsa_key_get_anonymous()
816 * 'anonymous' pseudonym (global static, d=1, public key = G
819 static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
824 GNUNET_CRYPTO_mpi_print_unsigned(anonymous.d,
833 * Convert the data specified in the given purpose argument to an
834 * S-expression suitable for signature operations.
836 * @param purpose data to convert
837 * @return converted s-expression
840 data_to_eddsa_value(const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
847 struct GNUNET_HashCode hc;
849 GNUNET_CRYPTO_hash(purpose, ntohl(purpose->size), &hc);
850 if (0 != (rc = gcry_sexp_build(&data,
852 "(data(flags eddsa)(hash-algo %s)(value %b))",
857 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
861 GNUNET_CRYPTO_hash(purpose, ntohl(purpose->size), &hc);
862 if (0 != (rc = gcry_sexp_build(&data,
864 "(data(flags eddsa)(hash-algo %s)(value %b))",
866 ntohl(purpose->size),
869 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
878 * Convert the data specified in the given purpose argument to an
879 * S-expression suitable for signature operations.
881 * @param purpose data to convert
882 * @return converted s-expression
885 data_to_ecdsa_value(const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
892 struct GNUNET_HashCode hc;
894 GNUNET_CRYPTO_hash(purpose, ntohl(purpose->size), &hc);
895 if (0 != (rc = gcry_sexp_build(&data,
897 "(data(flags rfc6979)(hash %s %b))",
902 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
906 if (0 != (rc = gcry_sexp_build(&data,
908 "(data(flags rfc6979)(hash %s %b))",
910 ntohl(purpose->size),
913 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
922 * Sign a given block.
924 * @param priv private key to use for the signing
925 * @param purpose what to sign (size, purpose)
926 * @param sig where to write the signature
927 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
930 GNUNET_CRYPTO_ecdsa_sign(
931 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
932 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
933 struct GNUNET_CRYPTO_EcdsaSignature *sig)
935 gcry_sexp_t priv_sexp;
936 gcry_sexp_t sig_sexp;
941 BENCHMARK_START(ecdsa_sign);
943 priv_sexp = decode_private_ecdsa_key(priv);
944 data = data_to_ecdsa_value(purpose);
945 if (0 != (rc = gcry_pk_sign(&sig_sexp, data, priv_sexp)))
947 LOG(GNUNET_ERROR_TYPE_WARNING,
948 _("ECC signing failed at %s:%d: %s\n"),
952 gcry_sexp_release(data);
953 gcry_sexp_release(priv_sexp);
954 return GNUNET_SYSERR;
956 gcry_sexp_release(priv_sexp);
957 gcry_sexp_release(data);
959 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
961 if (0 != (rc = key_from_sexp(rs, sig_sexp, "sig-val", "rs")))
964 gcry_sexp_release(sig_sexp);
965 return GNUNET_SYSERR;
967 gcry_sexp_release(sig_sexp);
968 GNUNET_CRYPTO_mpi_print_unsigned(sig->r, sizeof(sig->r), rs[0]);
969 GNUNET_CRYPTO_mpi_print_unsigned(sig->s, sizeof(sig->s), rs[1]);
970 gcry_mpi_release(rs[0]);
971 gcry_mpi_release(rs[1]);
973 BENCHMARK_END(ecdsa_sign);
980 * Sign a given block.
982 * @param priv private key to use for the signing
983 * @param purpose what to sign (size, purpose)
984 * @param sig where to write the signature
985 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
988 GNUNET_CRYPTO_eddsa_sign(
989 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
990 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
991 struct GNUNET_CRYPTO_EddsaSignature *sig)
993 gcry_sexp_t priv_sexp;
994 gcry_sexp_t sig_sexp;
999 BENCHMARK_START(eddsa_sign);
1001 priv_sexp = decode_private_eddsa_key(priv);
1002 data = data_to_eddsa_value(purpose);
1003 if (0 != (rc = gcry_pk_sign(&sig_sexp, data, priv_sexp)))
1005 LOG(GNUNET_ERROR_TYPE_WARNING,
1006 _("EdDSA signing failed at %s:%d: %s\n"),
1010 gcry_sexp_release(data);
1011 gcry_sexp_release(priv_sexp);
1012 return GNUNET_SYSERR;
1014 gcry_sexp_release(priv_sexp);
1015 gcry_sexp_release(data);
1017 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
1019 if (0 != (rc = key_from_sexp(rs, sig_sexp, "sig-val", "rs")))
1022 gcry_sexp_release(sig_sexp);
1023 return GNUNET_SYSERR;
1025 gcry_sexp_release(sig_sexp);
1026 GNUNET_CRYPTO_mpi_print_unsigned(sig->r, sizeof(sig->r), rs[0]);
1027 GNUNET_CRYPTO_mpi_print_unsigned(sig->s, sizeof(sig->s), rs[1]);
1028 gcry_mpi_release(rs[0]);
1029 gcry_mpi_release(rs[1]);
1031 BENCHMARK_END(eddsa_sign);
1040 * @param purpose what is the purpose that the signature should have?
1041 * @param validate block to validate (size, purpose, data)
1042 * @param sig signature that is being validated
1043 * @param pub public key of the signer
1044 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
1047 GNUNET_CRYPTO_ecdsa_verify(
1049 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
1050 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
1051 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
1054 gcry_sexp_t sig_sexpr;
1055 gcry_sexp_t pub_sexpr;
1058 BENCHMARK_START(ecdsa_verify);
1060 if (purpose != ntohl(validate->purpose))
1061 return GNUNET_SYSERR; /* purpose mismatch */
1063 /* build s-expression for signature */
1064 if (0 != (rc = gcry_sexp_build(&sig_sexpr,
1066 "(sig-val(ecdsa(r %b)(s %b)))",
1067 (int)sizeof(sig->r),
1069 (int)sizeof(sig->s),
1072 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1073 return GNUNET_SYSERR;
1075 data = data_to_ecdsa_value(validate);
1076 if (0 != (rc = gcry_sexp_build(&pub_sexpr,
1078 "(public-key(ecc(curve " CURVE ")(q %b)))",
1079 (int)sizeof(pub->q_y),
1082 gcry_sexp_release(data);
1083 gcry_sexp_release(sig_sexpr);
1084 return GNUNET_SYSERR;
1086 rc = gcry_pk_verify(sig_sexpr, data, pub_sexpr);
1087 gcry_sexp_release(pub_sexpr);
1088 gcry_sexp_release(data);
1089 gcry_sexp_release(sig_sexpr);
1092 LOG(GNUNET_ERROR_TYPE_INFO,
1093 _("ECDSA signature verification failed at %s:%d: %s\n"),
1097 BENCHMARK_END(ecdsa_verify);
1098 return GNUNET_SYSERR;
1100 BENCHMARK_END(ecdsa_verify);
1108 * @param purpose what is the purpose that the signature should have?
1109 * @param validate block to validate (size, purpose, data)
1110 * @param sig signature that is being validated
1111 * @param pub public key of the signer
1112 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
1115 GNUNET_CRYPTO_eddsa_verify(
1117 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
1118 const struct GNUNET_CRYPTO_EddsaSignature *sig,
1119 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
1122 gcry_sexp_t sig_sexpr;
1123 gcry_sexp_t pub_sexpr;
1126 BENCHMARK_START(eddsa_verify);
1128 if (purpose != ntohl(validate->purpose))
1129 return GNUNET_SYSERR; /* purpose mismatch */
1131 /* build s-expression for signature */
1132 if (0 != (rc = gcry_sexp_build(&sig_sexpr,
1134 "(sig-val(eddsa(r %b)(s %b)))",
1135 (int)sizeof(sig->r),
1137 (int)sizeof(sig->s),
1140 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1141 return GNUNET_SYSERR;
1143 data = data_to_eddsa_value(validate);
1144 if (0 != (rc = gcry_sexp_build(&pub_sexpr,
1146 "(public-key(ecc(curve " CURVE
1147 ")(flags eddsa)(q %b)))",
1148 (int)sizeof(pub->q_y),
1151 gcry_sexp_release(data);
1152 gcry_sexp_release(sig_sexpr);
1153 return GNUNET_SYSERR;
1155 rc = gcry_pk_verify(sig_sexpr, data, pub_sexpr);
1156 gcry_sexp_release(pub_sexpr);
1157 gcry_sexp_release(data);
1158 gcry_sexp_release(sig_sexpr);
1161 LOG(GNUNET_ERROR_TYPE_INFO,
1162 _("EdDSA signature verification of type %u failed at %s:%d: %s\n"),
1163 (unsigned int)purpose,
1167 BENCHMARK_END(eddsa_verify);
1168 return GNUNET_SYSERR;
1170 BENCHMARK_END(eddsa_verify);
1176 * Derive key material from a public and a private ECDHE key.
1178 * @param priv private key to use for the ECDH (x)
1179 * @param pub public key to use for the ECDH (yG)
1180 * @param key_material where to write the key material (xyG)
1181 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1184 GNUNET_CRYPTO_ecc_ecdh(const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1185 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1186 struct GNUNET_HashCode *key_material)
1188 gcry_mpi_point_t result;
1192 gcry_sexp_t pub_sexpr;
1193 gcry_mpi_t result_x;
1194 unsigned char xbuf[256 / 8];
1197 BENCHMARK_START(ecc_ecdh);
1199 /* first, extract the q = dP value from the public key */
1200 if (0 != gcry_sexp_build(&pub_sexpr,
1202 "(public-key(ecc(curve " CURVE ")(q %b)))",
1203 (int)sizeof(pub->q_y),
1205 return GNUNET_SYSERR;
1206 GNUNET_assert(0 == gcry_mpi_ec_new(&ctx, pub_sexpr, NULL));
1207 gcry_sexp_release(pub_sexpr);
1208 q = gcry_mpi_ec_get_point("q", ctx, 0);
1210 /* second, extract the d value from our private key */
1211 GNUNET_CRYPTO_mpi_scan_unsigned(&d, priv->d, sizeof(priv->d));
1213 /* then call the 'multiply' function, to compute the product */
1214 result = gcry_mpi_point_new(0);
1215 gcry_mpi_ec_mul(result, d, q, ctx);
1216 gcry_mpi_point_release(q);
1217 gcry_mpi_release(d);
1219 /* finally, convert point to string for hashing */
1220 result_x = gcry_mpi_new(256);
1221 if (gcry_mpi_ec_get_affine(result_x, NULL, result, ctx))
1223 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1224 gcry_mpi_point_release(result);
1225 gcry_ctx_release(ctx);
1226 return GNUNET_SYSERR;
1228 gcry_mpi_point_release(result);
1229 gcry_ctx_release(ctx);
1231 rsize = sizeof(xbuf);
1232 GNUNET_assert(!gcry_mpi_get_flag(result_x, GCRYMPI_FLAG_OPAQUE));
1233 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1234 as that does not include the sign bit; x should be a 255-bit
1235 value, so with the sign it should fit snugly into the 256-bit
1238 0 == gcry_mpi_print(GCRYMPI_FMT_STD, xbuf, rsize, &rsize, result_x));
1239 GNUNET_CRYPTO_hash(xbuf, rsize, key_material);
1240 gcry_mpi_release(result_x);
1241 BENCHMARK_END(ecc_ecdh);
1247 * Derive the 'h' value for key derivation, where
1250 * @param pub public key for deriviation
1251 * @param label label for deriviation
1252 * @param context additional context to use for HKDF of 'h';
1253 * typically the name of the subsystem/application
1257 derive_h(const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1259 const char *context)
1262 struct GNUNET_HashCode hc;
1263 static const char *const salt = "key-derivation";
1265 GNUNET_CRYPTO_kdf(&hc,
1277 GNUNET_CRYPTO_mpi_scan_unsigned(&h, (unsigned char *)&hc, sizeof(hc));
1283 * Derive a private key from a given private key and a label.
1284 * Essentially calculates a private key 'd = H(l,P) * x mod n'
1285 * where n is the size of the ECC group and P is the public
1286 * key associated with the private key 'd'.
1288 * @param priv original private key
1289 * @param label label to use for key deriviation
1290 * @param context additional context to use for HKDF of 'h';
1291 * typically the name of the subsystem/application
1292 * @return derived private key
1294 struct GNUNET_CRYPTO_EcdsaPrivateKey *
1295 GNUNET_CRYPTO_ecdsa_private_key_derive(
1296 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1298 const char *context)
1300 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
1301 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
1308 GNUNET_assert(0 == gcry_mpi_ec_new(&ctx, NULL, CURVE));
1310 n = gcry_mpi_ec_get_mpi("n", ctx, 1);
1311 GNUNET_CRYPTO_ecdsa_key_get_public(priv, &pub);
1313 h = derive_h(&pub, label, context);
1314 GNUNET_CRYPTO_mpi_scan_unsigned(&x, priv->d, sizeof(priv->d));
1315 d = gcry_mpi_new(256);
1316 gcry_mpi_mulm(d, h, x, n);
1317 gcry_mpi_release(h);
1318 gcry_mpi_release(x);
1319 gcry_mpi_release(n);
1320 gcry_ctx_release(ctx);
1321 ret = GNUNET_new(struct GNUNET_CRYPTO_EcdsaPrivateKey);
1322 GNUNET_CRYPTO_mpi_print_unsigned(ret->d, sizeof(ret->d), d);
1323 gcry_mpi_release(d);
1329 * Derive a public key from a given public key and a label.
1330 * Essentially calculates a public key 'V = H(l,P) * P'.
1332 * @param pub original public key
1333 * @param label label to use for key derivation
1334 * @param context additional context to use for HKDF of 'h';
1335 * typically the name of the subsystem/application
1336 * @param result where to write the derived public key
1339 GNUNET_CRYPTO_ecdsa_public_key_derive(
1340 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1342 const char *context,
1343 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
1353 GNUNET_assert(0 == gcry_mpi_ec_new(&ctx, NULL, CURVE));
1355 /* obtain point 'q' from original public key. The provided 'q' is
1356 compressed thus we first store it in the context and then get it
1357 back as a (decompresssed) point. */
1358 q_y = gcry_mpi_set_opaque_copy(NULL, pub->q_y, 8 * sizeof(pub->q_y));
1359 GNUNET_assert(NULL != q_y);
1360 GNUNET_assert(0 == gcry_mpi_ec_set_mpi("q", q_y, ctx));
1361 gcry_mpi_release(q_y);
1362 q = gcry_mpi_ec_get_point("q", ctx, 0);
1365 /* calculate h_mod_n = h % n */
1366 h = derive_h(pub, label, context);
1367 n = gcry_mpi_ec_get_mpi("n", ctx, 1);
1368 h_mod_n = gcry_mpi_new(256);
1369 gcry_mpi_mod(h_mod_n, h, n);
1370 /* calculate v = h_mod_n * q */
1371 v = gcry_mpi_point_new(0);
1372 gcry_mpi_ec_mul(v, h_mod_n, q, ctx);
1373 gcry_mpi_release(h_mod_n);
1374 gcry_mpi_release(h);
1375 gcry_mpi_release(n);
1376 gcry_mpi_point_release(q);
1378 /* convert point 'v' to public key that we return */
1379 GNUNET_assert(0 == gcry_mpi_ec_set_point("q", v, ctx));
1380 gcry_mpi_point_release(v);
1381 q_y = gcry_mpi_ec_get_mpi("q@eddsa", ctx, 0);
1383 GNUNET_CRYPTO_mpi_print_unsigned(result->q_y, sizeof(result->q_y), q_y);
1384 gcry_mpi_release(q_y);
1385 gcry_ctx_release(ctx);
1390 * Reverse the sequence of the bytes in @a buffer
1392 * @param[in|out] buffer buffer to invert
1393 * @param length number of bytes in @a buffer
1396 reverse_buffer(unsigned char *buffer, size_t length)
1401 for (i = 0; i < length / 2; i++)
1404 buffer[i] = buffer[length - 1 - i];
1405 buffer[length - 1 - i] = tmp;
1411 * Convert the secret @a d of an EdDSA key to the
1412 * value that is actually used in the EdDSA computation.
1414 * @param d secret input
1415 * @return value used for the calculation in EdDSA
1418 eddsa_d_to_a(gcry_mpi_t d)
1420 unsigned char rawmpi[32]; /* 256-bit value */
1422 unsigned char digest[64]; /* 512-bit hash value */
1423 gcry_buffer_t hvec[2];
1427 b = 256 / 8; /* number of bytes in `d` */
1429 /* Note that we clear DIGEST so we can use it as input to left pad
1430 the key with zeroes for hashing. */
1431 memset(digest, 0, sizeof digest);
1432 memset(hvec, 0, sizeof hvec);
1433 rawmpilen = sizeof(rawmpi);
1435 0 == gcry_mpi_print(GCRYMPI_FMT_USG, rawmpi, rawmpilen, &rawmpilen, d));
1436 hvec[0].data = digest;
1438 hvec[0].len = b > rawmpilen ? (b - rawmpilen) : 0;
1439 hvec[1].data = rawmpi;
1441 hvec[1].len = rawmpilen;
1443 0 == gcry_md_hash_buffers(GCRY_MD_SHA512, 0 /* flags */, digest, hvec, 2));
1444 /* Compute the A value. */
1445 reverse_buffer(digest, 32); /* Only the first half of the hash. */
1446 digest[0] = (digest[0] & 0x7f) | 0x40;
1449 GNUNET_CRYPTO_mpi_scan_unsigned(&a, digest, 32);
1455 * Take point from ECDH and convert it to key material.
1457 * @param result point from ECDH
1458 * @param ctx ECC context
1459 * @param key_material[out] set to derived key material
1460 * @return #GNUNET_OK on success
1463 point_to_hash(gcry_mpi_point_t result,
1465 struct GNUNET_HashCode *key_material)
1467 gcry_mpi_t result_x;
1468 unsigned char xbuf[256 / 8];
1471 /* finally, convert point to string for hashing */
1472 result_x = gcry_mpi_new(256);
1473 if (gcry_mpi_ec_get_affine(result_x, NULL, result, ctx))
1475 LOG_GCRY(GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1476 return GNUNET_SYSERR;
1479 rsize = sizeof(xbuf);
1480 GNUNET_assert(!gcry_mpi_get_flag(result_x, GCRYMPI_FLAG_OPAQUE));
1481 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1482 as that does not include the sign bit; x should be a 255-bit
1483 value, so with the sign it should fit snugly into the 256-bit
1486 0 == gcry_mpi_print(GCRYMPI_FMT_STD, xbuf, rsize, &rsize, result_x));
1487 GNUNET_CRYPTO_hash(xbuf, rsize, key_material);
1488 gcry_mpi_release(result_x);
1495 * Derive key material from a ECDH public key and a private EdDSA key.
1496 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1498 * @param priv private key from EdDSA to use for the ECDH (x)
1499 * @param pub public key to use for the ECDH (yG)
1500 * @param key_material where to write the key material H(h(x)yG)
1501 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1504 GNUNET_CRYPTO_eddsa_ecdh(const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1505 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1506 struct GNUNET_HashCode *key_material)
1508 gcry_mpi_point_t result;
1513 gcry_sexp_t pub_sexpr;
1516 BENCHMARK_START(eddsa_ecdh);
1518 /* first, extract the q = dP value from the public key */
1519 if (0 != gcry_sexp_build(&pub_sexpr,
1521 "(public-key(ecc(curve " CURVE ")(q %b)))",
1522 (int)sizeof(pub->q_y),
1524 return GNUNET_SYSERR;
1525 GNUNET_assert(0 == gcry_mpi_ec_new(&ctx, pub_sexpr, NULL));
1526 gcry_sexp_release(pub_sexpr);
1527 q = gcry_mpi_ec_get_point("q", ctx, 0);
1529 /* second, extract the d value from our private key */
1530 GNUNET_CRYPTO_mpi_scan_unsigned(&d, priv->d, sizeof(priv->d));
1532 /* NOW, because this is EdDSA, HASH 'd' first! */
1533 a = eddsa_d_to_a(d);
1534 gcry_mpi_release(d);
1536 /* then call the 'multiply' function, to compute the product */
1537 result = gcry_mpi_point_new(0);
1538 gcry_mpi_ec_mul(result, a, q, ctx);
1539 gcry_mpi_point_release(q);
1540 gcry_mpi_release(a);
1542 ret = point_to_hash(result, ctx, key_material);
1543 gcry_mpi_point_release(result);
1544 gcry_ctx_release(ctx);
1545 BENCHMARK_END(eddsa_ecdh);
1552 * Derive key material from a ECDH public key and a private ECDSA key.
1553 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1555 * @param priv private key from ECDSA to use for the ECDH (x)
1556 * @param pub public key to use for the ECDH (yG)
1557 * @param key_material where to write the key material H(h(x)yG)
1558 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1561 GNUNET_CRYPTO_ecdsa_ecdh(const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1562 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1563 struct GNUNET_HashCode *key_material)
1565 gcry_mpi_point_t result;
1569 gcry_sexp_t pub_sexpr;
1572 BENCHMARK_START(ecdsa_ecdh);
1574 /* first, extract the q = dP value from the public key */
1575 if (0 != gcry_sexp_build(&pub_sexpr,
1577 "(public-key(ecc(curve " CURVE ")(q %b)))",
1578 (int)sizeof(pub->q_y),
1580 return GNUNET_SYSERR;
1581 GNUNET_assert(0 == gcry_mpi_ec_new(&ctx, pub_sexpr, NULL));
1582 gcry_sexp_release(pub_sexpr);
1583 q = gcry_mpi_ec_get_point("q", ctx, 0);
1585 /* second, extract the d value from our private key */
1586 GNUNET_CRYPTO_mpi_scan_unsigned(&d, priv->d, sizeof(priv->d));
1588 /* then call the 'multiply' function, to compute the product */
1589 result = gcry_mpi_point_new(0);
1590 gcry_mpi_ec_mul(result, d, q, ctx);
1591 gcry_mpi_point_release(q);
1592 gcry_mpi_release(d);
1594 /* finally, convert point to string for hashing */
1595 ret = point_to_hash(result, ctx, key_material);
1596 gcry_mpi_point_release(result);
1597 gcry_ctx_release(ctx);
1598 BENCHMARK_END(ecdsa_ecdh);
1605 * Derive key material from a EdDSA public key and a private ECDH key.
1606 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1608 * @param priv private key to use for the ECDH (y)
1609 * @param pub public key from EdDSA to use for the ECDH (X=h(x)G)
1610 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1611 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1614 GNUNET_CRYPTO_ecdh_eddsa(const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1615 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1616 struct GNUNET_HashCode *key_material)
1618 gcry_mpi_point_t result;
1622 gcry_sexp_t pub_sexpr;
1625 BENCHMARK_START(ecdh_eddsa);
1627 /* first, extract the q = dP value from the public key */
1628 if (0 != gcry_sexp_build(&pub_sexpr,
1630 "(public-key(ecc(curve " CURVE ")(q %b)))",
1631 (int)sizeof(pub->q_y),
1633 return GNUNET_SYSERR;
1634 GNUNET_assert(0 == gcry_mpi_ec_new(&ctx, pub_sexpr, NULL));
1635 gcry_sexp_release(pub_sexpr);
1636 q = gcry_mpi_ec_get_point("q", ctx, 0);
1638 /* second, extract the d value from our private key */
1639 GNUNET_CRYPTO_mpi_scan_unsigned(&d, priv->d, sizeof(priv->d));
1641 /* then call the 'multiply' function, to compute the product */
1642 result = gcry_mpi_point_new(0);
1643 gcry_mpi_ec_mul(result, d, q, ctx);
1644 gcry_mpi_point_release(q);
1645 gcry_mpi_release(d);
1647 /* finally, convert point to string for hashing */
1648 ret = point_to_hash(result, ctx, key_material);
1649 gcry_mpi_point_release(result);
1650 gcry_ctx_release(ctx);
1651 BENCHMARK_END(ecdh_eddsa);
1657 * Derive key material from a ECDSA public key and a private ECDH key.
1658 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1660 * @param priv private key to use for the ECDH (y)
1661 * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
1662 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1663 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1666 GNUNET_CRYPTO_ecdh_ecdsa(const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1667 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1668 struct GNUNET_HashCode *key_material)
1670 return GNUNET_CRYPTO_ecdh_eddsa(priv,
1671 (const struct GNUNET_CRYPTO_EddsaPublicKey *)
1676 /* end of crypto_ecc.c */