xref: /dragonfly/test/testcases/crypto/aes/aestest.c (revision 0fe46dc6)
1 /*      $OpenBSD: djm $  */
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 crypto(4) AES with test vectors provided by Dr Brian Gladman:
30  * http://fp.gladman.plus.com/AES/
31  */
32 
33 #include <sys/types.h>
34 #include <sys/param.h>
35 #include <sys/ioctl.h>
36 #include <sys/sysctl.h>
37 #include <crypto/cryptodev.h>
38 #include <err.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <ctype.h>
45 
46 static int
47 syscrypt(const unsigned char *key, size_t klen, const unsigned char *in,
48     unsigned char *out, size_t len, int do_encrypt)
49 {
50 	struct session_op session;
51 	struct crypt_op cryp;
52 	int cryptodev_fd = -1, fd = -1;
53 	u_char iv[32];
54 
55 	/*
56 	 * Kludge; the kernel doesn't support ECB encryption so we
57 	 * use a all-zero IV and encrypt a single block only, so the
58 	 * result should be the same.
59 	 */
60 	bzero(iv, sizeof(iv));
61 
62 	if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
63 		warn("/dev/crypto");
64 		goto err;
65 	}
66 	if (ioctl(cryptodev_fd, CRIOGET, &fd) == -1) {
67 		warn("CRIOGET failed");
68 		goto err;
69 	}
70 	memset(&session, 0, sizeof(session));
71 	session.cipher = CRYPTO_AES_CBC;
72 	session.key = (caddr_t) key;
73 	session.keylen = klen;
74 	if (ioctl(fd, CIOCGSESSION, &session) == -1) {
75 		warn("CIOCGSESSION");
76 		goto err;
77 	}
78 	memset(&cryp, 0, sizeof(cryp));
79 	cryp.ses = session.ses;
80 	cryp.op = do_encrypt ? COP_ENCRYPT : COP_DECRYPT;
81 	cryp.flags = 0;
82 	cryp.len = len;
83 	cryp.src = (caddr_t) in;
84 	cryp.dst = (caddr_t) out;
85 	cryp.iv = (caddr_t) iv;
86 	cryp.mac = 0;
87 	if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
88 		warn("CIOCCRYPT");
89 		goto err;
90 	}
91 	if (ioctl(fd, CIOCFSESSION, &session.ses) == -1) {
92 		warn("CIOCFSESSION");
93 		goto err;
94 	}
95 	close(fd);
96 	close(cryptodev_fd);
97 	return (0);
98 
99 err:
100 	if (fd != -1)
101 		close(fd);
102 	if (cryptodev_fd != -1)
103 		close(cryptodev_fd);
104 	return (-1);
105 }
106 
107 static int
108 getallowsoft(void)
109 {
110 	int mib[2], old;
111 	size_t olen;
112 
113 	olen = sizeof(old);
114 
115 	if (sysctlbyname("kern.cryptodevallowsoft", &old, &olen, NULL, 0) < 0)
116 		err(1, "sysctl failed");
117 
118 	return old;
119 }
120 
121 static void
122 setallowsoft(int new)
123 {
124 	int mib[2], old;
125 	size_t olen, nlen;
126 
127 	olen = nlen = sizeof(new);
128 
129 	if (sysctlbyname("kern.cryptodevallowsoft", &old, &olen, &new, nlen) < 0)
130 		err(1, "sysctl failed");
131 }
132 
133 static int
134 match(unsigned char *a, unsigned char *b, size_t len)
135 {
136 	size_t i;
137 
138 	if (memcmp(a, b, len) == 0)
139 		return (1);
140 
141 	warnx("decrypt/plaintext mismatch");
142 
143 	for (i = 0; i < len; i++)
144 		printf("%2.2x", a[i]);
145 	printf("\n");
146 	for (i = 0; i < len; i++)
147 		printf("%2.2x", b[i]);
148 	printf("\n");
149 
150 	return (0);
151 }
152 
153 /*
154  * Match expected substring at start of line. If sequence is match, return
155  * a pointer to the first character in the string past the sequence and and
156  * following whitespace.
157  * returns NULL is the start of the line does not match.
158  */
159 static const char *
160 startswith(const char *line, const char *startswith)
161 {
162 	size_t len = strlen(startswith);
163 
164 	if (strncmp(line, startswith, len) != 0)
165 		return NULL;
166 	line = line + len;
167 	while (isspace(*line))
168 		line++;
169 	return line;
170 }
171 
172 /* Read a hex string and convert to bytes */
173 static void
174 parsehex(const char *hex, u_char **s, u_int *lenp)
175 {
176 	u_char *ret, v;
177 	u_int i, len;
178 	char c;
179 
180 	len = i = 0;
181 	ret = NULL;
182 	v = 0;
183 	while ((c = *(hex++)) != '\0') {
184 		if (strchr(" \t\r\n", c) != NULL)
185 			continue;
186 		if (c >= '0' && c <= '9')
187 			v |= c - '0';
188 		else if (c >= 'a' && c <= 'f')
189 			v |= 10 + (c - 'a');
190 		else if (c >= 'A' && c <= 'F')
191 			v |= 10 + c - 'A';
192 		else
193 			errx(1, "%s: invalid character \"%c\" in hex string",
194 			    __func__, c);
195 		switch (++i) {
196 		case 1:
197 			v <<= 4;
198 			break;
199 		case 2:
200 			if ((ret = realloc(ret, ++len)) == NULL)
201 				errx(1, "realloc(%u)", len);
202 			ret[len - 1] = v;
203 			v = 0;
204 			i = 0;
205 		}
206 	}
207 	if (i != 0)
208 		errx(1, "%s: odd number of characters in hex string", __func__);
209 	*lenp = len;
210 	*s = ret;
211 }
212 
213 static int
214 do_tests(const char *filename, int test_num, u_char *key, u_int keylen,
215     u_char *plaintext, u_char *ciphertext, u_int textlen)
216 {
217 	char result[32];
218 	int fail = 0;
219 
220 	/* Encrypt test */
221 	if (syscrypt(key, keylen, plaintext, result, textlen, 1) < 0) {
222 		warnx("encrypt with /dev/crypto failed");
223 		fail++;
224 	} else if (!match(result, ciphertext, textlen)) {
225 		fail++;
226 	} else
227 		printf("OK encrypt test vector %s %u\n", filename, test_num);
228 
229 	/* Decrypt test */
230 	if (syscrypt(key, keylen, ciphertext, result, textlen, 0) < 0) {
231 		warnx("decrypt with /dev/crypto failed");
232 		fail++;
233 	} else if (!match(result, plaintext, textlen)) {
234 		fail++;
235 	} else
236 		printf("OK decrypt test vector %s %u\n", filename, test_num);
237 
238 	return fail;
239 }
240 
241 static int
242 run_file(const char *filename)
243 {
244 	FILE *tv;
245 	char buf[1024], *eol;
246 	const char *cp, *errstr;
247 	int lnum = 0, fail = 0;
248 	u_char *key, *plaintext, *ciphertext;
249 	u_int keylen, textlen, tmp;
250 	int blocksize, keysize, test;
251 
252 	if ((tv = fopen(filename, "r")) == NULL)
253 		err(1, "fopen(\"%s\")", filename);
254 
255 	keylen = textlen = tmp = 0;
256 	key = ciphertext = plaintext = NULL;
257 	blocksize = keysize = test = -1;
258 	while ((fgets(buf, sizeof(buf), tv)) != NULL) {
259 		lnum++;
260 		eol = buf + strlen(buf) - 1;
261 		if (*eol != '\n')
262 			errx(1, "line %d: too long", lnum);
263 		if (eol > buf && *(eol - 1) == '\r')
264 			eol--;
265 		*eol = '\0';
266 		if ((cp = startswith(buf, "BLOCKSIZE=")) != NULL) {
267 			if (blocksize != -1)
268 				errx(1, "line %d: blocksize already set", lnum);
269 			blocksize = (int)strtonum(cp, 128, 128, &errstr);
270 			if (errstr)
271 				errx(1, "line %d: blocksize is %s: \"%s\"",
272 				    lnum, errstr, cp);
273 		} else if ((cp = startswith(buf, "KEYSIZE=")) != NULL) {
274 			if (keysize != -1)
275 				errx(1, "line %d: keysize already set", lnum);
276 			keysize = (int)strtonum(cp, 128, 256, &errstr);
277 			if (errstr)
278 				errx(1, "line %d: keysize is %s: \"%s\"",
279 				    lnum, errstr, cp);
280 			if (keysize != 128 && keysize != 256)
281 				errx(1, "line %d: XXX only 128 or 256 "
282 				    "bit keys for now (keysize = %d)",
283 				    lnum, keysize);
284 		} else if ((cp = startswith(buf, "PT=")) != NULL) {
285 			if (plaintext != NULL)
286 				free(plaintext);
287 			parsehex(cp, &plaintext, &tmp);
288 			if (tmp * 8 != (u_int)blocksize)
289 				errx(1, "line %d: plaintext len %u != "
290 				    "blocklen %d", lnum, tmp, blocksize);
291 			if (textlen != 0) {
292 				if (textlen != tmp)
293 					errx(1, "line %d: plaintext len %u != "
294 					    "ciphertext len %d", lnum, tmp,
295 					    textlen);
296 			} else
297 				textlen = tmp;
298 		} else if ((cp = startswith(buf, "CT=")) != NULL) {
299 			if (ciphertext != NULL)
300 				free(ciphertext);
301 			parsehex(cp, &ciphertext, &tmp);
302 			if (tmp * 8 != (u_int)blocksize)
303 				errx(1, "line %d: ciphertext len %u != "
304 				    "blocklen %d", lnum, tmp, blocksize);
305 			if (textlen != 0) {
306 				if (textlen != tmp)
307 					errx(1, "line %d: ciphertext len %u != "
308 					    "plaintext len %d", lnum, tmp,
309 					    textlen);
310 			} else
311 				textlen = tmp;
312 		} else if ((cp = startswith(buf, "KEY=")) != NULL) {
313 			if (key != NULL)
314 				free(key);
315 			parsehex(cp, &key, &keylen);
316 			if (keylen * 8 != (u_int)keysize)
317 				errx(1, "line %d: ciphertext len %u != "
318 				    "blocklen %d", lnum, tmp, textlen);
319 		} else if ((cp = startswith(buf, "TEST=")) != NULL) {
320 			if (plaintext == NULL || ciphertext == NULL ||
321 			    key == NULL || blocksize == -1 || keysize == -1) {
322 				if (test != -1)
323 					errx(1, "line %d: new test before "
324 					    "parameters", lnum);
325 				goto parsetest;
326 			}
327 			/* do the tests */
328 			fail += do_tests(filename, test, key, keylen,
329 			    plaintext, ciphertext, textlen);
330  parsetest:
331 			test = (int)strtonum(cp, 0, 65536, &errstr);
332 			if (errstr)
333 				errx(1, "line %d: test is %s: \"%s\"",
334 				    lnum, errstr, cp);
335 		} else {
336 			/* don't care */
337 			continue;
338 		}
339 	}
340 	fclose(tv);
341 
342 	return fail;
343 }
344 
345 int
346 main(int argc, char **argv)
347 {
348 	int allowed = 0, fail = 0, i;
349 
350 	if (argc < 2)
351 		errx(1, "usage: aestest [test-vector-file]");
352 
353 	if (geteuid() == 0) {
354 		allowed = getallowsoft();
355 		if (allowed == 0)
356 			setallowsoft(1);
357 	}
358 
359 	for (i = 1; i < argc; i++)
360 		fail += run_file(argv[1]);
361 
362 	if (geteuid() == 0 && allowed == 0)
363 		setallowsoft(0);
364 
365 	return fail > 0 ? 1 : 0;
366 }
367