pubkey: Move sexp parsing of remaining fucntions to the modules.
[libgcrypt.git] / cipher / ecc.c
index f98a5cc..bd4d253 100644 (file)
@@ -1397,66 +1397,106 @@ ecc_generate (const gcry_sexp_t genparms, gcry_sexp_t *r_skey)
 
 
 static gcry_err_code_t
-ecc_check_secret_key (int algo, gcry_mpi_t *skey)
+ecc_check_secret_key (gcry_sexp_t keyparms)
 {
-  gpg_err_code_t err;
+  gcry_err_code_t rc;
+  gcry_sexp_t l1 = NULL;
+  char *curvename = NULL;
+  gcry_mpi_t mpi_g = NULL;
+  gcry_mpi_t mpi_q = NULL;
   ECC_secret_key sk;
 
-  (void)algo;
-
-  /* FIXME:  This check looks a bit fishy:  Now long is the array?  */
-  if (!skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4] || !skey[5]
-      || !skey[6])
-    return GPG_ERR_BAD_MPI;
+  memset (&sk, 0, sizeof sk);
 
-  sk.E.model = MPI_EC_WEIERSTRASS;
-  sk.E.p = skey[0];
-  sk.E.a = skey[1];
-  sk.E.b = skey[2];
-  point_init (&sk.E.G);
-  err = _gcry_ecc_os2ec (&sk.E.G, skey[3]);
-  if (err)
+  /*
+   * Extract the key.
+   */
+  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?/q?+d",
+                                   &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                                   &mpi_q, &sk.d, NULL);
+  if (rc)
+    goto leave;
+  if (mpi_g)
+    {
+      point_init (&sk.E.G);
+      rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g);
+      if (rc)
+        goto leave;
+    }
+  /* Add missing parameters using the optional curve parameter.  */
+  gcry_sexp_release (l1);
+  l1 = gcry_sexp_find_token (keyparms, "curve", 5);
+  if (l1)
+    {
+      curvename = gcry_sexp_nth_string (l1, 1);
+      if (curvename)
+        {
+          rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL);
+          if (rc)
+            return rc;
+        }
+    }
+  /* Guess required fields if a curve parameter has not been given.
+     FIXME: This is a crude hacks.  We need to fix that.  */
+  if (!curvename)
     {
-      point_free (&sk.E.G);
-      return err;
+      sk.E.model = MPI_EC_WEIERSTRASS;
+      sk.E.dialect = ECC_DIALECT_STANDARD;
     }
-  sk.E.n = skey[4];
-  point_init (&sk.Q);
-  err = _gcry_ecc_os2ec (&sk.Q, skey[5]);
-  if (err)
+  if (DBG_CIPHER)
     {
-      point_free (&sk.E.G);
-      point_free (&sk.Q);
-      return err;
+      log_debug ("ecc_testkey inf: %s/%s\n",
+                 _gcry_ecc_model2str (sk.E.model),
+                 _gcry_ecc_dialect2str (sk.E.dialect));
+      if (sk.E.name)
+        log_debug  ("ecc_testkey nam: %s\n", sk.E.name);
+      log_printmpi ("ecc_testkey   p", sk.E.p);
+      log_printmpi ("ecc_testkey   a", sk.E.a);
+      log_printmpi ("ecc_testkey   b", sk.E.b);
+      log_printpnt ("ecc_testkey g",   &sk.E.G, NULL);
+      log_printmpi ("ecc_testkey   n", sk.E.n);
+      log_printmpi ("ecc_testkey   q", mpi_q);
+      if (!fips_mode ())
+        log_printmpi ("ecc_testkey   d", sk.d);
+    }
+  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d)
+    {
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
     }
 
-  {
-    const unsigned char *buf;
-    unsigned int n;
-
-    gcry_assert (mpi_is_opaque (skey[6]));
+  if (mpi_q)
+    {
+      point_init (&sk.Q);
+      rc = _gcry_ecc_os2ec (&sk.Q, mpi_q);
+      if (rc)
+        goto leave;
+    }
+  else
+    {
+      /* The current test requires Q.  */
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
+    }
 
-    buf = gcry_mpi_get_opaque (skey[6], &n);
-    if (!buf)
-      err = GPG_ERR_INV_OBJ;
-    else
-      {
-        n = (n + 7)/8;
-        sk.d = NULL;
-        err = gcry_mpi_scan (&sk.d, GCRYMPI_FMT_USG, buf, n, NULL);
-        if (!err)
-          {
-            if (check_secret_key (&sk))
-              err = GPG_ERR_BAD_SECKEY;
-            gcry_mpi_release (sk.d);
-            sk.d = NULL;
-          }
-      }
-  }
+  if (check_secret_key (&sk))
+    rc = GPG_ERR_BAD_SECKEY;
 
