blob: 31eb567cc8939efcbae63a2dde7ffea7e4edfb43 [file] [log] [blame]
Johannes Goetzfried7efe4072012-06-12 16:47:43 +08001/*
2 * Glue Code for AVX assembler versions of Serpent Cipher
3 *
4 * Copyright (C) 2012 Johannes Goetzfried
5 * <Johannes.Goetzfried@informatik.stud.uni-erlangen.de>
6 *
7 * Glue code based on serpent_sse2_glue.c by:
8 * Copyright (C) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 * USA
24 *
25 */
26
27#include <linux/module.h>
28#include <linux/hardirq.h>
29#include <linux/types.h>
30#include <linux/crypto.h>
31#include <linux/err.h>
32#include <crypto/algapi.h>
33#include <crypto/serpent.h>
34#include <crypto/cryptd.h>
35#include <crypto/b128ops.h>
36#include <crypto/ctr.h>
37#include <crypto/lrw.h>
38#include <crypto/xts.h>
39#include <asm/i387.h>
40#include <asm/xcr.h>
41#include <asm/xsave.h>
Jussi Kivilinna3387e7d2012-06-14 10:09:03 +080042#include <asm/serpent-avx.h>
Jussi Kivilinnaffaf9152012-06-18 14:06:58 +030043#include <asm/crypto/ablk_helper.h>
Johannes Goetzfried7efe4072012-06-12 16:47:43 +080044#include <crypto/scatterwalk.h>
45#include <linux/workqueue.h>
46#include <linux/spinlock.h>
47
Johannes Goetzfried7efe4072012-06-12 16:47:43 +080048static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes)
49{
50 if (fpu_enabled)
51 return true;
52
53 /* AVX is only used when chunk to be processed is large enough, so
54 * do not enable FPU until it is necessary.
55 */
56 if (nbytes < SERPENT_BLOCK_SIZE * SERPENT_PARALLEL_BLOCKS)
57 return false;
58
59 kernel_fpu_begin();
60 return true;
61}
62
63static inline void serpent_fpu_end(bool fpu_enabled)
64{
65 if (fpu_enabled)
66 kernel_fpu_end();
67}
68
69static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
70 bool enc)
71{
72 bool fpu_enabled = false;
73 struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
74 const unsigned int bsize = SERPENT_BLOCK_SIZE;
75 unsigned int nbytes;
76 int err;
77
78 err = blkcipher_walk_virt(desc, walk);
79 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
80
81 while ((nbytes = walk->nbytes)) {
82 u8 *wsrc = walk->src.virt.addr;
83 u8 *wdst = walk->dst.virt.addr;
84
85 fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
86
87 /* Process multi-block batch */
88 if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
89 do {
90 if (enc)
91 serpent_enc_blk_xway(ctx, wdst, wsrc);
92 else
93 serpent_dec_blk_xway(ctx, wdst, wsrc);
94
95 wsrc += bsize * SERPENT_PARALLEL_BLOCKS;
96 wdst += bsize * SERPENT_PARALLEL_BLOCKS;
97 nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
98 } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
99
100 if (nbytes < bsize)
101 goto done;
102 }
103
104 /* Handle leftovers */
105 do {
106 if (enc)
107 __serpent_encrypt(ctx, wdst, wsrc);
108 else
109 __serpent_decrypt(ctx, wdst, wsrc);
110
111 wsrc += bsize;
112 wdst += bsize;
113 nbytes -= bsize;
114 } while (nbytes >= bsize);
115
116done:
117 err = blkcipher_walk_done(desc, walk, nbytes);
118 }
119
120 serpent_fpu_end(fpu_enabled);
121 return err;
122}
123
124static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
125 struct scatterlist *src, unsigned int nbytes)
126{
127 struct blkcipher_walk walk;
128
129 blkcipher_walk_init(&walk, dst, src, nbytes);
130 return ecb_crypt(desc, &walk, true);
131}
132
133static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
134 struct scatterlist *src, unsigned int nbytes)
135{
136 struct blkcipher_walk walk;
137
138 blkcipher_walk_init(&walk, dst, src, nbytes);
139 return ecb_crypt(desc, &walk, false);
140}
141
142static unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
143 struct blkcipher_walk *walk)
144{
145 struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
146 const unsigned int bsize = SERPENT_BLOCK_SIZE;
147 unsigned int nbytes = walk->nbytes;
148 u128 *src = (u128 *)walk->src.virt.addr;
149 u128 *dst = (u128 *)walk->dst.virt.addr;
150 u128 *iv = (u128 *)walk->iv;
151
152 do {
153 u128_xor(dst, src, iv);
154 __serpent_encrypt(ctx, (u8 *)dst, (u8 *)dst);
155 iv = dst;
156
157 src += 1;
158 dst += 1;
159 nbytes -= bsize;
160 } while (nbytes >= bsize);
161
162 u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv);
163 return nbytes;
164}
165
166static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
167 struct scatterlist *src, unsigned int nbytes)
168{
169 struct blkcipher_walk walk;
170 int err;
171
172 blkcipher_walk_init(&walk, dst, src, nbytes);
173 err = blkcipher_walk_virt(desc, &walk);
174
175 while ((nbytes = walk.nbytes)) {
176 nbytes = __cbc_encrypt(desc, &walk);
177 err = blkcipher_walk_done(desc, &walk, nbytes);
178 }
179
180 return err;
181}
182
183static unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
184 struct blkcipher_walk *walk)
185{
186 struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
187 const unsigned int bsize = SERPENT_BLOCK_SIZE;
188 unsigned int nbytes = walk->nbytes;
189 u128 *src = (u128 *)walk->src.virt.addr;
190 u128 *dst = (u128 *)walk->dst.virt.addr;
191 u128 ivs[SERPENT_PARALLEL_BLOCKS - 1];
192 u128 last_iv;
193 int i;
194
195 /* Start of the last block. */
196 src += nbytes / bsize - 1;
197 dst += nbytes / bsize - 1;
198
199 last_iv = *src;
200
201 /* Process multi-block batch */
202 if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
203 do {
204 nbytes -= bsize * (SERPENT_PARALLEL_BLOCKS - 1);
205 src -= SERPENT_PARALLEL_BLOCKS - 1;
206 dst -= SERPENT_PARALLEL_BLOCKS - 1;
207
208 for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++)
209 ivs[i] = src[i];
210
211 serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
212
213 for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++)
214 u128_xor(dst + (i + 1), dst + (i + 1), ivs + i);
215
216 nbytes -= bsize;
217 if (nbytes < bsize)
218 goto done;
219
220 u128_xor(dst, dst, src - 1);
221 src -= 1;
222 dst -= 1;
223 } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
224
225 if (nbytes < bsize)
226 goto done;
227 }
228
229 /* Handle leftovers */
230 for (;;) {
231 __serpent_decrypt(ctx, (u8 *)dst, (u8 *)src);
232
233 nbytes -= bsize;
234 if (nbytes < bsize)
235 break;
236
237 u128_xor(dst, dst, src - 1);
238 src -= 1;
239 dst -= 1;
240 }
241
242done:
243 u128_xor(dst, dst, (u128 *)walk->iv);
244 *(u128 *)walk->iv = last_iv;
245
246 return nbytes;
247}
248
249static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
250 struct scatterlist *src, unsigned int nbytes)
251{
252 bool fpu_enabled = false;
253 struct blkcipher_walk walk;
254 int err;
255
256 blkcipher_walk_init(&walk, dst, src, nbytes);
257 err = blkcipher_walk_virt(desc, &walk);
258 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
259
260 while ((nbytes = walk.nbytes)) {
261 fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
262 nbytes = __cbc_decrypt(desc, &walk);
263 err = blkcipher_walk_done(desc, &walk, nbytes);
264 }
265
266 serpent_fpu_end(fpu_enabled);
267 return err;
268}
269
270static inline void u128_to_be128(be128 *dst, const u128 *src)
271{
272 dst->a = cpu_to_be64(src->a);
273 dst->b = cpu_to_be64(src->b);
274}
275
276static inline void be128_to_u128(u128 *dst, const be128 *src)
277{
278 dst->a = be64_to_cpu(src->a);
279 dst->b = be64_to_cpu(src->b);
280}
281
282static inline void u128_inc(u128 *i)
283{
284 i->b++;
285 if (!i->b)
286 i->a++;
287}
288
289static void ctr_crypt_final(struct blkcipher_desc *desc,
290 struct blkcipher_walk *walk)
291{
292 struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
293 u8 *ctrblk = walk->iv;
294 u8 keystream[SERPENT_BLOCK_SIZE];
295 u8 *src = walk->src.virt.addr;
296 u8 *dst = walk->dst.virt.addr;
297 unsigned int nbytes = walk->nbytes;
298
299 __serpent_encrypt(ctx, keystream, ctrblk);
300 crypto_xor(keystream, src, nbytes);
301 memcpy(dst, keystream, nbytes);
302
303 crypto_inc(ctrblk, SERPENT_BLOCK_SIZE);
304}
305
306static unsigned int __ctr_crypt(struct blkcipher_desc *desc,
307 struct blkcipher_walk *walk)
308{
309 struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
310 const unsigned int bsize = SERPENT_BLOCK_SIZE;
311 unsigned int nbytes = walk->nbytes;
312 u128 *src = (u128 *)walk->src.virt.addr;
313 u128 *dst = (u128 *)walk->dst.virt.addr;
314 u128 ctrblk;
315 be128 ctrblocks[SERPENT_PARALLEL_BLOCKS];
316 int i;
317
318 be128_to_u128(&ctrblk, (be128 *)walk->iv);
319
320 /* Process multi-block batch */
321 if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) {
322 do {
323 /* create ctrblks for parallel encrypt */
324 for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) {
325 if (dst != src)
326 dst[i] = src[i];
327
328 u128_to_be128(&ctrblocks[i], &ctrblk);
329 u128_inc(&ctrblk);
330 }
331
332 serpent_enc_blk_xway_xor(ctx, (u8 *)dst,
333 (u8 *)ctrblocks);
334
335 src += SERPENT_PARALLEL_BLOCKS;
336 dst += SERPENT_PARALLEL_BLOCKS;
337 nbytes -= bsize * SERPENT_PARALLEL_BLOCKS;
338 } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS);
339
340 if (nbytes < bsize)
341 goto done;
342 }
343
344 /* Handle leftovers */
345 do {
346 if (dst != src)
347 *dst = *src;
348
349 u128_to_be128(&ctrblocks[0], &ctrblk);
350 u128_inc(&ctrblk);
351
352 __serpent_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
353 u128_xor(dst, dst, (u128 *)ctrblocks);
354
355 src += 1;
356 dst += 1;
357 nbytes -= bsize;
358 } while (nbytes >= bsize);
359
360done:
361 u128_to_be128((be128 *)walk->iv, &ctrblk);
362 return nbytes;
363}
364
365static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
366 struct scatterlist *src, unsigned int nbytes)
367{
368 bool fpu_enabled = false;
369 struct blkcipher_walk walk;
370 int err;
371
372 blkcipher_walk_init(&walk, dst, src, nbytes);
373 err = blkcipher_walk_virt_block(desc, &walk, SERPENT_BLOCK_SIZE);
374 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
375
376 while ((nbytes = walk.nbytes) >= SERPENT_BLOCK_SIZE) {
377 fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes);
378 nbytes = __ctr_crypt(desc, &walk);
379 err = blkcipher_walk_done(desc, &walk, nbytes);
380 }
381
382 serpent_fpu_end(fpu_enabled);
383
384 if (walk.nbytes) {
385 ctr_crypt_final(desc, &walk);
386 err = blkcipher_walk_done(desc, &walk, 0);
387 }
388
389 return err;
390}
391
392struct crypt_priv {
393 struct serpent_ctx *ctx;
394 bool fpu_enabled;
395};
396
397static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
398{
399 const unsigned int bsize = SERPENT_BLOCK_SIZE;
400 struct crypt_priv *ctx = priv;
401 int i;
402
403 ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
404
405 if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
406 serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst);
407 return;
408 }
409
410 for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
411 __serpent_encrypt(ctx->ctx, srcdst, srcdst);
412}
413
414static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
415{
416 const unsigned int bsize = SERPENT_BLOCK_SIZE;
417 struct crypt_priv *ctx = priv;
418 int i;
419
420 ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes);
421
422 if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) {
423 serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst);
424 return;
425 }
426
427 for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
428 __serpent_decrypt(ctx->ctx, srcdst, srcdst);
429}
430
431struct serpent_lrw_ctx {
432 struct lrw_table_ctx lrw_table;
433 struct serpent_ctx serpent_ctx;
434};
435
436static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
437 unsigned int keylen)
438{
439 struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
440 int err;
441
442 err = __serpent_setkey(&ctx->serpent_ctx, key, keylen -
443 SERPENT_BLOCK_SIZE);
444 if (err)
445 return err;
446
447 return lrw_init_table(&ctx->lrw_table, key + keylen -
448 SERPENT_BLOCK_SIZE);
449}
450
451static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
452 struct scatterlist *src, unsigned int nbytes)
453{
454 struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
455 be128 buf[SERPENT_PARALLEL_BLOCKS];
456 struct crypt_priv crypt_ctx = {
457 .ctx = &ctx->serpent_ctx,
458 .fpu_enabled = false,
459 };
460 struct lrw_crypt_req req = {
461 .tbuf = buf,
462 .tbuflen = sizeof(buf),
463
464 .table_ctx = &ctx->lrw_table,
465 .crypt_ctx = &crypt_ctx,
466 .crypt_fn = encrypt_callback,
467 };
468 int ret;
469
470 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
471 ret = lrw_crypt(desc, dst, src, nbytes, &req);
472 serpent_fpu_end(crypt_ctx.fpu_enabled);
473
474 return ret;
475}
476
477static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
478 struct scatterlist *src, unsigned int nbytes)
479{
480 struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
481 be128 buf[SERPENT_PARALLEL_BLOCKS];
482 struct crypt_priv crypt_ctx = {
483 .ctx = &ctx->serpent_ctx,
484 .fpu_enabled = false,
485 };
486 struct lrw_crypt_req req = {
487 .tbuf = buf,
488 .tbuflen = sizeof(buf),
489
490 .table_ctx = &ctx->lrw_table,
491 .crypt_ctx = &crypt_ctx,
492 .crypt_fn = decrypt_callback,
493 };
494 int ret;
495
496 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
497 ret = lrw_crypt(desc, dst, src, nbytes, &req);
498 serpent_fpu_end(crypt_ctx.fpu_enabled);
499
500 return ret;
501}
502
503static void lrw_exit_tfm(struct crypto_tfm *tfm)
504{
505 struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
506
507 lrw_free_table(&ctx->lrw_table);
508}
509
510struct serpent_xts_ctx {
511 struct serpent_ctx tweak_ctx;
512 struct serpent_ctx crypt_ctx;
513};
514
515static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key,
516 unsigned int keylen)
517{
518 struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm);
519 u32 *flags = &tfm->crt_flags;
520 int err;
521
522 /* key consists of keys of equal size concatenated, therefore
523 * the length must be even
524 */
525 if (keylen % 2) {
526 *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
527 return -EINVAL;
528 }
529
530 /* first half of xts-key is for crypt */
531 err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2);
532 if (err)
533 return err;
534
535 /* second half of xts-key is for tweak */
536 return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2);
537}
538
539static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
540 struct scatterlist *src, unsigned int nbytes)
541{
542 struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
543 be128 buf[SERPENT_PARALLEL_BLOCKS];
544 struct crypt_priv crypt_ctx = {
545 .ctx = &ctx->crypt_ctx,
546 .fpu_enabled = false,
547 };
548 struct xts_crypt_req req = {
549 .tbuf = buf,
550 .tbuflen = sizeof(buf),
551
552 .tweak_ctx = &ctx->tweak_ctx,
553 .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
554 .crypt_ctx = &crypt_ctx,
555 .crypt_fn = encrypt_callback,
556 };
557 int ret;
558
559 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
560 ret = xts_crypt(desc, dst, src, nbytes, &req);
561 serpent_fpu_end(crypt_ctx.fpu_enabled);
562
563 return ret;
564}
565
566static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
567 struct scatterlist *src, unsigned int nbytes)
568{
569 struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
570 be128 buf[SERPENT_PARALLEL_BLOCKS];
571 struct crypt_priv crypt_ctx = {
572 .ctx = &ctx->crypt_ctx,
573 .fpu_enabled = false,
574 };
575 struct xts_crypt_req req = {
576 .tbuf = buf,
577 .tbuflen = sizeof(buf),
578
579 .tweak_ctx = &ctx->tweak_ctx,
580 .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt),
581 .crypt_ctx = &crypt_ctx,
582 .crypt_fn = decrypt_callback,
583 };
584 int ret;
585
586 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
587 ret = xts_crypt(desc, dst, src, nbytes, &req);
588 serpent_fpu_end(crypt_ctx.fpu_enabled);
589
590 return ret;
591}
592
Johannes Goetzfried7efe4072012-06-12 16:47:43 +0800593static struct crypto_alg serpent_algs[10] = { {
594 .cra_name = "__ecb-serpent-avx",
595 .cra_driver_name = "__driver-ecb-serpent-avx",
596 .cra_priority = 0,
597 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
598 .cra_blocksize = SERPENT_BLOCK_SIZE,
599 .cra_ctxsize = sizeof(struct serpent_ctx),
600 .cra_alignmask = 0,
601 .cra_type = &crypto_blkcipher_type,
602 .cra_module = THIS_MODULE,
603 .cra_list = LIST_HEAD_INIT(serpent_algs[0].cra_list),
604 .cra_u = {
605 .blkcipher = {
606 .min_keysize = SERPENT_MIN_KEY_SIZE,
607 .max_keysize = SERPENT_MAX_KEY_SIZE,
608 .setkey = serpent_setkey,
609 .encrypt = ecb_encrypt,
610 .decrypt = ecb_decrypt,
611 },
612 },
613}, {
614 .cra_name = "__cbc-serpent-avx",
615 .cra_driver_name = "__driver-cbc-serpent-avx",
616 .cra_priority = 0,
617 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
618 .cra_blocksize = SERPENT_BLOCK_SIZE,
619 .cra_ctxsize = sizeof(struct serpent_ctx),
620 .cra_alignmask = 0,
621 .cra_type = &crypto_blkcipher_type,
622 .cra_module = THIS_MODULE,
623 .cra_list = LIST_HEAD_INIT(serpent_algs[1].cra_list),
624 .cra_u = {
625 .blkcipher = {
626 .min_keysize = SERPENT_MIN_KEY_SIZE,
627 .max_keysize = SERPENT_MAX_KEY_SIZE,
628 .setkey = serpent_setkey,
629 .encrypt = cbc_encrypt,
630 .decrypt = cbc_decrypt,
631 },
632 },
633}, {
634 .cra_name = "__ctr-serpent-avx",
635 .cra_driver_name = "__driver-ctr-serpent-avx",
636 .cra_priority = 0,
637 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
638 .cra_blocksize = 1,
639 .cra_ctxsize = sizeof(struct serpent_ctx),
640 .cra_alignmask = 0,
641 .cra_type = &crypto_blkcipher_type,
642 .cra_module = THIS_MODULE,
643 .cra_list = LIST_HEAD_INIT(serpent_algs[2].cra_list),
644 .cra_u = {
645 .blkcipher = {
646 .min_keysize = SERPENT_MIN_KEY_SIZE,
647 .max_keysize = SERPENT_MAX_KEY_SIZE,
648 .ivsize = SERPENT_BLOCK_SIZE,
649 .setkey = serpent_setkey,
650 .encrypt = ctr_crypt,
651 .decrypt = ctr_crypt,
652 },
653 },
654}, {
655 .cra_name = "__lrw-serpent-avx",
656 .cra_driver_name = "__driver-lrw-serpent-avx",
657 .cra_priority = 0,
658 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
659 .cra_blocksize = SERPENT_BLOCK_SIZE,
660 .cra_ctxsize = sizeof(struct serpent_lrw_ctx),
661 .cra_alignmask = 0,
662 .cra_type = &crypto_blkcipher_type,
663 .cra_module = THIS_MODULE,
664 .cra_list = LIST_HEAD_INIT(serpent_algs[3].cra_list),
665 .cra_exit = lrw_exit_tfm,
666 .cra_u = {
667 .blkcipher = {
668 .min_keysize = SERPENT_MIN_KEY_SIZE +
669 SERPENT_BLOCK_SIZE,
670 .max_keysize = SERPENT_MAX_KEY_SIZE +
671 SERPENT_BLOCK_SIZE,
672 .ivsize = SERPENT_BLOCK_SIZE,
673 .setkey = lrw_serpent_setkey,
674 .encrypt = lrw_encrypt,
675 .decrypt = lrw_decrypt,
676 },
677 },
678}, {
679 .cra_name = "__xts-serpent-avx",
680 .cra_driver_name = "__driver-xts-serpent-avx",
681 .cra_priority = 0,
682 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
683 .cra_blocksize = SERPENT_BLOCK_SIZE,
684 .cra_ctxsize = sizeof(struct serpent_xts_ctx),
685 .cra_alignmask = 0,
686 .cra_type = &crypto_blkcipher_type,
687 .cra_module = THIS_MODULE,
688 .cra_list = LIST_HEAD_INIT(serpent_algs[4].cra_list),
689 .cra_u = {
690 .blkcipher = {
691 .min_keysize = SERPENT_MIN_KEY_SIZE * 2,
692 .max_keysize = SERPENT_MAX_KEY_SIZE * 2,
693 .ivsize = SERPENT_BLOCK_SIZE,
694 .setkey = xts_serpent_setkey,
695 .encrypt = xts_encrypt,
696 .decrypt = xts_decrypt,
697 },
698 },
699}, {
700 .cra_name = "ecb(serpent)",
701 .cra_driver_name = "ecb-serpent-avx",
702 .cra_priority = 500,
703 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
704 .cra_blocksize = SERPENT_BLOCK_SIZE,
Jussi Kivilinnaffaf9152012-06-18 14:06:58 +0300705 .cra_ctxsize = sizeof(struct async_helper_ctx),
Johannes Goetzfried7efe4072012-06-12 16:47:43 +0800706 .cra_alignmask = 0,
707 .cra_type = &crypto_ablkcipher_type,
708 .cra_module = THIS_MODULE,
709 .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list),
710 .cra_init = ablk_init,
711 .cra_exit = ablk_exit,
712 .cra_u = {
713 .ablkcipher = {
714 .min_keysize = SERPENT_MIN_KEY_SIZE,
715 .max_keysize = SERPENT_MAX_KEY_SIZE,
716 .setkey = ablk_set_key,
717 .encrypt = ablk_encrypt,
718 .decrypt = ablk_decrypt,
719 },
720 },
721}, {
722 .cra_name = "cbc(serpent)",
723 .cra_driver_name = "cbc-serpent-avx",
724 .cra_priority = 500,
725 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
726 .cra_blocksize = SERPENT_BLOCK_SIZE,
Jussi Kivilinnaffaf9152012-06-18 14:06:58 +0300727 .cra_ctxsize = sizeof(struct async_helper_ctx),
Johannes Goetzfried7efe4072012-06-12 16:47:43 +0800728 .cra_alignmask = 0,
729 .cra_type = &crypto_ablkcipher_type,
730 .cra_module = THIS_MODULE,
731 .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list),
732 .cra_init = ablk_init,
733 .cra_exit = ablk_exit,
734 .cra_u = {
735 .ablkcipher = {
736 .min_keysize = SERPENT_MIN_KEY_SIZE,
737 .max_keysize = SERPENT_MAX_KEY_SIZE,
738 .ivsize = SERPENT_BLOCK_SIZE,
739 .setkey = ablk_set_key,
740 .encrypt = __ablk_encrypt,
741 .decrypt = ablk_decrypt,
742 },
743 },
744}, {
745 .cra_name = "ctr(serpent)",
746 .cra_driver_name = "ctr-serpent-avx",
747 .cra_priority = 500,
748 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
749 .cra_blocksize = 1,
Jussi Kivilinnaffaf9152012-06-18 14:06:58 +0300750 .cra_ctxsize = sizeof(struct async_helper_ctx),
Johannes Goetzfried7efe4072012-06-12 16:47:43 +0800751 .cra_alignmask = 0,
752 .cra_type = &crypto_ablkcipher_type,
753 .cra_module = THIS_MODULE,
754 .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list),
755 .cra_init = ablk_init,
756 .cra_exit = ablk_exit,
757 .cra_u = {
758 .ablkcipher = {
759 .min_keysize = SERPENT_MIN_KEY_SIZE,
760 .max_keysize = SERPENT_MAX_KEY_SIZE,
761 .ivsize = SERPENT_BLOCK_SIZE,
762 .setkey = ablk_set_key,
763 .encrypt = ablk_encrypt,
764 .decrypt = ablk_encrypt,
765 .geniv = "chainiv",
766 },
767 },
768}, {
769 .cra_name = "lrw(serpent)",
770 .cra_driver_name = "lrw-serpent-avx",
771 .cra_priority = 500,
772 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
773 .cra_blocksize = SERPENT_BLOCK_SIZE,
Jussi Kivilinnaffaf9152012-06-18 14:06:58 +0300774 .cra_ctxsize = sizeof(struct async_helper_ctx),
Johannes Goetzfried7efe4072012-06-12 16:47:43 +0800775 .cra_alignmask = 0,
776 .cra_type = &crypto_ablkcipher_type,
777 .cra_module = THIS_MODULE,
778 .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list),
779 .cra_init = ablk_init,
780 .cra_exit = ablk_exit,
781 .cra_u = {
782 .ablkcipher = {
783 .min_keysize = SERPENT_MIN_KEY_SIZE +
784 SERPENT_BLOCK_SIZE,
785 .max_keysize = SERPENT_MAX_KEY_SIZE +
786 SERPENT_BLOCK_SIZE,
787 .ivsize = SERPENT_BLOCK_SIZE,
788 .setkey = ablk_set_key,
789 .encrypt = ablk_encrypt,
790 .decrypt = ablk_decrypt,
791 },
792 },
793}, {
794 .cra_name = "xts(serpent)",
795 .cra_driver_name = "xts-serpent-avx",
796 .cra_priority = 500,
797 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
798 .cra_blocksize = SERPENT_BLOCK_SIZE,
Jussi Kivilinnaffaf9152012-06-18 14:06:58 +0300799 .cra_ctxsize = sizeof(struct async_helper_ctx),
Johannes Goetzfried7efe4072012-06-12 16:47:43 +0800800 .cra_alignmask = 0,
801 .cra_type = &crypto_ablkcipher_type,
802 .cra_module = THIS_MODULE,
803 .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list),
804 .cra_init = ablk_init,
805 .cra_exit = ablk_exit,
806 .cra_u = {
807 .ablkcipher = {
808 .min_keysize = SERPENT_MIN_KEY_SIZE * 2,
809 .max_keysize = SERPENT_MAX_KEY_SIZE * 2,
810 .ivsize = SERPENT_BLOCK_SIZE,
811 .setkey = ablk_set_key,
812 .encrypt = ablk_encrypt,
813 .decrypt = ablk_decrypt,
814 },
815 },
816} };
817
818static int __init serpent_init(void)
819{
820 u64 xcr0;
821
822 if (!cpu_has_avx || !cpu_has_osxsave) {
823 printk(KERN_INFO "AVX instructions are not detected.\n");
824 return -ENODEV;
825 }
826
827 xcr0 = xgetbv(XCR_XFEATURE_ENABLED_MASK);
828 if ((xcr0 & (XSTATE_SSE | XSTATE_YMM)) != (XSTATE_SSE | XSTATE_YMM)) {
829 printk(KERN_INFO "AVX detected but unusable.\n");
830 return -ENODEV;
831 }
832
833 return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
834}
835
836static void __exit serpent_exit(void)
837{
838 crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs));
839}
840
841module_init(serpent_init);
842module_exit(serpent_exit);
843
844MODULE_DESCRIPTION("Serpent Cipher Algorithm, AVX optimized");
845MODULE_LICENSE("GPL");
846MODULE_ALIAS("serpent");