aes-test.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. /*
  2. * Copyright (C) 2013 Tobias Brunner
  3. * HSR Hochschule fuer Technik Rapperswil
  4. *
  5. * This program is free software; you can redistribute it and/or modify it
  6. * under the terms of the GNU General Public License as published by the
  7. * Free Software Foundation; either version 2 of the License, or (at your
  8. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  9. *
  10. * This program is distributed in the hope that it will be useful, but
  11. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  12. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. * for more details.
  14. */
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <unistd.h>
  19. #include <getopt.h>
  20. #include <errno.h>
  21. #include <library.h>
  22. /** plugins to load */
  23. #undef PLUGINS
  24. #define PLUGINS "openssl"
  25. /**
  26. * Context
  27. */
  28. static struct {
  29. /** input file */
  30. FILE *in;
  31. /** output file */
  32. FILE *out;
  33. /** whether to use GCM or CBC */
  34. bool use_gcm;
  35. /** whether to run the Monte Carlo Test */
  36. bool use_mct;
  37. /** whether to test encryption or decryption */
  38. bool decrypt;
  39. /** IV length in bits in case of GCM */
  40. int ivlen;
  41. /** ICV length in bits in case of GCM */
  42. int icvlen;
  43. } ctx;
  44. /**
  45. * Types of parameters of a test vector
  46. */
  47. typedef enum {
  48. PARAM_UNKNOWN,
  49. PARAM_COUNT,
  50. PARAM_KEY,
  51. PARAM_IV,
  52. PARAM_PLAINTEXT,
  53. PARAM_CIPHERTEXT,
  54. PARAM_AAD,
  55. PARAM_ICV,
  56. } param_t;
  57. static param_t parse_parameter(char *param)
  58. {
  59. if (strcaseeq(param, "COUNT"))
  60. {
  61. return PARAM_COUNT;
  62. }
  63. if (strcaseeq(param, "KEY"))
  64. {
  65. return PARAM_KEY;
  66. }
  67. if (strcaseeq(param, "IV"))
  68. {
  69. return PARAM_IV;
  70. }
  71. if (strcaseeq(param, "PLAINTEXT") ||
  72. strcaseeq(param, "PT"))
  73. {
  74. return PARAM_PLAINTEXT;
  75. }
  76. if (strcaseeq(param, "CIPHERTEXT") ||
  77. strcaseeq(param, "CT"))
  78. {
  79. return PARAM_CIPHERTEXT;
  80. }
  81. if (strcaseeq(param, "AAD"))
  82. {
  83. return PARAM_AAD;
  84. }
  85. if (strcaseeq(param, "TAG"))
  86. {
  87. return PARAM_ICV;
  88. }
  89. return PARAM_UNKNOWN;
  90. }
  91. /**
  92. * Test vector
  93. */
  94. typedef struct {
  95. /** encryption/decryption key */
  96. chunk_t key;
  97. /** initialization vector */
  98. chunk_t iv;
  99. /** plain text */
  100. chunk_t plain;
  101. /** cipher text */
  102. chunk_t cipher;
  103. /** associated data */
  104. chunk_t aad;
  105. /** ICV/tag */
  106. chunk_t icv;
  107. /** whether the IV was provided */
  108. bool external_iv;
  109. /** whether the decryption/verification in GCM mode was successful */
  110. bool success;
  111. } test_vector_t;
  112. static void test_vector_free(test_vector_t *test)
  113. {
  114. chunk_free(&test->key);
  115. chunk_free(&test->iv);
  116. chunk_free(&test->plain);
  117. chunk_free(&test->cipher);
  118. chunk_free(&test->aad);
  119. chunk_free(&test->icv);
  120. }
  121. static void print_result(test_vector_t *test)
  122. {
  123. if (ctx.use_gcm)
  124. {
  125. if (ctx.decrypt)
  126. {
  127. if (test->success)
  128. {
  129. fprintf(ctx.out, "PT = %+B\n", &test->plain);
  130. }
  131. else
  132. {
  133. fprintf(ctx.out, "FAIL\n");
  134. }
  135. return;
  136. }
  137. if (!test->external_iv)
  138. {
  139. fprintf(ctx.out, "IV = %+B\n", &test->iv);
  140. }
  141. fprintf(ctx.out, "CT = %+B\n", &test->cipher);
  142. fprintf(ctx.out, "Tag = %+B\n", &test->icv);
  143. }
  144. else
  145. {
  146. fprintf(ctx.out, "%s = %+B\n", ctx.decrypt ? "PLAINTEXT" : "CIPHERTEXT",
  147. ctx.decrypt ? &test->plain : &test->cipher);
  148. }
  149. }
  150. static bool get_next_test_vector(test_vector_t *test)
  151. {
  152. param_t param = PARAM_UNKNOWN;
  153. char line[512];
  154. memset(test, 0, sizeof(test_vector_t));
  155. while (fgets(line, sizeof(line), ctx.in))
  156. {
  157. enumerator_t *enumerator;
  158. chunk_t value = chunk_empty;
  159. char *token;
  160. int i;
  161. switch (line[0])
  162. {
  163. case '\n':
  164. case '\r':
  165. case '#':
  166. case '\0':
  167. /* copy comments, empty lines etc. directly to the output */
  168. if (param != PARAM_UNKNOWN)
  169. { /* seems we got a complete test vector */
  170. return TRUE;
  171. }
  172. fputs(line, ctx.out);
  173. continue;
  174. case '[':
  175. /* control directives */
  176. fputs(line, ctx.out);
  177. if (strpfx(line, "[ENCRYPT]"))
  178. {
  179. ctx.decrypt = FALSE;
  180. }
  181. else if (strpfx(line, "[DECRYPT]"))
  182. {
  183. ctx.decrypt = TRUE;
  184. }
  185. else if (strcasepfx(line, "[IVlen = "))
  186. {
  187. ctx.ivlen = atoi(line + strlen("[IVlen = "));
  188. }
  189. else if (strcasepfx(line, "[Taglen = "))
  190. {
  191. ctx.icvlen = atoi(line + strlen("[Taglen = "));
  192. }
  193. continue;
  194. default:
  195. /* we assume the rest of the lines are PARAM = VALUE pairs*/
  196. fputs(line, ctx.out);
  197. break;
  198. }
  199. i = 0;
  200. enumerator = enumerator_create_token(line, "=", " \n\r");
  201. while (enumerator->enumerate(enumerator, &token))
  202. {
  203. switch (i++)
  204. {
  205. case 0: /* PARAM */
  206. param = parse_parameter(token);
  207. continue;
  208. case 1: /* VALUE */
  209. if (param != PARAM_UNKNOWN && param != PARAM_COUNT)
  210. {
  211. value = chunk_from_hex(chunk_from_str(token), NULL);
  212. }
  213. else
  214. {
  215. value = chunk_empty;
  216. }
  217. continue;
  218. default:
  219. break;
  220. }
  221. break;
  222. }
  223. enumerator->destroy(enumerator);
  224. if (i < 2)
  225. {
  226. value = chunk_empty;
  227. }
  228. switch (param)
  229. {
  230. case PARAM_KEY:
  231. test->key = value;
  232. break;
  233. case PARAM_IV:
  234. test->iv = value;
  235. test->external_iv = TRUE;
  236. break;
  237. case PARAM_PLAINTEXT:
  238. test->plain = value;
  239. break;
  240. case PARAM_CIPHERTEXT:
  241. test->cipher = value;
  242. break;
  243. case PARAM_AAD:
  244. test->aad = value;
  245. break;
  246. case PARAM_ICV:
  247. test->icv = value;
  248. break;
  249. default:
  250. chunk_free(&value);
  251. break;
  252. }
  253. }
  254. if (param != PARAM_UNKNOWN)
  255. { /* could be that the file ended with a complete test vector */
  256. return TRUE;
  257. }
  258. return FALSE;
  259. }
  260. static bool verify_test_vector(test_vector_t *test)
  261. {
  262. if (ctx.use_gcm)
  263. {
  264. if (ctx.decrypt)
  265. {
  266. return test->key.ptr && test->iv.ptr && test->cipher.ptr &&
  267. test->icv.ptr;
  268. }
  269. return test->key.ptr && test->plain.ptr;
  270. }
  271. if (ctx.decrypt)
  272. {
  273. return test->key.ptr && test->iv.ptr && test->cipher.ptr;
  274. }
  275. return test->key.ptr && test->iv.ptr && test->plain.ptr;
  276. }
  277. static bool do_test_gcm(test_vector_t *test)
  278. {
  279. encryption_algorithm_t alg;
  280. chunk_t key, iv;
  281. aead_t *aead;
  282. size_t saltlen, ivlen;
  283. switch (ctx.icvlen / 8)
  284. {
  285. case 8:
  286. alg = ENCR_AES_GCM_ICV8;
  287. break;
  288. case 12:
  289. alg = ENCR_AES_GCM_ICV12;
  290. break;
  291. case 16:
  292. alg = ENCR_AES_GCM_ICV16;
  293. break;
  294. default:
  295. DBG1(DBG_APP, "unsupported ICV length: %d", ctx.icvlen);
  296. return FALSE;
  297. }
  298. aead = lib->crypto->create_aead(lib->crypto, alg, test->key.len, 4);
  299. if (!aead)
  300. {
  301. DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported",
  302. encryption_algorithm_names, alg, test->key.len * 8);
  303. return FALSE;
  304. }
  305. /* our API is quite RFC 4106 specific, that is, part of the IV is provided
  306. * at the end of the key. */
  307. saltlen = aead->get_key_size(aead) - test->key.len;
  308. ivlen = aead->get_iv_size(aead);
  309. if (ctx.ivlen / 8 != saltlen + ivlen)
  310. {
  311. DBG1(DBG_APP, "unsupported IV length: %d", ctx.ivlen);
  312. aead->destroy(aead);
  313. return FALSE;
  314. }
  315. if (!test->external_iv)
  316. {
  317. rng_t *rng;
  318. /* the IV consists of saltlen random bytes (usually additional keymat)
  319. * followed by a counter, zero here */
  320. test->iv = chunk_alloc(saltlen + ivlen);
  321. memset(test->iv.ptr, 0, test->iv.len);
  322. rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
  323. if (!rng || !rng->get_bytes(rng, saltlen, test->iv.ptr))
  324. {
  325. DBG1(DBG_APP, "failed to generate IV");
  326. DESTROY_IF(rng);
  327. aead->destroy(aead);
  328. return FALSE;
  329. }
  330. rng->destroy(rng);
  331. }
  332. key = chunk_alloca(test->key.len + saltlen);
  333. memcpy(key.ptr, test->key.ptr, test->key.len);
  334. memcpy(key.ptr + test->key.len, test->iv.ptr, saltlen);
  335. iv = chunk_alloca(ivlen);
  336. memcpy(iv.ptr, test->iv.ptr + saltlen, iv.len);
  337. if (!aead->set_key(aead, key))
  338. {
  339. DBG1(DBG_APP, "failed to set key");
  340. aead->destroy(aead);
  341. return FALSE;
  342. }
  343. if (ctx.decrypt)
  344. {
  345. /* the ICV is expected to follow the cipher text */
  346. chunk_t cipher = chunk_cata("cc", test->cipher, test->icv);
  347. /* store if the verification of the ICV verification is successful */
  348. test->success = aead->decrypt(aead, cipher, test->aad, iv,
  349. &test->plain);
  350. }
  351. else
  352. {
  353. if (!aead->encrypt(aead, test->plain, test->aad, iv, &test->cipher))
  354. {
  355. DBG1(DBG_APP, "encryption failed");
  356. aead->destroy(aead);
  357. return FALSE;
  358. }
  359. /* copy ICV from the end of the cipher text */
  360. test->icv = chunk_alloc(ctx.icvlen / 8);
  361. test->cipher.len -= test->icv.len;
  362. memcpy(test->icv.ptr, test->cipher.ptr + test->cipher.len,
  363. test->icv.len);
  364. }
  365. aead->destroy(aead);
  366. return TRUE;
  367. }
  368. static bool do_crypt(crypter_t *crypter, test_vector_t *test)
  369. {
  370. if (ctx.decrypt)
  371. {
  372. if (!crypter->decrypt(crypter, test->cipher, test->iv, &test->plain))
  373. {
  374. DBG1(DBG_APP, "decryption failed");
  375. return FALSE;
  376. }
  377. }
  378. else
  379. {
  380. if (!crypter->encrypt(crypter, test->plain, test->iv, &test->cipher))
  381. {
  382. DBG1(DBG_APP, "encryption failed");
  383. return FALSE;
  384. }
  385. }
  386. return TRUE;
  387. }
  388. static bool do_test_cbc(test_vector_t *test)
  389. {
  390. crypter_t *crypter;
  391. crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC,
  392. test->key.len);
  393. if (!crypter)
  394. {
  395. DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported",
  396. encryption_algorithm_names, ENCR_AES_CBC, test->key.len * 8);
  397. return FALSE;
  398. }
  399. if (!crypter->set_key(crypter, test->key))
  400. {
  401. DBG1(DBG_APP, "failed to set key");
  402. crypter->destroy(crypter);
  403. return FALSE;
  404. }
  405. if (!do_crypt(crypter, test))
  406. {
  407. crypter->destroy(crypter);
  408. return FALSE;
  409. }
  410. crypter->destroy(crypter);
  411. return TRUE;
  412. }
  413. static bool do_test_mct(test_vector_t *test)
  414. {
  415. crypter_t *crypter;
  416. chunk_t prev, *input, *output;
  417. int i, j;
  418. crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC,
  419. test->key.len);
  420. if (!crypter)
  421. {
  422. DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported",
  423. encryption_algorithm_names, ENCR_AES_CBC, test->key.len * 8);
  424. return FALSE;
  425. }
  426. input = ctx.decrypt ? &test->cipher : &test->plain;
  427. output = ctx.decrypt ? &test->plain : &test->cipher;
  428. if (crypter->get_block_size(crypter) != input->len)
  429. {
  430. DBG1(DBG_APP, "MCT only works for input with a length of one block");
  431. crypter->destroy(crypter);
  432. return FALSE;
  433. }
  434. prev = chunk_alloca(input->len);
  435. /* assume initial IV as previous output */
  436. *output = chunk_clone(test->iv);
  437. for (i = 0; i < 100; i++)
  438. {
  439. if (i > 0)
  440. { /* we copied the original lines already */
  441. fprintf(ctx.out, "COUNT = %d\n", i);
  442. fprintf(ctx.out, "KEY = %+B\n", &test->key);
  443. fprintf(ctx.out, "IV = %+B\n", &test->iv);
  444. fprintf(ctx.out, "%s = %+B\n",
  445. ctx.decrypt ? "CIPHERTEXT" : "PLAINTEXT", input);
  446. }
  447. if (!crypter->set_key(crypter, test->key))
  448. {
  449. DBG1(DBG_APP, "failed to set key");
  450. return FALSE;
  451. }
  452. for (j = 0; j < 1000; j++)
  453. {
  454. /* store previous output as it is used as input after next */
  455. memcpy(prev.ptr, output->ptr, prev.len);
  456. chunk_free(output);
  457. if (!do_crypt(crypter, test))
  458. {
  459. crypter->destroy(crypter);
  460. return FALSE;
  461. }
  462. /* prepare the next IV (our API does not allow incremental calls) */
  463. if (ctx.decrypt)
  464. {
  465. memcpy(test->iv.ptr, input->ptr, test->iv.len);
  466. }
  467. else
  468. {
  469. memcpy(test->iv.ptr, output->ptr, test->iv.len);
  470. }
  471. /* the previous output is the next input */
  472. memcpy(input->ptr, prev.ptr, input->len);
  473. }
  474. fprintf(ctx.out, "%s = %+B\n\n",
  475. ctx.decrypt ? "PLAINTEXT" : "CIPHERTEXT", output);
  476. /* derive key for next round */
  477. switch (test->key.len)
  478. {
  479. case 16:
  480. memxor(test->key.ptr, output->ptr, output->len);
  481. break;
  482. case 24:
  483. memxor(test->key.ptr, prev.ptr + 8, 8);
  484. memxor(test->key.ptr + 8, output->ptr, output->len);
  485. break;
  486. case 32:
  487. memxor(test->key.ptr, prev.ptr, prev.len);
  488. memxor(test->key.ptr + prev.len, output->ptr, output->len);
  489. break;
  490. }
  491. /* the current output is used as IV for the next round */
  492. memcpy(test->iv.ptr, output->ptr, test->iv.len);
  493. }
  494. crypter->destroy(crypter);
  495. /* we return FALSE as we print the output ourselves */
  496. return FALSE;
  497. }
  498. static bool do_test(test_vector_t *test)
  499. {
  500. if (ctx.use_gcm)
  501. {
  502. return do_test_gcm(test);
  503. }
  504. if (ctx.use_mct)
  505. {
  506. return do_test_mct(test);
  507. }
  508. return do_test_cbc(test);
  509. }
  510. static void usage(FILE *out, char *name)
  511. {
  512. fprintf(out, "Test AES implementation according to the AES Algorithm Validation Suite (AESAVS)\n");
  513. fprintf(out, "and the GCM Validation System (GCMVS)\n\n");
  514. fprintf(out, "%s [OPTIONS]\n\n", name);
  515. fprintf(out, "Options:\n");
  516. fprintf(out, " -h, --help print this help.\n");
  517. fprintf(out, " -d, --debug=LEVEL set debug level (default 1).\n");
  518. fprintf(out, " -m, --mode=MODE mode to test, either CBC or GCM (default CBC).\n");
  519. fprintf(out, " -t, --mct run Monte Carlo Test (MCT), only for CBC.\n");
  520. fprintf(out, " -x, --decrypt test decryption (not needed for CBC as files contain control directives).\n");
  521. fprintf(out, " -i, --in=FILE request file (default STDIN).\n");
  522. fprintf(out, " -o, --out=FILE response file (default STDOUT).\n");
  523. fprintf(out, "\n");
  524. }
  525. int main(int argc, char *argv[])
  526. {
  527. test_vector_t test;
  528. ctx.in = stdin;
  529. ctx.out = stdout;
  530. library_init(NULL, "aes-test");
  531. atexit(library_deinit);
  532. while (true)
  533. {
  534. struct option long_opts[] = {
  535. {"help", no_argument, NULL, 'h' },
  536. {"debug", required_argument, NULL, 'd' },
  537. {"mode", required_argument, NULL, 'm' },
  538. {"mct", no_argument, NULL, 't' },
  539. {"decrypt", no_argument, NULL, 'x' },
  540. {"in", required_argument, NULL, 'i' },
  541. {"out", required_argument, NULL, 'o' },
  542. {0,0,0,0 },
  543. };
  544. switch (getopt_long(argc, argv, "hd:m:txi:o:", long_opts, NULL))
  545. {
  546. case EOF:
  547. break;
  548. case 'h':
  549. usage(stdout, argv[0]);
  550. return 0;
  551. case 'd':
  552. dbg_default_set_level(atoi(optarg));
  553. continue;
  554. case 'm':
  555. if (strcaseeq(optarg, "GCM"))
  556. {
  557. ctx.use_gcm = TRUE;
  558. }
  559. else if (!strcaseeq(optarg, "CBC"))
  560. {
  561. usage(stderr, argv[0]);
  562. return 1;
  563. }
  564. continue;
  565. case 't':
  566. ctx.use_mct = TRUE;
  567. continue;
  568. case 'x':
  569. ctx.decrypt = TRUE;
  570. continue;
  571. case 'i':
  572. ctx.in = fopen(optarg, "r");
  573. if (!ctx.in)
  574. {
  575. fprintf(stderr, "failed to open '%s': %s\n", optarg,
  576. strerror(errno));
  577. usage(stderr, argv[0]);
  578. return 1;
  579. }
  580. continue;
  581. case 'o':
  582. ctx.out = fopen(optarg, "w");
  583. if (!ctx.out)
  584. {
  585. fprintf(stderr, "failed to open '%s': %s\n", optarg,
  586. strerror(errno));
  587. usage(stderr, argv[0]);
  588. return 1;
  589. }
  590. continue;
  591. default:
  592. usage(stderr, argv[0]);
  593. return 1;
  594. }
  595. break;
  596. }
  597. /* TODO: maybe make plugins configurable */
  598. lib->plugins->load(lib->plugins, PLUGINS);
  599. lib->plugins->status(lib->plugins, LEVEL_CTRL);
  600. while (get_next_test_vector(&test))
  601. {
  602. if (verify_test_vector(&test))
  603. {
  604. if (do_test(&test))
  605. {
  606. print_result(&test);
  607. }
  608. }
  609. else
  610. {
  611. DBG1(DBG_APP, "test vector with missing data encountered");
  612. }
  613. fprintf(ctx.out, "\n");
  614. test_vector_free(&test);
  615. }
  616. if (ctx.in != stdin)
  617. {
  618. fclose(ctx.in);
  619. }
  620. if (ctx.out != stdout)
  621. {
  622. fclose(ctx.out);
  623. }
  624. return 0;
  625. }