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