2 * ChaCha20 256-bit cipher algorithm, RFC7539, ARM NEON functions
4 * Copyright (C) 2016 Linaro, Ltd. <ard.biesheuvel@linaro.org>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
11 * ChaCha20 256-bit cipher algorithm, RFC7539, SIMD glue code
13 * Copyright (C) 2015 Martin Willi
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
21 #include <crypto/algapi.h>
22 #include <crypto/chacha20.h>
23 #include <crypto/internal/skcipher.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
27 #include <asm/hwcap.h>
31 asmlinkage void chacha20_block_xor_neon(u32 *state, u8 *dst, const u8 *src);
32 asmlinkage void chacha20_4block_xor_neon(u32 *state, u8 *dst, const u8 *src);
34 static void chacha20_doneon(u32 *state, u8 *dst, const u8 *src,
37 u8 buf[CHACHA20_BLOCK_SIZE];
39 while (bytes >= CHACHA20_BLOCK_SIZE * 4) {
40 chacha20_4block_xor_neon(state, dst, src);
41 bytes -= CHACHA20_BLOCK_SIZE * 4;
42 src += CHACHA20_BLOCK_SIZE * 4;
43 dst += CHACHA20_BLOCK_SIZE * 4;
46 while (bytes >= CHACHA20_BLOCK_SIZE) {
47 chacha20_block_xor_neon(state, dst, src);
48 bytes -= CHACHA20_BLOCK_SIZE;
49 src += CHACHA20_BLOCK_SIZE;
50 dst += CHACHA20_BLOCK_SIZE;
54 memcpy(buf, src, bytes);
55 chacha20_block_xor_neon(state, buf, buf);
56 memcpy(dst, buf, bytes);
60 static int chacha20_neon(struct skcipher_request *req)
62 struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
63 struct chacha20_ctx *ctx = crypto_skcipher_ctx(tfm);
64 struct skcipher_walk walk;
68 if (req->cryptlen <= CHACHA20_BLOCK_SIZE || !may_use_simd())
69 return crypto_chacha20_crypt(req);
71 err = skcipher_walk_virt(&walk, req, true);
73 crypto_chacha20_init(state, ctx, walk.iv);
76 while (walk.nbytes > 0) {
77 unsigned int nbytes = walk.nbytes;
79 if (nbytes < walk.total)
80 nbytes = round_down(nbytes, walk.stride);
82 chacha20_doneon(state, walk.dst.virt.addr, walk.src.virt.addr,
84 err = skcipher_walk_done(&walk, walk.nbytes - nbytes);
91 static struct skcipher_alg alg = {
92 .base.cra_name = "chacha20",
93 .base.cra_driver_name = "chacha20-neon",
94 .base.cra_priority = 300,
95 .base.cra_blocksize = 1,
96 .base.cra_ctxsize = sizeof(struct chacha20_ctx),
97 .base.cra_module = THIS_MODULE,
99 .min_keysize = CHACHA20_KEY_SIZE,
100 .max_keysize = CHACHA20_KEY_SIZE,
101 .ivsize = CHACHA20_IV_SIZE,
102 .chunksize = CHACHA20_BLOCK_SIZE,
103 .walksize = 4 * CHACHA20_BLOCK_SIZE,
104 .setkey = crypto_chacha20_setkey,
105 .encrypt = chacha20_neon,
106 .decrypt = chacha20_neon,
109 static int __init chacha20_simd_mod_init(void)
111 if (!(elf_hwcap & HWCAP_NEON))
114 return crypto_register_skcipher(&alg);
117 static void __exit chacha20_simd_mod_fini(void)
119 crypto_unregister_skcipher(&alg);
122 module_init(chacha20_simd_mod_init);
123 module_exit(chacha20_simd_mod_fini);
125 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
126 MODULE_LICENSE("GPL v2");
127 MODULE_ALIAS_CRYPTO("chacha20");