[git] GCRYPT - branch, master, updated. post-nuke-of-trailing-ws-33-ge179813

by Werner Koch cvs at cvs.gnupg.org
Wed May 11 18:18:01 CEST 2011


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU crypto library".

The branch, master has been updated
       via  e179813cfbc8bc90ae4b3d5dbabeb437ef57613b (commit)
       via  16c460cb9309b4151928ee8b510e3d19a8f2bf80 (commit)
       via  51311ecf5d7e372b36d1bebd0e3ee7f999d3d608 (commit)
      from  1351cc95b5ee70fde396f8d5754214ef6db4baec (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit e179813cfbc8bc90ae4b3d5dbabeb437ef57613b
Author: Werner Koch <wk at gnupg.org>
Date:   Wed May 11 11:11:16 2011 +0200

    Minor updates to the OAEP code.
    
    We now check that only one encoding method may be given.  In the error
    case we make sure that a released OAEP label variable is set to NULL.
    As a failsafe feature we use gpg_err_code_from_syserror all over in
    pubkey.c; this has the advantage that a misbehaving gcry_free function
    which does not set ERRNO now returns an error code in all cases.

diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index 2ddd968..d524d2c 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,14 @@
+2011-05-11  Werner Koch  <wk at g10code.com>
+
+	* pubkey.c (sexp_to_enc, sexp_data_to_mpi): Set LABEL to NULL
+	after free.
+	(sexp_to_enc, sexp_data_to_mpi): Do not allow multiple encoding
+	flags.
+	(oaep_encode, oaep_decode, sexp_to_key, sexp_to_sig)
+	(sexp_to_enc, sexp_data_to_mpi, gcry_pk_encrypt, gcry_pk_sign)
+	(gcry_pk_genkey, _gcry_pk_get_elements): Replace access to ERRNO
+	by gpg_err_code_from_syserror.
+
 2011-05-11  Daiki Ueno  <ueno at unixuser.org>
 
 	* pubkey.c (sexp_data_to_mpi): Factor some code out to ...
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index a434b82..f4a1cad 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -843,7 +843,7 @@ oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
     /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
     return GPG_ERR_TOO_SHORT; /* the key is too short */
   if ( !(frame = gcry_malloc_secure (nframe)))
-    return gpg_err_code_from_errno (errno);
+    return gpg_err_code_from_syserror ();
 
   /* FRAME = 00 || SEED || DB */
   memset (frame, 0, nframe);
@@ -862,7 +862,7 @@ oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
 
   if ( !(dmask = gcry_malloc_secure (nframe - dlen - 1)))
     {
-      rc = gpg_err_code_from_errno (errno);
+      rc = gpg_err_code_from_syserror ();
       gcry_free (frame);
       return rc;
     }
@@ -874,7 +874,7 @@ oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
 
   if ( !(smask = gcry_malloc_secure (dlen)))
     {
-      rc = gpg_err_code_from_errno (errno);
+      rc = gpg_err_code_from_syserror ();
       gcry_free (frame);
       return rc;
     }
@@ -907,7 +907,7 @@ oaep_decode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
   size_t n;
 
   if ( !(frame = gcry_malloc_secure (nframe)))
-    return gpg_err_code_from_errno (errno);
+    return gpg_err_code_from_syserror ();
 
   err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &n, value);
   if (err)
@@ -933,7 +933,7 @@ oaep_decode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
     }
   if ( !(smask = gcry_malloc_secure (dlen)))
     {
-      rc = gpg_err_code_from_errno (errno);
+      rc = gpg_err_code_from_syserror ();
       gcry_free (frame);
       return rc;
     }
@@ -944,7 +944,7 @@ oaep_decode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
 
   if ( !(dmask = gcry_malloc_secure (nframe - dlen - 1)))
     {
-      rc = gpg_err_code_from_errno (errno);
+      rc = gpg_err_code_from_syserror ();
       gcry_free (frame);
       return rc;
     }
@@ -1243,7 +1243,7 @@ sexp_to_key (gcry_sexp_t sexp, int want_private, const char *override_elems,
     elems = pubkey->elements_pkey;
   array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
   if (!array)
-    err = gpg_err_code_from_errno (errno);
+    err = gpg_err_code_from_syserror ();
   if (!err)
     {
       if (is_ecc)
@@ -1335,7 +1335,7 @@ sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray,
   elems = pubkey->elements_sig;
   array = gcry_calloc (strlen (elems) + 1 , sizeof *array );
   if (!array)
-    err = gpg_err_code_from_errno (errno);
+    err = gpg_err_code_from_syserror ();
 
   if (!err)
     err = sexp_elements_extract (list, elems, array, NULL);
@@ -1426,6 +1426,8 @@ get_hash_algo (const char *s, size_t n)
  *	      ))
  * HASH-ALGO and LABEL are specific to OAEP.
  * RET_MODERN is set to true when at least an empty flags list has been found.
+ * CTX is used to return encoding information; it may be NULL in which
+ * case raw encoding is used.
  */
 static gcry_err_code_t
 sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
@@ -1486,11 +1488,14 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
           s = gcry_sexp_nth_data (l2, i, &n);
           if (! s)
             ; /* Not a data element - ignore.  */
-          else if (n == 3 && !memcmp (s, "raw", 3))
+          else if (n == 3 && !memcmp (s, "raw", 3)
+                   && ctx->encoding == PUBKEY_ENC_RAW)
             ; /* This is just a dummy as it is the default.  */
-          else if (n == 5 && !memcmp (s, "pkcs1", 5))
+          else if (n == 5 && !memcmp (s, "pkcs1", 5)
+                   && ctx->encoding == PUBKEY_ENC_RAW)
             ctx->encoding = PUBKEY_ENC_PKCS1;
-          else if (n == 4 && !memcmp (s, "oaep", 4))
+          else if (n == 4 && !memcmp (s, "oaep", 4)
+                   && ctx->encoding == PUBKEY_ENC_RAW)
             ctx->encoding = PUBKEY_ENC_OAEP;
           else if (n == 11 && ! memcmp (s, "no-blinding", 11))
             parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
