Link libgnunetblockgroup to libgnunetblock
[oweals/gnunet.git] / src / util / crypto_ecc.c
index bcc04fea5c49cc3fdfc456d0486458d428ce0034..eaa49a99190e0c5d7f5bc31739f1340c548afdcf 100644 (file)
@@ -1,6 +1,6 @@
 /*
      This file is part of GNUnet.
-     Copyright (C) 2012, 2013, 2015 Christian Grothoff (and other contributing authors)
+     Copyright (C) 2012, 2013, 2015 GNUnet e.V.
 
      GNUnet is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published
  */
 #define CURVE "Ed25519"
 
-#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
+#define LOG(kind,...) GNUNET_log_from (kind, "util-crypto-ecc", __VA_ARGS__)
 
-#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
+#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-crypto-ecc", syscall)
 
-#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
+#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-crypto-ecc", syscall, filename)
 
 /**
  * Log an error message at log-level 'level' that indicates
@@ -488,6 +488,28 @@ struct GNUNET_CRYPTO_EcdhePrivateKey *
 GNUNET_CRYPTO_ecdhe_key_create ()
 {
   struct GNUNET_CRYPTO_EcdhePrivateKey *priv;
+
+  priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
+  if (GNUNET_OK !=
+      GNUNET_CRYPTO_ecdhe_key_create2 (priv))
+  {
+    GNUNET_free (priv);
+    return NULL;
+  }
+  return priv;
+}
+
+
+/**
+ * @ingroup crypto
+ * Create a new private key.  Clear with #GNUNET_CRYPTO_ecdhe_key_clear().
+ *
+ * @param[out] pk set to fresh private key;
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
+ */
+int
+GNUNET_CRYPTO_ecdhe_key_create2 (struct GNUNET_CRYPTO_EcdhePrivateKey *pk)
+{
   gcry_sexp_t priv_sexp;
   gcry_sexp_t s_keyparam;
   gcry_mpi_t d;
@@ -503,13 +525,13 @@ GNUNET_CRYPTO_ecdhe_key_create ()
                                   "(flags eddsa no-keytest)))")))
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
-    return NULL;
+    return GNUNET_SYSERR;
   }
   if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_genkey", rc);
     gcry_sexp_release (s_keyparam);
-    return NULL;
+    return GNUNET_SYSERR;
   }
   gcry_sexp_release (s_keyparam);
 #if EXTRA_CHECKS
@@ -517,20 +539,19 @@ GNUNET_CRYPTO_ecdhe_key_create ()
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
     gcry_sexp_release (priv_sexp);
-    return NULL;
+    return GNUNET_SYSERR;
   }
 #endif
   if (0 != (rc = key_from_sexp (&d, priv_sexp, "private-key", "d")))
   {
     LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "key_from_sexp", rc);
     gcry_sexp_release (priv_sexp);
-    return NULL;
+    return GNUNET_SYSERR;
   }
   gcry_sexp_release (priv_sexp);
-  priv = GNUNET_new (struct GNUNET_CRYPTO_EcdhePrivateKey);
-  GNUNET_CRYPTO_mpi_print_unsigned (priv->d, sizeof (priv->d), d);
+  GNUNET_CRYPTO_mpi_print_unsigned (pk->d, sizeof (pk->d), d);
   gcry_mpi_release (d);
-  return priv;
+  return GNUNET_OK;
 }
 
 
