2008-05-14 00:01:23

by Loc Ho

[permalink] [raw]
Subject: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

Hi Herbert,

I am re-sending this email as I don't believe it got to the mailing
list. Due to email problem, I am forward this patch on behalf of Shasi
Pulijala who worked on this user space interface for Linux CryptoAPI.
This should add support for OpenSSL. Please note that user of this patch
musts patch OpenSSL. The OpenSSL patch can be found in OCF-Linux as this
interface uses the same I/O control interface.

-Loc


>From 926bbdedff99b1e8bb25cd685cb7249ba21729d9 Mon Sep 17 00:00:00 2001
From: Shasi Pulijala <[email protected]>
Date: Thu, 8 May 2008 11:08:26 -0700
Subject: [PATCH] Add CryptoAPI User Interface Support


Signed-off-by: Shasi Pulijala <[email protected]>
---
crypto/Kconfig | 7 +
crypto/Makefile | 1 +
crypto/cryptodev.c | 1284
+++++++++++++++++++++++++++++++++++++++++++++
fs/fcntl.c | 9 +-
include/linux/cryptodev.h | 119 +++++
include/linux/fs.h | 1 +
6 files changed, 1420 insertions(+), 1 deletions(-)
create mode 100644 crypto/cryptodev.c
create mode 100644 include/linux/cryptodev.h

diff --git a/crypto/Kconfig b/crypto/Kconfig
index 69f1be6..de6d623 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -52,6 +52,13 @@ config CRYPTO_MANAGER
Create default cryptographic template instantiations such as
cbc(aes).

+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
tristate "HMAC support"
select CRYPTO_HASH
diff --git a/crypto/Makefile b/crypto/Makefile
index 85d0109..3d5251b 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -22,6 +22,7 @@ crypto_hash-objs += ahash.o
obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o

obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
+obj-$(CONFIG_CRYPTO_CRYPTODEV) += cryptodev.o
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
diff --git a/crypto/cryptodev.c b/crypto/cryptodev.c
new file mode 100644
index 0000000..9175ee0
--- /dev/null
+++ b/crypto/cryptodev.c
@@ -0,0 +1,1284 @@
+/**********************************************************************
*********
+ * cryptodev.c
+ *
+ * Linux CryptoAPI user space interface module
+ *
+ * Copyright (c) 2008 Shasi Pulijala <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * Detail Description:
+ * This file implements the /dev/crypto interface which is intended to
+ * provide user space interface to the Linux CryptoAPI.
+ *
+
************************************************************************
*******
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/fcntl.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 <linux/syscalls.h>
+#include <linux/scatterlist.h>
+#include <linux/time.h>
+#include <linux/unistd.h>
+#include <linux/rtnetlink.h>
+#include <linux/err.h>
+#include <crypto/aead.h>
+#include <crypto/authenc.h>
+#include <asm/uaccess.h>
+#include <asm/ioctl.h>
+#include <asm/scatterlist.h>
+#include <asm-powerpc/unistd.h>
+
+/**********************************************************************
*********
+ * Forward declaration
+
************************************************************************
*******
+ */
+#define CRYPTODEV_DEBUG
+
+/**********************************************************************
*********
+ * Macro declaration
+
************************************************************************
*******
+ */
+/* /dev/crypto is a char block device with majar 10 and minor below */
+#define CRYPTODEV_MINOR 70
+
+#define CRYPTODEV_UI_SUPPORT_DRIVER "0.1"
+
+/**********************************************************************
*********
+ * Module Parameters
+
************************************************************************
*******
+ */
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "0: normal, 1: verbose, 2: debug");
+
+static int sg_single;
+module_param(sg_single, int, 0644);
+MODULE_PARM_DESC(sg_single, "0: sg array list, 1: single sg entity");
+
+#ifdef CRYPTODEV_STATS
+static int enable_stats;
+module_param(enable_stats, int, 0644);
+MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev
usage");
+#endif
+
+/**********************************************************************
*********
+ * Debugging Macro's
+
************************************************************************
*******
+ */
+#define PFX "cryptodev: "
+
+#ifndef CRYPTODEV_DEBUG
+#define CRYPTODEV_HEXDUMP(b, l) \
+ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, \
+ 16, 1, (b), (l), false);
+#define CRYPTODEV_PRINTK(level, severity, format, a...)
\
+ do {
\
+ if (level <= debug)
\
+ printk(severity PFX "%s[%u]: " format,
\
+ current->comm, current->pid, ##a);
\
+ } while (0)
+#else
+#define CRYPTODEV_HEXDUMP(b, l)
+#define CRYPTODEV_PRINTK(level, severity, format, a...)
+#endif
+
+/**********************************************************************
*********
+ * Helper Structure
+
************************************************************************
*******
+ */
+#define CRYPTO_ACIPHER 0
+#define CRYPTO_AHASH 1
+#define CRYPTO_AEAD 2
+
+#define tfm_ablkcipher crt_tfm.acipher_tfm
+#define tfm_aead crt_tfm.aead_tfm
+#define tfm_ahash crt_tfm.ahash_tfm
+
+struct csession {
+ struct list_head entry;
+ struct semaphore sem;
+ union {
+ struct crypto_ablkcipher *acipher_tfm;
+ struct crypto_ahash *ahash_tfm;
+ struct crypto_aead *aead_tfm;
+ } crt_tfm;
+
+ int mode;
+ unsigned int sid;
+};
+
+/**********************************************************************
*********
+ * Table Lookup for Algorithms name(Crypto/hash name)
+ * Helper Structure
+
************************************************************************
*******
+ */
+char *algo_map_tbl[CRYPTO_ALGORITHM_MAX] = {
+ [CRYPTO_DES_CBC] = "cbc(des)",
+ [CRYPTO_3DES_CBC] = "cbc(des3_ede)",
+ [CRYPTO_MD5_HMAC] = "hmac(md5)",
+ [CRYPTO_BLF_CBC] = "cbc(blowfish)",
+ [CRYPTO_CAST_CBC] = "cbc(cast5)",
+ [CRYPTO_SKIPJACK_CBC] = "camellia",
+ [CRYPTO_MD5_HMAC] = "hmac(md5)",
+ [CRYPTO_SHA1_HMAC] = "hmac(sha1)",
+ [CRYPTO_RIPEMD160_HMAC] = "hmac(rmd160)",
+ [CRYPTO_MD5_KPDK] = "",
+ [CRYPTO_SHA1_KPDK] = "",
+ [CRYPTO_RIJNDAEL128_CBC] = "cbc(aes)",
+ [CRYPTO_AES_CBC] = "cbc(aes)",
+ [CRYPTO_ARC4] = "ecb(arc4)",
+ [CRYPTO_MD5] = "md5",
+ [CRYPTO_SHA1] = "sha1",
+ [CRYPTO_NULL_HMAC] = "",
+ [CRYPTO_NULL_CBC] = "",
+ [CRYPTO_DEFLATE_COMP] = "deflate",
+ [CRYPTO_SHA2_256_HMAC] = "hmac(sha256)",
+ [CRYPTO_SHA2_384_HMAC] = "hmac(sha384)",
+ [CRYPTO_SHA2_512_HMAC] = "hmac(sha512)",
+ [CRYPTO_CAMELLIA_CBC] = "cbc(camellia)",
+ [CRYPTO_SHA2_256] = "sha256",
+ [CRYPTO_SHA2_384] = "sha384",
+ [CRYPTO_SHA2_512] = "sha512",
+ [CRYPTO_RIPEMD160] = "rmd160",
+ [CRYPTO_AES_GCM] = "gcm(aes)",
+ [CRYPTO_AES_CCM] = "ccm(aes)",
+};
+
+struct fcrypt {
+ struct list_head list;
+ struct semaphore sem;
+};
+
+struct async_result {
+ struct completion completion;
+ int err;
+};
+
+/**********************************************************************
*********
+ * Function Declarations
+
************************************************************************
*******
+ */
+static int create_session_ablkcipher(char *alg_name,
+ struct fcrypt *fcr,
+ struct session_op *sop);
+static int create_session_ahash(char *alg_name,
+ struct fcrypt *fcr,
+ struct session_op *sop);
+static int create_session_aead(char *alg_name,
+ struct fcrypt *fcr,
+ struct session_op *sop);
+static int cryptodev_run_acipher(struct csession *ses_ptr,
+ struct crypt_op *cop);
+static int cryptodev_run_ahash(struct csession *ses_ptr,
+ struct crypt_op *cop);
+static int cryptodev_run_aead(struct csession *ses_ptr,
+ struct crypt_op *cop);
+static int sg_setup(unsigned char *addr, int bufsize, struct
scatterlist *sg,
+ int sg_single);
+
+/**********************************************************************
*********
+ * Asynchronous handling Routine
+ *
+
************************************************************************
*******
+ */
+static void cryptodev_async_complete(struct crypto_async_request *req,
int err)
+{
+ struct async_result *res = req->data;
+
+ if (err == -EINPROGRESS)
+ return;
+
+ res->err = err;
+ complete(&res->completion);
+}
+
+/**********************************************************************
*********
+ * Prepare session for future use
+ *
+
************************************************************************
*******
+ */
+static int cryptodev_create_session(struct fcrypt *fcr, struct
session_op *sop)
+{
+ char alg_name[CRYPTO_MAX_ALG_NAME];
+ int mode = -1;
+ int ret = 0;
+
+ if (sop->mac > CRYPTO_ALGORITHM_MAX ||
+ sop->cipher > CRYPTO_ALGORITHM_MAX) {
+ printk(KERN_INFO PFX "algorithm not supported or "
+ "not set\n");
+ return -EINVAL;
+ }
+
+ if (sop->cipher && sop->mac) {
+ mode = CRYPTO_AEAD;
+ printk(KERN_INFO PFX "authenc(%s,%s) (Algorithm
Chanining Mode"
+ "not yet supported", algo_map_tbl[sop->mac],
+ algo_map_tbl[sop->cipher]);
+ return -EINVAL;
+ } else if (sop->cipher) {
+ if (sop->cipher == CRYPTO_AES_GCM ||
+ sop->cipher == CRYPTO_AES_CCM)
+ mode = CRYPTO_AEAD;
+ else
+ mode = CRYPTO_ACIPHER;
+ strncpy(alg_name, algo_map_tbl[sop->cipher],
+ CRYPTO_MAX_ALG_NAME);
+ } else if (sop->mac) {
+ mode = CRYPTO_AHASH;
+ strncpy(alg_name, algo_map_tbl[sop->mac],
CRYPTO_MAX_ALG_NAME);
+ }
+
+ if (!alg_name)
+ return -EINVAL;
+
+ switch (mode) {
+ case CRYPTO_ACIPHER:
+ ret = create_session_ablkcipher(alg_name, fcr, sop);
+ break;
+ case CRYPTO_AHASH:
+ ret = create_session_ahash(alg_name, fcr, sop);
+ break;
+ case CRYPTO_AEAD:
+ ret = create_session_aead(alg_name, fcr, sop);
+ break;
+ default:
+ printk(KERN_INFO PFX "Improper Mode Set(Not
Cipher/Hash/Aead)");
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
+
+/**********************************************************************
*********
+ * Routine for Creating a Session for the Combined Mode Implementation
+ *
+
************************************************************************
*******
+ */
+static int create_session_aead(char *alg_name, struct fcrypt *fcr,
+ struct session_op *sop)
+{
+ struct csession *ses_new;
+ struct csession *ses_ptr;
+ struct crypto_aead *tfm;
+ char *keyp = NULL;
+ size_t authsize;
+ int ret = 0;
+
+ tfm = crypto_alloc_aead(alg_name, 0, 0);
+ if (IS_ERR(tfm)) {
+ printk(KERN_INFO PFX "Failed to load aead"
+ "transform for %s: %ld \n", alg_name,
PTR_ERR(tfm));
+ return -EINVAL;
+ }
+
+ crypto_aead_clear_flags(tfm, ~0);
+
+ keyp = kmalloc(sop->keylen, GFP_KERNEL);
+ if (unlikely(!keyp)) {
+ crypto_free_aead(tfm);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(keyp, sop->key, sop->keylen)) {
+ printk(KERN_INFO PFX "Copy of Key Failed from"
+ "User Space for %s\n", alg_name);
+ kfree(keyp);
+ crypto_free_aead(tfm);
+ return -EFAULT;
+ }
+
+ ret = crypto_aead_setkey(tfm, keyp, sop->keylen);
+ kfree(keyp);
+ if (ret) {
+ printk(KERN_INFO PFX
+ "Setting key failed for %s-%zu: flags=0x%X\n",
+ alg_name, sop->keylen*8,
+ crypto_aead_get_flags(tfm));
+ printk(KERN_INFO PFX
+ "(see CRYPTO_TFM_RES_* in <linux/crypto.h> "
+ "for details)\n");
+
+ crypto_free_aead(tfm);
+ return -EINVAL;
+ }
+
+ /* Supporting Authsize for ccm and gcm from mackeylen
+ (no separate field for authsize) */
+ authsize = sop->mackeylen;
+ ret = crypto_aead_setauthsize(tfm, authsize);
+ if (ret) {
+ printk(KERN_INFO "failed to set authsize = %u\n",
authsize);
+ crypto_free_aead(tfm);
+ return -EINVAL;
+ }
+
+ ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
+ if (!ses_new) {
+ crypto_free_aead(tfm);
+ return -ENOMEM;
+ }
+
+ memset(ses_new, 0, sizeof(*ses_new));
+ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
+ ses_new->tfm_aead = tfm;
+
+ ses_new->mode = CRYPTO_AEAD;
+ 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));
+ goto restart;
+ }
+ }
+
+ list_add(&ses_new->entry, &fcr->list);
+ up(&fcr->sem);
+
+ sop->ses = ses_new->sid;
+
+ return 0;
+}
+
+/**********************************************************************
*********
+ * Routine for Creating a Session for the Hash Implementation
+ *
+
************************************************************************
*******
+ */
+static int create_session_ahash(char *alg_name, struct fcrypt *fcr,
+ struct session_op *sop)
+{
+ struct csession *ses_new;
+ struct csession *ses_ptr;
+ struct crypto_ahash *tfm;
+ char *keyp = NULL;
+ int ret = 0;
+
+ tfm = crypto_alloc_ahash(alg_name, 0, 0);
+ if (IS_ERR(tfm)) {
+ printk(KERN_INFO PFX "Failed to load ahash "
+ "transform for %s: %ld \n", alg_name,
PTR_ERR(tfm));
+ return -EINVAL;
+ }
+ crypto_ahash_clear_flags(tfm, ~0);
+
+ /* Copy the key(hmac) from user and set to TFM. */
+ if (sop->mackey && (sop->mac != CRYPTO_MD5) && (sop->mac !=
CRYPTO_SHA1)
+ && (sop->mac != CRYPTO_SHA2_256)
+ && (sop->mac != CRYPTO_SHA2_384)
+ && (sop->mac != CRYPTO_SHA2_512)
+ && (sop->mac != CRYPTO_RIPEMD160)) {
+ keyp = kmalloc(sop->mackeylen, GFP_KERNEL);
+ if (unlikely(!keyp)) {
+ crypto_free_ahash(tfm);
+ return -ENOMEM;
+ }
+
+ if (copy_from_user(keyp, sop->mackey, sop->mackeylen)) {
+ printk(KERN_INFO PFX "Copy of Key Failed from
User"
+ "space for %s\n", alg_name);
+ kfree(keyp);
+ crypto_free_ahash(tfm);
+ return -EFAULT;
+ }
+
+ ret = crypto_ahash_setkey(tfm, keyp, sop->mackeylen);
+ kfree(keyp);
+ if (ret) {
+ printk(KERN_INFO PFX
+ "Setting key failed for %s-%zu:
flags=0x%X\n",
+ alg_name, sop->mackeylen * 8,
+ crypto_ahash_get_flags(tfm));
+ printk(KERN_INFO PFX
+ "(see CRYPTO_TFM_RES_* in "
+ "<linux/crypto.h> for details)\n");
+
+ crypto_free_ahash(tfm);
+ return -EINVAL;
+ }
+ }
+
+ ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
+ if (!ses_new) {
+ crypto_free_ahash(tfm);
+ return -ENOMEM;
+ }
+
+ memset(ses_new, 0, sizeof(*ses_new));
+ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
+ ses_new->tfm_ahash = tfm;
+
+ ses_new->mode = CRYPTO_AHASH;
+ 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));
+ goto restart;
+ }
+ }
+ list_add(&ses_new->entry, &fcr->list);
+ up(&fcr->sem);
+
+ /* Fill in some values for the user. */
+ sop->ses = ses_new->sid;
+
+ return 0;
+}
+
+/**********************************************************************
*********
+ * Routine for Creating a Session for the Crypto Implementation
+ *
+
************************************************************************
*******
+ */
+static int create_session_ablkcipher(char *alg_name, struct fcrypt
*fcr,
+ struct session_op *sop)
+{
+ struct csession *ses_new, *ses_ptr;
+ struct crypto_ablkcipher *tfm;
+ char *keyp = NULL;
+ int ret = 0;
+
+ tfm = crypto_alloc_ablkcipher(alg_name, 0, 0);
+ if (IS_ERR(tfm)) {
+ printk(KERN_INFO PFX "Failed to load crypto "
+ "transform for %s: %ld\n", alg_name,
PTR_ERR(tfm));
+ return -EINVAL;
+ }
+
+ crypto_ablkcipher_clear_flags(tfm, ~0);
+
+ /* Copy the key from user and set to TFM. */
+ keyp = kmalloc(sop->keylen, GFP_KERNEL);
+ if (unlikely(!keyp)) {
+ crypto_free_ablkcipher(tfm);
+ return -ENOMEM;
+
+ }
+
+ if (copy_from_user(keyp, sop->key, sop->keylen)) {
+ printk(KERN_INFO PFX "Copy of Key Failed from User"
+ "space for %s\n", alg_name);
+ kfree(keyp);
+ crypto_free_ablkcipher(tfm);
+ return -EFAULT;
+ }
+
+ ret = crypto_ablkcipher_setkey(tfm, keyp, sop->keylen);
+ kfree(keyp);
+ if (ret) {
+ printk(KERN_INFO PFX
+ "Setting key failed for %s-%zu: flags=0x%X\n",
+ alg_name, sop->keylen*8,
+ crypto_ablkcipher_get_flags(tfm));
+ printk(KERN_INFO PFX
+ "(see CRYPTO_TFM_RES_* in <linux/crypto.h> for "
+ "details)\n");
+
+ crypto_free_ablkcipher(tfm);
+ return -EINVAL;
+ }
+
+ ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
+ if (!ses_new) {
+ crypto_free_ablkcipher(tfm);
+ return -ENOMEM;
+ }
+
+ memset(ses_new, 0, sizeof(*ses_new));
+ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
+ ses_new->tfm_ablkcipher = tfm;
+
+ ses_new->mode = CRYPTO_ACIPHER;
+ 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));
+ goto restart;
+ }
+ }
+ list_add(&ses_new->entry, &fcr->list);
+ up(&fcr->sem);
+
+ /* Fill in some values for the user. */
+ sop->ses = ses_new->sid;
+
+ return 0;
+}
+
+/**********************************************************************
*********
+ * Everything that needs to be done when removing a session.
+ *
+
************************************************************************
*******
+ */
+static inline void cryptodev_destroy_session(struct csession *ses_ptr)
+{
+ if (down_trylock(&ses_ptr->sem)) {
+ CRYPTODEV_PRINTK(2, KERN_DEBUG,
+ "Waiting for semaphore of sid=0x%08X\n",
+ ses_ptr->sid);
+ down(&ses_ptr->sem);
+ }
+ CRYPTODEV_PRINTK(2, KERN_DEBUG, "Removed session 0x%08X\n",
+ ses_ptr->sid);
+
+ /* Check for mode and then delete */
+ switch (ses_ptr->mode) {
+ case CRYPTO_ACIPHER:
+ crypto_free_ablkcipher(ses_ptr->tfm_ablkcipher);
+ ses_ptr->tfm_ablkcipher = NULL;
+ break;
+ case CRYPTO_AHASH:
+ crypto_free_ahash(ses_ptr->tfm_ahash);
+ ses_ptr->tfm_ahash = NULL;
+ break;
+ case CRYPTO_AEAD:
+ crypto_free_aead(ses_ptr->tfm_aead);
+ ses_ptr->tfm_aead = NULL;
+ break;
+ }
+ up(&ses_ptr->sem);
+ kfree(ses_ptr);
+}
+
+/**********************************************************************
*********
+ * Look up a session by ID and remove.
+ *
+
************************************************************************
*******
+ */
+static int cryptodev_finish_session(struct fcrypt *fcr, u32 sid)
+{
+ struct csession *tmp;
+ struct csession *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);
+ cryptodev_destroy_session(ses_ptr);
+ break;
+ }
+ }
+
+ if (!ses_ptr) {
+ CRYPTODEV_PRINTK(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 cryptodev_finish_all_sessions(struct fcrypt *fcr)
+{
+ struct csession *tmp;
+ struct csession *ses_ptr;
+
+ down(&fcr->sem);
+ list_for_each_entry_safe(ses_ptr, tmp, &fcr->list, entry) {
+ list_del(&ses_ptr->entry);
+ cryptodev_destroy_session(ses_ptr);
+ }
+ up(&fcr->sem);
+
+ return 0;
+}
+
+/**********************************************************************
*********
+ * Look up session by session ID. The returned session is locked.
+
************************************************************************
*******
+ */
+static struct csession *cryptodev_get_session_by_sid(struct fcrypt
*fcr,
+ u32 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;
+}
+
+static void cryptodev_release_session(struct csession *session)
+{
+ if (session)
+ up(&session->sem);
+}
+
+/**********************************************************************
*********
+ * This is the main crypto function - feed it with plaintext
+ * and get a ciphertext
+
************************************************************************
*******
+ */
+static int cryptodev_run(struct fcrypt *fcr, struct crypt_op *cop)
+{
+
+ struct csession *ses_ptr;
+ int ret = 0;
+
+ if (cop->op &&
+ (cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
+ printk(KERN_INFO PFX "invalid operation op=%u\n",
cop->op);
+ return -EINVAL;
+ }
+
+ ses_ptr = cryptodev_get_session_by_sid(fcr, cop->ses);
+ if (!ses_ptr) {
+ printk(KERN_INFO PFX "invalid session ID=0x%08X\n",
cop->ses);
+ return -EINVAL;
+ }
+
+ switch (ses_ptr->mode) {
+ case CRYPTO_ACIPHER:
+ ret = cryptodev_run_acipher(ses_ptr, cop);
+ break;
+ case CRYPTO_AHASH:
+ ret = cryptodev_run_ahash(ses_ptr, cop);
+ break;
+ case CRYPTO_AEAD:
+ ret = cryptodev_run_aead(ses_ptr, cop);
+ break;
+ }
+ cryptodev_release_session(ses_ptr);
+
+ return ret;
+
+}
+
+/**********************************************************************
*********
+ * This is the routine that splits the user buffer data over
+ * pages and creates scatterlist
+
************************************************************************
*******
+ */
+static int sg_setup(unsigned char *data, int bufsize, struct
scatterlist *sg,
+ int sg_single)
+{
+ int sg_size, remainder_of_page;
+ int i = 0;
+
+ if (sg_single || (!bufsize)) {
+ sg_set_buf(&sg[0], data, bufsize);
+ return 1;
+ }
+ sg_size = bufsize % PAGE_SIZE == 0 ? bufsize/PAGE_SIZE :
+ bufsize/PAGE_SIZE + 1;
+ sg_init_table(sg, sg_size);
+
+ while (bufsize > 0 && i < sg_size) {
+ sg_set_buf(&sg[i], data, bufsize);
+ remainder_of_page = PAGE_SIZE - sg[i].offset;
+ if (bufsize > remainder_of_page) {
+ /* the buffer was split over multiple pages */
+ sg[i].length = remainder_of_page;
+ bufsize -= remainder_of_page;
+ data += remainder_of_page;
+ } else {
+ bufsize = 0;
+ }
+ i++;
+ }
+ sg_mark_end(&sg[sg_size - 1]);
+
+ return sg_size;
+}
+
+/**********************************************************************
*********
+ * This is the actual aead function that implements
+ * the Combined mode
+
************************************************************************
*******
+ */
+static int cryptodev_run_aead(struct csession *ses_ptr, struct crypt_op
*cop)
+{
+ char *data = NULL;
+ char *ivp = NULL;
+ char __user *src;
+ char __user *dst;
+ struct scatterlist sg[16];
+ struct scatterlist asg[1];
+ struct aead_request *req;
+ struct async_result result;
+ size_t bufsize;
+ size_t ivsize;
+ size_t order;
+ size_t authsize;
+ int ret = 0;
+ int nsg = 0;
+
+ /* Checking the Input Length */
+ bufsize = cop->len;
+ if (cop->len > CRYPTO_MAX_DATA_LEN) {
+ printk(KERN_INFO PFX "Maximum Data Size Exceeded: %d >
%d\n",
+ cop->len, CRYPTO_MAX_DATA_LEN);
+ return -E2BIG;
+ }
+
+ init_completion(&result.completion);
+
+ /* Setting the resquest */
+ req = aead_request_alloc(ses_ptr->tfm_aead, GFP_KERNEL);
+ if (!req) {
+ printk(KERN_INFO PFX "failed to allocate request");
+ return -EINVAL;
+ }
+
+ order = get_order(bufsize);
+ data = (char *) __get_free_pages(GFP_KERNEL, order);
+
+ if (unlikely(!data)) {
+ ret = -ENOMEM;
+ goto out_req;
+ }
+
+ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ cryptodev_async_complete, &result);
+
+ src = cop->src;
+ dst = cop->dst;
+
+ authsize = crypto_aead_authsize(ses_ptr->tfm_aead);
+
+ if (copy_from_user(data, src, bufsize)) {
+ printk(KERN_INFO PFX "Copy of src data Failed from User"
+ "space for aead\n");
+ free_pages((unsigned long)data, order);
+ ret = -EFAULT;
+ goto out_req;
+ }
+
+ ivsize = crypto_aead_ivsize(ses_ptr->tfm_aead);
+
+ ivp = kmalloc(ivsize, GFP_KERNEL);
+ if (unlikely(!ivp)) {
+ free_pages((unsigned long)data, order);
+ ret = -ENOMEM;
+ goto out_req;
+ }
+
+ memset(ivp, 0, ivsize);
+ if (cop->iv && copy_from_user(ivp, cop->iv, ivsize)) {
+ printk(KERN_INFO PFX "Copy of src iv Failed from User "
+ "space for aead\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ nsg = sg_setup(data, bufsize + authsize, sg, sg_single);
+ if (!nsg) {
+ printk("Scatter Allocation failed err due to improper"
+ "sg size");
+ goto out;
+ }
+
+ /* Additional Associated data set to 0 bytes */
+ sg_init_one(&asg[0], ivp, 0);
+
+ aead_request_set_crypt(req, sg, sg, bufsize, ivp);
+ aead_request_set_assoc(req, asg, 0);
+
+ if (cop->op == COP_ENCRYPT)
+ ret = crypto_aead_encrypt(req);
+ else
+ ret = crypto_aead_decrypt(req);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ case -EBUSY:
+ ret = wait_for_completion_interruptible(
+ &result.completion);
+ if (!ret)
+ ret = result.err;
+ if (!ret) {
+ INIT_COMPLETION(result.completion);
+ break;
+ }
+ /* fall through */
+ default:
+ printk("%s () failed err=%d\n", "enc/dec", -ret);
+ goto out;
+ }
+
+ CRYPTODEV_HEXDUMP(data, bufsize + authsize);
+ if (copy_to_user(dst, data, bufsize + authsize)) {
+ printk(KERN_INFO PFX "Copy of enc data Failed to User"
+ "space for aead\n");
+ ret = -EFAULT;
+ }
+
+out:
+ free_pages((unsigned long)data, order);
+ kfree(ivp);
+
+out_req:
+ aead_request_free(req);
+
+ return ret;
+}
+
+/**********************************************************************
*********
+ * This is the actual hash function that creates the
+ * authenticated data
+
************************************************************************
*******
+ */
+static int cryptodev_run_ahash(struct csession *ses_ptr, struct
crypt_op *cop)
+{
+
+ char *data = NULL;
+ char __user *src;
+ char __user *mac;
+ struct scatterlist sg[16];
+ struct ahash_request *req;
+ struct async_result result;
+ size_t authsize;
+ size_t bufsize;
+ size_t order;
+ int ret = 0;
+ int nsg = 0;
+ char digest_result[64];
+
+ /* Checking the Input Length */
+ bufsize = cop->len;
+ if (cop->len > CRYPTO_MAX_DATA_LEN) {
+ printk(KERN_INFO PFX "Maximum Data Size Exceeded: %d >
%d\n",
+ cop->len, CRYPTO_MAX_DATA_LEN);
+ return -E2BIG;
+ }
+
+ init_completion(&result.completion);
+
+ /* Setting the resquest */
+ req = ahash_request_alloc(ses_ptr->tfm_ahash, GFP_KERNEL);
+ if (!req) {
+ printk(KERN_INFO PFX "failed to allocate request");
+ return -EINVAL;
+ }
+
+ order = (!bufsize) ? 0 : get_order(bufsize);
+ data = (char *) __get_free_pages(GFP_KERNEL, order);
+
+ if (unlikely(!data)) {
+ printk(KERN_INFO PFX "Improper data size "
+ "set = %d\n", bufsize);
+ ret = -ENOMEM;
+ goto out_req;
+ }
+
+ authsize = crypto_ahash_digestsize(ses_ptr->tfm_ahash);
+ memset(digest_result, 0, 64);
+
+ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ cryptodev_async_complete,
&result);
+
+ src = cop->src;
+ mac = cop->mac;
+
+ if (copy_from_user(data, src, bufsize)) {
+ printk(KERN_INFO PFX "Copy of src data Failed from User"
+ "space for hash\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ nsg = sg_setup(data, bufsize, sg, sg_single);
+ if (!nsg) {
+ printk("Scatter Allocation () failed err=%d\n", nsg);
+ goto out;
+ }
+
+ ahash_request_set_crypt(req, sg, digest_result, bufsize);
+ ret = crypto_ahash_digest(req);
+
+ switch (ret) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ case -EBUSY:
+ ret = wait_for_completion_interruptible(
+ &result.completion);
+ if (!ret)
+ ret = result.err;
+ if (!ret) {
+ INIT_COMPLETION(result.completion);
+ break;
+ }
+ /* fall through */
+ default:
+ printk(KERN_INFO PFX "%s failed err=%d\n", "enc/dec",
-ret);
+ goto out;
+ }
+
+ CRYPTODEV_HEXDUMP(digest_result, authsize);
+ if (copy_to_user(mac, digest_result, authsize)) {
+ printk(KERN_INFO PFX "Copy of mac data Failed to User"
+ "space for hash\n");
+ ret = -EFAULT;
+ }
+
+out:
+ free_pages((unsigned long)data, order);
+
+out_req:
+ ahash_request_free(req);
+
+ return ret;
+}
+
+/**********************************************************************
*********
+ * This is the actual crypto function that creates the
+ * encrypted or decrypted data
+
************************************************************************
*******
+ */
+static int cryptodev_run_acipher(struct csession *ses_ptr, struct
crypt_op *cop)
+{
+ char *data = NULL;
+ char *ivp = NULL;
+ char __user *src;
+ char __user *dst;
+ struct scatterlist sg[16];
+ struct ablkcipher_request *req;
+ struct async_result result;
+ size_t bufsize;
+ size_t ivsize;
+ size_t order;
+ int ret = 0;
+ int nsg = 0;
+
+ /* Checking the Input Length */
+ bufsize = cop->len;
+ if (cop->len > CRYPTO_MAX_DATA_LEN) {
+ printk(KERN_INFO PFX "Maximum Data Size Exceeded: %d >
%d\n",
+ cop->len, CRYPTO_MAX_DATA_LEN);
+ return -E2BIG;
+ }
+
+ init_completion(&result.completion);
+
+ /* Setting the request */
+ req = ablkcipher_request_alloc(ses_ptr->tfm_ablkcipher,
GFP_KERNEL);
+ if (!req) {
+ printk(KERN_INFO PFX "failed to allocate request\n");
+ return -EINVAL;
+ }
+
+ if (bufsize %
crypto_ablkcipher_blocksize(ses_ptr->tfm_ablkcipher)) {
+ printk(KERN_INFO PFX
+ "data size (%zu) isn't a multiple of block size
(%u)\n",
+ bufsize, crypto_ablkcipher_blocksize
+ (ses_ptr->tfm_ablkcipher));
+ ret = -EINVAL;
+ goto out_req;
+ }
+
+ order = get_order(bufsize);
+ data = (char *) __get_free_pages(GFP_KERNEL, order);
+
+ if (unlikely(!data)) {
+ ret = -ENOMEM;
+ goto out_req;
+ }
+
+ ivsize = crypto_ablkcipher_ivsize(ses_ptr->tfm_ablkcipher);
+
+ ivp = kmalloc(ivsize, GFP_KERNEL);
+ if (unlikely(!ivp)) {
+ free_pages((unsigned long)data, order);
+ ret = -ENOMEM;
+ goto out_req;
+ }
+
+ memset(ivp, 0, ivsize);
+ if (cop->iv && copy_from_user(ivp, cop->iv, ivsize)) {
+ printk(KERN_INFO PFX "Copy of src iv Failed from User "
+ "space for crypto\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+ cryptodev_async_complete,
&result);
+
+ src = cop->src;
+ dst = cop->dst;
+
+ if (copy_from_user(data, src, bufsize)) {
+ printk(KERN_INFO PFX "Copy of src data Failed from User"
+ "space for crypto\n");
+ ret = -EFAULT;
+ goto out;
+ }
+
+ nsg = sg_setup(data, bufsize, sg, sg_single);
+ if (!nsg) {
+ printk(KERN_INFO PFX "Scatter Allocation failed
err=%d\n",
+ nsg);
+ goto out;
+ }
+ ablkcipher_request_set_crypt(req, sg, sg, bufsize, ivp);
+
+ if (cop->op == COP_ENCRYPT)
+ ret = crypto_ablkcipher_encrypt(req);
+ else
+ ret = crypto_ablkcipher_decrypt(req);
+ switch (ret) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ case -EBUSY:
+ ret = wait_for_completion_interruptible(
+ &result.completion);
+ if (!ret)
+ ret = result.err;
+ if (!ret) {
+ INIT_COMPLETION(result.completion);
+ break;
+ }
+ /* fall through */
+ default:
+ printk(KERN_INFO PFX "%s failed err=%d\n", "enc/dec",
-ret);
+ goto out;
+ }
+
+ CRYPTODEV_HEXDUMP(data, bufsize);
+ if (copy_to_user(dst, data, bufsize)) {
+ printk(KERN_INFO PFX "Copy of enc data Failed to User"
+ "space for crypto\n");
+ ret = -EFAULT;
+ }
+
+out:
+ free_pages((unsigned long)data, order);
+ kfree(ivp);
+
+out_req:
+ ablkcipher_request_free(req);
+
+ return ret;
+}
+
+
/***********************************************************************
******
+ * /dev/crypto function operation functions
+
************************************************************************
******
+ */
+static int cryptodev_clonefd(struct file *filp)
+{
+ mm_segment_t fs;
+ int fd;
+
+ fs = get_fs();
+ set_fs(get_ds());
+ for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++)
+ if (files_fdtable(current->files)->fd[fd] == filp)
+ break;
+ fd = __sys_dup(fd);
+ set_fs(fs);
+ return fd;
+}
+
+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) {
+ cryptodev_finish_all_sessions(fcr);
+ kfree(fcr);
+ filp->private_data = NULL;
+ }
+ return 0;
+}
+
+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;
+ unsigned int ses;
+ int ret;
+ int fd, feat;
+
+ if (!fcr)
+ BUG();
+
+ switch (cmd) {
+ case CRIOGET:
+ fd = cryptodev_clonefd(filp);
+ put_user(fd, (int *) arg);
+ return IS_ERR_VALUE(fd) ? fd : 0;
+
+ case CIOCGSESSION:
+ if (copy_from_user(&sop, (void *) arg, sizeof(sop))) {
+ printk(KERN_INFO PFX "Copy of Session data
failed"
+ "at CIOCGSESSION from user space\n");
+ return -EFAULT;
+ }
+ ret = cryptodev_create_session(fcr, &sop);
+ if (ret)
+ return ret;
+ if (copy_to_user((void *)arg, &sop, sizeof(sop))) {
+ printk(KERN_INFO PFX "Copy of Session data
failed"
+ "at CIOCGSESSION to user space\n");
+ return -EFAULT;
+ }
+ return 0;
+
+ case CIOCFSESSION:
+ get_user(ses, (u32 *) arg);
+ return cryptodev_finish_session(fcr, ses);
+
+ case CIOCCRYPT:
+ if (copy_from_user(&cop, (void *) arg, sizeof(cop))) {
+ printk(KERN_INFO PFX "Copy of src data failed"
+ "at CIOCCRYPT from user space\n");
+ return -EFAULT;
+ }
+ ret = cryptodev_run(fcr, &cop);
+ if (copy_to_user((void *) arg, &cop, sizeof(cop))) {
+ printk(KERN_INFO PFX "Copy of enc/dec/hash data
failed"
+ "at CIOCCRYPT to user space\n");
+ return -EFAULT;
+ }
+ return ret;
+
+ case CIOCASYMFEAT:
+ /* No Asymmetric Algorithms Supported */
+ feat = 0;
+ if (copy_to_user((void *)arg, &feat, sizeof(feat))) {
+ printk(KERN_INFO PFX "Copy of asymm algorithm
data"
+ " failed at CIOCASYMFEAT to user
space\n");
+ return -EFAULT;
+ }
+ return 0;
+
+ default:
+ printk(KERN_ERR PFX "un-supported command 0x%08X\n",
cmd);
+ 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 "CryptoAPI driver v%s loaded\n",
+ CRYPTODEV_UI_SUPPORT_DRIVER);
+
+ return 0;
+}
+
+void __exit exit_cryptodev(void)
+{
+ cryptodev_deregister();
+ printk(KERN_INFO PFX "CryptoAPI driver v%s unloaded\n",
+ CRYPTODEV_UI_SUPPORT_DRIVER);
+}
+
+module_init(init_cryptodev);
+module_exit(exit_cryptodev);
+
+MODULE_AUTHOR("Shasi Pulijala <[email protected]>");
+MODULE_DESCRIPTION("CryptoDev driver");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/fs/fcntl.c b/fs/fcntl.c
index e632da7..5afec53 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -137,6 +137,7 @@ static int dupfd(struct file *file, unsigned int
start, int cloexec)
return fd;
}