+ leave:
+  gcry_mpi_release (sk.E.p);
+  gcry_mpi_release (sk.E.a);
+  gcry_mpi_release (sk.E.b);
+  gcry_mpi_release (mpi_g);
   point_free (&sk.E.G);
+  gcry_mpi_release (sk.E.n);
+  gcry_mpi_release (mpi_q);
   point_free (&sk.Q);
-  return err;
+  gcry_mpi_release (sk.d);
+  gcry_free (curvename);
+  gcry_sexp_release (l1);
+  if (DBG_CIPHER)
+    log_debug ("ecc_testkey   => %s\n", gpg_strerror (rc));
+  return rc;
 }
 
 
@@ -1786,46 +1826,106 @@ ecc_verify (gcry_sexp_t s_sig, gcry_sexp_t s_data, gcry_sexp_t s_keyparms)
  *     result[0] : shared point (kdG)
  */
 static gcry_err_code_t
-ecc_encrypt_raw (int algo, gcry_sexp_t *r_result, gcry_mpi_t k,
-                 gcry_mpi_t *pkey, int flags)
+ecc_encrypt_raw (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
-  gpg_err_code_t rc;
+  gcry_err_code_t rc;
+  struct pk_encoding_ctx ctx;
+  gcry_sexp_t l1 = NULL;
+  char *curvename = NULL;
+  gcry_mpi_t mpi_g = NULL;
+  gcry_mpi_t mpi_q = NULL;
+  gcry_mpi_t mpi_s = NULL;
+  gcry_mpi_t mpi_e = NULL;
+  gcry_mpi_t data = NULL;
   ECC_public_key pk;
-  mpi_ec_t ctx;
-  gcry_mpi_t s, e;
-
-  (void)algo;
-  (void)flags;
+  mpi_ec_t ec = NULL;
 
-  if (!k
-      || !pkey[0] || !pkey[1] || !pkey[2] || !pkey[3] || !pkey[4] || !pkey[5])
-    return GPG_ERR_BAD_MPI;
+  memset (&pk, 0, sizeof pk);
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT,
+                                   ecc_get_nbits (keyparms));
 
-  pk.E.model = MPI_EC_WEIERSTRASS;
-  pk.E.p = pkey[0];
-  pk.E.a = pkey[1];
-  pk.E.b = pkey[2];
-  point_init (&pk.E.G);
-  rc = _gcry_ecc_os2ec (&pk.E.G, pkey[3]);
+  /*
+   * Extract the data.
+   */
+  rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
   if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    log_mpidump ("ecc_encrypt data", data);
+  if (mpi_is_opaque (data))
     {
-      point_free (&pk.E.G);
-      return rc;
+      rc = GPG_ERR_INV_DATA;
+      goto leave;
     }
-  pk.E.n = pkey[4];
-  point_init (&pk.Q);
-  rc = _gcry_ecc_os2ec (&pk.Q, pkey[5]);
+
+
+  /*
+   * Extract the key.
+   */
+  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+q",
+                                   &pk.E.p, &pk.E.a, &pk.E.b, &mpi_g, &pk.E.n,
+                                   &mpi_q, NULL);
   if (rc)
+    goto leave;
+  if (mpi_g)
     {
-      point_free (&pk.E.G);
-      point_free (&pk.Q);
-      return rc;
+      point_init (&pk.E.G);
+      rc = _gcry_ecc_os2ec (&pk.E.G, mpi_g);
+      if (rc)
+        goto leave;
+    }
+  /* Add missing parameters using the optional curve parameter.  */
+  gcry_sexp_release (l1);
+  l1 = gcry_sexp_find_token (keyparms, "curve", 5);
+  if (l1)
+    {
+      curvename = gcry_sexp_nth_string (l1, 1);
+      if (curvename)
+        {
+          rc = _gcry_ecc_fill_in_curve (0, curvename, &pk.E, NULL);
+          if (rc)
+            return rc;
+        }
+    }
+  /* Guess required fields if a curve parameter has not been given.  */
+  if (!curvename)
+    {
+      pk.E.model = MPI_EC_WEIERSTRASS;
+      pk.E.dialect = ECC_DIALECT_STANDARD;
     }
 