@@ -1536,7 +1541,7 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
 		{
 		  ctx->label = gcry_malloc (n);
 		  if (!ctx->label)
-		    err = gpg_err_code_from_errno (errno);
+		    err = gpg_err_code_from_syserror ();
 		  else
 		    {
 		      memcpy (ctx->label, s, n);
@@ -1594,7 +1599,7 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
   array = gcry_calloc (strlen (elems) + 1, sizeof (*array));
   if (!array)
     {
-      err = gpg_err_code_from_errno (errno);
+      err = gpg_err_code_from_syserror ();
       goto leave;
     }
 
@@ -1612,6 +1617,7 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
       ath_mutex_unlock (&pubkeys_registered_lock);
       gcry_free (array);
       gcry_free (ctx->label);
+      ctx->label = NULL;
     }
   else
     {
@@ -1689,11 +1695,14 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
             s = gcry_sexp_nth_data (lflags, i, &n);
             if (!s)
               ; /* not a data element*/
-            else if ( n == 3 && !memcmp (s, "raw", 3))
+            else if ( n == 3 && !memcmp (s, "raw", 3)
+                      && ctx->encoding == PUBKEY_ENC_UNKNOWN)
               ctx->encoding = PUBKEY_ENC_RAW;
-            else if ( n == 5 && !memcmp (s, "pkcs1", 5))
+            else if ( n == 5 && !memcmp (s, "pkcs1", 5)
+                      && ctx->encoding == PUBKEY_ENC_UNKNOWN)
               ctx->encoding = PUBKEY_ENC_PKCS1;
-            else if ( n == 4 && !memcmp (s, "oaep", 4))
+            else if ( n == 4 && !memcmp (s, "oaep", 4)
+                      && ctx->encoding == PUBKEY_ENC_UNKNOWN)
               ctx->encoding = PUBKEY_ENC_OAEP;
 	    else if (n == 11 && ! memcmp (s, "no-blinding", 11))
 	      parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
@@ -1738,7 +1747,7 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
           rc = GPG_ERR_TOO_SHORT; /* the key is too short */
         }
       else if ( !(frame = gcry_malloc_secure (nframe)))
-        rc = gpg_err_code_from_errno (errno);
+        rc = gpg_err_code_from_syserror ();
       else
         {
           n = 0;
@@ -1832,7 +1841,7 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
               rc = GPG_ERR_TOO_SHORT;
             }
           else if ( !(frame = gcry_malloc (nframe)) )
-            rc = gpg_err_code_from_errno (errno);
+            rc = gpg_err_code_from_syserror ();
           else
             { /* Assemble the pkcs#1 block type 1. */
               n = 0;
@@ -1896,7 +1905,7 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
 		{
 		  ctx->label = gcry_malloc (n);
 		  if (!ctx->label)
-		    rc = gpg_err_code_from_errno (errno);
+		    rc = gpg_err_code_from_syserror ();
 		  else
 		    {
 		      memcpy (ctx->label, s, n);
@@ -1923,7 +1932,10 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
   if (!rc)
     *flags = parsed_flags;
   else
-    gcry_free (ctx->label);
+    {
+      gcry_free (ctx->label);
+      ctx->label = NULL;
+    }
 
   return rc;
 }
@@ -1996,7 +2008,7 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
   ciph = gcry_calloc (strlen (algo_elems) + 1, sizeof (*ciph));
   if (!ciph)
     {
-      rc = gpg_err_code_from_errno (errno);
+      rc = gpg_err_code_from_syserror ();
       goto leave;
     }
   rc = pubkey_encrypt (module->mod_id, ciph, data, pkey, flags);
@@ -2017,7 +2029,7 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
     string = p = gcry_malloc (needed);
     if (!string)
       {
-        rc = gpg_err_code_from_errno (errno);
+        rc = gpg_err_code_from_syserror ();
         goto leave;
       }
     p = stpcpy ( p, "(enc-val(" );
@@ -2037,7 +2049,7 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
     arg_list = malloc (nelem * sizeof *arg_list);
     if (!arg_list)
       {
-        rc = gpg_err_code_from_errno (errno);
+        rc = gpg_err_code_from_syserror ();
         goto leave;
       }
 
@@ -2244,7 +2256,7 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
   result = gcry_calloc (strlen (algo_elems) + 1, sizeof (*result));
   if (!result)
     {
-      rc = gpg_err_code_from_errno (errno);
+      rc = gpg_err_code_from_syserror ();
       goto leave;
     }
   rc = pubkey_sign (module->mod_id, result, hash, skey);
@@ -2265,7 +2277,7 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
     string = p = gcry_malloc (needed);
     if (!string)
       {
-        rc = gpg_err_code_from_errno (errno);
+        rc = gpg_err_code_from_syserror ();
         goto leave;
       }
     p = stpcpy (p, "(sig-val(");
@@ -2281,7 +2293,7 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
     arg_list = malloc (nelem * sizeof *arg_list);
     if (!arg_list)
       {
-        rc = gpg_err_code_from_errno (errno);
+        rc = gpg_err_code_from_syserror ();
         goto leave;
       }
 
@@ -2596,7 +2608,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
     string = p = gcry_malloc (needed);
     if (!string)
       {
-        rc = gpg_err_code_from_errno (errno);
+        rc = gpg_err_code_from_syserror ();
         goto leave;
       }
     p = stpcpy (p, "(key-data");
@@ -2660,7 +2672,7 @@ gcry_pk_genkey (gcry_sexp_t *r_key, gcry_sexp_t s_parms)
       arg_list = gcry_calloc (nelem_cp+1, sizeof *arg_list);
       if (!arg_list)
         {
-          rc = gpg_err_code_from_errno (errno);
+          rc = gpg_err_code_from_syserror ();
           goto leave;
         }
       for (i = j = 0; i < elem_n; i++)
@@ -3219,7 +3231,7 @@ _gcry_pk_get_elements (int algo, char **enc, char **sig)
       enc_cp = strdup (spec->elements_enc);
       if (! enc_cp)
 	{
-	  err = gpg_err_code_from_errno (errno);
+	  err = gpg_err_code_from_syserror ();
 	  goto out;
 	}
     }
@@ -3229,7 +3241,7 @@ _gcry_pk_get_elements (int algo, char **enc, char **sig)
       sig_cp = strdup (spec->elements_sig);
       if (! sig_cp)
 	{
-	  err = gpg_err_code_from_errno (errno);
+	  err = gpg_err_code_from_syserror ();
 	  goto out;
 	}
     }

commit 16c460cb9309b4151928ee8b510e3d19a8f2bf80
Author: Werner Koch <wk at gnupg.org>
Date:   Wed May 11 10:57:33 2011 +0200

    Add missing ChangeLogs

diff --git a/NEWS b/NEWS
index b8d50e5..6657d76 100644
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,8 @@ Noteworthy changes in version 1.5.x (unreleased)
 
  * Support ECDH.
 
+ * Support OAEP.
+
  * gcry_sexp_build does now support opaque MPIs with "%m".
 
  * New functions gcry_pk_get_curve and gcry_pk_get_param to map ECC
@@ -52,6 +54,8 @@ Noteworthy changes in version 1.5.x (unreleased)
  gcry_pk_get_param          NEW.
  GCRYCTL_DISABLE_HWF        NEW.
  gcry_kdf_derive            NEW.
+ gcry_pk_encrypt            EXTENDED:  Support OAEP
+ gcry_pk_decrypt            EXTENDED:  Support OAEP
 
  * Interface changes relative to the 1.4.2 release:
  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/cipher/ChangeLog b/cipher/ChangeLog
index fb05141..2ddd968 100644
--- a/cipher/ChangeLog
+++ b/cipher/ChangeLog
@@ -1,3 +1,17 @@
+2011-05-11  Daiki Ueno  <ueno at unixuser.org>
+
+	* pubkey.c (sexp_data_to_mpi): Factor some code out to ...
+	(get_hash_algo): .. new.
+	(mgf1, oaep_encode, oaep_decode): New.
+	(sexp_to_enc): Add arg CTX.  Remove arg RET_WANT_PKCS1.  Support
+	OAEP.
+	(sexp_data_to_mpi): Add arg CTX.  Support OAEP.
+	(gcry_pk_encrypt): Pass a CTX to sexp_data_to_mpi.
+	(gcry_pk_decrypt): Pass a CTX tp sexp_to_enc and replace
+	WANT_PKCS1.  Implement unpadding for OAEP.
+	(gcry_pk_sign): Pass NULL for CTX arg of sexp_data_to_mpi.
+	(gcry_pk_verify): Ditto.
+
 2011-04-19  Werner Koch  <wk at g10code.com>
 
 	* cipher.c (gcry_cipher_open): Replace gpg_err_code_from_errno by
diff --git a/src/ChangeLog b/src/ChangeLog
index 2907e85..c95877f 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+2011-05-11  Daiki Ueno  <ueno at unixuser.org>
+
+	* cipher.h (PUBKEY_FLAG_UNPAD): New.
+	(enum pk_encoding): New.
+	(struct pk_encoding_ctx): New.
+
 2011-04-19  Werner Koch  <wk at g10code.com>
 
 	* stdmem.c (_gcry_private_malloc_secure, _gcry_private_malloc):
diff --git a/tests/ChangeLog b/tests/ChangeLog
index ccaf3bd..4687577 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,10 @@
+2011-05-11  Daiki Ueno  <ueno at unixuser.org>
+
+	* basic.c (check_pubkey_sign): Add an OAEP flag parsing test case.
+	(check_pubkey_crypt): New.
+	(do_check_one_pubkey): Call it.
+	(check_one_pubkey): Free SKEY and PKEY.
+
 2011-04-11  Werner Koch  <wk at g10code.com>
 
 	* basic.c (mismatch): New.

commit 51311ecf5d7e372b36d1bebd0e3ee7f999d3d608
Author: Daiki Ueno <ueno at unixuser.org>
Date:   Fri May 6 15:56:58 2011 +0900

    Support RSA-OAEP padding for encryption.

diff --git a/TODO b/TODO
index 596912a..ffadc06 100644
--- a/TODO
+++ b/TODO
@@ -36,8 +36,6 @@
   collectros need to run that bunch of Unix utilities we don't waste
   their precious results.
 
-* Add OAEP
-
 * gcryptrnd.c
   Requires a test for pth [done] as well as some other tests.
 
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 0fd87f9..a434b82 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -783,6 +783,205 @@ pubkey_verify (int algorithm, gcry_mpi_t hash, gcry_mpi_t *data,
   return rc;
 }
 
+static gcry_err_code_t
+mgf1 (unsigned char *output, size_t outlen, unsigned char *seed, size_t seedlen,
+      int algo)
+{
+  size_t dlen;
+  int idx;
+  gcry_md_hd_t hd;
+  gcry_error_t err;
+  unsigned char *p;
+
+  err = gcry_md_test_algo (algo);
+  if (err)
+    return gpg_err_code (err);
+
+  memset (output, 0, outlen);
+  dlen = gcry_md_get_algo_dlen (algo);
+  for (idx = 0, p = output; idx < (outlen + dlen - 1) / dlen; idx++, p += dlen)
+    {
+      unsigned char c[4], *digest;
+
+      c[0] = (idx >> 24) & 0xFF;
+      c[1] = (idx >> 16) & 0xFF;
+      c[2] = (idx >> 8) & 0xFF;
+      c[3] = idx & 0xFF;
+
+      err = gcry_md_open (&hd, algo, 0);
+      if (err)
+	return gpg_err_code (err);
+
+      gcry_md_write (hd, seed, seedlen);
+      gcry_md_write (hd, c, 4);
+      digest = gcry_md_read (hd, 0);
+      if (outlen - (p - output) >= dlen)
+	memcpy (p, digest, dlen);
+      else
+	memcpy (p, digest, outlen - (p - output));
+      gcry_md_close (hd);
+    }
+  return GPG_ERR_NO_ERROR;
+}
+
+static gcry_err_code_t
+oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
+             const unsigned char *value, size_t valuelen,
+             const unsigned char *label, size_t labellen)
+{
+  gcry_err_code_t rc = 0;
+  gcry_error_t err;
+  unsigned char *frame = NULL;
+  size_t nframe = (nbits+7) / 8;
+  unsigned char *dmask, *smask, *p;
+  size_t dlen;
+  gcry_md_hd_t hd;
+  size_t n;
+
+  dlen = gcry_md_get_algo_dlen (algo);
+  if (valuelen > nframe - 2 * dlen - 1 || !nframe)
+    /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
+    return GPG_ERR_TOO_SHORT; /* the key is too short */
+  if ( !(frame = gcry_malloc_secure (nframe)))
+    return gpg_err_code_from_errno (errno);
+
+  /* FRAME = 00 || SEED || DB */
+  memset (frame, 0, nframe);
+  n = 0;
+  frame[n++] = 0;
+  gcry_randomize (&frame[n], dlen, GCRY_STRONG_RANDOM);
+
+  n += dlen;
+  gcry_md_open (&hd, algo, 0);
+  gcry_md_write (hd, label, labellen);
+  memcpy (&frame[n], gcry_md_read (hd, 0), dlen);
+  gcry_md_close (hd);
+  n = nframe - valuelen - 1;
+  frame[n++] = 1;
+  memcpy (&frame[n], value, valuelen);
+
+  if ( !(dmask = gcry_malloc_secure (nframe - dlen - 1)))
+    {
+      rc = gpg_err_code_from_errno (errno);
+      gcry_free (frame);
+      return rc;
+    }
+  mgf1 (dmask, nframe - dlen - 1, &frame[1], dlen, algo);
+  for (n = 1 + dlen, p = dmask; n < nframe; n++)
+    frame[n] ^= *p++;
+  gcry_free (dmask);
+  n += valuelen;
+
+  if ( !(smask = gcry_malloc_secure (dlen)))
+    {
+      rc = gpg_err_code_from_errno (errno);
+      gcry_free (frame);
+      return rc;
+    }
+  mgf1 (smask, dlen, &frame[1 + dlen], nframe - dlen - 1, algo);
+  for (n = 1, p = smask; n < 1 + dlen; n++)
+    frame[n] ^= *p++;
+  gcry_free (smask);
+  n = nframe;
+
+  err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe);
+  if (err)
+    rc = gcry_err_code (err);
+  else if (DBG_CIPHER)
+    log_mpidump ("OAEP encoded data", *r_result);
+  gcry_free (frame);
+
+  return rc;
+}
+
+static gcry_err_code_t
+oaep_decode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
+             gcry_mpi_t value, const unsigned char *label, size_t labellen)
+{
+  gcry_err_code_t rc = 0;
+  gcry_error_t err;
+  unsigned char *frame = NULL, *dmask, *smask, *p;
+  size_t nframe = (nbits+7) / 8;
+  size_t dlen;
+  gcry_md_hd_t hd;
+  size_t n;
+
+  if ( !(frame = gcry_malloc_secure (nframe)))
+    return gpg_err_code_from_errno (errno);
+
+  err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &n, value);
+  if (err)
+    return gcry_err_code (err);
+  if (n < nframe)
+    {
+      memmove (frame + (nframe - n), frame, n);
+      memset (frame, 0, (nframe - n));
+    }
+
+  /* FRAME = 00 || MASKED_SEED || MASKED_DB */
+  if (frame[0])
+    {
+      gcry_free (frame);
+      return GPG_ERR_ENCODING_PROBLEM;
+    }
+
+  dlen = gcry_md_get_algo_dlen (algo);
+  if (nframe < 1 + 2 * dlen + 1)
+    {
+      gcry_free (frame);
+      return GPG_ERR_TOO_SHORT;
+    }
+  if ( !(smask = gcry_malloc_secure (dlen)))
+    {
+      rc = gpg_err_code_from_errno (errno);
+      gcry_free (frame);
+      return rc;
+    }
+  mgf1 (smask, dlen, &frame[1 + dlen], nframe - dlen - 1, algo);
+  for (n = 1, p = smask; n < 1 + dlen; n++)
+    frame[n] ^= *p++;
+  gcry_free (smask);
+
+  if ( !(dmask = gcry_malloc_secure (nframe - dlen - 1)))
+    {
+      rc = gpg_err_code_from_errno (errno);
+      gcry_free (frame);
+      return rc;
+    }
+  mgf1 (dmask, nframe - dlen - 1, &frame[1], dlen, algo);
+  for (n = 1 + dlen, p = dmask; n < nframe; n++)
+    frame[n] ^= *p++;
+  gcry_free (dmask);
+
+  gcry_md_open (&hd, algo, 0);
+  gcry_md_write (hd, label, labellen);
+  memcpy (&frame[1], gcry_md_read (hd, 0), dlen);
+  gcry_md_close (hd);
+
+  if (memcmp (&frame[1], &frame[1 + dlen], dlen))
+    {
+      gcry_free (frame);
+      return GPG_ERR_ENCODING_PROBLEM;
+    }
+
+  for (n = 1 + dlen * 2; n < nframe && !frame[n]; n++)
+    ;
+  if (n < nframe && frame[n] != 1)
+    {
+      gcry_free (frame);
+      return GPG_ERR_ENCODING_PROBLEM;
+    }
+
+  n++;
+  err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, &frame[n], nframe - n, NULL);
+  if (err)
+    rc = gcry_err_code (err);
+  else if (DBG_CIPHER)
+    log_mpidump ("value extracted from OAEP encoded data", *r_result);
+  gcry_free (frame);
+
+  return rc;
+}
 
 /* Internal function.   */
 static gcry_err_code_t
