summaryrefslogtreecommitdiff
path: root/linux/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'linux/crypto')
-rw-r--r--linux/crypto/algapi.c315
-rw-r--r--linux/crypto/api.c326
-rw-r--r--linux/crypto/cipher.c123
-rw-r--r--linux/crypto/internal.h78
-rw-r--r--linux/crypto/sha1_generic.c92
-rw-r--r--linux/crypto/shash.c294
6 files changed, 1228 insertions, 0 deletions
diff --git a/linux/crypto/algapi.c b/linux/crypto/algapi.c
new file mode 100644
index 0000000..5e8e97b
--- /dev/null
+++ b/linux/crypto/algapi.c
@@ -0,0 +1,315 @@
+/*
+ * 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/byteorder.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/rtnetlink.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+
+#include "internal.h"
+
+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_blocksize > PAGE_SIZE / 8)
+ return -EINVAL;
+
+ if (alg->cra_priority < 0)
+ return -EINVAL;
+
+ atomic_set(&alg->cra_refcnt, 1);
+
+ return crypto_set_driver_name(alg);
+}
+
+static int __crypto_register_alg(struct crypto_alg *alg)
+{
+ struct crypto_alg *q;
+ int ret = -EAGAIN;
+
+ INIT_LIST_HEAD(&alg->cra_users);
+
+ ret = -EEXIST;
+
+ list_for_each_entry(q, &crypto_alg_list, cra_list) {
+ if (q == alg)
+ goto err;
+
+ if (!strcmp(q->cra_driver_name, alg->cra_name) ||
+ !strcmp(q->cra_name, alg->cra_driver_name))
+ goto err;
+ }
+
+ list_add(&alg->cra_list, &crypto_alg_list);
+ return 0;
+err:
+ return ret;
+}
+
+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)
+{
+ int err;
+
+ err = crypto_check_alg(alg);
+ if (err)
+ return err;
+
+ down_write(&crypto_alg_sem);
+ err = __crypto_register_alg(alg);
+ up_write(&crypto_alg_sem);
+
+ return err;
+}
+
+static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
+{
+ if (unlikely(list_empty(&alg->cra_list)))
+ return -ENOENT;
+
+ list_del_init(&alg->cra_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;
+}
+
+int crypto_register_algs(struct crypto_alg *algs, int count)
+{
+ int i, ret;
+
+ for (i = 0; i < count; i++) {
+ ret = crypto_register_alg(&algs[i]);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ for (--i; i >= 0; --i)
+ crypto_unregister_alg(&algs[i]);
+
+ return ret;
+}
+
+int crypto_unregister_algs(struct crypto_alg *algs, int count)
+{
+ int i, ret;
+
+ for (i = 0; i < count; i++) {
+ ret = crypto_unregister_alg(&algs[i]);
+ if (ret)
+ pr_err("Failed to unregister %s %s: %d\n",
+ algs[i].cra_driver_name, algs[i].cra_name, ret);
+ }
+
+ return 0;
+}
+
+struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
+{
+ struct rtattr *rta = tb[0];
+ struct crypto_attr_type *algt;
+
+ if (!rta)
+ return ERR_PTR(-ENOENT);
+ if (RTA_PAYLOAD(rta) < sizeof(*algt))
+ return ERR_PTR(-EINVAL);
+ if (rta->rta_type != CRYPTOA_TYPE)
+ return ERR_PTR(-EINVAL);
+
+ algt = RTA_DATA(rta);
+
+ return algt;
+}
+
+int crypto_check_attr_type(struct rtattr **tb, u32 type)
+{
+ struct crypto_attr_type *algt;
+
+ algt = crypto_get_attr_type(tb);
+ if (IS_ERR(algt))
+ return PTR_ERR(algt);
+
+ if ((algt->type ^ type) & algt->mask)
+ return -EINVAL;
+
+ return 0;
+}
+
+const char *crypto_attr_alg_name(struct rtattr *rta)
+{
+ struct crypto_attr_alg *alga;
+
+ if (!rta)
+ return ERR_PTR(-ENOENT);
+ if (RTA_PAYLOAD(rta) < sizeof(*alga))
+ return ERR_PTR(-EINVAL);
+ if (rta->rta_type != CRYPTOA_ALG)
+ return ERR_PTR(-EINVAL);
+
+ alga = RTA_DATA(rta);
+ alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
+
+ return alga->name;
+}
+
+struct crypto_alg *crypto_attr_alg2(struct rtattr *rta,
+ const struct crypto_type *frontend,
+ u32 type, u32 mask)
+{
+ const char *name;
+
+ name = crypto_attr_alg_name(rta);
+ if (IS_ERR(name))
+ return ERR_CAST(name);
+
+ return crypto_find_alg(name, frontend, type, mask);
+}
+
+int crypto_attr_u32(struct rtattr *rta, u32 *num)
+{
+ struct crypto_attr_u32 *nu32;
+
+ if (!rta)
+ return -ENOENT;
+ if (RTA_PAYLOAD(rta) < sizeof(*nu32))
+ return -EINVAL;
+ if (rta->rta_type != CRYPTOA_U32)
+ return -EINVAL;
+
+ nu32 = RTA_DATA(rta);
+ *num = nu32->num;
+
+ return 0;
+}
+
+static inline void crypto_inc_byte(u8 *a, unsigned int size)
+{
+ u8 *b = (a + size);
+ u8 c;
+
+ for (; size; size--) {
+ c = *--b + 1;
+ *b = c;
+ if (c)
+ break;
+ }
+}
+
+void crypto_inc(u8 *a, unsigned int size)
+{
+ __be32 *b = (__be32 *)(a + size);
+ u32 c;
+
+ for (; size >= 4; size -= 4) {
+ c = be32_to_cpu(*--b) + 1;
+ *b = cpu_to_be32(c);
+ if (c)
+ return;
+ }
+
+ crypto_inc_byte(a, size);
+}
+
+static inline void crypto_xor_byte(u8 *a, const u8 *b, unsigned int size)
+{
+ for (; size; size--)
+ *a++ ^= *b++;
+}
+
+void crypto_xor(u8 *dst, const u8 *src, unsigned int size)
+{
+ u32 *a = (u32 *)dst;
+ u32 *b = (u32 *)src;
+
+ for (; size >= 4; size -= 4)
+ *a++ ^= *b++;
+
+ crypto_xor_byte((u8 *)a, (u8 *)b, size);
+}
+
+unsigned int crypto_alg_extsize(struct crypto_alg *alg)
+{
+ return alg->cra_ctxsize +
+ (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1));
+}
+
+int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
+ u32 type, u32 mask)
+{
+ int ret = 0;
+ struct crypto_alg *alg = crypto_find_alg(name, frontend, type, mask);
+
+ if (!IS_ERR(alg)) {
+ crypto_alg_put(alg);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cryptographic algorithms API");
diff --git a/linux/crypto/api.c b/linux/crypto/api.c
new file mode 100644
index 0000000..513a48a
--- /dev/null
+++ b/linux/crypto/api.c
@@ -0,0 +1,326 @@
+/*
+ * Scatterlist Cryptographic 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.
+ *
+ * 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/device.h>
+#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/slab.h>
+#include <linux/string.h>
+#include "internal.h"
+
+LIST_HEAD(crypto_alg_list);
+DECLARE_RWSEM(crypto_alg_sem);
+
+static struct crypto_alg *__crypto_alg_lookup(const char *name, 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;
+}
+
+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);
+
+ 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;
+ }
+
+ BUG();
+ return -EINVAL;
+}
+
+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;
+}
+
+struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
+ u32 mask)
+{
+ struct crypto_tfm *tfm = NULL;
+ unsigned int 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;
+
+ tfm->__crt_alg = alg;
+
+ err = crypto_init_ops(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;
+
+cra_init_failed:
+ crypto_exit_ops(tfm);
+out_free_tfm:
+ kfree(tfm);
+out_err:
+ tfm = ERR_PTR(err);
+out:
+ return tfm;
+}
+
+/*
+ * 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;
+ struct crypto_tfm *tfm;
+
+ alg = crypto_alg_mod_lookup(alg_name, type, mask);
+ if (IS_ERR(alg)) {
+ fprintf(stderr, "unknown cipher %s\n", alg_name);
+ return ERR_CAST(alg);
+ }
+
+ tfm = __crypto_alloc_tfm(alg, type, mask);
+ if (IS_ERR(tfm)) {
+ crypto_alg_put(alg);
+ return tfm;
+ }
+
+ return tfm;
+}
+
+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;
+ int err = -ENOMEM;
+
+ tfmsize = frontend->tfmsize;
+ total = tfmsize + sizeof(*tfm) + frontend->extsize(alg);
+
+ mem = kzalloc(total, GFP_KERNEL);
+ if (mem == NULL)
+ goto out_err;
+
+ tfm = (struct crypto_tfm *)(mem + tfmsize);
+ tfm->__crt_alg = alg;
+
+ err = frontend->init_tfm(tfm);
+ if (err)
+ goto out_free_tfm;
+
+ if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
+ goto cra_init_failed;
+
+ goto out;
+
+cra_init_failed:
+ crypto_exit_ops(tfm);
+out_free_tfm:
+ kfree(mem);
+out_err:
+ mem = ERR_PTR(err);
+out:
+ return mem;
+}
+
+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);
+}
+
+void *crypto_alloc_tfm(const char *alg_name,
+ const struct crypto_type *frontend, u32 type, u32 mask)
+{
+ struct crypto_alg *alg;
+ void *tfm;
+
+ alg = crypto_find_alg(alg_name, frontend, type, mask);
+ if (IS_ERR(alg))
+ return ERR_CAST(alg);
+
+ tfm = crypto_create_tfm(alg, frontend);
+ if (IS_ERR(tfm)) {
+ crypto_alg_put(alg);
+ return tfm;
+ }
+
+ return tfm;
+}
+
+void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm)
+{
+ struct crypto_alg *alg;
+
+ if (unlikely(!mem))
+ return;
+
+ alg = tfm->__crt_alg;
+
+ 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 ret = 0;
+ struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask);
+
+ if (!IS_ERR(alg)) {
+ crypto_alg_put(alg);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+MODULE_DESCRIPTION("Cryptographic core API");
+MODULE_LICENSE("GPL");
diff --git a/linux/crypto/cipher.c b/linux/crypto/cipher.c
new file mode 100644
index 0000000..6f47ac6
--- /dev/null
+++ b/linux/crypto/cipher.c
@@ -0,0 +1,123 @@
+/*
+ * Cryptographic API.
+ *
+ * Cipher operations.
+ *
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2005 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/kernel.h>
+#include <linux/crypto.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include "internal.h"
+
+static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ int ret;
+ u8 *buffer, *alignbuffer;
+ unsigned long absize;
+
+ absize = keylen + alignmask;
+ buffer = kmalloc(absize, GFP_ATOMIC);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ ret = cia->cia_setkey(tfm, alignbuffer, keylen);
+ memset(alignbuffer, 0, keylen);
+ kfree(buffer);
+ return ret;
+
+}
+
+static int setkey_default(struct crypto_tfm *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+
+ tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
+ if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) {
+ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+ if ((unsigned long)key & alignmask)
+ return setkey_unaligned(tfm, key, keylen);
+
+ return cia->cia_setkey(tfm, key, keylen);
+}
+
+static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *,
+ const u8 *),
+ struct crypto_tfm *tfm,
+ u8 *dst, const u8 *src)
+{
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ unsigned int size = crypto_tfm_alg_blocksize(tfm);
+ u8 buffer[size + alignmask];
+ u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+
+ memcpy(tmp, src, size);
+ fn(tfm, tmp, tmp);
+ memcpy(dst, tmp, size);
+}
+
+static void cipher_encrypt_unaligned(struct crypto_tfm *tfm,
+ u8 *dst, const u8 *src)
+{
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
+ cipher_crypt_unaligned(cipher->cia_encrypt, tfm, dst, src);
+ return;
+ }
+
+ cipher->cia_encrypt(tfm, dst, src);
+}
+
+static void cipher_decrypt_unaligned(struct crypto_tfm *tfm,
+ u8 *dst, const u8 *src)
+{
+ unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) {
+ cipher_crypt_unaligned(cipher->cia_decrypt, tfm, dst, src);
+ return;
+ }
+
+ cipher->cia_decrypt(tfm, dst, src);
+}
+
+int crypto_init_cipher_ops(struct crypto_tfm *tfm)
+{
+ struct cipher_tfm *ops = &tfm->crt_cipher;
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ ops->cit_setkey = setkey_default;
+ ops->cit_encrypt_one = crypto_tfm_alg_alignmask(tfm) ?
+ cipher_encrypt_unaligned : cipher->cia_encrypt;
+ ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ?
+ cipher_decrypt_unaligned : cipher->cia_decrypt;
+
+ return 0;
+}
+
+void crypto_exit_cipher_ops(struct crypto_tfm *tfm)
+{
+}
diff --git a/linux/crypto/internal.h b/linux/crypto/internal.h
new file mode 100644
index 0000000..b00dcea
--- /dev/null
+++ b/linux/crypto/internal.h
@@ -0,0 +1,78 @@
+/*
+ * Cryptographic API.
+ *
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2005 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.
+ *
+ */
+#ifndef _CRYPTO_INTERNAL_H
+#define _CRYPTO_INTERNAL_H
+
+#include <crypto/algapi.h>
+#include <linux/completion.h>
+#include <linux/mm.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#include <linux/rwsem.h>
+#include <linux/slab.h>
+
+struct crypto_instance;
+struct crypto_template;
+
+struct crypto_larval {
+ struct crypto_alg alg;
+ struct crypto_alg *adult;
+ struct completion completion;
+ u32 mask;
+};
+
+extern struct list_head crypto_alg_list;
+extern struct rw_semaphore crypto_alg_sem;
+
+static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg)
+{
+ return alg->cra_ctxsize;
+}
+
+int crypto_init_cipher_ops(struct crypto_tfm *tfm);
+void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
+
+void crypto_remove_final(struct list_head *list);
+struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
+ u32 mask);
+void *crypto_create_tfm(struct crypto_alg *alg,
+ const struct crypto_type *frontend);
+struct crypto_alg *crypto_find_alg(const char *alg_name,
+ const struct crypto_type *frontend,
+ u32 type, u32 mask);
+void *crypto_alloc_tfm(const char *alg_name,
+ const struct crypto_type *frontend, u32 type, u32 mask);
+
+int crypto_register_notifier(struct notifier_block *nb);
+int crypto_unregister_notifier(struct notifier_block *nb);
+
+unsigned int crypto_alg_extsize(struct crypto_alg *alg);
+
+int crypto_type_has_alg(const char *name, const struct crypto_type *frontend,
+ u32 type, u32 mask);
+
+static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
+{
+ atomic_inc(&alg->cra_refcnt);
+ return alg;
+}
+
+static inline void crypto_alg_put(struct crypto_alg *alg)
+{
+ if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy)
+ alg->cra_destroy(alg);
+}
+
+#endif /* _CRYPTO_INTERNAL_H */
+
diff --git a/linux/crypto/sha1_generic.c b/linux/crypto/sha1_generic.c
new file mode 100644
index 0000000..b0b9cd1
--- /dev/null
+++ b/linux/crypto/sha1_generic.c
@@ -0,0 +1,92 @@
+/*
+ * Cryptographic API.
+ *
+ * SHA1 Secure Hash Algorithm.
+ *
+ * Derived from cryptoapi implementation, adapted for in-place
+ * scatterlist interface.
+ *
+ * Copyright (c) Alan Smithee.
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
+ *
+ * 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 <crypto/internal/hash.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/cryptohash.h>
+#include <linux/types.h>
+#include <crypto/sha.h>
+#include <crypto/sha1_base.h>
+#include <asm/byteorder.h>
+
+const u8 sha1_zero_message_hash[SHA1_DIGEST_SIZE] = {
+ 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d,
+ 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60, 0x18, 0x90,
+ 0xaf, 0xd8, 0x07, 0x09
+};
+
+static void sha1_generic_block_fn(struct sha1_state *sst, u8 const *src,
+ int blocks)
+{
+ u32 temp[SHA_WORKSPACE_WORDS];
+
+ while (blocks--) {
+ sha_transform(sst->state, src, temp);
+ src += SHA1_BLOCK_SIZE;
+ }
+ memzero_explicit(temp, sizeof(temp));
+}
+
+int crypto_sha1_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ return sha1_base_do_update(desc, data, len, sha1_generic_block_fn);
+}
+
+static int sha1_final(struct shash_desc *desc, u8 *out)
+{
+ sha1_base_do_finalize(desc, sha1_generic_block_fn);
+ return sha1_base_finish(desc, out);
+}
+
+int crypto_sha1_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ sha1_base_do_update(desc, data, len, sha1_generic_block_fn);
+ return sha1_final(desc, out);
+}
+
+static struct shash_alg alg = {
+ .digestsize = SHA1_DIGEST_SIZE,
+ .init = sha1_base_init,
+ .update = crypto_sha1_update,
+ .final = sha1_final,
+ .finup = crypto_sha1_finup,
+ .descsize = sizeof(struct sha1_state),
+ .base = {
+ .cra_name = "sha1",
+ .cra_driver_name= "sha1-generic",
+ .cra_flags = CRYPTO_ALG_TYPE_SHASH,
+ .cra_blocksize = SHA1_BLOCK_SIZE,
+ .cra_module = THIS_MODULE,
+ }
+};
+
+static int __init sha1_generic_mod_init(void)
+{
+ return crypto_register_shash(&alg);
+}
+
+static void __exit sha1_generic_mod_fini(void)
+{
+ crypto_unregister_shash(&alg);
+}
+
+module_init(sha1_generic_mod_init);
+module_exit(sha1_generic_mod_fini);
diff --git a/linux/crypto/shash.c b/linux/crypto/shash.c
new file mode 100644
index 0000000..406ddfe
--- /dev/null
+++ b/linux/crypto/shash.c
@@ -0,0 +1,294 @@
+/*
+ * Synchronous Cryptographic Hash operations.
+ *
+ * Copyright (c) 2008 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 <crypto/internal/hash.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+
+#include "internal.h"
+
+static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ return -ENOSYS;
+}
+
+static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
+ unsigned long absize;
+ u8 *buffer, *alignbuffer;
+ int err;
+
+ absize = keylen + (alignmask & ~(crypto_tfm_ctx_alignment() - 1));
+ buffer = kmalloc(absize, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ memcpy(alignbuffer, key, keylen);
+ err = shash->setkey(tfm, alignbuffer, keylen);
+ kzfree(buffer);
+ return err;
+}
+
+int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key,
+ unsigned int keylen)
+{
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+ if ((unsigned long)key & alignmask)
+ return shash_setkey_unaligned(tfm, key, keylen);
+
+ return shash->setkey(tfm, key, keylen);
+}
+
+static inline unsigned int shash_align_buffer_size(unsigned len,
+ unsigned long mask)
+{
+ typedef u8 __attribute__ ((aligned)) u8_aligned;
+ return len + (mask & ~(__alignof__(u8_aligned) - 1));
+}
+
+static int shash_update_unaligned(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ struct crypto_shash *tfm = desc->tfm;
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
+ unsigned int unaligned_len = alignmask + 1 -
+ ((unsigned long)data & alignmask);
+ u8 ubuf[shash_align_buffer_size(unaligned_len, alignmask)]
+ __attribute__ ((aligned));
+ u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1);
+ int err;
+
+ if (unaligned_len > len)
+ unaligned_len = len;
+
+ memcpy(buf, data, unaligned_len);
+ err = shash->update(desc, buf, unaligned_len);
+ memset(buf, 0, unaligned_len);
+
+ return err ?:
+ shash->update(desc, data + unaligned_len, len - unaligned_len);
+}
+
+int crypto_shash_update(struct shash_desc *desc, const u8 *data,
+ unsigned int len)
+{
+ struct crypto_shash *tfm = desc->tfm;
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+ if ((unsigned long)data & alignmask)
+ return shash_update_unaligned(desc, data, len);
+
+ return shash->update(desc, data, len);
+}
+
+static int shash_final_unaligned(struct shash_desc *desc, u8 *out)
+{
+ struct crypto_shash *tfm = desc->tfm;
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned int ds = crypto_shash_digestsize(tfm);
+ u8 ubuf[shash_align_buffer_size(ds, alignmask)]
+ __attribute__ ((aligned));
+ u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1);
+ int err;
+
+ err = shash->final(desc, buf);
+ if (err)
+ goto out;
+
+ memcpy(out, buf, ds);
+
+out:
+ memset(buf, 0, ds);
+ return err;
+}
+
+int crypto_shash_final(struct shash_desc *desc, u8 *out)
+{
+ struct crypto_shash *tfm = desc->tfm;
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+ if ((unsigned long)out & alignmask)
+ return shash_final_unaligned(desc, out);
+
+ return shash->final(desc, out);
+}
+
+static int shash_finup_unaligned(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ return crypto_shash_update(desc, data, len) ?:
+ crypto_shash_final(desc, out);
+}
+
+int crypto_shash_finup(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ struct crypto_shash *tfm = desc->tfm;
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+ if (((unsigned long)data | (unsigned long)out) & alignmask)
+ return shash_finup_unaligned(desc, data, len, out);
+
+ return shash->finup(desc, data, len, out);
+}
+
+static int shash_digest_unaligned(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ return crypto_shash_init(desc) ?:
+ crypto_shash_finup(desc, data, len, out);
+}
+
+int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
+ unsigned int len, u8 *out)
+{
+ struct crypto_shash *tfm = desc->tfm;
+ struct shash_alg *shash = crypto_shash_alg(tfm);
+ unsigned long alignmask = crypto_shash_alignmask(tfm);
+
+ if (((unsigned long)data | (unsigned long)out) & alignmask)
+ return shash_digest_unaligned(desc, data, len, out);
+
+ return shash->digest(desc, data, len, out);
+}
+
+static int shash_default_export(struct shash_desc *desc, void *out)
+{
+ memcpy(out, shash_desc_ctx(desc), crypto_shash_descsize(desc->tfm));
+ return 0;
+}
+
+static int shash_default_import(struct shash_desc *desc, const void *in)
+{
+ memcpy(shash_desc_ctx(desc), in, crypto_shash_descsize(desc->tfm));
+ return 0;
+}
+
+static int crypto_shash_init_tfm(struct crypto_tfm *tfm)
+{
+ struct crypto_shash *hash = __crypto_shash_cast(tfm);
+
+ hash->descsize = crypto_shash_alg(hash)->descsize;
+ return 0;
+}
+
+static const struct crypto_type crypto_shash_type = {
+ .extsize = crypto_alg_extsize,
+ .init_tfm = crypto_shash_init_tfm,
+ .maskclear = ~CRYPTO_ALG_TYPE_MASK,
+ .maskset = CRYPTO_ALG_TYPE_MASK,
+ .type = CRYPTO_ALG_TYPE_SHASH,
+ .tfmsize = offsetof(struct crypto_shash, base),
+};
+
+struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type,
+ u32 mask)
+{
+ return crypto_alloc_tfm(alg_name, &crypto_shash_type, type, mask);
+}
+
+static int shash_prepare_alg(struct shash_alg *alg)
+{
+ struct crypto_alg *base = &alg->base;
+
+ if (alg->digestsize > PAGE_SIZE / 8 ||
+ alg->descsize > PAGE_SIZE / 8 ||
+ alg->statesize > PAGE_SIZE / 8)
+ return -EINVAL;
+
+ base->cra_type = &crypto_shash_type;
+ base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
+ base->cra_flags |= CRYPTO_ALG_TYPE_SHASH;
+
+ if (!alg->finup)
+ alg->finup = shash_finup_unaligned;
+ if (!alg->digest)
+ alg->digest = shash_digest_unaligned;
+ if (!alg->export) {
+ alg->export = shash_default_export;
+ alg->import = shash_default_import;
+ alg->statesize = alg->descsize;
+ }
+ if (!alg->setkey)
+ alg->setkey = shash_no_setkey;
+
+ return 0;
+}
+
+int crypto_register_shash(struct shash_alg *alg)
+{
+ struct crypto_alg *base = &alg->base;
+ int err;
+
+ err = shash_prepare_alg(alg);
+ if (err)
+ return err;
+
+ return crypto_register_alg(base);
+}
+
+int crypto_unregister_shash(struct shash_alg *alg)
+{
+ return crypto_unregister_alg(&alg->base);
+}
+
+int crypto_register_shashes(struct shash_alg *algs, int count)
+{
+ int i, ret;
+
+ for (i = 0; i < count; i++) {
+ ret = crypto_register_shash(&algs[i]);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ for (--i; i >= 0; --i)
+ crypto_unregister_shash(&algs[i]);
+
+ return ret;
+}
+
+int crypto_unregister_shashes(struct shash_alg *algs, int count)
+{
+ int i, ret;
+
+ for (i = count - 1; i >= 0; --i) {
+ ret = crypto_unregister_shash(&algs[i]);
+ if (ret)
+ pr_err("Failed to unregister %s %s: %d\n",
+ algs[i].base.cra_driver_name,
+ algs[i].base.cra_name, ret);
+ }
+
+ return 0;
+}
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Synchronous cryptographic hash type");