blob: 14cc6b08e4d3e34058003392e4d650b493a52f9f [file] [log] [blame]
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +00001/*
Eric Biggers38e3f252018-11-16 17:26:26 -08002 * ARM NEON accelerated ChaCha and XChaCha stream ciphers,
3 * including ChaCha20 (RFC7539)
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +00004 *
5 * Copyright (C) 2016 Linaro, Ltd. <ard.biesheuvel@linaro.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 * Based on:
12 * ChaCha20 256-bit cipher algorithm, RFC7539, SIMD glue code
13 *
14 * Copyright (C) 2015 Martin Willi
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 */
21
22#include <crypto/algapi.h>
Eric Biggersb8181f32018-11-16 17:26:21 -080023#include <crypto/chacha.h>
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000024#include <linux/crypto.h>
25#include <linux/kernel.h>
26#include <linux/module.h>
27
28#include <asm/hwcap.h>
29#include <asm/neon.h>
30#include <asm/simd.h>
31
Eric Biggers54a345a2018-11-16 17:26:25 -080032asmlinkage void chacha_block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
33 int nrounds);
34asmlinkage void chacha_4block_xor_neon(const u32 *state, u8 *dst, const u8 *src,
35 int nrounds);
36asmlinkage void hchacha_block_neon(const u32 *state, u32 *out, int nrounds);
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000037
Eric Biggers54a345a2018-11-16 17:26:25 -080038static void chacha_doneon(u32 *state, u8 *dst, const u8 *src,
39 unsigned int bytes, int nrounds)
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000040{
Eric Biggersb8181f32018-11-16 17:26:21 -080041 u8 buf[CHACHA_BLOCK_SIZE];
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000042
Eric Biggersb8181f32018-11-16 17:26:21 -080043 while (bytes >= CHACHA_BLOCK_SIZE * 4) {
Eric Biggers54a345a2018-11-16 17:26:25 -080044 chacha_4block_xor_neon(state, dst, src, nrounds);
Eric Biggersb8181f32018-11-16 17:26:21 -080045 bytes -= CHACHA_BLOCK_SIZE * 4;
46 src += CHACHA_BLOCK_SIZE * 4;
47 dst += CHACHA_BLOCK_SIZE * 4;
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000048 state[12] += 4;
49 }
Eric Biggersb8181f32018-11-16 17:26:21 -080050 while (bytes >= CHACHA_BLOCK_SIZE) {
Eric Biggers54a345a2018-11-16 17:26:25 -080051 chacha_block_xor_neon(state, dst, src, nrounds);
Eric Biggersb8181f32018-11-16 17:26:21 -080052 bytes -= CHACHA_BLOCK_SIZE;
53 src += CHACHA_BLOCK_SIZE;
54 dst += CHACHA_BLOCK_SIZE;
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000055 state[12]++;
56 }
57 if (bytes) {
58 memcpy(buf, src, bytes);
Eric Biggers54a345a2018-11-16 17:26:25 -080059 chacha_block_xor_neon(state, buf, buf, nrounds);
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000060 memcpy(dst, buf, bytes);
61 }
62}
63
Eric Biggers54a345a2018-11-16 17:26:25 -080064static int chacha_neon_stream_xor(struct blkcipher_desc *desc,
65 struct scatterlist *dst,
66 struct scatterlist *src,
67 unsigned int nbytes,
68 struct chacha_ctx *ctx, u8 *iv)
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000069{
70 struct blkcipher_walk walk;
71 u32 state[16];
72 int err;
73
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000074 blkcipher_walk_init(&walk, dst, src, nbytes);
Eric Biggersb8181f32018-11-16 17:26:21 -080075 err = blkcipher_walk_virt_block(desc, &walk, CHACHA_BLOCK_SIZE);
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000076
Eric Biggers0b8e72b2018-11-16 17:26:24 -080077 crypto_chacha_init(state, ctx, iv);
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000078
Eric Biggersb8181f32018-11-16 17:26:21 -080079 while (walk.nbytes >= CHACHA_BLOCK_SIZE) {
Eric Biggersd31aa622018-11-16 17:26:23 -080080 kernel_neon_begin();
Eric Biggers54a345a2018-11-16 17:26:25 -080081 chacha_doneon(state, walk.dst.virt.addr, walk.src.virt.addr,
82 rounddown(walk.nbytes, CHACHA_BLOCK_SIZE),
83 ctx->nrounds);
Eric Biggersd31aa622018-11-16 17:26:23 -080084 kernel_neon_end();
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000085 err = blkcipher_walk_done(desc, &walk,
Eric Biggersb8181f32018-11-16 17:26:21 -080086 walk.nbytes % CHACHA_BLOCK_SIZE);
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000087 }
88
89 if (walk.nbytes) {
Eric Biggersd31aa622018-11-16 17:26:23 -080090 kernel_neon_begin();
Eric Biggers54a345a2018-11-16 17:26:25 -080091 chacha_doneon(state, walk.dst.virt.addr, walk.src.virt.addr,
92 walk.nbytes, ctx->nrounds);
Eric Biggersd31aa622018-11-16 17:26:23 -080093 kernel_neon_end();
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000094 err = blkcipher_walk_done(desc, &walk, 0);
95 }
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +000096 return err;
97}
98
Eric Biggers54a345a2018-11-16 17:26:25 -080099static int chacha_neon(struct blkcipher_desc *desc, struct scatterlist *dst,
100 struct scatterlist *src, unsigned int nbytes)
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800101{
102 struct chacha_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
103 u8 *iv = desc->info;
104
105 if (nbytes <= CHACHA_BLOCK_SIZE || !may_use_simd())
106 return crypto_chacha_crypt(desc, dst, src, nbytes);
107
Eric Biggers54a345a2018-11-16 17:26:25 -0800108 return chacha_neon_stream_xor(desc, dst, src, nbytes, ctx, iv);
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800109}
110
Eric Biggers54a345a2018-11-16 17:26:25 -0800111static int xchacha_neon(struct blkcipher_desc *desc, struct scatterlist *dst,
112 struct scatterlist *src, unsigned int nbytes)
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800113{
114 struct chacha_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
115 u8 *iv = desc->info;
116 struct chacha_ctx subctx;
117 u32 state[16];
118 u8 real_iv[16];
119
120 if (nbytes <= CHACHA_BLOCK_SIZE || !may_use_simd())
121 return crypto_xchacha_crypt(desc, dst, src, nbytes);
122
123 crypto_chacha_init(state, ctx, iv);
124
125 kernel_neon_begin();
Eric Biggers54a345a2018-11-16 17:26:25 -0800126 hchacha_block_neon(state, subctx.key, ctx->nrounds);
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800127 kernel_neon_end();
Eric Biggers54a345a2018-11-16 17:26:25 -0800128 subctx.nrounds = ctx->nrounds;
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800129
130 memcpy(&real_iv[0], iv + 24, 8);
131 memcpy(&real_iv[8], iv + 16, 8);
Eric Biggers54a345a2018-11-16 17:26:25 -0800132 return chacha_neon_stream_xor(desc, dst, src, nbytes, &subctx, real_iv);
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800133}
134
135static struct crypto_alg algs[] = {
136 {
137 .cra_name = "chacha20",
138 .cra_driver_name = "chacha20-neon",
139 .cra_priority = 300,
140 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
141 .cra_blocksize = 1,
142 .cra_type = &crypto_blkcipher_type,
143 .cra_ctxsize = sizeof(struct chacha_ctx),
144 .cra_alignmask = sizeof(u32) - 1,
145 .cra_module = THIS_MODULE,
146 .cra_u = {
147 .blkcipher = {
148 .min_keysize = CHACHA_KEY_SIZE,
149 .max_keysize = CHACHA_KEY_SIZE,
150 .ivsize = CHACHA_IV_SIZE,
151 .geniv = "seqiv",
152 .setkey = crypto_chacha20_setkey,
Eric Biggers54a345a2018-11-16 17:26:25 -0800153 .encrypt = chacha_neon,
154 .decrypt = chacha_neon,
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800155 },
156 },
157 }, {
158 .cra_name = "xchacha20",
159 .cra_driver_name = "xchacha20-neon",
160 .cra_priority = 300,
161 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
162 .cra_blocksize = 1,
163 .cra_type = &crypto_blkcipher_type,
164 .cra_ctxsize = sizeof(struct chacha_ctx),
165 .cra_alignmask = sizeof(u32) - 1,
166 .cra_module = THIS_MODULE,
167 .cra_u = {
168 .blkcipher = {
169 .min_keysize = CHACHA_KEY_SIZE,
170 .max_keysize = CHACHA_KEY_SIZE,
171 .ivsize = XCHACHA_IV_SIZE,
172 .geniv = "seqiv",
173 .setkey = crypto_chacha20_setkey,
Eric Biggers54a345a2018-11-16 17:26:25 -0800174 .encrypt = xchacha_neon,
175 .decrypt = xchacha_neon,
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800176 },
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +0000177 },
Eric Biggers38e3f252018-11-16 17:26:26 -0800178 }, {
179 .cra_name = "xchacha12",
180 .cra_driver_name = "xchacha12-neon",
181 .cra_priority = 300,
182 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
183 .cra_blocksize = 1,
184 .cra_type = &crypto_blkcipher_type,
185 .cra_ctxsize = sizeof(struct chacha_ctx),
186 .cra_alignmask = sizeof(u32) - 1,
187 .cra_module = THIS_MODULE,
188 .cra_u = {
189 .blkcipher = {
190 .min_keysize = CHACHA_KEY_SIZE,
191 .max_keysize = CHACHA_KEY_SIZE,
192 .ivsize = XCHACHA_IV_SIZE,
193 .geniv = "seqiv",
194 .setkey = crypto_chacha12_setkey,
195 .encrypt = xchacha_neon,
196 .decrypt = xchacha_neon,
197 },
198 },
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +0000199 },
200};
201
Eric Biggers54a345a2018-11-16 17:26:25 -0800202static int __init chacha_simd_mod_init(void)
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +0000203{
204 if (!(elf_hwcap & HWCAP_NEON))
205 return -ENODEV;
206
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800207 return crypto_register_algs(algs, ARRAY_SIZE(algs));
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +0000208}
209
Eric Biggers54a345a2018-11-16 17:26:25 -0800210static void __exit chacha_simd_mod_fini(void)
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +0000211{
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800212 crypto_unregister_algs(algs, ARRAY_SIZE(algs));
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +0000213}
214
Eric Biggers54a345a2018-11-16 17:26:25 -0800215module_init(chacha_simd_mod_init);
216module_exit(chacha_simd_mod_fini);
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +0000217
Eric Biggers54a345a2018-11-16 17:26:25 -0800218MODULE_DESCRIPTION("ChaCha and XChaCha stream ciphers (NEON accelerated)");
Ard Biesheuveldc6ff2022016-12-08 14:28:59 +0000219MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
220MODULE_LICENSE("GPL v2");
221MODULE_ALIAS_CRYPTO("chacha20");
Eric Biggers0b8e72b2018-11-16 17:26:24 -0800222MODULE_ALIAS_CRYPTO("chacha20-neon");
223MODULE_ALIAS_CRYPTO("xchacha20");
224MODULE_ALIAS_CRYPTO("xchacha20-neon");
Eric Biggers38e3f252018-11-16 17:26:26 -0800225MODULE_ALIAS_CRYPTO("xchacha12");
226MODULE_ALIAS_CRYPTO("xchacha12-neon");