-  ctx = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect,
-                                     pk.E.p, pk.E.a, pk.E.b);
-  s = mpi_alloc (mpi_get_nlimbs (pk.E.p));
-  e = mpi_alloc (mpi_get_nlimbs (pk.E.p));
+  if (DBG_CIPHER)
+    {
+      log_debug ("ecc_encrypt info: %s/%s\n",
+                 _gcry_ecc_model2str (pk.E.model),
+                 _gcry_ecc_dialect2str (pk.E.dialect));
+      if (pk.E.name)
+        log_debug  ("ecc_encrypt name: %s\n", pk.E.name);
+      log_printmpi ("ecc_encrypt    p", pk.E.p);
+      log_printmpi ("ecc_encrypt    a", pk.E.a);
+      log_printmpi ("ecc_encrypt    b", pk.E.b);
+      log_printpnt ("ecc_encrypt  g",   &pk.E.G, NULL);
+      log_printmpi ("ecc_encrypt    n", pk.E.n);
+      log_printmpi ("ecc_encrypt    q", mpi_q);
+    }
+  if (!pk.E.p || !pk.E.a || !pk.E.b || !pk.E.G.x || !pk.E.n || !mpi_q)
+    {
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
+    }
+
+  /* Convert the public key.  */
+  if (mpi_q)
+    {
+      point_init (&pk.Q);
+      rc = _gcry_ecc_os2ec (&pk.Q, mpi_q);
+      if (rc)
+        goto leave;
+    }
+
+  /* Compute the encrypted value.  */
+  ec = _gcry_mpi_ec_p_internal_new (pk.E.model, pk.E.dialect,
+                                    pk.E.p, pk.E.a, pk.E.b);
 
   /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so */
   {
@@ -1838,18 +1938,18 @@ ecc_encrypt_raw (int algo, gcry_sexp_t *r_result, gcry_mpi_t k,
     point_init (&R);
 
     /* R = kQ  <=>  R = kdG  */
-    _gcry_mpi_ec_mul_point (&R, k, &pk.Q, ctx);
+    _gcry_mpi_ec_mul_point (&R, data, &pk.Q, ec);
 
-    if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ec))
       log_fatal ("ecdh: Failed to get affine coordinates for kdG\n");
-    s = _gcry_ecc_ec2os (x, y, pk.E.p);
+    mpi_s = _gcry_ecc_ec2os (x, y, pk.E.p);
 
     /* R = kG */
-    _gcry_mpi_ec_mul_point (&R, k, &pk.E.G, ctx);
+    _gcry_mpi_ec_mul_point (&R, data, &pk.E.G, ec);
 
-    if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ec))
       log_fatal ("ecdh: Failed to get affine coordinates for kG\n");
-    e = _gcry_ecc_ec2os (x, y, pk.E.p);
+    mpi_e = _gcry_ecc_ec2os (x, y, pk.E.p);
 
     mpi_free (x);
     mpi_free (y);
@@ -1857,17 +1957,30 @@ ecc_encrypt_raw (int algo, gcry_sexp_t *r_result, gcry_mpi_t k,
     point_free (&R);
   }
 
-  _gcry_mpi_ec_free (ctx);
+  rc = gcry_sexp_build (r_ciph, NULL, "(enc-val(ecdh(s%m)(e%m)))",
+                        mpi_s, mpi_e);
+
+ leave:
+  gcry_mpi_release (pk.E.p);
+  gcry_mpi_release (pk.E.a);
+  gcry_mpi_release (pk.E.b);
+  gcry_mpi_release (mpi_g);
   point_free (&pk.E.G);
+  gcry_mpi_release (pk.E.n);
+  gcry_mpi_release (mpi_q);
   point_free (&pk.Q);
