2102 lines · 50.8 KB · C
RawDownload
/* * Quick & dirty crypto testing module. * * This will only exist until we have a better testing mechanism * (e.g. a char device). * * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org> * Copyright (c) 2007 Nokia Siemens Networks * * Updated RFC4106 AES-GCM testing. *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com) *             Adrian Hoban <adrian.hoban@intel.com> *             Gabriele Paoloni <gabriele.paoloni@intel.com> *             Tadeusz Struk (tadeusz.struk@intel.com) *             Copyright (c) 2010, Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <crypto/aead.h>#include <crypto/hash.h>#include <crypto/skcipher.h>#include <linux/err.h>#include <linux/fips.h>#include <linux/init.h>#include <linux/gfp.h>#include <linux/module.h>#include <linux/scatterlist.h>#include <linux/string.h>#include <linux/moduleparam.h>#include <linux/jiffies.h>#include <linux/timex.h>#include <linux/interrupt.h>#include "tcrypt.h" /* * Need slab memory for testing (size in number of pages). */#define TVMEMSIZE	4 /** Used by test_cipher_speed()*/#define ENCRYPT 1#define DECRYPT 0 #define MAX_DIGEST_SIZE		64 /* * return a string with the driver name */#define get_driver_name(tfm_type, tfm) crypto_tfm_alg_driver_name(tfm_type ## _tfm(tfm)) /* * Used by test_cipher_speed() */static unsigned int sec; static char *alg = NULL;static u32 type;static u32 mask;static int mode;static char *tvmem[TVMEMSIZE]; static char *check[] = {	"des", "md5", "des3_ede", "rot13", "sha1", "sha224", "sha256",	"blowfish", "twofish", "serpent", "sha384", "sha512", "md4", "aes",	"cast6", "arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",	"khazad", "wp512", "wp384", "wp256", "tnepres", "xeta",  "fcrypt",	"camellia", "seed", "salsa20", "rmd128", "rmd160", "rmd256", "rmd320",	"lzo", "cts", "zlib", "sha3-224", "sha3-256", "sha3-384", "sha3-512",	NULL}; struct tcrypt_result {	struct completion completion;	int err;}; static void tcrypt_complete(struct crypto_async_request *req, int err){	struct tcrypt_result *res = req->data; 	if (err == -EINPROGRESS)		return; 	res->err = err;	complete(&res->completion);} static inline int do_one_aead_op(struct aead_request *req, int ret){	if (ret == -EINPROGRESS || ret == -EBUSY) {		struct tcrypt_result *tr = req->base.data; 		ret = wait_for_completion_interruptible(&tr->completion);		if (!ret)			ret = tr->err;		reinit_completion(&tr->completion);	} 	return ret;} static int test_aead_jiffies(struct aead_request *req, int enc,				int blen, int secs){	unsigned long start, end;	int bcount;	int ret; 	for (start = jiffies, end = start + secs * HZ, bcount = 0;	     time_before(jiffies, end); bcount++) {		if (enc)			ret = do_one_aead_op(req, crypto_aead_encrypt(req));		else			ret = do_one_aead_op(req, crypto_aead_decrypt(req)); 		if (ret)			return ret;	} 	printk("%d operations in %d seconds (%ld bytes)\n",	       bcount, secs, (long)bcount * blen);	return 0;} static int test_aead_cycles(struct aead_request *req, int enc, int blen){	unsigned long cycles = 0;	int ret = 0;	int i; 	/* Warm-up run. */	for (i = 0; i < 4; i++) {		if (enc)			ret = do_one_aead_op(req, crypto_aead_encrypt(req));		else			ret = do_one_aead_op(req, crypto_aead_decrypt(req)); 		if (ret)			goto out;	} 	/* The real thing. */	for (i = 0; i < 8; i++) {		cycles_t start, end; 		start = get_cycles();		if (enc)			ret = do_one_aead_op(req, crypto_aead_encrypt(req));		else			ret = do_one_aead_op(req, crypto_aead_decrypt(req));		end = get_cycles(); 		if (ret)			goto out; 		cycles += end - start;	} out:	if (ret == 0)		printk("1 operation in %lu cycles (%d bytes)\n",		       (cycles + 4) / 8, blen); 	return ret;} static u32 block_sizes[] = { 16, 64, 256, 1024, 8192, 0 };static u32 aead_sizes[] = { 16, 64, 256, 512, 1024, 2048, 4096, 8192, 0 }; #define XBUFSIZE 8#define MAX_IVLEN 32 static int testmgr_alloc_buf(char *buf[XBUFSIZE]){	int i; 	for (i = 0; i < XBUFSIZE; i++) {		buf[i] = (void *)__get_free_page(GFP_KERNEL);		if (!buf[i])			goto err_free_buf;	} 	return 0; err_free_buf:	while (i-- > 0)		free_page((unsigned long)buf[i]); 	return -ENOMEM;} static void testmgr_free_buf(char *buf[XBUFSIZE]){	int i; 	for (i = 0; i < XBUFSIZE; i++)		free_page((unsigned long)buf[i]);} static void sg_init_aead(struct scatterlist *sg, char *xbuf[XBUFSIZE],			unsigned int buflen){	int np = (buflen + PAGE_SIZE - 1)/PAGE_SIZE;	int k, rem; 	if (np > XBUFSIZE) {		rem = PAGE_SIZE;		np = XBUFSIZE;	} else {		rem = buflen % PAGE_SIZE;	} 	sg_init_table(sg, np + 1);	np--;	for (k = 0; k < np; k++)		sg_set_buf(&sg[k + 1], xbuf[k], PAGE_SIZE); 	sg_set_buf(&sg[k + 1], xbuf[k], rem);} static void test_aead_speed(const char *algo, int enc, unsigned int secs,			    struct aead_speed_template *template,			    unsigned int tcount, u8 authsize,			    unsigned int aad_size, u8 *keysize){	unsigned int i, j;	struct crypto_aead *tfm;	int ret = -ENOMEM;	const char *key;	struct aead_request *req;	struct scatterlist *sg;	struct scatterlist *sgout;	const char *e;	void *assoc;	char *iv;	char *xbuf[XBUFSIZE];	char *xoutbuf[XBUFSIZE];	char *axbuf[XBUFSIZE];	unsigned int *b_size;	unsigned int iv_len;	struct tcrypt_result result; 	iv = kzalloc(MAX_IVLEN, GFP_KERNEL);	if (!iv)		return; 	if (aad_size >= PAGE_SIZE) {		pr_err("associate data length (%u) too big\n", aad_size);		goto out_noxbuf;	} 	if (enc == ENCRYPT)		e = "encryption";	else		e = "decryption"; 	if (testmgr_alloc_buf(xbuf))		goto out_noxbuf;	if (testmgr_alloc_buf(axbuf))		goto out_noaxbuf;	if (testmgr_alloc_buf(xoutbuf))		goto out_nooutbuf; 	sg = kmalloc(sizeof(*sg) * 9 * 2, GFP_KERNEL);	if (!sg)		goto out_nosg;	sgout = &sg[9]; 	tfm = crypto_alloc_aead(algo, 0, 0); 	if (IS_ERR(tfm)) {		pr_err("alg: aead: Failed to load transform for %s: %ld\n", algo,		       PTR_ERR(tfm));		goto out_notfm;	} 	init_completion(&result.completion);	printk(KERN_INFO "\ntesting speed of %s (%s) %s\n", algo,			get_driver_name(crypto_aead, tfm), e); 	req = aead_request_alloc(tfm, GFP_KERNEL);	if (!req) {		pr_err("alg: aead: Failed to allocate request for %s\n",		       algo);		goto out_noreq;	} 	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,				  tcrypt_complete, &result); 	i = 0;	do {		b_size = aead_sizes;		do {			assoc = axbuf[0];			memset(assoc, 0xff, aad_size); 			if ((*keysize + *b_size) > TVMEMSIZE * PAGE_SIZE) {				pr_err("template (%u) too big for tvmem (%lu)\n",				       *keysize + *b_size,					TVMEMSIZE * PAGE_SIZE);				goto out;			} 			key = tvmem[0];			for (j = 0; j < tcount; j++) {				if (template[j].klen == *keysize) {					key = template[j].key;					break;				}			}			ret = crypto_aead_setkey(tfm, key, *keysize);			ret = crypto_aead_setauthsize(tfm, authsize); 			iv_len = crypto_aead_ivsize(tfm);			if (iv_len)				memset(iv, 0xff, iv_len); 			crypto_aead_clear_flags(tfm, ~0);			printk(KERN_INFO "test %u (%d bit key, %d byte blocks): ",					i, *keysize * 8, *b_size);  			memset(tvmem[0], 0xff, PAGE_SIZE); 			if (ret) {				pr_err("setkey() failed flags=%x\n",						crypto_aead_get_flags(tfm));				goto out;			} 			sg_init_aead(sg, xbuf,				    *b_size + (enc ? authsize : 0)); 			sg_init_aead(sgout, xoutbuf,				    *b_size + (enc ? authsize : 0)); 			sg_set_buf(&sg[0], assoc, aad_size);			sg_set_buf(&sgout[0], assoc, aad_size); 			aead_request_set_crypt(req, sg, sgout, *b_size, iv);			aead_request_set_ad(req, aad_size); 			if (secs)				ret = test_aead_jiffies(req, enc, *b_size,							secs);			else				ret = test_aead_cycles(req, enc, *b_size); 			if (ret) {				pr_err("%s() failed return code=%d\n", e, ret);				break;			}			b_size++;			i++;		} while (*b_size);		keysize++;	} while (*keysize); out:	aead_request_free(req);out_noreq:	crypto_free_aead(tfm);out_notfm:	kfree(sg);out_nosg:	testmgr_free_buf(xoutbuf);out_nooutbuf:	testmgr_free_buf(axbuf);out_noaxbuf:	testmgr_free_buf(xbuf);out_noxbuf:	kfree(iv);	return;} static void test_hash_sg_init(struct scatterlist *sg){	int i; 	sg_init_table(sg, TVMEMSIZE);	for (i = 0; i < TVMEMSIZE; i++) {		sg_set_buf(sg + i, tvmem[i], PAGE_SIZE);		memset(tvmem[i], 0xff, PAGE_SIZE);	}} static inline int do_one_ahash_op(struct ahash_request *req, int ret){	if (ret == -EINPROGRESS || ret == -EBUSY) {		struct tcrypt_result *tr = req->base.data; 		wait_for_completion(&tr->completion);		reinit_completion(&tr->completion);		ret = tr->err;	}	return ret;} struct test_mb_ahash_data {	struct scatterlist sg[TVMEMSIZE];	char result[64];	struct ahash_request *req;	struct tcrypt_result tresult;	char *xbuf[XBUFSIZE];}; static void test_mb_ahash_speed(const char *algo, unsigned int sec,				struct hash_speed *speed){	struct test_mb_ahash_data *data;	struct crypto_ahash *tfm;	unsigned long start, end;	unsigned long cycles;	unsigned int i, j, k;	int ret; 	data = kzalloc(sizeof(*data) * 8, GFP_KERNEL);	if (!data)		return; 	tfm = crypto_alloc_ahash(algo, 0, 0);	if (IS_ERR(tfm)) {		pr_err("failed to load transform for %s: %ld\n",			algo, PTR_ERR(tfm));		goto free_data;	} 	for (i = 0; i < 8; ++i) {		if (testmgr_alloc_buf(data[i].xbuf))			goto out; 		init_completion(&data[i].tresult.completion); 		data[i].req = ahash_request_alloc(tfm, GFP_KERNEL);		if (!data[i].req) {			pr_err("alg: hash: Failed to allocate request for %s\n",			       algo);			goto out;		} 		ahash_request_set_callback(data[i].req, 0,					   tcrypt_complete, &data[i].tresult);		test_hash_sg_init(data[i].sg);	} 	pr_info("\ntesting speed of multibuffer %s (%s)\n", algo,		get_driver_name(crypto_ahash, tfm)); 	for (i = 0; speed[i].blen != 0; i++) {		/* For some reason this only tests digests. */		if (speed[i].blen != speed[i].plen)			continue; 		if (speed[i].blen > TVMEMSIZE * PAGE_SIZE) {			pr_err("template (%u) too big for tvmem (%lu)\n",			       speed[i].blen, TVMEMSIZE * PAGE_SIZE);			goto out;		} 		if (speed[i].klen)			crypto_ahash_setkey(tfm, tvmem[0], speed[i].klen); 		for (k = 0; k < 8; k++)			ahash_request_set_crypt(data[k].req, data[k].sg,						data[k].result, speed[i].blen); 		pr_info("test%3u "			"(%5u byte blocks,%5u bytes per update,%4u updates): ",			i, speed[i].blen, speed[i].plen,			speed[i].blen / speed[i].plen); 		start = get_cycles(); 		for (k = 0; k < 8; k++) {			ret = crypto_ahash_digest(data[k].req);			if (ret == -EINPROGRESS) {				ret = 0;				continue;			} 			if (ret)				break; 			complete(&data[k].tresult.completion);			data[k].tresult.err = 0;		} 		for (j = 0; j < k; j++) {			struct tcrypt_result *tr = &data[j].tresult;

Lines 1–500 of 2102.