Annotation of embedaddon/strongswan/scripts/timeattack.c, revision 1.1.1.1
1.1 misho 1: #include <stdio.h>
2: #include <time.h>
3:
4: #include <library.h>
5:
6: typedef bool (*attackfn_t)(void *subj, u_char *data, size_t len);
7:
8: static void start_timing(struct timespec *start)
9: {
10: clock_gettime(CLOCK_PROCESS_CPUTIME_ID, start);
11: }
12:
13: static uint64_t end_timing(struct timespec *start)
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:
22: static int intcmp(const void *a, const void *b)
23: {
24: return *(uint64_t*)a - *(uint64_t*)b;
25: }
26:
27: static uint64_t median(uint64_t *m, int count)
28: {
29: qsort(m, count, sizeof(uint64_t), intcmp);
30: return m[count / 2];
31: }
32:
33: static 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];
38: uint64_t mini, maxi, t[256], m[256][10];
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:
160: CALLBACK(attack_memeq1, bool,
161: u_char *subj, u_char *data, size_t len)
162: {
163: return memeq(data, subj, len);
164: }
165:
166: CALLBACK(attack_memeq2, bool,
167: u_char *subj, u_char *data, size_t len)
168: {
169: return memeq(subj, data, len);
170: }
171:
172: CALLBACK(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:
187: CALLBACK(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:
199: CALLBACK(attack_memeq5, bool,
200: u_char *subj, u_char *data, size_t len)
201: {
202: return memeq_const(subj, data, len);
203: }
204:
205: static 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 },
215: { "memeq5", attack_memeq5 },
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:
238: CALLBACK(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:
244: CALLBACK(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:
250: static 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:
280: CALLBACK(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:
290: static 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:
325: CALLBACK(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:
331: static 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:
364: static 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:
393: int 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]);
402: fprintf(stderr, " <attack>: memeq[1-5] / chunk[1-2] / aead / signer\n");
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: }
413: if (strpfx(argv[1], "chunk"))
414: {
415: return !attack_chunk(argv[1], atoi(argv[2]), atoi(argv[3]));
416: }
417: return !attack_transform(argv[1], atoi(argv[2]), atoi(argv[3]));
418: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>