Reworked the ECC changes to better fit into the Libgcrypt API.
authorWerner Koch <wk@gnupg.org>
Mon, 31 Jan 2011 08:27:06 +0000 (09:27 +0100)
committerWerner Koch <wk@gnupg.org>
Mon, 31 Jan 2011 08:27:06 +0000 (09:27 +0100)
See ChangeLog for details.  Key generation, signing and verification works.
Encryption does not yet work.  Requires latest Libgcrypt changes.

12 files changed:
agent/ChangeLog
agent/protect.c
g10/ChangeLog
g10/build-packet.c
g10/ecdh.c
g10/keygen.c
g10/keyid.c
g10/main.h
g10/misc.c
g10/parse-packet.c
g10/pkglue.c
g10/pkglue.h

index 7dace3a..432803f 100644 (file)
@@ -1,3 +1,8 @@
+2011-01-27  Werner Koch  <wk@g10code.com>
+
+       * protect.c (protect_info): Adjust ECDSA and ECDH parameter names.
+       Add "ecc".
+
 2011-01-19  Werner Koch  <wk@g10code.com>
 
        * trustlist.c (read_one_trustfile): Also chop an CR.
index d0a5fe9..61ed8ee 100644 (file)
@@ -52,8 +52,9 @@ static struct {
   { "rsa",  "nedpqu", 2, 5 },
   { "dsa",  "pqgyx", 4, 4 },
   { "elg",  "pgyx", 3, 3 },
-  { "ecdsa","cqd", 2, 2 },
-  { "ecdh", "cqpd", 3, 3 },
+  { "ecdsa","pabgnqd", 6, 6 },
+  { "ecdh", "pabgnqd", 6, 6 },
+  { "ecc",  "pabgnqd", 6, 6 },
   { NULL }
 };
 
index b276015..f6c144d 100644 (file)
@@ -1,3 +1,37 @@
+2011-01-30  Werner Koch  <wk@g10code.com>
+
+
+       * keyid.c (keygrip_from_pk): Adjust ECC cases.
+       * pkglue.c (pk_verify): Ditto.
+
+       * parse-packet.c (read_size_body): Rewrite.
+       (parse_key): Simply ECC case.
+       (parse_pubkeyenc): Ditto.
+
+       * misc.c (pubkey_get_npkey): Special case ECC.
+       (pubkey_get_nskey): Ditto.
+       (mpi_print): Support printfing of opaque values.
+       (openpgp_oid_to_str): New.
+       (pubkey_nbits): For ECC pass curve parameter.
+
+       * ecdh.c (pk_ecdh_default_params): Change to return an opaque MPI.
+
+       * build-packet.c (do_key): Automatically handle real and opaque
+       key parameters.
+       (write_fake_data): Return an error code.
+       (mpi_write): Support writing opaque MPIs.
+       (do_pubkey_enc): Simplify ECC handling.
+
+2011-01-28  Werner Koch  <wk@g10code.com>
+
+       * keygen.c (gen_ecc): Rewrite.  Select a named curve and create a
+       keyspec based on that.
+       (pk_ecc_build_key_params): Remove.
+       (get_parameter_algo): Map algo number.
+       (ecckey_from_sexp): New.
+       * misc.c (map_pk_gcry_to_openpgp): New.
+       (openpgp_oid_from_str): New.  Based on libksba code.
+
 2011-01-26  Werner Koch  <wk@g10code.com>
 
        * misc.c (ecdsa_qbits_from_Q): Use unsigned int.
index e2bbdb5..122ef15 100644 (file)
@@ -1,6 +1,6 @@
 /* build-packet.c - assemble packets and write them
  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- *               2006, 2010 Free Software Foundation, Inc.
+ *               2006, 2010, 2011  Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -160,19 +160,31 @@ build_packet( IOBUF out, PACKET *pkt )
 static int
 mpi_write (iobuf_t out, gcry_mpi_t a)
 {
-  char buffer[(MAX_EXTERN_MPI_BITS+7)/8+2]; /* 2 is for the mpi length. */
-  size_t nbytes;
   int rc;
 
-  nbytes = DIM(buffer);
-  rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
-  if( !rc )
-    rc = iobuf_write( out, buffer, nbytes );
-  else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT )
+  if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
     {
-      log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a));
-      /* The buffer was too small. We better tell the user about the MPI. */
-      rc = gpg_error (GPG_ERR_TOO_LARGE);
+      size_t nbits;
+      const void *p;
+
+      p = gcry_mpi_get_opaque (a, &nbits);
+      rc = iobuf_write (out, p, (nbits+7)/8);
+    }
+  else
+    {
+      char buffer[(MAX_EXTERN_MPI_BITS+7)/8+2]; /* 2 is for the mpi length. */
+      size_t nbytes;
+
+      nbytes = DIM(buffer);
+      rc = gcry_mpi_print (GCRYMPI_FMT_PGP, buffer, nbytes, &nbytes, a );
+      if( !rc )
+        rc = iobuf_write( out, buffer, nbytes );
+      else if (gpg_err_code(rc) == GPG_ERR_TOO_SHORT )
+        {
+          log_info ("mpi too large (%u bits)\n", gcry_mpi_get_nbits (a));
+          /* The buffer was too small. We better tell the user about the MPI. */
+          rc = gpg_error (GPG_ERR_TOO_LARGE);
+        }
     }
 
   return rc;
@@ -252,19 +264,20 @@ calc_packet_length( PACKET *pkt )
     return n;
 }
 
-static void
+
+static gpg_error_t
 write_fake_data (IOBUF out, gcry_mpi_t a)
 {
-  if (a)
-    {
-      unsigned int n;
-      void *p;
+  unsigned int n;
+  void *p;
 
-      p = gcry_mpi_get_opaque ( a, &n );
-      iobuf_write (out, p, (n+7)/8 );
-    }
+  if (!a)
+    return 0;
+  p = gcry_mpi_get_opaque ( a, &n);
+  return iobuf_write (out, p, (n+7)/8 );
 }
 
+
 static int
 do_user_id( IOBUF out, int ctb, PKT_user_id *uid )
 {
@@ -326,33 +339,11 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
     }
   assert (npkey < nskey);
 