@@ -1161,22 +1360,76 @@ sexp_to_sig (gcry_sexp_t sexp, gcry_mpi_t **retarray,
   return err;
 }
 
+static inline int
+get_hash_algo (const char *s, size_t n)
+{
+  static const struct { const char *name; int algo; } hashnames[] = {
+    { "sha1",   GCRY_MD_SHA1 },
+    { "md5",    GCRY_MD_MD5 },
+    { "sha256", GCRY_MD_SHA256 },
+    { "ripemd160", GCRY_MD_RMD160 },
+    { "rmd160", GCRY_MD_RMD160 },
+    { "sha384", GCRY_MD_SHA384 },
+    { "sha512", GCRY_MD_SHA512 },
+    { "sha224", GCRY_MD_SHA224 },
+    { "md2",    GCRY_MD_MD2 },
+    { "md4",    GCRY_MD_MD4 },
+    { "tiger",  GCRY_MD_TIGER },
+    { "haval",  GCRY_MD_HAVAL },
+    { NULL, 0 }
+  };
+  int algo;
+  int i;
+
+  for (i=0; hashnames[i].name; i++)
+    {
+      if ( strlen (hashnames[i].name) == n
+	   && !memcmp (hashnames[i].name, s, n))
+	break;
+    }
+  if (hashnames[i].name)
+    algo = hashnames[i].algo;
+  else
+    {
+      /* In case of not listed or dynamically allocated hash
+	 algorithm we fall back to this somewhat slower
+	 method.  Further, it also allows to use OIDs as
+	 algorithm names. */
+      char *tmpname;
+
+      tmpname = gcry_malloc (n+1);
+      if (!tmpname)
+	algo = 0;  /* Out of core - silently give up.  */
+      else
+	{
+	  memcpy (tmpname, s, n);
+	  tmpname[n] = 0;
+	  algo = gcry_md_map_name (tmpname);
+	  gcry_free (tmpname);
+	}
+    }
+  return algo;
+}
+
 
 /****************
  * Take sexp and return an array of MPI as used for our internal decrypt
  * function.
  * s_data = (enc-val
- *           [(flags [pkcs1])]
+ *           [(flags [raw, pkcs1, oaep, no-blinding, unpad])]
+ *           [(hash-algo <algo>)]
+ *           [(label <label>)]
  *	      (<algo>
  *		(<param_name1> <mpi>)
  *		...
  *		(<param_namen> <mpi>)
  *	      ))
+ * HASH-ALGO and LABEL are specific to OAEP.
  * RET_MODERN is set to true when at least an empty flags list has been found.
  */
 static gcry_err_code_t
 sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
