chiark / gitweb /
Fix daft error in the comment for @gfshare_get@.
[catacomb] / rc4.c
1 /* -*-c-*-
2  *
3  * $Id: rc4.c,v 1.4 2000/06/17 11:55:22 mdw Exp $
4  *
5  * The alleged RC4 stream cipher
6  *
7  * (c) 1999 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of Catacomb.
13  *
14  * Catacomb is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * Catacomb is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with Catacomb; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Revision history --------------------------------------------------* 
31  *
32  * $Log: rc4.c,v $
33  * Revision 1.4  2000/06/17 11:55:22  mdw
34  * New key size interface.  Allow key material to be combined with an
35  * existing initialized context.  Use secure arena for memory allocation.
36  *
37  * Revision 1.3  1999/12/13 15:34:01  mdw
38  * Add support for seeding from a generic pseudorandom source.
39  *
40  * Revision 1.2  1999/12/10 23:27:35  mdw
41  * Generic cipher and RNG interfaces.
42  *
43  * Revision 1.1  1999/09/03 08:41:12  mdw
44  * Initial import.
45  *
46  */
47
48 /*----- Header files ------------------------------------------------------*/
49
50 #include <assert.h>
51 #include <stdarg.h>
52 #include <stdio.h>
53
54 #include <mLib/bits.h>
55 #include <mLib/sub.h>
56
57 #include "arena.h"
58 #include "gcipher.h"
59 #include "grand.h"
60 #include "paranoia.h"
61 #include "rc4.h"
62
63 /*----- Global variables --------------------------------------------------*/
64
65 const octet rc4_keysz[] = { KSZ_RANGE, RC4_KEYSZ, 1, 255, 1 };
66
67 /*----- Main code ---------------------------------------------------------*/
68
69 /* --- @rc4_addkey@ --- *
70  *
71  * Arguments:   @rc4_ctx *ctx@ = pointer to context to key
72  *              @const void *k@ = pointer to key data to use
73  *              @size_t sz@ = size of the key data
74  *
75  * Returns:     ---
76  *
77  * Use:         Mixes key data with an RC4 context.  The RC4 context is not
78  *              reset before mixing.  This may be used to mix new key
79  *              material with an existing RC4 context.
80  */
81
82 void rc4_addkey(rc4_ctx *ctx, const void *k, size_t sz)
83 {
84   unsigned i, j;
85   const octet *p = k, *q = p + sz;
86
87   KSZ_ASSERT(rc4, sz);
88
89   for (i = j = 0; i < 256; i++) {
90     unsigned si = ctx->s[i];
91     j = (j + si + *p++) & 0xff;
92     ctx->s[i] = ctx->s[j];
93     ctx->s[j] = si;
94     if (p == q)
95       p = k;
96   }  
97
98   ctx->i = ctx->j = 0;
99 }
100
101 /* --- @rc4_init@ --- *
102  *
103  * Arguments:   @rc4_ctx *ctx@ = pointer to context to initialize
104  *              @const void *k@ = pointer to key data to use
105  *              @size_t sz@ = size of the key data
106  *
107  * Returns:     ---
108  *
109  * Use:         Initializes an RC4 context ready for use.
110  */
111
112 void rc4_init(rc4_ctx *ctx, const void *k, size_t sz)
113 {
114   unsigned i;
115
116   for (i = 0; i < 256; i++)
117     ctx->s[i] = i;
118   ctx->f = 0;
119   rc4_addkey(ctx, k, sz);
120 }
121
122 /* --- @rc4_encrypt@ --- *
123  *
124  * Arguments:   @rc4_ctx *ctx@ = pointer to context to use
125  *              @const void *src@ = pointer to the source block
126  *              @void *dest@ = pointer to the destination block
127  *              @size_t sz@ = size of the block
128  *
129  * Returns:     ---
130  *
131  * Use:         Encrypts or decrypts a block of data.  The destination may
132  *              be null to just grind the generator around for a while.  It's
133  *              recommended that you say `@rc4_encrypt(&ctx, 0, 0, 1024)@'
134  *              after initializing a new context, to prevent keystream
135  *              guessing attacks.  The source may be null to just extract a
136  *              big lump of data from the generator.
137  */
138
139 void rc4_encrypt(rc4_ctx *ctx, const void *src, void *dest, size_t sz)
140 {
141   const octet *s = src;
142   octet *d = dest;
143
144   if (!d)
145     RC4_OPEN(ctx, while (sz) { unsigned x; RC4_BYTE(x); sz--; });
146   else if (!s)
147     RC4_OPEN(ctx, while (sz) { RC4_BYTE(*d++); sz--; });
148   else
149     RC4_OPEN(ctx,
150              while (sz) { unsigned x; RC4_BYTE(x); *d++ = *s++ ^ x; sz--; });
151 }
152
153 /*----- Generic cipher interface ------------------------------------------*/
154
155 typedef struct gctx {
156   gcipher c;
157   rc4_ctx rc4;
158 } gctx;
159
160 static const gcipher_ops gops;
161
162 static gcipher *ginit(const void *k, size_t sz)
163 {
164   gctx *g = S_CREATE(gctx);
165   g->c.ops = &gops;
166   rc4_init(&g->rc4, k, sz);
167   return (&g->c);
168 }
169
170 static void gencrypt(gcipher *c, const void *s, void *t, size_t sz)
171 {
172   gctx *g = (gctx *)c;
173   rc4_encrypt(&g->rc4, s, t, sz);
174 }
175
176 static void gdestroy(gcipher *c)
177 {
178   gctx *g = (gctx *)c;
179   BURN(*g);
180   S_DESTROY(g);
181 }
182
183 static const gcipher_ops gops = {
184   &rc4,
185   gencrypt, gencrypt, gdestroy, 0, 0
186 };
187
188 const gccipher rc4 = {
189   "rc4", rc4_keysz, 0,
190   ginit
191 };
192
193 /*----- Generic random number generator interface -------------------------*/
194
195 typedef struct grctx {
196   grand r;
197   rc4_ctx rc4;
198 } grctx;
199
200 static void grdestroy(grand *r)
201 {
202   grctx *g = (grctx *)r;
203   BURN(*g);
204   S_DESTROY(g);
205 }
206
207 static int grmisc(grand *r, unsigned op, ...)
208 {
209   grctx *g = (grctx *)r;
210   va_list ap;
211   int rc = 0;
212   octet buf[4];
213   va_start(ap, op);
214
215   switch (op) {
216     case GRAND_CHECK:
217       switch (va_arg(ap, unsigned)) {
218         case GRAND_CHECK:
219         case GRAND_SEEDINT:
220         case GRAND_SEEDUINT32:
221         case GRAND_SEEDBLOCK:
222         case GRAND_SEEDRAND:
223           rc = 1;
224           break;
225         default:
226           rc = 0;
227           break;
228       }
229       break;
230     case GRAND_SEEDINT:
231       STORE32(buf, va_arg(ap, unsigned));
232       rc4_addkey(&g->rc4, buf, sizeof(buf));
233       break;
234     case GRAND_SEEDUINT32:
235       STORE32(buf, va_arg(ap, uint32));
236       rc4_addkey(&g->rc4, buf, sizeof(buf));
237       break;
238     case GRAND_SEEDBLOCK: {
239       const void *p = va_arg(ap, const void *);
240       size_t sz = va_arg(ap, size_t);
241       rc4_addkey(&g->rc4, p, sz);
242     } break;
243     case GRAND_SEEDRAND: {
244       grand *rr = va_arg(ap, grand *);
245       octet buf[16];
246       rr->ops->fill(rr, buf, sizeof(buf));
247       rc4_addkey(&g->rc4, buf, sizeof(buf));
248     } break;
249     default:
250       GRAND_BADOP;
251       break;
252   }
253
254   va_end(ap);
255   return (rc);
256 }
257
258 static octet grbyte(grand *r)
259 {
260   grctx *g = (grctx *)r;
261   octet o;
262   RC4_OPEN(&g->rc4, RC4_BYTE(o););
263   return (o);
264 }
265
266 static uint32 grword(grand *r)
267 {
268   grctx *g = (grctx *)r;
269   octet b[4];
270   int i;
271   RC4_OPEN(&g->rc4,
272            for (i = 0; i < sizeof(b); i++)
273              RC4_BYTE(b[i]););
274   return (LOAD32(b));
275 }
276
277 static void grfill(grand *r, void *p, size_t sz)
278 {
279   grctx *g = (grctx *)r;
280   rc4_encrypt(&g->rc4, 0, p, sz);
281 }
282
283 static const grand_ops grops = {
284   "rc4",
285   GRAND_CRYPTO, 0,
286   grmisc, grdestroy,
287   grword, grbyte, grword, grand_range, grfill
288 };
289
290 /* --- @rc4_rand@ --- *
291  *
292  * Arguments:   @const void *k@ = pointer to key material
293  *              @size_t sz@ = size of key material
294  *
295  * Returns:     Pointer to generic random number generator interface.
296  *
297  * Use:         Creates a random number interface wrapper around an
298  *              OFB-mode block cipher.
299  */
300
301 grand *rc4_rand(const void *k, size_t sz)
302 {
303   grctx *g = S_CREATE(grctx);
304   g->r.ops = &grops;
305   rc4_init(&g->rc4, k, sz);
306   return (&g->r);
307 }
308
309 /*----- Test rig ----------------------------------------------------------*/
310
311 #ifdef TEST_RIG
312
313 #include <stdio.h>
314 #include <string.h>
315
316 #include <mLib/quis.h>
317 #include <mLib/testrig.h>
318
319 static int v_encrypt(dstr *v)
320 {
321   rc4_ctx ctx;
322   dstr d = DSTR_INIT;
323   int ok = 1;
324
325   rc4_init(&ctx, v[0].buf, v[0].len);
326   dstr_ensure(&d, v[1].len);
327   d.len = v[1].len;
328   rc4_encrypt(&ctx, v[1].buf, d.buf, d.len);
329
330   if (memcmp(v[2].buf, d.buf, d.len) != 0) {
331     ok = 0;
332     printf("\nfail encryption:"
333            "\n\tkey        = ");
334     type_hex.dump(&v[0], stdout);
335     printf("\n\tplaintext  = "); type_hex.dump(&v[1], stdout);
336     printf("\n\texpected   = "); type_hex.dump(&v[2], stdout);
337     printf("\n\tcalculated = "); type_hex.dump(&d, stdout);
338     putchar('\n');
339   }
340
341   return (ok);
342 }
343
344 static int v_generate(dstr *v)
345 {
346   rc4_ctx ctx;
347   dstr d = DSTR_INIT;
348   int ok = 1;
349
350   rc4_init(&ctx, v[0].buf, v[0].len);
351   rc4_encrypt(&ctx, 0, 0, *(int *)v[1].buf);
352   dstr_ensure(&d, v[2].len);
353   d.len = v[2].len;
354   rc4_encrypt(&ctx, 0, d.buf, d.len);
355
356   if (memcmp(v[2].buf, d.buf, d.len) != 0) {
357     ok = 0;
358     printf("\nfail generation:"
359            "\n\tkey        = ");
360     type_hex.dump(&v[0], stdout);
361     printf("\n\tskip len   = %i", *(int *)v[1].buf);
362     printf("\n\texpected   = "); type_hex.dump(&v[2], stdout);
363     printf("\n\tcalculated = "); type_hex.dump(&d, stdout);
364     putchar('\n');
365   }
366
367   return (ok);
368 }
369
370 static test_chunk defs[] = {
371   { "rc4-encrypt", v_encrypt, { &type_hex, &type_hex, &type_hex, 0 } },
372   { "rc4-generate", v_generate, { &type_hex, &type_int, &type_hex, 0 } },
373   { 0, 0, { 0 } }
374 };
375
376 int main(int argc, char *argv[])
377 {
378   test_run(argc, argv, defs, SRCDIR"/tests/rc4");
379   return (0);
380 }
381
382 #endif
383
384 /*----- That's all, folks -------------------------------------------------*/