Still ugly as hell (and therefore TODO): - no real error handling - 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) - ugly branching using is_compat_task() to stay compatible to 32bit userland from inside 64bit kernel ---
Hi! Please do not apply this patch as is - this is just meant for review, therefore I didn't bother removing debug output and dead code. IMO, a bigger rewrite of the internal routines in cryptodev_main.c is needed in order to support async operation in a clean manner: struct crypt_op should be used for communication with the user only, internally more things need to be passed around. For zero-copy, this is either the process' corresponding task_struct and mm_struct OR (when mapping pages at write() time) the set of user pages and scatterlists. In both cases (copy or not) the given IV needs to be held separately (the above mentioned copy_from_user problem) and most importantly some error reporting is needed. I'm looking forward to hearing your suggestions, hints and flame about my Kung Fu. :) Greetings, Phil --- .gitignore | 1 + Makefile | 3 +- cryptodev_int.h | 2 +- cryptodev_main.c | 356 +++++++++++++++++++++++++++++++++++++++++++---- examples/Makefile | 8 +- examples/async_cipher.c | 306 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 642 insertions(+), 34 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_int.h b/cryptodev_int.h index 15eb5bf..1a17413 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 */ diff --git a/cryptodev_main.c b/cryptodev_main.c index a27da96..eea6e78 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,26 @@ struct fcrypt { struct mutex sem; }; +union cryptask_result { + CR_GOOD = 0; + CR_BAD = 1; +}; + +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; + union cryptask_result 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 +545,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 +573,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 +619,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 +630,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 +642,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 +662,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 +701,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 +726,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 +762,38 @@ 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; + + printk(KERN_INFO "%s: being called\n", __func__); + + list_for_each_entry_safe(item, item_safe, &pcr->todo, __hook) { + mutex_lock(&item->sem); + printk(KERN_INFO "%s: calling crypto_run for item %lu\n", __func__, (unsigned long)item); + printk(KERN_INFO "%s: task is now %lu, mm %lu\n", __func__, (unsigned long)item->task, (unsigned long)item->mm); + /* FIXME: error handling! */ + if (crypto_run(&pcr->fcrypt, &item->cop, item->task, item->mm, item->iv)) { + item->result = CR_BAD; + printk(KERN_ERR "%s: crypto_run() failed!\n", __func__); + } else { + item->result = CR_GOOD; + } + 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 +803,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); + printk(KERN_INFO "%s: allocated new item at %lu\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 +825,36 @@ 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) { - crypto_finish_all_sessions(&pcr->fcrypt); - kfree(pcr); - filp->private_data = NULL; + printk(KERN_INFO "%s: being called\n", __func__); + if (!pcr) + return 0; + + cancel_work_sync(&pcr->cryptask); + printk(KERN_INFO "%s: canceled cryptask\n", __func__); + + list_splice_tail(&pcr->todo, &pcr->free); + list_splice_tail(&pcr->done, &pcr->free); + printk(KERN_INFO "%s: lists spliced\n", __func__); + + list_for_each_entry_safe(item, item_safe, &pcr->free, __hook) { + printk(KERN_INFO "%s: freeing item at %lu\n", __func__, (unsigned long)item); + list_del(&item->__hook); + printk(KERN_INFO "%s: deleted item from list\n", __func__); + kfree(item); + printk(KERN_INFO "%s: item kfree'd\n", __func__); + items_freed++; } + printk(KERN_INFO "%s: %d items freed\n", __func__, items_freed); + + crypto_finish_all_sessions(&pcr->fcrypt); + kfree(pcr); + filp->private_data = NULL; + printk(KERN_INFO "%s: returning\n", __func__); + dprintk(2, KERN_DEBUG, "Cryptodev handle deinitialised, %d elements freed\n", items_freed); return 0; } @@ -835,7 +922,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_) 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)))) @@ -949,7 +1036,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, 0, 0); if (unlikely(ret)) return ret; @@ -966,14 +1053,223 @@ cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_) #endif /* CONFIG_COMPAT */ +static ssize_t cryptodev_read(struct file *filp, char __user *buf, size_t buflen, loff_t *offset) +{ + int ret = 0; + struct crypt_priv *pcr = filp->private_data; + struct todo_list_item *item; + struct compat_crypt_op compat_cop; + + printk(KERN_INFO "%s: being called, buflen is %zd\n", __func__, buflen); + +again: + if (is_compat_task()) { + printk(KERN_INFO "%s: is compat task\n", __func__); + list_for_each_entry(item, &pcr->done, __hook) { + if (buflen - ret < sizeof(compat_cop)) + break; + + mutex_lock(&item->sem); + crypt_op_to_compat(&item->cop, &compat_cop); + /* + if (copy_to_user(item->cop.iv, item->iv, sizeof(item->cop.iv))) { + mutex_unlock(&item->sem); + break; + } + */ + if (copy_to_user(buf + ret, &compat_cop, sizeof(compat_cop))) { + mutex_unlock(&item->sem); + break; + } + list_move_tail(&item->__hook, &pcr->free); + mutex_unlock(&item->sem); + + ret += sizeof(compat_cop); + } + if (buflen - ret >= sizeof(compat_cop)) { + /* block when no done descriptors are available */ + while (list_empty(&pcr->done)) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (!list_empty(&pcr->done)) + break; + io_schedule(); + } + __set_current_state(TASK_RUNNING); + goto again; + } + } else { + list_for_each_entry(item, &pcr->done, __hook) { + if (buflen - ret <sizeof(item->cop)) + break; + + mutex_lock(&item->sem); + /* + if (copy_to_user(item->cop.iv, item->iv, sizeof(item->cop.iv))) { + mutex_unlock(&item->sem); + break; + } + */ + if (copy_to_user(buf + ret, &item->cop, sizeof(item->cop))) { + mutex_unlock(&item->sem); + break; + } + list_move_tail(&item->__hook, &pcr->free); + mutex_unlock(&item->sem); + + ret += sizeof(item->cop); + } + if (buflen - ret >= sizeof(struct crypt_op)) { + /* block when no done descriptors are available */ + while (list_empty(&pcr->done)) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (!list_empty(&pcr->done)) + break; + io_schedule(); + } + __set_current_state(TASK_RUNNING); + goto again; + } + } + if (ret) + wake_up_interruptible(&pcr->user_waiter); + return ret; + +} + +static ssize_t cryptodev_write(struct file *filp, + const char __user *buf, size_t buflen, loff_t *offset) +{ + int read = 0; + struct crypt_priv *pcr = filp->private_data; + struct todo_list_item *item; + struct compat_crypt_op compat_cop; + int i; + + printk(KERN_INFO "%s: being called, buflen is %zd, crypt_op is %zd bytes big\n", + __func__, buflen, sizeof(struct crypt_op)); + printk(KERN_INFO "%s: current is %lu, mm %lu\n", __func__, (unsigned long)current, (unsigned long)current->mm); + + /* + if (list_empty(pcr->free)) + return 0; + */ + +again: + if (is_compat_task()) { + printk(KERN_INFO "%s: is compat task\n", __func__); + list_for_each_entry(item, &pcr->free, __hook) { + if (buflen - read < sizeof(compat_cop)) + break; + + mutex_lock(&item->sem); + if (copy_from_user(&compat_cop, buf + read, sizeof(compat_cop))) { + printk(KERN_INFO "%s: copy_from_user for crypt_op failed!\n", __func__); + mutex_unlock(&item->sem); + return -EFAULT; + } + memset(&item->cop, 0, sizeof(item->cop)); + memset(item->iv, 0, EALG_MAX_BLOCK_LEN); + compat_to_crypt_op(&compat_cop, &item->cop); + //if (copy_from_user(item->iv, item->cop.iv, sizeof(item->cop.iv))) { + if (copy_from_user(item->iv, item->cop.iv, 16)) { + printk(KERN_INFO "%s: copy_from_user for IV failed!\n", __func__); + mutex_unlock(&item->sem); + return -EFAULT; + } + printk(KERN_INFO "%s: IV is: ", __func__); + for (i = 0; i < 16; i++) + printk("%02x ", item->iv[i]); + printk("\n"); + item->task = current; + item->mm = current->mm; + list_move_tail(&item->__hook, &pcr->todo); + mutex_unlock(&item->sem); + + read += sizeof(compat_cop); + } + schedule_work(&pcr->cryptask); + + /* block when no free descriptors are available */ + if (buflen - read >= sizeof(compat_cop)) { + while (list_empty(&pcr->free)) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (!list_empty(&pcr->free)) + break; + io_schedule(); + } + __set_current_state(TASK_RUNNING); + goto again; + } + } else { + list_for_each_entry(item, &pcr->free, __hook) { + if (buflen - read < sizeof(item->cop)) + break; + + mutex_lock(&item->sem); + memset(&item->cop, 0, sizeof(item->cop)); + memset(item->iv, 0, EALG_MAX_BLOCK_LEN); + if (copy_from_user(&item->cop, buf + read, sizeof(item->cop))) { + printk(KERN_INFO "%s: copy_from_user for crypt_op failed!\n", __func__); + mutex_unlock(&item->sem); + return -EFAULT; + } + if (copy_from_user(item->iv, item->cop.iv, sizeof(item->cop.iv))) { + printk(KERN_INFO "%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); + + read += sizeof(item->cop); + } + schedule_work(&pcr->cryptask); + /* block when no free descriptors are available */ + if (buflen - read >= sizeof(struct crypt_op)) { + while (list_empty(&pcr->free)) { + set_current_state(TASK_UNINTERRUPTIBLE); + if (!list_empty(&pcr->free)) + break; + io_schedule(); + } + __set_current_state(TASK_RUNNING); + goto again; + } + } + /* TODO: trigger work_queue */ + return read; +} + +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; + + printk(KERN_INFO "%s: returning %x\n", __func__, ret); + return ret; +} + static const struct file_operations cryptodev_fops = { .owner = THIS_MODULE, .open = cryptodev_open, + .read = cryptodev_read, + .write = cryptodev_write, .release = cryptodev_release, .unlocked_ioctl = cryptodev_ioctl, #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..ee6a1f5 --- /dev/null +++ b/examples/async_cipher.c @@ -0,0 +1,306 @@ +/* + * 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; + } + + + /* 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; + } + + if (ioctl(cfd, CIOCFSESSION, &sess.ses)) { + perror("ioctl(CIOCFSESSION)"); + return 1; + } + + if (ioctl(cfd, CIOCGSESSION, &sess)) { + perror("ioctl(CIOCGSESSION)"); + return 1; + } + + /* 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; + } + + /* 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 (write(cfd, &cryp1, sizeof(cryp1)) < sizeof(cryp1)) { + perror("write(cryp1)"); + 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 (write(cfd, &cryp2, sizeof(cryp2)) < sizeof(cryp2)) { + perror("write(cryp2)"); + 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 (read(cfd, &cryp1, sizeof(cryp1)) < sizeof(cryp1) || + read(cfd, &cryp2, sizeof(cryp2)) < sizeof(cryp2)) { + perror("read(cryp1 + cryp2)"); + 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