cryptotest.c revision 175979
150397Sobrien/*-
2117395Skan * Copyright (c) 2004 Sam Leffler, Errno Consulting
3117395Skan * All rights reserved.
450397Sobrien *
550397Sobrien * Redistribution and use in source and binary forms, with or without
690075Sobrien * modification, are permitted provided that the following conditions
750397Sobrien * are met:
890075Sobrien * 1. Redistributions of source code must retain the above copyright
990075Sobrien *    notice, this list of conditions and the following disclaimer,
1090075Sobrien *    without modification.
1190075Sobrien * 2. Redistributions in binary form must reproduce at minimum a disclaimer
1250397Sobrien *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
1390075Sobrien *    redistribution must be conditioned upon including a substantially
1490075Sobrien *    similar Disclaimer requirement for further binary redistribution.
1590075Sobrien * 3. Neither the names of the above-listed copyright holders nor the names
1690075Sobrien *    of any contributors may be used to endorse or promote products derived
1750397Sobrien *    from this software without specific prior written permission.
1850397Sobrien *
1990075Sobrien * NO WARRANTY
2090075Sobrien * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2190075Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2250397Sobrien * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
2350397Sobrien * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
2450397Sobrien * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
2550397Sobrien * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2690075Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2790075Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
2890075Sobrien * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2950397Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3050397Sobrien * THE POSSIBILITY OF SUCH DAMAGES.
3150397Sobrien *
3290075Sobrien * $FreeBSD: head/tools/tools/crypto/cryptotest.c 175979 2008-02-05 08:07:19Z matteo $
3350397Sobrien */
3452284Sobrien
3550397Sobrien/*
3690075Sobrien * Simple tool for testing hardware/system crypto support.
3752284Sobrien *
3890075Sobrien * cryptotest [-czsbv] [-a algorithm] [count] [size ...]
3990075Sobrien *
40117395Skan * Run count iterations of a crypt+decrypt or mac operation on a buffer of
4150397Sobrien * size bytes.  A random key and iv are used.  Options:
4252284Sobrien *	-c	check the results
4352284Sobrien *	-d dev	pin work on device dev
4490075Sobrien *	-z	run all available algorithms on a variety of buffer sizes
4590075Sobrien *	-v	be verbose
4652284Sobrien *	-b	mark operations for batching
4752284Sobrien *	-p	profile kernel crypto operations (must be root)
4852284Sobrien *	-t n	fork n threads and run tests concurrently
4952284Sobrien * Known algorithms are:
5052284Sobrien *	null	null cbc
5152284Sobrien *	des	des cbc
5252284Sobrien *	3des	3des cbc
5352284Sobrien *	blf	blowfish cbc
5452284Sobrien *	cast	cast cbc
5552284Sobrien *	skj	skipjack cbc
5652284Sobrien *	aes	rijndael/aes 128-bit cbc
5752284Sobrien *	aes192	rijndael/aes 192-bit cbc
5852284Sobrien *	aes256	rijndael/aes 256-bit cbc
5990075Sobrien *	md5	md5 hmac
6090075Sobrien *	sha1	sha1 hmac
6190075Sobrien *	sha256	256-bit sha2 hmac
6252284Sobrien *	sha384	384-bit sha2 hmac
6390075Sobrien *	sha512	512--bit sha2 hmac
6490075Sobrien *
6590075Sobrien * For a test of how fast a crypto card is, use something like:
6690075Sobrien *	cryptotest -z 1024
6790075Sobrien * This will run a series of tests using the available crypto/cipher
6852284Sobrien * algorithms over a variety of buffer sizes.  The 1024 says to do 1024
6952284Sobrien * iterations.  Extra arguments can be used to specify one or more buffer
7052284Sobrien * sizes to use in doing tests.
7152284Sobrien *
7290075Sobrien * To fork multiple processes all doing the same work, specify -t X on the
7390075Sobrien * command line to get X "threads" running simultaneously.  No effort is made
7452284Sobrien * to synchronize the threads or otherwise maximize load.
7590075Sobrien *
7652284Sobrien * If the kernel crypto code is built with CRYPTO_TIMING and you run as root,
7752284Sobrien * then you can specify the -p option to get a "profile" of the time spent
7890075Sobrien * processing crypto operations.  At present this data is only meaningful for
7952284Sobrien * symmetric operations.  To get meaningful numbers you must run on an idle
80117395Skan * machine.
8152284Sobrien *
8252284Sobrien * Expect ~400 Mb/s for a Broadcom 582x for 8K buffers on a reasonable CPU
8352284Sobrien * (64-bit PCI helps).  Hifn 7811 parts top out at ~110 Mb/s.
8452284Sobrien */
8552284Sobrien#include <sys/types.h>
8690075Sobrien#include <sys/param.h>
8790075Sobrien#include <sys/time.h>
8890075Sobrien#include <sys/ioctl.h>
8990075Sobrien#include <stdio.h>
9050397Sobrien#include <fcntl.h>
9190075Sobrien#include <unistd.h>
9290075Sobrien#include <sys/wait.h>
9390075Sobrien#include <sys/mman.h>
9490075Sobrien#include <paths.h>
9590075Sobrien#include <stdlib.h>
9690075Sobrien#include <string.h>
9790075Sobrien
9890075Sobrien#include <sys/sysctl.h>
9990075Sobrien#include <sys/time.h>
10090075Sobrien#include <crypto/cryptodev.h>
10190075Sobrien
10290075Sobrien#define	CHUNK	64	/* how much to display */
10390075Sobrien#define	N(a)		(sizeof (a) / sizeof (a[0]))
10490075Sobrien#define	streq(a,b)	(strcasecmp(a,b) == 0)
10590075Sobrien
10690075Sobrienvoid	hexdump(char *, int);
10790075Sobrien
10890075Sobrienint	verbose = 0;
10990075Sobrienint	opflags = 0;
11090075Sobrienint	verify = 0;
11190075Sobrienint	crid = CRYPTO_FLAG_HARDWARE;
11290075Sobrien
113117395Skanstruct alg {
114117395Skan	const char* name;
11590075Sobrien	int	ishash;
116117395Skan	int	blocksize;
117117395Skan	int	minkeylen;
118117395Skan	int	maxkeylen;
119117395Skan	int	code;
12090075Sobrien} algorithms[] = {
12150397Sobrien#ifdef CRYPTO_NULL_CBC
12250397Sobrien	{ "null",	0,	8,	1,	256,	CRYPTO_NULL_CBC },
12390075Sobrien#endif
12450397Sobrien	{ "des",	0,	8,	8,	8,	CRYPTO_DES_CBC },
12550397Sobrien	{ "3des",	0,	8,	24,	24,	CRYPTO_3DES_CBC },
12650397Sobrien	{ "blf",	0,	8,	5,	56,	CRYPTO_BLF_CBC },
12752284Sobrien	{ "cast",	0,	8,	5,	16,	CRYPTO_CAST_CBC },
12852284Sobrien	{ "skj",	0,	8,	10,	10,	CRYPTO_SKIPJACK_CBC },
12952284Sobrien	{ "aes",	0,	16,	16,	16,	CRYPTO_RIJNDAEL128_CBC},
13052284Sobrien	{ "aes192",	0,	16,	24,	24,	CRYPTO_RIJNDAEL128_CBC},
13152284Sobrien	{ "aes256",	0,	16,	32,	32,	CRYPTO_RIJNDAEL128_CBC},
13250397Sobrien#ifdef notdef
13350397Sobrien	{ "arc4",	0,	8,	1,	32,	CRYPTO_ARC4 },
13490075Sobrien#endif
13550397Sobrien	{ "md5",	1,	8,	16,	16,	CRYPTO_MD5_HMAC },
136117395Skan	{ "sha1",	1,	8,	20,	20,	CRYPTO_SHA1_HMAC },
13750397Sobrien	{ "sha256",	1,	8,	32,	32,	CRYPTO_SHA2_256_HMAC },
13850397Sobrien	{ "sha384",	1,	8,	48,	48,	CRYPTO_SHA2_384_HMAC },
13950397Sobrien	{ "sha512",	1,	8,	64,	64,	CRYPTO_SHA2_512_HMAC },
14050397Sobrien};
14150397Sobrien
14250397Sobrienstatic void
14350397Sobrienusage(const char* cmd)
14450397Sobrien{
145117395Skan	printf("usage: %s [-czsbv] [-d dev] [-a algorithm] [count] [size ...]\n",
14650397Sobrien		cmd);
14790075Sobrien	printf("where algorithm is one of:\n");
14890075Sobrien	printf("    des 3des (default) blowfish cast skipjack\n");
14990075Sobrien	printf("    aes (aka rijndael) aes192 aes256 arc4\n");
15090075Sobrien	printf("count is the number of encrypt/decrypt ops to do\n");
15190075Sobrien	printf("size is the number of bytes of text to encrypt+decrypt\n");
15290075Sobrien	printf("\n");
15390075Sobrien	printf("-c check the results (slows timing)\n");
15490075Sobrien	printf("-d use specific device\n");
15590075Sobrien	printf("-z run all available algorithms on a variety of sizes\n");
156117395Skan	printf("-v be verbose\n");
15790075Sobrien	printf("-b mark operations for batching\n");
15890075Sobrien	printf("-p profile kernel crypto operation (must be root)\n");
15990075Sobrien	exit(-1);
160117395Skan}
161117395Skan
162117395Skanstatic struct alg*
163117395Skangetalgbycode(int cipher)
16450397Sobrien{
16590075Sobrien	int i;
16690075Sobrien
16750397Sobrien	for (i = 0; i < N(algorithms); i++)
16850397Sobrien		if (cipher == algorithms[i].code)
16950397Sobrien			return &algorithms[i];
17050397Sobrien	return NULL;
17150397Sobrien}
17250397Sobrien
17350397Sobrienstatic struct alg*
17450397Sobriengetalgbyname(const char* name)
17550397Sobrien{
17650397Sobrien	int i;
17750397Sobrien
17890075Sobrien	for (i = 0; i < N(algorithms); i++)
17990075Sobrien		if (streq(name, algorithms[i].name))
18090075Sobrien			return &algorithms[i];
18190075Sobrien	return NULL;
18250397Sobrien}
18350397Sobrien
18450397Sobrienstatic int
18590075Sobriendevcrypto(void)
18650397Sobrien{
18750397Sobrien	static int fd = -1;
18850397Sobrien
18950397Sobrien	if (fd < 0) {
19090075Sobrien		fd = open(_PATH_DEV "crypto", O_RDWR, 0);
19190075Sobrien		if (fd < 0)
19290075Sobrien			err(1, _PATH_DEV "crypto");
19390075Sobrien		if (fcntl(fd, F_SETFD, 1) == -1)
19490075Sobrien			err(1, "fcntl(F_SETFD) (devcrypto)");
19590075Sobrien	}
19690075Sobrien	return fd;
19790075Sobrien}
19890075Sobrien
19950397Sobrienstatic int
20050397Sobriencrlookup(const char *devname)
20150397Sobrien{
20250397Sobrien	struct crypt_find_op find;
203117395Skan
20450397Sobrien	find.crid = -1;
20552284Sobrien	strlcpy(find.name, devname, sizeof(find.name));
20652284Sobrien	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
20790075Sobrien		err(1, "ioctl(CIOCFINDDEV)");
20852284Sobrien	return find.crid;
20952284Sobrien}
21052284Sobrien
21152284Sobrienstatic const char *
21252284Sobriencrfind(int crid)
21390075Sobrien{
21452284Sobrien	static struct crypt_find_op find;
21590075Sobrien
21690075Sobrien	bzero(&find, sizeof(find));
21752284Sobrien	find.crid = crid;
21890075Sobrien	if (ioctl(devcrypto(), CRIOFINDDEV, &find) == -1)
21952284Sobrien		err(1, "ioctl(CIOCFINDDEV): crid %d", crid);
22052284Sobrien	return find.name;
22190075Sobrien}
22290075Sobrien
22352284Sobrienstatic int
224117395Skancrget(void)
22552284Sobrien{
22652284Sobrien	int fd;
22752284Sobrien
22852284Sobrien	if (ioctl(devcrypto(), CRIOGET, &fd) == -1)
229117395Skan		err(1, "ioctl(CRIOGET)");
23052284Sobrien	if (fcntl(fd, F_SETFD, 1) == -1)
23152284Sobrien		err(1, "fcntl(F_SETFD) (crget)");
23252284Sobrien	return fd;
23352284Sobrien}
23452284Sobrien
23552284Sobrienstatic char
23652284Sobrienrdigit(void)
23790075Sobrien{
23890075Sobrien	const char a[] = {
23952284Sobrien		0x10,0x54,0x11,0x48,0x45,0x12,0x4f,0x13,0x49,0x53,0x14,0x41,
24052284Sobrien		0x15,0x16,0x4e,0x55,0x54,0x17,0x18,0x4a,0x4f,0x42,0x19,0x01
24152284Sobrien	};
24290075Sobrien	return 0x20+a[random()%N(a)];
24390075Sobrien}
24490075Sobrien
24590075Sobrienstatic void
24690075Sobrienruntest(struct alg *alg, int count, int size, u_long cmd, struct timeval *tv)
24790075Sobrien{
24890075Sobrien	int i, fd = crget();
24990075Sobrien	struct timeval start, stop, dt;
25090075Sobrien	char *cleartext, *ciphertext, *originaltext;
25190075Sobrien	struct session2_op sop;
25290075Sobrien	struct crypt_op cop;
25390075Sobrien	char iv[8];
25490075Sobrien
25590075Sobrien	bzero(&sop, sizeof(sop));
25690075Sobrien	if (!alg->ishash) {
25790075Sobrien		sop.keylen = (alg->minkeylen + alg->maxkeylen)/2;
25890075Sobrien		sop.key = (char *) malloc(sop.keylen);
25990075Sobrien		if (sop.key == NULL)
26090075Sobrien			err(1, "malloc (key)");
26190075Sobrien		for (i = 0; i < sop.keylen; i++)
26290075Sobrien			sop.key[i] = rdigit();
26390075Sobrien		sop.cipher = alg->code;
26490075Sobrien	} else {
26590075Sobrien		sop.mackeylen = (alg->minkeylen + alg->maxkeylen)/2;
26690075Sobrien		sop.mackey = (char *) malloc(sop.mackeylen);
26790075Sobrien		if (sop.mackey == NULL)
26890075Sobrien			err(1, "malloc (mac)");
26990075Sobrien		for (i = 0; i < sop.mackeylen; i++)
27090075Sobrien			sop.mackey[i] = rdigit();
27190075Sobrien		sop.mac = alg->code;
27290075Sobrien	}
27390075Sobrien	sop.crid = crid;
27490075Sobrien	if (ioctl(fd, cmd, &sop) < 0) {
27590075Sobrien		if (cmd == CIOCGSESSION || cmd == CIOCGSESSION2) {
27690075Sobrien			close(fd);
27790075Sobrien			if (verbose) {
27890075Sobrien				printf("cipher %s", alg->name);
27990075Sobrien				if (alg->ishash)
28090075Sobrien					printf(" mackeylen %u\n", sop.mackeylen);
28190075Sobrien				else
28290075Sobrien					printf(" keylen %u\n", sop.keylen);
28390075Sobrien				perror("CIOCGSESSION");
28490075Sobrien			}
28590075Sobrien			/* hardware doesn't support algorithm; skip it */
28690075Sobrien			return;
28790075Sobrien		}
28890075Sobrien		printf("cipher %s keylen %u mackeylen %u\n",
28990075Sobrien			alg->name, sop.keylen, sop.mackeylen);
29090075Sobrien		err(1, "CIOCGSESSION");
29190075Sobrien	}
29290075Sobrien
29390075Sobrien	originaltext = malloc(3*size);
29490075Sobrien	if (originaltext == NULL)
29590075Sobrien		err(1, "malloc (text)");
29690075Sobrien	cleartext = originaltext+size;
29790075Sobrien	ciphertext = cleartext+size;
29890075Sobrien	for (i = 0; i < size; i++)
29990075Sobrien		cleartext[i] = rdigit();
30090075Sobrien	memcpy(originaltext, cleartext, size);
30190075Sobrien	for (i = 0; i < N(iv); i++)
30290075Sobrien		iv[i] = rdigit();
30390075Sobrien
30490075Sobrien	if (verbose) {
30590075Sobrien		printf("session = 0x%x\n", sop.ses);
30652284Sobrien		printf("device = %s\n", crfind(sop.crid));
30752284Sobrien		printf("count = %d, size = %d\n", count, size);
30890075Sobrien		if (!alg->ishash) {
30990075Sobrien			printf("iv:");
31090075Sobrien			hexdump(iv, sizeof iv);
31190075Sobrien		}
31290075Sobrien		printf("cleartext:");
31390075Sobrien		hexdump(cleartext, MIN(size, CHUNK));
31490075Sobrien	}
31590075Sobrien
31690075Sobrien	gettimeofday(&start, NULL);
31790075Sobrien	if (!alg->ishash) {
31890075Sobrien		for (i = 0; i < count; i++) {
31990075Sobrien			cop.ses = sop.ses;
32090075Sobrien			cop.op = COP_ENCRYPT;
32190075Sobrien			cop.flags = opflags;
32290075Sobrien			cop.len = size;
32390075Sobrien			cop.src = cleartext;
32490075Sobrien			cop.dst = ciphertext;
32590075Sobrien			cop.mac = 0;
326117395Skan			cop.iv = iv;
327117395Skan
32890075Sobrien			if (ioctl(fd, CIOCCRYPT, &cop) < 0)
32990075Sobrien				err(1, "ioctl(CIOCCRYPT)");
33090075Sobrien
33190075Sobrien			if (verify && bcmp(ciphertext, cleartext, size) == 0) {
33252284Sobrien				printf("cipher text unchanged:");
33352284Sobrien				hexdump(ciphertext, size);
33490075Sobrien			}
33590075Sobrien
33690075Sobrien			memset(cleartext, 'x', MIN(size, CHUNK));
33790075Sobrien			cop.ses = sop.ses;
338107590Sobrien			cop.op = COP_DECRYPT;
339107590Sobrien			cop.flags = opflags;
34052284Sobrien			cop.len = size;
34152284Sobrien			cop.src = ciphertext;
34290075Sobrien			cop.dst = cleartext;
34390075Sobrien			cop.mac = 0;
34490075Sobrien			cop.iv = iv;
34590075Sobrien
34690075Sobrien			if (ioctl(fd, CIOCCRYPT, &cop) < 0)
34752284Sobrien				err(1, "ioctl(CIOCCRYPT)");
348117395Skan
349117395Skan			if (verify && bcmp(cleartext, originaltext, size) != 0) {
35052284Sobrien				printf("decrypt mismatch:\n");
351117395Skan				printf("original:");
352117395Skan				hexdump(originaltext, size);
353117395Skan				printf("cleartext:");
354117395Skan				hexdump(cleartext, size);
355117395Skan			}
356117395Skan		}
35752284Sobrien	} else {
35890075Sobrien		for (i = 0; i < count; i++) {
35990075Sobrien			cop.ses = sop.ses;
36090075Sobrien			cop.op = 0;
36190075Sobrien			cop.flags = opflags;
36290075Sobrien			cop.len = size;
36352284Sobrien			cop.src = cleartext;
36490075Sobrien			cop.dst = 0;
36590075Sobrien			cop.mac = ciphertext;
36690075Sobrien			cop.iv = 0;
36790075Sobrien
36890075Sobrien			if (ioctl(fd, CIOCCRYPT, &cop) < 0)
36952284Sobrien				err(1, "ioctl(CIOCCRYPT)");
37090075Sobrien		}
37190075Sobrien	}
37290075Sobrien	gettimeofday(&stop, NULL);
37390075Sobrien
37490075Sobrien	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
37590075Sobrien		perror("ioctl(CIOCFSESSION)");
37690075Sobrien
37790075Sobrien	if (verbose) {
37890075Sobrien		printf("cleartext:");
37990075Sobrien		hexdump(cleartext, MIN(size, CHUNK));
38090075Sobrien	}
38190075Sobrien	timersub(&stop, &start, tv);
38290075Sobrien
38390075Sobrien	free(originaltext);
38490075Sobrien
38590075Sobrien	close(fd);
38690075Sobrien}
38790075Sobrien
38890075Sobrien#ifdef __FreeBSD__
38990075Sobrienstatic void
39090075Sobrienresetstats()
39190075Sobrien{
39290075Sobrien	struct cryptostats stats;
39390075Sobrien	size_t slen;
39490075Sobrien
39590075Sobrien	slen = sizeof (stats);
39690075Sobrien	if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0) {
39790075Sobrien		perror("kern.crypto_stats");
39890075Sobrien		return;
39990075Sobrien	}
40090075Sobrien	bzero(&stats.cs_invoke, sizeof (stats.cs_invoke));
40190075Sobrien	bzero(&stats.cs_done, sizeof (stats.cs_done));
40290075Sobrien	bzero(&stats.cs_cb, sizeof (stats.cs_cb));
40390075Sobrien	bzero(&stats.cs_finis, sizeof (stats.cs_finis));
40490075Sobrien	stats.cs_invoke.min.tv_sec = 10000;
40590075Sobrien	stats.cs_done.min.tv_sec = 10000;
40690075Sobrien	stats.cs_cb.min.tv_sec = 10000;
40790075Sobrien	stats.cs_finis.min.tv_sec = 10000;
40890075Sobrien	if (sysctlbyname("kern.crypto_stats", NULL, NULL, &stats, sizeof (stats)) < 0)
40990075Sobrien		perror("kern.cryptostats");
41090075Sobrien}
41190075Sobrien
41290075Sobrienstatic void
41390075Sobrienprintt(const char* tag, struct cryptotstat *ts)
41490075Sobrien{
41590075Sobrien	uint64_t avg, min, max;
41690075Sobrien
41790075Sobrien	if (ts->count == 0)
41890075Sobrien		return;
41990075Sobrien	avg = (1000000000LL*ts->acc.tv_sec + ts->acc.tv_nsec) / ts->count;
42090075Sobrien	min = 1000000000LL*ts->min.tv_sec + ts->min.tv_nsec;
42190075Sobrien	max = 1000000000LL*ts->max.tv_sec + ts->max.tv_nsec;
42290075Sobrien	printf("%16.16s: avg %6llu ns : min %6llu ns : max %7llu ns [%u samps]\n",
42390075Sobrien		tag, avg, min, max, ts->count);
42452284Sobrien}
42590075Sobrien#endif
42690075Sobrien
42790075Sobrienstatic void
42852284Sobrienruntests(struct alg *alg, int count, int size, u_long cmd, int threads, int profile)
42990075Sobrien{
43090075Sobrien	int i, status;
43190075Sobrien	double t;
43290075Sobrien	void *region;
43390075Sobrien	struct timeval *tvp;
43490075Sobrien	struct timeval total;
43590075Sobrien	int otiming;
43690075Sobrien
43790075Sobrien	if (size % alg->blocksize) {
43890075Sobrien		if (verbose)
43990075Sobrien			printf("skipping blocksize %u 'cuz not a multiple of "
44090075Sobrien				"%s blocksize %u\n",
44190075Sobrien				size, alg->name, alg->blocksize);
44290075Sobrien		return;
44390075Sobrien	}
44490075Sobrien
44590075Sobrien	region = mmap(NULL, threads * sizeof (struct timeval),
44690075Sobrien			PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
44790075Sobrien	if (region == MAP_FAILED) {
44852284Sobrien		perror("mmap");
44952284Sobrien		return;
45052284Sobrien	}
45190075Sobrien	tvp = (struct timeval *) region;
45290075Sobrien#ifdef __FreeBSD__
45390075Sobrien	if (profile) {
45490075Sobrien		size_t tlen = sizeof (otiming);
45590075Sobrien		int timing = 1;
45690075Sobrien
45790075Sobrien		resetstats();
45890075Sobrien		if (sysctlbyname("debug.crypto_timing", &otiming, &tlen,
45990075Sobrien				&timing, sizeof (timing)) < 0)
46090075Sobrien			perror("debug.crypto_timing");
46190075Sobrien	}
46290075Sobrien#endif
46390075Sobrien
46490075Sobrien	if (threads > 1) {
46590075Sobrien		for (i = 0; i < threads; i++)
46690075Sobrien			if (fork() == 0) {
46790075Sobrien				runtest(alg, count, size, cmd, &tvp[i]);
46890075Sobrien				exit(0);
46990075Sobrien			}
47090075Sobrien		while (waitpid(WAIT_MYPGRP, &status, 0) != -1)
47190075Sobrien			;
47290075Sobrien	} else
47390075Sobrien		runtest(alg, count, size, cmd, tvp);
47490075Sobrien
47590075Sobrien	t = 0;
47690075Sobrien	for (i = 0; i < threads; i++)
47790075Sobrien		t += (((double)tvp[i].tv_sec * 1000000 + tvp[i].tv_usec) / 1000000);
47890075Sobrien	if (t) {
47990075Sobrien		int nops = alg->ishash ? count : 2*count;
48090075Sobrien
48190075Sobrien#if 0
48290075Sobrien		t /= threads;
48390075Sobrien		printf("%6.3lf sec, %7d %6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n",
48490075Sobrien		    t, nops, alg->name, size, (double)nops*size / t,
48590075Sobrien		    (double)nops*size / t * 8 / 1024 / 1024);
48690075Sobrien#else
48790075Sobrien		nops *= threads;
48890075Sobrien		printf("%8.3lf sec, %7d %6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n",
48990075Sobrien		    t, nops, alg->name, size, (double)nops*size / t,
49090075Sobrien		    (double)nops*size / t * 8 / 1024 / 1024);
49190075Sobrien#endif
49290075Sobrien	}
49390075Sobrien#ifdef __FreeBSD__
49490075Sobrien	if (profile) {
49590075Sobrien		struct cryptostats stats;
49690075Sobrien		size_t slen = sizeof (stats);
49790075Sobrien
49890075Sobrien		if (sysctlbyname("debug.crypto_timing", NULL, NULL,
49990075Sobrien				&otiming, sizeof (otiming)) < 0)
50090075Sobrien			perror("debug.crypto_timing");
50190075Sobrien		if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0)
50290075Sobrien			perror("kern.cryptostats");
50390075Sobrien		if (stats.cs_invoke.count) {
50490075Sobrien			printt("dispatch->invoke", &stats.cs_invoke);
50590075Sobrien			printt("invoke->done", &stats.cs_done);
50690075Sobrien			printt("done->cb", &stats.cs_cb);
50790075Sobrien			printt("cb->finis", &stats.cs_finis);
50890075Sobrien		}
50990075Sobrien	}
51090075Sobrien#endif
51190075Sobrien	fflush(stdout);
51290075Sobrien}
51390075Sobrien
51490075Sobrienint
51590075Sobrienmain(int argc, char **argv)
51690075Sobrien{
51790075Sobrien	struct alg *alg = NULL;
51890075Sobrien	int count = 1;
51990075Sobrien	int sizes[128], nsizes = 0;
52090075Sobrien	u_long cmd = CIOCGSESSION2;
52190075Sobrien	int testall = 0;
52290075Sobrien	int maxthreads = 1;
52390075Sobrien	int profile = 0;
52490075Sobrien	int i, ch;
525117395Skan
526117395Skan	while ((ch = getopt(argc, argv, "cpzsva:bd:t:")) != -1) {
52790075Sobrien		switch (ch) {
52890075Sobrien#ifdef CIOCGSSESSION
52990075Sobrien		case 's':
53090075Sobrien			cmd = CIOCGSSESSION;
53190075Sobrien			break;
53290075Sobrien#endif
53390075Sobrien		case 'v':
53490075Sobrien			verbose++;
53590075Sobrien			break;
53690075Sobrien		case 'a':
53790075Sobrien			alg = getalgbyname(optarg);
53890075Sobrien			if (alg == NULL) {
53990075Sobrien				if (streq(optarg, "rijndael"))
54090075Sobrien					alg = getalgbyname("aes");
54190075Sobrien				else
54290075Sobrien					usage(argv[0]);
54390075Sobrien			}
54490075Sobrien			break;
54590075Sobrien		case 'd':
54690075Sobrien			crid = crlookup(optarg);
54790075Sobrien			break;
54890075Sobrien		case 't':
54990075Sobrien			maxthreads = atoi(optarg);
55090075Sobrien			break;
55190075Sobrien		case 'z':
55290075Sobrien			testall = 1;
55390075Sobrien			break;
55490075Sobrien		case 'p':
55590075Sobrien			profile = 1;
55690075Sobrien			break;
55790075Sobrien		case 'b':
55890075Sobrien			opflags |= COP_F_BATCH;
55990075Sobrien			break;
56090075Sobrien		case 'c':
56190075Sobrien			verify = 1;
56290075Sobrien			break;
56390075Sobrien		default:
56490075Sobrien			usage(argv[0]);
56590075Sobrien		}
56690075Sobrien	}
56790075Sobrien	argc -= optind, argv += optind;
56890075Sobrien	if (argc > 0)
56990075Sobrien		count = atoi(argv[0]);
57090075Sobrien	while (argc > 1) {
57190075Sobrien		int s = atoi(argv[1]);
57290075Sobrien		if (nsizes < N(sizes)) {
57390075Sobrien			sizes[nsizes++] = s;
57490075Sobrien		} else {
57590075Sobrien			printf("Too many sizes, ignoring %u\n", s);
57690075Sobrien		}
57790075Sobrien		argc--, argv++;
57890075Sobrien	}
57990075Sobrien	if (nsizes == 0) {
58090075Sobrien		if (alg)
581102780Skan			sizes[nsizes++] = alg->blocksize;
582102780Skan		else
583102780Skan			sizes[nsizes++] = 8;
584102780Skan		if (testall) {
585102780Skan			while (sizes[nsizes-1] < 8*1024) {
586102780Skan				sizes[nsizes] = sizes[nsizes-1]<<1;
587102780Skan				nsizes++;
588102780Skan			}
58990075Sobrien		}
59090075Sobrien	}
59190075Sobrien
59290075Sobrien	if (testall) {
59390075Sobrien		for (i = 0; i < N(algorithms); i++) {
59490075Sobrien			int j;
59590075Sobrien			alg = &algorithms[i];
59690075Sobrien			for (j = 0; j < nsizes; j++)
59790075Sobrien				runtests(alg, count, sizes[j], cmd, maxthreads, profile);
59890075Sobrien		}
59990075Sobrien	} else {
60090075Sobrien		if (alg == NULL)
60190075Sobrien			alg = getalgbycode(CRYPTO_3DES_CBC);
60290075Sobrien		for (i = 0; i < nsizes; i++)
60390075Sobrien			runtests(alg, count, sizes[i], cmd, maxthreads, profile);
60490075Sobrien	}
60590075Sobrien
60690075Sobrien	return (0);
60790075Sobrien}
60890075Sobrien
60990075Sobrienvoid
61090075Sobrienhexdump(char *p, int n)
61190075Sobrien{
61290075Sobrien	int i, off;
61390075Sobrien
61490075Sobrien	for (off = 0; n > 0; off += 16, n -= 16) {
61590075Sobrien		printf("%s%04x:", off == 0 ? "\n" : "", off);
61652284Sobrien		i = (n >= 16 ? 16 : n);
61752284Sobrien		do {
61852284Sobrien			printf(" %02x", *p++ & 0xff);
61952284Sobrien		} while (--i);
620117395Skan		printf("\n");
62152284Sobrien	}
62252284Sobrien}
62352284Sobrien