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
This commit is contained in:
Sam Leffler 2003-01-06 22:11:56 +00:00
parent 305f2c0632
commit a5c6189066
4 changed files with 450 additions and 22 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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);