]> err.no Git - linux-2.6/commitdiff
[CRYPTO] skcipher: Create default givcipher instances
authorHerbert Xu <herbert@gondor.apana.org.au>
Tue, 4 Dec 2007 01:46:48 +0000 (12:46 +1100)
committerHerbert Xu <herbert@gondor.apana.org.au>
Thu, 10 Jan 2008 21:16:46 +0000 (08:16 +1100)
This patch makes crypto_alloc_ablkcipher/crypto_grab_skcipher always
return algorithms that are capable of generating their own IVs through
givencrypt and givdecrypt.  Each algorithm may specify its default IV
generator through the geniv field.

For algorithms that do not set the geniv field, the blkcipher layer will
pick a default.  Currently it's chainiv for synchronous algorithms and
eseqiv for asynchronous algorithms.  Note that if these wrappers do not
work on an algorithm then that algorithm must specify its own geniv or
it can't be used at all.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
crypto/ablkcipher.c
crypto/api.c
crypto/blkcipher.c
crypto/internal.h
include/crypto/internal/skcipher.h
include/linux/crypto.h

index 092d9659b86149b2ce6d7cb7da43d6a5505e08f5..d1df528c8fa347110dd40018277454c5bf983be0 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/rtnetlink.h>
+#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/seq_file.h>
 
@@ -68,6 +70,16 @@ static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type,
        return alg->cra_ctxsize;
 }
 
+int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req)
+{
+       return crypto_ablkcipher_encrypt(&req->creq);
+}
+
+int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req)
+{
+       return crypto_ablkcipher_decrypt(&req->creq);
+}
+
 static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
                                      u32 mask)
 {
@@ -80,6 +92,10 @@ static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type,
        crt->setkey = setkey;
        crt->encrypt = alg->encrypt;
        crt->decrypt = alg->decrypt;
+       if (!alg->ivsize) {
+               crt->givencrypt = skcipher_null_givencrypt;
+               crt->givdecrypt = skcipher_null_givdecrypt;
+       }
        crt->base = __crypto_ablkcipher_cast(tfm);
        crt->ivsize = alg->ivsize;
 
@@ -163,6 +179,108 @@ const char *crypto_default_geniv(const struct crypto_alg *alg)
        return alg->cra_flags & CRYPTO_ALG_ASYNC ? "eseqiv" : "chainiv";
 }
 
+static int crypto_givcipher_default(struct crypto_alg *alg, u32 type, u32 mask)
+{
+       struct rtattr *tb[3];
+       struct {
+               struct rtattr attr;
+               struct crypto_attr_type data;
+       } ptype;
+       struct {
+               struct rtattr attr;
+               struct crypto_attr_alg data;
+       } palg;
+       struct crypto_template *tmpl;
+       struct crypto_instance *inst;
+       struct crypto_alg *larval;
+       const char *geniv;
+       int err;
+
+       larval = crypto_larval_lookup(alg->cra_driver_name,
+                                     CRYPTO_ALG_TYPE_GIVCIPHER,
+                                     CRYPTO_ALG_TYPE_MASK);
+       err = PTR_ERR(larval);
+       if (IS_ERR(larval))
+               goto out;
+
+       err = -EAGAIN;
+       if (!crypto_is_larval(larval))
+               goto drop_larval;
+
+       ptype.attr.rta_len = sizeof(ptype);
+       ptype.attr.rta_type = CRYPTOA_TYPE;
+       ptype.data.type = type | CRYPTO_ALG_GENIV;
+       /* GENIV tells the template that we're making a default geniv. */
+       ptype.data.mask = mask | CRYPTO_ALG_GENIV;
+       tb[0] = &ptype.attr;
+
+       palg.attr.rta_len = sizeof(palg);
+       palg.attr.rta_type = CRYPTOA_ALG;
+       /* Must use the exact name to locate ourselves. */
+       memcpy(palg.data.name, alg->cra_driver_name, CRYPTO_MAX_ALG_NAME);
+       tb[1] = &palg.attr;
+
+       tb[2] = NULL;
+
+       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+           CRYPTO_ALG_TYPE_BLKCIPHER)
+               geniv = alg->cra_blkcipher.geniv;
+       else
+               geniv = alg->cra_ablkcipher.geniv;
+
+       if (!geniv)
+               geniv = crypto_default_geniv(alg);
+
+       tmpl = crypto_lookup_template(geniv);
+       err = -ENOENT;
+       if (!tmpl)
+               goto kill_larval;
+
+       inst = tmpl->alloc(tb);
+       err = PTR_ERR(inst);
+       if (IS_ERR(inst))
+               goto put_tmpl;
+
+       if ((err = crypto_register_instance(tmpl, inst))) {
+               tmpl->free(inst);
+               goto put_tmpl;
+       }
+
+       /* Redo the lookup to use the instance we just registered. */
+       err = -EAGAIN;
+
+put_tmpl:
+       crypto_tmpl_put(tmpl);
+kill_larval:
+       crypto_larval_kill(larval);
+drop_larval:
+       crypto_mod_put(larval);
+out:
+       crypto_mod_put(alg);
+       return err;
+}
+
+static struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type,
+                                                u32 mask)
+{
+       struct crypto_alg *alg;
+
+       alg = crypto_alg_mod_lookup(name, type, mask);
+       if (IS_ERR(alg))
+               return alg;
+
+       if ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+           CRYPTO_ALG_TYPE_GIVCIPHER)
+               return alg;
+
+       if (!((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
+             CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize :
+                                         alg->cra_ablkcipher.ivsize))
+               return alg;
+
+       return ERR_PTR(crypto_givcipher_default(alg, type, mask));
+}
+
 int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name,
                         u32 type, u32 mask)
 {
@@ -172,7 +290,7 @@ int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name,
        type = crypto_skcipher_type(type);
        mask = crypto_skcipher_mask(mask);
 
-       alg = crypto_alg_mod_lookup(name, type, mask);
+       alg = crypto_lookup_skcipher(name, type, mask);
        if (IS_ERR(alg))
                return PTR_ERR(alg);
 
@@ -182,5 +300,43 @@ int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name,
 }
 EXPORT_SYMBOL_GPL(crypto_grab_skcipher);
 
+struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name,
+                                                 u32 type, u32 mask)
+{
+       struct crypto_tfm *tfm;
+       int err;
+
+       type = crypto_skcipher_type(type);
+       mask = crypto_skcipher_mask(mask);
+
+       for (;;) {
+               struct crypto_alg *alg;
+
+               alg = crypto_lookup_skcipher(alg_name, type, mask);
+               if (IS_ERR(alg)) {
+                       err = PTR_ERR(alg);
+                       goto err;
+               }
+
+               tfm = __crypto_alloc_tfm(alg, type, mask);
+               if (!IS_ERR(tfm))
+                       return __crypto_ablkcipher_cast(tfm);
+
+               crypto_mod_put(alg);
+               err = PTR_ERR(tfm);
+
+err:
+               if (err != -EAGAIN)
+                       break;
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       break;
+               }
+       }
+
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_ablkcipher);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Asynchronous block chaining cipher type");
index 1f5c724773568acf31f7dde568972f4925f39407..a2496d1bc6d42234dba6477580a9ddafed6759a9 100644 (file)
@@ -137,7 +137,7 @@ static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type,
        return alg;
 }
 
-static void crypto_larval_kill(struct crypto_alg *alg)
+void crypto_larval_kill(struct crypto_alg *alg)
 {
        struct crypto_larval *larval = (void *)alg;
 
@@ -147,6 +147,7 @@ static void crypto_larval_kill(struct crypto_alg *alg)
        complete_all(&larval->completion);
        crypto_alg_put(alg);
 }
+EXPORT_SYMBOL_GPL(crypto_larval_kill);
 
 static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
 {
@@ -176,11 +177,9 @@ static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type,
        return alg;
 }
 
-struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
+struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask)
 {
        struct crypto_alg *alg;
-       struct crypto_alg *larval;
-       int ok;
 
        if (!name)
                return ERR_PTR(-ENOENT);
@@ -193,7 +192,17 @@ struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
        if (alg)
                return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
 
-       larval = crypto_larval_alloc(name, type, mask);
+       return crypto_larval_alloc(name, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_larval_lookup);
+
+struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask)
+{
+       struct crypto_alg *alg;
+       struct crypto_alg *larval;
+       int ok;
+
+       larval = crypto_larval_lookup(name, type, mask);
        if (IS_ERR(larval) || !crypto_is_larval(larval))
                return larval;
 
index ca6ef065cded9dde065e71922d5f8a3f7657a0b3..4a7e65c4df4dc3ac6af007efa1d136e1232be053 100644 (file)
@@ -450,6 +450,10 @@ static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm)
        crt->setkey = async_setkey;
        crt->encrypt = async_encrypt;
        crt->decrypt = async_decrypt;
+       if (!alg->ivsize) {
+               crt->givencrypt = skcipher_null_givencrypt;
+               crt->givdecrypt = skcipher_null_givdecrypt;
+       }
        crt->base = __crypto_ablkcipher_cast(tfm);
        crt->ivsize = alg->ivsize;
 
index cb13952f82bfc83c8cf767f40409cb6eff865239..32f4c214560315ccc284346499f6b9428bae1d66 100644 (file)
@@ -93,6 +93,8 @@ void crypto_exit_digest_ops(struct crypto_tfm *tfm);
 void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
 void crypto_exit_compress_ops(struct crypto_tfm *tfm);
 
+void crypto_larval_kill(struct crypto_alg *alg);
+struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask);
 void crypto_larval_error(const char *name, u32 type, u32 mask);
 
 void crypto_shoot_alg(struct crypto_alg *alg);
index 80c5bfb14a6031fe74b3bb6fabeea0ec2335f8c0..2071999d4b5ec43a3f1ef889572f505a545f2d96 100644 (file)
@@ -53,6 +53,8 @@ static inline struct crypto_ablkcipher *crypto_spawn_skcipher(
                                 crypto_skcipher_mask(0)));
 }
 
+int skcipher_null_givencrypt(struct skcipher_givcrypt_request *req);
+int skcipher_null_givdecrypt(struct skcipher_givcrypt_request *req);
 const char *crypto_default_geniv(const struct crypto_alg *alg);
 
 struct crypto_instance *skcipher_geniv_alloc(struct crypto_template *tmpl,
index fa7afa9b9f4f14910f13cbfb6fdc09180520ec9f..835dcaf3fe4ed84744d66b1ed384f1e997d58941 100644 (file)
@@ -561,13 +561,8 @@ static inline u32 crypto_skcipher_mask(u32 mask)
        return mask;
 }
 
-static inline struct crypto_ablkcipher *crypto_alloc_ablkcipher(
-       const char *alg_name, u32 type, u32 mask)
-{
-       return __crypto_ablkcipher_cast(
-               crypto_alloc_base(alg_name, crypto_skcipher_type(type),
-                                 crypto_skcipher_mask(mask)));
-}
+struct crypto_ablkcipher *crypto_alloc_ablkcipher(const char *alg_name,
+                                                 u32 type, u32 mask);
 
 static inline struct crypto_tfm *crypto_ablkcipher_tfm(
        struct crypto_ablkcipher *tfm)