comparison src/prngs/rc4.c @ 191:1c15b283127b libtomcrypt-orig

Import of libtomcrypt 1.02 with manual path rename rearrangement etc
author Matt Johnston <matt@ucc.asn.au>
date Fri, 06 May 2005 13:23:02 +0000
parents
children 39d5d58461d6
comparison
equal deleted inserted replaced
143:5d99163f7e32 191:1c15b283127b
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