pubkey: Move sexp parsing for gcry_pk_encrypt to the modules.
authorWerner Koch <wk@gnupg.org>
Fri, 11 Oct 2013 13:39:22 +0000 (15:39 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 11 Oct 2013 13:39:22 +0000 (15:39 +0200)
* cipher/rsa.c (rsa_encrypt): Revamp.
* cipher/elgamal.c (elg_encrypt): Revamp.
* cipher/ecc.c (ecc_encrypt_raw): Revamp.
* cipher/pubkey.c (gcry_pk_encrypt): Simplify.

* tests/basic.c (check_pubkey_crypt): Init plain, ciph, and data so
that they are initialized even after an encrypt failure.
--

Note that we do not have a regression test for ecc_encrypt_raw.  Thus
it is possible that a bug has been introduced.  Should be tested using
GnuPG master.

Signed-off-by: Werner Koch <wk@gnupg.org>
cipher/ecc.c
cipher/elgamal.c
cipher/pubkey.c
cipher/rsa.c
src/cipher-proto.h
tests/basic.c

index f98a5cc..051308f 100644 (file)
@@ -1786,46 +1786,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 +1898,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 +1917,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:
index a4f5ce3..3718287 100644 (file)
@@ -755,30 +755,57 @@ elg_check_secret_key (int algo, gcry_mpi_t *skey)
 
 
 static gcry_err_code_t
-elg_encrypt (int algo, gcry_sexp_t *r_result,
-             gcry_mpi_t data, gcry_mpi_t *pkey, int flags)
+elg_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
   gcry_err_code_t rc;
-  ELG_public_key pk;
-  gcry_mpi_t a, b;
+  struct pk_encoding_ctx ctx;
+  gcry_mpi_t mpi_a = NULL;
+  gcry_mpi_t mpi_b = NULL;
+  gcry_mpi_t data = NULL;
+  ELG_public_key pk = { NULL, NULL, NULL };
 
-  (void)algo;
-  (void)flags;
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT,
+                                   elg_get_nbits (keyparms));
 
-  if ((! data) || (! pkey[0]) || (! pkey[1]) || (! pkey[2]))
-    rc = GPG_ERR_BAD_MPI;
-  else
+  /* Extract the data.  */
+  rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    log_mpidump ("elg_encrypt data", data);
+  if (mpi_is_opaque (data))
+    {
+      rc = GPG_ERR_INV_DATA;
+      goto leave;
+    }
+
+  /* Extract the key.  */
+  rc = _gcry_pk_util_extract_mpis (keyparms, "pgy", &pk.p, &pk.g, &pk.y, NULL);
+  if (rc)
+    return rc;
+  if (DBG_CIPHER)
     {
-      pk.p = pkey[0];
-      pk.g = pkey[1];
-      pk.y = pkey[2];
-      a = mpi_alloc (mpi_get_nlimbs (pk.p));
-      b = mpi_alloc (mpi_get_nlimbs (pk.p));
-      do_encrypt (a, b, data, &pk);
-      rc = gcry_sexp_build (r_result, NULL, "(enc-val(elg(a%m)(b%m)))", a, b);
-      mpi_free (a);
-      mpi_free (b);
+      log_mpidump ("elg_encrypt  p", pk.p);
+      log_mpidump ("elg_encrypt  g", pk.g);
+      log_mpidump ("elg_encrypt  y", pk.y);
     }
+
+  /* Do Elgamal computation and build result.  */
+  mpi_a = gcry_mpi_new (0);
+  mpi_b = gcry_mpi_new (0);
+  do_encrypt (mpi_a, mpi_b, data, &pk);
+  rc = gcry_sexp_build (r_ciph, NULL, "(enc-val(elg(a%m)(b%m)))", mpi_a, mpi_b);
+
+ leave:
+  gcry_mpi_release (mpi_a);
+  gcry_mpi_release (mpi_b);
+  gcry_mpi_release (pk.p);
+  gcry_mpi_release (pk.g);
+  gcry_mpi_release (pk.y);
+  gcry_mpi_release (data);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
+  if (DBG_CIPHER)
+    log_debug ("elg_encrypt   => %s\n", gpg_strerror (rc));
   return rc;
 }
 
index c0f4ab2..8a46e4e 100644 (file)
@@ -926,60 +926,22 @@ gcry_error_t
 gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
 {
   gcry_err_code_t rc;
-  gcry_mpi_t *pkey = NULL;
-  gcry_mpi_t data = NULL;
-  struct pk_encoding_ctx ctx;
-  gcry_pk_spec_t *spec = NULL;
-  int i;
+  gcry_pk_spec_t *spec;
+  gcry_sexp_t keyparms;
 
   *r_ciph = NULL;
 
-  /* Get the key. */
-  rc = sexp_to_key (s_pkey, 0, GCRY_PK_USAGE_ENCR, NULL, &pkey, &spec, NULL);
-  if (rc)
-    goto leave;
-
-  gcry_assert (spec);
-
-  /* Get the stuff we want to encrypt. */
-  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT, gcry_pk_get_nbits (s_pkey));
-  rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
+  rc = spec_from_sexp (s_pkey, 0, &spec, &keyparms);
   if (rc)
     goto leave;
 
-  /* In fips mode DBG_CIPHER will never evaluate to true but as an
-     extra failsafe protection we explicitly test for fips mode
-     here. */
-  if (DBG_CIPHER && !fips_mode ())
-    {
-      log_debug ("pubkey_encrypt: algo=%d\n", spec->algo);
-      for(i = 0; i < pubkey_get_npkey (spec->algo); i++)
-       log_mpidump ("  pkey", pkey[i]);
-      log_mpidump ("  data", data);
-    }
-
   if (spec->encrypt)
