pk: Move RSA encoding functions to a new file.
authorWerner Koch <wk@gnupg.org>
Sat, 7 Sep 2013 08:06:46 +0000 (10:06 +0200)
committerWerner Koch <wk@gnupg.org>
Thu, 19 Sep 2013 14:43:33 +0000 (16:43 +0200)
* cipher/rsa-common: New.
* cipher/pubkey.c (pkcs1_encode_for_encryption): Move to rsa-common.c
and rename to _gcry_rsa_pkcs1_encode_for_enc.
(pkcs1_decode_for_encryption): Move to rsa-common.c and rename to
_gcry_rsa_pkcs1_decode_for_enc.
(pkcs1_encode_for_signature): Move to rsa-common.c and rename to
_gcry_rsa_pkcs1_encode_for_sig.
(oaep_encode): Move to rsa-common.c and rename to
_gcry_rsa_oaep_encode.
(oaep_decode): Move to rsa-common.c and rename to
_gcry_rsa_oaep_decode.
(pss_encode): Move to rsa-common.c and rename to _gcry_rsa_pss_encode.
(pss_verify): Move to rsa-common.c and rename to _gcry_rsa_pss_decode.
(octet_string_from_mpi, mgf1): Move to rsa-common.c.

Signed-off-by: Werner Koch <wk@gnupg.org>
cipher/Makefile.am
cipher/pubkey-internal.h
cipher/pubkey.c
cipher/rsa-common.c [new file with mode: 0644]

index 49d4cee..cce12c2 100644 (file)
@@ -49,7 +49,7 @@ bithelp.h  \
 bufhelp.h  \
 primegen.c  \
 hash-common.c hash-common.h \
-dsa-common.c \
+dsa-common.c rsa-common.c \
 rmd.h
 
 EXTRA_libcipher_la_SOURCES = \
index 9147cb2..a33ccfe 100644 (file)
 #ifndef GCRY_PUBKEY_INTERNAL_H
 #define GCRY_PUBKEY_INTERNAL_H
 
+/*-- rsa-common.h --*/
+gpg_err_code_t
+_gcry_rsa_pkcs1_encode_for_enc (gcry_mpi_t *r_result, unsigned int nbits,
+                                const unsigned char *value, size_t valuelen,
+                                const unsigned char *random_override,
+                                size_t random_override_len);
+gpg_err_code_t
+_gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen,
+                                unsigned int nbits, gcry_mpi_t value);
+gpg_err_code_t
+_gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
+                                const unsigned char *value, size_t valuelen,
+                                int algo);
+gpg_err_code_t
+_gcry_rsa_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,
+                       const void *random_override, size_t random_override_len);
+gpg_err_code_t
+_gcry_rsa_oaep_decode (unsigned char **r_result, size_t *r_resultlen,
+                       unsigned int nbits, int algo,
+                       gcry_mpi_t value,
+                       const unsigned char *label, size_t labellen);
+gpg_err_code_t
+_gcry_rsa_pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
+                      const unsigned char *value, size_t valuelen, int saltlen,
+                      const void *random_override, size_t random_override_len);
+gpg_err_code_t
+_gcry_rsa_pss_verify (gcry_mpi_t value, gcry_mpi_t encoded,
+                      unsigned int nbits, int algo, size_t saltlen);
+
+
+
 /*-- dsa-common.h --*/
 gcry_mpi_t _gcry_dsa_gen_k (gcry_mpi_t q, int security_level);
 gpg_err_code_t _gcry_dsa_gen_rfc6979_k (gcry_mpi_t *r_k,
index dc56cc3..2585981 100644 (file)
@@ -297,975 +297,6 @@ pubkey_check_secret_key (int algo, gcry_mpi_t *skey)
 }
 
 