+
asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
{
int err = -EBADF;
@@ -193,7 +194,7 @@ out_fput:
goto out;
}

-asmlinkage long sys_dup(unsigned int fildes)
+asmlinkage long __sys_dup(unsigned int fildes)
{
int ret = -EBADF;
struct file * file = fget(fildes);
@@ -202,6 +203,12 @@ asmlinkage long sys_dup(unsigned int fildes)
ret = dupfd(file, 0, 0);
return ret;
}
+EXPORT_SYMBOL(__sys_dup);
+
+asmlinkage long sys_dup(unsigned int fildes)
+{
+ return __sys_dup(fildes);
+}

#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC |
O_DIRECT | O_NOATIME)

diff --git a/include/linux/cryptodev.h b/include/linux/cryptodev.h
new file mode 100644
index 0000000..46466d4
--- /dev/null
+++ b/include/linux/cryptodev.h
@@ -0,0 +1,119 @@
+/**********************************************************************
*********
+ * cryptodev.h
+ *
+ * Linux CryptoAPI user space interface module
+ *
+ * Copyright (c) 2008 Shasi Pulijala <[email protected]>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * Detail Description:
+ * This file defines ioctl structures for the Linux CryptoAPI
interface. It
+ * provides user space applications accesss into the Linux CryptoAPI
+ * functionalities.
+ *
+
************************************************************************
*******
+ */
+#ifndef __CRYPTODEV_H__
+#define __CRYPTODEV_H__
+
+/* Crypto and Hash Algorithms */
+
+#define CRYPTO_ALGORITHM_MIN 1
+#define CRYPTO_DES_CBC 1
+#define CRYPTO_3DES_CBC 2
+#define CRYPTO_BLF_CBC 3
+#define CRYPTO_CAST_CBC 4
+#define CRYPTO_SKIPJACK_CBC 5
+#define CRYPTO_MD5_HMAC 6
+#define CRYPTO_SHA1_HMAC 7
+#define CRYPTO_RIPEMD160_HMAC 8
+#define CRYPTO_MD5_KPDK 9
+#define CRYPTO_SHA1_KPDK 10
+#define CRYPTO_RIJNDAEL128_CBC 11 /* 128 bit blocksize */
+#define CRYPTO_AES_CBC 11 /* 128 bit blocksize */
+#define CRYPTO_ARC4 12
+#define CRYPTO_MD5 13
+#define CRYPTO_SHA1 14
+#define CRYPTO_NULL_HMAC 15
+#define CRYPTO_NULL_CBC 16
+#define CRYPTO_DEFLATE_COMP 17 /* Deflate compression
algorithm */
+#define CRYPTO_SHA2_256_HMAC 18
+#define CRYPTO_SHA2_384_HMAC 19
+#define CRYPTO_SHA2_512_HMAC 20
+#define CRYPTO_CAMELLIA_CBC 21
+#define CRYPTO_SHA2_256 22
+#define CRYPTO_SHA2_384 23
+#define CRYPTO_SHA2_512 24
+#define CRYPTO_RIPEMD160 25
+#define CRYPTO_AES_GCM 26
+#define CRYPTO_AES_CCM 27
+#define CRYPTO_ALGORITHM_MAX 28 /* Keep last */
+
+/**
+ * @struct session_op
+ * @brief ioctl parameter to create a session
+ *
+
************************************************************************
*******
+ */
+struct session_op {
+ u32 cipher; /* e.g. CRYPTO_DES_CBC
*/
+ u32 mac; /* e.g. CRYPTO_MD5_HMAC
*/
+ u32 keylen; /* cipher key */
+ char *key;
+ int mackeylen; /* mac key length*/
+ char *mackey; /* mackey(hmac)/authsize
+ (ccm, gcm) */
+
+ /* Return values */
+ u32 ses; /* session ID */
+};
+
+#define CRYPTO_MAX_DATA_LEN 64*1024 - 1
+/**
+ * @struct crypt_op
+ * @brief ioctl parameter to request a crypt/decrypt operation against
a session
+ *
+
************************************************************************
*******
+ */
+struct crypt_op {
+ u32 ses;
+ u16 op; /* i.e. COP_ENCRYPT */
+#define COP_NONE 0
+#define COP_ENCRYPT 1
+#define COP_DECRYPT 2
+ u16 flags;
+#define COP_F_BATCH 0x0008 /* Batch op if
possible */
+ u_int len;
+ caddr_t src, dst; /* become sg inside
kernel */
+ caddr_t mac; /* must be big enough
for
+ chosen MAC */
+ caddr_t iv;
+};
+
+/* clone original filedescriptor */
+#define CRIOGET _IOWR('c', 100, unsigned int)
+
+/* create crypto session */
+#define CIOCGSESSION _IOWR('c', 101, struct session_op)
+
+/* finish crypto session */
+#define CIOCFSESSION _IOW('c', 102, unsigned int)
+
+/* 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, unsigned int)
+
+#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b84b848..e9dc39e 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -962,6 +962,7 @@ extern void __kill_fasync(struct fasync_struct *,
int, int);

extern int __f_setown(struct file *filp, struct pid *, enum pid_type,
int force);
extern int f_setown(struct file *filp, unsigned long arg, int force);
+extern long __sys_dup(unsigned int fildes);
extern void f_delown(struct file *filp);
extern pid_t f_getown(struct file *filp);
extern int send_sigurg(struct fown_struct *fown);
--
1.5.4.4


Subject: Re: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

* Loc Ho | 2008-05-13 17:00:58 [-0700]:

>I am re-sending this email as I don't believe it got to the mailing
>list. Due to email problem, I am forward this patch on behalf of Shasi
>Pulijala who worked on this user space interface for Linux CryptoAPI.
If you forward patches, you should put your sign-of there as well (so
you would have two).

>This should add support for OpenSSL. Please note that user of this patch
>musts patch OpenSSL. The OpenSSL patch can be found in OCF-Linux as this
>interface uses the same I/O control interface.
So this interface must stay as it in order not to patch openssl twice?

>
>-Loc
Loc, if you want to send patches that are proper formated please use
git-send-email (this patch looks like it is comming straight from
git-format-patch). You can specify there a smtp server.

There are a few comments below.

>From 926bbdedff99b1e8bb25cd685cb7249ba21729d9 Mon Sep 17 00:00:00 2001
>From: Shasi Pulijala <[email protected]>
>Date: Thu, 8 May 2008 11:08:26 -0700
>Subject: [PATCH] Add CryptoAPI User Interface Support
>
>
>Signed-off-by: Shasi Pulijala <[email protected]>
>---
> crypto/Kconfig | 7 +
> crypto/Makefile | 1 +
> crypto/cryptodev.c | 1284
>+++++++++++++++++++++++++++++++++++++++++++++
> fs/fcntl.c | 9 +-
> include/linux/cryptodev.h | 119 +++++
> include/linux/fs.h | 1 +
> 6 files changed, 1420 insertions(+), 1 deletions(-)
> create mode 100644 crypto/cryptodev.c
> create mode 100644 include/linux/cryptodev.h
>
>diff --git a/crypto/Kconfig b/crypto/Kconfig
>index 69f1be6..de6d623 100644
>--- a/crypto/Kconfig
>+++ b/crypto/Kconfig
>@@ -52,6 +52,13 @@ config CRYPTO_MANAGER
> Create default cryptographic template instantiations such as
> cbc(aes).
>
>+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
> tristate "HMAC support"
> select CRYPTO_HASH
>diff --git a/crypto/Makefile b/crypto/Makefile
>index 85d0109..3d5251b 100644
>--- a/crypto/Makefile
>+++ b/crypto/Makefile
>@@ -22,6 +22,7 @@ crypto_hash-objs += ahash.o
> obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
>
> obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
>+obj-$(CONFIG_CRYPTO_CRYPTODEV) += cryptodev.o
> obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
> obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o
> obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
>diff --git a/crypto/cryptodev.c b/crypto/cryptodev.c
>new file mode 100644
>index 0000000..9175ee0
>--- /dev/null
>+++ b/crypto/cryptodev.c
>@@ -0,0 +1,1284 @@
>+/**********************************************************************
>*********
>+ * cryptodev.c
>+ *
>+ * Linux CryptoAPI user space interface module
>+ *
>+ * Copyright (c) 2008 Shasi Pulijala <[email protected]>
>+ *
>+ * 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.
>+ *
>+ * This program is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>+ * GNU General Public License for more details.
>+ *
>+ *
>+ * Detail Description:
>+ * This file implements the /dev/crypto interface which is intended to
>+ * provide user space interface to the Linux CryptoAPI.
>+ *
>+
>************************************************************************
>*******
>+ */
>+#include <linux/module.h>
>+#include <linux/moduleparam.h>
>+#include <linux/init.h>
>+#include <linux/sched.h>
>+#include <linux/fs.h>
>+#include <linux/fcntl.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 <linux/syscalls.h>
>+#include <linux/scatterlist.h>
>+#include <linux/time.h>
>+#include <linux/unistd.h>
>+#include <linux/rtnetlink.h>
>+#include <linux/err.h>
>+#include <crypto/aead.h>
>+#include <crypto/authenc.h>
>+#include <asm/uaccess.h>
>+#include <asm/ioctl.h>
>+#include <asm/scatterlist.h>
Please avoid asm

