1 /* $OpenBSD: aestest.c,v 1.1 2008/06/12 19:42:48 djm 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 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 mib[0] = CTL_KERN; 116 mib[1] = KERN_CRYPTODEVALLOWSOFT; 117 if (sysctl(mib, 2, &old, &olen, NULL, 0) < 0) 118 err(1, "sysctl failed"); 119 120 return old; 121 } 122 123 static void 124 setallowsoft(int new) 125 { 126 int mib[2], old; 127 size_t olen, nlen; 128 129 olen = nlen = sizeof(new); 130 131 mib[0] = CTL_KERN; 132 mib[1] = KERN_CRYPTODEVALLOWSOFT; 133 134 if (sysctl(mib, 2, &old, &olen, &new, nlen) < 0) 135 err(1, "sysctl failed"); 136 } 137 138 static int 139 match(unsigned char *a, unsigned char *b, size_t len) 140 { 141 size_t i; 142 143 if (memcmp(a, b, len) == 0) 144 return (1); 145 146 warnx("decrypt/plaintext mismatch"); 147 148 for (i = 0; i < len; i++) 149 printf("%2.2x", a[i]); 150 printf("\n"); 151 for (i = 0; i < len; i++) 152 printf("%2.2x", b[i]); 153 printf("\n"); 154 155 return (0); 156 } 157 158 /* 159 * Match expected substring at start of line. If sequence is match, return 160 * a pointer to the first character in the string past the sequence and and 161 * following whitespace. 162 * returns NULL is the start of the line does not match. 163 */ 164 static const char * 165 startswith(const char *line, const char *startswith) 166 { 167 size_t len = strlen(startswith); 168 169 if (strncmp(line, startswith, len) != 0) 170 return NULL; 171 line = line + len; 172 while (isspace(*line)) 173 line++; 174 return line; 175 } 176 177 /* Read a hex string and convert to bytes */ 178 static void 179 parsehex(const char *hex, u_char **s, u_int *lenp) 180 { 181 u_char *ret, v; 182 u_int i, len; 183 char c; 184 185 len = i = 0; 186 ret = NULL; 187 v = 0; 188 while ((c = *(hex++)) != '\0') { 189 if (strchr(" \t\r\n", c) != NULL) 190 continue; 191 if (c >= '0' && c <= '9') 192 v |= c - '0'; 193 else if (c >= 'a' && c <= 'f') 194 v |= 10 + (c - 'a'); 195 else if (c >= 'A' && c <= 'F') 196 v |= 10 + c - 'A'; 197 else 198 errx(1, "%s: invalid character \"%c\" in hex string", 199 __func__, c); 200 switch (++i) { 201 case 1: 202 v <<= 4; 203 break; 204 case 2: 205 if ((ret = realloc(ret, ++len)) == NULL) 206 errx(1, "realloc(%u)", len); 207 ret[len - 1] = v; 208 v = 0; 209 i = 0; 210 } 211 } 212 if (i != 0) 213 errx(1, "%s: odd number of characters in hex string", __func__); 214 *lenp = len; 215 *s = ret; 216 } 217 218 static int 219 do_tests(const char *filename, int test_num, u_char *key, u_int keylen, 220 u_char *plaintext, u_char *ciphertext, u_int textlen) 221 { 222 char result[32]; 223 int fail = 0; 224 225 /* Encrypt test */ 226 if (syscrypt(key, keylen, plaintext, result, textlen, 1) < 0) { 227 warnx("encrypt with /dev/crypto failed"); 228 fail++; 229 } else if (!match(result, ciphertext, textlen)) { 230 fail++; 231 } else 232 printf("OK encrypt test vector %s %u\n", filename, test_num); 233 234 /* Decrypt test */ 235 if (syscrypt(key, keylen, ciphertext, result, textlen, 0) < 0) { 236 warnx("decrypt with /dev/crypto failed"); 237 fail++; 238 } else if (!match(result, plaintext, textlen)) { 239 fail++; 240 } else 241 printf("OK decrypt test vector %s %u\n", filename, test_num); 242 243 return fail; 244 } 245 246 static int 247 run_file(const char *filename) 248 { 249 FILE *tv; 250 char buf[1024], *eol; 251 const char *cp, *errstr; 252 int lnum = 0, fail = 0; 253 u_char *key, *plaintext, *ciphertext; 254 u_int keylen, textlen, tmp; 255 int blocksize, keysize, test; 256 257 if ((tv = fopen(filename, "r")) == NULL) 258 err(1, "fopen(\"%s\")", filename); 259 260 keylen = textlen = tmp = 0; 261 key = ciphertext = plaintext = NULL; 262 blocksize = keysize = test = -1; 263 while ((fgets(buf, sizeof(buf), tv)) != NULL) { 264 lnum++; 265 eol = buf + strlen(buf) - 1; 266 if (*eol != '\n') 267 errx(1, "line %d: too long", lnum); 268 if (eol > buf && *(eol - 1) == '\r') 269 eol--; 270 *eol = '\0'; 271 if ((cp = startswith(buf, "BLOCKSIZE=")) != NULL) { 272 if (blocksize != -1) 273 errx(1, "line %d: blocksize already set", lnum); 274 blocksize = (int)strtonum(cp, 128, 128, &errstr); 275 if (errstr) 276 errx(1, "line %d: blocksize is %s: \"%s\"", 277 lnum, errstr, cp); 278 } else if ((cp = startswith(buf, "KEYSIZE=")) != NULL) { 279 if (keysize != -1) 280 errx(1, "line %d: keysize already set", lnum); 281 keysize = (int)strtonum(cp, 128, 256, &errstr); 282 if (errstr) 283 errx(1, "line %d: keysize is %s: \"%s\"", 284 lnum, errstr, cp); 285 if (keysize != 128 && keysize != 256) 286 errx(1, "line %d: XXX only 128 or 256 " 287 "bit keys for now (keysize = %d)", 288 lnum, keysize); 289 } else if ((cp = startswith(buf, "PT=")) != NULL) { 290 if (plaintext != NULL) 291 free(plaintext); 292 parsehex(cp, &plaintext, &tmp); 293 if (tmp * 8 != (u_int)blocksize) 294 errx(1, "line %d: plaintext len %u != " 295 "blocklen %d", lnum, tmp, blocksize); 296 if (textlen != 0) { 297 if (textlen != tmp) 298 errx(1, "line %d: plaintext len %u != " 299 "ciphertext len %d", lnum, tmp, 300 textlen); 301 } else 302 textlen = tmp; 303 } else if ((cp = startswith(buf, "CT=")) != NULL) { 304 if (ciphertext != NULL) 305 free(ciphertext); 306 parsehex(cp, &ciphertext, &tmp); 307 if (tmp * 8 != (u_int)blocksize) 308 errx(1, "line %d: ciphertext len %u != " 309 "blocklen %d", lnum, tmp, blocksize); 310 if (textlen != 0) { 311 if (textlen != tmp) 312 errx(1, "line %d: ciphertext len %u != " 313 "plaintext len %d", lnum, tmp, 314 textlen); 315 } else 316 textlen = tmp; 317 } else if ((cp = startswith(buf, "KEY=")) != NULL) { 318 if (key != NULL) 319 free(key); 320 parsehex(cp, &key, &keylen); 321 if (keylen * 8 != (u_int)keysize) 322 errx(1, "line %d: ciphertext len %u != " 323 "blocklen %d", lnum, tmp, textlen); 324 } else if ((cp = startswith(buf, "TEST=")) != NULL) { 325 if (plaintext == NULL || ciphertext == NULL || 326 key == NULL || blocksize == -1 || keysize == -1) { 327 if (test != -1) 328 errx(1, "line %d: new test before " 329 "parameters", lnum); 330 goto parsetest; 331 } 332 /* do the tests */ 333 fail += do_tests(filename, test, key, keylen, 334 plaintext, ciphertext, textlen); 335 parsetest: 336 test = (int)strtonum(cp, 0, 65536, &errstr); 337 if (errstr) 338 errx(1, "line %d: test is %s: \"%s\"", 339 lnum, errstr, cp); 340 } else { 341 /* don't care */ 342 continue; 343 } 344 } 345 fclose(tv); 346 347 return fail; 348 } 349 350 int 351 main(int argc, char **argv) 352 { 353 int allowed = 0, fail = 0, i; 354 355 if (argc < 2) 356 errx(1, "usage: aestest [test-vector-file]"); 357 358 if (geteuid() == 0) { 359 allowed = getallowsoft(); 360 if (allowed == 0) 361 setallowsoft(1); 362 } 363 364 for (i = 1; i < argc; i++) 365 fail += run_file(argv[1]); 366 367 if (geteuid() == 0 && allowed == 0) 368 setallowsoft(0); 369 370 return fail > 0 ? 1 : 0; 371 } 372