-             int *ret_modern, int *ret_want_pkcs1, int *flags)
+             int *ret_modern, int *flags, struct pk_encoding_ctx *ctx)
 {
   gcry_err_code_t err = 0;
   gcry_sexp_t list = NULL, l2 = NULL;
@@ -1187,10 +1440,17 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
   int parsed_flags = 0;
   const char *elems;
   gcry_mpi_t *array = NULL;
+  struct pk_encoding_ctx dummy_ctx;
 
-  *ret_want_pkcs1 = 0;
   *ret_modern = 0;
 
+  if (!ctx)
+    ctx = &dummy_ctx;
+  ctx->encoding = PUBKEY_ENC_RAW;
+  ctx->hash_algo = GCRY_MD_SHA1;
+  ctx->label = NULL;
+  ctx->labellen = 0;
+
   /* Check that the first element is valid.  */
   list = gcry_sexp_find_token (sexp, "enc-val" , 0);
   if (!list)
@@ -1229,19 +1489,76 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
           else if (n == 3 && !memcmp (s, "raw", 3))
             ; /* This is just a dummy as it is the default.  */
           else if (n == 5 && !memcmp (s, "pkcs1", 5))
-            *ret_want_pkcs1 = 1;
+            ctx->encoding = PUBKEY_ENC_PKCS1;
+          else if (n == 4 && !memcmp (s, "oaep", 4))
+            ctx->encoding = PUBKEY_ENC_OAEP;
           else if (n == 11 && ! memcmp (s, "no-blinding", 11))
             parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
+	  else if (n == 5 && !memcmp (s, "unpad", 5))
+	    parsed_flags |= PUBKEY_FLAG_UNPAD;
           else
             {
               err = GPG_ERR_INV_FLAG;
               goto leave;
             }
         }
