Mercurial > dropbear
comparison libtomcrypt/src/prngs/rc4.c @ 399:a707e6148060
merge of '5fdf69ca60d1683cdd9f4c2595134bed26394834'
and '6b61c50f4cf888bea302ac8fcf5dbb573b443251'
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 03 Feb 2007 08:20:34 +0000 |
parents | 0cbe8f6dbf9e |
children | f849a5ca2efc |
comparison
equal
deleted
inserted
replaced
394:17d097fc111c | 399:a707e6148060 |
---|---|
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, [email protected], 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 */ | |
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 */ | |
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 */ | |
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 */ | |
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 */ | |
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 */ | |
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 */ | |
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 */ | |
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 $ */ |