>+#include <asm-powerpc/unistd.h>
and this is not acceptable at all.

>+
>+/**********************************************************************
>*********
>+ * Forward declaration
>+
>************************************************************************
I personally prefer not having the asterisks all over the place and not
commenting obvious things.

>*******
>+ */
>+#define CRYPTODEV_DEBUG
>+
>+/**********************************************************************
>*********
>+ * Macro declaration
>+
>************************************************************************
>*******
>+ */
>+/* /dev/crypto is a char block device with majar 10 and minor below */
>+#define CRYPTODEV_MINOR 70
>+
>+#define CRYPTODEV_UI_SUPPORT_DRIVER "0.1"
>+
>+/**********************************************************************
>*********
>+ * Module Parameters
>+
>************************************************************************
>*******
>+ */
>+static int debug;
>+module_param(debug, int, 0644);
>+MODULE_PARM_DESC(debug, "0: normal, 1: verbose, 2: debug");
>+
>+static int sg_single;
>+module_param(sg_single, int, 0644);
>+MODULE_PARM_DESC(sg_single, "0: sg array list, 1: single sg entity");
>+
>+#ifdef CRYPTODEV_STATS
>+static int enable_stats;
>+module_param(enable_stats, int, 0644);
>+MODULE_PARM_DESC(enable_stats, "collect statictics about cryptodev
>usage");
>+#endif
>+
>+/**********************************************************************
>*********
>+ * Debugging Macro's
>+
>************************************************************************
>*******
>+ */
>+#define PFX "cryptodev: "
>+
>+#ifndef CRYPTODEV_DEBUG
>+#define CRYPTODEV_HEXDUMP(b, l) \
>+ print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, \
>+ 16, 1, (b), (l), false);
>+#define CRYPTODEV_PRINTK(level, severity, format, a...)
>\
>+ do {
>\
>+ if (level <= debug)
>\
>+ printk(severity PFX "%s[%u]: " format,
>\
>+ current->comm, current->pid, ##a);
>\
>+ } while (0)
>+#else
>+#define CRYPTODEV_HEXDUMP(b, l)
>+#define CRYPTODEV_PRINTK(level, severity, format, a...)
>+#endif
>+
>+/**********************************************************************
>*********
>+ * Helper Structure
>+
>************************************************************************
>*******
>+ */
>+#define CRYPTO_ACIPHER 0
>+#define CRYPTO_AHASH 1
>+#define CRYPTO_AEAD 2
>+
>+#define tfm_ablkcipher crt_tfm.acipher_tfm
>+#define tfm_aead crt_tfm.aead_tfm
>+#define tfm_ahash crt_tfm.ahash_tfm
>+
>+struct csession {
>+ struct list_head entry;
>+ struct semaphore sem;
>+ union {
>+ struct crypto_ablkcipher *acipher_tfm;
>+ struct crypto_ahash *ahash_tfm;
>+ struct crypto_aead *aead_tfm;
>+ } crt_tfm;
>+
>+ int mode;
>+ unsigned int sid;
>+};
>+
>+/**********************************************************************
>*********
>+ * Table Lookup for Algorithms name(Crypto/hash name)
>+ * Helper Structure
>+
>************************************************************************
>*******
>+ */
>+char *algo_map_tbl[CRYPTO_ALGORITHM_MAX] = {
>+ [CRYPTO_DES_CBC] = "cbc(des)",
>+ [CRYPTO_3DES_CBC] = "cbc(des3_ede)",
>+ [CRYPTO_MD5_HMAC] = "hmac(md5)",
>+ [CRYPTO_BLF_CBC] = "cbc(blowfish)",
>+ [CRYPTO_CAST_CBC] = "cbc(cast5)",
>+ [CRYPTO_SKIPJACK_CBC] = "camellia",
>+ [CRYPTO_MD5_HMAC] = "hmac(md5)",
>+ [CRYPTO_SHA1_HMAC] = "hmac(sha1)",
>+ [CRYPTO_RIPEMD160_HMAC] = "hmac(rmd160)",
>+ [CRYPTO_MD5_KPDK] = "",
>+ [CRYPTO_SHA1_KPDK] = "",
>+ [CRYPTO_RIJNDAEL128_CBC] = "cbc(aes)",
>+ [CRYPTO_AES_CBC] = "cbc(aes)",
>+ [CRYPTO_ARC4] = "ecb(arc4)",
>+ [CRYPTO_MD5] = "md5",
>+ [CRYPTO_SHA1] = "sha1",
>+ [CRYPTO_NULL_HMAC] = "",
>+ [CRYPTO_NULL_CBC] = "",
>+ [CRYPTO_DEFLATE_COMP] = "deflate",
>+ [CRYPTO_SHA2_256_HMAC] = "hmac(sha256)",
>+ [CRYPTO_SHA2_384_HMAC] = "hmac(sha384)",
>+ [CRYPTO_SHA2_512_HMAC] = "hmac(sha512)",
>+ [CRYPTO_CAMELLIA_CBC] = "cbc(camellia)",
>+ [CRYPTO_SHA2_256] = "sha256",
>+ [CRYPTO_SHA2_384] = "sha384",
>+ [CRYPTO_SHA2_512] = "sha512",
>+ [CRYPTO_RIPEMD160] = "rmd160",
>+ [CRYPTO_AES_GCM] = "gcm(aes)",
>+ [CRYPTO_AES_CCM] = "ccm(aes)",
>+};

Wouldn't it be better to have dynamic algos? This way you must patch the
driver every single time a new algo is showing up.

>+
>+struct fcrypt {
>+ struct list_head list;
>+ struct semaphore sem;
>+};
>+
>+struct async_result {
>+ struct completion completion;
>+ int err;
>+};
>+
>+/**********************************************************************
>*********
>+ * Function Declarations
>+
>************************************************************************
>*******
>+ */
>+static int create_session_ablkcipher(char *alg_name,
>+ struct fcrypt *fcr,
>+ struct session_op *sop);
>+static int create_session_ahash(char *alg_name,
>+ struct fcrypt *fcr,
>+ struct session_op *sop);
>+static int create_session_aead(char *alg_name,
>+ struct fcrypt *fcr,
>+ struct session_op *sop);
>+static int cryptodev_run_acipher(struct csession *ses_ptr,
>+ struct crypt_op *cop);
>+static int cryptodev_run_ahash(struct csession *ses_ptr,
>+ struct crypt_op *cop);
>+static int cryptodev_run_aead(struct csession *ses_ptr,
>+ struct crypt_op *cop);
>+static int sg_setup(unsigned char *addr, int bufsize, struct
>scatterlist *sg,
>+ int sg_single);
>+
>+/**********************************************************************
>*********
>+ * Asynchronous handling Routine
>+ *
>+
>************************************************************************
>*******
>+ */
>+static void cryptodev_async_complete(struct crypto_async_request *req,
>int err)
>+{
>+ struct async_result *res = req->data;
>+
>+ if (err == -EINPROGRESS)
>+ return;
>+
>+ res->err = err;
>+ complete(&res->completion);
>+}
>+
>+/**********************************************************************
>*********
>+ * Prepare session for future use
>+ *
>+
>************************************************************************
>*******
>+ */
>+static int cryptodev_create_session(struct fcrypt *fcr, struct
>session_op *sop)
>+{
>+ char alg_name[CRYPTO_MAX_ALG_NAME];
>+ int mode = -1;
>+ int ret = 0;
>+
>+ if (sop->mac > CRYPTO_ALGORITHM_MAX ||
>+ sop->cipher > CRYPTO_ALGORITHM_MAX) {
>+ printk(KERN_INFO PFX "algorithm not supported or "
>+ "not set\n");
>+ return -EINVAL;
>+ }
>+
>+ if (sop->cipher && sop->mac) {
>+ mode = CRYPTO_AEAD;
>+ printk(KERN_INFO PFX "authenc(%s,%s) (Algorithm
>Chanining Mode"
>+ "not yet supported", algo_map_tbl[sop->mac],
>+ algo_map_tbl[sop->cipher]);
>+ return -EINVAL;
>+ } else if (sop->cipher) {
>+ if (sop->cipher == CRYPTO_AES_GCM ||
>+ sop->cipher == CRYPTO_AES_CCM)
>+ mode = CRYPTO_AEAD;
>+ else
>+ mode = CRYPTO_ACIPHER;
>+ strncpy(alg_name, algo_map_tbl[sop->cipher],
>+ CRYPTO_MAX_ALG_NAME);
>+ } else if (sop->mac) {
>+ mode = CRYPTO_AHASH;
>+ strncpy(alg_name, algo_map_tbl[sop->mac],
>CRYPTO_MAX_ALG_NAME);
>+ }
>+
>+ if (!alg_name)
>+ return -EINVAL;
>+
>+ switch (mode) {
>+ case CRYPTO_ACIPHER:
>+ ret = create_session_ablkcipher(alg_name, fcr, sop);
>+ break;
>+ case CRYPTO_AHASH:
>+ ret = create_session_ahash(alg_name, fcr, sop);
>+ break;
>+ case CRYPTO_AEAD:
>+ ret = create_session_aead(alg_name, fcr, sop);
>+ break;
>+ default:
>+ printk(KERN_INFO PFX "Improper Mode Set(Not
>Cipher/Hash/Aead)");
>+ ret = -EINVAL;
>+ break;
>+ }
>+ return ret;
>+}
>+
>+/**********************************************************************
>*********
>+ * Routine for Creating a Session for the Combined Mode Implementation
>+ *
>+
>************************************************************************
>*******
>+ */
>+static int create_session_aead(char *alg_name, struct fcrypt *fcr,
>+ struct session_op *sop)
>+{
>+ struct csession *ses_new;
>+ struct csession *ses_ptr;
>+ struct crypto_aead *tfm;
>+ char *keyp = NULL;
>+ size_t authsize;
>+ int ret = 0;
>+
>+ tfm = crypto_alloc_aead(alg_name, 0, 0);
>+ if (IS_ERR(tfm)) {
>+ printk(KERN_INFO PFX "Failed to load aead"
>+ "transform for %s: %ld \n", alg_name,
>PTR_ERR(tfm));
>+ return -EINVAL;
>+ }
>+
>+ crypto_aead_clear_flags(tfm, ~0);
>+
>+ keyp = kmalloc(sop->keylen, GFP_KERNEL);
>+ if (unlikely(!keyp)) {
>+ crypto_free_aead(tfm);
>+ return -ENOMEM;
>+ }
>+
>+ if (copy_from_user(keyp, sop->key, sop->keylen)) {
>+ printk(KERN_INFO PFX "Copy of Key Failed from"
>+ "User Space for %s\n", alg_name);
>+ kfree(keyp);
>+ crypto_free_aead(tfm);
>+ return -EFAULT;
>+ }
>+
>+ ret = crypto_aead_setkey(tfm, keyp, sop->keylen);
>+ kfree(keyp);
>+ if (ret) {
>+ printk(KERN_INFO PFX
>+ "Setting key failed for %s-%zu: flags=0x%X\n",
>+ alg_name, sop->keylen*8,
>+ crypto_aead_get_flags(tfm));
>+ printk(KERN_INFO PFX
>+ "(see CRYPTO_TFM_RES_* in <linux/crypto.h> "
>+ "for details)\n");
>+
>+ crypto_free_aead(tfm);
>+ return -EINVAL;
>+ }
>+
>+ /* Supporting Authsize for ccm and gcm from mackeylen
>+ (no separate field for authsize) */
>+ authsize = sop->mackeylen;
>+ ret = crypto_aead_setauthsize(tfm, authsize);
>+ if (ret) {
>+ printk(KERN_INFO "failed to set authsize = %u\n",
>authsize);
>+ crypto_free_aead(tfm);
>+ return -EINVAL;
>+ }
>+
>+ ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
>+ if (!ses_new) {
>+ crypto_free_aead(tfm);
>+ return -ENOMEM;
>+ }
>+
>+ memset(ses_new, 0, sizeof(*ses_new));
>+ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
>+ ses_new->tfm_aead = tfm;
>+
>+ ses_new->mode = CRYPTO_AEAD;
>+ 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));
>+ goto restart;
>+ }
>+ }
>+
>+ list_add(&ses_new->entry, &fcr->list);
>+ up(&fcr->sem);
>+
>+ sop->ses = ses_new->sid;
>+
>+ return 0;
>+}
>+
>+/**********************************************************************
>*********
>+ * Routine for Creating a Session for the Hash Implementation
>+ *
>+
>************************************************************************
>*******
>+ */
>+static int create_session_ahash(char *alg_name, struct fcrypt *fcr,
>+ struct session_op *sop)
>+{
>+ struct csession *ses_new;
>+ struct csession *ses_ptr;
>+ struct crypto_ahash *tfm;
>+ char *keyp = NULL;
>+ int ret = 0;
>+
>+ tfm = crypto_alloc_ahash(alg_name, 0, 0);
>+ if (IS_ERR(tfm)) {
>+ printk(KERN_INFO PFX "Failed to load ahash "
>+ "transform for %s: %ld \n", alg_name,
>PTR_ERR(tfm));
>+ return -EINVAL;
>+ }
>+ crypto_ahash_clear_flags(tfm, ~0);
>+
>+ /* Copy the key(hmac) from user and set to TFM. */
>+ if (sop->mackey && (sop->mac != CRYPTO_MD5) && (sop->mac !=
>CRYPTO_SHA1)
>+ && (sop->mac != CRYPTO_SHA2_256)
>+ && (sop->mac != CRYPTO_SHA2_384)
>+ && (sop->mac != CRYPTO_SHA2_512)
>+ && (sop->mac != CRYPTO_RIPEMD160)) {
>+ keyp = kmalloc(sop->mackeylen, GFP_KERNEL);
>+ if (unlikely(!keyp)) {
>+ crypto_free_ahash(tfm);
>+ return -ENOMEM;
>+ }
>+
>+ if (copy_from_user(keyp, sop->mackey, sop->mackeylen)) {
>+ printk(KERN_INFO PFX "Copy of Key Failed from
>User"
>+ "space for %s\n", alg_name);
>+ kfree(keyp);
>+ crypto_free_ahash(tfm);
>+ return -EFAULT;
>+ }
>+
>+ ret = crypto_ahash_setkey(tfm, keyp, sop->mackeylen);
>+ kfree(keyp);
>+ if (ret) {
>+ printk(KERN_INFO PFX
>+ "Setting key failed for %s-%zu:
>flags=0x%X\n",
>+ alg_name, sop->mackeylen * 8,
>+ crypto_ahash_get_flags(tfm));
>+ printk(KERN_INFO PFX
>+ "(see CRYPTO_TFM_RES_* in "
>+ "<linux/crypto.h> for details)\n");
>+
>+ crypto_free_ahash(tfm);
>+ return -EINVAL;
>+ }
>+ }
>+
>+ ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
>+ if (!ses_new) {
>+ crypto_free_ahash(tfm);
>+ return -ENOMEM;
>+ }
>+
>+ memset(ses_new, 0, sizeof(*ses_new));
>+ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
>+ ses_new->tfm_ahash = tfm;
>+
>+ ses_new->mode = CRYPTO_AHASH;
>+ 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));
>+ goto restart;
>+ }
>+ }
>+ list_add(&ses_new->entry, &fcr->list);
>+ up(&fcr->sem);
>+
>+ /* Fill in some values for the user. */
>+ sop->ses = ses_new->sid;
>+
>+ return 0;
>+}
>+
>+/**********************************************************************
>*********
>+ * Routine for Creating a Session for the Crypto Implementation
>+ *
>+
>************************************************************************
>*******
>+ */
>+static int create_session_ablkcipher(char *alg_name, struct fcrypt
>*fcr,
>+ struct session_op *sop)
>+{
>+ struct csession *ses_new, *ses_ptr;
>+ struct crypto_ablkcipher *tfm;
>+ char *keyp = NULL;
>+ int ret = 0;
>+
>+ tfm = crypto_alloc_ablkcipher(alg_name, 0, 0);
>+ if (IS_ERR(tfm)) {
>+ printk(KERN_INFO PFX "Failed to load crypto "
>+ "transform for %s: %ld\n", alg_name,
>PTR_ERR(tfm));
>+ return -EINVAL;
>+ }
>+
>+ crypto_ablkcipher_clear_flags(tfm, ~0);
>+
>+ /* Copy the key from user and set to TFM. */
>+ keyp = kmalloc(sop->keylen, GFP_KERNEL);
>+ if (unlikely(!keyp)) {
>+ crypto_free_ablkcipher(tfm);
>+ return -ENOMEM;
>+
>+ }
>+
>+ if (copy_from_user(keyp, sop->key, sop->keylen)) {
>+ printk(KERN_INFO PFX "Copy of Key Failed from User"
>+ "space for %s\n", alg_name);
>+ kfree(keyp);
>+ crypto_free_ablkcipher(tfm);
>+ return -EFAULT;
>+ }
>+
>+ ret = crypto_ablkcipher_setkey(tfm, keyp, sop->keylen);
>+ kfree(keyp);
>+ if (ret) {
>+ printk(KERN_INFO PFX
>+ "Setting key failed for %s-%zu: flags=0x%X\n",
>+ alg_name, sop->keylen*8,
>+ crypto_ablkcipher_get_flags(tfm));
>+ printk(KERN_INFO PFX
>+ "(see CRYPTO_TFM_RES_* in <linux/crypto.h> for "
>+ "details)\n");
>+
>+ crypto_free_ablkcipher(tfm);
>+ return -EINVAL;
>+ }
>+
>+ ses_new = kmalloc(sizeof(*ses_new), GFP_KERNEL);
>+ if (!ses_new) {
>+ crypto_free_ablkcipher(tfm);
>+ return -ENOMEM;
>+ }
>+
>+ memset(ses_new, 0, sizeof(*ses_new));
>+ get_random_bytes(&ses_new->sid, sizeof(ses_new->sid));
>+ ses_new->tfm_ablkcipher = tfm;
>+
>+ ses_new->mode = CRYPTO_ACIPHER;
>+ 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));
>+ goto restart;
>+ }
>+ }
>+ list_add(&ses_new->entry, &fcr->list);
>+ up(&fcr->sem);
>+
>+ /* Fill in some values for the user. */
>+ sop->ses = ses_new->sid;
>+
>+ return 0;
>+}
>+
>+/**********************************************************************
>*********
>+ * Everything that needs to be done when removing a session.
>+ *
>+
>************************************************************************
>*******
>+ */
>+static inline void cryptodev_destroy_session(struct csession *ses_ptr)
>+{
>+ if (down_trylock(&ses_ptr->sem)) {
>+ CRYPTODEV_PRINTK(2, KERN_DEBUG,
>+ "Waiting for semaphore of sid=0x%08X\n",
>+ ses_ptr->sid);
>+ down(&ses_ptr->sem);
>+ }
>+ CRYPTODEV_PRINTK(2, KERN_DEBUG, "Removed session 0x%08X\n",
>+ ses_ptr->sid);
>+
>+ /* Check for mode and then delete */
>+ switch (ses_ptr->mode) {
>+ case CRYPTO_ACIPHER:
>+ crypto_free_ablkcipher(ses_ptr->tfm_ablkcipher);
>+ ses_ptr->tfm_ablkcipher = NULL;
>+ break;
>+ case CRYPTO_AHASH:
>+ crypto_free_ahash(ses_ptr->tfm_ahash);
>+ ses_ptr->tfm_ahash = NULL;
>+ break;
>+ case CRYPTO_AEAD:
>+ crypto_free_aead(ses_ptr->tfm_aead);
>+ ses_ptr->tfm_aead = NULL;
>+ break;
>+ }
>+ up(&ses_ptr->sem);
>+ kfree(ses_ptr);
>+}
>+
>+/**********************************************************************
>*********
>+ * Look up a session by ID and remove.
>+ *
>+
>************************************************************************
>*******
>+ */
>+static int cryptodev_finish_session(struct fcrypt *fcr, u32 sid)
>+{
>+ struct csession *tmp;
>+ struct csession *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);
>+ cryptodev_destroy_session(ses_ptr);
>+ break;
>+ }
>+ }
>+
>+ if (!ses_ptr) {
>+ CRYPTODEV_PRINTK(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 cryptodev_finish_all_sessions(struct fcrypt *fcr)
>+{
>+ struct csession *tmp;
>+ struct csession *ses_ptr;
>+
>+ down(&fcr->sem);
>+ list_for_each_entry_safe(ses_ptr, tmp, &fcr->list, entry) {
>+ list_del(&ses_ptr->entry);
>+ cryptodev_destroy_session(ses_ptr);
>+ }
>+ up(&fcr->sem);
>+
>+ return 0;
>+}
>+
>+/**********************************************************************
>*********
>+ * Look up session by session ID. The returned session is locked.
>+
>************************************************************************
>*******
>+ */
>+static struct csession *cryptodev_get_session_by_sid(struct fcrypt
>*fcr,
>+ u32 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;
>+}
>+
>+static void cryptodev_release_session(struct csession *session)
>+{
>+ if (session)
>+ up(&session->sem);
>+}
>+
>+/**********************************************************************
>*********
>+ * This is the main crypto function - feed it with plaintext
>+ * and get a ciphertext
>+
>************************************************************************
>*******
>+ */
>+static int cryptodev_run(struct fcrypt *fcr, struct crypt_op *cop)
>+{
>+
>+ struct csession *ses_ptr;
>+ int ret = 0;
>+
>+ if (cop->op &&
>+ (cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) {
>+ printk(KERN_INFO PFX "invalid operation op=%u\n",
>cop->op);
>+ return -EINVAL;
>+ }
>+
>+ ses_ptr = cryptodev_get_session_by_sid(fcr, cop->ses);
>+ if (!ses_ptr) {
>+ printk(KERN_INFO PFX "invalid session ID=0x%08X\n",
>cop->ses);
>+ return -EINVAL;
>+ }
>+
>+ switch (ses_ptr->mode) {
>+ case CRYPTO_ACIPHER:
>+ ret = cryptodev_run_acipher(ses_ptr, cop);
>+ break;
>+ case CRYPTO_AHASH:
>+ ret = cryptodev_run_ahash(ses_ptr, cop);
>+ break;
>+ case CRYPTO_AEAD:
>+ ret = cryptodev_run_aead(ses_ptr, cop);
>+ break;
>+ }
>+ cryptodev_release_session(ses_ptr);
>+
>+ return ret;
>+
>+}
>+
>+/**********************************************************************
>*********
>+ * This is the routine that splits the user buffer data over
>+ * pages and creates scatterlist
>+
>************************************************************************
>*******
>+ */
>+static int sg_setup(unsigned char *data, int bufsize, struct
>scatterlist *sg,
>+ int sg_single)
>+{
>+ int sg_size, remainder_of_page;
>+ int i = 0;
>+
>+ if (sg_single || (!bufsize)) {
>+ sg_set_buf(&sg[0], data, bufsize);
>+ return 1;
>+ }
>+ sg_size = bufsize % PAGE_SIZE == 0 ? bufsize/PAGE_SIZE :
>+ bufsize/PAGE_SIZE + 1;
>+ sg_init_table(sg, sg_size);
>+
>+ while (bufsize > 0 && i < sg_size) {
>+ sg_set_buf(&sg[i], data, bufsize);
>+ remainder_of_page = PAGE_SIZE - sg[i].offset;
>+ if (bufsize > remainder_of_page) {
>+ /* the buffer was split over multiple pages */
>+ sg[i].length = remainder_of_page;
>+ bufsize -= remainder_of_page;
>+ data += remainder_of_page;
>+ } else {
>+ bufsize = 0;
>+ }
>+ i++;
>+ }
>+ sg_mark_end(&sg[sg_size - 1]);
>+
>+ return sg_size;
>+}
>+
>+/**********************************************************************
>*********
>+ * This is the actual aead function that implements
>+ * the Combined mode
>+
>************************************************************************
>*******
>+ */
>+static int cryptodev_run_aead(struct csession *ses_ptr, struct crypt_op
>*cop)
>+{
>+ char *data = NULL;
>+ char *ivp = NULL;
>+ char __user *src;
>+ char __user *dst;
>+ struct scatterlist sg[16];
>+ struct scatterlist asg[1];
>+ struct aead_request *req;
>+ struct async_result result;
>+ size_t bufsize;
>+ size_t ivsize;
>+ size_t order;
>+ size_t authsize;
>+ int ret = 0;
>+ int nsg = 0;
>+
>+ /* Checking the Input Length */
>+ bufsize = cop->len;
>+ if (cop->len > CRYPTO_MAX_DATA_LEN) {
>+ printk(KERN_INFO PFX "Maximum Data Size Exceeded: %d >
>%d\n",
>+ cop->len, CRYPTO_MAX_DATA_LEN);
>+ return -E2BIG;
>+ }
>+
>+ init_completion(&result.completion);
>+
>+ /* Setting the resquest */
>+ req = aead_request_alloc(ses_ptr->tfm_aead, GFP_KERNEL);
>+ if (!req) {
>+ printk(KERN_INFO PFX "failed to allocate request");
>+ return -EINVAL;
>+ }
>+
>+ order = get_order(bufsize);
>+ data = (char *) __get_free_pages(GFP_KERNEL, order);
>+
>+ if (unlikely(!data)) {
>+ ret = -ENOMEM;
>+ goto out_req;
>+ }
>+
>+ aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
>+ cryptodev_async_complete, &result);
>+
>+ src = cop->src;
>+ dst = cop->dst;
>+
>+ authsize = crypto_aead_authsize(ses_ptr->tfm_aead);
>+
>+ if (copy_from_user(data, src, bufsize)) {
>+ printk(KERN_INFO PFX "Copy of src data Failed from User"
>+ "space for aead\n");
>+ free_pages((unsigned long)data, order);
>+ ret = -EFAULT;
>+ goto out_req;
>+ }
>+
>+ ivsize = crypto_aead_ivsize(ses_ptr->tfm_aead);
>+
>+ ivp = kmalloc(ivsize, GFP_KERNEL);
>+ if (unlikely(!ivp)) {
>+ free_pages((unsigned long)data, order);
>+ ret = -ENOMEM;
>+ goto out_req;
>+ }
>+
>+ memset(ivp, 0, ivsize);
>+ if (cop->iv && copy_from_user(ivp, cop->iv, ivsize)) {
>+ printk(KERN_INFO PFX "Copy of src iv Failed from User "
>+ "space for aead\n");
>+ ret = -EFAULT;
>+ goto out;
>+ }
>+
>+ nsg = sg_setup(data, bufsize + authsize, sg, sg_single);
>+ if (!nsg) {
>+ printk("Scatter Allocation failed err due to improper"
>+ "sg size");
>+ goto out;
>+ }
>+
>+ /* Additional Associated data set to 0 bytes */
>+ sg_init_one(&asg[0], ivp, 0);
>+
>+ aead_request_set_crypt(req, sg, sg, bufsize, ivp);
>+ aead_request_set_assoc(req, asg, 0);
>+
>+ if (cop->op == COP_ENCRYPT)
>+ ret = crypto_aead_encrypt(req);
>+ else
>+ ret = crypto_aead_decrypt(req);
>+ switch (ret) {
>+ case 0:
>+ break;
>+ case -EINPROGRESS:
>+ case -EBUSY:
>+ ret = wait_for_completion_interruptible(
>+ &result.completion);
>+ if (!ret)
>+ ret = result.err;
>+ if (!ret) {
>+ INIT_COMPLETION(result.completion);
>+ break;
>+ }
>+ /* fall through */
>+ default:
>+ printk("%s () failed err=%d\n", "enc/dec", -ret);
>+ goto out;
>+ }
>+
>+ CRYPTODEV_HEXDUMP(data, bufsize + authsize);
>+ if (copy_to_user(dst, data, bufsize + authsize)) {
>+ printk(KERN_INFO PFX "Copy of enc data Failed to User"
>+ "space for aead\n");
>+ ret = -EFAULT;
>+ }
>+
>+out:
>+ free_pages((unsigned long)data, order);
>+ kfree(ivp);
>+
>+out_req:
>+ aead_request_free(req);
>+
>+ return ret;
>+}
>+
>+/**********************************************************************
>*********
>+ * This is the actual hash function that creates the
>+ * authenticated data
>+
>************************************************************************
>*******
>+ */
>+static int cryptodev_run_ahash(struct csession *ses_ptr, struct
>crypt_op *cop)
>+{
>+
>+ char *data = NULL;
>+ char __user *src;
>+ char __user *mac;
>+ struct scatterlist sg[16];
>+ struct ahash_request *req;
>+ struct async_result result;
>+ size_t authsize;
>+ size_t bufsize;
>+ size_t order;
>+ int ret = 0;
>+ int nsg = 0;
>+ char digest_result[64];
>+
>+ /* Checking the Input Length */
>+ bufsize = cop->len;
>+ if (cop->len > CRYPTO_MAX_DATA_LEN) {
>+ printk(KERN_INFO PFX "Maximum Data Size Exceeded: %d >
>%d\n",
>+ cop->len, CRYPTO_MAX_DATA_LEN);
>+ return -E2BIG;
>+ }
>+
>+ init_completion(&result.completion);
>+
>+ /* Setting the resquest */
>+ req = ahash_request_alloc(ses_ptr->tfm_ahash, GFP_KERNEL);
>+ if (!req) {
>+ printk(KERN_INFO PFX "failed to allocate request");
>+ return -EINVAL;
>+ }
>+
>+ order = (!bufsize) ? 0 : get_order(bufsize);
>+ data = (char *) __get_free_pages(GFP_KERNEL, order);
>+
>+ if (unlikely(!data)) {
>+ printk(KERN_INFO PFX "Improper data size "
>+ "set = %d\n", bufsize);
>+ ret = -ENOMEM;
>+ goto out_req;
>+ }
>+
>+ authsize = crypto_ahash_digestsize(ses_ptr->tfm_ahash);
>+ memset(digest_result, 0, 64);
>+
>+ ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
>+ cryptodev_async_complete,
>&result);
>+
>+ src = cop->src;
>+ mac = cop->mac;
>+
>+ if (copy_from_user(data, src, bufsize)) {
>+ printk(KERN_INFO PFX "Copy of src data Failed from User"
>+ "space for hash\n");
>+ ret = -EFAULT;
>+ goto out;
>+ }
>+
>+ nsg = sg_setup(data, bufsize, sg, sg_single);
>+ if (!nsg) {
>+ printk("Scatter Allocation () failed err=%d\n", nsg);
>+ goto out;
>+ }
>+
>+ ahash_request_set_crypt(req, sg, digest_result, bufsize);
>+ ret = crypto_ahash_digest(req);
>+
>+ switch (ret) {
>+ case 0:
>+ break;
>+ case -EINPROGRESS:
>+ case -EBUSY:
>+ ret = wait_for_completion_interruptible(
>+ &result.completion);
>+ if (!ret)
>+ ret = result.err;
>+ if (!ret) {
>+ INIT_COMPLETION(result.completion);
>+ break;
>+ }
>+ /* fall through */
>+ default:
>+ printk(KERN_INFO PFX "%s failed err=%d\n", "enc/dec",
>-ret);
>+ goto out;
>+ }
>+
>+ CRYPTODEV_HEXDUMP(digest_result, authsize);
>+ if (copy_to_user(mac, digest_result, authsize)) {
>+ printk(KERN_INFO PFX "Copy of mac data Failed to User"
>+ "space for hash\n");
>+ ret = -EFAULT;
>+ }
>+
>+out:
>+ free_pages((unsigned long)data, order);
>+
>+out_req:
>+ ahash_request_free(req);
>+
>+ return ret;
>+}
>+
>+/**********************************************************************
>*********
>+ * This is the actual crypto function that creates the
>+ * encrypted or decrypted data
>+
>************************************************************************
>*******
>+ */
>+static int cryptodev_run_acipher(struct csession *ses_ptr, struct
>crypt_op *cop)
>+{
>+ char *data = NULL;
>+ char *ivp = NULL;
>+ char __user *src;
>+ char __user *dst;
>+ struct scatterlist sg[16];
>+ struct ablkcipher_request *req;
>+ struct async_result result;
>+ size_t bufsize;
>+ size_t ivsize;
>+ size_t order;
>+ int ret = 0;
>+ int nsg = 0;
>+
>+ /* Checking the Input Length */
>+ bufsize = cop->len;
>+ if (cop->len > CRYPTO_MAX_DATA_LEN) {
>+ printk(KERN_INFO PFX "Maximum Data Size Exceeded: %d >
>%d\n",
>+ cop->len, CRYPTO_MAX_DATA_LEN);
>+ return -E2BIG;
>+ }
>+
>+ init_completion(&result.completion);
>+
>+ /* Setting the request */
>+ req = ablkcipher_request_alloc(ses_ptr->tfm_ablkcipher,
>GFP_KERNEL);
>+ if (!req) {
>+ printk(KERN_INFO PFX "failed to allocate request\n");
>+ return -EINVAL;
>+ }
>+
>+ if (bufsize %
>crypto_ablkcipher_blocksize(ses_ptr->tfm_ablkcipher)) {
>+ printk(KERN_INFO PFX
>+ "data size (%zu) isn't a multiple of block size
>(%u)\n",
>+ bufsize, crypto_ablkcipher_blocksize
>+ (ses_ptr->tfm_ablkcipher));
>+ ret = -EINVAL;
>+ goto out_req;
>+ }
>+
>+ order = get_order(bufsize);
>+ data = (char *) __get_free_pages(GFP_KERNEL, order);
>+
>+ if (unlikely(!data)) {
>+ ret = -ENOMEM;
>+ goto out_req;
>+ }
>+
>+ ivsize = crypto_ablkcipher_ivsize(ses_ptr->tfm_ablkcipher);
>+
>+ ivp = kmalloc(ivsize, GFP_KERNEL);
>+ if (unlikely(!ivp)) {
>+ free_pages((unsigned long)data, order);
>+ ret = -ENOMEM;
>+ goto out_req;
>+ }
>+
>+ memset(ivp, 0, ivsize);
>+ if (cop->iv && copy_from_user(ivp, cop->iv, ivsize)) {
>+ printk(KERN_INFO PFX "Copy of src iv Failed from User "
>+ "space for crypto\n");
>+ ret = -EFAULT;
>+ goto out;
>+ }
>+
>+ ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
>+ cryptodev_async_complete,
>&result);
>+
>+ src = cop->src;
>+ dst = cop->dst;
>+
>+ if (copy_from_user(data, src, bufsize)) {
>+ printk(KERN_INFO PFX "Copy of src data Failed from User"
>+ "space for crypto\n");
>+ ret = -EFAULT;
>+ goto out;
>+ }
>+
>+ nsg = sg_setup(data, bufsize, sg, sg_single);
>+ if (!nsg) {
>+ printk(KERN_INFO PFX "Scatter Allocation failed
>err=%d\n",
>+ nsg);
>+ goto out;
>+ }
>+ ablkcipher_request_set_crypt(req, sg, sg, bufsize, ivp);
>+
>+ if (cop->op == COP_ENCRYPT)
>+ ret = crypto_ablkcipher_encrypt(req);
>+ else
>+ ret = crypto_ablkcipher_decrypt(req);
>+ switch (ret) {
>+ case 0:
>+ break;
>+ case -EINPROGRESS:
>+ case -EBUSY:
>+ ret = wait_for_completion_interruptible(
>+ &result.completion);
>+ if (!ret)
>+ ret = result.err;
>+ if (!ret) {
>+ INIT_COMPLETION(result.completion);
>+ break;
>+ }
>+ /* fall through */
>+ default:
>+ printk(KERN_INFO PFX "%s failed err=%d\n", "enc/dec",
>-ret);
>+ goto out;
>+ }
>+
>+ CRYPTODEV_HEXDUMP(data, bufsize);
>+ if (copy_to_user(dst, data, bufsize)) {
>+ printk(KERN_INFO PFX "Copy of enc data Failed to User"
>+ "space for crypto\n");
>+ ret = -EFAULT;
>+ }
>+
>+out:
>+ free_pages((unsigned long)data, order);
>+ kfree(ivp);
>+
>+out_req:
>+ ablkcipher_request_free(req);
>+
>+ return ret;
>+}
>+
>+
>/***********************************************************************
>******
>+ * /dev/crypto function operation functions
>+
>************************************************************************
>******
>+ */
>+static int cryptodev_clonefd(struct file *filp)
>+{
>+ mm_segment_t fs;
>+ int fd;
>+
>+ fs = get_fs();
>+ set_fs(get_ds());
>+ for (fd = 0; fd < files_fdtable(current->files)->max_fds; fd++)
>+ if (files_fdtable(current->files)->fd[fd] == filp)
>+ break;
>+ fd = __sys_dup(fd);
>+ set_fs(fs);
>+ return fd;
>+}

