1 /* $FreeBSD: src/tools/tools/crypto/cryptotest.c,v 1.3.2.2 2003/06/03 00:14:44 sam Exp $ */
2 /* $DragonFly: src/tools/tools/crypto/Attic/cryptotest.c,v 1.2 2003/06/17 04:29:11 dillon Exp $ */
5 * This program repeatedly encrypts and decrypts a buffer with the built-in
6 * iv and key, using hardware crypto. At the end, it computes the data rate
7 * achieved. invoke with the number of times to encrypt and the buffer size.
9 * For a test of how fast a crypto card is, use something like:
11 * This will run a series of tests using the available crypto/cipher
12 * algorithms over a variety of buffer sizes. The 1024 says to do 1024
13 * iterations. Extra arguments can be used to specify one or more buffer
14 * sizes to use in doing tests.
16 * To fork multiple processes all doing the same work, specify -t X on the
17 * command line to get X "threads" running simultaneously. No effort is made
18 * synchronize the threads or otherwise maximize load.
20 * If the kernel crypto code is built with CRYPTO_TIMING and you run as root,
21 * then you can specify the -p option to get a "profile" of the time spent
22 * processing crypto operations. At present this data is only meaningful for
23 * symmetric operations. To get meaningful numbers you must run on an idle
26 * Expect ~400 Mb/s for a Broadcom 582x for 8K buffers on a reasonable CPU
27 * (64-bit PCI helps). Hifn 7811 parts top out at ~110 Mb/s.
29 * This code originally came from openbsd; give them all the credit.
31 #include <sys/types.h>
32 #include <sys/param.h>
34 #include <sys/ioctl.h>
41 #include <sys/sysctl.h>
43 #include <crypto/cryptodev.h>
45 #define CHUNK 64 /* how much to display */
46 #define N(a) (sizeof (a) / sizeof (a[0]))
47 #define streq(a,b) (strcasecmp(a,b) == 0)
49 void hexdump(char *, int);
53 struct session_op session;
54 struct crypt_op cryptop;
55 char iv[8] = "00000000";
68 #ifdef CRYPTO_NULL_CBC
69 { "null", 0, 8, 1, 256, CRYPTO_NULL_CBC },
71 { "des", 0, 8, 8, 8, CRYPTO_DES_CBC },
72 { "3des", 0, 8, 24, 24, CRYPTO_3DES_CBC },
73 { "blf", 0, 8, 5, 56, CRYPTO_BLF_CBC },
74 { "cast", 0, 8, 5, 16, CRYPTO_CAST_CBC },
75 { "skj", 0, 8, 10, 10, CRYPTO_SKIPJACK_CBC },
76 { "aes", 0, 16, 16, 16, CRYPTO_RIJNDAEL128_CBC},
77 { "aes192", 0, 16, 24, 24, CRYPTO_RIJNDAEL128_CBC},
78 { "aes256", 0, 16, 32, 32, CRYPTO_RIJNDAEL128_CBC},
80 { "arc4", 0, 8, 1, 32, CRYPTO_ARC4 },
82 { "md5", 1, 8, 16, 16, CRYPTO_MD5_HMAC },
83 { "sha1", 1, 8, 20, 20, CRYPTO_SHA1_HMAC },
84 { "sha256", 1, 8, 32, 32, CRYPTO_SHA2_HMAC },
85 { "sha384", 1, 8, 48, 48, CRYPTO_SHA2_HMAC },
86 { "sha512", 1, 8, 64, 64, CRYPTO_SHA2_HMAC },
90 usage(const char* cmd)
92 printf("usage: %s [-c] [-z] [-s] [-b] [-v] [-a algorithm] [count] [size ...]\n",
94 printf("where algorithm is one of:\n");
95 printf(" des 3des (default) blowfish cast skipjack\n");
96 printf(" aes (aka rijndael) aes192 aes256 arc4\n");
97 printf("count is the number of encrypt/decrypt ops to do\n");
98 printf("size is the number of bytes of text to encrypt+decrypt\n");
100 printf("-c check the results (slows timing)\n");
101 printf("-z run all available algorithms on a variety of sizes\n");
102 printf("-v be verbose\n");
103 printf("-b mark operations for batching\n");
104 printf("-p profile kernel crypto operation (must be root)\n");
109 getalgbycode(int cipher)
113 for (i = 0; i < N(algorithms); i++)
114 if (cipher == algorithms[i].code)
115 return &algorithms[i];
120 getalgbyname(const char* name)
124 for (i = 0; i < N(algorithms); i++)
125 if (streq(name, algorithms[i].name))
126 return &algorithms[i];
131 runtest(struct alg *alg, int count, int size, int cmd, struct timeval *tv)
134 struct timeval start, stop, dt;
135 char *cleartext, *ciphertext, *originaltext;
137 if (ioctl(cryptodev_fd,CRIOGET,&fd) == -1)
138 err(1, "CRIOGET failed");
140 bzero(&session, sizeof(session));
142 session.keylen = (alg->minkeylen + alg->maxkeylen)/2;
143 session.key = (char *) malloc(session.keylen);
144 if (session.key == NULL)
145 err(1, "malloc (key)");
146 for (i = 0; i < session.keylen; i++)
147 session.key[i] = '0' + (i%10);
148 session.cipher = alg->code;
150 session.mackeylen = (alg->minkeylen + alg->maxkeylen)/2;
151 session.mackey = (char *) malloc(session.mackeylen);
152 if (session.mackey == NULL)
153 err(1, "malloc (mac)");
154 for (i = 0; i < session.mackeylen; i++)
155 session.mackey[i] = '0' + (i%10);
156 session.mac = alg->code;
158 if (ioctl(fd, cmd, &session) == -1) {
159 if (cmd == CIOCGSESSION) {
162 printf("cipher %s", alg->name);
164 printf(" mackeylen %u\n", session.mackeylen);
166 printf(" keylen %u\n", session.keylen);
167 perror("CIOCGSESSION");
169 /* hardware doesn't support algorithm; skip it */
172 printf("cipher %s keylen %u mackeylen %u\n",
173 alg->name, session.keylen, session.mackeylen);
174 err(1, "CIOCGSESSION failed");
177 if ((originaltext = (char *)malloc(size)) == NULL)
178 err(1, "malloc (originaltext)");
179 if ((cleartext = (char *)malloc(size)) == NULL)
180 err(1, "malloc (cleartext)");
181 if ((ciphertext = (char *)malloc(size)) == NULL)
182 err(1, "malloc (ciphertext)");
183 for (i = 0; i < size; i++)
184 cleartext[i] = 'a' + i%26;
185 memcpy(originaltext, cleartext, size);
188 printf("session = 0x%x\n", session.ses);
189 printf("count = %d, size = %d\n", count, size);
190 cryptop.ses = session.ses;
193 hexdump(iv, sizeof iv);
195 printf("cleartext:");
196 hexdump(cleartext, MIN(size, CHUNK));
199 gettimeofday(&start, NULL);
201 for (i = 0; i < count; i++) {
202 cryptop.op = COP_ENCRYPT;
203 cryptop.flags = opflags;
205 cryptop.src = cleartext;
206 cryptop.dst = ciphertext;
210 if (ioctl(fd, CIOCCRYPT, &cryptop) == -1)
211 err(1, "CIOCCRYPT failed");
213 if (verify && bcmp(ciphertext, cleartext, size) == 0) {
214 printf("cipher text unchanged:");
215 hexdump(ciphertext, size);
218 memset(cleartext, 'x', MIN(size, CHUNK));
219 cryptop.op = COP_DECRYPT;
220 cryptop.flags = opflags;
222 cryptop.src = ciphertext;
223 cryptop.dst = cleartext;
227 if (ioctl(fd, CIOCCRYPT, &cryptop) == -1)
228 err(1, "CIOCCRYPT failed");
230 if (verify && bcmp(cleartext, originaltext, size) != 0) {
231 printf("decrypt mismatch:\n");
233 hexdump(originaltext, size);
234 printf("cleartext:");
235 hexdump(cleartext, size);
239 for (i = 0; i < count; i++) {
241 cryptop.flags = opflags;
243 cryptop.src = cleartext;
245 cryptop.mac = ciphertext;
248 if (ioctl(fd, CIOCCRYPT, &cryptop) == -1)
249 err(1, "CIOCCRYPT failed");
252 gettimeofday(&stop, NULL);
254 if (ioctl(fd, CIOCFSESSION, &session.ses) == -1)
255 perror("CIOCFSESSION");
258 printf("cleartext:");
259 hexdump(cleartext, MIN(size, CHUNK));
261 timersub(&stop, &start, tv);
273 struct cryptostats stats;
276 slen = sizeof (stats);
277 if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, NULL) < 0) {
278 perror("kern.crypto_stats");
281 bzero(&stats.cs_invoke, sizeof (stats.cs_invoke));
282 bzero(&stats.cs_done, sizeof (stats.cs_done));
283 bzero(&stats.cs_cb, sizeof (stats.cs_cb));
284 bzero(&stats.cs_finis, sizeof (stats.cs_finis));
285 stats.cs_invoke.min.tv_sec = 10000;
286 stats.cs_done.min.tv_sec = 10000;
287 stats.cs_cb.min.tv_sec = 10000;
288 stats.cs_finis.min.tv_sec = 10000;
289 if (sysctlbyname("kern.crypto_stats", NULL, NULL, &stats, sizeof (stats)) < 0)
290 perror("kern.cryptostats");
294 printt(const char* tag, struct cryptotstat *ts)
296 uint64_t avg, min, max;
300 avg = (1000000000LL*ts->acc.tv_sec + ts->acc.tv_nsec) / ts->count;
301 min = 1000000000LL*ts->min.tv_sec + ts->min.tv_nsec;
302 max = 1000000000LL*ts->max.tv_sec + ts->max.tv_nsec;
303 printf("%16.16s: avg %6llu ns : min %6llu ns : max %7llu ns [%u samps]\n",
304 tag, avg, min, max, ts->count);
309 runtests(struct alg *alg, int count, int size, int cmd, int threads, int profile)
315 struct timeval total;
318 if (size % alg->blocksize) {
320 printf("skipping blocksize %u 'cuz not a multiple of "
322 size, alg->name, alg->blocksize);
326 region = mmap(NULL, threads * sizeof (struct timeval),
327 PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
328 if (region == MAP_FAILED) {
332 tvp = (struct timeval *) region;
335 size_t tlen = sizeof (otiming);
339 if (sysctlbyname("debug.crypto_timing", &otiming, &tlen,
340 &timing, sizeof (timing)) < 0)
341 perror("debug.crypto_timing");
346 for (i = 0; i < threads; i++)
348 runtest(alg, count, size, cmd, &tvp[i]);
351 while (waitpid(WAIT_MYPGRP, &status, 0) != -1)
354 runtest(alg, count, size, cmd, tvp);
357 for (i = 0; i < threads; i++)
358 t += (((double)tvp[i].tv_sec * 1000000 + tvp[i].tv_usec) / 1000000);
360 int nops = alg->ishash ? count : 2*count;
363 printf("%6.3lf sec, %7d %6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n",
364 t, nops, alg->name, size, (double)nops*size / t,
365 (double)nops*size / t * 8 / 1024 / 1024);
369 struct cryptostats stats;
370 size_t slen = sizeof (stats);
372 if (sysctlbyname("debug.crypto_timing", NULL, NULL,
373 &otiming, sizeof (otiming)) < 0)
374 perror("debug.crypto_timing");
375 if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, NULL) < 0)
376 perror("kern.cryptostats");
377 if (stats.cs_invoke.count) {
378 printt("dispatch->invoke", &stats.cs_invoke);
379 printt("invoke->done", &stats.cs_done);
380 printt("done->cb", &stats.cs_cb);
381 printt("cb->finis", &stats.cs_finis);
389 main(int argc, char **argv)
391 struct alg *alg = NULL;
393 int sizes[128], nsizes = 0;
394 int cmd = CIOCGSESSION;
400 while ((ch = getopt(argc, argv, "cpzsva:bt:")) != -1) {
411 alg = getalgbyname(optarg);
413 if (streq(optarg, "rijndael"))
414 alg = getalgbyname("aes");
420 maxthreads = atoi(optarg);
429 opflags |= COP_F_BATCH;
438 argc -= optind, argv += optind;
440 count = atoi(argv[0]);
442 int s = atoi(argv[1]);
443 if (nsizes < N(sizes)) {
446 printf("Too many sizes, ignoring %u\n", s);
452 sizes[nsizes++] = alg->blocksize;
456 while (sizes[nsizes-1] < 8*1024) {
457 sizes[nsizes] = sizes[nsizes-1]<<1;
463 if ((cryptodev_fd = open("/dev/crypto",O_RDWR,0)) < 0)
464 err(1, "/dev/crypto");
467 for (i = 0; i < N(algorithms); i++) {
469 alg = &algorithms[i];
470 for (j = 0; j < nsizes; j++)
471 runtests(alg, count, sizes[j], cmd, maxthreads, profile);
475 alg = getalgbycode(CRYPTO_3DES_CBC);
476 for (i = 0; i < nsizes; i++)
477 runtests(alg, count, sizes[i], cmd, maxthreads, profile);
484 hexdump(char *p, int n)
487 for (i = 0; i < n; i++) {
493 for (j = 0; j < 16; j++,l++)
494 printf("%c", (((*l)&0xff)>0x1f && ((*l)&0xff)<0x7f) ? (*l)&0xff : '.');
497 printf("\n%04x: ", i);
499 printf(" %02x", (int)(*p++)&0xff);