-
-  rc = gcry_sexp_build (r_result, NULL, "(enc-val(ecdh(s%m)(e%m)))", s, e);
-  mpi_free (s);
-  mpi_free (e);
-
+  gcry_mpi_release (data);
+  gcry_mpi_release (mpi_s);
+  gcry_mpi_release (mpi_e);
+  gcry_free (curvename);
+  _gcry_mpi_ec_free (ec);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
+  if (DBG_CIPHER)
+    log_debug ("ecc_encrypt    => %s\n", gpg_strerror (rc));
   return rc;
 }
 
+
 /*  input:
  *     data[0] : a point kG (ephemeral public key)
  *   output:
@@ -1876,70 +1989,115 @@ ecc_encrypt_raw (int algo, gcry_sexp_t *r_result, gcry_mpi_t k,
  *  see ecc_encrypt_raw for details.
  */
 static gcry_err_code_t
-ecc_decrypt_raw (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data,
-                 gcry_mpi_t *skey, int flags,
-                 enum pk_encoding encoding, int hash_algo,
-                 unsigned char *label, size_t labellen)
+ecc_decrypt_raw (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
   gpg_err_code_t rc;
+  struct pk_encoding_ctx ctx;
+  gcry_sexp_t l1 = NULL;
+  gcry_mpi_t data_e = NULL;
   ECC_secret_key sk;
-  mpi_point_struct R;  /* Result that we return.  */
+  gcry_mpi_t mpi_g = NULL;
+  char *curvename = NULL;
+  mpi_ec_t ec = NULL;
   mpi_point_struct kG;
-  mpi_ec_t ctx;
-  gcry_mpi_t r;
+  mpi_point_struct R;
+  gcry_mpi_t r = NULL;
 
-  (void)algo;
-  (void)flags;
-  (void)encoding;
-  (void)hash_algo;
-  (void)label;
-  (void)labellen;
+  memset (&sk, 0, sizeof sk);
+  point_init (&kG);
+  point_init (&R);
 
-  if (!data || !data[0]
-      || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4]
-      || !skey[5] || !skey[6] )
-    return GPG_ERR_BAD_MPI;
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT,
+                                   ecc_get_nbits (keyparms));
 
-  point_init (&kG);
-  rc = _gcry_ecc_os2ec (&kG, data[0]);
+  /*
+   * Extract the data.
+   */
+  rc = _gcry_pk_util_preparse_encval (s_data, ecc_names, &l1, &ctx);
+  if (rc)
+    goto leave;
+  rc = _gcry_pk_util_extract_mpis (l1, "e", &data_e, NULL);
   if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    log_printmpi ("ecc_decrypt  d_e", data_e);
+  if (mpi_is_opaque (data_e))
     {
-      point_free (&kG);
-      return rc;
+      rc = GPG_ERR_INV_DATA;
+      goto leave;
     }
 
-  sk.E.model = MPI_EC_WEIERSTRASS;
-  sk.E.p = skey[0];
-  sk.E.a = skey[1];
-  sk.E.b = skey[2];
-  point_init (&sk.E.G);
-  rc = _gcry_ecc_os2ec (&sk.E.G, skey[3]);
+  /*
+   * Extract the key.
+   */
+  rc = _gcry_pk_util_extract_mpis (keyparms, "-p?a?b?g?n?+d",
+                                   &sk.E.p, &sk.E.a, &sk.E.b, &mpi_g, &sk.E.n,
+                                   &sk.d, NULL);
   if (rc)
