[CRYPTO] blkcipher: Add givcipher_alloc_inst/givcipher_free_inst

This patch creates the infrastructure to help the construction of givcipher
templates that wrap around existing blkcipher/ablkcipher algorithms by adding
an IV generator to them.

It also adds the function crypto_spawn_nivcipher that spawns ablkcipher
objects without the givcrypt method.  This is to be used internally by
the givcipher templates.

Signed-off-by: Herbert Xu <[EMAIL PROTECTED]>
---

 crypto/algapi.c         |   23 +++++---
 crypto/blkcipher.c      |  136 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/crypto/algapi.h |   16 +++++
 include/linux/crypto.h  |    1 
 4 files changed, 168 insertions(+), 8 deletions(-)

diff --git a/crypto/algapi.c b/crypto/algapi.c
index 08eca6d..217919c 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -519,14 +519,21 @@ struct crypto_instance *crypto_alloc_instance(const char 
*name,
        if (!inst)
                return ERR_PTR(-ENOMEM);
 
-       err = -ENAMETOOLONG;
-       if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
-                    alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
-               goto err_free_inst;
-
-       if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
-                    name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
-               goto err_free_inst;
+       if (name) {
+               err = -ENAMETOOLONG;
+               if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
+                            name, alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
+                       goto err_free_inst;
+
+               if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
+                            "%s(%s)", name, alg->cra_driver_name) >=
+                   CRYPTO_MAX_ALG_NAME)
+                       goto err_free_inst;
+       } else {
+               memcpy(inst->alg.cra_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+               memcpy(inst->alg.cra_driver_name, alg->cra_driver_name,
+                      CRYPTO_MAX_ALG_NAME);
+       }
 
        spawn = crypto_instance_ctx(inst);
        err = crypto_init_spawn(spawn, alg, inst,
diff --git a/crypto/blkcipher.c b/crypto/blkcipher.c
index 75c3ab9..bd34643 100644
--- a/crypto/blkcipher.c
+++ b/crypto/blkcipher.c
@@ -508,5 +508,141 @@ const struct crypto_type crypto_blkcipher_type = {
 };
 EXPORT_SYMBOL_GPL(crypto_blkcipher_type);
 
+struct crypto_instance *givcipher_alloc_inst(struct crypto_template *tmpl,
+                                            struct rtattr **tb, u32 type,
+                                            u32 mask)
+{
+       struct {
+               int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key,
+                             unsigned int keylen);
+               int (*encrypt)(struct ablkcipher_request *req);
+               int (*decrypt)(struct ablkcipher_request *req);
+
+               unsigned int min_keysize;
+               unsigned int max_keysize;
+               unsigned int ivsize;
+
+               const char *geniv;
+       } balg;
+       const char *name;
+       struct crypto_attr_type *algt;
+       struct crypto_instance *inst;
+       struct crypto_alg *alg;
+       int err;
+
+       algt = crypto_get_attr_type(tb);
+       if (IS_ERR(algt))
+               return ERR_PTR(PTR_ERR(algt));
+
+       err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_GIVCIPHER);
+       if (err)
+               return ERR_PTR(err);
+
+       /* First look for an algorithm with no IV generator. */
+       alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER | type,
+                                 CRYPTO_ALG_TYPE_NIVCIPHER_MASK | mask);
+       err = PTR_ERR(alg);
+       if (IS_ERR(alg)) {
+               if (err != -ENOENT)
+                       return ERR_PTR(err);
+               alg = NULL;
+       }
+
+       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+           CRYPTO_ALG_TYPE_BLKCIPHER) {
+               balg.ivsize = alg->cra_blkcipher.ivsize;
+               balg.min_keysize = alg->cra_blkcipher.min_keysize;
+               balg.max_keysize = alg->cra_blkcipher.max_keysize;
+
+               balg.setkey = async_setkey;
+               balg.encrypt = async_encrypt;
+               balg.decrypt = async_decrypt;
+
+               balg.geniv = alg->cra_blkcipher.geniv;
+       } else {
+               balg.ivsize = alg->cra_ablkcipher.ivsize;
+               balg.min_keysize = alg->cra_ablkcipher.min_keysize;
+               balg.max_keysize = alg->cra_ablkcipher.max_keysize;
+
+               balg.setkey = alg->cra_ablkcipher.setkey;
+               balg.encrypt = alg->cra_ablkcipher.encrypt;
+               balg.decrypt = alg->cra_ablkcipher.decrypt;
+
+               balg.geniv = alg->cra_ablkcipher.geniv;
+       }
+
+       inst = ERR_PTR(-EAGAIN);
+
+       if (!balg.ivsize)
+               goto out_put_alg;
+
+       /* Use original name for default IV generator. */
+       name = NULL;
+
+       /*
+        * This is set unless we're constructing an algorithm with its
+        * default IV generator.  So check algorithms with IV generators
+        * too since we may be overriding them.
+        */
+       if (algt->mask) {
+               struct crypto_alg *giv;
+
+               giv = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_BLKCIPHER | type,
+                                         CRYPTO_ALG_TYPE_BLKCIPHER_MASK |
+                                         mask);
+               err = PTR_ERR(giv);
+               if (IS_ERR(giv)) {
+                       inst = ERR_PTR(err);
+                       if (err != -ENOENT)
+                               goto out_put_alg;
+                       giv = NULL;
+               }
+
+               if (!alg)
+                       alg = giv;
+               else if (giv) {
+                       if (giv->cra_priority < alg->cra_priority) {
+                               crypto_mod_put(alg);
+                               alg = giv;
+                       } else
+                               crypto_mod_put(giv);
+               }
+
+               name = tmpl->name;
+       } else if (strcmp(tmpl->name, balg.geniv))
+               goto out_put_alg;
+
+       inst = crypto_alloc_instance(name, alg);
+       if (IS_ERR(inst))
+               goto out_put_alg;
+
+       inst->alg.cra_flags = CRYPTO_ALG_TYPE_GIVCIPHER;
+       inst->alg.cra_flags |= alg->cra_flags & CRYPTO_ALG_ASYNC;
+       inst->alg.cra_priority = alg->cra_priority;
+       inst->alg.cra_blocksize = alg->cra_blocksize;
+       inst->alg.cra_alignmask = alg->cra_alignmask;
+       inst->alg.cra_type = &crypto_givcipher_type;
+
+       inst->alg.cra_ablkcipher.ivsize = balg.ivsize;
+       inst->alg.cra_ablkcipher.min_keysize = balg.min_keysize;
+       inst->alg.cra_ablkcipher.max_keysize = balg.max_keysize;
+
+       inst->alg.cra_ablkcipher.setkey = balg.setkey;
+       inst->alg.cra_ablkcipher.encrypt = balg.encrypt;
+       inst->alg.cra_ablkcipher.decrypt = balg.decrypt;
+
+out_put_alg:
+       crypto_mod_put(alg);
+       return inst;
+}
+EXPORT_SYMBOL_GPL(givcipher_alloc_inst);
+
+void givcipher_free_inst(struct crypto_instance *inst)
+{
+       crypto_drop_spawn(crypto_instance_ctx(inst));
+       kfree(inst);
+}
+EXPORT_SYMBOL_GPL(givcipher_free_inst);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Generic block chaining cipher type");
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 7f71c41..bb8a2e8 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -139,6 +139,11 @@ int blkcipher_walk_virt_block(struct blkcipher_desc *desc,
                              struct blkcipher_walk *walk,
                              unsigned int blocksize);
 
