When trying to en-/decrypt a buffer using CBC in two steps by passing a
part from the buffer's start at first, and then the remaining data in
the second call, the second operation depends on the first one in that
it's IV depends on it's result.

Insiders know of course, that the IV of any CBC block to operate on is
simply the enciphered last block. So this patch is maybe most useful for
everyone else, altering the passed IV upon returning the results.

I see two possible problems with this patch:

1) Since it changes existing behaviour, it may be (yet another) attempt
   to accidentially turn cryptodev incompatible to OCF.

2) Beware of const input data. When the user's code does something like
   this:
   | cop.iv = "totally cool IV";
   everything will probably blow up.

But still, things aren't completely hopeless: there is still the 'flags'
field, so I could define CRYPTO_FLAG_UPDATE_IV or something.
---
 cryptodev_int.h  |    6 +++
 cryptodev_main.c |   99 ++++++++++++++++++++++++++++++++----------------------
 2 files changed, 65 insertions(+), 40 deletions(-)

diff --git a/cryptodev_int.h b/cryptodev_int.h
index 4d9d6f6..ba20326 100644
--- a/cryptodev_int.h
+++ b/cryptodev_int.h
@@ -66,6 +66,12 @@ inline static void cryptodev_cipher_set_iv(struct 
cipher_data *cdata,
        memcpy(cdata->async.iv, iv, min(iv_size, sizeof(cdata->async.iv)));
 }
 
+inline static void cryptodev_cipher_get_iv(struct cipher_data *cdata,
+                               void *iv, size_t iv_size)
+{
+       memcpy(iv, cdata->async.iv, min(iv_size, sizeof(cdata->async.iv)));
+}
+
 /* hash stuff */
 struct hash_data {
        int init; /* 0 uninitialized */
diff --git a/cryptodev_main.c b/cryptodev_main.c
index 7e174aa..26892d1 100644
--- a/cryptodev_main.c
+++ b/cryptodev_main.c
@@ -738,6 +738,11 @@ static int crypto_run(struct fcrypt *fcr, struct 
kernel_crypt_op *kcop)
                        goto out_unlock;
        }
 
+       if (ses_ptr->cdata.init != 0) {
+               cryptodev_cipher_get_iv(&ses_ptr->cdata, kcop->iv,
+                               min(ses_ptr->cdata.ivsize, kcop->ivlen));
+       }
+
        if (ses_ptr->hdata.init != 0 &&
                ((cop->flags & COP_FLAG_FINAL) ||
                   (!(cop->flags & COP_FLAG_UPDATE) || cop->len == 0))) {
@@ -999,6 +1004,26 @@ static int fill_kcop_from_cop(struct kernel_crypt_op 
*kcop, struct fcrypt *fcr)
        return 0;
 }
 
