/* -*-c-*-
*
- * $Id: oaep.c,v 1.2 2000/07/15 10:01:48 mdw Exp $
+ * $Id: oaep.c,v 1.6 2004/04/08 01:36:15 mdw Exp $
*
* Optimal asymmetric encryption packing
*
* (c) 2000 Straylight/Edgeware
*/
-/*----- Licensing notice --------------------------------------------------*
+/*----- Licensing notice --------------------------------------------------*
*
* This file is part of Catacomb.
*
* 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: oaep.c,v $
- * Revision 1.2 2000/07/15 10:01:48 mdw
- * Test rig added, based on RIPEMD160-MGF1 test vectors.
- *
- * Revision 1.1 2000/07/01 11:18:30 mdw
- * Support for Optimal Asymmetric Encryption Padding.
- *
- */
-
/*----- Header files ------------------------------------------------------*/
#include <string.h>
#include "gcipher.h"
#include "ghash.h"
#include "grand.h"
-#include "oaep.h"
+#include "rsa.h"
/*----- Main code ---------------------------------------------------------*/
/* --- @oaep_encode@ --- *
*
- * Arguments: @const void *msg@ = pointer to message data
+ * Arguments: @mp *d@ = where to put the answer
+ * @const void *m@ = pointer to message data
* @size_t msz@ = size of message data
- * @void *buf@ = pointer to output buffer
- * @size_t sz@ = size of the output buffer
+ * @octet *b@ = spare buffer
+ * @size_t sz@ = size of the buffer (big enough)
+ * @unsigned long nbits@ = length of bits of @n@
* @void *p@ = pointer to OAEP parameter block
*
- * Returns: Zero if all went well, negative on failure.
+ * Returns: The encoded plaintext, or null on failure.
*
* Use: Implements the operation @EME-OAEP-ENCODE@, as defined in
* PKCS#1 v. 2.0 (RFC2437).
*/
-int oaep_encode(const void *msg, size_t msz, void *buf, size_t sz, void *p)
+mp *oaep_encode(mp *d, const void *m, size_t msz, octet *b, size_t sz,
+ unsigned long nbits, void *p)
{
oaep *o = p;
size_t hsz = o->ch->hashsz;
- ghash *h = o->ch->init();
+ ghash *h;
octet *q, *mq, *qq;
octet *pp;
gcipher *c;
/* --- Ensure that everything is sensibly sized --- */
if (2 * hsz + 2 + msz > sz)
- return (-1);
+ return (0);
/* --- Make the `seed' value --- */
- q = buf;
+ q = b;
*q++ = 0; sz--;
mq = q + hsz;
qq = q + sz;
- o->r->ops->fill(o->r, q, hsz);
+ GR_FILL(o->r, q, hsz);
/* --- Fill in the rest of the buffer --- */
- h->ops->hash(h, o->ep, o->epsz);
- h->ops->done(h, mq);
- h->ops->destroy(h);
+ h = GH_INIT(o->ch);
+ GH_HASH(h, o->ep, o->epsz);
+ GH_DONE(h, mq);
+ GH_DESTROY(h);
pp = mq + hsz;
n = sz - 2 * hsz - msz - 1;
memset(pp, 0, n);
pp += n;
*pp++ = 1;
- memcpy(pp, msg, msz);
+ memcpy(pp, m, msz);
/* --- Do the packing --- */
n = sz - hsz;
- c = o->cc->init(q, hsz);
- c->ops->encrypt(c, mq, mq, n);
- c->ops->destroy(c);
+ c = GC_INIT(o->cc, q, hsz);
+ GC_ENCRYPT(c, mq, mq, n);
+ GC_DESTROY(c);
- c = o->cc->init(mq, n);
- c->ops->encrypt(c, q, q, hsz);
- c->ops->destroy(c);
+ c = GC_INIT(o->cc, mq, n);
+ GC_ENCRYPT(c, q, q, hsz);
+ GC_DESTROY(c);
/* --- Done --- */
- return (0);
+ return (mp_loadb(d, b, sz + 1));
}
/* --- @oaep_decode@ --- *
*
- * Arguments: @const void *buf@ = pointer to encoded buffer
- * @size_t sz@ = size of the encoded buffer
- * @dstr *d@ = pointer to destination string
+ * Arguments: @mp *m@ = the decrypted message
+ * @octet *b@ = pointer to a buffer to work in
+ * @size_t sz@ = the size of the buffer (big enough)
+ * @unsigned long nbits@ = the number of bits in @n@
* @void *p@ = pointer to OAEP parameter block
*
* Returns: The length of the output string if successful, negative on
* PKCS#1 v. 2.0 (RFC2437).
*/
-int oaep_decode(const void *buf, size_t sz, dstr *d, void *p)
+static int memeq(const void *xx, const void *yy, size_t sz)
+{
+ int eq = 1;
+ const octet *x = xx, *y = yy;
+ while (sz) { /* Always check every byte */
+ if (*x++ != *y++) eq = 0;
+ sz--;
+ }
+ return (eq);
+}
+
+int oaep_decode(mp *m, octet *b, size_t sz, unsigned long nbits, void *p)
{
oaep *o = p;
gcipher *c;
ghash *h;
octet *q, *mq, *qq;
octet *pp;
+ unsigned bad = 0;
size_t n;
size_t hsz = o->ch->hashsz;
- int rc = -1;
/* --- Ensure that the block is large enough --- */
- if (sz < 2 * hsz)
+ if (sz < 2 * hsz) /* Doesn't depend on ciphertext */
return (-1);
- q = x_alloc(d->a, sz);
- memcpy(q, buf, sz);
-
/* --- Decrypt the message --- */
- if (*q != 0)
- goto fail;
+ mp_storeb(m, b, sz);
+ q = b;
+ bad = *q;
q++; sz--;
mq = q + hsz;
qq = q + sz;
n = sz - hsz;
- c = o->cc->init(mq, n);
- c->ops->decrypt(c, q, q, hsz);
- c->ops->destroy(c);
+ c = GC_INIT(o->cc, mq, n);
+ GC_DECRYPT(c, q, q, hsz);
+ GC_DESTROY(c);
- c = o->cc->init(q, hsz);
- c->ops->decrypt(c, mq, mq, n);
- c->ops->destroy(c);
+ c = GC_INIT(o->cc, q, hsz);
+ GC_DECRYPT(c, mq, mq, n);
+ GC_DESTROY(c);
q--;
/* --- Check the hash on the encoding parameters --- */
- h = o->ch->init();
- h->ops->hash(h, o->ep, o->epsz);
- h->ops->done(h, q);
- if (memcmp(q, mq, hsz) != 0)
- goto fail;
+ h = GH_INIT(o->ch);
+ GH_HASH(h, o->ep, o->epsz);
+ GH_DONE(h, q);
+ GH_DESTROY(h);
+ bad |= !memeq(q, mq, hsz);
/* --- Now find the start of the actual message --- */
pp = mq + hsz;
while (*pp == 0 && pp < qq)
pp++;
- if (pp >= qq || *pp++ != 1)
- return (-1);
+ bad |= (pp >= qq) | (*pp != 1);
+ pp++;
n = qq - pp;
- dstr_putm(d, pp, n);
- rc = n;
-
-fail:
- x_free(d->a, q);
- return (rc);
+ memmove(q, pp, n);
+ return (bad ? -1 : n);
}
-/*----- Test rig ----------------------------------------------------------*/
-
-#ifdef TEST_RIG
-
-#include <mLib/testrig.h>
-
-#include "rmd160.h"
-#include "rmd160-mgf.h"
-
-typedef struct gctx {
- grand r;
- octet *buf;
-} gctx;
-
-static void rfill(grand *r, void *buf, size_t sz)
-{
- gctx *g = (gctx *)r;
- memcpy(buf, g->buf, sz);
-}
-
-static const grand_ops gops = {
- "const", 0, 0,
- 0, 0,
- 0, 0, 0, 0, rfill
-};
-
-static int verify(dstr *v)
-{
- gctx gr;
- dstr d = DSTR_INIT;
- oaep o;
- int ok = 1;
-
- dstr_ensure(&d, v[3].len);
- d.len = v[3].len;
- gr.r.ops = &gops;
- gr.buf = v[2].buf;
-
- o.cc = &rmd160_mgf;
- o.ch = &rmd160;
- o.r = &gr.r;
- o.ep = v[1].buf;
- o.epsz = v[1].len;
-
- if (oaep_encode(v[0].buf, v[0].len, d.buf, d.len, &o) ||
- memcmp(d.buf, v[3].buf, d.len) != 0) {
- ok = 0;
- fputs("\nfailure in oaep_encode", stderr);
- fputs("\n message = ", stderr); type_hex.dump(&v[0], stderr);
- fputs("\n params = ", stderr); type_hex.dump(&v[1], stderr);
- fputs("\n salt = ", stderr); type_hex.dump(&v[2], stderr);
- fputs("\nexpected = ", stderr); type_hex.dump(&v[3], stderr);
- fputs("\n output = ", stderr); type_hex.dump(&d, stderr);
- fputc('\n', stderr);
- }
-
- DRESET(&d);
- if (oaep_decode(v[3].buf, v[3].len, &d, &o) < 0 ||
- d.len != v[0].len || memcmp(d.buf, v[0].buf, d.len) != 0) {
- ok = 0;
- fputs("\nfailure in oaep_decode", stderr);
- fputs("\n goop = ", stderr); type_hex.dump(&v[3], stderr);
- fputs("\n params = ", stderr); type_hex.dump(&v[1], stderr);
- fputs("\n salt = ", stderr); type_hex.dump(&v[2], stderr);
- fputs("\nexpected = ", stderr); type_hex.dump(&v[0], stderr);
- fputs("\n output = ", stderr); type_hex.dump(&d, stderr);
- fputc('\n', stderr);
- }
-
- dstr_destroy(&d);
- return (ok);
-}
-
-static test_chunk tests[] = {
- { "oaep", verify, { &type_hex, &type_hex, &type_hex, &type_hex, 0 } },
- { 0, 0, { 0 } }
-};
-
-int main(int argc, char *argv[])
-{
- test_run(argc, argv, tests, SRCDIR "/tests/oaep");
- return (0);
-}
-
-#endif
-
/*----- That's all, folks -------------------------------------------------*/