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