1 /* Copyright (c) 2014, Google Inc.
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
20 #include <openssl/aead.h>
22 /* This program tests an AEAD against a series of test vectors from a file. The
23 * test vector file consists of key-value lines where the key and value are
24 * separated by a colon and optional whitespace. The keys are listed in
25 * |NAMES|, below. The values are hex-encoded data.
27 * After a number of key-value lines, a blank line or EOF indicates the end of
30 * For example, here's a valid test case:
32 * KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4
33 * NONCE: 978105dfce667bf4
37 * TAG: 1d45758621762e061368e68868e2f929
42 /* These are the different types of line that are found in the input file. */
44 KEY = 0, /* hex encoded key. */
45 NONCE, /* hex encoded nonce. */
46 IN, /* hex encoded plaintext. */
47 AD, /* hex encoded additional data. */
48 CT, /* hex encoded ciphertext (not including the authenticator,
50 TAG, /* hex encoded authenticator. */
54 static const char NAMES[6][NUM_TYPES] = {
55 "KEY", "NONCE", "IN", "AD", "CT", "TAG",
58 static unsigned char hex_digit(char h) {
59 if (h >= '0' && h <= '9') {
61 } else if (h >= 'a' && h <= 'f') {
63 } else if (h >= 'A' && h <= 'F') {
70 static int run_test_case(const EVP_AEAD *aead,
71 unsigned char bufs[NUM_TYPES][BUF_MAX],
72 const unsigned int lengths[NUM_TYPES],
73 unsigned int line_no) {
75 size_t ciphertext_len, plaintext_len;
76 unsigned char out[BUF_MAX + EVP_AEAD_MAX_OVERHEAD], out2[BUF_MAX];
78 if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
80 fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
84 if (!EVP_AEAD_CTX_seal(&ctx, out, &ciphertext_len, sizeof(out), bufs[NONCE],
85 lengths[NONCE], bufs[IN], lengths[IN], bufs[AD],
87 fprintf(stderr, "Failed to run AEAD on line %u\n", line_no);
91 if (ciphertext_len != lengths[CT] + lengths[TAG]) {
92 fprintf(stderr, "Bad output length on line %u: %u vs %u\n", line_no,
93 (unsigned)ciphertext_len, (unsigned)(lengths[CT] + lengths[TAG]));
97 if (memcmp(out, bufs[CT], lengths[CT]) != 0) {
98 fprintf(stderr, "Bad output on line %u\n", line_no);
102 if (memcmp(out + lengths[CT], bufs[TAG], lengths[TAG]) != 0) {
103 fprintf(stderr, "Bad tag on line %u\n", line_no);
107 /* The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
108 * reset after each operation. */
109 EVP_AEAD_CTX_cleanup(&ctx);
110 if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
112 fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
116 if (!EVP_AEAD_CTX_open(&ctx, out2, &plaintext_len, lengths[IN], bufs[NONCE],
117 lengths[NONCE], out, ciphertext_len, bufs[AD],
119 fprintf(stderr, "Failed to decrypt on line %u\n", line_no);
123 if (plaintext_len != lengths[IN]) {
124 fprintf(stderr, "Bad decrypt on line %u: %u\n", line_no,
125 (unsigned)ciphertext_len);
129 /* The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
130 * reset after each operation. */
131 EVP_AEAD_CTX_cleanup(&ctx);
132 if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
134 fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
139 if (EVP_AEAD_CTX_open(&ctx, out2, &plaintext_len, lengths[IN], bufs[NONCE],
140 lengths[NONCE], out, ciphertext_len, bufs[AD],
142 fprintf(stderr, "Decrypted bad data on line %u\n", line_no);
146 EVP_AEAD_CTX_cleanup(&ctx);
150 int main(int argc, char **argv) {
152 const EVP_AEAD *aead = NULL;
153 unsigned int line_no = 0, num_tests = 0, j;
155 unsigned char bufs[NUM_TYPES][BUF_MAX];
156 unsigned int lengths[NUM_TYPES];
159 fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]);
163 if (strcmp(argv[1], "aes-128-gcm") == 0) {
164 aead = EVP_aead_aes_128_gcm();
165 } else if (strcmp(argv[1], "aes-256-gcm") == 0) {
166 aead = EVP_aead_aes_256_gcm();
167 } else if (strcmp(argv[1], "chacha20-poly1305") == 0) {
168 aead = EVP_aead_chacha20_poly1305();
169 } else if (strcmp(argv[1], "rc4-md5") == 0) {
170 aead = EVP_aead_rc4_md5_tls();
171 } else if (strcmp(argv[1], "aes-128-key-wrap") == 0) {
172 aead = EVP_aead_aes_128_key_wrap();
173 } else if (strcmp(argv[1], "aes-256-key-wrap") == 0) {
174 aead = EVP_aead_aes_256_key_wrap();
176 fprintf(stderr, "Unknown AEAD: %s\n", argv[1]);
180 f = fopen(argv[2], "r");
182 perror("failed to open input");
186 for (j = 0; j < NUM_TYPES; j++) {
192 unsigned int i, type_len = 0;
194 unsigned char *buf = NULL;
195 unsigned int *buf_len = NULL;
197 if (!fgets(line, sizeof(line), f)) {
202 if (line[0] == '#') {
206 if (line[0] == '\n' || line[0] == 0) {
207 /* Run a test, if possible. */
208 char any_values_set = 0;
209 for (j = 0; j < NUM_TYPES; j++) {
210 if (lengths[j] != 0) {
216 if (any_values_set) {
217 if (!run_test_case(aead, bufs, lengths, line_no)) {
221 for (j = 0; j < NUM_TYPES; j++) {
234 /* Each line looks like:
236 * Where "TYPE" is the type of the data on the line,
238 for (i = 0; line[i] != 0 && line[i] != '\n'; i++) {
239 if (line[i] == ':') {
247 fprintf(stderr, "Parse error on line %u\n", line_no);
251 /* After the colon, there's optional whitespace. */
252 for (; line[i] != 0 && line[i] != '\n'; i++) {
253 if (line[i] != ' ' && line[i] != '\t') {
259 for (j = 0; j < NUM_TYPES; j++) {
260 if (strcmp(line, NAMES[j]) != 0) {
263 if (lengths[j] != 0) {
264 fprintf(stderr, "Duplicate value on line %u\n", line_no);
268 buf_len = &lengths[j];
272 fprintf(stderr, "Unknown line type on line %u\n", line_no);
277 for (; line[i] != 0 && line[i] != '\n'; i++) {
279 v = hex_digit(line[i++]);
280 if (line[i] == 0 || line[i] == '\n') {
281 fprintf(stderr, "Odd-length hex data on line %u\n", line_no);
284 v2 = hex_digit(line[i]);
285 if (v > 15 || v2 > 15) {
286 fprintf(stderr, "Invalid hex char on line %u\n", line_no);
293 fprintf(stderr, "Too much hex data on line %u (max is %u bytes)\n",
294 line_no, (unsigned)BUF_MAX);
298 *buf_len = *buf_len + 1;
302 printf("Completed %u test cases\n", num_tests);