comparison libtomcrypt/src/prngs/rc4.c @ 1471:6dba84798cd5

Update to libtomcrypt 1.18.1, merged with Dropbear changes
author Matt Johnston <matt@ucc.asn.au>
date Fri, 09 Feb 2018 21:44:05 +0800
parents f849a5ca2efc
children
comparison
equal deleted inserted replaced
1470:8bba51a55704 1471:6dba84798cd5
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$ */