blob: ff2244c97241039a21d5a262774eafe3555217b3 [file] [log] [blame]
Adam Langleydfe30532014-06-20 12:00:00 -07001/* Copyright (c) 2014, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15#include <stdint.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19
20#include <openssl/aead.h>
David Benjamina70c75c2014-09-11 19:11:15 -040021#include <openssl/crypto.h>
Adam Langleydfe30532014-06-20 12:00:00 -070022
23/* This program tests an AEAD against a series of test vectors from a file. The
24 * test vector file consists of key-value lines where the key and value are
25 * separated by a colon and optional whitespace. The keys are listed in
26 * |NAMES|, below. The values are hex-encoded data.
27 *
28 * After a number of key-value lines, a blank line or EOF indicates the end of
29 * the test case.
30 *
31 * For example, here's a valid test case:
32 *
33 * KEY: 5a19f3173586b4c42f8412f4d5a786531b3231753e9e00998aec12fda8df10e4
34 * NONCE: 978105dfce667bf4
35 * IN: 6a4583908d
36 * AD: b654574932
37 * CT: 5294265a60
38 * TAG: 1d45758621762e061368e68868e2f929
39 */
40
41#define BUF_MAX 512
42
43/* These are the different types of line that are found in the input file. */
44enum {
45 KEY = 0, /* hex encoded key. */
46 NONCE, /* hex encoded nonce. */
47 IN, /* hex encoded plaintext. */
48 AD, /* hex encoded additional data. */
49 CT, /* hex encoded ciphertext (not including the authenticator,
50 which is next). */
51 TAG, /* hex encoded authenticator. */
52 NUM_TYPES,
53};
54
55static const char NAMES[6][NUM_TYPES] = {
56 "KEY", "NONCE", "IN", "AD", "CT", "TAG",
57};
58
59static unsigned char hex_digit(char h) {
60 if (h >= '0' && h <= '9') {
61 return h - '0';
62 } else if (h >= 'a' && h <= 'f') {
63 return h - 'a' + 10;
64 } else if (h >= 'A' && h <= 'F') {
65 return h - 'A' + 10;
66 } else {
67 return 16;
68 }
69}
70
71static int run_test_case(const EVP_AEAD *aead,
72 unsigned char bufs[NUM_TYPES][BUF_MAX],
73 const unsigned int lengths[NUM_TYPES],
74 unsigned int line_no) {
75 EVP_AEAD_CTX ctx;
76 size_t ciphertext_len, plaintext_len;
77 unsigned char out[BUF_MAX + EVP_AEAD_MAX_OVERHEAD], out2[BUF_MAX];
78
79 if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
80 NULL)) {
81 fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
82 return 0;
83 }
84
85 if (!EVP_AEAD_CTX_seal(&ctx, out, &ciphertext_len, sizeof(out), bufs[NONCE],
86 lengths[NONCE], bufs[IN], lengths[IN], bufs[AD],
87 lengths[AD])) {
88 fprintf(stderr, "Failed to run AEAD on line %u\n", line_no);
89 return 0;
90 }
91
92 if (ciphertext_len != lengths[CT] + lengths[TAG]) {
93 fprintf(stderr, "Bad output length on line %u: %u vs %u\n", line_no,
94 (unsigned)ciphertext_len, (unsigned)(lengths[CT] + lengths[TAG]));
95 return 0;
96 }
97
98 if (memcmp(out, bufs[CT], lengths[CT]) != 0) {
99 fprintf(stderr, "Bad output on line %u\n", line_no);
100 return 0;
101 }
102
103 if (memcmp(out + lengths[CT], bufs[TAG], lengths[TAG]) != 0) {
104 fprintf(stderr, "Bad tag on line %u\n", line_no);
105 return 0;
106 }
107
Adam Langley45ec21b2014-06-24 17:26:59 -0700108 /* The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
109 * reset after each operation. */
110 EVP_AEAD_CTX_cleanup(&ctx);
111 if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
112 NULL)) {
113 fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
114 return 0;
115 }
116
Adam Langleydfe30532014-06-20 12:00:00 -0700117 if (!EVP_AEAD_CTX_open(&ctx, out2, &plaintext_len, lengths[IN], bufs[NONCE],
118 lengths[NONCE], out, ciphertext_len, bufs[AD],
119 lengths[AD])) {
120 fprintf(stderr, "Failed to decrypt on line %u\n", line_no);
121 return 0;
122 }
123
124 if (plaintext_len != lengths[IN]) {
125 fprintf(stderr, "Bad decrypt on line %u: %u\n", line_no,
126 (unsigned)ciphertext_len);
127 return 0;
128 }
129
Adam Langley45ec21b2014-06-24 17:26:59 -0700130 /* The "stateful" AEADs for implementing pre-AEAD cipher suites need to be
131 * reset after each operation. */
132 EVP_AEAD_CTX_cleanup(&ctx);
133 if (!EVP_AEAD_CTX_init(&ctx, aead, bufs[KEY], lengths[KEY], lengths[TAG],
134 NULL)) {
135 fprintf(stderr, "Failed to init AEAD on line %u\n", line_no);
136 return 0;
137 }
138
Adam Langleydfe30532014-06-20 12:00:00 -0700139 out[0] ^= 0x80;
140 if (EVP_AEAD_CTX_open(&ctx, out2, &plaintext_len, lengths[IN], bufs[NONCE],
141 lengths[NONCE], out, ciphertext_len, bufs[AD],
142 lengths[AD])) {
143 fprintf(stderr, "Decrypted bad data on line %u\n", line_no);
144 return 0;
145 }
146
147 EVP_AEAD_CTX_cleanup(&ctx);
148 return 1;
149}
150
151int main(int argc, char **argv) {
152 FILE *f;
153 const EVP_AEAD *aead = NULL;
154 unsigned int line_no = 0, num_tests = 0, j;
155
156 unsigned char bufs[NUM_TYPES][BUF_MAX];
157 unsigned int lengths[NUM_TYPES];
158
David Benjamina70c75c2014-09-11 19:11:15 -0400159 CRYPTO_library_init();
160
Adam Langleydfe30532014-06-20 12:00:00 -0700161 if (argc != 3) {
162 fprintf(stderr, "%s <aead> <test file.txt>\n", argv[0]);
163 return 1;
164 }
165
166 if (strcmp(argv[1], "aes-128-gcm") == 0) {
167 aead = EVP_aead_aes_128_gcm();
168 } else if (strcmp(argv[1], "aes-256-gcm") == 0) {
169 aead = EVP_aead_aes_256_gcm();
Adam Langleyde0b2022014-06-20 12:00:00 -0700170 } else if (strcmp(argv[1], "chacha20-poly1305") == 0) {
171 aead = EVP_aead_chacha20_poly1305();
Adam Langley45ec21b2014-06-24 17:26:59 -0700172 } else if (strcmp(argv[1], "rc4-md5") == 0) {
173 aead = EVP_aead_rc4_md5_tls();
Adam Langley93a3dcd2014-07-25 15:40:44 -0700174 } else if (strcmp(argv[1], "aes-128-key-wrap") == 0) {
175 aead = EVP_aead_aes_128_key_wrap();
176 } else if (strcmp(argv[1], "aes-256-key-wrap") == 0) {
177 aead = EVP_aead_aes_256_key_wrap();
Adam Langleydfe30532014-06-20 12:00:00 -0700178 } else {
179 fprintf(stderr, "Unknown AEAD: %s\n", argv[1]);
180 return 2;
181 }
182
183 f = fopen(argv[2], "r");
184 if (f == NULL) {
185 perror("failed to open input");
186 return 1;
187 }
188
189 for (j = 0; j < NUM_TYPES; j++) {
190 lengths[j] = 0;
191 }
192
193 for (;;) {
194 char line[4096];
195 unsigned int i, type_len = 0;
196
197 unsigned char *buf = NULL;
198 unsigned int *buf_len = NULL;
199
200 if (!fgets(line, sizeof(line), f)) {
Adam Langleyd54dc242014-06-24 16:28:24 -0700201 line[0] = 0;
Adam Langleydfe30532014-06-20 12:00:00 -0700202 }
203
204 line_no++;
205 if (line[0] == '#') {
206 continue;
207 }
208
209 if (line[0] == '\n' || line[0] == 0) {
210 /* Run a test, if possible. */
211 char any_values_set = 0;
212 for (j = 0; j < NUM_TYPES; j++) {
213 if (lengths[j] != 0) {
214 any_values_set = 1;
215 break;
216 }
217 }
218
Adam Langleyd54dc242014-06-24 16:28:24 -0700219 if (any_values_set) {
220 if (!run_test_case(aead, bufs, lengths, line_no)) {
221 return 4;
222 }
223
224 for (j = 0; j < NUM_TYPES; j++) {
225 lengths[j] = 0;
226 }
227
228 num_tests++;
Adam Langleydfe30532014-06-20 12:00:00 -0700229 }
230
Adam Langleyd54dc242014-06-24 16:28:24 -0700231 if (line[0] == 0) {
232 break;
Adam Langleydfe30532014-06-20 12:00:00 -0700233 }
Adam Langleydfe30532014-06-20 12:00:00 -0700234 continue;
235 }
236
237 /* Each line looks like:
238 * TYPE: 0123abc
239 * Where "TYPE" is the type of the data on the line,
240 * e.g. "KEY". */
241 for (i = 0; line[i] != 0 && line[i] != '\n'; i++) {
242 if (line[i] == ':') {
243 type_len = i;
244 break;
245 }
246 }
247 i++;
248
249 if (type_len == 0) {
250 fprintf(stderr, "Parse error on line %u\n", line_no);
251 return 3;
252 }
253
254 /* After the colon, there's optional whitespace. */
255 for (; line[i] != 0 && line[i] != '\n'; i++) {
256 if (line[i] != ' ' && line[i] != '\t') {
257 break;
258 }
259 }
260
261 line[type_len] = 0;
262 for (j = 0; j < NUM_TYPES; j++) {
263 if (strcmp(line, NAMES[j]) != 0) {
264 continue;
265 }
266 if (lengths[j] != 0) {
267 fprintf(stderr, "Duplicate value on line %u\n", line_no);
268 return 3;
269 }
270 buf = bufs[j];
271 buf_len = &lengths[j];
272 }
273
274 if (buf == NULL) {
275 fprintf(stderr, "Unknown line type on line %u\n", line_no);
276 return 3;
277 }
278
279 j = 0;
280 for (; line[i] != 0 && line[i] != '\n'; i++) {
281 unsigned char v, v2;
282 v = hex_digit(line[i++]);
283 if (line[i] == 0 || line[i] == '\n') {
284 fprintf(stderr, "Odd-length hex data on line %u\n", line_no);
285 return 3;
286 }
287 v2 = hex_digit(line[i]);
288 if (v > 15 || v2 > 15) {
289 fprintf(stderr, "Invalid hex char on line %u\n", line_no);
290 return 3;
291 }
292 v <<= 4;
293 v |= v2;
294
295 if (j == BUF_MAX) {
296 fprintf(stderr, "Too much hex data on line %u (max is %u bytes)\n",
297 line_no, (unsigned)BUF_MAX);
298 return 3;
299 }
300 buf[j++] = v;
301 *buf_len = *buf_len + 1;
302 }
303 }
304
305 printf("Completed %u test cases\n", num_tests);
306 printf("PASS\n");
307 fclose(f);
308
309 return 0;
310}