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 "Ed25519"
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 * Extract values from an S-expression.
58 * @param array where to store the result(s)
59 * @param sexp S-expression to parse
60 * @param topname top-level name in the S-expression that is of interest
61 * @param elems names of the elements to extract
62 * @return 0 on success
65 key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
74 list = gcry_sexp_find_token (sexp, topname, 0);
77 l2 = gcry_sexp_cadr (list);
78 gcry_sexp_release (list);
84 for (s = elems; *s; s++, idx++)
86 l2 = gcry_sexp_find_token (list, s, 1);
89 for (i = 0; i < idx; i++)
94 gcry_sexp_release (list);
95 return 3; /* required parameter not found */
97 array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
98 gcry_sexp_release (l2);
101 for (i = 0; i < idx; i++)
103 gcry_free (array[i]);
106 gcry_sexp_release (list);
107 return 4; /* required parameter is invalid */
110 gcry_sexp_release (list);
116 * If target != size, move @a target bytes to the end of the size-sized
117 * buffer and zero out the first @a target - @a size bytes.
119 * @param buf original buffer
120 * @param size number of bytes in @a buf
121 * @param target target size of the buffer
124 adjust (unsigned char *buf,
130 memmove (&buf[target - size], buf, size);
131 memset (buf, 0, target - size);
137 * Output the given MPI value to the given buffer.
139 * @param buf where to output to
140 * @param size number of bytes in @a buf
141 * @param val value to write to @a buf
144 mpi_print (unsigned char *buf,
152 gcry_mpi_print (GCRYMPI_FMT_USG, buf, rsize, &rsize,
154 adjust (buf, rsize, size);
159 * Convert data buffer into MPI value.
161 * @param result where to store MPI value (allocated)
162 * @param data raw data (GCRYMPI_FMT_USG)
163 * @param size number of bytes in data
166 mpi_scan (gcry_mpi_t *result,
167 const unsigned char *data,
172 if (0 != (rc = gcry_mpi_scan (result,
176 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
183 * Convert the given private key from the network format to the
184 * S-expression that can be used by libgcrypt.
186 * @param priv private key to decode
187 * @return NULL on error
190 decode_private_key (const struct GNUNET_CRYPTO_EccPrivateKey *priv)
199 rc = gcry_sexp_build (&result, NULL,
200 "(private-key(ecc(curve \"" CURVE "\")(d %m)))",
202 gcry_mpi_release (d);
205 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
209 if (0 != (rc = gcry_pk_testkey (result)))
211 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
220 * Extract the public key for the given private key.
222 * @param priv the private key
223 * @param pub where to write the public key
226 GNUNET_CRYPTO_ecc_key_get_public_for_signature (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
227 struct GNUNET_CRYPTO_EccPublicSignKey *pub)
233 sexp = decode_private_key (priv);
234 gcry_sexp_dump (sexp);
235 GNUNET_assert (NULL != sexp);
236 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
237 gcry_sexp_release (sexp);
238 if (NULL == (q_y = gcry_mpi_ec_get_mpi ("y", ctx, 0)))
240 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
241 "gcry_mpi_ec_get_mpi failed", 0);
244 mpi_print (pub->q_y, sizeof (pub->q_y), q_y);
245 gcry_ctx_release (ctx);
246 // gcry_mpi_release (q_y); /* needed? we set copy to 0... */
251 * Extract the public key for the given private key.
253 * @param priv the private key
254 * @param pub where to write the public key
257 GNUNET_CRYPTO_ecc_key_get_public_for_encryption (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
258 struct GNUNET_CRYPTO_EccPublicEncryptKey *pub)
264 sexp = decode_private_key (priv);
265 GNUNET_assert (NULL != sexp);
266 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, sexp, NULL));
267 gcry_sexp_release (sexp);
268 if (NULL == (q_x = gcry_mpi_ec_get_mpi ("x", ctx, 0)))
270 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
271 "gcry_mpi_ec_get_mpi failed", 0);
274 mpi_print (pub->q_x, sizeof (pub->q_x), q_x);
275 gcry_ctx_release (ctx);
280 * Convert a public key to a string.
282 * @param pub key to convert
283 * @return string representing @a pub
286 GNUNET_CRYPTO_ecc_public_sign_key_to_string (const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
289 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)) * 8;
293 keylen += 5 - keylen % 5;
295 pubkeybuf = GNUNET_malloc (keylen + 1);
296 end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
297 sizeof (struct GNUNET_CRYPTO_EccPublicSignKey),
302 GNUNET_free (pubkeybuf);
311 * Convert a string representing a public key to a public key.
313 * @param enc encoded public key
314 * @param enclen number of bytes in @a enc (without 0-terminator)
315 * @param pub where to store the public key
316 * @return #GNUNET_OK on success
319 GNUNET_CRYPTO_ecc_public_sign_key_from_string (const char *enc,
321 struct GNUNET_CRYPTO_EccPublicSignKey *pub)
323 size_t keylen = (sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)) * 8;
326 keylen += 5 - keylen % 5;
328 if (enclen != keylen)
329 return GNUNET_SYSERR;
331 if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
333 sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)))
334 return GNUNET_SYSERR;
340 * Convert the given public key from the network format to the
341 * S-expression that can be used by libgcrypt.
343 * @param pub public key to decode
344 * @return NULL on error
347 decode_public_sign_key (const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
349 gcry_sexp_t pub_sexp;
353 mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
354 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
355 gcry_mpi_ec_set_mpi ("y", q_y, ctx);
356 gcry_mpi_release (q_y);
358 /* convert 'ctx' to 'sexp' */
359 GNUNET_assert (0 == gcry_pubkey_get_sexp (&pub_sexp, GCRY_PK_GET_PUBKEY, ctx));
360 gcry_ctx_release (ctx);
367 * Clear memory that was used to store a private key.
369 * @param pk location of the key
372 GNUNET_CRYPTO_ecc_key_clear (struct GNUNET_CRYPTO_EccPrivateKey *pk)
374 memset (pk, 0, sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
379 * Create a new private key. Caller must free return value.
381 * @return fresh private key
383 struct GNUNET_CRYPTO_EccPrivateKey *
384 GNUNET_CRYPTO_ecc_key_create ()
386 struct GNUNET_CRYPTO_EccPrivateKey *priv;
387 gcry_sexp_t priv_sexp;
388 gcry_sexp_t s_keyparam;
392 if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
393 "(genkey(ecc(curve \"" CURVE "\")))")))
395 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
398 if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
400 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
401 gcry_sexp_release (s_keyparam);
404 gcry_sexp_release (s_keyparam);
406 if (0 != (rc = gcry_pk_testkey (priv_sexp)))
408 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
409 gcry_sexp_release (priv_sexp);
413 if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
415 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
416 gcry_sexp_release (priv_sexp);
419 gcry_sexp_release (priv_sexp);
420 priv = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
421 mpi_print (priv->d, sizeof (priv->d), d);
422 gcry_mpi_release (d);
428 * Get the shared private key we use for anonymous users.
430 * @return "anonymous" private key
432 const struct GNUNET_CRYPTO_EccPrivateKey *
433 GNUNET_CRYPTO_ecc_key_get_anonymous ()
436 * 'anonymous' pseudonym (global static, d=1, public key = G
439 static struct GNUNET_CRYPTO_EccPrivateKey anonymous;
444 mpi_print (anonymous.d,
445 sizeof (anonymous.d),
453 * Wait for a short time (we're trying to lock a file or want
454 * to give another process a shot at finishing a disk write, etc.).
455 * Sleeps for 100ms (as that should be long enough for virtually all
456 * modern systems to context switch and allow another process to do
462 struct GNUNET_TIME_Relative timeout;
464 timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 100);
465 (void) GNUNET_NETWORK_socket_select (NULL, NULL, NULL, timeout);
470 * Create a new private key by reading it from a file. If the
471 * files does not exist, create a new key and write it to the
472 * file. Caller must free return value. Note that this function
473 * can not guarantee that another process might not be trying
474 * the same operation on the same file at the same time.
475 * If the contents of the file
476 * are invalid the old file is deleted and a fresh key is
479 * @param filename name of file to use to store the key
480 * @return new private key, NULL on error (for example,
483 struct GNUNET_CRYPTO_EccPrivateKey *
484 GNUNET_CRYPTO_ecc_key_create_from_file (const char *filename)
486 struct GNUNET_CRYPTO_EccPrivateKey *priv;
487 struct GNUNET_DISK_FileHandle *fd;
492 if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename))
494 while (GNUNET_YES != GNUNET_DISK_file_test (filename))
496 fd = GNUNET_DISK_file_open (filename,
497 GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE
498 | GNUNET_DISK_OPEN_FAILIFEXISTS,
499 GNUNET_DISK_PERM_USER_READ |
500 GNUNET_DISK_PERM_USER_WRITE);
505 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
507 /* must exist but not be accessible, fail for good! */
508 if (0 != ACCESS (filename, R_OK))
509 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename);
511 GNUNET_break (0); /* what is going on!? */
516 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
521 GNUNET_DISK_file_lock (fd, 0,
522 sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
529 LOG (GNUNET_ERROR_TYPE_ERROR,
530 _("Could not acquire lock on file `%s': %s...\n"), filename,
534 LOG (GNUNET_ERROR_TYPE_INFO,
535 _("Creating a new private key. This may take a while.\n"));
536 priv = GNUNET_CRYPTO_ecc_key_create ();
537 GNUNET_assert (NULL != priv);
538 GNUNET_assert (sizeof (*priv) ==
539 GNUNET_DISK_file_write (fd, priv, sizeof (*priv)));
540 GNUNET_DISK_file_sync (fd);
542 GNUNET_DISK_file_unlock (fd, 0,
543 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
544 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
545 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
548 /* key file exists already, read it! */
549 fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ,
550 GNUNET_DISK_PERM_NONE);
553 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename);
560 GNUNET_DISK_file_lock (fd, 0,
561 sizeof (struct GNUNET_CRYPTO_EccPrivateKey),
567 LOG (GNUNET_ERROR_TYPE_ERROR,
568 _("Could not acquire lock on file `%s': %s...\n"), filename,
570 LOG (GNUNET_ERROR_TYPE_ERROR,
572 ("This may be ok if someone is currently generating a private key.\n"));
577 if (GNUNET_YES != GNUNET_DISK_file_test (filename))
579 /* eh, what!? File we opened is now gone!? */
580 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename);
582 GNUNET_DISK_file_unlock (fd, 0,
583 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
584 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
585 GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
589 if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
591 if (fs < sizeof (struct GNUNET_CRYPTO_EccPrivateKey))
593 /* maybe we got the read lock before the key generating
594 * process had a chance to get the write lock; give it up! */
596 GNUNET_DISK_file_unlock (fd, 0,
597 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
598 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
601 LOG (GNUNET_ERROR_TYPE_ERROR,
603 ("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"),
604 filename, (unsigned int) fs,
605 (unsigned int) sizeof (struct GNUNET_CRYPTO_EccPrivateKey));
606 LOG (GNUNET_ERROR_TYPE_ERROR,
608 ("This may be ok if someone is currently generating a key.\n"));
610 short_wait (); /* wait a bit longer! */
615 fs = sizeof (struct GNUNET_CRYPTO_EccPrivateKey);
616 priv = GNUNET_malloc (fs);
617 GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs));
619 GNUNET_DISK_file_unlock (fd, 0,
620 sizeof (struct GNUNET_CRYPTO_EccPrivateKey)))
621 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename);
622 GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd));
628 * Create a new private key by reading our peer's key from
629 * the file specified in the configuration.
631 * @param cfg the configuration to use
632 * @return new private key, NULL on error (for example,
635 struct GNUNET_CRYPTO_EccPrivateKey *
636 GNUNET_CRYPTO_ecc_key_create_from_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
638 struct GNUNET_CRYPTO_EccPrivateKey *priv;
642 GNUNET_CONFIGURATION_get_value_filename (cfg, "PEER", "PRIVATE_KEY", &fn))
644 priv = GNUNET_CRYPTO_ecc_key_create_from_file (fn);
651 * Setup a key file for a peer given the name of the
652 * configuration file (!). This function is used so that
653 * at a later point code can be certain that reading a
654 * key is fast (for example in time-dependent testcases).
656 * @param cfg_name name of the configuration file to use
659 GNUNET_CRYPTO_ecc_setup_key (const char *cfg_name)
661 struct GNUNET_CONFIGURATION_Handle *cfg;
662 struct GNUNET_CRYPTO_EccPrivateKey *priv;
664 cfg = GNUNET_CONFIGURATION_create ();
665 (void) GNUNET_CONFIGURATION_load (cfg, cfg_name);
666 priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg);
669 GNUNET_CONFIGURATION_destroy (cfg);
674 * Retrieve the identity of the host's peer.
676 * @param cfg configuration to use
677 * @param dst pointer to where to write the peer identity
678 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the identity
679 * could not be retrieved
682 GNUNET_CRYPTO_get_host_identity (const struct GNUNET_CONFIGURATION_Handle *cfg,
683 struct GNUNET_PeerIdentity *dst)
685 struct GNUNET_CRYPTO_EccPrivateKey *priv;
686 struct GNUNET_CRYPTO_EccPublicSignKey pub;
688 if (NULL == (priv = GNUNET_CRYPTO_ecc_key_create_from_configuration (cfg)))
690 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
691 _("Could not load peer's private key\n"));
692 return GNUNET_SYSERR;
694 GNUNET_CRYPTO_ecc_key_get_public_for_signature (priv, &pub);
696 GNUNET_CRYPTO_hash (&pub, sizeof (pub), &dst->hashPubKey);
702 * Convert the data specified in the given purpose argument to an
703 * S-expression suitable for signature operations.
705 * @param purpose data to convert
706 * @return converted s-expression
709 data_to_pkcs1 (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose)
711 struct GNUNET_HashCode hc;
715 GNUNET_CRYPTO_hash (purpose, ntohl (purpose->size), &hc);
716 if (0 != (rc = gcry_sexp_build (&data, NULL,
717 "(data(flags eddsa)(hash %s %b))",
722 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
730 * Sign a given block.
732 * @param priv private key to use for the signing
733 * @param purpose what to sign (size, purpose)
734 * @param sig where to write the signature
735 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
738 GNUNET_CRYPTO_ecc_sign (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
739 const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
740 struct GNUNET_CRYPTO_EccSignature *sig)
742 gcry_sexp_t priv_sexp;
743 gcry_sexp_t sig_sexp;
748 priv_sexp = decode_private_key (priv);
749 data = data_to_pkcs1 (purpose);
750 if (0 != (rc = gcry_pk_sign (&sig_sexp, data, priv_sexp)))
752 LOG (GNUNET_ERROR_TYPE_WARNING,
753 _("ECC signing failed at %s:%d: %s\n"), __FILE__,
754 __LINE__, gcry_strerror (rc));
755 gcry_sexp_release (data);
756 gcry_sexp_release (priv_sexp);
757 return GNUNET_SYSERR;
759 gcry_sexp_release (priv_sexp);
760 gcry_sexp_release (data);
762 /* extract 'r' and 's' values from sexpression 'sig_sexp' and store in
764 if (0 != (rc = key_from_sexp (rs, sig_sexp, "sig-val", "rs")))
767 gcry_sexp_release (sig_sexp);
768 return GNUNET_SYSERR;
770 gcry_sexp_release (sig_sexp);
771 mpi_print (sig->r, sizeof (sig->r), rs[0]);
772 mpi_print (sig->s, sizeof (sig->s), rs[1]);
773 gcry_mpi_release (rs[0]);
774 gcry_mpi_release (rs[1]);
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_ecc_verify (uint32_t purpose,
790 const struct GNUNET_CRYPTO_EccSignaturePurpose
792 const struct GNUNET_CRYPTO_EccSignature *sig,
793 const struct GNUNET_CRYPTO_EccPublicSignKey *pub)
796 gcry_sexp_t sig_sexpr;
797 gcry_sexp_t pub_sexpr;
802 if (purpose != ntohl (validate->purpose))
803 return GNUNET_SYSERR; /* purpose mismatch */
805 /* build s-expression for signature */
806 mpi_scan (&r, sig->r, sizeof (sig->r));
807 mpi_scan (&s, sig->s, sizeof (sig->s));
808 if (0 != (rc = gcry_sexp_build (&sig_sexpr, NULL,
809 "(sig-val(eddsa(r %m)(s %m)))",
812 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
813 gcry_mpi_release (r);
814 gcry_mpi_release (s);
815 return GNUNET_SYSERR;
817 gcry_mpi_release (r);
818 gcry_mpi_release (s);
819 data = data_to_pkcs1 (validate);
820 if (! (pub_sexpr = decode_public_sign_key (pub)))
822 gcry_sexp_release (data);
823 gcry_sexp_release (sig_sexpr);
824 return GNUNET_SYSERR;
826 rc = gcry_pk_verify (sig_sexpr, data, pub_sexpr);
827 gcry_sexp_release (pub_sexpr);
828 gcry_sexp_release (data);
829 gcry_sexp_release (sig_sexpr);
832 LOG (GNUNET_ERROR_TYPE_INFO,
833 _("ECC signature verification failed at %s:%d: %s\n"), __FILE__,
834 __LINE__, gcry_strerror (rc));
835 return GNUNET_SYSERR;
842 * Convert the given public key from the network format to the
843 * S-expression that can be used by libgcrypt.
845 * @param pub public key to decode
846 * @return NULL on error
849 decode_public_encrypt_key (const struct GNUNET_CRYPTO_EccPublicEncryptKey *pub)
851 gcry_sexp_t pub_sexp;
856 mpi_scan (&q_x, pub->q_x, sizeof (pub->q_x));
857 /* initialize 'ctx' with 'x' */
858 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
859 if (0 != (rc = gcry_mpi_ec_set_mpi ("x", q_x, ctx)))
860 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_set_mpi", rc);
861 gcry_mpi_release (q_x);
863 /* convert 'ctx' to 'sexp' */
864 GNUNET_assert (0 == gcry_pubkey_get_sexp (&pub_sexp, GCRY_PK_GET_PUBKEY, ctx));
865 gcry_ctx_release (ctx);
871 * Derive key material from a public and a private ECC key.
873 * @param priv private key to use for the ECDH (x)
874 * @param pub public key to use for the ECDH (yG)
875 * @param key_material where to write the key material (xyG)
876 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
879 GNUNET_CRYPTO_ecc_ecdh (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
880 const struct GNUNET_CRYPTO_EccPublicEncryptKey *pub,
881 struct GNUNET_HashCode *key_material)
883 gcry_mpi_point_t result;
887 gcry_sexp_t pub_sexpr;
890 unsigned char xbuf[256 / 8];
893 /* first, extract the q = dP value from the public key */
894 if (! (pub_sexpr = decode_public_encrypt_key (pub)))
895 return GNUNET_SYSERR;
896 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
897 gcry_sexp_release (pub_sexpr);
898 q = gcry_mpi_ec_get_point ("q", ctx, 0);
901 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_get_point", 0);
902 return GNUNET_SYSERR;
905 /* second, extract the d value from our private key */
906 mpi_scan (&d, priv->d, sizeof (priv->d));
908 /* then call the 'multiply' function, to compute the product */
909 result = gcry_mpi_point_new (0);
910 gcry_mpi_ec_mul (result, d, q, ctx);
911 gcry_mpi_point_release (q);
912 gcry_mpi_release (d);
914 /* finally, convert point to string for hashing */
915 result_x = gcry_mpi_new (256);
916 result_y = gcry_mpi_new (256);
917 if (0 != (rc = gcry_mpi_ec_get_affine (result_x, result_y, result, ctx)))
919 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_get_affine", rc);
920 gcry_mpi_point_release (result);
921 gcry_ctx_release (ctx);
922 return GNUNET_SYSERR;
924 gcry_mpi_point_release (result);
925 gcry_ctx_release (ctx);
927 mpi_print (xbuf, sizeof (xbuf), result_x);
928 GNUNET_CRYPTO_hash (xbuf, sizeof (xbuf), key_material);
929 gcry_mpi_release (result_x);
930 gcry_mpi_release (result_y);
936 * Derive the 'h' value for key derivation, where
939 * @param pub public key for deriviation
940 * @param label label for deriviation
941 * @param context additional context to use for HKDF of 'h';
942 * typically the name of the subsystem/application
946 derive_h (const struct GNUNET_CRYPTO_EccPublicSignKey *pub,
951 struct GNUNET_HashCode hc;
953 GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
954 "key-derivation", strlen ("key-derivation"),
956 label, strlen (label),
957 context, strlen (context),
959 mpi_scan (&h, (unsigned char *) &hc, sizeof (hc));
965 * Derive a private key from a given private key and a label.
966 * Essentially calculates a private key 'd = H(l,P) * x mod n'
967 * where n is the size of the ECC group and P is the public
968 * key associated with the private key 'd'.
970 * @param priv original private key
971 * @param label label to use for key deriviation
972 * @param context additional context to use for HKDF of 'h';
973 * typically the name of the subsystem/application
974 * @return derived private key
976 struct GNUNET_CRYPTO_EccPrivateKey *
977 GNUNET_CRYPTO_ecc_key_derive (const struct GNUNET_CRYPTO_EccPrivateKey *priv,
981 struct GNUNET_CRYPTO_EccPublicSignKey pub;
982 struct GNUNET_CRYPTO_EccPrivateKey *ret;
989 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
990 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
991 GNUNET_CRYPTO_ecc_key_get_public_for_signature (priv, &pub);
992 h = derive_h (&pub, label, context);
993 mpi_scan (&x, priv->d, sizeof (priv->d));
994 d = gcry_mpi_new (256);
995 gcry_mpi_mulm (d, h, x, n);
996 gcry_mpi_release (h);
997 gcry_mpi_release (x);
998 gcry_mpi_release (n);
999 gcry_ctx_release (ctx);
1000 ret = GNUNET_new (struct GNUNET_CRYPTO_EccPrivateKey);
1001 mpi_print (ret->d, sizeof (ret->d), d);
1002 gcry_mpi_release (d);
1008 * Derive a public key from a given public key and a label.
1009 * Essentially calculates a public key 'V = H(l,P) * P'.
1011 * @param pub original public key
1012 * @param label label to use for key deriviation
1013 * @param context additional context to use for HKDF of 'h';
1014 * typically the name of the subsystem/application
1015 * @param result where to write the derived public key
1018 GNUNET_CRYPTO_ecc_public_key_derive (const struct GNUNET_CRYPTO_EccPublicSignKey *pub,
1020 const char *context,
1021 struct GNUNET_CRYPTO_EccPublicSignKey *result)
1032 GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, NULL, CURVE));
1034 /* obtain point 'y' from original public key */
1035 mpi_scan (&q_y, pub->q_y, sizeof (pub->q_y));
1036 if (0 != (rc = gcry_mpi_ec_set_mpi ("y", q_y, ctx)))
1038 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_set_mpi", rc);
1041 gcry_mpi_release (q_y);
1043 /* calulcate h_mod_n = h % n */
1044 h = derive_h (pub, label, context);
1045 n = gcry_mpi_ec_get_mpi ("n", ctx, 1);
1046 GNUNET_assert (NULL != n);
1047 h_mod_n = gcry_mpi_new (256);
1048 gcry_mpi_mod (h_mod_n, h, n);
1049 /* calculate v = h_mod_n * q */
1050 v = gcry_mpi_point_new (0);
1051 q = gcry_mpi_ec_get_point ("q", ctx, 0);
1052 GNUNET_assert (NULL != q);
1053 gcry_mpi_ec_mul (v, h_mod_n, q, ctx);
1054 gcry_mpi_release (h_mod_n);
1055 gcry_mpi_release (h);
1056 gcry_mpi_release (n);
1057 gcry_mpi_point_release (q);
1058 /* convert point 'v' to public key that we return */
1059 if (0 != (rc = gcry_mpi_ec_set_point ("q", v, ctx)))
1060 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_ec_set_point", rc);
1061 gcry_mpi_point_release (v);
1062 if (NULL == (q_y = gcry_mpi_ec_get_mpi ("y", ctx, 0)))
1064 LOG_GCRY (GNUNET_ERROR_TYPE_ERROR,
1065 "gcry_mpi_ec_get_mpi", 0);
1068 mpi_print (result->q_y, sizeof (result->q_y), q_y);
1069 // gcry_mpi_release (q_y); /* needed? we set copy to 0... */
1070 gcry_ctx_release (ctx);
1074 /* end of crypto_ecc.c */