summaryrefslogtreecommitdiff
path: root/cipher/pubkey.c
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2011-06-08 20:18:42 +0200
committerWerner Koch <wk@gnupg.org>2011-06-08 20:20:05 +0200
commit5ff191d09d2ab8333c7149b7e68efee672e68c35 (patch)
tree2093917f8bb4762edc149255918f12b1b8c9f63c /cipher/pubkey.c
parent44393d7959758e5298b0238dca26ff8f17635e6b (diff)
downloadlibgcrypt-5ff191d09d2ab8333c7149b7e68efee672e68c35.tar.gz
Restructure pss_encode to match the description in rfc-3447.
Diffstat (limited to 'cipher/pubkey.c')
-rw-r--r--cipher/pubkey.c165
1 files changed, 100 insertions, 65 deletions
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 8f6e1001..cd9c79f5 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1191,10 +1191,40 @@ oaep_decode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
}
-/* Encode {VALUE,VALUELEN} for an NBITS keys using the PSS padding.
- ALGO is a hash algorithm and SALTLEN is a length of salt used
- internally. On sucess the result is stored as a new MPI at
- R_RESULT. On error the value at R_RESULT is undefined. */
+/* RFC-3447 (pkcs#1 v2.1) PSS encoding. Encode {VALUE,VALUELEN} for
+ an NBITS key. 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.
+
+ 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,
@@ -1202,97 +1232,102 @@ pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo,
{
gcry_err_code_t rc = 0;
gcry_error_t err;
- unsigned char *frame = NULL, *buf = NULL, *dmask = NULL, *h = NULL, *salt, *p;
- size_t nframe = (nbits+7) / 8;
- size_t dlen;
- gcry_md_hd_t hd = NULL;
+ 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;
- err = gcry_md_open (&hd, algo, 0);
- if (err)
- {
- rc = gpg_err_code (err);
- goto leave;
- }
- dlen = gcry_md_get_algo_dlen (algo);
+ /* This code is implemented as described by rfc-3447 9.1.1. */
- if (nframe < dlen + saltlen + 2)
- {
- /* Can't encode a VALUELEN value in a NFRAME bytes frame. */
- rc = GPG_ERR_TOO_SHORT; /* the key is too short */
- goto leave;
- }
+ /* Get the length of the digest. */
+ hlen = gcry_md_get_algo_dlen (algo);
+ gcry_assert (hlen); /* We expect a valid ALGO here. */
- if ( !(frame = gcry_calloc_secure (nframe, sizeof *frame)))
+ /* 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: mHash = Hash(M). */
+ /* Fixme: We should not do that but use VALUE directly as the hash. */
+ gcry_md_hash_buffer (algo, mhash, value, valuelen);
- if ( !(buf = gcry_calloc_secure (8 + dlen + saltlen, sizeof *buf)))
+ /* Step 3: Check length constraints. */
+ if (emlen < hlen + saltlen + 2)
{
- rc = gpg_err_code_from_syserror ();
+ rc = GPG_ERR_TOO_SHORT;
goto leave;
}
- /* M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */
- n = 8;
- gcry_md_reset (hd);
- gcry_md_write (hd, value, valuelen);
- memcpy (&buf[n], gcry_md_read (hd, 0), dlen);
- n += dlen;
- salt = &buf[n];
- gcry_randomize (salt, saltlen, GCRY_STRONG_RANDOM);
- n += saltlen;
-
- /* H = Hash(M') */
- if ( !(h = gcry_malloc_secure (dlen)))
+ /* Allocate space for EM. */
+ em = gcry_malloc (emlen);
+ if (!em)
{
rc = gpg_err_code_from_syserror ();
goto leave;
}
- gcry_md_reset (hd);
- gcry_md_write (hd, buf, n);
- memcpy (h, gcry_md_read (hd, 0), dlen);
+ h = em + emlen - 1 - hlen;
- /* DB = PS || 0x01 || salt */
- n = nframe - saltlen - dlen - 2;
- frame[n++] = 1;
- memcpy (&frame[n], salt, saltlen);
- n += saltlen;
+ /* Step 4: Create a salt. */
+ if (saltlen)
+ gcry_randomize (salt, saltlen, GCRY_STRONG_RANDOM);
- if ( !(dmask = gcry_malloc_secure (nframe - dlen - 1)))
- {
- rc = gpg_err_code_from_syserror ();
- goto leave;
- }
+ /* Step 5 and 6: M' = Hash(Padding1 || mHash || salt). */
+ memset (buf, 0, 8); /* Padding. */
+ gcry_md_hash_buffer (algo, h, buf, 8 + hlen + saltlen);
- /* DMASK = MGF(H, NFRAME - DLEN - 1) */
- mgf1 (dmask, nframe - dlen - 1, h, dlen, algo);
+ /* 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);
- /* FRAME = DB xor DMASK || H || 0xbc */
- for (n = 0, p = dmask; n < nframe - dlen - 1; n++)
- frame[n] ^= *p++;
+ /* Step 9: dbmask = MGF(H, emlen - hlen - 1). */
+ mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo);
- memcpy (&frame[n], h, dlen);
- n += dlen;
- frame[n++] = 0xbc;
- gcry_assert (n == nframe);
+ /* 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);
- frame[0] &= 0xFF >> (8 * nframe - nbits);
+ /* Step 12: EM = maskedDB || H || 0xbc. */
+ em[emlen-1] = 0xbc;
- err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, nframe, NULL);
+ /* 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:
- gcry_md_close (hd);
- gcry_free (frame);
- gcry_free (buf);
- gcry_free (dmask);
- gcry_free (h);
+ if (em)
+ {
+ wipememory (em, emlen);
+ gcry_free (em);
+ }
+ if (buf)
+ {
+ wipememory (buf, buflen);
+ gcry_free (buf);
+ }
return rc;
}