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