Mercurial > dropbear
comparison libtomcrypt/src/prngs/rc4.c @ 1478:3a933956437e coverity
update coverity
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Fri, 09 Feb 2018 23:49:22 +0800 |
parents | 6dba84798cd5 |
children |
comparison
equal
deleted
inserted
replaced
1439:8d24733026c5 | 1478:3a933956437e |
---|---|
3 * LibTomCrypt is a library that provides various cryptographic | 3 * LibTomCrypt is a library that provides various cryptographic |
4 * algorithms in a highly modular and flexible manner. | 4 * algorithms in a highly modular and flexible manner. |
5 * | 5 * |
6 * The library is free for all purposes without any express | 6 * The library is free for all purposes without any express |
7 * guarantee it works. | 7 * guarantee it works. |
8 * | |
9 * Tom St Denis, [email protected], http://libtom.org | |
10 */ | 8 */ |
11 #include "tomcrypt.h" | 9 #include "tomcrypt.h" |
12 | 10 |
13 /** | 11 /** |
14 @file rc4.c | 12 @file prngs/rc4.c |
15 LTC_RC4 PRNG, Tom St Denis | 13 RC4 PRNG, Tom St Denis |
16 */ | 14 */ |
17 | 15 |
18 #ifdef LTC_RC4 | 16 #ifdef LTC_RC4 |
19 | 17 |
20 const struct ltc_prng_descriptor rc4_desc = | 18 const struct ltc_prng_descriptor rc4_desc = |
21 { | 19 { |
22 "rc4", 32, | 20 "rc4", |
23 &rc4_start, | 21 32, |
24 &rc4_add_entropy, | 22 &rc4_start, |
25 &rc4_ready, | 23 &rc4_add_entropy, |
26 &rc4_read, | 24 &rc4_ready, |
27 &rc4_done, | 25 &rc4_read, |
28 &rc4_export, | 26 &rc4_done, |
29 &rc4_import, | 27 &rc4_export, |
30 &rc4_test | 28 &rc4_import, |
29 &rc4_test | |
31 }; | 30 }; |
32 | 31 |
33 /** | 32 /** |
34 Start the PRNG | 33 Start the PRNG |
35 @param prng [out] The PRNG state to initialize | 34 @param prng [out] The PRNG state to initialize |
36 @return CRYPT_OK if successful | 35 @return CRYPT_OK if successful |
37 */ | 36 */ |
38 int rc4_start(prng_state *prng) | 37 int rc4_start(prng_state *prng) |
39 { | 38 { |
40 LTC_ARGCHK(prng != NULL); | 39 LTC_ARGCHK(prng != NULL); |
41 | 40 prng->ready = 0; |
42 /* set keysize to zero */ | 41 /* set entropy (key) size to zero */ |
43 prng->rc4.x = 0; | 42 prng->rc4.s.x = 0; |
44 | 43 /* clear entropy (key) buffer */ |
45 return CRYPT_OK; | 44 XMEMSET(&prng->rc4.s.buf, 0, sizeof(prng->rc4.s.buf)); |
45 LTC_MUTEX_INIT(&prng->lock) | |
46 return CRYPT_OK; | |
46 } | 47 } |
47 | 48 |
48 /** | 49 /** |
49 Add entropy to the PRNG state | 50 Add entropy to the PRNG state |
50 @param in The data to add | 51 @param in The data to add |
51 @param inlen Length of the data to add | 52 @param inlen Length of the data to add |
52 @param prng PRNG state to update | 53 @param prng PRNG state to update |
53 @return CRYPT_OK if successful | 54 @return CRYPT_OK if successful |
54 */ | 55 */ |
55 int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) | 56 int rc4_add_entropy(const unsigned char *in, unsigned long inlen, prng_state *prng) |
56 { | 57 { |
57 LTC_ARGCHK(in != NULL); | 58 unsigned char buf[256]; |
58 LTC_ARGCHK(prng != NULL); | 59 unsigned long i; |
59 | 60 int err; |
60 /* trim as required */ | 61 |
61 if (prng->rc4.x + inlen > 256) { | 62 LTC_ARGCHK(prng != NULL); |
62 if (prng->rc4.x == 256) { | 63 LTC_ARGCHK(in != NULL); |
63 /* I can't possibly accept another byte, ok maybe a mint wafer... */ | 64 LTC_ARGCHK(inlen > 0); |
64 return CRYPT_OK; | 65 |
65 } else { | 66 LTC_MUTEX_LOCK(&prng->lock); |
66 /* only accept part of it */ | 67 if (prng->ready) { |
67 inlen = 256 - prng->rc4.x; | 68 /* rc4_ready() was already called, do "rekey" operation */ |
68 } | 69 if ((err = rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK; |
69 } | 70 for(i = 0; i < inlen; i++) buf[i % sizeof(buf)] ^= in[i]; |
70 | 71 /* initialize RC4 */ |
71 while (inlen--) { | 72 if ((err = rc4_stream_setup(&prng->rc4.s, buf, sizeof(buf))) != CRYPT_OK) goto LBL_UNLOCK; |
72 prng->rc4.buf[prng->rc4.x++] = *in++; | 73 /* drop first 3072 bytes - https://en.wikipedia.org/wiki/RC4#Fluhrer.2C_Mantin_and_Shamir_attack */ |
73 } | 74 for (i = 0; i < 12; i++) rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf)); |
74 | 75 zeromem(buf, sizeof(buf)); |
75 return CRYPT_OK; | 76 } |
76 | 77 else { |
78 /* rc4_ready() was not called yet, add entropy to the buffer */ | |
79 while (inlen--) prng->rc4.s.buf[prng->rc4.s.x++ % sizeof(prng->rc4.s.buf)] ^= *in++; | |
80 } | |
81 err = CRYPT_OK; | |
82 LBL_UNLOCK: | |
83 LTC_MUTEX_UNLOCK(&prng->lock); | |
84 return err; | |
77 } | 85 } |
78 | 86 |
79 /** | 87 /** |
80 Make the PRNG ready to read from | 88 Make the PRNG ready to read from |
81 @param prng The PRNG to make active | 89 @param prng The PRNG to make active |
82 @return CRYPT_OK if successful | 90 @return CRYPT_OK if successful |
83 */ | 91 */ |
84 int rc4_ready(prng_state *prng) | 92 int rc4_ready(prng_state *prng) |
85 { | 93 { |
86 unsigned char key[256], tmp, *s; | 94 unsigned char buf[256] = { 0 }; |
87 int keylen, x, y, j; | 95 unsigned long len; |
88 | 96 int err, i; |
89 LTC_ARGCHK(prng != NULL); | 97 |
90 | 98 LTC_ARGCHK(prng != NULL); |
91 /* extract the key */ | 99 |
92 s = prng->rc4.buf; | 100 LTC_MUTEX_LOCK(&prng->lock); |
93 XMEMCPY(key, s, 256); | 101 if (prng->ready) { err = CRYPT_OK; goto LBL_UNLOCK; } |
94 keylen = prng->rc4.x; | 102 XMEMCPY(buf, prng->rc4.s.buf, sizeof(buf)); |
95 | 103 /* initialize RC4 */ |
96 /* make LTC_RC4 perm and shuffle */ | 104 len = MIN(prng->rc4.s.x, 256); /* TODO: we can perhaps always use all 256 bytes */ |
97 for (x = 0; x < 256; x++) { | 105 if ((err = rc4_stream_setup(&prng->rc4.s, buf, len)) != CRYPT_OK) goto LBL_UNLOCK; |
98 s[x] = x; | 106 /* drop first 3072 bytes - https://en.wikipedia.org/wiki/RC4#Fluhrer.2C_Mantin_and_Shamir_attack */ |
99 } | 107 for (i = 0; i < 12; i++) rc4_stream_keystream(&prng->rc4.s, buf, sizeof(buf)); |
100 | 108 prng->ready = 1; |
101 for (j = x = y = 0; x < 256; x++) { | 109 LBL_UNLOCK: |
102 y = (y + prng->rc4.buf[x] + key[j++]) & 255; | 110 LTC_MUTEX_UNLOCK(&prng->lock); |
103 if (j == keylen) { | 111 return err; |
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 } | 112 } |
117 | 113 |
118 /** | 114 /** |
119 Read from the PRNG | 115 Read from the PRNG |
120 @param out Destination | 116 @param out Destination |
121 @param outlen Length of output | 117 @param outlen Length of output |
122 @param prng The active PRNG to read from | 118 @param prng The active PRNG to read from |
123 @return Number of octets read | 119 @return Number of octets read |
124 */ | 120 */ |
125 unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng) | 121 unsigned long rc4_read(unsigned char *out, unsigned long outlen, prng_state *prng) |
126 { | 122 { |
127 unsigned char x, y, *s, tmp; | 123 if (outlen == 0 || prng == NULL || out == NULL) return 0; |
128 unsigned long n; | 124 LTC_MUTEX_LOCK(&prng->lock); |
129 | 125 if (!prng->ready) { outlen = 0; goto LBL_UNLOCK; } |
130 LTC_ARGCHK(out != NULL); | 126 if (rc4_stream_keystream(&prng->rc4.s, out, outlen) != CRYPT_OK) outlen = 0; |
131 LTC_ARGCHK(prng != NULL); | 127 LBL_UNLOCK: |
132 | 128 LTC_MUTEX_UNLOCK(&prng->lock); |
133 #ifdef LTC_VALGRIND | 129 return outlen; |
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 } | 130 } |
152 | 131 |
153 /** | 132 /** |
154 Terminate the PRNG | 133 Terminate the PRNG |
155 @param prng The PRNG to terminate | 134 @param prng The PRNG to terminate |
156 @return CRYPT_OK if successful | 135 @return CRYPT_OK if successful |
157 */ | 136 */ |
158 int rc4_done(prng_state *prng) | 137 int rc4_done(prng_state *prng) |
159 { | 138 { |
160 LTC_ARGCHK(prng != NULL); | 139 int err; |
161 return CRYPT_OK; | 140 LTC_ARGCHK(prng != NULL); |
141 LTC_MUTEX_LOCK(&prng->lock); | |
142 prng->ready = 0; | |
143 err = rc4_stream_done(&prng->rc4.s); | |
144 LTC_MUTEX_UNLOCK(&prng->lock); | |
145 LTC_MUTEX_DESTROY(&prng->lock); | |
146 return err; | |
162 } | 147 } |
163 | 148 |
164 /** | 149 /** |
165 Export the PRNG state | 150 Export the PRNG state |
166 @param out [out] Destination | 151 @param out [out] Destination |
167 @param outlen [in/out] Max size and resulting size of the state | 152 @param outlen [in/out] Max size and resulting size of the state |
168 @param prng The PRNG to export | 153 @param prng The PRNG to export |
169 @return CRYPT_OK if successful | 154 @return CRYPT_OK if successful |
170 */ | 155 */ |
171 int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng) | 156 int rc4_export(unsigned char *out, unsigned long *outlen, prng_state *prng) |
172 { | 157 { |
158 unsigned long len = rc4_desc.export_size; | |
159 | |
160 LTC_ARGCHK(prng != NULL); | |
161 LTC_ARGCHK(out != NULL); | |
173 LTC_ARGCHK(outlen != NULL); | 162 LTC_ARGCHK(outlen != NULL); |
174 LTC_ARGCHK(out != NULL); | 163 |
175 LTC_ARGCHK(prng != NULL); | 164 if (*outlen < len) { |
176 | 165 *outlen = len; |
177 if (*outlen < 32) { | |
178 *outlen = 32; | |
179 return CRYPT_BUFFER_OVERFLOW; | 166 return CRYPT_BUFFER_OVERFLOW; |
180 } | 167 } |
181 | 168 |
182 if (rc4_read(out, 32, prng) != 32) { | 169 if (rc4_read(out, len, prng) != len) { |
183 return CRYPT_ERROR_READPRNG; | 170 return CRYPT_ERROR_READPRNG; |
184 } | 171 } |
185 *outlen = 32; | 172 |
186 | 173 *outlen = len; |
187 return CRYPT_OK; | 174 return CRYPT_OK; |
188 } | 175 } |
189 | 176 |
190 /** | 177 /** |
191 Import a PRNG state | 178 Import a PRNG state |
192 @param in The PRNG state | 179 @param in The PRNG state |
193 @param inlen Size of the state | 180 @param inlen Size of the state |
194 @param prng The PRNG to import | 181 @param prng The PRNG to import |
195 @return CRYPT_OK if successful | 182 @return CRYPT_OK if successful |
196 */ | 183 */ |
197 int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng) | 184 int rc4_import(const unsigned char *in, unsigned long inlen, prng_state *prng) |
198 { | 185 { |
199 int err; | 186 int err; |
187 | |
188 LTC_ARGCHK(prng != NULL); | |
200 LTC_ARGCHK(in != NULL); | 189 LTC_ARGCHK(in != NULL); |
201 LTC_ARGCHK(prng != NULL); | 190 if (inlen < (unsigned long)rc4_desc.export_size) return CRYPT_INVALID_ARG; |
202 | 191 |
203 if (inlen != 32) { | 192 if ((err = rc4_start(prng)) != CRYPT_OK) return err; |
204 return CRYPT_INVALID_ARG; | 193 if ((err = rc4_add_entropy(in, inlen, prng)) != CRYPT_OK) return err; |
205 } | 194 return CRYPT_OK; |
206 | |
207 if ((err = rc4_start(prng)) != CRYPT_OK) { | |
208 return err; | |
209 } | |
210 return rc4_add_entropy(in, 32, prng); | |
211 } | 195 } |
212 | 196 |
213 /** | 197 /** |
214 PRNG self-test | 198 PRNG self-test |
215 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled | 199 @return CRYPT_OK if successful, CRYPT_NOP if self-testing has been disabled |
216 */ | 200 */ |
217 int rc4_test(void) | 201 int rc4_test(void) |
218 { | 202 { |
219 #if !defined(LTC_TEST) || defined(LTC_VALGRIND) | 203 #ifndef LTC_TEST |
220 return CRYPT_NOP; | 204 return CRYPT_NOP; |
221 #else | 205 #else |
222 static const struct { | 206 prng_state st; |
223 unsigned char key[8], pt[8], ct[8]; | 207 unsigned char en[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, |
224 } tests[] = { | 208 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, |
225 { | 209 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, |
226 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, | 210 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, |
227 { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef }, | 211 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32 }; |
228 { 0x75, 0xb7, 0x87, 0x80, 0x99, 0xe0, 0xc5, 0x96 } | 212 unsigned char dmp[500]; |
229 } | 213 unsigned long dmplen = sizeof(dmp); |
230 }; | 214 unsigned char out[1000]; |
231 prng_state prng; | 215 unsigned char t1[] = { 0xE0, 0x4D, 0x9A, 0xF6, 0xA8, 0x9D, 0x77, 0x53, 0xAE, 0x09 }; |
232 unsigned char dst[8]; | 216 unsigned char t2[] = { 0xEF, 0x80, 0xA2, 0xE6, 0x50, 0x91, 0xF3, 0x17, 0x4A, 0x8A }; |
233 int err, x; | 217 unsigned char t3[] = { 0x4B, 0xD6, 0x5C, 0x67, 0x99, 0x03, 0x56, 0x12, 0x80, 0x48 }; |
234 | 218 int err; |
235 for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) { | 219 |
236 if ((err = rc4_start(&prng)) != CRYPT_OK) { | 220 if ((err = rc4_start(&st)) != CRYPT_OK) return err; |
237 return err; | 221 /* add entropy to uninitialized prng */ |
238 } | 222 if ((err = rc4_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; |
239 if ((err = rc4_add_entropy(tests[x].key, 8, &prng)) != CRYPT_OK) { | 223 if ((err = rc4_ready(&st)) != CRYPT_OK) return err; |
240 return err; | 224 if (rc4_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ |
241 } | 225 if (compare_testvector(out, 10, t1, sizeof(t1), "RC4-PRNG", 1)) return CRYPT_FAIL_TESTVECTOR; |
242 if ((err = rc4_ready(&prng)) != CRYPT_OK) { | 226 if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ |
243 return err; | 227 /* add entropy to already initialized prng */ |
244 } | 228 if ((err = rc4_add_entropy(en, sizeof(en), &st)) != CRYPT_OK) return err; |
245 XMEMCPY(dst, tests[x].pt, 8); | 229 if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ |
246 if (rc4_read(dst, 8, &prng) != 8) { | 230 if ((err = rc4_export(dmp, &dmplen, &st)) != CRYPT_OK) return err; |
247 return CRYPT_ERROR_READPRNG; | 231 if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ |
248 } | 232 if (rc4_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ |
249 rc4_done(&prng); | 233 if (compare_testvector(out, 10, t2, sizeof(t2), "RC4-PRNG", 2)) return CRYPT_FAIL_TESTVECTOR; |
250 if (XMEMCMP(dst, tests[x].ct, 8)) { | 234 if ((err = rc4_done(&st)) != CRYPT_OK) return err; |
251 #if 0 | 235 if ((err = rc4_import(dmp, dmplen, &st)) != CRYPT_OK) return err; |
252 int y; | 236 if ((err = rc4_ready(&st)) != CRYPT_OK) return err; |
253 printf("\n\nLTC_RC4 failed, I got:\n"); | 237 if (rc4_read(out, 500, &st) != 500) return CRYPT_ERROR_READPRNG; /* skip 500 bytes */ |
254 for (y = 0; y < 8; y++) printf("%02x ", dst[y]); | 238 if (rc4_read(out, 10, &st) != 10) return CRYPT_ERROR_READPRNG; /* 10 bytes for testing */ |
255 printf("\n"); | 239 if (compare_testvector(out, 10, t3, sizeof(t3), "RC4-PRNG", 3)) return CRYPT_FAIL_TESTVECTOR; |
240 if ((err = rc4_done(&st)) != CRYPT_OK) return err; | |
241 | |
242 return CRYPT_OK; | |
256 #endif | 243 #endif |
257 return CRYPT_FAIL_TESTVECTOR; | 244 } |
258 } | 245 |
259 } | |
260 return CRYPT_OK; | |
261 #endif | 246 #endif |
262 } | 247 |
263 | 248 /* ref: $Format:%D$ */ |
264 #endif | 249 /* git commit: $Format:%H$ */ |
265 | 250 /* commit time: $Format:%ai$ */ |
266 | |
267 /* $Source$ */ | |
268 /* $Revision$ */ | |
269 /* $Date$ */ |