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
;
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
;
271 static bool verify_test_vector(test_vector_t
*test
)
277 return test
->key
.ptr
&& test
->iv
.ptr
&& test
->cipher
.ptr
&&
280 return test
->key
.ptr
&& test
->plain
.ptr
;
284 return test
->key
.ptr
&& test
->iv
.ptr
&& test
->cipher
.ptr
;
286 return test
->key
.ptr
&& test
->iv
.ptr
&& test
->plain
.ptr
;
289 static bool do_test_gcm(test_vector_t
*test
)
291 encryption_algorithm_t alg
;
294 size_t saltlen
, ivlen
;
296 switch (ctx
.icvlen
/ 8)
299 alg
= ENCR_AES_GCM_ICV8
;
302 alg
= ENCR_AES_GCM_ICV12
;
305 alg
= ENCR_AES_GCM_ICV16
;
308 DBG1(DBG_APP
, "unsupported ICV length: %d", ctx
.icvlen
);
312 aead
= lib
->crypto
->create_aead(lib
->crypto
, alg
, test
->key
.len
);
315 DBG1(DBG_APP
, "algorithm %N or key length (%d bits) not supported",
316 encryption_algorithm_names
, alg
, test
->key
.len
* 8);
319 /* our API is quite RFC 4106 specific, that is, part of the IV is provided
320 * at the end of the key. */
321 saltlen
= aead
->get_key_size(aead
) - test
->key
.len
;
322 ivlen
= aead
->get_iv_size(aead
);
323 if (ctx
.ivlen
/ 8 != saltlen
+ ivlen
)
325 DBG1(DBG_APP
, "unsupported IV length: %d", ctx
.ivlen
);
329 if (!test
->external_iv
)
333 /* the IV consists of saltlen random bytes (usually additional keymat)
334 * followed by a counter, zero here */
335 test
->iv
= chunk_alloc(saltlen
+ ivlen
);
336 memset(test
->iv
.ptr
, 0, test
->iv
.len
);
337 rng
= lib
->crypto
->create_rng(lib
->crypto
, RNG_STRONG
);
338 if (!rng
|| !rng
->get_bytes(rng
, saltlen
, test
->iv
.ptr
))
340 DBG1(DBG_APP
, "failed to generate IV");
347 key
= chunk_alloca(test
->key
.len
+ saltlen
);
348 memcpy(key
.ptr
, test
->key
.ptr
, test
->key
.len
);
349 memcpy(key
.ptr
+ test
->key
.len
, test
->iv
.ptr
, saltlen
);
350 iv
= chunk_alloca(ivlen
);
351 memcpy(iv
.ptr
, test
->iv
.ptr
+ saltlen
, iv
.len
);
352 if (!aead
->set_key(aead
, key
))
354 DBG1(DBG_APP
, "failed to set key");
360 /* the ICV is expected to follow the cipher text */
361 chunk_t cipher
= chunk_cata("cc", test
->cipher
, test
->icv
);
362 /* store if the verification of the ICV verification is successful */
363 test
->success
= aead
->decrypt(aead
, cipher
, test
->aad
, iv
,
368 if (!aead
->encrypt(aead
, test
->plain
, test
->aad
, iv
, &test
->cipher
))
370 DBG1(DBG_APP
, "encryption failed");
374 /* copy ICV from the end of the cipher text */
375 test
->icv
= chunk_alloc(ctx
.icvlen
/ 8);
376 test
->cipher
.len
-= test
->icv
.len
;
377 memcpy(test
->icv
.ptr
, test
->cipher
.ptr
+ test
->cipher
.len
,
384 static bool crypt(crypter_t
*crypter
, test_vector_t
*test
)
388 if (!crypter
->decrypt(crypter
, test
->cipher
, test
->iv
, &test
->plain
))
390 DBG1(DBG_APP
, "decryption failed");
396 if (!crypter
->encrypt(crypter
, test
->plain
, test
->iv
, &test
->cipher
))
398 DBG1(DBG_APP
, "encryption failed");
405 static bool do_test_cbc(test_vector_t
*test
)
409 crypter
= lib
->crypto
->create_crypter(lib
->crypto
, ENCR_AES_CBC
,
413 DBG1(DBG_APP
, "algorithm %N or key length (%d bits) not supported",
414 encryption_algorithm_names
, ENCR_AES_CBC
, test
->key
.len
* 8);
417 if (!crypter
->set_key(crypter
, test
->key
))
419 DBG1(DBG_APP
, "failed to set key");
420 crypter
->destroy(crypter
);
423 if (!crypt(crypter
, test
))
425 crypter
->destroy(crypter
);
428 crypter
->destroy(crypter
);
432 static bool do_test_mct(test_vector_t
*test
)
435 chunk_t prev
, *input
, *output
;
438 crypter
= lib
->crypto
->create_crypter(lib
->crypto
, ENCR_AES_CBC
,
442 DBG1(DBG_APP
, "algorithm %N or key length (%d bits) not supported",
443 encryption_algorithm_names
, ENCR_AES_CBC
, test
->key
.len
* 8);
446 input
= ctx
.decrypt
? &test
->cipher
: &test
->plain
;
447 output
= ctx
.decrypt
? &test
->plain
: &test
->cipher
;
448 if (crypter
->get_block_size(crypter
) != input
->len
)
450 DBG1(DBG_APP
, "MCT only works for input with a length of one block");
451 crypter
->destroy(crypter
);
454 prev
= chunk_alloca(input
->len
);
455 /* assume initial IV as previous output */
456 *output
= chunk_clone(test
->iv
);
457 for (i
= 0; i
< 100; i
++)
460 { /* we copied the original lines already */
461 fprintf(ctx
.out
, "COUNT = %d\n", i
);
462 fprintf(ctx
.out
, "KEY = %+B\n", &test
->key
);
463 fprintf(ctx
.out
, "IV = %+B\n", &test
->iv
);
464 fprintf(ctx
.out
, "%s = %+B\n",
465 ctx
.decrypt
? "CIPHERTEXT" : "PLAINTEXT", input
);
467 if (!crypter
->set_key(crypter
, test
->key
))
469 DBG1(DBG_APP
, "failed to set key");
472 for (j
= 0; j
< 1000; j
++)
474 /* store previous output as it is used as input after next */
475 memcpy(prev
.ptr
, output
->ptr
, prev
.len
);
477 if (!crypt(crypter
, test
))
479 crypter
->destroy(crypter
);
482 /* prepare the next IV (our API does not allow incremental calls) */
485 memcpy(test
->iv
.ptr
, input
->ptr
, test
->iv
.len
);
489 memcpy(test
->iv
.ptr
, output
->ptr
, test
->iv
.len
);
491 /* the previous output is the next input */
492 memcpy(input
->ptr
, prev
.ptr
, input
->len
);
494 fprintf(ctx
.out
, "%s = %+B\n\n",
495 ctx
.decrypt
? "PLAINTEXT" : "CIPHERTEXT", output
);
496 /* derive key for next round */
497 switch (test
->key
.len
)
500 memxor(test
->key
.ptr
, output
->ptr
, output
->len
);
503 memxor(test
->key
.ptr
, prev
.ptr
+ 8, 8);
504 memxor(test
->key
.ptr
+ 8, output
->ptr
, output
->len
);
507 memxor(test
->key
.ptr
, prev
.ptr
, prev
.len
);
508 memxor(test
->key
.ptr
+ prev
.len
, output
->ptr
, output
->len
);
511 /* the current output is used as IV for the next round */
512 memcpy(test
->iv
.ptr
, output
->ptr
, test
->iv
.len
);
514 crypter
->destroy(crypter
);
515 /* we return FALSE as we print the output ourselves */
519 static bool do_test(test_vector_t
*test
)
523 return do_test_gcm(test
);
527 return do_test_mct(test
);
529 return do_test_cbc(test
);
532 static void usage(FILE *out
, char *name
)
534 fprintf(out
, "Test AES implementation according to the AES Algorithm Validation Suite (AESAVS)\n");
535 fprintf(out
, "and the GCM Validation System (GCMVS)\n\n");
536 fprintf(out
, "%s [OPTIONS]\n\n", name
);
537 fprintf(out
, "Options:\n");
538 fprintf(out
, " -h, --help print this help.\n");
539 fprintf(out
, " -d, --debug=LEVEL set debug level (default 1).\n");
540 fprintf(out
, " -m, --mode=MODE mode to test, either CBC or GCM (default CBC).\n");
541 fprintf(out
, " -t, --mct run Monte Carlo Test (MCT), only for CBC.\n");
542 fprintf(out
, " -x, --decrypt test decryption (not needed for CBC as files contain control directives).\n");
543 fprintf(out
, " -i, --in=FILE request file (default STDIN).\n");
544 fprintf(out
, " -o, --out=FILE response file (default STDOUT).\n");
548 int main(int argc
, char *argv
[])
556 atexit(library_deinit
);
560 struct option long_opts
[] = {
561 {"help", no_argument
, NULL
, 'h' },
562 {"debug", required_argument
, NULL
, 'd' },
563 {"mode", required_argument
, NULL
, 'm' },
564 {"mct", no_argument
, NULL
, 't' },
565 {"decrypt", no_argument
, NULL
, 'x' },
566 {"in", required_argument
, NULL
, 'i' },
567 {"out", required_argument
, NULL
, 'o' },
570 switch (getopt_long(argc
, argv
, "hd:m:txi:o:", long_opts
, NULL
))
575 usage(stdout
, argv
[0]);
578 dbg_default_set_level(atoi(optarg
));
581 if (strcaseeq(optarg
, "GCM"))
585 else if (!strcaseeq(optarg
, "CBC"))
587 usage(stderr
, argv
[0]);
598 ctx
.in
= fopen(optarg
, "r");
601 fprintf(stderr
, "failed to open '%s': %s\n", optarg
,
603 usage(stderr
, argv
[0]);
608 ctx
.out
= fopen(optarg
, "w");
611 fprintf(stderr
, "failed to open '%s': %s\n", optarg
,
613 usage(stderr
, argv
[0]);
618 usage(stderr
, argv
[0]);
623 /* TODO: maybe make plugins configurable */
624 lib
->plugins
->load(lib
->plugins
, PLUGINS
);
625 lib
->plugins
->status(lib
->plugins
, LEVEL_CTRL
);
627 while (get_next_test_vector(&test
))
629 if (verify_test_vector(&test
))
638 DBG1(DBG_APP
, "test vector with missing data encountered");
640 fprintf(ctx
.out
, "\n");
641 test_vector_free(&test
);
648 if (ctx
.out
!= stdout
)