X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/c080c887f9304819f3df80195ed3670680e3f05c..df8e52c798e925d8d6fc1ec0d43996bebf1092ef:/pss.c diff --git a/pss.c b/pss.c index 8bbccca..b4771db 100644 --- a/pss.c +++ b/pss.c @@ -1,13 +1,13 @@ /* -*-c-*- * - * $Id: pss.c,v 1.1 2000/07/20 20:13:38 mdw Exp $ + * $Id: pss.c,v 1.2 2004/04/08 01:36:15 mdw Exp $ * * Probabistic signature scheme * * (c) 2000 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of Catacomb. * @@ -15,26 +15,18 @@ * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * Catacomb 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 Library General Public License for more details. - * + * * You should have received a copy of the GNU Library General Public * License along with Catacomb; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* - * - * $Log: pss.c,v $ - * Revision 1.1 2000/07/20 20:13:38 mdw - * Added Bellare and Rogaway's PSS encoding for RSA signatures. - * - */ - /*----- Header files ------------------------------------------------------*/ #include @@ -46,191 +38,151 @@ #include "gcipher.h" #include "ghash.h" #include "grand.h" -#include "pss.h" +#include "rsa.h" -/*----- Main code ---------------------------------------------------------*/ +/*----- Magic statics -----------------------------------------------------*/ -/* --- @pss_presign@ --- * - * - * Arguments: @pss *pp@ = pointer to PSS parameter block - * - * Returns: An initialized generic hash context. - * - * Use: Initializes a hash function for signing with PSS. A salt is - * chosen and written into the parameter block. - */ - -ghash *pss_presign(pss *pp) -{ - size_t hsz = pp->ch->hashsz; - octet *salt = xmalloc(hsz); - ghash *h; +static const octet z8[8] = { 0 }; - pp->r->ops->fill(pp->r, salt, hsz); - pp->salt = salt; - h = pp->ch->init(); - h->ops->hash(h, salt, hsz); - return (h); -} +/*----- Main code ---------------------------------------------------------*/ /* --- @pss_encode@ --- * * - * Arguments: @const void *msg@ = pointer to message (hash) data - * @size_t msz@ = size of message data - * @void *buf@ = pointer to output buffer - * @size_t sz@ = size of the output buffer - * @void *p@ = pointer to PSS parameter block + * Arguments: @mp *d@ = where to put the answer + * @const void *m@ = pointer to the message hash + * @size_t msz@ = the size of the message hash + * @octet *b@ = scratch buffer + * @size_t sz@ = sizeo of the buffer (large enough) + * @unsigned long nbits@ = size in bits of @n@ + * @void *p@ = pointer to the PSS parameters * - * Returns: Zero of all went well, negative on failure. + * Returns: Encoded message representative, or null on error. * * Use: Implements the operation @EMSA-PSS-ENCODE@, as defined in - * PKCS#1 v. 2.1 draft 1. + * PKCS#1 v. 2.1 (RFC3447). */ -int pss_encode(const void *msg, size_t msz, void *buf, size_t sz, void *p) +mp *pss_encode(mp *d, const void *m, size_t msz, octet *b, size_t sz, + unsigned long nbits, void *p) { pss *pp = p; - octet *q, *mq, *qq; + octet *s, *r; + ghash *h; gcipher *c; - size_t hsz = pp->ch->hashsz; - size_t n; - - /* --- Ensure that everything is sensibly sized --- */ - - if (hsz + msz + 1 > sz) - return (-1); - - /* --- Fill in the initial buffer --- */ - - q = buf; - *q++ = 0; sz--; - mq = q + msz; - qq = q + sz; - n = sz - msz; - memcpy(q, msg, msz); - if (pp->salt) - memcpy(mq, pp->salt, hsz); - else - memset(mq, 0, hsz); - memset(mq + hsz, 0, n - hsz); - - /* --- Do the encryption --- */ - - c = pp->cc->init(msg, msz); - c->ops->encrypt(c, mq, mq, n); - c->ops->destroy(c); - - /* --- Done --- */ - - return (0); + unsigned mask; + size_t pssz, hsz = pp->ch->hashsz; + + /* --- Check the message length --- */ + + nbits--; + sz = (nbits + 7)/8; + mask = (1 << nbits%8) - 1; + if (!mask) mask = 0xff; + if (hsz + pp->ssz + 2 > sz) + return (0); + + /* --- Generate a random salt --- */ + + pssz = sz - pp->ssz - hsz - 2; + memset(b, 0, pssz); + b[pssz] = 0x01; + s = b + pssz + 1; + r = s + pp->ssz; + GR_FILL(pp->r, s, pp->ssz); + + /* --- Compute the salted hash --- */ + + h = GH_INIT(pp->ch); + GH_HASH(h, z8, 8); + GH_HASH(h, m, msz); + GH_HASH(h, s, pp->ssz); + GH_DONE(h, r); + r[hsz] = 0xbc; + + /* --- Do the masking --- */ + + c = GC_INIT(pp->cc, r, hsz); + GC_ENCRYPT(c, b, b, pssz + pp->ssz + 1); + GC_DESTROY(c); + b[0] &= mask; + return (mp_loadb(d, b, sz)); } /* --- @pss_decode@ --- * * - * Arguments: @const void *buf@ = pointer to encoded buffer - * @size_t sz@ = size of the encoded byffer - * @dstr *d@ = pointer to destination string - * @void *p@ = pointer to PSS parameter block + * Arguments: @mp *s@ = the message representative + * @const void *m@ = the original message + * @size_t msz@ = the message size + * @octet *b@ = a scratch buffer + * @size_t sz@ = size of the buffer (large enough) + * @unsigned long nbits@ = number of bits in @n@ + * @void *p@ = pointer to PKCS1 parameters * - * Returns: The length of the output string (hash) if successful, - * negative on failure. + * Returns: The length of the output string if successful, negative on + * failure. * - * Use: Implements most of the operation @EMSA_PSS_VERIFY@, as - * defined in PCSK#1 v. 2.1 draft 1. The salt value is filled - * in ready for hashing of the data to start. + * Use: Implements the operation @EMSA_PSS_VERIFY@, as defined in + * PCSK#1 v. 2.1 (RFC3447). */ -int pss_decode(const void *buf, size_t sz, dstr *d, void *p) +int pss_decode(mp *mi, const void *m, size_t msz, octet *b, size_t sz, + unsigned long nbits, void *p) { pss *pp = p; + octet *s, *r; + ghash *h; gcipher *c; - octet *q, *mq, *qq; - octet *ppp; - size_t n; - size_t hsz = pp->ch->hashsz; - int rc = -1; + unsigned mask; + size_t pssz, hsz = pp->ch->hashsz, i; + int rc; - /* --- Ensure that the block is large enough --- */ + /* --- Check the message length --- */ - if (sz < 2 * hsz + 1) + nbits--; + sz = (nbits + 7)/8; + if (mp_octets(mi) > sz) return (-1); + mask = (1 << nbits%8) - 1; + if (!mask) mask = 0xff; + if (hsz + pp->ssz + 2 > sz) + return (-1); + mp_storeb(mi, b, sz); - q = x_alloc(d->a, sz); - memcpy(q, buf, sz); - - /* --- Recover the salt --- */ + /* --- Split up the buffer --- */ - if (*q++ != 0) - goto fail; - sz--; - mq = q + hsz; - qq = q + sz; - n = sz - hsz; - c = pp->cc->init(q, hsz); - c->ops->decrypt(c, mq, mq, n); - c->ops->destroy(c); + pssz = sz - hsz - pp->ssz - 2; + s = b + pssz + 1; + r = s + pp->ssz; + if (r[hsz] != 0xbc) + return (-1); - /* --- Now check the recovery --- */ + /* --- Decode the seed --- */ - ppp = mq + hsz; - while (ppp < qq) { - if (*ppp) - goto fail; - ppp++; - } + if (b[0] & ~mask) + return (-1); + c = GC_INIT(pp->cc, r, hsz); + GC_DECRYPT(c, b, b, pssz + pp->ssz + 1); + GC_DESTROY(c); + b[0] &= mask; + for (i = 0; i < pssz; i++) + if (b[i]) return (-1); + if (b[pssz] != 0x01) + return (-1); - /* --- Done --- */ + /* --- Hash the message --- */ - if (pp->salt) { - if (memcmp(pp->salt, mq, hsz) != 0) - goto fail; - } else { - qq = xmalloc(hsz); - memcpy(qq, mq, hsz); - pp->salt = qq; - } - dstr_putm(d, q, hsz); - rc = hsz; - -fail: - x_free(d->a, q - 1); - return (rc); -} + h = GH_INIT(pp->ch); + GH_HASH(h, z8, 8); + GH_HASH(h, m, msz); + GH_HASH(h, s, pp->ssz); + s = GH_DONE(h, 0); + rc = !memcmp(s, r, hsz); + GH_DESTROY(h); + if (!rc) return (-1); -/* --- @pss_preverify@ --- * - * - * Arguments: @pss *pp@ = pointer to PSS parameter block - * - * Returns: An initialized generic hash context. - * - * Use: Initializes a hash function for use with PSS. A salt is - * read from the parameter block, where @pss_decode@ should have - * left it. - */ - -ghash *pss_preverify(pss *pp) -{ - size_t hsz = pp->ch->hashsz; - ghash *h = pp->ch->init(); - h->ops->hash(h, pp->salt, hsz); - return (h); -} - -/* --- @pss_done@ --- * - * - * Arguments: @pss *pp@ = pointer to PSS parameter block - * - * Returns: --- - * - * Use: Disposes of a PSS parameter block once it's finished with. - */ + /* --- Done --- */ -void pss_done(pss *pp) -{ - if (pp->salt) { - xfree(pp->salt); - pp->salt = 0; - } + return (0); } /*----- That's all, folks -------------------------------------------------*/