pk: Move s-exp creation for gcry_pk_decrypt to the modules.
authorWerner Koch <wk@gnupg.org>
Sat, 7 Sep 2013 08:06:46 +0000 (10:06 +0200)
committerWerner Koch <wk@gnupg.org>
Fri, 20 Sep 2013 15:41:19 +0000 (17:41 +0200)
* cipher/pubkey.c (sexp_to_enc): Remove RET_MODERN arg and merge it
into FLAGS.
(gcry_pk_decrypt): Move result s-exp building into the modules.
* src/cipher-proto.h (gcry_pk_decrypt_t): Add some args.
* cipher/ecc.c (ecc_decrypt_raw): Change to return an s-exp.
* cipher/elgamal.c (elg_decrypt): Ditto.
* cipher/rsa.c (rsa_decrypt): Ditto.
(rsa_blind, rsa_unblind): Merge into rsa_decrypt.  This saves several
extra MPI allocations.

--

The extra args added to gcry_pk_decrypt_t are a temporary solution
unti we move the input s-exp parsing also into the modules.

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

index 9a9c21b..cf054f8 100644 (file)
@@ -1661,20 +1661,24 @@ 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_mpi_t *result, gcry_mpi_t *data,
-                 gcry_mpi_t *skey, int flags)
+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)
 {
+  gpg_err_code_t rc;
   ECC_secret_key sk;
   mpi_point_struct R;  /* Result that we return.  */
   mpi_point_struct kG;
   mpi_ec_t ctx;
   gcry_mpi_t r;
-  int err;
 
   (void)algo;
   (void)flags;
-
-  *result = NULL;
+  (void)encoding;
+  (void)hash_algo;
+  (void)label;
+  (void)labellen;
 
   if (!data || !data[0]
       || !skey[0] || !skey[1] || !skey[2] || !skey[3] || !skey[4]
@@ -1682,11 +1686,11 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
     return GPG_ERR_BAD_MPI;
 
   point_init (&kG);
-  err = _gcry_ecc_os2ec (&kG, data[0]);
-  if (err)
+  rc = _gcry_ecc_os2ec (&kG, data[0]);
+  if (rc)
     {
       point_free (&kG);
-      return err;
+      return rc;
     }
 
   sk.E.model = MPI_EC_WEIERSTRASS;
@@ -1694,22 +1698,22 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
   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)
+  rc = _gcry_ecc_os2ec (&sk.E.G, skey[3]);
+  if (rc)
     {
       point_free (&kG);
       point_free (&sk.E.G);
-      return err;
+      return rc;
     }
   sk.E.n = skey[4];
   point_init (&sk.Q);
-  err = _gcry_ecc_os2ec (&sk.Q, skey[5]);
-  if (err)
+  rc = _gcry_ecc_os2ec (&sk.Q, skey[5]);
+  if (rc)
     {
       point_free (&kG);
       point_free (&sk.E.G);
       point_free (&sk.Q);
-      return err;
+      return rc;
     }
   sk.d = skey[6];
 
@@ -1733,6 +1737,10 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
       log_fatal ("ecdh: Failed to get affine coordinates\n");
 
     r = _gcry_ecc_ec2os (x, y, sk.E.p);
+    if (!r)
+      rc = gpg_err_code_from_syserror ();
+    else
+      rc = 0;
     mpi_free (x);
     mpi_free (y);
   }
@@ -1743,14 +1751,10 @@ ecc_decrypt_raw (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
   point_free (&sk.E.G);
   point_free (&sk.Q);
 
-  if (!r)
-    return GPG_ERR_ENOMEM;
-
-  /* Success.  */
-
-  *result = r;
-
-  return 0;
+  if (!rc)
+    rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %m)", r));
+  mpi_free (r);
+  return rc;
 }
 
 
index c2a953b..ecbac75 100644 (file)
@@ -30,6 +30,8 @@
 #include "g10lib.h"
 #include "mpi.h"
 #include "cipher.h"
