* arcfour.c (do_encrypt_stream): Don't use increment op when
[libgcrypt.git] / cipher / arcfour.c
1 /* arcfour.c  -  The arcfour stream cipher
2  *      Copyright (C) 2000, 2001, 2002 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 "arcfour.h"
33
34 static const char *selftest(void);
35
36
37 typedef struct {
38     int idx_i, idx_j;
39     byte sbox[256];
40 } ARCFOUR_context;
41
42
43 static void
44 burn_stack (int bytes)
45 {
46     char buf[64];
47     
48     memset (buf, 0, sizeof buf);
49     bytes -= sizeof buf;
50     if (bytes > 0)
51         burn_stack (bytes);
52 }
53
54
55 static void
56 do_encrypt_stream( ARCFOUR_context *ctx,
57                 byte *outbuf, const byte *inbuf, unsigned int length )
58 {
59   register int i = ctx->idx_i;
60   register int j = ctx->idx_j;
61   register byte *sbox = ctx->sbox;
62   register int t;  
63
64   while ( length-- )
65     {
66       i++;
67       i = i & 255; /* and seems to be faster than mod */
68       j += sbox[i];
69       j &= 255;
70       t = sbox[i]; sbox[i] = sbox[j]; sbox[j] = t;
71       *outbuf++ = *inbuf++ ^ sbox[(sbox[i] + sbox[j]) & 255];
72     }
73   
74   ctx->idx_i = i;
75   ctx->idx_j = j;
76 }
77
78 static void
79 encrypt_stream( ARCFOUR_context *ctx,
80                 byte *outbuf, const byte *inbuf, unsigned int length )
81 {
82
83     do_encrypt_stream (ctx, outbuf, inbuf, length );
84     burn_stack (64);
85 }
86
87
88 static int
89 do_arcfour_setkey( ARCFOUR_context *ctx, const byte *key, unsigned int keylen )
90 {
91     static int initialized;
92     static const char* selftest_failed;
93     int i, j;
94     byte karr[256];
95
96     if( !initialized ) {
97         initialized = 1;
98         selftest_failed = selftest();
99         if( selftest_failed )
100             log_error ("ARCFOUR selftest failed (%s)\n", selftest_failed );
101     }
102     if( selftest_failed )
103         return GCRYERR_SELFTEST;
104
105     if( keylen < 40/8 ) /* we want at least 40 bits */
106         return GCRYERR_INV_KEYLEN; 
107
108     ctx->idx_i = ctx->idx_j = 0;
109     for (i=0; i < 256; i++ )
110         ctx->sbox[i] = i;
111     for (i=0; i < 256; i++ )
112         karr[i] = key[i%keylen];
113     for (i=j=0; i < 256; i++ ) {
114         int t;
115         j = (j + ctx->sbox[i] + karr[i]) % 256;
116         t = ctx->sbox[i];
117         ctx->sbox[i] = ctx->sbox[j];
118         ctx->sbox[j] = t;
119     } 
120     memset( karr, 0, 256 );
121
122     return 0;
123 }
124
125 static int
126 arcfour_setkey ( ARCFOUR_context *ctx, const byte *key, unsigned int keylen )
127 {
128     int rc = do_arcfour_setkey (ctx, key, keylen );
129     burn_stack (300);
130     return rc;
131 }
132
133
134 static const char*
135 selftest(void)
136 {
137     ARCFOUR_context ctx;
138     byte scratch[16];      
139     
140     /* Test vector from Cryptlib labeled there:
141      * "from the State/Commerce Department" */
142     static const byte key_1[] =
143         { 0x61, 0x8A, 0x63, 0xD2, 0xFB };
144     static const byte plaintext_1[] =
145         { 0xDC, 0xEE, 0x4C, 0xF9, 0x2C };
146     static const byte ciphertext_1[] =
147         { 0xF1, 0x38, 0x29, 0xC9, 0xDE };
148
149     arcfour_setkey( &ctx, key_1, sizeof(key_1));
150     encrypt_stream( &ctx, scratch, plaintext_1, sizeof(plaintext_1));
151     if (memcmp (scratch, ciphertext_1, sizeof (ciphertext_1)))
152         return "Arcfour encryption test 1 failed.";
153     arcfour_setkey( &ctx, key_1, sizeof(key_1));
154     encrypt_stream(&ctx, scratch, scratch, sizeof(plaintext_1)); /* decrypt */
155     if ( memcmp (scratch, plaintext_1, sizeof (plaintext_1)))
156         return "Arcfour decryption test 1 failed.";
157     return NULL;
158 }
159
160
161 /****************
162  * Return some information about the algorithm.  We need algo here to
163  * distinguish different flavors of the algorithm.
164  * Returns: A pointer to string describing the algorithm or NULL if
165  *          the ALGO is invalid.
166  * NOTE: This is a special get_info function which is different from all
167  * others because arcfour is a stream cipher.  We use this hack until
168  * we have redesign the interface.
169  */
170 const char *
171 _gcry_arcfour_get_info( int algo, size_t *keylen, size_t *blocksize,
172                    size_t *contextsize,
173                    int  (**r_setkey)( void *c, byte *key, unsigned keylen ),
174                    void (**r_stencrypt)( void *c, byte *outbuf,
175                                        byte *inbuf, unsigned int nbytes ),
176                    void (**r_stdecrypt)( void *c, byte *outbuf,
177                                        byte *inbuf, unsigned int nbytes )
178                  )
179 {
180     *keylen = 128; /* arbitrary value */
181     *blocksize = 1;
182     *contextsize = sizeof(ARCFOUR_context);
183     *(int  (**)(ARCFOUR_context*, const byte*, unsigned))r_setkey
184                                                         = arcfour_setkey;
185     *(void (**)(ARCFOUR_context*, byte*, const byte*, unsigned))r_stencrypt
186                                                         = encrypt_stream;
187     *(void (**)(ARCFOUR_context*, byte*, const byte*, unsigned))r_stdecrypt
188                                                         = encrypt_stream;
189
190
191     if( algo == 301 )
192         return "ARCFOUR";
193     return NULL;
194 }