]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/tools/crypto/cryptotest.c
Update expat to 2.2.6
[FreeBSD/FreeBSD.git] / tools / tools / crypto / cryptotest.c
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(), CRIOFINDDEV, &find) == -1)
233                 err(1, "ioctl(CIOCFINDDEV): crid %d", crid);
234         return find.name;
235 }
236
237 int
238 crget(void)
239 {
240         int fd;
241
242         if (ioctl(devcrypto(), CRIOGET, &fd) == -1)
243                 err(1, "ioctl(CRIOGET)");
244         if (fcntl(fd, F_SETFD, 1) == -1)
245                 err(1, "fcntl(F_SETFD) (crget)");
246         return fd;
247 }
248
249 char
250 rdigit(void)
251 {
252         const char a[] = {
253                 0x10,0x54,0x11,0x48,0x45,0x12,0x4f,0x13,0x49,0x53,0x14,0x41,
254                 0x15,0x16,0x4e,0x55,0x54,0x17,0x18,0x4a,0x4f,0x42,0x19,0x01
255         };
256         return 0x20+a[random()%nitems(a)];
257 }
258
259 void
260 runtest(struct alg *ealg, struct alg *alg, int count, int size, u_long cmd, struct timeval *tv)
261 {
262         int i, fd = crget();
263         struct timeval start, stop, dt;
264         char *cleartext, *ciphertext, *originaltext, *key;
265         struct session2_op sop;
266         struct crypt_op cop;
267         char iv[EALG_MAX_BLOCK_LEN];
268         char digest[512/8];
269
270         /* Canonicalize 'ealg' to crypt alg and 'alg' to authentication alg. */
271         if (ealg == NULL && !alg->ishash) {
272                 ealg = alg;
273                 alg = NULL;
274         }
275
276         bzero(&sop, sizeof(sop));
277         if (ealg != NULL) {
278                 sop.keylen = (ealg->minkeylen + ealg->maxkeylen)/2;
279                 key = (char *) malloc(sop.keylen);
280                 if (key == NULL)
281                         err(1, "malloc (key)");
282                 for (i = 0; i < sop.keylen; i++)
283                         key[i] = rdigit();
284                 sop.key = key;
285                 sop.cipher = ealg->code;
286         }
287         if (alg != NULL) {
288                 sop.mackeylen = (alg->minkeylen + alg->maxkeylen)/2;
289                 key = (char *) malloc(sop.mackeylen);
290                 if (key == NULL)
291                         err(1, "malloc (mac)");
292                 for (i = 0; i < sop.mackeylen; i++)
293                         key[i] = rdigit();
294                 sop.mackey = key;
295                 sop.mac = alg->code;
296         }
297
298         sop.crid = crid;
299         if (ioctl(fd, cmd, &sop) < 0) {
300                 if (cmd == CIOCGSESSION || cmd == CIOCGSESSION2) {
301                         close(fd);
302                         if (verbose) {
303                                 printf("cipher %s%s%s", ealg? ealg->name : "",
304                                     (ealg && alg) ? "+" : "",
305                                     alg? alg->name : "");
306
307                                 if (alg->ishash)
308                                         printf(" mackeylen %u\n", sop.mackeylen);
309                                 else
310                                         printf(" keylen %u\n", sop.keylen);
311                                 perror("CIOCGSESSION");
312                         }
313                         /* hardware doesn't support algorithm; skip it */
314                         return;
315                 }
316                 printf("cipher %s%s%s keylen %u mackeylen %u\n",
317                     ealg? ealg->name : "", (ealg && alg) ? "+" : "",
318                     alg? alg->name : "", sop.keylen, sop.mackeylen);
319                 err(1, "CIOCGSESSION");
320         }
321
322         originaltext = malloc(3*size);
323         if (originaltext == NULL)
324                 err(1, "malloc (text)");
325         cleartext = originaltext+size;
326         ciphertext = cleartext+size;
327         for (i = 0; i < size; i++)
328                 cleartext[i] = rdigit();
329         memcpy(originaltext, cleartext, size);
330         for (i = 0; i < nitems(iv); i++)
331                 iv[i] = rdigit();
332
333         if (verbose) {
334                 printf("session = 0x%x\n", sop.ses);
335                 printf("device = %s\n", crfind(sop.crid));
336                 printf("count = %d, size = %d\n", count, size);
337                 if (ealg) {
338                         printf("iv:");
339                         hexdump(iv, sizeof iv);
340                 }
341                 printf("cleartext:");
342                 hexdump(cleartext, MIN(size, CHUNK));
343         }
344
345         gettimeofday(&start, NULL);
346         if (ealg) {
347                 for (i = 0; i < count; i++) {
348                         cop.ses = sop.ses;
349                         cop.op = COP_ENCRYPT;
350                         cop.flags = opflags | COP_F_CIPHER_FIRST;
351                         cop.len = size;
352                         cop.src = cleartext;
353                         cop.dst = ciphertext;
354                         if (alg)
355                                 cop.mac = digest;
356                         else
357                                 cop.mac = 0;
358                         cop.iv = iv;
359
360                         if (ioctl(fd, CIOCCRYPT, &cop) < 0)
361                                 err(1, "ioctl(CIOCCRYPT)");
362
363                         if (verify && bcmp(ciphertext, cleartext, size) == 0) {
364                                 printf("cipher text unchanged:");
365                                 hexdump(ciphertext, size);
366                         }
367
368                         memset(cleartext, 'x', MIN(size, CHUNK));
369                         cop.ses = sop.ses;
370                         cop.op = COP_DECRYPT;
371                         cop.flags = opflags;
372                         cop.len = size;
373                         cop.src = ciphertext;
374                         cop.dst = cleartext;
375                         if (alg)
376                                 cop.mac = digest;
377                         else
378                                 cop.mac = 0;
379                         cop.iv = iv;
380
381                         if (ioctl(fd, CIOCCRYPT, &cop) < 0)
382                                 err(1, "ioctl(CIOCCRYPT)");
383
384                         if (verify && bcmp(cleartext, originaltext, size) != 0) {
385                                 printf("decrypt mismatch:\n");
386                                 printf("original:");
387                                 hexdump(originaltext, size);
388                                 printf("cleartext:");
389                                 hexdump(cleartext, size);
390                         }
391                 }
392         } else {
393                 for (i = 0; i < count; i++) {
394                         cop.ses = sop.ses;
395                         cop.op = 0;
396                         cop.flags = opflags;
397                         cop.len = size;
398                         cop.src = cleartext;
399                         cop.dst = 0;
400                         cop.mac = ciphertext;
401                         cop.iv = 0;
402
403                         if (ioctl(fd, CIOCCRYPT, &cop) < 0)
404                                 err(1, "ioctl(CIOCCRYPT)");
405                 }
406         }
407         gettimeofday(&stop, NULL);
408  
409         if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0)
410                 perror("ioctl(CIOCFSESSION)");
411
412         if (verbose) {
413                 printf("cleartext:");
414                 hexdump(cleartext, MIN(size, CHUNK));
415         }
416         timersub(&stop, &start, tv);
417
418         free(originaltext);
419
420         close(fd);
421 }
422
423 #ifdef __FreeBSD__
424 void
425 resetstats()
426 {
427         struct cryptostats stats;
428         size_t slen;
429
430         slen = sizeof (stats);
431         if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0) {
432                 perror("kern.crypto_stats");
433                 return;
434         }
435         bzero(&stats.cs_invoke, sizeof (stats.cs_invoke));
436         bzero(&stats.cs_done, sizeof (stats.cs_done));
437         bzero(&stats.cs_cb, sizeof (stats.cs_cb));
438         bzero(&stats.cs_finis, sizeof (stats.cs_finis));
439         stats.cs_invoke.min.tv_sec = 10000;
440         stats.cs_done.min.tv_sec = 10000;
441         stats.cs_cb.min.tv_sec = 10000;
442         stats.cs_finis.min.tv_sec = 10000;
443         if (sysctlbyname("kern.crypto_stats", NULL, NULL, &stats, sizeof (stats)) < 0)
444                 perror("kern.cryptostats");
445 }
446
447 void
448 printt(const char* tag, struct cryptotstat *ts)
449 {
450         uint64_t avg, min, max;
451
452         if (ts->count == 0)
453                 return;
454         avg = (1000000000LL*ts->acc.tv_sec + ts->acc.tv_nsec) / ts->count;
455         min = 1000000000LL*ts->min.tv_sec + ts->min.tv_nsec;
456         max = 1000000000LL*ts->max.tv_sec + ts->max.tv_nsec;
457         printf("%16.16s: avg %6llu ns : min %6llu ns : max %7llu ns [%u samps]\n",
458                 tag, avg, min, max, ts->count);
459 }
460 #endif
461
462 void
463 runtests(struct alg *ealg, struct alg *alg, int count, int size, u_long cmd, int threads, int profile)
464 {
465         int i, status;
466         double t;
467         void *region;
468         struct timeval *tvp;
469         struct timeval total;
470         int otiming;
471
472         if (size % alg->blocksize || (ealg && size % ealg->blocksize)) {
473                 if (verbose)
474                         printf("skipping blocksize %u 'cuz not a multiple of "
475                                 "%s blocksize %u (or %s blocksize %u)\n",
476                                 size, alg->name, alg->blocksize,
477                                 ealg ?  ealg->name : "n/a",
478                                 ealg ? ealg->blocksize : 0);
479                 return;
480         }
481
482         region = mmap(NULL, threads * sizeof (struct timeval),
483                         PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
484         if (region == MAP_FAILED) {
485                 perror("mmap");
486                 return;
487         }
488         tvp = (struct timeval *) region;
489 #ifdef __FreeBSD__
490         if (profile) {
491                 size_t tlen = sizeof (otiming);
492                 int timing = 1;
493
494                 resetstats();
495                 if (sysctlbyname("debug.crypto_timing", &otiming, &tlen,
496                                 &timing, sizeof (timing)) < 0)
497                         perror("debug.crypto_timing");
498         }
499 #endif
500
501         if (threads > 1) {
502                 for (i = 0; i < threads; i++)
503                         if (fork() == 0) {
504                                 cpuset_t mask;
505                                 CPU_ZERO(&mask);
506                                 CPU_SET(i, &mask);
507                                 cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID,
508                                     -1, sizeof(mask), &mask);
509                                 runtest(ealg, alg, count, size, cmd, &tvp[i]);
510                                 exit(0);
511                         }
512                 while (waitpid(WAIT_MYPGRP, &status, 0) != -1)
513                         ;
514         } else
515                 runtest(ealg, alg, count, size, cmd, tvp);
516
517         t = 0;
518         for (i = 0; i < threads; i++)
519                 t += (((double)tvp[i].tv_sec * 1000000 + tvp[i].tv_usec) / 1000000);
520         if (t) {
521                 int nops = alg->ishash ? count : 2*count;
522
523                 nops *= threads;
524                 printf("%8.3lf sec, %7d %6s%s%6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n",
525                     t, nops, alg->name, ealg? "+" : "", ealg? ealg->name : "",
526                     size, (double)nops*size / t,
527                     (double)nops*size / t * 8 / 1024 / 1024);
528         }
529 #ifdef __FreeBSD__
530         if (profile) {
531                 struct cryptostats stats;
532                 size_t slen = sizeof (stats);
533
534                 if (sysctlbyname("debug.crypto_timing", NULL, NULL,
535                                 &otiming, sizeof (otiming)) < 0)
536                         perror("debug.crypto_timing");
537                 if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0)
538                         perror("kern.cryptostats");
539                 if (stats.cs_invoke.count) {
540                         printt("dispatch->invoke", &stats.cs_invoke);
541                         printt("invoke->done", &stats.cs_done);
542                         printt("done->cb", &stats.cs_cb);
543                         printt("cb->finis", &stats.cs_finis);
544                 }
545         }
546 #endif
547         fflush(stdout);
548 }
549
550 int
551 main(int argc, char **argv)
552 {
553         struct alg *alg = NULL, *ealg = NULL;
554         char *tmp;
555         int count = 1;
556         int sizes[128], nsizes = 0;
557         u_long cmd = CIOCGSESSION2;
558         int testall = 0;
559         int maxthreads = 1;
560         int profile = 0;
561         int i, ch;
562
563         while ((ch = getopt(argc, argv, "cpzsva:bd:t:")) != -1) {
564                 switch (ch) {
565 #ifdef CIOCGSSESSION
566                 case 's':
567                         cmd = CIOCGSSESSION;
568                         break;
569 #endif
570                 case 'v':
571                         verbose++;
572                         break;
573                 case 'a':
574                         tmp = strchr(optarg, '+');
575                         if (tmp != NULL) {
576                                 *tmp = '\0';
577                                 ealg = getalgbyname(optarg);
578                                 if (ealg == NULL || ealg->ishash)
579                                         usage(argv[0]);
580                                 optarg = tmp + 1;
581                         }
582
583                         alg = getalgbyname(optarg);
584                         if (alg == NULL) {
585                                 if (streq(optarg, "rijndael"))
586                                         alg = getalgbyname("aes");
587                                 else
588                                         usage(argv[0]);
589                         } else if (ealg != NULL && !alg->ishash)
590                                 usage(argv[0]);
591                         break;
592                 case 'd':
593                         crid = crlookup(optarg);
594                         break;
595                 case 't':
596                         maxthreads = atoi(optarg);
597                         break;
598                 case 'z':
599                         testall = 1;
600                         break;
601                 case 'p':
602                         profile = 1;
603                         break;
604                 case 'b':
605                         opflags |= COP_F_BATCH;
606                         break;
607                 case 'c':
608                         verify = 1;
609                         break;
610                 default:
611                         usage(argv[0]);
612                 }
613         }
614         argc -= optind, argv += optind;
615         if (argc > 0)
616                 count = atoi(argv[0]);
617         while (argc > 1) {
618                 int s = atoi(argv[1]);
619                 if (nsizes < nitems(sizes)) {
620                         sizes[nsizes++] = s;
621                 } else {
622                         printf("Too many sizes, ignoring %u\n", s);
623                 }
624                 argc--, argv++;
625         }
626         if (maxthreads > CPU_SETSIZE)
627                 errx(EX_USAGE, "Too many threads, %d, choose fewer.", maxthreads);
628         
629         if (nsizes == 0) {
630                 if (alg)
631                         sizes[nsizes++] = alg->blocksize;
632                 else
633                         sizes[nsizes++] = 8;
634                 if (testall) {
635                         while (sizes[nsizes-1] < 8*1024) {
636                                 sizes[nsizes] = sizes[nsizes-1]<<1;
637                                 nsizes++;
638                         }
639                 }
640         }
641
642         if (testall) {
643                 for (i = 0; i < nitems(algorithms); i++) {
644                         int j;
645                         alg = &algorithms[i];
646                         for (j = 0; j < nsizes; j++)
647                                 runtests(ealg, alg, count, sizes[j], cmd, maxthreads, profile);
648                 }
649         } else {
650                 if (alg == NULL)
651                         alg = getalgbycode(CRYPTO_3DES_CBC);
652                 for (i = 0; i < nsizes; i++)
653                         runtests(ealg, alg, count, sizes[i], cmd, maxthreads, profile);
654         }
655
656         return (0);
657 }
658
659 void
660 hexdump(char *p, int n)
661 {
662         int i, off;
663
664         for (off = 0; n > 0; off += 16, n -= 16) {
665                 printf("%s%04x:", off == 0 ? "\n" : "", off);
666                 i = (n >= 16 ? 16 : n);
667                 do {
668                         printf(" %02x", *p++ & 0xff);
669                 } while (--i);
670                 printf("\n");
671         }
672 }