-  /* Writing the public parameters is easy.  Except if we do an
-     adjustment for ECC OID and possibly KEK params for ECDH.  */
-  if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
-      || pk->pubkey_algo == PUBKEY_ALGO_ECDH)
+  for (i=0; i < npkey; i++ )
     {
-      /* Write DER of OID with preceeding length byte.  */
-      err = write_size_body_mpi (a, pk->pkey[0]);
-      if (err)
-        goto leave;
-      /* Write point Q, the public key.  */
-      err = mpi_write (a, pk->pkey[1]);
+      err = mpi_write (a, pk->pkey[i]);
       if (err)
         goto leave;
-
-      /* Write one more public field for ECDH.  */
-      if (pk->pubkey_algo == PUBKEY_ALGO_ECDH)
-        {
-          err = write_size_body_mpi (a, pk->pkey[2]);
-          if (err)
-            goto leave;
-        }
-    }
-  else
-    {
-      for (i=0; i < npkey; i++ )
-        if ((err = mpi_write (a, pk->pkey[i])))
-          goto leave;
     }
 
 
@@ -520,20 +511,8 @@ do_pubkey_enc( IOBUF out, int ctb, PKT_pubkey_enc *enc )
   if ( !n )
     write_fake_data( a, enc->data[0] );
 
-  if (enc->pubkey_algo == PUBKEY_ALGO_ECDH )
-    {
-      /* The second field persists as a LEN+field structure, even
-       * though it is stored for uniformity as an MPI internally.  */
-      assert (n == 2);
-      rc = mpi_write (a, enc->data[0]);
-      if (!rc)
-        rc = write_size_body_mpi (a, enc->data[1]);
-    }
-  else
-    {
-      for (i=0; i < n && !rc ; i++ )
-        rc = mpi_write(a, enc->data[i] );
-    }
+  for (i=0; i < n && !rc ; i++ )
+    rc = mpi_write (a, enc->data[i]);
 
   if (!rc)
     {
index 95bd866..cf002b9 100644 (file)
@@ -48,16 +48,17 @@ static const struct
 
 
 
-/* Returns allocated (binary) KEK parameters; the size is returned in
-   sizeout.  The caller must free the returned value.  Returns NULL
-   and sets ERRNO on error.  */
-byte *
-pk_ecdh_default_params (unsigned int qbits, size_t *sizeout)
+/* Return KEK parameters as an opaque MPI The caller must free the
+   returned value.  Returns NULL and sets ERRNO on error.  */
+gcry_mpi_t
+pk_ecdh_default_params (unsigned int qbits)
 {
-  byte kek_params[4];
+  byte *kek_params;
   int i;
-  byte *buffer;
 
+  kek_params = xtrymalloc (4);
+  if (!kek_params)
+    return NULL;
   kek_params[0] = 3; /* Number of bytes to follow. */
   kek_params[1] = 1; /* Version for KDF+AESWRAP.   */ 
   
@@ -78,12 +79,7 @@ pk_ecdh_default_params (unsigned int qbits, size_t *sizeout)
   if (DBG_CIPHER)
     log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) );
   
-  buffer = xtrymalloc (sizeof(kek_params));
-  if (!buffer)
-    return NULL;
-  memcpy (buffer, kek_params, sizeof (kek_params));
-  *sizeout = sizeof (kek_params);
-  return buffer;
+  return gcry_mpi_set_opaque (NULL, kek_params, 4 * 8);
 }
 
 
@@ -411,8 +407,8 @@ gen_k (unsigned nbits)
       unsigned char *buffer;
       if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, k))
         BUG ();
-      log_debug("ephemeral scalar MPI #0: %s\n", buffer);
-      gcry_free( buffer );
+      log_debug ("ephemeral scalar MPI #0: %s\n", buffer);
+      gcry_free (buffer);
     }
 
   return k;
index b42121b..4d911f0 100644 (file)
@@ -1081,7 +1081,107 @@ write_keybinding (KBNODE root, PKT_public_key *pri_psk, PKT_public_key *sub_psk,
 }
 
 
+static gpg_error_t
+ecckey_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp, int algo)
+{
+  gpg_error_t err;
+  gcry_sexp_t list, l2;
+  char *curve;
+  int i;
+  const char *oidstr;
+  unsigned int nbits;
+
+  array[0] = NULL;
+  array[1] = NULL;
+  array[2] = NULL;
+
+  list = gcry_sexp_find_token (sexp, "public-key", 0);
+  if (!list)
+    return gpg_error (GPG_ERR_INV_OBJ);
+  l2 = gcry_sexp_cadr (list);
+  gcry_sexp_release (list);
+  list = l2;
+  if (!list)
+    return gpg_error (GPG_ERR_NO_OBJ);
+
+  l2 = gcry_sexp_find_token (list, "curve", 0);
+  if (!l2)
+    {
+      err = gpg_error (GPG_ERR_NO_OBJ);
+      goto leave;
+    }
+  curve = gcry_sexp_nth_string (l2, 1);
+  if (!curve)
+    {
+      err = gpg_error (GPG_ERR_NO_OBJ);
+      goto leave;
+    }
+  gcry_sexp_release (l2);
+  if (!strcmp (curve, "NIST P-256"))
+    {
+      oidstr = "1.2.840.10045.3.1.7";
+      nbits = 256;
+    }
+  else if (!strcmp (curve, "NIST P-384"))
+    {
+      oidstr = "1.3.132.0.34";
+      nbits = 384;
+    }
+  else if (!strcmp (curve, "NIST P-521"))
+    {
+      oidstr = "1.3.132.0.35";
+      nbits = 521;
+    }
+  else
+    {
+      err = gpg_error (GPG_ERR_INV_OBJ);
+      goto leave;
+    }
+  err = openpgp_oid_from_str (oidstr, &array[0]);
+  if (err)
+    goto leave;
+
+  l2 = gcry_sexp_find_token (list, "q", 0);
+  if (!l2)
+    {
+      err = gpg_error (GPG_ERR_NO_OBJ);
+      goto leave;
+    }
+  array[1] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
+  gcry_sexp_release (l2);
+  if (!array[1])
+    {
+      err = gpg_error (GPG_ERR_INV_OBJ);
+      goto leave;
+    }
+  gcry_sexp_release (list);
 
+  if (algo == PUBKEY_ALGO_ECDH)
+    {
+      array[2] = pk_ecdh_default_params (nbits);
+      if (!array[2])
+        {
+          err = gpg_error_from_syserror ();
+          goto leave;
+        }
+    }
+
+ leave:
+  if (err)
+    {
+      for (i=0; i < 3; i++)
+        {
+          gcry_mpi_release (array[i]);
+          array[i] = NULL;
+        }
+    }
+  return 0;
+}
+
+
+/* Extract key parameters from SEXP and store them in ARRAY.  ELEMS is
+   a string where each character denotes a parameter name.  TOPNAME is
+   the name of the top element above the elements.  */ 
 static int
 key_from_sexp (gcry_mpi_t *array, gcry_sexp_t sexp,
                const char *topname, const char *elems)
@@ -1165,7 +1265,10 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
     pk->expiredate = pk->timestamp + expireval;
   pk->pubkey_algo = algo;
 
-  err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
+  if (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH)
+    err = ecckey_from_sexp (pk->pkey, s_key, algo);
+  else
+    err = key_from_sexp (pk->pkey, s_key, "public-key", algoelem);
   if (err) 
     {
       log_error ("key_from_sexp failed: %s\n", gpg_strerror (err) );
@@ -1173,7 +1276,6 @@ common_gen (const char *keyparms, int algo, const char *algoelem,
       free_public_key (pk);
       return err;
     }
-  gcry_sexp_release (s_key);
   
   pkt = xtrycalloc (1, sizeof *pkt);
   if (!pkt)
@@ -1329,126 +1431,45 @@ gen_dsa (unsigned int nbits, KBNODE pub_root,
 
 
 
-/* Create an S-expression string out of QBITS, ALGO and the TRANSIENT
-   flag.  On success a malloced string is returned, on failure NULL
-   and ERRNO is set.  */
-static char *
-pk_ecc_build_key_params (int qbits, int algo, int transient)
-{
-  byte *kek_params = NULL;
-  size_t kek_params_size;
-  char qbitsstr[35];
-  char *result;
-  size_t n;
-
-  /* KEK parameters are only needed for long term key generation.  */
-  if (!transient && algo == PUBKEY_ALGO_ECDH)
-    {
-      kek_params = pk_ecdh_default_params (qbits, &kek_params_size);
-      if (!kek_params)
-        return NULL;
-    }
-  else
-    kek_params = NULL;
-
-  snprintf (qbitsstr, sizeof qbitsstr, "%u", qbits);
-  if (algo == PUBKEY_ALGO_ECDSA || !kek_params)
-    {
-      result = xtryasprintf ("(genkey(%s(nbits %zu:%s)"
-                               /**/      "(qbits %zu:%s)"
-                               /**/      "(transient-key 1:%d)))",
-                               algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
-                               strlen (qbitsstr), qbitsstr,
-                               strlen (qbitsstr), qbitsstr,
-                               transient);
-    }
-  else
-    {
-      char *tmpstr;
-
-      assert (kek_params);
-      tmpstr = xtryasprintf ("(genkey(ecdh(nbits %zu:%s)"
-                             /**/        "(qbits %zu:%s)"
-                             /**/        "(transient-key 1:%d)"
-                             /**/        "(kek-params %zu:",
-                             strlen (qbitsstr), qbitsstr,
-                             strlen (qbitsstr), qbitsstr,
-                             transient,
-                             kek_params_size);
-      if (!tmpstr)
-        {
-          xfree (kek_params);
-          return NULL;
-        }
-      /* Append the binary KEK parmas.  */
-      n = strlen (tmpstr);
-      result = xtryrealloc (tmpstr, n + kek_params_size + 4);
-      if (!result)
-        {
-          xfree (tmpstr);
-          xfree (kek_params);
-          return NULL;
-        }
-      memcpy (result + n, kek_params, kek_params_size);
-      strcpy (result + n + kek_params_size, ")))");
-    }
-  xfree (kek_params);
-  return result;
-}
-
-
 /*
  * Generate an ECC key
  */
 static gpg_error_t
-gen_ecc (int algo, unsigned int nbits, KBNODE pub_root,
+gen_ecc (int algo, unsigned int nbits, kbnode_t pub_root,
          u32 timestamp, u32 expireval, int is_subkey,
          int keygen_flags, char **cache_nonce_addr)
 {
-  int err;
-  unsigned int qbits;
+  gpg_error_t err;
+  const char *curve;
   char *keyparms;
 
   assert (algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH);
 
-  if (pubkey_get_npkey (PUBKEY_ALGO_ECDSA) != 2
-      || pubkey_get_nskey (PUBKEY_ALGO_ECDSA) != 3
-      || pubkey_get_npkey (PUBKEY_ALGO_ECDH)  != 3
-      || pubkey_get_nskey (PUBKEY_ALGO_ECDH)  != 4)
-    {
-      log_error ("broken version of Libgcrypt\n");
-      return gpg_error (GPG_ERR_INTERNAL);  /* ABI silently changed.  */
-    }
-
-  if (nbits != 256 && nbits != 384 && nbits != 521)
-    {
-      log_info (_("keysize invalid; using %u bits\n"), 256);
-      /* FIXME:  Where do we set it to 256?  */
-    }
-
-  /* Figure out a Q size based on the key size.  See gen_dsa for more
-     details.  Due to 8-bit rounding we may get 528 here instead of 521. */
-  nbits = qbits = (nbits < 521 ? nbits : 521 );
-
-  keyparms = pk_ecc_build_key_params
-    (qbits, algo,  !!( (keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
-                       && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION)) );
+  /* For now we may only use one of the 3 NISY curves.  */
+  if (nbits <= 256)
+    curve = "NIST P-256";
+  else if (nbits <= 384)
+    curve = "NIST P-384";
+  else 
+    curve = "NIST P-521";
+
+  keyparms = xtryasprintf ("(genkey(%s(curve %zu:%s)%s))", 
+                           algo == PUBKEY_ALGO_ECDSA ? "ecdsa" : "ecdh",
+                           strlen (curve), curve,
+                           ((keygen_flags & KEYGEN_FLAG_TRANSIENT_KEY)
+                            && (keygen_flags & KEYGEN_FLAG_NO_PROTECTION))?
+                           "(transient-key)" : "" );
   if (!keyparms)
-    {
-      err = gpg_error_from_syserror ();
-      log_error ("ecc pk_ecc_build_key_params failed: %s\n",
-                 gpg_strerror (err));
-    }
+    err = gpg_error_from_syserror ();
   else
     {
-      err = common_gen (keyparms, algo,
-                        algo == PUBKEY_ALGO_ECDSA? "cq" : "cqp",
+      err = common_gen (keyparms, algo, "",
                         pub_root, timestamp, expireval, is_subkey,
                         keygen_flags, cache_nonce_addr);
       xfree (keyparms);
     }
 
-  return 0;
+  return err;
 }
 
 
@@ -2428,7 +2449,7 @@ get_parameter_algo( struct para_data_s *para, enum para_name key,
            || !strcmp (r->u.value, "ELG"))
     i = GCRY_PK_ELG_E;
   else
-    i = gcry_pk_map_name (r->u.value);
+    i = map_pk_gcry_to_openpgp (gcry_pk_map_name (r->u.value));
 
   if (i == PUBKEY_ALGO_RSA_E || i == PUBKEY_ALGO_RSA_S)
     i = 0; /* we don't want to allow generation of these algorithms */
index 0405b8b..6571a51 100644 (file)
@@ -724,17 +724,20 @@ keygrip_from_pk (PKT_public_key *pk, unsigned char *array)
 
     case PUBKEY_ALGO_ECDSA:
     case PUBKEY_ALGO_ECDH:
-      err = gcry_sexp_build (&s_pkey, NULL,
-                             "(public-key(ecc(c%m)(q%m)))",
-                             pk->pkey[0], pk->pkey[1]);
+      {
+        char *curve = openpgp_oid_to_str (pk->pkey[0]);
+        if (!curve)
+          err = gpg_error_from_syserror ();
+        else
+          {
+            err = gcry_sexp_build (&s_pkey, NULL,
+                                   "(public-key(ecc(curve%s)(q%m)))",
+                                   curve, pk->pkey[1]);
+            xfree (curve);
+          }
+      }
       break;
 
-   /* case PUBKEY_ALGO_ECDH: */
-   /*    err = gcry_sexp_build (&s_pkey, NULL, */
-   /*                           "(public-key(ecdh(c%m)(q%m)(p%m)))", */
-   /*                           pk->pkey[0], pk->pkey[1], pk->pkey[2]); */
-   /*    break; */
-
     default:
       err = gpg_error (GPG_ERR_PUBKEY_ALGO);
       break;
index 4cec61f..d76d96b 100644 (file)
@@ -97,6 +97,7 @@ int openpgp_cipher_blocklen (int algo);
 int openpgp_cipher_test_algo( int algo );
 const char *openpgp_cipher_algo_name (int algo);
 int map_pk_openpgp_to_gcry (int algo);
+int map_pk_gcry_to_openpgp (enum gcry_pk_algos algo);
 int openpgp_pk_test_algo( int algo );
 int openpgp_pk_test_algo2 ( int algo, unsigned int use );
 int openpgp_pk_algo_usage ( int algo );
@@ -154,15 +155,21 @@ int is_valid_mailbox (const char *name);
 const char *get_libexecdir (void);
 int path_access(const char *file,int mode);
 
-/* Temporary helpers. */
 int pubkey_get_npkey( int algo );
 int pubkey_get_nskey( int algo );
 int pubkey_get_nsig( int algo );
 int pubkey_get_nenc( int algo );
+
+/* Temporary helpers. */
 unsigned int pubkey_nbits( int algo, gcry_mpi_t *pkey );
 int mpi_print (estream_t stream, gcry_mpi_t a, int mode);
 unsigned int ecdsa_qbits_from_Q (unsigned int qbits);
 
+/* Other stuff */
+gpg_error_t openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi);
+char *openpgp_oid_to_str (gcry_mpi_t a);
+
+
 /*-- status.c --*/
 void set_status_fd ( int fd );
 int  is_status_enabled ( void );
@@ -300,7 +307,7 @@ gpg_error_t export_pubkey_buffer (ctrl_t ctrl, const char *keyspec,
 int export_seckeys (ctrl_t ctrl, strlist_t users);
 int export_secsubkeys (ctrl_t ctrl, strlist_t users);
 
-/* dearmor.c --*/
+/*-- dearmor.c --*/
 int dearmor_file( const char *fname );
 int enarmor_file( const char *fname );
 
index dc2f73b..2052e96 100644 (file)
@@ -379,6 +379,19 @@ map_pk_openpgp_to_gcry (int algo)
     }
 }
 
+/* Map Gcrypt public key algorithm numbers to those used by
+   OpenPGP.  */
+int
+map_pk_gcry_to_openpgp (enum gcry_pk_algos algo)
+{
+  switch (algo)
+    {
+    case GCRY_PK_ECDSA:  return PUBKEY_ALGO_ECDSA;
+    case GCRY_PK_ECDH:   return PUBKEY_ALGO_ECDH;
+    default: return algo < 110 ? algo : 0;
+    }
+}
+
 
 /* Return the block length of an OpenPGP cipher algorithm.  */
 int 
@@ -1347,35 +1360,44 @@ path_access(const char *file,int mode)
 
 
 \f
-/* Temporary helper. */
+/* Return the number of public key parameters as used by OpenPGP.  */
 int
-pubkey_get_npkey( int algo )
+pubkey_get_npkey (int algo)
 {
   size_t n;
 
+  /* ECC is special.  */
+  if (algo == PUBKEY_ALGO_ECDSA)
+    return 2;
+  else if (algo == PUBKEY_ALGO_ECDH)
+    return 3;
+
+  /* All other algorithms match those of Libgcrypt.  */
   if (algo == GCRY_PK_ELG_E)
     algo = GCRY_PK_ELG;
-  else if (algo == PUBKEY_ALGO_ECDSA)
-    algo = GCRY_PK_ECDSA;
-  else if (algo == PUBKEY_ALGO_ECDH)
-    algo = GCRY_PK_ECDH;
-  if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
+
+  if (gcry_pk_algo_info (algo, GCRYCTL_GET_ALGO_NPKEY, NULL, &n))
     n = 0;
   return n;
 }
 
-/* Temporary helper. */
+
+/* Return the number of secret key parameters as used by OpenPGP.  */
 int
-pubkey_get_nskey( int algo )
+pubkey_get_nskey (int algo)
 {
   size_t n;
 
+  /* ECC is special.  */
+  if (algo == PUBKEY_ALGO_ECDSA)
+    return 3;
+  else if (algo == PUBKEY_ALGO_ECDH)
+    return 4;
+
+  /* All other algorithms match those of Libgcrypt.  */
   if (algo == GCRY_PK_ELG_E)
     algo = GCRY_PK_ELG;
-  else if (algo == PUBKEY_ALGO_ECDSA)
-    algo = GCRY_PK_ECDSA;
-  else if (algo == PUBKEY_ALGO_ECDH)
-    algo = GCRY_PK_ECDH;
+
   if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSKEY, NULL, &n ))
     n = 0;
   return n;
@@ -1383,33 +1405,40 @@ pubkey_get_nskey( int algo )
 
 /* Temporary helper. */
 int
-pubkey_get_nsig( int algo )
+pubkey_get_nsig (int algo)
 {
   size_t n;
 
+  /* ECC is special.  */
+  if (algo == PUBKEY_ALGO_ECDSA)
+    return 2;
+  else if (algo == PUBKEY_ALGO_ECDH)
+    return 0;
+
   if (algo == GCRY_PK_ELG_E)
     algo = GCRY_PK_ELG;
-  else if (algo == PUBKEY_ALGO_ECDSA)
-    algo = GCRY_PK_ECDSA;
-  else if (algo == PUBKEY_ALGO_ECDH)
-    algo = GCRY_PK_ECDH;
+
   if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NSIGN, NULL, &n))
     n = 0;
   return n;
 }
 
