* [PATCH] /dev/crypto for Linux
@ 2004-08-24 21:37 Michal Ludvig
[not found] ` <20040824215351.GA9272@halcrow.us>
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Michal Ludvig @ 2004-08-24 21:37 UTC (permalink / raw)
To: CryptoAPI List; +Cc: linux-kernel, James Morris
[-- Attachment #1: Type: text/plain, Size: 1517 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi all,
attached is a driver for OpenBSD-like /dev/crypto device (aka CryptoDev)
that makes a way for userspace processes to access ciphers provided by
in-kernel CryptoAPI modules.
How does it work?
- - Process opens /dev/crypto and with a set of ioctl() commands does what
it wants to. I.e. obtains a crypto session, does the {enc,dec}ryption
and finally closes the session. The sessions are bound to "struct file"
of the open /dev/crypto and thus are automatically removed even if the
process dies unexpectedly.
What is it good for?
- - One can build really light-weigth programs with crypto support that
don't need any external libraries (e.g. OpenSSL) or built-in algorithms.
- - Easier testing of new CryptoAPI ciphers (later also hashes and maybe
asymmetric ciphers as well).
- - Once, maybe, userspace access to crypto accelerators through kernel
drivers.
- - etc :-)
For more info about /dev/crypto usage, demo programs and OpenSSL patch
see http://www.logix.cz/michal/devel/cryptodev/
Comments? Any chance to have this accepted into vanilla kernel?
Michal Ludvig
- --
SUSE Labs mludvig@suse.cz
(+420) 296.542.373 http://www.suse.cz
Personal homepage http://www.logix.cz/michal
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFBK7URDDolCcRbIhgRAhbSAJ4uf2jXY3X8zYcmbgqLATG7SuT0QwCg4IF6
RxZNkz+u+xjaI+pja8bSt3M=
=CrP/
-----END PGP SIGNATURE-----
[-- Attachment #2: cryptodev-2.6.8.diff --]
[-- Type: text/plain, Size: 17433 bytes --]
#
# Linux driver for /dev/crypto (aka CryptoDev)
# See http://www.logix.cz/michal/devel/cryptodev for details.
#
# Signed-off-by: Michal Ludvig <mludvig@suse.cz>
#
Index: linux-2.6.8/crypto/Kconfig
===================================================================
--- linux-2.6.8.orig/crypto/Kconfig 2004-08-14 07:38:04.000000000 +0200
+++ linux-2.6.8/crypto/Kconfig 2004-08-24 22:58:21.000000000 +0200
@@ -9,6 +9,13 @@
help
This option provides the core Cryptographic API.
+config CRYPTO_CRYPTODEV
+ tristate "Cryptodev (/dev/crypto) interface"
+ depends on CRYPTO
+ help
+ Device /dev/crypto gives userspace programs access to
+ kernel crypto algorithms.
+
config CRYPTO_HMAC
bool "HMAC support"
depends on CRYPTO
Index: linux-2.6.8/crypto/Makefile
===================================================================
--- linux-2.6.8.orig/crypto/Makefile 2004-08-14 07:38:04.000000000 +0200
+++ linux-2.6.8/crypto/Makefile 2004-08-24 22:58:21.000000000 +0200
@@ -7,6 +7,7 @@
obj-$(CONFIG_CRYPTO) += api.o scatterwalk.o cipher.o digest.o compress.o \
$(proc-crypto-y)
+obj-$(CONFIG_CRYPTO_CRYPTODEV) += cryptodev.o
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
obj-$(CONFIG_CRYPTO_MD4) += md4.o
Index: linux-2.6.8/crypto/cryptodev.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.8/crypto/cryptodev.c 2004-08-24 23:27:09.784974592 +0200
@@ -0,0 +1,563 @@
+/*
+ * Driver for /dev/crypto device (aka CryptoDev)
+ *
+ * Copyright (c) 2004 Michal Ludvig <mludvig@suse.cz>, SuSE Labs
+ *
+ * Device /dev/crypto provides an interface for
+ * accessing kernel CryptoAPI algorithms (ciphers,
+ * hashes) from userspace programs.
+ *
+ * /dev/crypto interface was originally introduced in
+ * OpenBSD and this module attempts to keep the API,
+ * although a bit extended.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/miscdevice.h>
+#include <linux/crypto.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/random.h>
+#include <linux/cryptodev.h>
+#include <asm/uaccess.h>
+#include <asm/ioctl.h>
+#include <asm/scatterlist.h>
+
+MODULE_AUTHOR("Michal Ludvig <mludvig@suse.cz>");
+MODULE_DESCRIPTION("CryptoDev driver");
+MODULE_LICENSE("Dual BSD/GPL");
+
+/* ====== Compile-time config ====== */
+
+#define CRYPTODEV_STATS
+
+/* ====== Module parameters ====== */
+
+static int verbosity = 0;
+module_param(verbosity, int, 0644);
+MODULE_PARM_DESC(verbosity, "0: normal, 1: verbose, 2: debug");
+
+#ifdef CRYPTODEV_STATS
+static int enable_stats = 0;
+module_param(enable_stats, int, 0644);
+MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev usage");
+#endif
+
+/* ====== Debug helpers ====== */
+
+#define PFX "cryptodev: "
+#define dprintk(level,severity,format,a...) \
+ do { \
+ if (level <= verbosity) \
+ printk(severity PFX "%s[%u]: " format, \
+ current->comm, current->pid, \
+ ##a); \
+ } while (0)
+
+/* ====== CryptoAPI ====== */
+
+#define FILL_SG(sg,ptr,len) \
+ do { \
+ (sg)->page = virt_to_page(ptr); \
+ (sg)->offset = offset_in_page(ptr); \
+ (sg)->length = len; \
+ (sg)->dma_address = 0; \
+ } while (0)
+
+static char *crypto_cipher_modes[] = {
+ [CRYPTO_TFM_MODE_ECB] = "ecb",
+ [CRYPTO_TFM_MODE_CBC] = "cbc",
+ [CRYPTO_TFM_MODE_CFB] = "cfb",
+ [CRYPTO_TFM_MODE_CTR] = "ctr",
+#if 0
+ [CRYPTO_TFM_MODE_OFB] = "ofb",
+#endif
+};
+
+struct csession {
+ struct list_head entry;
+ struct semaphore sem;
+ struct crypto_tfm *tfm;
+ uint32_t sid;
+#ifdef CRYPTODEV_STATS
+#if ! ((COP_ENCRYPT < 2) && (COP_DECRYPT < 2))
+#error Struct csession.stat uses COP_{ENCRYPT,DECRYPT} as indices. Do something!
+#endif
+ unsigned long long stat[2];
+ size_t stat_max_size, stat_count;
+#endif
+};
+
+struct fcrypt {
+ struct list_head list;
+ struct semaphore sem;
+};
+
+/* Prepare session for future use. */
+static int
+crypto_create_session(struct fcrypt *fcr, struct session_op *sop)
+{
+ struct csession *ses_new, *ses_ptr;
+ struct crypto_tfm *tfm;
+ int mode, ret = 0;
+ char alg_name[MAX_ALG_NAME_LEN+1];
+ char *keyp;
+
+ /* Does the request make sense? */
+ if (!sop->cipher == !sop->mac) {
+ dprintk(1, KERN_DEBUG, "Both 'cipher' and 'mac' set or unset.\n");
+ return -EINVAL;
+ }
+
+ /* Copy-in the algorithm name if necessary. */
+ if (!sop->alg_namelen) {
+ /* Hmm, compatibility with OpenBSD CRYPTO_* constants...
+ Should we support it? */
+ dprintk(2, KERN_DEBUG, "OpenBSD constants are not (yet?) supported.\n");
+ return -EINVAL;
+ }
+
+ if(sop->alg_namelen > MAX_ALG_NAME_LEN) {
+ dprintk(1, KERN_DEBUG, "Algorithm name too long (%zu > %u)\n",
+ sop->alg_namelen, MAX_ALG_NAME_LEN);
+ return -EINVAL;
+ }
+
+ copy_from_user(alg_name, sop->alg_name, sop->alg_namelen);
+ alg_name[sop->alg_namelen] = '\0';
+
+ if(!sop->cipher) {
+ dprintk(2, KERN_DEBUG, "Hashes are not yet supported.\n");
+ return -EINVAL;
+ }
+
+ switch (sop->cipher & CRYPTO_FLAG_MASK) {
+ case CRYPTO_FLAG_ECB: mode = CRYPTO_TFM_MODE_ECB; break;
+ case CRYPTO_FLAG_CBC: mode = CRYPTO_TFM_MODE_CBC; break;
+ case CRYPTO_FLAG_CFB: mode = CRYPTO_TFM_MODE_CFB; break;
+ case CRYPTO_FLAG_CTR: mode = CRYPTO_TFM_MODE_CTR; break;
+#if 0
+ /* These modes are not yet supported. */
+ case CRYPTO_FLAG_OFB: mode = CRYPTO_TFM_MODE_OFB; break;
+#endif
+ default: return -EINVAL;
+ }
+
+ /* Set-up crypto transform. */
+ tfm = crypto_alloc_tfm(alg_name, mode);
+ if (!tfm) {
+ dprintk(1, KERN_DEBUG, "Failed to load transform for %s %s\n",
+ alg_name, crypto_cipher_modes[mode]);
+ return -EINVAL;
+ }
+
+ /* Was correct key length supplied? */
+ if ((sop->keylen < crypto_tfm_alg_min_keysize(tfm)) ||
+ (sop->keylen > crypto_tfm_alg_max_keysize(tfm))) {
+ dprintk(1, KERN_DEBUG,
+ "Wrong keylen '%zu' for algorithm '%s'. Use %u to %u.\n",
+ sop->keylen, alg_name, crypto_tfm_alg_min_keysize(tfm),
+ crypto_tfm_alg_max_keysize(tfm));
+ crypto_free_tfm(tfm);
+ return -EINVAL;
+ }
+
+ /* Copy the key from user and set to TFM. */
+ keyp = kmalloc(sop->keylen, GFP_KERNEL);
+ copy_from_user(keyp, sop->key, sop->keylen);
+ ret = crypto_cipher_setkey(tfm, keyp, sop->keylen);
+ kfree(keyp);
+ if (ret) {
+ dprintk(2, KERN_DEBUG,
+ "Setting key failed for %s-%zu-%s: flags=0x%X\n",
+ alg_name, sop->keylen*8, crypto_cipher_modes[mode],
+ tfm->crt_flags);
+ dprintk(2, KERN_DEBUG,
+ "(see CRYPTO_TFM_RES_* in <linux/crypto.h> for details)\n");
+ crypto_free_tfm(tfm);
+ return -EINVAL;
+ }
+
+ /* Create a session and put it to the list. */
+ ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
+ if(!ses_new)
+ return -ENOMEM;
+
+ memset(ses_new, 0, sizeof(*ses_new));
+ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
+ ses_new->tfm = tfm;
+ init_MUTEX(&ses_new->sem);
+
+ down(&fcr->sem);
+restart:
+ list_for_each_entry(ses_ptr, &fcr->list, entry) {
+ /* Check for duplicate SID */
+ if (unlikely(ses_new->sid == ses_ptr->sid)) {
+ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
+ /* Unless we have a broken RNG this
+ shouldn't loop forever... ;-) */
+ goto restart;
+ }
+ }
+
+ list_add(&ses_new->entry, &fcr->list);
+ up(&fcr->sem);
+
+ dprintk(2, KERN_DEBUG, "Added session 0x%08X (%s-%zu-%s)\n",
+ ses_new->sid, alg_name, sop->keylen*8, crypto_cipher_modes[mode]);
+
+ /* Fill in some values for the user. */
+ sop->ses = ses_new->sid;
+ sop->blocksize = crypto_tfm_alg_blocksize(tfm);
+
+ return 0;
+}
+
+/* Everything that needs to be done when remowing a session. */
+static inline void
+crypto_destroy_session(struct csession *ses_ptr)
+{
+ if(down_trylock(&ses_ptr->sem)) {
+ dprintk(2, KERN_DEBUG, "Waiting for semaphore of sid=0x%08X\n",
+ ses_ptr->sid);
+ down(&ses_ptr->sem);
+ }
+ dprintk(2, KERN_DEBUG, "Removed session 0x%08X\n", ses_ptr->sid);
+#if defined(CRYPTODEV_STATS)
+ if(enable_stats)
+ dprintk(2, KERN_DEBUG,
+ "Usage in Bytes: enc=%llu, dec=%llu, max=%zu, avg=%lu, cnt=%zu\n",
+ ses_ptr->stat[COP_ENCRYPT], ses_ptr->stat[COP_DECRYPT],
+ ses_ptr->stat_max_size, ses_ptr->stat_count > 0
+ ? ((unsigned long)(ses_ptr->stat[COP_ENCRYPT]+
+ ses_ptr->stat[COP_DECRYPT]) /
+ ses_ptr->stat_count) : 0,
+ ses_ptr->stat_count);
+#endif
+ crypto_free_tfm(ses_ptr->tfm);
+ ses_ptr->tfm = NULL;
+ up(&ses_ptr->sem);
+ kfree(ses_ptr);
+}
+
+/* Look up a session by ID and remove. */
+static int
+crypto_finish_session(struct fcrypt *fcr, uint32_t sid)
+{
+ struct csession *tmp, *ses_ptr;
+ struct list_head *head;
+ int ret = 0;
+
+ down(&fcr->sem);
+ head = &fcr->list;
+ list_for_each_entry_safe(ses_ptr, tmp, head, entry) {
+ if(ses_ptr->sid == sid) {
+ list_del(&ses_ptr->entry);
+ crypto_destroy_session(ses_ptr);
+ break;
+ }
+ }
+
+ if (!ses_ptr) {
+ dprintk(1, KERN_ERR, "Session with sid=0x%08X not found!\n", sid);
+ ret = -ENOENT;
+ }
+ up(&fcr->sem);
+
+ return ret;
+}
+
+/* Remove all sessions when closing the file */
+static int
+crypto_finish_all_sessions(struct fcrypt *fcr)
+{
+ struct csession *tmp, *ses_ptr;
+
+ down(&fcr->sem);
+ list_for_each_entry_safe(ses_ptr, tmp, &fcr->list, entry) {
+ list_del(&ses_ptr->entry);
+ crypto_destroy_session(ses_ptr);
+ }
+ up(&fcr->sem);
+
+ return 0;
+}
+
+/* Look up session by session ID. The returned session is locked. */
+static struct csession *
+crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid)
+{
+ struct csession *ses_ptr;
+
+ down(&fcr->sem);
+ list_for_each_entry(ses_ptr, &fcr->list, entry) {
+ if(ses_ptr->sid == sid) {
+ down(&ses_ptr->sem);
+ break;
+ }
+ }
+ up(&fcr->sem);
+
+ return ses_ptr;
+}
+
+/* This is the main crypto function - feed it with plaintext
+ and get a ciphertext (or vice versa :-) */
+static int
+crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
+{
+ char *data, *ivp;
+ char __user *src, __user *dst;
+ struct scatterlist sg;
+ struct csession *ses_ptr;
+ unsigned int ivsize;
+ size_t nbytes, bufsize;
+ int ret = 0;
+
+ nbytes = cop->len;
+
+ if (cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT) {
+ dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op);
+ return -EINVAL;
+ }
+
+ ses_ptr = crypto_get_session_by_sid(fcr, cop->ses);
+ if (!ses_ptr) {
+ dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses);
+ return -EINVAL;
+ }
+
+ if (nbytes % crypto_tfm_alg_blocksize(ses_ptr->tfm)) {
+ dprintk(1, KERN_ERR,
+ "data size (%zu) isn't a multiple of block size (%u)\n",
+ nbytes, crypto_tfm_alg_blocksize(ses_ptr->tfm));
+ ret = -EINVAL;
+ goto out_unlock;
+ }
+
+ bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes;
+ data = (char*)__get_free_page(GFP_KERNEL);
+
+ if (unlikely(!data)) {
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+ ivsize = crypto_tfm_alg_ivsize(ses_ptr->tfm);
+
+ ivp = kmalloc(ivsize, GFP_KERNEL);
+ if (unlikely(!ivp)) {
+ free_page((unsigned long)data);
+ ret = -ENOMEM;
+ goto out_unlock;
+ }
+
+ if (cop->iv) {
+ copy_from_user(ivp, cop->iv, ivsize);
+ crypto_cipher_set_iv(ses_ptr->tfm, ivp, ivsize);
+ }
+
+ src = cop->src;
+ dst = cop->dst;
+
+ while(nbytes > 0) {
+ size_t current_len = nbytes > bufsize ? bufsize : nbytes;
+
+ copy_from_user(data, src, current_len);
+
+ FILL_SG(&sg, data, current_len);
+
+ if (cop->op == COP_DECRYPT)
+ ret = crypto_cipher_decrypt(ses_ptr->tfm, &sg, &sg, current_len);
+ else
+ ret = crypto_cipher_encrypt(ses_ptr->tfm, &sg, &sg, current_len);
+
+ if (unlikely(ret)) {
+ dprintk(0, KERN_ERR, "CryptoAPI failure: flags=0x%x\n",
+ ses_ptr->tfm->crt_flags);
+ goto out;
+ }
+
+ copy_to_user(dst, data, current_len);
+
+ nbytes -= current_len;
+ src += current_len;
+ dst += current_len;
+ }
+
+#if defined(CRYPTODEV_STATS)
+ if (enable_stats) {
+ /* this is safe - we check cop->op at the function entry */
+ ses_ptr->stat[cop->op] += cop->len;
+ if (ses_ptr->stat_max_size < cop->len)
+ ses_ptr->stat_max_size = cop->len;
+ ses_ptr->stat_count++;
+ }
+#endif
+
+out:
+ free_page((unsigned long)data);
+
+ kfree(ivp);
+
+out_unlock:
+ up(&ses_ptr->sem);
+
+ return ret;
+}
+
+/* ====== /dev/crypto ====== */
+
+static int
+cryptodev_open(struct inode *inode, struct file *filp)
+{
+ struct fcrypt *fcr;
+
+ fcr = kmalloc(sizeof(*fcr), GFP_KERNEL);
+ if(!fcr)
+ return -ENOMEM;
+
+ memset(fcr, 0, sizeof(*fcr));
+ init_MUTEX(&fcr->sem);
+ INIT_LIST_HEAD(&fcr->list);
+ filp->private_data = fcr;
+
+ return 0;
+}
+
+static int
+cryptodev_release(struct inode *inode, struct file *filp)
+{
+ struct fcrypt *fcr = filp->private_data;
+
+ if(fcr) {
+ crypto_finish_all_sessions(fcr);
+ kfree(fcr);
+ filp->private_data = NULL;
+ }
+ return 0;
+}
+
+static int
+clonefd(struct file *filp)
+{
+ struct files_struct * files = current->files;
+ int fd;
+
+ fd = get_unused_fd();
+ if (fd >= 0) {
+ get_file(filp);
+ FD_SET(fd, files->open_fds);
+ fd_install(fd, filp);
+ }
+
+ return fd;
+}
+
+static int
+cryptodev_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct session_op sop;
+ struct crypt_op cop;
+ struct fcrypt *fcr = filp->private_data;
+ uint32_t ses;
+ int ret, fd;
+
+ if (!fcr)
+ BUG();
+
+ switch (cmd) {
+ case CRIOGET:
+ fd = clonefd(filp);
+ put_user(fd, (int*)arg);
+ return 0;
+
+ case CIOCGSESSION:
+ copy_from_user(&sop, (void*)arg, sizeof(sop));
+ ret = crypto_create_session(fcr, &sop);
+ if (ret)
+ return ret;
+ copy_to_user((void*)arg, &sop, sizeof(sop));
+ return 0;
+
+ case CIOCFSESSION:
+ get_user(ses, (uint32_t*)arg);
+ ret = crypto_finish_session(fcr, ses);
+ return ret;
+
+ case CIOCCRYPT:
+ copy_from_user(&cop, (void*)arg, sizeof(cop));
+ ret = crypto_run(fcr, &cop);
+ copy_to_user((void*)arg, &cop, sizeof(cop));
+ return ret;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+struct file_operations cryptodev_fops = {
+ .owner = THIS_MODULE,
+ .open = cryptodev_open,
+ .release = cryptodev_release,
+ .ioctl = cryptodev_ioctl,
+};
+
+struct miscdevice cryptodev = {
+ .minor = CRYPTODEV_MINOR,
+ .name = "crypto",
+ .fops = &cryptodev_fops,
+};
+
+static int
+cryptodev_register(void)
+{
+ int rc;
+
+ rc = misc_register (&cryptodev);
+ if (rc) {
+ printk(KERN_ERR PFX "registeration of /dev/crypto failed\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static void
+cryptodev_deregister(void)
+{
+ misc_deregister(&cryptodev);
+}
+
+/* ====== Module init/exit ====== */
+
+int __init
+init_cryptodev(void)
+{
+ int rc;
+
+ rc = cryptodev_register();
+ if (rc)
+ return rc;
+
+ printk(KERN_INFO PFX "driver loaded.\n");
+
+ return 0;
+}
+
+void __exit
+exit_cryptodev(void)
+{
+ cryptodev_deregister();
+ printk(KERN_INFO PFX "driver unloaded.\n");
+}
+
+module_init(init_cryptodev);
+module_exit(exit_cryptodev);
Index: linux-2.6.8/include/linux/cryptodev.h
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.8/include/linux/cryptodev.h 2004-08-24 23:33:09.460295632 +0200
@@ -0,0 +1,82 @@
+/*
+ * Driver for /dev/crypto device (aka CryptoDev)
+ *
+ * Copyright (c) 2004 Michal Ludvig <mludvig@suse.cz>, SuSE Labs
+ *
+ * Structures and ioctl command names were taken from
+ * OpenBSD to preserve compatibility with their API.
+ *
+ */
+
+#ifndef _CRYPTODEV_H
+#define _CRYPTODEV_H
+
+#ifndef __KERNEL__
+#include <inttypes.h>
+#endif
+
+#define CRYPTODEV_MINOR MISC_DYNAMIC_MINOR
+
+#define CRYPTO_FLAG_ECB 0x0000
+#define CRYPTO_FLAG_CBC 0x0001
+#define CRYPTO_FLAG_CFB 0x0002
+#define CRYPTO_FLAG_OFB 0x0003
+#define CRYPTO_FLAG_CTR 0x0004
+#define CRYPTO_FLAG_HMAC 0x0010
+#define CRYPTO_FLAG_MASK 0x00FF
+
+#define CRYPTO_CIPHER_NAME 0x0100
+#define CRYPTO_CIPHER_NAME_CBC (CRYPTO_CIPHER_NAME | CRYPTO_FLAG_CBC)
+#define CRYPTO_HASH_NAME 0x0200
+#define CRYPTO_HASH_NAME_HMAC (CRYPTO_HASH_NAME | CRYPTO_FLAG_HMAC)
+
+/* ioctl parameter to create a session */
+struct session_op {
+ unsigned int cipher; /* e.g. CRYPTO_DES_CBC */
+ unsigned int mac; /* e.g. CRYPTO_MD5_HMAC */
+ char *alg_name; /* set cipher=CRYPTO_CIPHER_NAME
+ or mac=CRYPTO_HASH_NAME */
+ #define MAX_ALG_NAME_LEN 128
+ size_t alg_namelen;
+
+ size_t keylen; /* cipher key */
+ char *key;
+ int mackeylen; /* mac key */
+ char *mackey;
+
+ /* Return values */
+ unsigned int blocksize; /* selected algorithm's block size */
+ uint32_t ses; /* session ID */
+};
+
+/* ioctl parameter to request a crypt/decrypt operation against a session */
+struct crypt_op {
+ uint32_t ses; /* from session_op->ses */
+ #define COP_DECRYPT 0
+ #define COP_ENCRYPT 1
+ uint32_t op; /* ie. COP_ENCRYPT */
+ uint32_t flags; /* unused */
+
+ size_t len;
+ char *src, *dst;
+ char *mac;
+ char *iv;
+};
+
+/* clone original filedescriptor */
+#define CRIOGET _IOWR('c', 100, uint32_t)
+
+/* create crypto session */
+#define CIOCGSESSION _IOWR('c', 101, struct session_op)
+
+/* finish crypto session */
+#define CIOCFSESSION _IOW('c', 102, uint32_t)
+
+/* request encryption/decryptions of a given buffer */
+#define CIOCCRYPT _IOWR('c', 103, struct crypt_op)
+
+/* ioctl()s for asym-crypto. Not yet supported. */
+#define CIOCKEY _IOWR('c', 104, void *)
+#define CIOCASYMFEAT _IOR('c', 105, uint32_t)
+
+#endif /* _CRYPTODEV_H */
^ permalink raw reply [flat|nested] 9+ messages in thread[parent not found: <20040824215351.GA9272@halcrow.us>]
* Re: [PATCH] /dev/crypto for Linux
[not found] ` <20040824215351.GA9272@halcrow.us>
@ 2004-08-25 7:37 ` Michal Ludvig
2004-08-25 14:17 ` Jeff Garzik
0 siblings, 1 reply; 9+ messages in thread
From: Michal Ludvig @ 2004-08-25 7:37 UTC (permalink / raw)
To: Michael Halcrow; +Cc: CryptoAPI List, linux-kernel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Michael Halcrow told me that:
> On Tue, Aug 24, 2004 at 11:37:27PM +0200, Michal Ludvig wrote:
>
>>attached is a driver for OpenBSD-like /dev/crypto device (aka
>>CryptoDev) that makes a way for userspace processes to access
>>ciphers provided by in-kernel CryptoAPI modules.
>
> Cool! Now if I'm interpreting this right, this is only good for
> working on up to one page worth of data at a time, right?
Of course the userspace can request encrypting any amount of data (well,
multiple of blocksize), but only at most one page at a time is copied
into the kernel, encrypted and returned back to the process' memory.
IMHO It is faster than allocating e.g. 4 MB in the kernel, copying all
of this from userspace, encrypting and returning back. That wouldn't use
the CPU cache too efficiently.
> In cryptfs, I have written some functions that essentially do what
> your FILL_SG() macro does, only it spreads across multiple sg's, if
> necessary. Do you think this might be appropriate for /dev/crypto?
As I'm currently working only on one kernel page at a time I think
FILL_SG() is sufficient. But I'm definitely interested how to use
multiple sg's at once (although I don't immediately ned it). Where can I
see these functions? Maybe thay could go to some library directly in
linux/crypto/...?
Michal Ludvig
- --
SUSE Labs mludvig@suse.cz
(+420) 296.542.396 http://www.suse.cz
Personal homepage http://www.logix.cz/michal
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFBLEGhDDolCcRbIhgRApPrAJ9ghoyWXhxnk+wUQL9evde3o5uDqgCfdde8
OsMo/MlzKifupt1+pbNovYk=
=yKGK
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] /dev/crypto for Linux
2004-08-25 7:37 ` Michal Ludvig
@ 2004-08-25 14:17 ` Jeff Garzik
2004-08-25 14:41 ` Michal Ludvig
0 siblings, 1 reply; 9+ messages in thread
From: Jeff Garzik @ 2004-08-25 14:17 UTC (permalink / raw)
To: Michal Ludvig; +Cc: Michael Halcrow, CryptoAPI List, linux-kernel
> What is it good for?
> One can build really light-weigth programs with crypto support that
> don't need any external libraries (e.g. OpenSSL) or built-in algorithms.
> Easier testing of new CryptoAPI ciphers (later also hashes and maybe
> asymmetric ciphers as well).
> Once, maybe, userspace access to crypto accelerators through kernel
> drivers.
Let's see...
1) This increases context switches over a solution that links with
libcrypto and libssl.
2) "build really lightweight programs with crypto support" implies that
you think it's a benefit to use the kernel as your crypto lib. Shared libs
3) Your proposal actually avoids existing, working hardware crypto
support such as Broadcom's hwcrypto driver which is fully supported by
openssh.
4) "open it and use ioctls to transfer data" is typically a bad idea.
ioctl(2) is a historical Unix mistake, to be avoided where possible.
read(2)/write(2) are to be used to transfer data.
Jeff
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] /dev/crypto for Linux
2004-08-25 14:17 ` Jeff Garzik
@ 2004-08-25 14:41 ` Michal Ludvig
0 siblings, 0 replies; 9+ messages in thread
From: Michal Ludvig @ 2004-08-25 14:41 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Michael Halcrow, CryptoAPI List, linux-kernel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Jeff Garzik told me that:
>
>> What is it good for? One can build really light-weigth programs
>> with crypto support that don't need any external libraries (e.g.
>> OpenSSL) or built-in algorithms. Easier testing of new CryptoAPI
>> ciphers (later also hashes and maybe asymmetric ciphers as well).
>> Once, maybe, userspace access to crypto accelerators through kernel
>> drivers.
>
> Let's see...
>
> 1) This increases context switches over a solution that links with
> libcrypto and libssl.
Indeed. It is not ment to replace libcrypto - just a possibility if needed.
> 2) "build really lightweight programs with crypto support" implies
> that you think it's a benefit to use the kernel as your crypto lib.
Yes, I think it may come handy in some scenarios. The algorithm is there
in the kernel so why not use it from the userspace?
Also (a wild guess) similar interface could provide access to some
key-management done in the kernel.
> 3) Your proposal actually avoids existing, working hardware crypto
> support such as Broadcom's hwcrypto driver which is fully supported
> by openssh.
Why avoids? I don't force OpenSSH to use it and I agree that typically
the everything-in-the-userspace is better/faster. This is just an option
for situations where no other cryptolib is available.
On my todo list is adding a module option for selecting allowed
algorithms. Something like "allow=-ALL:+aes:+sha1".
> 4) "open it and use ioctls to transfer data" is typically a bad idea.
> ioctl(2) is a historical Unix mistake, to be avoided where possible.
> read(2)/write(2) are to be used to transfer data.
Well yes, my driver actually reuses the API from OpenBSD. I have no
problem in changing (or extending) it but for now I did it this way for
easier testing with the OpenSSL cryptodev engine. This can definitely
evolve...
Michal Ludvig
- --
SUSE Labs mludvig@suse.cz
(+420) 296.542.396 http://www.suse.cz
Personal homepage http://www.logix.cz/michal
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFBLKUoDDolCcRbIhgRApyzAKDYFtdhhDWgGeOtivbzPqsLbFT4ZACaA4H0
rdxbrN0z31pNtMomjMevbZU=
=6XVI
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] /dev/crypto for Linux
2004-08-24 21:37 [PATCH] /dev/crypto for Linux Michal Ludvig
[not found] ` <20040824215351.GA9272@halcrow.us>
@ 2004-08-25 14:26 ` Christoph Hellwig
2004-08-25 15:44 ` Michal Ludvig
2004-08-25 14:42 ` Christoph Hellwig
2004-08-25 14:44 ` James Morris
3 siblings, 1 reply; 9+ messages in thread
From: Christoph Hellwig @ 2004-08-25 14:26 UTC (permalink / raw)
To: Michal Ludvig; +Cc: CryptoAPI List, linux-kernel, James Morris
> +static int verbosity = 0;
no need to initialize to 0
> +module_param(verbosity, int, 0644);
> +MODULE_PARM_DESC(verbosity, "0: normal, 1: verbose, 2: debug");
> +
> +#ifdef CRYPTODEV_STATS
whi is this not a config option?
> +static int enable_stats = 0;
as above
> + copy_from_user(alg_name, sop->alg_name, sop->alg_namelen);
this needs error checking.
> + keyp = kmalloc(sop->keylen, GFP_KERNEL);
retval checking
> + copy_from_user(keyp, sop->key, sop->keylen);
error checking
> + if(down_trylock(&ses_ptr->sem)) {
> + dprintk(2, KERN_DEBUG, "Waiting for semaphore of sid=0x%08X\n",
> + ses_ptr->sid);
> + down(&ses_ptr->sem);
> + }
just use down please
> +static int
> +clonefd(struct file *filp)
> +{
> + struct files_struct * files = current->files;
> + int fd;
> +
> + fd = get_unused_fd();
> + if (fd >= 0) {
> + get_file(filp);
> + FD_SET(fd, files->open_fds);
> + fd_install(fd, filp);
> + }
> +
> + return fd;
> +}
Yikes.
> +static int
> +cryptodev_ioctl(struct inode *inode, struct file *filp,
> + unsigned int cmd, unsigned long arg)
> +{
> + struct session_op sop;
> + struct crypt_op cop;
> + struct fcrypt *fcr = filp->private_data;
> + uint32_t ses;
> + int ret, fd;
> +
> + if (!fcr)
> + BUG();
> +
> + switch (cmd) {
> + case CRIOGET:
> + fd = clonefd(filp);
> + put_user(fd, (int*)arg);
> + return 0;
Extremly bad API. Just allow opening the device multiple times,
and get a new context each time (can be stored in file->private_data
> + case CIOCGSESSION:
> + copy_from_user(&sop, (void*)arg, sizeof(sop));
> + ret = crypto_create_session(fcr, &sop);
> + if (ret)
> + return ret;
> + copy_to_user((void*)arg, &sop, sizeof(sop));
missing error check.
> + return 0;
> +
> + case CIOCFSESSION:
> + get_user(ses, (uint32_t*)arg);
dito
> + ret = crypto_finish_session(fcr, ses);
> + return ret;
> +
> + case CIOCCRYPT:
> + copy_from_user(&cop, (void*)arg, sizeof(cop));
> + ret = crypto_run(fcr, &cop);
> + copy_to_user((void*)arg, &cop, sizeof(cop));
dito
besides the rather crappy implementation I'm not sure a crypto device
makes any sense until we have hardware accelerators, and for these this
is most likely not he right API
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] /dev/crypto for Linux
2004-08-25 14:26 ` Christoph Hellwig
@ 2004-08-25 15:44 ` Michal Ludvig
0 siblings, 0 replies; 9+ messages in thread
From: Michal Ludvig @ 2004-08-25 15:44 UTC (permalink / raw)
To: Christoph Hellwig; +Cc: CryptoAPI List, linux-kernel
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Christoph Hellwig told me that:
>>+static int
>>+clonefd(struct file *filp)
>>+{
>>+ struct files_struct * files = current->files;
>>+ int fd;
>>+
>>+ fd = get_unused_fd();
>>+ if (fd >= 0) {
>>+ get_file(filp);
>>+ FD_SET(fd, files->open_fds);
>>+ fd_install(fd, filp);
>>+ }
>>+
>>+ return fd;
>>+}
>
>
> Yikes.
>
>
>>+static int
>>+cryptodev_ioctl(struct inode *inode, struct file *filp,
>>+ unsigned int cmd, unsigned long arg)
>>+{
>>+ struct session_op sop;
>>+ struct crypt_op cop;
>>+ struct fcrypt *fcr = filp->private_data;
>>+ uint32_t ses;
>>+ int ret, fd;
>>+
>>+ if (!fcr)
>>+ BUG();
>>+
>>+ switch (cmd) {
>>+ case CRIOGET:
>>+ fd = clonefd(filp);
>>+ put_user(fd, (int*)arg);
>>+ return 0;
>
>
> Extremly bad API. Just allow opening the device multiple times,
> and get a new context each time (can be stored in file->private_data
As I already said - these are relicts from the OpenBSD API. Will be
redesigned and rewritten.
Michal Ludvig
- --
SUSE Labs mludvig@suse.cz
(+420) 296.542.396 http://www.suse.cz
Personal homepage http://www.logix.cz/michal
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFBLLPQDDolCcRbIhgRAvglAJ48SiKsO2NymzGqsn9x8EYZSoMoMQCfWqsC
t8E+AdtAgZc9Wi2Ta0xz1bs=
=emM8
-----END PGP SIGNATURE-----
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] /dev/crypto for Linux
2004-08-24 21:37 [PATCH] /dev/crypto for Linux Michal Ludvig
[not found] ` <20040824215351.GA9272@halcrow.us>
2004-08-25 14:26 ` Christoph Hellwig
@ 2004-08-25 14:42 ` Christoph Hellwig
2004-08-25 14:44 ` James Morris
3 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2004-08-25 14:42 UTC (permalink / raw)
To: Michal Ludvig; +Cc: CryptoAPI List, linux-kernel
Btw, please stop crossposting on lkml and moderated lists.
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] /dev/crypto for Linux
2004-08-24 21:37 [PATCH] /dev/crypto for Linux Michal Ludvig
` (2 preceding siblings ...)
2004-08-25 14:42 ` Christoph Hellwig
@ 2004-08-25 14:44 ` James Morris
2004-08-25 21:28 ` Bill Davidsen
3 siblings, 1 reply; 9+ messages in thread
From: James Morris @ 2004-08-25 14:44 UTC (permalink / raw)
To: Michal Ludvig; +Cc: CryptoAPI List, linux-kernel
On Tue, 24 Aug 2004, Michal Ludvig wrote:
> How does it work?
> - - Process opens /dev/crypto and with a set of ioctl() commands does what
> it wants to. I.e. obtains a crypto session, does the {enc,dec}ryption
> and finally closes the session. The sessions are bound to "struct file"
> of the open /dev/crypto and thus are automatically removed even if the
> process dies unexpectedly.
I don't think this is the way forward for the user crypto API. Rather
than using the openbsd device as a starting point, we need to look at what
is the best for Linux and work from there.
In any case, the openbsd device is the wrong model. An ioctl() based
interface is just a set of backdoor syscalls, but with weak semantics, and
a potential maintenance nightmare.
At this stage, the only real use for the device is to make it easier to
test and benchmark the crypto modules, and I'm not sure if this is enough
justification for integration with the kernel at this stage. Currently,
the tcrypt module provides a convienient way to test modules on whatever
architecture you can boot a kernel on, without the need for external
userspace packages. It also tests some specific scatterlist cases. So,
your crypto dev would not likely be considered a full replacement for
tcrypt at this stage.
I would also want to see the user API evolve with the development of
hardware crypto support, and not lock us into forever supporting some
potentially inadequate/broken model. So, any user API at this stage
should be marked experimental if it is going to be merged, if at all.
I think there are really two options for developing the user API:
1) a set of syscalls, or
2) a filesystem.
The main idea being to provide a well-structured, text-based (as far as
possible) API with strong semantics. I have a preference for a filesystem
API (and done some initial design), but have not established yet whether
it is feasible compared to the syscall approach.
I would encourage you to look at a filesystem API, as a project which
evolves with the addition of hardware support. I guess this is something
we could discuss in more detail on the crypto list rather than annoy the
lkml folk with.
- James
--
James Morris
<jmorris@redhat.com>
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: [PATCH] /dev/crypto for Linux
2004-08-25 14:44 ` James Morris
@ 2004-08-25 21:28 ` Bill Davidsen
0 siblings, 0 replies; 9+ messages in thread
From: Bill Davidsen @ 2004-08-25 21:28 UTC (permalink / raw)
To: linux-kernel
James Morris wrote:
> On Tue, 24 Aug 2004, Michal Ludvig wrote:
>
>
>>How does it work?
>>- - Process opens /dev/crypto and with a set of ioctl() commands does what
>>it wants to. I.e. obtains a crypto session, does the {enc,dec}ryption
>>and finally closes the session. The sessions are bound to "struct file"
>>of the open /dev/crypto and thus are automatically removed even if the
>>process dies unexpectedly.
>
>
> I don't think this is the way forward for the user crypto API. Rather
> than using the openbsd device as a starting point, we need to look at what
> is the best for Linux and work from there.
>
> In any case, the openbsd device is the wrong model. An ioctl() based
> interface is just a set of backdoor syscalls, but with weak semantics, and
> a potential maintenance nightmare.
>
> At this stage, the only real use for the device is to make it easier to
> test and benchmark the crypto modules, and I'm not sure if this is enough
> justification for integration with the kernel at this stage. Currently,
> the tcrypt module provides a convienient way to test modules on whatever
> architecture you can boot a kernel on, without the need for external
> userspace packages. It also tests some specific scatterlist cases. So,
> your crypto dev would not likely be considered a full replacement for
> tcrypt at this stage.
The use of this would be to provide some access to crypto for portable
programs which might be usefully run on systems which have not installed
the big libs needed for usermode crypto. And it also addresses the
reality that many people update their kernel more often than their libs,
and new methods are more likely to be available there. For a low-volume
task like encoding a key or other small chunk of data it might be that
the overhead of the system call would be no more than the memory
footprint of loading a lib to do a single operation.
And every time I see a new method in the kernel, I wonder why it's there
is users can't access it?
Don't take this as a stand to include this, I'm just being devil's
advocate and bringing up the benefits since multiple people are bringing
up the drawbacks. If this was actually going to happen it *might* be
done with a totally different interface and happen in a kernel thread or
some such. One feature of MULTICS we don't have is the ability to
execute kernel code in user mode, sort of like a shared library.
--
-bill davidsen (davidsen@tmr.com)
"The secret to procrastination is to put things off until the
last possible moment - but no longer" -me
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2004-08-25 21:34 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-08-24 21:37 [PATCH] /dev/crypto for Linux Michal Ludvig
[not found] ` <20040824215351.GA9272@halcrow.us>
2004-08-25 7:37 ` Michal Ludvig
2004-08-25 14:17 ` Jeff Garzik
2004-08-25 14:41 ` Michal Ludvig
2004-08-25 14:26 ` Christoph Hellwig
2004-08-25 15:44 ` Michal Ludvig
2004-08-25 14:42 ` Christoph Hellwig
2004-08-25 14:44 ` James Morris
2004-08-25 21:28 ` Bill Davidsen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox