xref: /openbsd-src/regress/lib/libcrypto/aead/aeadtest.c (revision 6d94593ae4d8e7e98f09e4134bb84c097d71d234)
1*6d94593aStb /*	$OpenBSD: aeadtest.c,v 1.26 2023/09/28 14:55:48 tb Exp $	*/
24d581453Sjsing /*
31470904cSjsing  * Copyright (c) 2022 Joel Sing <jsing@openbsd.org>
44d581453Sjsing  * Copyright (c) 2014, Google Inc.
530d5732cSjsing  *
64d581453Sjsing  * Permission to use, copy, modify, and/or distribute this software for any
74d581453Sjsing  * purpose with or without fee is hereby granted, provided that the above
84d581453Sjsing  * copyright notice and this permission notice appear in all copies.
930d5732cSjsing  *
104d581453Sjsing  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
114d581453Sjsing  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
124d581453Sjsing  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
134d581453Sjsing  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
144d581453Sjsing  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
154d581453Sjsing  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
164d581453Sjsing  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1730d5732cSjsing  */
1830d5732cSjsing 
1966af3f7eSjsing #include <ctype.h>
2066af3f7eSjsing #include <stdint.h>
2130d5732cSjsing #include <stdio.h>
2230d5732cSjsing #include <stdlib.h>
2330d5732cSjsing #include <string.h>
2464bf2397Sdlg #include <unistd.h>
2530d5732cSjsing 
2664bf2397Sdlg #include <openssl/err.h>
2766af3f7eSjsing #include <openssl/evp.h>
2830d5732cSjsing 
299c0455e0Sjsing /*
309c0455e0Sjsing  * This program tests an AEAD against a series of test vectors from a file. The
3130d5732cSjsing  * test vector file consists of key-value lines where the key and value are
3230d5732cSjsing  * separated by a colon and optional whitespace. The keys are listed in
33d88516c4Sjsing  * NAMES, below. The values are hex-encoded data.
3430d5732cSjsing  *
35d88516c4Sjsing  * After a number of key-value lines, a blank line indicates the end of the
36d88516c4Sjsing  * test case.
3730d5732cSjsing  *
3830d5732cSjsing  * For example, here's a valid test case:
3930d5732cSjsing  *
4030d5732cSjsing  *   AEAD: chacha20-poly1305
41d88516c4Sjsing  *   KEY: bcb2639bf989c6251b29bf38d39a9bdce7c55f4b2ac12a39c8a37b5d0a5cc2b5
42d88516c4Sjsing  *   NONCE: 1e8b4c510f5ca083
43d88516c4Sjsing  *   IN: 8c8419bc27
44d88516c4Sjsing  *   AD: 34ab88c265
45d88516c4Sjsing  *   CT: 1a7c2f33f5
46d88516c4Sjsing  *   TAG: 2875c659d0f2808de3a40027feff91a4
4730d5732cSjsing  */
4830d5732cSjsing 
490267a604Sjsing #define BUF_MAX 1024
5030d5732cSjsing 
51d6517dbdSbcook /* MS defines in global headers, remove it */
52d6517dbdSbcook #ifdef _MSC_VER
53d6517dbdSbcook #ifdef IN
54d6517dbdSbcook #undef IN
55d6517dbdSbcook #endif
56d6517dbdSbcook #endif
57d6517dbdSbcook 
5830d5732cSjsing /* These are the different types of line that are found in the input file. */
5930d5732cSjsing enum {
6030d5732cSjsing 	AEAD = 0,	/* name of the AEAD algorithm. */
6130d5732cSjsing 	KEY,		/* hex encoded key. */
6230d5732cSjsing 	NONCE,		/* hex encoded nonce. */
6330d5732cSjsing 	IN,		/* hex encoded plaintext. */
6430d5732cSjsing 	AD,		/* hex encoded additional data. */
6530d5732cSjsing 	CT,		/* hex encoded ciphertext (not including the
6630d5732cSjsing 			 * authenticator, which is next. */
6730d5732cSjsing 	TAG,		/* hex encoded authenticator. */
6830d5732cSjsing 	NUM_TYPES
6930d5732cSjsing };
7030d5732cSjsing 
7130d5732cSjsing static const char NAMES[NUM_TYPES][6] = {
7230d5732cSjsing 	"AEAD",
7330d5732cSjsing 	"KEY",
7430d5732cSjsing 	"NONCE",
7530d5732cSjsing 	"IN",
7630d5732cSjsing 	"AD",
7730d5732cSjsing 	"CT",
7830d5732cSjsing 	"TAG",
7930d5732cSjsing };
8030d5732cSjsing 
8130d5732cSjsing static unsigned char
hex_digit(char h)825ffa517cSjsing hex_digit(char h)
835ffa517cSjsing {
8430d5732cSjsing 	if (h >= '0' && h <= '9')
8530d5732cSjsing 		return h - '0';
8630d5732cSjsing 	else if (h >= 'a' && h <= 'f')
8730d5732cSjsing 		return h - 'a' + 10;
8830d5732cSjsing 	else if (h >= 'A' && h <= 'F')
8930d5732cSjsing 		return h - 'A' + 10;
9030d5732cSjsing 	else
9130d5732cSjsing 		return 16;
9230d5732cSjsing }
9330d5732cSjsing 
9425d44175Sjsing static int
aead_from_name(const EVP_AEAD ** aead,const EVP_CIPHER ** cipher,const char * name)955de38535Sjsing aead_from_name(const EVP_AEAD **aead, const EVP_CIPHER **cipher,
965de38535Sjsing     const char *name)
970267a604Sjsing {
9830d5732cSjsing 	*aead = NULL;
995de38535Sjsing 	*cipher = NULL;
10030d5732cSjsing 
10130d5732cSjsing 	if (strcmp(name, "aes-128-gcm") == 0) {
10230d5732cSjsing 		*aead = EVP_aead_aes_128_gcm();
1035de38535Sjsing 		*cipher = EVP_aes_128_gcm();
1042dec3b2cSjsing 	} else if (strcmp(name, "aes-192-gcm") == 0) {
1052dec3b2cSjsing 		*cipher = EVP_aes_192_gcm();
10630d5732cSjsing 	} else if (strcmp(name, "aes-256-gcm") == 0) {
10730d5732cSjsing 		*aead = EVP_aead_aes_256_gcm();
1085de38535Sjsing 		*cipher = EVP_aes_256_gcm();
1090267a604Sjsing 	} else if (strcmp(name, "chacha20-poly1305") == 0) {
1100267a604Sjsing 		*aead = EVP_aead_chacha20_poly1305();
111711d32f8Sjsing 		*cipher = EVP_chacha20_poly1305();
11264bf2397Sdlg 	} else if (strcmp(name, "xchacha20-poly1305") == 0) {
11364bf2397Sdlg 		*aead = EVP_aead_xchacha20_poly1305();
11430d5732cSjsing 	} else {
11530d5732cSjsing 		fprintf(stderr, "Unknown AEAD: %s\n", name);
11630d5732cSjsing 		return 0;
1175de38535Sjsing 	}
11830d5732cSjsing 
11930d5732cSjsing 	return 1;
12030d5732cSjsing }
12130d5732cSjsing 
12230d5732cSjsing static int
run_aead_test(const EVP_AEAD * aead,unsigned char bufs[NUM_TYPES][BUF_MAX],const unsigned int lengths[NUM_TYPES],unsigned int line_no)1235de38535Sjsing run_aead_test(const EVP_AEAD *aead, unsigned char bufs[NUM_TYPES][BUF_MAX],
12430d5732cSjsing     const unsigned int lengths[NUM_TYPES], unsigned int line_no)
12530d5732cSjsing {
126290ca929Stb 	EVP_AEAD_CTX *ctx;
12730d5732cSjsing 	unsigned char out[BUF_MAX + EVP_AEAD_MAX_TAG_LENGTH], out2[BUF_MAX];
12825d44175Sjsing 	size_t out_len, out_len2;
129290ca929Stb 	int ret = 0;
13030d5732cSjsing 
131290ca929Stb 	if ((ctx = EVP_AEAD_CTX_new()) == NULL) {
132290ca929Stb 		fprintf(stderr, "Failed to allocate AEAD context on line %u\n",
133290ca929Stb 		    line_no);
134290ca929Stb 		goto err;
13530d5732cSjsing 	}
13630d5732cSjsing 
137290ca929Stb 	if (!EVP_AEAD_CTX_init(ctx, aead, bufs[KEY], lengths[KEY],
138290ca929Stb 	    lengths[TAG], NULL)) {
139290ca929Stb 		fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
140290ca929Stb 		goto err;
141290ca929Stb 	}
142290ca929Stb 
143290ca929Stb 	if (!EVP_AEAD_CTX_seal(ctx, out, &out_len, sizeof(out), bufs[NONCE],
14425d44175Sjsing 	    lengths[NONCE], bufs[IN], lengths[IN], bufs[AD], lengths[AD])) {
14530d5732cSjsing 		fprintf(stderr, "Failed to run AEAD on line %u\n", line_no);
146290ca929Stb 		goto err;
14730d5732cSjsing 	}
14830d5732cSjsing 
14925d44175Sjsing 	if (out_len != lengths[CT] + lengths[TAG]) {
15025d44175Sjsing 		fprintf(stderr, "Bad output length on line %u: %zu vs %u\n",
15125d44175Sjsing 		    line_no, out_len, (unsigned)(lengths[CT] + lengths[TAG]));
152290ca929Stb 		goto err;
15330d5732cSjsing 	}
15430d5732cSjsing 
15530d5732cSjsing 	if (memcmp(out, bufs[CT], lengths[CT]) != 0) {
15630d5732cSjsing 		fprintf(stderr, "Bad output on line %u\n", line_no);
157290ca929Stb 		goto err;
15830d5732cSjsing 	}
15930d5732cSjsing 
16030d5732cSjsing 	if (memcmp(out + lengths[CT], bufs[TAG], lengths[TAG]) != 0) {
16130d5732cSjsing 		fprintf(stderr, "Bad tag on line %u\n", line_no);
162290ca929Stb 		goto err;
16330d5732cSjsing 	}
16430d5732cSjsing 
165290ca929Stb 	if (!EVP_AEAD_CTX_open(ctx, out2, &out_len2, lengths[IN], bufs[NONCE],
16625d44175Sjsing 	    lengths[NONCE], out, out_len, bufs[AD], lengths[AD])) {
16730d5732cSjsing 		fprintf(stderr, "Failed to decrypt on line %u\n", line_no);
168290ca929Stb 		goto err;
16930d5732cSjsing 	}
17030d5732cSjsing 
17125d44175Sjsing 	if (out_len2 != lengths[IN]) {
17225d44175Sjsing 		fprintf(stderr, "Bad decrypt on line %u: %zu\n",
17325d44175Sjsing 		    line_no, out_len2);
174290ca929Stb 		goto err;
17530d5732cSjsing 	}
17630d5732cSjsing 
177ae8558bbSjsing 	if (memcmp(out2, bufs[IN], out_len2) != 0) {
178ae8558bbSjsing 		fprintf(stderr, "Plaintext mismatch on line %u\n", line_no);
179290ca929Stb 		goto err;
180ae8558bbSjsing 	}
181ae8558bbSjsing 
18230d5732cSjsing 	out[0] ^= 0x80;
183290ca929Stb 	if (EVP_AEAD_CTX_open(ctx, out2, &out_len2, lengths[IN], bufs[NONCE],
18425d44175Sjsing 	    lengths[NONCE], out, out_len, bufs[AD], lengths[AD])) {
18530d5732cSjsing 		fprintf(stderr, "Decrypted bad data on line %u\n", line_no);
186290ca929Stb 		goto err;
18730d5732cSjsing 	}
18830d5732cSjsing 
189290ca929Stb 	ret = 1;
190290ca929Stb 
191290ca929Stb  err:
192290ca929Stb 	EVP_AEAD_CTX_free(ctx);
193290ca929Stb 
194290ca929Stb 	return ret;
19530d5732cSjsing }
19630d5732cSjsing 
1975de38535Sjsing static int
run_cipher_aead_encrypt_test(const EVP_CIPHER * cipher,unsigned char bufs[NUM_TYPES][BUF_MAX],const unsigned int lengths[NUM_TYPES],unsigned int line_no)1985de38535Sjsing run_cipher_aead_encrypt_test(const EVP_CIPHER *cipher,
1995de38535Sjsing     unsigned char bufs[NUM_TYPES][BUF_MAX],
2005de38535Sjsing     const unsigned int lengths[NUM_TYPES], unsigned int line_no)
2015de38535Sjsing {
2025de38535Sjsing 	unsigned char out[BUF_MAX + EVP_AEAD_MAX_TAG_LENGTH];
2035de38535Sjsing 	EVP_CIPHER_CTX *ctx;
2045de38535Sjsing 	size_t out_len;
2055de38535Sjsing 	int len;
20652effe6aStb 	int ivlen;
2075de38535Sjsing 	int ret = 0;
2085de38535Sjsing 
2095de38535Sjsing 	if ((ctx = EVP_CIPHER_CTX_new()) == NULL) {
2105de38535Sjsing 		fprintf(stderr, "FAIL: EVP_CIPHER_CTX_new\n");
2115de38535Sjsing 		goto err;
2125de38535Sjsing 	}
2135de38535Sjsing 
2145de38535Sjsing 	if (!EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL)) {
2155de38535Sjsing 		fprintf(stderr, "FAIL: EVP_EncryptInit_ex with cipher\n");
2165de38535Sjsing 		goto err;
2175de38535Sjsing 	}
2185de38535Sjsing 
2195de38535Sjsing 	if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, lengths[NONCE], NULL)) {
2205de38535Sjsing 		fprintf(stderr, "FAIL: EVP_CTRL_AEAD_SET_IVLEN\n");
2215de38535Sjsing 		goto err;
2225de38535Sjsing 	}
2235de38535Sjsing 
22452effe6aStb 	ivlen = EVP_CIPHER_CTX_iv_length(ctx);
22552effe6aStb 	if (ivlen != (int)lengths[NONCE]) {
226*6d94593aStb 		fprintf(stderr, "FAIL: ivlen %d != nonce length %d\n", ivlen,
22752effe6aStb 		    (int)lengths[NONCE]);
22852effe6aStb 		goto err;
22952effe6aStb 	}
23052effe6aStb 
2315de38535Sjsing 	if (!EVP_EncryptInit_ex(ctx, NULL, NULL, bufs[KEY], NULL)) {
2325de38535Sjsing 		fprintf(stderr, "FAIL: EVP_EncryptInit_ex with key\n");
2335de38535Sjsing 		goto err;
2345de38535Sjsing 	}
2355de38535Sjsing 	if (!EVP_EncryptInit_ex(ctx, NULL, NULL, NULL, bufs[NONCE])) {
2365de38535Sjsing 		fprintf(stderr, "FAIL: EVP_EncryptInit_ex with nonce\n");
2375de38535Sjsing 		goto err;
2385de38535Sjsing 	}
2395de38535Sjsing 
2405de38535Sjsing 	if (!EVP_EncryptUpdate(ctx, NULL, &len, bufs[AD], lengths[AD])) {
2415de38535Sjsing 		fprintf(stderr, "FAIL: EVP_EncryptUpdate with AD\n");
2425de38535Sjsing 		goto err;
2435de38535Sjsing 	}
2445de38535Sjsing 	if ((unsigned int)len != lengths[AD]) {
2455de38535Sjsing 		fprintf(stderr, "FAIL: EVP_EncryptUpdate with AD length = %u, "
2465de38535Sjsing 		    "want %u\n", len, lengths[AD]);
2475de38535Sjsing 		goto err;
2485de38535Sjsing 	}
2495de38535Sjsing 	if (!EVP_EncryptUpdate(ctx, out, &len, bufs[IN], lengths[IN])) {
2505de38535Sjsing 		fprintf(stderr, "FAIL: EVP_EncryptUpdate with plaintext\n");
2515de38535Sjsing 		goto err;
2525de38535Sjsing 	}
2535de38535Sjsing 	out_len = len;
2545de38535Sjsing 	if (!EVP_EncryptFinal_ex(ctx, out + out_len, &len)) {
2555de38535Sjsing 		fprintf(stderr, "FAIL: EVP_EncryptFinal_ex\n");
2565de38535Sjsing 		goto err;
2575de38535Sjsing 	}
2585de38535Sjsing 	out_len += len;
2595de38535Sjsing 	if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG, lengths[TAG],
2605de38535Sjsing 	    out + out_len)) {
2615de38535Sjsing 		fprintf(stderr, "FAIL: EVP_EncryptInit_ex with cipher\n");
2625de38535Sjsing 		goto err;
2635de38535Sjsing 	}
2645de38535Sjsing 	out_len += lengths[TAG];
2655de38535Sjsing 
2665de38535Sjsing 	if (out_len != lengths[CT] + lengths[TAG]) {
2675de38535Sjsing 		fprintf(stderr, "Bad output length on line %u: %zu vs %u\n",
2685de38535Sjsing 		    line_no, out_len, (unsigned)(lengths[CT] + lengths[TAG]));
2695de38535Sjsing 		goto err;
2705de38535Sjsing 	}
2715de38535Sjsing 
2725de38535Sjsing 	if (memcmp(out, bufs[CT], lengths[CT]) != 0) {
2735de38535Sjsing 		fprintf(stderr, "Bad output on line %u\n", line_no);
2745de38535Sjsing 		goto err;
2755de38535Sjsing 	}
2765de38535Sjsing 
2775de38535Sjsing 	if (memcmp(out + lengths[CT], bufs[TAG], lengths[TAG]) != 0) {
2785de38535Sjsing 		fprintf(stderr, "Bad tag on line %u\n", line_no);
2795de38535Sjsing 		goto err;
2805de38535Sjsing 	}
2815de38535Sjsing 
2825de38535Sjsing 	ret = 1;
2835de38535Sjsing 
2845de38535Sjsing  err:
2855de38535Sjsing 	EVP_CIPHER_CTX_free(ctx);
2865de38535Sjsing 
2875de38535Sjsing 	return ret;
2885de38535Sjsing }
2895de38535Sjsing 
2905de38535Sjsing static int
run_cipher_aead_decrypt_test(const EVP_CIPHER * cipher,int invalid,unsigned char bufs[NUM_TYPES][BUF_MAX],const unsigned int lengths[NUM_TYPES],unsigned int line_no)2915de38535Sjsing run_cipher_aead_decrypt_test(const EVP_CIPHER *cipher, int invalid,
2925de38535Sjsing     unsigned char bufs[NUM_TYPES][BUF_MAX],
2935de38535Sjsing     const unsigned int lengths[NUM_TYPES], unsigned int line_no)
2945de38535Sjsing {
2955de38535Sjsing 	unsigned char in[BUF_MAX], out[BUF_MAX + EVP_AEAD_MAX_TAG_LENGTH];
2965de38535Sjsing 	EVP_CIPHER_CTX *ctx;
2975de38535Sjsing 	size_t out_len;
2985de38535Sjsing 	int len;
2995de38535Sjsing 	int ret = 0;
3005de38535Sjsing 
3015de38535Sjsing 	if ((ctx = EVP_CIPHER_CTX_new()) == NULL) {
3025de38535Sjsing 		fprintf(stderr, "FAIL: EVP_CIPHER_CTX_new\n");
3035de38535Sjsing 		goto err;
3045de38535Sjsing 	}
3055de38535Sjsing 
3065de38535Sjsing 	if (!EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL)) {
3075de38535Sjsing 		fprintf(stderr, "FAIL: EVP_DecryptInit_ex with cipher\n");
3085de38535Sjsing 		goto err;
3095de38535Sjsing 	}
3105de38535Sjsing 
3115de38535Sjsing 	if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_IVLEN, lengths[NONCE],
3125de38535Sjsing 	    NULL)) {
3135de38535Sjsing 		fprintf(stderr, "FAIL: EVP_CTRL_AEAD_SET_IVLEN\n");
3145de38535Sjsing 		goto err;
3155de38535Sjsing 	}
3165de38535Sjsing 
3175de38535Sjsing 	memcpy(in, bufs[TAG], lengths[TAG]);
3185de38535Sjsing 	if (invalid && lengths[CT] == 0)
3195de38535Sjsing 		in[0] ^= 0x80;
3205de38535Sjsing 
3215de38535Sjsing 	if (!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_SET_TAG, lengths[TAG], in)) {
3225de38535Sjsing 		fprintf(stderr, "FAIL: EVP_CTRL_AEAD_SET_TAG\n");
3235de38535Sjsing 		goto err;
3245de38535Sjsing 	}
3255de38535Sjsing 
3265de38535Sjsing 	if (!EVP_DecryptInit_ex(ctx, NULL, NULL, bufs[KEY], NULL)) {
3275de38535Sjsing 		fprintf(stderr, "FAIL: EVP_DecryptInit_ex with key\n");
3285de38535Sjsing 		goto err;
3295de38535Sjsing 	}
3305de38535Sjsing 	if (!EVP_DecryptInit_ex(ctx, NULL, NULL, NULL, bufs[NONCE])) {
3315de38535Sjsing 		fprintf(stderr, "FAIL: EVP_DecryptInit_ex with nonce\n");
3325de38535Sjsing 		goto err;
3335de38535Sjsing 	}
3345de38535Sjsing 
3355de38535Sjsing 	if (!EVP_DecryptUpdate(ctx, NULL, &len, bufs[AD], lengths[AD])) {
3365de38535Sjsing 		fprintf(stderr, "FAIL: EVP_DecryptUpdate with AD\n");
3375de38535Sjsing 		goto err;
3385de38535Sjsing 	}
3395de38535Sjsing 	if ((unsigned int)len != lengths[AD]) {
3405de38535Sjsing 		fprintf(stderr, "FAIL: EVP_EncryptUpdate with AD length = %u, "
3415de38535Sjsing 		    "want %u\n", len, lengths[AD]);
3425de38535Sjsing 		goto err;
3435de38535Sjsing 	}
3445de38535Sjsing 
3455de38535Sjsing 	memcpy(in, bufs[CT], lengths[CT]);
3465de38535Sjsing 	if (invalid && lengths[CT] > 0)
3475de38535Sjsing 		in[0] ^= 0x80;
3485de38535Sjsing 
3495de38535Sjsing 	if (!EVP_DecryptUpdate(ctx, out, &len, in, lengths[CT])) {
3505de38535Sjsing 		fprintf(stderr, "FAIL: EVP_DecryptUpdate with ciphertext\n");
3515de38535Sjsing 		goto err;
3525de38535Sjsing 	}
3535de38535Sjsing 	out_len = len;
3545de38535Sjsing 
3555de38535Sjsing 	if (invalid) {
3565de38535Sjsing 		if (EVP_DecryptFinal_ex(ctx, out + out_len, &len)) {
3575de38535Sjsing 			fprintf(stderr, "FAIL: EVP_DecryptFinal_ex succeeded "
3585de38535Sjsing 			    "with invalid ciphertext on line %u\n", line_no);
3595de38535Sjsing 			goto err;
3605de38535Sjsing 		}
3615de38535Sjsing 		goto done;
3625de38535Sjsing 	}
3635de38535Sjsing 
3645de38535Sjsing 	if (!EVP_DecryptFinal_ex(ctx, out + out_len, &len)) {
3655de38535Sjsing 		fprintf(stderr, "FAIL: EVP_DecryptFinal_ex\n");
3665de38535Sjsing 		goto err;
3675de38535Sjsing 	}
3685de38535Sjsing 	out_len += len;
3695de38535Sjsing 
3705de38535Sjsing 	if (out_len != lengths[IN]) {
3715de38535Sjsing 		fprintf(stderr, "Bad decrypt on line %u: %zu\n",
3725de38535Sjsing 		    line_no, out_len);
3735de38535Sjsing 		goto err;
3745de38535Sjsing 	}
3755de38535Sjsing 
3765de38535Sjsing 	if (memcmp(out, bufs[IN], out_len) != 0) {
3775de38535Sjsing 		fprintf(stderr, "Plaintext mismatch on line %u\n", line_no);
3785de38535Sjsing 		goto err;
3795de38535Sjsing 	}
3805de38535Sjsing 
3815de38535Sjsing  done:
3825de38535Sjsing 	ret = 1;
3835de38535Sjsing 
3845de38535Sjsing  err:
3855de38535Sjsing 	EVP_CIPHER_CTX_free(ctx);
3865de38535Sjsing 
3875de38535Sjsing 	return ret;
3885de38535Sjsing }
3895de38535Sjsing 
3905de38535Sjsing static int
run_cipher_aead_test(const EVP_CIPHER * cipher,unsigned char bufs[NUM_TYPES][BUF_MAX],const unsigned int lengths[NUM_TYPES],unsigned int line_no)3915de38535Sjsing run_cipher_aead_test(const EVP_CIPHER *cipher,
3925de38535Sjsing     unsigned char bufs[NUM_TYPES][BUF_MAX],
3935de38535Sjsing     const unsigned int lengths[NUM_TYPES], unsigned int line_no)
3945de38535Sjsing {
3955de38535Sjsing 	if (!run_cipher_aead_encrypt_test(cipher, bufs, lengths, line_no))
3965de38535Sjsing 		return 0;
3975de38535Sjsing 	if (!run_cipher_aead_decrypt_test(cipher, 0, bufs, lengths, line_no))
3985de38535Sjsing 		return 0;
3995de38535Sjsing 	if (!run_cipher_aead_decrypt_test(cipher, 1, bufs, lengths, line_no))
4005de38535Sjsing 		return 0;
4015de38535Sjsing 
4025de38535Sjsing 	return 1;
4035de38535Sjsing }
4045de38535Sjsing 
40530d5732cSjsing int
main(int argc,char ** argv)40630d5732cSjsing main(int argc, char **argv)
40730d5732cSjsing {
40830d5732cSjsing 	FILE *f;
40930d5732cSjsing 	const EVP_AEAD *aead = NULL;
4105de38535Sjsing 	const EVP_CIPHER *cipher = NULL;
41130d5732cSjsing 	unsigned int line_no = 0, num_tests = 0, j;
41230d5732cSjsing 	unsigned char bufs[NUM_TYPES][BUF_MAX];
41330d5732cSjsing 	unsigned int lengths[NUM_TYPES];
414bc6ec5ceSjsing 	const char *aeadname;
41530d5732cSjsing 
416bc6ec5ceSjsing 	if (argc != 3) {
417bc6ec5ceSjsing 		fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]);
41830d5732cSjsing 		return 1;
41930d5732cSjsing 	}
42030d5732cSjsing 
421bc6ec5ceSjsing 	if ((f = fopen(argv[2], "r")) == NULL) {
42230d5732cSjsing 		perror("failed to open input");
42330d5732cSjsing 		return 1;
42430d5732cSjsing 	}
42530d5732cSjsing 
42630d5732cSjsing 	for (j = 0; j < NUM_TYPES; j++)
42730d5732cSjsing 		lengths[j] = 0;
42830d5732cSjsing 
42930d5732cSjsing 	for (;;) {
43030d5732cSjsing 		char line[4096];
43130d5732cSjsing 		unsigned int i, type_len = 0;
43230d5732cSjsing 
43330d5732cSjsing 		unsigned char *buf = NULL;
43430d5732cSjsing 		unsigned int *buf_len = NULL;
43530d5732cSjsing 
43630d5732cSjsing 		if (!fgets(line, sizeof(line), f))
43730d5732cSjsing 			break;
43830d5732cSjsing 
43930d5732cSjsing 		line_no++;
44030d5732cSjsing 		if (line[0] == '#')
44130d5732cSjsing 			continue;
44230d5732cSjsing 
44330d5732cSjsing 		if (line[0] == '\n' || line[0] == 0) {
44430d5732cSjsing 			/* Run a test, if possible. */
44530d5732cSjsing 			char any_values_set = 0;
44630d5732cSjsing 			for (j = 0; j < NUM_TYPES; j++) {
44730d5732cSjsing 				if (lengths[j] != 0) {
44830d5732cSjsing 					any_values_set = 1;
44930d5732cSjsing 					break;
45030d5732cSjsing 				}
45130d5732cSjsing 			}
45230d5732cSjsing 
45330d5732cSjsing 			if (!any_values_set)
45430d5732cSjsing 				continue;
45530d5732cSjsing 
456bc6ec5ceSjsing 			aeadname = argv[1];
457bc6ec5ceSjsing 			if (lengths[AEAD] != 0)
458bc6ec5ceSjsing 				aeadname = bufs[AEAD];
459bc6ec5ceSjsing 
460bc6ec5ceSjsing 			if (!aead_from_name(&aead, &cipher, aeadname)) {
46130d5732cSjsing 				fprintf(stderr, "Aborting...\n");
46230d5732cSjsing 				return 4;
46330d5732cSjsing 			}
46430d5732cSjsing 
4655de38535Sjsing 			if (aead != NULL) {
4665de38535Sjsing 				if (!run_aead_test(aead, bufs, lengths,
4675de38535Sjsing 				    line_no))
46830d5732cSjsing 					return 4;
4695de38535Sjsing 			}
4705de38535Sjsing 			if (cipher != NULL) {
4715de38535Sjsing 				if (!run_cipher_aead_test(cipher, bufs, lengths,
4725de38535Sjsing 				    line_no))
4735de38535Sjsing 					return 4;
4745de38535Sjsing 			}
47530d5732cSjsing 
47630d5732cSjsing 			for (j = 0; j < NUM_TYPES; j++)
47730d5732cSjsing 				lengths[j] = 0;
47830d5732cSjsing 
47930d5732cSjsing 			num_tests++;
48030d5732cSjsing 			continue;
48130d5732cSjsing 		}
48230d5732cSjsing 
4839c0455e0Sjsing 		/*
4849c0455e0Sjsing 		 * Each line looks like:
48530d5732cSjsing 		 *   TYPE: 0123abc
48630d5732cSjsing 		 * Where "TYPE" is the type of the data on the line,
4879c0455e0Sjsing 		 * e.g. "KEY".
4889c0455e0Sjsing 		 */
48930d5732cSjsing 		for (i = 0; line[i] != 0 && line[i] != '\n'; i++) {
49030d5732cSjsing 			if (line[i] == ':') {
49130d5732cSjsing 				type_len = i;
49230d5732cSjsing 				break;
49330d5732cSjsing 			}
49430d5732cSjsing 		}
49530d5732cSjsing 		i++;
49630d5732cSjsing 
49730d5732cSjsing 		if (type_len == 0) {
49830d5732cSjsing 			fprintf(stderr, "Parse error on line %u\n", line_no);
49930d5732cSjsing 			return 3;
50030d5732cSjsing 		}
50130d5732cSjsing 
50230d5732cSjsing 		/* After the colon, there's optional whitespace. */
50330d5732cSjsing 		for (; line[i] != 0 && line[i] != '\n'; i++) {
50430d5732cSjsing 			if (line[i] != ' ' && line[i] != '\t')
50530d5732cSjsing 				break;
50630d5732cSjsing 		}
50730d5732cSjsing 
50830d5732cSjsing 		line[type_len] = 0;
50930d5732cSjsing 		for (j = 0; j < NUM_TYPES; j++) {
51030d5732cSjsing 			if (strcmp(line, NAMES[j]) != 0)
51130d5732cSjsing 				continue;
51230d5732cSjsing 			if (lengths[j] != 0) {
51330d5732cSjsing 				fprintf(stderr, "Duplicate value on line %u\n",
51430d5732cSjsing 				    line_no);
51530d5732cSjsing 				return 3;
51630d5732cSjsing 			}
51730d5732cSjsing 			buf = bufs[j];
51830d5732cSjsing 			buf_len = &lengths[j];
51930d5732cSjsing 			break;
52030d5732cSjsing 		}
52130d5732cSjsing 
52230d5732cSjsing 		if (buf == NULL) {
52330d5732cSjsing 			fprintf(stderr, "Unknown line type on line %u\n",
52430d5732cSjsing 			    line_no);
52530d5732cSjsing 			return 3;
52630d5732cSjsing 		}
52730d5732cSjsing 
52830d5732cSjsing 		if (j == AEAD) {
52930d5732cSjsing 			*buf_len = strlcpy(buf, line + i, BUF_MAX);
53030d5732cSjsing 			for (j = 0; j < BUF_MAX; j++) {
53130d5732cSjsing 				if (buf[j] == '\n')
53230d5732cSjsing 					buf[j] = '\0';
53330d5732cSjsing 			}
53430d5732cSjsing 			continue;
53530d5732cSjsing 		}
53630d5732cSjsing 
53716abd8ebSjsing 		if (line[i] == '"') {
53816abd8ebSjsing 			i++;
53916abd8ebSjsing 			for (j = 0; line[i] != 0 && line[i] != '\n'; i++) {
54016abd8ebSjsing 				if (line[i] == '"')
54116abd8ebSjsing 					break;
54216abd8ebSjsing 				if (j == BUF_MAX) {
54316abd8ebSjsing 					fprintf(stderr, "Too much data on "
54416abd8ebSjsing 					    "line %u (max is %u bytes)\n",
54516abd8ebSjsing 					    line_no, (unsigned) BUF_MAX);
54616abd8ebSjsing 					return 3;
54716abd8ebSjsing 				}
54816abd8ebSjsing 				buf[j++] = line[i];
54916abd8ebSjsing 				*buf_len = *buf_len + 1;
55016abd8ebSjsing 			}
55116abd8ebSjsing 			if (line[i + 1] != 0 && line[i + 1] != '\n') {
55216abd8ebSjsing 				fprintf(stderr, "Trailing data on line %u\n",
55316abd8ebSjsing 				    line_no);
55416abd8ebSjsing 				return 3;
55516abd8ebSjsing 			}
55616abd8ebSjsing 		} else {
55730d5732cSjsing 			for (j = 0; line[i] != 0 && line[i] != '\n'; i++) {
55830d5732cSjsing 				unsigned char v, v2;
55930d5732cSjsing 				v = hex_digit(line[i++]);
56030d5732cSjsing 				if (line[i] == 0 || line[i] == '\n') {
56116abd8ebSjsing 					fprintf(stderr, "Odd-length hex data "
56216abd8ebSjsing 					    "on line %u\n", line_no);
56330d5732cSjsing 					return 3;
56430d5732cSjsing 				}
56530d5732cSjsing 				v2 = hex_digit(line[i]);
56630d5732cSjsing 				if (v > 15 || v2 > 15) {
56716abd8ebSjsing 					fprintf(stderr, "Invalid hex char on "
56816abd8ebSjsing 					    "line %u\n", line_no);
56930d5732cSjsing 					return 3;
57030d5732cSjsing 				}
57130d5732cSjsing 				v <<= 4;
57230d5732cSjsing 				v |= v2;
57330d5732cSjsing 
57430d5732cSjsing 				if (j == BUF_MAX) {
57516abd8ebSjsing 					fprintf(stderr, "Too much hex data on "
57616abd8ebSjsing 					    "line %u (max is %u bytes)\n",
57730d5732cSjsing 					    line_no, (unsigned) BUF_MAX);
57830d5732cSjsing 					return 3;
57930d5732cSjsing 				}
58030d5732cSjsing 				buf[j++] = v;
58130d5732cSjsing 				*buf_len = *buf_len + 1;
58230d5732cSjsing 			}
58330d5732cSjsing 		}
58416abd8ebSjsing 	}
58530d5732cSjsing 
58630d5732cSjsing 	printf("Completed %u test cases\n", num_tests);
58730d5732cSjsing 	printf("PASS\n");
58830d5732cSjsing 	fclose(f);
58930d5732cSjsing 
59030d5732cSjsing 	return 0;
59130d5732cSjsing }
592