3 * The alleged RC4 stream cipher
5 * (c) 1999 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 /*----- Header files ------------------------------------------------------*/
34 #include <mLib/bits.h>
43 /*----- Global variables --------------------------------------------------*/
45 const octet rc4_keysz
[] = { KSZ_RANGE
, RC4_KEYSZ
, 1, 255, 1 };
47 /*----- Main code ---------------------------------------------------------*/
49 /* --- @rc4_addkey@ --- *
51 * Arguments: @rc4_ctx *ctx@ = pointer to context to key
52 * @const void *k@ = pointer to key data to use
53 * @size_t sz@ = size of the key data
57 * Use: Mixes key data with an RC4 context. The RC4 context is not
58 * reset before mixing. This may be used to mix new key
59 * material with an existing RC4 context.
62 void rc4_addkey(rc4_ctx
*ctx
, const void *k
, size_t sz
)
65 const octet
*p
= k
, *q
= p
+ sz
;
69 for (i
= j
= 0; i
< 256; i
++) {
70 unsigned si
= ctx
->s
[i
];
71 j
= (j
+ si
+ *p
++) & 0xff;
72 ctx
->s
[i
] = ctx
->s
[j
];
81 /* --- @rc4_init@ --- *
83 * Arguments: @rc4_ctx *ctx@ = pointer to context to initialize
84 * @const void *k@ = pointer to key data to use
85 * @size_t sz@ = size of the key data
89 * Use: Initializes an RC4 context ready for use.
92 void rc4_init(rc4_ctx
*ctx
, const void *k
, size_t sz
)
96 for (i
= 0; i
< 256; i
++)
99 rc4_addkey(ctx
, k
, sz
);
102 /* --- @rc4_encrypt@ --- *
104 * Arguments: @rc4_ctx *ctx@ = pointer to context to use
105 * @const void *src@ = pointer to the source block
106 * @void *dest@ = pointer to the destination block
107 * @size_t sz@ = size of the block
111 * Use: Encrypts or decrypts a block of data. The destination may
112 * be null to just grind the generator around for a while. It's
113 * recommended that you say `@rc4_encrypt(&ctx, 0, 0, 1024)@'
114 * after initializing a new context, to prevent keystream
115 * guessing attacks. The source may be null to just extract a
116 * big lump of data from the generator.
119 void rc4_encrypt(rc4_ctx
*ctx
, const void *src
, void *dest
, size_t sz
)
121 const octet
*s
= src
;
125 RC4_OPEN(ctx
, while (sz
) { unsigned x
; RC4_BYTE(x
); (void)x
; sz
--; });
127 RC4_OPEN(ctx
, while (sz
) { RC4_BYTE(*d
++); sz
--; });
130 while (sz
) { unsigned x
; RC4_BYTE(x
); *d
++ = *s
++ ^ x
; sz
--; });
133 /*----- Generic cipher interface ------------------------------------------*/
135 typedef struct gctx
{
140 static const gcipher_ops gops
;
142 static gcipher
*ginit(const void *k
, size_t sz
)
144 gctx
*g
= S_CREATE(gctx
);
146 rc4_init(&g
->rc4
, k
, sz
);
150 static void gencrypt(gcipher
*c
, const void *s
, void *t
, size_t sz
)
153 rc4_encrypt(&g
->rc4
, s
, t
, sz
);
156 static void gdestroy(gcipher
*c
)
163 static const gcipher_ops gops
= {
165 gencrypt
, gencrypt
, gdestroy
, 0, 0
168 const gccipher rc4
= {
173 /*----- Generic random number generator interface -------------------------*/
175 typedef struct grctx
{
180 static void grdestroy(grand
*r
)
182 grctx
*g
= (grctx
*)r
;
187 static int grmisc(grand
*r
, unsigned op
, ...)
189 grctx
*g
= (grctx
*)r
;
198 switch (va_arg(ap
, unsigned)) {
201 case GRAND_SEEDUINT32
:
202 case GRAND_SEEDBLOCK
:
212 i
= va_arg(ap
, unsigned);
214 rc4_addkey(&g
->rc4
, buf
, sizeof(buf
));
216 case GRAND_SEEDUINT32
:
217 i
= va_arg(ap
, uint32
);
219 rc4_addkey(&g
->rc4
, buf
, sizeof(buf
));
221 case GRAND_SEEDBLOCK
: {
222 const void *p
= va_arg(ap
, const void *);
223 size_t sz
= va_arg(ap
, size_t);
224 rc4_addkey(&g
->rc4
, p
, sz
);
226 case GRAND_SEEDRAND
: {
227 grand
*rr
= va_arg(ap
, grand
*);
229 rr
->ops
->fill(rr
, buf
, sizeof(buf
));
230 rc4_addkey(&g
->rc4
, buf
, sizeof(buf
));
241 static octet
grbyte(grand
*r
)
243 grctx
*g
= (grctx
*)r
;
245 RC4_OPEN(&g
->rc4
, RC4_BYTE(o
););
249 static uint32
grword(grand
*r
)
251 grctx
*g
= (grctx
*)r
;
255 for (i
= 0; i
< sizeof(b
); i
++)
260 static void grfill(grand
*r
, void *p
, size_t sz
)
262 grctx
*g
= (grctx
*)r
;
263 rc4_encrypt(&g
->rc4
, 0, p
, sz
);
266 static const grand_ops grops
= {
270 grword
, grbyte
, grword
, grand_defaultrange
, grfill
273 /* --- @rc4_rand@ --- *
275 * Arguments: @const void *k@ = pointer to key material
276 * @size_t sz@ = size of key material
278 * Returns: Pointer to generic random number generator interface.
280 * Use: Creates a random number interface wrapper around the RC4
284 grand
*rc4_rand(const void *k
, size_t sz
)
286 grctx
*g
= S_CREATE(grctx
);
288 rc4_init(&g
->rc4
, k
, sz
);
292 /*----- Test rig ----------------------------------------------------------*/
299 #include <mLib/macros.h>
300 #include <mLib/quis.h>
301 #include <mLib/testrig.h>
303 static int v_encrypt(dstr
*v
)
309 rc4_init(&ctx
, v
[0].buf
, v
[0].len
);
310 dstr_ensure(&d
, v
[1].len
);
312 rc4_encrypt(&ctx
, v
[1].buf
, d
.buf
, d
.len
);
314 if (MEMCMP(v
[2].buf
, !=, d
.buf
, d
.len
)) {
316 printf("\nfail encryption:"
318 type_hex
.dump(&v
[0], stdout
);
319 printf("\n\tplaintext = "); type_hex
.dump(&v
[1], stdout
);
320 printf("\n\texpected = "); type_hex
.dump(&v
[2], stdout
);
321 printf("\n\tcalculated = "); type_hex
.dump(&d
, stdout
);
328 static int v_generate(dstr
*v
)
334 rc4_init(&ctx
, v
[0].buf
, v
[0].len
);
335 rc4_encrypt(&ctx
, 0, 0, *(int *)v
[1].buf
);
336 dstr_ensure(&d
, v
[2].len
);
338 rc4_encrypt(&ctx
, 0, d
.buf
, d
.len
);
340 if (MEMCMP(v
[2].buf
, !=, d
.buf
, d
.len
)) {
342 printf("\nfail generation:"
344 type_hex
.dump(&v
[0], stdout
);
345 printf("\n\tskip len = %i", *(int *)v
[1].buf
);
346 printf("\n\texpected = "); type_hex
.dump(&v
[2], stdout
);
347 printf("\n\tcalculated = "); type_hex
.dump(&d
, stdout
);
354 static test_chunk defs
[] = {
355 { "rc4-encrypt", v_encrypt
, { &type_hex
, &type_hex
, &type_hex
, 0 } },
356 { "rc4-generate", v_generate
, { &type_hex
, &type_int
, &type_hex
, 0 } },
360 int main(int argc
, char *argv
[])
362 test_run(argc
, argv
, defs
, SRCDIR
"/t/rc4");
368 /*----- That's all, folks -------------------------------------------------*/