+#include "pubkey-internal.h"
+
 
 typedef struct
 {
@@ -777,28 +779,73 @@ elg_encrypt (int algo, gcry_sexp_t *r_result,
 
 
 static gcry_err_code_t
-elg_decrypt (int algo, gcry_mpi_t *result,
-             gcry_mpi_t *data, gcry_mpi_t *skey, int flags)
+elg_decrypt (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)
 {
-  gcry_err_code_t err = GPG_ERR_NO_ERROR;
+  gcry_err_code_t rc;
   ELG_secret_key sk;
+  gcry_mpi_t plain;
 
   (void)algo;
-  (void)flags;
 
   if ((! data[0]) || (! data[1])
       || (! skey[0]) || (! skey[1]) || (! skey[2]) || (! skey[3]))
-    err = GPG_ERR_BAD_MPI;
+    rc = GPG_ERR_BAD_MPI;
   else
     {
+      unsigned char *unpad = NULL;
+      size_t unpadlen = 0;
+      unsigned int nbits;
+
       sk.p = skey[0];
       sk.g = skey[1];
       sk.y = skey[2];
       sk.x = skey[3];
-      *result = mpi_alloc_secure (mpi_get_nlimbs (sk.p));
-      decrypt (*result, data[0], data[1], &sk);
+
+      nbits = gcry_mpi_get_nbits (sk.p);
+
+      plain = mpi_snew (nbits);
+      decrypt (plain, data[0], data[1], &sk);
+
+      /* Reverse the encoding and build the s-expression.  */
+      switch (encoding)
+        {
+        case PUBKEY_ENC_PKCS1:
+          rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, nbits, plain);
+          mpi_free (plain);
+          plain = NULL;
+          if (!rc)
+            rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
+                                                 (int)unpadlen, unpad));
+          break;
+
+        case PUBKEY_ENC_OAEP:
+          rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen,
+                                      nbits, hash_algo, plain, label, labellen);
+          mpi_free (plain);
+          plain = NULL;
+          if (!rc)
+            rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
+                                             (int)unpadlen, unpad));
+          break;
+
+        default:
+          /* Raw format.  For backward compatibility we need to assume a
+             signed mpi by using the sexp format string "%m".  */
+          rc = gcry_err_code
+            (gcry_sexp_build (r_plain, NULL,
+                              (flags & PUBKEY_FLAG_LEGACYRESULT)
+                              ? "%m" : "(value %m)",
+                              plain));
+          break;
+        }
+
+      gcry_free (unpad);
+      mpi_free (plain);
     }
-  return err;
+  return rc;
 }
 
 
index 7085b25..99b9ba8 100644 (file)
@@ -714,7 +714,7 @@ get_hash_algo (const char *s, size_t n)
  */
 static gcry_err_code_t
 sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec,
-             int *ret_modern, int *flags, struct pk_encoding_ctx *ctx)
+             int *flags, struct pk_encoding_ctx *ctx)
 {
   gcry_err_code_t err = 0;
   gcry_sexp_t list = NULL;
@@ -726,8 +726,6 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec,
   const char *elems;
   gcry_mpi_t *array = NULL;
 
-  *ret_modern = 0;
-
   /* Check that the first element is valid.  */
   list = gcry_sexp_find_token (sexp, "enc-val" , 0);
   if (!list)
@@ -757,7 +755,6 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec,
       const char *s;
       int i;
 
-      *ret_modern = 1;
       for (i = gcry_sexp_length (l2) - 1; i > 0; i--)
         {
           s = gcry_sexp_nth_data (l2, i, &n);
@@ -863,6 +860,8 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec,
       list = l2;
       l2 = NULL;
     }
+  else
+    parsed_flags |= PUBKEY_FLAG_LEGACYRESULT;
 
   spec = spec_from_name (name);
   if (!spec)
@@ -1533,11 +1532,8 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
   gcry_err_code_t rc;
   gcry_mpi_t *skey = NULL;
   gcry_mpi_t *data = NULL;
-  gcry_mpi_t plain = NULL;
-  unsigned char *unpad = NULL;
-  size_t unpadlen = 0;
   int i;
-  int modern, flags;
+  int flags;
   struct pk_encoding_ctx ctx;
   gcry_pk_spec_t *spec = NULL;
   gcry_pk_spec_t *spec_enc = NULL;
@@ -1551,7 +1547,7 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
     goto leave;
 
   init_encoding_ctx (&ctx, PUBKEY_OP_DECRYPT, gcry_pk_get_nbits (s_skey));
-  rc = sexp_to_enc (s_data, &data, &spec_enc, &modern, &flags, &ctx);
+  rc = sexp_to_enc (s_data, &data, &spec_enc, &flags, &ctx);
   if (rc)
     goto leave;
 
@@ -1571,59 +1567,25 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
     }
 
   if (spec->decrypt)