-
-      /* Get the next which has the actual data. */
       gcry_sexp_release (l2);
-      l2 = gcry_sexp_nth (list, 2);
+
+      /* Get the OAEP parameters HASH-ALGO and LABEL, if any. */
+      if (ctx->encoding == PUBKEY_ENC_OAEP)
+	{
+	  /* Get HASH-ALGO. */
+	  l2 = gcry_sexp_find_token (list, "hash-algo", 0);
+	  if (l2)
+	    {
+	      s = gcry_sexp_nth_data (l2, 1, &n);
+	      if (!s)
+		err = GPG_ERR_NO_OBJ;
+	      else
+		{
+		  ctx->hash_algo = get_hash_algo (s, n);
+		  if (!ctx->hash_algo)
+		    err = GPG_ERR_DIGEST_ALGO;
+		}
+	      gcry_sexp_release (l2);
+	      if (err)
+		goto leave;
+	    }
+
+	  /* Get LABEL. */
+	  l2 = gcry_sexp_find_token (list, "label", 0);
+	  if (l2)
+	    {
+	      s = gcry_sexp_nth_data (l2, 1, &n);
+	      if (!s)
+		err = GPG_ERR_NO_OBJ;
+	      else if (n > 0)
+		{
+		  ctx->label = gcry_malloc (n);
+		  if (!ctx->label)
+		    err = gpg_err_code_from_errno (errno);
+		  else
+		    {
+		      memcpy (ctx->label, s, n);
+		      ctx->labellen = n;
+		    }
+		}
+	      gcry_sexp_release (l2);
+	      if (err)
+		goto leave;
+	    }
+	}
+
+      /* Get the next which has the actual data - skip HASH-ALGO and LABEL. */
+      for (i = 2; (l2 = gcry_sexp_nth (list, i)) != NULL; i++)
+	{
+	  s = gcry_sexp_nth_data (l2, 0, &n);
+	  if (!(n == 9 && !memcmp (s, "hash-algo", 9))
+	      && !(n == 5 && !memcmp (s, "label", 5)))
+	    break;
+	  gcry_sexp_release (l2);
+	}
+
       if (!l2)
         {
           err = GPG_ERR_NO_OBJ; /* No cdr for the data object. */
@@ -1294,6 +1611,7 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
       _gcry_module_release (module);
       ath_mutex_unlock (&pubkeys_registered_lock);
       gcry_free (array);
+      gcry_free (ctx->label);
     }
   else
     {
@@ -1314,32 +1632,45 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_module_t *retalgo,
    (<mpi>)
    or
    (data
-    [(flags [pkcs1])]
+    [(flags [raw, pkcs1, oaep, no-blinding])]
     [(hash <algo> <value>)]
     [(value <text>)]
+    [(hash-algo <algo>)]
+    [(label <label>)]
    )
 
    Either the VALUE or the HASH element must be present for use
    with signatures.  VALUE is used for encryption.
 
+   HASH-ALGO and LABEL are specific to OAEP.
+
    NBITS is the length of the key in bits.
 
 */
 static gcry_err_code_t
 sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
-                  int for_encryption, int *flags)
+                  int for_encryption, int *flags, struct pk_encoding_ctx *ctx)
 {
   gcry_err_code_t rc = 0;
   gcry_sexp_t ldata, lhash, lvalue;
   int i;
   size_t n;
   const char *s;
-  int is_raw = 0, is_pkcs1 = 0, unknown_flag=0;
+  int unknown_flag=0;
   int parsed_flags = 0, dummy_flags;
+  struct pk_encoding_ctx dummy_ctx;
 
   if (! flags)
     flags = &dummy_flags;
 
+  if (! ctx)
+    ctx = &dummy_ctx;
+
+  ctx->encoding = PUBKEY_ENC_UNKNOWN;
+  ctx->hash_algo = GCRY_MD_SHA1;
+  ctx->label = NULL;
+  ctx->labellen = 0;
+
   *ret_mpi = NULL;
   ldata = gcry_sexp_find_token (input, "data", 0);
   if (!ldata)
@@ -1359,9 +1690,11 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
             if (!s)
               ; /* not a data element*/
             else if ( n == 3 && !memcmp (s, "raw", 3))
-              is_raw = 1;
+              ctx->encoding = PUBKEY_ENC_RAW;
             else if ( n == 5 && !memcmp (s, "pkcs1", 5))
-              is_pkcs1 = 1;
+              ctx->encoding = PUBKEY_ENC_PKCS1;
+            else if ( n == 4 && !memcmp (s, "oaep", 4))
+              ctx->encoding = PUBKEY_ENC_OAEP;
 	    else if (n == 11 && ! memcmp (s, "no-blinding", 11))
 	      parsed_flags |= PUBKEY_FLAG_NO_BLINDING;
             else
@@ -1371,8 +1704,8 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
       }
   }
 
