xref: /freebsd/tools/tools/crypto/cryptotest.c (revision 9768746b)
1 /*-
2  * Copyright (c) 2004 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  * 3. Neither the names of the above-listed copyright holders nor the names
16  *    of any contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * NO WARRANTY
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
23  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
24  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
25  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
28  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30  * THE POSSIBILITY OF SUCH DAMAGES.
31  *
32  * $FreeBSD$
33  */
34 
35 /*
36  * Simple tool for testing hardware/system crypto support.
37  *
38  * cryptotest [-czsbv] [-a algorithm] [count] [size ...]
39  *
40  * Run count iterations of a crypt+decrypt or mac operation on a buffer of
41  * size bytes.  A random key and iv are used.  Options:
42  *	-c	check the results
43  *	-d dev	pin work on device dev
44  *	-z	run all available algorithms on a variety of buffer sizes
45  *	-v	be verbose
46  *	-b	mark operations for batching
47  *	-p	profile kernel crypto operations (must be root)
48  *	-t n	fork n threads and run tests concurrently
49  * Known algorithms are:
50  *	null	null cbc
51  *	des	des cbc
52  *	3des	3des cbc
53  *	blf	blowfish cbc
54  *	cast	cast cbc
55  *	skj	skipjack cbc
56  *	aes	rijndael/aes 128-bit cbc
57  *	aes192	rijndael/aes 192-bit cbc
58  *	aes256	rijndael/aes 256-bit cbc
59  *	chacha20 Chacha20 stream cipher
60  *	blake2b	Blake2b
61  *	blake2s	Blake2s
62  *	md5	md5 hmac
63  *	sha1	sha1 hmac
64  *	sha256	256-bit sha2 hmac
65  *	sha384	384-bit sha2 hmac
66  *	sha512	512--bit sha2 hmac
67  *
68  * For a test of how fast a crypto card is, use something like:
69  *	cryptotest -z 1024
70  * This will run a series of tests using the available crypto/cipher
71  * algorithms over a variety of buffer sizes.  The 1024 says to do 1024
72  * iterations.  Extra arguments can be used to specify one or more buffer
73  * sizes to use in doing tests.
74  *
75  * To fork multiple processes all doing the same work, specify -t X on the
76  * command line to get X "threads" running simultaneously.  No effort is made
77  * to synchronize the threads or otherwise maximize load.
78  *
79  * If the kernel crypto code is built with CRYPTO_TIMING and you run as root,
80  * then you can specify the -p option to get a "profile" of the time spent
81  * processing crypto operations.  At present this data is only meaningful for
82  * symmetric operations.  To get meaningful numbers you must run on an idle
83  * machine.
84  *
85  * Expect ~400 Mb/s for a Broadcom 582x for 8K buffers on a reasonable CPU
86  * (64-bit PCI helps).  Hifn 7811 parts top out at ~110 Mb/s.
87  */
88 
89 #include <sys/param.h>
90 #include <sys/cpuset.h>
91 #include <sys/ioctl.h>
92 #include <sys/mman.h>
93 #include <sys/sysctl.h>
94 #include <sys/time.h>
95 #include <sys/wait.h>
96 
97 #include <err.h>
98 #include <fcntl.h>
99 #include <paths.h>
100 #include <stdio.h>
101 #include <stdlib.h>
102 #include <string.h>
103 #include <sysexits.h>
104 #include <unistd.h>
105 
106 #include <crypto/cryptodev.h>
107 
108 #define	CHUNK	64	/* how much to display */
109 #define	streq(a,b)	(strcasecmp(a,b) == 0)
110 
111 void	hexdump(char *, int);
112 
113 int	verbose = 0;
114 int	opflags = 0;
115 int	verify = 0;
116 int	crid = CRYPTO_FLAG_HARDWARE;
117 
118 struct alg {
119 	const char* name;
120 	int	ishash;
121 	int	blocksize;
122 	int	minkeylen;
123 	int	maxkeylen;
124 	int	code;
125 } algorithms[] = {
126 #ifdef CRYPTO_NULL_CBC
127 	{ "null",	0,	8,	1,	256,	CRYPTO_NULL_CBC },
128 #endif
129 	{ "des",	0,	8,	8,	8,	CRYPTO_DES_CBC },
130 	{ "3des",	0,	8,	24,	24,	CRYPTO_3DES_CBC },
131 	{ "blf",	0,	8,	5,	56,	CRYPTO_BLF_CBC },
132 	{ "cast",	0,	8,	5,	16,	CRYPTO_CAST_CBC },
133 	{ "skj",	0,	8,	10,	10,	CRYPTO_SKIPJACK_CBC },
134 	{ "rij",	0,	16,	16,	16,	CRYPTO_RIJNDAEL128_CBC},
135 	{ "aes",	0,	16,	16,	16,	CRYPTO_AES_CBC},
136 	{ "aes192",	0,	16,	24,	24,	CRYPTO_AES_CBC},
137 	{ "aes256",	0,	16,	32,	32,	CRYPTO_AES_CBC},
138 	{ "chacha20",	0,	1,	32,	32,	CRYPTO_CHACHA20},
139 	{ "blake2b",	1,	128,	64,	64,	CRYPTO_BLAKE2B },
140 	{ "blake2s",	1,	64,	32,	32,	CRYPTO_BLAKE2S },
141 	{ "md5",	1,	8,	16,	16,	CRYPTO_MD5_HMAC },
142 	{ "sha1",	1,	8,	20,	20,	CRYPTO_SHA1_HMAC },
143 	{ "sha256",	1,	8,	32,	32,	CRYPTO_SHA2_256_HMAC },
144 	{ "sha384",	1,	8,	48,	48,	CRYPTO_SHA2_384_HMAC },
145 	{ "sha512",	1,	8,	64,	64,	CRYPTO_SHA2_512_HMAC },
146 };
147 
148 void
149 usage(const char* cmd)
150 {
151 	printf("usage: %s [-czsbv] [-d dev] [-a algorithm] [count] [size ...]\n",
152 		cmd);
153 	printf("where algorithm is one of:\n");
154 	printf("    null des 3des (default) blowfish cast skipjack rij\n");
155 	printf("    aes aes192 aes256 chacha20 md5 sha1 sha256 sha384 sha512\n");
156 	printf("    blake2b blake2s\n");
157 	printf(" or an encryption algorithm concatented with authentication\n");
158 	printf(" algorithm with '+' in the middle, e.g., aes+sha1.\n");
159 	printf("count is the number of encrypt/decrypt ops to do\n");
160 	printf("size is the number of bytes of text to encrypt+decrypt\n");
161 	printf("\n");
162 	printf("-c check the results (slows timing)\n");
163 	printf("-d use specific device, specify 'soft' for testing software implementations\n");
164 	printf("\tNOTE: to use software you must set:\n\t sysctl kern.cryptodevallowsoft=1\n");
165 	printf("-z run all available algorithms on a variety of sizes\n");
166 	printf("-v be verbose\n");
167 	printf("-b mark operations for batching\n");
168 	printf("-p profile kernel crypto operation (must be root)\n");
169 	printf("-t n for n threads and run tests concurrently\n");
170 	exit(-1);
171 }
172 
173 struct alg*
174 getalgbycode(int cipher)
175 {
176 	int i;
177 
178 	for (i = 0; i < nitems(algorithms); i++)
179 		if (cipher == algorithms[i].code)
180 			return &algorithms[i];
181 	return NULL;
182 }
183 
184 struct alg*
185 getalgbyname(const char* name)
186 {
187 	int i;
188 
189 	for (i = 0; i < nitems(algorithms); i++)
190 		if (streq(name, algorithms[i].name))
191 			return &algorithms[i];
192 	return NULL;
193 }
194 
195 int
196 devcrypto(void)
197 {
198 	int fd = -1;
199 
200 	if (fd < 0) {
201 		fd = open(_PATH_DEV "crypto", O_RDWR, 0);
202 		if (fd < 0)
203 			err(1, _PATH_DEV "crypto");
204 		if (fcntl(fd, F_SETFD, 1) == -1)
205 			err(1, "fcntl(F_SETFD) (devcrypto)");
206 	}
207 	return fd;
208 }
209 
210 int
211 crlookup(const char *devname)
212 {
213 	struct crypt_find_op find;
214 
215 	if (strncmp(devname, "soft", 4) == 0)
216 		return CRYPTO_FLAG_SOFTWARE;
217 
218 	find.crid = -1;
219 	strlcpy(find.name, devname, sizeof(find.name));
220 	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
221 		err(1, "ioctl(CIOCFINDDEV)");
222 	return find.crid;
223 }
224 
225 const char *
226 crfind(int crid)
227 {
228 	static struct crypt_find_op find;
229 
230 	bzero(&find, sizeof(find));
231 	find.crid = crid;
232 	if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1)
233 		err(1, "ioctl(CIOCFINDDEV): crid %d", crid);
234 	return find.name;
235 }
236 
237 char
238 rdigit(void)
239 {
240 	const char a[] = {
241 		0x10,0x54,0x11,0x48,0x45,0x12,0x4f,0x13,0x49,0x53,0x14,0x41,
242 		0x15,0x16,0x4e,0x55,0x54,0x17,0x18,0x4a,0x4f,0x42,0x19,0x01
243 	};
244 	return 0x20+a[random()%nitems(a)];
245 }
246 
247 void
248 runtest(struct alg *ealg, struct alg *alg, int count, int size, u_long cmd, struct timeval *tv)
249 {
250 	int i, fd = devcrypto();
251 	struct timeval start, stop, dt;
252 	char *cleartext, *ciphertext, *originaltext, *key;
253 	struct session2_op sop;
254 	struct crypt_op cop;
255 	char iv[EALG_MAX_BLOCK_LEN];
256 	char digest[512/8];
257 
258 	/* Canonicalize 'ealg' to crypt alg and 'alg' to authentication alg. */
259 	if (ealg == NULL && !alg->ishash) {
260 		ealg = alg;
261 		alg = NULL;
262 	}
263 
264 	bzero(&sop, sizeof(sop));
265 	if (ealg != NULL) {
266 		sop.keylen = (ealg->minkeylen + ealg->maxkeylen)/2;
267 		key = (char *) malloc(sop.keylen);
268 		if (key == NULL)
269 			err(1, "malloc (key)");
270 		for (i = 0; i < sop.keylen; i++)
271 			key[i] = rdigit();
272 		sop.key = key;
273 		sop.cipher = ealg->code;
274 	}
275 	if (alg != NULL) {
276 		sop.mackeylen = (alg->minkeylen + alg->maxkeylen)/2;
277 		key = (char *) malloc(sop.mackeylen);
278 		if (key == NULL)
279 			err(1, "malloc (mac)");
280 		for (i = 0; i < sop.mackeylen; i++)
281 			key[i] = rdigit();
282 		sop.mackey = key;
283 		sop.mac = alg->code;
284 	}
285 
286 	sop.crid = crid;
287 	if (ioctl(fd, cmd, &sop) < 0) {
288 		if (cmd == CIOCGSESSION || cmd == CIOCGSESSION2) {
289 			close(fd);
290 			if (verbose) {
291 				printf("cipher %s%s%s", ealg? ealg->name : "",
292 				    (ealg && alg) ? "+" : "",
293 				    alg? alg->name : "");
294 
295 				if (alg->ishash)
296 					printf(" mackeylen %u\n", sop.mackeylen);
297 				else
298 					printf(" keylen %u\n", sop.keylen);
299 				perror("CIOCGSESSION");
300 			}
301 			/* hardware doesn't support algorithm; skip it */
302 			return;
303 		}
304 		printf("cipher %s%s%s keylen %u mackeylen %u\n",
305 		    ealg? ealg->name : "", (ealg && alg) ? "+" : "",
306 		    alg? alg->name : "", sop.keylen, sop.mackeylen);
307 		err(1, "CIOCGSESSION");
308 	}
309 
310 	originaltext = malloc(3*size);
311 	if (originaltext == NULL)
312 		err(1, "malloc (text)");
313 	cleartext = originaltext+size;
314 	ciphertext = cleartext+size;
315 	for (i = 0; i < size; i++)
316 		cleartext[i] = rdigit();
317 	memcpy(originaltext, cleartext, size);
318 	for (i = 0; i < nitems(iv); i++)
319 		iv[i] = rdigit();
320 
321 	if (verbose) {
322 		printf("session = 0x%x\n", sop.ses);
323 		printf("device = %s\n", crfind(sop.crid));
324 		printf("count = %d, size = %d\n", count, size);
325 		if (ealg) {
326 			printf("iv:");
327 			hexdump(iv, sizeof iv);
328 		}
329 		printf("cleartext:");
330 		hexdump(cleartext, MIN(size, CHUNK));
331 	}
332 
333 	gettimeofday(&start, NULL);
334 	if (ealg) {
335 		for (i = 0; i < count; i++) {
336 			cop.ses = sop.ses;
337 			cop.op = COP_ENCRYPT;
338 			cop.flags = opflags | COP_F_CIPHER_FIRST;
339 			cop.len = size;
340 			cop.src = cleartext;
341 			cop.dst = ciphertext;
342 			if (alg)
343 				cop.mac = digest;
344 			else
345 				cop.mac = 0;
346 			cop.iv = iv;
347 
348 			if (ioctl(fd, CIOCCRYPT, &cop) < 0)
349 				err(1, "ioctl(CIOCCRYPT)");
350 
351 			if (verify && bcmp(ciphertext, cleartext, size) == 0) {
352 				printf("cipher text unchanged:");
353 				hexdump(ciphertext, size);
354 			}
355 
356 			memset(cleartext, 'x', MIN(size, CHUNK));
357 			cop.ses = sop.ses;
358 			cop.op = COP_DECRYPT;
359 			cop.flags = opflags;
360 			cop.len = size;
361 			cop.src = ciphertext;
362 			cop.dst = cleartext;
363 			if (alg)
364 				cop.mac = digest;
365 			else
366 				cop.mac = 0;
367 			cop.iv = iv;
368 
369 			if (ioctl(fd, CIOCCRYPT, &cop) < 0)
370 				err(1, "ioctl(CIOCCRYPT)");
371 
372 			if (verify && bcmp(cleartext, originaltext, size) != 0) {
373 				printf("decrypt mismatch:\n");
374 				printf("original:");
375 				hexdump(originaltext, size);
376 				printf("cleartext:");
377 				hexdump(cleartext, size);
378 			}
379 		}
380 	} else {
381 		for (i = 0; i < count; i++) {
382 			cop.ses = sop.ses;
383 			cop.op = 0;
384 			cop.flags = opflags;
385 			cop.len = size;
386 			cop.src = cleartext;
387 			cop.dst = 0;
388 			cop.mac = ciphertext;
389 			cop.iv = 0;
390 
391 			if (ioctl(fd, CIOCCRYPT, &cop) < 0)
392 				err(1, "ioctl(CIOCCRYPT)");
393 		}
394 	}
395 	gettimeofday(&stop, NULL);
396 
397 	if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
398 		perror("ioctl(CIOCFSESSION)");
399 
400 	if (verbose) {
401 		printf("cleartext:");
402 		hexdump(cleartext, MIN(size, CHUNK));
403 	}
404 	timersub(&stop, &start, tv);
405 
406 	free(originaltext);
407 
408 	close(fd);
409 }
410 
411 #ifdef __FreeBSD__
412 void
413 resetstats()
414 {
415 	struct cryptostats stats;
416 	size_t slen;
417 
418 	slen = sizeof (stats);
419 	if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0) {
420 		perror("kern.crypto_stats");
421 		return;
422 	}
423 	bzero(&stats.cs_invoke, sizeof (stats.cs_invoke));
424 	bzero(&stats.cs_done, sizeof (stats.cs_done));
425 	bzero(&stats.cs_cb, sizeof (stats.cs_cb));
426 	bzero(&stats.cs_finis, sizeof (stats.cs_finis));
427 	stats.cs_invoke.min.tv_sec = 10000;
428 	stats.cs_done.min.tv_sec = 10000;
429 	stats.cs_cb.min.tv_sec = 10000;
430 	stats.cs_finis.min.tv_sec = 10000;
431 	if (sysctlbyname("kern.crypto_stats", NULL, NULL, &stats, sizeof (stats)) < 0)
432 		perror("kern.cryptostats");
433 }
434 
435 void
436 printt(const char* tag, struct cryptotstat *ts)
437 {
438 	uint64_t avg, min, max;
439 
440 	if (ts->count == 0)
441 		return;
442 	avg = (1000000000LL*ts->acc.tv_sec + ts->acc.tv_nsec) / ts->count;
443 	min = 1000000000LL*ts->min.tv_sec + ts->min.tv_nsec;
444 	max = 1000000000LL*ts->max.tv_sec + ts->max.tv_nsec;
445 	printf("%16.16s: avg %6llu ns : min %6llu ns : max %7llu ns [%u samps]\n",
446 		tag, avg, min, max, ts->count);
447 }
448 #endif
449 
450 void
451 runtests(struct alg *ealg, struct alg *alg, int count, int size, u_long cmd, int threads, int profile)
452 {
453 	int i, status;
454 	double t;
455 	void *region;
456 	struct timeval *tvp;
457 	struct timeval total;
458 	int otiming;
459 
460 	if (size % alg->blocksize || (ealg && size % ealg->blocksize)) {
461 		if (verbose)
462 			printf("skipping blocksize %u 'cuz not a multiple of "
463 				"%s blocksize %u (or %s blocksize %u)\n",
464 				size, alg->name, alg->blocksize,
465 				ealg ?  ealg->name : "n/a",
466 				ealg ? ealg->blocksize : 0);
467 		return;
468 	}
469 
470 	region = mmap(NULL, threads * sizeof (struct timeval),
471 			PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
472 	if (region == MAP_FAILED) {
473 		perror("mmap");
474 		return;
475 	}
476 	tvp = (struct timeval *) region;
477 #ifdef __FreeBSD__
478 	if (profile) {
479 		size_t tlen = sizeof (otiming);
480 		int timing = 1;
481 
482 		resetstats();
483 		if (sysctlbyname("debug.crypto_timing", &otiming, &tlen,
484 				&timing, sizeof (timing)) < 0)
485 			perror("debug.crypto_timing");
486 	}
487 #endif
488 
489 	if (threads > 1) {
490 		for (i = 0; i < threads; i++)
491 			if (fork() == 0) {
492 				cpuset_t mask;
493 				CPU_ZERO(&mask);
494 				CPU_SET(i, &mask);
495 				cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
496 				    -1, sizeof(mask), &mask);
497 				runtest(ealg, alg, count, size, cmd, &tvp[i]);
498 				exit(0);
499 			}
500 		while (waitpid(WAIT_MYPGRP, &status, 0) != -1)
501 			;
502 	} else
503 		runtest(ealg, alg, count, size, cmd, tvp);
504 
505 	t = 0;
506 	for (i = 0; i < threads; i++)
507 		t += (((double)tvp[i].tv_sec * 1000000 + tvp[i].tv_usec) / 1000000);
508 	if (t) {
509 		int nops = alg->ishash ? count : 2*count;
510 
511 		nops *= threads;
512 		printf("%8.3lf sec, %7d %6s%s%6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n",
513 		    t, nops, alg->name, ealg? "+" : "", ealg? ealg->name : "",
514 		    size, (double)nops*size / t,
515 		    (double)nops*size / t * 8 / 1024 / 1024);
516 	}
517 #ifdef __FreeBSD__
518 	if (profile) {
519 		struct cryptostats stats;
520 		size_t slen = sizeof (stats);
521 
522 		if (sysctlbyname("debug.crypto_timing", NULL, NULL,
523 				&otiming, sizeof (otiming)) < 0)
524 			perror("debug.crypto_timing");
525 		if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0)
526 			perror("kern.cryptostats");
527 		if (stats.cs_invoke.count) {
528 			printt("dispatch->invoke", &stats.cs_invoke);
529 			printt("invoke->done", &stats.cs_done);
530 			printt("done->cb", &stats.cs_cb);
531 			printt("cb->finis", &stats.cs_finis);
532 		}
533 	}
534 #endif
535 	fflush(stdout);
536 }
537 
538 int
539 main(int argc, char **argv)
540 {
541 	struct alg *alg = NULL, *ealg = NULL;
542 	char *tmp;
543 	int count = 1;
544 	int sizes[128], nsizes = 0;
545 	u_long cmd = CIOCGSESSION2;
546 	int testall = 0;
547 	int maxthreads = 1;
548 	int profile = 0;
549 	int i, ch;
550 
551 	while ((ch = getopt(argc, argv, "cpzsva:bd:t:")) != -1) {
552 		switch (ch) {
553 #ifdef CIOCGSSESSION
554 		case 's':
555 			cmd = CIOCGSSESSION;
556 			break;
557 #endif
558 		case 'v':
559 			verbose++;
560 			break;
561 		case 'a':
562 			tmp = strchr(optarg, '+');
563 			if (tmp != NULL) {
564 				*tmp = '\0';
565 				ealg = getalgbyname(optarg);
566 				if (ealg == NULL || ealg->ishash)
567 					usage(argv[0]);
568 				optarg = tmp + 1;
569 			}
570 
571 			alg = getalgbyname(optarg);
572 			if (alg == NULL) {
573 				if (streq(optarg, "rijndael"))
574 					alg = getalgbyname("aes");
575 				else
576 					usage(argv[0]);
577 			} else if (ealg != NULL && !alg->ishash)
578 				usage(argv[0]);
579 			break;
580 		case 'd':
581 			crid = crlookup(optarg);
582 			break;
583 		case 't':
584 			maxthreads = atoi(optarg);
585 			break;
586 		case 'z':
587 			testall = 1;
588 			break;
589 		case 'p':
590 			profile = 1;
591 			break;
592 		case 'b':
593 			opflags |= COP_F_BATCH;
594 			break;
595 		case 'c':
596 			verify = 1;
597 			break;
598 		default:
599 			usage(argv[0]);
600 		}
601 	}
602 	argc -= optind, argv += optind;
603 	if (argc > 0)
604 		count = atoi(argv[0]);
605 	while (argc > 1) {
606 		int s = atoi(argv[1]);
607 		if (nsizes < nitems(sizes)) {
608 			sizes[nsizes++] = s;
609 		} else {
610 			printf("Too many sizes, ignoring %u\n", s);
611 		}
612 		argc--, argv++;
613 	}
614 	if (maxthreads > CPU_SETSIZE)
615 		errx(EX_USAGE, "Too many threads, %d, choose fewer.", maxthreads);
616 
617 	if (nsizes == 0) {
618 		if (alg)
619 			sizes[nsizes++] = alg->blocksize;
620 		else
621 			sizes[nsizes++] = 8;
622 		if (testall) {
623 			while (sizes[nsizes-1] < 8*1024) {
624 				sizes[nsizes] = sizes[nsizes-1]<<1;
625 				nsizes++;
626 			}
627 		}
628 	}
629 
630 	if (testall) {
631 		for (i = 0; i < nitems(algorithms); i++) {
632 			int j;
633 			alg = &algorithms[i];
634 			for (j = 0; j < nsizes; j++)
635 				runtests(ealg, alg, count, sizes[j], cmd, maxthreads, profile);
636 		}
637 	} else {
638 		if (alg == NULL)
639 			alg = getalgbycode(CRYPTO_3DES_CBC);
640 		for (i = 0; i < nsizes; i++)
641 			runtests(ealg, alg, count, sizes[i], cmd, maxthreads, profile);
642 	}
643 
644 	return (0);
645 }
646 
647 void
648 hexdump(char *p, int n)
649 {
650 	int i, off;
651 
652 	for (off = 0; n > 0; off += 16, n -= 16) {
653 		printf("%s%04x:", off == 0 ? "\n" : "", off);
654 		i = (n >= 16 ? 16 : n);
655 		do {
656 			printf(" %02x", *p++ & 0xff);
657 		} while (--i);
658 		printf("\n");
659 	}
660 }
661