-    rc = spec->decrypt (spec->algo, &plain, data, skey, flags);
+    rc = spec->decrypt (spec->algo, r_plain, data, skey, flags,
+                        ctx.encoding, ctx.hash_algo,
+                        ctx.label, ctx.labellen);
   else
     rc = GPG_ERR_NOT_IMPLEMENTED;
   if (rc)
     goto leave;
 
-  if (DBG_CIPHER && !fips_mode ())
-    log_mpidump (" plain", plain);
-
-  /* Do un-padding if necessary. */
-  switch (ctx.encoding)
-    {
-    case PUBKEY_ENC_PKCS1:
-      rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen,
-                                           gcry_pk_get_nbits (s_skey),
-                                           plain);
-      mpi_free (plain);
-      plain = NULL;
-      if (!rc)
-        rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
-                                             (int)unpadlen, unpad));
-      break;
-
-    case PUBKEY_ENC_OAEP:
-      rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen,
-                                  gcry_pk_get_nbits (s_skey), ctx.hash_algo,
-                                  plain, ctx.label, ctx.labellen);
-      mpi_free (plain);
-      plain = NULL;
-      if (!rc)
-        rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
-                                             (int)unpadlen, unpad));
-      break;
+  /* if (DBG_CIPHER && !fips_mode ()) */
+  /*   log_mpidump (" plain", plain); */
 
-    default:
-      /* Raw format.  For backward compatibility we need to assume a
-         signed mpi by using the sexp format string "%m".  */
-      rc = gcry_err_code (gcry_sexp_build
-                          (r_plain, NULL, modern? "(value %m)" : "%m", plain));
-      break;
-    }
 
  leave:
-  gcry_free (unpad);
-
   if (skey)
     {
       release_mpi_array (skey);
       gcry_free (skey);
     }
 