+struct crypto_instance *givcipher_alloc_inst(struct crypto_template *tmpl,
+                                            struct rtattr **tb, u32 type,
+                                            u32 mask);
+void givcipher_free_inst(struct crypto_instance *inst);
+
 static inline void *crypto_tfm_ctx_aligned(struct crypto_tfm *tfm)
 {
        unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm);
@@ -201,6 +206,17 @@ static inline struct crypto_ablkcipher 
*crypto_spawn_ablkcipher(
        return __crypto_ablkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
 }
 
+static inline struct crypto_ablkcipher *crypto_spawn_nivcipher(
+       struct crypto_spawn *spawn)
+{
+       u32 type = CRYPTO_ALG_TYPE_BLKCIPHER;
+       u32 mask = (spawn->alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+                  CRYPTO_ALG_TYPE_GIVCIPHER ? CRYPTO_ALG_TYPE_BLKCIPHER_MASK :
+                                              CRYPTO_ALG_TYPE_NIVCIPHER_MASK;
+
+       return __crypto_ablkcipher_cast(crypto_spawn_tfm(spawn, type, mask));
+}
+
 static inline struct crypto_blkcipher *crypto_spawn_blkcipher(
        struct crypto_spawn *spawn)
 {
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 95e99f4..cdbd251 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -39,6 +39,7 @@
 #define CRYPTO_ALG_TYPE_AEAD           0x00000009
 
 #define CRYPTO_ALG_TYPE_HASH_MASK      0x0000000e
+#define CRYPTO_ALG_TYPE_NIVCIPHER_MASK 0x0000000e
 #define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c
 
 #define CRYPTO_ALG_LARVAL              0x00000010
-
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to