Commit a2eef419 authored by Adam Langley's avatar Adam Langley
Browse files

AEAD Tests.

Add tests for AEAD functions: AES-128-GCM, AES-256-GCM and
ChaCha20+Poly1305.
parent 9a864651
Loading
Loading
Loading
Loading

crypto/evp/aeadtest.c

0 → 100644
+386 −0
Original line number Diff line number Diff line
/* ====================================================================
 * Copyright (c) 2011-2013 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    licensing@OpenSSL.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#include <openssl/evp.h>

/* This program tests an AEAD against a series of test vectors from a file. The
 * test vector file consists of key-value lines where the key and value are
 * separated by a colon and optional whitespace. The keys are listed in
 * |NAMES|, below. The values are hex-encoded data.
 *
 * After a number of key-value lines, a blank line or EOF indicates the end of
 * the test case.
 *
 * For example, here's a valid test case:
 *
 *   KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4
 *   NONCE: 978105dfce667bf4
 *   IN: 6a4583908d
 *   AD: b654574932
 *   CT: 5294265a60
 *   TAG: 1d45758621762e061368e68868e2f929
 */

#define BUF_MAX 512

/* These are the different types of line that are found in the input file. */
enum
	{
	KEY = 0,  /* hex encoded key. */
	NONCE,    /* hex encoded nonce. */
	IN,       /* hex encoded plaintext. */
	AD,       /* hex encoded additional data. */
	CT,       /* hex encoded ciphertext (not including the authenticator,
		     which is next. */
	TAG,      /* hex encoded authenticator. */
	NUM_TYPES,
	};

static const char NAMES[6][NUM_TYPES] =
	{
	"KEY",
	"NONCE",
	"IN",
	"AD",
	"CT",
	"TAG",
	};

static unsigned char hex_digit(char h)
	{
	if (h >= '0' && h <= '9')
		return h - '0';
	else if (h >= 'a' && h <= 'f')
		return h - 'a' + 10;
	else if (h >= 'A' && h <= 'F')
		return h - 'A' + 10;
	else
		return 16;
	}

static int run_test_case(const EVP_AEAD* aead,
			 unsigned char bufs[NUM_TYPES][BUF_MAX],
			 const unsigned int lengths[NUM_TYPES],
			 unsigned int line_no)
	{
	EVP_AEAD_CTX ctx;
	ssize_t n;
	size_t un;
	unsigned char out[BUF_MAX+EVP_AEAD_MAX_TAG_LENGTH], out2[BUF_MAX];

	if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY],
			       lengths[TAG], NULL))
		{
		fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
		return 0;
		}

	n = EVP_AEAD_CTX_seal(
		&ctx, out, sizeof(out),
		bufs[NONCE], lengths[NONCE],
		bufs[IN], lengths[IN],
		bufs[AD], lengths[AD]);

	if (n < 0)
		{
		fprintf(stderr, "Failed to run AEAD on line %u\n",
			line_no);
		return 0;
		}

	un = (size_t) n;

	if (un != lengths[CT] + lengths[TAG])
		{
		fprintf(stderr, "Bad output length on line %u: %u vs %u\n",
			line_no, (unsigned) un,
			(unsigned)(lengths[CT] + lengths[TAG]));
		return 0;
		}

	if (memcmp(out, bufs[CT], lengths[CT]) != 0)
		{
		fprintf(stderr, "Bad output on line %u\n", line_no);
		return 0;
		}

	if (memcmp(out + lengths[CT], bufs[TAG], lengths[TAG]) != 0)
		{
		fprintf(stderr, "Bad tag on line %u\n", line_no);
		return 0;
		}

	n = EVP_AEAD_CTX_open(&ctx, out2, lengths[IN],
		      bufs[NONCE], lengths[NONCE],
		      out, un,
		      bufs[AD], lengths[AD]);
	if (n < 0)
		{
		fprintf(stderr, "Failed to decrypt on line %u\n", line_no);
		return 0;
		}

	if ((size_t) n != lengths[IN])
		{
		fprintf(stderr, "Bad decrypt on line %u: %u\n", line_no,
			(unsigned) n);
		return 0;
		}

	out[0] ^= 0x80;
	n = EVP_AEAD_CTX_open(&ctx, out2, lengths[IN],
		      bufs[NONCE], lengths[NONCE],
		      out, un,
		      bufs[AD], lengths[AD]);
	if (n >= 0)
		{
		fprintf(stderr, "Decrypted bad data on line %u\n", line_no);
		return 0;
		}

	EVP_AEAD_CTX_cleanup(&ctx);
	return 1;
	}

