From f123f38532ae022e818312a9bc04cdb287e9623f Mon Sep 17 00:00:00 2001 From: Cristian Stoica Date: Thu, 17 Dec 2015 10:34:20 +0200 Subject: [PATCH 35/38] use directly crypto API 'digest' operation for CIOCHASH Signed-off-by: Cristian Stoica --- crypto/cryptodev.h | 2 +- cryptodev_int.h | 10 ++++ ioctl.c | 158 ++++++++++++++++++++++++++++++++++++++++++++--------- main.c | 39 ++++++++++++- 4 files changed, 179 insertions(+), 30 deletions(-) diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h index c6083f7..9ade102 100644 --- a/crypto/cryptodev.h +++ b/crypto/cryptodev.h @@ -169,7 +169,7 @@ struct crypt_auth_op { /* data container for CIOCHASH operations */ struct hash_op_data { - __u32 ses; /* session identifier */ + struct csession *ses; /* session identifier */ __u32 mac_op; /* cryptodev_crypto_op_t */ __u8 *mackey; __u32 mackeylen; diff --git a/cryptodev_int.h b/cryptodev_int.h index cb005d7..74c295a 100644 --- a/cryptodev_int.h +++ b/cryptodev_int.h @@ -164,6 +164,15 @@ struct kernel_crypt_op { struct mm_struct *mm; }; +struct kernel_hash_op { + struct hash_op_data hash_op; + + int digestsize; + uint8_t hash_output[AALG_MAX_RESULT_LEN]; + struct task_struct *task; + struct mm_struct *mm; +}; + struct kernel_crypt_auth_op { struct crypt_auth_op caop; @@ -192,6 +201,7 @@ int kcaop_to_user(struct kernel_crypt_auth_op *kcaop, struct fcrypt *fcr, void __user *arg); int crypto_auth_run(struct fcrypt *fcr, struct kernel_crypt_auth_op *kcaop); int crypto_run(struct fcrypt *fcr, struct kernel_crypt_op *kcop); +int hash_run(struct kernel_hash_op *khop); #include diff --git a/ioctl.c b/ioctl.c index 3763954..a052614 100644 --- a/ioctl.c +++ b/ioctl.c @@ -397,7 +397,128 @@ session_error: return ret; } -/* Everything that needs to be done when removing a session. */ +static inline void hash_destroy_session(struct csession *ses_ptr) +{ + cryptodev_hash_deinit(&ses_ptr->hdata); + kfree(ses_ptr->pages); + kfree(ses_ptr->sg); + kfree(ses_ptr); +} + +static int hash_create_session(struct hash_op_data *hash_op) +{ + struct csession *ses; + int ret = 0; + const char *hash_name; + int hmac_mode = 1; + uint8_t mkey[CRYPTO_HMAC_MAX_KEY_LEN]; + + switch (hash_op->mac_op) { + case CRYPTO_MD5_HMAC: + hash_name = "hmac(md5)"; + break; + case CRYPTO_RIPEMD160_HMAC: + hash_name = "hmac(rmd160)"; + break; + case CRYPTO_SHA1_HMAC: + hash_name = "hmac(sha1)"; + break; + case CRYPTO_SHA2_224_HMAC: + hash_name = "hmac(sha224)"; + break; + case CRYPTO_SHA2_256_HMAC: + hash_name = "hmac(sha256)"; + break; + case CRYPTO_SHA2_384_HMAC: + hash_name = "hmac(sha384)"; + break; + case CRYPTO_SHA2_512_HMAC: + hash_name = "hmac(sha512)"; + break; + /* non-hmac cases */ + case CRYPTO_MD5: + hash_name = "md5"; + hmac_mode = 0; + break; + case CRYPTO_RIPEMD160: + hash_name = "rmd160"; + hmac_mode = 0; + break; + case CRYPTO_SHA1: + hash_name = "sha1"; + hmac_mode = 0; + break; + case CRYPTO_SHA2_224: + hash_name = "sha224"; + hmac_mode = 0; + break; + case CRYPTO_SHA2_256: + hash_name = "sha256"; + hmac_mode = 0; + break; + case CRYPTO_SHA2_384: + hash_name = "sha384"; + hmac_mode = 0; + break; + case CRYPTO_SHA2_512: + hash_name = "sha512"; + hmac_mode = 0; + break; + default: + ddebug(1, "bad mac: %d", hash_op->mac_op); + return -EINVAL; + } + + ses = kzalloc(sizeof(*ses), GFP_KERNEL); + if (!ses) { + return -ENOMEM; + } + + if (unlikely(hash_op->mackeylen > CRYPTO_HMAC_MAX_KEY_LEN)) { + ddebug(1, "Setting key failed for %s-%zu.", hash_name, + (size_t)hash_op->mackeylen * 8); + ret = -EINVAL; + goto error_hash; + } + + if (hash_op->mackey && + unlikely(copy_from_user(mkey, hash_op->mackey, hash_op->mackeylen))) { + ret = -EFAULT; + goto error_hash; + } + + ret = cryptodev_hash_init(&ses->hdata, hash_name, hmac_mode, + mkey, hash_op->mackeylen); + if (ret != 0) { + ddebug(1, "Failed to load hash for %s", hash_name); + ret = -EINVAL; + goto error_hash; + } + + ses->alignmask = ses->hdata.alignmask; + ddebug(2, "got alignmask %d", ses->alignmask); + + ses->array_size = DEFAULT_PREALLOC_PAGES; + ddebug(2, "preallocating for %d user pages", ses->array_size); + + ses->pages = kzalloc(ses->array_size * sizeof(struct page *), GFP_KERNEL); + ses->sg = kzalloc(ses->array_size * sizeof(struct scatterlist), GFP_KERNEL); + if (ses->sg == NULL || ses->pages == NULL) { + ddebug(0, "Memory error"); + ret = -ENOMEM; + goto error_hash; + } + + hash_op->ses = ses; + return 0; + +error_hash: + hash_destroy_session(ses); + return ret; +} + + +/* Everything that needs to be done when remowing a session. */ static inline void crypto_destroy_session(struct csession *ses_ptr) { @@ -960,7 +1081,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_) void __user *arg = (void __user *)arg_; int __user *p = arg; struct session_op sop; - struct hash_op_data hash_op; + struct kernel_hash_op khop; struct kernel_crypt_op kcop; struct kernel_crypt_auth_op kcaop; struct crypt_priv *pcr = filp->private_data; @@ -1051,52 +1172,35 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg_) return kcop_to_user(&kcop, fcr, arg); case CIOCHASH: - /* get session */ - if (unlikely(copy_from_user(&hash_op, arg, sizeof(struct hash_op_data)))) { + if (unlikely(copy_from_user(&khop.hash_op, arg, sizeof(struct hash_op_data)))) { pr_err("copy from user fault\n"); return -EFAULT; } + khop.task = current; + khop.mm = current->mm; - sop.cipher = 0; - sop.mac = hash_op.mac_op; - sop.mackey = hash_op.mackey; - sop.mackeylen = hash_op.mackeylen; - - /* writes sop.ses as a side-effect */ - ret = crypto_create_session(fcr, &sop); + /* get session */ + ret = hash_create_session(&khop.hash_op); if (unlikely(ret)) { pr_err("can't get session\n"); return ret; } /* do hashing */ - kcop.cop.ses = sop.ses; - kcop.cop.flags = hash_op.flags; - kcop.cop.len = hash_op.len; - kcop.cop.src = hash_op.src; - kcop.cop.mac = hash_op.mac_result; - kcop.cop.dst = 0; - kcop.cop.op = 0; - kcop.cop.iv = 0; - kcop.ivlen = 0; - kcop.digestsize = 0; /* will be updated during operation */ - kcop.task = current; - kcop.mm = current->mm; - - ret = crypto_run(fcr, &kcop); + ret = hash_run(&khop); if (unlikely(ret)) { dwarning(1, "Error in hash run"); return ret; } - ret = copy_to_user(kcop.cop.mac, kcop.hash_output, kcop.digestsize); + ret = copy_to_user(khop.hash_op.mac_result, khop.hash_output, khop.digestsize); if (unlikely(ret)) { dwarning(1, "Error in copy to user"); return ret; } /* put session */ - ret = crypto_finish_session(fcr, sop.ses); + hash_destroy_session(khop.hash_op.ses); return 0; case CIOCAUTHCRYPT: if (unlikely(ret = kcaop_from_user(&kcaop, fcr, arg))) { diff --git a/main.c b/main.c index ec11129..095aea5 100644 --- a/main.c +++ b/main.c @@ -159,8 +159,6 @@ __crypto_run_std(struct csession *ses_ptr, struct crypt_op *cop) return ret; } - - /* This is the main crypto function - zero-copy edition */ static int __crypto_run_zc(struct csession *ses_ptr, struct kernel_crypt_op *kcop) @@ -841,3 +839,40 @@ out_unlock: crypto_put_session(ses_ptr); return ret; } + +int hash_run(struct kernel_hash_op *khop) +{ + struct hash_op_data *hash_op = &khop->hash_op; + struct csession *ses_ptr = hash_op->ses; + struct hash_data *hdata = &ses_ptr->hdata; + int ret; + struct scatterlist *src_sg; + struct scatterlist *dst_sg; /* required by get_userbuf but not used */ + + if (hash_op->len == 0) { + src_sg = NULL; + } else { + ret = get_userbuf(ses_ptr, hash_op->src, hash_op->len, NULL, 0, + khop->task, khop->mm, &src_sg, &dst_sg); + if (unlikely(ret)) { + derr(1, "Error getting user pages"); + return ret; + } + } + + ahash_request_set_crypt(hdata->async.request, src_sg, khop->hash_output, hash_op->len); + + ret = crypto_ahash_digest(hdata->async.request); + if (ret == -EINPROGRESS || ret == -EBUSY) { + wait_for_completion(&hdata->async.result.completion); + ret = hdata->async.result.err; + if (ret != 0) { + derr(0, "CryptoAPI failure: %d", ret); + } + } + + khop->digestsize = ses_ptr->hdata.digestsize; + + release_user_pages(ses_ptr); + return ret; +} -- 2.7.0