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) GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
46 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
49 * Log an error message at log-level 'level' that indicates
50 * a failure of the command 'cmd' with the message given
51 * by gcry_strerror(rc).
53 #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)
57 * Extract values from an S-expression.
59 * @param array where to store the result(s)
60 * @param sexp S-expression to parse
61 * @param topname top-level name in the S-expression that is of interest
62 * @param elems names of the elements to extract
63 * @return 0 on success
66 key_from_sexp (gcry_mpi_t * array,
77 list = gcry_sexp_find_token (sexp, topname, 0);
80 l2 = gcry_sexp_cadr (list);
81 gcry_sexp_release (list);
87 for (s = elems; *s; s++, idx++)
89 l2 = gcry_sexp_find_token (list, s, 1);
92 for (i = 0; i < idx; i++)
97 gcry_sexp_release (list);
98 return 3; /* required parameter not found */
100 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
101 gcry_sexp_release (l2);
104 for (i = 0; i < idx; i++)
106 gcry_free (array[i]);
109 gcry_sexp_release (list);
110 return 4; /* required parameter is invalid */
113 gcry_sexp_release (list);
119 * Convert the given private key from the network format to the
120 * S-expression that can be used by libgcrypt.
122 * @param priv private key to decode
123 * @return NULL on error
126 decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
131 rc = gcry_sexp_build (&result, NULL,
132 "(private-key(ecc(curve \"" CURVE "\")"
134 (int) sizeof (priv->d), priv->d);
137 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
141 if (0 != (rc = gcry_pk_testkey (result)))
143 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
152 * Convert the given private key from the network format to the
153 * S-expression that can be used by libgcrypt.
155 * @param priv private key to decode
156 * @return NULL on error
159 decode_private_eddsa_key (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
164 rc = gcry_sexp_build (&result, NULL,
165 "(private-key(ecc(curve \"" CURVE "\")"
166 "(flags eddsa)(d %b)))",
167 (int)sizeof (priv->d), priv->d);
170 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
174 if (0 != (rc = gcry_pk_testkey (result)))
176 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
185 * Convert the given private key from the network format to the
186 * S-expression that can be used by libgcrypt.
188 * @param priv private key to decode
189 * @return NULL on error
192 decode_private_ecdhe_key (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv)
197 rc = gcry_sexp_build (&result, NULL,
198 "(private-key(ecc(curve \"" CURVE "\")"
200 (int)sizeof (priv->d), priv->d);
203 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
207 if (0 != (rc = gcry_pk_testkey (result)))
209 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
218 * Extract the public key for the given private key.
220 * @param priv the private key
221 * @param pub where to write the public key
224 GNUNET_CRYPTO_ecdsa_key_get_public (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
225 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
231 BENCHMARK_START (ecdsa_key_get_public);
233 sexp = decode_private_ecdsa_key (priv);
234 GNUNET_assert (NULL != sexp);
235 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
236 gcry_sexp_release (sexp);
237 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
238 GNUNET_assert (NULL != q);
239 GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
240 gcry_mpi_release (q);
241 gcry_ctx_release (ctx);
243 BENCHMARK_END (ecdsa_key_get_public);
248 * Extract the public key for the given private key.
250 * @param priv the private key
251 * @param pub where to write the public key
254 GNUNET_CRYPTO_eddsa_key_get_public (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
255 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
261 BENCHMARK_START (eddsa_key_get_public);
263 sexp = decode_private_eddsa_key (priv);
264 GNUNET_assert (NULL != sexp);
265 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
266 gcry_sexp_release (sexp);
267 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
269 GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
270 gcry_mpi_release (q);
271 gcry_ctx_release (ctx);
273 BENCHMARK_END (eddsa_key_get_public);
278 * Extract the public key for the given private key.
280 * @param priv the private key
281 * @param pub where to write the public key
284 GNUNET_CRYPTO_ecdhe_key_get_public (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
285 struct GNUNET_CRYPTO_EcdhePublicKey *pub)
291 BENCHMARK_START (ecdhe_key_get_public);
293 sexp = decode_private_ecdhe_key (priv);
294 GNUNET_assert (NULL != sexp);
295 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
296 gcry_sexp_release (sexp);
297 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
299 GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
300 gcry_mpi_release (q);
301 gcry_ctx_release (ctx);
303 BENCHMARK_END (ecdhe_key_get_public);
308 * Convert a public key to a string.
310 * @param pub key to convert
311 * @return string representing @a pub
314 GNUNET_CRYPTO_ecdsa_public_key_to_string (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
317 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
321 keylen += 5 - keylen % 5;
323 pubkeybuf = GNUNET_malloc (keylen + 1);
324 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
325 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
330 GNUNET_free (pubkeybuf);
339 * Convert a public key to a string.
341 * @param pub key to convert
342 * @return string representing @a pub
345 GNUNET_CRYPTO_eddsa_public_key_to_string (const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
348 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
352 keylen += 5 - keylen % 5;
354 pubkeybuf = GNUNET_malloc (keylen + 1);
355 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
356 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
361 GNUNET_free (pubkeybuf);
370 * Convert a private key to a string.
372 * @param priv key to convert
373 * @return string representing @a pub
376 GNUNET_CRYPTO_eddsa_private_key_to_string (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
379 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
383 keylen += 5 - keylen % 5;
385 privkeybuf = GNUNET_malloc (keylen + 1);
386 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
387 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
392 GNUNET_free (privkeybuf);
401 * Convert a string representing a public key to a public key.
403 * @param enc encoded public key
404 * @param enclen number of bytes in @a enc (without 0-terminator)
405 * @param pub where to store the public key
406 * @return #GNUNET_OK on success
409 GNUNET_CRYPTO_ecdsa_public_key_from_string (const char *enc,
411 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
413 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
416 keylen += 5 - keylen % 5;
418 if (enclen != keylen)
419 return GNUNET_SYSERR;
422 GNUNET_STRINGS_string_to_data (enc, enclen,
424 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
425 return GNUNET_SYSERR;
431 * Convert a string representing a public key to a public key.
433 * @param enc encoded public key
434 * @param enclen number of bytes in @a enc (without 0-terminator)
435 * @param pub where to store the public key
436 * @return #GNUNET_OK on success
439 GNUNET_CRYPTO_eddsa_public_key_from_string (const char *enc,
441 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
443 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
446 keylen += 5 - keylen % 5;
448 if (enclen != keylen)
449 return GNUNET_SYSERR;
452 GNUNET_STRINGS_string_to_data (enc, enclen,
454 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
455 return GNUNET_SYSERR;
461 * Convert a string representing a private key to a private key.
463 * @param enc encoded public key
464 * @param enclen number of bytes in @a enc (without 0-terminator)
465 * @param priv where to store the private key
466 * @return #GNUNET_OK on success
469 GNUNET_CRYPTO_eddsa_private_key_from_string (const char *enc,
471 struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
473 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
476 keylen += 5 - keylen % 5;
478 if (enclen != keylen)
479 return GNUNET_SYSERR;
482 GNUNET_STRINGS_string_to_data (enc, enclen,
484 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
485 return GNUNET_SYSERR;
488 check_eddsa_key (priv))
500 * Clear memory that was used to store a private key.
502 * @param pk location of the key
505 GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
507 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
513 * Clear memory that was used to store a private key.
515 * @param pk location of the key
518 GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
520 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
526 * Clear memory that was used to store a private key.
528 * @param pk location of the key
531 GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
533 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
538 * Create a new private key. Caller must free return value.
540 * @return fresh private key
542 struct GNUNET_CRYPTO_EcdhePrivateKey *
543 GNUNET_CRYPTO_ecdhe_key_create ()
545 struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
547 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
549 GNUNET_CRYPTO_ecdhe_key_create2 (priv))
560 * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
562 * @param[out] pk set to fresh private key;
563 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
566 GNUNET_CRYPTO_ecdhe_key_create2 (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
568 gcry_sexp_t priv_sexp;
569 gcry_sexp_t s_keyparam;
573 BENCHMARK_START (ecdhe_key_create);
575 /* NOTE: For libgcrypt >= 1.7, we do not need the 'eddsa' flag here,
576 but should also be harmless. For libgcrypt < 1.7, using 'eddsa'
577 disables an expensive key testing routine. We do not want to run
578 the expensive check for ECDHE, as we generate TONS of keys to
579 use for a very short time. */
580 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
581 "(genkey(ecc(curve \"" CURVE "\")"
582 "(flags eddsa no-keytest)))")))
584 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
585 return GNUNET_SYSERR;
587 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
589 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
590 gcry_sexp_release (s_keyparam);
591 return GNUNET_SYSERR;
593 gcry_sexp_release (s_keyparam);
595 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
597 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
598 gcry_sexp_release (priv_sexp);
599 return GNUNET_SYSERR;
602 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
604 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
605 gcry_sexp_release (priv_sexp);
606 return GNUNET_SYSERR;
608 gcry_sexp_release (priv_sexp);
609 GNUNET_CRYPTO_mpi_print_unsigned (pk->d, sizeof (pk->d), d);
610 gcry_mpi_release (d);
612 BENCHMARK_END (ecdhe_key_create);
619 * Create a new private key. Caller must free return value.
621 * @return fresh private key
623 struct GNUNET_CRYPTO_EcdsaPrivateKey *
624 GNUNET_CRYPTO_ecdsa_key_create ()
626 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
627 gcry_sexp_t priv_sexp;
628 gcry_sexp_t s_keyparam;
632 BENCHMARK_START (ecdsa_key_create);
634 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
635 "(genkey(ecc(curve \"" CURVE "\")"
638 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
641 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
643 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
644 gcry_sexp_release (s_keyparam);
647 gcry_sexp_release (s_keyparam);
649 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
651 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
652 gcry_sexp_release (priv_sexp);
656 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
658 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
659 gcry_sexp_release (priv_sexp);
662 gcry_sexp_release (priv_sexp);
663 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
664 GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
665 gcry_mpi_release (d);
667 BENCHMARK_END (ecdsa_key_create);
673 * Create a new private key. Caller must free return value.
675 * @return fresh private key
677 struct GNUNET_CRYPTO_EddsaPrivateKey *
678 GNUNET_CRYPTO_eddsa_key_create ()
680 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
681 gcry_sexp_t priv_sexp;
682 gcry_sexp_t s_keyparam;
686 BENCHMARK_START (eddsa_key_create);
691 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
692 "(genkey(ecc(curve \"" CURVE "\")"
695 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
698 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
700 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
701 gcry_sexp_release (s_keyparam);
704 gcry_sexp_release (s_keyparam);
706 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
708 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
709 gcry_sexp_release (priv_sexp);
713 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
715 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
716 gcry_sexp_release (priv_sexp);
719 gcry_sexp_release (priv_sexp);
720 priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
721 GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
722 gcry_mpi_release (d);
726 check_eddsa_key (priv))
734 BENCHMARK_END (eddsa_key_create);
741 * Get the shared private key we use for anonymous users.
743 * @return "anonymous" private key
745 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
746 GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
749 * 'anonymous' pseudonym (global static, d=1, public key = G
752 static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
757 GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
758 sizeof (anonymous.d),
766 * Convert the data specified in the given purpose argument to an
767 * S-expression suitable for signature operations.
769 * @param purpose data to convert
770 * @return converted s-expression
773 data_to_eddsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
780 struct GNUNET_HashCode hc;
782 GNUNET_CRYPTO_hash (purpose,
783 ntohl (purpose->size),
785 if (0 != (rc = gcry_sexp_build (&data, NULL,
786 "(data(flags eddsa)(hash-algo %s)(value %b))",
791 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
797 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
798 if (0 != (rc = gcry_sexp_build (&data, NULL,
799 "(data(flags eddsa)(hash-algo %s)(value %b))",
801 ntohl (purpose->size),
804 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
815 * Convert the data specified in the given purpose argument to an
816 * S-expression suitable for signature operations.
818 * @param purpose data to convert
819 * @return converted s-expression
822 data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
829 struct GNUNET_HashCode hc;
831 GNUNET_CRYPTO_hash (purpose,
832 ntohl (purpose->size),
834 if (0 != (rc = gcry_sexp_build (&data, NULL,
835 "(data(flags rfc6979)(hash %s %b))",
837 (int)sizeof (hc), &hc)))
839 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
845 if (0 != (rc = gcry_sexp_build (&data, NULL,
846 "(data(flags rfc6979)(hash %s %b))",
848 ntohl (purpose->size),
851 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
862 * Sign a given block.
864 * @param priv private key to use for the signing
865 * @param purpose what to sign (size, purpose)
866 * @param sig where to write the signature
867 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
870 GNUNET_CRYPTO_ecdsa_sign (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
871 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
872 struct GNUNET_CRYPTO_EcdsaSignature *sig)
874 gcry_sexp_t priv_sexp;
875 gcry_sexp_t sig_sexp;
880 BENCHMARK_START (ecdsa_sign);
882 priv_sexp = decode_private_ecdsa_key (priv);
883 data = data_to_ecdsa_value (purpose);
884 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
886 LOG (GNUNET_ERROR_TYPE_WARNING,
887 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
888 __LINE__, gcry_strerror (rc));
889 gcry_sexp_release (data);
890 gcry_sexp_release (priv_sexp);
891 return GNUNET_SYSERR;
893 gcry_sexp_release (priv_sexp);
894 gcry_sexp_release (data);
896 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
898 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
901 gcry_sexp_release (sig_sexp);
902 return GNUNET_SYSERR;
904 gcry_sexp_release (sig_sexp);
905 GNUNET_CRYPTO_mpi_print_unsigned (sig->r,
908 GNUNET_CRYPTO_mpi_print_unsigned (sig->s,
911 gcry_mpi_release (rs[0]);
912 gcry_mpi_release (rs[1]);
914 BENCHMARK_END (ecdsa_sign);
921 * Sign a given block.
923 * @param priv private key to use for the signing
924 * @param purpose what to sign (size, purpose)
925 * @param sig where to write the signature
926 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
929 GNUNET_CRYPTO_eddsa_sign (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
930 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
931 struct GNUNET_CRYPTO_EddsaSignature *sig)
933 gcry_sexp_t priv_sexp;
934 gcry_sexp_t sig_sexp;
939 BENCHMARK_START (eddsa_sign);
941 priv_sexp = decode_private_eddsa_key (priv);
942 data = data_to_eddsa_value (purpose);
943 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
945 LOG (GNUNET_ERROR_TYPE_WARNING,
946 _("EdDSA signing failed at %s:%d: %s\n"), __FILE__,
947 __LINE__, gcry_strerror (rc));
948 gcry_sexp_release (data);
949 gcry_sexp_release (priv_sexp);
950 return GNUNET_SYSERR;
952 gcry_sexp_release (priv_sexp);
953 gcry_sexp_release (data);
955 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
957 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
960 gcry_sexp_release (sig_sexp);
961 return GNUNET_SYSERR;
963 gcry_sexp_release (sig_sexp);
964 GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
965 GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
966 gcry_mpi_release (rs[0]);
967 gcry_mpi_release (rs[1]);
969 BENCHMARK_END (eddsa_sign);
978 * @param purpose what is the purpose that the signature should have?
979 * @param validate block to validate (size, purpose, data)
980 * @param sig signature that is being validated
981 * @param pub public key of the signer
982 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
985 GNUNET_CRYPTO_ecdsa_verify (uint32_t purpose,
986 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
987 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
988 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
991 gcry_sexp_t sig_sexpr;
992 gcry_sexp_t pub_sexpr;
995 BENCHMARK_START (ecdsa_verify);
997 if (purpose != ntohl (validate->purpose))
998 return GNUNET_SYSERR; /* purpose mismatch */
1000 /* build s-expression for signature */
1001 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
1002 "(sig-val(ecdsa(r %b)(s %b)))",
1003 (int) sizeof (sig->r), sig->r,
1004 (int) sizeof (sig->s), sig->s)))
1006 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1007 return GNUNET_SYSERR;
1009 data = data_to_ecdsa_value (validate);
1010 if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
1011 "(public-key(ecc(curve " CURVE ")(q %b)))",
1012 (int) sizeof (pub->q_y), pub->q_y)))
1014 gcry_sexp_release (data);
1015 gcry_sexp_release (sig_sexpr);
1016 return GNUNET_SYSERR;
1018 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
1019 gcry_sexp_release (pub_sexpr);
1020 gcry_sexp_release (data);
1021 gcry_sexp_release (sig_sexpr);
1024 LOG (GNUNET_ERROR_TYPE_INFO,
1025 _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1026 __LINE__, gcry_strerror (rc));
1027 BENCHMARK_END (ecdsa_verify);
1028 return GNUNET_SYSERR;
1030 BENCHMARK_END (ecdsa_verify);
1039 * @param purpose what is the purpose that the signature should have?
1040 * @param validate block to validate (size, purpose, data)
1041 * @param sig signature that is being validated
1042 * @param pub public key of the signer
1043 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
1046 GNUNET_CRYPTO_eddsa_verify (uint32_t purpose,
1047 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
1048 const struct GNUNET_CRYPTO_EddsaSignature *sig,
1049 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
1052 gcry_sexp_t sig_sexpr;
1053 gcry_sexp_t pub_sexpr;
1056 BENCHMARK_START (eddsa_verify);
1058 if (purpose != ntohl (validate->purpose))
1059 return GNUNET_SYSERR; /* purpose mismatch */
1061 /* build s-expression for signature */
1062 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
1063 "(sig-val(eddsa(r %b)(s %b)))",
1064 (int)sizeof (sig->r), sig->r,
1065 (int)sizeof (sig->s), sig->s)))
1067 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1068 return GNUNET_SYSERR;
1070 data = data_to_eddsa_value (validate);
1071 if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
1072 "(public-key(ecc(curve " CURVE ")(flags eddsa)(q %b)))",
1073 (int)sizeof (pub->q_y), pub->q_y)))
1075 gcry_sexp_release (data);
1076 gcry_sexp_release (sig_sexpr);
1077 return GNUNET_SYSERR;
1079 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
1080 gcry_sexp_release (pub_sexpr);
1081 gcry_sexp_release (data);
1082 gcry_sexp_release (sig_sexpr);
1085 LOG (GNUNET_ERROR_TYPE_INFO,
1086 _("EdDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1087 __LINE__, gcry_strerror (rc));
1088 BENCHMARK_END (eddsa_verify);
1089 return GNUNET_SYSERR;
1091 BENCHMARK_END (eddsa_verify);
1097 * Derive key material from a public and a private ECDHE key.
1099 * @param priv private key to use for the ECDH (x)
1100 * @param pub public key to use for the ECDH (yG)
1101 * @param key_material where to write the key material (xyG)
1102 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1105 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1106 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1107 struct GNUNET_HashCode *key_material)
1109 gcry_mpi_point_t result;
1113 gcry_sexp_t pub_sexpr;
1114 gcry_mpi_t result_x;
1115 unsigned char xbuf[256 / 8];
1118 BENCHMARK_START (ecc_ecdh);
1120 /* first, extract the q = dP value from the public key */
1121 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1122 "(public-key(ecc(curve " CURVE ")(q %b)))",
1123 (int)sizeof (pub->q_y), pub->q_y))
1124 return GNUNET_SYSERR;
1125 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1126 gcry_sexp_release (pub_sexpr);
1127 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1129 /* second, extract the d value from our private key */
1130 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1132 /* then call the 'multiply' function, to compute the product */
1133 result = gcry_mpi_point_new (0);
1134 gcry_mpi_ec_mul (result, d, q, ctx);
1135 gcry_mpi_point_release (q);
1136 gcry_mpi_release (d);
1138 /* finally, convert point to string for hashing */
1139 result_x = gcry_mpi_new (256);
1140 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1142 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1143 gcry_mpi_point_release (result);
1144 gcry_ctx_release (ctx);
1145 return GNUNET_SYSERR;
1147 gcry_mpi_point_release (result);
1148 gcry_ctx_release (ctx);
1150 rsize = sizeof (xbuf);
1151 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1152 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1153 as that does not include the sign bit; x should be a 255-bit
1154 value, so with the sign it should fit snugly into the 256-bit
1157 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1159 GNUNET_CRYPTO_hash (xbuf,
1162 gcry_mpi_release (result_x);
1163 BENCHMARK_END (ecc_ecdh);
1169 * Derive the 'h' value for key derivation, where
1172 * @param pub public key for deriviation
1173 * @param label label for deriviation
1174 * @param context additional context to use for HKDF of 'h';
1175 * typically the name of the subsystem/application
1179 derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1181 const char *context)
1184 struct GNUNET_HashCode hc;
1185 static const char *const salt = "key-derivation";
1187 GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
1188 salt, strlen (salt),
1190 label, strlen (label),
1191 context, strlen (context),
1193 GNUNET_CRYPTO_mpi_scan_unsigned (&h,
1194 (unsigned char *) &hc,
1201 * Derive a private key from a given private key and a label.
1202 * Essentially calculates a private key 'd = H(l,P) * x mod n'
1203 * where n is the size of the ECC group and P is the public
1204 * key associated with the private key 'd'.
1206 * @param priv original private key
1207 * @param label label to use for key deriviation
1208 * @param context additional context to use for HKDF of 'h';
1209 * typically the name of the subsystem/application
1210 * @return derived private key
1212 struct GNUNET_CRYPTO_EcdsaPrivateKey *
1213 GNUNET_CRYPTO_ecdsa_private_key_derive (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1215 const char *context)
1217 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
1218 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
1225 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1227 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1228 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
1230 h = derive_h (&pub, label, context);
1231 GNUNET_CRYPTO_mpi_scan_unsigned (&x,
1234 d = gcry_mpi_new (256);
1235 gcry_mpi_mulm (d, h, x, n);
1236 gcry_mpi_release (h);
1237 gcry_mpi_release (x);
1238 gcry_mpi_release (n);
1239 gcry_ctx_release (ctx);
1240 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
1241 GNUNET_CRYPTO_mpi_print_unsigned (ret->d, sizeof (ret->d), d);
1242 gcry_mpi_release (d);
1248 * Derive a public key from a given public key and a label.
1249 * Essentially calculates a public key 'V = H(l,P) * P'.
1251 * @param pub original public key
1252 * @param label label to use for key derivation
1253 * @param context additional context to use for HKDF of 'h';
1254 * typically the name of the subsystem/application
1255 * @param result where to write the derived public key
1258 GNUNET_CRYPTO_ecdsa_public_key_derive (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1260 const char *context,
1261 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
1271 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1273 /* obtain point 'q' from original public key. The provided 'q' is
1274 compressed thus we first store it in the context and then get it
1275 back as a (decompresssed) point. */
1276 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8*sizeof (pub->q_y));
1277 GNUNET_assert (NULL != q_y);
1278 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
1279 gcry_mpi_release (q_y);
1280 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1283 /* calculate h_mod_n = h % n */
1284 h = derive_h (pub, label, context);
1285 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1286 h_mod_n = gcry_mpi_new (256);
1287 gcry_mpi_mod (h_mod_n, h, n);
1288 /* calculate v = h_mod_n * q */
1289 v = gcry_mpi_point_new (0);
1290 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1291 gcry_mpi_release (h_mod_n);
1292 gcry_mpi_release (h);
1293 gcry_mpi_release (n);
1294 gcry_mpi_point_release (q);
1296 /* convert point 'v' to public key that we return */
1297 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
1298 gcry_mpi_point_release (v);
1299 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
1300 GNUNET_assert (q_y);
1301 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y,
1302 sizeof (result->q_y),
1304 gcry_mpi_release (q_y);
1305 gcry_ctx_release (ctx);
1310 * Reverse the sequence of the bytes in @a buffer
1312 * @param[in|out] buffer buffer to invert
1313 * @param length number of bytes in @a buffer
1316 reverse_buffer (unsigned char *buffer,
1322 for (i=0; i < length/2; i++)
1325 buffer[i] = buffer[length-1-i];
1326 buffer[length-1-i] = tmp;
1332 * Convert the secret @a d of an EdDSA key to the
1333 * value that is actually used in the EdDSA computation.
1335 * @param d secret input
1336 * @return value used for the calculation in EdDSA
1339 eddsa_d_to_a (gcry_mpi_t d)
1341 unsigned char rawmpi[32]; /* 256-bit value */
1343 unsigned char digest[64]; /* 512-bit hash value */
1344 gcry_buffer_t hvec[2];
1348 b = 256 / 8; /* number of bytes in `d` */
1350 /* Note that we clear DIGEST so we can use it as input to left pad
1351 the key with zeroes for hashing. */
1352 memset (digest, 0, sizeof digest);
1353 memset (hvec, 0, sizeof hvec);
1354 rawmpilen = sizeof (rawmpi);
1356 gcry_mpi_print (GCRYMPI_FMT_USG,
1357 rawmpi, rawmpilen, &rawmpilen,
1359 hvec[0].data = digest;
1361 hvec[0].len = b > rawmpilen ? (b - rawmpilen) : 0;
1362 hvec[1].data = rawmpi;
1364 hvec[1].len = rawmpilen;
1366 gcry_md_hash_buffers (GCRY_MD_SHA512,
1370 /* Compute the A value. */
1371 reverse_buffer (digest, 32); /* Only the first half of the hash. */
1372 digest[0] = (digest[0] & 0x7f) | 0x40;
1375 GNUNET_CRYPTO_mpi_scan_unsigned (&a,
1383 * Take point from ECDH and convert it to key material.
1385 * @param result point from ECDH
1386 * @param ctx ECC context
1387 * @param key_material[out] set to derived key material
1388 * @return #GNUNET_OK on success
1391 point_to_hash (gcry_mpi_point_t result,
1393 struct GNUNET_HashCode *key_material)
1395 gcry_mpi_t result_x;
1396 unsigned char xbuf[256 / 8];
1399 /* finally, convert point to string for hashing */
1400 result_x = gcry_mpi_new (256);
1401 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1403 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1404 return GNUNET_SYSERR;
1407 rsize = sizeof (xbuf);
1408 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1409 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1410 as that does not include the sign bit; x should be a 255-bit
1411 value, so with the sign it should fit snugly into the 256-bit
1414 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1416 GNUNET_CRYPTO_hash (xbuf,
1419 gcry_mpi_release (result_x);
1426 * Derive key material from a ECDH public key and a private EdDSA key.
1427 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1429 * @param priv private key from EdDSA to use for the ECDH (x)
1430 * @param pub public key to use for the ECDH (yG)
1431 * @param key_material where to write the key material H(h(x)yG)
1432 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1435 GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1436 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1437 struct GNUNET_HashCode *key_material)
1439 gcry_mpi_point_t result;
1444 gcry_sexp_t pub_sexpr;
1447 BENCHMARK_START (eddsa_ecdh);
1449 /* first, extract the q = dP value from the public key */
1450 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1451 "(public-key(ecc(curve " CURVE ")(q %b)))",
1452 (int)sizeof (pub->q_y), pub->q_y))
1453 return GNUNET_SYSERR;
1454 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1455 gcry_sexp_release (pub_sexpr);
1456 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1458 /* second, extract the d value from our private key */
1459 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1461 /* NOW, because this is EdDSA, HASH 'd' first! */
1462 a = eddsa_d_to_a (d);
1463 gcry_mpi_release (d);
1465 /* then call the 'multiply' function, to compute the product */
1466 result = gcry_mpi_point_new (0);
1467 gcry_mpi_ec_mul (result, a, q, ctx);
1468 gcry_mpi_point_release (q);
1469 gcry_mpi_release (a);
1471 ret = point_to_hash (result,
1474 gcry_mpi_point_release (result);
1475 gcry_ctx_release (ctx);
1476 BENCHMARK_END (eddsa_ecdh);
1483 * Derive key material from a ECDH public key and a private ECDSA key.
1484 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1486 * @param priv private key from ECDSA to use for the ECDH (x)
1487 * @param pub public key to use for the ECDH (yG)
1488 * @param key_material where to write the key material H(h(x)yG)
1489 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1492 GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1493 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1494 struct GNUNET_HashCode *key_material)
1496 gcry_mpi_point_t result;
1500 gcry_sexp_t pub_sexpr;
1503 BENCHMARK_START (ecdsa_ecdh);
1505 /* first, extract the q = dP value from the public key */
1506 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1507 "(public-key(ecc(curve " CURVE ")(q %b)))",
1508 (int)sizeof (pub->q_y), pub->q_y))
1509 return GNUNET_SYSERR;
1510 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1511 gcry_sexp_release (pub_sexpr);
1512 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1514 /* second, extract the d value from our private key */
1515 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1517 /* then call the 'multiply' function, to compute the product */
1518 result = gcry_mpi_point_new (0);
1519 gcry_mpi_ec_mul (result, d, q, ctx);
1520 gcry_mpi_point_release (q);
1521 gcry_mpi_release (d);
1523 /* finally, convert point to string for hashing */
1524 ret = point_to_hash (result,
1527 gcry_mpi_point_release (result);
1528 gcry_ctx_release (ctx);
1529 BENCHMARK_END (ecdsa_ecdh);
1537 * Derive key material from a EdDSA public key and a private ECDH key.
1538 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1540 * @param priv private key to use for the ECDH (y)
1541 * @param pub public key from EdDSA to use for the ECDH (X=h(x)G)
1542 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1543 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1546 GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1547 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1548 struct GNUNET_HashCode *key_material)
1550 gcry_mpi_point_t result;
1554 gcry_sexp_t pub_sexpr;
1557 BENCHMARK_START (ecdh_eddsa);
1559 /* first, extract the q = dP value from the public key */
1560 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1561 "(public-key(ecc(curve " CURVE ")(q %b)))",
1562 (int)sizeof (pub->q_y), pub->q_y))
1563 return GNUNET_SYSERR;
1564 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1565 gcry_sexp_release (pub_sexpr);
1566 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1568 /* second, extract the d value from our private key */
1569 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1571 /* then call the 'multiply' function, to compute the product */
1572 result = gcry_mpi_point_new (0);
1573 gcry_mpi_ec_mul (result, d, q, ctx);
1574 gcry_mpi_point_release (q);
1575 gcry_mpi_release (d);
1577 /* finally, convert point to string for hashing */
1578 ret = point_to_hash (result,
1581 gcry_mpi_point_release (result);
1582 gcry_ctx_release (ctx);
1583 BENCHMARK_END (ecdh_eddsa);
1589 * Derive key material from a ECDSA public key and a private ECDH key.
1590 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1592 * @param priv private key to use for the ECDH (y)
1593 * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
1594 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1595 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1598 GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1599 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1600 struct GNUNET_HashCode *key_material)
1602 return GNUNET_CRYPTO_ecdh_eddsa (priv,
1603 (const struct GNUNET_CRYPTO_EddsaPublicKey *)pub,
1607 /* end of crypto_ecc.c */