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 sexp = decode_private_ecdsa_key (priv);
230 GNUNET_assert (NULL != sexp);
231 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
232 gcry_sexp_release (sexp);
233 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
234 GNUNET_assert (NULL != q);
235 GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
236 gcry_mpi_release (q);
237 gcry_ctx_release (ctx);
242 * Extract the public key for the given private key.
244 * @param priv the private key
245 * @param pub where to write the public key
248 GNUNET_CRYPTO_eddsa_key_get_public (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
249 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
255 sexp = decode_private_eddsa_key (priv);
256 GNUNET_assert (NULL != sexp);
257 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
258 gcry_sexp_release (sexp);
259 q = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
261 GNUNET_CRYPTO_mpi_print_unsigned (pub->q_y, sizeof (pub->q_y), q);
262 gcry_mpi_release (q);
263 gcry_ctx_release (ctx);
268 * Extract the public key for the given private key.
270 * @param priv the private key
271 * @param pub where to write the public key
274 GNUNET_CRYPTO_ecdhe_key_get_public (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
275 struct GNUNET_CRYPTO_EcdhePublicKey *pub)
281 sexp = decode_private_ecdhe_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);
288 gcry_mpi_release (q);
289 gcry_ctx_release (ctx);
294 * Convert a public key to a string.
296 * @param pub key to convert
297 * @return string representing @a pub
300 GNUNET_CRYPTO_ecdsa_public_key_to_string (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
303 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
307 keylen += 5 - keylen % 5;
309 pubkeybuf = GNUNET_malloc (keylen + 1);
310 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
311 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
316 GNUNET_free (pubkeybuf);
325 * Convert a public key to a string.
327 * @param pub key to convert
328 * @return string representing @a pub
331 GNUNET_CRYPTO_eddsa_public_key_to_string (const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
334 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
338 keylen += 5 - keylen % 5;
340 pubkeybuf = GNUNET_malloc (keylen + 1);
341 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
342 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey),
347 GNUNET_free (pubkeybuf);
356 * Convert a private key to a string.
358 * @param priv key to convert
359 * @return string representing @a pub
362 GNUNET_CRYPTO_eddsa_private_key_to_string (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
365 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
369 keylen += 5 - keylen % 5;
371 privkeybuf = GNUNET_malloc (keylen + 1);
372 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
373 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey),
378 GNUNET_free (privkeybuf);
387 * Convert a string representing a public key to a public key.
389 * @param enc encoded public key
390 * @param enclen number of bytes in @a enc (without 0-terminator)
391 * @param pub where to store the public key
392 * @return #GNUNET_OK on success
395 GNUNET_CRYPTO_ecdsa_public_key_from_string (const char *enc,
397 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
399 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
402 keylen += 5 - keylen % 5;
404 if (enclen != keylen)
405 return GNUNET_SYSERR;
408 GNUNET_STRINGS_string_to_data (enc, enclen,
410 sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey)))
411 return GNUNET_SYSERR;
417 * Convert a string representing a public key to a public key.
419 * @param enc encoded public key
420 * @param enclen number of bytes in @a enc (without 0-terminator)
421 * @param pub where to store the public key
422 * @return #GNUNET_OK on success
425 GNUNET_CRYPTO_eddsa_public_key_from_string (const char *enc,
427 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
429 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
432 keylen += 5 - keylen % 5;
434 if (enclen != keylen)
435 return GNUNET_SYSERR;
438 GNUNET_STRINGS_string_to_data (enc, enclen,
440 sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
441 return GNUNET_SYSERR;
447 * Convert a string representing a private key to a private key.
449 * @param enc encoded public key
450 * @param enclen number of bytes in @a enc (without 0-terminator)
451 * @param priv where to store the private key
452 * @return #GNUNET_OK on success
455 GNUNET_CRYPTO_eddsa_private_key_from_string (const char *enc,
457 struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
459 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
462 keylen += 5 - keylen % 5;
464 if (enclen != keylen)
465 return GNUNET_SYSERR;
468 GNUNET_STRINGS_string_to_data (enc, enclen,
470 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)))
471 return GNUNET_SYSERR;
474 check_eddsa_key (priv))
486 * Clear memory that was used to store a private key.
488 * @param pk location of the key
491 GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
493 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
499 * Clear memory that was used to store a private key.
501 * @param pk location of the key
504 GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
506 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
512 * Clear memory that was used to store a private key.
514 * @param pk location of the key
517 GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
519 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
524 * Create a new private key. Caller must free return value.
526 * @return fresh private key
528 struct GNUNET_CRYPTO_EcdhePrivateKey *
529 GNUNET_CRYPTO_ecdhe_key_create ()
531 struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
533 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
535 GNUNET_CRYPTO_ecdhe_key_create2 (priv))
546 * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
548 * @param[out] pk set to fresh private key;
549 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
552 GNUNET_CRYPTO_ecdhe_key_create2 (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
554 gcry_sexp_t priv_sexp;
555 gcry_sexp_t s_keyparam;
559 /* NOTE: For libgcrypt >= 1.7, we do not need the 'eddsa' flag here,
560 but should also be harmless. For libgcrypt < 1.7, using 'eddsa'
561 disables an expensive key testing routine. We do not want to run
562 the expensive check for ECDHE, as we generate TONS of keys to
563 use for a very short time. */
564 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
565 "(genkey(ecc(curve \"" CURVE "\")"
566 "(flags eddsa no-keytest)))")))
568 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
569 return GNUNET_SYSERR;
571 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
573 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
574 gcry_sexp_release (s_keyparam);
575 return GNUNET_SYSERR;
577 gcry_sexp_release (s_keyparam);
579 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
581 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
582 gcry_sexp_release (priv_sexp);
583 return GNUNET_SYSERR;
586 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
588 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
589 gcry_sexp_release (priv_sexp);
590 return GNUNET_SYSERR;
592 gcry_sexp_release (priv_sexp);
593 GNUNET_CRYPTO_mpi_print_unsigned (pk->d, sizeof (pk->d), d);
594 gcry_mpi_release (d);
600 * Create a new private key. Caller must free return value.
602 * @return fresh private key
604 struct GNUNET_CRYPTO_EcdsaPrivateKey *
605 GNUNET_CRYPTO_ecdsa_key_create ()
607 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
608 gcry_sexp_t priv_sexp;
609 gcry_sexp_t s_keyparam;
613 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
614 "(genkey(ecc(curve \"" CURVE "\")"
617 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
620 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
622 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
623 gcry_sexp_release (s_keyparam);
626 gcry_sexp_release (s_keyparam);
628 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
630 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
631 gcry_sexp_release (priv_sexp);
635 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
637 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
638 gcry_sexp_release (priv_sexp);
641 gcry_sexp_release (priv_sexp);
642 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
643 GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
644 gcry_mpi_release (d);
649 * Create a new private key. Caller must free return value.
651 * @return fresh private key
653 struct GNUNET_CRYPTO_EddsaPrivateKey *
654 GNUNET_CRYPTO_eddsa_key_create ()
656 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
657 gcry_sexp_t priv_sexp;
658 gcry_sexp_t s_keyparam;
665 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
666 "(genkey(ecc(curve \"" CURVE "\")"
669 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
672 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
674 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
675 gcry_sexp_release (s_keyparam);
678 gcry_sexp_release (s_keyparam);
680 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
682 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
683 gcry_sexp_release (priv_sexp);
687 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
689 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
690 gcry_sexp_release (priv_sexp);
693 gcry_sexp_release (priv_sexp);
694 priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
695 GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
696 gcry_mpi_release (d);
700 check_eddsa_key (priv))
713 * Get the shared private key we use for anonymous users.
715 * @return "anonymous" private key
717 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
718 GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
721 * 'anonymous' pseudonym (global static, d=1, public key = G
724 static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
729 GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
730 sizeof (anonymous.d),
738 * Compare two Peer Identities.
740 * @param first first peer identity
741 * @param second second peer identity
742 * @return bigger than 0 if first > second,
743 * 0 if they are the same
744 * smaller than 0 if second > first
747 GNUNET_CRYPTO_cmp_peer_identity (const struct GNUNET_PeerIdentity *first,
748 const struct GNUNET_PeerIdentity *second)
750 return memcmp (first, second, sizeof (struct GNUNET_PeerIdentity));
755 * Convert the data specified in the given purpose argument to an
756 * S-expression suitable for signature operations.
758 * @param purpose data to convert
759 * @return converted s-expression
762 data_to_eddsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
764 struct GNUNET_HashCode hc;
768 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
769 if (0 != (rc = gcry_sexp_build (&data, NULL,
770 "(data(flags eddsa)(hash-algo %s)(value %b))",
772 (int)sizeof (hc), &hc)))
774 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
782 * Convert the data specified in the given purpose argument to an
783 * S-expression suitable for signature operations.
785 * @param purpose data to convert
786 * @return converted s-expression
789 data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
791 struct GNUNET_HashCode hc;
795 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
796 if (0 != (rc = gcry_sexp_build (&data, NULL,
797 "(data(flags rfc6979)(hash %s %b))",
799 (int)sizeof (hc), &hc)))
801 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
809 * Sign a given block.
811 * @param priv private key to use for the signing
812 * @param purpose what to sign (size, purpose)
813 * @param sig where to write the signature
814 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
817 GNUNET_CRYPTO_ecdsa_sign (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
818 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
819 struct GNUNET_CRYPTO_EcdsaSignature *sig)
821 gcry_sexp_t priv_sexp;
822 gcry_sexp_t sig_sexp;
827 priv_sexp = decode_private_ecdsa_key (priv);
828 data = data_to_ecdsa_value (purpose);
829 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
831 LOG (GNUNET_ERROR_TYPE_WARNING,
832 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
833 __LINE__, gcry_strerror (rc));
834 gcry_sexp_release (data);
835 gcry_sexp_release (priv_sexp);
836 return GNUNET_SYSERR;
838 gcry_sexp_release (priv_sexp);
839 gcry_sexp_release (data);
841 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
843 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
846 gcry_sexp_release (sig_sexp);
847 return GNUNET_SYSERR;
849 gcry_sexp_release (sig_sexp);
850 GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
851 GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
852 gcry_mpi_release (rs[0]);
853 gcry_mpi_release (rs[1]);
859 * Sign a given block.
861 * @param priv private key to use for the signing
862 * @param purpose what to sign (size, purpose)
863 * @param sig where to write the signature
864 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
867 GNUNET_CRYPTO_eddsa_sign (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
868 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
869 struct GNUNET_CRYPTO_EddsaSignature *sig)
871 gcry_sexp_t priv_sexp;
872 gcry_sexp_t sig_sexp;
878 struct BenchmarkData *bd = get_benchmark_data ();
879 bd->eddsa_sign_count++;
880 printf("crypto eddsa sign\n");
883 priv_sexp = decode_private_eddsa_key (priv);
884 data = data_to_eddsa_value (purpose);
885 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
887 LOG (GNUNET_ERROR_TYPE_WARNING,
888 _("EdDSA signing failed at %s:%d: %s\n"), __FILE__,
889 __LINE__, gcry_strerror (rc));
890 gcry_sexp_release (data);
891 gcry_sexp_release (priv_sexp);
892 return GNUNET_SYSERR;
894 gcry_sexp_release (priv_sexp);
895 gcry_sexp_release (data);
897 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
899 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
902 gcry_sexp_release (sig_sexp);
903 return GNUNET_SYSERR;
905 gcry_sexp_release (sig_sexp);
906 GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof (sig->r), rs[0]);
907 GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof (sig->s), rs[1]);
908 gcry_mpi_release (rs[0]);
909 gcry_mpi_release (rs[1]);
917 * @param purpose what is the purpose that the signature should have?
918 * @param validate block to validate (size, purpose, data)
919 * @param sig signature that is being validated
920 * @param pub public key of the signer
921 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
924 GNUNET_CRYPTO_ecdsa_verify (uint32_t purpose,
925 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
926 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
927 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
930 gcry_sexp_t sig_sexpr;
931 gcry_sexp_t pub_sexpr;
934 if (purpose != ntohl (validate->purpose))
935 return GNUNET_SYSERR; /* purpose mismatch */
937 /* build s-expression for signature */
938 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
939 "(sig-val(ecdsa(r %b)(s %b)))",
940 (int) sizeof (sig->r), sig->r,
941 (int) sizeof (sig->s), sig->s)))
943 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
944 return GNUNET_SYSERR;
946 data = data_to_ecdsa_value (validate);
947 if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
948 "(public-key(ecc(curve " CURVE ")(q %b)))",
949 (int) sizeof (pub->q_y), pub->q_y)))
951 gcry_sexp_release (data);
952 gcry_sexp_release (sig_sexpr);
953 return GNUNET_SYSERR;
955 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
956 gcry_sexp_release (pub_sexpr);
957 gcry_sexp_release (data);
958 gcry_sexp_release (sig_sexpr);
961 LOG (GNUNET_ERROR_TYPE_INFO,
962 _("ECDSA signature verification failed at %s:%d: %s\n"), __FILE__,
963 __LINE__, gcry_strerror (rc));
964 return GNUNET_SYSERR;
974 * @param purpose what is the purpose that the signature should have?
975 * @param validate block to validate (size, purpose, data)
976 * @param sig signature that is being validated
977 * @param pub public key of the signer
978 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
981 GNUNET_CRYPTO_eddsa_verify (uint32_t purpose,
982 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
983 const struct GNUNET_CRYPTO_EddsaSignature *sig,
984 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
987 gcry_sexp_t sig_sexpr;
988 gcry_sexp_t pub_sexpr;
991 if (purpose != ntohl (validate->purpose))
992 return GNUNET_SYSERR; /* purpose mismatch */
994 /* build s-expression for signature */
995 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
996 "(sig-val(eddsa(r %b)(s %b)))",
997 (int)sizeof (sig->r), sig->r,
998 (int)sizeof (sig->s), sig->s)))
1000 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
1001 return GNUNET_SYSERR;
1003 data = data_to_eddsa_value (validate);
1004 if (0 != (rc = gcry_sexp_build (&pub_sexpr, NULL,
1005 "(public-key(ecc(curve " CURVE ")(flags eddsa)(q %b)))",
1006 (int)sizeof (pub->q_y), pub->q_y)))
1008 gcry_sexp_release (data);
1009 gcry_sexp_release (sig_sexpr);
1010 return GNUNET_SYSERR;
1012 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
1013 gcry_sexp_release (pub_sexpr);
1014 gcry_sexp_release (data);
1015 gcry_sexp_release (sig_sexpr);
1018 LOG (GNUNET_ERROR_TYPE_INFO,
1019 _("EdDSA signature verification failed at %s:%d: %s\n"), __FILE__,
1020 __LINE__, gcry_strerror (rc));
1021 return GNUNET_SYSERR;
1028 * Derive key material from a public and a private ECDHE key.
1030 * @param priv private key to use for the ECDH (x)
1031 * @param pub public key to use for the ECDH (yG)
1032 * @param key_material where to write the key material (xyG)
1033 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1036 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1037 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1038 struct GNUNET_HashCode *key_material)
1040 gcry_mpi_point_t result;
1044 gcry_sexp_t pub_sexpr;
1045 gcry_mpi_t result_x;
1046 unsigned char xbuf[256 / 8];
1049 /* first, extract the q = dP value from the public key */
1050 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1051 "(public-key(ecc(curve " CURVE ")(q %b)))",
1052 (int)sizeof (pub->q_y), pub->q_y))
1053 return GNUNET_SYSERR;
1054 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1055 gcry_sexp_release (pub_sexpr);
1056 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1058 /* second, extract the d value from our private key */
1059 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1061 /* then call the 'multiply' function, to compute the product */
1062 result = gcry_mpi_point_new (0);
1063 gcry_mpi_ec_mul (result, d, q, ctx);
1064 gcry_mpi_point_release (q);
1065 gcry_mpi_release (d);
1067 /* finally, convert point to string for hashing */
1068 result_x = gcry_mpi_new (256);
1069 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1071 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1072 gcry_mpi_point_release (result);
1073 gcry_ctx_release (ctx);
1074 return GNUNET_SYSERR;
1076 gcry_mpi_point_release (result);
1077 gcry_ctx_release (ctx);
1079 rsize = sizeof (xbuf);
1080 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1081 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1082 as that does not include the sign bit; x should be a 255-bit
1083 value, so with the sign it should fit snugly into the 256-bit
1086 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1088 GNUNET_CRYPTO_hash (xbuf,
1091 gcry_mpi_release (result_x);
1097 * Derive the 'h' value for key derivation, where
1100 * @param pub public key for deriviation
1101 * @param label label for deriviation
1102 * @param context additional context to use for HKDF of 'h';
1103 * typically the name of the subsystem/application
1107 derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1109 const char *context)
1112 struct GNUNET_HashCode hc;
1113 static const char *const salt = "key-derivation";
1115 GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
1116 salt, strlen (salt),
1118 label, strlen (label),
1119 context, strlen (context),
1121 GNUNET_CRYPTO_mpi_scan_unsigned (&h,
1122 (unsigned char *) &hc,
1129 * Derive a private key from a given private key and a label.
1130 * Essentially calculates a private key 'd = H(l,P) * x mod n'
1131 * where n is the size of the ECC group and P is the public
1132 * key associated with the private key 'd'.
1134 * @param priv original private key
1135 * @param label label to use for key deriviation
1136 * @param context additional context to use for HKDF of 'h';
1137 * typically the name of the subsystem/application
1138 * @return derived private key
1140 struct GNUNET_CRYPTO_EcdsaPrivateKey *
1141 GNUNET_CRYPTO_ecdsa_private_key_derive (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1143 const char *context)
1145 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
1146 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
1153 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1155 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1156 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
1158 h = derive_h (&pub, label, context);
1159 GNUNET_CRYPTO_mpi_scan_unsigned (&x,
1162 d = gcry_mpi_new (256);
1163 gcry_mpi_mulm (d, h, x, n);
1164 gcry_mpi_release (h);
1165 gcry_mpi_release (x);
1166 gcry_mpi_release (n);
1167 gcry_ctx_release (ctx);
1168 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
1169 GNUNET_CRYPTO_mpi_print_unsigned (ret->d, sizeof (ret->d), d);
1170 gcry_mpi_release (d);
1176 * Derive a public key from a given public key and a label.
1177 * Essentially calculates a public key 'V = H(l,P) * P'.
1179 * @param pub original public key
1180 * @param label label to use for key derivation
1181 * @param context additional context to use for HKDF of 'h';
1182 * typically the name of the subsystem/application
1183 * @param result where to write the derived public key
1186 GNUNET_CRYPTO_ecdsa_public_key_derive (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1188 const char *context,
1189 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
1199 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1201 /* obtain point 'q' from original public key. The provided 'q' is
1202 compressed thus we first store it in the context and then get it
1203 back as a (decompresssed) point. */
1204 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8*sizeof (pub->q_y));
1205 GNUNET_assert (NULL != q_y);
1206 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
1207 gcry_mpi_release (q_y);
1208 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1211 /* calculate h_mod_n = h % n */
1212 h = derive_h (pub, label, context);
1213 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1214 h_mod_n = gcry_mpi_new (256);
1215 gcry_mpi_mod (h_mod_n, h, n);
1216 /* calculate v = h_mod_n * q */
1217 v = gcry_mpi_point_new (0);
1218 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1219 gcry_mpi_release (h_mod_n);
1220 gcry_mpi_release (h);
1221 gcry_mpi_release (n);
1222 gcry_mpi_point_release (q);
1224 /* convert point 'v' to public key that we return */
1225 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
1226 gcry_mpi_point_release (v);
1227 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
1228 GNUNET_assert (q_y);
1229 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y,
1230 sizeof (result->q_y),
1232 gcry_mpi_release (q_y);
1233 gcry_ctx_release (ctx);
1238 * Reverse the sequence of the bytes in @a buffer
1240 * @param[in|out] buffer buffer to invert
1241 * @param length number of bytes in @a buffer
1244 reverse_buffer (unsigned char *buffer,
1250 for (i=0; i < length/2; i++)
1253 buffer[i] = buffer[length-1-i];
1254 buffer[length-1-i] = tmp;
1260 * Convert the secret @a d of an EdDSA key to the
1261 * value that is actually used in the EdDSA computation.
1263 * @param d secret input
1264 * @return value used for the calculation in EdDSA
1267 eddsa_d_to_a (gcry_mpi_t d)
1269 unsigned char rawmpi[32]; /* 256-bit value */
1271 unsigned char digest[64]; /* 512-bit hash value */
1272 gcry_buffer_t hvec[2];
1276 b = 256 / 8; /* number of bytes in `d` */
1278 /* Note that we clear DIGEST so we can use it as input to left pad
1279 the key with zeroes for hashing. */
1280 memset (digest, 0, sizeof digest);
1281 memset (hvec, 0, sizeof hvec);
1282 rawmpilen = sizeof (rawmpi);
1284 gcry_mpi_print (GCRYMPI_FMT_USG,
1285 rawmpi, rawmpilen, &rawmpilen,
1287 hvec[0].data = digest;
1289 hvec[0].len = b > rawmpilen ? (b - rawmpilen) : 0;
1290 hvec[1].data = rawmpi;
1292 hvec[1].len = rawmpilen;
1294 gcry_md_hash_buffers (GCRY_MD_SHA512,
1298 /* Compute the A value. */
1299 reverse_buffer (digest, 32); /* Only the first half of the hash. */
1300 digest[0] = (digest[0] & 0x7f) | 0x40;
1303 GNUNET_CRYPTO_mpi_scan_unsigned (&a,
1311 * Take point from ECDH and convert it to key material.
1313 * @param result point from ECDH
1314 * @param ctx ECC context
1315 * @param key_material[out] set to derived key material
1316 * @return #GNUNET_OK on success
1319 point_to_hash (gcry_mpi_point_t result,
1321 struct GNUNET_HashCode *key_material)
1323 gcry_mpi_t result_x;
1324 unsigned char xbuf[256 / 8];
1327 /* finally, convert point to string for hashing */
1328 result_x = gcry_mpi_new (256);
1329 if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
1331 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
1332 return GNUNET_SYSERR;
1335 rsize = sizeof (xbuf);
1336 GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
1337 /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
1338 as that does not include the sign bit; x should be a 255-bit
1339 value, so with the sign it should fit snugly into the 256-bit
1342 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
1344 GNUNET_CRYPTO_hash (xbuf,
1347 gcry_mpi_release (result_x);
1354 * Derive key material from a ECDH public key and a private EdDSA key.
1355 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1357 * @param priv private key from EdDSA to use for the ECDH (x)
1358 * @param pub public key to use for the ECDH (yG)
1359 * @param key_material where to write the key material H(h(x)yG)
1360 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1363 GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1364 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1365 struct GNUNET_HashCode *key_material)
1367 gcry_mpi_point_t result;
1372 gcry_sexp_t pub_sexpr;
1375 /* first, extract the q = dP value from the public key */
1376 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1377 "(public-key(ecc(curve " CURVE ")(q %b)))",
1378 (int)sizeof (pub->q_y), pub->q_y))
1379 return GNUNET_SYSERR;
1380 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1381 gcry_sexp_release (pub_sexpr);
1382 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1384 /* second, extract the d value from our private key */
1385 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1387 /* NOW, because this is EdDSA, HASH 'd' first! */
1388 a = eddsa_d_to_a (d);
1389 gcry_mpi_release (d);
1391 /* then call the 'multiply' function, to compute the product */
1392 result = gcry_mpi_point_new (0);
1393 gcry_mpi_ec_mul (result, a, q, ctx);
1394 gcry_mpi_point_release (q);
1395 gcry_mpi_release (a);
1397 ret = point_to_hash (result,
1400 gcry_mpi_point_release (result);
1401 gcry_ctx_release (ctx);
1408 * Derive key material from a ECDH public key and a private ECDSA key.
1409 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1411 * @param priv private key from ECDSA to use for the ECDH (x)
1412 * @param pub public key to use for the ECDH (yG)
1413 * @param key_material where to write the key material H(h(x)yG)
1414 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1417 GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1418 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1419 struct GNUNET_HashCode *key_material)
1421 gcry_mpi_point_t result;
1425 gcry_sexp_t pub_sexpr;
1428 /* first, extract the q = dP value from the public key */
1429 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1430 "(public-key(ecc(curve " CURVE ")(q %b)))",
1431 (int)sizeof (pub->q_y), pub->q_y))
1432 return GNUNET_SYSERR;
1433 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1434 gcry_sexp_release (pub_sexpr);
1435 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1437 /* second, extract the d value from our private key */
1438 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1440 /* then call the 'multiply' function, to compute the product */
1441 result = gcry_mpi_point_new (0);
1442 gcry_mpi_ec_mul (result, d, q, ctx);
1443 gcry_mpi_point_release (q);
1444 gcry_mpi_release (d);
1446 /* finally, convert point to string for hashing */
1447 ret = point_to_hash (result,
1450 gcry_mpi_point_release (result);
1451 gcry_ctx_release (ctx);
1459 * Derive key material from a EdDSA public key and a private ECDH key.
1460 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1462 * @param priv private key to use for the ECDH (y)
1463 * @param pub public key from EdDSA to use for the ECDH (X=h(x)G)
1464 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1465 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1468 GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1469 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1470 struct GNUNET_HashCode *key_material)
1472 gcry_mpi_point_t result;
1476 gcry_sexp_t pub_sexpr;
1479 /* first, extract the q = dP value from the public key */
1480 if (0 != gcry_sexp_build (&pub_sexpr, NULL,
1481 "(public-key(ecc(curve " CURVE ")(q %b)))",
1482 (int)sizeof (pub->q_y), pub->q_y))
1483 return GNUNET_SYSERR;
1484 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
1485 gcry_sexp_release (pub_sexpr);
1486 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1488 /* second, extract the d value from our private key */
1489 GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
1491 /* then call the 'multiply' function, to compute the product */
1492 result = gcry_mpi_point_new (0);
1493 gcry_mpi_ec_mul (result, d, q, ctx);
1494 gcry_mpi_point_release (q);
1495 gcry_mpi_release (d);
1497 /* finally, convert point to string for hashing */
1498 ret = point_to_hash (result,
1501 gcry_mpi_point_release (result);
1502 gcry_ctx_release (ctx);
1508 * Derive key material from a ECDSA public key and a private ECDH key.
1509 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1511 * @param priv private key to use for the ECDH (y)
1512 * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
1513 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1514 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1517 GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1518 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1519 struct GNUNET_HashCode *key_material)
1521 return GNUNET_CRYPTO_ecdh_eddsa (priv,
1522 (const struct GNUNET_CRYPTO_EddsaPublicKey *)pub,
1526 /* end of crypto_ecc.c */