+    goto leave;
+  if (mpi_g)
     {
-      point_free (&kG);
-      point_free (&sk.E.G);
-      return rc;
+      point_init (&sk.E.G);
+      rc = _gcry_ecc_os2ec (&sk.E.G, mpi_g);
+      if (rc)
+        goto leave;
+    }
+  /* Add missing parameters using the optional curve parameter.  */
+  gcry_sexp_release (l1);
+  l1 = gcry_sexp_find_token (keyparms, "curve", 5);
+  if (l1)
+    {
+      curvename = gcry_sexp_nth_string (l1, 1);
+      if (curvename)
+        {
+          rc = _gcry_ecc_fill_in_curve (0, curvename, &sk.E, NULL);
+          if (rc)
+            return rc;
+        }
+    }
+  /* Guess required fields if a curve parameter has not been given.  */
+  if (!curvename)
+    {
+      sk.E.model = MPI_EC_WEIERSTRASS;
+      sk.E.dialect = ECC_DIALECT_STANDARD;
+    }
+  if (DBG_CIPHER)
+    {
+      log_debug ("ecc_decrypt info: %s/%s\n",
+                 _gcry_ecc_model2str (sk.E.model),
+                 _gcry_ecc_dialect2str (sk.E.dialect));
+      if (sk.E.name)
+        log_debug  ("ecc_decrypt name: %s\n", sk.E.name);
+      log_printmpi ("ecc_decrypt    p", sk.E.p);
+      log_printmpi ("ecc_decrypt    a", sk.E.a);
+      log_printmpi ("ecc_decrypt    b", sk.E.b);
+      log_printpnt ("ecc_decrypt  g",   &sk.E.G, NULL);
+      log_printmpi ("ecc_decrypt    n", sk.E.n);
+      if (!fips_mode ())
+        log_printmpi ("ecc_decrypt    d", sk.d);
+    }
+  if (!sk.E.p || !sk.E.a || !sk.E.b || !sk.E.G.x || !sk.E.n || !sk.d)
+    {
+      rc = GPG_ERR_NO_OBJ;
+      goto leave;
     }
-  sk.E.n = skey[4];
-  point_init (&sk.Q);
-  rc = _gcry_ecc_os2ec (&sk.Q, skey[5]);
+
+
+  /*
+   * Compute the plaintext.
+   */
+  rc = _gcry_ecc_os2ec (&kG, data_e);
   if (rc)
     {
       point_free (&kG);
-      point_free (&sk.E.G);
-      point_free (&sk.Q);
       return rc;
     }
-  sk.d = skey[6];
 
-  ctx = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect,
-                                     sk.E.p, sk.E.a, sk.E.b);
+  ec = _gcry_mpi_ec_p_internal_new (sk.E.model, sk.E.dialect,
+                                    sk.E.p, sk.E.a, sk.E.b);
 
   /* R = dkG */
-  point_init (&R);
-  _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ctx);
-
-  point_free (&kG);
+  _gcry_mpi_ec_mul_point (&R, sk.d, &kG, ec);
 
   /* The following is false: assert( mpi_cmp_ui( R.x, 1 )==0 );, so:  */
   {
@@ -1948,7 +2106,7 @@ ecc_decrypt_raw (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data,
     x = mpi_new (0);
     y = mpi_new (0);
 
-    if (_gcry_mpi_ec_get_affine (x, y, &R, ctx))
+    if (_gcry_mpi_ec_get_affine (x, y, &R, ec))
       log_fatal ("ecdh: Failed to get affine coordinates\n");
 
     r = _gcry_ecc_ec2os (x, y, sk.E.p);
@@ -1959,16 +2117,30 @@ ecc_decrypt_raw (int algo, gcry_sexp_t *r_plain, gcry_mpi_t *data,
     mpi_free (x);
     mpi_free (y);
   }
+  if (DBG_CIPHER)
+    log_printmpi ("ecc_decrypt  res", r);
+
+  if (!rc)
+    rc = gcry_sexp_build (r_plain, NULL, "(value %m)", r);
 
+ leave:
   point_free (&R);
-  _gcry_mpi_ec_free (ctx);
   point_free (&kG);
+  gcry_mpi_release (r);
+  gcry_mpi_release (sk.E.p);
+  gcry_mpi_release (sk.E.a);
+  gcry_mpi_release (sk.E.b);
+  gcry_mpi_release (mpi_g);
   point_free (&sk.E.G);
-  point_free (&sk.Q);
-
-  if (!rc)
-    rc = gcry_sexp_build (r_plain, NULL, "(value %m)", r);
-  mpi_free (r);
+  gcry_mpi_release (sk.E.n);
+  gcry_mpi_release (sk.d);
+  gcry_mpi_release (data_e);
+  gcry_free (curvename);
+  gcry_sexp_release (l1);
+  _gcry_mpi_ec_free (ec);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
+  if (DBG_CIPHER)
+    log_debug ("ecc_decrypt    => %s\n", gpg_strerror (rc));
   return rc;
 }