crypto: geode-aes - switch to skcipher for cbc(aes) fallback
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Sat, 5 Oct 2019 09:11:10 +0000 (11:11 +0200)
committerHerbert Xu <herbert@gondor.apana.org.au>
Thu, 10 Oct 2019 12:42:45 +0000 (23:42 +1100)
Commit 79c65d179a40e145 ("crypto: cbc - Convert to skcipher") updated
the generic CBC template wrapper from a blkcipher to a skcipher algo,
to get away from the deprecated blkcipher interface. However, as a side
effect, drivers that instantiate CBC transforms using the blkcipher as
a fallback no longer work, since skciphers can wrap blkciphers but not
the other way around. This broke the geode-aes driver.

So let's fix it by moving to the sync skcipher interface when allocating
the fallback. At the same time, align with the generic API for ECB and
CBC by rejecting inputs that are not a multiple of the AES block size.

Fixes: 79c65d179a40e145 ("crypto: cbc - Convert to skcipher")
Cc: <stable@vger.kernel.org> # v4.20+ ONLY
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Signed-off-by: Florian Bezdeka <florian@bezdeka.de>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/geode-aes.c
drivers/crypto/geode-aes.h

index d81a1297cb9e5f75693a15ad3d50d7439ead3de1..940485112d152ae63701efca0b1a02ff42386a6a 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/spinlock.h>
 #include <crypto/algapi.h>
 #include <crypto/aes.h>
+#include <crypto/skcipher.h>
 
 #include <linux/io.h>
 #include <linux/delay.h>
@@ -166,13 +167,15 @@ static int geode_setkey_blk(struct crypto_tfm *tfm, const u8 *key,
        /*
         * The requested key size is not supported by HW, do a fallback
         */
-       op->fallback.blk->base.crt_flags &= ~CRYPTO_TFM_REQ_MASK;
-       op->fallback.blk->base.crt_flags |= (tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
+       crypto_sync_skcipher_clear_flags(op->fallback.blk, CRYPTO_TFM_REQ_MASK);
+       crypto_sync_skcipher_set_flags(op->fallback.blk,
+                                      tfm->crt_flags & CRYPTO_TFM_REQ_MASK);
 
-       ret = crypto_blkcipher_setkey(op->fallback.blk, key, len);
+       ret = crypto_sync_skcipher_setkey(op->fallback.blk, key, len);
        if (ret) {
                tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
-               tfm->crt_flags |= (op->fallback.blk->base.crt_flags & CRYPTO_TFM_RES_MASK);
+               tfm->crt_flags |= crypto_sync_skcipher_get_flags(op->fallback.blk) &
+                                 CRYPTO_TFM_RES_MASK;
        }
        return ret;
 }
@@ -181,33 +184,28 @@ static int fallback_blk_dec(struct blkcipher_desc *desc,
                struct scatterlist *dst, struct scatterlist *src,
                unsigned int nbytes)
 {
-       unsigned int ret;
-       struct crypto_blkcipher *tfm;
        struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+       SYNC_SKCIPHER_REQUEST_ON_STACK(req, op->fallback.blk);
 
-       tfm = desc->tfm;
-       desc->tfm = op->fallback.blk;
-
-       ret = crypto_blkcipher_decrypt_iv(desc, dst, src, nbytes);
+       skcipher_request_set_sync_tfm(req, op->fallback.blk);
+       skcipher_request_set_callback(req, 0, NULL, NULL);
+       skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
 
-       desc->tfm = tfm;
-       return ret;
+       return crypto_skcipher_decrypt(req);
 }
+
 static int fallback_blk_enc(struct blkcipher_desc *desc,
                struct scatterlist *dst, struct scatterlist *src,
                unsigned int nbytes)
 {
-       unsigned int ret;
-       struct crypto_blkcipher *tfm;
        struct geode_aes_op *op = crypto_blkcipher_ctx(desc->tfm);
+       SYNC_SKCIPHER_REQUEST_ON_STACK(req, op->fallback.blk);
 
-       tfm = desc->tfm;
-       desc->tfm = op->fallback.blk;
-
-       ret = crypto_blkcipher_encrypt_iv(desc, dst, src, nbytes);
+       skcipher_request_set_sync_tfm(req, op->fallback.blk);
+       skcipher_request_set_callback(req, 0, NULL, NULL);
+       skcipher_request_set_crypt(req, src, dst, nbytes, desc->info);
 
-       desc->tfm = tfm;
-       return ret;
+       return crypto_skcipher_encrypt(req);
 }
 
 static void
@@ -307,6 +305,9 @@ geode_cbc_decrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err, ret;
 
+       if (nbytes % AES_BLOCK_SIZE)
+               return -EINVAL;
+
        if (unlikely(op->keylen != AES_KEYSIZE_128))
                return fallback_blk_dec(desc, dst, src, nbytes);
 
@@ -339,6 +340,9 @@ geode_cbc_encrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err, ret;
 
+       if (nbytes % AES_BLOCK_SIZE)
+               return -EINVAL;
+
        if (unlikely(op->keylen != AES_KEYSIZE_128))
                return fallback_blk_enc(desc, dst, src, nbytes);
 
@@ -366,9 +370,8 @@ static int fallback_init_blk(struct crypto_tfm *tfm)
        const char *name = crypto_tfm_alg_name(tfm);
        struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 
-       op->fallback.blk = crypto_alloc_blkcipher(name, 0,
-                       CRYPTO_ALG_ASYNC | CRYPTO_ALG_NEED_FALLBACK);
-
+       op->fallback.blk = crypto_alloc_sync_skcipher(name, 0,
+                                                     CRYPTO_ALG_NEED_FALLBACK);
        if (IS_ERR(op->fallback.blk)) {
                printk(KERN_ERR "Error allocating fallback algo %s\n", name);
                return PTR_ERR(op->fallback.blk);
@@ -381,7 +384,7 @@ static void fallback_exit_blk(struct crypto_tfm *tfm)
 {
        struct geode_aes_op *op = crypto_tfm_ctx(tfm);
 
-       crypto_free_blkcipher(op->fallback.blk);
+       crypto_free_sync_skcipher(op->fallback.blk);
        op->fallback.blk = NULL;
 }
 
@@ -420,6 +423,9 @@ geode_ecb_decrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err, ret;
 
+       if (nbytes % AES_BLOCK_SIZE)
+               return -EINVAL;
+
        if (unlikely(op->keylen != AES_KEYSIZE_128))
                return fallback_blk_dec(desc, dst, src, nbytes);
 
@@ -450,6 +456,9 @@ geode_ecb_encrypt(struct blkcipher_desc *desc,
        struct blkcipher_walk walk;
        int err, ret;
 
+       if (nbytes % AES_BLOCK_SIZE)
+               return -EINVAL;
+
        if (unlikely(op->keylen != AES_KEYSIZE_128))
                return fallback_blk_enc(desc, dst, src, nbytes);
 
index 5c6e131a8f9d181417ba8586a24d76954a52e9bd..f8a86898ac22670031c8f4706e448f33edf03986 100644 (file)
@@ -60,7 +60,7 @@ struct geode_aes_op {
        u8 *iv;
 
        union {
-               struct crypto_blkcipher *blk;
+               struct crypto_sync_skcipher *blk;
                struct crypto_cipher *cip;
        } fallback;
        u32 keylen;