This time insertion and collection of asynchronous jobs is implemented
via ioctl calls.

DONE since first working version:
- error handling: any error code occuring during the completion of a job
  is saved and returned by ioctl() upon collection. The requested struct
  crypt_op is copied to userspace anyway, so the caller knows which one
  of the inserted jobs failed.
- No need for is_compat_task() anymore, since the compat ioctl
  infrastructure is simply used for that purpose.

Still ugly as hell (and therefore TODO):
- having to pass task_struct and mm_struct from the calling process
  around
- need to copy the IV right at write() time (copy_from_user seems to
  work in process context only)
---
Hi,

still, please do not apply as is. Though it's getting better, I still want to
solve the TODO entries above (and split the whole mess up into a bunch of
patches) before anything serious is done with it.

What do you think about the preallocated list items? The implementation is
flexible enough to allow for creating them right when they're needed (i.e.
pcr->free becomes empty). Also, one could make the amount of (preallocated)
items variable, similar to how get_userbuf() does with the struct page array.

Greetings, Phil
---
 .gitignore              |    1 +
 Makefile                |    3 +-
 cryptodev.h             |    4 +
 cryptodev_int.h         |    4 +-
 cryptodev_main.c        |  235 ++++++++++++++++++++++++++++++-----
 examples/Makefile       |    8 +-
 examples/async_cipher.c |  313 +++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 532 insertions(+), 36 deletions(-)
 create mode 100644 examples/async_cipher.c

diff --git a/.gitignore b/.gitignore
index 8b6dce9..4335219 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ modules.order
 examples/cipher
 examples/hmac
 examples/speed
+examples/async_cipher
 releases
 scripts
 version.h
diff --git a/Makefile b/Makefile
index cd6c8d8..bd84e5e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,5 @@
-KERNEL_DIR = /lib/modules/$(shell uname -r)/build
+#KERNEL_DIR = /lib/modules/$(shell uname -r)/build
+KERNEL_DIR = /home/n0-1/git/make-embedded/linux-2.6
 VERSION = 0.5
 
 cryptodev-objs = cryptodev_main.o cryptodev_cipher.o
diff --git a/cryptodev.h b/cryptodev.h
index e2a8484..97a54ab 100644
--- a/cryptodev.h
+++ b/cryptodev.h
@@ -159,4 +159,8 @@ enum cryptodev_crk_op_t {
 #define CIOCKEY         _IOWR('c', 105, struct crypt_kop)
 #define CIOCASYMFEAT    _IOR('c', 106, __u32)
 
+/* additional ioctls for asynchronous  operation */
+#define CIOCASYNCCRYPT    _IOW('c', 107, struct crypt_op)
+#define CIOCASYNCFETCH    _IOR('c', 108, struct crypt_op)
+
 #endif /* L_CRYPTODEV_H */
diff --git a/cryptodev_int.h b/cryptodev_int.h
index 15eb5bf..2697cb5 100644
--- a/cryptodev_int.h
+++ b/cryptodev_int.h
@@ -26,7 +26,7 @@ extern int cryptodev_verbosity;
 
 /* For zero copy */
 int __get_userbuf(uint8_t __user *addr, uint32_t len, int write,
-               int pgcount, struct page **pg, struct scatterlist *sg);
+               int pgcount, struct page **pg, struct scatterlist *sg, struct 
task_struct *task, struct mm_struct *mm);
 void release_user_pages(struct page **pg, int pagecount);
 
 /* last page - first page + 1 */
@@ -114,6 +114,8 @@ struct compat_session_op {
 /* compat ioctls, defined for the above structs */
 #define COMPAT_CIOCGSESSION    _IOWR('c', 102, struct compat_session_op)
 #define COMPAT_CIOCCRYPT       _IOWR('c', 104, struct compat_crypt_op)
+#define COMPAT_CIOCASYNCCRYPT  _IOW('c', 107, struct compat_crypt_op)
+#define COMPAT_CIOCASYNCFETCH  _IOR('c', 108, struct compat_crypt_op)
 
 #endif /* CONFIG_COMPAT */
 
diff --git a/cryptodev_main.c b/cryptodev_main.c
index a27da96..01008ef 100644
--- a/cryptodev_main.c
+++ b/cryptodev_main.c
@@ -39,12 +39,16 @@
 #include <linux/random.h>
 #include <linux/syscalls.h>
 #include <linux/pagemap.h>
+#include <linux/poll.h>
 #include <linux/uaccess.h>
 #include "cryptodev.h"
 #include <linux/scatterlist.h>
 #include "cryptodev_int.h"
 #include "version.h"
 
+/* power of two! */
+#define DEF_COP_RINGSIZE 16
+
 MODULE_AUTHOR("Nikos Mavrogiannopoulos <n...@gnutls.org>");
 MODULE_DESCRIPTION("CryptoDev driver");
 MODULE_LICENSE("GPL");
@@ -71,8 +75,21 @@ struct fcrypt {
        struct mutex sem;
 };
 
+struct todo_list_item {
+       struct list_head __hook;
+       struct crypt_op cop;
+       uint8_t iv[EALG_MAX_BLOCK_LEN];
+       struct mutex sem;
+       struct task_struct *task;
+       struct mm_struct *mm;
+       int result;
+};
+
 struct crypt_priv {
        struct fcrypt fcrypt;
+       struct list_head free, todo, done;
+       struct work_struct cryptask;
+       wait_queue_head_t user_waiter;
 };
 
 #define FILL_SG(sg, ptr, len)                                  \
@@ -523,15 +540,15 @@ void release_user_pages(struct page **pg, int pagecount)
 
 /* fetch the pages addr resides in into pg and initialise sg with them */
 int __get_userbuf(uint8_t __user *addr, uint32_t len, int write,
-               int pgcount, struct page **pg, struct scatterlist *sg)
+               int pgcount, struct page **pg, struct scatterlist *sg, struct 
task_struct *task, struct mm_struct *mm)
 {
        int ret, pglen, i = 0;
        struct scatterlist *sgp;
 
-       down_write(&current->mm->mmap_sem);
-       ret = get_user_pages(current, current->mm,
+       down_write(&mm->mmap_sem);
+       ret = get_user_pages(task, mm,
                        (unsigned long)addr, pgcount, write, 0, pg, NULL);
-       up_write(&current->mm->mmap_sem);
+       up_write(&mm->mmap_sem);
        if (ret != pgcount)
                return -EINVAL;
 
@@ -551,8 +568,8 @@ int __get_userbuf(uint8_t __user *addr, uint32_t len, int 
write,
 }
 
 /* make cop->src and cop->dst available in scatterlists */
-static int get_userbuf(struct csession *ses,
-               struct crypt_op *cop, struct scatterlist **src_sg,
+static int get_userbuf(struct csession *ses, struct crypt_op *cop,
+               struct task_struct *task, struct mm_struct *mm, struct 
scatterlist **src_sg,
                struct scatterlist **dst_sg, int *tot_pages)
 {
        int src_pagecount, dst_pagecount = 0, pagecount, write_src = 1;
@@ -597,7 +614,7 @@ static int get_userbuf(struct csession *ses,
        }
 
        if (__get_userbuf(cop->src, cop->len, write_src,
-                       src_pagecount, ses->pages, ses->sg)) {
+                       src_pagecount, ses->pages, ses->sg, task, mm)) {
                dprintk(1, KERN_ERR,
                        "failed to get user pages for data input\n");
                return -EINVAL;
@@ -608,7 +625,7 @@ static int get_userbuf(struct csession *ses,
                (*dst_sg) = ses->sg + src_pagecount;
 
                if (__get_userbuf(cop->dst, cop->len, 1, dst_pagecount,
-                                       ses->pages + src_pagecount, *dst_sg)) {
+                                       ses->pages + src_pagecount, *dst_sg, 
task, mm)) {
                        dprintk(1, KERN_ERR,
                                "failed to get user pages for data output\n");
                        release_user_pages(ses->pages, src_pagecount);
@@ -620,12 +637,12 @@ static int get_userbuf(struct csession *ses,
 
 /* This is the main crypto function - zero-copy edition */
 static int
-__crypto_run_zc(struct csession *ses_ptr, struct crypt_op *cop)
+__crypto_run_zc(struct csession *ses_ptr, struct crypt_op *cop, struct 
task_struct *task, struct mm_struct *mm)
 {
        struct scatterlist *src_sg, *dst_sg;
        int ret = 0, pagecount;
 
-       ret = get_userbuf(ses_ptr, cop, &src_sg, &dst_sg, &pagecount);
+       ret = get_userbuf(ses_ptr, cop, task, mm, &src_sg, &dst_sg, &pagecount);
        if (unlikely(ret)) {
                dprintk(1, KERN_ERR, "Error getting user pages. \
                                        Falling back to non zero copy.\n");
@@ -640,7 +657,7 @@ __crypto_run_zc(struct csession *ses_ptr, struct crypt_op 
*cop)
 
 #endif /* DISABLE_ZCOPY */
 
-static int crypto_run(struct fcrypt *fcr, struct crypt_op *cop)
+static int crypto_run(struct fcrypt *fcr, struct crypt_op *cop, struct 
task_struct *task, struct mm_struct *mm, u8 *user_iv)
 {
        struct csession *ses_ptr;
        uint8_t hash_output[AALG_MAX_RESULT_LEN];
@@ -679,21 +696,23 @@ static int crypto_run(struct fcrypt *fcr, struct crypt_op 
*cop)
                        goto out_unlock;
                }
 
-               if (cop->iv) {
+               if (cop->iv || user_iv) {
                        uint8_t iv[EALG_MAX_BLOCK_LEN];
-
-                       ret = copy_from_user(iv, cop->iv,
-                               min((int)sizeof(iv), (ses_ptr->cdata.ivsize)));
-                       if (unlikely(ret)) {
-                               dprintk(1, KERN_ERR,
-                                       "error copying IV (%d bytes)\n",
-                                       min((int)sizeof(iv),
-                                       (ses_ptr->cdata.ivsize)));
-                               ret = -EFAULT;
-                               goto out_unlock;
+                       if (!user_iv) {
+
+                               ret = copy_from_user(iv, cop->iv,
+                                       min((int)sizeof(iv), 
(ses_ptr->cdata.ivsize)));
+                               if (unlikely(ret)) {
+                                       dprintk(1, KERN_ERR,
+                                               "error copying IV (%d bytes), 
copy_from_user returned %d for address %lx\n",
+                                               min((int)sizeof(iv),
+                                               (ses_ptr->cdata.ivsize)), ret, 
(unsigned long)cop->iv);
+                                       ret = -EFAULT;
+                                       goto out_unlock;
+                               }
                        }
 
-                       cryptodev_cipher_set_iv(&ses_ptr->cdata, iv,
+                       cryptodev_cipher_set_iv(&ses_ptr->cdata, user_iv ? 
user_iv : iv,
                                                ses_ptr->cdata.ivsize);
                }
        }
@@ -702,7 +721,7 @@ static int crypto_run(struct fcrypt *fcr, struct crypt_op 
*cop)
 #ifdef DISABLE_ZCOPY
                ret = __crypto_run_std(ses_ptr, cop);
 #else /* normal */
-               ret = __crypto_run_zc(ses_ptr, cop);
+               ret = __crypto_run_zc(ses_ptr, cop, task, mm);
 #endif
                if (unlikely(ret))
                        goto out_unlock;
@@ -738,12 +757,29 @@ out_unlock:
        return ret;
 }
 
+static void cryptask_routine(struct work_struct *work)
+{
+       struct crypt_priv *pcr = container_of(work, struct crypt_priv, 
cryptask);
+       struct todo_list_item *item, *item_safe;
+
+       list_for_each_entry_safe(item, item_safe, &pcr->todo, __hook) {
+               mutex_lock(&item->sem);
+               if ((item->result = crypto_run(&pcr->fcrypt, &item->cop, 
item->task, item->mm, item->iv)))
+                       dprintk(0, KERN_ERR, "%s: crypto_run() failed: %d\n", 
__func__, item->result);
+               list_move(&item->__hook, &pcr->done);
+               mutex_unlock(&item->sem);
+
+               wake_up_interruptible(&pcr->user_waiter);
+       }
+}
+
 /* ====== /dev/crypto ====== */
 
 static int
 cryptodev_open(struct inode *inode, struct file *filp)
 {
        struct crypt_priv *pcr;
+       int i;
 
        pcr = kmalloc(sizeof(*pcr), GFP_KERNEL);
        if (!pcr)
@@ -753,7 +789,21 @@ cryptodev_open(struct inode *inode, struct file *filp)
        mutex_init(&pcr->fcrypt.sem);
        INIT_LIST_HEAD(&pcr->fcrypt.list);
 
+       INIT_LIST_HEAD(&pcr->free);
+       INIT_LIST_HEAD(&pcr->todo);
+       INIT_LIST_HEAD(&pcr->done);
+       INIT_WORK(&pcr->cryptask, cryptask_routine);
+       init_waitqueue_head(&pcr->user_waiter);
+
+       for (i = 0; i < DEF_COP_RINGSIZE; i++) {
+               struct todo_list_item *tmp = kzalloc(sizeof(struct 
todo_list_item), GFP_KERNEL);
+               dprintk(2, KERN_DEBUG, "%s: allocated new item at %lx\n", 
__func__, (unsigned long)tmp);
+               mutex_init(&tmp->sem);
+               list_add(&tmp->__hook, &pcr->free);
+       }
+
        filp->private_data = pcr;
+       dprintk(2, KERN_DEBUG, "Cryptodev handle initialised, %d elements in 
queue\n", DEF_COP_RINGSIZE);
        return 0;
 }
 
@@ -761,13 +811,29 @@ static int
 cryptodev_release(struct inode *inode, struct file *filp)
 {
        struct crypt_priv *pcr = filp->private_data;
+       struct todo_list_item *item, *item_safe;
+       int items_freed = 0;
+
+       if (!pcr)
+               return 0;
 
-       if (pcr) {
-               crypto_finish_all_sessions(&pcr->fcrypt);
-               kfree(pcr);
-               filp->private_data = NULL;
+       cancel_work_sync(&pcr->cryptask);
+
+       list_splice_tail(&pcr->todo, &pcr->free);
+       list_splice_tail(&pcr->done, &pcr->free);
+
+       list_for_each_entry_safe(item, item_safe, &pcr->free, __hook) {
+               dprintk(2, KERN_DEBUG, "%s: freeing item at %lx\n", __func__, 
(unsigned long)item);
+               list_del(&item->__hook);
+               kfree(item);
+               items_freed++;
        }
 
+       crypto_finish_all_sessions(&pcr->fcrypt);
+       kfree(pcr);
+       filp->private_data = NULL;
+
+       dprintk(2, KERN_DEBUG, "Cryptodev handle deinitialised, %d elements 
freed\n", items_freed);
        return 0;
 }
 
@@ -784,6 +850,64 @@ clonefd(struct file *filp)
        return ret;
 }
 
+/* enqueue a job for asynchronous completion
+ *
+ * returns:
+ * -EBUSY when there are no free queue slots left
+ * -EFAULT on memory access error
+ * 0 on success */
+static int crypto_async_run(struct crypt_priv *pcr, struct crypt_op *cop)
+{
+       struct todo_list_item *item;
+
+       if (list_empty(&pcr->free))
+               return -EBUSY;
+       item = list_first_entry(&pcr->free, struct todo_list_item, __hook);
+
+       mutex_lock(&item->sem);
+
+       memcpy(&item->cop, cop, sizeof(struct crypt_op));
+       if (copy_from_user(item->iv, item->cop.iv, sizeof(item->cop.iv))) {
+               dprintk(0, KERN_ERR, "%s: copy_from_user for IV failed!\n", 
__func__);
+               mutex_unlock(&item->sem);
+               return -EFAULT;
+       }
+       item->task = current;
+       item->mm = current->mm;
+       list_move_tail(&item->__hook, &pcr->todo);
+
+       mutex_unlock(&item->sem);
+
+       schedule_work(&pcr->cryptask);
+       return 0;
+}
+
+/* get the first completed job from the "done" queue
+ *
+ * returns:
+ * -EBUSY if no completed jobs are ready (yet)
+ * the return value of crypto_run() otherwise */
+static int crypto_async_fetch(struct crypt_priv *pcr, struct crypt_op *cop)
+{
+       struct todo_list_item *item;
+       int retval;
+
+       if (list_empty(&pcr->done))
+               return -EBUSY;
+       item = list_first_entry(&pcr->done, struct todo_list_item, __hook);
+
+       mutex_lock(&item->sem);
+
+       memcpy(cop, &item->cop, sizeof(struct crypt_op));
+       retval = item->result;
+       list_move_tail(&item->__hook, &pcr->free);
+
+       mutex_unlock(&item->sem);
+
+       wake_up_interruptible(&pcr->user_waiter);
+       return retval;
+}
+
 static long
 cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_)
 {
@@ -804,6 +928,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, 
unsigned long arg_)
        switch (cmd) {
        case CIOCASYMFEAT:
                return put_user(0, p);
+
        case CRIOGET:
                fd = clonefd(filp);
                ret = put_user(fd, p);
@@ -812,6 +937,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, 
unsigned long arg_)
                        return ret;
                }
                return ret;
+
        case CIOCGSESSION:
                if (unlikely(copy_from_user(&sop, arg, sizeof(sop))))
                        return -EFAULT;
@@ -825,23 +951,36 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, 
unsigned long arg_)
                        return -EFAULT;
                }
                return ret;
+
        case CIOCFSESSION:
                ret = get_user(ses, (uint32_t __user *)arg);
                if (unlikely(ret))
                        return ret;
                ret = crypto_finish_session(fcr, ses);
                return ret;
+
        case CIOCCRYPT:
                if (unlikely(copy_from_user(&cop, arg, sizeof(cop))))
                        return -EFAULT;
 
-               ret = crypto_run(fcr, &cop);
+               ret = crypto_run(fcr, &cop, current, 0, 0);
                if (unlikely(ret))
                        return ret;
                if (unlikely(copy_to_user(arg, &cop, sizeof(cop))))
                        return -EFAULT;
                return 0;
 
+       case CIOCASYNCCRYPT:
+               if (unlikely(copy_from_user(&cop, arg, sizeof(cop))))
+                       return -EFAULT;
+               return crypto_async_run(pcr, &cop);
+
+       case CIOCASYNCFETCH:
+               ret = crypto_async_fetch(pcr, &cop);
+               if (copy_to_user(arg, &cop, sizeof(cop)))
+                       return -EFAULT;
+               return ret;
+
        default:
                return -EINVAL;
        }
@@ -908,15 +1047,17 @@ static long
 cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
 {
        void __user *arg = (void __user *)arg_;
-       struct fcrypt *fcr = file->private_data;
+       struct crypt_priv *pcr = file->private_data;
+       struct fcrypt *fcr;
        struct session_op sop;
        struct compat_session_op compat_sop;
        struct crypt_op cop;
        struct compat_crypt_op compat_cop;
        int ret;
 
-       if (unlikely(!fcr))
+       if (unlikely(!pcr))
                BUG();
+       fcr = &pcr->fcrypt;
 
        switch (cmd) {
        case CIOCASYMFEAT:
@@ -949,7 +1090,7 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg_)
 
                compat_to_crypt_op(&compat_cop, &cop);
 
-               ret = crypto_run(fcr, &cop);
+               ret = crypto_run(fcr, &cop, current, current->mm, 0);
                if (unlikely(ret))
                        return ret;
 
@@ -959,6 +1100,19 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg_)
                        return -EFAULT;
                return 0;
 
+       case COMPAT_CIOCASYNCCRYPT:
+               if (unlikely(copy_from_user(&compat_cop, arg, 
sizeof(compat_cop))))
+                       return -EFAULT;
+               compat_to_crypt_op(&compat_cop, &cop);
+               return crypto_async_run(pcr, &cop);
+
+       case COMPAT_CIOCASYNCFETCH:
+               ret = crypto_async_fetch(pcr, &cop);
+               crypt_op_to_compat(&cop, &compat_cop);
+               if (copy_to_user(arg, &compat_cop, sizeof(compat_cop)))
+                       return -EFAULT;
+               return ret;
+
        default:
                return -EINVAL;
        }
@@ -966,6 +1120,22 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg_)
 
 #endif /* CONFIG_COMPAT */
 
+static unsigned int cryptodev_poll(struct file *file, poll_table *wait)
+{
+       struct crypt_priv *pcr = file->private_data;
+       int ret = 0;
+
+       poll_wait(file, &pcr->user_waiter, wait);
+
+       /* trigger for POLLIN when pcr->done is non-empty */
+       if (!list_empty(&pcr->done))
+               ret |= POLLIN | POLLRDNORM;
+       if (!list_empty(&pcr->free))
+               ret |= POLLOUT | POLLWRNORM;
+
+       return ret;
+}
+
 static const struct file_operations cryptodev_fops = {
        .owner = THIS_MODULE,
        .open = cryptodev_open,
@@ -974,6 +1144,7 @@ static const struct file_operations cryptodev_fops = {
 #ifdef CONFIG_COMPAT
        .compat_ioctl = cryptodev_compat_ioctl,
 #endif /* CONFIG_COMPAT */
+       .poll = cryptodev_poll,
 };
 
 static struct miscdevice cryptodev = {
diff --git a/examples/Makefile b/examples/Makefile
index 937eb6d..9ddec43 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -1,13 +1,17 @@
 KERNEL_DIR ?= /lib/modules/$(shell uname -r)/build
 
-hostprogs := cipher hmac speed
+CFLAGS=-m32
+
+#hostprogs := cipher hmac speed async-cipher
+hostprogs := async_cipher
 example-cipher-objs := cipher.o
 example-hmac-objs := hmac.o
 example-speed-objs := speed.c
+example-async_cipher-objs := async_cipher.o
 
 check: $(hostprogs)
        ./cipher
        ./hmac
 
 clean:
-       rm -f *.o *~ hmac cipher speed
+       rm -f *.o *~ hmac cipher speed async_cipher
diff --git a/examples/async_cipher.c b/examples/async_cipher.c
new file mode 100644
index 0000000..2095dc0
--- /dev/null
+++ b/examples/async_cipher.c
@@ -0,0 +1,313 @@
+/*
+ * Demo on how to use /dev/crypto device for ciphering.
+ *
+ * Placed under public domain.
+ *
+ */
+#include <poll.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sys/ioctl.h>
+#include <crypto/cryptodev.h>
+
+#define        DATA_SIZE       8*1024
+#define        BLOCK_SIZE      16
+#define        KEY_SIZE        16
+
+static int
+test_crypto(int cfd)
+{
+       char plaintext[DATA_SIZE];
+       char ciphertext[DATA_SIZE];
+       char iv[BLOCK_SIZE];
+       char key[KEY_SIZE];
+
+       struct session_op sess;
+       struct crypt_op cryp;
+
+       printf("running %s\n", __func__);
+
+       memset(&sess, 0, sizeof(sess));
+       memset(&cryp, 0, sizeof(cryp));
+
+       memset(plaintext, 0x15,  sizeof(plaintext));
+       memset(key, 0x33,  sizeof(key));
+       memset(iv, 0x03,  sizeof(iv));
+
+       /* Get crypto session for AES128 */
+       sess.cipher = CRYPTO_AES_CBC;
+       sess.keylen = KEY_SIZE;
+       sess.key = key;
+       if (ioctl(cfd, CIOCGSESSION, &sess)) {
+               perror("ioctl(CIOCGSESSION)");
+               return 1;
+       }
+
+       printf("%s: got the session\n", __func__);
+
+
+       /* Encrypt data.in to data.encrypted */
+       cryp.ses = sess.ses;
+       cryp.len = sizeof(plaintext);
+       cryp.src = plaintext;
+       cryp.dst = ciphertext;
+       cryp.iv = iv;
+       cryp.op = COP_ENCRYPT;
+       if (ioctl(cfd, CIOCCRYPT, &cryp)) {
+               perror("ioctl(CIOCCRYPT)");
+               return 1;
+       }
+       printf("%s: data encrypted\n", __func__);
+
+       if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
+               perror("ioctl(CIOCFSESSION)");
+               return 1;
+       }
+       printf("%s: session finished\n", __func__);
+
+       if (ioctl(cfd, CIOCGSESSION, &sess)) {
+               perror("ioctl(CIOCGSESSION)");
+               return 1;
+       }
+       printf("%s: got new session\n", __func__);
+       
+       /* Decrypt data.encrypted to data.decrypted */
+       cryp.ses = sess.ses;
+       cryp.len = sizeof(plaintext);
+       cryp.src = ciphertext;
+       cryp.dst = ciphertext;
+       cryp.iv = iv;
+       cryp.op = COP_DECRYPT;
+       if (ioctl(cfd, CIOCCRYPT, &cryp)) {
+               perror("ioctl(CIOCCRYPT)");
+               return 1;
+       }
+       printf("%s: data encrypted\n", __func__);
+
+       /* Verify the result */
+       if (memcmp(plaintext, ciphertext, sizeof(plaintext)) != 0) {
+               fprintf(stderr,
+                       "FAIL: Decrypted data are different from the input 
data.\n");
+               return 1;
+       } else
+               printf("Test passed\n");
+
+       /* Finish crypto session */
+       if (ioctl(cfd, CIOCFSESSION, &sess.ses)) {
+               perror("ioctl(CIOCFSESSION)");
+               return 1;
+       }
+
+       return 0;
+}
+
+static int test_aes(int cfd)
+{
+       char plaintext1[BLOCK_SIZE];
+       char ciphertext1[BLOCK_SIZE] = { 0xdf, 0x55, 0x6a, 0x33, 0x43, 0x8d, 
0xb8, 0x7b, 0xc4, 0x1b, 0x17, 0x52, 0xc5, 0x5e, 0x5e, 0x49 };
+       char iv1[BLOCK_SIZE];
+       char key1[KEY_SIZE] = { 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       char plaintext2[BLOCK_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00 };
+       char ciphertext2[BLOCK_SIZE] = { 0xb7, 0x97, 0x2b, 0x39, 0x41, 0xc4, 
0x4b, 0x90, 0xaf, 0xa7, 0xb2, 0x64, 0xbf, 0xba, 0x73, 0x87 };
+       char iv2[BLOCK_SIZE];
+       char key2[KEY_SIZE];
+
+       struct session_op sess1, sess2;
+       struct crypt_op cryp1, cryp2;
+       struct pollfd pfd;
+
+       printf("running %s\n", __func__);
+
+       memset(&sess1, 0, sizeof(sess1));
+       memset(&sess2, 0, sizeof(sess2));
+       memset(&cryp1, 0, sizeof(cryp1));
+       memset(&cryp2, 0, sizeof(cryp2));
+
+       memset(plaintext1, 0x0, sizeof(plaintext1));
+       memset(iv1, 0x0, sizeof(iv1));
+
+       /* Get crypto session for AES128 */
+       sess1.cipher = CRYPTO_AES_CBC;
+       sess1.keylen = KEY_SIZE;
+       sess1.key = key1;
+       if (ioctl(cfd, CIOCGSESSION, &sess1)) {
+               perror("ioctl(CIOCGSESSION)");
+               return 1;
+       }
+
+       memset(key2, 0x0, sizeof(key2));
+
+       /* Get second crypto session for AES128 */
+       sess2.cipher = CRYPTO_AES_CBC;
+       sess2.keylen = KEY_SIZE;
+       sess2.key = key2;
+       if (ioctl(cfd, CIOCGSESSION, &sess2)) {
+               perror("ioctl(CIOCGSESSION)");
+               return 1;
+       }
+
+       pfd.fd = cfd;
+       pfd.events = POLLOUT;
+       if (poll(&pfd, 1, 0) < 1) {
+               perror("poll()");
+               return 1;
+       }
+       printf("poll() returned good\n");
+
+       /* Encrypt data.in to data.encrypted */
+       cryp1.ses = sess1.ses;
+       cryp1.len = sizeof(plaintext1);
+       cryp1.src = plaintext1;
+       cryp1.dst = plaintext1;
+       cryp1.iv = iv1;
+       cryp1.op = COP_ENCRYPT;
+       if (ioctl(cfd, CIOCASYNCCRYPT, &cryp1)) {
+               perror("ioctl(CIOCASYNCCRYPT)");
+               return 1;
+       }
+
+       printf("cryp1 written out\n");
+
+       memset(iv2, 0x0, sizeof(iv2));
+
+       /* Encrypt data.in to data.encrypted */
+       cryp2.ses = sess2.ses;
+       cryp2.len = sizeof(plaintext2);
+       cryp2.src = plaintext2;
+       cryp2.dst = plaintext2;
+       cryp2.iv = iv2;
+       cryp2.op = COP_ENCRYPT;
+
+       pfd.fd = cfd;
+       pfd.events = POLLOUT;
+       if (poll(&pfd, 1, 0) < 1) {
+               perror("poll()");
+               return 1;
+       }
+       printf("poll() returned good\n");
+
+       if (ioctl(cfd, CIOCASYNCCRYPT, &cryp2)) {
+               perror("ioctl(CIOCASYNCCRYPT)");
+               return 1;
+       }
+       printf("cryp2 written out\n");
+
+       pfd.fd = cfd;
+       pfd.events = POLLIN;
+       if (poll(&pfd, 1, 0) < 1) {
+               perror("poll()");
+               return 1;
+       }
+       printf("poll() returned good\n");
+
+       if (ioctl(cfd, CIOCASYNCFETCH, &cryp1) ||
+           ioctl(cfd, CIOCASYNCFETCH, &cryp2)) {
+               perror("ioctl(CIOCASYNCFETCH)");
+               return 1;
+       }
+       printf("cryp1 + cryp2 successfully read\n");
+
+       /* Verify the result */
+       if (memcmp(plaintext1, ciphertext1, sizeof(plaintext1)) != 0) {
+               int i;
+               fprintf(stderr,
+                       "FAIL: Decrypted data are different from the input 
data.\n");
+               printf("cipher text should be:\t");
+               for (i = 0; i < BLOCK_SIZE; i++) {
+                       printf("%02x ", (unsigned char)ciphertext1[i]);
+               }
+               printf("\nbut really is:\t\t");
+               for (i = 0; i < BLOCK_SIZE; i++) {
+                       printf("%02x ", (unsigned char)plaintext1[i]);
+               }
+               printf("\n");
+               return 1;
+       } else {
+               printf("result 1 passed\n");
+       }
+
+       /* Test 2 */
+
+       /* Verify the result */
+       if (memcmp(plaintext2, ciphertext2, sizeof(plaintext2)) != 0) {
+               int i;
+               fprintf(stderr,
+                       "FAIL: Decrypted data are different from the input 
data.\n");
+               printf("cipher text should be:\t");
+               for (i = 0; i < BLOCK_SIZE; i++) {
+                       printf("%02x ", (unsigned char)ciphertext2[i]);
+               }
+               printf("\nbut really is:\t\t");
+               for (i = 0; i < BLOCK_SIZE; i++) {
+                       printf("%02x ", (unsigned char)plaintext2[i]);
+               }
+               printf("\n");
+               return 1;
+       } else {
+               printf("result 2 passed\n");
+       }
+
+       printf("AES Test passed\n");
+
+       /* Finish crypto session */
+       if (ioctl(cfd, CIOCFSESSION, &sess1.ses)) {
+               perror("ioctl(CIOCFSESSION)");
+               return 1;
+       }
+       if (ioctl(cfd, CIOCFSESSION, &sess2.ses)) {
+               perror("ioctl(CIOCFSESSION)");
+               return 1;
+       }
+
+       return 0;
+}
+
+int
+main()
+{
+       int fd = -1, cfd = -1;
+
+       /* Open the crypto device */
+       fd = open("/dev/crypto", O_RDWR, 0);
+       if (fd < 0) {
+               perror("open(/dev/crypto)");
+               return 1;
+       }
+
+       /* Clone file descriptor */
+       if (ioctl(fd, CRIOGET, &cfd)) {
+               perror("ioctl(CRIOGET)");
+               return 1;
+       }
+
+       /* Set close-on-exec (not really neede here) */
+       if (fcntl(cfd, F_SETFD, 1) == -1) {
+               perror("fcntl(F_SETFD)");
+               return 1;
+       }
+
+       /* Run the test itself */
+       if (test_aes(cfd))
+               return 1;
+
+       if (test_crypto(cfd))
+               return 1;
+
+       /* Close cloned descriptor */
+       if (close(cfd)) {
+               perror("close(cfd)");
+               return 1;
+       }
+
+       /* Close the original descriptor */
+       if (close(fd)) {
+               perror("close(fd)");
+               return 1;
+       }
+
+       return 0;
+}
+
-- 
1.7.2.2



_______________________________________________
Cryptodev-linux-devel mailing list
Cryptodev-linux-devel@gna.org
https://mail.gna.org/listinfo/cryptodev-linux-devel

Reply via email to