Signed-off-by: Cristian Stoica <cristian.sto...@nxp.com>
---
 crypto/cryptodev.h |   2 +-
 cryptodev_int.h    |  10 ++++
 ioctl.c            | 158 ++++++++++++++++++++++++++++++++++++++++++++---------
 main.c             |  38 ++++++++++++-
 4 files changed, 178 insertions(+), 30 deletions(-)

diff --git a/crypto/cryptodev.h b/crypto/cryptodev.h
index 20ae8ba..0b9f407 100644
--- a/crypto/cryptodev.h
+++ b/crypto/cryptodev.h
@@ -158,7 +158,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 d7660fa..df47780 100644
--- a/cryptodev_int.h
+++ b/cryptodev_int.h
@@ -95,6 +95,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;
 
@@ -114,6 +123,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 <cryptlib.h>
 
diff --git a/ioctl.c b/ioctl.c
index 53bac35..6157c8a 100644
--- a/ioctl.c
+++ b/ioctl.c
@@ -337,7 +337,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)
 {
@@ -808,7 +929,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;
@@ -874,52 +995,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 57e5c38..a736d99 100644
--- a/main.c
+++ b/main.c
@@ -158,8 +158,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)
@@ -265,3 +263,39 @@ 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;
+
+       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, NULL);
+               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.4.10


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

Reply via email to