aestest.c revision 1.5
1/*      $OpenBSD: aestest.c,v 1.5 2021/12/13 16:56:49 deraadt Exp $  */
2
3/*
4 * Copyright (c) 2002 Markus Friedl.  All rights reserved.
5 * Copyright (c) 2008 Damien Miller.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * Test kernel AES implementation with test vectors provided by
30 * Dr Brian Gladman:  http://fp.gladman.plus.com/AES/
31 */
32
33#include <sys/types.h>
34#include <crypto/aes.h>
35#include <err.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <unistd.h>
40#include <ctype.h>
41
42static int
43docrypt(const unsigned char *key, size_t klen, const unsigned char *in,
44    unsigned char *out, size_t len, int do_encrypt)
45{
46	AES_CTX ctx;
47	int error = 0;
48
49	memset(&ctx, 0, sizeof(ctx));
50	error = AES_Setkey(&ctx, key, klen);
51	if (error)
52		return -1;
53	if (do_encrypt)
54		AES_Encrypt(&ctx, in, out);
55	else
56		AES_Decrypt(&ctx, in, out);
57	return 0;
58}
59
60static int
61match(unsigned char *a, unsigned char *b, size_t len)
62{
63	size_t i;
64
65	if (memcmp(a, b, len) == 0)
66		return (1);
67
68	warnx("decrypt/plaintext mismatch");
69
70	for (i = 0; i < len; i++)
71		printf("%2.2x", a[i]);
72	printf("\n");
73	for (i = 0; i < len; i++)
74		printf("%2.2x", b[i]);
75	printf("\n");
76
77	return (0);
78}
79
80/*
81 * Match expected substring at start of line. If sequence is match, return
82 * a pointer to the first character in the string past the sequence and and
83 * following whitespace.
84 * returns NULL is the start of the line does not match.
85 */
86static const char *
87startswith(const char *line, const char *startswith)
88{
89	size_t len = strlen(startswith);
90
91	if (strncmp(line, startswith, len) != 0)
92		return NULL;
93	line = line + len;
94	while (isspace((unsigned char)*line))
95		line++;
96	return line;
97}
98
99/* Read a hex string and convert to bytes */
100static void
101parsehex(const char *hex, u_char **s, u_int *lenp)
102{
103	u_char *ret, v;
104	u_int i, len;
105	char c;
106
107	len = i = 0;
108	ret = NULL;
109	v = 0;
110	while ((c = *(hex++)) != '\0') {
111		if (strchr(" \t\r\n", c) != NULL)
112			continue;
113		if (c >= '0' && c <= '9')
114			v |= c - '0';
115		else if (c >= 'a' && c <= 'f')
116			v |= 10 + (c - 'a');
117		else if (c >= 'A' && c <= 'F')
118			v |= 10 + c - 'A';
119		else
120			errx(1, "%s: invalid character \"%c\" in hex string",
121			    __func__, c);
122		switch (++i) {
123		case 1:
124			v <<= 4;
125			break;
126		case 2:
127			if ((ret = realloc(ret, ++len)) == NULL)
128				errx(1, "realloc(%u)", len);
129			ret[len - 1] = v;
130			v = 0;
131			i = 0;
132		}
133	}
134	if (i != 0)
135		errx(1, "%s: odd number of characters in hex string", __func__);
136	*lenp = len;
137	*s = ret;
138}
139
140static int
141do_tests(const char *filename, int test_num, u_char *key, u_int keylen,
142    u_char *plaintext, u_char *ciphertext, u_int textlen)
143{
144	char result[32];
145	int fail = 0;
146
147	/* Encrypt test */
148	if (docrypt(key, keylen, plaintext, result, textlen, 1) < 0) {
149		warnx("encryption failed");
150		fail++;
151	} else if (!match(result, ciphertext, textlen)) {
152		fail++;
153	} else
154		printf("OK encrypt test vector %s %u\n", filename, test_num);
155
156	/* Decrypt test */
157	if (docrypt(key, keylen, ciphertext, result, textlen, 0) < 0) {
158		warnx("decryption failed");
159		fail++;
160	} else if (!match(result, plaintext, textlen)) {
161		fail++;
162	} else
163		printf("OK decrypt test vector %s %u\n", filename, test_num);
164
165	return fail;
166}
167
168static int
169run_file(const char *filename)
170{
171	FILE *tv;
172	char buf[1024], *eol;
173	const char *cp, *errstr;
174	int lnum = 0, fail = 0;
175	u_char *key, *plaintext, *ciphertext;
176	u_int keylen, textlen, tmp;
177	int blocksize, keysize, test;
178
179	if ((tv = fopen(filename, "r")) == NULL)
180		err(1, "fopen(\"%s\")", filename);
181
182	keylen = textlen = tmp = 0;
183	key = ciphertext = plaintext = NULL;
184	blocksize = keysize = test = -1;
185	while ((fgets(buf, sizeof(buf), tv)) != NULL) {
186		lnum++;
187		eol = buf + strlen(buf) - 1;
188		if (*eol != '\n')
189			errx(1, "line %d: too long", lnum);
190		if (eol > buf && *(eol - 1) == '\r')
191			eol--;
192		*eol = '\0';
193		if ((cp = startswith(buf, "BLOCKSIZE=")) != NULL) {
194			if (blocksize != -1)
195				errx(1, "line %d: blocksize already set", lnum);
196			blocksize = (int)strtonum(cp, 128, 128, &errstr);
197			if (errstr)
198				errx(1, "line %d: blocksize is %s: \"%s\"",
199				    lnum, errstr, cp);
200		} else if ((cp = startswith(buf, "KEYSIZE=")) != NULL) {
201			if (keysize != -1)
202				errx(1, "line %d: keysize already set", lnum);
203			keysize = (int)strtonum(cp, 128, 256, &errstr);
204			if (errstr)
205				errx(1, "line %d: keysize is %s: \"%s\"",
206				    lnum, errstr, cp);
207			if (keysize != 128 && keysize != 256)
208				errx(1, "line %d: XXX only 128 or 256 "
209				    "bit keys for now (keysize = %d)",
210				    lnum, keysize);
211		} else if ((cp = startswith(buf, "PT=")) != NULL) {
212			if (plaintext != NULL)
213				free(plaintext);
214			parsehex(cp, &plaintext, &tmp);
215			if (tmp * 8 != (u_int)blocksize)
216				errx(1, "line %d: plaintext len %u != "
217				    "blocklen %d", lnum, tmp, blocksize);
218			if (textlen != 0) {
219				if (textlen != tmp)
220					errx(1, "line %d: plaintext len %u != "
221					    "ciphertext len %d", lnum, tmp,
222					    textlen);
223			} else
224				textlen = tmp;
225		} else if ((cp = startswith(buf, "CT=")) != NULL) {
226			if (ciphertext != NULL)
227				free(ciphertext);
228			parsehex(cp, &ciphertext, &tmp);
229			if (tmp * 8 != (u_int)blocksize)
230				errx(1, "line %d: ciphertext len %u != "
231				    "blocklen %d", lnum, tmp, blocksize);
232			if (textlen != 0) {
233				if (textlen != tmp)
234					errx(1, "line %d: ciphertext len %u != "
235					    "plaintext len %d", lnum, tmp,
236					    textlen);
237			} else
238				textlen = tmp;
239		} else if ((cp = startswith(buf, "KEY=")) != NULL) {
240			if (key != NULL)
241				free(key);
242			parsehex(cp, &key, &keylen);
243			if (keylen * 8 != (u_int)keysize)
244				errx(1, "line %d: ciphertext len %u != "
245				    "blocklen %d", lnum, tmp, textlen);
246		} else if ((cp = startswith(buf, "TEST=")) != NULL) {
247			if (plaintext == NULL || ciphertext == NULL ||
248			    key == NULL || blocksize == -1 || keysize == -1) {
249				if (test != -1)
250					errx(1, "line %d: new test before "
251					    "parameters", lnum);
252				goto parsetest;
253			}
254			/* do the tests */
255			fail += do_tests(filename, test, key, keylen,
256			    plaintext, ciphertext, textlen);
257 parsetest:
258			test = (int)strtonum(cp, 0, 65536, &errstr);
259			if (errstr)
260				errx(1, "line %d: test is %s: \"%s\"",
261				    lnum, errstr, cp);
262		} else {
263			/* don't care */
264			continue;
265		}
266	}
267	fclose(tv);
268
269	return fail;
270}
271
272int
273main(int argc, char **argv)
274{
275	int fail = 0, i;
276
277	if (argc < 2)
278		errx(1, "usage: aestest [test-vector-file]");
279
280	for (i = 1; i < argc; i++)
281		fail += run_file(argv[1]);
282
283	return fail > 0 ? 1 : 0;
284}
285