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
29 #include "gnunet_crypto_lib.h"
30 #include "gnunet_strings_lib.h"
31 #include "benchmark.h"
32 #include "tweetnacl-gnunet.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)
143 rc = gcry_sexp_build (&result,
145 "(private-key(ecc(curve \"" CURVE "\")"
147 (int) sizeof(priv->d),
151 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
155 if (0 != (rc = gcry_pk_testkey (result)))
157 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
166 * Extract the public key for the given private key.
168 * @param priv the private key
169 * @param pub where to write the public key
172 GNUNET_CRYPTO_ecdsa_key_get_public (
173 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
174 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
176 BENCHMARK_START (ecdsa_key_get_public);
177 GNUNET_TWEETNACL_scalarmult_gnunet_ecdsa (pub->q_y, priv->d);
178 BENCHMARK_END (ecdsa_key_get_public);
183 * Extract the public key for the given private key.
185 * @param priv the private key
186 * @param pub where to write the public key
189 GNUNET_CRYPTO_eddsa_key_get_public (
190 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
191 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
193 BENCHMARK_START (eddsa_key_get_public);
194 GNUNET_TWEETNACL_sign_pk_from_seed (pub->q_y, priv->d);
195 BENCHMARK_END (eddsa_key_get_public);
200 * Extract the public key for the given private key.
202 * @param priv the private key
203 * @param pub where to write the public key
206 GNUNET_CRYPTO_ecdhe_key_get_public (
207 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
208 struct GNUNET_CRYPTO_EcdhePublicKey *pub)
210 BENCHMARK_START (ecdhe_key_get_public);
211 GNUNET_TWEETNACL_scalarmult_curve25519_base (pub->q_y, priv->d);
212 BENCHMARK_END (ecdhe_key_get_public);
217 * Convert a public key to a string.
219 * @param pub key to convert
220 * @return string representing @a pub
223 GNUNET_CRYPTO_ecdsa_public_key_to_string (
224 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
227 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
231 keylen += 5 - keylen % 5;
233 pubkeybuf = GNUNET_malloc (keylen + 1);
235 GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
236 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey),
241 GNUNET_free (pubkeybuf);
250 * Convert a public key to a string.
252 * @param pub key to convert
253 * @return string representing @a pub
256 GNUNET_CRYPTO_eddsa_public_key_to_string (
257 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
260 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
264 keylen += 5 - keylen % 5;
266 pubkeybuf = GNUNET_malloc (keylen + 1);
268 GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
269 sizeof(struct GNUNET_CRYPTO_EddsaPublicKey),
274 GNUNET_free (pubkeybuf);
283 * Convert a private key to a string.
285 * @param priv key to convert
286 * @return string representing @a pub
289 GNUNET_CRYPTO_eddsa_private_key_to_string (
290 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
293 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
297 keylen += 5 - keylen % 5;
299 privkeybuf = GNUNET_malloc (keylen + 1);
300 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
302 struct GNUNET_CRYPTO_EddsaPrivateKey),
307 GNUNET_free (privkeybuf);
316 * Convert a private key to a string.
318 * @param priv key to convert
319 * @return string representing @a priv
322 GNUNET_CRYPTO_ecdsa_private_key_to_string (
323 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv)
326 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey)) * 8;
330 keylen += 5 - keylen % 5;
332 privkeybuf = GNUNET_malloc (keylen + 1);
333 end = GNUNET_STRINGS_data_to_string ((unsigned char *) priv,
335 struct GNUNET_CRYPTO_EcdsaPrivateKey),
340 GNUNET_free (privkeybuf);
349 * Convert a string representing a public key to a public key.
351 * @param enc encoded public key
352 * @param enclen number of bytes in @a enc (without 0-terminator)
353 * @param pub where to store the public key
354 * @return #GNUNET_OK on success
357 GNUNET_CRYPTO_ecdsa_public_key_from_string (
360 struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
362 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)) * 8;
365 keylen += 5 - keylen % 5;
367 if (enclen != keylen)
368 return GNUNET_SYSERR;
371 GNUNET_STRINGS_string_to_data (enc,
375 struct GNUNET_CRYPTO_EcdsaPublicKey)))
376 return GNUNET_SYSERR;
382 * Convert a string representing a public key to a public key.
384 * @param enc encoded public key
385 * @param enclen number of bytes in @a enc (without 0-terminator)
386 * @param pub where to store the public key
387 * @return #GNUNET_OK on success
390 GNUNET_CRYPTO_eddsa_public_key_from_string (
393 struct GNUNET_CRYPTO_EddsaPublicKey *pub)
395 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) * 8;
398 keylen += 5 - keylen % 5;
400 if (enclen != keylen)
401 return GNUNET_SYSERR;
404 GNUNET_STRINGS_string_to_data (enc,
408 struct GNUNET_CRYPTO_EddsaPublicKey)))
409 return GNUNET_SYSERR;
415 * Convert a string representing a private key to a private key.
417 * @param enc encoded public key
418 * @param enclen number of bytes in @a enc (without 0-terminator)
419 * @param priv where to store the private key
420 * @return #GNUNET_OK on success
423 GNUNET_CRYPTO_eddsa_private_key_from_string (
426 struct GNUNET_CRYPTO_EddsaPrivateKey *priv)
428 size_t keylen = (sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey)) * 8;
431 keylen += 5 - keylen % 5;
433 if (enclen != keylen)
434 return GNUNET_SYSERR;
437 GNUNET_STRINGS_string_to_data (enc,
441 struct GNUNET_CRYPTO_EddsaPrivateKey)))
442 return GNUNET_SYSERR;
444 if (GNUNET_OK != check_eddsa_key (priv))
456 * Clear memory that was used to store a private key.
458 * @param pk location of the key
461 GNUNET_CRYPTO_ecdhe_key_clear (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
463 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdhePrivateKey));
469 * Clear memory that was used to store a private key.
471 * @param pk location of the key
474 GNUNET_CRYPTO_ecdsa_key_clear (struct GNUNET_CRYPTO_EcdsaPrivateKey *pk)
476 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EcdsaPrivateKey));
482 * Clear memory that was used to store a private key.
484 * @param pk location of the key
487 GNUNET_CRYPTO_eddsa_key_clear (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
489 memset (pk, 0, sizeof(struct GNUNET_CRYPTO_EddsaPrivateKey));
494 * Create a new private key. Caller must free return value.
496 * @return fresh private key
498 struct GNUNET_CRYPTO_EcdhePrivateKey *
499 GNUNET_CRYPTO_ecdhe_key_create ()
501 struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
503 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
504 if (GNUNET_OK != GNUNET_CRYPTO_ecdhe_key_create2 (priv))
515 * Create a new private key. Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
517 * @param[out] pk set to fresh private key;
518 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
521 GNUNET_CRYPTO_ecdhe_key_create2 (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
523 BENCHMARK_START (ecdhe_key_create);
524 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
526 sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
527 BENCHMARK_END (ecdhe_key_create);
533 * Create a new private key. Caller must free return value.
535 * @return fresh private key
537 struct GNUNET_CRYPTO_EcdsaPrivateKey *
538 GNUNET_CRYPTO_ecdsa_key_create ()
540 struct GNUNET_CRYPTO_EcdsaPrivateKey *priv;
541 gcry_sexp_t priv_sexp;
542 gcry_sexp_t s_keyparam;
546 BENCHMARK_START (ecdsa_key_create);
548 if (0 != (rc = gcry_sexp_build (&s_keyparam,
550 "(genkey(ecc(curve \"" CURVE "\")"
553 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
556 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
558 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
559 gcry_sexp_release (s_keyparam);
562 gcry_sexp_release (s_keyparam);
564 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
566 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
567 gcry_sexp_release (priv_sexp);
571 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
573 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
574 gcry_sexp_release (priv_sexp);
577 gcry_sexp_release (priv_sexp);
578 priv = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
579 GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof(priv->d), d);
580 gcry_mpi_release (d);
582 BENCHMARK_END (ecdsa_key_create);
589 * Create a new private key. Caller must free return value.
591 * @return fresh private key
593 struct GNUNET_CRYPTO_EddsaPrivateKey *
594 GNUNET_CRYPTO_eddsa_key_create ()
596 struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
598 BENCHMARK_START (eddsa_key_create);
599 priv = GNUNET_new (struct GNUNET_CRYPTO_EddsaPrivateKey);
600 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
602 sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey));
603 BENCHMARK_END (eddsa_key_create);
610 * Get the shared private key we use for anonymous users.
612 * @return "anonymous" private key
614 const struct GNUNET_CRYPTO_EcdsaPrivateKey *
615 GNUNET_CRYPTO_ecdsa_key_get_anonymous ()
618 * 'anonymous' pseudonym (global static, d=1, public key = G
621 static struct GNUNET_CRYPTO_EcdsaPrivateKey anonymous;
626 GNUNET_CRYPTO_mpi_print_unsigned (anonymous.d,
635 * Convert the data specified in the given purpose argument to an
636 * S-expression suitable for signature operations.
638 * @param purpose data to convert
639 * @return converted s-expression
642 data_to_ecdsa_value (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
649 struct GNUNET_HashCode hc;
651 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
652 if (0 != (rc = gcry_sexp_build (&data,
654 "(data(flags rfc6979)(hash %s %b))",
659 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
663 if (0 != (rc = gcry_sexp_build (&data,
665 "(data(flags rfc6979)(hash %s %b))",
667 ntohl (purpose->size),
670 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
679 * Sign a given block. The @a purpose data is the
680 * beginning of the data of which the signature is to be
681 * created. The `size` field in @a purpose must correctly
682 * indicate the number of bytes of the data structure, including
685 * @param priv private key to use for the signing
686 * @param purpose what to sign (size, purpose)
687 * @param sig where to write the signature
688 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
691 GNUNET_CRYPTO_ecdsa_sign_ (
692 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
693 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
694 struct GNUNET_CRYPTO_EcdsaSignature *sig)
696 gcry_sexp_t priv_sexp;
697 gcry_sexp_t sig_sexp;
702 BENCHMARK_START (ecdsa_sign);
704 priv_sexp = decode_private_ecdsa_key (priv);
705 data = data_to_ecdsa_value (purpose);
706 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
708 LOG (GNUNET_ERROR_TYPE_WARNING,
709 _ ("ECC signing failed at %s:%d: %s\n"),
713 gcry_sexp_release (data);
714 gcry_sexp_release (priv_sexp);
715 return GNUNET_SYSERR;
717 gcry_sexp_release (priv_sexp);
718 gcry_sexp_release (data);
720 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
722 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
725 gcry_sexp_release (sig_sexp);
726 return GNUNET_SYSERR;
728 gcry_sexp_release (sig_sexp);
729 GNUNET_CRYPTO_mpi_print_unsigned (sig->r, sizeof(sig->r), rs[0]);
730 GNUNET_CRYPTO_mpi_print_unsigned (sig->s, sizeof(sig->s), rs[1]);
731 gcry_mpi_release (rs[0]);
732 gcry_mpi_release (rs[1]);
734 BENCHMARK_END (ecdsa_sign);
741 * Sign a given block. The @a purpose data is the
742 * beginning of the data of which the signature is to be
743 * created. The `size` field in @a purpose must correctly
744 * indicate the number of bytes of the data structure, including
747 * @param priv private key to use for the signing
748 * @param purpose what to sign (size, purpose)
749 * @param sig where to write the signature
750 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
753 GNUNET_CRYPTO_eddsa_sign_ (
754 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
755 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
756 struct GNUNET_CRYPTO_EddsaSignature *sig)
759 size_t mlen = ntohl (purpose->size);
760 unsigned char sk[GNUNET_TWEETNACL_SIGN_SECRETKEYBYTES];
763 BENCHMARK_START (eddsa_sign);
764 GNUNET_TWEETNACL_sign_sk_from_seed (sk, priv->d);
765 res = GNUNET_TWEETNACL_sign_detached ((uint8_t *) sig,
769 BENCHMARK_END (eddsa_sign);
770 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
775 * Verify signature. The @a validate data is the
776 * beginning of the data of which the signature is to be
777 * verified. The `size` field in @a validate must correctly
778 * indicate the number of bytes of the data structure, including
779 * its header. If @a purpose does not match the purpose given
780 * in @a validate (the latter
782 * @param purpose what is the purpose that the signature should have?
783 * @param validate block to validate (size, purpose, data)
784 * @param sig signature that is being validated
785 * @param pub public key of the signer
786 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
789 GNUNET_CRYPTO_ecdsa_verify_ (
791 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
792 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
793 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub)
796 gcry_sexp_t sig_sexpr;
797 gcry_sexp_t pub_sexpr;
800 BENCHMARK_START (ecdsa_verify);
802 if (purpose != ntohl (validate->purpose))
803 return GNUNET_SYSERR; /* purpose mismatch */
805 /* build s-expression for signature */
806 if (0 != (rc = gcry_sexp_build (&sig_sexpr,
808 "(sig-val(ecdsa(r %b)(s %b)))",
809 (int) sizeof(sig->r),
811 (int) sizeof(sig->s),
814 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
815 return GNUNET_SYSERR;
817 data = data_to_ecdsa_value (validate);
818 if (0 != (rc = gcry_sexp_build (&pub_sexpr,
820 "(public-key(ecc(curve " CURVE ")(q %b)))",
821 (int) sizeof(pub->q_y),
824 gcry_sexp_release (data);
825 gcry_sexp_release (sig_sexpr);
826 return GNUNET_SYSERR;
828 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
829 gcry_sexp_release (pub_sexpr);
830 gcry_sexp_release (data);
831 gcry_sexp_release (sig_sexpr);
834 LOG (GNUNET_ERROR_TYPE_INFO,
835 _ ("ECDSA signature verification failed at %s:%d: %s\n"),
839 BENCHMARK_END (ecdsa_verify);
840 return GNUNET_SYSERR;
842 BENCHMARK_END (ecdsa_verify);
848 * Verify signature. The @a validate data is the
849 * beginning of the data of which the signature is to be
850 * verified. The `size` field in @a validate must correctly
851 * indicate the number of bytes of the data structure, including
852 * its header. If @a purpose does not match the purpose given
853 * in @a validate (the latter must be in big endian), signature
854 * verification fails.
856 * @param purpose what is the purpose that the signature should have?
857 * @param validate block to validate (size, purpose, data)
858 * @param sig signature that is being validated
859 * @param pub public key of the signer
860 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
863 GNUNET_CRYPTO_eddsa_verify_ (
865 const struct GNUNET_CRYPTO_EccSignaturePurpose *validate,
866 const struct GNUNET_CRYPTO_EddsaSignature *sig,
867 const struct GNUNET_CRYPTO_EddsaPublicKey *pub)
869 const unsigned char *m = (const void *) validate;
870 size_t mlen = ntohl (validate->size);
871 const unsigned char *s = (const void *) sig;
875 if (purpose != ntohl (validate->purpose))
876 return GNUNET_SYSERR; /* purpose mismatch */
878 BENCHMARK_START (eddsa_verify);
879 res = GNUNET_TWEETNACL_sign_detached_verify (s, m, mlen, pub->q_y);
880 BENCHMARK_END (eddsa_verify);
881 return (res == 0) ? GNUNET_OK : GNUNET_SYSERR;
886 * Derive key material from a public and a private ECDHE key.
888 * @param priv private key to use for the ECDH (x)
889 * @param pub public key to use for the ECDH (yG)
890 * @param key_material where to write the key material (xyG)
891 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
894 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
895 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
896 struct GNUNET_HashCode *key_material)
898 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
899 GNUNET_TWEETNACL_scalarmult_curve25519 (p, priv->d, pub->q_y);
900 GNUNET_CRYPTO_hash (p, GNUNET_TWEETNACL_SCALARMULT_BYTES, key_material);
906 * Derive the 'h' value for key derivation, where
909 * @param pub public key for deriviation
910 * @param label label for deriviation
911 * @param context additional context to use for HKDF of 'h';
912 * typically the name of the subsystem/application
916 derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
921 struct GNUNET_HashCode hc;
922 static const char *const salt = "key-derivation";
924 GNUNET_CRYPTO_kdf (&hc,
936 GNUNET_CRYPTO_mpi_scan_unsigned (&h, (unsigned char *) &hc, sizeof(hc));
942 * Derive a private key from a given private key and a label.
943 * Essentially calculates a private key 'd = H(l,P) * x mod n'
944 * where n is the size of the ECC group and P is the public
945 * key associated with the private key 'd'.
947 * @param priv original private key
948 * @param label label to use for key deriviation
949 * @param context additional context to use for HKDF of 'h';
950 * typically the name of the subsystem/application
951 * @return derived private key
953 struct GNUNET_CRYPTO_EcdsaPrivateKey *
954 GNUNET_CRYPTO_ecdsa_private_key_derive (
955 const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
959 struct GNUNET_CRYPTO_EcdsaPublicKey pub;
960 struct GNUNET_CRYPTO_EcdsaPrivateKey *ret;
967 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
969 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
970 GNUNET_CRYPTO_ecdsa_key_get_public (priv, &pub);
972 h = derive_h (&pub, label, context);
973 GNUNET_CRYPTO_mpi_scan_unsigned (&x, priv->d, sizeof(priv->d));
974 d = gcry_mpi_new (256);
975 gcry_mpi_mulm (d, h, x, n);
976 gcry_mpi_release (h);
977 gcry_mpi_release (x);
978 gcry_mpi_release (n);
979 gcry_ctx_release (ctx);
980 ret = GNUNET_new (struct GNUNET_CRYPTO_EcdsaPrivateKey);
981 GNUNET_CRYPTO_mpi_print_unsigned (ret->d, sizeof(ret->d), d);
982 gcry_mpi_release (d);
988 * Derive a public key from a given public key and a label.
989 * Essentially calculates a public key 'V = H(l,P) * P'.
991 * @param pub original public key
992 * @param label label to use for key derivation
993 * @param context additional context to use for HKDF of 'h';
994 * typically the name of the subsystem/application
995 * @param result where to write the derived public key
998 GNUNET_CRYPTO_ecdsa_public_key_derive (
999 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1001 const char *context,
1002 struct GNUNET_CRYPTO_EcdsaPublicKey *result)
1012 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1014 /* obtain point 'q' from original public key. The provided 'q' is
1015 compressed thus we first store it in the context and then get it
1016 back as a (decompresssed) point. */
1017 q_y = gcry_mpi_set_opaque_copy (NULL, pub->q_y, 8 * sizeof(pub->q_y));
1018 GNUNET_assert (NULL != q_y);
1019 GNUNET_assert (0 == gcry_mpi_ec_set_mpi ("q", q_y, ctx));
1020 gcry_mpi_release (q_y);
1021 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1024 /* calculate h_mod_n = h % n */
1025 h = derive_h (pub, label, context);
1026 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1027 h_mod_n = gcry_mpi_new (256);
1028 gcry_mpi_mod (h_mod_n, h, n);
1029 /* calculate v = h_mod_n * q */
1030 v = gcry_mpi_point_new (0);
1031 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1032 gcry_mpi_release (h_mod_n);
1033 gcry_mpi_release (h);
1034 gcry_mpi_release (n);
1035 gcry_mpi_point_release (q);
1037 /* convert point 'v' to public key that we return */
1038 GNUNET_assert (0 == gcry_mpi_ec_set_point ("q", v, ctx));
1039 gcry_mpi_point_release (v);
1040 q_y = gcry_mpi_ec_get_mpi ("q@eddsa", ctx, 0);
1041 GNUNET_assert (q_y);
1042 GNUNET_CRYPTO_mpi_print_unsigned (result->q_y, sizeof(result->q_y), q_y);
1043 gcry_mpi_release (q_y);
1044 gcry_ctx_release (ctx);
1050 * Derive key material from a ECDH public key and a private EdDSA key.
1051 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1053 * @param priv private key from EdDSA to use for the ECDH (x)
1054 * @param pub public key to use for the ECDH (yG)
1055 * @param key_material where to write the key material H(h(x)yG)
1056 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1059 GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
1060 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1061 struct GNUNET_HashCode *key_material)
1063 struct GNUNET_HashCode hc;
1064 uint8_t a[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1065 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1067 GNUNET_CRYPTO_hash (priv,
1068 sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey),
1070 memcpy (a, &hc, sizeof (struct GNUNET_CRYPTO_EcdhePrivateKey));
1071 GNUNET_TWEETNACL_scalarmult_curve25519 (p, a, pub->q_y);
1072 GNUNET_CRYPTO_hash (p,
1073 GNUNET_TWEETNACL_SCALARMULT_BYTES,
1081 * Derive key material from a ECDH public key and a private ECDSA key.
1082 * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
1084 * @param priv private key from ECDSA to use for the ECDH (x)
1085 * @param pub public key to use for the ECDH (yG)
1086 * @param key_material where to write the key material H(h(x)yG)
1087 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1090 GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
1091 const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
1092 struct GNUNET_HashCode *key_material)
1094 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1095 uint8_t d_rev[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1097 BENCHMARK_START (ecdsa_ecdh);
1098 for (size_t i = 0; i < 32; i++)
1099 d_rev[i] = priv->d[31 - i];
1100 GNUNET_TWEETNACL_scalarmult_curve25519 (p, d_rev, pub->q_y);
1101 GNUNET_CRYPTO_hash (p,
1102 GNUNET_TWEETNACL_SCALARMULT_BYTES,
1104 BENCHMARK_END (ecdsa_ecdh);
1111 * Derive key material from a EdDSA public key and a private ECDH key.
1112 * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
1114 * @param priv private key to use for the ECDH (y)
1115 * @param pub public key from EdDSA to use for the ECDH (X=h(x)G)
1116 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1117 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1120 GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1121 const struct GNUNET_CRYPTO_EddsaPublicKey *pub,
1122 struct GNUNET_HashCode *key_material)
1124 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1125 uint8_t curve25510_pk[GNUNET_TWEETNACL_SIGN_PUBLICBYTES];
1127 GNUNET_TWEETNACL_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y);
1128 GNUNET_TWEETNACL_scalarmult_curve25519 (p, priv->d, curve25510_pk);
1129 GNUNET_CRYPTO_hash (p, GNUNET_TWEETNACL_SCALARMULT_BYTES, key_material);
1136 * Derive key material from a ECDSA public key and a private ECDH key.
1137 * Dual to #GNUNET_CRYPTO_ecdsa_ecdh.
1139 * @param priv private key to use for the ECDH (y)
1140 * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
1141 * @param key_material where to write the key material H(yX)=H(h(x)yG)
1142 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
1145 GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
1146 const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
1147 struct GNUNET_HashCode *key_material)
1149 uint8_t p[GNUNET_TWEETNACL_SCALARMULT_BYTES];
1150 uint8_t curve25510_pk[GNUNET_TWEETNACL_SIGN_PUBLICBYTES];
1152 GNUNET_TWEETNACL_sign_ed25519_pk_to_curve25519 (curve25510_pk, pub->q_y);
1153 GNUNET_TWEETNACL_scalarmult_curve25519 (p, priv->d, curve25510_pk);
1154 GNUNET_CRYPTO_hash (p, GNUNET_TWEETNACL_SCALARMULT_BYTES, key_material);
1159 /* end of crypto_ecc.c */