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/chacha20_generic.c | |
parent | e4d1c93d85a5b86c04599bfc9f658308d741fd41 (diff) |
New on disk format - encryption
Diffstat (limited to 'linux/crypto/chacha20_generic.c')
-rw-r--r-- | linux/crypto/chacha20_generic.c | 99 |
1 files changed, 99 insertions, 0 deletions
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); +} |