-  mpi_free (plain);
-
   if (data)
     {
       release_mpi_array (data);
index 5754e43..7105271 100644 (file)
@@ -32,6 +32,7 @@
 #include "g10lib.h"
 #include "mpi.h"
 #include "cipher.h"
+#include "pubkey-internal.h"
 
 
 typedef struct
@@ -737,47 +738,6 @@ secret (gcry_mpi_t output, gcry_mpi_t input, RSA_secret_key *skey )
 
 
 
-/* Perform RSA blinding.  */
-static gcry_mpi_t
-rsa_blind (gcry_mpi_t x, gcry_mpi_t r, gcry_mpi_t e, gcry_mpi_t n)
-{
-  /* A helper.  */
-  gcry_mpi_t a;
-
-  /* Result.  */
-  gcry_mpi_t y;
-
-  a = gcry_mpi_snew (gcry_mpi_get_nbits (n));
-  y = gcry_mpi_snew (gcry_mpi_get_nbits (n));
-
-  /* Now we calculate: y = (x * r^e) mod n, where r is the random
-     number, e is the public exponent, x is the non-blinded data and n
-     is the RSA modulus.  */
-  gcry_mpi_powm (a, r, e, n);
-  gcry_mpi_mulm (y, a, x, n);
-
-  gcry_mpi_release (a);
-
-  return y;
-}
-
-/* Undo RSA blinding.  */
-static gcry_mpi_t
-rsa_unblind (gcry_mpi_t x, gcry_mpi_t ri, gcry_mpi_t n)
-{
-  gcry_mpi_t y;
-
-  y = gcry_mpi_snew (gcry_mpi_get_nbits (n));
-
-  /* Here we calculate: y = (x * r^-1) mod n, where x is the blinded
-     decrypted data, ri is the modular multiplicative inverse of r and
-     n is the RSA modulus.  */
-
-  gcry_mpi_mulm (y, ri, x, n);
-
-  return y;
-}
-
 /*********************************************
  **************  interface  ******************
  *********************************************/
@@ -926,15 +886,18 @@ rsa_encrypt (int algo, gcry_sexp_t *r_result, gcry_mpi_t data,
 
 
 static gcry_err_code_t
-rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
-             gcry_mpi_t *skey, int flags)
+rsa_decrypt (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)
+
 {
+  gpg_err_code_t rc;
   RSA_secret_key sk;
-  gcry_mpi_t r = MPI_NULL;     /* Random number needed for blinding.  */
-  gcry_mpi_t ri = MPI_NULL;    /* Modular multiplicative inverse of
-                                  r.  */
-  gcry_mpi_t x = MPI_NULL;     /* Data to decrypt.  */
-  gcry_mpi_t y;                        /* Result.  */
+  gcry_mpi_t plain;            /* Decrypted data.  */
+  unsigned char *unpad = NULL;
+  size_t unpadlen = 0;
+  unsigned int nbits;
 
   (void)algo;
 
@@ -946,24 +909,29 @@ rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
   sk.q = skey[4]; /* Optional. */
   sk.u = skey[5]; /* Optional. */
 
-  y = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n));
+  nbits = gcry_mpi_get_nbits (sk.n);
+
+  plain = gcry_mpi_snew (nbits);
 
   /* We use blinding by default to mitigate timing attacks which can
      be practically mounted over the network as shown by Brumley and
      Boney in 2003.  */
   if (! (flags & PUBKEY_FLAG_NO_BLINDING))
     {
-      /* Initialize blinding.  */
+      gcry_mpi_t r;    /* Random number needed for blinding.  */
+      gcry_mpi_t ri;   /* Modular multiplicative inverse of r.  */
+      gcry_mpi_t ciph; /* Blinded data to decrypt.  */
 
       /* First, we need a random number r between 0 and n - 1, which
         is relatively prime to n (i.e. it is neither p nor q).  The
         random number needs to be only unpredictable, thus we employ
         the gcry_create_nonce function by using GCRY_WEAK_RANDOM with
         gcry_mpi_randomize.  */
-      r = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n));
-      ri = gcry_mpi_snew (gcry_mpi_get_nbits (sk.n));
+      r = gcry_mpi_snew (nbits);
+      ri = gcry_mpi_snew (nbits);
+      ciph = gcry_mpi_snew (nbits);
 
-      gcry_mpi_randomize (r, gcry_mpi_get_nbits (sk.n), GCRY_WEAK_RANDOM);
+      gcry_mpi_randomize (r, nbits, GCRY_WEAK_RANDOM);
       gcry_mpi_mod (r, r, sk.n);
 
       /* Calculate inverse of r.  It practically impossible that the
@@ -971,39 +939,64 @@ rsa_decrypt (int algo, gcry_mpi_t *result, gcry_mpi_t *data,
          allocated resources.  */
       if (!gcry_mpi_invm (ri, r, sk.n))
        return GPG_ERR_INTERNAL;
-    }
 
-  if (! (flags & PUBKEY_FLAG_NO_BLINDING))
-    x = rsa_blind (data[0], r, sk.e, sk.n);
-  else
-    x = data[0];
-
-  /* Do the encryption.  */
-  secret (y, x, &sk);
+      /* Do blinding.  We calculate: y = (x * r^e) mod n, where r is
+         the random number, e is the public exponent, x is the
+         non-blinded data and n is the RSA modulus.  */
+      gcry_mpi_powm (ciph, r, sk.e, sk.n);
+      gcry_mpi_mulm (ciph, ciph, data[0], sk.n);
 
-  if (! (flags & PUBKEY_FLAG_NO_BLINDING))
-    {
-      /* Undo blinding.  */
-      gcry_mpi_t a = gcry_mpi_copy (y);
+      /* Perform decryption.  */
+      secret (plain, ciph, &sk);
 
-      gcry_mpi_release (y);
-      y = rsa_unblind (a, ri, sk.n);
+      /* Undo blinding.  Here we calculate: y = (x * r^-1) mod n,
+         where x is the blinded decrypted data, ri is the modular
+         multiplicative inverse of r and n is the RSA modulus.  */
+      gcry_mpi_mulm (plain, plain, ri, sk.n);
 
-      gcry_mpi_release (a);
+      gcry_mpi_release (ciph);
+      gcry_mpi_release (r);
+      gcry_mpi_release (ri);
     }
