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