2 This file is part of GNUnet.
3 (C) 2012, 2013 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
22 * @file util/crypto_ecc.c
23 * @brief public key cryptography (ECC) with libgcrypt
24 * @author Christian Grothoff
28 #include "gnunet_common.h"
29 #include "gnunet_util_lib.h"
31 #define EXTRA_CHECKS ALLOW_EXTRA_CHECKS
34 * Name of the curve we are using. Note that we have hard-coded
35 * structs that use 256 bits, so using a bigger curve will require
36 * changes that break stuff badly. The name of the curve given here
37 * must be agreed by all peers and be supported by libgcrypt.
39 * NOTE: this will change to Curve25519 before GNUnet 0.10.0.
41 #define CURVE "NIST P-256"
43 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
45 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
47 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
50 * Log an error message at log-level 'level' that indicates
51 * a failure of the command 'cmd' with the message given
52 * by gcry_strerror(rc).
54 #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)
58 * Extract values from an S-expression.
60 * @param array where to store the result(s)
61 * @param sexp S-expression to parse
62 * @param topname top-level name in the S-expression that is of interest
63 * @param elems names of the elements to extract
64 * @return 0 on success
67 key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
76 list = gcry_sexp_find_token (sexp, topname, 0);
79 l2 = gcry_sexp_cadr (list);
80 gcry_sexp_release (list);
86 for (s = elems; *s; s++, idx++)
88 l2 = gcry_sexp_find_token (list, s, 1);
91 for (i = 0; i < idx; i++)
96 gcry_sexp_release (list);
97 return 3; /* required parameter not found */
99 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
100 gcry_sexp_release (l2);
103 for (i = 0; i < idx; i++)
105 gcry_free (array[i]);
108 gcry_sexp_release (list);
109 return 4; /* required parameter is invalid */
112 gcry_sexp_release (list);
118 * If target != size, move @a target bytes to the end of the size-sized
119 * buffer and zero out the first @a target - @a size bytes.
121 * @param buf original buffer
122 * @param size number of bytes in @a buf
123 * @param target target size of the buffer
126 adjust (unsigned char *buf,
132 memmove (&buf[target - size], buf, size);
133 memset (buf, 0, target - size);
139 * Output the given MPI value to the given buffer.
141 * @param buf where to output to
142 * @param size number of bytes in @a buf
143 * @param val value to write to @a buf
146 mpi_print (unsigned char *buf,
154 gcry_mpi_print (GCRYMPI_FMT_USG, buf, rsize, &rsize,
156 adjust (buf, rsize, size);
161 * Convert data buffer into MPI value.
163 * @param result where to store MPI value (allocated)
164 * @param data raw data (GCRYMPI_FMT_USG)
165 * @param size number of bytes in data
168 mpi_scan (gcry_mpi_t *result,
169 const unsigned char *data,
174 if (0 != (rc = gcry_mpi_scan (result,
178 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
185 * Convert the given private key from the network format to the
186 * S-expression that can be used by libgcrypt.
188 * @param priv private key to decode
189 * @return NULL on error
192 decode_private_key (const struct GNUNET_CRYPTO_EccPrivateKey *priv)
201 rc = gcry_sexp_build (&result, NULL,
202 "(private-key(ecdsa(curve \"" CURVE "\")(d %m)))",
204 gcry_mpi_release (d);
207 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
211 if (0 != (rc = gcry_pk_testkey (result)))
213 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
222 * Initialize public key struct from the respective point
225 * @param q point on curve
226 * @param pub public key struct to initialize
227 * @param ctx context to use for ECC operations
230 point_to_public_sign_key (gcry_mpi_point_t q,
232 struct GNUNET_CRYPTO_EccPublicSignKey *pub)
237 q_x = gcry_mpi_new (256);
238 q_y = gcry_mpi_new (256);
239 if (gcry_mpi_ec_get_affine (q_x, q_y, q, ctx))
241 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
245 mpi_print (pub->q_x, sizeof (pub->q_x), q_x);
246 mpi_print (pub->q_y, sizeof (pub->q_y), q_y);
247 gcry_mpi_release (q_x);
248 gcry_mpi_release (q_y);
253 * Initialize public key struct from the respective point
256 * @param q point on curve
257 * @param pub public key struct to initialize
258 * @param ctx context to use for ECC operations
261 point_to_public_encrypt_key (gcry_mpi_point_t q,
263 struct GNUNET_CRYPTO_EccPublicEncryptKey *pub)
268 q_x = gcry_mpi_new (256);
269 q_y = gcry_mpi_new (256);
270 if (gcry_mpi_ec_get_affine (q_x, q_y, q, ctx))
272 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
276 mpi_print (pub->q_x, sizeof (pub->q_x), q_x);
277 mpi_print (pub->q_y, sizeof (pub->q_y), q_y);
278 gcry_mpi_release (q_x);
279 gcry_mpi_release (q_y);
284 * Extract the public key for the given private key.
286 * @param priv the private key
287 * @param pub where to write the public key
290 GNUNET_CRYPTO_ecc_key_get_public_for_signature (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
291 struct GNUNET_CRYPTO_EccPublicSignKey *pub)
297 sexp = decode_private_key (priv);
298 GNUNET_assert (NULL != sexp);
299 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
300 gcry_sexp_release (sexp);
301 q = gcry_mpi_ec_get_point ("q", ctx, 0);
302 point_to_public_sign_key (q, ctx, pub);
303 gcry_ctx_release (ctx);
304 gcry_mpi_point_release (q);
309 * Extract the public key for the given private key.
311 * @param priv the private key
312 * @param pub where to write the public key
315 GNUNET_CRYPTO_ecc_key_get_public_for_encryption (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
316 struct GNUNET_CRYPTO_EccPublicEncryptKey *pub)
322 sexp = decode_private_key (priv);
323 GNUNET_assert (NULL != sexp);
324 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
325 gcry_sexp_release (sexp);
326 q = gcry_mpi_ec_get_point ("q", ctx, 0);
327 point_to_public_encrypt_key (q, ctx, pub);
328 gcry_ctx_release (ctx);
329 gcry_mpi_point_release (q);
334 * Convert a public key to a string.
336 * @param pub key to convert
337 * @return string representing @a pub
340 GNUNET_CRYPTO_ecc_public_sign_key_to_string (const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
343 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)) * 8;
347 keylen += 5 - keylen % 5;
349 pubkeybuf = GNUNET_malloc (keylen + 1);
350 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
351 sizeof (struct GNUNET_CRYPTO_EccPublicSignKey),
356 GNUNET_free (pubkeybuf);
365 * Convert a string representing a public key to a public key.
367 * @param enc encoded public key
368 * @param enclen number of bytes in @a enc (without 0-terminator)
369 * @param pub where to store the public key
370 * @return #GNUNET_OK on success
373 GNUNET_CRYPTO_ecc_public_sign_key_from_string (const char *enc,
375 struct GNUNET_CRYPTO_EccPublicSignKey *pub)
377 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)) * 8;
380 keylen += 5 - keylen % 5;
382 if (enclen != keylen)
383 return GNUNET_SYSERR;
385 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
387 sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)))
388 return GNUNET_SYSERR;
394 * Convert the given public key from the network format to the
395 * S-expression that can be used by libgcrypt.
397 * @param pub public key to decode
398 * @return NULL on error
401 decode_public_sign_key (const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
403 gcry_sexp_t pub_sexp;
409 mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x));
410 mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
411 q = gcry_mpi_point_new (256);
412 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
413 gcry_mpi_release (q_x);
414 gcry_mpi_release (q_y);
416 /* initialize 'ctx' with 'q' */
417 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
418 gcry_mpi_ec_set_point ("q", q, ctx);
419 gcry_mpi_point_release (q);
421 /* convert 'ctx' to 'sexp' */
422 GNUNET_assert (0 == gcry_pubkey_get_sexp (&pub_sexp, GCRY_PK_GET_PUBKEY, ctx));
423 gcry_ctx_release (ctx);
430 * Clear memory that was used to store a private key.
432 * @param pk location of the key
435 GNUNET_CRYPTO_ecc_key_clear (struct GNUNET_CRYPTO_EccPrivateKey *pk)
437 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
442 * Create a new private key. Caller must free return value.
444 * @return fresh private key
446 struct GNUNET_CRYPTO_EccPrivateKey *
447 GNUNET_CRYPTO_ecc_key_create ()
449 struct GNUNET_CRYPTO_EccPrivateKey *priv;
450 gcry_sexp_t priv_sexp;
451 gcry_sexp_t s_keyparam;
455 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
456 "(genkey(ecdsa(curve \"" CURVE "\")))")))
458 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
461 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
463 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
464 gcry_sexp_release (s_keyparam);
467 gcry_sexp_release (s_keyparam);
469 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
471 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
472 gcry_sexp_release (priv_sexp);
476 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
478 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
479 gcry_sexp_release (priv_sexp);
482 gcry_sexp_release (priv_sexp);
483 priv = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
484 mpi_print (priv->d, sizeof (priv->d), d);
485 gcry_mpi_release (d);
491 * Get the shared private key we use for anonymous users.
493 * @return "anonymous" private key
495 const struct GNUNET_CRYPTO_EccPrivateKey *
496 GNUNET_CRYPTO_ecc_key_get_anonymous ()
499 * 'anonymous' pseudonym (global static, d=1, public key = G
502 static struct GNUNET_CRYPTO_EccPrivateKey anonymous;
507 mpi_print (anonymous.d,
508 sizeof (anonymous.d),
516 * Wait for a short time (we're trying to lock a file or want
517 * to give another process a shot at finishing a disk write, etc.).
518 * Sleeps for 100ms (as that should be long enough for virtually all
519 * modern systems to context switch and allow another process to do
525 struct GNUNET_TIME_Relative timeout;
527 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
528 (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
533 * Create a new private key by reading it from a file. If the
534 * files does not exist, create a new key and write it to the
535 * file. Caller must free return value. Note that this function
536 * can not guarantee that another process might not be trying
537 * the same operation on the same file at the same time.
538 * If the contents of the file
539 * are invalid the old file is deleted and a fresh key is
542 * @param filename name of file to use to store the key
543 * @return new private key, NULL on error (for example,
546 struct GNUNET_CRYPTO_EccPrivateKey *
547 GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
549 struct GNUNET_CRYPTO_EccPrivateKey *priv;
550 struct GNUNET_DISK_FileHandle *fd;
555 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
557 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
559 fd = GNUNET_DISK_file_open (filename,
560 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
561 | GNUNET_DISK_OPEN_FAILIFEXISTS,
562 GNUNET_DISK_PERM_USER_READ |
563 GNUNET_DISK_PERM_USER_WRITE);
568 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
570 /* must exist but not be accessible, fail for good! */
571 if (0 != ACCESS (filename, R_OK))
572 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
574 GNUNET_break (0); /* what is going on!? */
579 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
584 GNUNET_DISK_file_lock (fd, 0,
585 sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
592 LOG (GNUNET_ERROR_TYPE_ERROR,
593 _("Could not acquire lock on file `%s': %s...\n"), filename,
597 LOG (GNUNET_ERROR_TYPE_INFO,
598 _("Creating a new private key. This may take a while.\n"));
599 priv = GNUNET_CRYPTO_ecc_key_create ();
600 GNUNET_assert (NULL != priv);
601 GNUNET_assert (sizeof (*priv) ==
602 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
603 GNUNET_DISK_file_sync (fd);
605 GNUNET_DISK_file_unlock (fd, 0,
606 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
607 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
608 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
611 /* key file exists already, read it! */
612 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
613 GNUNET_DISK_PERM_NONE);
616 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
623 GNUNET_DISK_file_lock (fd, 0,
624 sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
630 LOG (GNUNET_ERROR_TYPE_ERROR,
631 _("Could not acquire lock on file `%s': %s...\n"), filename,
633 LOG (GNUNET_ERROR_TYPE_ERROR,
635 ("This may be ok if someone is currently generating a private key.\n"));
640 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
642 /* eh, what!? File we opened is now gone!? */
643 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
645 GNUNET_DISK_file_unlock (fd, 0,
646 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
647 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
648 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
652 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
654 if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKey))
656 /* maybe we got the read lock before the key generating
657 * process had a chance to get the write lock; give it up! */
659 GNUNET_DISK_file_unlock (fd, 0,
660 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
661 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
664 LOG (GNUNET_ERROR_TYPE_ERROR,
666 ("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
667 filename, (unsigned int) fs,
668 (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
669 LOG (GNUNET_ERROR_TYPE_ERROR,
671 ("This may be ok if someone is currently generating a key.\n"));
673 short_wait (); /* wait a bit longer! */
678 fs = sizeof (struct GNUNET_CRYPTO_EccPrivateKey);
679 priv = GNUNET_malloc (fs);
680 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
682 GNUNET_DISK_file_unlock (fd, 0,
683 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
684 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
685 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
691 * Create a new private key by reading our peer's key from
692 * the file specified in the configuration.
694 * @param cfg the configuration to use
695 * @return new private key, NULL on error (for example,
698 struct GNUNET_CRYPTO_EccPrivateKey *
699 GNUNET_CRYPTO_ecc_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
701 struct GNUNET_CRYPTO_EccPrivateKey *priv;
705 GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
707 priv = GNUNET_CRYPTO_ecc_key_create_from_file (fn);
714 * Setup a key file for a peer given the name of the
715 * configuration file (!). This function is used so that
716 * at a later point code can be certain that reading a
717 * key is fast (for example in time-dependent testcases).
719 * @param cfg_name name of the configuration file to use
722 GNUNET_CRYPTO_ecc_setup_key (const char *cfg_name)
724 struct GNUNET_CONFIGURATION_Handle *cfg;
725 struct GNUNET_CRYPTO_EccPrivateKey *priv;
727 cfg = GNUNET_CONFIGURATION_create ();
728 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
729 priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg);
732 GNUNET_CONFIGURATION_destroy (cfg);
737 * Retrieve the identity of the host's peer.
739 * @param cfg configuration to use
740 * @param dst pointer to where to write the peer identity
741 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the identity
742 * could not be retrieved
745 GNUNET_CRYPTO_get_host_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
746 struct GNUNET_PeerIdentity *dst)
748 struct GNUNET_CRYPTO_EccPrivateKey *priv;
749 struct GNUNET_CRYPTO_EccPublicSignKey pub;
751 if (NULL == (priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg)))
753 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
754 _("Could not load peer's private key\n"));
755 return GNUNET_SYSERR;
757 GNUNET_CRYPTO_ecc_key_get_public_for_signature (priv, &pub);
759 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &dst->hashPubKey);
765 * Convert the data specified in the given purpose argument to an
766 * S-expression suitable for signature operations.
768 * @param purpose data to convert
769 * @return converted s-expression
772 data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
774 struct GNUNET_HashCode hc;
778 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
779 if (0 != (rc = gcry_sexp_build (&data, NULL,
780 "(data(flags rfc6979)(hash %s %b))",
785 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
793 * Sign a given block.
795 * @param priv private key to use for the signing
796 * @param purpose what to sign (size, purpose)
797 * @param sig where to write the signature
798 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
801 GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
802 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
803 struct GNUNET_CRYPTO_EccSignature *sig)
805 gcry_sexp_t priv_sexp;
806 gcry_sexp_t sig_sexp;
811 priv_sexp = decode_private_key (priv);
812 data = data_to_pkcs1 (purpose);
813 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
815 LOG (GNUNET_ERROR_TYPE_WARNING,
816 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
817 __LINE__, gcry_strerror (rc));
818 gcry_sexp_release (data);
819 gcry_sexp_release (priv_sexp);
820 return GNUNET_SYSERR;
822 gcry_sexp_release (priv_sexp);
823 gcry_sexp_release (data);
825 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
827 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
830 gcry_sexp_release (sig_sexp);
831 return GNUNET_SYSERR;
833 gcry_sexp_release (sig_sexp);
834 mpi_print (sig->r, sizeof (sig->r), rs[0]);
835 mpi_print (sig->s, sizeof (sig->s), rs[1]);
836 gcry_mpi_release (rs[0]);
837 gcry_mpi_release (rs[1]);
845 * @param purpose what is the purpose that the signature should have?
846 * @param validate block to validate (size, purpose, data)
847 * @param sig signature that is being validated
848 * @param pub public key of the signer
849 * @returns #GNUNET_OK if ok, #GNUNET_SYSERR if invalid
852 GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
853 const struct GNUNET_CRYPTO_EccSignaturePurpose
855 const struct GNUNET_CRYPTO_EccSignature *sig,
856 const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
859 gcry_sexp_t sig_sexpr;
860 gcry_sexp_t pub_sexpr;
865 if (purpose != ntohl (validate->purpose))
866 return GNUNET_SYSERR; /* purpose mismatch */
868 /* build s-expression for signature */
869 mpi_scan (&r, sig->r, sizeof (sig->r));
870 mpi_scan (&s, sig->s, sizeof (sig->s));
871 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
872 "(sig-val(ecdsa(r %m)(s %m)))",
875 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
876 gcry_mpi_release (r);
877 gcry_mpi_release (s);
878 return GNUNET_SYSERR;
880 gcry_mpi_release (r);
881 gcry_mpi_release (s);
882 data = data_to_pkcs1 (validate);
883 if (! (pub_sexpr = decode_public_sign_key (pub)))
885 gcry_sexp_release (data);
886 gcry_sexp_release (sig_sexpr);
887 return GNUNET_SYSERR;
889 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
890 gcry_sexp_release (pub_sexpr);
891 gcry_sexp_release (data);
892 gcry_sexp_release (sig_sexpr);
895 LOG (GNUNET_ERROR_TYPE_INFO,
896 _("ECC signature verification failed at %s:%d: %s\n"), __FILE__,
897 __LINE__, gcry_strerror (rc));
898 return GNUNET_SYSERR;
905 * Convert the given public key from the network format to the
906 * S-expression that can be used by libgcrypt.
908 * @param pub public key to decode
909 * @return NULL on error
912 decode_public_encrypt_key (const struct GNUNET_CRYPTO_EccPublicEncryptKey *pub)
914 gcry_sexp_t pub_sexp;
920 mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x));
921 mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
922 q = gcry_mpi_point_new (256);
923 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
924 gcry_mpi_release (q_x);
925 gcry_mpi_release (q_y);
927 /* initialize 'ctx' with 'q' */
928 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
929 gcry_mpi_ec_set_point ("q", q, ctx);
930 gcry_mpi_point_release (q);
932 /* convert 'ctx' to 'sexp' */
933 GNUNET_assert (0 == gcry_pubkey_get_sexp (&pub_sexp, GCRY_PK_GET_PUBKEY, ctx));
934 gcry_ctx_release (ctx);
940 * Derive key material from a public and a private ECC key.
942 * @param priv private key to use for the ECDH (x)
943 * @param pub public key to use for the ECDH (yG)
944 * @param key_material where to write the key material (xyG)
945 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
948 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
949 const struct GNUNET_CRYPTO_EccPublicEncryptKey *pub,
950 struct GNUNET_HashCode *key_material)
952 gcry_mpi_point_t result;
956 gcry_sexp_t pub_sexpr;
959 unsigned char xbuf[256 / 8];
961 /* first, extract the q = dP value from the public key */
962 if (! (pub_sexpr = decode_public_encrypt_key (pub)))
963 return GNUNET_SYSERR;
964 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
965 gcry_sexp_release (pub_sexpr);
966 q = gcry_mpi_ec_get_point ("q", ctx, 0);
968 /* second, extract the d value from our private key */
969 mpi_scan (&d, priv->d, sizeof (priv->d));
971 /* then call the 'multiply' function, to compute the product */
972 result = gcry_mpi_point_new (0);
973 gcry_mpi_ec_mul (result, d, q, ctx);
974 gcry_mpi_point_release (q);
975 gcry_mpi_release (d);
977 /* finally, convert point to string for hashing */
978 result_x = gcry_mpi_new (256);
979 result_y = gcry_mpi_new (256);
980 if (gcry_mpi_ec_get_affine (result_x, result_y, result, ctx))
982 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
983 gcry_mpi_point_release (result);
984 gcry_ctx_release (ctx);
985 return GNUNET_SYSERR;
987 gcry_mpi_point_release (result);
988 gcry_ctx_release (ctx);
990 mpi_print (xbuf, sizeof (xbuf), result_x);
991 GNUNET_CRYPTO_hash (xbuf, sizeof (xbuf), key_material);
992 gcry_mpi_release (result_x);
993 gcry_mpi_release (result_y);
999 * Derive the 'h' value for key derivation, where
1002 * @param pub public key for deriviation
1003 * @param label label for deriviation
1004 * @param context additional context to use for HKDF of 'h';
1005 * typically the name of the subsystem/application
1009 derive_h (const struct GNUNET_CRYPTO_EccPublicSignKey *pub,
1011 const char *context)
1014 struct GNUNET_HashCode hc;
1016 GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
1017 "key-derivation", strlen ("key-derivation"),
1019 label, strlen (label),
1020 context, strlen (context),
1022 mpi_scan (&h, (unsigned char *) &hc, sizeof (hc));
1028 * Derive a private key from a given private key and a label.
1029 * Essentially calculates a private key 'd = H(l,P) * x mod n'
1030 * where n is the size of the ECC group and P is the public
1031 * key associated with the private key 'd'.
1033 * @param priv original private key
1034 * @param label label to use for key deriviation
1035 * @param context additional context to use for HKDF of 'h';
1036 * typically the name of the subsystem/application
1037 * @return derived private key
1039 struct GNUNET_CRYPTO_EccPrivateKey *
1040 GNUNET_CRYPTO_ecc_key_derive (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
1042 const char *context)
1044 struct GNUNET_CRYPTO_EccPublicSignKey pub;
1045 struct GNUNET_CRYPTO_EccPrivateKey *ret;
1052 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1053 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1054 GNUNET_CRYPTO_ecc_key_get_public_for_signature (priv, &pub);
1055 h = derive_h (&pub, label, context);
1056 mpi_scan (&x, priv->d, sizeof (priv->d));
1057 d = gcry_mpi_new (256);
1058 gcry_mpi_mulm (d, h, x, n);
1059 gcry_mpi_release (h);
1060 gcry_mpi_release (x);
1061 gcry_mpi_release (n);
1062 gcry_ctx_release (ctx);
1063 ret = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
1064 mpi_print (ret->d, sizeof (ret->d), d);
1065 gcry_mpi_release (d);
1071 * Derive a public key from a given public key and a label.
1072 * Essentially calculates a public key 'V = H(l,P) * P'.
1074 * @param pub original public key
1075 * @param label label to use for key deriviation
1076 * @param context additional context to use for HKDF of 'h';
1077 * typically the name of the subsystem/application
1078 * @param result where to write the derived public key
1081 GNUNET_CRYPTO_ecc_public_key_derive (const struct GNUNET_CRYPTO_EccPublicSignKey *pub,
1083 const char *context,
1084 struct GNUNET_CRYPTO_EccPublicSignKey *result)
1095 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1097 /* obtain point 'q' from original public key */
1098 mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x));
1099 mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
1101 q = gcry_mpi_point_new (0);
1102 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
1103 gcry_mpi_release (q_x);
1104 gcry_mpi_release (q_y);
1106 /* calulcate h_mod_n = h % n */
1107 h = derive_h (pub, label, context);
1108 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1109 h_mod_n = gcry_mpi_new (256);
1110 gcry_mpi_mod (h_mod_n, h, n);
1111 /* calculate v = h_mod_n * q */
1112 v = gcry_mpi_point_new (0);
1113 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1114 gcry_mpi_release (h_mod_n);
1115 gcry_mpi_release (h);
1116 gcry_mpi_release (n);
1117 gcry_mpi_point_release (q);
1118 /* convert point 'v' to public key that we return */
1119 point_to_public_sign_key (v, ctx, result);
1120 gcry_mpi_point_release (v);
1121 gcry_ctx_release (ctx);
1125 /* end of crypto_ecc.c */