blob: c7d18569d408efee989dcf21dc3dc19c712cffb6 [file] [log] [blame]
Eric Biggersf152ce12018-03-05 11:17:07 -08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * NEON-accelerated implementation of Speck128-XTS and Speck64-XTS
4 * (64-bit version; based on the 32-bit version)
5 *
6 * Copyright (c) 2018 Google, Inc
7 */
8
9#include <asm/hwcap.h>
10#include <asm/neon.h>
11#include <asm/simd.h>
12#include <crypto/algapi.h>
13#include <crypto/gf128mul.h>
14#include <crypto/speck.h>
15#include <crypto/xts.h>
16#include <linux/kernel.h>
17#include <linux/module.h>
18
19/* The assembly functions only handle multiples of 128 bytes */
20#define SPECK_NEON_CHUNK_SIZE 128
21
22/* Speck128 */
23
24struct speck128_xts_tfm_ctx {
25 struct speck128_tfm_ctx main_key;
26 struct speck128_tfm_ctx tweak_key;
27};
28
29asmlinkage void speck128_xts_encrypt_neon(const u64 *round_keys, int nrounds,
30 void *dst, const void *src,
31 unsigned int nbytes, void *tweak);
32
33asmlinkage void speck128_xts_decrypt_neon(const u64 *round_keys, int nrounds,
34 void *dst, const void *src,
35 unsigned int nbytes, void *tweak);
36
37typedef void (*speck128_crypt_one_t)(const struct speck128_tfm_ctx *,
38 u8 *, const u8 *);
39typedef void (*speck128_xts_crypt_many_t)(const u64 *, int, void *,
40 const void *, unsigned int, void *);
41
42static __always_inline int
43__speck128_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
44 struct scatterlist *src, unsigned int nbytes,
45 speck128_crypt_one_t crypt_one,
46 speck128_xts_crypt_many_t crypt_many)
47{
48 struct crypto_blkcipher *tfm = desc->tfm;
49 const struct speck128_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm);
50 struct blkcipher_walk walk;
51 le128 tweak;
52 int err;
53
54 blkcipher_walk_init(&walk, dst, src, nbytes);
55 err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE);
56
57 crypto_speck128_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
58
59 while (walk.nbytes > 0) {
60 unsigned int nbytes = walk.nbytes;
61 u8 *dst = walk.dst.virt.addr;
62 const u8 *src = walk.src.virt.addr;
63
64 if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
65 unsigned int count;
66
67 count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
68 kernel_neon_begin();
69 (*crypt_many)(ctx->main_key.round_keys,
70 ctx->main_key.nrounds,
71 dst, src, count, &tweak);
72 kernel_neon_end();
73 dst += count;
74 src += count;
75 nbytes -= count;
76 }
77
78 /* Handle any remainder with generic code */
79 while (nbytes >= sizeof(tweak)) {
80 le128_xor((le128 *)dst, (const le128 *)src, &tweak);
81 (*crypt_one)(&ctx->main_key, dst, dst);
82 le128_xor((le128 *)dst, (const le128 *)dst, &tweak);
83 gf128mul_x_ble((be128 *)&tweak, (const be128 *)&tweak);
84
85 dst += sizeof(tweak);
86 src += sizeof(tweak);
87 nbytes -= sizeof(tweak);
88 }
89 err = blkcipher_walk_done(desc, &walk, nbytes);
90 }
91
92 return err;
93}
94
95static int speck128_xts_encrypt(struct blkcipher_desc *desc,
96 struct scatterlist *dst,
97 struct scatterlist *src,
98 unsigned int nbytes)
99{
100 return __speck128_xts_crypt(desc, dst, src, nbytes,
101 crypto_speck128_encrypt,
102 speck128_xts_encrypt_neon);
103}
104
105static int speck128_xts_decrypt(struct blkcipher_desc *desc,
106 struct scatterlist *dst,
107 struct scatterlist *src,
108 unsigned int nbytes)
109{
110 return __speck128_xts_crypt(desc, dst, src, nbytes,
111 crypto_speck128_decrypt,
112 speck128_xts_decrypt_neon);
113}
114
115static int speck128_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
116 unsigned int keylen)
117{
118 struct speck128_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
119 int err;
120
121 if (keylen % 2)
122 return -EINVAL;
123
124 keylen /= 2;
125
126 err = crypto_speck128_setkey(&ctx->main_key, key, keylen);
127 if (err)
128 return err;
129
130 return crypto_speck128_setkey(&ctx->tweak_key, key + keylen, keylen);
131}
132
133/* Speck64 */
134
135struct speck64_xts_tfm_ctx {
136 struct speck64_tfm_ctx main_key;
137 struct speck64_tfm_ctx tweak_key;
138};
139
140asmlinkage void speck64_xts_encrypt_neon(const u32 *round_keys, int nrounds,
141 void *dst, const void *src,
142 unsigned int nbytes, void *tweak);
143
144asmlinkage void speck64_xts_decrypt_neon(const u32 *round_keys, int nrounds,
145 void *dst, const void *src,
146 unsigned int nbytes, void *tweak);
147
148typedef void (*speck64_crypt_one_t)(const struct speck64_tfm_ctx *,
149 u8 *, const u8 *);
150typedef void (*speck64_xts_crypt_many_t)(const u32 *, int, void *,
151 const void *, unsigned int, void *);
152
153static __always_inline int
154__speck64_xts_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
155 struct scatterlist *src, unsigned int nbytes,
156 speck64_crypt_one_t crypt_one,
157 speck64_xts_crypt_many_t crypt_many)
158{
159 struct crypto_blkcipher *tfm = desc->tfm;
160 const struct speck64_xts_tfm_ctx *ctx = crypto_blkcipher_ctx(tfm);
161 struct blkcipher_walk walk;
162 __le64 tweak;
163 int err;
164
165 blkcipher_walk_init(&walk, dst, src, nbytes);
166 err = blkcipher_walk_virt_block(desc, &walk, SPECK_NEON_CHUNK_SIZE);
167
168 crypto_speck64_encrypt(&ctx->tweak_key, (u8 *)&tweak, walk.iv);
169
170 while (walk.nbytes > 0) {
171 unsigned int nbytes = walk.nbytes;
172 u8 *dst = walk.dst.virt.addr;
173 const u8 *src = walk.src.virt.addr;
174
175 if (nbytes >= SPECK_NEON_CHUNK_SIZE && may_use_simd()) {
176 unsigned int count;
177
178 count = round_down(nbytes, SPECK_NEON_CHUNK_SIZE);
179 kernel_neon_begin();
180 (*crypt_many)(ctx->main_key.round_keys,
181 ctx->main_key.nrounds,
182 dst, src, count, &tweak);
183 kernel_neon_end();
184 dst += count;
185 src += count;
186 nbytes -= count;
187 }
188
189 /* Handle any remainder with generic code */
190 while (nbytes >= sizeof(tweak)) {
191 *(__le64 *)dst = *(__le64 *)src ^ tweak;
192 (*crypt_one)(&ctx->main_key, dst, dst);
193 *(__le64 *)dst ^= tweak;
194 tweak = cpu_to_le64((le64_to_cpu(tweak) << 1) ^
195 ((tweak & cpu_to_le64(1ULL << 63)) ?
196 0x1B : 0));
197 dst += sizeof(tweak);
198 src += sizeof(tweak);
199 nbytes -= sizeof(tweak);
200 }
201 err = blkcipher_walk_done(desc, &walk, nbytes);
202 }
203
204 return err;
205}
206
207static int speck64_xts_encrypt(struct blkcipher_desc *desc,
208 struct scatterlist *dst, struct scatterlist *src,
209 unsigned int nbytes)
210{
211 return __speck64_xts_crypt(desc, dst, src, nbytes,
212 crypto_speck64_encrypt,
213 speck64_xts_encrypt_neon);
214}
215
216static int speck64_xts_decrypt(struct blkcipher_desc *desc,
217 struct scatterlist *dst, struct scatterlist *src,
218 unsigned int nbytes)
219{
220 return __speck64_xts_crypt(desc, dst, src, nbytes,
221 crypto_speck64_decrypt,
222 speck64_xts_decrypt_neon);
223}
224
225static int speck64_xts_setkey(struct crypto_tfm *tfm, const u8 *key,
226 unsigned int keylen)
227{
228 struct speck64_xts_tfm_ctx *ctx = crypto_tfm_ctx(tfm);
229 int err;
230
231 if (keylen % 2)
232 return -EINVAL;
233
234 keylen /= 2;
235
236 err = crypto_speck64_setkey(&ctx->main_key, key, keylen);
237 if (err)
238 return err;
239
240 return crypto_speck64_setkey(&ctx->tweak_key, key + keylen, keylen);
241}
242
243static struct crypto_alg speck_algs[] = {
244 {
245 .cra_name = "xts(speck128)",
246 .cra_driver_name = "xts-speck128-neon",
247 .cra_priority = 300,
248 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
249 .cra_blocksize = SPECK128_BLOCK_SIZE,
250 .cra_type = &crypto_blkcipher_type,
251 .cra_ctxsize = sizeof(struct speck128_xts_tfm_ctx),
252 .cra_alignmask = 7,
253 .cra_module = THIS_MODULE,
254 .cra_u = {
255 .blkcipher = {
256 .min_keysize = 2 * SPECK128_128_KEY_SIZE,
257 .max_keysize = 2 * SPECK128_256_KEY_SIZE,
258 .ivsize = SPECK128_BLOCK_SIZE,
259 .setkey = speck128_xts_setkey,
260 .encrypt = speck128_xts_encrypt,
261 .decrypt = speck128_xts_decrypt,
262 }
263 }
264 }, {
265 .cra_name = "xts(speck64)",
266 .cra_driver_name = "xts-speck64-neon",
267 .cra_priority = 300,
268 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
269 .cra_blocksize = SPECK64_BLOCK_SIZE,
270 .cra_type = &crypto_blkcipher_type,
271 .cra_ctxsize = sizeof(struct speck64_xts_tfm_ctx),
272 .cra_alignmask = 7,
273 .cra_module = THIS_MODULE,
274 .cra_u = {
275 .blkcipher = {
276 .min_keysize = 2 * SPECK64_96_KEY_SIZE,
277 .max_keysize = 2 * SPECK64_128_KEY_SIZE,
278 .ivsize = SPECK64_BLOCK_SIZE,
279 .setkey = speck64_xts_setkey,
280 .encrypt = speck64_xts_encrypt,
281 .decrypt = speck64_xts_decrypt,
282 }
283 }
284 }
285};
286
287static int __init speck_neon_module_init(void)
288{
289 if (!(elf_hwcap & HWCAP_ASIMD))
290 return -ENODEV;
291 return crypto_register_algs(speck_algs, ARRAY_SIZE(speck_algs));
292}
293
294static void __exit speck_neon_module_exit(void)
295{
296 crypto_unregister_algs(speck_algs, ARRAY_SIZE(speck_algs));
297}
298
299module_init(speck_neon_module_init);
300module_exit(speck_neon_module_exit);
301
302MODULE_DESCRIPTION("Speck block cipher (NEON-accelerated)");
303MODULE_LICENSE("GPL");
304MODULE_AUTHOR("Eric Biggers <ebiggers@google.com>");
305MODULE_ALIAS_CRYPTO("xts(speck128)");
306MODULE_ALIAS_CRYPTO("xts-speck128-neon");
307MODULE_ALIAS_CRYPTO("xts(speck64)");
308MODULE_ALIAS_CRYPTO("xts-speck64-neon");