diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-10-03 19:22:17 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2017-02-28 03:05:38 -0900 |
commit | a5b5eba7f788bb77cf57f9c94f3474a2d439ab0b (patch) | |
tree | 278813d1b1a9024174531376d41a2ba04a3b27f6 /linux/crypto | |
parent | e4d1c93d85a5b86c04599bfc9f658308d741fd41 (diff) |
New on disk format - encryption
Diffstat (limited to 'linux/crypto')
-rw-r--r-- | linux/crypto/algapi.c | 315 | ||||
-rw-r--r-- | linux/crypto/api.c | 227 | ||||
-rw-r--r-- | linux/crypto/blkcipher.c | 47 | ||||
-rw-r--r-- | linux/crypto/chacha20_generic.c | 99 | ||||
-rw-r--r-- | linux/crypto/cipher.c | 123 | ||||
-rw-r--r-- | linux/crypto/internal.h | 63 | ||||
-rw-r--r-- | linux/crypto/poly1305_generic.c | 76 | ||||
-rw-r--r-- | linux/crypto/sha1_generic.c | 85 | ||||
-rw-r--r-- | linux/crypto/sha256_generic.c | 69 | ||||
-rw-r--r-- | linux/crypto/shash.c | 252 |
10 files changed, 362 insertions, 994 deletions
diff --git a/linux/crypto/algapi.c b/linux/crypto/algapi.c deleted file mode 100644 index 5e8e97b9..00000000 --- a/linux/crypto/algapi.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * 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 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"); diff --git a/linux/crypto/blkcipher.c b/linux/crypto/blkcipher.c new file mode 100644 index 00000000..31f91418 --- /dev/null +++ b/linux/crypto/blkcipher.c @@ -0,0 +1,47 @@ +/* + * Block chaining cipher operations. + * + * Generic encrypt/decrypt wrapper for ciphers, handles operations across + * multiple page boundaries by using temporary blocks. In user context, + * the kernel is given a chance to schedule us once per page. + * + * 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/errno.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/string.h> + +#include <crypto/algapi.h> +#include "internal.h" + +static unsigned crypto_blkcipher_ctxsize(struct crypto_alg *alg, + u32 type, u32 mask) +{ + return alg->cra_ctxsize; +} + +static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) +{ + struct blkcipher_tfm *crt = &tfm->crt_blkcipher; + struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; + + BUG_ON((mask & CRYPTO_ALG_TYPE_MASK) != CRYPTO_ALG_TYPE_MASK); + + crt->setkey = alg->setkey; + crt->encrypt = alg->encrypt; + crt->decrypt = alg->decrypt; + return 0; +} + +const struct crypto_type crypto_blkcipher_type = { + .ctxsize = crypto_blkcipher_ctxsize, + .init = crypto_init_blkcipher_ops, +}; diff --git a/linux/crypto/chacha20_generic.c b/linux/crypto/chacha20_generic.c new file mode 100644 index 00000000..7ac68321 --- /dev/null +++ b/linux/crypto/chacha20_generic.c @@ -0,0 +1,99 @@ +/* + * ChaCha20 256-bit cipher algorithm, RFC7539 + * + * Copyright (C) 2015 Martin Willi + * + * 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/errno.h> +#include <linux/kernel.h> +#include <linux/scatterlist.h> +#include <asm/unaligned.h> + +#include <linux/crypto.h> +#include <crypto/algapi.h> +#include <crypto/chacha20.h> + +#include <sodium/crypto_stream_chacha20.h> + +struct chacha20_ctx { + u32 key[8]; +}; + +static int crypto_chacha20_setkey(struct crypto_tfm *tfm, const u8 *key, + unsigned int keysize) +{ + struct chacha20_ctx *ctx = crypto_tfm_ctx(tfm); + int i; + + if (keysize != CHACHA20_KEY_SIZE) + return -EINVAL; + + for (i = 0; i < ARRAY_SIZE(ctx->key); i++) + ctx->key[i] = get_unaligned_le32(key + i * sizeof(u32)); + + return 0; +} + +static int crypto_chacha20_crypt(struct blkcipher_desc *desc, + struct scatterlist *dst, + struct scatterlist *src, + unsigned nbytes) +{ + struct chacha20_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); + struct scatterlist *sg = src; + u32 iv[4]; + int ret; + + BUG_ON(src != dst); + + memcpy(iv, desc->info, sizeof(iv)); + + while (1) { + ret = crypto_stream_chacha20_xor_ic(sg_virt(sg), + sg_virt(sg), + sg->length, + (void *) &iv[2], + iv[0] | ((u64) iv[1] << 32), + (void *) ctx->key); + BUG_ON(ret); + + nbytes -= sg->length; + + if (sg_is_last(sg)) + break; + + BUG_ON(sg->length % CHACHA20_BLOCK_SIZE); + iv[0] += sg->length / CHACHA20_BLOCK_SIZE; + sg = sg_next(sg); + }; + + BUG_ON(nbytes); + + return 0; +} + +static struct crypto_alg alg = { + .cra_name = "chacha20", + .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, + .cra_type = &crypto_blkcipher_type, + .cra_ctxsize = sizeof(struct chacha20_ctx), + .cra_u = { + .blkcipher = { + .setkey = crypto_chacha20_setkey, + .encrypt = crypto_chacha20_crypt, + .decrypt = crypto_chacha20_crypt, + }, + }, +}; + +__attribute__((constructor(110))) +static int chacha20_generic_mod_init(void) +{ + return crypto_register_alg(&alg); +} diff --git a/linux/crypto/cipher.c b/linux/crypto/cipher.c deleted file mode 100644 index 6f47ac6c..00000000 --- a/linux/crypto/cipher.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * 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 index b00dcea2..5b21f836 100644 --- a/linux/crypto/internal.h +++ b/linux/crypto/internal.h @@ -13,66 +13,11 @@ #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_type; +struct crypto_alg; -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); -} +void *crypto_alloc_tfm(const char *, const struct crypto_type *, u32, u32); +unsigned int crypto_alg_extsize(struct crypto_alg *); #endif /* _CRYPTO_INTERNAL_H */ diff --git a/linux/crypto/poly1305_generic.c b/linux/crypto/poly1305_generic.c new file mode 100644 index 00000000..5d385d54 --- /dev/null +++ b/linux/crypto/poly1305_generic.c @@ -0,0 +1,76 @@ +/* + * Poly1305 authenticator algorithm, RFC7539 + * + * Copyright (C) 2015 Martin Willi + * + * Based on public domain code by Andrew Moon and Daniel J. Bernstein. + * + * 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/errno.h> +#include <linux/kernel.h> +#include <asm/unaligned.h> + +#include <linux/crypto.h> +#include <crypto/algapi.h> +#include <crypto/internal/hash.h> +#include <crypto/poly1305.h> + +struct poly1305_desc_ctx { + bool key_done; + crypto_onetimeauth_poly1305_state s; +}; + + +static int poly1305_init(struct shash_desc *desc) +{ + struct poly1305_desc_ctx *state = shash_desc_ctx(desc); + + state->key_done = false; + return 0; +} + +static int poly1305_update(struct shash_desc *desc, + const u8 *src, unsigned len) +{ + struct poly1305_desc_ctx *state = shash_desc_ctx(desc); + + if (!state->key_done) { + BUG_ON(len != crypto_onetimeauth_poly1305_KEYBYTES); + + state->key_done = true; + return crypto_onetimeauth_poly1305_init(&state->s, src); + } + + return crypto_onetimeauth_poly1305_update(&state->s, src, len); +} + +static int poly1305_final(struct shash_desc *desc, u8 *out) +{ + struct poly1305_desc_ctx *state = shash_desc_ctx(desc); + + return crypto_onetimeauth_poly1305_final(&state->s, out); +} + +static struct shash_alg poly1305_alg = { + .digestsize = crypto_onetimeauth_poly1305_BYTES, + .init = poly1305_init, + .update = poly1305_update, + .final = poly1305_final, + .descsize = sizeof(struct poly1305_desc_ctx), + .base = { + .cra_name = "poly1305", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + }, +}; + +__attribute__((constructor(110))) +static int poly1305_mod_init(void) +{ + return crypto_register_shash(&poly1305_alg); +} diff --git a/linux/crypto/sha1_generic.c b/linux/crypto/sha1_generic.c deleted file mode 100644 index 31b5d12e..00000000 --- a/linux/crypto/sha1_generic.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * 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, - } -}; - -__attribute__((constructor(110))) -static int __init sha1_generic_mod_init(void) -{ - return crypto_register_shash(&alg); -} diff --git a/linux/crypto/sha256_generic.c b/linux/crypto/sha256_generic.c new file mode 100644 index 00000000..0bd272f0 --- /dev/null +++ b/linux/crypto/sha256_generic.c @@ -0,0 +1,69 @@ +/* + * Cryptographic API. + * + * SHA-256, as specified in + * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf + * + * SHA-256 code by Jean-Luc Cooke <jlcooke@certainkey.com>. + * + * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com> + * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk> + * Copyright (c) 2002 James Morris <jmorris@intercode.com.au> + * SHA224 Support Copyright 2007 Intel Corporation <jonathan.lynch@intel.com> + * + * 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/bitops.h> +#include <linux/byteorder.h> +#include <linux/types.h> +#include <asm/unaligned.h> + +#include <linux/crypto.h> +#include <crypto/internal/hash.h> + +#include <sodium/crypto_hash_sha256.h> + +static int sha256_init(struct shash_desc *desc) +{ + crypto_hash_sha256_state *state = shash_desc_ctx(desc); + + return crypto_hash_sha256_init(state); +} + +static int sha256_update(struct shash_desc *desc, const u8 *data, + unsigned int len) +{ + crypto_hash_sha256_state *state = shash_desc_ctx(desc); + + return crypto_hash_sha256_update(state, data, len); +} + +static int sha256_final(struct shash_desc *desc, u8 *out) +{ + crypto_hash_sha256_state *state = shash_desc_ctx(desc); + + return crypto_hash_sha256_final(state, out); +} + +static struct shash_alg sha256_alg = { + .digestsize = crypto_hash_sha256_BYTES, + .init = sha256_init, + .update = sha256_update, + .final = sha256_final, + .descsize = sizeof(crypto_hash_sha256_state), + .base = { + .cra_name = "sha256", + .cra_flags = CRYPTO_ALG_TYPE_SHASH, + } +}; + +__attribute__((constructor(110))) +static int __init sha256_generic_mod_init(void) +{ + return crypto_register_shash(&sha256_alg); +} diff --git a/linux/crypto/shash.c b/linux/crypto/shash.c index 406ddfe8..4f07a8b8 100644 --- a/linux/crypto/shash.c +++ b/linux/crypto/shash.c @@ -13,181 +13,25 @@ #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) +static int shash_finup(struct shash_desc *desc, const u8 *data, + unsigned 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) +static int shash_digest(struct shash_desc *desc, const u8 *data, + unsigned 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); @@ -197,98 +41,32 @@ static int crypto_shash_init_tfm(struct crypto_tfm *tfm) } 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), + .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) +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) +int crypto_register_shash(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; + alg->finup = shash_finup; 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; + alg->digest = shash_digest; 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"); |