This is so broke. Why does dup() not work? It is allready available in
userspace.

>+
>+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) {
>+ cryptodev_finish_all_sessions(fcr);
>+ kfree(fcr);
>+ filp->private_data = NULL;
>+ }
>+ return 0;
>+}
>+
>+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;
>+ unsigned int ses;
>+ int ret;
>+ int fd, feat;
>+
>+ if (!fcr)
>+ BUG();
>+
>+ switch (cmd) {
>+ case CRIOGET:
>+ fd = cryptodev_clonefd(filp);
>+ put_user(fd, (int *) arg);
>+ return IS_ERR_VALUE(fd) ? fd : 0;
>+
>+ case CIOCGSESSION:
>+ if (copy_from_user(&sop, (void *) arg, sizeof(sop))) {
>+ printk(KERN_INFO PFX "Copy of Session data
>failed"
>+ "at CIOCGSESSION from user space\n");
>+ return -EFAULT;
>+ }
>+ ret = cryptodev_create_session(fcr, &sop);
>+ if (ret)
>+ return ret;
>+ if (copy_to_user((void *)arg, &sop, sizeof(sop))) {
>+ printk(KERN_INFO PFX "Copy of Session data
>failed"
>+ "at CIOCGSESSION to user space\n");
>+ return -EFAULT;
>+ }
>+ return 0;
>+
>+ case CIOCFSESSION:
>+ get_user(ses, (u32 *) arg);
>+ return cryptodev_finish_session(fcr, ses);
>+
>+ case CIOCCRYPT:
>+ if (copy_from_user(&cop, (void *) arg, sizeof(cop))) {
>+ printk(KERN_INFO PFX "Copy of src data failed"
>+ "at CIOCCRYPT from user space\n");
>+ return -EFAULT;
>+ }
>+ ret = cryptodev_run(fcr, &cop);
>+ if (copy_to_user((void *) arg, &cop, sizeof(cop))) {
>+ printk(KERN_INFO PFX "Copy of enc/dec/hash data
>failed"
>+ "at CIOCCRYPT to user space\n");
>+ return -EFAULT;
>+ }
>+ return ret;
>+
>+ case CIOCASYMFEAT:
>+ /* No Asymmetric Algorithms Supported */
>+ feat = 0;
>+ if (copy_to_user((void *)arg, &feat, sizeof(feat))) {
>+ printk(KERN_INFO PFX "Copy of asymm algorithm
>data"
>+ " failed at CIOCASYMFEAT to user
>space\n");
>+ return -EFAULT;
>+ }
>+ return 0;
>+
>+ default:
>+ printk(KERN_ERR PFX "un-supported command 0x%08X\n",
>cmd);
>+ 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,
couldn't you use a dynamic 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 "CryptoAPI driver v%s loaded\n",
>+ CRYPTODEV_UI_SUPPORT_DRIVER);
>+
>+ return 0;
>+}
>+
>+void __exit exit_cryptodev(void)
>+{
>+ cryptodev_deregister();
>+ printk(KERN_INFO PFX "CryptoAPI driver v%s unloaded\n",
>+ CRYPTODEV_UI_SUPPORT_DRIVER);
>+}
>+
>+module_init(init_cryptodev);
>+module_exit(exit_cryptodev);
>+
>+MODULE_AUTHOR("Shasi Pulijala <[email protected]>");
>+MODULE_DESCRIPTION("CryptoDev driver");
>+MODULE_LICENSE("Dual BSD/GPL");
>diff --git a/fs/fcntl.c b/fs/fcntl.c
>index e632da7..5afec53 100644
>--- a/fs/fcntl.c
>+++ b/fs/fcntl.c
>@@ -137,6 +137,7 @@ static int dupfd(struct file *file, unsigned int
>start, int cloexec)
> return fd;
> }
>
>+
> asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd)
> {
> int err = -EBADF;
>@@ -193,7 +194,7 @@ out_fput:
> goto out;
> }
>
>-asmlinkage long sys_dup(unsigned int fildes)
>+asmlinkage long __sys_dup(unsigned int fildes)
> {
> int ret = -EBADF;
> struct file * file = fget(fildes);
>@@ -202,6 +203,12 @@ asmlinkage long sys_dup(unsigned int fildes)
> ret = dupfd(file, 0, 0);
> return ret;
> }
>+EXPORT_SYMBOL(__sys_dup);
>+
>+asmlinkage long sys_dup(unsigned int fildes)
>+{
>+ return __sys_dup(fildes);
>+}

I don't see the difference between sys_dup() & __sys_dup()

>
> #define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC |
>O_DIRECT | O_NOATIME)
>
>diff --git a/include/linux/cryptodev.h b/include/linux/cryptodev.h
>new file mode 100644
>index 0000000..46466d4
>--- /dev/null
>+++ b/include/linux/cryptodev.h
>@@ -0,0 +1,119 @@
>+/**********************************************************************
>*********
>+ * cryptodev.h
>+ *
>+ * Linux CryptoAPI user space interface module
>+ *
>+ * Copyright (c) 2008 Shasi Pulijala <[email protected]>
>+ *
>+ * 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.
>+ *
>+ * This program is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>+ * GNU General Public License for more details.
>+ *
>+ *
>+ * Detail Description:
>+ * This file defines ioctl structures for the Linux CryptoAPI
>interface. It
>+ * provides user space applications accesss into the Linux CryptoAPI
>+ * functionalities.
>+ *
>+
>************************************************************************
>*******
>+ */
>+#ifndef __CRYPTODEV_H__
>+#define __CRYPTODEV_H__
>+
>+/* Crypto and Hash Algorithms */
>+
>+#define CRYPTO_ALGORITHM_MIN 1
>+#define CRYPTO_DES_CBC 1
>+#define CRYPTO_3DES_CBC 2
>+#define CRYPTO_BLF_CBC 3
>+#define CRYPTO_CAST_CBC 4
>+#define CRYPTO_SKIPJACK_CBC 5
>+#define CRYPTO_MD5_HMAC 6
>+#define CRYPTO_SHA1_HMAC 7
>+#define CRYPTO_RIPEMD160_HMAC 8
>+#define CRYPTO_MD5_KPDK 9
>+#define CRYPTO_SHA1_KPDK 10
>+#define CRYPTO_RIJNDAEL128_CBC 11 /* 128 bit blocksize */
>+#define CRYPTO_AES_CBC 11 /* 128 bit blocksize */
>+#define CRYPTO_ARC4 12
>+#define CRYPTO_MD5 13
>+#define CRYPTO_SHA1 14
>+#define CRYPTO_NULL_HMAC 15
>+#define CRYPTO_NULL_CBC 16
>+#define CRYPTO_DEFLATE_COMP 17 /* Deflate compression
>algorithm */
>+#define CRYPTO_SHA2_256_HMAC 18
>+#define CRYPTO_SHA2_384_HMAC 19
>+#define CRYPTO_SHA2_512_HMAC 20
>+#define CRYPTO_CAMELLIA_CBC 21
>+#define CRYPTO_SHA2_256 22
>+#define CRYPTO_SHA2_384 23
>+#define CRYPTO_SHA2_512 24
>+#define CRYPTO_RIPEMD160 25
>+#define CRYPTO_AES_GCM 26
>+#define CRYPTO_AES_CCM 27
>+#define CRYPTO_ALGORITHM_MAX 28 /* Keep last */
>+
>+/**
>+ * @struct session_op
>+ * @brief ioctl parameter to create a session
>+ *
>+
>************************************************************************
>*******
>+ */
>+struct session_op {
>+ u32 cipher; /* e.g. CRYPTO_DES_CBC
>*/
>+ u32 mac; /* e.g. CRYPTO_MD5_HMAC
>*/
>+ u32 keylen; /* cipher key */
>+ char *key;
>+ int mackeylen; /* mac key length*/
>+ char *mackey; /* mackey(hmac)/authsize
>+ (ccm, gcm) */
>+
>+ /* Return values */
>+ u32 ses; /* session ID */
>+};
>+
>+#define CRYPTO_MAX_DATA_LEN 64*1024 - 1
>+/**
>+ * @struct crypt_op
>+ * @brief ioctl parameter to request a crypt/decrypt operation against
>a session
>+ *
>+
>************************************************************************
>*******
>+ */
>+struct crypt_op {
>+ u32 ses;
>+ u16 op; /* i.e. COP_ENCRYPT */
>+#define COP_NONE 0
>+#define COP_ENCRYPT 1
>+#define COP_DECRYPT 2
>+ u16 flags;
>+#define COP_F_BATCH 0x0008 /* Batch op if
>possible */
>+ u_int len;
>+ caddr_t src, dst; /* become sg inside
>kernel */
>+ caddr_t mac; /* must be big enough
>for
>+ chosen MAC */
>+ caddr_t iv;
>+};
>+
>+/* clone original filedescriptor */
>+#define CRIOGET _IOWR('c', 100, unsigned int)
>+
>+/* create crypto session */
>+#define CIOCGSESSION _IOWR('c', 101, struct session_op)
>+
>+/* finish crypto session */
>+#define CIOCFSESSION _IOW('c', 102, unsigned int)
>+
>+/* 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, unsigned int)
>+
>+#endif
>diff --git a/include/linux/fs.h b/include/linux/fs.h
>index b84b848..e9dc39e 100644
>--- a/include/linux/fs.h
>+++ b/include/linux/fs.h
>@@ -962,6 +962,7 @@ extern void __kill_fasync(struct fasync_struct *,
>int, int);
>
> extern int __f_setown(struct file *filp, struct pid *, enum pid_type,
>int force);
> extern int f_setown(struct file *filp, unsigned long arg, int force);
>+extern long __sys_dup(unsigned int fildes);
> extern void f_delown(struct file *filp);
> extern pid_t f_getown(struct file *filp);
> extern int send_sigurg(struct fown_struct *fown);
>--
>1.5.4.4
>--
>To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
>the body of a message to [email protected]
>More majordomo info at http://vger.kernel.org/majordomo-info.html

Sebastian

2008-05-14 11:03:26

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

On Wed, May 14, 2008 at 12:32:24PM +0200, Sebastian Siewior wrote:
>
> >This should add support for OpenSSL. Please note that user of this patch
> >musts patch OpenSSL. The OpenSSL patch can be found in OCF-Linux as this
> >interface uses the same I/O control interface.
> So this interface must stay as it in order not to patch openssl twice?

I don't think compatibility with OCF is necessary at all. We
should create an interface that is suitable for Linux first of
all rather than concentrating on OCF.

Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

2008-05-14 11:25:44

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

On Tue, May 13, 2008 at 05:00:58PM -0700, Loc Ho ([email protected]) wrote:
> Hi Herbert,
>
> I am re-sending this email as I don't believe it got to the mailing
> list. Due to email problem, I am forward this patch on behalf of Shasi
> Pulijala who worked on this user space interface for Linux CryptoAPI.
> This should add support for OpenSSL. Please note that user of this patch
> musts patch OpenSSL. The OpenSSL patch can be found in OCF-Linux as this
> interface uses the same I/O control interface.

There is number of problems with this patchset:
1. codying style - likely the most harmless
2. on-stack allocation should be dropped where possible
3. session id can be generated as pointer to session, not via getting
random bytes in a loop
4. linked list of in-flight session really does not scale
5. session destruction seems to be racy
6. do not use semaphores, mutex works ok here
7. lots of kmalloc/copy_*_user also much slower than single bigger
allocation and sinegle copy_*_user
8. use kzalloc instead of kmalloc/memset
9. having pointer in structure shared between kernel and
userspace is very wrong
10. userspace does not know about u32 and friends, use __u32 abd others
instead

Please also provide a high-level description of the protocol used for
crypto processing.

--
Evgeniy Polyakov

Subject: Userspace API proposal was: Re: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

* Herbert Xu | 2008-05-14 19:03:11 [+0800]:

>On Wed, May 14, 2008 at 12:32:24PM +0200, Sebastian Siewior wrote:
>>
>> >This should add support for OpenSSL. Please note that user of this patch
>> >musts patch OpenSSL. The OpenSSL patch can be found in OCF-Linux as this
>> >interface uses the same I/O control interface.
>> So this interface must stay as it in order not to patch openssl twice?
>
>I don't think compatibility with OCF is necessary at all. We
>should create an interface that is suitable for Linux first of
>all rather than concentrating on OCF.
Great. Here a few ideas for a new interface:
- /dev/crypto:
- open file, creates a new ctx which may be one of crypto/hash/...
- set type via ioctl / netlink
- set key / other attributes via ioctl
- put a block for encryption via write()
- wait until it is done. poll() could be used to determine this state
- read the result via read().
- ->final() (hash) could be executed on read()
- cryptofs attempt (somehow inspired by spufs):
- 1 syscall to create a special crypto device (that is aes(cbc),
hmac(sha1) or what ever the crypto api offers).
- returns a handle and creates a unique folder in cryptfs
- the folder is RW to the owner
- and contains properties of the algorithm. So we write in the file
keysize to specify the size of the key and write to the file key to
set the key. This properties are based on the class of the algorithm
(should be almost equal I guess).
- Every crypto request will be created once a file in the request
folder is created. Request is fed with data via the write().
- I'm not sure how we signalize that a request is done. Maybe another
file pops up and we can track this via inotify.

So I put this two for discussion :)
I came up with those two a while ago but never wrote code because I had
no use case.

>
>Cheers,

Sebastian

2008-05-14 12:19:13

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: Userspace API proposal was: Re: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

On Wed, May 14, 2008 at 01:57:30PM +0200, Sebastian Siewior ([email protected]) wrote:
> Great. Here a few ideas for a new interface:
> - /dev/crypto:
> - open file, creates a new ctx which may be one of crypto/hash/...
> - set type via ioctl / netlink
> - set key / other attributes via ioctl
> - put a block for encryption via write()
> - wait until it is done. poll() could be used to determine this state
> - read the result via read().
> - ->final() (hash) could be executed on read()

Above but without special device, but syscall instead, which will have
all needed parameters like mode string, key, iv and sizes.

> - cryptofs attempt (somehow inspired by spufs):
> - 1 syscall to create a special crypto device (that is aes(cbc),
> hmac(sha1) or what ever the crypto api offers).
> - returns a handle and creates a unique folder in cryptfs
> - the folder is RW to the owner
> - and contains properties of the algorithm. So we write in the file
> keysize to specify the size of the key and write to the file key to
> set the key. This properties are based on the class of the algorithm
> (should be almost equal I guess).
> - Every crypto request will be created once a file in the request
> folder is created. Request is fed with data via the write().
> - I'm not sure how we signalize that a request is done. Maybe another
> file pops up and we can track this via inotify.
>
> So I put this two for discussion :)
> I came up with those two a while ago but never wrote code because I had
> no use case.

Well, it might be time to start :)

I'm not sure virtual filesystem is needed though, but as well can be a
good idea. At least not ioctl hell with /dev/crypto

--
Evgeniy Polyakov

2008-05-14 15:04:49

by Loc Ho

[permalink] [raw]
Subject: RE: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

Hi,

Yes... It is intended not to patch OpenSSL twice. Besides the interface
API, the internal does NOT resemble OCF in anyway.

-Loc

-----Original Message-----
From: Herbert Xu [mailto:[email protected]]
Sent: Wednesday, May 14, 2008 4:03 AM
To: Sebastian Siewior
Cc: Loc Ho; Shasi Pulijala; [email protected]
Subject: Re: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

On Wed, May 14, 2008 at 12:32:24PM +0200, Sebastian Siewior wrote:
>
> >This should add support for OpenSSL. Please note that user of this
> >patch musts patch OpenSSL. The OpenSSL patch can be found in
> >OCF-Linux as this interface uses the same I/O control interface.
> So this interface must stay as it in order not to patch openssl twice?

I don't think compatibility with OCF is necessary at all. We should
create an interface that is suitable for Linux first of all rather than
concentrating on OCF.

Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]> Home Page:
http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

2008-05-14 15:41:07

by Loc Ho

[permalink] [raw]
Subject: RE: Userspace API proposal was: Re: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

Hi,

We here would like to create an user space interface that can be
accepted into Linux CryptoAPI. Therefore, let me summary the current
suggestion:

Option #1:
1. Use file descriptor named '/dev/crypto' or use syscall
2. Each opened file creates a new 'crypto' context that represents a
crypto algorithms - crypto, hash, compression, etc
3. The type of algorithm (#2) is selected via IO control call - like I/O
control with algorithm ASCII name
4. The key and other attributes are set via I/O control
5. Operation such as encrypt, decrypt, hash, and etc are operated via
function write and read. Caller is expected to read the entire result
blocks. If not, failed with an error code.
6. It supports asyncrhonous as file descriptor can be in non-blocking
mode
7. For hash and possible other operation, a read will also execute
final. I don't like this unless it is preceded with a flush call.

Option #2:
1. Use syscall with algorithm name and its associated parameters
2. Operation such as encrypt, decrypt, hash, and etc are operated via
another two system call - crypto_read and crypto_write
3. For this option, how should one handle asynchronous operation???

Option #3:

1. Use syscall to create a special crypto device folder per an algorithm
2. A handle is returned and a crypto filesystem entry is create for that
handle
3. Crypto parameter can be set based on read/write on that folder
4. Crypto operation will be based on file created under that folder. It
will inherit all crypto attributes of that folder.
5. And etc... (See previous email)
6. This approach is overkill and totally unnecessary.

Does this email summary all suggested solution? If not please add to
this list. Which one will like be accepted into the crypto tree???

-Loc

2008-05-14 16:01:23

by Herbert Xu

[permalink] [raw]
Subject: Re: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

On Wed, May 14, 2008 at 08:04:22AM -0700, Loc Ho wrote:
> Hi,
>
> Yes... It is intended not to patch OpenSSL twice. Besides the interface
> API, the internal does NOT resemble OCF in anyway.

But it's exactly the interface that would tie us down to OCF.
For instance, we use strings to locate algorithms rather than
hard-coded integer IDs. Compatibility with an interface that
was never part of the Linux kernel is simply not an issue.

Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

2008-05-14 16:09:53

by Evgeniy Polyakov

[permalink] [raw]
Subject: Re: Userspace API proposal was: Re: [PATCH 1/1] RFC: Add CryptoAPI User Space Interface Support

Hi.

On Wed, May 14, 2008 at 08:40:43AM -0700, Loc Ho ([email protected]) wrote:
> Option #2:
> 1. Use syscall with algorithm name and its associated parameters
> 2. Operation such as encrypt, decrypt, hash, and etc are operated via
> another two system call - crypto_read and crypto_write
> 3. For this option, how should one handle asynchronous operation???

No need to read/write syscall, initialization one returns a file
descriptor, which can be read/written via usual read/write calls.
It is also pollable.

> Option #3:
>
> 1. Use syscall to create a special crypto device folder per an algorithm
> 2. A handle is returned and a crypto filesystem entry is create for that
> handle
> 3. Crypto parameter can be set based on read/write on that folder
> 4. Crypto operation will be based on file created under that folder. It
> will inherit all crypto attributes of that folder.
> 5. And etc... (See previous email)
> 6. This approach is overkill and totally unnecessary.
>
> Does this email summary all suggested solution? If not please add to
> this list. Which one will like be accepted into the crypto tree???

Essentially it is the same as second one, but with aditional eye-candies
like simplified key management (some file in some dir written and key is
being changed).


Belive me, there will be always people, who do not like your interface,
whatever one you will create, with second or third approach such number
will be smaller, so just create what you like and prove your point is
strong. New interfaces is such a tasty ground for empty talks :)

--
Evgeniy Polyakov

2008-05-15 20:16:27

by Loc Ho

[permalink] [raw]
Subject: Linux CryptoAPI Userspace API proposal

Hi,

Linux Crypto User Space Interface Requirement:

1. Support crypto and hashing/digest
2. Flexible to support compression in the future
3. Flexible to support PKA (public key acceleration) in the future
4. A file descriptor per algorithms
5. Key and algorithm attributes provided by user space application
(caller)
6. Support non-blocking and blocking mode
7. Support multiple operation requests concurrently
8. Support cancel a pending operation for user space caller
9. Flexible to avoid double memory copy for future
10. scalable - meaning can operate on large amount of data if the
underlying algorithm support it. Hardware algorithm (such as HMAC
hashing) have a limit. This requirement complicate the interface. May
not support initially.

Linux Crypto User Space Interface Proposal:

1. Use file descriptor named '/dev/crypto'
2. Each opened file creates a new 'crypto' context that represents a
crypto algorithms - crypto, hash, compression, PKA, and etc
3. The type of algorithm, key, and other attributes are selected via IO
control call. This will be a single call.
4. Algorithm name maps directly into Linux CryptoAPI algorithm name
5. Interface for per operation (such as encrypt, decrypt, compress, PKA,
and hashing)
5a. Read and write functions
5a.1. Read and write functions are stream based. We are
packet based. Using this interface isn't quite appropriate. In addition,
the input data also has an output data. Read and write doesn't quite
correlate properly. This can be a problem as the output buffer isn't
available until the read operation is performed. In addition, the caller
will have to correlate between the write and read. If it is AIO, then
this would be simpler to correlate but still doesn't solve the problem
with an output buffer requirement. For crypto, the output can be the
input buffer. But what about hashing operation. This model just does fit
well. In addition, for PKA, input operands are bundled into a single
byte array. This makes it difficults to understand.
5b. I/O control calls
5b.1. The objection to this is 'I/O control hell'. This
isn't that bad. To handle asynchronous I/O, once can implement
asynchronous I/O control.
5c. System calls
5c.1. This can be used if majority of the community
don't like to use I/O control. The first input will be the file
descriptor.

Any comments or objection?

Herbert,

I haven't heard your comment. What do you think?

-Loc



2008-05-20 04:01:13

by Herbert Xu

[permalink] [raw]
Subject: Re: Linux CryptoAPI Userspace API proposal

On Thu, May 15, 2008 at 01:16:03PM -0700, Loc Ho wrote:
>
> Linux Crypto User Space Interface Requirement:
>
> 1. Support crypto and hashing/digest
> 2. Flexible to support compression in the future
> 3. Flexible to support PKA (public key acceleration) in the future

I think extensibility as you've noted is really important.

As the crypto API is really an algorithm API, please make this
interface generic enough so that adding new (potentially non-crypto)
operations is easy.

> 4. A file descriptor per algorithms
> 5. Key and algorithm attributes provided by user space application
> (caller)

I would say that a file descriptor per tfm would make more sense.

> 8. Support cancel a pending operation for user space caller

We don't need to be able to cancel a specific operation. The
ability to free a tfm and thereby flushing all requests associated
with it should be enough.

> 3. The type of algorithm, key, and other attributes are selected via IO
> control call. This will be a single call.

Being a single call doesn't matter too much here because this is
the slow path.

> 5. Interface for per operation (such as encrypt, decrypt, compress, PKA,
> and hashing)

It might be useful to consider an interface that allowed in-place
operations.

Cheers,
--
Visit Openswan at http://www.openswan.org/
Email: Herbert Xu ~{PmV>HI~} <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt

2008-06-04 21:33:37

by Loc Ho

[permalink] [raw]
Subject: RE: Linux CryptoAPI Userspace API proposal

Hi Herbert,

We re-work part of the user space API. I would like to run it by you for
comment:

The Linux CryptoAPI User Interface behaves as follow:

1. User access via file descriptor /dev/crypto
2. Each opened file dscriptor represents a tfm
3. Algorithm and properties are set via an I/O control function call.
4. Algorithm name is string based and other properties are the same as
before
5. Use I/O control for per operation such as encrypt, decrypt, compress,
PKA, and hashing.
5a. Synchrnous call supports only (for the moment) as asynchronous
requires notification and complicates the design
5b. Operation destinction/result is byte pointer based, which can be
in-line
5c. Use direct I/O (no memory copy between user space and kernel space,
except key, hash result, IV, and associated data)

We will be submitting soon...

-Loc

-----Original Message-----
From: Herbert Xu [mailto:[email protected]]
Sent: Monday, May 19, 2008 9:01 PM
To: Loc Ho
Cc: Evgeniy Polyakov; Sebastian Siewior; Shasi Pulijala;
[email protected]
Subject: Re: Linux CryptoAPI Userspace API proposal

On Thu, May 15, 2008 at 01:16:03PM -0700, Loc Ho wrote:
>
> Linux Crypto User Space Interface Requirement:
>
> 1. Support crypto and hashing/digest
> 2. Flexible to support compression in the future 3. Flexible to
> support PKA (public key acceleration) in the future

I think extensibility as you've noted is really important.

As the crypto API is really an algorithm API, please make this interface
generic enough so that adding new (potentially non-crypto) operations is
easy.

> 4. A file descriptor per algorithms
> 5. Key and algorithm attributes provided by user space application
> (caller)

I would say that a file descriptor per tfm would make more sense.

> 8. Support cancel a pending operation for user space caller

We don't need to be able to cancel a specific operation. The ability to
free a tfm and thereby flushing all requests associated with it should
be enough.

> 3. The type of algorithm, key, and other attributes are selected via
> IO control call. This will be a single call.

Being a single call doesn't matter too much here because this is the
slow path.

> 5. Interface for per operation (such as encrypt, decrypt, compress,
> PKA, and hashing)

It might be useful to consider an interface that allowed in-place
operations.