-/* Turn VALUE into an octet string and store it in an allocated buffer
-   at R_FRAME or - if R_RAME is NULL - copy it into the caller
-   provided buffer SPACE; either SPACE or R_FRAME may be used.  If
-   SPACE if not NULL, the caller must provide a buffer of at least
-   NBYTES.  If the resulting octet string is shorter than NBYTES pad
-   it to the left with zeroes.  If VALUE does not fit into NBYTES
-   return an error code.  */
-static gpg_err_code_t
-octet_string_from_mpi (unsigned char **r_frame, void *space,
-                       gcry_mpi_t value, size_t nbytes)
-{
-  return _gcry_mpi_to_octet_string (r_frame, space, value, nbytes);
-}
-
-
-/* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block
-   type 2 padding.  On sucess the result is stored as a new MPI at
-   R_RESULT.  On error the value at R_RESULT is undefined.
-
-   If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
-   the seed instead of using a random string for it.  This feature is
-   only useful for regression tests.  Note that this value may not
-   contain zero bytes.
-
-   We encode the value in this way:
-
-     0  2  RND(n bytes)  0  VALUE
-
-   0   is a marker we unfortunately can't encode because we return an
-       MPI which strips all leading zeroes.
-   2   is the block type.
-   RND are non-zero random bytes.
-
-   (Note that OpenPGP includes the cipher algorithm and a checksum in
-   VALUE; the caller needs to prepare the value accordingly.)
-  */
-static gcry_err_code_t
-pkcs1_encode_for_encryption (gcry_mpi_t *r_result, unsigned int nbits,
-                            const unsigned char *value, size_t valuelen,
-                             const unsigned char *random_override,
-                             size_t random_override_len)
-{
-  gcry_err_code_t rc = 0;
-  gcry_error_t err;
-  unsigned char *frame = NULL;
-  size_t nframe = (nbits+7) / 8;
-  int i;
-  size_t n;
-  unsigned char *p;
-
-  if (valuelen + 7 > nframe || !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_syserror ();
-
-  n = 0;
-  frame[n++] = 0;
-  frame[n++] = 2; /* block type */
-  i = nframe - 3 - valuelen;
-  gcry_assert (i > 0);
-
-  if (random_override)
-    {
-      int j;
-
-      if (random_override_len != i)
-        {
-          gcry_free (frame);
-          return GPG_ERR_INV_ARG;
-        }
-      /* Check that random does not include a zero byte.  */
-      for (j=0; j < random_override_len; j++)
-        if (!random_override[j])
-          {
-            gcry_free (frame);
-            return GPG_ERR_INV_ARG;
-          }
-      memcpy (frame + n, random_override, random_override_len);
-      n += random_override_len;
-    }
-  else
-    {
-      p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
-      /* Replace zero bytes by new values. */
-      for (;;)
-        {
-          int j, k;
-          unsigned char *pp;
-
-          /* Count the zero bytes. */
-          for (j=k=0; j < i; j++)
-            {
-              if (!p[j])
-                k++;
-            }
-          if (!k)
-            break; /* Okay: no (more) zero bytes. */
-
-          k += k/128 + 3; /* Better get some more. */
-          pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
-          for (j=0; j < i && k; )
-            {
-              if (!p[j])
-                p[j] = pp[--k];
-              if (p[j])
-                j++;
-            }
-          gcry_free (pp);
-        }
-      memcpy (frame+n, p, i);
-      n += i;
-      gcry_free (p);
-    }
-
-  frame[n++] = 0;
-  memcpy (frame+n, value, valuelen);
-  n += valuelen;
-  gcry_assert (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 ("PKCS#1 block type 2 encoded data", *r_result);
-  gcry_free (frame);
-
-  return rc;
-}
-
-
-/* Decode a plaintext in VALUE assuming pkcs#1 block type 2 padding.
-   NBITS is the size of the secret key.  On success the result is
-   stored as a newly allocated buffer at R_RESULT and its valid length at
-   R_RESULTLEN.  On error NULL is stored at R_RESULT.  */
-static gcry_err_code_t
-pkcs1_decode_for_encryption (unsigned char **r_result, size_t *r_resultlen,
-                             unsigned int nbits, gcry_mpi_t value)
-{
-  gcry_error_t err;
-  unsigned char *frame = NULL;
-  size_t nframe = (nbits+7) / 8;
-  size_t n;
-
-  *r_result = NULL;
-
-  if ( !(frame = gcry_malloc_secure (nframe)))
-    return gpg_err_code_from_syserror ();
-
-  err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &n, value);
-  if (err)
-    {
-      gcry_free (frame);
-      return gcry_err_code (err);
-    }
-
-  nframe = n; /* Set NFRAME to the actual length.  */
-
-  /* FRAME = 0x00 || 0x02 || PS || 0x00 || M
-
-     pkcs#1 requires that the first byte is zero.  Our MPIs usually
-     strip leading zero bytes; thus we are not able to detect them.
-     However due to the way gcry_mpi_print is implemented we may see
-     leading zero bytes nevertheless.  We handle this by making the
-     first zero byte optional.  */
-  if (nframe < 4)
-    {
-      gcry_free (frame);
-      return GPG_ERR_ENCODING_PROBLEM;  /* Too short.  */
-    }
-  n = 0;
-  if (!frame[0])
-    n++;
-  if (frame[n++] != 0x02)
-    {
-      gcry_free (frame);
-      return GPG_ERR_ENCODING_PROBLEM;  /* Wrong block type.  */
-    }
-
-  /* Skip the non-zero random bytes and the terminating zero byte.  */
-  for (; n < nframe && frame[n] != 0x00; n++)
-    ;
-  if (n+1 >= nframe)
-    {
-      gcry_free (frame);
-      return GPG_ERR_ENCODING_PROBLEM; /* No zero byte.  */
-    }
-  n++; /* Skip the zero byte.  */
-
-  /* To avoid an extra allocation we reuse the frame buffer.  The only
-     caller of this function will anyway free the result soon.  */
-  memmove (frame, frame + n, nframe - n);
-  *r_result = frame;
-  *r_resultlen = nframe - n;
-
-  if (DBG_CIPHER)
-    log_printhex ("value extracted from PKCS#1 block type 2 encoded data",
-                  *r_result, *r_resultlen);
-
-  return 0;
-}
-
-
-/* Encode {VALUE,VALUELEN} for an NBITS keys and hash algorith ALGO
-   using the pkcs#1 block type 1 padding.  On success the result is
-   stored as a new MPI at R_RESULT.  On error the value at R_RESULT is
-   undefined.
-
-   We encode the value in this way:
-
-     0  1  PAD(n bytes)  0  ASN(asnlen bytes) VALUE(valuelen bytes)
-
-   0   is a marker we unfortunately can't encode because we return an
-       MPI which strips all leading zeroes.
-   1   is the block type.
-   PAD consists of 0xff bytes.
-   0   marks the end of the padding.
-   ASN is the DER encoding of the hash algorithm; along with the VALUE
-       it yields a valid DER encoding.
-
-   (Note that PGP prior to version 2.3 encoded the message digest as:
-      0   1   MD(16 bytes)   0   PAD(n bytes)   1
-    The MD is always 16 bytes here because it's always MD5.  GnuPG
-    does not not support pre-v2.3 signatures, but I'm including this
-    comment so the information is easily found if needed.)
-*/
-static gcry_err_code_t
-pkcs1_encode_for_signature (gcry_mpi_t *r_result, unsigned int nbits,
-                           const unsigned char *value, size_t valuelen,
-                           int algo)
-{
-  gcry_err_code_t rc = 0;
-  gcry_error_t err;
-  byte asn[100];
-  byte *frame = NULL;
-  size_t nframe = (nbits+7) / 8;
-  int i;
-  size_t n;
-  size_t asnlen, dlen;
-
-  asnlen = DIM(asn);
-  dlen = gcry_md_get_algo_dlen (algo);
-
-  if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
-    {
-      /* We don't have yet all of the above algorithms.  */
-      return GPG_ERR_NOT_IMPLEMENTED;
-    }
-
-  if ( valuelen != dlen )
-    {
-      /* Hash value does not match the length of digest for
-         the given algorithm.  */
-      return GPG_ERR_CONFLICT;
-    }
-
-  if ( !dlen || dlen + asnlen + 4 > nframe)
-    {
-      /* Can't encode an DLEN byte digest MD into an NFRAME byte
-         frame.  */
-      return GPG_ERR_TOO_SHORT;
-    }
-
-  if ( !(frame = gcry_malloc (nframe)) )
-    return gpg_err_code_from_syserror ();
-
-  /* Assemble the pkcs#1 block type 1. */
-  n = 0;
-  frame[n++] = 0;
-  frame[n++] = 1; /* block type */
-  i = nframe - valuelen - asnlen - 3 ;
-  gcry_assert (i > 1);
-  memset (frame+n, 0xff, i );
-  n += i;
-  frame[n++] = 0;
-  memcpy (frame+n, asn, asnlen);
-  n += asnlen;
-  memcpy (frame+n, value, valuelen );
-  n += valuelen;
-  gcry_assert (n == nframe);
-
-  /* Convert it into an MPI. */
-  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 ("PKCS#1 block type 1 encoded data", *r_result);
-  gcry_free (frame);
-
-  return rc;
-}
-
-
-/* Mask generation function for OAEP.  See RFC-3447 B.2.1.  */
-static gcry_err_code_t
-mgf1 (unsigned char *output, size_t outlen, unsigned char *seed, size_t seedlen,
-      int algo)
-{
-  size_t dlen, nbytes, n;
-  int idx;
-  gcry_md_hd_t hd;
-  gcry_error_t err;
-
-  err = gcry_md_open (&hd, algo, 0);
-  if (err)
-    return gpg_err_code (err);
-
-  dlen = gcry_md_get_algo_dlen (algo);
-
-  /* We skip step 1 which would be assert(OUTLEN <= 2^32).  The loop
-     in step 3 is merged with step 4 by concatenating no more octets
-     than what would fit into OUTPUT.  The ceiling for the counter IDX
-     is implemented indirectly.  */
-  nbytes = 0;  /* Step 2.  */
-  idx = 0;
-  while ( nbytes < outlen )
-    {
-      unsigned char c[4], *digest;
-
-      if (idx)
-        gcry_md_reset (hd);
-
-      c[0] = (idx >> 24) & 0xFF;
-      c[1] = (idx >> 16) & 0xFF;
-      c[2] = (idx >> 8) & 0xFF;
-      c[3] = idx & 0xFF;
-      idx++;
-
-      gcry_md_write (hd, seed, seedlen);
-      gcry_md_write (hd, c, 4);
-      digest = gcry_md_read (hd, 0);
-
-      n = (outlen - nbytes < dlen)? (outlen - nbytes) : dlen;
-      memcpy (output+nbytes, digest, n);
-      nbytes += n;
-    }
-
-  gcry_md_close (hd);
-  return GPG_ERR_NO_ERROR;
-}
-
-
-/* RFC-3447 (pkcs#1 v2.1) OAEP encoding.  NBITS is the length of the
-   key measured in bits.  ALGO is the hash function; it must be a
-   valid and usable algorithm.  {VALUE,VALUELEN} is the message to
-   encrypt.  {LABEL,LABELLEN} is the optional label to be associated
-   with the message, if LABEL is NULL the default is to use the empty
-   string as label.  On success the encoded ciphertext is returned at
-   R_RESULT.
-
-   If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
-   the seed instead of using a random string for it.  This feature is
-   only useful for regression tests.
-
-   Here is figure 1 from the RFC depicting the process:
-
-                             +----------+---------+-------+
-                        DB = |  lHash   |    PS   |   M   |
-                             +----------+---------+-------+
-                                            |
-                  +----------+              V
-                  |   seed   |--> MGF ---> xor
-                  +----------+              |
-                        |                   |
-               +--+     V                   |
-               |00|    xor <----- MGF <-----|
-               +--+     |                   |
-                 |      |                   |
-                 V      V                   V
-               +--+----------+----------------------------+
-         EM =  |00|maskedSeed|          maskedDB          |
-               +--+----------+----------------------------+
-  */
-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,
-             const void *random_override, size_t random_override_len)
-{
-  gcry_err_code_t rc = 0;
-  gcry_error_t err;
-  unsigned char *frame = NULL;
-  size_t nframe = (nbits+7) / 8;
-  unsigned char *p;
-  size_t hlen;
-  size_t n;
-
-  *r_result = NULL;
-
-  /* Set defaults for LABEL.  */
-  if (!label || !labellen)
-    {
-      label = (const unsigned char*)"";
-      labellen = 0;
-    }
-
-  hlen = gcry_md_get_algo_dlen (algo);
-
-  /* We skip step 1a which would be to check that LABELLEN is not
-     greater than 2^61-1.  See rfc-3447 7.1.1. */
-
-  /* Step 1b.  Note that the obsolete rfc-2437 uses the check:
-     valuelen > nframe - 2 * hlen - 1 .  */
-  if (valuelen > nframe - 2 * hlen - 2 || !nframe)
-    {
-      /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
-      return GPG_ERR_TOO_SHORT; /* The key is too short.  */
-    }
-
-  /* Allocate the frame.  */
-  frame = gcry_calloc_secure (1, nframe);
-  if (!frame)
-    return gpg_err_code_from_syserror ();
-
-  /* Step 2a: Compute the hash of the label.  We store it in the frame
-     where later the maskedDB will commence.  */
-  gcry_md_hash_buffer (algo, frame + 1 + hlen, label, labellen);
-
-  /* Step 2b: Set octet string to zero.  */
-  /* This has already been done while allocating FRAME.  */
-
-  /* Step 2c: Create DB by concatenating lHash, PS, 0x01 and M.  */
-  n = nframe - valuelen - 1;
-  frame[n] = 0x01;
-  memcpy (frame + n + 1, value, valuelen);
-
-  /* Step 3d: Generate seed.  We store it where the maskedSeed will go
-     later. */
-  if (random_override)
-    {
-      if (random_override_len != hlen)
-        {
-          gcry_free (frame);
-          return GPG_ERR_INV_ARG;
-        }
-      memcpy (frame + 1, random_override, hlen);
-    }
-  else
-    gcry_randomize (frame + 1, hlen, GCRY_STRONG_RANDOM);
-
-  /* Step 2e and 2f: Create maskedDB.  */
-  {
-    unsigned char *dmask;
-
-    dmask = gcry_malloc_secure (nframe - hlen - 1);
-    if (!dmask)
-      {
-        rc = gpg_err_code_from_syserror ();
-        gcry_free (frame);
-        return rc;
-      }
-    rc = mgf1 (dmask, nframe - hlen - 1, frame+1, hlen, algo);
-    if (rc)
-      {
-        gcry_free (dmask);
-        gcry_free (frame);
-        return rc;
-      }
-    for (n = 1 + hlen, p = dmask; n < nframe; n++)
-      frame[n] ^= *p++;
-    gcry_free (dmask);
-  }
-
-  /* Step 2g and 2h: Create maskedSeed.  */
-  {
-    unsigned char *smask;
-
-    smask = gcry_malloc_secure (hlen);
-    if (!smask)
-      {
-        rc = gpg_err_code_from_syserror ();
-        gcry_free (frame);
-        return rc;
-      }
-    rc = mgf1 (smask, hlen, frame + 1 + hlen, nframe - hlen - 1, algo);
-    if (rc)
-      {
-        gcry_free (smask);
-        gcry_free (frame);
-        return rc;
-      }
-    for (n = 1, p = smask; n < 1 + hlen; n++)
-      frame[n] ^= *p++;
-    gcry_free (smask);
-  }
-
-  /* Step 2i: Concatenate 0x00, maskedSeed and maskedDB.  */
-  /* This has already been done by using in-place operations.  */
-
-  /* Convert the stuff into an MPI as expected by the caller.  */
-  err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, nframe, NULL);
-  if (err)
-    rc = gcry_err_code (err);
-  else if (DBG_CIPHER)
-    log_mpidump ("OAEP encoded data", *r_result);
-  gcry_free (frame);
-
-  return rc;
-}
-
-
-/* RFC-3447 (pkcs#1 v2.1) OAEP decoding.  NBITS is the length of the
-   key measured in bits.  ALGO is the hash function; it must be a
-   valid and usable algorithm.  VALUE is the raw decrypted message
-   {LABEL,LABELLEN} is the optional label to be associated with the
-   message, if LABEL is NULL the default is to use the empty string as
-   label.  On success the plaintext is returned as a newly allocated
-   buffer at R_RESULT; its valid length is stored at R_RESULTLEN.  On
-   error NULL is stored at R_RESULT.  */
-static gcry_err_code_t
-oaep_decode (unsigned char **r_result, size_t *r_resultlen,
-             unsigned int nbits, int algo,
-             gcry_mpi_t value, const unsigned char *label, size_t labellen)
-{
-  gcry_err_code_t rc;
-  unsigned char *frame = NULL; /* Encoded messages (EM).  */
-  unsigned char *masked_seed;  /* Points into FRAME.  */
-  unsigned char *masked_db;    /* Points into FRAME.  */
-  unsigned char *seed = NULL;  /* Allocated space for the seed and DB.  */
-  unsigned char *db;           /* Points into SEED.  */
-  unsigned char *lhash = NULL; /* Hash of the label.  */
-  size_t nframe;               /* Length of the ciphertext (EM).  */
-  size_t hlen;                 /* Length of the hash digest.  */
-  size_t db_len;               /* Length of DB and masked_db.  */
-  size_t nkey = (nbits+7)/8;   /* Length of the key in bytes.  */
-  int failed = 0;              /* Error indicator.  */
-  size_t n;
-
-  *r_result = NULL;
-
-  /* This code is implemented as described by rfc-3447 7.1.2.  */
-
-  /* Set defaults for LABEL.  */
-  if (!label || !labellen)
-    {
-      label = (const unsigned char*)"";
-      labellen = 0;
-    }
-
-  /* Get the length of the digest.  */
-  hlen = gcry_md_get_algo_dlen (algo);
-
-  /* Hash the label right away.  */
-  lhash = gcry_malloc (hlen);
-  if (!lhash)
-    return gpg_err_code_from_syserror ();
-  gcry_md_hash_buffer (algo, lhash, label, labellen);
-
-  /* Turn the MPI into an octet string.  If the octet string is
-     shorter than the key we pad it to the left with zeroes.  This may
-     happen due to the leading zero in OAEP frames and due to the
-     following random octets (seed^mask) which may have leading zero
-     bytes.  This all is needed to cope with our leading zeroes
-     suppressing MPI implementation.  The code implictly implements
-     Step 1b (bail out if NFRAME != N).  */
-  rc = octet_string_from_mpi (&frame, NULL, value, nkey);
-  if (rc)
-    {
-      gcry_free (lhash);
-      return GPG_ERR_ENCODING_PROBLEM;
-    }
-  nframe = nkey;
-
-  /* Step 1c: Check that the key is long enough.  */
-  if ( nframe < 2 * hlen + 2 )
-    {
-      gcry_free (frame);
-      gcry_free (lhash);
-      return GPG_ERR_ENCODING_PROBLEM;
-    }
-
-  /* Step 2 has already been done by the caller and the
-     gcry_mpi_aprint above.  */
-
-  /* Allocate space for SEED and DB.  */
-  seed = gcry_malloc_secure (nframe - 1);
-  if (!seed)
-    {
-      rc = gpg_err_code_from_syserror ();
-      gcry_free (frame);
-      gcry_free (lhash);
-      return rc;
-    }
-  db = seed + hlen;
-
-  /* To avoid choosen ciphertext attacks from now on we make sure to
-     run all code even in the error case; this avoids possible timing
-     attacks as described by Manger.  */
-
-  /* Step 3a: Hash the label.  */
-  /* This has already been done.  */
-
-  /* Step 3b: Separate the encoded message.  */
-  masked_seed = frame + 1;
-  masked_db   = frame + 1 + hlen;
-  db_len      = nframe - 1 - hlen;
-
-  /* Step 3c and 3d: seed = maskedSeed ^ mgf(maskedDB, hlen).  */
-  if (mgf1 (seed, hlen, masked_db, db_len, algo))
-    failed = 1;
-  for (n = 0; n < hlen; n++)
-    seed[n] ^= masked_seed[n];
-
-  /* Step 3e and 3f: db = maskedDB ^ mgf(seed, db_len).  */
-  if (mgf1 (db, db_len, seed, hlen, algo))
-    failed = 1;
-  for (n = 0; n < db_len; n++)
-    db[n] ^= masked_db[n];
-
-  /* Step 3g: Check lhash, an possible empty padding string terminated
-     by 0x01 and the first byte of EM being 0.  */
-  if (memcmp (lhash, db, hlen))
-    failed = 1;
-  for (n = hlen; n < db_len; n++)
-    if (db[n] == 0x01)
-      break;
-  if (n == db_len)
-    failed = 1;
-  if (frame[0])
-    failed = 1;
-
-  gcry_free (lhash);
-  gcry_free (frame);
-  if (failed)
-    {
-      gcry_free (seed);
-      return GPG_ERR_ENCODING_PROBLEM;
-    }
-
-  /* Step 4: Output M.  */
-  /* To avoid an extra allocation we reuse the seed buffer.  The only
-     caller of this function will anyway free the result soon.  */
-  n++;
-  memmove (seed, db + n, db_len - n);
-  *r_result = seed;
-  *r_resultlen = db_len - n;
-  seed = NULL;
-
-  if (DBG_CIPHER)
-    log_printhex ("value extracted from OAEP encoded data",
-                  *r_result, *r_resultlen);
-
-  return 0;
-}
-
-
-/* RFC-3447 (pkcs#1 v2.1) PSS encoding.  Encode {VALUE,VALUELEN} for
-   an NBITS key.  Note that VALUE is already the mHash from the
-   picture below.  ALGO is a valid hash algorithm and SALTLEN is the
-   length of salt to be used.  On success the result is stored as a
-   new MPI at R_RESULT.  On error the value at R_RESULT is undefined.
-
-   If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
-   the salt instead of using a random string for the salt.  This
-   feature is only useful for regression tests.
-
-   Here is figure 2 from the RFC (errata 595 applied) depicting the
-   process:
-
-                                  +-----------+
-                                  |     M     |
-                                  +-----------+
-                                        |
-                                        V
-                                      Hash
-                                        |
-                                        V
-                          +--------+----------+----------+
-                     M' = |Padding1|  mHash   |   salt   |
-                          +--------+----------+----------+
-                                         |
-               +--------+----------+     V
-         DB =  |Padding2| salt     |   Hash
-               +--------+----------+     |
-                         |               |
-                         V               |    +----+
-                        xor <--- MGF <---|    |0xbc|
-                         |               |    +----+
-                         |               |      |
-                         V               V      V
-               +-------------------+----------+----+
-         EM =  |    maskedDB       |     H    |0xbc|
-               +-------------------+----------+----+
-
-  */
-static gcry_err_code_t
-pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
-           const unsigned char *value, size_t valuelen, int saltlen,
-            const void *random_override, size_t random_override_len)
-{
-  gcry_err_code_t rc = 0;
-  gcry_error_t err;
-  size_t hlen;                 /* Length of the hash digest.  */
-  unsigned char *em = NULL;    /* Encoded message.  */
-  size_t emlen = (nbits+7)/8;  /* Length in bytes of EM.  */
-  unsigned char *h;            /* Points into EM.  */
-  unsigned char *buf = NULL;   /* Help buffer.  */
-  size_t buflen;               /* Length of BUF.  */
-  unsigned char *mhash;        /* Points into BUF.  */
-  unsigned char *salt;         /* Points into BUF.  */
-  unsigned char *dbmask;       /* Points into BUF.  */
-  unsigned char *p;
-  size_t n;
-
-  /* This code is implemented as described by rfc-3447 9.1.1.  */
-
-  /* Get the length of the digest.  */
-  hlen = gcry_md_get_algo_dlen (algo);
-  gcry_assert (hlen);  /* We expect a valid ALGO here.  */
-
-  /* Allocate a help buffer and setup some pointers.  */
-  buflen = 8 + hlen + saltlen + (emlen - hlen - 1);
-  buf = gcry_malloc (buflen);
-  if (!buf)
-    {
-      rc = gpg_err_code_from_syserror ();
-      goto leave;
-    }
-  mhash = buf + 8;
-  salt  = mhash + hlen;
-  dbmask= salt + saltlen;
-
-  /* Step 2: That would be: mHash = Hash(M) but our input is already
-     mHash thus we do only a consistency check and copy to MHASH.  */
-  if (valuelen != hlen)
-    {
-      rc = GPG_ERR_INV_LENGTH;
-      goto leave;
-    }
-  memcpy (mhash, value, hlen);
-
-  /* Step 3: Check length constraints.  */
-  if (emlen < hlen + saltlen + 2)
-    {
-      rc = GPG_ERR_TOO_SHORT;
-      goto leave;
-    }
-
-  /* Allocate space for EM.  */
-  em = gcry_malloc (emlen);
-  if (!em)
-    {
-      rc = gpg_err_code_from_syserror ();
-      goto leave;
-    }
-  h = em + emlen - 1 - hlen;
-
-  /* Step 4: Create a salt.  */
-  if (saltlen)
-    {
-      if (random_override)
-        {
-          if (random_override_len != saltlen)
-            {
-              rc = GPG_ERR_INV_ARG;
-              goto leave;
-            }
-          memcpy (salt, random_override, saltlen);
-        }
-      else
-        gcry_randomize (salt, saltlen, GCRY_STRONG_RANDOM);
-    }
-
-  /* Step 5 and 6: M' = Hash(Padding1 || mHash || salt).  */
-  memset (buf, 0, 8);  /* Padding.  */
-  gcry_md_hash_buffer (algo, h, buf, 8 + hlen + saltlen);
-
-  /* Step 7 and 8: DB = PS || 0x01 || salt.  */
-  /* Note that we use EM to store DB and later Xor in-place.  */
-  p = em + emlen - 1 - hlen - saltlen - 1;
-  memset (em, 0, p - em);
-  *p++ = 0x01;
-  memcpy (p, salt, saltlen);
-
-  /* Step 9: dbmask = MGF(H, emlen - hlen - 1).  */
-  mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
-
-  /* Step 10: maskedDB = DB ^ dbMask */
-  for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
-    em[n] ^= *p;
-
-  /* Step 11: Set the leftmost bits to zero.  */
-  em[0] &= 0xFF >> (8 * emlen - nbits);
-
-  /* Step 12: EM = maskedDB || H || 0xbc.  */
-  em[emlen-1] = 0xbc;
-
-  /* Convert EM into an MPI.  */
-  err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, em, emlen, NULL);
-  if (err)
-    rc = gcry_err_code (err);
-  else if (DBG_CIPHER)
-    log_mpidump ("PSS encoded data", *r_result);
-
- leave:
-  if (em)
-    {
-      wipememory (em, emlen);
-      gcry_free (em);
-    }
-  if (buf)
-    {
-      wipememory (buf, buflen);
-      gcry_free (buf);
-    }
-  return rc;
-}
-
-
-/* Verify a signature assuming PSS padding.  VALUE is the hash of the
-   message (mHash) encoded as an MPI; its length must match the digest
-   length of ALGO.  ENCODED is the output of the RSA public key
-   function (EM).  NBITS is the size of the public key.  ALGO is the
-   hash algorithm and SALTLEN is the length of the used salt.  The
-   function returns 0 on success or on error code.  */
-static gcry_err_code_t
-pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, unsigned int nbits, int algo,
-            size_t saltlen)
-{
-  gcry_err_code_t rc = 0;
-  size_t hlen;                 /* Length of the hash digest.  */
-  unsigned char *em = NULL;    /* Encoded message.  */
-  size_t emlen = (nbits+7)/8;  /* Length in bytes of EM.  */
-  unsigned char *salt;         /* Points into EM.  */
-  unsigned char *h;            /* Points into EM.  */
-  unsigned char *buf = NULL;   /* Help buffer.  */
-  size_t buflen;               /* Length of BUF.  */
-  unsigned char *dbmask;       /* Points into BUF.  */
-  unsigned char *mhash;        /* Points into BUF.  */
-  unsigned char *p;
-  size_t n;
-
-  /* This code is implemented as described by rfc-3447 9.1.2.  */
-
-  /* Get the length of the digest.  */
-  hlen = gcry_md_get_algo_dlen (algo);
-  gcry_assert (hlen);  /* We expect a valid ALGO here.  */
-
-  /* Allocate a help buffer and setup some pointers.
-     This buffer is used for two purposes:
-        +------------------------------+-------+
-     1. | dbmask                       | mHash |
-        +------------------------------+-------+
-           emlen - hlen - 1              hlen
-
-        +----------+-------+---------+-+-------+
-     2. | padding1 | mHash | salt    | | mHash |
-        +----------+-------+---------+-+-------+
-             8       hlen    saltlen     hlen
-  */
-  buflen = 8 + hlen + saltlen;
-  if (buflen < emlen - hlen - 1)
-    buflen = emlen - hlen - 1;
-  buflen += hlen;
-  buf = gcry_malloc (buflen);
-  if (!buf)
-    {
-      rc = gpg_err_code_from_syserror ();
-      goto leave;
-    }
-  dbmask = buf;
-  mhash = buf + buflen - hlen;
-
-  /* Step 2: That would be: mHash = Hash(M) but our input is already
-     mHash thus we only need to convert VALUE into MHASH.  */
-  rc = octet_string_from_mpi (NULL, mhash, value, hlen);
-  if (rc)
-    goto leave;
-
-  /* Convert the signature into an octet string.  */
-  rc = octet_string_from_mpi (&em, NULL, encoded, emlen);
-  if (rc)
-    goto leave;
-
-  /* Step 3: Check length of EM.  Because we internally use MPI
-     functions we can't do this properly; EMLEN is always the length
-     of the key because octet_string_from_mpi needs to left pad the
-     result with zero to cope with the fact that our MPIs suppress all
-     leading zeroes.  Thus what we test here are merely the digest and
-     salt lengths to the key.  */
-  if (emlen < hlen + saltlen + 2)
-    {
-      rc = GPG_ERR_TOO_SHORT; /* For the hash and saltlen.  */
-      goto leave;
-    }
-
-  /* Step 4: Check last octet.  */
-  if (em[emlen - 1] != 0xbc)
-    {
-      rc = GPG_ERR_BAD_SIGNATURE;
-      goto leave;
-    }
-
-  /* Step 5: Split EM.  */
-  h = em + emlen - 1 - hlen;
-
-  /* Step 6: Check the leftmost bits.  */
-  if ((em[0] & ~(0xFF >> (8 * emlen - nbits))))
-    {
-      rc = GPG_ERR_BAD_SIGNATURE;
-      goto leave;
-    }
-
-  /* Step 7: dbmask = MGF(H, emlen - hlen - 1).  */
-  mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
-
-  /* Step 8: maskedDB = DB ^ dbMask.  */
-  for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
-    em[n] ^= *p;
-
-  /* Step 9: Set leftmost bits in DB to zero.  */
-  em[0] &= 0xFF >> (8 * emlen - nbits);
-
-  /* Step 10: Check the padding of DB.  */
-  for (n = 0; n < emlen - hlen - saltlen - 2 && !em[n]; n++)
-    ;
-  if (n != emlen - hlen - saltlen - 2 || em[n++] != 1)
-    {
-      rc = GPG_ERR_BAD_SIGNATURE;
-      goto leave;
-    }
-
-  /* Step 11: Extract salt from DB.  */
-  salt = em + n;
-
-  /* Step 12:  M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */
-  memset (buf, 0, 8);
-  memcpy (buf+8, mhash, hlen);
-  memcpy (buf+8+hlen, salt, saltlen);
-
-  /* Step 13:  H' = Hash(M').  */
-  gcry_md_hash_buffer (algo, buf, buf, 8 + hlen + saltlen);
-
-  /* Step 14:  Check H == H'.   */
-  rc = memcmp (h, buf, hlen) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR;
-
- leave:
-  if (em)
-    {
-      wipememory (em, emlen);
-      gcry_free (em);
-    }
-  if (buf)
-    {
-      wipememory (buf, buflen);
-      gcry_free (buf);
-    }
-  return rc;
-}
-
-
-/* Callback for the pubkey algorithm code to verify PSS signatures.
-   OPAQUE is the data provided by the actual caller.  The meaning of
-   TMP depends on the actual algorithm (but there is only RSA); now
-   for RSA it is the output of running the public key function on the
-   input.  */
-static int
-pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
-{
-  struct pk_encoding_ctx *ctx = opaque;
-  gcry_mpi_t hash = ctx->verify_arg;
-
-  return pss_verify (hash, tmp, ctx->nbits - 1, ctx->hash_algo, ctx->saltlen);
-}
-
-
 /* Internal function.   */
 static gcry_err_code_t
 sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names,