+
 /* Temporary helper. */
 int
-pubkey_get_nenc( int algo )
+pubkey_get_nenc (int algo)
 {
   size_t n;
   
+  /* ECC is special.  */
+  if (algo == PUBKEY_ALGO_ECDSA)
+    return 0;
+  else if (algo == PUBKEY_ALGO_ECDH)
+    return 2;
+
   if (algo == GCRY_PK_ELG_E)
     algo = GCRY_PK_ELG;
-  else if (algo == PUBKEY_ALGO_ECDSA)
-    algo = GCRY_PK_ECDSA;
-  else if (algo == PUBKEY_ALGO_ECDH)
-    algo = GCRY_PK_ECDH;
+
   if (gcry_pk_algo_info( algo, GCRYCTL_GET_ALGO_NENCR, NULL, &n ))
     n = 0;
   return n;
@@ -1442,9 +1471,16 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
                                  key[0], key[1] );
     }
     else if( algo == PUBKEY_ALGO_ECDSA || algo == PUBKEY_ALGO_ECDH ) {
-       rc = gcry_sexp_build ( &sexp, NULL,
-                             "(public-key(ecc(c%m)(q%m)))",
-                                 key[0], key[1] /* not affecting the size calculation, so use 'ecc' == 'ecdsa' */ );
+        char *curve = openpgp_oid_to_str (key[0]);
+        if (!curve)
+          rc = gpg_error_from_syserror ();
+        else
+          {
+            rc = gcry_sexp_build (&sexp, NULL,
+                                  "(public-key(ecc(curve%s)(q%m)))",
+                                 curve, key[1]);
+            xfree (curve);
+          }
     }
     else
        return 0;
