diff options
author | sam <sam@FreeBSD.org> | 2003-01-06 22:11:56 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2003-01-06 22:11:56 +0000 |
commit | f0f8069fbc66b75d41b6f8ff349d866f03c23fce (patch) | |
tree | 63a1e0eac96d0d272b2dded0cb071ff6dd4bbffb /tools | |
parent | d110043285c7f70ed63981b7aac6fbea8c664982 (diff) | |
download | FreeBSD-src-f0f8069fbc66b75d41b6f8ff349d866f03c23fce.zip FreeBSD-src-f0f8069fbc66b75d41b6f8ff349d866f03c23fce.tar.gz |
more crypto test stuff:
o cryptotest can now run multiple threads with -t option
o cryptotest can now "profile" time spent doing symmetric ops with -p
o cryptostats dumps the crypto statistics block
o cryptokeystat is an openbsd app that tests public key ops
Diffstat (limited to 'tools')
-rw-r--r-- | tools/tools/crypto/Makefile | 8 | ||||
-rw-r--r-- | tools/tools/crypto/cryptokeytest.c | 224 | ||||
-rw-r--r-- | tools/tools/crypto/cryptostats.c | 77 | ||||
-rw-r--r-- | tools/tools/crypto/cryptotest.c | 163 |
4 files changed, 450 insertions, 22 deletions
diff --git a/tools/tools/crypto/Makefile b/tools/tools/crypto/Makefile index e592761..8dda355 100644 --- a/tools/tools/crypto/Makefile +++ b/tools/tools/crypto/Makefile @@ -1,11 +1,17 @@ # $FreeBSD$ -ALL= cryptotest +ALL= cryptotest cryptokeytest cryptostats all: ${ALL} cryptotest: cryptotest.c ${CC} -o cryptotest cryptotest.c +cryptokeytest: cryptokeytest.c + ${CC} -o cryptokeytest cryptokeytest.c -lcrypto + +cryptostats: cryptostats.c + ${CC} -o cryptostats cryptostats.c + clean: rm -f ${ALL} core a.out diff --git a/tools/tools/crypto/cryptokeytest.c b/tools/tools/crypto/cryptokeytest.c new file mode 100644 index 0000000..a031faf --- /dev/null +++ b/tools/tools/crypto/cryptokeytest.c @@ -0,0 +1,224 @@ +/* $FreeBSD$ */ +/* + * The big num stuff is a bit broken at the moment and I've not yet fixed it. + * The symtom is that odd size big nums will fail. Test code below (it only + * uses modexp currently). + * + * --Jason L. Wright + */ +#include <sys/types.h> +#include <sys/ioctl.h> +#include <machine/endian.h> +#include <sys/time.h> +#include <crypto/cryptodev.h> +#include <openssl/bn.h> +#include <fcntl.h> +#include <err.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +static int crypto_fd = -1; + +/* + * Convert a little endian byte string in 'p' that + * is 'plen' bytes long to a BIGNUM. If 'dst' is NULL, + * a new BIGNUM is allocated. Returns NULL on failure. + * + * XXX there has got to be a more efficient way to do + * this, but I haven't figured out enough of the OpenSSL + * magic. + */ +BIGNUM * +le_to_bignum(BIGNUM *dst, u_int8_t *p, int plen) +{ + u_int8_t *pd; + int i; + + if (plen == 0) + return (NULL); + + if ((pd = (u_int8_t *)malloc(plen)) == NULL) + return (NULL); + + for (i = 0; i < plen; i++) + pd[i] = p[plen - i - 1]; + + dst = BN_bin2bn(pd, plen, dst); + free(pd); + return (dst); +} + +/* + * Convert a BIGNUM to a little endian byte string. + * If 'rd' is NULL, allocate space for it, otherwise + * 'rd' is assumed to have room for BN_num_bytes(n) + * bytes. Returns NULL on failure. + */ +u_int8_t * +bignum_to_le(BIGNUM *n, u_int8_t *rd) +{ + int i, j, k; + int blen = BN_num_bytes(n); + + if (blen == 0) + return (NULL); + if (rd == NULL) + rd = (u_int8_t *)malloc(blen); + if (rd == NULL) + return (NULL); + + for (i = 0, j = 0; i < n->top; i++) { + for (k = 0; k < BN_BITS2 / 8; k++) { + if ((j + k) >= blen) + goto out; + rd[j + k] = n->d[i] >> (k * 8); + } + j += BN_BITS2 / 8; + } +out: + return (rd); +} + +int +UB_mod_exp(BIGNUM *res, BIGNUM *a, BIGNUM *b, BIGNUM *c, BN_CTX *ctx) +{ + struct crypt_kop kop; + u_int8_t *ale, *ble, *cle; + + if (crypto_fd == -1) { + int fd, fdc = open("/dev/crypto", O_RDONLY); + + if (fdc == -1) + err(1, "/dev/crypto"); + if (ioctl(fdc, CRIOGET, &fd) == -1) + err(1, "CRIOGET"); + close(fdc); + crypto_fd = fd; + } + + if ((ale = bignum_to_le(a, NULL)) == NULL) + err(1, "bignum_to_le, a"); + if ((ble = bignum_to_le(b, NULL)) == NULL) + err(1, "bignum_to_le, b"); + if ((cle = bignum_to_le(c, NULL)) == NULL) + err(1, "bignum_to_le, c"); + + bzero(&kop, sizeof(kop)); + kop.crk_op = CRK_MOD_EXP; + kop.crk_iparams = 3; + kop.crk_oparams = 1; + kop.crk_param[0].crp_p = ale; + kop.crk_param[0].crp_nbits = BN_num_bytes(a) * 8; + kop.crk_param[1].crp_p = ble; + kop.crk_param[1].crp_nbits = BN_num_bytes(b) * 8; + kop.crk_param[2].crp_p = cle; + kop.crk_param[2].crp_nbits = BN_num_bytes(c) * 8; + kop.crk_param[3].crp_p = cle; + kop.crk_param[3].crp_nbits = BN_num_bytes(c) * 8; + + if (ioctl(crypto_fd, CIOCKEY, &kop) == -1) + err(1, "CIOCKEY"); + + bzero(ale, BN_num_bytes(a)); + free(ale); + bzero(ble, BN_num_bytes(b)); + free(ble); + + if (kop.crk_status != 0) { + printf("error %d\n", kop.crk_status); + bzero(cle, BN_num_bytes(c)); + free(cle); + return (-1); + } else { + res = le_to_bignum(res, cle, BN_num_bytes(c)); + bzero(cle, BN_num_bytes(c)); + free(cle); + if (res == NULL) + err(1, "le_to_bignum"); + return (0); + } + return (0); +} + +void +show_result(a, b, c, sw, hw) +BIGNUM *a, *b, *c, *sw, *hw; +{ + printf("\n"); + + printf("A = "); + BN_print_fp(stdout, a); + printf("\n"); + + printf("B = "); + BN_print_fp(stdout, b); + printf("\n"); + + printf("C = "); + BN_print_fp(stdout, c); + printf("\n"); + + printf("sw= "); + BN_print_fp(stdout, sw); + printf("\n"); + + printf("hw= "); + BN_print_fp(stdout, hw); + printf("\n"); + + printf("\n"); +} + +void +testit(void) +{ + BIGNUM *a, *b, *c, *r1, *r2; + BN_CTX *ctx; + + ctx = BN_CTX_new(); + + a = BN_new(); + b = BN_new(); + c = BN_new(); + r1 = BN_new(); + r2 = BN_new(); + + BN_pseudo_rand(a, 1023, 0, 0); + BN_pseudo_rand(b, 1023, 0, 0); + BN_pseudo_rand(c, 1024, 0, 0); + + if (BN_cmp(a, c) > 0) { + BIGNUM *rem = BN_new(); + + BN_mod(rem, a, c, ctx); + UB_mod_exp(r2, rem, b, c, ctx); + BN_free(rem); + } else { + UB_mod_exp(r2, a, b, c, ctx); + } + BN_mod_exp(r1, a, b, c, ctx); + + if (BN_cmp(r1, r2) != 0) { + show_result(a, b, c, r1, r2); + } + + BN_free(r2); + BN_free(r1); + BN_free(c); + BN_free(b); + BN_free(a); + BN_CTX_free(ctx); +} + +int +main() +{ + int i; + + for (i = 0; i < 1000; i++) { + fprintf(stderr, "test %d\n", i); + testit(); + } + return (0); +} diff --git a/tools/tools/crypto/cryptostats.c b/tools/tools/crypto/cryptostats.c new file mode 100644 index 0000000..3e0c5c1 --- /dev/null +++ b/tools/tools/crypto/cryptostats.c @@ -0,0 +1,77 @@ +/* $FreeBSD$ */ + +/* + * Little program to dump the crypto statistics block and, optionally, + * zero all the stats or just the timing stuff. + */ +#include <stdio.h> + +#include <sys/types.h> +#include <sys/sysctl.h> +#include <sys/time.h> +#include <crypto/cryptodev.h> + +static void +printt(const char* tag, struct cryptotstat *ts) +{ + uint64_t avg, min, max; + + if (ts->count == 0) + return; + avg = (1000000000LL*ts->acc.tv_sec + ts->acc.tv_nsec) / ts->count; + min = 1000000000LL*ts->min.tv_sec + ts->min.tv_nsec; + max = 1000000000LL*ts->max.tv_sec + ts->max.tv_nsec; + printf("%16.16s: avg %6llu ns : min %6llu ns : max %7llu ns [%u samps]\n", + tag, avg, min, max, ts->count); +} + +int +main(int argc, char *argv[]) +{ + struct cryptostats stats; + size_t slen; + + slen = sizeof (stats); + if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, NULL) < 0) + err(1, "kern.cryptostats"); + + if (argc > 1 && strcmp(argv[1], "-z") == 0) { + bzero(&stats.cs_invoke, sizeof (stats.cs_invoke)); + bzero(&stats.cs_done, sizeof (stats.cs_done)); + bzero(&stats.cs_cb, sizeof (stats.cs_cb)); + bzero(&stats.cs_finis, sizeof (stats.cs_finis)); + stats.cs_invoke.min.tv_sec = 10000; + stats.cs_done.min.tv_sec = 10000; + stats.cs_cb.min.tv_sec = 10000; + stats.cs_finis.min.tv_sec = 10000; + if (sysctlbyname("kern.crypto_stats", NULL, NULL, &stats, sizeof (stats)) < 0) + err(1, "kern.cryptostats"); + exit(0); + } + if (argc > 1 && strcmp(argv[1], "-Z") == 0) { + bzero(&stats, sizeof (stats)); + stats.cs_invoke.min.tv_sec = 10000; + stats.cs_done.min.tv_sec = 10000; + stats.cs_cb.min.tv_sec = 10000; + stats.cs_finis.min.tv_sec = 10000; + if (sysctlbyname("kern.crypto_stats", NULL, NULL, &stats, sizeof (stats)) < 0) + err(1, "kern.cryptostats"); + exit(0); + } + + + printf("%u symmetric crypto ops (%u errors, %u times driver blocked)\n" + , stats.cs_ops, stats.cs_errs, stats.cs_blocks); + printf("%u key ops (%u errors, %u times driver blocked)\n" + , stats.cs_kops, stats.cs_kerrs, stats.cs_kblocks); + printf("%u crypto dispatch thread activations\n", stats.cs_intrs); + printf("%u crypto return thread activations\n", stats.cs_rets); + if (stats.cs_invoke.count) { + printf("\n"); + printt("dispatch->invoke", &stats.cs_invoke); + printt("invoke->done", &stats.cs_done); + printt("done->cb", &stats.cs_cb); + printt("cb->finis", &stats.cs_finis); + } + return 0; +} diff --git a/tools/tools/crypto/cryptotest.c b/tools/tools/crypto/cryptotest.c index 70008b2..c4b1df5 100644 --- a/tools/tools/crypto/cryptotest.c +++ b/tools/tools/crypto/cryptotest.c @@ -12,20 +12,34 @@ * iterations. Extra arguments can be used to specify one or more buffer * sizes to use in doing tests. * + * To fork multiple processes all doing the same work, specify -t X on the + * command line to get X "threads" running simultaneously. No effort is made + * synchronize the threads or otherwise maximize load. + * + * If the kernel crypto code is built with CRYPTO_TIMING and you run as root, + * then you can specify the -p option to get a "profile" of the time spent + * processing crypto operations. At present this data is only meaningful for + * symmetric operations. To get meaningful numbers you must run on an idle + * machine. + * * Expect ~400 Mb/s for a Broadcom 582x for 16K buffers on a reasonable CPU. * Hifn 7811 parts top out at ~110 Mb/s. * * This code originally came from openbsd; give them all the credit. */ - #include <sys/types.h> #include <sys/param.h> #include <sys/time.h> -#include <crypto/cryptodev.h> #include <sys/ioctl.h> #include <stdio.h> #include <fcntl.h> #include <unistd.h> +#include <sys/wait.h> +#include <sys/mman.h> + +#include <sys/sysctl.h> +#include <sys/time.h> +#include <crypto/cryptodev.h> #define CHUNK 64 /* how much to display */ #define N(a) (sizeof (a) / sizeof (a[0])) @@ -47,7 +61,9 @@ struct alg { int maxkeylen; int code; } algorithms[] = { +#ifdef CRYPTO_NULL_CBC { "null", 8, 1, 256, CRYPTO_NULL_CBC }, +#endif { "des", 8, 8, 8, CRYPTO_DES_CBC }, { "3des", 8, 24, 24, CRYPTO_3DES_CBC }, { "blf", 8, 5, 56, CRYPTO_BLF_CBC }, @@ -95,20 +111,11 @@ getalgbyname(const char* name) } static void -runtest(struct alg *alg, int count, int size, int cmd) +runtest(struct alg *alg, int count, int size, int cmd, struct timeval *tv) { int i; struct timeval start, stop, dt; char *cleartext, *ciphertext; - double t; - - if (size % alg->blocksize) { - if (verbose) - printf("skipping blocksize %u 'cuz not a multiple of " - "%s blocksize %u\n", - size, alg->name, alg->blocksize); - return; - } if (ioctl(cryptodev_fd,CRIOGET,&fd) == -1) err(1, "CRIOGET failed"); @@ -182,11 +189,7 @@ runtest(struct alg *alg, int count, int size, int cmd) printf("cleartext:"); hexdump(cleartext, MIN(size, CHUNK)); } - timersub(&stop, &start, &dt); - t = (((double)dt.tv_sec * 1000000 + dt.tv_usec) / 1000000); - printf("%6.3lf sec, %7d %6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n", - t, 2*count, alg->name, size, (double)2*count*size / t, - (double)2*count*size / t * 8 / 1024 / 1024); + timersub(&stop, &start, tv); free(ciphertext); free(cleartext); @@ -194,6 +197,116 @@ runtest(struct alg *alg, int count, int size, int cmd) close(fd); } +static void +resetstats() +{ + struct cryptostats stats; + size_t slen; + + slen = sizeof (stats); + if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, NULL) < 0) { + perror("kern.crypto_stats"); + return; + } + bzero(&stats.cs_invoke, sizeof (stats.cs_invoke)); + bzero(&stats.cs_done, sizeof (stats.cs_done)); + bzero(&stats.cs_cb, sizeof (stats.cs_cb)); + bzero(&stats.cs_finis, sizeof (stats.cs_finis)); + stats.cs_invoke.min.tv_sec = 10000; + stats.cs_done.min.tv_sec = 10000; + stats.cs_cb.min.tv_sec = 10000; + stats.cs_finis.min.tv_sec = 10000; + if (sysctlbyname("kern.crypto_stats", NULL, NULL, &stats, sizeof (stats)) < 0) + perror("kern.cryptostats"); +} + +static void +printt(const char* tag, struct cryptotstat *ts) +{ + uint64_t avg, min, max; + + if (ts->count == 0) + return; + avg = (1000000000LL*ts->acc.tv_sec + ts->acc.tv_nsec) / ts->count; + min = 1000000000LL*ts->min.tv_sec + ts->min.tv_nsec; + max = 1000000000LL*ts->max.tv_sec + ts->max.tv_nsec; + printf("%16.16s: avg %6llu ns : min %6llu ns : max %7llu ns [%u samps]\n", + tag, avg, min, max, ts->count); +} + +static void +runtests(struct alg *alg, int count, int size, int cmd, int threads, int profile) +{ + int i, status; + double t; + void *region; + struct timeval *tvp; + struct timeval total; + int otiming; + + if (size % alg->blocksize) { + if (verbose) + printf("skipping blocksize %u 'cuz not a multiple of " + "%s blocksize %u\n", + size, alg->name, alg->blocksize); + return; + } + + region = mmap(NULL, threads * sizeof (struct timeval), + PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); + if (region == MAP_FAILED) { + perror("mmap"); + return; + } + tvp = (struct timeval *) region; + if (profile) { + size_t tlen = sizeof (otiming); + int timing = 1; + + resetstats(); + if (sysctlbyname("debug.crypto_timing", &otiming, &tlen, + &timing, sizeof (timing)) < 0) + perror("debug.crypto_timing"); + } + + if (threads > 1) { + for (i = 0; i < threads; i++) + if (fork() == 0) { + runtest(alg, count, size, cmd, &tvp[i]); + exit(0); + } + while (waitpid(WAIT_MYPGRP, &status, 0) != -1) + ; + } else + runtest(alg, count, size, cmd, tvp); + + t = 0; + for (i = 0; i < threads; i++) + t += (((double)tvp[i].tv_sec * 1000000 + tvp[i].tv_usec) / 1000000); + if (t) { + printf("%6.3lf sec, %7d %6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n", + t/threads, 2*count*threads, alg->name, size, (double)2*count*size*threads / t, + (double)2*count*size*threads / t * 8 / 1024 / 1024); + } + if (profile) { + struct cryptostats stats; + size_t slen = sizeof (stats); + + if (sysctlbyname("debug.crypto_timing", NULL, NULL, + &otiming, sizeof (otiming)) < 0) + perror("debug.crypto_timing"); + if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, NULL) < 0) + perror("kern.cryptostats"); + if (stats.cs_invoke.count) { + printt("dispatch->invoke", &stats.cs_invoke); + printt("invoke->done", &stats.cs_done); + printt("done->cb", &stats.cs_cb); + printt("cb->finis", &stats.cs_finis); + } + } + fflush(stdout); +} + int main(int argc, char **argv) { @@ -202,9 +315,11 @@ main(int argc, char **argv) int sizes[128], nsizes = 0; int cmd = CIOCGSESSION; int testall = 0; + int maxthreads = 1; + int profile = 0; int i, ch; - while ((ch = getopt(argc, argv, "zsva:")) != -1) { + while ((ch = getopt(argc, argv, "pzsva:t:")) != -1) { switch (ch) { #ifdef CIOCGSSESSION case 's': @@ -223,9 +338,15 @@ main(int argc, char **argv) usage(argv[0]); } break; + case 't': + maxthreads = atoi(optarg); + break; case 'z': testall = 1; break; + case 'p': + profile = 1; + break; default: usage(argv[0]); } @@ -245,7 +366,7 @@ main(int argc, char **argv) if (nsizes == 0) { sizes[nsizes++] = 8; if (testall) { - while (sizes[nsizes-1] < 32768) { + while (sizes[nsizes-1] < 8*1024) { sizes[nsizes] = sizes[nsizes-1]<<1; nsizes++; } @@ -260,13 +381,13 @@ main(int argc, char **argv) int j; alg = &algorithms[i]; for (j = 0; j < nsizes; j++) - runtest(alg, count, sizes[j], cmd); + runtests(alg, count, sizes[j], cmd, maxthreads, profile); } } else { if (alg == NULL) alg = getalgbycode(CRYPTO_3DES_CBC); for (i = 0; i < nsizes; i++) - runtest(alg, count, sizes[i], cmd); + runtests(alg, count, sizes[i], cmd, maxthreads, profile); } return (0); |