3
|
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 "mycrypt.h" |
|
12 |
|
13 #ifdef RC4 |
|
14 |
|
15 const struct _prng_descriptor rc4_desc = |
|
16 { |
143
|
17 "rc4", 32, |
3
|
18 &rc4_start, |
|
19 &rc4_add_entropy, |
|
20 &rc4_ready, |
143
|
21 &rc4_read, |
|
22 &rc4_done, |
|
23 &rc4_export, |
|
24 &rc4_import, |
|
25 &rc4_test |
3
|
26 }; |
|
27 |
|
28 int rc4_start(prng_state *prng) |
|
29 { |
|
30 _ARGCHK(prng != NULL); |
|
31 |
|
32 /* set keysize to zero */ |
|
33 prng->rc4.x = 0; |
|
34 |
|
35 return CRYPT_OK; |
|
36 } |
|
37 |
|
38 int rc4_add_entropy(const unsigned char *buf, unsigned long len, prng_state *prng) |
|
39 { |
143
|
40 _ARGCHK(buf != NULL); |
3
|
41 _ARGCHK(prng != NULL); |
143
|
42 |
|
43 /* trim as required */ |
3
|
44 if (prng->rc4.x + len > 256) { |
143
|
45 if (prng->rc4.x == 256) { |
|
46 /* I can't possibly accept another byte, ok maybe a mint wafer... */ |
|
47 return CRYPT_OK; |
|
48 } else { |
|
49 /* only accept part of it */ |
|
50 len = 256 - prng->rc4.x; |
|
51 } |
3
|
52 } |
|
53 |
|
54 while (len--) { |
|
55 prng->rc4.buf[prng->rc4.x++] = *buf++; |
|
56 } |
|
57 |
|
58 return CRYPT_OK; |
|
59 |
|
60 } |
|
61 |
|
62 int rc4_ready(prng_state *prng) |
|
63 { |
143
|
64 unsigned char key[256], tmp, *s; |
|
65 int keylen, x, y, j; |
3
|
66 |
|
67 _ARGCHK(prng != NULL); |
|
68 |
|
69 /* extract the key */ |
143
|
70 s = prng->rc4.buf; |
|
71 XMEMCPY(key, s, 256); |
3
|
72 keylen = prng->rc4.x; |
|
73 |
|
74 /* make RC4 perm and shuffle */ |
|
75 for (x = 0; x < 256; x++) { |
143
|
76 s[x] = x; |
3
|
77 } |
|
78 |
143
|
79 for (j = x = y = 0; x < 256; x++) { |
|
80 y = (y + prng->rc4.buf[x] + key[j++]) & 255; |
|
81 if (j == keylen) { |
|
82 j = 0; |
|
83 } |
|
84 tmp = s[x]; s[x] = s[y]; s[y] = tmp; |
3
|
85 } |
143
|
86 prng->rc4.x = 0; |
|
87 prng->rc4.y = 0; |
3
|
88 |
|
89 #ifdef CLEAN_STACK |
|
90 zeromem(key, sizeof(key)); |
|
91 #endif |
|
92 |
|
93 return CRYPT_OK; |
|
94 } |
|
95 |
|
96 unsigned long rc4_read(unsigned char *buf, unsigned long len, prng_state *prng) |
|
97 { |
143
|
98 unsigned char x, y, *s, tmp; |
3
|
99 unsigned long n; |
|
100 |
|
101 _ARGCHK(buf != NULL); |
|
102 _ARGCHK(prng != NULL); |
|
103 |
|
104 n = len; |
|
105 x = prng->rc4.x; |
|
106 y = prng->rc4.y; |
|
107 s = prng->rc4.buf; |
|
108 while (len--) { |
|
109 x = (x + 1) & 255; |
|
110 y = (y + s[x]) & 255; |
|
111 tmp = s[x]; s[x] = s[y]; s[y] = tmp; |
|
112 tmp = (s[x] + s[y]) & 255; |
|
113 *buf++ ^= s[tmp]; |
|
114 } |
|
115 prng->rc4.x = x; |
|
116 prng->rc4.y = y; |
|
117 return n; |
|
118 } |
|
119 |
143
|
120 int rc4_done(prng_state *prng) |
|
121 { |
|
122 _ARGCHK(prng != NULL); |
|
123 return CRYPT_OK; |
|
124 } |
|
125 |
|
126 int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng) |
|
127 { |
|
128 _ARGCHK(outlen != NULL); |
|
129 _ARGCHK(out != NULL); |
|
130 _ARGCHK(prng != NULL); |
|
131 |
|
132 if (*outlen < 32) { |
|
133 return CRYPT_BUFFER_OVERFLOW; |
|
134 } |
|
135 |
|
136 if (rc4_read(out, 32, prng) != 32) { |
|
137 return CRYPT_ERROR_READPRNG; |
|
138 } |
|
139 *outlen = 32; |
|
140 |
|
141 return CRYPT_OK; |
|
142 } |
|
143 |
|
144 int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng) |
|
145 { |
|
146 int err; |
|
147 _ARGCHK(in != NULL); |
|
148 _ARGCHK(prng != NULL); |
|
149 |
|
150 if (inlen != 32) { |
|
151 return CRYPT_INVALID_ARG; |
|
152 } |
|
153 |
|
154 if ((err = rc4_start(prng)) != CRYPT_OK) { |
|
155 return err; |
|
156 } |
|
157 return rc4_add_entropy(in, 32, prng); |
|
158 } |
|
159 |
|
160 int rc4_test(void) |
|
161 { |
|
162 #ifndef LTC_TEST |
|
163 return CRYPT_NOP; |
|
164 #else |
|
165 static const struct { |
|
166 unsigned char key[8], pt[8], ct[8]; |
|
167 } tests[] = { |
|
168 { |
|
169 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, |
|
170 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, |
|
171 { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 } |
|
172 } |
|
173 }; |
|
174 prng_state prng; |
|
175 unsigned char dst[8]; |
|
176 int err, x; |
|
177 |
|
178 for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { |
|
179 if ((err = rc4_start(&prng)) != CRYPT_OK) { |
|
180 return err; |
|
181 } |
|
182 if ((err = rc4_add_entropy(tests[x].key, 8, &prng)) != CRYPT_OK) { |
|
183 return err; |
|
184 } |
|
185 if ((err = rc4_ready(&prng)) != CRYPT_OK) { |
|
186 return err; |
|
187 } |
|
188 XMEMCPY(dst, tests[x].pt, 8); |
|
189 if (rc4_read(dst, 8, &prng) != 8) { |
|
190 return CRYPT_ERROR_READPRNG; |
|
191 } |
|
192 rc4_done(&prng); |
|
193 if (memcmp(dst, tests[x].ct, 8)) { |
|
194 #if 0 |
|
195 int y; |
|
196 printf("\n\nRC4 failed, I got:\n"); |
|
197 for (y = 0; y < 8; y++) printf("%02x ", dst[y]); |
|
198 printf("\n"); |
|
199 #endif |
|
200 return CRYPT_FAIL_TESTVECTOR; |
|
201 } |
|
202 } |
|
203 return CRYPT_OK; |
|
204 #endif |
|
205 } |
|
206 |
3
|
207 #endif |
|
208 |