@@ -1472,6 +1508,19 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
       n1 = gcry_mpi_get_nbits(a);
       n += es_fprintf (fp, "[%u bits]", n1);
     }
+  else if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    {
+      unsigned int nbits;
+      unsigned char *p = gcry_mpi_get_opaque (a, &nbits);
+      if (!p)
+        n += es_fprintf (fp, "[invalid opaque value]");
+      else
+        {
+          nbits = (nbits + 7)/8;
+          for (; nbits; nbits--, p++)
+            n += es_fprintf (fp, "%02X", *p);
+        }
+    }
   else
     {
       unsigned char *buffer;
@@ -1501,3 +1550,206 @@ ecdsa_qbits_from_Q (unsigned int qbits)
   qbits /= 2;
   return qbits;
 }
+
+
+
+/* Helper for openpgp_oid_from_str.  */
+static size_t
+make_flagged_int (unsigned long value, char *buf, size_t buflen)
+{
+  int more = 0;
+  int shift;
+
+  /* fixme: figure out the number of bits in an ulong and start with
+     that value as shift (after making it a multiple of 7) a more
+     straigtforward implementation is to do it in reverse order using
+     a temporary buffer - saves a lot of compares */
+  for (more=0, shift=28; shift > 0; shift -= 7)
+    {
+      if (more || value >= (1<<shift))
+        {
+          buf[buflen++] = 0x80 | (value >> shift);
+          value -= (value >> shift) << shift;
+          more = 1;
+        }
+    }
+  buf[buflen++] = value;
+  return buflen;
+}
+
+
+/* Convert the OID given in dotted decimal form in STRING to an DER
+ * encoding and store it as an opaque value at R_MPI.  The format of
+ * the DER encoded is not a regular ASN.1 object but the modified
+ * format as used by OpenPGP for the ECC curve description.  On error
+ * the function returns and error code an NULL is stored at R_BUG.
+ * Note that scanning STRING stops at the first white space
+ * character.  */
+gpg_error_t
+openpgp_oid_from_str (const char *string, gcry_mpi_t *r_mpi)
+{
+  unsigned char *buf;
+  size_t buflen;
+  unsigned long val1, val;
+  const char *endp;
+  int arcno;
+
+  *r_mpi = NULL;
+
+  if (!string || !*string)
+    return gpg_error (GPG_ERR_INV_VALUE);
+
+  /* We can safely assume that the encoded OID is shorter than the string. */
+  buf = xtrymalloc (1 + strlen (string) + 2);
+  if (!buf)
+    return gpg_error_from_syserror ();
+  /* Save the first byte for the length.  */
+  buflen = 1;
+
+  val1 = 0; /* Avoid compiler warning.  */
+  arcno = 0;
+  do {
+    arcno++;
+    val = strtoul (string, (char**)&endp, 10);
+    if (!digitp (string) || !(*endp == '.' || !*endp))
+      {
+        xfree (buf);
+        return gpg_error (GPG_ERR_INV_OID_STRING);
+      }
+    if (*endp == '.')
+      string = endp+1;
+
+    if (arcno == 1)
+      {
+        if (val > 2)
+          break; /* Not allowed, error catched below.  */
+        val1 = val;
+      }
+    else if (arcno == 2)
+      { /* Need to combine the first two arcs in one octet.  */
+        if (val1 < 2)
+          {
+            if (val > 39)
+              {
+                xfree (buf);
+                return gpg_error (GPG_ERR_INV_OID_STRING);
+              }
+            buf[buflen++] = val1*40 + val;
+          }
+        else
+          {
+            val += 80;
+            buflen = make_flagged_int (val, buf, buflen);
+          }
+      }
+    else
+      {
+        buflen = make_flagged_int (val, buf, buflen);
+      }
+  } while (*endp == '.');
+
+  if (arcno == 1 || buflen < 2 || buflen > 254 )
+    { /* It is not possible to encode only the first arc.  */
+      xfree (buf);
+      return gpg_error (GPG_ERR_INV_OID_STRING);
+    }
+
+  *buf = buflen - 1;
+  *r_mpi = gcry_mpi_set_opaque (NULL, buf, buflen * 8);
+  if (!*r_mpi)
+    {
+      xfree (buf);
+      return gpg_error_from_syserror ();
+    }
+  return 0; 
+}
+
+
+/* Return a malloced string represenation of the OID in the opaque MPI
+   A.  In case of an error NULL is returned and ERRNO is set.  */
+char *
+openpgp_oid_to_str (gcry_mpi_t a)
+{
+  const unsigned char *buf;
+  size_t length;
+  char *string, *p;
+  int n = 0;
+  unsigned long val, valmask;
+
+  valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
+
+  if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+
+  buf = gcry_mpi_get_opaque (a, &length);
+  length = (length+7)/8;
+
+  /* The first bytes gives the length; check consistency.  */
+  if (!length || buf[0] != length -1)
+    {
+      gpg_err_set_errno (EINVAL);
+      return NULL;
+    }
+  /* Skip length byte.  */
+  length--;
+  buf++;
+
+  /* To calculate the length of the string we can safely assume an
+     upper limit of 3 decimal characters per byte.  Two extra bytes
+     account for the special first octect */
+  string = p = xtrymalloc (length*(1+3)+2+1);
+  if (!string)
+    return NULL;
+  if (!buf || !length)
+    {
+      *p = 0;
+      return string;
+    }
+
+  if (buf[0] < 40)
+    p += sprintf (p, "0.%d", buf[n]);
+  else if (buf[0] < 80)
+    p += sprintf (p, "1.%d", buf[n]-40);
+  else {
+    val = buf[n] & 0x7f;
+    while ( (buf[n]&0x80) && ++n < length )
+      {
+        if ( (val & valmask) )
+          goto badoid;  /* Overflow.  */
+        val <<= 7;
+        val |= buf[n] & 0x7f;
+      }
+    val -= 80;
+    sprintf (p, "2.%lu", val);
+    p += strlen (p);
+  }
+  for (n++; n < length; n++)
+    {
+      val = buf[n] & 0x7f;
+      while ( (buf[n]&0x80) && ++n < length )
+        {
+          if ( (val & valmask) )
+            goto badoid;  /* Overflow.  */
+          val <<= 7;
+          val |= buf[n] & 0x7f;
+        }
+      sprintf (p, ".%lu", val);
+      p += strlen (p);
+    }
+    
+  *p = 0;
+  return string;
+
+ badoid:
+  /* Return a special OID (gnu.gnupg.badoid) to indicate the error
+     case.  The OID is broken and thus we return one which can't do
+     any harm.  Formally this does not need to be a bad OID but an OID
+     with an arc that can't be represented in a 32 bit word is more
+     than likely corrupt.  */
+  xfree (string);
+  return xtrystrdup ("1.3.6.1.4.1.11591.2.12242973"); 
+}
+
index a0844c7..83be15d 100644 (file)
@@ -741,51 +741,57 @@ read_rest (IOBUF inp, size_t pktlen, int partial)
 }
 
 
