2210 lines · 52.1 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. * */ #include <crypto/aead.h>#include <crypto/hash.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 /* * 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", NULL}; static int test_cipher_jiffies(struct blkcipher_desc *desc, int enc,			       struct scatterlist *sg, 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 = crypto_blkcipher_encrypt(desc, sg, sg, blen);		else			ret = crypto_blkcipher_decrypt(desc, sg, sg, blen); 		if (ret)			return ret;	} 	printk("%d operations in %d seconds (%ld bytes)\n",	       bcount, secs, (long)bcount * blen);	return 0;} static int test_cipher_cycles(struct blkcipher_desc *desc, int enc,			      struct scatterlist *sg, int blen){	unsigned long cycles = 0;	int ret = 0;	int i; 	local_irq_disable(); 	/* Warm-up run. */	for (i = 0; i < 4; i++) {		if (enc)			ret = crypto_blkcipher_encrypt(desc, sg, sg, blen);		else			ret = crypto_blkcipher_decrypt(desc, sg, sg, blen); 		if (ret)			goto out;	} 	/* The real thing. */	for (i = 0; i < 8; i++) {		cycles_t start, end; 		start = get_cycles();		if (enc)			ret = crypto_blkcipher_encrypt(desc, sg, sg, blen);		else			ret = crypto_blkcipher_decrypt(desc, sg, sg, blen);		end = get_cycles(); 		if (ret)			goto out; 		cycles += end - start;	} out:	local_irq_enable(); 	if (ret == 0)		printk("1 operation in %lu cycles (%d bytes)\n",		       (cycles + 4) / 8, blen); 	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 = crypto_aead_encrypt(req);		else			ret = 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; 	local_irq_disable(); 	/* Warm-up run. */	for (i = 0; i < 4; i++) {		if (enc)			ret = crypto_aead_encrypt(req);		else			ret = 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 = crypto_aead_encrypt(req);		else			ret = crypto_aead_decrypt(req);		end = get_cycles(); 		if (ret)			goto out; 		cycles += end - start;	} out:	local_irq_enable(); 	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; 	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;	} 	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;	} 	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_cipher_speed(const char *algo, int enc, unsigned int secs,			      struct cipher_speed_template *template,			      unsigned int tcount, u8 *keysize){	unsigned int ret, i, j, iv_len;	const char *key;	char iv[128];	struct crypto_blkcipher *tfm;	struct blkcipher_desc desc;	const char *e;	u32 *b_size; 	if (enc == ENCRYPT)	        e = "encryption";	else		e = "decryption"; 	tfm = crypto_alloc_blkcipher(algo, 0, CRYPTO_ALG_ASYNC); 	if (IS_ERR(tfm)) {		printk("failed to load transform for %s: %ld\n", algo,		       PTR_ERR(tfm));		return;	}	desc.tfm = tfm;	desc.flags = 0; 	printk(KERN_INFO "\ntesting speed of %s (%s) %s\n", algo,			get_driver_name(crypto_blkcipher, tfm), e); 	i = 0;	do { 		b_size = block_sizes;		do {			struct scatterlist sg[TVMEMSIZE]; 			if ((*keysize + *b_size) > TVMEMSIZE * PAGE_SIZE) {				printk("template (%u) too big for "				       "tvmem (%lu)\n", *keysize + *b_size,				       TVMEMSIZE * PAGE_SIZE);				goto out;			} 			printk("test %u (%d bit key, %d byte blocks): ", i,					*keysize * 8, *b_size); 			memset(tvmem[0], 0xff, PAGE_SIZE); 			/* set key, plain text and IV */			key = tvmem[0];			for (j = 0; j < tcount; j++) {				if (template[j].klen == *keysize) {					key = template[j].key;					break;				}			} 			ret = crypto_blkcipher_setkey(tfm, key, *keysize);			if (ret) {				printk("setkey() failed flags=%x\n",						crypto_blkcipher_get_flags(tfm));				goto out;			} 			sg_init_table(sg, TVMEMSIZE);			sg_set_buf(sg, tvmem[0] + *keysize,				   PAGE_SIZE - *keysize);			for (j = 1; j < TVMEMSIZE; j++) {				sg_set_buf(sg + j, tvmem[j], PAGE_SIZE);				memset (tvmem[j], 0xff, PAGE_SIZE);			} 			iv_len = crypto_blkcipher_ivsize(tfm);			if (iv_len) {				memset(&iv, 0xff, iv_len);				crypto_blkcipher_set_iv(tfm, iv, iv_len);			} 			if (secs)				ret = test_cipher_jiffies(&desc, enc, sg,

Lines 1–500 of 2210.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t