2 * Copyright (C) 2013 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
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>.
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
25 /** plugins to load */
27 #define PLUGINS "openssl"
37 /** whether to use GCM or CBC */
39 /** whether to run the Monte Carlo Test */
41 /** whether to test encryption or decryption */
43 /** IV length in bits in case of GCM */
45 /** ICV length in bits in case of GCM */
50 * Types of parameters of a test vector
63 static param_t
parse_parameter(char *param
)
65 if (strcaseeq(param
, "COUNT"))
69 if (strcaseeq(param
, "KEY"))
73 if (strcaseeq(param
, "IV"))
77 if (strcaseeq(param
, "PLAINTEXT") ||
78 strcaseeq(param
, "PT"))
80 return PARAM_PLAINTEXT
;
82 if (strcaseeq(param
, "CIPHERTEXT") ||
83 strcaseeq(param
, "CT"))
85 return PARAM_CIPHERTEXT
;
87 if (strcaseeq(param
, "AAD"))
91 if (strcaseeq(param
, "TAG"))
102 /** encryption/decryption key */
104 /** initialization vector */
110 /** associated data */
114 /** whether the IV was provided */
116 /** whether the decryption/verification in GCM mode was successful */
120 static void test_vector_free(test_vector_t
*test
)
122 chunk_free(&test
->key
);
123 chunk_free(&test
->iv
);
124 chunk_free(&test
->plain
);
125 chunk_free(&test
->cipher
);
126 chunk_free(&test
->aad
);
127 chunk_free(&test
->icv
);
130 static void print_result(test_vector_t
*test
)
138 fprintf(ctx
.out
, "PT = %+B\n", &test
->plain
);
142 fprintf(ctx
.out
, "FAIL\n");
146 if (!test
->external_iv
)
148 fprintf(ctx
.out
, "IV = %+B\n", &test
->iv
);
150 fprintf(ctx
.out
, "CT = %+B\n", &test
->cipher
);
151 fprintf(ctx
.out
, "Tag = %+B\n", &test
->icv
);
155 fprintf(ctx
.out
, "%s = %+B\n", ctx
.decrypt
? "PLAINTEXT" : "CIPHERTEXT",
156 ctx
.decrypt
? &test
->plain
: &test
->cipher
);
160 static bool get_next_test_vector(test_vector_t
*test
)
162 param_t param
= PARAM_UNKNOWN
;
165 memset(test
, 0, sizeof(test_vector_t
));
167 while (fgets(line
, sizeof(line
), ctx
.in
))
169 enumerator_t
*enumerator
;
170 chunk_t value
= chunk_empty
;
180 /* copy comments, empty lines etc. directly to the output */
181 if (param
!= PARAM_UNKNOWN
)
182 { /* seems we got a complete test vector */
185 fputs(line
, ctx
.out
);
188 /* control directives */
189 fputs(line
, ctx
.out
);
190 if (strpfx(line
, "[ENCRYPT]"))
194 else if (strpfx(line
, "[DECRYPT]"))
198 else if (strcasepfx(line
, "[IVlen = "))
200 ctx
.ivlen
= atoi(line
+ strlen("[IVlen = "));
202 else if (strcasepfx(line
, "[Taglen = "))
204 ctx
.icvlen
= atoi(line
+ strlen("[Taglen = "));
208 /* we assume the rest of the lines are PARAM = VALUE pairs*/
209 fputs(line
, ctx
.out
);
214 enumerator
= enumerator_create_token(line
, "=", " \n\r");
215 while (enumerator
->enumerate(enumerator
, &token
))
220 param
= parse_parameter(token
);
223 if (param
!= PARAM_UNKNOWN
&& param
!= PARAM_COUNT
)
225 value
= chunk_from_hex(chunk_from_str(token
), NULL
);
237 enumerator
->destroy(enumerator
);
249 test
->external_iv
= TRUE
;
251 case PARAM_PLAINTEXT
:
254 case PARAM_CIPHERTEXT
:
255 test
->cipher
= value
;
268 if (param
!= PARAM_UNKNOWN
)
269 { /* could be that the file ended with a complete test vector */
275 static bool verify_test_vector(test_vector_t
*test
)
281 return test
->key
.ptr
&& test
->iv
.ptr
&& test
->cipher
.ptr
&&
284 return test
->key
.ptr
&& test
->plain
.ptr
;
288 return test
->key
.ptr
&& test
->iv
.ptr
&& test
->cipher
.ptr
;
290 return test
->key
.ptr
&& test
->iv
.ptr
&& test
->plain
.ptr
;
293 static bool do_test_gcm(test_vector_t
*test
)
295 encryption_algorithm_t alg
;
298 size_t saltlen
, ivlen
;
300 switch (ctx
.icvlen
/ 8)
303 alg
= ENCR_AES_GCM_ICV8
;
306 alg
= ENCR_AES_GCM_ICV12
;
309 alg
= ENCR_AES_GCM_ICV16
;
312 DBG1(DBG_APP
, "unsupported ICV length: %d", ctx
.icvlen
);
316 aead
= lib
->crypto
->create_aead(lib
->crypto
, alg
, test
->key
.len
, 4);
319 DBG1(DBG_APP
, "algorithm %N or key length (%d bits) not supported",
320 encryption_algorithm_names
, alg
, test
->key
.len
* 8);
323 /* our API is quite RFC 4106 specific, that is, part of the IV is provided
324 * at the end of the key. */
325 saltlen
= aead
->get_key_size(aead
) - test
->key
.len
;
326 ivlen
= aead
->get_iv_size(aead
);
327 if (ctx
.ivlen
/ 8 != saltlen
+ ivlen
)
329 DBG1(DBG_APP
, "unsupported IV length: %d", ctx
.ivlen
);
333 if (!test
->external_iv
)
337 /* the IV consists of saltlen random bytes (usually additional keymat)
338 * followed by a counter, zero here */
339 test
->iv
= chunk_alloc(saltlen
+ ivlen
);
340 memset(test
->iv
.ptr
, 0, test
->iv
.len
);
341 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_STRONG
);
342 if (!rng
|| !rng
->get_bytes(rng
, saltlen
, test
->iv
.ptr
))
344 DBG1(DBG_APP
, "failed to generate IV");
351 key
= chunk_alloca(test
->key
.len
+ saltlen
);
352 memcpy(key
.ptr
, test
->key
.ptr
, test
->key
.len
);
353 memcpy(key
.ptr
+ test
->key
.len
, test
->iv
.ptr
, saltlen
);
354 iv
= chunk_alloca(ivlen
);
355 memcpy(iv
.ptr
, test
->iv
.ptr
+ saltlen
, iv
.len
);
356 if (!aead
->set_key(aead
, key
))
358 DBG1(DBG_APP
, "failed to set key");
364 /* the ICV is expected to follow the cipher text */
365 chunk_t cipher
= chunk_cata("cc", test
->cipher
, test
->icv
);
366 /* store if the verification of the ICV verification is successful */
367 test
->success
= aead
->decrypt(aead
, cipher
, test
->aad
, iv
,
372 if (!aead
->encrypt(aead
, test
->plain
, test
->aad
, iv
, &test
->cipher
))
374 DBG1(DBG_APP
, "encryption failed");
378 /* copy ICV from the end of the cipher text */
379 test
->icv
= chunk_alloc(ctx
.icvlen
/ 8);
380 test
->cipher
.len
-= test
->icv
.len
;
381 memcpy(test
->icv
.ptr
, test
->cipher
.ptr
+ test
->cipher
.len
,
388 static bool do_crypt(crypter_t
*crypter
, test_vector_t
*test
)
392 if (!crypter
->decrypt(crypter
, test
->cipher
, test
->iv
, &test
->plain
))
394 DBG1(DBG_APP
, "decryption failed");
400 if (!crypter
->encrypt(crypter
, test
->plain
, test
->iv
, &test
->cipher
))
402 DBG1(DBG_APP
, "encryption failed");
409 static bool do_test_cbc(test_vector_t
*test
)
413 crypter
= lib
->crypto
->create_crypter(lib
->crypto
, ENCR_AES_CBC
,
417 DBG1(DBG_APP
, "algorithm %N or key length (%d bits) not supported",
418 encryption_algorithm_names
, ENCR_AES_CBC
, test
->key
.len
* 8);
421 if (!crypter
->set_key(crypter
, test
->key
))
423 DBG1(DBG_APP
, "failed to set key");
424 crypter
->destroy(crypter
);
427 if (!do_crypt(crypter
, test
))
429 crypter
->destroy(crypter
);
432 crypter
->destroy(crypter
);
436 static bool do_test_mct(test_vector_t
*test
)
439 chunk_t prev
, *input
, *output
;
442 crypter
= lib
->crypto
->create_crypter(lib
->crypto
, ENCR_AES_CBC
,
446 DBG1(DBG_APP
, "algorithm %N or key length (%d bits) not supported",
447 encryption_algorithm_names
, ENCR_AES_CBC
, test
->key
.len
* 8);
450 input
= ctx
.decrypt
? &test
->cipher
: &test
->plain
;
451 output
= ctx
.decrypt
? &test
->plain
: &test
->cipher
;
452 if (crypter
->get_block_size(crypter
) != input
->len
)
454 DBG1(DBG_APP
, "MCT only works for input with a length of one block");
455 crypter
->destroy(crypter
);
458 prev
= chunk_alloca(input
->len
);
459 /* assume initial IV as previous output */
460 *output
= chunk_clone(test
->iv
);
461 for (i
= 0; i
< 100; i
++)
464 { /* we copied the original lines already */
465 fprintf(ctx
.out
, "COUNT = %d\n", i
);
466 fprintf(ctx
.out
, "KEY = %+B\n", &test
->key
);
467 fprintf(ctx
.out
, "IV = %+B\n", &test
->iv
);
468 fprintf(ctx
.out
, "%s = %+B\n",
469 ctx
.decrypt
? "CIPHERTEXT" : "PLAINTEXT", input
);
471 if (!crypter
->set_key(crypter
, test
->key
))
473 DBG1(DBG_APP
, "failed to set key");
476 for (j
= 0; j
< 1000; j
++)
478 /* store previous output as it is used as input after next */
479 memcpy(prev
.ptr
, output
->ptr
, prev
.len
);
481 if (!do_crypt(crypter
, test
))
483 crypter
->destroy(crypter
);
486 /* prepare the next IV (our API does not allow incremental calls) */
489 memcpy(test
->iv
.ptr
, input
->ptr
, test
->iv
.len
);
493 memcpy(test
->iv
.ptr
, output
->ptr
, test
->iv
.len
);
495 /* the previous output is the next input */
496 memcpy(input
->ptr
, prev
.ptr
, input
->len
);
498 fprintf(ctx
.out
, "%s = %+B\n\n",
499 ctx
.decrypt
? "PLAINTEXT" : "CIPHERTEXT", output
);
500 /* derive key for next round */
501 switch (test
->key
.len
)
504 memxor(test
->key
.ptr
, output
->ptr
, output
->len
);
507 memxor(test
->key
.ptr
, prev
.ptr
+ 8, 8);
508 memxor(test
->key
.ptr
+ 8, output
->ptr
, output
->len
);
511 memxor(test
->key
.ptr
, prev
.ptr
, prev
.len
);
512 memxor(test
->key
.ptr
+ prev
.len
, output
->ptr
, output
->len
);
515 /* the current output is used as IV for the next round */
516 memcpy(test
->iv
.ptr
, output
->ptr
, test
->iv
.len
);
518 crypter
->destroy(crypter
);
519 /* we return FALSE as we print the output ourselves */
523 static bool do_test(test_vector_t
*test
)
527 return do_test_gcm(test
);
531 return do_test_mct(test
);
533 return do_test_cbc(test
);
536 static void usage(FILE *out
, char *name
)
538 fprintf(out
, "Test AES implementation according to the AES Algorithm Validation Suite (AESAVS)\n");
539 fprintf(out
, "and the GCM Validation System (GCMVS)\n\n");
540 fprintf(out
, "%s [OPTIONS]\n\n", name
);
541 fprintf(out
, "Options:\n");
542 fprintf(out
, " -h, --help print this help.\n");
543 fprintf(out
, " -d, --debug=LEVEL set debug level (default 1).\n");
544 fprintf(out
, " -m, --mode=MODE mode to test, either CBC or GCM (default CBC).\n");
545 fprintf(out
, " -t, --mct run Monte Carlo Test (MCT), only for CBC.\n");
546 fprintf(out
, " -x, --decrypt test decryption (not needed for CBC as files contain control directives).\n");
547 fprintf(out
, " -i, --in=FILE request file (default STDIN).\n");
548 fprintf(out
, " -o, --out=FILE response file (default STDOUT).\n");
552 int main(int argc
, char *argv
[])
559 library_init(NULL
, "aes-test");
560 atexit(library_deinit
);
564 struct option long_opts
[] = {
565 {"help", no_argument
, NULL
, 'h' },
566 {"debug", required_argument
, NULL
, 'd' },
567 {"mode", required_argument
, NULL
, 'm' },
568 {"mct", no_argument
, NULL
, 't' },
569 {"decrypt", no_argument
, NULL
, 'x' },
570 {"in", required_argument
, NULL
, 'i' },
571 {"out", required_argument
, NULL
, 'o' },
574 switch (getopt_long(argc
, argv
, "hd:m:txi:o:", long_opts
, NULL
))
579 usage(stdout
, argv
[0]);
582 dbg_default_set_level(atoi(optarg
));
585 if (strcaseeq(optarg
, "GCM"))
589 else if (!strcaseeq(optarg
, "CBC"))
591 usage(stderr
, argv
[0]);
602 ctx
.in
= fopen(optarg
, "r");
605 fprintf(stderr
, "failed to open '%s': %s\n", optarg
,
607 usage(stderr
, argv
[0]);
612 ctx
.out
= fopen(optarg
, "w");
615 fprintf(stderr
, "failed to open '%s': %s\n", optarg
,
617 usage(stderr
, argv
[0]);
622 usage(stderr
, argv
[0]);
627 /* TODO: maybe make plugins configurable */
628 lib
->plugins
->load(lib
->plugins
, PLUGINS
);
629 lib
->plugins
->status(lib
->plugins
, LEVEL_CTRL
);
631 while (get_next_test_vector(&test
))
633 if (verify_test_vector(&test
))
642 DBG1(DBG_APP
, "test vector with missing data encountered");
644 fprintf(ctx
.out
, "\n");
645 test_vector_free(&test
);
652 if (ctx
.out
!= stdout
)