-/*
- * Read a special size+body from inp into body[body_max_size] and
- * return it in a buffer and as MPI.  On success the number of
- * consumed bytes will body[0]+1.  The format of the content of the
- * returned MPI is one byte LEN, following by LEN bytes.  Caller is
- * expected to pre-allocate fixed-size 255 byte buffer (or smaller
- * when appropriate).
- */
-static int
-read_size_body (iobuf_t inp, byte *body, int body_max_size,
-                int pktlen, gcry_mpi_t *out )
+/* Read a special size+body from INP.  On success store an opaque MPI
+   with it at R_DATA.  On error return an error code and store NULL at
+   R_DATA.  Even in the error case store the number of read bytes at
+   R_NREAD.  The caller shall pass the remaining size of the packet in
+   PKTLEN.  */
+static gpg_error_t
+read_size_body (iobuf_t inp, int pktlen, size_t *r_nread,
+                gcry_mpi_t *r_data)
 {
-  unsigned int n;
-  int rc;
-  gcry_mpi_t result;
+  char buffer[256];
+  char *tmpbuf;
+  int i, c, nbytes;
+
+  *r_nread = 0;
+  *r_data = NULL;
+
+  if (!pktlen)
+    return gpg_error (GPG_ERR_INV_PACKET);
+  c = iobuf_readbyte (inp);
+  if (c < 0)
+    return gpg_error (GPG_ERR_INV_PACKET);
+  pktlen--;
+  ++*r_nread;
+  nbytes = c;
+  if (nbytes < 2 || nbytes > 254)
+    return gpg_error (GPG_ERR_INV_PACKET);
+  if (nbytes > pktlen)
+    return gpg_error (GPG_ERR_INV_PACKET);
 
-  *out = NULL;
+  buffer[0] = nbytes;
 
-  if( (n = iobuf_readbyte(inp)) == -1 )
-    {
-      return G10ERR_INVALID_PACKET;
-    }
-  if ( n >= body_max_size || n < 2)
-    {
-      log_error("invalid size+body field\n");
-      return G10ERR_INVALID_PACKET;
-    }
-  body[0] = n;
-  if ((n = iobuf_read(inp, body+1, n)) == -1)
+  for (i = 0; i < nbytes; i++)
     {
-      log_error("invalid size+body field\n");
-      return G10ERR_INVALID_PACKET;
+      c = iobuf_get (inp);
+      if (c < 0)
+        return gpg_error (GPG_ERR_INV_PACKET);
+      ++*r_nread;
+      buffer[1+i] = c;
     }
-  if (n+1 > pktlen)
+
+  tmpbuf = xtrymalloc (1 + nbytes);
+  if (!tmpbuf)
+    return gpg_error_from_syserror ();
+  memcpy (tmpbuf, buffer, 1 + nbytes);
+  *r_data = gcry_mpi_set_opaque (NULL, tmpbuf, 8 * (1 + nbytes));
+  if (!*r_data)
     {
-      log_error("size+body field is larger than the packet\n");
-      return G10ERR_INVALID_PACKET;
+      xfree (tmpbuf);
+      return gpg_error_from_syserror ();
     }
-  rc = gcry_mpi_scan (&result, GCRYMPI_FMT_USG, body, n+1, NULL);
-  if (rc)
-    log_fatal ("mpi_scan failed: %s\n", gpg_strerror (rc));
-
-  *out = result;
-
-  return rc;
+  return 0;
 }
 
 
