]> git.ipfire.org Git - people/ms/strongswan.git/blame - scripts/timeattack.c
traffic-selector: Avoid out-of-bound array access when calculating range
[people/ms/strongswan.git] / scripts / timeattack.c
CommitLineData
39e1ddec
MW
1#include <stdio.h>
2#include <time.h>
3
4#include <library.h>
5
6typedef bool (*attackfn_t)(void *subj, u_char *data, size_t len);
7
8static void start_timing(struct timespec *start)
9{
10 clock_gettime(CLOCK_PROCESS_CPUTIME_ID, start);
11}
12
b12c53ce 13static uint64_t end_timing(struct timespec *start)
39e1ddec
MW
14{
15 struct timespec end;
16
17 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
18 return (end.tv_nsec - start->tv_nsec) +
19 (end.tv_sec - start->tv_sec) * 1000000000;
20}
21
22static int intcmp(const void *a, const void *b)
23{
b12c53ce 24 return *(uint64_t*)a - *(uint64_t*)b;
39e1ddec
MW
25}
26
b12c53ce 27static uint64_t median(uint64_t *m, int count)
39e1ddec 28{
b12c53ce 29 qsort(m, count, sizeof(uint64_t), intcmp);
39e1ddec
MW
30 return m[count / 2];
31}
32
33static bool timeattack(attackfn_t attackfn, void *subj, size_t dlen,
34 u_int iterations, u_int distance)
35{
36 struct timespec start;
37 u_char test[dlen];
b12c53ce 38 uint64_t mini, maxi, t[256], m[256][10];
39e1ddec
MW
39 float fastdist = 0, slowdist = 0;
40 int i, j, k, l, byte, limit, retry = 0;
41 int fastest = 0, slowest = 0;
42
43 memset(test, 0, dlen);
44
45 /* do some iterations to fill caches */
46 for (i = 0; i < iterations; i++)
47 {
48 attackfn(subj, test, dlen);
49 }
50
51 for (byte = 0; byte < dlen;)
52 {
53 memset(t, 0, sizeof(t));
54 memset(m, 0, sizeof(m));
55
56 limit = iterations * (retry + 1);
57
58 /* measure timing for all patterns in next byte */
59 for (k = 0; k < 10; k++)
60 {
61 for (j = 0; j < 256; j++)
62 {
63 for (l = 0; l < 100; l++)
64 {
65 test[byte] = j;
66 start_timing(&start);
67 for (i = 0; i < limit; i++)
68 {
69 attackfn(subj, test, dlen);
70 }
71 m[j][k] += end_timing(&start);
72 }
73 }
74 }
75
76 for (j = 0; j < 256; j++)
77 {
78 t[j] = median(m[j], countof(m[j]));
79 }
80
81 /* find fastest/slowest runs */
82 mini = ~0;
83 maxi = 0;
84 for (j = 0; j < 256; j++)
85 {
86 if (t[j] < mini)
87 {
88 mini = min(t[j], mini);
89 fastest = j;
90 }
91 if (t[j] > maxi)
92 {
93 maxi = max(t[j], maxi);
94 slowest = j;
95 }
96 }
97 /* calculate distance to next result */
98 mini = ~0;
99 maxi = 0;
100 for (j = 0; j < 256; j++)
101 {
102 if (fastest != j && t[j] < mini)
103 {
104 mini = min(t[j], mini);
105 fastdist = (float)(t[j] - t[fastest]) / distance;
106 }
107 if (slowest != j && t[j] > maxi)
108 {
109 maxi = max(t[j], maxi);
110 slowdist = (float)(t[slowest] - t[j]) / distance;
111 }
112 }
113 if (fastdist > 1.0f)
114 {
115 fprintf(stderr, "byte %02d: %02x (fastest, dist %02.2f)\n",
116 byte, fastest, fastdist);
117 test[byte] = fastest;
118 retry = 0;
119 byte++;
120 }
121 else if (slowdist > 1.0f)
122 {
123 fprintf(stderr, "byte %02d: %02x (slowest, dist %02.2f)\n",
124 byte, slowest, slowdist);
125 test[byte] = slowest;
126 retry = 0;
127 byte++;
128 }
129 else
130 {
131 if (retry++ > 5 && byte > 0)
132 {
133 fprintf(stderr, "distance fastest %02.2f (%02x), "
134 "slowest %02.2f (%02x), stepping back\n",
135 fastdist, fastest, slowdist, slowest);
136 test[byte--] = 0;
137 }
138 else if (retry < 10)
139 {
140 fprintf(stderr, "distance fastest %02.2f (%02x), "
141 "slowest %02.2f (%02x), retrying (%d)\n",
142 fastdist, fastest, slowdist, slowest, retry);
143 }
144 else
145 {
146 printf("attack failed, giving up\n");
147 return FALSE;
148 }
149 }
150 }
151 if (attackfn(subj, test, dlen))
152 {
153 printf("attack successful with %b\n", test, dlen);
154 return TRUE;
155 }
156 printf("attack failed with %b\n", test, dlen);
157 return FALSE;
158}
159
160CALLBACK(attack_memeq1, bool,
161 u_char *subj, u_char *data, size_t len)
162{
163 return memeq(data, subj, len);
164}
165
166CALLBACK(attack_memeq2, bool,
167 u_char *subj, u_char *data, size_t len)
168{
169 return memeq(subj, data, len);
170}
171
172CALLBACK(attack_memeq3, bool,
173 u_char *subj, u_char *data, size_t len)
174{
175 int i;
176
177 for (i = 0; i < len; i++)
178 {
179 if (subj[i] != data[i])
180 {
181 return FALSE;
182 }
183 }
184 return TRUE;
185}
186
187CALLBACK(attack_memeq4, bool,
188 u_char *subj, u_char *data, size_t len)
189{
190 int i, m = 0;
191
192 for (i = 0; i < len; i++)
193 {
194 m |= subj[i] != data[i];
195 }
196 return !m;
197}
198
b8339632
MW
199CALLBACK(attack_memeq5, bool,
200 u_char *subj, u_char *data, size_t len)
201{
202 return memeq_const(subj, data, len);
203}
204
39e1ddec
MW
205static bool attack_memeq(char *name, u_int iterations, u_int distance)
206{
207 struct {
208 char *name;
209 attackfn_t fn;
210 } attacks[] = {
211 { "memeq1", attack_memeq1 },
212 { "memeq2", attack_memeq2 },
213 { "memeq3", attack_memeq3 },
214 { "memeq4", attack_memeq4 },
b8339632 215 { "memeq5", attack_memeq5 },
39e1ddec
MW
216 };
217 u_char exp[16];
218 int i;
219
220 srandom(time(NULL));
221 for (i = 0; i < sizeof(exp); i++)
222 {
223 exp[i] = random();
224 }
225 fprintf(stderr, "attacking %b\n", exp, sizeof(exp));
226
227 for (i = 0; i < countof(attacks); i++)
228 {
229 if (streq(name, attacks[i].name))
230 {
231 return timeattack(attacks[i].fn, exp, sizeof(exp),
232 iterations, distance);
233 }
234 }
235 return FALSE;
236}
237
9d6e9522
MW
238CALLBACK(attack_chunk1, bool,
239 u_char *subj, u_char *data, size_t len)
240{
241 return chunk_equals(chunk_create(subj, len), chunk_create(data, len));
242}
243
244CALLBACK(attack_chunk2, bool,
245 u_char *subj, u_char *data, size_t len)
246{
247 return chunk_equals_const(chunk_create(subj, len), chunk_create(data, len));
248}
249
250static bool attack_chunk(char *name, u_int iterations, u_int distance)
251{
252 struct {
253 char *name;
254 attackfn_t fn;
255 } attacks[] = {
256 { "chunk1", attack_chunk1 },
257 { "chunk2", attack_chunk2 },
258 };
259 u_char exp[16];
260 int i;
261
262 srandom(time(NULL));
263 for (i = 0; i < sizeof(exp); i++)
264 {
265 exp[i] = random();
266 }
267 fprintf(stderr, "attacking %b\n", exp, sizeof(exp));
268
269 for (i = 0; i < countof(attacks); i++)
270 {
271 if (streq(name, attacks[i].name))
272 {
273 return timeattack(attacks[i].fn, exp, sizeof(exp),
274 iterations, distance);
275 }
276 }
277 return FALSE;
278}
279
39e1ddec
MW
280CALLBACK(attack_aead, bool,
281 aead_t *aead, u_char *data, size_t len)
282{
283 u_char iv[aead->get_iv_size(aead)];
284
285 memset(iv, 0, sizeof(iv));
286 return aead->decrypt(aead, chunk_create(data, len), chunk_empty,
287 chunk_from_thing(iv), NULL);
288}
289
290static bool attack_aeads(encryption_algorithm_t alg, size_t key_size,
291 u_int iterations, u_int distance)
292{
293 u_char buf[64];
294 aead_t *aead;
295 bool res;
296
297 aead = lib->crypto->create_aead(lib->crypto, alg, key_size, 0);
298 if (!aead)
299 {
300 fprintf(stderr, "creating AEAD %N failed\n",
301 encryption_algorithm_names, alg);
302 return FALSE;
303 }
304 memset(buf, 0xe3, sizeof(buf));
305 if (!aead->set_key(aead, chunk_create(buf, aead->get_key_size(aead))))
306 {
307 aead->destroy(aead);
308 return FALSE;
309 }
310 memset(buf, 0, aead->get_iv_size(aead));
311 if (!aead->encrypt(aead, chunk_create(buf, 0), chunk_empty,
312 chunk_create(buf, aead->get_iv_size(aead)), NULL))
313 {
314 aead->destroy(aead);
315 return FALSE;
316 }
317 fprintf(stderr, "attacking %b\n", buf, aead->get_icv_size(aead));
318
319 res = timeattack(attack_aead, aead, aead->get_icv_size(aead),
320 iterations, distance);
321 aead->destroy(aead);
322 return res;
323}
324
325CALLBACK(attack_signer, bool,
326 signer_t *signer, u_char *data, size_t len)
327{
328 return signer->verify_signature(signer, chunk_empty, chunk_create(data, len));
329}
330
331static bool attack_signers(integrity_algorithm_t alg,
332 u_int iterations, u_int distance)
333{
334 u_char buf[64];
335 signer_t *signer;
336 bool res;
337
338 signer = lib->crypto->create_signer(lib->crypto, alg);
339 if (!signer)
340 {
341 fprintf(stderr, "creating signer %N failed\n",
342 integrity_algorithm_names, alg);
343 return FALSE;
344 }
345 memset(buf, 0xe3, sizeof(buf));
346 if (!signer->set_key(signer, chunk_create(buf, signer->get_key_size(signer))))
347 {
348 signer->destroy(signer);
349 return FALSE;
350 }
351 if (!signer->get_signature(signer, chunk_empty, buf))
352 {
353 signer->destroy(signer);
354 return FALSE;
355 }
356 fprintf(stderr, "attacking %b\n", buf, signer->get_block_size(signer));
357
358 res = timeattack(attack_signer, signer, signer->get_block_size(signer),
359 iterations, distance);
360 signer->destroy(signer);
361 return res;
362}
363
364static bool attack_transform(char *name, u_int iterations, u_int distance)
365{
366 const proposal_token_t *token;
367
368 token = lib->proposal->get_token(lib->proposal, name);
369 if (!token)
370 {
371 fprintf(stderr, "algorithm '%s' unknown\n", name);
372 return FALSE;
373 }
374
375 switch (token->type)
376 {
377 case ENCRYPTION_ALGORITHM:
378 if (encryption_algorithm_is_aead(token->algorithm))
379 {
380 return attack_aeads(token->algorithm, token->keysize / 8,
381 iterations, distance);
382 }
383 fprintf(stderr, "can't attack a crypter\n");
384 return FALSE;
385 case INTEGRITY_ALGORITHM:
386 return attack_signers(token->algorithm, iterations, distance);
387 default:
388 fprintf(stderr, "can't attack a %N\n", transform_type_names, token->type);
389 return FALSE;
390 }
391}
392
393int main(int argc, char *argv[])
394{
395 library_init(NULL, "timeattack");
396 atexit(library_deinit);
397 lib->plugins->load(lib->plugins, getenv("PLUGINS") ?: PLUGINS);
398
399 if (argc < 3)
400 {
401 fprintf(stderr, "usage: %s <attack> <iterations> <distance>\n", argv[0]);
9d6e9522 402 fprintf(stderr, " <attack>: memeq[1-5] / chunk[1-2] / aead / signer\n");
39e1ddec
MW
403 fprintf(stderr, " <iterations>: number of invocations * 1000\n");
404 fprintf(stderr, " <distance>: time difference in ns for a hit\n");
405 fprintf(stderr, " example: %s memeq1 100 500\n", argv[0]);
406 fprintf(stderr, " example: %s aes128gcm16 100 4000\n", argv[0]);
407 return 1;
408 }
409 if (strpfx(argv[1], "memeq"))
410 {
411 return !attack_memeq(argv[1], atoi(argv[2]), atoi(argv[3]));
412 }
9d6e9522
MW
413 if (strpfx(argv[1], "chunk"))
414 {
415 return !attack_chunk(argv[1], atoi(argv[2]), atoi(argv[3]));
416 }
39e1ddec
MW
417 return !attack_transform(argv[1], atoi(argv[2]), atoi(argv[3]));
418}