Skip to content

Commit

Permalink
[CRYPTO] aead: Create default givcipher instances
Browse files Browse the repository at this point in the history
This patch makes crypto_alloc_aead always return algorithms that is
capable of generating their own IVs through givencrypt and givdecrypt.
All existing AEAD algorithms already do.  New ones must either supply
their own or specify a generic IV generator with the geniv field.

Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
herbertx committed Jan 10, 2008
1 parent 14df4d8 commit d29ce98
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 9 deletions.
153 changes: 153 additions & 0 deletions crypto/aead.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/rtnetlink.h>
#include <linux/slab.h>
#include <linux/seq_file.h>

Expand Down Expand Up @@ -328,5 +329,157 @@ void aead_geniv_exit(struct crypto_tfm *tfm)
}
EXPORT_SYMBOL_GPL(aead_geniv_exit);

static int crypto_nivaead_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_AEAD | CRYPTO_ALG_GENIV,
CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
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;

geniv = alg->cra_aead.geniv;

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_aead(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_type == &crypto_aead_type)
return alg;

if (!alg->cra_aead.ivsize)
return alg;

return ERR_PTR(crypto_nivaead_default(alg, type, mask));
}

int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name,
u32 type, u32 mask)
{
struct crypto_alg *alg;
int err;

type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
type |= CRYPTO_ALG_TYPE_AEAD;
mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
mask |= CRYPTO_ALG_TYPE_MASK;

alg = crypto_lookup_aead(name, type, mask);
if (IS_ERR(alg))
return PTR_ERR(alg);

err = crypto_init_spawn(&spawn->base, alg, spawn->base.inst, mask);
crypto_mod_put(alg);
return err;
}
EXPORT_SYMBOL_GPL(crypto_grab_aead);

struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask)
{
struct crypto_tfm *tfm;
int err;

type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
type |= CRYPTO_ALG_TYPE_AEAD;
mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV);
mask |= CRYPTO_ALG_TYPE_MASK;

for (;;) {
struct crypto_alg *alg;

alg = crypto_lookup_aead(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_aead_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_aead);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)");
3 changes: 3 additions & 0 deletions include/crypto/internal/aead.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ static inline void crypto_set_aead_spawn(
crypto_set_spawn(&spawn->base, inst);
}

int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name,
u32 type, u32 mask);

static inline void crypto_drop_aead(struct crypto_aead_spawn *spawn)
{
crypto_drop_spawn(&spawn->base);
Expand Down
10 changes: 1 addition & 9 deletions include/linux/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -723,15 +723,7 @@ static inline struct crypto_aead *__crypto_aead_cast(struct crypto_tfm *tfm)
return (struct crypto_aead *)tfm;
}

static inline struct crypto_aead *crypto_alloc_aead(const char *alg_name,
u32 type, u32 mask)
{
type &= ~CRYPTO_ALG_TYPE_MASK;
type |= CRYPTO_ALG_TYPE_AEAD;
mask |= CRYPTO_ALG_TYPE_MASK;

return __crypto_aead_cast(crypto_alloc_base(alg_name, type, mask));
}
struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask);

static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm)
{
Expand Down

0 comments on commit d29ce98

Please sign in to comment.