diff options
-rw-r--r-- | cryptodev.c | 184 | ||||
-rw-r--r-- | cryptodev.h | 29 | ||||
-rw-r--r-- | cryptodev.mod.c | 57 |
3 files changed, 139 insertions, 131 deletions
diff --git a/cryptodev.c b/cryptodev.c index 6007648..76581c4 100644 --- a/cryptodev.c +++ b/cryptodev.c @@ -401,10 +401,7 @@ crypto_get_session_by_sid(struct fcrypt *fcr, uint32_t sid) return ses_ptr; } -/* This is the main crypto function - feed it with plaintext - and get a ciphertext (or vice versa :-) */ -static int -crypto_run(struct fcrypt *fcr, struct crypt_op *cop) +static int crypto_runv(struct fcrypt *fcr, struct crypt_opv *copv) { char *data, ivp[EALG_MAX_BLOCK_LEN]; char __user *src, __user *dst; @@ -414,6 +411,7 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop) size_t nbytes, bufsize; int ret = 0; uint8_t hash_output[HASH_MAX_LEN]; + int blocksize=1, i; struct blkcipher_desc bdesc = { .flags = CRYPTO_TFM_REQ_MAY_SLEEP, }; @@ -422,29 +420,27 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop) }; - if (unlikely(cop->op != COP_ENCRYPT && cop->op != COP_DECRYPT)) { - dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", cop->op); + if (unlikely(copv->op != COP_ENCRYPT && copv->op != COP_DECRYPT)) { + dprintk(1, KERN_DEBUG, "invalid operation op=%u\n", copv->op); return -EINVAL; } - ses_ptr = crypto_get_session_by_sid(fcr, cop->ses); + ses_ptr = crypto_get_session_by_sid(fcr, copv->ses); if (!ses_ptr) { - dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", cop->ses); + dprintk(1, KERN_ERR, "invalid session ID=0x%08X\n", copv->ses); return -EINVAL; } - nbytes = cop->len; data = (char*)__get_free_page(GFP_KERNEL); if (unlikely(!data)) { ret = -ENOMEM; goto out_unlock; } - bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes; - nbytes = cop->len; bdesc.tfm = ses_ptr->tfm; hdesc.tfm = ses_ptr->hash_tfm; + if (hdesc.tfm) { ret = crypto_hash_init(&hdesc); if (unlikely(ret)) { @@ -455,7 +451,21 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop) } if (ses_ptr->tfm) { - if (nbytes % crypto_blkcipher_blocksize(ses_ptr->tfm)) { + blocksize = crypto_blkcipher_blocksize(ses_ptr->tfm); + ivsize = crypto_blkcipher_ivsize(ses_ptr->tfm); + + if (copv->iv) { + copy_from_user(ivp, copv->iv, ivsize); + crypto_blkcipher_set_iv(ses_ptr->tfm, ivp, ivsize); + } + } + + dst = copv->dst; + + for (i=0;i<copv->iovec_cnt;i++) { + nbytes = copv->iovec[i].len; + + if (unlikely(bdesc.tfm && (nbytes % blocksize))) { dprintk(1, KERN_ERR, "data size (%zu) isn't a multiple of block size (%u)\n", nbytes, crypto_blkcipher_blocksize(ses_ptr->tfm)); @@ -463,70 +473,74 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop) goto out_unlock; } - ivsize = crypto_blkcipher_ivsize(ses_ptr->tfm); - - if (cop->iv) { - copy_from_user(ivp, cop->iv, ivsize); - crypto_blkcipher_set_iv(ses_ptr->tfm, ivp, ivsize); - } - } - - src = cop->src; - dst = cop->dst; + bufsize = PAGE_SIZE < nbytes ? PAGE_SIZE : nbytes; + src = copv->iovec[i].src; - while(nbytes > 0) { - size_t current_len = nbytes > bufsize ? bufsize : nbytes; + while(nbytes > 0) { + size_t current_len = nbytes > bufsize ? bufsize : nbytes; - copy_from_user(data, src, current_len); + copy_from_user(data, src, current_len); - sg_set_buf(&sg, data, current_len); + sg_set_buf(&sg, data, current_len); - /* Always hash before encryption and after decryption. Maybe - * we should introduce a flag to switch... TBD later on. - */ - if (cop->op == COP_ENCRYPT) { - if (hdesc.tfm) { - ret = crypto_hash_update(&hdesc, &sg, current_len); - if (unlikely(ret)) { - dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret); - goto out; + /* Always hash before encryption and after decryption. Maybe + * we should introduce a flag to switch... TBD later on. + */ + if (copv->op == COP_ENCRYPT) { + if (hdesc.tfm && (copv->iovec[i].op_flags & IOP_HASH)) { + ret = crypto_hash_update(&hdesc, &sg, current_len); + if (unlikely(ret)) { + dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret); + goto out; + } } - } - if (bdesc.tfm) { - ret = crypto_blkcipher_encrypt(&bdesc, &sg, &sg, current_len); - - if (unlikely(ret)) { - dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret); - goto out; + if (bdesc.tfm && (copv->iovec[i].op_flags & IOP_CIPHER)) { + ret = crypto_blkcipher_encrypt(&bdesc, &sg, &sg, current_len); + + if (unlikely(ret)) { + dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret); + goto out; + } + copy_to_user(dst, data, current_len); + dst += current_len; } - copy_to_user(dst, data, current_len); - dst += current_len; - } - } else { - if (bdesc.tfm) { - ret = crypto_blkcipher_decrypt(&bdesc, &sg, &sg, current_len); + } else { + if (bdesc.tfm && (copv->iovec[i].op_flags & IOP_CIPHER)) { + ret = crypto_blkcipher_decrypt(&bdesc, &sg, &sg, current_len); - if (unlikely(ret)) { - dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret); - goto out; - } - copy_to_user(dst, data, current_len); - dst += current_len; + if (unlikely(ret)) { + dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret); + goto out; + } + copy_to_user(dst, data, current_len); + dst += current_len; - } + } - if (hdesc.tfm) { - ret = crypto_hash_update(&hdesc, &sg, current_len); - if (unlikely(ret)) { - dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret); - goto out; + if (hdesc.tfm && (copv->iovec[i].op_flags & IOP_HASH)) { + ret = crypto_hash_update(&hdesc, &sg, current_len); + if (unlikely(ret)) { + dprintk(0, KERN_ERR, "CryptoAPI failure: %d\n",ret); + goto out; + } } } + + nbytes -= current_len; + src += current_len; } - nbytes -= current_len; - src += current_len; +#if defined(CRYPTODEV_STATS) + if (enable_stats) { + /* this is safe - we check cop->op at the function entry */ + ses_ptr->stat[copv->op] += copv->iovec[i].len; + if (ses_ptr->stat_max_size < copv->iovec[i].len) + ses_ptr->stat_max_size = copv->iovec[i].len; + ses_ptr->stat_count++; + } +#endif + } if (hdesc.tfm) { @@ -536,19 +550,9 @@ crypto_run(struct fcrypt *fcr, struct crypt_op *cop) goto out; } - copy_to_user(cop->mac, hash_output, crypto_hash_digestsize(ses_ptr->hash_tfm)); + copy_to_user(copv->mac, hash_output, crypto_hash_digestsize(ses_ptr->hash_tfm)); } -#if defined(CRYPTODEV_STATS) - if (enable_stats) { - /* this is safe - we check cop->op at the function entry */ - ses_ptr->stat[cop->op] += cop->len; - if (ses_ptr->stat_max_size < cop->len) - ses_ptr->stat_max_size = cop->len; - ses_ptr->stat_count++; - } -#endif - out: free_page((unsigned long)data); @@ -558,6 +562,33 @@ out_unlock: return ret; } +/* This is the main crypto function - feed it with plaintext + and get a ciphertext (or vice versa :-) */ +static int crypto_run(struct fcrypt *fcr, struct crypt_op *cop) +{ + struct crypt_opv copv; + struct crypt_iovec iovec; + + iovec.src = cop->src; + iovec.len = cop->len; + iovec.op_flags = IOP_CIPHER|IOP_HASH; + + copv.op = cop->op; + copv.ses = cop->ses; + copv.flags = cop->flags; + copv.iovec = &iovec; + copv.iovec_cnt = 1; + + copv.dst = cop->dst; + copv.mac = cop->mac; + copv.iv = cop->iv; + + return crypto_runv(fcr, &copv); + +} + + + /* ====== /dev/crypto ====== */ static int @@ -613,6 +644,7 @@ cryptodev_ioctl(struct inode *inode, struct file *filp, int __user *p = (void __user *)arg; struct session_op sop; struct crypt_op cop; + struct crypt_opv copv; struct fcrypt *fcr = filp->private_data; uint32_t ses; int ret, fd; @@ -648,6 +680,12 @@ cryptodev_ioctl(struct inode *inode, struct file *filp, copy_to_user((void*)arg, &cop, sizeof(cop)); return ret; + case CIOCCRYPTV: + copy_from_user(&cop, (void*)arg, sizeof(copv)); + ret = crypto_runv(fcr, &copv); + copy_to_user((void*)arg, &copv, sizeof(copv)); + return ret; + default: return -EINVAL; } diff --git a/cryptodev.h b/cryptodev.h index 895ad1c..891ad2a 100644 --- a/cryptodev.h +++ b/cryptodev.h @@ -75,7 +75,7 @@ struct crypt_op { uint32_t ses; /* from session_op->ses */ #define COP_DECRYPT 0 #define COP_ENCRYPT 1 - uint32_t op; /* ie. COP_ENCRYPT */ + uint16_t op; /* ie. COP_ENCRYPT */ uint32_t flags; /* unused */ size_t len; @@ -84,6 +84,30 @@ struct crypt_op { void *iv; }; +struct crypt_iovec { +#define IOP_CIPHER 1 +#define IOP_HASH 2 + uint16_t op_flags; /* ie. IOP_CIPHER|IOP_HASH */ + void *src; + size_t len; +}; + +/* ioctl parameter to request a crypt/decrypt operation against a session */ +struct crypt_opv { + uint32_t ses; /* from session_op->ses */ + #define COP_DECRYPT 0 + #define COP_ENCRYPT 1 + uint16_t op; /* ie. COP_ENCRYPT */ + uint32_t flags; /* unused */ + + struct crypt_iovec* iovec; + uint16_t iovec_cnt; + + void *dst; + void *mac; + void *iv; +}; + /* clone original filedescriptor */ #define CRIOGET _IOWR('c', 101, uint32_t) @@ -100,6 +124,9 @@ struct crypt_op { #define CIOCKEY _IOWR('c', 105, void *) #define CIOCASYMFEAT _IOR('c', 106, uint32_t) +/* request encryption/decryptions of a given buffer vector */ +#define CIOCCRYPTV _IOWR('c', 107, struct crypt_opv) + #endif /* _CRYPTODEV_H */ /* unused structures */ diff --git a/cryptodev.mod.c b/cryptodev.mod.c deleted file mode 100644 index 983f1f4..0000000 --- a/cryptodev.mod.c +++ /dev/null @@ -1,57 +0,0 @@ -#include <linux/module.h> -#include <linux/vermagic.h> -#include <linux/compiler.h> - -MODULE_INFO(vermagic, VERMAGIC_STRING); - -struct module __this_module -__attribute__((section(".gnu.linkonce.this_module"))) = { - .name = KBUILD_MODNAME, - .init = init_module, -#ifdef CONFIG_MODULE_UNLOAD - .exit = cleanup_module, -#endif - .arch = MODULE_ARCH_INIT, -}; - -static const struct modversion_info ____versions[] -__used -__attribute__((section("__versions"))) = { - { 0x903a5ec4, "module_layout" }, - { 0x6980fe91, "param_get_int" }, - { 0xff964b25, "param_set_int" }, - { 0x79aa04a2, "get_random_bytes" }, - { 0x4661e311, "__tracepoint_kmalloc" }, - { 0x893412fe, "kmem_cache_alloc" }, - { 0xadee93f3, "kmalloc_caches" }, - { 0x4e1e7401, "crypto_alloc_base" }, - { 0x4302d0eb, "free_pages" }, - { 0xe52947e7, "__phys_addr" }, - { 0x236c8c64, "memcpy" }, - { 0xbe499d81, "copy_to_user" }, - { 0x93fca811, "__get_free_pages" }, - { 0x37a0cba, "kfree" }, - { 0x3f1899f1, "up" }, - { 0x9bf377f5, "crypto_destroy_tfm" }, - { 0x9ced38aa, "down_trylock" }, - { 0x945bc6a7, "copy_from_user" }, - { 0x748caf40, "down" }, - { 0x6729d3df, "__get_user_4" }, - { 0xf0fdf6cb, "__stack_chk_fail" }, - { 0xb2fd5ceb, "__put_user_4" }, - { 0xa1c76e0a, "_cond_resched" }, - { 0xa62a61be, "fd_install" }, - { 0x99bfbe39, "get_unused_fd" }, - { 0xd8778690, "per_cpu__current_task" }, - { 0x54b8041c, "misc_register" }, - { 0xea147363, "printk" }, - { 0x11cef3ea, "misc_deregister" }, -}; - -static const char __module_depends[] -__used -__attribute__((section(".modinfo"))) = -"depends="; - - -MODULE_INFO(srcversion, "A0688FBD1488A8A38E2DF83"); |