aboutsummaryrefslogtreecommitdiff
path: root/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'crypto')
-rw-r--r--crypto/Kconfig154
-rw-r--r--crypto/Makefile16
-rw-r--r--crypto/aes.c5
-rw-r--r--crypto/algapi.c486
-rw-r--r--crypto/anubis.c3
-rw-r--r--crypto/api.c428
-rw-r--r--crypto/arc4.c2
-rw-r--r--crypto/blkcipher.c405
-rw-r--r--crypto/blowfish.c3
-rw-r--r--crypto/cast5.c8
-rw-r--r--crypto/cast6.c5
-rw-r--r--crypto/cbc.c344
-rw-r--r--crypto/cipher.c117
-rw-r--r--crypto/crc32c.c30
-rw-r--r--crypto/crypto_null.c2
-rw-r--r--crypto/cryptomgr.c156
-rw-r--r--crypto/des.c6
-rw-r--r--crypto/digest.c155
-rw-r--r--crypto/ecb.c181
-rw-r--r--crypto/hash.c61
-rw-r--r--crypto/hmac.c278
-rw-r--r--crypto/internal.h106
-rw-r--r--crypto/khazad.c8
-rw-r--r--crypto/michael_mic.c5
-rw-r--r--crypto/proc.c13
-rw-r--r--crypto/scatterwalk.c89
-rw-r--r--crypto/scatterwalk.h52
-rw-r--r--crypto/serpent.c19
-rw-r--r--crypto/sha1.c3
-rw-r--r--crypto/sha256.c3
-rw-r--r--crypto/tcrypt.c901
-rw-r--r--crypto/tcrypt.h202
-rw-r--r--crypto/tea.c16
-rw-r--r--crypto/twofish.c700
-rw-r--r--crypto/twofish_common.c744
35 files changed, 4103 insertions, 1603 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig
index ba133d55704..1e2f39c2118 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -9,47 +9,71 @@ config CRYPTO
help
This option provides the core Cryptographic API.
+if CRYPTO
+
+config CRYPTO_ALGAPI
+ tristate
+ help
+ This option provides the API for cryptographic algorithms.
+
+config CRYPTO_BLKCIPHER
+ tristate
+ select CRYPTO_ALGAPI
+
+config CRYPTO_HASH
+ tristate
+ select CRYPTO_ALGAPI
+
+config CRYPTO_MANAGER
+ tristate "Cryptographic algorithm manager"
+ select CRYPTO_ALGAPI
+ default m
+ help
+ Create default cryptographic template instantiations such as
+ cbc(aes).
+
config CRYPTO_HMAC
- bool "HMAC support"
- depends on CRYPTO
+ tristate "HMAC support"
+ select CRYPTO_HASH
help
HMAC: Keyed-Hashing for Message Authentication (RFC2104).
This is required for IPSec.
config CRYPTO_NULL
tristate "Null algorithms"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
These are 'Null' algorithms, used by IPsec, which do nothing.
config CRYPTO_MD4
tristate "MD4 digest algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
MD4 message digest algorithm (RFC1320).
config CRYPTO_MD5
tristate "MD5 digest algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
MD5 message digest algorithm (RFC1321).
config CRYPTO_SHA1
tristate "SHA1 digest algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
config CRYPTO_SHA1_S390
tristate "SHA1 digest algorithm (s390)"
- depends on CRYPTO && S390
+ depends on S390
+ select CRYPTO_ALGAPI
help
This is the s390 hardware accelerated implementation of the
SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
config CRYPTO_SHA256
tristate "SHA256 digest algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
SHA256 secure hash standard (DFIPS 180-2).
@@ -58,7 +82,8 @@ config CRYPTO_SHA256
config CRYPTO_SHA256_S390
tristate "SHA256 digest algorithm (s390)"
- depends on CRYPTO && S390
+ depends on S390
+ select CRYPTO_ALGAPI
help
This is the s390 hardware accelerated implementation of the
SHA256 secure hash standard (DFIPS 180-2).
@@ -68,7 +93,7 @@ config CRYPTO_SHA256_S390
config CRYPTO_SHA512
tristate "SHA384 and SHA512 digest algorithms"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
SHA512 secure hash standard (DFIPS 180-2).
@@ -80,7 +105,7 @@ config CRYPTO_SHA512
config CRYPTO_WP512
tristate "Whirlpool digest algorithms"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
Whirlpool hash algorithm 512, 384 and 256-bit hashes
@@ -92,7 +117,7 @@ config CRYPTO_WP512
config CRYPTO_TGR192
tristate "Tiger digest algorithms"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
Tiger hash algorithm 192, 160 and 128-bit hashes
@@ -103,21 +128,40 @@ config CRYPTO_TGR192
See also:
<http://www.cs.technion.ac.il/~biham/Reports/Tiger/>.
+config CRYPTO_ECB
+ tristate "ECB support"
+ select CRYPTO_BLKCIPHER
+ default m
+ help
+ ECB: Electronic CodeBook mode
+ This is the simplest block cipher algorithm. It simply encrypts
+ the input block by block.
+
+config CRYPTO_CBC
+ tristate "CBC support"
+ select CRYPTO_BLKCIPHER
+ default m
+ help
+ CBC: Cipher Block Chaining mode
+ This block cipher algorithm is required for IPSec.
+
config CRYPTO_DES
tristate "DES and Triple DES EDE cipher algorithms"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
config CRYPTO_DES_S390
tristate "DES and Triple DES cipher algorithms (s390)"
- depends on CRYPTO && S390
+ depends on S390
+ select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
help
DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
config CRYPTO_BLOWFISH
tristate "Blowfish cipher algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
Blowfish cipher algorithm, by Bruce Schneier.
@@ -130,7 +174,8 @@ config CRYPTO_BLOWFISH
config CRYPTO_TWOFISH
tristate "Twofish cipher algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
+ select CRYPTO_TWOFISH_COMMON
help
Twofish cipher algorithm.
@@ -142,9 +187,47 @@ config CRYPTO_TWOFISH
See also:
<http://www.schneier.com/twofish.html>
+config CRYPTO_TWOFISH_COMMON
+ tristate
+ help
+ Common parts of the Twofish cipher algorithm shared by the
+ generic c and the assembler implementations.
+
+config CRYPTO_TWOFISH_586
+ tristate "Twofish cipher algorithms (i586)"
+ depends on (X86 || UML_X86) && !64BIT
+ select CRYPTO_ALGAPI
+ select CRYPTO_TWOFISH_COMMON
+ help
+ Twofish cipher algorithm.
+
+ Twofish was submitted as an AES (Advanced Encryption Standard)
+ candidate cipher by researchers at CounterPane Systems. It is a
+ 16 round block cipher supporting key sizes of 128, 192, and 256
+ bits.
+
+ See also:
+ <http://www.schneier.com/twofish.html>
+
+config CRYPTO_TWOFISH_X86_64
+ tristate "Twofish cipher algorithm (x86_64)"
+ depends on (X86 || UML_X86) && 64BIT
+ select CRYPTO_ALGAPI
+ select CRYPTO_TWOFISH_COMMON
+ help
+ Twofish cipher algorithm (x86_64).
+
+ Twofish was submitted as an AES (Advanced Encryption Standard)
+ candidate cipher by researchers at CounterPane Systems. It is a
+ 16 round block cipher supporting key sizes of 128, 192, and 256
+ bits.
+
+ See also:
+ <http://www.schneier.com/twofish.html>
+
config CRYPTO_SERPENT
tristate "Serpent cipher algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
Serpent cipher algorithm, by Anderson, Biham & Knudsen.
@@ -157,7 +240,7 @@ config CRYPTO_SERPENT
config CRYPTO_AES
tristate "AES cipher algorithms"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
AES cipher algorithms (FIPS-197). AES uses the Rijndael
algorithm.
@@ -177,7 +260,8 @@ config CRYPTO_AES
config CRYPTO_AES_586
tristate "AES cipher algorithms (i586)"
- depends on CRYPTO && ((X86 || UML_X86) && !64BIT)
+ depends on (X86 || UML_X86) && !64BIT
+ select CRYPTO_ALGAPI
help
AES cipher algorithms (FIPS-197). AES uses the Rijndael
algorithm.
@@ -197,7 +281,8 @@ config CRYPTO_AES_586
config CRYPTO_AES_X86_64
tristate "AES cipher algorithms (x86_64)"
- depends on CRYPTO && ((X86 || UML_X86) && 64BIT)
+ depends on (X86 || UML_X86) && 64BIT
+ select CRYPTO_ALGAPI
help
AES cipher algorithms (FIPS-197). AES uses the Rijndael
algorithm.
@@ -217,7 +302,9 @@ config CRYPTO_AES_X86_64
config CRYPTO_AES_S390
tristate "AES cipher algorithms (s390)"
- depends on CRYPTO && S390
+ depends on S390
+ select CRYPTO_ALGAPI
+ select CRYPTO_BLKCIPHER
help
This is the s390 hardware accelerated implementation of the
AES cipher algorithms (FIPS-197). AES uses the Rijndael
@@ -237,21 +324,21 @@ config CRYPTO_AES_S390
config CRYPTO_CAST5
tristate "CAST5 (CAST-128) cipher algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
The CAST5 encryption algorithm (synonymous with CAST-128) is
described in RFC2144.
config CRYPTO_CAST6
tristate "CAST6 (CAST-256) cipher algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
The CAST6 encryption algorithm (synonymous with CAST-256) is
described in RFC2612.
config CRYPTO_TEA
tristate "TEA, XTEA and XETA cipher algorithms"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
TEA cipher algorithm.
@@ -268,7 +355,7 @@ config CRYPTO_TEA
config CRYPTO_ARC4
tristate "ARC4 cipher algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
ARC4 cipher algorithm.
@@ -279,7 +366,7 @@ config CRYPTO_ARC4
config CRYPTO_KHAZAD
tristate "Khazad cipher algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
Khazad cipher algorithm.
@@ -292,7 +379,7 @@ config CRYPTO_KHAZAD
config CRYPTO_ANUBIS
tristate "Anubis cipher algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
Anubis cipher algorithm.
@@ -307,7 +394,7 @@ config CRYPTO_ANUBIS
config CRYPTO_DEFLATE
tristate "Deflate compression algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
select ZLIB_INFLATE
select ZLIB_DEFLATE
help
@@ -318,7 +405,7 @@ config CRYPTO_DEFLATE
config CRYPTO_MICHAEL_MIC
tristate "Michael MIC keyed digest algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
help
Michael MIC is used for message integrity protection in TKIP
(IEEE 802.11i). This algorithm is required for TKIP, but it
@@ -327,7 +414,7 @@ config CRYPTO_MICHAEL_MIC
config CRYPTO_CRC32C
tristate "CRC32c CRC algorithm"
- depends on CRYPTO
+ select CRYPTO_ALGAPI
select LIBCRC32C
help
Castagnoli, et al Cyclic Redundancy-Check Algorithm. Used
@@ -337,10 +424,13 @@ config CRYPTO_CRC32C
config CRYPTO_TEST
tristate "Testing module"
- depends on CRYPTO && m
+ depends on m
+ select CRYPTO_ALGAPI
help
Quick & dirty crypto test module.
source "drivers/crypto/Kconfig"
-endmenu
+endif # if CRYPTO
+
+endmenu
diff --git a/crypto/Makefile b/crypto/Makefile
index d287b9e60c4..72366208e29 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -2,11 +2,18 @@
# Cryptographic API
#
-proc-crypto-$(CONFIG_PROC_FS) = proc.o
+obj-$(CONFIG_CRYPTO) += api.o scatterwalk.o cipher.o digest.o compress.o
-obj-$(CONFIG_CRYPTO) += api.o scatterwalk.o cipher.o digest.o compress.o \
- $(proc-crypto-y)
+crypto_algapi-$(CONFIG_PROC_FS) += proc.o
+crypto_algapi-objs := algapi.o $(crypto_algapi-y)
+obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o
+obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o
+
+crypto_hash-objs := hash.o
+obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
+
+obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
obj-$(CONFIG_CRYPTO_MD4) += md4.o
@@ -16,9 +23,12 @@ obj-$(CONFIG_CRYPTO_SHA256) += sha256.o
obj-$(CONFIG_CRYPTO_SHA512) += sha512.o
obj-$(CONFIG_CRYPTO_WP512) += wp512.o
obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o
+obj-$(CONFIG_CRYPTO_ECB) += ecb.o
+obj-$(CONFIG_CRYPTO_CBC) += cbc.o
obj-$(CONFIG_CRYPTO_DES) += des.o
obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
obj-$(CONFIG_CRYPTO_TWOFISH) += twofish.o
+obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o
obj-$(CONFIG_CRYPTO_SERPENT) += serpent.o
obj-$(CONFIG_CRYPTO_AES) += aes.o
obj-$(CONFIG_CRYPTO_CAST5) += cast5.o
diff --git a/crypto/aes.c b/crypto/aes.c
index a038711831e..e2440773878 100644
--- a/crypto/aes.c
+++ b/crypto/aes.c
@@ -249,13 +249,14 @@ gen_tabs (void)
}
static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
- unsigned int key_len, u32 *flags)
+ unsigned int key_len)
{
struct aes_ctx *ctx = crypto_tfm_ctx(tfm);
const __le32 *key = (const __le32 *)in_key;
+ u32 *flags = &tfm->crt_flags;
u32 i, t, u, v, w;
- if (key_len != 16 && key_len != 24 && key_len != 32) {
+ if (key_len % 8) {
*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
return -EINVAL;
}
diff --git a/crypto/algapi.c b/crypto/algapi.c
new file mode 100644
index 00000000000..c91530021e9
--- /dev/null
+++ b/crypto/algapi.c
@@ -0,0 +1,486 @@
+/*
+ * Cryptographic API for algorithms (i.e., low-level API).
+ *
+ * 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
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/rtnetlink.h>
+#include <linux/string.h>
+
+#include "internal.h"
+
+static LIST_HEAD(crypto_template_list);
+
+void crypto_larval_error(const char *name, u32 type, u32 mask)
+{
+ struct crypto_alg *alg;
+
+ down_read(&crypto_alg_sem);
+ alg = __crypto_alg_lookup(name, type, mask);
+ up_read(&crypto_alg_sem);
+
+ if (alg) {
+ if (crypto_is_larval(alg)) {
+ struct crypto_larval *larval = (void *)alg;
+ complete(&larval->completion);
+ }
+ crypto_mod_put(alg);
+ }
+}
+EXPORT_SYMBOL_GPL(crypto_larval_error);
+
+static inline int crypto_set_driver_name(struct crypto_alg *alg)
+{
+ static const char suffix[] = "-generic";
+ char *driver_name = alg->cra_driver_name;
+ int len;
+
+ if (*driver_name)
+ return 0;
+
+ len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
+ if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME)
+ return -ENAMETOOLONG;
+
+ memcpy(driver_name + len, suffix, sizeof(suffix));
+ return 0;
+}
+
+static int crypto_check_alg(struct crypto_alg *alg)
+{
+ if (alg->cra_alignmask & (alg->cra_alignmask + 1))
+ return -EINVAL;
+
+ if (alg->cra_alignmask & alg->cra_blocksize)
+ return -EINVAL;
+
+ if (alg->cra_blocksize > PAGE_SIZE / 8)
+ return -EINVAL;
+
+ if (alg->cra_priority < 0)
+ return -EINVAL;
+
+ return crypto_set_driver_name(alg);
+}
+
+static void crypto_destroy_instance(struct crypto_alg *alg)
+{
+ struct crypto_instance *inst = (void *)alg;
+ struct crypto_template *tmpl = inst->tmpl;
+
+ tmpl->free(inst);
+ crypto_tmpl_put(tmpl);
+}
+
+static void crypto_remove_spawns(struct list_head *spawns,
+ struct list_head *list)
+{
+ struct crypto_spawn *spawn, *n;
+
+ list_for_each_entry_safe(spawn, n, spawns, list) {
+ struct crypto_instance *inst = spawn->inst;
+ struct crypto_template *tmpl = inst->tmpl;
+
+ list_del_init(&spawn->list);
+ spawn->alg = NULL;
+
+ if (crypto_is_dead(&inst->alg))
+ continue;
+
+ inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
+ if (!tmpl || !crypto_tmpl_get(tmpl))
+ continue;
+
+ crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
+ list_move(&inst->alg.cra_list, list);
+ hlist_del(&inst->list);
+ inst->alg.cra_destroy = crypto_destroy_instance;
+
+ if (!list_empty(&inst->alg.cra_users)) {
+ if (&n->list == spawns)
+ n = list_entry(inst->alg.cra_users.next,
+ typeof(*n), list);
+ __list_splice(&inst->alg.cra_users, spawns->prev);
+ }
+ }
+}
+
+static int __crypto_register_alg(struct crypto_alg *alg,
+ struct list_head *list)
+{
+ struct crypto_alg *q;
+ int ret = -EAGAIN;
+
+ if (crypto_is_dead(alg))
+ goto out;
+
+ INIT_LIST_HEAD(&alg->cra_users);
+
+ ret = -EEXIST;
+
+ atomic_set(&alg->cra_refcnt, 1);
+ list_for_each_entry(q, &crypto_alg_list, cra_list) {
+ if (q == alg)
+ goto out;
+
+ if (crypto_is_moribund(q))
+ continue;
+
+ if (crypto_is_larval(q)) {
+ struct crypto_larval *larval = (void *)q;
+
+ if (strcmp(alg->cra_name, q->cra_name) &&
+ strcmp(alg->cra_driver_name, q->cra_name))
+ continue;
+
+ if (larval->adult)
+ continue;
+ if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
+ continue;
+ if (!crypto_mod_get(alg))
+ continue;
+
+ larval->adult = alg;
+ complete(&larval->completion);
+ continue;
+ }
+
+ if (strcmp(alg->cra_name, q->cra_name))
+ continue;
+
+ if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
+ q->cra_priority > alg->cra_priority)
+ continue;
+
+ crypto_remove_spawns(&q->cra_users, list);
+ }
+
+ list_add(&alg->cra_list, &crypto_alg_list);
+
+ crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
+ ret = 0;
+
+out:
+ return ret;
+}
+
+static void crypto_remove_final(struct list_head *list)
+{
+ struct crypto_alg *alg;
+ struct crypto_alg *n;
+
+ list_for_each_entry_safe(alg, n, list, cra_list) {
+ list_del_init(&alg->cra_list);
+ crypto_alg_put(alg);
+ }
+}
+
+int crypto_register_alg(struct crypto_alg *alg)
+{
+ LIST_HEAD(list);
+ int err;
+
+ err = crypto_check_alg(alg);
+ if (err)
+ return err;
+
+ down_write(&crypto_alg_sem);
+ err = __crypto_register_alg(alg, &list);
+ up_write(&crypto_alg_sem);
+
+ crypto_remove_final(&list);
+ return err;
+}
+EXPORT_SYMBOL_GPL(crypto_register_alg);
+
+static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
+{
+ if (unlikely(list_empty(&alg->cra_list)))
+ return -ENOENT;
+
+ alg->cra_flags |= CRYPTO_ALG_DEAD;
+
+ crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
+ list_del_init(&alg->cra_list);
+ crypto_remove_spawns(&alg->cra_users, list);
+
+ return 0;
+}
+
+int crypto_unregister_alg(struct crypto_alg *alg)
+{
+ int ret;
+ LIST_HEAD(list);
+
+ down_write(&crypto_alg_sem);
+ ret = crypto_remove_alg(alg, &list);
+ up_write(&crypto_alg_sem);
+
+ if (ret)
+ return ret;
+
+ BUG_ON(atomic_read(&alg->cra_refcnt) != 1);
+ if (alg->cra_destroy)
+ alg->cra_destroy(alg);
+
+ crypto_remove_final(&list);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_alg);
+
+int crypto_register_template(struct crypto_template *tmpl)
+{
+ struct crypto_template *q;
+ int err = -EEXIST;
+
+ down_write(&crypto_alg_sem);
+
+ list_for_each_entry(q, &crypto_template_list, list) {
+ if (q == tmpl)
+ goto out;
+ }
+
+ list_add(&tmpl->list, &crypto_template_list);
+ crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl);
+ err = 0;
+out:
+ up_write(&crypto_alg_sem);
+ return err;
+}
+EXPORT_SYMBOL_GPL(crypto_register_template);
+
+void crypto_unregister_template(struct crypto_template *tmpl)
+{
+ struct crypto_instance *inst;
+ struct hlist_node *p, *n;
+ struct hlist_head *list;
+ LIST_HEAD(users);
+
+ down_write(&crypto_alg_sem);
+
+ BUG_ON(list_empty(&tmpl->list));
+ list_del_init(&tmpl->list);
+
+ list = &tmpl->instances;
+ hlist_for_each_entry(inst, p, list, list) {
+ int err = crypto_remove_alg(&inst->alg, &users);
+ BUG_ON(err);
+ }
+
+ crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
+
+ up_write(&crypto_alg_sem);
+
+ hlist_for_each_entry_safe(inst, p, n, list, list) {
+ BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
+ tmpl->free(inst);
+ }
+ crypto_remove_final(&users);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_template);
+
+static struct crypto_template *__crypto_lookup_template(const char *name)
+{
+ struct crypto_template *q, *tmpl = NULL;
+
+ down_read(&crypto_alg_sem);
+ list_for_each_entry(q, &crypto_template_list, list) {
+ if (strcmp(q->name, name))
+ continue;
+ if (unlikely(!crypto_tmpl_get(q)))
+ continue;
+
+ tmpl = q;
+ break;
+ }
+ up_read(&crypto_alg_sem);
+
+ return tmpl;
+}
+
+struct crypto_template *crypto_lookup_template(const char *name)
+{
+ return try_then_request_module(__crypto_lookup_template(name), name);
+}
+EXPORT_SYMBOL_GPL(crypto_lookup_template);
+
+int crypto_register_instance(struct crypto_template *tmpl,
+ struct crypto_instance *inst)
+{
+ LIST_HEAD(list);
+ int err = -EINVAL;
+
+ if (inst->alg.cra_destroy)
+ goto err;
+
+ err = crypto_check_alg(&inst->alg);
+ if (err)
+ goto err;
+
+ inst->alg.cra_module = tmpl->module;
+
+ down_write(&crypto_alg_sem);
+
+ err = __crypto_register_alg(&inst->alg, &list);
+ if (err)
+ goto unlock;
+
+ hlist_add_head(&inst->list, &tmpl->instances);
+ inst->tmpl = tmpl;
+
+unlock:
+ up_write(&crypto_alg_sem);
+
+ crypto_remove_final(&list);
+
+err:
+ return err;
+}
+EXPORT_SYMBOL_GPL(crypto_register_instance);
+
+int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
+ struct crypto_instance *inst)
+{
+ int err = -EAGAIN;
+
+ spawn->inst = inst;
+
+ down_write(&crypto_alg_sem);
+ if (!crypto_is_moribund(alg)) {
+ list_add(&spawn->list, &alg->cra_users);
+ spawn->alg = alg;
+ err = 0;
+ }
+ up_write(&crypto_alg_sem);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(crypto_init_spawn);
+
+void crypto_drop_spawn(struct crypto_spawn *spawn)
+{
+ down_write(&crypto_alg_sem);
+ list_del(&spawn->list);
+ up_write(&crypto_alg_sem);
+}
+EXPORT_SYMBOL_GPL(crypto_drop_spawn);
+
+struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
+{
+ struct crypto_alg *alg;
+ struct crypto_alg *alg2;
+ struct crypto_tfm *tfm;
+
+ down_read(&crypto_alg_sem);
+ alg = spawn->alg;
+ alg2 = alg;
+ if (alg2)
+ alg2 = crypto_mod_get(alg2);
+ up_read(&crypto_alg_sem);
+
+ if (!alg2) {
+ if (alg)
+ crypto_shoot_alg(alg);
+ return ERR_PTR(-EAGAIN);
+ }
+
+ tfm = __crypto_alloc_tfm(alg, 0);
+ if (IS_ERR(tfm))
+ crypto_mod_put(alg);
+
+ return tfm;
+}
+EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
+
+int crypto_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&crypto_chain, nb);
+}
+EXPORT_SYMBOL_GPL(crypto_register_notifier);
+
+int crypto_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&crypto_chain, nb);
+}
+EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
+
+struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
+ u32 type, u32 mask)
+{
+ struct rtattr *rta = param;
+ struct crypto_attr_alg *alga;
+
+ if (!RTA_OK(rta, len))
+ return ERR_PTR(-EBADR);
+ if (rta->rta_type != CRYPTOA_ALG || RTA_PAYLOAD(rta) < sizeof(*alga))
+ return ERR_PTR(-EINVAL);
+
+ alga = RTA_DATA(rta);
+ alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
+
+ return crypto_alg_mod_lookup(alga->name, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_get_attr_alg);
+
+struct crypto_instance *crypto_alloc_instance(const char *name,
+ struct crypto_alg *alg)
+{
+ struct crypto_instance *inst;
+ struct crypto_spawn *spawn;
+ int err;
+
+ inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+ 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;
+
+ spawn = crypto_instance_ctx(inst);
+ err = crypto_init_spawn(spawn, alg, inst);
+
+ if (err)
+ goto err_free_inst;
+
+ return inst;
+
+err_free_inst:
+ kfree(inst);
+ return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_instance);
+
+static int __init crypto_algapi_init(void)
+{
+ crypto_init_proc();
+ return 0;
+}
+
+static void __exit crypto_algapi_exit(void)
+{
+ crypto_exit_proc();
+}
+
+module_init(crypto_algapi_init);
+module_exit(crypto_algapi_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cryptographic algorithms API");
diff --git a/crypto/anubis.c b/crypto/anubis.c
index 7e2e1a29800..1c771f7f4dc 100644
--- a/crypto/anubis.c
+++ b/crypto/anubis.c
@@ -461,10 +461,11 @@ static const u32 rc[] = {
};
static int anubis_setkey(struct crypto_tfm *tfm, const u8 *in_key,
- unsigned int key_len, u32 *flags)
+ unsigned int key_len)
{
struct anubis_ctx *ctx = crypto_tfm_ctx(tfm);
const __be32 *key = (const __be32 *)in_key;
+ u32 *flags = &tfm->crt_flags;
int N, R, i, r;
u32 kappa[ANUBIS_MAX_N];
u32 inter[ANUBIS_MAX_N];
diff --git a/crypto/api.c b/crypto/api.c
index c11ec1fd4f1..2e84d4b5479 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -15,70 +15,202 @@
*
*/
-#include <linux/compiler.h>
-#include <linux/init.h>
-#include <linux/crypto.h>
+#include <linux/err.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/kmod.h>
-#include <linux/rwsem.h>
+#include <linux/module.h>
+#include <linux/param.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/string.h>
#include "internal.h"
LIST_HEAD(crypto_alg_list);
+EXPORT_SYMBOL_GPL(crypto_alg_list);
DECLARE_RWSEM(crypto_alg_sem);
+EXPORT_SYMBOL_GPL(crypto_alg_sem);
-static inline int crypto_alg_get(struct crypto_alg *alg)
+BLOCKING_NOTIFIER_HEAD(crypto_chain);
+EXPORT_SYMBOL_GPL(crypto_chain);
+
+static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
+{
+ atomic_inc(&alg->cra_refcnt);
+ return alg;
+}
+
+struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
{
- return try_module_get(alg->cra_module);
+ return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
}
+EXPORT_SYMBOL_GPL(crypto_mod_get);
-static inline void crypto_alg_put(struct crypto_alg *alg)
+void crypto_mod_put(struct crypto_alg *alg)
{</