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
25 * @author Florian Dold
30 #include "gnunet_crypto_lib.h"
31 #include "gnunet_strings_lib.h"
32 #include "benchmark.h"
34 #define EXTRA_CHECKS 0
38 * Name of the curve we are using. Note that we have hard-coded
39 * structs that use 256 bits, so using a bigger curve will require
40 * changes that break stuff badly. The name of the curve given here
41 * must be agreed by all peers and be supported by libgcrypt.
43 #define CURVE "Ed25519"
45 #define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
47 #define LOG_STRERROR(kind, syscall) \
48 GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
50 #define LOG_STRERROR_FILE(kind, syscall, filename) \
51 GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
54 * Log an error message at log-level 'level' that indicates
55 * a failure of the command 'cmd' with the message given
56 * by gcry_strerror(rc).
58 #define LOG_GCRY(level, cmd, rc) \
62 _ ("`%s' failed at %s:%d with error: %s\n"), \
66 gcry_strerror (rc)); \
71 * Extract values from an S-expression.
73 * @param array where to store the result(s)
74 * @param sexp S-expression to parse
75 * @param topname top-level name in the S-expression that is of interest
76 * @param elems names of the elements to extract
77 * @return 0 on success
80 key_from_sexp (gcry_mpi_t *array,
89 list = gcry_sexp_find_token (sexp, topname, 0);
92 l2 = gcry_sexp_cadr (list);
93 gcry_sexp_release (list);
99 for (const char *s = elems; *s; s++, idx++)
101 l2 = gcry_sexp_find_token (list, s, 1);
104 for (unsigned int i = 0; i < idx; i++)
106 gcry_free (array[i]);
109 gcry_sexp_release (list);
110 return 3; /* required parameter not found */
112 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
113 gcry_sexp_release (l2);
116 for (unsigned int i = 0; i < idx; i++)
118 gcry_free (array[i]);
121 gcry_sexp_release (list);
122 return 4; /* required parameter is invalid */
125 gcry_sexp_release (list);
131 * Convert the given private key from the network format to the
132 * S-expression that can be used by libgcrypt.
134 * @param priv private key to decode
135 * @return NULL on error
138 decode_private_ecdsa_key (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
144 for (size_t i=0; i<32; i++)
145 d[i] = priv->d[31 - i];
147 rc = gcry_sexp_build (&result,
149 "(private-key(ecc(curve \"" CURVE "\")"
155 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
159 if (0 != (rc = gcry_pk_testkey (result)))
161 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
170 * Extract the public key for the given private key.
172 * @param priv the private key
173 * @param pub where to write the public key
176 GNUNET_CRYPTO_ecdsa_key_get_public (
177 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
178 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
180 BENCHMARK_START (ecdsa_key_get_public);
181 crypto_scalarmult_ed25519_base_noclamp (pub->q_y, priv->d);
182 BENCHMARK_END (ecdsa_key_get_public);
187 * Extract the public key for the given private key.
189 * @param priv the private key
190 * @param pub where to write the public key
193 GNUNET_CRYPTO_eddsa_key_get_public (
194 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
195 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
197 unsigned char pk[crypto_sign_PUBLICKEYBYTES];
198 unsigned char sk[crypto_sign_SECRETKEYBYTES];
200 BENCHMARK_START (eddsa_key_get_public);
201 GNUNET_assert (0 == crypto_sign_seed_keypair (pk, sk, priv->d));
202 GNUNET_memcpy (pub->q_y, pk, crypto_sign_PUBLICKEYBYTES);
203 sodium_memzero (sk, crypto_sign_SECRETKEYBYTES);
204 BENCHMARK_END (eddsa_key_get_public);
209 * Extract the public key for the given private key.
211 * @param priv the private key
212 * @param pub where to write the public key
215 GNUNET_CRYPTO_ecdhe_key_get_public (
216 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
217 struct GNUNET_CRYPTO_EcdhePublicKey *pub)
219 BENCHMARK_START (ecdhe_key_get_public);
220 GNUNET_assert (0 == crypto_scalarmult_base (pub->q_y, priv->d));
221 BENCHMARK_END (ecdhe_key_get_public);
226 * Convert a public key to a string.
228 * @param pub key to convert
229 * @return string representing @a pub
232 GNUNET_CRYPTO_ecdsa_public_key_to_string (
233 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
236 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
240 keylen += 5 - keylen % 5;
242 pubkeybuf = GNUNET_malloc (keylen + 1);
244 GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
245 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
250 GNUNET_free (pubkeybuf);
259 * Convert a public key to a string.
261 * @param pub key to convert
262 * @return string representing @a pub
265 GNUNET_CRYPTO_eddsa_public_key_to_string (
266 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
269 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
273 keylen += 5 - keylen % 5;
275 pubkeybuf = GNUNET_malloc (keylen + 1);
277 GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
278 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
283 GNUNET_free (pubkeybuf);
292 * Convert a private key to a string.
294 * @param priv key to convert
295 * @return string representing @a pub
298 GNUNET_CRYPTO_eddsa_private_key_to_string (
299 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
302 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
306 keylen += 5 - keylen % 5;
308 privkeybuf = GNUNET_malloc (keylen + 1);
309 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
311 struct GNUNET_CRYPTO_EddsaPrivateKey),
316 GNUNET_free (privkeybuf);
325 * Convert a private key to a string.
327 * @param priv key to convert
328 * @return string representing @a priv
331 GNUNET_CRYPTO_ecdsa_private_key_to_string (
332 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
335 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey)) * 8;
339 keylen += 5 - keylen % 5;
341 privkeybuf = GNUNET_malloc (keylen + 1);
342 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
344 struct GNUNET_CRYPTO_EcdsaPrivateKey),
349 GNUNET_free (privkeybuf);
358 * Convert a string representing a public key to a public key.
360 * @param enc encoded public key
361 * @param enclen number of bytes in @a enc (without 0-terminator)
362 * @param pub where to store the public key
363 * @return #GNUNET_OK on success
366 GNUNET_CRYPTO_ecdsa_public_key_from_string (
369 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
371 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
374 keylen += 5 - keylen % 5;
376 if (enclen != keylen)
377 return GNUNET_SYSERR;
380 GNUNET_STRINGS_string_to_data (enc,
384 struct GNUNET_CRYPTO_EcdsaPublicKey)))
385 return GNUNET_SYSERR;
391 * Convert a string representing a public key to a public key.
393 * @param enc encoded public key
394 * @param enclen number of bytes in @a enc (without 0-terminator)
395 * @param pub where to store the public key
396 * @return #GNUNET_OK on success
399 GNUNET_CRYPTO_eddsa_public_key_from_string (
402 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
404 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
407 keylen += 5 - keylen % 5;
409 if (enclen != keylen)
410 return GNUNET_SYSERR;
413 GNUNET_STRINGS_string_to_data (enc,
417 struct GNUNET_CRYPTO_EddsaPublicKey)))
418 return GNUNET_SYSERR;
424 * Convert a string representing a private key to a private key.
426 * @param enc encoded public key
427 * @param enclen number of bytes in @a enc (without 0-terminator)
428 * @param priv where to store the private key
429 * @return #GNUNET_OK on success
432 GNUNET_CRYPTO_eddsa_private_key_from_string (
435 struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
437 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
440 keylen += 5 - keylen % 5;
442 if (enclen != keylen)
443 return GNUNET_SYSERR;
446 GNUNET_STRINGS_string_to_data (enc,
450 struct GNUNET_CRYPTO_EddsaPrivateKey)))
451 return GNUNET_SYSERR;
453 if (GNUNET_OK != check_eddsa_key (priv))
465 * Clear memory that was used to store a private key.
467 * @param pk location of the key
470 GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
472 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
478 * Clear memory that was used to store a private key.
480 * @param pk location of the key
483 GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
485 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey));
491 * Clear memory that was used to store a private key.
493 * @param pk location of the key
496 GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
498 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey));
503 * Create a new private key.
505 * @param[out] pk fresh private key
508 GNUNET_CRYPTO_ecdhe_key_create (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
510 BENCHMARK_START (ecdhe_key_create);
511 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
513 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
514 BENCHMARK_END (ecdhe_key_create);
519 * Create a new private key.
521 * @param[out] pk private key to initialize
524 GNUNET_CRYPTO_ecdsa_key_create (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
526 BENCHMARK_START (ecdsa_key_create);
527 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
529 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey));
534 BENCHMARK_END (ecdsa_key_create);
539 * Create a new private key.
541 * @param[out] pk set to fresh private key
544 GNUNET_CRYPTO_eddsa_key_create (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
546 BENCHMARK_START (eddsa_key_create);
547 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
549 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
550 // FIXME: should we not do the clamping here? Or is this done elsewhere?
551 BENCHMARK_END (eddsa_key_create);
556 * Get the shared private key we use for anonymous users.
558 * @return "anonymous" private key
560 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
561 GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
564 * 'anonymous' pseudonym (global static, d=1, public key = G
567 static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
572 GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
581 * Convert the data specified in the given purpose argument to an
582 * S-expression suitable for signature operations.
584 * @param purpose data to convert
585 * @return converted s-expression
588 data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
595 struct GNUNET_HashCode hc;
597 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
598 if (0 != (rc = gcry_sexp_build (&data,
600 "(data(flags rfc6979)(hash %s %b))",
605 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
609 if (0 != (rc = gcry_sexp_build (&data,
611 "(data(flags rfc6979)(hash %s %b))",
613 ntohl (purpose->size),
616 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
625 * Sign a given block. The @a purpose data is the
626 * beginning of the data of which the signature is to be
627 * created. The `size` field in @a purpose must correctly
628 * indicate the number of bytes of the data structure, including
631 * @param priv private key to use for the signing
632 * @param purpose what to sign (size, purpose)
633 * @param sig where to write the signature
634 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
637 GNUNET_CRYPTO_ecdsa_sign_ (
638 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
639 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
640 struct GNUNET_CRYPTO_EcdsaSignature *sig)
642 gcry_sexp_t priv_sexp;
643 gcry_sexp_t sig_sexp;
648 BENCHMARK_START (ecdsa_sign);
650 priv_sexp = decode_private_ecdsa_key (priv);
651 data = data_to_ecdsa_value (purpose);
652 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
654 LOG (GNUNET_ERROR_TYPE_WARNING,
655 _ ("ECC signing failed at %s:%d: %s\n"),
659 gcry_sexp_release (data);
660 gcry_sexp_release (priv_sexp);
661 return GNUNET_SYSERR;
663 gcry_sexp_release (priv_sexp);
664 gcry_sexp_release (data);
666 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
668 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
671 gcry_sexp_release (sig_sexp);
672 return GNUNET_SYSERR;
674 gcry_sexp_release (sig_sexp);
675 GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof(sig->r), rs[0]);
676 GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof(sig->s), rs[1]);
677 gcry_mpi_release (rs[0]);
678 gcry_mpi_release (rs[1]);
680 BENCHMARK_END (ecdsa_sign);
687 * Sign a given block. The @a purpose data is the
688 * beginning of the data of which the signature is to be
689 * created. The `size` field in @a purpose must correctly
690 * indicate the number of bytes of the data structure, including
693 * @param priv private key to use for the signing
694 * @param purpose what to sign (size, purpose)
695 * @param sig where to write the signature
696 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
699 GNUNET_CRYPTO_eddsa_sign_ (
700 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
701 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
702 struct GNUNET_CRYPTO_EddsaSignature *sig)
705 size_t mlen = ntohl (purpose->size);
706 unsigned char sk[crypto_sign_SECRETKEYBYTES];
707 unsigned char pk[crypto_sign_PUBLICKEYBYTES];
710 BENCHMARK_START (eddsa_sign);
711 GNUNET_assert (0 == crypto_sign_seed_keypair (pk, sk, priv->d));
712 res = crypto_sign_detached ((uint8_t *) sig,
717 BENCHMARK_END (eddsa_sign);
718 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
723 * Verify signature. The @a validate data is the
724 * beginning of the data of which the signature is to be
725 * verified. The `size` field in @a validate must correctly
726 * indicate the number of bytes of the data structure, including
727 * its header. If @a purpose does not match the purpose given
728 * in @a validate (the latter
730 * @param purpose what is the purpose that the signature should have?
731 * @param validate block to validate (size, purpose, data)
732 * @param sig signature that is being validated
733 * @param pub public key of the signer
734 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
737 GNUNET_CRYPTO_ecdsa_verify_ (
739 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
740 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
741 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
744 gcry_sexp_t sig_sexpr;
745 gcry_sexp_t pub_sexpr;
748 BENCHMARK_START (ecdsa_verify);
750 if (purpose != ntohl (validate->purpose))
751 return GNUNET_SYSERR; /* purpose mismatch */
753 /* build s-expression for signature */
754 if (0 != (rc = gcry_sexp_build (&sig_sexpr,
756 "(sig-val(ecdsa(r %b)(s %b)))",
757 (int) sizeof(sig->r),
759 (int) sizeof(sig->s),
762 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
763 return GNUNET_SYSERR;
765 data = data_to_ecdsa_value (validate);
766 if (0 != (rc = gcry_sexp_build (&pub_sexpr,
768 "(public-key(ecc(curve " CURVE ")(q %b)))",
769 (int) sizeof(pub->q_y),
772 gcry_sexp_release (data);
773 gcry_sexp_release (sig_sexpr);
774 return GNUNET_SYSERR;
776 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
777 gcry_sexp_release (pub_sexpr);
778 gcry_sexp_release (data);
779 gcry_sexp_release (sig_sexpr);
782 LOG (GNUNET_ERROR_TYPE_INFO,
783 _ ("ECDSA signature verification failed at %s:%d: %s\n"),
787 BENCHMARK_END (ecdsa_verify);
788 return GNUNET_SYSERR;
790 BENCHMARK_END (ecdsa_verify);
796 * Verify signature. The @a validate data is the
797 * beginning of the data of which the signature is to be
798 * verified. The `size` field in @a validate must correctly
799 * indicate the number of bytes of the data structure, including
800 * its header. If @a purpose does not match the purpose given
801 * in @a validate (the latter must be in big endian), signature
802 * verification fails.
804 * @param purpose what is the purpose that the signature should have?
805 * @param validate block to validate (size, purpose, data)
806 * @param sig signature that is being validated
807 * @param pub public key of the signer
808 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
811 GNUNET_CRYPTO_eddsa_verify_ (
813 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
814 const struct GNUNET_CRYPTO_EddsaSignature *sig,
815 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
817 const unsigned char *m = (const void *) validate;
818 size_t mlen = ntohl (validate->size);
819 const unsigned char *s = (const void *) sig;
823 if (purpose != ntohl (validate->purpose))
824 return GNUNET_SYSERR; /* purpose mismatch */
826 BENCHMARK_START (eddsa_verify);
827 res = crypto_sign_verify_detached (s, m, mlen, pub->q_y);
828 BENCHMARK_END (eddsa_verify);
829 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
834 * Derive key material from a public and a private ECDHE key.
836 * @param priv private key to use for the ECDH (x)
837 * @param pub public key to use for the ECDH (yG)
838 * @param key_material where to write the key material (xyG)
839 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
842 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
843 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
844 struct GNUNET_HashCode *key_material)
846 uint8_t p[crypto_scalarmult_BYTES];
847 if (0 != crypto_scalarmult (p, priv->d, pub->q_y))
848 return GNUNET_SYSERR;
849 GNUNET_CRYPTO_hash (p, crypto_scalarmult_BYTES, key_material);
855 * Derive the 'h' value for key derivation, where
858 * @param pub public key for deriviation
859 * @param label label for deriviation
860 * @param context additional context to use for HKDF of 'h';
861 * typically the name of the subsystem/application
865 derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
870 struct GNUNET_HashCode hc;
871 static const char *const salt = "key-derivation";
873 GNUNET_CRYPTO_kdf (&hc,
885 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
891 * Derive a private key from a given private key and a label.
892 * Essentially calculates a private key 'd = H(l,P) * x mod n'
893 * where n is the size of the ECC group and P is the public
894 * key associated with the private key 'd'.
896 * @param priv original private key
897 * @param label label to use for key deriviation
898 * @param context additional context to use for HKDF of 'h';
899 * typically the name of the subsystem/application
900 * @return derived private key
902 struct GNUNET_CRYPTO_EcdsaPrivateKey *
903 GNUNET_CRYPTO_ecdsa_private_key_derive (
904 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
908 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
909 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
917 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
919 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
920 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
922 h = derive_h (&pub, label, context);
923 /* Convert to big endian for libgcrypt */
924 for (size_t i=0; i < 32; i++)
925 dc[i] = priv->d[31 - i];
926 GNUNET_CRYPTO_mpi_scan_unsigned (&x, dc, sizeof(dc));
927 d = gcry_mpi_new (256);
928 gcry_mpi_mulm (d, h, x, n);
929 gcry_mpi_release (h);
930 gcry_mpi_release (x);
931 gcry_mpi_release (n);
932 gcry_ctx_release (ctx);
933 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
934 GNUNET_CRYPTO_mpi_print_unsigned (dc, sizeof(dc), d);
935 /* Convert to big endian for libgcrypt */
936 for (size_t i=0; i < 32; i++)
937 ret->d[i] = dc[31 - i];
938 sodium_memzero(dc, sizeof(dc));
939 gcry_mpi_release (d);
945 * Derive a public key from a given public key and a label.
946 * Essentially calculates a public key 'V = H(l,P) * P'.
948 * @param pub original public key
949 * @param label label to use for key derivation
950 * @param context additional context to use for HKDF of 'h';
951 * typically the name of the subsystem/application
952 * @param result where to write the derived public key
955 GNUNET_CRYPTO_ecdsa_public_key_derive (
956 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
959 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
969 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
971 /* obtain point 'q' from original public key. The provided 'q' is
972 compressed thus we first store it in the context and then get it
973 back as a (decompresssed) point. */
974 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
975 GNUNET_assert (NULL != q_y);
976 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
977 gcry_mpi_release (q_y);
978 q = gcry_mpi_ec_get_point ("q", ctx, 0);
981 /* calculate h_mod_n = h % n */
982 h = derive_h (pub, label, context);
983 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
984 h_mod_n = gcry_mpi_new (256);
985 gcry_mpi_mod (h_mod_n, h, n);
986 /* calculate v = h_mod_n * q */
987 v = gcry_mpi_point_new (0);
988 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
989 gcry_mpi_release (h_mod_n);
990 gcry_mpi_release (h);
991 gcry_mpi_release (n);
992 gcry_mpi_point_release (q);
994 /* convert point 'v' to public key that we return */
995 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
996 gcry_mpi_point_release (v);
997 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
999 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
1000 gcry_mpi_release (q_y);
1001 gcry_ctx_release (ctx);
1007 * Derive key material from a ECDH public key and a private EdDSA key.
1008 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1010 * @param priv private key from EdDSA to use for the ECDH (x)
1011 * @param pub public key to use for the ECDH (yG)
1012 * @param key_material where to write the key material H(h(x)yG)
1013 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1016 GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1017 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1018 struct GNUNET_HashCode *key_material)
1020 struct GNUNET_HashCode hc;
1021 uint8_t a[crypto_scalarmult_SCALARBYTES];
1022 uint8_t p[crypto_scalarmult_BYTES];
1024 GNUNET_CRYPTO_hash (priv,
1025 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
1027 memcpy (a, &hc, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1028 if (0 != crypto_scalarmult (p, a, pub->q_y))
1029 return GNUNET_SYSERR;
1030 GNUNET_CRYPTO_hash (p,
1031 crypto_scalarmult_BYTES,
1039 * Derive key material from a ECDH public key and a private ECDSA key.
1040 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1042 * @param priv private key from ECDSA to use for the ECDH (x)
1043 * @param pub public key to use for the ECDH (yG)
1044 * @param key_material where to write the key material H(h(x)yG)
1045 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1048 GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1049 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1050 struct GNUNET_HashCode *key_material)
1052 uint8_t p[crypto_scalarmult_BYTES];
1054 BENCHMARK_START (ecdsa_ecdh);
1055 if (0 != crypto_scalarmult (p, priv->d, pub->q_y))
1056 return GNUNET_SYSERR;
1057 GNUNET_CRYPTO_hash (p,
1058 crypto_scalarmult_BYTES,
1060 BENCHMARK_END (ecdsa_ecdh);
1067 * Derive key material from a EdDSA public key and a private ECDH key.
1068 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1070 * @param priv private key to use for the ECDH (y)
1071 * @param pub public key from EdDSA to use for the ECDH (X=h(x)G)
1072 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1073 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1076 GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1077 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1078 struct GNUNET_HashCode *key_material)
1080 uint8_t p[crypto_scalarmult_BYTES];
1081 uint8_t curve25510_pk[crypto_scalarmult_BYTES];
1083 if (0 != crypto_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y))
1084 return GNUNET_SYSERR;
1085 if (0 != crypto_scalarmult (p, priv->d, curve25510_pk))
1086 return GNUNET_SYSERR;
1087 GNUNET_CRYPTO_hash (p, crypto_scalarmult_BYTES, key_material);
1094 * Derive key material from a ECDSA public key and a private ECDH key.
1095 * Dual to #GNUNET_CRYPTO_ecdsa_ecdh.
1097 * @param priv private key to use for the ECDH (y)
1098 * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
1099 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1100 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1103 GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1104 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1105 struct GNUNET_HashCode *key_material)
1107 uint8_t p[crypto_scalarmult_BYTES];
1108 uint8_t curve25510_pk[crypto_scalarmult_BYTES];
1110 if (0 != crypto_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y))
1111 return GNUNET_SYSERR;
1112 if (0 != crypto_scalarmult (p, priv->d, curve25510_pk))
1113 return GNUNET_SYSERR;
1114 GNUNET_CRYPTO_hash (p, crypto_scalarmult_BYTES, key_material);
1119 /* end of crypto_ecc.c */