@@ -1926,6 +957,23 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec,
   return err;
 }
 
+
+/* Callback for the pubkey algorithm code to verify PSS signatures.
+   OPAQUE is the data provided by the actual caller.  The meaning of
+   TMP depends on the actual algorithm (but there is only RSA); now
+   for RSA it is the output of running the public key function on the
+   input.  */
+static int
+pss_verify_cmp (void *opaque, gcry_mpi_t tmp)
+{
+  struct pk_encoding_ctx *ctx = opaque;
+  gcry_mpi_t hash = ctx->verify_arg;
+
+  return _gcry_rsa_pss_verify (hash, tmp, ctx->nbits - 1,
+                               ctx->hash_algo, ctx->saltlen);
+}
+
+
 /* Take the hash value and convert into an MPI, suitable for
    passing to the low level functions.  We currently support the
    old style way of passing just a MPI and the modern interface which
@@ -2174,10 +1222,10 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
                 goto leave;
             }
 
-          rc = pkcs1_encode_for_encryption (ret_mpi, ctx->nbits,
-                                            value, valuelen,
-                                            random_override,
-                                            random_override_len);
+          rc = _gcry_rsa_pkcs1_encode_for_enc (ret_mpi, ctx->nbits,
+                                               value, valuelen,
+                                               random_override,
+                                               random_override_len);
           gcry_free (random_override);
         }
     }
@@ -2201,9 +1249,9 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
                     || !valuelen )
             rc = GPG_ERR_INV_OBJ;
           else
-           rc = pkcs1_encode_for_signature (ret_mpi, ctx->nbits,
-                                            value, valuelen,
-                                            ctx->hash_algo);
+           rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits,
+                                                 value, valuelen,
+                                                 ctx->hash_algo);
         }
     }
   else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
@@ -2283,10 +1331,10 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
                 goto leave;
             }
 
-         rc = oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
-                           value, valuelen,
-                           ctx->label, ctx->labellen,
-                            random_override, random_override_len);
+         rc = _gcry_rsa_oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo,
+                                      value, valuelen,
+                                      ctx->label, ctx->labellen,
+                                      random_override, random_override_len);
 
           gcry_free (random_override);
        }
@@ -2354,9 +1402,10 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
                 }
 
               /* Encode the data.  (NBITS-1 is due to 8.1.1, step 1.) */
