1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Glue Code for the AVX assembler implementation of the Cast5 Cipher
5 * Copyright (C) 2012 Johannes Goetzfried
6 * <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
9 #include <asm/crypto/glue_helper.h>
10 #include <crypto/algapi.h>
11 #include <crypto/cast5.h>
12 #include <crypto/internal/simd.h>
13 #include <linux/crypto.h>
14 #include <linux/err.h>
15 #include <linux/module.h>
16 #include <linux/types.h>
18 #define CAST5_PARALLEL_BLOCKS 16
20 asmlinkage
void cast5_ecb_enc_16way(struct cast5_ctx
*ctx
, u8
*dst
,
22 asmlinkage
void cast5_ecb_dec_16way(struct cast5_ctx
*ctx
, u8
*dst
,
24 asmlinkage
void cast5_cbc_dec_16way(struct cast5_ctx
*ctx
, u8
*dst
,
26 asmlinkage
void cast5_ctr_16way(struct cast5_ctx
*ctx
, u8
*dst
, const u8
*src
,
29 static int cast5_setkey_skcipher(struct crypto_skcipher
*tfm
, const u8
*key
,
32 return cast5_setkey(&tfm
->base
, key
, keylen
);
35 static inline bool cast5_fpu_begin(bool fpu_enabled
, struct skcipher_walk
*walk
,
38 return glue_fpu_begin(CAST5_BLOCK_SIZE
, CAST5_PARALLEL_BLOCKS
,
39 walk
, fpu_enabled
, nbytes
);
42 static inline void cast5_fpu_end(bool fpu_enabled
)
44 return glue_fpu_end(fpu_enabled
);
47 static int ecb_crypt(struct skcipher_request
*req
, bool enc
)
49 bool fpu_enabled
= false;
50 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
51 struct cast5_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
52 struct skcipher_walk walk
;
53 const unsigned int bsize
= CAST5_BLOCK_SIZE
;
55 void (*fn
)(struct cast5_ctx
*ctx
, u8
*dst
, const u8
*src
);
58 err
= skcipher_walk_virt(&walk
, req
, false);
60 while ((nbytes
= walk
.nbytes
)) {
61 u8
*wsrc
= walk
.src
.virt
.addr
;
62 u8
*wdst
= walk
.dst
.virt
.addr
;
64 fpu_enabled
= cast5_fpu_begin(fpu_enabled
, &walk
, nbytes
);
66 /* Process multi-block batch */
67 if (nbytes
>= bsize
* CAST5_PARALLEL_BLOCKS
) {
68 fn
= (enc
) ? cast5_ecb_enc_16way
: cast5_ecb_dec_16way
;
72 wsrc
+= bsize
* CAST5_PARALLEL_BLOCKS
;
73 wdst
+= bsize
* CAST5_PARALLEL_BLOCKS
;
74 nbytes
-= bsize
* CAST5_PARALLEL_BLOCKS
;
75 } while (nbytes
>= bsize
* CAST5_PARALLEL_BLOCKS
);
81 fn
= (enc
) ? __cast5_encrypt
: __cast5_decrypt
;
83 /* Handle leftovers */
90 } while (nbytes
>= bsize
);
93 err
= skcipher_walk_done(&walk
, nbytes
);
96 cast5_fpu_end(fpu_enabled
);
100 static int ecb_encrypt(struct skcipher_request
*req
)
102 return ecb_crypt(req
, true);
105 static int ecb_decrypt(struct skcipher_request
*req
)
107 return ecb_crypt(req
, false);
110 static int cbc_encrypt(struct skcipher_request
*req
)
112 const unsigned int bsize
= CAST5_BLOCK_SIZE
;
113 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
114 struct cast5_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
115 struct skcipher_walk walk
;
119 err
= skcipher_walk_virt(&walk
, req
, false);
121 while ((nbytes
= walk
.nbytes
)) {
122 u64
*src
= (u64
*)walk
.src
.virt
.addr
;
123 u64
*dst
= (u64
*)walk
.dst
.virt
.addr
;
124 u64
*iv
= (u64
*)walk
.iv
;
128 __cast5_encrypt(ctx
, (u8
*)dst
, (u8
*)dst
);
133 } while (nbytes
>= bsize
);
135 *(u64
*)walk
.iv
= *iv
;
136 err
= skcipher_walk_done(&walk
, nbytes
);
142 static unsigned int __cbc_decrypt(struct cast5_ctx
*ctx
,
143 struct skcipher_walk
*walk
)
145 const unsigned int bsize
= CAST5_BLOCK_SIZE
;
146 unsigned int nbytes
= walk
->nbytes
;
147 u64
*src
= (u64
*)walk
->src
.virt
.addr
;
148 u64
*dst
= (u64
*)walk
->dst
.virt
.addr
;
151 /* Start of the last block. */
152 src
+= nbytes
/ bsize
- 1;
153 dst
+= nbytes
/ bsize
- 1;
157 /* Process multi-block batch */
158 if (nbytes
>= bsize
* CAST5_PARALLEL_BLOCKS
) {
160 nbytes
-= bsize
* (CAST5_PARALLEL_BLOCKS
- 1);
161 src
-= CAST5_PARALLEL_BLOCKS
- 1;
162 dst
-= CAST5_PARALLEL_BLOCKS
- 1;
164 cast5_cbc_dec_16way(ctx
, (u8
*)dst
, (u8
*)src
);
173 } while (nbytes
>= bsize
* CAST5_PARALLEL_BLOCKS
);
176 /* Handle leftovers */
178 __cast5_decrypt(ctx
, (u8
*)dst
, (u8
*)src
);
190 *dst
^= *(u64
*)walk
->iv
;
191 *(u64
*)walk
->iv
= last_iv
;
196 static int cbc_decrypt(struct skcipher_request
*req
)
198 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
199 struct cast5_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
200 bool fpu_enabled
= false;
201 struct skcipher_walk walk
;
205 err
= skcipher_walk_virt(&walk
, req
, false);
207 while ((nbytes
= walk
.nbytes
)) {
208 fpu_enabled
= cast5_fpu_begin(fpu_enabled
, &walk
, nbytes
);
209 nbytes
= __cbc_decrypt(ctx
, &walk
);
210 err
= skcipher_walk_done(&walk
, nbytes
);
213 cast5_fpu_end(fpu_enabled
);
217 static void ctr_crypt_final(struct skcipher_walk
*walk
, struct cast5_ctx
*ctx
)
219 u8
*ctrblk
= walk
->iv
;
220 u8 keystream
[CAST5_BLOCK_SIZE
];
221 u8
*src
= walk
->src
.virt
.addr
;
222 u8
*dst
= walk
->dst
.virt
.addr
;
223 unsigned int nbytes
= walk
->nbytes
;
225 __cast5_encrypt(ctx
, keystream
, ctrblk
);
226 crypto_xor_cpy(dst
, keystream
, src
, nbytes
);
228 crypto_inc(ctrblk
, CAST5_BLOCK_SIZE
);
231 static unsigned int __ctr_crypt(struct skcipher_walk
*walk
,
232 struct cast5_ctx
*ctx
)
234 const unsigned int bsize
= CAST5_BLOCK_SIZE
;
235 unsigned int nbytes
= walk
->nbytes
;
236 u64
*src
= (u64
*)walk
->src
.virt
.addr
;
237 u64
*dst
= (u64
*)walk
->dst
.virt
.addr
;
239 /* Process multi-block batch */
240 if (nbytes
>= bsize
* CAST5_PARALLEL_BLOCKS
) {
242 cast5_ctr_16way(ctx
, (u8
*)dst
, (u8
*)src
,
245 src
+= CAST5_PARALLEL_BLOCKS
;
246 dst
+= CAST5_PARALLEL_BLOCKS
;
247 nbytes
-= bsize
* CAST5_PARALLEL_BLOCKS
;
248 } while (nbytes
>= bsize
* CAST5_PARALLEL_BLOCKS
);
254 /* Handle leftovers */
261 ctrblk
= *(u64
*)walk
->iv
;
262 be64_add_cpu((__be64
*)walk
->iv
, 1);
264 __cast5_encrypt(ctx
, (u8
*)&ctrblk
, (u8
*)&ctrblk
);
270 } while (nbytes
>= bsize
);
276 static int ctr_crypt(struct skcipher_request
*req
)
278 struct crypto_skcipher
*tfm
= crypto_skcipher_reqtfm(req
);
279 struct cast5_ctx
*ctx
= crypto_skcipher_ctx(tfm
);
280 bool fpu_enabled
= false;
281 struct skcipher_walk walk
;
285 err
= skcipher_walk_virt(&walk
, req
, false);
287 while ((nbytes
= walk
.nbytes
) >= CAST5_BLOCK_SIZE
) {
288 fpu_enabled
= cast5_fpu_begin(fpu_enabled
, &walk
, nbytes
);
289 nbytes
= __ctr_crypt(&walk
, ctx
);
290 err
= skcipher_walk_done(&walk
, nbytes
);
293 cast5_fpu_end(fpu_enabled
);
296 ctr_crypt_final(&walk
, ctx
);
297 err
= skcipher_walk_done(&walk
, 0);
303 static struct skcipher_alg cast5_algs
[] = {
305 .base
.cra_name
= "__ecb(cast5)",
306 .base
.cra_driver_name
= "__ecb-cast5-avx",
307 .base
.cra_priority
= 200,
308 .base
.cra_flags
= CRYPTO_ALG_INTERNAL
,
309 .base
.cra_blocksize
= CAST5_BLOCK_SIZE
,
310 .base
.cra_ctxsize
= sizeof(struct cast5_ctx
),
311 .base
.cra_module
= THIS_MODULE
,
312 .min_keysize
= CAST5_MIN_KEY_SIZE
,
313 .max_keysize
= CAST5_MAX_KEY_SIZE
,
314 .setkey
= cast5_setkey_skcipher
,
315 .encrypt
= ecb_encrypt
,
316 .decrypt
= ecb_decrypt
,
318 .base
.cra_name
= "__cbc(cast5)",
319 .base
.cra_driver_name
= "__cbc-cast5-avx",
320 .base
.cra_priority
= 200,
321 .base
.cra_flags
= CRYPTO_ALG_INTERNAL
,
322 .base
.cra_blocksize
= CAST5_BLOCK_SIZE
,
323 .base
.cra_ctxsize
= sizeof(struct cast5_ctx
),
324 .base
.cra_module
= THIS_MODULE
,
325 .min_keysize
= CAST5_MIN_KEY_SIZE
,
326 .max_keysize
= CAST5_MAX_KEY_SIZE
,
327 .ivsize
= CAST5_BLOCK_SIZE
,
328 .setkey
= cast5_setkey_skcipher
,
329 .encrypt
= cbc_encrypt
,
330 .decrypt
= cbc_decrypt
,
332 .base
.cra_name
= "__ctr(cast5)",
333 .base
.cra_driver_name
= "__ctr-cast5-avx",
334 .base
.cra_priority
= 200,
335 .base
.cra_flags
= CRYPTO_ALG_INTERNAL
,
336 .base
.cra_blocksize
= 1,
337 .base
.cra_ctxsize
= sizeof(struct cast5_ctx
),
338 .base
.cra_module
= THIS_MODULE
,
339 .min_keysize
= CAST5_MIN_KEY_SIZE
,
340 .max_keysize
= CAST5_MAX_KEY_SIZE
,
341 .ivsize
= CAST5_BLOCK_SIZE
,
342 .chunksize
= CAST5_BLOCK_SIZE
,
343 .setkey
= cast5_setkey_skcipher
,
344 .encrypt
= ctr_crypt
,
345 .decrypt
= ctr_crypt
,
349 static struct simd_skcipher_alg
*cast5_simd_algs
[ARRAY_SIZE(cast5_algs
)];
351 static int __init
cast5_init(void)
353 const char *feature_name
;
355 if (!cpu_has_xfeatures(XFEATURE_MASK_SSE
| XFEATURE_MASK_YMM
,
357 pr_info("CPU feature '%s' is not supported.\n", feature_name
);
361 return simd_register_skciphers_compat(cast5_algs
,
362 ARRAY_SIZE(cast5_algs
),
366 static void __exit
cast5_exit(void)
368 simd_unregister_skciphers(cast5_algs
, ARRAY_SIZE(cast5_algs
),
372 module_init(cast5_init
);
373 module_exit(cast5_exit
);
375 MODULE_DESCRIPTION("Cast5 Cipher Algorithm, AVX optimized");
376 MODULE_LICENSE("GPL");
377 MODULE_ALIAS_CRYPTO("cast5");