cryptotest.c revision 167755
1134911Ssam/*-
2134911Ssam * Copyright (c) 2004 Sam Leffler, Errno Consulting
3134911Ssam * All rights reserved.
4134911Ssam *
5134911Ssam * Redistribution and use in source and binary forms, with or without
6134911Ssam * modification, are permitted provided that the following conditions
7134911Ssam * are met:
8134911Ssam * 1. Redistributions of source code must retain the above copyright
9134911Ssam *    notice, this list of conditions and the following disclaimer,
10134911Ssam *    without modification.
11134911Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12134911Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13134911Ssam *    redistribution must be conditioned upon including a substantially
14134911Ssam *    similar Disclaimer requirement for further binary redistribution.
15134911Ssam * 3. Neither the names of the above-listed copyright holders nor the names
16134911Ssam *    of any contributors may be used to endorse or promote products derived
17134911Ssam *    from this software without specific prior written permission.
18134911Ssam *
19134911Ssam * NO WARRANTY
20134911Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21134911Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22134911Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
23134911Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
24134911Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
25134911Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26134911Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27134911Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
28134911Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29134911Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30134911Ssam * THE POSSIBILITY OF SUCH DAMAGES.
31134911Ssam *
32134911Ssam * $FreeBSD: head/tools/tools/crypto/cryptotest.c 167755 2007-03-21 03:42:51Z sam $
33134911Ssam */
34134911Ssam
35134911Ssam/*
36134911Ssam * Simple tool for testing hardware/system crypto support.
37134911Ssam *
38134911Ssam * cryptotest [-czsbv] [-a algorithm] [count] [size ...]
39134911Ssam *
40134911Ssam * Run count iterations of a crypt+decrypt or mac operation on a buffer of
41134911Ssam * size bytes.  A random key and iv are used.  Options:
42134911Ssam *	-c	check the results
43167755Ssam *	-d dev	pin work on device dev
44134911Ssam *	-z	run all available algorithms on a variety of buffer sizes
45134911Ssam *	-v	be verbose
46134911Ssam *	-b	mark operations for batching
47134911Ssam *	-p	profile kernel crypto operations (must be root)
48134911Ssam *	-t n	fork n threads and run tests concurrently
49134911Ssam * Known algorithms are:
50134911Ssam *	null	null cbc
51134911Ssam *	des	des cbc
52134911Ssam *	3des	3des cbc
53134911Ssam *	blf	blowfish cbc
54134911Ssam *	cast	cast cbc
55134911Ssam *	skj	skipjack cbc
56134911Ssam *	aes	rijndael/aes 128-bit cbc
57134911Ssam *	aes192	rijndael/aes 192-bit cbc
58134911Ssam *	aes256	rijndael/aes 256-bit cbc
59134911Ssam *	md5	md5 hmac
60134911Ssam *	sha1	sha1 hmac
61134911Ssam *	sha256	256-bit sha2 hmac
62134911Ssam *	sha384	384-bit sha2 hmac
63134911Ssam *	sha512	512--bit sha2 hmac
64134911Ssam *
65134911Ssam * For a test of how fast a crypto card is, use something like:
66134911Ssam *	cryptotest -z 1024
67134911Ssam * This will run a series of tests using the available crypto/cipher
68134911Ssam * algorithms over a variety of buffer sizes.  The 1024 says to do 1024
69134911Ssam * iterations.  Extra arguments can be used to specify one or more buffer
70134911Ssam * sizes to use in doing tests.
71134911Ssam *
72134911Ssam * To fork multiple processes all doing the same work, specify -t X on the
73134911Ssam * command line to get X "threads" running simultaneously.  No effort is made
74134911Ssam * to synchronize the threads or otherwise maximize load.
75134911Ssam *
76134911Ssam * If the kernel crypto code is built with CRYPTO_TIMING and you run as root,
77134911Ssam * then you can specify the -p option to get a "profile" of the time spent
78134911Ssam * processing crypto operations.  At present this data is only meaningful for
79134911Ssam * symmetric operations.  To get meaningful numbers you must run on an idle
80134911Ssam * machine.
81134911Ssam *
82134911Ssam * Expect ~400 Mb/s for a Broadcom 582x for 8K buffers on a reasonable CPU
83134911Ssam * (64-bit PCI helps).  Hifn 7811 parts top out at ~110 Mb/s.
84134911Ssam */
85134911Ssam#include <sys/types.h>
86134911Ssam#include <sys/param.h>
87134911Ssam#include <sys/time.h>
88134911Ssam#include <sys/ioctl.h>
89134911Ssam#include <stdio.h>
90134911Ssam#include <fcntl.h>
91134911Ssam#include <unistd.h>
92134911Ssam#include <sys/wait.h>
93134911Ssam#include <sys/mman.h>
94134911Ssam#include <paths.h>
95134911Ssam#include <stdlib.h>
96134911Ssam
97134911Ssam#include <sys/sysctl.h>
98134911Ssam#include <sys/time.h>
99134911Ssam#include <crypto/cryptodev.h>
100134911Ssam
101134911Ssam#define	CHUNK	64	/* how much to display */
102134911Ssam#define	N(a)		(sizeof (a) / sizeof (a[0]))
103134911Ssam#define	streq(a,b)	(strcasecmp(a,b) == 0)
104134911Ssam
105134911Ssamvoid	hexdump(char *, int);
106134911Ssam
107134911Ssamint	verbose = 0;
108134911Ssamint	opflags = 0;
109134911Ssamint	verify = 0;
110167755Ssamint	crid = CRYPTO_FLAG_HARDWARE;
111134911Ssam
112134911Ssamstruct alg {
113134911Ssam	const char* name;
114134911Ssam	int	ishash;
115134911Ssam	int	blocksize;
116134911Ssam	int	minkeylen;
117134911Ssam	int	maxkeylen;
118134911Ssam	int	code;
119134911Ssam} algorithms[] = {
120134911Ssam#ifdef CRYPTO_NULL_CBC
121134911Ssam	{ "null",	0,	8,	1,	256,	CRYPTO_NULL_CBC },
122134911Ssam#endif
123134911Ssam	{ "des",	0,	8,	8,	8,	CRYPTO_DES_CBC },
124134911Ssam	{ "3des",	0,	8,	24,	24,	CRYPTO_3DES_CBC },
125134911Ssam	{ "blf",	0,	8,	5,	56,	CRYPTO_BLF_CBC },
126134911Ssam	{ "cast",	0,	8,	5,	16,	CRYPTO_CAST_CBC },
127134911Ssam	{ "skj",	0,	8,	10,	10,	CRYPTO_SKIPJACK_CBC },
128134911Ssam	{ "aes",	0,	16,	16,	16,	CRYPTO_RIJNDAEL128_CBC},
129134911Ssam	{ "aes192",	0,	16,	24,	24,	CRYPTO_RIJNDAEL128_CBC},
130134911Ssam	{ "aes256",	0,	16,	32,	32,	CRYPTO_RIJNDAEL128_CBC},
131134911Ssam#ifdef notdef
132134911Ssam	{ "arc4",	0,	8,	1,	32,	CRYPTO_ARC4 },
133134911Ssam#endif
134134911Ssam	{ "md5",	1,	8,	16,	16,	CRYPTO_MD5_HMAC },
135134911Ssam	{ "sha1",	1,	8,	20,	20,	CRYPTO_SHA1_HMAC },
136158886Smr	{ "sha256",	1,	8,	32,	32,	CRYPTO_SHA2_256_HMAC },
137158886Smr	{ "sha384",	1,	8,	48,	48,	CRYPTO_SHA2_384_HMAC },
138158886Smr	{ "sha512",	1,	8,	64,	64,	CRYPTO_SHA2_512_HMAC },
139134911Ssam};
140134911Ssam
141134911Ssamstatic void
142134911Ssamusage(const char* cmd)
143134911Ssam{
144167755Ssam	printf("usage: %s [-czsbv] [-d dev] [-a algorithm] [count] [size ...]\n",
145134911Ssam		cmd);
146134911Ssam	printf("where algorithm is one of:\n");
147134911Ssam	printf("    des 3des (default) blowfish cast skipjack\n");
148134911Ssam	printf("    aes (aka rijndael) aes192 aes256 arc4\n");
149134911Ssam	printf("count is the number of encrypt/decrypt ops to do\n");
150134911Ssam	printf("size is the number of bytes of text to encrypt+decrypt\n");
151134911Ssam	printf("\n");
152134911Ssam	printf("-c check the results (slows timing)\n");
153167755Ssam	printf("-d use specific device\n");
154134911Ssam	printf("-z run all available algorithms on a variety of sizes\n");
155134911Ssam	printf("-v be verbose\n");
156134911Ssam	printf("-b mark operations for batching\n");
157134911Ssam	printf("-p profile kernel crypto operation (must be root)\n");
158134911Ssam	exit(-1);
159134911Ssam}
160134911Ssam
161134911Ssamstatic struct alg*
162134911Ssamgetalgbycode(int cipher)
163134911Ssam{
164134911Ssam	int i;
165134911Ssam
166134911Ssam	for (i = 0; i < N(algorithms); i++)
167134911Ssam		if (cipher == algorithms[i].code)
168134911Ssam			return &algorithms[i];
169134911Ssam	return NULL;
170134911Ssam}
171134911Ssam
172134911Ssamstatic struct alg*
173134911Ssamgetalgbyname(const char* name)
174134911Ssam{
175134911Ssam	int i;
176134911Ssam
177134911Ssam	for (i = 0; i < N(algorithms); i++)
178134911Ssam		if (streq(name, algorithms[i].name))
179134911Ssam			return &algorithms[i];
180134911Ssam	return NULL;
181134911Ssam}
182134911Ssam
183134911Ssamstatic int
184134911Ssamdevcrypto(void)
185134911Ssam{
186134911Ssam	static int fd = -1;
187134911Ssam
188134911Ssam	if (fd < 0) {
189134911Ssam		fd = open(_PATH_DEV "crypto", O_RDWR, 0);
190134911Ssam		if (fd < 0)
191134911Ssam			err(1, _PATH_DEV "crypto");
192134911Ssam		if (fcntl(fd, F_SETFD, 1) == -1)
193134911Ssam			err(1, "fcntl(F_SETFD) (devcrypto)");
194134911Ssam	}
195134911Ssam	return fd;
196134911Ssam}
197134911Ssam
198134911Ssamstatic int
199167755Ssamcrlookup(const char *devname)
200167755Ssam{
201167755Ssam	struct crypt_find_op find;
202167755Ssam
203167755Ssam	find.crid = -1;
204167755Ssam	strlcpy(find.name, devname, sizeof(find.name));
205167755Ssam	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
206167755Ssam		err(1, "ioctl(CIOCFINDDEV)");
207167755Ssam	return find.crid;
208167755Ssam}
209167755Ssam
210167755Ssamstatic const char *
211167755Ssamcrfind(int crid)
212167755Ssam{
213167755Ssam	static struct crypt_find_op find;
214167755Ssam
215167755Ssam	bzero(&find, sizeof(find));
216167755Ssam	find.crid = crid;
217167755Ssam	if (ioctl(devcrypto(), CRIOFINDDEV, &find) == -1)
218167755Ssam		err(1, "ioctl(CIOCFINDDEV): crid %d", crid);
219167755Ssam	return find.name;
220167755Ssam}
221167755Ssam
222167755Ssamstatic int
223134911Ssamcrget(void)
224134911Ssam{
225134911Ssam	int fd;
226134911Ssam
227134911Ssam	if (ioctl(devcrypto(), CRIOGET, &fd) == -1)
228134911Ssam		err(1, "ioctl(CRIOGET)");
229134911Ssam	if (fcntl(fd, F_SETFD, 1) == -1)
230134911Ssam		err(1, "fcntl(F_SETFD) (crget)");
231134911Ssam	return fd;
232134911Ssam}
233134911Ssam
234134911Ssamstatic char
235134911Ssamrdigit(void)
236134911Ssam{
237134911Ssam	const char a[] = {
238134911Ssam		0x10,0x54,0x11,0x48,0x45,0x12,0x4f,0x13,0x49,0x53,0x14,0x41,
239134911Ssam		0x15,0x16,0x4e,0x55,0x54,0x17,0x18,0x4a,0x4f,0x42,0x19,0x01
240134911Ssam	};
241134911Ssam	return 0x20+a[random()%N(a)];
242134911Ssam}
243134911Ssam
244134911Ssamstatic void
245140407Sphkruntest(struct alg *alg, int count, int size, u_long cmd, struct timeval *tv)
246134911Ssam{
247134911Ssam	int i, fd = crget();
248134911Ssam	struct timeval start, stop, dt;
249134911Ssam	char *cleartext, *ciphertext, *originaltext;
250167755Ssam	struct session2_op sop;
251134911Ssam	struct crypt_op cop;
252134911Ssam	char iv[8];
253134911Ssam
254134911Ssam	bzero(&sop, sizeof(sop));
255134911Ssam	if (!alg->ishash) {
256134911Ssam		sop.keylen = (alg->minkeylen + alg->maxkeylen)/2;
257134911Ssam		sop.key = (char *) malloc(sop.keylen);
258134911Ssam		if (sop.key == NULL)
259134911Ssam			err(1, "malloc (key)");
260134911Ssam		for (i = 0; i < sop.keylen; i++)
261134911Ssam			sop.key[i] = rdigit();
262134911Ssam		sop.cipher = alg->code;
263134911Ssam	} else {
264134911Ssam		sop.mackeylen = (alg->minkeylen + alg->maxkeylen)/2;
265134911Ssam		sop.mackey = (char *) malloc(sop.mackeylen);
266134911Ssam		if (sop.mackey == NULL)
267134911Ssam			err(1, "malloc (mac)");
268134911Ssam		for (i = 0; i < sop.mackeylen; i++)
269134911Ssam			sop.mackey[i] = rdigit();
270134911Ssam		sop.mac = alg->code;
271134911Ssam	}
272167755Ssam	sop.crid = crid;
273134911Ssam	if (ioctl(fd, cmd, &sop) < 0) {
274167755Ssam		if (cmd == CIOCGSESSION || cmd == CIOCGSESSION2) {
275134911Ssam			close(fd);
276134911Ssam			if (verbose) {
277134911Ssam				printf("cipher %s", alg->name);
278134911Ssam				if (alg->ishash)
279134911Ssam					printf(" mackeylen %u\n", sop.mackeylen);
280134911Ssam				else
281134911Ssam					printf(" keylen %u\n", sop.keylen);
282134911Ssam				perror("CIOCGSESSION");
283134911Ssam			}
284134911Ssam			/* hardware doesn't support algorithm; skip it */
285134911Ssam			return;
286134911Ssam		}
287134911Ssam		printf("cipher %s keylen %u mackeylen %u\n",
288134911Ssam			alg->name, sop.keylen, sop.mackeylen);
289134911Ssam		err(1, "CIOCGSESSION");
290134911Ssam	}
291134911Ssam
292134911Ssam	originaltext = malloc(3*size);
293134911Ssam	if (originaltext == NULL)
294134911Ssam		err(1, "malloc (text)");
295134911Ssam	cleartext = originaltext+size;
296134911Ssam	ciphertext = cleartext+size;
297134911Ssam	for (i = 0; i < size; i++)
298134911Ssam		cleartext[i] = rdigit();
299134911Ssam	memcpy(originaltext, cleartext, size);
300134911Ssam	for (i = 0; i < N(iv); i++)
301134911Ssam		iv[i] = rdigit();
302134911Ssam
303134911Ssam	if (verbose) {
304134911Ssam		printf("session = 0x%x\n", sop.ses);
305167755Ssam		printf("device = %s\n", crfind(sop.crid));
306134911Ssam		printf("count = %d, size = %d\n", count, size);
307134911Ssam		if (!alg->ishash) {
308134911Ssam			printf("iv:");
309134911Ssam			hexdump(iv, sizeof iv);
310134911Ssam		}
311134911Ssam		printf("cleartext:");
312134911Ssam		hexdump(cleartext, MIN(size, CHUNK));
313134911Ssam	}
314134911Ssam
315134911Ssam	gettimeofday(&start, NULL);
316134911Ssam	if (!alg->ishash) {
317134911Ssam		for (i = 0; i < count; i++) {
318134911Ssam			cop.ses = sop.ses;
319134911Ssam			cop.op = COP_ENCRYPT;
320134911Ssam			cop.flags = opflags;
321134911Ssam			cop.len = size;
322134911Ssam			cop.src = cleartext;
323134911Ssam			cop.dst = ciphertext;
324134911Ssam			cop.mac = 0;
325134911Ssam			cop.iv = iv;
326134911Ssam
327134911Ssam			if (ioctl(fd, CIOCCRYPT, &cop) < 0)
328134911Ssam				err(1, "ioctl(CIOCCRYPT)");
329134911Ssam
330134911Ssam			if (verify && bcmp(ciphertext, cleartext, size) == 0) {
331134911Ssam				printf("cipher text unchanged:");
332134911Ssam				hexdump(ciphertext, size);
333134911Ssam			}
334134911Ssam
335134911Ssam			memset(cleartext, 'x', MIN(size, CHUNK));
336134911Ssam			cop.ses = sop.ses;
337134911Ssam			cop.op = COP_DECRYPT;
338134911Ssam			cop.flags = opflags;
339134911Ssam			cop.len = size;
340134911Ssam			cop.src = ciphertext;
341134911Ssam			cop.dst = cleartext;
342134911Ssam			cop.mac = 0;
343134911Ssam			cop.iv = iv;
344134911Ssam
345134911Ssam			if (ioctl(fd, CIOCCRYPT, &cop) < 0)
346134911Ssam				err(1, "ioctl(CIOCCRYPT)");
347134911Ssam
348134911Ssam			if (verify && bcmp(cleartext, originaltext, size) != 0) {
349134911Ssam				printf("decrypt mismatch:\n");
350134911Ssam				printf("original:");
351134911Ssam				hexdump(originaltext, size);
352134911Ssam				printf("cleartext:");
353134911Ssam				hexdump(cleartext, size);
354134911Ssam			}
355134911Ssam		}
356134911Ssam	} else {
357134911Ssam		for (i = 0; i < count; i++) {
358134911Ssam			cop.ses = sop.ses;
359134911Ssam			cop.op = 0;
360134911Ssam			cop.flags = opflags;
361134911Ssam			cop.len = size;
362134911Ssam			cop.src = cleartext;
363134911Ssam			cop.dst = 0;
364134911Ssam			cop.mac = ciphertext;
365134911Ssam			cop.iv = 0;
366134911Ssam
367134911Ssam			if (ioctl(fd, CIOCCRYPT, &cop) < 0)
368134911Ssam				err(1, "ioctl(CIOCCRYPT)");
369134911Ssam		}
370134911Ssam	}
371134911Ssam	gettimeofday(&stop, NULL);
372134911Ssam
373134911Ssam	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
374134911Ssam		perror("ioctl(CIOCFSESSION)");
375134911Ssam
376134911Ssam	if (verbose) {
377134911Ssam		printf("cleartext:");
378134911Ssam		hexdump(cleartext, MIN(size, CHUNK));
379134911Ssam	}
380134911Ssam	timersub(&stop, &start, tv);
381134911Ssam
382134911Ssam	free(originaltext);
383134911Ssam
384134911Ssam	close(fd);
385134911Ssam}
386134911Ssam
387134911Ssam#ifdef __FreeBSD__
388134911Ssamstatic void
389134911Ssamresetstats()
390134911Ssam{
391134911Ssam	struct cryptostats stats;
392134911Ssam	size_t slen;
393134911Ssam
394134911Ssam	slen = sizeof (stats);
395140407Sphk	if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0) {
396134911Ssam		perror("kern.crypto_stats");
397134911Ssam		return;
398134911Ssam	}
399134911Ssam	bzero(&stats.cs_invoke, sizeof (stats.cs_invoke));
400134911Ssam	bzero(&stats.cs_done, sizeof (stats.cs_done));
401134911Ssam	bzero(&stats.cs_cb, sizeof (stats.cs_cb));
402134911Ssam	bzero(&stats.cs_finis, sizeof (stats.cs_finis));
403134911Ssam	stats.cs_invoke.min.tv_sec = 10000;
404134911Ssam	stats.cs_done.min.tv_sec = 10000;
405134911Ssam	stats.cs_cb.min.tv_sec = 10000;
406134911Ssam	stats.cs_finis.min.tv_sec = 10000;
407134911Ssam	if (sysctlbyname("kern.crypto_stats", NULL, NULL, &stats, sizeof (stats)) < 0)
408134911Ssam		perror("kern.cryptostats");
409134911Ssam}
410134911Ssam
411134911Ssamstatic void
412134911Ssamprintt(const char* tag, struct cryptotstat *ts)
413134911Ssam{
414134911Ssam	uint64_t avg, min, max;
415134911Ssam
416134911Ssam	if (ts->count == 0)
417134911Ssam		return;
418134911Ssam	avg = (1000000000LL*ts->acc.tv_sec + ts->acc.tv_nsec) / ts->count;
419134911Ssam	min = 1000000000LL*ts->min.tv_sec + ts->min.tv_nsec;
420134911Ssam	max = 1000000000LL*ts->max.tv_sec + ts->max.tv_nsec;
421134911Ssam	printf("%16.16s: avg %6llu ns : min %6llu ns : max %7llu ns [%u samps]\n",
422134911Ssam		tag, avg, min, max, ts->count);
423134911Ssam}
424134911Ssam#endif
425134911Ssam
426134911Ssamstatic void
427140407Sphkruntests(struct alg *alg, int count, int size, u_long cmd, int threads, int profile)
428134911Ssam{
429134911Ssam	int i, status;
430134911Ssam	double t;
431134911Ssam	void *region;
432134911Ssam	struct timeval *tvp;
433134911Ssam	struct timeval total;
434134911Ssam	int otiming;
435134911Ssam
436134911Ssam	if (size % alg->blocksize) {
437134911Ssam		if (verbose)
438134911Ssam			printf("skipping blocksize %u 'cuz not a multiple of "
439134911Ssam				"%s blocksize %u\n",
440134911Ssam				size, alg->name, alg->blocksize);
441134911Ssam		return;
442134911Ssam	}
443134911Ssam
444134911Ssam	region = mmap(NULL, threads * sizeof (struct timeval),
445134911Ssam			PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
446134911Ssam	if (region == MAP_FAILED) {
447134911Ssam		perror("mmap");
448134911Ssam		return;
449134911Ssam	}
450134911Ssam	tvp = (struct timeval *) region;
451134911Ssam#ifdef __FreeBSD__
452134911Ssam	if (profile) {
453134911Ssam		size_t tlen = sizeof (otiming);
454134911Ssam		int timing = 1;
455134911Ssam
456134911Ssam		resetstats();
457134911Ssam		if (sysctlbyname("debug.crypto_timing", &otiming, &tlen,
458134911Ssam				&timing, sizeof (timing)) < 0)
459134911Ssam			perror("debug.crypto_timing");
460134911Ssam	}
461134911Ssam#endif
462134911Ssam
463134911Ssam	if (threads > 1) {
464134911Ssam		for (i = 0; i < threads; i++)
465134911Ssam			if (fork() == 0) {
466134911Ssam				runtest(alg, count, size, cmd, &tvp[i]);
467134911Ssam				exit(0);
468134911Ssam			}
469134911Ssam		while (waitpid(WAIT_MYPGRP, &status, 0) != -1)
470134911Ssam			;
471134911Ssam	} else
472134911Ssam		runtest(alg, count, size, cmd, tvp);
473134911Ssam
474134911Ssam	t = 0;
475134911Ssam	for (i = 0; i < threads; i++)
476134911Ssam		t += (((double)tvp[i].tv_sec * 1000000 + tvp[i].tv_usec) / 1000000);
477134911Ssam	if (t) {
478134911Ssam		int nops = alg->ishash ? count : 2*count;
479134911Ssam
480167755Ssam#if 0
481134911Ssam		t /= threads;
482134911Ssam		printf("%6.3lf sec, %7d %6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n",
483134911Ssam		    t, nops, alg->name, size, (double)nops*size / t,
484134911Ssam		    (double)nops*size / t * 8 / 1024 / 1024);
485167755Ssam#else
486167755Ssam		nops *= threads;
487167755Ssam		printf("%8.3lf sec, %7d %6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n",
488167755Ssam		    t, nops, alg->name, size, (double)nops*size / t,
489167755Ssam		    (double)nops*size / t * 8 / 1024 / 1024);
490167755Ssam#endif
491134911Ssam	}
492134911Ssam#ifdef __FreeBSD__
493134911Ssam	if (profile) {
494134911Ssam		struct cryptostats stats;
495134911Ssam		size_t slen = sizeof (stats);
496134911Ssam
497134911Ssam		if (sysctlbyname("debug.crypto_timing", NULL, NULL,
498134911Ssam				&otiming, sizeof (otiming)) < 0)
499134911Ssam			perror("debug.crypto_timing");
500140407Sphk		if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0)
501134911Ssam			perror("kern.cryptostats");
502134911Ssam		if (stats.cs_invoke.count) {
503134911Ssam			printt("dispatch->invoke", &stats.cs_invoke);
504134911Ssam			printt("invoke->done", &stats.cs_done);
505134911Ssam			printt("done->cb", &stats.cs_cb);
506134911Ssam			printt("cb->finis", &stats.cs_finis);
507134911Ssam		}
508134911Ssam	}
509134911Ssam#endif
510134911Ssam	fflush(stdout);
511134911Ssam}
512134911Ssam
513134911Ssamint
514134911Ssammain(int argc, char **argv)
515134911Ssam{
516134911Ssam	struct alg *alg = NULL;
517134911Ssam	int count = 1;
518134911Ssam	int sizes[128], nsizes = 0;
519167755Ssam	u_long cmd = CIOCGSESSION2;
520134911Ssam	int testall = 0;
521134911Ssam	int maxthreads = 1;
522134911Ssam	int profile = 0;
523134911Ssam	int i, ch;
524134911Ssam
525167755Ssam	while ((ch = getopt(argc, argv, "cpzsva:bd:t:")) != -1) {
526134911Ssam		switch (ch) {
527134911Ssam#ifdef CIOCGSSESSION
528134911Ssam		case 's':
529134911Ssam			cmd = CIOCGSSESSION;
530134911Ssam			break;
531134911Ssam#endif
532134911Ssam		case 'v':
533134911Ssam			verbose++;
534134911Ssam			break;
535134911Ssam		case 'a':
536134911Ssam			alg = getalgbyname(optarg);
537134911Ssam			if (alg == NULL) {
538134911Ssam				if (streq(optarg, "rijndael"))
539134911Ssam					alg = getalgbyname("aes");
540134911Ssam				else
541134911Ssam					usage(argv[0]);
542134911Ssam			}
543134911Ssam			break;
544167755Ssam		case 'd':
545167755Ssam			crid = crlookup(optarg);
546167755Ssam			break;
547134911Ssam		case 't':
548134911Ssam			maxthreads = atoi(optarg);
549134911Ssam			break;
550134911Ssam		case 'z':
551134911Ssam			testall = 1;
552134911Ssam			break;
553134911Ssam		case 'p':
554134911Ssam			profile = 1;
555134911Ssam			break;
556134911Ssam		case 'b':
557134911Ssam			opflags |= COP_F_BATCH;
558134911Ssam			break;
559134911Ssam		case 'c':
560134911Ssam			verify = 1;
561134911Ssam			break;
562134911Ssam		default:
563134911Ssam			usage(argv[0]);
564134911Ssam		}
565134911Ssam	}
566134911Ssam	argc -= optind, argv += optind;
567134911Ssam	if (argc > 0)
568134911Ssam		count = atoi(argv[0]);
569134911Ssam	while (argc > 1) {
570134911Ssam		int s = atoi(argv[1]);
571134911Ssam		if (nsizes < N(sizes)) {
572134911Ssam			sizes[nsizes++] = s;
573134911Ssam		} else {
574134911Ssam			printf("Too many sizes, ignoring %u\n", s);
575134911Ssam		}
576134911Ssam		argc--, argv++;
577134911Ssam	}
578134911Ssam	if (nsizes == 0) {
579134911Ssam		if (alg)
580134911Ssam			sizes[nsizes++] = alg->blocksize;
581134911Ssam		else
582134911Ssam			sizes[nsizes++] = 8;
583134911Ssam		if (testall) {
584134911Ssam			while (sizes[nsizes-1] < 8*1024) {
585134911Ssam				sizes[nsizes] = sizes[nsizes-1]<<1;
586134911Ssam				nsizes++;
587134911Ssam			}
588134911Ssam		}
589134911Ssam	}
590134911Ssam
591134911Ssam	if (testall) {
592134911Ssam		for (i = 0; i < N(algorithms); i++) {
593134911Ssam			int j;
594134911Ssam			alg = &algorithms[i];
595134911Ssam			for (j = 0; j < nsizes; j++)
596134911Ssam				runtests(alg, count, sizes[j], cmd, maxthreads, profile);
597134911Ssam		}
598134911Ssam	} else {
599134911Ssam		if (alg == NULL)
600134911Ssam			alg = getalgbycode(CRYPTO_3DES_CBC);
601134911Ssam		for (i = 0; i < nsizes; i++)
602134911Ssam			runtests(alg, count, sizes[i], cmd, maxthreads, profile);
603134911Ssam	}
604134911Ssam
605134911Ssam	return (0);
606134911Ssam}
607134911Ssam
608134911Ssamvoid
609134911Ssamhexdump(char *p, int n)
610134911Ssam{
611134911Ssam	int i, off;
612134911Ssam
613134911Ssam	for (off = 0; n > 0; off += 16, n -= 16) {
614134911Ssam		printf("%s%04x:", off == 0 ? "\n" : "", off);
615134911Ssam		i = (n >= 16 ? 16 : n);
616134911Ssam		do {
617134911Ssam			printf(" %02x", *p++ & 0xff);
618134911Ssam		} while (--i);
619134911Ssam		printf("\n");
620134911Ssam	}
621134911Ssam}
622