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/>.
20 * @file util/crypto_ecc.c
21 * @brief public key cryptography (ECC) with libgcrypt
22 * @author Christian Grothoff
26 #include "gnunet_crypto_lib.h"
27 #include "gnunet_strings_lib.h"
28 #include "benchmark.h"
30 #define EXTRA_CHECKS 0
33 * Name of the curve we are using. Note that we have hard-coded
34 * structs that use 256 bits, so using a bigger curve will require
35 * changes that break stuff badly. The name of the curve given here
36 * must be agreed by all peers and be supported by libgcrypt.
38 #define CURVE "Ed25519"
40 #define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
42 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
44 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
47 * Log an error message at log-level 'level' that indicates
48 * a failure of the command 'cmd' with the message given
49 * by gcry_strerror(rc).
51 #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)
55 * Extract values from an S-expression.
57 * @param array where to store the result(s)
58 * @param sexp S-expression to parse
59 * @param topname top-level name in the S-expression that is of interest
60 * @param elems names of the elements to extract
61 * @return 0 on success
64 key_from_sexp (gcry_mpi_t * array,
75 list = gcry_sexp_find_token (sexp, topname, 0);
78 l2 = gcry_sexp_cadr (list);
79 gcry_sexp_release (list);
85 for (s = elems; *s; s++, idx++)
87 l2 = gcry_sexp_find_token (list, s, 1);
90 for (i = 0; i < idx; i++)
95 gcry_sexp_release (list);
96 return 3; /* required parameter not found */
98 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
99 gcry_sexp_release (l2);
102 for (i = 0; i < idx; i++)
104 gcry_free (array[i]);
107 gcry_sexp_release (list);
108 return 4; /* required parameter is invalid */
111 gcry_sexp_release (list);
117 * Convert the given private key from the network format to the
118 * S-expression that can be used by libgcrypt.
120 * @param priv private key to decode
121 * @return NULL on error
124 decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
129 rc = gcry_sexp_build (&result, NULL,
130 "(private-key(ecc(curve \"" CURVE "\")"
132 (int) sizeof (priv->d), priv->d);
135 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
139 if (0 != (rc = gcry_pk_testkey (result)))
141 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
150 * Convert the given private key from the network format to the
151 * S-expression that can be used by libgcrypt.
153 * @param priv private key to decode
154 * @return NULL on error
157 decode_private_eddsa_key (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
162 rc = gcry_sexp_build (&result, NULL,
163 "(private-key(ecc(curve \"" CURVE "\")"
164 "(flags eddsa)(d %b)))",
165 (int)sizeof (priv->d), priv->d);
168 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
172 if (0 != (rc = gcry_pk_testkey (result)))
174 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
183 * Convert the given private key from the network format to the
184 * S-expression that can be used by libgcrypt.
186 * @param priv private key to decode
187 * @return NULL on error
190 decode_private_ecdhe_key (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv)
195 rc = gcry_sexp_build (&result, NULL,
196 "(private-key(ecc(curve \"" CURVE "\")"
198 (int)sizeof (priv->d), priv->d);
201 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
205 if (0 != (rc = gcry_pk_testkey (result)))
207 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
216 * Extract the public key for the given private key.
218 * @param priv the private key
219 * @param pub where to write the public key
222 GNUNET_CRYPTO_ecdsa_key_get_public (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
223 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
229 BENCHMARK_START (ecdsa_key_get_public);
231 sexp = decode_private_ecdsa_key (priv);
232 GNUNET_assert (NULL != sexp);
233 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
234 gcry_sexp_release (sexp);
235 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
236 GNUNET_assert (NULL != q);
237 GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
238 gcry_mpi_release (q);
239 gcry_ctx_release (ctx);
241 BENCHMARK_END (ecdsa_key_get_public);
246 * Extract the public key for the given private key.
248 * @param priv the private key
249 * @param pub where to write the public key
252 GNUNET_CRYPTO_eddsa_key_get_public (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
253 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
259 BENCHMARK_START (eddsa_key_get_public);
261 sexp = decode_private_eddsa_key (priv);
262 GNUNET_assert (NULL != sexp);
263 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
264 gcry_sexp_release (sexp);
265 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
267 GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
268 gcry_mpi_release (q);
269 gcry_ctx_release (ctx);
271 BENCHMARK_END (eddsa_key_get_public);
276 * Extract the public key for the given private key.
278 * @param priv the private key
279 * @param pub where to write the public key
282 GNUNET_CRYPTO_ecdhe_key_get_public (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
283 struct GNUNET_CRYPTO_EcdhePublicKey *pub)
289 BENCHMARK_START (ecdhe_key_get_public);
291 sexp = decode_private_ecdhe_key (priv);
292 GNUNET_assert (NULL != sexp);
293 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
294 gcry_sexp_release (sexp);
295 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
297 GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
298 gcry_mpi_release (q);
299 gcry_ctx_release (ctx);
301 BENCHMARK_END (ecdhe_key_get_public);
306 * Convert a public key to a string.
308 * @param pub key to convert
309 * @return string representing @a pub
312 GNUNET_CRYPTO_ecdsa_public_key_to_string (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
315 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
319 keylen += 5 - keylen % 5;
321 pubkeybuf = GNUNET_malloc (keylen + 1);
322 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
323 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
328 GNUNET_free (pubkeybuf);
337 * Convert a public key to a string.
339 * @param pub key to convert
340 * @return string representing @a pub
343 GNUNET_CRYPTO_eddsa_public_key_to_string (const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
346 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
350 keylen += 5 - keylen % 5;
352 pubkeybuf = GNUNET_malloc (keylen + 1);
353 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
354 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
359 GNUNET_free (pubkeybuf);
368 * Convert a private key to a string.
370 * @param priv key to convert
371 * @return string representing @a pub
374 GNUNET_CRYPTO_eddsa_private_key_to_string (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
377 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
381 keylen += 5 - keylen % 5;
383 privkeybuf = GNUNET_malloc (keylen + 1);
384 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
385 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
390 GNUNET_free (privkeybuf);
399 * Convert a string representing a public key to a public key.
401 * @param enc encoded public key
402 * @param enclen number of bytes in @a enc (without 0-terminator)
403 * @param pub where to store the public key
404 * @return #GNUNET_OK on success
407 GNUNET_CRYPTO_ecdsa_public_key_from_string (const char *enc,
409 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
411 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
414 keylen += 5 - keylen % 5;
416 if (enclen != keylen)
417 return GNUNET_SYSERR;
420 GNUNET_STRINGS_string_to_data (enc, enclen,
422 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
423 return GNUNET_SYSERR;
429 * Convert a string representing a public key to a public key.
431 * @param enc encoded public key
432 * @param enclen number of bytes in @a enc (without 0-terminator)
433 * @param pub where to store the public key
434 * @return #GNUNET_OK on success
437 GNUNET_CRYPTO_eddsa_public_key_from_string (const char *enc,
439 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
441 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
444 keylen += 5 - keylen % 5;
446 if (enclen != keylen)
447 return GNUNET_SYSERR;
450 GNUNET_STRINGS_string_to_data (enc, enclen,
452 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
453 return GNUNET_SYSERR;
459 * Convert a string representing a private key to a private key.
461 * @param enc encoded public key
462 * @param enclen number of bytes in @a enc (without 0-terminator)
463 * @param priv where to store the private key
464 * @return #GNUNET_OK on success
467 GNUNET_CRYPTO_eddsa_private_key_from_string (const char *enc,
469 struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
471 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
474 keylen += 5 - keylen % 5;
476 if (enclen != keylen)
477 return GNUNET_SYSERR;
480 GNUNET_STRINGS_string_to_data (enc, enclen,
482 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
483 return GNUNET_SYSERR;
486 check_eddsa_key (priv))
498 * Clear memory that was used to store a private key.
500 * @param pk location of the key
503 GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
505 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
511 * Clear memory that was used to store a private key.
513 * @param pk location of the key
516 GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
518 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
524 * Clear memory that was used to store a private key.
526 * @param pk location of the key
529 GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
531 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
536 * Create a new private key. Caller must free return value.
538 * @return fresh private key
540 struct GNUNET_CRYPTO_EcdhePrivateKey *
541 GNUNET_CRYPTO_ecdhe_key_create ()
543 struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
545 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
547 GNUNET_CRYPTO_ecdhe_key_create2 (priv))
558 * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
560 * @param[out] pk set to fresh private key;
561 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
564 GNUNET_CRYPTO_ecdhe_key_create2 (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
566 gcry_sexp_t priv_sexp;
567 gcry_sexp_t s_keyparam;
571 BENCHMARK_START (ecdhe_key_create);
573 /* NOTE: For libgcrypt >= 1.7, we do not need the 'eddsa' flag here,
574 but should also be harmless. For libgcrypt < 1.7, using 'eddsa'
575 disables an expensive key testing routine. We do not want to run
576 the expensive check for ECDHE, as we generate TONS of keys to
577 use for a very short time. */
578 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
579 "(genkey(ecc(curve \"" CURVE "\")"
580 "(flags eddsa no-keytest)))")))
582 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
583 return GNUNET_SYSERR;
585 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
587 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
588 gcry_sexp_release (s_keyparam);
589 return GNUNET_SYSERR;
591 gcry_sexp_release (s_keyparam);
593 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
595 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
596 gcry_sexp_release (priv_sexp);
597 return GNUNET_SYSERR;
600 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
602 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
603 gcry_sexp_release (priv_sexp);
604 return GNUNET_SYSERR;
606 gcry_sexp_release (priv_sexp);
607 GNUNET_CRYPTO_mpi_print_unsigned (pk->d, sizeof (pk->d), d);
608 gcry_mpi_release (d);
610 BENCHMARK_END (ecdhe_key_create);
617 * Create a new private key. Caller must free return value.
619 * @return fresh private key
621 struct GNUNET_CRYPTO_EcdsaPrivateKey *
622 GNUNET_CRYPTO_ecdsa_key_create ()
624 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
625 gcry_sexp_t priv_sexp;
626 gcry_sexp_t s_keyparam;
630 BENCHMARK_START (ecdsa_key_create);
632 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
633 "(genkey(ecc(curve \"" CURVE "\")"
636 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
639 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
641 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
642 gcry_sexp_release (s_keyparam);
645 gcry_sexp_release (s_keyparam);
647 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
649 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
650 gcry_sexp_release (priv_sexp);
654 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
656 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
657 gcry_sexp_release (priv_sexp);
660 gcry_sexp_release (priv_sexp);
661 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
662 GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
663 gcry_mpi_release (d);
665 BENCHMARK_END (ecdsa_key_create);
671 * Create a new private key. Caller must free return value.
673 * @return fresh private key
675 struct GNUNET_CRYPTO_EddsaPrivateKey *
676 GNUNET_CRYPTO_eddsa_key_create ()
678 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
679 gcry_sexp_t priv_sexp;
680 gcry_sexp_t s_keyparam;
684 BENCHMARK_START (eddsa_key_create);
689 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
690 "(genkey(ecc(curve \"" CURVE "\")"
693 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
696 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
698 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
699 gcry_sexp_release (s_keyparam);
702 gcry_sexp_release (s_keyparam);
704 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
706 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
707 gcry_sexp_release (priv_sexp);
711 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
713 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
714 gcry_sexp_release (priv_sexp);
717 gcry_sexp_release (priv_sexp);
718 priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
719 GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
720 gcry_mpi_release (d);
724 check_eddsa_key (priv))
732 BENCHMARK_END (eddsa_key_create);
739 * Get the shared private key we use for anonymous users.
741 * @return "anonymous" private key
743 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
744 GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
747 * 'anonymous' pseudonym (global static, d=1, public key = G
750 static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
755 GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
756 sizeof (anonymous.d),
764 * Compare two Peer Identities.
766 * @param first first peer identity
767 * @param second second peer identity
768 * @return bigger than 0 if first > second,
769 * 0 if they are the same
770 * smaller than 0 if second > first
773 GNUNET_CRYPTO_cmp_peer_identity (const struct GNUNET_PeerIdentity *first,
774 const struct GNUNET_PeerIdentity *second)
776 return memcmp (first, second, sizeof (struct GNUNET_PeerIdentity));
781 * Convert the data specified in the given purpose argument to an
782 * S-expression suitable for signature operations.
784 * @param purpose data to convert
785 * @return converted s-expression
788 data_to_eddsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
790 struct GNUNET_HashCode hc;
794 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
795 if (0 != (rc = gcry_sexp_build (&data, NULL,
796 "(data(flags eddsa)(hash-algo %s)(value %b))",
798 (int)sizeof (hc), &hc)))
800 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
808 * Convert the data specified in the given purpose argument to an
809 * S-expression suitable for signature operations.
811 * @param purpose data to convert
812 * @return converted s-expression
815 data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
817 struct GNUNET_HashCode hc;
821 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
822 if (0 != (rc = gcry_sexp_build (&data, NULL,
823 "(data(flags rfc6979)(hash %s %b))",
825 (int)sizeof (hc), &hc)))
827 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
835 * Sign a given block.
837 * @param priv private key to use for the signing
838 * @param purpose what to sign (size, purpose)
839 * @param sig where to write the signature
840 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
843 GNUNET_CRYPTO_ecdsa_sign (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
844 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
845 struct GNUNET_CRYPTO_EcdsaSignature *sig)
847 gcry_sexp_t priv_sexp;
848 gcry_sexp_t sig_sexp;
853 BENCHMARK_START (ecdsa_sign);
855 priv_sexp = decode_private_ecdsa_key (priv);
856 data = data_to_ecdsa_value (purpose);
857 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
859 LOG (GNUNET_ERROR_TYPE_WARNING,
860 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
861 __LINE__, gcry_strerror (rc));
862 gcry_sexp_release (data);
863 gcry_sexp_release (priv_sexp);
864 return GNUNET_SYSERR;
866 gcry_sexp_release (priv_sexp);
867 gcry_sexp_release (data);
869 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
871 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
874 gcry_sexp_release (sig_sexp);
875 return GNUNET_SYSERR;
877 gcry_sexp_release (sig_sexp);
878 GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
879 GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
880 gcry_mpi_release (rs[0]);
881 gcry_mpi_release (rs[1]);
883 BENCHMARK_END (ecdsa_sign);
890 * Sign a given block.
892 * @param priv private key to use for the signing
893 * @param purpose what to sign (size, purpose)
894 * @param sig where to write the signature
895 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
898 GNUNET_CRYPTO_eddsa_sign (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
899 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
900 struct GNUNET_CRYPTO_EddsaSignature *sig)
902 gcry_sexp_t priv_sexp;
903 gcry_sexp_t sig_sexp;
908 BENCHMARK_START (eddsa_sign);
910 priv_sexp = decode_private_eddsa_key (priv);
911 data = data_to_eddsa_value (purpose);
912 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
914 LOG (GNUNET_ERROR_TYPE_WARNING,
915 _("EdDSA signing failed at %s:%d: %s\n"), __FILE__,
916 __LINE__, gcry_strerror (rc));
917 gcry_sexp_release (data);
918 gcry_sexp_release (priv_sexp);
919 return GNUNET_SYSERR;
921 gcry_sexp_release (priv_sexp);
922 gcry_sexp_release (data);
924 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
926 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
929 gcry_sexp_release (sig_sexp);
930 return GNUNET_SYSERR;
932 gcry_sexp_release (sig_sexp);
933 GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
934 GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
935 gcry_mpi_release (rs[0]);
936 gcry_mpi_release (rs[1]);
938 BENCHMARK_END (eddsa_sign);
947 * @param purpose what is the purpose that the signature should have?
948 * @param validate block to validate (size, purpose, data)
949 * @param sig signature that is being validated
950 * @param pub public key of the signer
951 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
954 GNUNET_CRYPTO_ecdsa_verify (uint32_t purpose,
955 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
956 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
957 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
960 gcry_sexp_t sig_sexpr;
961 gcry_sexp_t pub_sexpr;
964 BENCHMARK_START (ecdsa_verify);
966 if (purpose != ntohl (validate->purpose))
967 return GNUNET_SYSERR; /* purpose mismatch */
969 /* build s-expression for signature */
970 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
971 "(sig-val(ecdsa(r %b)(s %b)))",
972 (int) sizeof (sig->r), sig->r,
973 (int) sizeof (sig->s), sig->s)))
975 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
976 return GNUNET_SYSERR;
978 data = data_to_ecdsa_value (validate);
979 if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
980 "(public-key(ecc(curve " CURVE ")(q %b)))",
981 (int) sizeof (pub->q_y), pub->q_y)))
983 gcry_sexp_release (data);
984 gcry_sexp_release (sig_sexpr);
985 return GNUNET_SYSERR;
987 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
988 gcry_sexp_release (pub_sexpr);
989 gcry_sexp_release (data);
990 gcry_sexp_release (sig_sexpr);
993 LOG (GNUNET_ERROR_TYPE_INFO,
994 _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
995 __LINE__, gcry_strerror (rc));
996 BENCHMARK_END (ecdsa_verify);
997 return GNUNET_SYSERR;
999 BENCHMARK_END (ecdsa_verify);
1008 * @param purpose what is the purpose that the signature should have?
1009 * @param validate block to validate (size, purpose, data)
1010 * @param sig signature that is being validated
1011 * @param pub public key of the signer
1012 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
1015 GNUNET_CRYPTO_eddsa_verify (uint32_t purpose,
1016 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
1017 const struct GNUNET_CRYPTO_EddsaSignature *sig,
1018 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
1021 gcry_sexp_t sig_sexpr;
1022 gcry_sexp_t pub_sexpr;
1025 BENCHMARK_START (eddsa_verify);
1027 if (purpose != ntohl (validate->purpose))
1028 return GNUNET_SYSERR; /* purpose mismatch */
1030 /* build s-expression for signature */
1031 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
1032 "(sig-val(eddsa(r %b)(s %b)))",
1033 (int)sizeof (sig->r), sig->r,
1034 (int)sizeof (sig->s), sig->s)))
1036 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1037 return GNUNET_SYSERR;
1039 data = data_to_eddsa_value (validate);
1040 if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
1041 "(public-key(ecc(curve " CURVE ")(flags eddsa)(q %b)))",
1042 (int)sizeof (pub->q_y), pub->q_y)))
1044 gcry_sexp_release (data);
1045 gcry_sexp_release (sig_sexpr);
1046 return GNUNET_SYSERR;
1048 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
1049 gcry_sexp_release (pub_sexpr);
1050 gcry_sexp_release (data);
1051 gcry_sexp_release (sig_sexpr);
1054 LOG (GNUNET_ERROR_TYPE_INFO,
1055 _("EdDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1056 __LINE__, gcry_strerror (rc));
1057 BENCHMARK_END (eddsa_verify);
1058 return GNUNET_SYSERR;
1060 BENCHMARK_END (eddsa_verify);
1066 * Derive key material from a public and a private ECDHE key.
1068 * @param priv private key to use for the ECDH (x)
1069 * @param pub public key to use for the ECDH (yG)
1070 * @param key_material where to write the key material (xyG)
1071 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1074 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1075 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1076 struct GNUNET_HashCode *key_material)
1078 gcry_mpi_point_t result;
1082 gcry_sexp_t pub_sexpr;
1083 gcry_mpi_t result_x;
1084 unsigned char xbuf[256 / 8];
1087 BENCHMARK_START (ecc_ecdh);
1089 /* first, extract the q = dP value from the public key */
1090 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1091 "(public-key(ecc(curve " CURVE ")(q %b)))",
1092 (int)sizeof (pub->q_y), pub->q_y))
1093 return GNUNET_SYSERR;
1094 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1095 gcry_sexp_release (pub_sexpr);
1096 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1098 /* second, extract the d value from our private key */
1099 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1101 /* then call the 'multiply' function, to compute the product */
1102 result = gcry_mpi_point_new (0);
1103 gcry_mpi_ec_mul (result, d, q, ctx);
1104 gcry_mpi_point_release (q);
1105 gcry_mpi_release (d);
1107 /* finally, convert point to string for hashing */
1108 result_x = gcry_mpi_new (256);
1109 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1111 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1112 gcry_mpi_point_release (result);
1113 gcry_ctx_release (ctx);
1114 return GNUNET_SYSERR;
1116 gcry_mpi_point_release (result);
1117 gcry_ctx_release (ctx);
1119 rsize = sizeof (xbuf);
1120 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1121 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1122 as that does not include the sign bit; x should be a 255-bit
1123 value, so with the sign it should fit snugly into the 256-bit
1126 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1128 GNUNET_CRYPTO_hash (xbuf,
1131 gcry_mpi_release (result_x);
1132 BENCHMARK_END (ecc_ecdh);
1138 * Derive the 'h' value for key derivation, where
1141 * @param pub public key for deriviation
1142 * @param label label for deriviation
1143 * @param context additional context to use for HKDF of 'h';
1144 * typically the name of the subsystem/application
1148 derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1150 const char *context)
1153 struct GNUNET_HashCode hc;
1154 static const char *const salt = "key-derivation";
1156 GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
1157 salt, strlen (salt),
1159 label, strlen (label),
1160 context, strlen (context),
1162 GNUNET_CRYPTO_mpi_scan_unsigned (&h,
1163 (unsigned char *) &hc,
1170 * Derive a private key from a given private key and a label.
1171 * Essentially calculates a private key 'd = H(l,P) * x mod n'
1172 * where n is the size of the ECC group and P is the public
1173 * key associated with the private key 'd'.
1175 * @param priv original private key
1176 * @param label label to use for key deriviation
1177 * @param context additional context to use for HKDF of 'h';
1178 * typically the name of the subsystem/application
1179 * @return derived private key
1181 struct GNUNET_CRYPTO_EcdsaPrivateKey *
1182 GNUNET_CRYPTO_ecdsa_private_key_derive (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1184 const char *context)
1186 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
1187 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
1194 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1196 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1197 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
1199 h = derive_h (&pub, label, context);
1200 GNUNET_CRYPTO_mpi_scan_unsigned (&x,
1203 d = gcry_mpi_new (256);
1204 gcry_mpi_mulm (d, h, x, n);
1205 gcry_mpi_release (h);
1206 gcry_mpi_release (x);
1207 gcry_mpi_release (n);
1208 gcry_ctx_release (ctx);
1209 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
1210 GNUNET_CRYPTO_mpi_print_unsigned (ret->d, sizeof (ret->d), d);
1211 gcry_mpi_release (d);
1217 * Derive a public key from a given public key and a label.
1218 * Essentially calculates a public key 'V = H(l,P) * P'.
1220 * @param pub original public key
1221 * @param label label to use for key derivation
1222 * @param context additional context to use for HKDF of 'h';
1223 * typically the name of the subsystem/application
1224 * @param result where to write the derived public key
1227 GNUNET_CRYPTO_ecdsa_public_key_derive (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1229 const char *context,
1230 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
1240 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1242 /* obtain point 'q' from original public key. The provided 'q' is
1243 compressed thus we first store it in the context and then get it
1244 back as a (decompresssed) point. */
1245 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8*sizeof (pub->q_y));
1246 GNUNET_assert (NULL != q_y);
1247 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
1248 gcry_mpi_release (q_y);
1249 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1252 /* calculate h_mod_n = h % n */
1253 h = derive_h (pub, label, context);
1254 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1255 h_mod_n = gcry_mpi_new (256);
1256 gcry_mpi_mod (h_mod_n, h, n);
1257 /* calculate v = h_mod_n * q */
1258 v = gcry_mpi_point_new (0);
1259 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1260 gcry_mpi_release (h_mod_n);
1261 gcry_mpi_release (h);
1262 gcry_mpi_release (n);
1263 gcry_mpi_point_release (q);
1265 /* convert point 'v' to public key that we return */
1266 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
1267 gcry_mpi_point_release (v);
1268 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
1269 GNUNET_assert (q_y);
1270 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y,
1271 sizeof (result->q_y),
1273 gcry_mpi_release (q_y);
1274 gcry_ctx_release (ctx);
1279 * Reverse the sequence of the bytes in @a buffer
1281 * @param[in|out] buffer buffer to invert
1282 * @param length number of bytes in @a buffer
1285 reverse_buffer (unsigned char *buffer,
1291 for (i=0; i < length/2; i++)
1294 buffer[i] = buffer[length-1-i];
1295 buffer[length-1-i] = tmp;
1301 * Convert the secret @a d of an EdDSA key to the
1302 * value that is actually used in the EdDSA computation.
1304 * @param d secret input
1305 * @return value used for the calculation in EdDSA
1308 eddsa_d_to_a (gcry_mpi_t d)
1310 unsigned char rawmpi[32]; /* 256-bit value */
1312 unsigned char digest[64]; /* 512-bit hash value */
1313 gcry_buffer_t hvec[2];
1317 b = 256 / 8; /* number of bytes in `d` */
1319 /* Note that we clear DIGEST so we can use it as input to left pad
1320 the key with zeroes for hashing. */
1321 memset (digest, 0, sizeof digest);
1322 memset (hvec, 0, sizeof hvec);
1323 rawmpilen = sizeof (rawmpi);
1325 gcry_mpi_print (GCRYMPI_FMT_USG,
1326 rawmpi, rawmpilen, &rawmpilen,
1328 hvec[0].data = digest;
1330 hvec[0].len = b > rawmpilen ? (b - rawmpilen) : 0;
1331 hvec[1].data = rawmpi;
1333 hvec[1].len = rawmpilen;
1335 gcry_md_hash_buffers (GCRY_MD_SHA512,
1339 /* Compute the A value. */
1340 reverse_buffer (digest, 32); /* Only the first half of the hash. */
1341 digest[0] = (digest[0] & 0x7f) | 0x40;
1344 GNUNET_CRYPTO_mpi_scan_unsigned (&a,
1352 * Take point from ECDH and convert it to key material.
1354 * @param result point from ECDH
1355 * @param ctx ECC context
1356 * @param key_material[out] set to derived key material
1357 * @return #GNUNET_OK on success
1360 point_to_hash (gcry_mpi_point_t result,
1362 struct GNUNET_HashCode *key_material)
1364 gcry_mpi_t result_x;
1365 unsigned char xbuf[256 / 8];
1368 /* finally, convert point to string for hashing */
1369 result_x = gcry_mpi_new (256);
1370 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1372 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1373 return GNUNET_SYSERR;
1376 rsize = sizeof (xbuf);
1377 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1378 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1379 as that does not include the sign bit; x should be a 255-bit
1380 value, so with the sign it should fit snugly into the 256-bit
1383 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1385 GNUNET_CRYPTO_hash (xbuf,
1388 gcry_mpi_release (result_x);
1395 * Derive key material from a ECDH public key and a private EdDSA key.
1396 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1398 * @param priv private key from EdDSA to use for the ECDH (x)
1399 * @param pub public key to use for the ECDH (yG)
1400 * @param key_material where to write the key material H(h(x)yG)
1401 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1404 GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1405 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1406 struct GNUNET_HashCode *key_material)
1408 gcry_mpi_point_t result;
1413 gcry_sexp_t pub_sexpr;
1416 BENCHMARK_START (eddsa_ecdh);
1418 /* first, extract the q = dP value from the public key */
1419 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1420 "(public-key(ecc(curve " CURVE ")(q %b)))",
1421 (int)sizeof (pub->q_y), pub->q_y))
1422 return GNUNET_SYSERR;
1423 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1424 gcry_sexp_release (pub_sexpr);
1425 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1427 /* second, extract the d value from our private key */
1428 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1430 /* NOW, because this is EdDSA, HASH 'd' first! */
1431 a = eddsa_d_to_a (d);
1432 gcry_mpi_release (d);
1434 /* then call the 'multiply' function, to compute the product */
1435 result = gcry_mpi_point_new (0);
1436 gcry_mpi_ec_mul (result, a, q, ctx);
1437 gcry_mpi_point_release (q);
1438 gcry_mpi_release (a);
1440 ret = point_to_hash (result,
1443 gcry_mpi_point_release (result);
1444 gcry_ctx_release (ctx);
1445 BENCHMARK_END (eddsa_ecdh);
1452 * Derive key material from a ECDH public key and a private ECDSA key.
1453 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1455 * @param priv private key from ECDSA to use for the ECDH (x)
1456 * @param pub public key to use for the ECDH (yG)
1457 * @param key_material where to write the key material H(h(x)yG)
1458 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1461 GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1462 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1463 struct GNUNET_HashCode *key_material)
1465 gcry_mpi_point_t result;
1469 gcry_sexp_t pub_sexpr;
1472 BENCHMARK_START (ecdsa_ecdh);
1474 /* first, extract the q = dP value from the public key */
1475 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1476 "(public-key(ecc(curve " CURVE ")(q %b)))",
1477 (int)sizeof (pub->q_y), pub->q_y))
1478 return GNUNET_SYSERR;
1479 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1480 gcry_sexp_release (pub_sexpr);
1481 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1483 /* second, extract the d value from our private key */
1484 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1486 /* then call the 'multiply' function, to compute the product */
1487 result = gcry_mpi_point_new (0);
1488 gcry_mpi_ec_mul (result, d, q, ctx);
1489 gcry_mpi_point_release (q);
1490 gcry_mpi_release (d);
1492 /* finally, convert point to string for hashing */
1493 ret = point_to_hash (result,
1496 gcry_mpi_point_release (result);
1497 gcry_ctx_release (ctx);
1498 BENCHMARK_END (ecdsa_ecdh);
1506 * Derive key material from a EdDSA public key and a private ECDH key.
1507 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1509 * @param priv private key to use for the ECDH (y)
1510 * @param pub public key from EdDSA to use for the ECDH (X=h(x)G)
1511 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1512 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1515 GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1516 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1517 struct GNUNET_HashCode *key_material)
1519 gcry_mpi_point_t result;
1523 gcry_sexp_t pub_sexpr;
1526 BENCHMARK_START (ecdh_eddsa);
1528 /* first, extract the q = dP value from the public key */
1529 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1530 "(public-key(ecc(curve " CURVE ")(q %b)))",
1531 (int)sizeof (pub->q_y), pub->q_y))
1532 return GNUNET_SYSERR;
1533 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1534 gcry_sexp_release (pub_sexpr);
1535 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1537 /* second, extract the d value from our private key */
1538 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1540 /* then call the 'multiply' function, to compute the product */
1541 result = gcry_mpi_point_new (0);
1542 gcry_mpi_ec_mul (result, d, q, ctx);
1543 gcry_mpi_point_release (q);
1544 gcry_mpi_release (d);
1546 /* finally, convert point to string for hashing */
1547 ret = point_to_hash (result,
1550 gcry_mpi_point_release (result);
1551 gcry_ctx_release (ctx);
1552 BENCHMARK_END (ecdh_eddsa);
1558 * Derive key material from a ECDSA public key and a private ECDH key.
1559 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1561 * @param priv private key to use for the ECDH (y)
1562 * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
1563 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1564 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1567 GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1568 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1569 struct GNUNET_HashCode *key_material)
1571 return GNUNET_CRYPTO_ecdh_eddsa (priv,
1572 (const struct GNUNET_CRYPTO_EddsaPublicKey *)pub,
1576 /* end of crypto_ecc.c */