-    rc = spec->encrypt (spec->algo, r_ciph, data, pkey, ctx.flags);
+    rc = spec->encrypt (r_ciph, s_data, keyparms);
   else
     rc = GPG_ERR_NOT_IMPLEMENTED;
 
-
-  /* if (DBG_CIPHER && !fips_mode ()) */
-  /*   { */
-  /*     for (i = 0; i < pubkey_get_nenc (spec->algo); i++) */
-  /*       log_mpidump ("  encr", ciph[i]); */
-  /*   } */
-
  leave:
-  mpi_free (data);
-  if (pkey)
-    {
-      release_mpi_array (pkey);
-      gcry_free (pkey);
-    }
-
-  gcry_free (ctx.label);
-
+  gcry_sexp_release (keyparms);
   return gcry_error (rc);
 }
 
index db64452..51480df 100644 (file)
@@ -861,39 +861,68 @@ rsa_check_secret_key (int algo, gcry_mpi_t *skey)
 
 
 static gcry_err_code_t
-rsa_encrypt (int algo, gcry_sexp_t *r_result, gcry_mpi_t data,
-             gcry_mpi_t *pkey, int flags)
+rsa_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t keyparms)
 {
-  gpg_err_code_t rc;
-  RSA_public_key pk;
-  gcry_mpi_t result;
+  gcry_err_code_t rc;
+  struct pk_encoding_ctx ctx;
+  gcry_mpi_t data = NULL;
+  RSA_public_key pk = {NULL, NULL};
+  gcry_mpi_t ciph = NULL;
 
-  (void)algo;
-  (void)flags;
+  _gcry_pk_util_init_encoding_ctx (&ctx, PUBKEY_OP_ENCRYPT,
+                                   rsa_get_nbits (keyparms));
 
-  pk.n = pkey[0];
-  pk.e = pkey[1];
-  result = mpi_alloc (mpi_get_nlimbs (pk.n));
-  public (result, data, &pk);
-  if ((flags & PUBKEY_FLAG_FIXEDLEN))
+  /* Extract the data.  */
+  rc = _gcry_pk_util_data_to_mpi (s_data, &data, &ctx);
+  if (rc)
+    goto leave;
+  if (DBG_CIPHER)
+    log_mpidump ("rsa_encrypt data", data);
+  if (mpi_is_opaque (data))
+    {
+      rc = GPG_ERR_INV_DATA;
+      goto leave;
+    }
+
+  /* Extract the key.  */
+  rc = _gcry_pk_util_extract_mpis (keyparms, "ne", &pk.n, &pk.e, NULL);
+  if (rc)
+    return rc;
+  if (DBG_CIPHER)
+    {
+      log_mpidump ("rsa_encrypt  n", pk.n);
+      log_mpidump ("rsa_encrypt  e", pk.e);
+    }
+
+  /* Do RSA computation and build result.  */
+  ciph = gcry_mpi_new (0);
+  public (ciph, data, &pk);
+  if ((ctx.flags & PUBKEY_FLAG_FIXEDLEN))
     {
       /* We need to make sure to return the correct length to avoid
          problems with missing leading zeroes.  */
       unsigned char *em;
       size_t emlen = (mpi_get_nbits (pk.n)+7)/8;
 
-      rc = _gcry_mpi_to_octet_string (&em, NULL, result, emlen);
+      rc = _gcry_mpi_to_octet_string (&em, NULL, ciph, emlen);
       if (!rc)
         {
-          rc = gcry_sexp_build (r_result, NULL,
+          rc = gcry_sexp_build (r_ciph, NULL,
                                 "(enc-val(rsa(a%b)))", (int)emlen, em);
           gcry_free (em);
         }
     }
   else
-    rc = gcry_sexp_build (r_result, NULL, "(enc-val(rsa(a%m)))", result);
+    rc = gcry_sexp_build (r_ciph, NULL, "(enc-val(rsa(a%m)))", ciph);
 
-  mpi_free (result);
+ leave:
+  gcry_mpi_release (ciph);
+  gcry_mpi_release (pk.n);
+  gcry_mpi_release (pk.e);
+  gcry_mpi_release (data);
+  _gcry_pk_util_free_encoding_ctx (&ctx);
+  if (DBG_CIPHER)
+    log_debug ("rsa_encrypt   => %s\n", gpg_strerror (rc));
   return rc;
 }
 
index 8892ddf..c570e5f 100644 (file)
@@ -58,11 +58,9 @@ typedef gcry_err_code_t (*gcry_pk_check_secret_key_t) (int algo,
                                                       gcry_mpi_t *skey);
 
 /* Type for the pk_encrypt function.  */
-typedef gcry_err_code_t (*gcry_pk_encrypt_t) (int algo,
-                                             gcry_sexp_t *r_result,
-                                             gcry_mpi_t data,
-                                             gcry_mpi_t *pkey,
-                                             int flags);
+typedef gcry_err_code_t (*gcry_pk_encrypt_t) (gcry_sexp_t *r_ciph,
+                                              gcry_sexp_t s_data,
+                                              gcry_sexp_t keyparms);
 
 /* Type for the pk_decrypt function.  */
 typedef gcry_err_code_t (*gcry_pk_decrypt_t) (int algo,
index 13a8600..ee04900 100644 (file)
@@ -3486,7 +3486,9 @@ static void
 check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
 {
   gcry_error_t rc;
-  gcry_sexp_t plain, ciph, data;
+  gcry_sexp_t plain = NULL;
+  gcry_sexp_t ciph = NULL;
+  gcry_sexp_t data = NULL;
   int dataidx;
   static struct
   {