-             rc = pss_encode (ret_mpi, ctx->nbits - 1, ctx->hash_algo,
-                              value, valuelen, ctx->saltlen,
-                               random_override, random_override_len);
+             rc = _gcry_rsa_pss_encode (ret_mpi, ctx->nbits - 1,
+                                         ctx->hash_algo,
+                                         value, valuelen, ctx->saltlen,
+                                         random_override, random_override_len);
 
               gcry_free (random_override);
            }
@@ -2590,8 +1639,9 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
   switch (ctx.encoding)
     {
     case PUBKEY_ENC_PKCS1:
-      rc = pkcs1_decode_for_encryption (&unpad, &unpadlen,
-                                        gcry_pk_get_nbits (s_skey), plain);
+      rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen,
+                                           gcry_pk_get_nbits (s_skey),
+                                           plain);
       mpi_free (plain);
       plain = NULL;
       if (!rc)
@@ -2600,9 +1650,9 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey)
       break;
 
     case PUBKEY_ENC_OAEP:
-      rc = oaep_decode (&unpad, &unpadlen,
-                        gcry_pk_get_nbits (s_skey), ctx.hash_algo,
-                       plain, ctx.label, ctx.labellen);
+      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)
diff --git a/cipher/rsa-common.c b/cipher/rsa-common.c
new file mode 100644 (file)
index 0000000..b1b212f
--- /dev/null
@@ -0,0 +1,985 @@
+/* rsa-common.c - Supporting functions for RSA
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013  g10 Code GmbH
+ *
+ * This file is part of Libgcrypt.
+ *
+ * Libgcrypt is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * Libgcrypt is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "g10lib.h"
+#include "mpi.h"
+#include "cipher.h"
+#include "pubkey-internal.h"
+
+
+/* Turn VALUE into an octet string and store it in an allocated buffer
+   at R_FRAME or - if R_RAME is NULL - copy it into the caller
+   provided buffer SPACE; either SPACE or R_FRAME may be used.  If
+   SPACE if not NULL, the caller must provide a buffer of at least
+   NBYTES.  If the resulting octet string is shorter than NBYTES pad
+   it to the left with zeroes.  If VALUE does not fit into NBYTES
+   return an error code.  */
+static gpg_err_code_t
+octet_string_from_mpi (unsigned char **r_frame, void *space,
+                       gcry_mpi_t value, size_t nbytes)
+{
+  return _gcry_mpi_to_octet_string (r_frame, space, value, nbytes);
+}
+
+
+
+/* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block
+   type 2 padding.  On sucess the result is stored as a new MPI at
+   R_RESULT.  On error the value at R_RESULT is undefined.
+
+   If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
+   the seed instead of using a random string for it.  This feature is
+   only useful for regression tests.  Note that this value may not
+   contain zero bytes.
+
+   We encode the value in this way:
+
+     0  2  RND(n bytes)  0  VALUE
+
+   0   is a marker we unfortunately can't encode because we return an
+       MPI which strips all leading zeroes.
+   2   is the block type.
+   RND are non-zero random bytes.
+
+   (Note that OpenPGP includes the cipher algorithm and a checksum in
+   VALUE; the caller needs to prepare the value accordingly.)
+  */
+gpg_err_code_t
+_gcry_rsa_pkcs1_encode_for_enc (gcry_mpi_t *r_result, unsigned int nbits,
+                                const unsigned char *value, size_t valuelen,
+                                const unsigned char *random_override,
+                                size_t random_override_len)
+{
+  gcry_err_code_t rc = 0;
+  gcry_error_t err;
+  unsigned char *frame = NULL;
+  size_t nframe = (nbits+7) / 8;
+  int i;
+  size_t n;
+  unsigned char *p;
+
+  if (valuelen + 7 > nframe || !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_syserror ();
+
+  n = 0;
+  frame[n++] = 0;
+  frame[n++] = 2; /* block type */
+  i = nframe - 3 - valuelen;
+  gcry_assert (i > 0);
+
+  if (random_override)
+    {
+      int j;
+
+      if (random_override_len != i)
+        {
+          gcry_free (frame);
+          return GPG_ERR_INV_ARG;
+        }
+      /* Check that random does not include a zero byte.  */
+      for (j=0; j < random_override_len; j++)
+        if (!random_override[j])
+          {
+            gcry_free (frame);
+            return GPG_ERR_INV_ARG;
+          }
+      memcpy (frame + n, random_override, random_override_len);
+      n += random_override_len;
+    }
+  else
+    {
+      p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
+      /* Replace zero bytes by new values. */
+      for (;;)
+        {
+          int j, k;
+          unsigned char *pp;
+
+          /* Count the zero bytes. */
+          for (j=k=0; j < i; j++)
+            {
+              if (!p[j])
+                k++;
+            }
+          if (!k)
+            break; /* Okay: no (more) zero bytes. */
+
+          k += k/128 + 3; /* Better get some more. */
+          pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
+          for (j=0; j < i && k; )
+            {
+              if (!p[j])
+                p[j] = pp[--k];
+              if (p[j])
+                j++;
+            }
+          gcry_free (pp);
+        }
+      memcpy (frame+n, p, i);
+      n += i;
+      gcry_free (p);
+    }
+
+  frame[n++] = 0;
+  memcpy (frame+n, value, valuelen);
+  n += valuelen;
+  gcry_assert (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 ("PKCS#1 block type 2 encoded data", *r_result);
+  gcry_free (frame);
+
+  return rc;
+}
+
+
+/* Decode a plaintext in VALUE assuming pkcs#1 block type 2 padding.
+   NBITS is the size of the secret key.  On success the result is
+   stored as a newly allocated buffer at R_RESULT and its valid length at
+   R_RESULTLEN.  On error NULL is stored at R_RESULT.  */
+gpg_err_code_t
+_gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen,
+                                unsigned int nbits, gcry_mpi_t value)
+{
+  gcry_error_t err;
+  unsigned char *frame = NULL;
+  size_t nframe = (nbits+7) / 8;
+  size_t n;
+
+  *r_result = NULL;
+
+  if ( !(frame = gcry_malloc_secure (nframe)))
+    return gpg_err_code_from_syserror ();
+
+  err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &n, value);
+  if (err)
+    {
+      gcry_free (frame);
+      return gcry_err_code (err);
+    }
+
+  nframe = n; /* Set NFRAME to the actual length.  */
+
+  /* FRAME = 0x00 || 0x02 || PS || 0x00 || M
+
+     pkcs#1 requires that the first byte is zero.  Our MPIs usually
+     strip leading zero bytes; thus we are not able to detect them.
+     However due to the way gcry_mpi_print is implemented we may see
+     leading zero bytes nevertheless.  We handle this by making the
+     first zero byte optional.  */
+  if (nframe < 4)
+    {
+      gcry_free (frame);
+      return GPG_ERR_ENCODING_PROBLEM;  /* Too short.  */
+    }
+  n = 0;
+  if (!frame[0])
+    n++;
+  if (frame[n++] != 0x02)
+    {
+      gcry_free (frame);
+      return GPG_ERR_ENCODING_PROBLEM;  /* Wrong block type.  */
+    }
+
+  /* Skip the non-zero random bytes and the terminating zero byte.  */
+  for (; n < nframe && frame[n] != 0x00; n++)
+    ;
+  if (n+1 >= nframe)
+    {
+      gcry_free (frame);
+      return GPG_ERR_ENCODING_PROBLEM; /* No zero byte.  */
+    }
+  n++; /* Skip the zero byte.  */
+
+  /* To avoid an extra allocation we reuse the frame buffer.  The only
+     caller of this function will anyway free the result soon.  */
+  memmove (frame, frame + n, nframe - n);
+  *r_result = frame;
+  *r_resultlen = nframe - n;
+
+  if (DBG_CIPHER)
+    log_printhex ("value extracted from PKCS#1 block type 2 encoded data",
+                  *r_result, *r_resultlen);
+
+  return 0;
+}
+
+
+/* Encode {VALUE,VALUELEN} for an NBITS keys and hash algorith ALGO
+   using the pkcs#1 block type 1 padding.  On success the result is
+   stored as a new MPI at R_RESULT.  On error the value at R_RESULT is
+   undefined.
+
+   We encode the value in this way:
+
+     0  1  PAD(n bytes)  0  ASN(asnlen bytes) VALUE(valuelen bytes)
+
+   0   is a marker we unfortunately can't encode because we return an
+       MPI which strips all leading zeroes.
+   1   is the block type.
+   PAD consists of 0xff bytes.
+   0   marks the end of the padding.
+   ASN is the DER encoding of the hash algorithm; along with the VALUE
+       it yields a valid DER encoding.
+
+   (Note that PGP prior to version 2.3 encoded the message digest as:
+      0   1   MD(16 bytes)   0   PAD(n bytes)   1
+    The MD is always 16 bytes here because it's always MD5.  GnuPG
+    does not not support pre-v2.3 signatures, but I'm including this
+    comment so the information is easily found if needed.)
+*/
+gpg_err_code_t
+_gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
+                                const unsigned char *value, size_t valuelen,
+                                int algo)
+{
+  gcry_err_code_t rc = 0;
+  gcry_error_t err;
+  byte asn[100];
+  byte *frame = NULL;
+  size_t nframe = (nbits+7) / 8;
+  int i;
+  size_t n;
+  size_t asnlen, dlen;
+
+  asnlen = DIM(asn);
+  dlen = gcry_md_get_algo_dlen (algo);
+
+  if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
+    {
+      /* We don't have yet all of the above algorithms.  */
+      return GPG_ERR_NOT_IMPLEMENTED;
+    }
+
+  if ( valuelen != dlen )
+    {
+      /* Hash value does not match the length of digest for
+         the given algorithm.  */
+      return GPG_ERR_CONFLICT;
+    }
+
+  if ( !dlen || dlen + asnlen + 4 > nframe)
+    {
+      /* Can't encode an DLEN byte digest MD into an NFRAME byte
+         frame.  */
+      return GPG_ERR_TOO_SHORT;
+    }
+
+  if ( !(frame = gcry_malloc (nframe)) )
+    return gpg_err_code_from_syserror ();
+
+  /* Assemble the pkcs#1 block type 1. */
+  n = 0;
+  frame[n++] = 0;
+  frame[n++] = 1; /* block type */
+  i = nframe - valuelen - asnlen - 3 ;
+  gcry_assert (i > 1);
+  memset (frame+n, 0xff, i );
+  n += i;
+  frame[n++] = 0;
+  memcpy (frame+n, asn, asnlen);
+  n += asnlen;
+  memcpy (frame+n, value, valuelen );
+  n += valuelen;
+  gcry_assert (n == nframe);
+
+  /* Convert it into an MPI. */
+  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 ("PKCS#1 block type 1 encoded data", *r_result);
+  gcry_free (frame);
+
+  return rc;
+}
+
+
+/* Mask generation function for OAEP.  See RFC-3447 B.2.1.  */
+static gcry_err_code_t
+mgf1 (unsigned char *output, size_t outlen, unsigned char *seed, size_t seedlen,
+      int algo)
+{
+  size_t dlen, nbytes, n;
+  int idx;
+  gcry_md_hd_t hd;
+  gcry_error_t err;
+
+  err = gcry_md_open (&hd, algo, 0);
+  if (err)
+    return gpg_err_code (err);
+
+  dlen = gcry_md_get_algo_dlen (algo);
+
+  /* We skip step 1 which would be assert(OUTLEN <= 2^32).  The loop
+     in step 3 is merged with step 4 by concatenating no more octets
+     than what would fit into OUTPUT.  The ceiling for the counter IDX
+     is implemented indirectly.  */
+  nbytes = 0;  /* Step 2.  */
+  idx = 0;
+  while ( nbytes < outlen )
+    {
+      unsigned char c[4], *digest;
+
+      if (idx)
+        gcry_md_reset (hd);
+
+      c[0] = (idx >> 24) & 0xFF;
+      c[1] = (idx >> 16) & 0xFF;
+      c[2] = (idx >> 8) & 0xFF;
+      c[3] = idx & 0xFF;
+      idx++;
+
+      gcry_md_write (hd, seed, seedlen);
+      gcry_md_write (hd, c, 4);
+      digest = gcry_md_read (hd, 0);
+
+      n = (outlen - nbytes < dlen)? (outlen - nbytes) : dlen;
+      memcpy (output+nbytes, digest, n);
+      nbytes += n;
+    }
+
+  gcry_md_close (hd);
+  return GPG_ERR_NO_ERROR;
+}
+
+
+/* RFC-3447 (pkcs#1 v2.1) OAEP encoding.  NBITS is the length of the
+   key measured in bits.  ALGO is the hash function; it must be a
+   valid and usable algorithm.  {VALUE,VALUELEN} is the message to
+   encrypt.  {LABEL,LABELLEN} is the optional label to be associated
+   with the message, if LABEL is NULL the default is to use the empty
+   string as label.  On success the encoded ciphertext is returned at
+   R_RESULT.
+
+   If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
+   the seed instead of using a random string for it.  This feature is
+   only useful for regression tests.
+
+   Here is figure 1 from the RFC depicting the process:
+
+                             +----------+---------+-------+
+                        DB = |  lHash   |    PS   |   M   |
+                             +----------+---------+-------+
+                                            |
+                  +----------+              V
+                  |   seed   |--> MGF ---> xor
+                  +----------+              |
+                        |                   |
+               +--+     V                   |
+               |00|    xor <----- MGF <-----|
+               +--+     |                   |
+                 |      |                   |
+                 V      V                   V
+               +--+----------+----------------------------+
+         EM =  |00|maskedSeed|          maskedDB          |
+               +--+----------+----------------------------+
+  */
+gpg_err_code_t
+_gcry_rsa_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,
+                       const void *random_override, size_t random_override_len)
+{
+  gcry_err_code_t rc = 0;
+  gcry_error_t err;
+  unsigned char *frame = NULL;
+  size_t nframe = (nbits+7) / 8;
+  unsigned char *p;
+  size_t hlen;
+  size_t n;
+
+  *r_result = NULL;
+
+  /* Set defaults for LABEL.  */
+  if (!label || !labellen)
+    {
+      label = (const unsigned char*)"";
+      labellen = 0;
+    }
+
+  hlen = gcry_md_get_algo_dlen (algo);
+
+  /* We skip step 1a which would be to check that LABELLEN is not
+     greater than 2^61-1.  See rfc-3447 7.1.1. */
+
+  /* Step 1b.  Note that the obsolete rfc-2437 uses the check:
+     valuelen > nframe - 2 * hlen - 1 .  */
+  if (valuelen > nframe - 2 * hlen - 2 || !nframe)
+    {
+      /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
+      return GPG_ERR_TOO_SHORT; /* The key is too short.  */
+    }
+
+  /* Allocate the frame.  */
+  frame = gcry_calloc_secure (1, nframe);
+  if (!frame)
+    return gpg_err_code_from_syserror ();
+
+  /* Step 2a: Compute the hash of the label.  We store it in the frame
+     where later the maskedDB will commence.  */
+  gcry_md_hash_buffer (algo, frame + 1 + hlen, label, labellen);
+
+  /* Step 2b: Set octet string to zero.  */
+  /* This has already been done while allocating FRAME.  */
+
+  /* Step 2c: Create DB by concatenating lHash, PS, 0x01 and M.  */
+  n = nframe - valuelen - 1;
+  frame[n] = 0x01;
+  memcpy (frame + n + 1, value, valuelen);
+
+  /* Step 3d: Generate seed.  We store it where the maskedSeed will go
+     later. */
+  if (random_override)
+    {
+      if (random_override_len != hlen)
+        {
+          gcry_free (frame);
+          return GPG_ERR_INV_ARG;
+        }
+      memcpy (frame + 1, random_override, hlen);
+    }
+  else
+    gcry_randomize (frame + 1, hlen, GCRY_STRONG_RANDOM);
+
+  /* Step 2e and 2f: Create maskedDB.  */
+  {
+    unsigned char *dmask;
+
+    dmask = gcry_malloc_secure (nframe - hlen - 1);
+    if (!dmask)
+      {
+        rc = gpg_err_code_from_syserror ();
+        gcry_free (frame);
+        return rc;
+      }
+    rc = mgf1 (dmask, nframe - hlen - 1, frame+1, hlen, algo);
+    if (rc)
+      {
+        gcry_free (dmask);
+        gcry_free (frame);
+        return rc;
+      }
+    for (n = 1 + hlen, p = dmask; n < nframe; n++)
+      frame[n] ^= *p++;
+    gcry_free (dmask);
+  }
+
+  /* Step 2g and 2h: Create maskedSeed.  */
+  {
+    unsigned char *smask;
+
+    smask = gcry_malloc_secure (hlen);
+    if (!smask)
+      {
+        rc = gpg_err_code_from_syserror ();
+        gcry_free (frame);
+        return rc;
+      }
+    rc = mgf1 (smask, hlen, frame + 1 + hlen, nframe - hlen - 1, algo);
+    if (rc)
+      {
+        gcry_free (smask);
+        gcry_free (frame);
+        return rc;
+      }
+    for (n = 1, p = smask; n < 1 + hlen; n++)
+      frame[n] ^= *p++;
+    gcry_free (smask);
+  }
+
+  /* Step 2i: Concatenate 0x00, maskedSeed and maskedDB.  */
+  /* This has already been done by using in-place operations.  */
+
+  /* Convert the stuff into an MPI as expected by the caller.  */
+  err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, nframe, NULL);
+  if (err)
+    rc = gcry_err_code (err);
+  else if (DBG_CIPHER)
+    log_mpidump ("OAEP encoded data", *r_result);
+  gcry_free (frame);
+
+  return rc;
+}
+
+
+/* RFC-3447 (pkcs#1 v2.1) OAEP decoding.  NBITS is the length of the
+   key measured in bits.  ALGO is the hash function; it must be a
+   valid and usable algorithm.  VALUE is the raw decrypted message
+   {LABEL,LABELLEN} is the optional label to be associated with the
+   message, if LABEL is NULL the default is to use the empty string as
+   label.  On success the plaintext is returned as a newly allocated
+   buffer at R_RESULT; its valid length is stored at R_RESULTLEN.  On
+   error NULL is stored at R_RESULT.  */
+gpg_err_code_t
+_gcry_rsa_oaep_decode (unsigned char **r_result, size_t *r_resultlen,
+                       unsigned int nbits, int algo,
+                       gcry_mpi_t value,
+                       const unsigned char *label, size_t labellen)
+{
+  gcry_err_code_t rc;
+  unsigned char *frame = NULL; /* Encoded messages (EM).  */
+  unsigned char *masked_seed;  /* Points into FRAME.  */
+  unsigned char *masked_db;    /* Points into FRAME.  */
+  unsigned char *seed = NULL;  /* Allocated space for the seed and DB.  */
+  unsigned char *db;           /* Points into SEED.  */
+  unsigned char *lhash = NULL; /* Hash of the label.  */
+  size_t nframe;               /* Length of the ciphertext (EM).  */
+  size_t hlen;                 /* Length of the hash digest.  */
+  size_t db_len;               /* Length of DB and masked_db.  */
+  size_t nkey = (nbits+7)/8;   /* Length of the key in bytes.  */
+  int failed = 0;              /* Error indicator.  */
+  size_t n;
+
+  *r_result = NULL;
+
+  /* This code is implemented as described by rfc-3447 7.1.2.  */
+
+  /* Set defaults for LABEL.  */
+  if (!label || !labellen)
+    {
+      label = (const unsigned char*)"";
+      labellen = 0;
+    }
+
+  /* Get the length of the digest.  */
+  hlen = gcry_md_get_algo_dlen (algo);
+
+  /* Hash the label right away.  */
+  lhash = gcry_malloc (hlen);
+  if (!lhash)
+    return gpg_err_code_from_syserror ();
+  gcry_md_hash_buffer (algo, lhash, label, labellen);
+
+  /* Turn the MPI into an octet string.  If the octet string is
+     shorter than the key we pad it to the left with zeroes.  This may
+     happen due to the leading zero in OAEP frames and due to the
+     following random octets (seed^mask) which may have leading zero
+     bytes.  This all is needed to cope with our leading zeroes
+     suppressing MPI implementation.  The code implictly implements
+     Step 1b (bail out if NFRAME != N).  */
+  rc = octet_string_from_mpi (&frame, NULL, value, nkey);
+  if (rc)
+    {
+      gcry_free (lhash);
+      return GPG_ERR_ENCODING_PROBLEM;
+    }
+  nframe = nkey;
+
+  /* Step 1c: Check that the key is long enough.  */
+  if ( nframe < 2 * hlen + 2 )
+    {
+      gcry_free (frame);
+      gcry_free (lhash);
+      return GPG_ERR_ENCODING_PROBLEM;
+    }
+
+  /* Step 2 has already been done by the caller and the
+     gcry_mpi_aprint above.  */
+
+  /* Allocate space for SEED and DB.  */
+  seed = gcry_malloc_secure (nframe - 1);
+  if (!seed)
+    {
+      rc = gpg_err_code_from_syserror ();
+      gcry_free (frame);
+      gcry_free (lhash);
+      return rc;
+    }
+  db = seed + hlen;
+
+  /* To avoid choosen ciphertext attacks from now on we make sure to
+     run all code even in the error case; this avoids possible timing
+     attacks as described by Manger.  */
+
+  /* Step 3a: Hash the label.  */
+  /* This has already been done.  */
+
+  /* Step 3b: Separate the encoded message.  */
+  masked_seed = frame + 1;
+  masked_db   = frame + 1 + hlen;
+  db_len      = nframe - 1 - hlen;
+
+  /* Step 3c and 3d: seed = maskedSeed ^ mgf(maskedDB, hlen).  */
+  if (mgf1 (seed, hlen, masked_db, db_len, algo))
+    failed = 1;
+  for (n = 0; n < hlen; n++)
+    seed[n] ^= masked_seed[n];
+
+  /* Step 3e and 3f: db = maskedDB ^ mgf(seed, db_len).  */
+  if (mgf1 (db, db_len, seed, hlen, algo))
+    failed = 1;
+  for (n = 0; n < db_len; n++)
+    db[n] ^= masked_db[n];
+
+  /* Step 3g: Check lhash, an possible empty padding string terminated
+     by 0x01 and the first byte of EM being 0.  */
+  if (memcmp (lhash, db, hlen))
+    failed = 1;
+  for (n = hlen; n < db_len; n++)
+    if (db[n] == 0x01)
+      break;
+  if (n == db_len)
+    failed = 1;
+  if (frame[0])
+    failed = 1;
+
+  gcry_free (lhash);
+  gcry_free (frame);
+  if (failed)
+    {
+      gcry_free (seed);
+      return GPG_ERR_ENCODING_PROBLEM;
+    }
+
+  /* Step 4: Output M.  */
+  /* To avoid an extra allocation we reuse the seed buffer.  The only
+     caller of this function will anyway free the result soon.  */
+  n++;
+  memmove (seed, db + n, db_len - n);
+  *r_result = seed;
+  *r_resultlen = db_len - n;
+  seed = NULL;
+
+  if (DBG_CIPHER)
+    log_printhex ("value extracted from OAEP encoded data",
+                  *r_result, *r_resultlen);
+
+  return 0;
+}
+
+
+/* RFC-3447 (pkcs#1 v2.1) PSS encoding.  Encode {VALUE,VALUELEN} for
+   an NBITS key.  Note that VALUE is already the mHash from the
+   picture below.  ALGO is a valid hash algorithm and SALTLEN is the
+   length of salt to be used.  On success the result is stored as a
+   new MPI at R_RESULT.  On error the value at R_RESULT is undefined.
+
+   If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as
+   the salt instead of using a random string for the salt.  This
+   feature is only useful for regression tests.
+
+   Here is figure 2 from the RFC (errata 595 applied) depicting the
+   process:
+
+                                  +-----------+
+                                  |     M     |
+                                  +-----------+
+                                        |
+                                        V
+                                      Hash
+                                        |
+                                        V
+                          +--------+----------+----------+
+                     M' = |Padding1|  mHash   |   salt   |
+                          +--------+----------+----------+
+                                         |
+               +--------+----------+     V
+         DB =  |Padding2| salt     |   Hash
+               +--------+----------+     |
+                         |               |
+                         V               |    +----+
+                        xor <--- MGF <---|    |0xbc|
+                         |               |    +----+
+                         |               |      |
+                         V               V      V
+               +-------------------+----------+----+
+         EM =  |    maskedDB       |     H    |0xbc|
+               +-------------------+----------+----+
+
+  */
+gpg_err_code_t
+_gcry_rsa_pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
+                      const unsigned char *value, size_t valuelen, int saltlen,
+                      const void *random_override, size_t random_override_len)
+{
+  gcry_err_code_t rc = 0;
+  gcry_error_t err;
+  size_t hlen;                 /* Length of the hash digest.  */
+  unsigned char *em = NULL;    /* Encoded message.  */
+  size_t emlen = (nbits+7)/8;  /* Length in bytes of EM.  */
+  unsigned char *h;            /* Points into EM.  */
+  unsigned char *buf = NULL;   /* Help buffer.  */
+  size_t buflen;               /* Length of BUF.  */
+  unsigned char *mhash;        /* Points into BUF.  */
+  unsigned char *salt;         /* Points into BUF.  */
+  unsigned char *dbmask;       /* Points into BUF.  */
+  unsigned char *p;
+  size_t n;
+
+  /* This code is implemented as described by rfc-3447 9.1.1.  */
+
+  /* Get the length of the digest.  */
+  hlen = gcry_md_get_algo_dlen (algo);
+  gcry_assert (hlen);  /* We expect a valid ALGO here.  */
+
+  /* Allocate a help buffer and setup some pointers.  */
+  buflen = 8 + hlen + saltlen + (emlen - hlen - 1);
+  buf = gcry_malloc (buflen);
+  if (!buf)
+    {
+      rc = gpg_err_code_from_syserror ();
+      goto leave;
+    }
+  mhash = buf + 8;
+  salt  = mhash + hlen;
+  dbmask= salt + saltlen;
+
+  /* Step 2: That would be: mHash = Hash(M) but our input is already
+     mHash thus we do only a consistency check and copy to MHASH.  */
+  if (valuelen != hlen)
+    {
+      rc = GPG_ERR_INV_LENGTH;
+      goto leave;
+    }
+  memcpy (mhash, value, hlen);
+
+  /* Step 3: Check length constraints.  */
+  if (emlen < hlen + saltlen + 2)
+    {
+      rc = GPG_ERR_TOO_SHORT;
+      goto leave;
+    }
+
+  /* Allocate space for EM.  */
+  em = gcry_malloc (emlen);
+  if (!em)
+    {
+      rc = gpg_err_code_from_syserror ();
+      goto leave;
+    }
+  h = em + emlen - 1 - hlen;
+
+  /* Step 4: Create a salt.  */
+  if (saltlen)
+    {
+      if (random_override)
+        {
+          if (random_override_len != saltlen)
+            {
+              rc = GPG_ERR_INV_ARG;
+              goto leave;
+            }
+          memcpy (salt, random_override, saltlen);
+        }
+      else
+        gcry_randomize (salt, saltlen, GCRY_STRONG_RANDOM);
+    }
+
+  /* Step 5 and 6: M' = Hash(Padding1 || mHash || salt).  */
+  memset (buf, 0, 8);  /* Padding.  */
+  gcry_md_hash_buffer (algo, h, buf, 8 + hlen + saltlen);
+
+  /* Step 7 and 8: DB = PS || 0x01 || salt.  */
+  /* Note that we use EM to store DB and later Xor in-place.  */
+  p = em + emlen - 1 - hlen - saltlen - 1;
+  memset (em, 0, p - em);
+  *p++ = 0x01;
+  memcpy (p, salt, saltlen);
+
+  /* Step 9: dbmask = MGF(H, emlen - hlen - 1).  */
+  mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
+
+  /* Step 10: maskedDB = DB ^ dbMask */
+  for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
+    em[n] ^= *p;
+
+  /* Step 11: Set the leftmost bits to zero.  */
+  em[0] &= 0xFF >> (8 * emlen - nbits);
+
+  /* Step 12: EM = maskedDB || H || 0xbc.  */
+  em[emlen-1] = 0xbc;
+
+  /* Convert EM into an MPI.  */
+  err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, em, emlen, NULL);
+  if (err)
+    rc = gcry_err_code (err);
+  else if (DBG_CIPHER)
+    log_mpidump ("PSS encoded data", *r_result);
+
+ leave:
+  if (em)
+    {
+      wipememory (em, emlen);
+      gcry_free (em);
+    }
+  if (buf)
+    {
+      wipememory (buf, buflen);
+      gcry_free (buf);
+    }
+  return rc;
+}
+
+
+/* Verify a signature assuming PSS padding.  VALUE is the hash of the
+   message (mHash) encoded as an MPI; its length must match the digest
+   length of ALGO.  ENCODED is the output of the RSA public key
+   function (EM).  NBITS is the size of the public key.  ALGO is the
+   hash algorithm and SALTLEN is the length of the used salt.  The
+   function returns 0 on success or on error code.  */
+gpg_err_code_t
+_gcry_rsa_pss_verify (gcry_mpi_t value, gcry_mpi_t encoded,
+                      unsigned int nbits, int algo, size_t saltlen)
+{
+  gcry_err_code_t rc = 0;
+  size_t hlen;                 /* Length of the hash digest.  */
+  unsigned char *em = NULL;    /* Encoded message.  */
+  size_t emlen = (nbits+7)/8;  /* Length in bytes of EM.  */
+  unsigned char *salt;         /* Points into EM.  */
+  unsigned char *h;            /* Points into EM.  */
+  unsigned char *buf = NULL;   /* Help buffer.  */
+  size_t buflen;               /* Length of BUF.  */
+  unsigned char *dbmask;       /* Points into BUF.  */
+  unsigned char *mhash;        /* Points into BUF.  */
+  unsigned char *p;
+  size_t n;
+
+  /* This code is implemented as described by rfc-3447 9.1.2.  */
+
+  /* Get the length of the digest.  */
+  hlen = gcry_md_get_algo_dlen (algo);
+  gcry_assert (hlen);  /* We expect a valid ALGO here.  */
+
+  /* Allocate a help buffer and setup some pointers.
+     This buffer is used for two purposes:
+        +------------------------------+-------+
+     1. | dbmask                       | mHash |
+        +------------------------------+-------+
+           emlen - hlen - 1              hlen
+
+        +----------+-------+---------+-+-------+
+     2. | padding1 | mHash | salt    | | mHash |
+        +----------+-------+---------+-+-------+
+             8       hlen    saltlen     hlen
+  */
+  buflen = 8 + hlen + saltlen;
+  if (buflen < emlen - hlen - 1)
+    buflen = emlen - hlen - 1;
+  buflen += hlen;
+  buf = gcry_malloc (buflen);
+  if (!buf)
+    {
+      rc = gpg_err_code_from_syserror ();
+      goto leave;
+    }
+  dbmask = buf;
+  mhash = buf + buflen - hlen;
+
+  /* Step 2: That would be: mHash = Hash(M) but our input is already
+     mHash thus we only need to convert VALUE into MHASH.  */
+  rc = octet_string_from_mpi (NULL, mhash, value, hlen);
+  if (rc)
+    goto leave;
+
+  /* Convert the signature into an octet string.  */
+  rc = octet_string_from_mpi (&em, NULL, encoded, emlen);
+  if (rc)
+    goto leave;
+
+  /* Step 3: Check length of EM.  Because we internally use MPI
+     functions we can't do this properly; EMLEN is always the length
+     of the key because octet_string_from_mpi needs to left pad the
+     result with zero to cope with the fact that our MPIs suppress all
+     leading zeroes.  Thus what we test here are merely the digest and
+     salt lengths to the key.  */
+  if (emlen < hlen + saltlen + 2)
+    {
+      rc = GPG_ERR_TOO_SHORT; /* For the hash and saltlen.  */
+      goto leave;
+    }
+
+  /* Step 4: Check last octet.  */
+  if (em[emlen - 1] != 0xbc)
+    {
+      rc = GPG_ERR_BAD_SIGNATURE;
+      goto leave;
+    }
+
+  /* Step 5: Split EM.  */
+  h = em + emlen - 1 - hlen;
+
+  /* Step 6: Check the leftmost bits.  */
+  if ((em[0] & ~(0xFF >> (8 * emlen - nbits))))
+    {
+      rc = GPG_ERR_BAD_SIGNATURE;
+      goto leave;
+    }
+
+  /* Step 7: dbmask = MGF(H, emlen - hlen - 1).  */
+  mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
+
+  /* Step 8: maskedDB = DB ^ dbMask.  */
+  for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++)
+    em[n] ^= *p;
+
+  /* Step 9: Set leftmost bits in DB to zero.  */
+  em[0] &= 0xFF >> (8 * emlen - nbits);
+
+  /* Step 10: Check the padding of DB.  */
+  for (n = 0; n < emlen - hlen - saltlen - 2 && !em[n]; n++)
+    ;
+  if (n != emlen - hlen - saltlen - 2 || em[n++] != 1)
+    {
+      rc = GPG_ERR_BAD_SIGNATURE;
+      goto leave;
+    }
+
+  /* Step 11: Extract salt from DB.  */
+  salt = em + n;
+
+  /* Step 12:  M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */
+  memset (buf, 0, 8);
+  memcpy (buf+8, mhash, hlen);
+  memcpy (buf+8+hlen, salt, saltlen);
+
+  /* Step 13:  H' = Hash(M').  */
+  gcry_md_hash_buffer (algo, buf, buf, 8 + hlen + saltlen);
+
+  /* Step 14:  Check H == H'.   */
+  rc = memcmp (h, buf, hlen) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR;
+
+ leave:
+  if (em)
+    {
+      wipememory (em, emlen);
+      gcry_free (em);
+    }
+  if (buf)
+    {
+      wipememory (buf, buflen);
+      gcry_free (buf);
+    }
+  return rc;
+}