Hash utilities: maintain a hash state object, not a bundle of arguments.
[u/mdw/catacomb] / rc4.c
diff --git a/rc4.c b/rc4.c
index a4e595f..83b5104 100644 (file)
--- a/rc4.c
+++ b/rc4.c
@@ -1,13 +1,13 @@
 /* -*-c-*-
  *
- * $Id: rc4.c,v 1.3 1999/12/13 15:34:01 mdw Exp $
+ * $Id: rc4.c,v 1.6 2004/04/08 01:36:15 mdw Exp $
  *
  * The alleged RC4 stream cipher
  *
  * (c) 1999 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: rc4.c,v $
- * Revision 1.3  1999/12/13 15:34:01  mdw
- * Add support for seeding from a generic pseudorandom source.
- *
- * Revision 1.2  1999/12/10 23:27:35  mdw
- * Generic cipher and RNG interfaces.
- *
- * Revision 1.1  1999/09/03 08:41:12  mdw
- * Initial import.
- *
- */
-
 /*----- Header files ------------------------------------------------------*/
 
 #include <assert.h>
 #include <mLib/bits.h>
 #include <mLib/sub.h>
 
+#include "arena.h"
 #include "gcipher.h"
 #include "grand.h"
+#include "paranoia.h"
 #include "rc4.h"
 
+/*----- Global variables --------------------------------------------------*/
+
+const octet rc4_keysz[] = { KSZ_RANGE, RC4_KEYSZ, 1, 255, 1 };
+
 /*----- Main code ---------------------------------------------------------*/
 
-/* --- @rc4_init@ --- *
+/* --- @rc4_addkey@ --- *
  *
- * Arguments:  @rc4_ctx *ctx@ = pointer to context to initialize
+ * Arguments:  @rc4_ctx *ctx@ = pointer to context to key
  *             @const void *k@ = pointer to key data to use
  *             @size_t sz@ = size of the key data
  *
  * Returns:    ---
  *
- * Use:                Initializes an RC4 context ready for use.
+ * Use:                Mixes key data with an RC4 context.  The RC4 context is not
+ *             reset before mixing.  This may be used to mix new key
+ *             material with an existing RC4 context.
  */
 
