4 * Copyright (c) 2002 Markus Friedl. All rights reserved.
5 * Copyright (c) 2008 Damien Miller. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
29 * Test crypto(4) AES with test vectors provided by Dr Brian Gladman:
30 * http://fp.gladman.plus.com/AES/
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>
47 syscrypt(const unsigned char *key, size_t klen, const unsigned char *in,
48 unsigned char *out, size_t len, int do_encrypt)
50 struct session_op session;
52 int cryptodev_fd = -1, fd = -1;
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.
60 bzero(iv, sizeof(iv));
62 if ((cryptodev_fd = open("/dev/crypto", O_RDWR, 0)) < 0) {
66 if (ioctl(cryptodev_fd, CRIOGET, &fd) == -1) {
67 warn("CRIOGET failed");
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) {
78 memset(&cryp, 0, sizeof(cryp));
79 cryp.ses = session.ses;
80 cryp.op = do_encrypt ? COP_ENCRYPT : COP_DECRYPT;
83 cryp.src = (caddr_t) in;
84 cryp.dst = (caddr_t) out;
85 cryp.iv = (caddr_t) iv;
87 if (ioctl(fd, CIOCCRYPT, &cryp) == -1) {
91 if (ioctl(fd, CIOCFSESSION, &session.ses) == -1) {
102 if (cryptodev_fd != -1)
115 if (sysctlbyname("kern.cryptodevallowsoft", &old, &olen, NULL, 0) < 0)
116 err(1, "sysctl failed");
122 setallowsoft(int new)
127 olen = nlen = sizeof(new);
129 if (sysctlbyname("kern.cryptodevallowsoft", &old, &olen, &new, nlen) < 0)
130 err(1, "sysctl failed");
134 match(unsigned char *a, unsigned char *b, size_t len)
138 if (memcmp(a, b, len) == 0)
141 warnx("decrypt/plaintext mismatch");
143 for (i = 0; i < len; i++)
144 printf("%2.2x", a[i]);
146 for (i = 0; i < len; i++)
147 printf("%2.2x", b[i]);
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.
160 startswith(const char *line, const char *startswith)
162 size_t len = strlen(startswith);
164 if (strncmp(line, startswith, len) != 0)
167 while (isspace(*line))
172 /* Read a hex string and convert to bytes */
174 parsehex(const char *hex, u_char **s, u_int *lenp)
183 while ((c = *(hex++)) != '\0') {
184 if (strchr(" \t\r\n", c) != NULL)
186 if (c >= '0' && c <= '9')
188 else if (c >= 'a' && c <= 'f')
190 else if (c >= 'A' && c <= 'F')
193 errx(1, "%s: invalid character \"%c\" in hex string",
200 if ((ret = realloc(ret, ++len)) == NULL)
201 errx(1, "realloc(%u)", len);
208 errx(1, "%s: odd number of characters in hex string", __func__);
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)
221 if (syscrypt(key, keylen, plaintext, result, textlen, 1) < 0) {
222 warnx("encrypt with /dev/crypto failed");
224 } else if (!match(result, ciphertext, textlen)) {
227 printf("OK encrypt test vector %s %u\n", filename, test_num);
230 if (syscrypt(key, keylen, ciphertext, result, textlen, 0) < 0) {
231 warnx("decrypt with /dev/crypto failed");
233 } else if (!match(result, plaintext, textlen)) {
236 printf("OK decrypt test vector %s %u\n", filename, test_num);
242 run_file(const char *filename)
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;
252 if ((tv = fopen(filename, "r")) == NULL)
253 err(1, "fopen(\"%s\")", filename);
255 keylen = textlen = tmp = 0;
256 key = ciphertext = plaintext = NULL;
257 blocksize = keysize = test = -1;
258 while ((fgets(buf, sizeof(buf), tv)) != NULL) {
260 eol = buf + strlen(buf) - 1;
262 errx(1, "line %d: too long", lnum);
263 if (eol > buf && *(eol - 1) == '\r')
266 if ((cp = startswith(buf, "BLOCKSIZE=")) != NULL) {
268 errx(1, "line %d: blocksize already set", lnum);
269 blocksize = (int)strtonum(cp, 128, 128, &errstr);
271 errx(1, "line %d: blocksize is %s: \"%s\"",
273 } else if ((cp = startswith(buf, "KEYSIZE=")) != NULL) {
275 errx(1, "line %d: keysize already set", lnum);
276 keysize = (int)strtonum(cp, 128, 256, &errstr);
278 errx(1, "line %d: keysize is %s: \"%s\"",
280 if (keysize != 128 && keysize != 256)
281 errx(1, "line %d: XXX only 128 or 256 "
282 "bit keys for now (keysize = %d)",
284 } else if ((cp = startswith(buf, "PT=")) != NULL) {
285 if (plaintext != NULL)
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);
293 errx(1, "line %d: plaintext len %u != "
294 "ciphertext len %d", lnum, tmp,
298 } else if ((cp = startswith(buf, "CT=")) != NULL) {
299 if (ciphertext != NULL)
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);
307 errx(1, "line %d: ciphertext len %u != "
308 "plaintext len %d", lnum, tmp,
312 } else if ((cp = startswith(buf, "KEY=")) != NULL) {
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) {
323 errx(1, "line %d: new test before "
328 fail += do_tests(filename, test, key, keylen,
329 plaintext, ciphertext, textlen);
331 test = (int)strtonum(cp, 0, 65536, &errstr);
333 errx(1, "line %d: test is %s: \"%s\"",
346 main(int argc, char **argv)
348 int allowed = 0, fail = 0, i;
351 errx(1, "usage: aestest [test-vector-file]");
353 if (geteuid() == 0) {
354 allowed = getallowsoft();
359 for (i = 1; i < argc; i++)
360 fail += run_file(argv[1]);
362 if (geteuid() == 0 && allowed == 0)
365 return fail > 0 ? 1 : 0;