+/* this function has to be called from process context */
+static int fill_cop_from_kcop(struct kernel_crypt_op *kcop, struct fcrypt *fcr)
+{
+       int ret;
+
+       if (kcop->digestsize) {
+               ret = copy_to_user(kcop->cop.mac,
+                               kcop->hash_output, kcop->digestsize);
+               if (unlikely(ret))
+                       return -EFAULT;
+       }
+       if (kcop->ivlen) {
+               ret = copy_to_user(kcop->cop.iv,
+                               kcop->iv, kcop->ivlen);
+               if (unlikely(ret))
+                       return -EFAULT;
+       }
+       return 0;
+}
+
 static int kcop_from_user(struct kernel_crypt_op *kcop,
                        struct fcrypt *fcr, void __user *arg)
 {
@@ -1008,6 +1033,20 @@ static int kcop_from_user(struct kernel_crypt_op *kcop,
        return fill_kcop_from_cop(kcop, fcr);
 }
 
+static int kcop_to_user(struct kernel_crypt_op *kcop,
+                       struct fcrypt *fcr, void __user *arg)
+{
+       int ret;
+
+       ret = fill_cop_from_kcop(kcop, fcr);
+       if (unlikely(ret))
+               return ret;
+
+       if (unlikely(copy_to_user(arg, &kcop->cop, sizeof(kcop->cop))))
+               return -EFAULT;
+       return 0;
+}
+
 static inline void tfm_info_to_alg_info(struct alg_info *dst, struct 
crypto_tfm *tfm)
 {
        snprintf(dst->cra_name, CRYPTODEV_MAX_ALG_NAME,
@@ -1104,15 +1143,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, 
unsigned long arg_)
                if (unlikely(ret))
                        return ret;
 
-               if (kcop.digestsize) {
-                       ret = copy_to_user(kcop.cop.mac,
-                                       kcop.hash_output, kcop.digestsize);
-                       if (unlikely(ret))
-                               return -EFAULT;
-               }
-               if (unlikely(copy_to_user(arg, &kcop.cop, sizeof(kcop.cop))))
-                       return -EFAULT;
-               return 0;
+               return kcop_to_user(&kcop, fcr, arg);
        case CIOCASYNCCRYPT:
                if (unlikely(ret = kcop_from_user(&kcop, fcr, arg)))
                        return ret;
@@ -1123,15 +1154,7 @@ cryptodev_ioctl(struct file *filp, unsigned int cmd, 
unsigned long arg_)
                if (unlikely(ret))
                        return ret;
 
-               if (kcop.digestsize) {
-                       ret = copy_to_user(kcop.cop.mac,
-                                       kcop.hash_output, kcop.digestsize);
-                       if (unlikely(ret))
-                               return -EFAULT;
-               }
-
-               return copy_to_user(arg, &kcop.cop, sizeof(kcop.cop));
-
+               return kcop_to_user(&kcop, fcr, arg);
        default:
                return -EINVAL;
        }
@@ -1206,6 +1229,22 @@ static int compat_kcop_from_user(struct kernel_crypt_op 
*kcop,
        return fill_kcop_from_cop(kcop, fcr);
 }
 
+static int compat_kcop_to_user(struct kernel_crypt_op *kcop,
+                                 struct fcrypt *fcr, void __user *arg)
+{
+       int ret;
+       struct compat_crypt_op compat_cop;
+
+       ret = fill_cop_from_kcop(kcop, fcr);
+       if (unlikely(ret))
+               return ret;
+       crypt_op_to_compat(&kcop->cop, &compat_cop);
+
+       if (unlikely(copy_to_user(arg, &compat_cop, sizeof(compat_cop))))
+               return -EFAULT;
+       return 0;
+}
+
 static long
 cryptodev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg_)
 {
@@ -1215,7 +1254,6 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg_)
        struct session_op sop;
        struct compat_session_op compat_sop;
        struct kernel_crypt_op kcop;
-       struct compat_crypt_op compat_cop;
        int ret;
 
        if (unlikely(!pcr))
@@ -1257,18 +1295,7 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg_)
                if (unlikely(ret))
                        return ret;
 
-               if (kcop.digestsize) {
-                       ret = copy_to_user(kcop.cop.mac,
-                                       kcop.hash_output, kcop.digestsize);
-                       if (unlikely(ret))
-                               return -EFAULT;
-               }
-
-               crypt_op_to_compat(&kcop.cop, &compat_cop);
-               if (unlikely(copy_to_user(arg, &compat_cop,
-                                         sizeof(compat_cop))))
-                       return -EFAULT;
-               return 0;
+               return compat_kcop_to_user(&kcop, fcr, arg);
        case COMPAT_CIOCASYNCCRYPT:
                if (unlikely(ret = compat_kcop_from_user(&kcop, fcr, arg)))
                        return ret;
@@ -1279,15 +1306,7 @@ cryptodev_compat_ioctl(struct file *file, unsigned int 
cmd, unsigned long arg_)
                if (unlikely(ret))
                        return ret;
 
-               if (kcop.digestsize) {
-                       ret = copy_to_user(kcop.cop.mac,
-                                       kcop.hash_output, kcop.digestsize);
-                       if (unlikely(ret))
-                               return -EFAULT;
-               }
-
-               crypt_op_to_compat(&kcop.cop, &compat_cop);
-               return copy_to_user(arg, &compat_cop, sizeof(compat_cop));
+               return compat_kcop_to_user(&kcop, fcr, arg);
 
        default:
                return -EINVAL;
-- 
1.7.3.4



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

Reply via email to