-  if (!is_pkcs1 && !is_raw)
-    is_raw = 1; /* default to raw */
+  if (ctx->encoding == PUBKEY_ENC_UNKNOWN)
+    ctx->encoding = PUBKEY_ENC_RAW; /* default to raw */
 
   /* Get HASH or MPI */
   lhash = gcry_sexp_find_token (ldata, "hash", 0);
@@ -1382,15 +1715,13 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
     rc = GPG_ERR_INV_OBJ; /* none or both given */
   else if (unknown_flag)
     rc = GPG_ERR_INV_FLAG;
-  else if (is_raw && is_pkcs1 && !for_encryption)
-    rc = GPG_ERR_CONFLICT;
-  else if (is_raw && lvalue)
+  else if (ctx->encoding == PUBKEY_ENC_RAW && lvalue)
     {
       *ret_mpi = gcry_sexp_nth_mpi (lvalue, 1, 0);
       if (!*ret_mpi)
         rc = GPG_ERR_INV_OBJ;
     }
-  else if (is_pkcs1 && lvalue && for_encryption)
+  else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue && for_encryption)
     {
       /* Create pkcs#1 block type 2 padding. */
       unsigned char *frame = NULL;
@@ -1457,7 +1788,7 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
 
       gcry_free(frame);
     }
-  else if (is_pkcs1 && lhash && !for_encryption)
+  else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash && !for_encryption)
     {
       /* Create pkcs#1 block type 1 padding. */
       if (gcry_sexp_length (lhash) != 3)
@@ -1466,21 +1797,6 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
         rc = GPG_ERR_INV_OBJ;
       else
         {
-          static struct { const char *name; int algo; } hashnames[] =
-          { { "sha1",   GCRY_MD_SHA1 },
-            { "md5",    GCRY_MD_MD5 },
-            { "sha256", GCRY_MD_SHA256 },
-            { "ripemd160", GCRY_MD_RMD160 },
-            { "rmd160", GCRY_MD_RMD160 },
-            { "sha384", GCRY_MD_SHA384 },
-            { "sha512", GCRY_MD_SHA512 },
-            { "sha224", GCRY_MD_SHA224 },
-            { "md2",    GCRY_MD_MD2 },
-            { "md4",    GCRY_MD_MD4 },
-            { "tiger",  GCRY_MD_TIGER },
-            { "haval",  GCRY_MD_HAVAL },
-            { NULL, 0 }
-          };
           int algo;
           byte asn[100];
           byte *frame = NULL;
@@ -1489,34 +1805,7 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
           size_t valuelen;
           size_t asnlen, dlen;
 
-          for (i=0; hashnames[i].name; i++)
-            {
-              if ( strlen (hashnames[i].name) == n
-                   && !memcmp (hashnames[i].name, s, n))
-                break;
-            }
-          if (hashnames[i].name)
-            algo = hashnames[i].algo;
-          else
-            {
-              /* In case of not listed or dynamically allocated hash
-                 algorithm we fall back to this somewhat slower
-                 method.  Further, it also allows to use OIDs as
-                 algorithm names. */
-              char *tmpname;
-
-              tmpname = gcry_malloc (n+1);
-              if (!tmpname)
-                algo = 0;  /* Out of core - silently give up.  */
-              else
-                {
-                  memcpy (tmpname, s, n);
-                  tmpname[n] = 0;
-                  algo = gcry_md_map_name (tmpname);
-                  gcry_free (tmpname);
-                }
-            }
-
+	  algo = get_hash_algo (s, n);
           asnlen = DIM(asn);
           dlen = gcry_md_get_algo_dlen (algo);
 
@@ -1567,15 +1856,74 @@ sexp_data_to_mpi (gcry_sexp_t input, unsigned int nbits, gcry_mpi_t *ret_mpi,
           gcry_free (frame);
         }
     }
+  else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue && for_encryption)
+    {
+      const void * value;
+      size_t valuelen;
+
+      if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
+	rc = GPG_ERR_INV_OBJ;
+      else
+	{
+	  gcry_sexp_t list;
+
+	  /* Get HASH-ALGO. */
+	  list = gcry_sexp_find_token (ldata, "hash-algo", 0);
+	  if (list)
+	    {
+	      s = gcry_sexp_nth_data (list, 1, &n);
+	      if (!s)
+		rc = GPG_ERR_NO_OBJ;
+	      else
+		{
+		  ctx->hash_algo = get_hash_algo (s, n);
+		  if (!ctx->hash_algo)
+		    rc = GPG_ERR_DIGEST_ALGO;
+		}
+	      gcry_sexp_release (list);
+	      if (rc)
+		goto leave;
+	    }
+
+	  /* Get LABEL. */
+	  list = gcry_sexp_find_token (ldata, "label", 0);
+	  if (list)
+	    {
+	      s = gcry_sexp_nth_data (list, 1, &n);
+	      if (!s)
+		rc = GPG_ERR_NO_OBJ;
+	      else if (n > 0)
+		{
+		  ctx->label = gcry_malloc (n);
+		  if (!ctx->label)
+		    rc = gpg_err_code_from_errno (errno);
+		  else
+		    {
+		      memcpy (ctx->label, s, n);
+		      ctx->labellen = n;
+		    }
+		}
+	      gcry_sexp_release (list);
+	      if (rc)
+		goto leave;
+	    }
+
+	  rc = oaep_encode (ret_mpi, nbits, ctx->hash_algo, value, valuelen,
+			    ctx->label, ctx->labellen);
+	}
+    }
   else
     rc = GPG_ERR_CONFLICT;
 
+ leave:
   gcry_sexp_release (ldata);
   gcry_sexp_release (lhash);
   gcry_sexp_release (lvalue);
 
   if (!rc)
     *flags = parsed_flags;