+  else
+    secret (plain, data[0], &sk);
 
-  if (! (flags & PUBKEY_FLAG_NO_BLINDING))
+  /* Reverse the encoding and build the s-expression.  */
+  switch (encoding)
     {
-      /* Deallocate resources needed for blinding.  */
-      gcry_mpi_release (x);
-      gcry_mpi_release (r);
-      gcry_mpi_release (ri);
+    case PUBKEY_ENC_PKCS1:
+      rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, nbits, plain);
+      mpi_free (plain);
+      plain = NULL;
+      if (!rc)
+        rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
+                                             (int)unpadlen, unpad));
+      break;
+
+    case PUBKEY_ENC_OAEP:
+      rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen,
+                                  nbits, hash_algo, plain, label, labellen);
+      mpi_free (plain);
+      plain = NULL;
+      if (!rc)
+        rc = gcry_err_code (gcry_sexp_build (r_plain, NULL, "(value %b)",
+                                             (int)unpadlen, unpad));
+      break;
+
+    default:
+      /* Raw format.  For backward compatibility we need to assume a
+         signed mpi by using the sexp format string "%m".  */
+      rc = gcry_err_code
+        (gcry_sexp_build (r_plain, NULL,
+                          (flags & PUBKEY_FLAG_LEGACYRESULT)? "%m":"(value %m)",
+                          plain));
+      break;
     }
 
-  /* Copy out result.  */
-  *result = y;
+  gcry_free (unpad);
+  mpi_free (plain);
 
-  return GPG_ERR_NO_ERROR;
+  return rc;
 }
 
 
index 1285fe8..212857b 100644 (file)
@@ -67,10 +67,14 @@ typedef gcry_err_code_t (*gcry_pk_encrypt_t) (int algo,
 
 /* Type for the pk_decrypt function.  */
 typedef gcry_err_code_t (*gcry_pk_decrypt_t) (int algo,
-                                             gcry_mpi_t *result,
+                                             gcry_sexp_t *r_result,
                                              gcry_mpi_t *data,
                                              gcry_mpi_t *skey,
-                                             int flags);
+                                             int flags,
+                                              enum pk_encoding encoding,
+                                              int hash_algo,
+                                              unsigned char *label,
+                                              size_t labellen);
 
 /* Type for the pk_sign function.  */
 typedef gcry_err_code_t (*gcry_pk_sign_t) (int algo,
index 9fe30a6..e3a2fe0 100644 (file)
@@ -30,6 +30,7 @@
 #define PUBKEY_FLAG_RFC6979        (1 << 1)
 #define PUBKEY_FLAG_EDDSA          (1 << 2)
 #define PUBKEY_FLAG_FIXEDLEN       (1 << 3)
+#define PUBKEY_FLAG_LEGACYRESULT   (1 << 4)
 
 enum pk_operation
   {
index 14ceea4..e9709d5 100644 (file)
@@ -3654,7 +3654,18 @@ check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
            }
          rc = gcry_pk_decrypt (&plain, ciph, skey);
          if (gcry_err_code (rc) != datas[dataidx].decrypt_expected_rc)
-           fail ("gcry_pk_decrypt failed: %s\n", gpg_strerror (rc));
+            {
+              if (verbose)
+                {
+                  show_sexp ("  data:\n", data);
+                  show_sexp ("  ciph:\n", ciph);
+                  show_sexp ("   key:\n", skey);
+                }
+              fail ("gcry_pk_decrypt failed: expected %d (%s), got %d (%s)\n",
+                    datas[dataidx].decrypt_expected_rc,
+                    gpg_strerror (datas[dataidx].decrypt_expected_rc),
+                    rc, gpg_strerror (rc));
+            }
 
          if (!rc && datas[dataidx].unpadded)
            {