diff options
Diffstat (limited to 'crypto/simd.c')
-rw-r--r-- | crypto/simd.c | 273 |
1 files changed, 271 insertions, 2 deletions
diff --git a/crypto/simd.c b/crypto/simd.c index 78e8d037ae2b..3e3b1d1a6b1f 100644 --- a/crypto/simd.c +++ b/crypto/simd.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * | 3 | * |
4 | * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> | 4 | * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> |
5 | * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au> | 5 | * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au> |
6 | * Copyright (c) 2019 Google LLC | ||
6 | * | 7 | * |
7 | * Based on aesni-intel_glue.c by: | 8 | * Based on aesni-intel_glue.c by: |
8 | * Copyright (C) 2008, Intel Corp. | 9 | * Copyright (C) 2008, Intel Corp. |
@@ -20,10 +21,26 @@ | |||
20 | * | 21 | * |
21 | * You should have received a copy of the GNU General Public License | 22 | * You should have received a copy of the GNU General Public License |
22 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 23 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
24 | */ | ||
25 | |||
26 | /* | ||
27 | * Shared crypto SIMD helpers. These functions dynamically create and register | ||
28 | * an skcipher or AEAD algorithm that wraps another, internal algorithm. The | ||
29 | * wrapper ensures that the internal algorithm is only executed in a context | ||
30 | * where SIMD instructions are usable, i.e. where may_use_simd() returns true. | ||
31 | * If SIMD is already usable, the wrapper directly calls the internal algorithm. | ||
32 | * Otherwise it defers execution to a workqueue via cryptd. | ||
23 | * | 33 | * |
34 | * This is an alternative to the internal algorithm implementing a fallback for | ||
35 | * the !may_use_simd() case itself. | ||
36 | * | ||
37 | * Note that the wrapper algorithm is asynchronous, i.e. it has the | ||
38 | * CRYPTO_ALG_ASYNC flag set. Therefore it won't be found by users who | ||
39 | * explicitly allocate a synchronous algorithm. | ||
24 | */ | 40 | */ |
25 | 41 | ||
26 | #include <crypto/cryptd.h> | 42 | #include <crypto/cryptd.h> |
43 | #include <crypto/internal/aead.h> | ||
27 | #include <crypto/internal/simd.h> | 44 | #include <crypto/internal/simd.h> |
28 | #include <crypto/internal/skcipher.h> | 45 | #include <crypto/internal/skcipher.h> |
29 | #include <linux/kernel.h> | 46 | #include <linux/kernel.h> |
@@ -31,6 +48,8 @@ | |||
31 | #include <linux/preempt.h> | 48 | #include <linux/preempt.h> |
32 | #include <asm/simd.h> | 49 | #include <asm/simd.h> |
33 | 50 | ||
51 | /* skcipher support */ | ||
52 | |||
34 | struct simd_skcipher_alg { | 53 | struct simd_skcipher_alg { |
35 | const char *ialg_name; | 54 | const char *ialg_name; |
36 | struct skcipher_alg alg; | 55 | struct skcipher_alg alg; |
@@ -66,7 +85,7 @@ static int simd_skcipher_encrypt(struct skcipher_request *req) | |||
66 | subreq = skcipher_request_ctx(req); | 85 | subreq = skcipher_request_ctx(req); |
67 | *subreq = *req; | 86 | *subreq = *req; |
68 | 87 | ||
69 | if (!may_use_simd() || | 88 | if (!crypto_simd_usable() || |
70 | (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) | 89 | (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) |
71 | child = &ctx->cryptd_tfm->base; | 90 | child = &ctx->cryptd_tfm->base; |
72 | else | 91 | else |
@@ -87,7 +106,7 @@ static int simd_skcipher_decrypt(struct skcipher_request *req) | |||
87 | subreq = skcipher_request_ctx(req); | 106 | subreq = skcipher_request_ctx(req); |
88 | *subreq = *req; | 107 | *subreq = *req; |
89 | 108 | ||
90 | if (!may_use_simd() || | 109 | if (!crypto_simd_usable() || |
91 | (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) | 110 | (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) |
92 | child = &ctx->cryptd_tfm->base; | 111 | child = &ctx->cryptd_tfm->base; |
93 | else | 112 | else |
@@ -272,4 +291,254 @@ void simd_unregister_skciphers(struct skcipher_alg *algs, int count, | |||
272 | } | 291 | } |
273 | EXPORT_SYMBOL_GPL(simd_unregister_skciphers); | 292 | EXPORT_SYMBOL_GPL(simd_unregister_skciphers); |
274 | 293 | ||
294 | /* AEAD support */ | ||
295 | |||
296 | struct simd_aead_alg { | ||
297 | const char *ialg_name; | ||
298 | struct aead_alg alg; | ||
299 | }; | ||
300 | |||
301 | struct simd_aead_ctx { | ||
302 | struct cryptd_aead *cryptd_tfm; | ||
303 | }; | ||
304 | |||
305 | static int simd_aead_setkey(struct crypto_aead *tfm, const u8 *key, | ||
306 | unsigned int key_len) | ||
307 | { | ||
308 | struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); | ||
309 | struct crypto_aead *child = &ctx->cryptd_tfm->base; | ||
310 | int err; | ||
311 | |||
312 | crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); | ||
313 | crypto_aead_set_flags(child, crypto_aead_get_flags(tfm) & | ||
314 | CRYPTO_TFM_REQ_MASK); | ||
315 | err = crypto_aead_setkey(child, key, key_len); | ||
316 | crypto_aead_set_flags(tfm, crypto_aead_get_flags(child) & | ||
317 | CRYPTO_TFM_RES_MASK); | ||
318 | return err; | ||
319 | } | ||
320 | |||
321 | static int simd_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) | ||
322 | { | ||
323 | struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); | ||
324 | struct crypto_aead *child = &ctx->cryptd_tfm->base; | ||
325 | |||
326 | return crypto_aead_setauthsize(child, authsize); | ||
327 | } | ||
328 | |||
329 | static int simd_aead_encrypt(struct aead_request *req) | ||
330 | { | ||
331 | struct crypto_aead *tfm = crypto_aead_reqtfm(req); | ||
332 | struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); | ||
333 | struct aead_request *subreq; | ||
334 | struct crypto_aead *child; | ||
335 | |||
336 | subreq = aead_request_ctx(req); | ||
337 | *subreq = *req; | ||
338 | |||
339 | if (!crypto_simd_usable() || | ||
340 | (in_atomic() && cryptd_aead_queued(ctx->cryptd_tfm))) | ||
341 | child = &ctx->cryptd_tfm->base; | ||
342 | else | ||
343 | child = cryptd_aead_child(ctx->cryptd_tfm); | ||
344 | |||
345 | aead_request_set_tfm(subreq, child); | ||
346 | |||
347 | return crypto_aead_encrypt(subreq); | ||
348 | } | ||
349 | |||
350 | static int simd_aead_decrypt(struct aead_request *req) | ||
351 | { | ||
352 | struct crypto_aead *tfm = crypto_aead_reqtfm(req); | ||
353 | struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); | ||
354 | struct aead_request *subreq; | ||
355 | struct crypto_aead *child; | ||
356 | |||
357 | subreq = aead_request_ctx(req); | ||
358 | *subreq = *req; | ||
359 | |||
360 | if (!crypto_simd_usable() || | ||
361 | (in_atomic() && cryptd_aead_queued(ctx->cryptd_tfm))) | ||
362 | child = &ctx->cryptd_tfm->base; | ||
363 | else | ||
364 | child = cryptd_aead_child(ctx->cryptd_tfm); | ||
365 | |||
366 | aead_request_set_tfm(subreq, child); | ||
367 | |||
368 | return crypto_aead_decrypt(subreq); | ||
369 | } | ||
370 | |||
371 | static void simd_aead_exit(struct crypto_aead *tfm) | ||
372 | { | ||
373 | struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); | ||
374 | |||
375 | cryptd_free_aead(ctx->cryptd_tfm); | ||
376 | } | ||
377 | |||
378 | static int simd_aead_init(struct crypto_aead *tfm) | ||
379 | { | ||
380 | struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); | ||
381 | struct cryptd_aead *cryptd_tfm; | ||
382 | struct simd_aead_alg *salg; | ||
383 | struct aead_alg *alg; | ||
384 | unsigned reqsize; | ||
385 | |||
386 | alg = crypto_aead_alg(tfm); | ||
387 | salg = container_of(alg, struct simd_aead_alg, alg); | ||
388 | |||
389 | cryptd_tfm = cryptd_alloc_aead(salg->ialg_name, CRYPTO_ALG_INTERNAL, | ||
390 | CRYPTO_ALG_INTERNAL); | ||
391 | if (IS_ERR(cryptd_tfm)) | ||
392 | return PTR_ERR(cryptd_tfm); | ||
393 | |||
394 | ctx->cryptd_tfm = cryptd_tfm; | ||
395 | |||
396 | reqsize = crypto_aead_reqsize(cryptd_aead_child(cryptd_tfm)); | ||
397 | reqsize = max(reqsize, crypto_aead_reqsize(&cryptd_tfm->base)); | ||
398 | reqsize += sizeof(struct aead_request); | ||
399 | |||
400 | crypto_aead_set_reqsize(tfm, reqsize); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | struct simd_aead_alg *simd_aead_create_compat(const char *algname, | ||
406 | const char *drvname, | ||
407 | const char *basename) | ||
408 | { | ||
409 | struct simd_aead_alg *salg; | ||
410 | struct crypto_aead *tfm; | ||
411 | struct aead_alg *ialg; | ||
412 | struct aead_alg *alg; | ||
413 | int err; | ||
414 | |||
415 | tfm = crypto_alloc_aead(basename, CRYPTO_ALG_INTERNAL, | ||
416 | CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); | ||
417 | if (IS_ERR(tfm)) | ||
418 | return ERR_CAST(tfm); | ||
419 | |||
420 | ialg = crypto_aead_alg(tfm); | ||
421 | |||
422 | salg = kzalloc(sizeof(*salg), GFP_KERNEL); | ||
423 | if (!salg) { | ||
424 | salg = ERR_PTR(-ENOMEM); | ||
425 | goto out_put_tfm; | ||
426 | } | ||
427 | |||
428 | salg->ialg_name = basename; | ||
429 | alg = &salg->alg; | ||
430 | |||
431 | err = -ENAMETOOLONG; | ||
432 | if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", algname) >= | ||
433 | CRYPTO_MAX_ALG_NAME) | ||
434 | goto out_free_salg; | ||
435 | |||
436 | if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", | ||
437 | drvname) >= CRYPTO_MAX_ALG_NAME) | ||
438 | goto out_free_salg; | ||
439 | |||
440 | alg->base.cra_flags = CRYPTO_ALG_ASYNC; | ||
441 | alg->base.cra_priority = ialg->base.cra_priority; | ||
442 | alg->base.cra_blocksize = ialg->base.cra_blocksize; | ||
443 | alg->base.cra_alignmask = ialg->base.cra_alignmask; | ||
444 | alg->base.cra_module = ialg->base.cra_module; | ||
445 | alg->base.cra_ctxsize = sizeof(struct simd_aead_ctx); | ||
446 | |||
447 | alg->ivsize = ialg->ivsize; | ||
448 | alg->maxauthsize = ialg->maxauthsize; | ||
449 | alg->chunksize = ialg->chunksize; | ||
450 | |||
451 | alg->init = simd_aead_init; | ||
452 | alg->exit = simd_aead_exit; | ||
453 | |||
454 | alg->setkey = simd_aead_setkey; | ||
455 | alg->setauthsize = simd_aead_setauthsize; | ||
456 | alg->encrypt = simd_aead_encrypt; | ||
457 | alg->decrypt = simd_aead_decrypt; | ||
458 | |||
459 | err = crypto_register_aead(alg); | ||
460 | if (err) | ||
461 | goto out_free_salg; | ||
462 | |||
463 | out_put_tfm: | ||
464 | crypto_free_aead(tfm); | ||
465 | return salg; | ||
466 | |||
467 | out_free_salg: | ||
468 | kfree(salg); | ||
469 | salg = ERR_PTR(err); | ||
470 | goto out_put_tfm; | ||
471 | } | ||
472 | EXPORT_SYMBOL_GPL(simd_aead_create_compat); | ||
473 | |||
474 | struct simd_aead_alg *simd_aead_create(const char *algname, | ||
475 | const char *basename) | ||
476 | { | ||
477 | char drvname[CRYPTO_MAX_ALG_NAME]; | ||
478 | |||
479 | if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= | ||
480 | CRYPTO_MAX_ALG_NAME) | ||
481 | return ERR_PTR(-ENAMETOOLONG); | ||
482 | |||
483 | return simd_aead_create_compat(algname, drvname, basename); | ||
484 | } | ||
485 | EXPORT_SYMBOL_GPL(simd_aead_create); | ||
486 | |||
487 | void simd_aead_free(struct simd_aead_alg *salg) | ||
488 | { | ||
489 | crypto_unregister_aead(&salg->alg); | ||
490 | kfree(salg); | ||
491 | } | ||
492 | EXPORT_SYMBOL_GPL(simd_aead_free); | ||
493 | |||
494 | int simd_register_aeads_compat(struct aead_alg *algs, int count, | ||
495 | struct simd_aead_alg **simd_algs) | ||
496 | { | ||
497 | int err; | ||
498 | int i; | ||
499 | const char *algname; | ||
500 | const char *drvname; | ||
501 | const char *basename; | ||
502 | struct simd_aead_alg *simd; | ||
503 | |||
504 | err = crypto_register_aeads(algs, count); | ||
505 | if (err) | ||
506 | return err; | ||
507 | |||
508 | for (i = 0; i < count; i++) { | ||
509 | WARN_ON(strncmp(algs[i].base.cra_name, "__", 2)); | ||
510 | WARN_ON(strncmp(algs[i].base.cra_driver_name, "__", 2)); | ||
511 | algname = algs[i].base.cra_name + 2; | ||
512 | drvname = algs[i].base.cra_driver_name + 2; | ||
513 | basename = algs[i].base.cra_driver_name; | ||
514 | simd = simd_aead_create_compat(algname, drvname, basename); | ||
515 | err = PTR_ERR(simd); | ||
516 | if (IS_ERR(simd)) | ||
517 | goto err_unregister; | ||
518 | simd_algs[i] = simd; | ||
519 | } | ||
520 | return 0; | ||
521 | |||
522 | err_unregister: | ||
523 | simd_unregister_aeads(algs, count, simd_algs); | ||
524 | return err; | ||
525 | } | ||
526 | EXPORT_SYMBOL_GPL(simd_register_aeads_compat); | ||
527 | |||
528 | void simd_unregister_aeads(struct aead_alg *algs, int count, | ||
529 | struct simd_aead_alg **simd_algs) | ||
530 | { | ||
531 | int i; | ||
532 | |||
533 | crypto_unregister_aeads(algs, count); | ||
534 | |||
535 | for (i = 0; i < count; i++) { | ||
536 | if (simd_algs[i]) { | ||
537 | simd_aead_free(simd_algs[i]); | ||
538 | simd_algs[i] = NULL; | ||
539 | } | ||
540 | } | ||
541 | } | ||
542 | EXPORT_SYMBOL_GPL(simd_unregister_aeads); | ||
543 | |||
275 | MODULE_LICENSE("GPL"); | 544 | MODULE_LICENSE("GPL"); |