+  else
+    gcry_free (ctx->label);
 
   return rc;
 }
@@ -1609,6 +1957,7 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
   gcry_mpi_t *pkey = NULL, data = NULL, *ciph = NULL;
   const char *algo_name, *algo_elems;
   int flags;
+  struct pk_encoding_ctx ctx;
   gcry_err_code_t rc;
   gcry_pk_spec_t *pubkey = NULL;
   gcry_module_t module = NULL;
@@ -1617,6 +1966,7 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
 
   REGISTER_DEFAULT_PUBKEYS;
 
+  memset (&ctx, 0, sizeof(struct pk_encoding_ctx));
   /* Get the key. */
   rc = sexp_to_key (s_pkey, 0, NULL, &pkey, &module);
   if (rc)
@@ -1638,7 +1988,7 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
 
   /* Get the stuff we want to encrypt. */
   rc = sexp_data_to_mpi (s_data, gcry_pk_get_nbits (s_pkey), &data, 1,
-                         &flags);
+                         &flags, &ctx);
   if (rc)
     goto leave;
 
@@ -1721,6 +2071,8 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
       ath_mutex_unlock (&pubkeys_registered_lock);
     }
 
+  gcry_free (ctx.label);
+
   return gcry_error (rc);
 }
 
@@ -1751,12 +2103,14 @@ gcry_pk_encrypt (gcry_sexp_t *r_ciph, gcry_sexp_t s_data, gcry_sexp_t s_pkey)
 gcry_error_t
 gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
 {
-  gcry_mpi_t *skey = NULL, *data = NULL, plain = NULL;
-  int modern, want_pkcs1, flags;
+  gcry_mpi_t *skey = NULL, *data = NULL, plain = NULL, unpad = NULL;
+  int modern, flags;
+  struct pk_encoding_ctx ctx;
   gcry_err_code_t rc;
   gcry_module_t module_enc = NULL, module_key = NULL;
 
   *r_plain = NULL;
+  ctx.label = NULL;
 
   REGISTER_DEFAULT_PUBKEYS;
 
@@ -1764,7 +2118,7 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
   if (rc)
     goto leave;
 
-  rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &want_pkcs1, &flags);
+  rc = sexp_to_enc (s_data, &data, &module_enc, &modern, &flags, &ctx);
   if (rc)
     goto leave;
 
@@ -1778,6 +2132,18 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
   if (rc)
     goto leave;
 
+  /* Do un-padding. */
+  /* FIXME: Currently only OAEP is supported. */
+  if ((flags & PUBKEY_FLAG_UNPAD) && ctx.encoding == PUBKEY_ENC_OAEP)
+    {
+      rc = oaep_decode (&unpad, gcry_pk_get_nbits (s_skey), ctx.hash_algo,
+			plain, ctx.label, ctx.labellen);
+      mpi_free (plain);
+      if (rc)
+	goto leave;
+      plain = unpad;
+    }
+
   if (gcry_sexp_build (r_plain, NULL, modern? "(value %m)" : "%m", plain))
     BUG ();
 
@@ -1807,6 +2173,8 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
       ath_mutex_unlock (&pubkeys_registered_lock);
     }
 
+  gcry_free (ctx.label);
+
   return gcry_error (rc);
 }
 
@@ -1869,7 +2237,7 @@ gcry_pk_sign (gcry_sexp_t *r_sig, gcry_sexp_t s_hash, gcry_sexp_t s_skey)
   /* Get the stuff we want to sign.  Note that pk_get_nbits does also
       work on a private key. */
   rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_skey),
-                             &hash, 0, NULL);
+                             &hash, 0, NULL, NULL);
   if (rc)
     goto leave;
 
@@ -1980,7 +2348,7 @@ gcry_pk_verify (gcry_sexp_t s_sig, gcry_sexp_t s_hash, gcry_sexp_t s_pkey)
       goto leave;
     }
 
-  rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_pkey), &hash, 0, 0);
+  rc = sexp_data_to_mpi (s_hash, gcry_pk_get_nbits (s_pkey), &hash, 0, 0, NULL);
   if (rc)
     goto leave;
 
diff --git a/src/cipher.h b/src/cipher.h
index a568800..689995b 100644
--- a/src/cipher.h
+++ b/src/cipher.h
@@ -1,5 +1,5 @@
 /* cipher.h
- *	Copyright (C) 1998, 2002, 2003 Free Software Foundation, Inc.
+ *	Copyright (C) 1998, 2002, 2003, 2009 Free Software Foundation, Inc.
  *
  * This file is part of Libgcrypt.
  *
@@ -27,6 +27,23 @@
 #include "../random/random.h"
 
 #define PUBKEY_FLAG_NO_BLINDING    (1 << 0)
+#define PUBKEY_FLAG_UNPAD          (1 << 1)
+
+enum pk_encoding
+  {
+    PUBKEY_ENC_RAW,
+    PUBKEY_ENC_PKCS1,
+    PUBKEY_ENC_OAEP,
+    PUBKEY_ENC_UNKNOWN
+  };
+
+struct pk_encoding_ctx
+{
+  enum pk_encoding encoding;
+  int hash_algo;
+  unsigned char *label;
+  size_t labellen;
+};
 
 #define CIPHER_INFO_NO_WEAK_KEY    1
 
diff --git a/tests/basic.c b/tests/basic.c
index 2216476..cf4fb8c 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -2295,6 +2295,9 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey)
       { "(data\n (flags pkcs1)\n"
 	" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
 	0 },
+      { "(data\n (flags oaep)\n"
+	" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
+	GPG_ERR_CONFLICT },
       /* This test is to see whether hash algorithms not hard wired in
          pubkey.c are detected:  */
       { "(data\n (flags pkcs1)\n"
@@ -2355,6 +2358,151 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey)
 }
 
 static void
