/* -*-c-*-
*
- * $Id: rc4.c,v 1.2 1999/12/10 23:27:35 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.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;
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@ --- *
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);
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
};
static void grdestroy(grand *r)
{
grctx *g = (grctx *)r;
- DESTROY(g);
+ BURN(*g);
+ S_DESTROY(g);
}
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);
case GRAND_SEEDINT:
case GRAND_SEEDUINT32:
case GRAND_SEEDBLOCK:
+ case GRAND_SEEDRAND:
rc = 1;
break;
default:
}
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_addkey(&g->rc4, buf, sizeof(buf));
+ } break;
+ default:
+ GRAND_BADOP;
+ break;
}
va_end(ap);
static const grand_ops grops = {
"rc4",
- 0,
+ GRAND_CRYPTO, 0,
grmisc, grdestroy,
grword, grbyte, grword, grand_range, grfill
};
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);
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);
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);