2003-04-16 Moritz Schulte <moritz@g10code.com>
[libgcrypt.git] / cipher / arcfour.c
1 /* arcfour.c  -  The arcfour stream cipher
2  *      Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser general Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  *
20  * For a description of the algorithm, see:
21  *   Bruce Schneier: Applied Cryptography. John Wiley & Sons, 1996.
22  *   ISBN 0-471-11709-9. Pages 397 ff.
23  */
24
25
26 #include <config.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include "types.h"
31 #include "g10lib.h"
32 #include "cipher.h"
33
34 static const char *selftest(void);
35
36 typedef struct {
37     int idx_i, idx_j;
38     byte sbox[256];
39 } ARCFOUR_context;
40
41 static void
42 do_encrypt_stream( ARCFOUR_context *ctx,
43                    byte *outbuf, const byte *inbuf, unsigned int length )
44 {
45   register int i = ctx->idx_i;
46   register int j = ctx->idx_j;
47   register byte *sbox = ctx->sbox;
48   register int t;  
49
50   while ( length-- )
51     {
52       i++;
53       i = i & 255; /* and seems to be faster than mod */
54       j += sbox[i];
55       j &= 255;
56       t = sbox[i]; sbox[i] = sbox[j]; sbox[j] = t;
57       *outbuf++ = *inbuf++ ^ sbox[(sbox[i] + sbox[j]) & 255];
58     }
59   
60   ctx->idx_i = i;
61   ctx->idx_j = j;
62 }
63
64 static void
65 encrypt_stream (void *context,
66                 byte *outbuf, const byte *inbuf, unsigned int length)
67 {
68   ARCFOUR_context *ctx = (ARCFOUR_context *) context;
69   do_encrypt_stream (ctx, outbuf, inbuf, length );
70   _gcry_burn_stack (64);
71 }
72
73
74 static int
75 do_arcfour_setkey (void *context, const byte *key, unsigned int keylen)
76 {
77     static int initialized;
78     static const char* selftest_failed;
79     int i, j;
80     byte karr[256];
81     ARCFOUR_context *ctx = (ARCFOUR_context *) context;
82
83     if( !initialized ) {
84         initialized = 1;
85         selftest_failed = selftest();
86         if( selftest_failed )
87             log_error ("ARCFOUR selftest failed (%s)\n", selftest_failed );
88     }
89     if( selftest_failed )
90         return GCRYERR_SELFTEST;
91
92     if( keylen < 40/8 ) /* we want at least 40 bits */
93         return GCRYERR_INV_KEYLEN; 
94
95     ctx->idx_i = ctx->idx_j = 0;
96     for (i=0; i < 256; i++ )
97         ctx->sbox[i] = i;
98     for (i=0; i < 256; i++ )
99         karr[i] = key[i%keylen];
100     for (i=j=0; i < 256; i++ ) {
101         int t;
102         j = (j + ctx->sbox[i] + karr[i]) % 256;
103         t = ctx->sbox[i];
104         ctx->sbox[i] = ctx->sbox[j];
105         ctx->sbox[j] = t;
106     } 
107     memset( karr, 0, 256 );
108
109     return 0;
110 }
111
112 static int
113 arcfour_setkey ( void *context, const byte *key, unsigned int keylen )
114 {
115   ARCFOUR_context *ctx = (ARCFOUR_context *) context;
116   int rc = do_arcfour_setkey (ctx, key, keylen );
117   _gcry_burn_stack (300);
118   return rc;
119 }
120
121
122 static const char*
123 selftest(void)
124 {
125     ARCFOUR_context ctx;
126     byte scratch[16];      
127     
128     /* Test vector from Cryptlib labeled there:
129      * "from the State/Commerce Department" */
130     static byte key_1[] =
131         { 0x61, 0x8A, 0x63, 0xD2, 0xFB };
132     static byte plaintext_1[] =
133         { 0xDC, 0xEE, 0x4C, 0xF9, 0x2C };
134     static const byte ciphertext_1[] =
135         { 0xF1, 0x38, 0x29, 0xC9, 0xDE };
136
137     arcfour_setkey( &ctx, key_1, sizeof(key_1));
138     encrypt_stream( &ctx, scratch, plaintext_1, sizeof(plaintext_1));
139     if (memcmp (scratch, ciphertext_1, sizeof (ciphertext_1)))
140         return "Arcfour encryption test 1 failed.";
141     arcfour_setkey( &ctx, key_1, sizeof(key_1));
142     encrypt_stream(&ctx, scratch, scratch, sizeof(plaintext_1)); /* decrypt */
143     if ( memcmp (scratch, plaintext_1, sizeof (plaintext_1)))
144         return "Arcfour decryption test 1 failed.";
145     return NULL;
146 }
147
148 \f
149
150 GcryCipherSpec cipher_spec_arcfour =
151   {
152     "ARCFOUR", GCRY_CIPHER_ARCFOUR, 1, 128, sizeof (ARCFOUR_context),
153     arcfour_setkey, NULL, NULL, encrypt_stream, encrypt_stream,
154   };