⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cryptosoft.c

📁 linux下基于加密芯片的加密设备
💻 C
字号:
/* * An OCF module that uses the linux kernel cryptoapi, based on the * original cryptosoft for BSD by Angelos D. Keromytis (angelos@cis.upenn.edu) * but is mostly unrecognisable, * * Copyright (C) 2004 David McCullough <davidm@snapgear.com> * All rights reserved. * * LICENSE TERMS * * The free distribution and use of this software in both source and binary * form is allowed (with or without changes) provided that: * *   1. distributions of this source code include the above copyright *      notice, this list of conditions and the following disclaimer; * *   2. distributions in binary form include the above copyright *      notice, this list of conditions and the following disclaimer *      in the documentation and/or other associated materials; * *   3. the copyright holder's name is not used to endorse products *      built using this software without specific written permission. * * ALTERNATIVELY, provided that this notice is retained in full, this product * may be distributed under the terms of the GNU General Public License (GPL), * in which case the provisions of the GPL apply INSTEAD OF those given above. * * DISCLAIMER * * This software is provided 'as is' with no explicit or implied warranties * in respect of its properties, including, but not limited to, correctness * and/or fitness for purpose. * --------------------------------------------------------------------------- */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/sched.h>#include <linux/wait.h>#include <linux/crypto.h>#include <asm/scatterlist.h>#include <cryptodev.h>#include <uio.h>#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)/* Software session entry */#define SW_TYPE_CIPHER	0#define SW_TYPE_HMAC	1#define SW_TYPE_AUTH2	2#define SW_TYPE_AUTH3	3#define SW_TYPE_COMP	4struct swcr_data {	int					sw_type;	int					sw_alg;	struct crypto_tfm	*sw_tfm;	union {		struct {			char sw_key[HMAC_BLOCK_LEN];			int  sw_klen;		} hmac;	} u;	struct swcr_data	*sw_next;};static int32_t swcr_id = -1;static struct swcr_data **swcr_sessions = NULL;static u_int32_t swcr_sesnum = 0;static	int swcr_process(void *, struct cryptop *, int);static	int swcr_newsession(void *, u_int32_t *, struct cryptoini *);static	int swcr_freesession(void *, u_int64_t);static int debug = 0;MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug,	   "Enable debug");/* * add data into a potentially chained/scattered buffer */static voidswcr_inject_data(int type, void *buf, unsigned char *result, int offset){	printk("%s,%d: %s()\n", __FILE__, __LINE__, __FUNCTION__);}/* * Generate a new software session. */static intswcr_newsession(void *arg, u_int32_t *sid, struct cryptoini *cri){	struct swcr_data **swd;	u_int32_t i;	int error;	char *algo;	int mode, sw_type;	dprintk("%s()\n", __FUNCTION__);	if (sid == NULL || cri == NULL) {		dprintk("%s,%d - EINVAL\n", __FILE__, __LINE__);		return EINVAL;	}	if (swcr_sessions) {		for (i = 1; i < swcr_sesnum; i++)			if (swcr_sessions[i] == NULL)				break;	} else		i = 1;		/* NB: to silence compiler warning */	if (swcr_sessions == NULL || i == swcr_sesnum) {		if (swcr_sessions == NULL) {			i = 1; /* We leave swcr_sessions[0] empty */			swcr_sesnum = CRYPTO_SW_SESSIONS;		} else			swcr_sesnum *= 2;		swd = kmalloc(swcr_sesnum * sizeof(struct swcr_data *), GFP_ATOMIC);		if (swd == NULL) {			/* Reset session number */			if (swcr_sesnum == CRYPTO_SW_SESSIONS)				swcr_sesnum = 0;			else				swcr_sesnum /= 2;			dprintk("%s,%d: ENOBUFS\n", __FILE__, __LINE__);			return ENOBUFS;		}		memset(swd, 0, swcr_sesnum * sizeof(struct swcr_data *));		/* Copy existing sessions */		if (swcr_sessions) {			memcpy(swd, swcr_sessions,			    (swcr_sesnum / 2) * sizeof(struct swcr_data *));			kfree(swcr_sessions);		}		swcr_sessions = swd;	}	swd = &swcr_sessions[i];	*sid = i;	while (cri) {		*swd = (struct swcr_data *) kmalloc(sizeof(struct swcr_data),				GFP_ATOMIC);		if (*swd == NULL) {			swcr_freesession(NULL, i);			dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);			return ENOBUFS;		}		memset(*swd, 0, sizeof(struct swcr_data));		algo = NULL;		mode = 0;		sw_type = SW_TYPE_CIPHER;		switch (cri->cri_alg) {		case CRYPTO_DES_CBC:			algo = "des";			mode = CRYPTO_TFM_MODE_CBC;			break;		case CRYPTO_3DES_CBC:			algo = "des3_ede";			mode = CRYPTO_TFM_MODE_CBC;			break;		case CRYPTO_BLF_CBC:			algo = "blowfish";			mode = CRYPTO_TFM_MODE_CBC;			break;		case CRYPTO_CAST_CBC:			algo = "cast5";			mode = CRYPTO_TFM_MODE_CBC;			break;		case CRYPTO_SKIPJACK_CBC:			algo = "skipjack";			mode = CRYPTO_TFM_MODE_CBC;			break;		case CRYPTO_RIJNDAEL128_CBC:			algo = "aes";			mode = CRYPTO_TFM_MODE_CBC;			break;		case CRYPTO_NULL_CBC:			algo = "cipher_null";			mode = 0;			cri->cri_klen = 0; /* make it work with crypto API */			break;		case CRYPTO_MD5_HMAC:			algo = "md5";			sw_type = SW_TYPE_HMAC;			break;		case CRYPTO_SHA1_HMAC:			algo = "sha1";			sw_type = SW_TYPE_HMAC;			break;		case CRYPTO_SHA2_HMAC:			if (cri->cri_klen == 256)				algo = "sha256";			else if (cri->cri_klen == 384)				algo = "sha384";			else if (cri->cri_klen == 512)				algo = "sha512";			sw_type = SW_TYPE_HMAC;			break;		case CRYPTO_NULL_HMAC:			algo = "digest_null";			sw_type = SW_TYPE_HMAC;			break;		case CRYPTO_RIPEMD160_HMAC:			algo = "ripemd160";			sw_type = SW_TYPE_HMAC;			break;		case CRYPTO_MD5_KPDK:			algo = "??";			sw_type = SW_TYPE_AUTH2;			break;		case CRYPTO_SHA1_KPDK:			algo = "??";			sw_type = SW_TYPE_AUTH2;			break;		case CRYPTO_MD5:			algo = "md5";			sw_type = SW_TYPE_AUTH3;			break;		case CRYPTO_SHA1:			algo = "sha1";			sw_type = SW_TYPE_AUTH3;			break;		case CRYPTO_DEFLATE_COMP:			algo = "deflate";			sw_type = SW_TYPE_COMP;			break;		default:			break;		}		if (!algo || !*algo) {			printk("cryptosoft: Unknown algo 0x%x\n", cri->cri_alg);			swcr_freesession(NULL, i);			return EINVAL;		}		dprintk("%s crypto_alloc_tfm(%s, 0x%x)\n", __FUNCTION__, algo, mode);		(*swd)->sw_tfm = crypto_alloc_tfm(algo, mode);		if (!(*swd)->sw_tfm) {			printk("cryptosoft: crypto_alloc_tfm failed(%s,0x%x)\n",algo,mode);			swcr_freesession(NULL, i);			return EINVAL;		}		if (sw_type == SW_TYPE_CIPHER) {			if (debug) {				dprintk("%s key:", __FUNCTION__);				for (i = 0; i < cri->cri_klen / 8; i++)					dprintk("%s0x%x", (i % 8) ? " " : "\n    ",cri->cri_key[i]);				dprintk("\n");			}			error = crypto_cipher_setkey((*swd)->sw_tfm, cri->cri_key,					cri->cri_klen / 8);			if (error) {				printk("cryptosoft: setkey failed %d (crt_flags=0x%x)\n", error,						(*swd)->sw_tfm->crt_flags);				swcr_freesession(NULL, i);				return error;			}		} else if (sw_type == SW_TYPE_HMAC) {			(*swd)->u.hmac.sw_klen = cri->cri_klen / 8;			memcpy((*swd)->u.hmac.sw_key, cri->cri_key, (*swd)->u.hmac.sw_klen);		} else {			printk("cryptosoft: Unhandled sw_type %d\n", sw_type);			swcr_freesession(NULL, i);			return EINVAL;		}		(*swd)->sw_alg = cri->cri_alg;		(*swd)->sw_type = sw_type;		cri = cri->cri_next;		swd = &((*swd)->sw_next);	}	return 0;}/* * Free a session. */static intswcr_freesession(void *arg, u_int64_t tid){	struct swcr_data *swd;	u_int32_t sid = CRYPTO_SESID2LID(tid);	dprintk("%s()\n", __FUNCTION__);	if (sid > swcr_sesnum || swcr_sessions == NULL ||			swcr_sessions[sid] == NULL) {		dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);		return(EINVAL);	}	/* Silently accept and return */	if (sid == 0)		return(0);	while ((swd = swcr_sessions[sid]) != NULL) {		swcr_sessions[sid] = swd->sw_next;		if (swd->sw_tfm)			crypto_free_tfm(swd->sw_tfm);		kfree(swd);	}	return 0;}/* * Process a software request. */static intswcr_process(void *arg, struct cryptop *crp, int hint){	struct cryptodesc *crd;	struct swcr_data *sw;	u_int32_t lid;	int type;	struct scatterlist sg[16];	struct uio *uiop;	int sg_num, sg_len;	dprintk("%s()\n", __FUNCTION__);	/* Sanity check */	if (crp == NULL) {		dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);		return EINVAL;	}	crp->crp_etype = 0;	if (crp->crp_desc == NULL || crp->crp_buf == NULL) {		dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);		crp->crp_etype = EINVAL;		goto done;	}	lid = crp->crp_sid & 0xffffffff;	if (lid >= swcr_sesnum || lid == 0 || swcr_sessions == NULL ||			swcr_sessions[lid] == NULL) {		crp->crp_etype = ENOENT;		dprintk("%s,%d: ENOENT\n", __FILE__, __LINE__);		goto done;	}	if (crp->crp_flags & CRYPTO_F_IMBUF) {		type = CRYPTO_BUF_MBUF;		panic("CRYPTO_F_IMBUF");		goto done;	} else if (crp->crp_flags & CRYPTO_F_IOV) {		type = CRYPTO_BUF_IOV;		uiop = (struct uio *) crp->crp_buf;		sg_len = 0;		for (sg_num = 0; sg_num < uiop->uio_iovcnt && sg_num < 16; sg_num++) {			sg[sg_num].address = 0;			sg[sg_num].page   = virt_to_page(uiop->uio_iov[sg_num].iov_base);			sg[sg_num].offset = offset_in_page(uiop->uio_iov[sg_num].iov_base);			sg[sg_num].length = uiop->uio_iov[sg_num].iov_len;			sg_len += sg[sg_num].length;		}	} else {		type = CRYPTO_BUF_CONTIG;		sg[0].address = 0;		sg[0].page   = virt_to_page(crp->crp_buf);		sg[0].offset = offset_in_page(crp->crp_buf);		sg_len = sg[0].length = crp->crp_ilen;		sg_num = 1;	}	/* Go through crypto descriptors, processing as we go */	for (crd = crp->crp_desc; crd; crd = crd->crd_next) {		/*		 * Find the crypto context.		 *		 * XXX Note that the logic here prevents us from having		 * XXX the same algorithm multiple times in a session		 * XXX (or rather, we can but it won't give us the right		 * XXX results). To do that, we'd need some way of differentiating		 * XXX between the various instances of an algorithm (so we can		 * XXX locate the correct crypto context).		 */		for (sw = swcr_sessions[lid]; sw && sw->sw_alg != crd->crd_alg;				sw = sw->sw_next)			;		/* No such context ? */		if (sw == NULL) {			crp->crp_etype = EINVAL;			dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);			goto done;		}		if (sg_len < crypto_tfm_alg_blocksize(sw->sw_tfm)) {			crp->crp_etype = EINVAL;			dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);			goto done;		}		switch (sw->sw_type) {		case SW_TYPE_CIPHER:			if (crd->crd_flags & CRD_F_IV_EXPLICIT)				crypto_cipher_set_iv(sw->sw_tfm, crd->crd_iv, 						crypto_tfm_alg_ivsize(sw->sw_tfm));			if (crd->crd_flags & CRD_F_ENCRYPT)				crypto_cipher_encrypt(sw->sw_tfm, sg, sg, sg_len);			else				crypto_cipher_decrypt(sw->sw_tfm, sg, sg, sg_len);			break;		case SW_TYPE_HMAC:			/*			 * BSD and linux seem to differ on digests a little.  Linux			 * has a block size of 64,  while BSD ranges from 8 up.  I			 * don't know what the difference is,  but we have to check it			 * here before calling into the linux crypto or we will be very			 * unhappy with the results			 */			if (sg_len - crd->crd_inject <					crypto_tfm_alg_digestsize(sw->sw_tfm)) {				dprintk("cryptosoft: EINVAL len=%d, digestsize=%d\n", sg_len,						crypto_tfm_alg_digestsize(sw->sw_tfm));				crp->crp_etype = EINVAL;				goto done;			}			if (type == CRYPTO_BUF_CONTIG) {				crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen,						sg, sg_num, crp->crp_buf + crd->crd_inject);			} else {				char result[AALG_MAX_RESULT_LEN];				crypto_hmac(sw->sw_tfm, sw->u.hmac.sw_key, &sw->u.hmac.sw_klen,						sg, sg_num, result);				if (type == CRYPTO_BUF_IOV) {					cuio_copyback((struct uio *) crp->crp_buf, crd->crd_inject,							crypto_tfm_alg_digestsize(sw->sw_tfm), result);				} else					swcr_inject_data(type,crp->crp_buf,result,crd->crd_inject);			}			break;		case SW_TYPE_COMP:#if 0			data = allocate contiguous buffer (crp->crp_buf, crd->crd_len)			if (crd->crd_flags & CRD_F_COMP)				ret = crypto_comp_compress(sw->sw_tfm, data, len, result, &dlen);			else				ret = crypto_comp_decompress(sw->sw_tfm, data, len, result, &dlen);#endif			break;		default:			/* Unknown/unsupported algorithm */			dprintk("%s,%d: EINVAL\n", __FILE__, __LINE__);			crp->crp_etype = EINVAL;			goto done;		}	}done:	crypto_done(crp);	return 0;}static intcryptosoft_init(void){	dprintk("%s(%p)\n", __FUNCTION__, cryptosoft_init);	swcr_id = crypto_get_driverid(CRYPTOCAP_F_SOFTWARE | CRYPTOCAP_F_SYNC);	if (swcr_id < 0)		panic("Software crypto device cannot initialize!");	crypto_register(swcr_id, CRYPTO_DES_CBC,	    0, 0, swcr_newsession, swcr_freesession, swcr_process, NULL);#define	REGISTER(alg) \	crypto_register(swcr_id, alg, 0,0,NULL,NULL,NULL,NULL)	REGISTER(CRYPTO_3DES_CBC);	REGISTER(CRYPTO_BLF_CBC);	REGISTER(CRYPTO_CAST_CBC);	REGISTER(CRYPTO_SKIPJACK_CBC);	REGISTER(CRYPTO_NULL_CBC);	REGISTER(CRYPTO_MD5_HMAC);	REGISTER(CRYPTO_SHA1_HMAC);	REGISTER(CRYPTO_SHA2_HMAC);	REGISTER(CRYPTO_RIPEMD160_HMAC);	REGISTER(CRYPTO_NULL_HMAC);	REGISTER(CRYPTO_MD5_KPDK);	REGISTER(CRYPTO_SHA1_KPDK);	REGISTER(CRYPTO_MD5);	REGISTER(CRYPTO_SHA1);	REGISTER(CRYPTO_RIJNDAEL128_CBC);	REGISTER(CRYPTO_DEFLATE_COMP);#undef REGISTER	return(0);}static voidcryptosoft_exit(void){	dprintk("%s()\n", __FUNCTION__);	crypto_unregister_all(swcr_id);	swcr_id = -1;}module_init(cryptosoft_init);module_exit(cryptosoft_exit);MODULE_LICENSE("Dual BSD/GPL");MODULE_AUTHOR("davidm@snapgear.com");MODULE_DESCRIPTION("Cryptosoft (OCF module for kernel crypto)");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -