1/*-
2 * Copyright (c) 2017 Chelsio Communications, Inc.
3 * All rights reserved.
4 * Written by: John Baldwin <jhb@FreeBSD.org>
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27/*-
28 * Copyright (c) 2004 Sam Leffler, Errno Consulting
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 *    notice, this list of conditions and the following disclaimer,
36 *    without modification.
37 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
38 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
39 *    redistribution must be conditioned upon including a substantially
40 *    similar Disclaimer requirement for further binary redistribution.
41 * 3. Neither the names of the above-listed copyright holders nor the names
42 *    of any contributors may be used to endorse or promote products derived
43 *    from this software without specific prior written permission.
44 *
45 * NO WARRANTY
46 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
47 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
48 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
49 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
50 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
51 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
52 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
53 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
54 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
55 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
56 * THE POSSIBILITY OF SUCH DAMAGES.
57 *
58 * $FreeBSD: stable/11/tools/tools/crypto/cryptocheck.c 345028 2019-03-11 21:37:58Z jhb $
59 */
60
61/*
62 * A different tool for checking hardware crypto support.  Whereas
63 * cryptotest is focused on simple performance numbers, this tool is
64 * focused on correctness.  For each crypto operation, it performs the
65 * operation once in software via OpenSSL and a second time via
66 * OpenCrypto and compares the results.
67 *
68 * cryptocheck [-vz] [-A aad length] [-a algorithm] [-d dev] [size ...]
69 *
70 * Options:
71 *	-v	Verbose.
72 *	-z	Run all algorithms on a variety of buffer sizes.
73 *
74 * Supported algorithms:
75 *	all		Run all tests
76 *	hmac		Run all hmac tests
77 *	blkcipher	Run all block cipher tests
78 *	authenc		Run all authenticated encryption tests
79 *	aead		Run all authenticated encryption with associated data
80 *			tests
81 *
82 * HMACs:
83 *	sha1		sha1 hmac
84 *	sha256		256-bit sha2 hmac
85 *	sha384		384-bit sha2 hmac
86 *	sha512		512-bit	sha2 hmac
87 *
88 * Block Ciphers:
89 *	aes-cbc		128-bit aes cbc
90 *	aes-cbc192	192-bit	aes cbc
91 *	aes-cbc256	256-bit aes cbc
92 *	aes-ctr		128-bit aes ctr
93 *	aes-ctr192	192-bit aes ctr
94 *	aes-ctr256	256-bit aes ctr
95 *	aes-xts		128-bit aes xts
96 *	aes-xts256	256-bit aes xts
97 *
98 * Authenticated Encryption:
99 *	<block cipher>+<hmac>
100 *
101 * Authenticated Encryption with Associated Data:
102 *	aes-gcm		128-bit aes gcm
103 *	aes-gcm192	192-bit aes gcm
104 *	aes-gcm256	256-bit aes gcm
105 */
106
107#include <sys/param.h>
108#include <assert.h>
109#include <err.h>
110#include <fcntl.h>
111#include <libutil.h>
112#include <stdbool.h>
113#include <stdio.h>
114#include <string.h>
115#include <unistd.h>
116
117#include <openssl/err.h>
118#include <openssl/hmac.h>
119
120#include <crypto/cryptodev.h>
121
122/* XXX: Temporary hack */
123#ifndef COP_F_CIPHER_FIRST
124#define	COP_F_CIPHER_FIRST	0x0001	/* Cipher before MAC. */
125#endif
126
127struct alg {
128	const char *name;
129	int cipher;
130	int mac;
131	enum { T_HMAC, T_BLKCIPHER, T_AUTHENC, T_GCM } type;
132	const EVP_CIPHER *(*evp_cipher)(void);
133	const EVP_MD *(*evp_md)(void);
134} algs[] = {
135	{ .name = "sha1", .mac = CRYPTO_SHA1_HMAC, .type = T_HMAC,
136	  .evp_md = EVP_sha1 },
137	{ .name = "sha256", .mac = CRYPTO_SHA2_256_HMAC, .type = T_HMAC,
138	  .evp_md = EVP_sha256 },
139	{ .name = "sha384", .mac = CRYPTO_SHA2_384_HMAC, .type = T_HMAC,
140	  .evp_md = EVP_sha384 },
141	{ .name = "sha512", .mac = CRYPTO_SHA2_512_HMAC, .type = T_HMAC,
142	  .evp_md = EVP_sha512 },
143	{ .name = "aes-cbc", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
144	  .evp_cipher = EVP_aes_128_cbc },
145	{ .name = "aes-cbc192", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
146	  .evp_cipher = EVP_aes_192_cbc },
147	{ .name = "aes-cbc256", .cipher = CRYPTO_AES_CBC, .type = T_BLKCIPHER,
148	  .evp_cipher = EVP_aes_256_cbc },
149	{ .name = "aes-ctr", .cipher = CRYPTO_AES_ICM, .type = T_BLKCIPHER,
150	  .evp_cipher = EVP_aes_128_ctr },
151	{ .name = "aes-ctr192", .cipher = CRYPTO_AES_ICM, .type = T_BLKCIPHER,
152	  .evp_cipher = EVP_aes_192_ctr },
153	{ .name = "aes-ctr256", .cipher = CRYPTO_AES_ICM, .type = T_BLKCIPHER,
154	  .evp_cipher = EVP_aes_256_ctr },
155	{ .name = "aes-xts", .cipher = CRYPTO_AES_XTS, .type = T_BLKCIPHER,
156	  .evp_cipher = EVP_aes_128_xts },
157	{ .name = "aes-xts256", .cipher = CRYPTO_AES_XTS, .type = T_BLKCIPHER,
158	  .evp_cipher = EVP_aes_256_xts },
159	{ .name = "aes-gcm", .cipher = CRYPTO_AES_NIST_GCM_16,
160	  .mac = CRYPTO_AES_128_NIST_GMAC, .type = T_GCM,
161	  .evp_cipher = EVP_aes_128_gcm },
162	{ .name = "aes-gcm192", .cipher = CRYPTO_AES_NIST_GCM_16,
163	  .mac = CRYPTO_AES_192_NIST_GMAC, .type = T_GCM,
164	  .evp_cipher = EVP_aes_192_gcm },
165	{ .name = "aes-gcm256", .cipher = CRYPTO_AES_NIST_GCM_16,
166	  .mac = CRYPTO_AES_256_NIST_GMAC, .type = T_GCM,
167	  .evp_cipher = EVP_aes_256_gcm },
168};
169
170static bool verbose;
171static int crid;
172static size_t aad_len;
173
174static void
175usage(void)
176{
177	fprintf(stderr,
178	    "usage: cryptocheck [-z] [-a algorithm] [-d dev] [size ...]\n");
179	exit(1);
180}
181
182static struct alg *
183find_alg(const char *name)
184{
185	u_int i;
186
187	for (i = 0; i < nitems(algs); i++)
188		if (strcasecmp(algs[i].name, name) == 0)
189			return (&algs[i]);
190	return (NULL);
191}
192
193static struct alg *
194build_authenc(struct alg *cipher, struct alg *hmac)
195{
196	static struct alg authenc;
197	char *name;
198
199	assert(cipher->type == T_BLKCIPHER);
200	assert(hmac->type == T_HMAC);
201	memset(&authenc, 0, sizeof(authenc));
202	asprintf(&name, "%s+%s", cipher->name, hmac->name);
203	authenc.name = name;
204	authenc.cipher = cipher->cipher;
205	authenc.mac = hmac->mac;
206	authenc.type = T_AUTHENC;
207	authenc.evp_cipher = cipher->evp_cipher;
208	authenc.evp_md = hmac->evp_md;
209	return (&authenc);
210}
211
212static struct alg *
213build_authenc_name(const char *name)
214{
215	struct alg *cipher, *hmac;
216	const char *hmac_name;
217	char *cp, *cipher_name;
218
219	cp = strchr(name, '+');
220	cipher_name = strndup(name, cp - name);
221	hmac_name = cp + 1;
222	cipher = find_alg(cipher_name);
223	free(cipher_name);
224	if (cipher == NULL)
225		errx(1, "Invalid cipher %s", cipher_name);
226	hmac = find_alg(hmac_name);
227	if (hmac == NULL)
228		errx(1, "Invalid hash %s", hmac_name);
229	return (build_authenc(cipher, hmac));
230}
231
232static int
233devcrypto(void)
234{
235	static int fd = -1;
236
237	if (fd < 0) {
238		fd = open("/dev/crypto", O_RDWR | O_CLOEXEC, 0);
239		if (fd < 0)
240			err(1, "/dev/crypto");
241	}
242	return (fd);
243}
244
245static int
246crlookup(const char *devname)
247{
248	struct crypt_find_op find;
249
250	if (strncmp(devname, "soft", 4) == 0)
251		return CRYPTO_FLAG_SOFTWARE;
252
253	find.crid = -1;
254	strlcpy(find.name, devname, sizeof(find.name));
255	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
256		err(1, "ioctl(CIOCFINDDEV)");
257	return (find.crid);
258}
259
260const char *
261crfind(int crid)
262{
263	static struct crypt_find_op find;
264
265	if (crid == CRYPTO_FLAG_SOFTWARE)
266		return ("soft");
267	else if (crid == CRYPTO_FLAG_HARDWARE)
268		return ("unknown");
269
270	bzero(&find, sizeof(find));
271	find.crid = crid;
272	if (ioctl(devcrypto(), CRIOFINDDEV, &find) == -1)
273		err(1, "ioctl(CIOCFINDDEV): crid %d", crid);
274	return (find.name);
275}
276
277static int
278crget(void)
279{
280	int fd;
281
282	if (ioctl(devcrypto(), CRIOGET, &fd) == -1)
283		err(1, "ioctl(CRIOGET)");
284	if (fcntl(fd, F_SETFD, 1) == -1)
285		err(1, "fcntl(F_SETFD) (crget)");
286	return fd;
287}
288
289static char
290rdigit(void)
291{
292	const char a[] = {
293		0x10,0x54,0x11,0x48,0x45,0x12,0x4f,0x13,0x49,0x53,0x14,0x41,
294		0x15,0x16,0x4e,0x55,0x54,0x17,0x18,0x4a,0x4f,0x42,0x19,0x01
295	};
296	return 0x20+a[random()%nitems(a)];
297}
298
299static char *
300alloc_buffer(size_t len)
301{
302	char *buf;
303	size_t i;
304
305	buf = malloc(len);
306	for (i = 0; i < len; i++)
307		buf[i] = rdigit();
308	return (buf);
309}
310
311static char *
312generate_iv(size_t len, struct alg *alg)
313{
314	char *iv;
315
316	iv = alloc_buffer(len);
317	switch (alg->cipher) {
318	case CRYPTO_AES_ICM:
319		/* Clear the low 32 bits of the IV to hold the counter. */
320		iv[len - 4] = 0;
321		iv[len - 3] = 0;
322		iv[len - 2] = 0;
323		iv[len - 1] = 0;
324		break;
325	case CRYPTO_AES_XTS:
326		/*
327		 * Clear the low 64-bits to only store a 64-bit block
328		 * number.
329		 */
330		iv[len - 8] = 0;
331		iv[len - 7] = 0;
332		iv[len - 6] = 0;
333		iv[len - 5] = 0;
334		iv[len - 4] = 0;
335		iv[len - 3] = 0;
336		iv[len - 2] = 0;
337		iv[len - 1] = 0;
338		break;
339	}
340	return (iv);
341}
342
343static bool
344ocf_hmac(struct alg *alg, const char *buffer, size_t size, const char *key,
345    size_t key_len, char *digest, int *cridp)
346{
347	struct session2_op sop;
348	struct crypt_op cop;
349	int fd;
350
351	memset(&sop, 0, sizeof(sop));
352	memset(&cop, 0, sizeof(cop));
353	sop.crid = crid;
354	sop.mackeylen = key_len;
355	sop.mackey = (char *)key;
356	sop.mac = alg->mac;
357	fd = crget();
358	if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
359		warn("cryptodev %s HMAC not supported for device %s",
360		    alg->name, crfind(crid));
361		close(fd);
362		return (false);
363	}
364
365	cop.ses = sop.ses;
366	cop.op = 0;
367	cop.len = size;
368	cop.src = (char *)buffer;
369	cop.dst = NULL;
370	cop.mac = digest;
371	cop.iv = NULL;
372
373	if (ioctl(fd, CIOCCRYPT, &cop) < 0) {
374		warn("cryptodev %s (%zu) HMAC failed for device %s", alg->name,
375		    size, crfind(crid));
376		close(fd);
377		return (false);
378	}
379
380	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
381		warn("ioctl(CIOCFSESSION)");
382
383	close(fd);
384	*cridp = sop.crid;
385	return (true);
386}
387
388static void
389run_hmac_test(struct alg *alg, size_t size)
390{
391	const EVP_MD *md;
392	char *key, *buffer;
393	u_int key_len, digest_len;
394	int crid;
395	char control_digest[EVP_MAX_MD_SIZE], test_digest[EVP_MAX_MD_SIZE];
396
397	memset(control_digest, 0x3c, sizeof(control_digest));
398	memset(test_digest, 0x3c, sizeof(test_digest));
399
400	md = alg->evp_md();
401	key_len = EVP_MD_size(md);
402	assert(EVP_MD_size(md) <= sizeof(control_digest));
403
404	key = alloc_buffer(key_len);
405	buffer = alloc_buffer(size);
406
407	/* OpenSSL HMAC. */
408	digest_len = sizeof(control_digest);
409	if (HMAC(md, key, key_len, (u_char *)buffer, size,
410	    (u_char *)control_digest, &digest_len) == NULL)
411		errx(1, "OpenSSL %s (%zu) HMAC failed: %s", alg->name,
412		    size, ERR_error_string(ERR_get_error(), NULL));
413
414	/* cryptodev HMAC. */
415	if (!ocf_hmac(alg, buffer, size, key, key_len, test_digest, &crid))
416		goto out;
417	if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) {
418		if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0)
419			printf("%s (%zu) mismatch in trailer:\n",
420			    alg->name, size);
421		else
422			printf("%s (%zu) mismatch:\n", alg->name, size);
423		printf("control:\n");
424		hexdump(control_digest, sizeof(control_digest), NULL, 0);
425		printf("test (cryptodev device %s):\n", crfind(crid));
426		hexdump(test_digest, sizeof(test_digest), NULL, 0);
427		goto out;
428	}
429
430	if (verbose)
431		printf("%s (%zu) matched (cryptodev device %s)\n",
432		    alg->name, size, crfind(crid));
433
434out:
435	free(buffer);
436	free(key);
437}
438
439static void
440openssl_cipher(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
441    const char *iv, const char *input, char *output, size_t size, int enc)
442{
443	EVP_CIPHER_CTX *ctx;
444	int outl, total;
445
446	ctx = EVP_CIPHER_CTX_new();
447	if (ctx == NULL)
448		errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
449		    size, ERR_error_string(ERR_get_error(), NULL));
450	if (EVP_CipherInit_ex(ctx, cipher, NULL, (const u_char *)key,
451	    (const u_char *)iv, enc) != 1)
452		errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
453		    size, ERR_error_string(ERR_get_error(), NULL));
454	EVP_CIPHER_CTX_set_padding(ctx, 0);
455	if (EVP_CipherUpdate(ctx, (u_char *)output, &outl,
456	    (const u_char *)input, size) != 1)
457		errx(1, "OpenSSL %s (%zu) cipher update failed: %s", alg->name,
458		    size, ERR_error_string(ERR_get_error(), NULL));
459	total = outl;
460	if (EVP_CipherFinal_ex(ctx, (u_char *)output + outl, &outl) != 1)
461		errx(1, "OpenSSL %s (%zu) cipher final failed: %s", alg->name,
462		    size, ERR_error_string(ERR_get_error(), NULL));
463	total += outl;
464	if (total != size)
465		errx(1, "OpenSSL %s (%zu) cipher size mismatch: %d", alg->name,
466		    size, total);
467	EVP_CIPHER_CTX_free(ctx);
468}
469
470static bool
471ocf_cipher(struct alg *alg, const char *key, size_t key_len,
472    const char *iv, const char *input, char *output, size_t size, int enc,
473    int *cridp)
474{
475	struct session2_op sop;
476	struct crypt_op cop;
477	int fd;
478
479	memset(&sop, 0, sizeof(sop));
480	memset(&cop, 0, sizeof(cop));
481	sop.crid = crid;
482	sop.keylen = key_len;
483	sop.key = (char *)key;
484	sop.cipher = alg->cipher;
485	fd = crget();
486	if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
487		warn("cryptodev %s block cipher not supported for device %s",
488		    alg->name, crfind(crid));
489		close(fd);
490		return (false);
491	}
492
493	cop.ses = sop.ses;
494	cop.op = enc ? COP_ENCRYPT : COP_DECRYPT;
495	cop.len = size;
496	cop.src = (char *)input;
497	cop.dst = output;
498	cop.mac = NULL;
499	cop.iv = (char *)iv;
500
501	if (ioctl(fd, CIOCCRYPT, &cop) < 0) {
502		warn("cryptodev %s (%zu) block cipher failed for device %s",
503		    alg->name, size, crfind(crid));
504		close(fd);
505		return (false);
506	}
507
508	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
509		warn("ioctl(CIOCFSESSION)");
510
511	close(fd);
512	*cridp = sop.crid;
513	return (true);
514}
515
516static void
517run_blkcipher_test(struct alg *alg, size_t size)
518{
519	const EVP_CIPHER *cipher;
520	char *buffer, *cleartext, *ciphertext;
521	char *iv, *key;
522	u_int iv_len, key_len;
523	int crid;
524
525	cipher = alg->evp_cipher();
526	if (size % EVP_CIPHER_block_size(cipher) != 0) {
527		if (verbose)
528			printf(
529			    "%s (%zu): invalid buffer size (block size %d)\n",
530			    alg->name, size, EVP_CIPHER_block_size(cipher));
531		return;
532	}
533
534	key_len = EVP_CIPHER_key_length(cipher);
535	iv_len = EVP_CIPHER_iv_length(cipher);
536
537	key = alloc_buffer(key_len);
538	iv = generate_iv(iv_len, alg);
539	cleartext = alloc_buffer(size);
540	buffer = malloc(size);
541	ciphertext = malloc(size);
542
543	/* OpenSSL cipher. */
544	openssl_cipher(alg, cipher, key, iv, cleartext, ciphertext, size, 1);
545	if (size > 0 && memcmp(cleartext, ciphertext, size) == 0)
546		errx(1, "OpenSSL %s (%zu): cipher text unchanged", alg->name,
547		    size);
548	openssl_cipher(alg, cipher, key, iv, ciphertext, buffer, size, 0);
549	if (memcmp(cleartext, buffer, size) != 0) {
550		printf("OpenSSL %s (%zu): cipher mismatch:", alg->name, size);
551		printf("original:\n");
552		hexdump(cleartext, size, NULL, 0);
553		printf("decrypted:\n");
554		hexdump(buffer, size, NULL, 0);
555		exit(1);
556	}
557
558	/* OCF encrypt. */
559	if (!ocf_cipher(alg, key, key_len, iv, cleartext, buffer, size, 1,
560	    &crid))
561		goto out;
562	if (memcmp(ciphertext, buffer, size) != 0) {
563		printf("%s (%zu) encryption mismatch:\n", alg->name, size);
564		printf("control:\n");
565		hexdump(ciphertext, size, NULL, 0);
566		printf("test (cryptodev device %s):\n", crfind(crid));
567		hexdump(buffer, size, NULL, 0);
568		goto out;
569	}
570
571	/* OCF decrypt. */
572	if (!ocf_cipher(alg, key, key_len, iv, ciphertext, buffer, size, 0,
573	    &crid))
574		goto out;
575	if (memcmp(cleartext, buffer, size) != 0) {
576		printf("%s (%zu) decryption mismatch:\n", alg->name, size);
577		printf("control:\n");
578		hexdump(cleartext, size, NULL, 0);
579		printf("test (cryptodev device %s):\n", crfind(crid));
580		hexdump(buffer, size, NULL, 0);
581		goto out;
582	}
583
584	if (verbose)
585		printf("%s (%zu) matched (cryptodev device %s)\n",
586		    alg->name, size, crfind(crid));
587
588out:
589	free(ciphertext);
590	free(buffer);
591	free(cleartext);
592	free(iv);
593	free(key);
594}
595
596static bool
597ocf_authenc(struct alg *alg, const char *cipher_key, size_t cipher_key_len,
598    const char *iv, size_t iv_len, const char *auth_key, size_t auth_key_len,
599    const char *aad, size_t aad_len, const char *input, char *output,
600    size_t size, char *digest, int enc, int *cridp)
601{
602	struct session2_op sop;
603	int fd;
604
605	memset(&sop, 0, sizeof(sop));
606	sop.crid = crid;
607	sop.keylen = cipher_key_len;
608	sop.key = (char *)cipher_key;
609	sop.cipher = alg->cipher;
610	sop.mackeylen = auth_key_len;
611	sop.mackey = (char *)auth_key;
612	sop.mac = alg->mac;
613	fd = crget();
614	if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
615		warn("cryptodev %s AUTHENC not supported for device %s",
616		    alg->name, crfind(crid));
617		close(fd);
618		return (false);
619	}
620
621	if (aad_len != 0) {
622		struct crypt_aead caead;
623
624		memset(&caead, 0, sizeof(caead));
625		caead.ses = sop.ses;
626		caead.op = enc ? COP_ENCRYPT : COP_DECRYPT;
627		caead.flags = enc ? COP_F_CIPHER_FIRST : 0;
628		caead.len = size;
629		caead.aadlen = aad_len;
630		caead.ivlen = iv_len;
631		caead.src = (char *)input;
632		caead.dst = output;
633		caead.aad = (char *)aad;
634		caead.tag = digest;
635		caead.iv = (char *)iv;
636
637		if (ioctl(fd, CIOCCRYPTAEAD, &caead) < 0) {
638			warn("cryptodev %s (%zu) failed for device %s",
639			    alg->name, size, crfind(crid));
640			close(fd);
641			return (false);
642		}
643	} else {
644		struct crypt_op cop;
645
646		memset(&cop, 0, sizeof(cop));
647		cop.ses = sop.ses;
648		cop.op = enc ? COP_ENCRYPT : COP_DECRYPT;
649		cop.flags = enc ? COP_F_CIPHER_FIRST : 0;
650		cop.len = size;
651		cop.src = (char *)input;
652		cop.dst = output;
653		cop.mac = digest;
654		cop.iv = (char *)iv;
655
656		if (ioctl(fd, CIOCCRYPT, &cop) < 0) {
657			warn("cryptodev %s (%zu) AUTHENC failed for device %s",
658			    alg->name, size, crfind(crid));
659			close(fd);
660			return (false);
661		}
662	}
663
664	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
665		warn("ioctl(CIOCFSESSION)");
666
667	close(fd);
668	*cridp = sop.crid;
669	return (true);
670}
671
672static void
673run_authenc_test(struct alg *alg, size_t size)
674{
675	const EVP_CIPHER *cipher;
676	const EVP_MD *md;
677	char *aad, *buffer, *cleartext, *ciphertext;
678	char *iv, *auth_key, *cipher_key;
679	u_int iv_len, auth_key_len, cipher_key_len, digest_len;
680	int crid;
681	char control_digest[EVP_MAX_MD_SIZE], test_digest[EVP_MAX_MD_SIZE];
682
683	cipher = alg->evp_cipher();
684	if (size % EVP_CIPHER_block_size(cipher) != 0) {
685		if (verbose)
686			printf(
687			    "%s (%zu): invalid buffer size (block size %d)\n",
688			    alg->name, size, EVP_CIPHER_block_size(cipher));
689		return;
690	}
691
692	memset(control_digest, 0x3c, sizeof(control_digest));
693	memset(test_digest, 0x3c, sizeof(test_digest));
694
695	md = alg->evp_md();
696
697	cipher_key_len = EVP_CIPHER_key_length(cipher);
698	iv_len = EVP_CIPHER_iv_length(cipher);
699	auth_key_len = EVP_MD_size(md);
700
701	cipher_key = alloc_buffer(cipher_key_len);
702	iv = generate_iv(iv_len, alg);
703	auth_key = alloc_buffer(auth_key_len);
704	cleartext = alloc_buffer(aad_len + size);
705	buffer = malloc(aad_len + size);
706	ciphertext = malloc(aad_len + size);
707
708	/* OpenSSL encrypt + HMAC. */
709	if (aad_len != 0)
710		memcpy(ciphertext, cleartext, aad_len);
711	openssl_cipher(alg, cipher, cipher_key, iv, cleartext + aad_len,
712	    ciphertext + aad_len, size, 1);
713	if (size > 0 && memcmp(cleartext + aad_len, ciphertext + aad_len,
714	    size) == 0)
715		errx(1, "OpenSSL %s (%zu): cipher text unchanged", alg->name,
716		    size);
717	digest_len = sizeof(control_digest);
718	if (HMAC(md, auth_key, auth_key_len, (u_char *)ciphertext,
719	    aad_len + size, (u_char *)control_digest, &digest_len) == NULL)
720		errx(1, "OpenSSL %s (%zu) HMAC failed: %s", alg->name,
721		    size, ERR_error_string(ERR_get_error(), NULL));
722
723	/* OCF encrypt + HMAC. */
724	if (!ocf_authenc(alg, cipher_key, cipher_key_len, iv, iv_len, auth_key,
725	    auth_key_len, aad_len != 0 ? cleartext : NULL, aad_len,
726	    cleartext + aad_len, buffer + aad_len, size, test_digest, 1, &crid))
727		goto out;
728	if (memcmp(ciphertext + aad_len, buffer + aad_len, size) != 0) {
729		printf("%s (%zu) encryption mismatch:\n", alg->name, size);
730		printf("control:\n");
731		hexdump(ciphertext + aad_len, size, NULL, 0);
732		printf("test (cryptodev device %s):\n", crfind(crid));
733		hexdump(buffer + aad_len, size, NULL, 0);
734		goto out;
735	}
736	if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) {
737		if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0)
738			printf("%s (%zu) enc hash mismatch in trailer:\n",
739			    alg->name, size);
740		else
741			printf("%s (%zu) enc hash mismatch:\n", alg->name,
742			    size);
743		printf("control:\n");
744		hexdump(control_digest, sizeof(control_digest), NULL, 0);
745		printf("test (cryptodev device %s):\n", crfind(crid));
746		hexdump(test_digest, sizeof(test_digest), NULL, 0);
747		goto out;
748	}
749
750	/* OCF HMAC + decrypt. */
751	memset(test_digest, 0x3c, sizeof(test_digest));
752	if (!ocf_authenc(alg, cipher_key, cipher_key_len, iv, iv_len, auth_key,
753	    auth_key_len, aad_len != 0 ? ciphertext : NULL, aad_len,
754	    ciphertext + aad_len, buffer + aad_len, size, test_digest, 0,
755	    &crid))
756		goto out;
757	if (memcmp(control_digest, test_digest, sizeof(control_digest)) != 0) {
758		if (memcmp(control_digest, test_digest, EVP_MD_size(md)) == 0)
759			printf("%s (%zu) dec hash mismatch in trailer:\n",
760			    alg->name, size);
761		else
762			printf("%s (%zu) dec hash mismatch:\n", alg->name,
763			    size);
764		printf("control:\n");
765		hexdump(control_digest, sizeof(control_digest), NULL, 0);
766		printf("test (cryptodev device %s):\n", crfind(crid));
767		hexdump(test_digest, sizeof(test_digest), NULL, 0);
768		goto out;
769	}
770	if (memcmp(cleartext + aad_len, buffer + aad_len, size) != 0) {
771		printf("%s (%zu) decryption mismatch:\n", alg->name, size);
772		printf("control:\n");
773		hexdump(cleartext, size, NULL, 0);
774		printf("test (cryptodev device %s):\n", crfind(crid));
775		hexdump(buffer, size, NULL, 0);
776		goto out;
777	}
778
779	if (verbose)
780		printf("%s (%zu) matched (cryptodev device %s)\n",
781		    alg->name, size, crfind(crid));
782
783out:
784	free(ciphertext);
785	free(buffer);
786	free(cleartext);
787	free(auth_key);
788	free(iv);
789	free(cipher_key);
790}
791
792static void
793openssl_gcm_encrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
794    const char *iv, const char *aad, size_t aad_len, const char *input,
795    char *output, size_t size, char *tag)
796{
797	EVP_CIPHER_CTX *ctx;
798	int outl, total;
799
800	ctx = EVP_CIPHER_CTX_new();
801	if (ctx == NULL)
802		errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
803		    size, ERR_error_string(ERR_get_error(), NULL));
804	if (EVP_EncryptInit_ex(ctx, cipher, NULL, (const u_char *)key,
805	    (const u_char *)iv) != 1)
806		errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
807		    size, ERR_error_string(ERR_get_error(), NULL));
808	EVP_CIPHER_CTX_set_padding(ctx, 0);
809	if (aad != NULL) {
810		if (EVP_EncryptUpdate(ctx, NULL, &outl, (const u_char *)aad,
811		    aad_len) != 1)
812			errx(1, "OpenSSL %s (%zu) aad update failed: %s",
813			    alg->name, size,
814			    ERR_error_string(ERR_get_error(), NULL));
815	}
816	if (EVP_EncryptUpdate(ctx, (u_char *)output, &outl,
817	    (const u_char *)input, size) != 1)
818		errx(1, "OpenSSL %s (%zu) encrypt update failed: %s", alg->name,
819		    size, ERR_error_string(ERR_get_error(), NULL));
820	total = outl;
821	if (EVP_EncryptFinal_ex(ctx, (u_char *)output + outl, &outl) != 1)
822		errx(1, "OpenSSL %s (%zu) encrypt final failed: %s", alg->name,
823		    size, ERR_error_string(ERR_get_error(), NULL));
824	total += outl;
825	if (total != size)
826		errx(1, "OpenSSL %s (%zu) encrypt size mismatch: %d", alg->name,
827		    size, total);
828	if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, AES_GMAC_HASH_LEN,
829	    tag) != 1)
830		errx(1, "OpenSSL %s (%zu) get tag failed: %s", alg->name,
831		    size, ERR_error_string(ERR_get_error(), NULL));
832	EVP_CIPHER_CTX_free(ctx);
833}
834
835static bool
836ocf_gcm(struct alg *alg, const char *key, size_t key_len, const char *iv,
837    size_t iv_len, const char *aad, size_t aad_len, const char *input,
838    char *output, size_t size, char *tag, int enc, int *cridp)
839{
840	struct session2_op sop;
841	struct crypt_aead caead;
842	int fd;
843
844	memset(&sop, 0, sizeof(sop));
845	memset(&caead, 0, sizeof(caead));
846	sop.crid = crid;
847	sop.keylen = key_len;
848	sop.key = (char *)key;
849	sop.cipher = alg->cipher;
850	sop.mackeylen = key_len;
851	sop.mackey = (char *)key;
852	sop.mac = alg->mac;
853	fd = crget();
854	if (ioctl(fd, CIOCGSESSION2, &sop) < 0) {
855		warn("cryptodev %s not supported for device %s",
856		    alg->name, crfind(crid));
857		close(fd);
858		return (false);
859	}
860
861	caead.ses = sop.ses;
862	caead.op = enc ? COP_ENCRYPT : COP_DECRYPT;
863	caead.len = size;
864	caead.aadlen = aad_len;
865	caead.ivlen = iv_len;
866	caead.src = (char *)input;
867	caead.dst = output;
868	caead.aad = (char *)aad;
869	caead.tag = tag;
870	caead.iv = (char *)iv;
871
872	if (ioctl(fd, CIOCCRYPTAEAD, &caead) < 0) {
873		warn("cryptodev %s (%zu) failed for device %s",
874		    alg->name, size, crfind(crid));
875		close(fd);
876		return (false);
877	}
878
879	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
880		warn("ioctl(CIOCFSESSION)");
881
882	close(fd);
883	*cridp = sop.crid;
884	return (true);
885}
886
887#ifdef notused
888static bool
889openssl_gcm_decrypt(struct alg *alg, const EVP_CIPHER *cipher, const char *key,
890    const char *iv, const char *aad, size_t aad_len, const char *input,
891    char *output, size_t size, char *tag)
892{
893	EVP_CIPHER_CTX *ctx;
894	int outl, total;
895	bool valid;
896
897	ctx = EVP_CIPHER_CTX_new();
898	if (ctx == NULL)
899		errx(1, "OpenSSL %s (%zu) ctx new failed: %s", alg->name,
900		    size, ERR_error_string(ERR_get_error(), NULL));
901	if (EVP_DecryptInit_ex(ctx, cipher, NULL, (const u_char *)key,
902	    (const u_char *)iv) != 1)
903		errx(1, "OpenSSL %s (%zu) ctx init failed: %s", alg->name,
904		    size, ERR_error_string(ERR_get_error(), NULL));
905	EVP_CIPHER_CTX_set_padding(ctx, 0);
906	if (aad != NULL) {
907		if (EVP_DecryptUpdate(ctx, NULL, &outl, (const u_char *)aad,
908		    aad_len) != 1)
909			errx(1, "OpenSSL %s (%zu) aad update failed: %s",
910			    alg->name, size,
911			    ERR_error_string(ERR_get_error(), NULL));
912	}
913	if (EVP_DecryptUpdate(ctx, (u_char *)output, &outl,
914	    (const u_char *)input, size) != 1)
915		errx(1, "OpenSSL %s (%zu) decrypt update failed: %s", alg->name,
916		    size, ERR_error_string(ERR_get_error(), NULL));
917	total = outl;
918	if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, AES_GMAC_HASH_LEN,
919	    tag) != 1)
920		errx(1, "OpenSSL %s (%zu) get tag failed: %s", alg->name,
921		    size, ERR_error_string(ERR_get_error(), NULL));
922	valid = (EVP_DecryptFinal_ex(ctx, (u_char *)output + outl, &outl) != 1);
923	total += outl;
924	if (total != size)
925		errx(1, "OpenSSL %s (%zu) decrypt size mismatch: %d", alg->name,
926		    size, total);
927	EVP_CIPHER_CTX_free(ctx);
928	return (valid);
929}
930#endif
931
932static void
933run_gcm_test(struct alg *alg, size_t size)
934{
935	const EVP_CIPHER *cipher;
936	char *aad, *buffer, *cleartext, *ciphertext;
937	char *iv, *key;
938	u_int iv_len, key_len;
939	int crid;
940	char control_tag[AES_GMAC_HASH_LEN], test_tag[AES_GMAC_HASH_LEN];
941
942	cipher = alg->evp_cipher();
943	if (size % EVP_CIPHER_block_size(cipher) != 0) {
944		if (verbose)
945			printf(
946			    "%s (%zu): invalid buffer size (block size %d)\n",
947			    alg->name, size, EVP_CIPHER_block_size(cipher));
948		return;
949	}
950
951	memset(control_tag, 0x3c, sizeof(control_tag));
952	memset(test_tag, 0x3c, sizeof(test_tag));
953
954	key_len = EVP_CIPHER_key_length(cipher);
955	iv_len = EVP_CIPHER_iv_length(cipher);
956
957	key = alloc_buffer(key_len);
958	iv = generate_iv(iv_len, alg);
959	cleartext = alloc_buffer(size);
960	buffer = malloc(size);
961	ciphertext = malloc(size);
962	if (aad_len != 0)
963		aad = alloc_buffer(aad_len);
964	else
965		aad = NULL;
966
967	/* OpenSSL encrypt */
968	openssl_gcm_encrypt(alg, cipher, key, iv, aad, aad_len, cleartext,
969	    ciphertext, size, control_tag);
970
971	/* OCF encrypt */
972	if (!ocf_gcm(alg, key, key_len, iv, iv_len, aad, aad_len, cleartext,
973	    buffer, size, test_tag, 1, &crid))
974		goto out;
975	if (memcmp(ciphertext, buffer, size) != 0) {
976		printf("%s (%zu) encryption mismatch:\n", alg->name, size);
977		printf("control:\n");
978		hexdump(ciphertext, size, NULL, 0);
979		printf("test (cryptodev device %s):\n", crfind(crid));
980		hexdump(buffer, size, NULL, 0);
981		goto out;
982	}
983	if (memcmp(control_tag, test_tag, sizeof(control_tag)) != 0) {
984		printf("%s (%zu) enc tag mismatch:\n", alg->name, size);
985		printf("control:\n");
986		hexdump(control_tag, sizeof(control_tag), NULL, 0);
987		printf("test (cryptodev device %s):\n", crfind(crid));
988		hexdump(test_tag, sizeof(test_tag), NULL, 0);
989		goto out;
990	}
991
992	/* OCF decrypt */
993	if (!ocf_gcm(alg, key, key_len, iv, iv_len, aad, aad_len, ciphertext,
994	    buffer, size, control_tag, 0, &crid))
995		goto out;
996	if (memcmp(cleartext, buffer, size) != 0) {
997		printf("%s (%zu) decryption mismatch:\n", alg->name, size);
998		printf("control:\n");
999		hexdump(cleartext, size, NULL, 0);
1000		printf("test (cryptodev device %s):\n", crfind(crid));
1001		hexdump(buffer, size, NULL, 0);
1002		goto out;
1003	}
1004
1005	if (verbose)
1006		printf("%s (%zu) matched (cryptodev device %s)\n",
1007		    alg->name, size, crfind(crid));
1008
1009out:
1010	free(aad);
1011	free(ciphertext);
1012	free(buffer);
1013	free(cleartext);
1014	free(iv);
1015	free(key);
1016}
1017
1018static void
1019run_test(struct alg *alg, size_t size)
1020{
1021
1022	switch (alg->type) {
1023	case T_HMAC:
1024		run_hmac_test(alg, size);
1025		break;
1026	case T_BLKCIPHER:
1027		run_blkcipher_test(alg, size);
1028		break;
1029	case T_AUTHENC:
1030		run_authenc_test(alg, size);
1031		break;
1032	case T_GCM:
1033		run_gcm_test(alg, size);
1034		break;
1035	}
1036}
1037
1038static void
1039run_test_sizes(struct alg *alg, size_t *sizes, u_int nsizes)
1040{
1041	u_int i;
1042
1043	for (i = 0; i < nsizes; i++)
1044		run_test(alg, sizes[i]);
1045}
1046
1047static void
1048run_hmac_tests(size_t *sizes, u_int nsizes)
1049{
1050	u_int i;
1051
1052	for (i = 0; i < nitems(algs); i++)
1053		if (algs[i].type == T_HMAC)
1054			run_test_sizes(&algs[i], sizes, nsizes);
1055}
1056
1057static void
1058run_blkcipher_tests(size_t *sizes, u_int nsizes)
1059{
1060	u_int i;
1061
1062	for (i = 0; i < nitems(algs); i++)
1063		if (algs[i].type == T_BLKCIPHER)
1064			run_test_sizes(&algs[i], sizes, nsizes);
1065}
1066
1067static void
1068run_authenc_tests(size_t *sizes, u_int nsizes)
1069{
1070	struct alg *authenc, *cipher, *hmac;
1071	u_int i, j;
1072
1073	for (i = 0; i < nitems(algs); i++) {
1074		cipher = &algs[i];
1075		if (cipher->type != T_BLKCIPHER)
1076			continue;
1077		for (j = 0; j < nitems(algs); j++) {
1078			hmac = &algs[j];
1079			if (hmac->type != T_HMAC)
1080				continue;
1081			authenc = build_authenc(cipher, hmac);
1082			run_test_sizes(authenc, sizes, nsizes);
1083			free((char *)authenc->name);
1084		}
1085	}
1086}
1087
1088static void
1089run_aead_tests(size_t *sizes, u_int nsizes)
1090{
1091	u_int i;
1092
1093	for (i = 0; i < nitems(algs); i++)
1094		if (algs[i].type == T_GCM)
1095			run_test_sizes(&algs[i], sizes, nsizes);
1096}
1097
1098int
1099main(int ac, char **av)
1100{
1101	const char *algname;
1102	struct alg *alg;
1103	size_t sizes[128];
1104	u_int i, nsizes;
1105	bool testall;
1106	int ch;
1107
1108	algname = NULL;
1109	crid = CRYPTO_FLAG_HARDWARE;
1110	testall = false;
1111	verbose = false;
1112	while ((ch = getopt(ac, av, "A:a:d:vz")) != -1)
1113		switch (ch) {
1114		case 'A':
1115			aad_len = atoi(optarg);
1116			break;
1117		case 'a':
1118			algname = optarg;
1119			break;
1120		case 'd':
1121			crid = crlookup(optarg);
1122			break;
1123		case 'v':
1124			verbose = true;
1125			break;
1126		case 'z':
1127			testall = true;
1128			break;
1129		default:
1130			usage();
1131		}
1132	ac -= optind;
1133	av += optind;
1134	nsizes = 0;
1135	while (ac > 0) {
1136		char *cp;
1137
1138		if (nsizes >= nitems(sizes)) {
1139			warnx("Too many sizes, ignoring extras");
1140			break;
1141		}
1142		sizes[nsizes] = strtol(av[0], &cp, 0);
1143		if (*cp != '\0')
1144			errx(1, "Bad size %s", av[0]);
1145		nsizes++;
1146		ac--;
1147		av++;
1148	}
1149
1150	if (algname == NULL)
1151		errx(1, "Algorithm required");
1152	if (nsizes == 0) {
1153		sizes[0] = 16;
1154		nsizes++;
1155		if (testall) {
1156			while (sizes[nsizes - 1] * 2 < 240 * 1024) {
1157				assert(nsizes < nitems(sizes));
1158				sizes[nsizes] = sizes[nsizes - 1] * 2;
1159				nsizes++;
1160			}
1161			if (sizes[nsizes - 1] < 240 * 1024) {
1162				assert(nsizes < nitems(sizes));
1163				sizes[nsizes] = 240 * 1024;
1164				nsizes++;
1165			}
1166		}
1167	}
1168
1169	if (strcasecmp(algname, "hmac") == 0)
1170		run_hmac_tests(sizes, nsizes);
1171	else if (strcasecmp(algname, "blkcipher") == 0)
1172		run_blkcipher_tests(sizes, nsizes);
1173	else if (strcasecmp(algname, "authenc") == 0)
1174		run_authenc_tests(sizes, nsizes);
1175	else if (strcasecmp(algname, "aead") == 0)
1176		run_aead_tests(sizes, nsizes);
1177	else if (strcasecmp(algname, "all") == 0) {
1178		run_hmac_tests(sizes, nsizes);
1179		run_blkcipher_tests(sizes, nsizes);
1180		run_authenc_tests(sizes, nsizes);
1181		run_aead_tests(sizes, nsizes);
1182	} else if (strchr(algname, '+') != NULL) {
1183		alg = build_authenc_name(algname);
1184		run_test_sizes(alg, sizes, nsizes);
1185	} else {
1186		alg = find_alg(algname);
1187		if (alg == NULL)
1188			errx(1, "Invalid algorithm %s", algname);
1189		run_test_sizes(alg, sizes, nsizes);
1190	}
1191
1192	return (0);
1193}
1194