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

📄 crypto.c

📁 linux下基于加密芯片的加密设备
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * The linux port of this code done by David McCullough <davidm@snapgear.com> * The license and original author are listed below. * Copyright (C) 2004 David McCullough <davidm@snapgear.com> * * The author of this code is Angelos D. Keromytis (angelos@cis.upenn.edu) * * This code was written by Angelos D. Keromytis in Athens, Greece, in * February 2000. Network Security Technologies Inc. (NSTI) kindly * supported the development of this code. * * Copyright (c) 2000, 2001 Angelos D. Keromytis * * Permission to use, copy, and modify this software with or without fee * is hereby granted, provided that this entire notice is included in * all source code copies of any software which is or includes a copy or * modification of this software. * * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR * IMPLIED WARRANTY. IN PARTICULAR, NONE OF THE AUTHORS MAKES ANY * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE * MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR * PURPOSE. */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/list.h>#include <linux/slab.h>#include <linux/wait.h>#include <linux/sched.h>#include <linux/spinlock.h>#include <cryptodev.h>/* * keep track of whether or not we have been initialised, a big * issue if we are linked into the kernel and a driver gets started before * us */static int crypto_initted = 0;/* * Crypto drivers register themselves by allocating a slot in the * crypto_drivers table with crypto_get_driverid() and then registering * each algorithm they support with crypto_register() and crypto_kregister(). */static spinlock_t crypto_drivers_lock;		/* lock on driver table */#define	CRYPTO_DRIVER_LOCK() \			({ \				spin_lock_irqsave(&crypto_drivers_lock, d_flags); \				dprintk("%s,%d: DRIVER_LOCK()\n", __FILE__, __LINE__); \			 })#define	CRYPTO_DRIVER_UNLOCK() \			({ \			 	dprintk("%s,%d: DRIVER_UNLOCK()\n", __FILE__, __LINE__); \				spin_unlock_irqrestore(&crypto_drivers_lock, d_flags); \			 })static struct cryptocap *crypto_drivers = NULL;static int crypto_drivers_num = 0;/* * There are two queues for crypto requests; one for symmetric (e.g. * cipher) operations and one for asymmetric (e.g. MOD)operations. * A single mutex is used to lock access to both queues.  We could * have one per-queue but having one simplifies handling of block/unblock * operations. */static LIST_HEAD(crp_q);		/* request queues */static LIST_HEAD(crp_kq);static int crypto_q_locked = 0;	/* on !SMP systems, spin locks do nothing :-( */static spinlock_t crypto_q_lock;#define	CRYPTO_Q_LOCK() \			({ \				spin_lock_irqsave(&crypto_q_lock, q_flags); \			 	dprintk("%s,%d: Q_LOCK()\n", __FILE__, __LINE__); \				crypto_q_locked++; \			 })#define	CRYPTO_Q_UNLOCK() \			({ \			 	dprintk("%s,%d: Q_UNLOCK()\n", __FILE__, __LINE__); \				crypto_q_locked--; \				spin_unlock_irqrestore(&crypto_q_lock, q_flags); \			 })/* * There are two queues for processing completed crypto requests; one * for the symmetric and one for the asymmetric ops.  We only need one * but have two to avoid type futzing (cryptop vs. cryptkop).  A single * mutex is used to lock access to both queues.  Note that this lock * must be separate from the lock on request queues to insure driver * callbacks don't generate lock order reversals. */static LIST_HEAD(crp_ret_q);		/* callback queues */static LIST_HEAD(crp_ret_kq);static spinlock_t crypto_ret_q_lock;#define	CRYPTO_RETQ_LOCK() \			({ \				spin_lock_irqsave(&crypto_ret_q_lock, r_flags); \				dprintk("%s,%d: RETQ_LOCK\n", __FILE__, __LINE__); \			 })#define	CRYPTO_RETQ_UNLOCK() \			({ \			 	dprintk("%s,%d: RETQ_UNLOCK\n", __FILE__, __LINE__); \				spin_unlock_irqrestore(&crypto_ret_q_lock, r_flags); \			 })static kmem_cache_t *cryptop_zone;static kmem_cache_t *cryptodesc_zone;static int debug = 0;MODULE_PARM(debug, "i");MODULE_PARM_DESC(debug,	   "Enable debug");static int crypto_verbose = 0;MODULE_PARM(crypto_verbose, "i");MODULE_PARM_DESC(crypto_verbose,	   "Enable verbose crypto startup");static int	crypto_userasymcrypto = 1;	/* userland may do asym crypto reqs */MODULE_PARM(crypto_userasymcrypto, "i");MODULE_PARM_DESC(crypto_userasymcrypto,	   "Enable/disable user-mode access to asymmetric crypto support");static int	crypto_devallowsoft = 0;	/* only use hardware crypto for asym */MODULE_PARM(crypto_devallowsoft, "i");MODULE_PARM_DESC(crypto_devallowsoft,	   "Enable/disable use of software asym crypto support");static pid_t	cryptoproc = (pid_t) -1;static struct	completion cryptoproc_exited;static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait);static pid_t	cryptoretproc = (pid_t) -1;static struct	completion cryptoretproc_exited;static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait);static	int crypto_proc(void *arg);static	int crypto_ret_proc(void *arg);static	int crypto_invoke(struct cryptop *crp, int hint);static	int crypto_kinvoke(struct cryptkop *krp, int hint);static	void crypto_exit(void);static  int crypto_init(void);static	struct cryptostats cryptostats;/* * Create a new session. */intcrypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard){	struct cryptoini *cr;	u_int32_t hid, lid;	int err = EINVAL, d_flags;	dprintk("%s()\n", __FUNCTION__);	CRYPTO_DRIVER_LOCK();	if (crypto_drivers == NULL) {		dprintk("%s,%d: %s - no drivers\n", __FILE__, __LINE__, __FUNCTION__);		goto done;	}	/*	 * The algorithm we use here is pretty stupid; just use the	 * first driver that supports all the algorithms we need.	 *	 * XXX We need more smarts here (in real life too, but that's	 * XXX another story altogether).	 */	for (hid = 0; hid < crypto_drivers_num; hid++) {		struct cryptocap *cap = &crypto_drivers[hid];		/*		 * If it's not initialized or has remaining sessions		 * referencing it, skip.		 */		if (cap->cc_newsession == NULL ||				(cap->cc_flags & CRYPTOCAP_F_CLEANUP)) {			dprintk("%s,%d: %s skip1\n", __FILE__, __LINE__, __FUNCTION__);			continue;		}		/* Hardware required -- ignore software drivers. */		if (hard > 0 && (cap->cc_flags & CRYPTOCAP_F_SOFTWARE)) {			dprintk("%s,%d: %s skip not HW\n",__FILE__,__LINE__,__FUNCTION__);			continue;		}		/* Software required -- ignore hardware drivers. */		if (hard < 0 && (cap->cc_flags & CRYPTOCAP_F_SOFTWARE) == 0) {			dprintk("%s,%d: %s skip not SW\n",__FILE__,__LINE__,__FUNCTION__);			continue;		}		/* See if all the algorithms are supported. */		for (cr = cri; cr; cr = cr->cri_next)			if (cap->cc_alg[cr->cri_alg] == 0)				break;		if (cr == NULL) {			/* Ok, all algorithms are supported. */			/*			 * Can't do everything in one session.			 *			 * XXX Fix this. We need to inject a "virtual" session layer right			 * XXX about here.			 */			/* Call the driver initialization routine. */			lid = hid;		/* Pass the driver ID. */			err = (*cap->cc_newsession)(cap->cc_arg, &lid, cri);			if (err == 0) {				/* XXX assert (hid &~ 0xffffff) == 0 */				/* XXX assert (cap->cc_flags &~ 0xff) == 0 */				(*sid) = ((cap->cc_flags & 0xff) << 24) | hid;				(*sid) <<= 32;				(*sid) |= (lid & 0xffffffff);				cap->cc_sessions++;			} else				dprintk("%s,%d: %s - newsession returned %d\n",						__FILE__, __LINE__, __FUNCTION__, err);			break;		}	}done:	CRYPTO_DRIVER_UNLOCK();	return err;}/* * Delete an existing session (or a reserved session on an unregistered * driver). */intcrypto_freesession(u_int64_t sid){	u_int32_t hid;	int err, d_flags;	dprintk("%s()\n", __FUNCTION__);	CRYPTO_DRIVER_LOCK();	if (crypto_drivers == NULL) {		err = EINVAL;		goto done;	}	/* Determine two IDs. */	hid = CRYPTO_SESID2HID(sid);	if (hid >= crypto_drivers_num) {		err = ENOENT;		goto done;	}	if (crypto_drivers[hid].cc_sessions)		crypto_drivers[hid].cc_sessions--;	/* Call the driver cleanup routine, if available. */	if (crypto_drivers[hid].cc_freesession)		err = crypto_drivers[hid].cc_freesession(				crypto_drivers[hid].cc_arg, sid);	else		err = 0;	/*	 * If this was the last session of a driver marked as invalid,	 * make the entry available for reuse.	 */	if ((crypto_drivers[hid].cc_flags & CRYPTOCAP_F_CLEANUP) &&	    crypto_drivers[hid].cc_sessions == 0)		memset(&crypto_drivers[hid], 0, sizeof(struct cryptocap));done:	CRYPTO_DRIVER_UNLOCK();	return err;}/* * Return an unused driver id.  Used by drivers prior to registering * support for the algorithms they handle. */int32_tcrypto_get_driverid(u_int32_t flags){	struct cryptocap *newdrv;	int i, d_flags;	dprintk("%s()\n", __FUNCTION__);	if (!crypto_initted) {		i = crypto_init();		if (i) {			printk("crypto: failed to init crypto!\n");			return(-1);		}	}	CRYPTO_DRIVER_LOCK();	for (i = 0; i < crypto_drivers_num; i++)		if (crypto_drivers[i].cc_process == NULL &&		    (crypto_drivers[i].cc_flags & CRYPTOCAP_F_CLEANUP) == 0 &&		    crypto_drivers[i].cc_sessions == 0)			break;	/* Out of entries, allocate some more. */	if (i == crypto_drivers_num) {		/* Be careful about wrap-around. */		if (2 * crypto_drivers_num <= crypto_drivers_num) {			CRYPTO_DRIVER_UNLOCK();			printk("crypto: driver count wraparound!\n");			return -1;		}		newdrv = kmalloc(2 * crypto_drivers_num * sizeof(struct cryptocap),				GFP_KERNEL);		if (newdrv == NULL) {			CRYPTO_DRIVER_UNLOCK();			printk("crypto: no space to expand driver table!\n");			return -1;		}		memcpy(newdrv, crypto_drivers,				crypto_drivers_num * sizeof(struct cryptocap));		memset(&crypto_drivers[crypto_drivers_num], 0,				2 * crypto_drivers_num * sizeof(struct cryptocap));		crypto_drivers_num *= 2;		kfree(crypto_drivers);		crypto_drivers = newdrv;	}	/* NB: state is zero'd on free */	crypto_drivers[i].cc_sessions = 1;	/* Mark */	crypto_drivers[i].cc_flags = flags;	if (crypto_verbose)		printk("crypto: assign driver %u, flags %u\n", i, flags);	CRYPTO_DRIVER_UNLOCK();	return i;}static struct cryptocap *crypto_checkdriver(u_int32_t hid){	dprintk("%s()\n", __FUNCTION__);	if (crypto_drivers == NULL) {		dprintk("%s,%d: %s no drivers\n", __FILE__, __LINE__, __FUNCTION__);		return NULL;	}	return (hid >= crypto_drivers_num ? NULL : &crypto_drivers[hid]);}/* * Register support for a key-related algorithm.  This routine * is called once for each algorithm supported a driver. */intcrypto_kregister(u_int32_t driverid, int kalg, u_int32_t flags,    int (*kprocess)(void*, struct cryptkop *, int),    void *karg){	struct cryptocap *cap;	int err, d_flags;	dprintk("%s()\n", __FUNCTION__);	CRYPTO_DRIVER_LOCK();	cap = crypto_checkdriver(driverid);	if (cap != NULL &&	    (CRK_ALGORITM_MIN <= kalg && kalg <= CRK_ALGORITHM_MAX)) {		/*		 * XXX Do some performance testing to determine placing.		 * XXX We probably need an auxiliary data structure that		 * XXX describes relative performances.		 */		cap->cc_kalg[kalg] = flags | CRYPTO_ALG_FLAG_SUPPORTED;		if (crypto_verbose)			printk("crypto: driver %u registers key alg %u flags %u\n"				, driverid				, kalg				, flags			);		if (cap->cc_kprocess == NULL) {			cap->cc_karg = karg;			cap->cc_kprocess = kprocess;		}		err = 0;	} else		err = EINVAL;	CRYPTO_DRIVER_UNLOCK();	return err;}/* * Register support for a non-key-related algorithm.  This routine * is called once for each such algorithm supported by a driver. */intcrypto_register(u_int32_t driverid, int alg, u_int16_t maxoplen,    u_int32_t flags,    int (*newses)(void*, u_int32_t*, struct cryptoini*),    int (*freeses)(void*, u_int64_t),    int (*process)(void*, struct cryptop *, int),    void *arg){	struct cryptocap *cap;	int err, d_flags;	dprintk("%s()\n", __FUNCTION__);	CRYPTO_DRIVER_LOCK();	cap = crypto_checkdriver(driverid);	/* NB: algorithms are in the range [1..max] */	if (cap != NULL &&

⌨️ 快捷键说明

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