@@ -988,46 +994,29 @@ parse_pubkeyenc (IOBUF inp, int pkttype, unsigned long pktlen,
     }
   else
     {
-      if (k->pubkey_algo == PUBKEY_ALGO_ECDH)
+      for (i = 0; i < ndata; i++)
         {
-          byte encr_buf[255];
-          
-          assert (ndata == 2);
-          n = pktlen;
-          k->data[0] = mpi_read (inp, &n, 0);
-          pktlen -= n;
-          rc = read_size_body (inp, encr_buf, sizeof(encr_buf),
-                               pktlen, k->data+1);
-          if (rc)
-            goto leave;
-
-          if (list_mode)
+          if (k->pubkey_algo == PUBKEY_ALGO_ECDH && i == 1)
             {
-              es_fprintf (listfp, "\tdata: ");
-              mpi_print (listfp, k->data[0], mpi_print_mode );
-              es_putc ('\n', listfp);
-              es_fprintf (listfp, "\tdata: [% 3d bytes] ", encr_buf[0]+1);
-              mpi_print (listfp, k->data[1], mpi_print_mode );
-              es_putc ('\n', listfp);
+              rc = read_size_body (inp, pktlen, &n, k->data+i);
+              pktlen -= n;
             }
-          pktlen -= (encr_buf[0]+1);
-        }
-      else
-        {
-          for (i = 0; i < ndata; i++)
+          else
             {
               n = pktlen;
               k->data[i] = mpi_read (inp, &n, 0);
               pktlen -= n;
-              if (list_mode)
-                {
-                  es_fprintf (listfp, "\tdata: ");
-                  mpi_print (listfp, k->data[i], mpi_print_mode);
-                  es_putc ('\n', listfp);
-                }
               if (!k->data[i])
                 rc = gpg_error (GPG_ERR_INV_PACKET);
             }
+          if (rc)
+            goto leave;
+          if (list_mode)
+            {
+              es_fprintf (listfp, "\tdata: ");
+              mpi_print (listfp, k->data[i], mpi_print_mode);
+              es_putc ('\n', listfp);
+            }
         }
     }
 
@@ -1989,7 +1978,6 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
       unknown_pubkey_warning (algorithm);
     }
 
-
   if (!npkey)
     {
       /* Unknown algorithm - put data into an opaque MPI.  */
@@ -2001,79 +1989,32 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
     }
   else
     {
-      /* Fill in public key parameters.  */
-      if (algorithm == PUBKEY_ALGO_ECDSA || algorithm == PUBKEY_ALGO_ECDH)
+      for (i = 0; i < npkey; i++)
         {
-          /* FIXME: The code in this function ignores the errors.  */
-          byte name_oid[256];
-          
-          err = read_size_body (inp, name_oid, sizeof(name_oid),
-                                pktlen, pk->pkey+0);
-          if (err)
-            goto leave;
-          n = name_oid[0];
-          if (list_mode)
-            es_fprintf (listfp, "\tpkey[0]: curve OID [%d] ...%02x %02x\n", 
-                       n, name_oid[1+n-2], name_oid[1+n-1]);
-          pktlen -= (n+1);
-          /* Set item [1], which corresponds to the public key; these
-             two fields are all we need to uniquely define the key/ */
-          n = pktlen;
-          pk->pkey[1] = mpi_read( inp, &n, 0 );
-          pktlen -=n;
-          if (!pk->pkey[1])
-            err = gpg_error (GPG_ERR_INV_PACKET);
-          else if (list_mode)
+          if ((algorithm == PUBKEY_ALGO_ECDSA
+               || algorithm == PUBKEY_ALGO_ECDH) && (i==0 || i == 2))
             {
-              es_fprintf (listfp, "\tpkey[1]: ");
-              mpi_print (listfp, pk->pkey[1], mpi_print_mode);
-              es_putc ('\n', listfp);
-           }
-          /* One more field for ECDH. */
-          if (algorithm == PUBKEY_ALGO_ECDH)
-            {
-              /* (NAMEOID holds the KEK params.)  */
-              err = read_size_body (inp, name_oid, sizeof(name_oid),
-                                    pktlen, pk->pkey+2);
-              if (err)
-                goto leave;
-              n = name_oid[0];
-              if (name_oid[1] != 1)
-                {
-                  log_error ("invalid ecdh KEK parameters field type in "
-                             "private key: understand type 1, "
-                             "but found 0x%02x\n", name_oid[1]);
-                  err = gpg_error (GPG_ERR_INV_PACKET);
-                  goto leave;
-                }
-              if (list_mode)
-                es_fprintf (listfp, "\tpkey[2]: KEK params type=01 "
-                            "hash:%d sym-algo:%d\n",
-                            name_oid[1+n-2], name_oid[1+n-1]);
-              pktlen -= (n+1);
+              err = read_size_body (inp, pktlen, &n, pk->pkey+i);
+              pktlen -= n;
             }
-        }
-      else
-        {
-          for (i = 0; i < npkey; i++)
+          else
             {
               n = pktlen;
               pk->pkey[i] = mpi_read (inp, &n, 0);
               pktlen -= n;
-              if (list_mode)
-                {
-                  es_fprintf (listfp, "\tpkey[%d]: ", i);
-                  mpi_print (listfp, pk->pkey[i], mpi_print_mode);
-                  es_putc ('\n', listfp);
-                }
               if (!pk->pkey[i])
                 err = gpg_error (GPG_ERR_INV_PACKET);
             }
+          if (err)
+            goto leave;
+          if (list_mode)
+            {
+              es_fprintf (listfp, "\tpkey[%d]: ", i);
+              mpi_print (listfp, pk->pkey[i], mpi_print_mode);
+              es_putc ('\n', listfp);
+            }
         }
-      if (err)
-       goto leave;
     }
-
   if (list_mode)
     keyid_from_pk (pk, keyid);
 
index 3aba4e4..27ee239 100644 (file)
@@ -79,8 +79,16 @@ pk_verify (int algo, gcry_mpi_t hash, gcry_mpi_t *data, gcry_mpi_t *pkey)
     }
   else if (pkalgo == GCRY_PK_ECDSA) /* Same as GCRY_PK_ECDH */
     {
-      rc = gcry_sexp_build (&s_pkey, NULL,
-                           "(public-key(ecdsa(c%m)(q%m)))", pkey[0], pkey[1]);
+      char *curve = openpgp_oid_to_str (pkey[0]);
+      if (!curve)
+        rc = gpg_error_from_syserror ();
+      else
+        {
+          rc = gcry_sexp_build (&s_pkey, NULL,
+                                "(public-key(ecdsa(curve %s)(q%m)))",
+                                curve, pkey[1]);
+          xfree (curve);
+        }
     }
   else
     return GPG_ERR_PUBKEY_ALGO;
@@ -174,18 +182,27 @@ pk_encrypt (int algo, gcry_mpi_t *resarr, gcry_mpi_t data,
   else if (algo == PUBKEY_ALGO_ECDH)   
     {
       gcry_mpi_t k;
+      char *curve;
 
       rc = pk_ecdh_generate_ephemeral_key (pkey, &k);
       if (rc)
         return rc;
       
-      /* Now use the ephemeral secret to compute the shared point.  */
-      rc = gcry_sexp_build (&s_pkey, NULL,
-                            "(public-key(ecdh(c%m)(q%m)(p%m)))",
-                            pkey[0], pkey[1], pkey[2]);
-      /* Put K into a simplified S-expression.  */
-      if (rc || gcry_sexp_build (&s_data, NULL, "%m", k))
-        BUG ();
+      curve = openpgp_oid_to_str (pkey[0]);
+      if (!curve)
+        rc = gpg_error_from_syserror ();
+      else
+        {
+          /* Now use the ephemeral secret to compute the shared point.  */
+          rc = gcry_sexp_build (&s_pkey, NULL,
+                                "(public-key(ecdh(curve%s)(q%m)))",
+                                curve, pkey[1]);
+          xfree (curve);
+          /* FIXME: Take care of RC.  */
+          /* Put K into a simplified S-expression.  */
+          if (rc || gcry_sexp_build (&s_data, NULL, "%m", k))
+            BUG ();
+        }
     }
   else
     return gpg_error (GPG_ERR_PUBKEY_ALGO);
@@ -272,9 +289,16 @@ pk_check_secret_key (int algo, gcry_mpi_t *skey)
     }
   else if (gcry_pkalgo == GCRY_PK_ECDSA || gcry_pkalgo == GCRY_PK_ECDH)
     {
-      rc = gcry_sexp_build (&s_skey, NULL,
-                           "(private-key(ecdsa(c%m)(q%m)(d%m)))",
-                           skey[0], skey[1], skey[2] );
+      char *curve = openpgp_oid_to_str (skey[0]);
+      if (!curve)
+        rc = gpg_error_from_syserror ();
+      else
+        {
+          rc = gcry_sexp_build (&s_skey, NULL,
+                                "(private-key(ecdsa(curve%s)(q%m)(d%m)))",
+                                curve, skey[1], skey[2]);
+          xfree (curve);
+        }
     }
   else
     return GPG_ERR_PUBKEY_ALGO;
index 98d8c14..eb0d7c1 100644 (file)
@@ -32,7 +32,7 @@ int pk_check_secret_key (int algo, gcry_mpi_t *skey);
 
 
 /*-- ecdh.c --*/
-byte *pk_ecdh_default_params (unsigned int qbits, size_t *sizeout);
+gcry_mpi_t  pk_ecdh_default_params (unsigned int qbits);
 gpg_error_t pk_ecdh_generate_ephemeral_key (gcry_mpi_t *pkey, gcry_mpi_t *r_k);
 gpg_error_t pk_ecdh_encrypt_with_shared_point
 /*         */  (int is_encrypt, gcry_mpi_t shared_mpi,