Mercurial > dropbear
comparison libtomcrypt/src/prngs/rc4.c @ 285:1b9e69c058d2
propagate from branch 'au.asn.ucc.matt.ltc.dropbear' (head 20dccfc09627970a312d77fb41dc2970b62689c3)
to branch 'au.asn.ucc.matt.dropbear' (head fdf4a7a3b97ae5046139915de7e40399cceb2c01)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 08 Mar 2006 13:23:58 +0000 |
parents | |
children | 0cbe8f6dbf9e |
comparison
equal
deleted
inserted
replaced
281:997e6f7dc01e | 285:1b9e69c058d2 |
---|---|
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.org | |
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 n = outlen; | |
134 x = prng->rc4.x; | |
135 y = prng->rc4.y; | |
136 s = prng->rc4.buf; | |
137 while (outlen--) { | |
138 x = (x + 1) & 255; | |
139 y = (y + s[x]) & 255; | |
140 tmp = s[x]; s[x] = s[y]; s[y] = tmp; | |
141 tmp = (s[x] + s[y]) & 255; | |
142 *out++ ^= s[tmp]; | |
143 } | |
144 prng->rc4.x = x; | |
145 prng->rc4.y = y; | |
146 return n; | |
147 } | |
148 | |
149 /** | |
150 Terminate the PRNG | |
151 @param prng The PRNG to terminate | |
152 @return CRYPT_OK if successful | |
153 */ | |
154 int rc4_done(prng_state *prng) | |
155 { | |
156 LTC_ARGCHK(prng != NULL); | |
157 return CRYPT_OK; | |
158 } | |
159 | |
160 /** | |
161 Export the PRNG state | |
162 @param out [out] Destination | |
163 @param outlen [in/out] Max size and resulting size of the state | |
164 @param prng The PRNG to export | |
165 @return CRYPT_OK if successful | |
166 */ | |
167 int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng) | |
168 { | |
169 LTC_ARGCHK(outlen != NULL); | |
170 LTC_ARGCHK(out != NULL); | |
171 LTC_ARGCHK(prng != NULL); | |
172 | |
173 if (*outlen < 32) { | |
174 return CRYPT_BUFFER_OVERFLOW; | |
175 } | |
176 | |
177 if (rc4_read(out, 32, prng) != 32) { | |
178 return CRYPT_ERROR_READPRNG; | |
179 } | |
180 *outlen = 32; | |
181 | |
182 return CRYPT_OK; | |
183 } | |
184 | |
185 /** | |
186 Import a PRNG state | |
187 @param in The PRNG state | |
188 @param inlen Size of the state | |
189 @param prng The PRNG to import | |
190 @return CRYPT_OK if successful | |
191 */ | |
192 int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng) | |
193 { | |
194 int err; | |
195 LTC_ARGCHK(in != NULL); | |
196 LTC_ARGCHK(prng != NULL); | |
197 | |
198 if (inlen != 32) { | |
199 return CRYPT_INVALID_ARG; | |
200 } | |
201 | |
202 if ((err = rc4_start(prng)) != CRYPT_OK) { | |
203 return err; | |
204 } | |
205 return rc4_add_entropy(in, 32, prng); | |
206 } | |
207 | |
208 /** | |
209 PRNG self-test | |
210 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled | |
211 */ | |
212 int rc4_test(void) | |
213 { | |
214 #ifndef LTC_TEST | |
215 return CRYPT_NOP; | |
216 #else | |
217 static const struct { | |
218 unsigned char key[8], pt[8], ct[8]; | |
219 } tests[] = { | |
220 { | |
221 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, | |
222 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, | |
223 { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 } | |
224 } | |
225 }; | |
226 prng_state prng; | |
227 unsigned char dst[8]; | |
228 int err, x; | |
229 | |
230 for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { | |
231 if ((err = rc4_start(&prng)) != CRYPT_OK) { | |
232 return err; | |
233 } | |
234 if ((err = rc4_add_entropy(tests[x].key, 8, &prng)) != CRYPT_OK) { | |
235 return err; | |
236 } | |
237 if ((err = rc4_ready(&prng)) != CRYPT_OK) { | |
238 return err; | |
239 } | |
240 XMEMCPY(dst, tests[x].pt, 8); | |
241 if (rc4_read(dst, 8, &prng) != 8) { | |
242 return CRYPT_ERROR_READPRNG; | |
243 } | |
244 rc4_done(&prng); | |
245 if (memcmp(dst, tests[x].ct, 8)) { | |
246 #if 0 | |
247 int y; | |
248 printf("\n\nRC4 failed, I got:\n"); | |
249 for (y = 0; y < 8; y++) printf("%02x ", dst[y]); | |
250 printf("\n"); | |
251 #endif | |
252 return CRYPT_FAIL_TESTVECTOR; | |
253 } | |
254 } | |
255 return CRYPT_OK; | |
256 #endif | |
257 } | |
258 | |
259 #endif | |
260 | |
261 | |
262 /* $Source: /cvs/libtom/libtomcrypt/src/prngs/rc4.c,v $ */ | |
263 /* $Revision: 1.3 $ */ | |
264 /* $Date: 2005/05/05 14:35:59 $ */ |