@@ -1028,9 +1049,10 @@ derive_h (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
 {
   gcry_mpi_t h;
   struct GNUNET_HashCode hc;
+  static const char *const salt = "key-derivation";
 
   GNUNET_CRYPTO_kdf (&hc, sizeof (hc),
-                    "key-derivation", strlen ("key-derivation"),
+                    salt, strlen (salt),
                     pub, sizeof (*pub),
                     label, strlen (label),
                     context, strlen (context),
@@ -1298,6 +1320,77 @@ GNUNET_CRYPTO_eddsa_ecdh (const struct GNUNET_CRYPTO_EddsaPrivateKey *priv,
   return GNUNET_OK;
 }
 
+/**
+ * @ingroup crypto
+ * Derive key material from a ECDH public key and a private ECDSA key.
+ * Dual to #GNUNET_CRRYPTO_ecdh_eddsa.
+ *
+ * @param priv private key from ECDSA to use for the ECDH (x)
+ * @param pub public key to use for the ECDH (yG)
+ * @param key_material where to write the key material H(h(x)yG)
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_ecdsa_ecdh (const struct GNUNET_CRYPTO_EcdsaPrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EcdhePublicKey *pub,
+                          struct GNUNET_HashCode *key_material)
+{
+  gcry_mpi_point_t result;
+  gcry_mpi_point_t q;
+  gcry_mpi_t d;
+  gcry_ctx_t ctx;
+  gcry_sexp_t pub_sexpr;
+  gcry_mpi_t result_x;
+  unsigned char xbuf[256 / 8];
+  size_t rsize;
+
+  /* first, extract the q = dP value from the public key */
+  if (0 != gcry_sexp_build (&pub_sexpr, NULL,
+                            "(public-key(ecc(curve " CURVE ")(q %b)))",
+                            (int)sizeof (pub->q_y), pub->q_y))
+    return GNUNET_SYSERR;
+  GNUNET_assert (0 == gcry_mpi_ec_new (&ctx, pub_sexpr, NULL));
+  gcry_sexp_release (pub_sexpr);
+  q = gcry_mpi_ec_get_point ("q", ctx, 0);
+
+  /* second, extract the d value from our private key */
+  GNUNET_CRYPTO_mpi_scan_unsigned (&d, priv->d, sizeof (priv->d));
+
+  /* then call the 'multiply' function, to compute the product */
+  result = gcry_mpi_point_new (0);
+  gcry_mpi_ec_mul (result, d, q, ctx);
+  gcry_mpi_point_release (q);
+  gcry_mpi_release (d);
+
+  /* finally, convert point to string for hashing */
+  result_x = gcry_mpi_new (256);
+  if (gcry_mpi_ec_get_affine (result_x, NULL, result, ctx))
+  {
+    LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "get_affine failed", 0);
+    gcry_mpi_point_release (result);
+    gcry_ctx_release (ctx);
+    return GNUNET_SYSERR;
+  }
+  gcry_mpi_point_release (result);
+  gcry_ctx_release (ctx);
+
+  rsize = sizeof (xbuf);
+  GNUNET_assert (! gcry_mpi_get_flag (result_x, GCRYMPI_FLAG_OPAQUE));
+  /* result_x can be negative here, so we do not use 'GNUNET_CRYPTO_mpi_print_unsigned'
+     as that does not include the sign bit; x should be a 255-bit
+     value, so with the sign it should fit snugly into the 256-bit
+     xbuf */
+  GNUNET_assert (0 ==
+                 gcry_mpi_print (GCRYMPI_FMT_STD, xbuf, rsize, &rsize,
+                                 result_x));
+  GNUNET_CRYPTO_hash (xbuf,
+                      rsize,
+                      key_material);
+  gcry_mpi_release (result_x);
+  return GNUNET_OK;
+}
+
+
 
 /**
  * @ingroup crypto
@@ -1369,6 +1462,24 @@ GNUNET_CRYPTO_ecdh_eddsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
   return GNUNET_OK;
 }
 
-
+/**
+ * @ingroup crypto
+ * Derive key material from a ECDSA public key and a private ECDH key.
+ * Dual to #GNUNET_CRRYPTO_eddsa_ecdh.
+ *
+ * @param priv private key to use for the ECDH (y)
+ * @param pub public key from ECDSA to use for the ECDH (X=h(x)G)
+ * @param key_material where to write the key material H(yX)=H(h(x)yG)
+ * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
+ */
+int
+GNUNET_CRYPTO_ecdh_ecdsa (const struct GNUNET_CRYPTO_EcdhePrivateKey *priv,
+                          const struct GNUNET_CRYPTO_EcdsaPublicKey *pub,
+                          struct GNUNET_HashCode *key_material)
+{
+  return GNUNET_CRYPTO_ecdh_eddsa (priv,
+                                   (const struct GNUNET_CRYPTO_EddsaPublicKey *)pub,
+                                   key_material);
+}
 
 /* end of crypto_ecc.c */