int main(int argc, char **argv)
	{
	FILE *f;
	const EVP_AEAD *aead = NULL;
	unsigned int line_no = 0, num_tests = 0, j;

	unsigned char bufs[NUM_TYPES][BUF_MAX];
	unsigned int lengths[NUM_TYPES];

	if (argc != 3)
		{
		fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]);
		return 1;
		}

	if (strcmp(argv[1], "chacha20-poly1305") == 0)
		{
#if !defined(OPENSSL_NO_CHACHA) && !defined(OPENSSL_NO_POLY1305)
		aead = EVP_aead_chacha20_poly1305();
#else
		fprintf(stderr, "No chacha20-poly1305 support. Skipping test.\n");
		return 0;
#endif
		}
	else if (strcmp(argv[1], "aes-128-gcm") == 0)
		{
#ifndef OPENSSL_NO_AES
		aead = EVP_aead_aes_128_gcm();
#else
		fprintf(stderr, "No AES support. Skipping test.\n");
		return 0;
#endif
		}
	else if (strcmp(argv[1], "aes-256-gcm") == 0)
		{
#ifndef OPENSSL_NO_AES
		aead = EVP_aead_aes_256_gcm();
#else
		fprintf(stderr, "No AES support. Skipping test.\n");
		return 0;
#endif
		}
	else
		{
		fprintf(stderr, "Unknown AEAD: %s\n", argv[1]);
		return 2;
		}

	f = fopen(argv[2], "r");
	if (f == NULL)
		{
		perror("failed to open input");
		return 1;
		}

	for (j = 0; j < NUM_TYPES; j++)
		lengths[j] = 0;

	for (;;)
		{
		char line[4096];
		unsigned int i, type_len = 0;

		unsigned char *buf = NULL;
		unsigned int *buf_len;

		if (!fgets(line, sizeof(line), f))
			break;

		line_no++;
		if (line[0] == '#')
			continue;

		if (line[0] == '\n' || line[0] == 0)
			{
			/* Run a test, if possible. */
			char any_values_set = 0;
			for (j = 0; j < NUM_TYPES; j++)
				{
				if (lengths[j] != 0)
					{
					any_values_set = 1;
					break;
					}
				}

			if (!any_values_set)
				continue;

			if (!run_test_case(aead, bufs, lengths, line_no))
				return 4;

			for (j = 0; j < NUM_TYPES; j++)
				lengths[j] = 0;

			num_tests++;
			continue;
			}

		/* Each line looks like:
		 *   TYPE: 0123abc
		 * Where "TYPE" is the type of the data on the line,
		 * e.g. "KEY". */
		for (i = 0; line[i] != 0 && line[i] != '\n'; i++)
			{
			if (line[i] == ':')
				{
				type_len = i;
				break;
				}
			}
		i++;

		if (type_len == 0)
			{
			fprintf(stderr, "Parse error on line %u\n",
				line_no);
			return 3;
			}

		/* After the colon, there's optional whitespace. */
		for (; line[i] != 0 && line[i] != '\n'; i++)
			{
			if (line[i] != ' ' && line[i] != '\t')
				break;
			}

		line[type_len] = 0;
		for (j = 0; j < NUM_TYPES; j++)
			{
			if (strcmp(line, NAMES[j]) != 0)
				continue;
			if (lengths[j] != 0)
				{
				fprintf(stderr, "Duplicate value on line %u\n",
					line_no);
				return 3;
				}
			buf = bufs[j];
			buf_len = &lengths[j];
			}

		if (buf == NULL)
			{
			fprintf(stderr, "Unknown line type on line %u\n",
				line_no);
			return 3;
			}

		j = 0;
		for (; line[i] != 0 && line[i] != '\n'; i++)
			{
			unsigned char v, v2;
			v = hex_digit(line[i++]);
			if (line[i] == 0 || line[i] == '\n')
				{
				fprintf(stderr, "Odd-length hex data"
						" on line %u\n",
					line_no);
				return 3;
				}
			v2 = hex_digit(line[i]);
			if (v > 15 || v2 > 15)
				{
				fprintf(stderr, "Invalid hex char"
						" on line %u\n",
					line_no);
				return 3;
				}
			v <<= 4;
			v |= v2;

			if (j == BUF_MAX)
				{
				fprintf(stderr, "Too much hex data"
						" on line %u (max is"
						" %u bytes)\n",
					line_no, (unsigned) BUF_MAX);
				return 3;
				}
			buf[j++] = v;
			*buf_len = *buf_len + 1;
			}
		}

	printf("Completed %u test cases\n", num_tests);
	printf("PASS\n");
	fclose(f);

	return 0;
	}
+7 −0
Original line number Diff line number Diff line
@@ -1314,6 +1314,13 @@ typedef struct evp_aead_ctx_st {
	void *aead_state;
} EVP_AEAD_CTX;

