timeattack.c 9.0 KB

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