6 typedef bool (*attackfn_t
)(void *subj
, u_char
*data
, size_t len
);
8 static void start_timing(struct timespec
*start
)
10 clock_gettime(CLOCK_PROCESS_CPUTIME_ID
, start
);
13 static uint64_t end_timing(struct timespec
*start
)
17 clock_gettime(CLOCK_THREAD_CPUTIME_ID
, &end
);
18 return (end
.tv_nsec
- start
->tv_nsec
) +
19 (end
.tv_sec
- start
->tv_sec
) * 1000000000;
22 static int intcmp(const void *a
, const void *b
)
24 return *(uint64_t*)a
- *(uint64_t*)b
;
27 static uint64_t median(uint64_t *m
, int count
)
29 qsort(m
, count
, sizeof(uint64_t), intcmp
);
33 static bool timeattack(attackfn_t attackfn
, void *subj
, size_t dlen
,
34 u_int iterations
, u_int distance
)
36 struct timespec start
;
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;
43 memset(test
, 0, dlen
);
45 /* do some iterations to fill caches */
46 for (i
= 0; i
< iterations
; i
++)
48 attackfn(subj
, test
, dlen
);
51 for (byte
= 0; byte
< dlen
;)
53 memset(t
, 0, sizeof(t
));
54 memset(m
, 0, sizeof(m
));
56 limit
= iterations
* (retry
+ 1);
58 /* measure timing for all patterns in next byte */
59 for (k
= 0; k
< 10; k
++)
61 for (j
= 0; j
< 256; j
++)
63 for (l
= 0; l
< 100; l
++)
67 for (i
= 0; i
< limit
; i
++)
69 attackfn(subj
, test
, dlen
);
71 m
[j
][k
] += end_timing(&start
);
76 for (j
= 0; j
< 256; j
++)
78 t
[j
] = median(m
[j
], countof(m
[j
]));
81 /* find fastest/slowest runs */
84 for (j
= 0; j
< 256; j
++)
88 mini
= min(t
[j
], mini
);
93 maxi
= max(t
[j
], maxi
);
97 /* calculate distance to next result */
100 for (j
= 0; j
< 256; j
++)
102 if (fastest
!= j
&& t
[j
] < mini
)
104 mini
= min(t
[j
], mini
);
105 fastdist
= (float)(t
[j
] - t
[fastest
]) / distance
;
107 if (slowest
!= j
&& t
[j
] > maxi
)
109 maxi
= max(t
[j
], maxi
);
110 slowdist
= (float)(t
[slowest
] - t
[j
]) / distance
;
115 fprintf(stderr
, "byte %02d: %02x (fastest, dist %02.2f)\n",
116 byte
, fastest
, fastdist
);
117 test
[byte
] = fastest
;
121 else if (slowdist
> 1.0f
)
123 fprintf(stderr
, "byte %02d: %02x (slowest, dist %02.2f)\n",
124 byte
, slowest
, slowdist
);
125 test
[byte
] = slowest
;
131 if (retry
++ > 5 && byte
> 0)
133 fprintf(stderr
, "distance fastest %02.2f (%02x), "
134 "slowest %02.2f (%02x), stepping back\n",
135 fastdist
, fastest
, slowdist
, slowest
);
140 fprintf(stderr
, "distance fastest %02.2f (%02x), "
141 "slowest %02.2f (%02x), retrying (%d)\n",
142 fastdist
, fastest
, slowdist
, slowest
, retry
);
146 printf("attack failed, giving up\n");
151 if (attackfn(subj
, test
, dlen
))
153 printf("attack successful with %b\n", test
, dlen
);
156 printf("attack failed with %b\n", test
, dlen
);
160 CALLBACK(attack_memeq1
, bool,
161 u_char
*subj
, u_char
*data
, size_t len
)
163 return memeq(data
, subj
, len
);
166 CALLBACK(attack_memeq2
, bool,
167 u_char
*subj
, u_char
*data
, size_t len
)
169 return memeq(subj
, data
, len
);
172 CALLBACK(attack_memeq3
, bool,
173 u_char
*subj
, u_char
*data
, size_t len
)
177 for (i
= 0; i
< len
; i
++)
179 if (subj
[i
] != data
[i
])
187 CALLBACK(attack_memeq4
, bool,
188 u_char
*subj
, u_char
*data
, size_t len
)
192 for (i
= 0; i
< len
; i
++)
194 m
|= subj
[i
] != data
[i
];
199 CALLBACK(attack_memeq5
, bool,
200 u_char
*subj
, u_char
*data
, size_t len
)
202 return memeq_const(subj
, data
, len
);
205 static bool attack_memeq(char *name
, u_int iterations
, u_int distance
)
211 { "memeq1", attack_memeq1
},
212 { "memeq2", attack_memeq2
},
213 { "memeq3", attack_memeq3
},
214 { "memeq4", attack_memeq4
},
215 { "memeq5", attack_memeq5
},
221 for (i
= 0; i
< sizeof(exp
); i
++)
225 fprintf(stderr
, "attacking %b\n", exp
, sizeof(exp
));
227 for (i
= 0; i
< countof(attacks
); i
++)
229 if (streq(name
, attacks
[i
].name
))
231 return timeattack(attacks
[i
].fn
, exp
, sizeof(exp
),
232 iterations
, distance
);
238 CALLBACK(attack_chunk1
, bool,
239 u_char
*subj
, u_char
*data
, size_t len
)
241 return chunk_equals(chunk_create(subj
, len
), chunk_create(data
, len
));
244 CALLBACK(attack_chunk2
, bool,
245 u_char
*subj
, u_char
*data
, size_t len
)
247 return chunk_equals_const(chunk_create(subj
, len
), chunk_create(data
, len
));
250 static bool attack_chunk(char *name
, u_int iterations
, u_int distance
)
256 { "chunk1", attack_chunk1
},
257 { "chunk2", attack_chunk2
},
263 for (i
= 0; i
< sizeof(exp
); i
++)
267 fprintf(stderr
, "attacking %b\n", exp
, sizeof(exp
));
269 for (i
= 0; i
< countof(attacks
); i
++)
271 if (streq(name
, attacks
[i
].name
))
273 return timeattack(attacks
[i
].fn
, exp
, sizeof(exp
),
274 iterations
, distance
);
280 CALLBACK(attack_aead
, bool,
281 aead_t
*aead
, u_char
*data
, size_t len
)
283 u_char iv
[aead
->get_iv_size(aead
)];
285 memset(iv
, 0, sizeof(iv
));
286 return aead
->decrypt(aead
, chunk_create(data
, len
), chunk_empty
,
287 chunk_from_thing(iv
), NULL
);
290 static bool attack_aeads(encryption_algorithm_t alg
, size_t key_size
,
291 u_int iterations
, u_int distance
)
297 aead
= lib
->crypto
->create_aead(lib
->crypto
, alg
, key_size
, 0);
300 fprintf(stderr
, "creating AEAD %N failed\n",
301 encryption_algorithm_names
, alg
);
304 memset(buf
, 0xe3, sizeof(buf
));
305 if (!aead
->set_key(aead
, chunk_create(buf
, aead
->get_key_size(aead
))))
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
))
317 fprintf(stderr
, "attacking %b\n", buf
, aead
->get_icv_size(aead
));
319 res
= timeattack(attack_aead
, aead
, aead
->get_icv_size(aead
),
320 iterations
, distance
);
325 CALLBACK(attack_signer
, bool,
326 signer_t
*signer
, u_char
*data
, size_t len
)
328 return signer
->verify_signature(signer
, chunk_empty
, chunk_create(data
, len
));
331 static bool attack_signers(integrity_algorithm_t alg
,
332 u_int iterations
, u_int distance
)
338 signer
= lib
->crypto
->create_signer(lib
->crypto
, alg
);
341 fprintf(stderr
, "creating signer %N failed\n",
342 integrity_algorithm_names
, alg
);
345 memset(buf
, 0xe3, sizeof(buf
));
346 if (!signer
->set_key(signer
, chunk_create(buf
, signer
->get_key_size(signer
))))
348 signer
->destroy(signer
);
351 if (!signer
->get_signature(signer
, chunk_empty
, buf
))
353 signer
->destroy(signer
);
356 fprintf(stderr
, "attacking %b\n", buf
, signer
->get_block_size(signer
));
358 res
= timeattack(attack_signer
, signer
, signer
->get_block_size(signer
),
359 iterations
, distance
);
360 signer
->destroy(signer
);
364 static bool attack_transform(char *name
, u_int iterations
, u_int distance
)
366 const proposal_token_t
*token
;
368 token
= lib
->proposal
->get_token(lib
->proposal
, name
);
371 fprintf(stderr
, "algorithm '%s' unknown\n", name
);
377 case ENCRYPTION_ALGORITHM
:
378 if (encryption_algorithm_is_aead(token
->algorithm
))
380 return attack_aeads(token
->algorithm
, token
->keysize
/ 8,
381 iterations
, distance
);
383 fprintf(stderr
, "can't attack a crypter\n");
385 case INTEGRITY_ALGORITHM
:
386 return attack_signers(token
->algorithm
, iterations
, distance
);
388 fprintf(stderr
, "can't attack a %N\n", transform_type_names
, token
->type
);
393 int main(int argc
, char *argv
[])
395 library_init(NULL
, "timeattack");
396 atexit(library_deinit
);
397 lib
->plugins
->load(lib
->plugins
, getenv("PLUGINS") ?: PLUGINS
);
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]);
409 if (strpfx(argv
[1], "memeq"))
411 return !attack_memeq(argv
[1], atoi(argv
[2]), atoi(argv
[3]));
413 if (strpfx(argv
[1], "chunk"))
415 return !attack_chunk(argv
[1], atoi(argv
[2]), atoi(argv
[3]));
417 return !attack_transform(argv
[1], atoi(argv
[2]), atoi(argv
[3]));