2 * Glue Code for x86_64/AVX2 assembler optimized version of Serpent
4 * Copyright © 2012-2013 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
13 #include <linux/module.h>
14 #include <linux/types.h>
15 #include <linux/crypto.h>
16 #include <linux/err.h>
17 #include <crypto/algapi.h>
18 #include <crypto/ctr.h>
19 #include <crypto/lrw.h>
20 #include <crypto/xts.h>
21 #include <crypto/serpent.h>
23 #include <asm/xsave.h>
24 #include <asm/crypto/serpent-avx.h>
25 #include <asm/crypto/ablk_helper.h>
26 #include <asm/crypto/glue_helper.h>
28 #define SERPENT_AVX2_PARALLEL_BLOCKS 16
30 /* 16-way AVX2 parallel cipher functions */
31 asmlinkage
void serpent_ecb_enc_16way(struct serpent_ctx
*ctx
, u8
*dst
,
33 asmlinkage
void serpent_ecb_dec_16way(struct serpent_ctx
*ctx
, u8
*dst
,
35 asmlinkage
void serpent_cbc_dec_16way(void *ctx
, u128
*dst
, const u128
*src
);
37 asmlinkage
void serpent_ctr_16way(void *ctx
, u128
*dst
, const u128
*src
,
39 asmlinkage
void serpent_xts_enc_16way(struct serpent_ctx
*ctx
, u8
*dst
,
40 const u8
*src
, le128
*iv
);
41 asmlinkage
void serpent_xts_dec_16way(struct serpent_ctx
*ctx
, u8
*dst
,
42 const u8
*src
, le128
*iv
);
44 static const struct common_glue_ctx serpent_enc
= {
46 .fpu_blocks_limit
= 8,
50 .fn_u
= { .ecb
= GLUE_FUNC_CAST(serpent_ecb_enc_16way
) }
53 .fn_u
= { .ecb
= GLUE_FUNC_CAST(serpent_ecb_enc_8way_avx
) }
56 .fn_u
= { .ecb
= GLUE_FUNC_CAST(__serpent_encrypt
) }
60 static const struct common_glue_ctx serpent_ctr
= {
62 .fpu_blocks_limit
= 8,
66 .fn_u
= { .ctr
= GLUE_CTR_FUNC_CAST(serpent_ctr_16way
) }
69 .fn_u
= { .ctr
= GLUE_CTR_FUNC_CAST(serpent_ctr_8way_avx
) }
72 .fn_u
= { .ctr
= GLUE_CTR_FUNC_CAST(__serpent_crypt_ctr
) }
76 static const struct common_glue_ctx serpent_enc_xts
= {
78 .fpu_blocks_limit
= 8,
82 .fn_u
= { .xts
= GLUE_XTS_FUNC_CAST(serpent_xts_enc_16way
) }
85 .fn_u
= { .xts
= GLUE_XTS_FUNC_CAST(serpent_xts_enc_8way_avx
) }
88 .fn_u
= { .xts
= GLUE_XTS_FUNC_CAST(serpent_xts_enc
) }
92 static const struct common_glue_ctx serpent_dec
= {
94 .fpu_blocks_limit
= 8,
98 .fn_u
= { .ecb
= GLUE_FUNC_CAST(serpent_ecb_dec_16way
) }
101 .fn_u
= { .ecb
= GLUE_FUNC_CAST(serpent_ecb_dec_8way_avx
) }
104 .fn_u
= { .ecb
= GLUE_FUNC_CAST(__serpent_decrypt
) }
108 static const struct common_glue_ctx serpent_dec_cbc
= {
110 .fpu_blocks_limit
= 8,
114 .fn_u
= { .cbc
= GLUE_CBC_FUNC_CAST(serpent_cbc_dec_16way
) }
117 .fn_u
= { .cbc
= GLUE_CBC_FUNC_CAST(serpent_cbc_dec_8way_avx
) }
120 .fn_u
= { .cbc
= GLUE_CBC_FUNC_CAST(__serpent_decrypt
) }
124 static const struct common_glue_ctx serpent_dec_xts
= {
126 .fpu_blocks_limit
= 8,
130 .fn_u
= { .xts
= GLUE_XTS_FUNC_CAST(serpent_xts_dec_16way
) }
133 .fn_u
= { .xts
= GLUE_XTS_FUNC_CAST(serpent_xts_dec_8way_avx
) }
136 .fn_u
= { .xts
= GLUE_XTS_FUNC_CAST(serpent_xts_dec
) }
140 static int ecb_encrypt(struct blkcipher_desc
*desc
, struct scatterlist
*dst
,
141 struct scatterlist
*src
, unsigned int nbytes
)
143 return glue_ecb_crypt_128bit(&serpent_enc
, desc
, dst
, src
, nbytes
);
146 static int ecb_decrypt(struct blkcipher_desc
*desc
, struct scatterlist
*dst
,
147 struct scatterlist
*src
, unsigned int nbytes
)
149 return glue_ecb_crypt_128bit(&serpent_dec
, desc
, dst
, src
, nbytes
);
152 static int cbc_encrypt(struct blkcipher_desc
*desc
, struct scatterlist
*dst
,
153 struct scatterlist
*src
, unsigned int nbytes
)
155 return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__serpent_encrypt
), desc
,
159 static int cbc_decrypt(struct blkcipher_desc
*desc
, struct scatterlist
*dst
,
160 struct scatterlist
*src
, unsigned int nbytes
)
162 return glue_cbc_decrypt_128bit(&serpent_dec_cbc
, desc
, dst
, src
,
166 static int ctr_crypt(struct blkcipher_desc
*desc
, struct scatterlist
*dst
,
167 struct scatterlist
*src
, unsigned int nbytes
)
169 return glue_ctr_crypt_128bit(&serpent_ctr
, desc
, dst
, src
, nbytes
);
172 static inline bool serpent_fpu_begin(bool fpu_enabled
, unsigned int nbytes
)
174 /* since reusing AVX functions, starts using FPU at 8 parallel blocks */
175 return glue_fpu_begin(SERPENT_BLOCK_SIZE
, 8, NULL
, fpu_enabled
, nbytes
);
178 static inline void serpent_fpu_end(bool fpu_enabled
)
180 glue_fpu_end(fpu_enabled
);
184 struct serpent_ctx
*ctx
;
188 static void encrypt_callback(void *priv
, u8
*srcdst
, unsigned int nbytes
)
190 const unsigned int bsize
= SERPENT_BLOCK_SIZE
;
191 struct crypt_priv
*ctx
= priv
;
194 ctx
->fpu_enabled
= serpent_fpu_begin(ctx
->fpu_enabled
, nbytes
);
196 if (nbytes
>= SERPENT_AVX2_PARALLEL_BLOCKS
* bsize
) {
197 serpent_ecb_enc_16way(ctx
->ctx
, srcdst
, srcdst
);
198 srcdst
+= bsize
* SERPENT_AVX2_PARALLEL_BLOCKS
;
199 nbytes
-= bsize
* SERPENT_AVX2_PARALLEL_BLOCKS
;
202 while (nbytes
>= SERPENT_PARALLEL_BLOCKS
* bsize
) {
203 serpent_ecb_enc_8way_avx(ctx
->ctx
, srcdst
, srcdst
);
204 srcdst
+= bsize
* SERPENT_PARALLEL_BLOCKS
;
205 nbytes
-= bsize
* SERPENT_PARALLEL_BLOCKS
;
208 for (i
= 0; i
< nbytes
/ bsize
; i
++, srcdst
+= bsize
)
209 __serpent_encrypt(ctx
->ctx
, srcdst
, srcdst
);
212 static void decrypt_callback(void *priv
, u8
*srcdst
, unsigned int nbytes
)
214 const unsigned int bsize
= SERPENT_BLOCK_SIZE
;
215 struct crypt_priv
*ctx
= priv
;
218 ctx
->fpu_enabled
= serpent_fpu_begin(ctx
->fpu_enabled
, nbytes
);
220 if (nbytes
>= SERPENT_AVX2_PARALLEL_BLOCKS
* bsize
) {
221 serpent_ecb_dec_16way(ctx
->ctx
, srcdst
, srcdst
);
222 srcdst
+= bsize
* SERPENT_AVX2_PARALLEL_BLOCKS
;
223 nbytes
-= bsize
* SERPENT_AVX2_PARALLEL_BLOCKS
;
226 while (nbytes
>= SERPENT_PARALLEL_BLOCKS
* bsize
) {
227 serpent_ecb_dec_8way_avx(ctx
->ctx
, srcdst
, srcdst
);
228 srcdst
+= bsize
* SERPENT_PARALLEL_BLOCKS
;
229 nbytes
-= bsize
* SERPENT_PARALLEL_BLOCKS
;
232 for (i
= 0; i
< nbytes
/ bsize
; i
++, srcdst
+= bsize
)
233 __serpent_decrypt(ctx
->ctx
, srcdst
, srcdst
);
236 static int lrw_encrypt(struct blkcipher_desc
*desc
, struct scatterlist
*dst
,
237 struct scatterlist
*src
, unsigned int nbytes
)
239 struct serpent_lrw_ctx
*ctx
= crypto_blkcipher_ctx(desc
->tfm
);
240 be128 buf
[SERPENT_AVX2_PARALLEL_BLOCKS
];
241 struct crypt_priv crypt_ctx
= {
242 .ctx
= &ctx
->serpent_ctx
,
243 .fpu_enabled
= false,
245 struct lrw_crypt_req req
= {
247 .tbuflen
= sizeof(buf
),
249 .table_ctx
= &ctx
->lrw_table
,
250 .crypt_ctx
= &crypt_ctx
,
251 .crypt_fn
= encrypt_callback
,
255 desc
->flags
&= ~CRYPTO_TFM_REQ_MAY_SLEEP
;
256 ret
= lrw_crypt(desc
, dst
, src
, nbytes
, &req
);
257 serpent_fpu_end(crypt_ctx
.fpu_enabled
);
262 static int lrw_decrypt(struct blkcipher_desc
*desc
, struct scatterlist
*dst
,
263 struct scatterlist
*src
, unsigned int nbytes
)
265 struct serpent_lrw_ctx
*ctx
= crypto_blkcipher_ctx(desc
->tfm
);
266 be128 buf
[SERPENT_AVX2_PARALLEL_BLOCKS
];
267 struct crypt_priv crypt_ctx
= {
268 .ctx
= &ctx
->serpent_ctx
,
269 .fpu_enabled
= false,
271 struct lrw_crypt_req req
= {
273 .tbuflen
= sizeof(buf
),
275 .table_ctx
= &ctx
->lrw_table
,
276 .crypt_ctx
= &crypt_ctx
,
277 .crypt_fn
= decrypt_callback
,
281 desc
->flags
&= ~CRYPTO_TFM_REQ_MAY_SLEEP
;
282 ret
= lrw_crypt(desc
, dst
, src
, nbytes
, &req
);
283 serpent_fpu_end(crypt_ctx
.fpu_enabled
);
288 static int xts_encrypt(struct blkcipher_desc
*desc
, struct scatterlist
*dst
,
289 struct scatterlist
*src
, unsigned int nbytes
)
291 struct serpent_xts_ctx
*ctx
= crypto_blkcipher_ctx(desc
->tfm
);
293 return glue_xts_crypt_128bit(&serpent_enc_xts
, desc
, dst
, src
, nbytes
,
294 XTS_TWEAK_CAST(__serpent_encrypt
),
295 &ctx
->tweak_ctx
, &ctx
->crypt_ctx
);
298 static int xts_decrypt(struct blkcipher_desc
*desc
, struct scatterlist
*dst
,
299 struct scatterlist
*src
, unsigned int nbytes
)
301 struct serpent_xts_ctx
*ctx
= crypto_blkcipher_ctx(desc
->tfm
);
303 return glue_xts_crypt_128bit(&serpent_dec_xts
, desc
, dst
, src
, nbytes
,
304 XTS_TWEAK_CAST(__serpent_encrypt
),
305 &ctx
->tweak_ctx
, &ctx
->crypt_ctx
);
308 static struct crypto_alg srp_algs
[10] = { {
309 .cra_name
= "__ecb-serpent-avx2",
310 .cra_driver_name
= "__driver-ecb-serpent-avx2",
312 .cra_flags
= CRYPTO_ALG_TYPE_BLKCIPHER
,
313 .cra_blocksize
= SERPENT_BLOCK_SIZE
,
314 .cra_ctxsize
= sizeof(struct serpent_ctx
),
316 .cra_type
= &crypto_blkcipher_type
,
317 .cra_module
= THIS_MODULE
,
318 .cra_list
= LIST_HEAD_INIT(srp_algs
[0].cra_list
),
321 .min_keysize
= SERPENT_MIN_KEY_SIZE
,
322 .max_keysize
= SERPENT_MAX_KEY_SIZE
,
323 .setkey
= serpent_setkey
,
324 .encrypt
= ecb_encrypt
,
325 .decrypt
= ecb_decrypt
,
329 .cra_name
= "__cbc-serpent-avx2",
330 .cra_driver_name
= "__driver-cbc-serpent-avx2",
332 .cra_flags
= CRYPTO_ALG_TYPE_BLKCIPHER
,
333 .cra_blocksize
= SERPENT_BLOCK_SIZE
,
334 .cra_ctxsize
= sizeof(struct serpent_ctx
),
336 .cra_type
= &crypto_blkcipher_type
,
337 .cra_module
= THIS_MODULE
,
338 .cra_list
= LIST_HEAD_INIT(srp_algs
[1].cra_list
),
341 .min_keysize
= SERPENT_MIN_KEY_SIZE
,
342 .max_keysize
= SERPENT_MAX_KEY_SIZE
,
343 .setkey
= serpent_setkey
,
344 .encrypt
= cbc_encrypt
,
345 .decrypt
= cbc_decrypt
,
349 .cra_name
= "__ctr-serpent-avx2",
350 .cra_driver_name
= "__driver-ctr-serpent-avx2",
352 .cra_flags
= CRYPTO_ALG_TYPE_BLKCIPHER
,
354 .cra_ctxsize
= sizeof(struct serpent_ctx
),
356 .cra_type
= &crypto_blkcipher_type
,
357 .cra_module
= THIS_MODULE
,
358 .cra_list
= LIST_HEAD_INIT(srp_algs
[2].cra_list
),
361 .min_keysize
= SERPENT_MIN_KEY_SIZE
,
362 .max_keysize
= SERPENT_MAX_KEY_SIZE
,
363 .ivsize
= SERPENT_BLOCK_SIZE
,
364 .setkey
= serpent_setkey
,
365 .encrypt
= ctr_crypt
,
366 .decrypt
= ctr_crypt
,
370 .cra_name
= "__lrw-serpent-avx2",
371 .cra_driver_name
= "__driver-lrw-serpent-avx2",
373 .cra_flags
= CRYPTO_ALG_TYPE_BLKCIPHER
,
374 .cra_blocksize
= SERPENT_BLOCK_SIZE
,
375 .cra_ctxsize
= sizeof(struct serpent_lrw_ctx
),
377 .cra_type
= &crypto_blkcipher_type
,
378 .cra_module
= THIS_MODULE
,
379 .cra_list
= LIST_HEAD_INIT(srp_algs
[3].cra_list
),
380 .cra_exit
= lrw_serpent_exit_tfm
,
383 .min_keysize
= SERPENT_MIN_KEY_SIZE
+
385 .max_keysize
= SERPENT_MAX_KEY_SIZE
+
387 .ivsize
= SERPENT_BLOCK_SIZE
,
388 .setkey
= lrw_serpent_setkey
,
389 .encrypt
= lrw_encrypt
,
390 .decrypt
= lrw_decrypt
,
394 .cra_name
= "__xts-serpent-avx2",
395 .cra_driver_name
= "__driver-xts-serpent-avx2",
397 .cra_flags
= CRYPTO_ALG_TYPE_BLKCIPHER
,
398 .cra_blocksize
= SERPENT_BLOCK_SIZE
,
399 .cra_ctxsize
= sizeof(struct serpent_xts_ctx
),
401 .cra_type
= &crypto_blkcipher_type
,
402 .cra_module
= THIS_MODULE
,
403 .cra_list
= LIST_HEAD_INIT(srp_algs
[4].cra_list
),
406 .min_keysize
= SERPENT_MIN_KEY_SIZE
* 2,
407 .max_keysize
= SERPENT_MAX_KEY_SIZE
* 2,
408 .ivsize
= SERPENT_BLOCK_SIZE
,
409 .setkey
= xts_serpent_setkey
,
410 .encrypt
= xts_encrypt
,
411 .decrypt
= xts_decrypt
,
415 .cra_name
= "ecb(serpent)",
416 .cra_driver_name
= "ecb-serpent-avx2",
418 .cra_flags
= CRYPTO_ALG_TYPE_ABLKCIPHER
| CRYPTO_ALG_ASYNC
,
419 .cra_blocksize
= SERPENT_BLOCK_SIZE
,
420 .cra_ctxsize
= sizeof(struct async_helper_ctx
),
422 .cra_type
= &crypto_ablkcipher_type
,
423 .cra_module
= THIS_MODULE
,
424 .cra_list
= LIST_HEAD_INIT(srp_algs
[5].cra_list
),
425 .cra_init
= ablk_init
,
426 .cra_exit
= ablk_exit
,
429 .min_keysize
= SERPENT_MIN_KEY_SIZE
,
430 .max_keysize
= SERPENT_MAX_KEY_SIZE
,
431 .setkey
= ablk_set_key
,
432 .encrypt
= ablk_encrypt
,
433 .decrypt
= ablk_decrypt
,
437 .cra_name
= "cbc(serpent)",
438 .cra_driver_name
= "cbc-serpent-avx2",
440 .cra_flags
= CRYPTO_ALG_TYPE_ABLKCIPHER
| CRYPTO_ALG_ASYNC
,
441 .cra_blocksize
= SERPENT_BLOCK_SIZE
,
442 .cra_ctxsize
= sizeof(struct async_helper_ctx
),
444 .cra_type
= &crypto_ablkcipher_type
,
445 .cra_module
= THIS_MODULE
,
446 .cra_list
= LIST_HEAD_INIT(srp_algs
[6].cra_list
),
447 .cra_init
= ablk_init
,
448 .cra_exit
= ablk_exit
,
451 .min_keysize
= SERPENT_MIN_KEY_SIZE
,
452 .max_keysize
= SERPENT_MAX_KEY_SIZE
,
453 .ivsize
= SERPENT_BLOCK_SIZE
,
454 .setkey
= ablk_set_key
,
455 .encrypt
= __ablk_encrypt
,
456 .decrypt
= ablk_decrypt
,
460 .cra_name
= "ctr(serpent)",
461 .cra_driver_name
= "ctr-serpent-avx2",
463 .cra_flags
= CRYPTO_ALG_TYPE_ABLKCIPHER
| CRYPTO_ALG_ASYNC
,
465 .cra_ctxsize
= sizeof(struct async_helper_ctx
),
467 .cra_type
= &crypto_ablkcipher_type
,
468 .cra_module
= THIS_MODULE
,
469 .cra_list
= LIST_HEAD_INIT(srp_algs
[7].cra_list
),
470 .cra_init
= ablk_init
,
471 .cra_exit
= ablk_exit
,
474 .min_keysize
= SERPENT_MIN_KEY_SIZE
,
475 .max_keysize
= SERPENT_MAX_KEY_SIZE
,
476 .ivsize
= SERPENT_BLOCK_SIZE
,
477 .setkey
= ablk_set_key
,
478 .encrypt
= ablk_encrypt
,
479 .decrypt
= ablk_encrypt
,
484 .cra_name
= "lrw(serpent)",
485 .cra_driver_name
= "lrw-serpent-avx2",
487 .cra_flags
= CRYPTO_ALG_TYPE_ABLKCIPHER
| CRYPTO_ALG_ASYNC
,
488 .cra_blocksize
= SERPENT_BLOCK_SIZE
,
489 .cra_ctxsize
= sizeof(struct async_helper_ctx
),
491 .cra_type
= &crypto_ablkcipher_type
,
492 .cra_module
= THIS_MODULE
,
493 .cra_list
= LIST_HEAD_INIT(srp_algs
[8].cra_list
),
494 .cra_init
= ablk_init
,
495 .cra_exit
= ablk_exit
,
498 .min_keysize
= SERPENT_MIN_KEY_SIZE
+
500 .max_keysize
= SERPENT_MAX_KEY_SIZE
+
502 .ivsize
= SERPENT_BLOCK_SIZE
,
503 .setkey
= ablk_set_key
,
504 .encrypt
= ablk_encrypt
,
505 .decrypt
= ablk_decrypt
,
509 .cra_name
= "xts(serpent)",
510 .cra_driver_name
= "xts-serpent-avx2",
512 .cra_flags
= CRYPTO_ALG_TYPE_ABLKCIPHER
| CRYPTO_ALG_ASYNC
,
513 .cra_blocksize
= SERPENT_BLOCK_SIZE
,
514 .cra_ctxsize
= sizeof(struct async_helper_ctx
),
516 .cra_type
= &crypto_ablkcipher_type
,
517 .cra_module
= THIS_MODULE
,
518 .cra_list
= LIST_HEAD_INIT(srp_algs
[9].cra_list
),
519 .cra_init
= ablk_init
,
520 .cra_exit
= ablk_exit
,
523 .min_keysize
= SERPENT_MIN_KEY_SIZE
* 2,
524 .max_keysize
= SERPENT_MAX_KEY_SIZE
* 2,
525 .ivsize
= SERPENT_BLOCK_SIZE
,
526 .setkey
= ablk_set_key
,
527 .encrypt
= ablk_encrypt
,
528 .decrypt
= ablk_decrypt
,
533 static int __init
init(void)
537 if (!cpu_has_avx2
|| !cpu_has_osxsave
) {
538 pr_info("AVX2 instructions are not detected.\n");
542 xcr0
= xgetbv(XCR_XFEATURE_ENABLED_MASK
);
543 if ((xcr0
& (XSTATE_SSE
| XSTATE_YMM
)) != (XSTATE_SSE
| XSTATE_YMM
)) {
544 pr_info("AVX detected but unusable.\n");
548 return crypto_register_algs(srp_algs
, ARRAY_SIZE(srp_algs
));
551 static void __exit
fini(void)
553 crypto_unregister_algs(srp_algs
, ARRAY_SIZE(srp_algs
));
559 MODULE_LICENSE("GPL");
560 MODULE_DESCRIPTION("Serpent Cipher Algorithm, AVX2 optimized");
561 MODULE_ALIAS("serpent");
562 MODULE_ALIAS("serpent-asm");