diff options
Diffstat (limited to 'linux/crypto/api.c')
-rw-r--r-- | linux/crypto/api.c | 227 |
1 files changed, 52 insertions, 175 deletions
diff --git a/linux/crypto/api.c b/linux/crypto/api.c index 513a48aa..2d24630e 100644 --- a/linux/crypto/api.c +++ b/linux/crypto/api.c @@ -1,12 +1,7 @@ /* - * Scatterlist Cryptographic API. + * Cryptographic API for algorithms (i.e., low-level API). * - * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> - * Copyright (c) 2002 David S. Miller (davem@redhat.com) - * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au> - * - * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no> - * and Nettle, by Niels Möller. + * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -19,183 +14,80 @@ #include <linux/err.h> #include <linux/errno.h> #include <linux/kernel.h> -#include <linux/module.h> -#include <linux/param.h> -#include <linux/sched.h> +#include <linux/list.h> +#include <linux/rwsem.h> #include <linux/slab.h> #include <linux/string.h> + +#include <crypto/algapi.h> #include "internal.h" -LIST_HEAD(crypto_alg_list); -DECLARE_RWSEM(crypto_alg_sem); +static LIST_HEAD(crypto_alg_list); +static DECLARE_RWSEM(crypto_alg_sem); -static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, - u32 mask) +static unsigned crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) { - struct crypto_alg *q, *alg = NULL; - int best = -2; - - list_for_each_entry(q, &crypto_alg_list, cra_list) { - int exact, fuzzy; - - if ((q->cra_flags ^ type) & mask) - continue; - - exact = !strcmp(q->cra_driver_name, name); - fuzzy = !strcmp(q->cra_name, name); - if (!exact && !(fuzzy && q->cra_priority > best)) - continue; - - if (unlikely(!crypto_alg_get(q))) - continue; - - best = q->cra_priority; - if (alg) - crypto_alg_put(alg); - alg = q; - - if (exact) - break; - } + return alg->cra_type->ctxsize(alg, type, mask); +} - return alg; +unsigned crypto_alg_extsize(struct crypto_alg *alg) +{ + return alg->cra_ctxsize; } struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) { struct crypto_alg *alg; - /* - * If the internal flag is set for a cipher, require a caller to - * to invoke the cipher with the internal flag to use that cipher. - * Also, if a caller wants to allocate a cipher that may or may - * not be an internal cipher, use type | CRYPTO_ALG_INTERNAL and - * !(mask & CRYPTO_ALG_INTERNAL). - */ - if (!((type | mask) & CRYPTO_ALG_INTERNAL)) - mask |= CRYPTO_ALG_INTERNAL; - down_read(&crypto_alg_sem); - alg = __crypto_alg_lookup(name, type, mask); - up_read(&crypto_alg_sem); + list_for_each_entry(alg, &crypto_alg_list, cra_list) + if (!((alg->cra_flags ^ type) & mask) && + !strcmp(alg->cra_name, name)) + goto found; - return alg ?: ERR_PTR(-ENOENT); -} - -static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask) -{ - const struct crypto_type *type_obj = tfm->__crt_alg->cra_type; - - if (type_obj) - return type_obj->init(tfm, type, mask); - - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - return crypto_init_cipher_ops(tfm); - default: - break; - } + alg = ERR_PTR(-ENOENT); +found: + up_read(&crypto_alg_sem); - BUG(); - return -EINVAL; + return alg; } static void crypto_exit_ops(struct crypto_tfm *tfm) { - const struct crypto_type *type = tfm->__crt_alg->cra_type; - - if (type) { - if (tfm->exit) - tfm->exit(tfm); - return; - } - - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - crypto_exit_cipher_ops(tfm); - break; - - default: - BUG(); - } -} - -static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) -{ - const struct crypto_type *type_obj = alg->cra_type; - unsigned int len; - - len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1); - if (type_obj) - return len + type_obj->ctxsize(alg, type, mask); - - switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { - default: - BUG(); - - case CRYPTO_ALG_TYPE_CIPHER: - len += crypto_cipher_ctxsize(alg); - break; - } - - return len; + if (tfm->exit) + tfm->exit(tfm); } -struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, - u32 mask) +static struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, + u32 type, u32 mask) { struct crypto_tfm *tfm = NULL; - unsigned int tfm_size; + unsigned tfm_size; int err = -ENOMEM; tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask); tfm = kzalloc(tfm_size, GFP_KERNEL); if (tfm == NULL) - goto out_err; + return ERR_PTR(-ENOMEM); tfm->__crt_alg = alg; - err = crypto_init_ops(tfm, type, mask); + err = alg->cra_type->init(tfm, type, mask); if (err) goto out_free_tfm; if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm))) goto cra_init_failed; - goto out; + return tfm; cra_init_failed: crypto_exit_ops(tfm); out_free_tfm: kfree(tfm); -out_err: - tfm = ERR_PTR(err); -out: - return tfm; + return ERR_PTR(err); } -/* - * crypto_alloc_base - Locate algorithm and allocate transform - * @alg_name: Name of algorithm - * @type: Type of algorithm - * @mask: Mask for type comparison - * - * This function should not be used by new algorithm types. - * Please use crypto_alloc_tfm instead. - * - * crypto_alloc_base() will first attempt to locate an already loaded - * algorithm. If that fails and the kernel supports dynamically loadable - * modules, it will then attempt to load a module of the same name or - * alias. If that fails it will send a query to any loaded crypto manager - * to construct an algorithm on the fly. A refcount is grabbed on the - * algorithm which is then associated with the new transform. - * - * The returned transform is of a non-determinate type. Most people - * should use one of the more specific allocation functions such as - * crypto_alloc_blkcipher. - * - * In case of error the return value is an error pointer. - */ struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) { struct crypto_alg *alg; @@ -208,31 +100,29 @@ struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) } tfm = __crypto_alloc_tfm(alg, type, mask); - if (IS_ERR(tfm)) { - crypto_alg_put(alg); + if (IS_ERR(tfm)) return tfm; - } return tfm; } -void *crypto_create_tfm(struct crypto_alg *alg, - const struct crypto_type *frontend) +static void *crypto_create_tfm(struct crypto_alg *alg, + const struct crypto_type *frontend) { - char *mem; struct crypto_tfm *tfm = NULL; - unsigned int tfmsize; - unsigned int total; + unsigned tfmsize; + unsigned total; + void *mem; int err = -ENOMEM; tfmsize = frontend->tfmsize; total = tfmsize + sizeof(*tfm) + frontend->extsize(alg); mem = kzalloc(total, GFP_KERNEL); - if (mem == NULL) + if (!mem) goto out_err; - tfm = (struct crypto_tfm *)(mem + tfmsize); + tfm = mem + tfmsize; tfm->__crt_alg = alg; err = frontend->init_tfm(tfm); @@ -254,28 +144,23 @@ out: return mem; } -struct crypto_alg *crypto_find_alg(const char *alg_name, - const struct crypto_type *frontend, - u32 type, u32 mask) +static struct crypto_alg *crypto_find_alg(const char *alg_name, + const struct crypto_type *frontend, + u32 type, u32 mask) { - struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask) = - crypto_alg_mod_lookup; - if (frontend) { type &= frontend->maskclear; mask &= frontend->maskclear; type |= frontend->type; mask |= frontend->maskset; - - if (frontend->lookup) - lookup = frontend->lookup; } - return lookup(alg_name, type, mask); + return crypto_alg_mod_lookup(alg_name, type, mask); } void *crypto_alloc_tfm(const char *alg_name, - const struct crypto_type *frontend, u32 type, u32 mask) + const struct crypto_type *frontend, + u32 type, u32 mask) { struct crypto_alg *alg; void *tfm; @@ -285,10 +170,8 @@ void *crypto_alloc_tfm(const char *alg_name, return ERR_CAST(alg); tfm = crypto_create_tfm(alg, frontend); - if (IS_ERR(tfm)) { - crypto_alg_put(alg); + if (IS_ERR(tfm)) return tfm; - } return tfm; } @@ -305,22 +188,16 @@ void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm) if (!tfm->exit && alg->cra_exit) alg->cra_exit(tfm); crypto_exit_ops(tfm); - crypto_alg_put(alg); kzfree(mem); } -int crypto_has_alg(const char *name, u32 type, u32 mask) +int crypto_register_alg(struct crypto_alg *alg) { - int ret = 0; - struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask); + INIT_LIST_HEAD(&alg->cra_users); - if (!IS_ERR(alg)) { - crypto_alg_put(alg); - ret = 1; - } + down_write(&crypto_alg_sem); + list_add(&alg->cra_list, &crypto_alg_list); + up_write(&crypto_alg_sem); - return ret; + return 0; } - -MODULE_DESCRIPTION("Cryptographic core API"); -MODULE_LICENSE("GPL"); |