-void rc4_init(rc4_ctx *ctx, const void *k, size_t sz)
+void rc4_addkey(rc4_ctx *ctx, const void *k, size_t sz)
 {
   unsigned i, j;
   const octet *p = k, *q = p + sz;
 
-  assert(((void)"RC4 does not support zero length keys", sz != 0));
+  KSZ_ASSERT(rc4, sz);
 
-  for (i = 0; i < 256; i++)
-    ctx->s[i] = i;
-  ctx->f = 0;
-  ctx->i = ctx->j = 0;
-  
   for (i = j = 0; i < 256; i++) {
     unsigned si = ctx->s[i];
     j = (j + si + *p++) & 0xff;
@@ -87,6 +76,29 @@ void rc4_init(rc4_ctx *ctx, const void *k, size_t sz)
     if (p == q)
       p = k;
   }
+
+  ctx->i = ctx->j = 0;
+}
+
+/* --- @rc4_init@ --- *
+ *
+ * Arguments:  @rc4_ctx *ctx@ = pointer to context to initialize
+ *             @const void *k@ = pointer to key data to use
+ *             @size_t sz@ = size of the key data
+ *
+ * Returns:    ---
+ *
+ * Use:                Initializes an RC4 context ready for use.
+ */
+
+void rc4_init(rc4_ctx *ctx, const void *k, size_t sz)
+{
+  unsigned i;
+
+  for (i = 0; i < 256; i++)
+    ctx->s[i] = i;
+  ctx->f = 0;
+  rc4_addkey(ctx, k, sz);
 }
 
 /* --- @rc4_encrypt@ --- *
@@ -131,7 +143,7 @@ static const gcipher_ops gops;
 
 static gcipher *ginit(const void *k, size_t sz)
 {
-  gctx *g = CREATE(gctx);
+  gctx *g = S_CREATE(gctx);
   g->c.ops = &gops;
   rc4_init(&g->rc4, k, sz);
   return (&g->c);
@@ -146,16 +158,17 @@ static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)
 static void gdestroy(gcipher *c)
 {
   gctx *g = (gctx *)c;
-  DESTROY(g);
+  BURN(*g);
+  S_DESTROY(g);
 }
 
 static const gcipher_ops gops = {
-  &rc4.b,
+  &rc4,
   gencrypt, gencrypt, gdestroy, 0, 0
 };
 
 const gccipher rc4 = {
-  { "rc4", 0, 0 },
+  "rc4", rc4_keysz, 0,
   ginit
 };
 
@@ -169,7 +182,8 @@ typedef struct grctx {
 static void grdestroy(grand *r)
 {
   grctx *g = (grctx *)r;
-  DESTROY(g);
+  BURN(*g);
+  S_DESTROY(g);
 }
 
 static int grmisc(grand *r, unsigned op, ...)
@@ -177,6 +191,7 @@ static int grmisc(grand *r, unsigned op, ...)
   grctx *g = (grctx *)r;
   va_list ap;
   int rc = 0;
+  uint32 i;
   octet buf[4];
   va_start(ap, op);
 
@@ -196,23 +211,25 @@ static int grmisc(grand *r, unsigned op, ...)
       }
       break;
     case GRAND_SEEDINT:
-      STORE32(buf, va_arg(ap, unsigned));
-      rc4_init(&g->rc4, buf, sizeof(buf));
+      i = va_arg(ap, unsigned);
+      STORE32(buf, i);
+      rc4_addkey(&g->rc4, buf, sizeof(buf));
       break;
     case GRAND_SEEDUINT32:
-      STORE32(buf, va_arg(ap, uint32));
-      rc4_init(&g->rc4, buf, sizeof(buf));
+      i = va_arg(ap, uint32);
+      STORE32(buf, i);
+      rc4_addkey(&g->rc4, buf, sizeof(buf));
       break;
     case GRAND_SEEDBLOCK: {
       const void *p = va_arg(ap, const void *);
       size_t sz = va_arg(ap, size_t);
-      rc4_init(&g->rc4, p, sz);
+      rc4_addkey(&g->rc4, p, sz);
     } break;
     case GRAND_SEEDRAND: {
       grand *rr = va_arg(ap, grand *);
       octet buf[16];
       rr->ops->fill(rr, buf, sizeof(buf));
-      rc4_init(&g->rc4, buf, sizeof(buf));
+      rc4_addkey(&g->rc4, buf, sizeof(buf));
     } break;
     default:
       GRAND_BADOP;
@@ -250,7 +267,7 @@ static void grfill(grand *r, void *p, size_t sz)
 
 static const grand_ops grops = {
   "rc4",
-  0,
+  GRAND_CRYPTO, 0,
   grmisc, grdestroy,
   grword, grbyte, grword, grand_range, grfill
 };
@@ -268,7 +285,7 @@ static const grand_ops grops = {
 
 grand *rc4_rand(const void *k, size_t sz)
 {
-  grctx *g = CREATE(grctx);
+  grctx *g = S_CREATE(grctx);
   g->r.ops = &grops;
   rc4_init(&g->rc4, k, sz);
   return (&g->r);
@@ -298,7 +315,7 @@ static int v_encrypt(dstr *v)
   if (memcmp(v[2].buf, d.buf, d.len) != 0) {
     ok = 0;
     printf("\nfail encryption:"
-          "\n\tkey        = ");
+          "\n\tkey        = ");
     type_hex.dump(&v[0], stdout);
     printf("\n\tplaintext  = "); type_hex.dump(&v[1], stdout);
     printf("\n\texpected   = "); type_hex.dump(&v[2], stdout);
@@ -324,7 +341,7 @@ static int v_generate(dstr *v)
   if (memcmp(v[2].buf, d.buf, d.len) != 0) {
     ok = 0;
     printf("\nfail generation:"
-          "\n\tkey        = ");
+          "\n\tkey        = ");
     type_hex.dump(&v[0], stdout);
     printf("\n\tskip len   = %i", *(int *)v[1].buf);
     printf("\n\texpected   = "); type_hex.dump(&v[2], stdout);