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 #define CURVE "NIST P-256"
41 #define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
43 #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
45 #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
48 * Log an error message at log-level 'level' that indicates
49 * a failure of the command 'cmd' with the message given
50 * by gcry_strerror(rc).
52 #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);
56 * Free memory occupied by ECC key
58 * @param priv pointer to the memory to free
61 GNUNET_CRYPTO_ecc_key_free (struct GNUNET_CRYPTO_EccPrivateKey *priv)
68 * Extract values from an S-expression.
70 * @param array where to store the result(s)
71 * @param sexp S-expression to parse
72 * @param topname top-level name in the S-expression that is of interest
73 * @param elems names of the elements to extract
74 * @return 0 on success
77 key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
86 list = gcry_sexp_find_token (sexp, topname, 0);
89 l2 = gcry_sexp_cadr (list);
90 gcry_sexp_release (list);
96 for (s = elems; *s; s++, idx++)
98 l2 = gcry_sexp_find_token (list, s, 1);
101 for (i = 0; i < idx; i++)
103 gcry_free (array[i]);
106 gcry_sexp_release (list);
107 return 3; /* required parameter not found */
109 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
110 gcry_sexp_release (l2);
113 for (i = 0; i < idx; i++)
115 gcry_free (array[i]);
118 gcry_sexp_release (list);
119 return 4; /* required parameter is invalid */
122 gcry_sexp_release (list);
128 * If target != size, move target bytes to the end of the size-sized
129 * buffer and zero out the first target-size bytes.
131 * @param buf original buffer
132 * @param size number of bytes in the buffer
133 * @param target target size of the buffer
136 adjust (unsigned char *buf,
142 memmove (&buf[target - size], buf, size);
143 memset (buf, 0, target - size);
149 * Output the given MPI value to the given buffer.
151 * @param buf where to output to
152 * @param size number of bytes in buf
153 * @param val value to write to buf
156 mpi_print (unsigned char *buf,
164 gcry_mpi_print (GCRYMPI_FMT_USG, buf, rsize, &rsize,
166 adjust (buf, rsize, size);
171 * Convert data buffer into MPI value.
173 * @param result where to store MPI value (allocated)
174 * @param data raw data (GCRYMPI_FMT_USG)
175 * @param size number of bytes in data
178 mpi_scan (gcry_mpi_t *result,
179 const unsigned char *data,
184 if (0 != (rc = gcry_mpi_scan (result,
188 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
195 * Convert the given private key from the network format to the
196 * S-expression that can be used by libgcrypt.
198 * @param priv private key to decode
199 * @return NULL on error
202 decode_private_key (const struct GNUNET_CRYPTO_EccPrivateKey *priv)
212 rc = gcry_sexp_build (&result, &erroff,
213 "(private-key(ecdsa(curve \"" CURVE "\")(d %m)))",
215 gcry_mpi_release (d);
218 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */
222 if (0 != (rc = gcry_pk_testkey (result)))
224 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
233 * Initialize public key struct from the respective point
236 * @param q point on curve
237 * @param pub public key struct to initialize
238 * @param ctx context to use for ECC operations
241 point_to_public_key (gcry_mpi_point_t q,
243 struct GNUNET_CRYPTO_EccPublicKey *pub)
248 q_x = gcry_mpi_new (256);
249 q_y = gcry_mpi_new (256);
250 if (gcry_mpi_ec_get_affine (q_x, q_y, q, ctx))
252 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
255 mpi_print (pub->q_x, sizeof (pub->q_x), q_x);
256 mpi_print (pub->q_y, sizeof (pub->q_y), q_y);
257 gcry_mpi_release (q_x);
258 gcry_mpi_release (q_y);
263 * Extract the public key for the given private key.
265 * @param priv the private key
266 * @param pub where to write the public key
269 GNUNET_CRYPTO_ecc_key_get_public (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
270 struct GNUNET_CRYPTO_EccPublicKey *pub)
277 sexp = decode_private_key (priv);
278 GNUNET_assert (NULL != sexp);
279 if (0 != (rc = gcry_mpi_ec_new (&ctx, sexp, NULL)))
281 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
284 gcry_sexp_release (sexp);
285 q = gcry_mpi_ec_get_point ("q", ctx, 0);
286 point_to_public_key (q, ctx, pub);
287 gcry_ctx_release (ctx);
288 gcry_mpi_point_release (q);
293 * Convert a public key to a string.
295 * @param pub key to convert
296 * @return string representing 'pub'
299 GNUNET_CRYPTO_ecc_public_key_to_string (const struct GNUNET_CRYPTO_EccPublicKey *pub)
302 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKey)) * 8;
306 keylen += 5 - keylen % 5;
308 pubkeybuf = GNUNET_malloc (keylen + 1);
309 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
310 sizeof (struct GNUNET_CRYPTO_EccPublicKey),
315 GNUNET_free (pubkeybuf);
324 * Convert a string representing a public key to a public key.
326 * @param enc encoded public key
327 * @param enclen number of bytes in enc (without 0-terminator)
328 * @param pub where to store the public key
329 * @return GNUNET_OK on success
332 GNUNET_CRYPTO_ecc_public_key_from_string (const char *enc,
334 struct GNUNET_CRYPTO_EccPublicKey *pub)
336 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicKey)) * 8;
339 keylen += 5 - keylen % 5;
341 if (enclen != keylen)
342 return GNUNET_SYSERR;
344 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
346 sizeof (struct GNUNET_CRYPTO_EccPublicKey)))
347 return GNUNET_SYSERR;
353 * Convert the given public key from the network format to the
354 * S-expression that can be used by libgcrypt.
356 * @param pub public key to decode
357 * @return NULL on error
360 decode_public_key (const struct GNUNET_CRYPTO_EccPublicKey *pub)
362 gcry_sexp_t pub_sexp;
369 mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x));
370 mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
371 q = gcry_mpi_point_new (256);
372 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
373 gcry_mpi_release (q_x);
374 gcry_mpi_release (q_y);
376 /* create basic ECC context */
377 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, CURVE)))
379 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
380 gcry_mpi_point_release (q);
383 /* initialize 'ctx' with 'q' */
384 gcry_mpi_ec_set_point ("q", q, ctx);
385 gcry_mpi_point_release (q);
387 /* convert 'ctx' to 'sexp' */
388 if (0 != (rc = gcry_pubkey_get_sexp (&pub_sexp, GCRY_PK_GET_PUBKEY, ctx)))
390 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_from_context", rc);
391 gcry_ctx_release (ctx);
394 gcry_ctx_release (ctx);
400 * Create a new private key. Caller must free return value.
402 * @return fresh private key
404 struct GNUNET_CRYPTO_EccPrivateKey *
405 GNUNET_CRYPTO_ecc_key_create ()
407 struct GNUNET_CRYPTO_EccPrivateKey *priv;
408 gcry_sexp_t priv_sexp;
409 gcry_sexp_t s_keyparam;
413 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
414 "(genkey(ecdsa(curve \"" CURVE "\")))")))
416 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
419 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
421 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
422 gcry_sexp_release (s_keyparam);
425 gcry_sexp_release (s_keyparam);
427 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
429 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
430 gcry_sexp_release (priv_sexp);
434 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
436 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
437 gcry_sexp_release (priv_sexp);
440 gcry_sexp_release (priv_sexp);
441 priv = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
442 mpi_print (priv->d, sizeof (priv->d), d);
443 gcry_mpi_release (d);
449 * Get the shared private key we use for anonymous users.
451 * @return "anonymous" private key
453 const struct GNUNET_CRYPTO_EccPrivateKey *
454 GNUNET_CRYPTO_ecc_key_get_anonymous ()
457 * 'anonymous' pseudonym (global static, d=1, public key = G
460 static struct GNUNET_CRYPTO_EccPrivateKey anonymous;
465 mpi_print (anonymous.d,
466 sizeof (anonymous.d),
474 * Wait for a short time (we're trying to lock a file or want
475 * to give another process a shot at finishing a disk write, etc.).
476 * Sleeps for 100ms (as that should be long enough for virtually all
477 * modern systems to context switch and allow another process to do
483 struct GNUNET_TIME_Relative timeout;
485 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
486 (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
491 * Create a new private key by reading it from a file. If the
492 * files does not exist, create a new key and write it to the
493 * file. Caller must free return value. Note that this function
494 * can not guarantee that another process might not be trying
495 * the same operation on the same file at the same time.
496 * If the contents of the file
497 * are invalid the old file is deleted and a fresh key is
500 * @param filename name of file to use to store the key
501 * @return new private key, NULL on error (for example,
504 struct GNUNET_CRYPTO_EccPrivateKey *
505 GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
507 struct GNUNET_CRYPTO_EccPrivateKey *priv;
508 struct GNUNET_DISK_FileHandle *fd;
513 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
515 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
517 fd = GNUNET_DISK_file_open (filename,
518 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
519 | GNUNET_DISK_OPEN_FAILIFEXISTS,
520 GNUNET_DISK_PERM_USER_READ |
521 GNUNET_DISK_PERM_USER_WRITE);
526 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
528 /* must exist but not be accessible, fail for good! */
529 if (0 != ACCESS (filename, R_OK))
530 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
532 GNUNET_break (0); /* what is going on!? */
537 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
543 GNUNET_DISK_file_lock (fd, 0,
544 sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
551 LOG (GNUNET_ERROR_TYPE_ERROR,
552 _("Could not acquire lock on file `%s': %s...\n"), filename,
556 LOG (GNUNET_ERROR_TYPE_INFO,
557 _("Creating a new private key. This may take a while.\n"));
558 priv = GNUNET_CRYPTO_ecc_key_create ();
559 GNUNET_assert (NULL != priv);
560 GNUNET_assert (sizeof (*priv) ==
561 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
562 GNUNET_DISK_file_sync (fd);
564 GNUNET_DISK_file_unlock (fd, 0,
565 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
566 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
567 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
570 /* key file exists already, read it! */
571 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
572 GNUNET_DISK_PERM_NONE);
575 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
582 GNUNET_DISK_file_lock (fd, 0,
583 sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
589 LOG (GNUNET_ERROR_TYPE_ERROR,
590 _("Could not acquire lock on file `%s': %s...\n"), filename,
592 LOG (GNUNET_ERROR_TYPE_ERROR,
594 ("This may be ok if someone is currently generating a private key.\n"));
599 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
601 /* eh, what!? File we opened is now gone!? */
602 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
604 GNUNET_DISK_file_unlock (fd, 0,
605 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
606 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
607 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
611 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
613 if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKey))
615 /* maybe we got the read lock before the key generating
616 * process had a chance to get the write lock; give it up! */
618 GNUNET_DISK_file_unlock (fd, 0,
619 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
620 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
623 LOG (GNUNET_ERROR_TYPE_ERROR,
625 ("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
626 filename, (unsigned int) fs,
627 (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
628 LOG (GNUNET_ERROR_TYPE_ERROR,
630 ("This may be ok if someone is currently generating a key.\n"));
632 short_wait (); /* wait a bit longer! */
637 fs = sizeof (struct GNUNET_CRYPTO_EccPrivateKey);
638 priv = GNUNET_malloc (fs);
639 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
641 GNUNET_DISK_file_unlock (fd, 0,
642 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
643 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
644 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
650 * Create a new private key by reading our peer's key from
651 * the file specified in the configuration.
653 * @return new private key, NULL on error (for example,
656 struct GNUNET_CRYPTO_EccPrivateKey *
657 GNUNET_CRYPTO_ecc_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
659 struct GNUNET_CRYPTO_EccPrivateKey *priv;
663 GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
665 priv = GNUNET_CRYPTO_ecc_key_create_from_file (fn);
672 * Setup a key file for a peer given the name of the
673 * configuration file (!). This function is used so that
674 * at a later point code can be certain that reading a
675 * key is fast (for example in time-dependent testcases).
677 * @param cfg_name name of the configuration file to use
680 GNUNET_CRYPTO_ecc_setup_key (const char *cfg_name)
682 struct GNUNET_CONFIGURATION_Handle *cfg;
683 struct GNUNET_CRYPTO_EccPrivateKey *priv;
685 cfg = GNUNET_CONFIGURATION_create ();
686 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
687 priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg);
689 GNUNET_CRYPTO_ecc_key_free (priv);
690 GNUNET_CONFIGURATION_destroy (cfg);
695 * Retrieve the identity of the host's peer.
697 * @param cfg configuration to use
698 * @param dst pointer to where to write the peer identity
699 * @return GNUNET_OK on success, GNUNET_SYSERR if the identity
700 * could not be retrieved
703 GNUNET_CRYPTO_get_host_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
704 struct GNUNET_PeerIdentity *dst)
706 struct GNUNET_CRYPTO_EccPrivateKey *priv;
707 struct GNUNET_CRYPTO_EccPublicKey pub;
709 if (NULL == (priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg)))
711 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
712 _("Could not load peer's private key\n"));
713 return GNUNET_SYSERR;
715 GNUNET_CRYPTO_ecc_key_get_public (priv, &pub);
716 GNUNET_CRYPTO_ecc_key_free (priv);
717 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &dst->hashPubKey);
723 * Convert the data specified in the given purpose argument to an
724 * S-expression suitable for signature operations.
726 * @param purpose data to convert
727 * @return converted s-expression
730 data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
732 struct GNUNET_CRYPTO_ShortHashCode hc;
736 GNUNET_CRYPTO_short_hash (purpose, ntohl (purpose->size), &hc);
737 if (0 != (rc = gcry_sexp_build (&data, NULL,
738 "(data(flags rfc6979)(hash %s %b))",
743 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
751 * Sign a given block.
753 * @param priv private key to use for the signing
754 * @param purpose what to sign (size, purpose)
755 * @param sig where to write the signature
756 * @return GNUNET_SYSERR on error, GNUNET_OK on success
759 GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
760 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
761 struct GNUNET_CRYPTO_EccSignature *sig)
763 gcry_sexp_t priv_sexp;
764 gcry_sexp_t sig_sexp;
769 priv_sexp = decode_private_key (priv);
770 data = data_to_pkcs1 (purpose);
771 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
773 LOG (GNUNET_ERROR_TYPE_WARNING,
774 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
775 __LINE__, gcry_strerror (rc));
776 gcry_sexp_release (data);
777 gcry_sexp_release (priv_sexp);
778 return GNUNET_SYSERR;
780 gcry_sexp_release (priv_sexp);
781 gcry_sexp_release (data);
783 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
785 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
788 gcry_sexp_release (sig_sexp);
789 return GNUNET_SYSERR;
791 gcry_sexp_release (sig_sexp);
792 mpi_print (sig->r, sizeof (sig->r), rs[0]);
793 mpi_print (sig->s, sizeof (sig->s), rs[1]);
794 gcry_mpi_release (rs[0]);
795 gcry_mpi_release (rs[1]);
803 * @param purpose what is the purpose that the signature should have?
804 * @param validate block to validate (size, purpose, data)
805 * @param sig signature that is being validated
806 * @param pub public key of the signer
807 * @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
810 GNUNET_CRYPTO_ecc_verify (uint32_t purpose,
811 const struct GNUNET_CRYPTO_EccSignaturePurpose
813 const struct GNUNET_CRYPTO_EccSignature *sig,
814 const struct GNUNET_CRYPTO_EccPublicKey *pub)
817 gcry_sexp_t sig_sexpr;
818 gcry_sexp_t pub_sexpr;
824 if (purpose != ntohl (validate->purpose))
825 return GNUNET_SYSERR; /* purpose mismatch */
827 /* build s-expression for signature */
828 mpi_scan (&r, sig->r, sizeof (sig->r));
829 mpi_scan (&s, sig->s, sizeof (sig->s));
830 if (0 != (rc = gcry_sexp_build (&sig_sexpr, &erroff, "(sig-val(ecdsa(r %m)(s %m)))",
833 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
834 gcry_mpi_release (r);
835 gcry_mpi_release (s);
836 return GNUNET_SYSERR;
838 gcry_mpi_release (r);
839 gcry_mpi_release (s);
840 data = data_to_pkcs1 (validate);
841 if (! (pub_sexpr = decode_public_key (pub)))
843 gcry_sexp_release (data);
844 gcry_sexp_release (sig_sexpr);
845 return GNUNET_SYSERR;
847 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
848 gcry_sexp_release (pub_sexpr);
849 gcry_sexp_release (data);
850 gcry_sexp_release (sig_sexpr);
853 LOG (GNUNET_ERROR_TYPE_WARNING,
854 _("ECC signature verification failed at %s:%d: %s\n"), __FILE__,
855 __LINE__, gcry_strerror (rc));
856 return GNUNET_SYSERR;
863 * Derive key material from a public and a private ECC key.
865 * @param priv private key to use for the ECDH (x)
866 * @param pub public key to use for the ECDH (yG)
867 * @param key_material where to write the key material (xyG)
868 * @return GNUNET_SYSERR on error, GNUNET_OK on success
871 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
872 const struct GNUNET_CRYPTO_EccPublicKey *pub,
873 struct GNUNET_HashCode *key_material)
878 unsigned char sdata_buf[2048]; /* big enough to print dh-shared-secret as S-expression */
879 gcry_mpi_point_t result;
883 gcry_sexp_t pub_sexpr;
884 gcry_sexp_t ecdh_sexp;
888 /* first, extract the q = dP value from the public key */
889 if (! (pub_sexpr = decode_public_key (pub)))
890 return GNUNET_SYSERR;
891 if (0 != (rc = gcry_mpi_ec_new (&ctx, pub_sexpr, NULL)))
893 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
894 return GNUNET_SYSERR;
896 gcry_sexp_release (pub_sexpr);
897 q = gcry_mpi_ec_get_point ("q", ctx, 0);
898 gcry_ctx_release (ctx);
900 /* second, extract the d value from our private key */
901 mpi_scan (&d, priv->d, sizeof (priv->d));
903 /* create a new context for definitively the correct curve;
904 theoretically the 'public_key' might not use the right curve */
905 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, CURVE)))
907 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc); /* erroff gives more info */
908 gcry_mpi_release (d);
909 gcry_mpi_point_release (q);
910 return GNUNET_SYSERR;
913 /* then call the 'multiply' function, to compute the product */
914 GNUNET_assert (NULL != ctx);
915 result = gcry_mpi_point_new (0);
916 gcry_mpi_ec_mul (result, d, q, ctx);
917 gcry_mpi_point_release (q);
918 gcry_mpi_release (d);
920 /* finally, convert point to string for hashing */
921 result_x = gcry_mpi_new (256);
922 result_y = gcry_mpi_new (256);
923 if (gcry_mpi_ec_get_affine (result_x, result_y, result, ctx))
925 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
926 gcry_mpi_point_release (result);
927 gcry_ctx_release (ctx);
928 return GNUNET_SYSERR;
930 gcry_mpi_point_release (result);
931 gcry_ctx_release (ctx);
932 if (0 != (rc = gcry_sexp_build (&ecdh_sexp, &erroff,
933 "(dh-shared-secret (x %m)(y %m))",
937 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */
938 gcry_mpi_release (result_x);
939 gcry_mpi_release (result_y);
940 return GNUNET_SYSERR;
942 gcry_mpi_release (result_x);
943 gcry_mpi_release (result_y);
944 slen = gcry_sexp_sprint (ecdh_sexp,
945 GCRYSEXP_FMT_DEFAULT,
946 sdata_buf, sizeof (sdata_buf));
947 GNUNET_assert (0 != slen);
948 gcry_sexp_release (ecdh_sexp);
949 /* finally, get a string of the resulting S-expression and hash it
950 to generate the key material */
951 GNUNET_CRYPTO_hash (sdata_buf, slen, key_material);
957 * Derive the 'h' value for key derivation, where
960 * @param pub public key for deriviation
961 * @param label label for deriviation
965 derive_h (const struct GNUNET_CRYPTO_EccPublicKey *pub,
969 struct GNUNET_HashCode hc;
971 GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
972 "key-derivation", strlen ("key-derivation"),
974 label, sizeof (label),
976 mpi_scan (&h, (unsigned char *) &hc, sizeof (hc));
982 * Derive a private key from a given private key and a label.
983 * Essentially calculates a private key 'd = H(l,P) * x mod n'
984 * where n is the size of the ECC group and P is the public
985 * key associated with the private key 'd'.
987 * @param priv original private key
988 * @param label label to use for key deriviation
989 * @return derived private key
991 struct GNUNET_CRYPTO_EccPrivateKey *
992 GNUNET_CRYPTO_ecc_key_derive (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
995 struct GNUNET_CRYPTO_EccPublicKey pub;
996 struct GNUNET_CRYPTO_EccPrivateKey *ret;
1003 GNUNET_CRYPTO_ecc_key_get_public (priv, &pub);
1004 h = derive_h (&pub, label);
1005 mpi_scan (&x, priv->d, sizeof (priv->d));
1006 /* initialize 'n' from P-256; hex copied from libgcrypt code */
1007 if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_HEX,
1008 "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 0, NULL)))
1010 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
1011 gcry_mpi_release (h);
1014 d = gcry_mpi_new (256);
1015 gcry_mpi_mulm (d, h, x, n);
1016 gcry_mpi_release (h);
1017 gcry_mpi_release (x);
1018 gcry_mpi_release (n);
1019 ret = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
1020 mpi_print (ret->d, sizeof (ret->d), d);
1021 gcry_mpi_release (d);
1027 * Derive a public key from a given public key and a label.
1028 * Essentially calculates a public key 'V = H(l,P) * P'.
1030 * @param pub original public key
1031 * @param label label to use for key deriviation
1032 * @param result where to write the derived public key
1035 GNUNET_CRYPTO_ecc_public_key_derive (const struct GNUNET_CRYPTO_EccPublicKey *pub,
1037 struct GNUNET_CRYPTO_EccPublicKey *result)
1047 h = derive_h (pub, label);
1048 mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x));
1049 mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
1050 q = gcry_mpi_point_new (256);
1051 gcry_mpi_point_set (q, q_x, q_y, GCRYMPI_CONST_ONE);
1052 gcry_mpi_release (q_x);
1053 gcry_mpi_release (q_y);
1055 /* create basic ECC context */
1056 if (0 != (rc = gcry_mpi_ec_new (&ctx, NULL, CURVE)))
1058 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_new", rc);
1059 gcry_mpi_point_release (q);
1060 gcry_mpi_release (h);
1063 v = gcry_mpi_point_new (256);
1064 /* we could calculate 'h mod n' here first, but hopefully
1065 libgcrypt is smart enough to do that for us... */
1066 gcry_mpi_ec_mul (v, h, q, ctx);
1067 gcry_mpi_release (h);
1068 gcry_mpi_point_release (q);
1069 point_to_public_key (v, ctx, result);
1070 gcry_mpi_point_release (v);
1071 gcry_ctx_release (ctx);
1075 /* end of crypto_ecc.c */