• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
2  *
3  * LibTomCrypt is a library that provides various cryptographic
4  * algorithms in a highly modular and flexible manner.
5  *
6  * The library is free for all purposes without any express
7  * guarantee it works.
8  *
9  * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
10  */
11 #include "tomcrypt.h"
12 
13 /**
14   @file rc4.c
15   RC4 PRNG, Tom St Denis
16 */
17 
18 #ifdef RC4
19 
20 const struct ltc_prng_descriptor rc4_desc =
21 {
22    "rc4", 32,
23     &rc4_start,
24     &rc4_add_entropy,
25     &rc4_ready,
26     &rc4_read,
27     &rc4_done,
28     &rc4_export,
29     &rc4_import,
30     &rc4_test
31 };
32 
33 /**
34   Start the PRNG
35   @param prng     [out] The PRNG state to initialize
36   @return CRYPT_OK if successful
37 */
rc4_start(prng_state * prng)38 int rc4_start(prng_state *prng)
39 {
40     LTC_ARGCHK(prng != NULL);
41 
42     /* set keysize to zero */
43     prng->rc4.x = 0;
44 
45     return CRYPT_OK;
46 }
47 
48 /**
49   Add entropy to the PRNG state
50   @param in       The data to add
51   @param inlen    Length of the data to add
52   @param prng     PRNG state to update
53   @return CRYPT_OK if successful
54 */
rc4_add_entropy(const unsigned char * in,unsigned long inlen,prng_state * prng)55 int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng)
56 {
57     LTC_ARGCHK(in  != NULL);
58     LTC_ARGCHK(prng != NULL);
59 
60     /* trim as required */
61     if (prng->rc4.x + inlen > 256) {
62        if (prng->rc4.x == 256) {
63           /* I can't possibly accept another byte, ok maybe a mint wafer... */
64           return CRYPT_OK;
65        } else {
66           /* only accept part of it */
67           inlen = 256 - prng->rc4.x;
68        }
69     }
70 
71     while (inlen--) {
72        prng->rc4.buf[prng->rc4.x++] = *in++;
73     }
74 
75     return CRYPT_OK;
76 
77 }
78 
79 /**
80   Make the PRNG ready to read from
81   @param prng   The PRNG to make active
82   @return CRYPT_OK if successful
83 */
rc4_ready(prng_state * prng)84 int rc4_ready(prng_state *prng)
85 {
86     unsigned char key[256], tmp, *s;
87     int keylen, x, y, j;
88 
89     LTC_ARGCHK(prng != NULL);
90 
91     /* extract the key */
92     s = prng->rc4.buf;
93     XMEMCPY(key, s, 256);
94     keylen = prng->rc4.x;
95 
96     /* make RC4 perm and shuffle */
97     for (x = 0; x < 256; x++) {
98         s[x] = x;
99     }
100 
101     for (j = x = y = 0; x < 256; x++) {
102         y = (y + prng->rc4.buf[x] + key[j++]) & 255;
103         if (j == keylen) {
104            j = 0;
105         }
106         tmp = s[x]; s[x] = s[y]; s[y] = tmp;
107     }
108     prng->rc4.x = 0;
109     prng->rc4.y = 0;
110 
111 #ifdef LTC_CLEAN_STACK
112     zeromem(key, sizeof(key));
113 #endif
114 
115     return CRYPT_OK;
116 }
117 
118 /**
119   Read from the PRNG
120   @param out      Destination
121   @param outlen   Length of output
122   @param prng     The active PRNG to read from
123   @return Number of octets read
124 */
rc4_read(unsigned char * out,unsigned long outlen,prng_state * prng)125 unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng)
126 {
127    unsigned char x, y, *s, tmp;
128    unsigned long n;
129 
130    LTC_ARGCHK(out != NULL);
131    LTC_ARGCHK(prng != NULL);
132 
133 #ifdef LTC_VALGRIND
134    zeromem(out, outlen);
135 #endif
136 
137    n = outlen;
138    x = prng->rc4.x;
139    y = prng->rc4.y;
140    s = prng->rc4.buf;
141    while (outlen--) {
142       x = (x + 1) & 255;
143       y = (y + s[x]) & 255;
144       tmp = s[x]; s[x] = s[y]; s[y] = tmp;
145       tmp = (s[x] + s[y]) & 255;
146       *out++ ^= s[tmp];
147    }
148    prng->rc4.x = x;
149    prng->rc4.y = y;
150    return n;
151 }
152 
153 /**
154   Terminate the PRNG
155   @param prng   The PRNG to terminate
156   @return CRYPT_OK if successful
157 */
rc4_done(prng_state * prng)158 int rc4_done(prng_state *prng)
159 {
160    LTC_ARGCHK(prng != NULL);
161    return CRYPT_OK;
162 }
163 
164 /**
165   Export the PRNG state
166   @param out       [out] Destination
167   @param outlen    [in/out] Max size and resulting size of the state
168   @param prng      The PRNG to export
169   @return CRYPT_OK if successful
170 */
rc4_export(unsigned char * out,unsigned long * outlen,prng_state * prng)171 int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng)
172 {
173    LTC_ARGCHK(outlen != NULL);
174    LTC_ARGCHK(out    != NULL);
175    LTC_ARGCHK(prng   != NULL);
176 
177    if (*outlen < 32) {
178       *outlen = 32;
179       return CRYPT_BUFFER_OVERFLOW;
180    }
181 
182    if (rc4_read(out, 32, prng) != 32) {
183       return CRYPT_ERROR_READPRNG;
184    }
185    *outlen = 32;
186 
187    return CRYPT_OK;
188 }
189 
190 /**
191   Import a PRNG state
192   @param in       The PRNG state
193   @param inlen    Size of the state
194   @param prng     The PRNG to import
195   @return CRYPT_OK if successful
196 */
rc4_import(const unsigned char * in,unsigned long inlen,prng_state * prng)197 int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng)
198 {
199    int err;
200    LTC_ARGCHK(in   != NULL);
201    LTC_ARGCHK(prng != NULL);
202 
203    if (inlen != 32) {
204       return CRYPT_INVALID_ARG;
205    }
206 
207    if ((err = rc4_start(prng)) != CRYPT_OK) {
208       return err;
209    }
210    return rc4_add_entropy(in, 32, prng);
211 }
212 
213 /**
214   PRNG self-test
215   @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled
216 */
rc4_test(void)217 int rc4_test(void)
218 {
219 #if !defined(LTC_TEST) || defined(LTC_VALGRIND)
220    return CRYPT_NOP;
221 #else
222    static const struct {
223       unsigned char key[8], pt[8], ct[8];
224    } tests[] = {
225 {
226    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
227    { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef },
228    { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 }
229 }
230 };
231    prng_state prng;
232    unsigned char dst[8];
233    int err, x;
234 
235    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
236        if ((err = rc4_start(&prng)) != CRYPT_OK) {
237           return err;
238        }
239        if ((err = rc4_add_entropy(tests[x].key, 8, &prng)) != CRYPT_OK) {
240           return err;
241        }
242        if ((err = rc4_ready(&prng)) != CRYPT_OK) {
243           return err;
244        }
245        XMEMCPY(dst, tests[x].pt, 8);
246        if (rc4_read(dst, 8, &prng) != 8) {
247           return CRYPT_ERROR_READPRNG;
248        }
249        rc4_done(&prng);
250        if (XMEMCMP(dst, tests[x].ct, 8)) {
251 #if 0
252           int y;
253           printf("\n\nRC4 failed, I got:\n");
254           for (y = 0; y < 8; y++) printf("%02x ", dst[y]);
255           printf("\n");
256 #endif
257           return CRYPT_FAIL_TESTVECTOR;
258        }
259    }
260    return CRYPT_OK;
261 #endif
262 }
263 
264 #endif
265 
266 
267 /* $Source: /cvs/libtom/libtomcrypt/src/prngs/rc4.c,v $ */
268 /* $Revision: 1.9 $ */
269 /* $Date: 2006/11/16 00:32:18 $ */
270