/* EVP_AEAD_MAX_TAG_LENGTH contains the maximum tag length used by any AEAD
 * defined in this header. */
#define EVP_AEAD_MAX_TAG_LENGTH 16

/* EVP_AEAD_DEFAULT_TAG_LENGTH is a magic value that can be passed to
 * EVP_AEAD_CTX_init to indicate that the default tag length for an AEAD should
 * be used. */
#define EVP_AEAD_DEFAULT_TAG_LENGTH 0

/* EVP_AEAD_init initializes |ctx| for the given AEAD algorithm from |impl|.
+18 −3
Original line number Diff line number Diff line
@@ -67,6 +67,7 @@ V3NAMETEST= v3nametest
ASN1TEST=	asn1test
CHACHATEST=	chachatest
POLY1305TEST=	poly1305test
AEADTEST=	aeadtest

TESTS=		alltests

@@ -91,7 +92,7 @@ OBJ= $(BNTEST).o $(ECTEST).o $(ECDSATEST).o $(ECDHTEST).o $(IDEATEST).o \
	$(RANDTEST).o $(DHTEST).o $(ENGINETEST).o $(CASTTEST).o \
	$(BFTEST).o  $(SSLTEST).o  $(DSATEST).o  $(EXPTEST).o $(RSATEST).o \
	$(EVPTEST).o $(IGETEST).o $(JPAKETEST).o $(ASN1TEST).o $(V3NAMETEST).o \
	$(CHACHATEST).o $(POLY1305TEST).o
	$(CHACHATEST).o $(POLY1305TEST).o $(AEADTEST).o

SRC=	$(BNTEST).c $(ECTEST).c  $(ECDSATEST).c $(ECDHTEST).c $(IDEATEST).c \
	$(MD2TEST).c  $(MD4TEST).c $(MD5TEST).c \
@@ -101,7 +102,7 @@ SRC= $(BNTEST).c $(ECTEST).c $(ECDSATEST).c $(ECDHTEST).c $(IDEATEST).c \
	$(RANDTEST).c $(DHTEST).c $(ENGINETEST).c $(CASTTEST).c \
	$(BFTEST).c  $(SSLTEST).c $(DSATEST).c   $(EXPTEST).c $(RSATEST).c \
	$(EVPTEST).c $(IGETEST).c $(JPAKETEST).c $(SRPTEST).c $(ASN1TEST).c \
	$(V3NAMETEST).c $(CHACHATEST).c $(POLY1305TEST).c
	$(V3NAMETEST).c $(CHACHATEST).c $(POLY1305TEST).c $(AEADTEST).c

EXHEADER= 
HEADER=	$(EXHEADER)
@@ -145,7 +146,7 @@ alltests: \
	test_gen test_req test_pkcs7 test_verify test_dh test_dsa \
	test_ss test_ca test_engine test_evp test_ssl test_tsa test_ige \
	test_jpake test_srp test_cms test_ocsp test_v3name test_chacha \
	test_poly1305
	test_poly1305 test_aead

test_evp: $(EVPTEST) evptests.txt
	../util/shlib_wrap.sh ./$(EVPTEST) evptests.txt
@@ -344,6 +345,17 @@ test_poly1305: $(POLY1305TEST)$(EXE_EXT)
	@echo "Test Poly1305"
	../util/shlib_wrap.sh ./$(POLY1305TEST)

test_aead: $(AEADTEST)$(EXE_EXT)
	@echo "Test ChaCha20+Poly1305"
	../util/shlib_wrap.sh ./$(AEADTEST) chacha20-poly1305 \
		chacha20_poly1305_tests.txt
	@echo "Test AES-128-GCM"
	../util/shlib_wrap.sh ./$(AEADTEST) aes-128-gcm \
		aes_128_gcm_tests.txt
	@echo "Test AES-256-GCM"
	../util/shlib_wrap.sh ./$(AEADTEST) aes-256-gcm \
		aes_256_gcm_tests.txt

lint:
	lint -DLINT $(INCLUDES) $(SRC)>fluff

@@ -426,6 +438,9 @@ $(CHACHATEST)$(EXE_EXT): $(CHACHATEST).o $(DLIBCRYPTO)
$(POLY1305TEST)$(EXE_EXT): $(POLY1305TEST).o $(DLIBCRYPTO)
	@target=$(POLY1305TEST); $(BUILD_CMD)

$(AEADTEST)$(EXE_EXT): $(AEADTEST).o $(DLIBCRYPTO)
	@target=$(AEADTEST); $(BUILD_CMD)

$(RMDTEST)$(EXE_EXT): $(RMDTEST).o $(DLIBCRYPTO)
	@target=$(RMDTEST); $(BUILD_CMD)

+420 −0

File added.

Preview size limit exceeded, changes collapsed.

+420 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading