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(¤t->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(¤t->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