blob: 49c552c060e9b65c1ddb70e710becfbd246d3791 [file] [log] [blame]
Huang Ying54b6a1b2009-01-18 16:28:34 +11001/*
2 * Support for Intel AES-NI instructions. This file contains glue
3 * code, the real AES implementation is in intel-aes_asm.S.
4 *
5 * Copyright (C) 2008, Intel Corp.
6 * Author: Huang Ying <ying.huang@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/hardirq.h>
15#include <linux/types.h>
16#include <linux/crypto.h>
17#include <linux/err.h>
18#include <crypto/algapi.h>
19#include <crypto/aes.h>
20#include <crypto/cryptd.h>
21#include <asm/i387.h>
22#include <asm/aes.h>
23
Huang Ying2cf4ac82009-03-29 15:41:20 +080024#if defined(CONFIG_CRYPTO_CTR) || defined(CONFIG_CRYPTO_CTR_MODULE)
25#define HAS_CTR
26#endif
27
28#if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE)
29#define HAS_LRW
30#endif
31
32#if defined(CONFIG_CRYPTO_PCBC) || defined(CONFIG_CRYPTO_PCBC_MODULE)
33#define HAS_PCBC
34#endif
35
36#if defined(CONFIG_CRYPTO_XTS) || defined(CONFIG_CRYPTO_XTS_MODULE)
37#define HAS_XTS
38#endif
39
Huang Ying54b6a1b2009-01-18 16:28:34 +110040struct async_aes_ctx {
41 struct cryptd_ablkcipher *cryptd_tfm;
42};
43
44#define AESNI_ALIGN 16
45#define AES_BLOCK_MASK (~(AES_BLOCK_SIZE-1))
46
47asmlinkage int aesni_set_key(struct crypto_aes_ctx *ctx, const u8 *in_key,
48 unsigned int key_len);
49asmlinkage void aesni_enc(struct crypto_aes_ctx *ctx, u8 *out,
50 const u8 *in);
51asmlinkage void aesni_dec(struct crypto_aes_ctx *ctx, u8 *out,
52 const u8 *in);
53asmlinkage void aesni_ecb_enc(struct crypto_aes_ctx *ctx, u8 *out,
54 const u8 *in, unsigned int len);
55asmlinkage void aesni_ecb_dec(struct crypto_aes_ctx *ctx, u8 *out,
56 const u8 *in, unsigned int len);
57asmlinkage void aesni_cbc_enc(struct crypto_aes_ctx *ctx, u8 *out,
58 const u8 *in, unsigned int len, u8 *iv);
59asmlinkage void aesni_cbc_dec(struct crypto_aes_ctx *ctx, u8 *out,
60 const u8 *in, unsigned int len, u8 *iv);
61
Huang Ying54b6a1b2009-01-18 16:28:34 +110062static inline struct crypto_aes_ctx *aes_ctx(void *raw_ctx)
63{
64 unsigned long addr = (unsigned long)raw_ctx;
65 unsigned long align = AESNI_ALIGN;
66
67 if (align <= crypto_tfm_ctx_alignment())
68 align = 1;
69 return (struct crypto_aes_ctx *)ALIGN(addr, align);
70}
71
72static int aes_set_key_common(struct crypto_tfm *tfm, void *raw_ctx,
73 const u8 *in_key, unsigned int key_len)
74{
75 struct crypto_aes_ctx *ctx = aes_ctx(raw_ctx);
76 u32 *flags = &tfm->crt_flags;
77 int err;
78
79 if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 &&
80 key_len != AES_KEYSIZE_256) {
81 *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
82 return -EINVAL;
83 }
84
Huang Ying13b79b972009-10-20 16:20:47 +090085 if (!irq_fpu_usable())
Huang Ying54b6a1b2009-01-18 16:28:34 +110086 err = crypto_aes_expand_key(ctx, in_key, key_len);
87 else {
88 kernel_fpu_begin();
89 err = aesni_set_key(ctx, in_key, key_len);
90 kernel_fpu_end();
91 }
92
93 return err;
94}
95
96static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
97 unsigned int key_len)
98{
99 return aes_set_key_common(tfm, crypto_tfm_ctx(tfm), in_key, key_len);
100}
101
102static void aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
103{
104 struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
105
Huang Ying13b79b972009-10-20 16:20:47 +0900106 if (!irq_fpu_usable())
Huang Ying54b6a1b2009-01-18 16:28:34 +1100107 crypto_aes_encrypt_x86(ctx, dst, src);
108 else {
109 kernel_fpu_begin();
110 aesni_enc(ctx, dst, src);
111 kernel_fpu_end();
112 }
113}
114
115static void aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
116{
117 struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
118
Huang Ying13b79b972009-10-20 16:20:47 +0900119 if (!irq_fpu_usable())
Huang Ying54b6a1b2009-01-18 16:28:34 +1100120 crypto_aes_decrypt_x86(ctx, dst, src);
121 else {
122 kernel_fpu_begin();
123 aesni_dec(ctx, dst, src);
124 kernel_fpu_end();
125 }
126}
127
128static struct crypto_alg aesni_alg = {
129 .cra_name = "aes",
130 .cra_driver_name = "aes-aesni",
131 .cra_priority = 300,
132 .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
133 .cra_blocksize = AES_BLOCK_SIZE,
134 .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
135 .cra_alignmask = 0,
136 .cra_module = THIS_MODULE,
137 .cra_list = LIST_HEAD_INIT(aesni_alg.cra_list),
138 .cra_u = {
139 .cipher = {
140 .cia_min_keysize = AES_MIN_KEY_SIZE,
141 .cia_max_keysize = AES_MAX_KEY_SIZE,
142 .cia_setkey = aes_set_key,
143 .cia_encrypt = aes_encrypt,
144 .cia_decrypt = aes_decrypt
145 }
146 }
147};
148
Huang Ying2cf4ac82009-03-29 15:41:20 +0800149static void __aes_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
150{
151 struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
152
153 aesni_enc(ctx, dst, src);
154}
155
156static void __aes_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
157{
158 struct crypto_aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(tfm));
159
160 aesni_dec(ctx, dst, src);
161}
162
163static struct crypto_alg __aesni_alg = {
164 .cra_name = "__aes-aesni",
165 .cra_driver_name = "__driver-aes-aesni",
166 .cra_priority = 0,
167 .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
168 .cra_blocksize = AES_BLOCK_SIZE,
169 .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
170 .cra_alignmask = 0,
171 .cra_module = THIS_MODULE,
172 .cra_list = LIST_HEAD_INIT(__aesni_alg.cra_list),
173 .cra_u = {
174 .cipher = {
175 .cia_min_keysize = AES_MIN_KEY_SIZE,
176 .cia_max_keysize = AES_MAX_KEY_SIZE,
177 .cia_setkey = aes_set_key,
178 .cia_encrypt = __aes_encrypt,
179 .cia_decrypt = __aes_decrypt
180 }
181 }
182};
183
Huang Ying54b6a1b2009-01-18 16:28:34 +1100184static int ecb_encrypt(struct blkcipher_desc *desc,
185 struct scatterlist *dst, struct scatterlist *src,
186 unsigned int nbytes)
187{
188 struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
189 struct blkcipher_walk walk;
190 int err;
191
192 blkcipher_walk_init(&walk, dst, src, nbytes);
193 err = blkcipher_walk_virt(desc, &walk);
Huang Ying9251b642009-06-18 19:41:27 +0800194 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
Huang Ying54b6a1b2009-01-18 16:28:34 +1100195
196 kernel_fpu_begin();
197 while ((nbytes = walk.nbytes)) {
198 aesni_ecb_enc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
199 nbytes & AES_BLOCK_MASK);
200 nbytes &= AES_BLOCK_SIZE - 1;
201 err = blkcipher_walk_done(desc, &walk, nbytes);
202 }
203 kernel_fpu_end();
204
205 return err;
206}
207
208static int ecb_decrypt(struct blkcipher_desc *desc,
209 struct scatterlist *dst, struct scatterlist *src,
210 unsigned int nbytes)
211{
212 struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
213 struct blkcipher_walk walk;
214 int err;
215
216 blkcipher_walk_init(&walk, dst, src, nbytes);
217 err = blkcipher_walk_virt(desc, &walk);
Huang Ying9251b642009-06-18 19:41:27 +0800218 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
Huang Ying54b6a1b2009-01-18 16:28:34 +1100219
220 kernel_fpu_begin();
221 while ((nbytes = walk.nbytes)) {
222 aesni_ecb_dec(ctx, walk.dst.virt.addr, walk.src.virt.addr,
223 nbytes & AES_BLOCK_MASK);
224 nbytes &= AES_BLOCK_SIZE - 1;
225 err = blkcipher_walk_done(desc, &walk, nbytes);
226 }
227 kernel_fpu_end();
228
229 return err;
230}
231
232static struct crypto_alg blk_ecb_alg = {
233 .cra_name = "__ecb-aes-aesni",
234 .cra_driver_name = "__driver-ecb-aes-aesni",
235 .cra_priority = 0,
236 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
237 .cra_blocksize = AES_BLOCK_SIZE,
238 .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
239 .cra_alignmask = 0,
240 .cra_type = &crypto_blkcipher_type,
241 .cra_module = THIS_MODULE,
242 .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list),
243 .cra_u = {
244 .blkcipher = {
245 .min_keysize = AES_MIN_KEY_SIZE,
246 .max_keysize = AES_MAX_KEY_SIZE,
247 .setkey = aes_set_key,
248 .encrypt = ecb_encrypt,
249 .decrypt = ecb_decrypt,
250 },
251 },
252};
253
254static int cbc_encrypt(struct blkcipher_desc *desc,
255 struct scatterlist *dst, struct scatterlist *src,
256 unsigned int nbytes)
257{
258 struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
259 struct blkcipher_walk walk;
260 int err;
261
262 blkcipher_walk_init(&walk, dst, src, nbytes);
263 err = blkcipher_walk_virt(desc, &walk);
Huang Ying9251b642009-06-18 19:41:27 +0800264 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
Huang Ying54b6a1b2009-01-18 16:28:34 +1100265
266 kernel_fpu_begin();
267 while ((nbytes = walk.nbytes)) {
268 aesni_cbc_enc(ctx, walk.dst.virt.addr, walk.src.virt.addr,
269 nbytes & AES_BLOCK_MASK, walk.iv);
270 nbytes &= AES_BLOCK_SIZE - 1;
271 err = blkcipher_walk_done(desc, &walk, nbytes);
272 }
273 kernel_fpu_end();
274
275 return err;
276}
277
278static int cbc_decrypt(struct blkcipher_desc *desc,
279 struct scatterlist *dst, struct scatterlist *src,
280 unsigned int nbytes)
281{
282 struct crypto_aes_ctx *ctx = aes_ctx(crypto_blkcipher_ctx(desc->tfm));
283 struct blkcipher_walk walk;
284 int err;
285
286 blkcipher_walk_init(&walk, dst, src, nbytes);
287 err = blkcipher_walk_virt(desc, &walk);
Huang Ying9251b642009-06-18 19:41:27 +0800288 desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
Huang Ying54b6a1b2009-01-18 16:28:34 +1100289
290 kernel_fpu_begin();
291 while ((nbytes = walk.nbytes)) {
292 aesni_cbc_dec(ctx, walk.dst.virt.addr, walk.src.virt.addr,
293 nbytes & AES_BLOCK_MASK, walk.iv);
294 nbytes &= AES_BLOCK_SIZE - 1;
295 err = blkcipher_walk_done(desc, &walk, nbytes);
296 }
297 kernel_fpu_end();
298
299 return err;
300}
301
302static struct crypto_alg blk_cbc_alg = {
303 .cra_name = "__cbc-aes-aesni",
304 .cra_driver_name = "__driver-cbc-aes-aesni",
305 .cra_priority = 0,
306 .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER,
307 .cra_blocksize = AES_BLOCK_SIZE,
308 .cra_ctxsize = sizeof(struct crypto_aes_ctx)+AESNI_ALIGN-1,
309 .cra_alignmask = 0,
310 .cra_type = &crypto_blkcipher_type,
311 .cra_module = THIS_MODULE,
312 .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list),
313 .cra_u = {
314 .blkcipher = {
315 .min_keysize = AES_MIN_KEY_SIZE,
316 .max_keysize = AES_MAX_KEY_SIZE,
317 .setkey = aes_set_key,
318 .encrypt = cbc_encrypt,
319 .decrypt = cbc_decrypt,
320 },
321 },
322};
323
324static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key,
325 unsigned int key_len)
326{
327 struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
Huang Ying2cf4ac82009-03-29 15:41:20 +0800328 struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base;
329 int err;
Huang Ying54b6a1b2009-01-18 16:28:34 +1100330
Huang Ying2cf4ac82009-03-29 15:41:20 +0800331 crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK);
332 crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm)
333 & CRYPTO_TFM_REQ_MASK);
334 err = crypto_ablkcipher_setkey(child, key, key_len);
335 crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child)
336 & CRYPTO_TFM_RES_MASK);
337 return err;
Huang Ying54b6a1b2009-01-18 16:28:34 +1100338}
339
340static int ablk_encrypt(struct ablkcipher_request *req)
341{
342 struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
343 struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
344
Huang Ying13b79b972009-10-20 16:20:47 +0900345 if (!irq_fpu_usable()) {
Huang Ying54b6a1b2009-01-18 16:28:34 +1100346 struct ablkcipher_request *cryptd_req =
347 ablkcipher_request_ctx(req);
348 memcpy(cryptd_req, req, sizeof(*req));
349 ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
350 return crypto_ablkcipher_encrypt(cryptd_req);
351 } else {
352 struct blkcipher_desc desc;
353 desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
354 desc.info = req->info;
355 desc.flags = 0;
356 return crypto_blkcipher_crt(desc.tfm)->encrypt(
357 &desc, req->dst, req->src, req->nbytes);
358 }
359}
360
361static int ablk_decrypt(struct ablkcipher_request *req)
362{
363 struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req);
364 struct async_aes_ctx *ctx = crypto_ablkcipher_ctx(tfm);
365
Huang Ying13b79b972009-10-20 16:20:47 +0900366 if (!irq_fpu_usable()) {
Huang Ying54b6a1b2009-01-18 16:28:34 +1100367 struct ablkcipher_request *cryptd_req =
368 ablkcipher_request_ctx(req);
369 memcpy(cryptd_req, req, sizeof(*req));
370 ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base);
371 return crypto_ablkcipher_decrypt(cryptd_req);
372 } else {
373 struct blkcipher_desc desc;
374 desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm);
375 desc.info = req->info;
376 desc.flags = 0;
377 return crypto_blkcipher_crt(desc.tfm)->decrypt(
378 &desc, req->dst, req->src, req->nbytes);
379 }
380}
381
382static void ablk_exit(struct crypto_tfm *tfm)
383{
384 struct async_aes_ctx *ctx = crypto_tfm_ctx(tfm);
385
386 cryptd_free_ablkcipher(ctx->cryptd_tfm);
387}
388
389static void ablk_init_common(struct crypto_tfm *tfm,
390 struct cryptd_ablkcipher *cryptd_tfm)
391{
392 struct async_aes_ctx *ctx = crypto_tfm_ctx(tfm);
393
394 ctx->cryptd_tfm = cryptd_tfm;
395 tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
396 crypto_ablkcipher_reqsize(&cryptd_tfm->base);
397}
398
399static int ablk_ecb_init(struct crypto_tfm *tfm)
400{
401 struct cryptd_ablkcipher *cryptd_tfm;
402
403 cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-aes-aesni", 0, 0);
404 if (IS_ERR(cryptd_tfm))
405 return PTR_ERR(cryptd_tfm);
406 ablk_init_common(tfm, cryptd_tfm);
407 return 0;
408}
409
410static struct crypto_alg ablk_ecb_alg = {
411 .cra_name = "ecb(aes)",
412 .cra_driver_name = "ecb-aes-aesni",
413 .cra_priority = 400,
414 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
415 .cra_blocksize = AES_BLOCK_SIZE,
416 .cra_ctxsize = sizeof(struct async_aes_ctx),
417 .cra_alignmask = 0,
418 .cra_type = &crypto_ablkcipher_type,
419 .cra_module = THIS_MODULE,
420 .cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list),
421 .cra_init = ablk_ecb_init,
422 .cra_exit = ablk_exit,
423 .cra_u = {
424 .ablkcipher = {
425 .min_keysize = AES_MIN_KEY_SIZE,
426 .max_keysize = AES_MAX_KEY_SIZE,
427 .setkey = ablk_set_key,
428 .encrypt = ablk_encrypt,
429 .decrypt = ablk_decrypt,
430 },
431 },
432};
433
434static int ablk_cbc_init(struct crypto_tfm *tfm)
435{
436 struct cryptd_ablkcipher *cryptd_tfm;
437
438 cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-aes-aesni", 0, 0);
439 if (IS_ERR(cryptd_tfm))
440 return PTR_ERR(cryptd_tfm);
441 ablk_init_common(tfm, cryptd_tfm);
442 return 0;
443}
444
445static struct crypto_alg ablk_cbc_alg = {
446 .cra_name = "cbc(aes)",
447 .cra_driver_name = "cbc-aes-aesni",
448 .cra_priority = 400,
449 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
450 .cra_blocksize = AES_BLOCK_SIZE,
451 .cra_ctxsize = sizeof(struct async_aes_ctx),
452 .cra_alignmask = 0,
453 .cra_type = &crypto_ablkcipher_type,
454 .cra_module = THIS_MODULE,
455 .cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list),
456 .cra_init = ablk_cbc_init,
457 .cra_exit = ablk_exit,
458 .cra_u = {
459 .ablkcipher = {
460 .min_keysize = AES_MIN_KEY_SIZE,
461 .max_keysize = AES_MAX_KEY_SIZE,
462 .ivsize = AES_BLOCK_SIZE,
463 .setkey = ablk_set_key,
464 .encrypt = ablk_encrypt,
465 .decrypt = ablk_decrypt,
466 },
467 },
468};
469
Huang Ying2cf4ac82009-03-29 15:41:20 +0800470#ifdef HAS_CTR
471static int ablk_ctr_init(struct crypto_tfm *tfm)
472{
473 struct cryptd_ablkcipher *cryptd_tfm;
474
475 cryptd_tfm = cryptd_alloc_ablkcipher("fpu(ctr(__driver-aes-aesni))",
476 0, 0);
477 if (IS_ERR(cryptd_tfm))
478 return PTR_ERR(cryptd_tfm);
479 ablk_init_common(tfm, cryptd_tfm);
480 return 0;
481}
482
483static struct crypto_alg ablk_ctr_alg = {
484 .cra_name = "ctr(aes)",
485 .cra_driver_name = "ctr-aes-aesni",
486 .cra_priority = 400,
487 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
488 .cra_blocksize = 1,
489 .cra_ctxsize = sizeof(struct async_aes_ctx),
490 .cra_alignmask = 0,
491 .cra_type = &crypto_ablkcipher_type,
492 .cra_module = THIS_MODULE,
493 .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list),
494 .cra_init = ablk_ctr_init,
495 .cra_exit = ablk_exit,
496 .cra_u = {
497 .ablkcipher = {
498 .min_keysize = AES_MIN_KEY_SIZE,
499 .max_keysize = AES_MAX_KEY_SIZE,
500 .ivsize = AES_BLOCK_SIZE,
501 .setkey = ablk_set_key,
502 .encrypt = ablk_encrypt,
503 .decrypt = ablk_decrypt,
504 .geniv = "chainiv",
505 },
506 },
507};
508#endif
509
510#ifdef HAS_LRW
511static int ablk_lrw_init(struct crypto_tfm *tfm)
512{
513 struct cryptd_ablkcipher *cryptd_tfm;
514
515 cryptd_tfm = cryptd_alloc_ablkcipher("fpu(lrw(__driver-aes-aesni))",
516 0, 0);
517 if (IS_ERR(cryptd_tfm))
518 return PTR_ERR(cryptd_tfm);
519 ablk_init_common(tfm, cryptd_tfm);
520 return 0;
521}
522
523static struct crypto_alg ablk_lrw_alg = {
524 .cra_name = "lrw(aes)",
525 .cra_driver_name = "lrw-aes-aesni",
526 .cra_priority = 400,
527 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
528 .cra_blocksize = AES_BLOCK_SIZE,
529 .cra_ctxsize = sizeof(struct async_aes_ctx),
530 .cra_alignmask = 0,
531 .cra_type = &crypto_ablkcipher_type,
532 .cra_module = THIS_MODULE,
533 .cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list),
534 .cra_init = ablk_lrw_init,
535 .cra_exit = ablk_exit,
536 .cra_u = {
537 .ablkcipher = {
538 .min_keysize = AES_MIN_KEY_SIZE + AES_BLOCK_SIZE,
539 .max_keysize = AES_MAX_KEY_SIZE + AES_BLOCK_SIZE,
540 .ivsize = AES_BLOCK_SIZE,
541 .setkey = ablk_set_key,
542 .encrypt = ablk_encrypt,
543 .decrypt = ablk_decrypt,
544 },
545 },
546};
547#endif
548
549#ifdef HAS_PCBC
550static int ablk_pcbc_init(struct crypto_tfm *tfm)
551{
552 struct cryptd_ablkcipher *cryptd_tfm;
553
554 cryptd_tfm = cryptd_alloc_ablkcipher("fpu(pcbc(__driver-aes-aesni))",
555 0, 0);
556 if (IS_ERR(cryptd_tfm))
557 return PTR_ERR(cryptd_tfm);
558 ablk_init_common(tfm, cryptd_tfm);
559 return 0;
560}
561
562static struct crypto_alg ablk_pcbc_alg = {
563 .cra_name = "pcbc(aes)",
564 .cra_driver_name = "pcbc-aes-aesni",
565 .cra_priority = 400,
566 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
567 .cra_blocksize = AES_BLOCK_SIZE,
568 .cra_ctxsize = sizeof(struct async_aes_ctx),
569 .cra_alignmask = 0,
570 .cra_type = &crypto_ablkcipher_type,
571 .cra_module = THIS_MODULE,
572 .cra_list = LIST_HEAD_INIT(ablk_pcbc_alg.cra_list),
573 .cra_init = ablk_pcbc_init,
574 .cra_exit = ablk_exit,
575 .cra_u = {
576 .ablkcipher = {
577 .min_keysize = AES_MIN_KEY_SIZE,
578 .max_keysize = AES_MAX_KEY_SIZE,
579 .ivsize = AES_BLOCK_SIZE,
580 .setkey = ablk_set_key,
581 .encrypt = ablk_encrypt,
582 .decrypt = ablk_decrypt,
583 },
584 },
585};
586#endif
587
588#ifdef HAS_XTS
589static int ablk_xts_init(struct crypto_tfm *tfm)
590{
591 struct cryptd_ablkcipher *cryptd_tfm;
592
593 cryptd_tfm = cryptd_alloc_ablkcipher("fpu(xts(__driver-aes-aesni))",
594 0, 0);
595 if (IS_ERR(cryptd_tfm))
596 return PTR_ERR(cryptd_tfm);
597 ablk_init_common(tfm, cryptd_tfm);
598 return 0;
599}
600
601static struct crypto_alg ablk_xts_alg = {
602 .cra_name = "xts(aes)",
603 .cra_driver_name = "xts-aes-aesni",
604 .cra_priority = 400,
605 .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER|CRYPTO_ALG_ASYNC,
606 .cra_blocksize = AES_BLOCK_SIZE,
607 .cra_ctxsize = sizeof(struct async_aes_ctx),
608 .cra_alignmask = 0,
609 .cra_type = &crypto_ablkcipher_type,
610 .cra_module = THIS_MODULE,
611 .cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list),
612 .cra_init = ablk_xts_init,
613 .cra_exit = ablk_exit,
614 .cra_u = {
615 .ablkcipher = {
616 .min_keysize = 2 * AES_MIN_KEY_SIZE,
617 .max_keysize = 2 * AES_MAX_KEY_SIZE,
618 .ivsize = AES_BLOCK_SIZE,
619 .setkey = ablk_set_key,
620 .encrypt = ablk_encrypt,
621 .decrypt = ablk_decrypt,
622 },
623 },
624};
625#endif
626
Huang Ying54b6a1b2009-01-18 16:28:34 +1100627static int __init aesni_init(void)
628{
629 int err;
630
631 if (!cpu_has_aes) {
Roland Dreierc9944882009-06-24 13:42:40 +0800632 printk(KERN_INFO "Intel AES-NI instructions are not detected.\n");
Huang Ying54b6a1b2009-01-18 16:28:34 +1100633 return -ENODEV;
634 }
635 if ((err = crypto_register_alg(&aesni_alg)))
636 goto aes_err;
Huang Ying2cf4ac82009-03-29 15:41:20 +0800637 if ((err = crypto_register_alg(&__aesni_alg)))
638 goto __aes_err;
Huang Ying54b6a1b2009-01-18 16:28:34 +1100639 if ((err = crypto_register_alg(&blk_ecb_alg)))
640 goto blk_ecb_err;
641 if ((err = crypto_register_alg(&blk_cbc_alg)))
642 goto blk_cbc_err;
643 if ((err = crypto_register_alg(&ablk_ecb_alg)))
644 goto ablk_ecb_err;
645 if ((err = crypto_register_alg(&ablk_cbc_alg)))
646 goto ablk_cbc_err;
Huang Ying2cf4ac82009-03-29 15:41:20 +0800647#ifdef HAS_CTR
648 if ((err = crypto_register_alg(&ablk_ctr_alg)))
649 goto ablk_ctr_err;
650#endif
651#ifdef HAS_LRW
652 if ((err = crypto_register_alg(&ablk_lrw_alg)))
653 goto ablk_lrw_err;
654#endif
655#ifdef HAS_PCBC
656 if ((err = crypto_register_alg(&ablk_pcbc_alg)))
657 goto ablk_pcbc_err;
658#endif
659#ifdef HAS_XTS
660 if ((err = crypto_register_alg(&ablk_xts_alg)))
661 goto ablk_xts_err;
662#endif
Huang Ying54b6a1b2009-01-18 16:28:34 +1100663
664 return err;
665
Huang Ying2cf4ac82009-03-29 15:41:20 +0800666#ifdef HAS_XTS
667ablk_xts_err:
668#endif
669#ifdef HAS_PCBC
670 crypto_unregister_alg(&ablk_pcbc_alg);
671ablk_pcbc_err:
672#endif
673#ifdef HAS_LRW
674 crypto_unregister_alg(&ablk_lrw_alg);
675ablk_lrw_err:
676#endif
677#ifdef HAS_CTR
678 crypto_unregister_alg(&ablk_ctr_alg);
679ablk_ctr_err:
680#endif
681 crypto_unregister_alg(&ablk_cbc_alg);
Huang Ying54b6a1b2009-01-18 16:28:34 +1100682ablk_cbc_err:
683 crypto_unregister_alg(&ablk_ecb_alg);
684ablk_ecb_err:
685 crypto_unregister_alg(&blk_cbc_alg);
686blk_cbc_err:
687 crypto_unregister_alg(&blk_ecb_alg);
688blk_ecb_err:
Huang Ying2cf4ac82009-03-29 15:41:20 +0800689 crypto_unregister_alg(&__aesni_alg);
690__aes_err:
Huang Ying54b6a1b2009-01-18 16:28:34 +1100691 crypto_unregister_alg(&aesni_alg);
692aes_err:
693 return err;
694}
695
696static void __exit aesni_exit(void)
697{
Huang Ying2cf4ac82009-03-29 15:41:20 +0800698#ifdef HAS_XTS
699 crypto_unregister_alg(&ablk_xts_alg);
700#endif
701#ifdef HAS_PCBC
702 crypto_unregister_alg(&ablk_pcbc_alg);
703#endif
704#ifdef HAS_LRW
705 crypto_unregister_alg(&ablk_lrw_alg);
706#endif
707#ifdef HAS_CTR
708 crypto_unregister_alg(&ablk_ctr_alg);
709#endif
Huang Ying54b6a1b2009-01-18 16:28:34 +1100710 crypto_unregister_alg(&ablk_cbc_alg);
711 crypto_unregister_alg(&ablk_ecb_alg);
712 crypto_unregister_alg(&blk_cbc_alg);
713 crypto_unregister_alg(&blk_ecb_alg);
Huang Ying2cf4ac82009-03-29 15:41:20 +0800714 crypto_unregister_alg(&__aesni_alg);
Huang Ying54b6a1b2009-01-18 16:28:34 +1100715 crypto_unregister_alg(&aesni_alg);
716}
717
718module_init(aesni_init);
719module_exit(aesni_exit);
720
721MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm, Intel AES-NI instructions optimized");
722MODULE_LICENSE("GPL");
723MODULE_ALIAS("aes");