1135 lines · 30.0 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> * * 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. * * 2004-08-09 Added cipher speed tests (Reyk Floeter <reyk@vantronix.net>) * 2003-09-14 Rewritten by Kartikey Mahendra Bhatt * */ #include <linux/init.h>#include <linux/module.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/scatterlist.h>#include <linux/string.h>#include <linux/crypto.h>#include <linux/highmem.h>#include <linux/moduleparam.h>#include <linux/jiffies.h>#include <linux/timex.h>#include <linux/interrupt.h>#include "tcrypt.h" /* * Need to kmalloc() memory for testing kmap(). */#define TVMEMSIZE	16384#define XBUFSIZE	32768 /* * Indexes into the xbuf to simulate cross-page access. */#define IDX1		37#define IDX2		32400#define IDX3		1#define IDX4		8193#define IDX5		22222#define IDX6		17101#define IDX7		27333#define IDX8		3000 /** Used by test_cipher()*/#define ENCRYPT 1#define DECRYPT 0#define MODE_ECB 1#define MODE_CBC 0 static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; /* * Used by test_cipher_speed() */static unsigned int sec; static int mode;static char *xbuf;static char *tvmem; static char *check[] = {	"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",	"twofish", "serpent", "sha384", "sha512", "md4", "aes", "cast6",	"arc4", "michael_mic", "deflate", "crc32c", "tea", "xtea",	"khazad", "wp512", "wp384", "wp256", "tnepres", "xeta", NULL}; static void hexdump(unsigned char *buf, unsigned int len){	while (len--)		printk("%02x", *buf++); 	printk("\n");} static void test_hash(char *algo, struct hash_testvec *template,		      unsigned int tcount){	unsigned int i, j, k, temp;	struct scatterlist sg[8];	char result[64];	struct crypto_tfm *tfm;	struct hash_testvec *hash_tv;	unsigned int tsize; 	printk("\ntesting %s\n", algo); 	tsize = sizeof(struct hash_testvec);	tsize *= tcount; 	if (tsize > TVMEMSIZE) {		printk("template (%u) too big for tvmem (%u)\n", tsize, TVMEMSIZE);		return;	} 	memcpy(tvmem, template, tsize);	hash_tv = (void *)tvmem;	tfm = crypto_alloc_tfm(algo, 0);	if (tfm == NULL) {		printk("failed to load transform for %s\n", algo);		return;	} 	for (i = 0; i < tcount; i++) {		printk("test %u:\n", i + 1);		memset(result, 0, 64); 		sg_set_buf(&sg[0], hash_tv[i].plaintext, hash_tv[i].psize); 		crypto_digest_init(tfm);		if (tfm->crt_u.digest.dit_setkey) {			crypto_digest_setkey(tfm, hash_tv[i].key,					     hash_tv[i].ksize);		}		crypto_digest_update(tfm, sg, 1);		crypto_digest_final(tfm, result); 		hexdump(result, crypto_tfm_alg_digestsize(tfm));		printk("%s\n",		       memcmp(result, hash_tv[i].digest,			      crypto_tfm_alg_digestsize(tfm)) ?		       "fail" : "pass");	} 	printk("testing %s across pages\n", algo); 	/* setup the dummy buffer first */	memset(xbuf, 0, XBUFSIZE); 	j = 0;	for (i = 0; i < tcount; i++) {		if (hash_tv[i].np) {			j++;			printk("test %u:\n", j);			memset(result, 0, 64); 			temp = 0;			for (k = 0; k < hash_tv[i].np; k++) {				memcpy(&xbuf[IDX[k]],				       hash_tv[i].plaintext + temp,				       hash_tv[i].tap[k]);				temp += hash_tv[i].tap[k];				sg_set_buf(&sg[k], &xbuf[IDX[k]],					    hash_tv[i].tap[k]);			} 			crypto_digest_digest(tfm, sg, hash_tv[i].np, result); 			hexdump(result, crypto_tfm_alg_digestsize(tfm));			printk("%s\n",			       memcmp(result, hash_tv[i].digest,				      crypto_tfm_alg_digestsize(tfm)) ?			       "fail" : "pass");		}	} 	crypto_free_tfm(tfm);}  #ifdef CONFIG_CRYPTO_HMAC static void test_hmac(char *algo, struct hmac_testvec *template,		      unsigned int tcount){	unsigned int i, j, k, temp;	struct scatterlist sg[8];	char result[64];	struct crypto_tfm *tfm;	struct hmac_testvec *hmac_tv;	unsigned int tsize, klen; 	tfm = crypto_alloc_tfm(algo, 0);	if (tfm == NULL) {		printk("failed to load transform for %s\n", algo);		return;	} 	printk("\ntesting hmac_%s\n", algo); 	tsize = sizeof(struct hmac_testvec);	tsize *= tcount;	if (tsize > TVMEMSIZE) {		printk("template (%u) too big for tvmem (%u)\n", tsize,		       TVMEMSIZE);		goto out;	} 	memcpy(tvmem, template, tsize);	hmac_tv = (void *)tvmem; 	for (i = 0; i < tcount; i++) {		printk("test %u:\n", i + 1);		memset(result, 0, sizeof (result)); 		klen = hmac_tv[i].ksize;		sg_set_buf(&sg[0], hmac_tv[i].plaintext, hmac_tv[i].psize); 		crypto_hmac(tfm, hmac_tv[i].key, &klen, sg, 1, result); 		hexdump(result, crypto_tfm_alg_digestsize(tfm));		printk("%s\n",		       memcmp(result, hmac_tv[i].digest,			      crypto_tfm_alg_digestsize(tfm)) ? "fail" :		       "pass");	} 	printk("\ntesting hmac_%s across pages\n", algo); 	memset(xbuf, 0, XBUFSIZE); 	j = 0;	for (i = 0; i < tcount; i++) {		if (hmac_tv[i].np) {			j++;			printk("test %u:\n",j);			memset(result, 0, 64); 			temp = 0;			klen = hmac_tv[i].ksize;			for (k = 0; k < hmac_tv[i].np; k++) {				memcpy(&xbuf[IDX[k]],				       hmac_tv[i].plaintext + temp,				       hmac_tv[i].tap[k]);				temp += hmac_tv[i].tap[k];				sg_set_buf(&sg[k], &xbuf[IDX[k]],					    hmac_tv[i].tap[k]);			} 			crypto_hmac(tfm, hmac_tv[i].key, &klen, sg,				    hmac_tv[i].np, result);			hexdump(result, crypto_tfm_alg_digestsize(tfm)); 			printk("%s\n",			       memcmp(result, hmac_tv[i].digest,				      crypto_tfm_alg_digestsize(tfm)) ?			       "fail" : "pass");		}	}out:	crypto_free_tfm(tfm);} #endif	/* CONFIG_CRYPTO_HMAC */ static void test_cipher(char *algo, int mode, int enc,			struct cipher_testvec *template, unsigned int tcount){	unsigned int ret, i, j, k, temp;	unsigned int tsize;	char *q;	struct crypto_tfm *tfm;	char *key;	struct cipher_testvec *cipher_tv;	struct scatterlist sg[8];	const char *e, *m; 	if (enc == ENCRYPT)	        e = "encryption";	else		e = "decryption";	if (mode == MODE_ECB)		m = "ECB";	else		m = "CBC"; 	printk("\ntesting %s %s %s\n", algo, m, e); 	tsize = sizeof (struct cipher_testvec);	tsize *= tcount; 	if (tsize > TVMEMSIZE) {		printk("template (%u) too big for tvmem (%u)\n", tsize,		       TVMEMSIZE);		return;	} 	memcpy(tvmem, template, tsize);	cipher_tv = (void *)tvmem; 	if (mode)		tfm = crypto_alloc_tfm(algo, 0);	else		tfm = crypto_alloc_tfm(algo, CRYPTO_TFM_MODE_CBC); 	if (tfm == NULL) {		printk("failed to load transform for %s %s\n", algo, m);		return;	} 	j = 0;	for (i = 0; i < tcount; i++) {		if (!(cipher_tv[i].np)) {			j++;			printk("test %u (%d bit key):\n",			j, cipher_tv[i].klen * 8); 			tfm->crt_flags = 0;			if (cipher_tv[i].wk)				tfm->crt_flags |= CRYPTO_TFM_REQ_WEAK_KEY;			key = cipher_tv[i].key; 			ret = crypto_cipher_setkey(tfm, key, cipher_tv[i].klen);			if (ret) {				printk("setkey() failed flags=%x\n", tfm->crt_flags); 				if (!cipher_tv[i].fail)					goto out;			} 			sg_set_buf(&sg[0], cipher_tv[i].input,				   cipher_tv[i].ilen); 			if (!mode) {				crypto_cipher_set_iv(tfm, cipher_tv[i].iv,					crypto_tfm_alg_ivsize(tfm));			} 			if (enc)				ret = crypto_cipher_encrypt(tfm, sg, sg, cipher_tv[i].ilen);			else				ret = crypto_cipher_decrypt(tfm, sg, sg, cipher_tv[i].ilen);  			if (ret) {				printk("%s () failed flags=%x\n", e, tfm->crt_flags);				goto out;			} 			q = kmap(sg[0].page) + sg[0].offset;			hexdump(q, cipher_tv[i].rlen); 			printk("%s\n",			       memcmp(q, cipher_tv[i].result,				      cipher_tv[i].rlen) ? "fail" : "pass");		}	} 	printk("\ntesting %s %s %s across pages (chunking)\n", algo, m, e);	memset(xbuf, 0, XBUFSIZE); 	j = 0;	for (i = 0; i < tcount; i++) {		if (cipher_tv[i].np) {			j++;			printk("test %u (%d bit key):\n",			j, cipher_tv[i].klen * 8); 			tfm->crt_flags = 0;			if (cipher_tv[i].wk)				tfm->crt_flags |= CRYPTO_TFM_REQ_WEAK_KEY;			key = cipher_tv[i].key; 			ret = crypto_cipher_setkey(tfm, key, cipher_tv[i].klen);			if (ret) {				printk("setkey() failed flags=%x\n", tfm->crt_flags); 				if (!cipher_tv[i].fail)					goto out;			} 			temp = 0;			for (k = 0; k < cipher_tv[i].np; k++) {				memcpy(&xbuf[IDX[k]],				       cipher_tv[i].input + temp,				       cipher_tv[i].tap[k]);				temp += cipher_tv[i].tap[k];				sg_set_buf(&sg[k], &xbuf[IDX[k]],					   cipher_tv[i].tap[k]);			} 			if (!mode) {				crypto_cipher_set_iv(tfm, cipher_tv[i].iv,						crypto_tfm_alg_ivsize(tfm));			} 			if (enc)				ret = crypto_cipher_encrypt(tfm, sg, sg, cipher_tv[i].ilen);			else				ret = crypto_cipher_decrypt(tfm, sg, sg, cipher_tv[i].ilen); 			if (ret) {				printk("%s () failed flags=%x\n", e, tfm->crt_flags);				goto out;			} 			temp = 0;			for (k = 0; k < cipher_tv[i].np; k++) {				printk("page %u\n", k);				q = kmap(sg[k].page) + sg[k].offset;				hexdump(q, cipher_tv[i].tap[k]);				printk("%s\n",					memcmp(q, cipher_tv[i].result + temp,						cipher_tv[i].tap[k]) ? "fail" :					"pass");				temp += cipher_tv[i].tap[k];			}		}	} out:	crypto_free_tfm(tfm);} static int test_cipher_jiffies(struct crypto_tfm *tfm, int enc, char *p,			       int blen, int sec){	struct scatterlist sg[1];	unsigned long start, end;	int bcount;	int ret; 	sg_set_buf(sg, p, blen); 	for (start = jiffies, end = start + sec * HZ, bcount = 0;	     time_before(jiffies, end); bcount++) {		if (enc)			ret = crypto_cipher_encrypt(tfm, sg, sg, blen);		else			ret = crypto_cipher_decrypt(tfm, sg, sg, blen); 		if (ret)			return ret;	} 	printk("%d operations in %d seconds (%ld bytes)\n",	       bcount, sec, (long)bcount * blen);	return 0;} static int test_cipher_cycles(struct crypto_tfm *tfm, int enc, char *p,			      int blen){	struct scatterlist sg[1];	unsigned long cycles = 0;	int ret = 0;	int i; 	sg_set_buf(sg, p, blen); 	local_bh_disable();	local_irq_disable(); 	/* Warm-up run. */	for (i = 0; i < 4; i++) {		if (enc)			ret = crypto_cipher_encrypt(tfm, sg, sg, blen);		else			ret = crypto_cipher_decrypt(tfm, 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_cipher_encrypt(tfm, sg, sg, blen);		else			ret = crypto_cipher_decrypt(tfm, sg, sg, blen);		end = get_cycles(); 		if (ret)			goto out; 		cycles += end - start;	} out:	local_irq_enable();	local_bh_enable(); 	if (ret == 0)		printk("1 operation in %lu cycles (%d bytes)\n",		       (cycles + 4) / 8, blen); 	return ret;} static void test_cipher_speed(char *algo, int mode, int enc, unsigned int sec,			      struct cipher_testvec *template,			      unsigned int tcount, struct cipher_speed *speed){	unsigned int ret, i, j, iv_len;	unsigned char *key, *p, iv[128];	struct crypto_tfm *tfm;	const char *e, *m;

Lines 1–500 of 1135.