+check_pubkey_crypt (int n, gcry_sexp_t skey, gcry_sexp_t pkey)
+{
+  gcry_error_t rc;
+  gcry_sexp_t plain, ciph, data;
+  int dataidx;
+  static struct
+  {
+    const char *data;
+    const char *hint;
+    int unpadded;
+    int expected_rc;
+  } datas[] =
+    {
+      {	"(data\n (flags pkcs1)\n"
+	" (value #11223344556677889900AA#))\n",
+	NULL,
+	0,
+	0 },
+      { "(data\n (flags oaep)\n"
+	" (value #11223344556677889900AA#))\n",
+	"(flags oaep unpad)",
+	1,
+	0 },
+      { "(data\n (flags oaep)\n (hash-algo sha1)\n"
+	" (value #11223344556677889900AA#))\n",
+	"(flags oaep unpad)(hash-algo sha1)",
+	1,
+	0 },
+      { "(data\n (flags oaep)\n (hash-algo sha1)\n (label \"test\")\n"
+	" (value #11223344556677889900AA#))\n",
+	"(flags oaep unpad)(hash-algo sha1)(label \"test\")",
+	1,
+	0 },
+      {	"(data\n (flags )\n" " (value #11223344556677889900AA#))\n",
+	NULL,
+	1,
+	0 },
+      {	"(data\n (flags )\n" " (value #0090223344556677889900AA#))\n",
+	NULL,
+	1,
+	0 },
+      { "(data\n (flags raw)\n" " (value #11223344556677889900AA#))\n",
+	NULL,
+	1,
+	0 },
+      { "(data\n (flags pkcs1)\n"
+	" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
+	NULL,
+	0,
+	GPG_ERR_CONFLICT },
+      { "(data\n (flags raw foo)\n"
+	" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
+	NULL,
+	0,
+	GPG_ERR_INV_FLAG },
+      { NULL }
+    };
+
+  (void)n;
+
+  for (dataidx = 0; datas[dataidx].data; dataidx++)
+    {
+      if (verbose)
+	fprintf (stderr, "  encryption/decryption test %d\n", dataidx);
+
+      rc = gcry_sexp_sscan (&data, NULL, datas[dataidx].data,
+			    strlen (datas[dataidx].data));
+      if (rc)
+	die ("converting data failed: %s\n", gpg_strerror (rc));
+
+      rc = gcry_pk_encrypt (&ciph, data, pkey);
+      if (gcry_err_code (rc) != datas[dataidx].expected_rc)
+	fail ("gcry_pk_encrypt failed: %s\n", gpg_strerror (rc));
+
+      if (!rc)
+	{
+	  /* Insert decoding hint to CIPH. */
+	  if (datas[dataidx].hint)
+	    {
+	      size_t hint_len, len;
+	      char *hint, *buf;
+	      gcry_sexp_t list;
+
+	      /* Convert decoding hint into canonical sexp. */
+	      hint_len = gcry_sexp_new (&list, datas[dataidx].hint,
+					strlen (datas[dataidx].hint), 1);
+	      hint_len = gcry_sexp_sprint (list, GCRYSEXP_FMT_CANON, NULL, 0);
+	      hint = gcry_malloc (hint_len);
+	      if (!hint)
+		die ("can't allocate memory\n");
+	      hint_len = gcry_sexp_sprint (list, GCRYSEXP_FMT_CANON, hint,
+					   hint_len);
+	      gcry_sexp_release (list);
+
+	      /* Convert CIPH into canonical sexp. */
+	      len = gcry_sexp_sprint (ciph, GCRYSEXP_FMT_CANON, NULL, 0);
+	      buf = gcry_malloc (len + hint_len);
+	      if (!buf)
+		die ("can't allocate memory\n");
+	      len = gcry_sexp_sprint (ciph, GCRYSEXP_FMT_CANON, buf, len);
+	      /* assert (!strcmp (buf, "(7:enc-val", 10)); */
+
+	      /* Copy decoding hint into CIPH. */
+	      memmove (buf + 10 + hint_len, buf + 10, len - 10);
+	      memcpy (buf + 10, hint, hint_len);
+	      gcry_free (hint);
+	      gcry_sexp_new (&list, buf, len + hint_len, 1);
+	      gcry_free (buf);
+	      gcry_sexp_release (ciph);
+	      ciph = list;
+	    }
+	  rc = gcry_pk_decrypt (&plain, ciph, skey);
+	  if (rc)
+	    fail ("gcry_pk_decrypt failed: %s\n", gpg_strerror (rc));
+	  else if (datas[dataidx].unpadded)
+	    {
+	      gcry_sexp_t p1, p2;
+
+	      p1 = gcry_sexp_find_token (data, "value", 0);
+	      p2 = gcry_sexp_find_token (plain, "value", 0);
+	      if (p1 && p2)
+		{
+		  const char *s1, *s2;
+		  size_t n1, n2;
+
+		  s1 = gcry_sexp_nth_data (p1, 1, &n1);
+		  s2 = gcry_sexp_nth_data (p2, 1, &n2);
+		  if (n1 != n2 || memcmp (s1, s2, n1))
+		    fail ("gcry_pk_encrypt/gcry_pk_decrypt do not roundtrip\n");
+		}
+	      gcry_sexp_release (p1);
+	      gcry_sexp_release (p2);
+	    }
+	}
+
+      gcry_sexp_release (plain);
+      plain = NULL;
+      gcry_sexp_release (ciph);
+      ciph = NULL;
+      gcry_sexp_release (data);
+      data = NULL;
+    }
+}
+
+static void
 check_pubkey_grip (int n, const unsigned char *grip,
 		   gcry_sexp_t skey, gcry_sexp_t pkey)
 {
@@ -2376,6 +2524,8 @@ do_check_one_pubkey (int n, gcry_sexp_t skey, gcry_sexp_t pkey,
 {
  if (flags & FLAG_SIGN)
     check_pubkey_sign (n, skey, pkey);
+ if (flags & FLAG_CRYPT)
+   check_pubkey_crypt (n, skey, pkey);
  if (grip && (flags & FLAG_GRIP))
    check_pubkey_grip (n, grip, skey, pkey);
 }
@@ -2439,6 +2589,8 @@ check_one_pubkey_new (int n)
 
   get_keys_new (&pkey, &skey);
   do_check_one_pubkey (n, skey, pkey, NULL, FLAG_SIGN | FLAG_CRYPT);
+  gcry_sexp_release (pkey);
+  gcry_sexp_release (skey);
 }
 
 /* Run all tests for the public key functions. */

-----------------------------------------------------------------------

Summary of changes:
 NEWS             |    4 +
 TODO             |    2 -
 cipher/ChangeLog |   25 +++
 cipher/pubkey.c  |  554 +++++++++++++++++++++++++++++++++++++++++++++---------
 src/ChangeLog    |    6 +
 src/cipher.h     |   19 ++-
 tests/ChangeLog  |    7 +
 tests/basic.c    |  152 +++++++++++++++
 8 files changed, 679 insertions(+), 90 deletions(-)


hooks/post-receive
-- 
The GNU crypto library
http://git.gnupg.org




More information about the Gnupg-commits mailing list