18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Shared crypto simd helpers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2012 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 68c2ecf20Sopenharmony_ci * Copyright (c) 2016 Herbert Xu <herbert@gondor.apana.org.au> 78c2ecf20Sopenharmony_ci * Copyright (c) 2019 Google LLC 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Based on aesni-intel_glue.c by: 108c2ecf20Sopenharmony_ci * Copyright (C) 2008, Intel Corp. 118c2ecf20Sopenharmony_ci * Author: Huang Ying <ying.huang@intel.com> 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci/* 158c2ecf20Sopenharmony_ci * Shared crypto SIMD helpers. These functions dynamically create and register 168c2ecf20Sopenharmony_ci * an skcipher or AEAD algorithm that wraps another, internal algorithm. The 178c2ecf20Sopenharmony_ci * wrapper ensures that the internal algorithm is only executed in a context 188c2ecf20Sopenharmony_ci * where SIMD instructions are usable, i.e. where may_use_simd() returns true. 198c2ecf20Sopenharmony_ci * If SIMD is already usable, the wrapper directly calls the internal algorithm. 208c2ecf20Sopenharmony_ci * Otherwise it defers execution to a workqueue via cryptd. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * This is an alternative to the internal algorithm implementing a fallback for 238c2ecf20Sopenharmony_ci * the !may_use_simd() case itself. 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Note that the wrapper algorithm is asynchronous, i.e. it has the 268c2ecf20Sopenharmony_ci * CRYPTO_ALG_ASYNC flag set. Therefore it won't be found by users who 278c2ecf20Sopenharmony_ci * explicitly allocate a synchronous algorithm. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <crypto/cryptd.h> 318c2ecf20Sopenharmony_ci#include <crypto/internal/aead.h> 328c2ecf20Sopenharmony_ci#include <crypto/internal/simd.h> 338c2ecf20Sopenharmony_ci#include <crypto/internal/skcipher.h> 348c2ecf20Sopenharmony_ci#include <linux/kernel.h> 358c2ecf20Sopenharmony_ci#include <linux/module.h> 368c2ecf20Sopenharmony_ci#include <linux/preempt.h> 378c2ecf20Sopenharmony_ci#include <asm/simd.h> 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* skcipher support */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct simd_skcipher_alg { 428c2ecf20Sopenharmony_ci const char *ialg_name; 438c2ecf20Sopenharmony_ci struct skcipher_alg alg; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistruct simd_skcipher_ctx { 478c2ecf20Sopenharmony_ci struct cryptd_skcipher *cryptd_tfm; 488c2ecf20Sopenharmony_ci}; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic int simd_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, 518c2ecf20Sopenharmony_ci unsigned int key_len) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 548c2ecf20Sopenharmony_ci struct crypto_skcipher *child = &ctx->cryptd_tfm->base; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); 578c2ecf20Sopenharmony_ci crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(tfm) & 588c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 598c2ecf20Sopenharmony_ci return crypto_skcipher_setkey(child, key, key_len); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int simd_skcipher_encrypt(struct skcipher_request *req) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 658c2ecf20Sopenharmony_ci struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 668c2ecf20Sopenharmony_ci struct skcipher_request *subreq; 678c2ecf20Sopenharmony_ci struct crypto_skcipher *child; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci subreq = skcipher_request_ctx(req); 708c2ecf20Sopenharmony_ci *subreq = *req; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (!crypto_simd_usable() || 738c2ecf20Sopenharmony_ci (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) 748c2ecf20Sopenharmony_ci child = &ctx->cryptd_tfm->base; 758c2ecf20Sopenharmony_ci else 768c2ecf20Sopenharmony_ci child = cryptd_skcipher_child(ctx->cryptd_tfm); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci skcipher_request_set_tfm(subreq, child); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci return crypto_skcipher_encrypt(subreq); 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_cistatic int simd_skcipher_decrypt(struct skcipher_request *req) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 868c2ecf20Sopenharmony_ci struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 878c2ecf20Sopenharmony_ci struct skcipher_request *subreq; 888c2ecf20Sopenharmony_ci struct crypto_skcipher *child; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci subreq = skcipher_request_ctx(req); 918c2ecf20Sopenharmony_ci *subreq = *req; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (!crypto_simd_usable() || 948c2ecf20Sopenharmony_ci (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) 958c2ecf20Sopenharmony_ci child = &ctx->cryptd_tfm->base; 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci child = cryptd_skcipher_child(ctx->cryptd_tfm); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci skcipher_request_set_tfm(subreq, child); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return crypto_skcipher_decrypt(subreq); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_cistatic void simd_skcipher_exit(struct crypto_skcipher *tfm) 1058c2ecf20Sopenharmony_ci{ 1068c2ecf20Sopenharmony_ci struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci cryptd_free_skcipher(ctx->cryptd_tfm); 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic int simd_skcipher_init(struct crypto_skcipher *tfm) 1128c2ecf20Sopenharmony_ci{ 1138c2ecf20Sopenharmony_ci struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); 1148c2ecf20Sopenharmony_ci struct cryptd_skcipher *cryptd_tfm; 1158c2ecf20Sopenharmony_ci struct simd_skcipher_alg *salg; 1168c2ecf20Sopenharmony_ci struct skcipher_alg *alg; 1178c2ecf20Sopenharmony_ci unsigned reqsize; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci alg = crypto_skcipher_alg(tfm); 1208c2ecf20Sopenharmony_ci salg = container_of(alg, struct simd_skcipher_alg, alg); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci cryptd_tfm = cryptd_alloc_skcipher(salg->ialg_name, 1238c2ecf20Sopenharmony_ci CRYPTO_ALG_INTERNAL, 1248c2ecf20Sopenharmony_ci CRYPTO_ALG_INTERNAL); 1258c2ecf20Sopenharmony_ci if (IS_ERR(cryptd_tfm)) 1268c2ecf20Sopenharmony_ci return PTR_ERR(cryptd_tfm); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci ctx->cryptd_tfm = cryptd_tfm; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci reqsize = crypto_skcipher_reqsize(cryptd_skcipher_child(cryptd_tfm)); 1318c2ecf20Sopenharmony_ci reqsize = max(reqsize, crypto_skcipher_reqsize(&cryptd_tfm->base)); 1328c2ecf20Sopenharmony_ci reqsize += sizeof(struct skcipher_request); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, reqsize); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci return 0; 1378c2ecf20Sopenharmony_ci} 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_cistruct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, 1408c2ecf20Sopenharmony_ci const char *drvname, 1418c2ecf20Sopenharmony_ci const char *basename) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct simd_skcipher_alg *salg; 1448c2ecf20Sopenharmony_ci struct crypto_skcipher *tfm; 1458c2ecf20Sopenharmony_ci struct skcipher_alg *ialg; 1468c2ecf20Sopenharmony_ci struct skcipher_alg *alg; 1478c2ecf20Sopenharmony_ci int err; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL, 1508c2ecf20Sopenharmony_ci CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); 1518c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 1528c2ecf20Sopenharmony_ci return ERR_CAST(tfm); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci ialg = crypto_skcipher_alg(tfm); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci salg = kzalloc(sizeof(*salg), GFP_KERNEL); 1578c2ecf20Sopenharmony_ci if (!salg) { 1588c2ecf20Sopenharmony_ci salg = ERR_PTR(-ENOMEM); 1598c2ecf20Sopenharmony_ci goto out_put_tfm; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci salg->ialg_name = basename; 1638c2ecf20Sopenharmony_ci alg = &salg->alg; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci err = -ENAMETOOLONG; 1668c2ecf20Sopenharmony_ci if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", algname) >= 1678c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 1688c2ecf20Sopenharmony_ci goto out_free_salg; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 1718c2ecf20Sopenharmony_ci drvname) >= CRYPTO_MAX_ALG_NAME) 1728c2ecf20Sopenharmony_ci goto out_free_salg; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci alg->base.cra_flags = CRYPTO_ALG_ASYNC | 1758c2ecf20Sopenharmony_ci (ialg->base.cra_flags & CRYPTO_ALG_INHERITED_FLAGS); 1768c2ecf20Sopenharmony_ci alg->base.cra_priority = ialg->base.cra_priority; 1778c2ecf20Sopenharmony_ci alg->base.cra_blocksize = ialg->base.cra_blocksize; 1788c2ecf20Sopenharmony_ci alg->base.cra_alignmask = ialg->base.cra_alignmask; 1798c2ecf20Sopenharmony_ci alg->base.cra_module = ialg->base.cra_module; 1808c2ecf20Sopenharmony_ci alg->base.cra_ctxsize = sizeof(struct simd_skcipher_ctx); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci alg->ivsize = ialg->ivsize; 1838c2ecf20Sopenharmony_ci alg->chunksize = ialg->chunksize; 1848c2ecf20Sopenharmony_ci alg->min_keysize = ialg->min_keysize; 1858c2ecf20Sopenharmony_ci alg->max_keysize = ialg->max_keysize; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci alg->init = simd_skcipher_init; 1888c2ecf20Sopenharmony_ci alg->exit = simd_skcipher_exit; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci alg->setkey = simd_skcipher_setkey; 1918c2ecf20Sopenharmony_ci alg->encrypt = simd_skcipher_encrypt; 1928c2ecf20Sopenharmony_ci alg->decrypt = simd_skcipher_decrypt; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci err = crypto_register_skcipher(alg); 1958c2ecf20Sopenharmony_ci if (err) 1968c2ecf20Sopenharmony_ci goto out_free_salg; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciout_put_tfm: 1998c2ecf20Sopenharmony_ci crypto_free_skcipher(tfm); 2008c2ecf20Sopenharmony_ci return salg; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ciout_free_salg: 2038c2ecf20Sopenharmony_ci kfree(salg); 2048c2ecf20Sopenharmony_ci salg = ERR_PTR(err); 2058c2ecf20Sopenharmony_ci goto out_put_tfm; 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_skcipher_create_compat); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistruct simd_skcipher_alg *simd_skcipher_create(const char *algname, 2108c2ecf20Sopenharmony_ci const char *basename) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci char drvname[CRYPTO_MAX_ALG_NAME]; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= 2158c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 2168c2ecf20Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return simd_skcipher_create_compat(algname, drvname, basename); 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_skcipher_create); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_civoid simd_skcipher_free(struct simd_skcipher_alg *salg) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci crypto_unregister_skcipher(&salg->alg); 2258c2ecf20Sopenharmony_ci kfree(salg); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_skcipher_free); 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ciint simd_register_skciphers_compat(struct skcipher_alg *algs, int count, 2308c2ecf20Sopenharmony_ci struct simd_skcipher_alg **simd_algs) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci int err; 2338c2ecf20Sopenharmony_ci int i; 2348c2ecf20Sopenharmony_ci const char *algname; 2358c2ecf20Sopenharmony_ci const char *drvname; 2368c2ecf20Sopenharmony_ci const char *basename; 2378c2ecf20Sopenharmony_ci struct simd_skcipher_alg *simd; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci err = crypto_register_skciphers(algs, count); 2408c2ecf20Sopenharmony_ci if (err) 2418c2ecf20Sopenharmony_ci return err; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 2448c2ecf20Sopenharmony_ci WARN_ON(strncmp(algs[i].base.cra_name, "__", 2)); 2458c2ecf20Sopenharmony_ci WARN_ON(strncmp(algs[i].base.cra_driver_name, "__", 2)); 2468c2ecf20Sopenharmony_ci algname = algs[i].base.cra_name + 2; 2478c2ecf20Sopenharmony_ci drvname = algs[i].base.cra_driver_name + 2; 2488c2ecf20Sopenharmony_ci basename = algs[i].base.cra_driver_name; 2498c2ecf20Sopenharmony_ci simd = simd_skcipher_create_compat(algname, drvname, basename); 2508c2ecf20Sopenharmony_ci err = PTR_ERR(simd); 2518c2ecf20Sopenharmony_ci if (IS_ERR(simd)) 2528c2ecf20Sopenharmony_ci goto err_unregister; 2538c2ecf20Sopenharmony_ci simd_algs[i] = simd; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cierr_unregister: 2588c2ecf20Sopenharmony_ci simd_unregister_skciphers(algs, count, simd_algs); 2598c2ecf20Sopenharmony_ci return err; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_register_skciphers_compat); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_civoid simd_unregister_skciphers(struct skcipher_alg *algs, int count, 2648c2ecf20Sopenharmony_ci struct simd_skcipher_alg **simd_algs) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci int i; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci crypto_unregister_skciphers(algs, count); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 2718c2ecf20Sopenharmony_ci if (simd_algs[i]) { 2728c2ecf20Sopenharmony_ci simd_skcipher_free(simd_algs[i]); 2738c2ecf20Sopenharmony_ci simd_algs[i] = NULL; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci } 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_unregister_skciphers); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci/* AEAD support */ 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_cistruct simd_aead_alg { 2828c2ecf20Sopenharmony_ci const char *ialg_name; 2838c2ecf20Sopenharmony_ci struct aead_alg alg; 2848c2ecf20Sopenharmony_ci}; 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistruct simd_aead_ctx { 2878c2ecf20Sopenharmony_ci struct cryptd_aead *cryptd_tfm; 2888c2ecf20Sopenharmony_ci}; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int simd_aead_setkey(struct crypto_aead *tfm, const u8 *key, 2918c2ecf20Sopenharmony_ci unsigned int key_len) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 2948c2ecf20Sopenharmony_ci struct crypto_aead *child = &ctx->cryptd_tfm->base; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci crypto_aead_clear_flags(child, CRYPTO_TFM_REQ_MASK); 2978c2ecf20Sopenharmony_ci crypto_aead_set_flags(child, crypto_aead_get_flags(tfm) & 2988c2ecf20Sopenharmony_ci CRYPTO_TFM_REQ_MASK); 2998c2ecf20Sopenharmony_ci return crypto_aead_setkey(child, key, key_len); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int simd_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 3058c2ecf20Sopenharmony_ci struct crypto_aead *child = &ctx->cryptd_tfm->base; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return crypto_aead_setauthsize(child, authsize); 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_cistatic int simd_aead_encrypt(struct aead_request *req) 3118c2ecf20Sopenharmony_ci{ 3128c2ecf20Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 3138c2ecf20Sopenharmony_ci struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 3148c2ecf20Sopenharmony_ci struct aead_request *subreq; 3158c2ecf20Sopenharmony_ci struct crypto_aead *child; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci subreq = aead_request_ctx(req); 3188c2ecf20Sopenharmony_ci *subreq = *req; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!crypto_simd_usable() || 3218c2ecf20Sopenharmony_ci (in_atomic() && cryptd_aead_queued(ctx->cryptd_tfm))) 3228c2ecf20Sopenharmony_ci child = &ctx->cryptd_tfm->base; 3238c2ecf20Sopenharmony_ci else 3248c2ecf20Sopenharmony_ci child = cryptd_aead_child(ctx->cryptd_tfm); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci aead_request_set_tfm(subreq, child); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci return crypto_aead_encrypt(subreq); 3298c2ecf20Sopenharmony_ci} 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_cistatic int simd_aead_decrypt(struct aead_request *req) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct crypto_aead *tfm = crypto_aead_reqtfm(req); 3348c2ecf20Sopenharmony_ci struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 3358c2ecf20Sopenharmony_ci struct aead_request *subreq; 3368c2ecf20Sopenharmony_ci struct crypto_aead *child; 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci subreq = aead_request_ctx(req); 3398c2ecf20Sopenharmony_ci *subreq = *req; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (!crypto_simd_usable() || 3428c2ecf20Sopenharmony_ci (in_atomic() && cryptd_aead_queued(ctx->cryptd_tfm))) 3438c2ecf20Sopenharmony_ci child = &ctx->cryptd_tfm->base; 3448c2ecf20Sopenharmony_ci else 3458c2ecf20Sopenharmony_ci child = cryptd_aead_child(ctx->cryptd_tfm); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci aead_request_set_tfm(subreq, child); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci return crypto_aead_decrypt(subreq); 3508c2ecf20Sopenharmony_ci} 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_cistatic void simd_aead_exit(struct crypto_aead *tfm) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci cryptd_free_aead(ctx->cryptd_tfm); 3578c2ecf20Sopenharmony_ci} 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic int simd_aead_init(struct crypto_aead *tfm) 3608c2ecf20Sopenharmony_ci{ 3618c2ecf20Sopenharmony_ci struct simd_aead_ctx *ctx = crypto_aead_ctx(tfm); 3628c2ecf20Sopenharmony_ci struct cryptd_aead *cryptd_tfm; 3638c2ecf20Sopenharmony_ci struct simd_aead_alg *salg; 3648c2ecf20Sopenharmony_ci struct aead_alg *alg; 3658c2ecf20Sopenharmony_ci unsigned reqsize; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci alg = crypto_aead_alg(tfm); 3688c2ecf20Sopenharmony_ci salg = container_of(alg, struct simd_aead_alg, alg); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci cryptd_tfm = cryptd_alloc_aead(salg->ialg_name, CRYPTO_ALG_INTERNAL, 3718c2ecf20Sopenharmony_ci CRYPTO_ALG_INTERNAL); 3728c2ecf20Sopenharmony_ci if (IS_ERR(cryptd_tfm)) 3738c2ecf20Sopenharmony_ci return PTR_ERR(cryptd_tfm); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ctx->cryptd_tfm = cryptd_tfm; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci reqsize = crypto_aead_reqsize(cryptd_aead_child(cryptd_tfm)); 3788c2ecf20Sopenharmony_ci reqsize = max(reqsize, crypto_aead_reqsize(&cryptd_tfm->base)); 3798c2ecf20Sopenharmony_ci reqsize += sizeof(struct aead_request); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci crypto_aead_set_reqsize(tfm, reqsize); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return 0; 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistruct simd_aead_alg *simd_aead_create_compat(const char *algname, 3878c2ecf20Sopenharmony_ci const char *drvname, 3888c2ecf20Sopenharmony_ci const char *basename) 3898c2ecf20Sopenharmony_ci{ 3908c2ecf20Sopenharmony_ci struct simd_aead_alg *salg; 3918c2ecf20Sopenharmony_ci struct crypto_aead *tfm; 3928c2ecf20Sopenharmony_ci struct aead_alg *ialg; 3938c2ecf20Sopenharmony_ci struct aead_alg *alg; 3948c2ecf20Sopenharmony_ci int err; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci tfm = crypto_alloc_aead(basename, CRYPTO_ALG_INTERNAL, 3978c2ecf20Sopenharmony_ci CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); 3988c2ecf20Sopenharmony_ci if (IS_ERR(tfm)) 3998c2ecf20Sopenharmony_ci return ERR_CAST(tfm); 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci ialg = crypto_aead_alg(tfm); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci salg = kzalloc(sizeof(*salg), GFP_KERNEL); 4048c2ecf20Sopenharmony_ci if (!salg) { 4058c2ecf20Sopenharmony_ci salg = ERR_PTR(-ENOMEM); 4068c2ecf20Sopenharmony_ci goto out_put_tfm; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci salg->ialg_name = basename; 4108c2ecf20Sopenharmony_ci alg = &salg->alg; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci err = -ENAMETOOLONG; 4138c2ecf20Sopenharmony_ci if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", algname) >= 4148c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 4158c2ecf20Sopenharmony_ci goto out_free_salg; 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", 4188c2ecf20Sopenharmony_ci drvname) >= CRYPTO_MAX_ALG_NAME) 4198c2ecf20Sopenharmony_ci goto out_free_salg; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci alg->base.cra_flags = CRYPTO_ALG_ASYNC | 4228c2ecf20Sopenharmony_ci (ialg->base.cra_flags & CRYPTO_ALG_INHERITED_FLAGS); 4238c2ecf20Sopenharmony_ci alg->base.cra_priority = ialg->base.cra_priority; 4248c2ecf20Sopenharmony_ci alg->base.cra_blocksize = ialg->base.cra_blocksize; 4258c2ecf20Sopenharmony_ci alg->base.cra_alignmask = ialg->base.cra_alignmask; 4268c2ecf20Sopenharmony_ci alg->base.cra_module = ialg->base.cra_module; 4278c2ecf20Sopenharmony_ci alg->base.cra_ctxsize = sizeof(struct simd_aead_ctx); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci alg->ivsize = ialg->ivsize; 4308c2ecf20Sopenharmony_ci alg->maxauthsize = ialg->maxauthsize; 4318c2ecf20Sopenharmony_ci alg->chunksize = ialg->chunksize; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci alg->init = simd_aead_init; 4348c2ecf20Sopenharmony_ci alg->exit = simd_aead_exit; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci alg->setkey = simd_aead_setkey; 4378c2ecf20Sopenharmony_ci alg->setauthsize = simd_aead_setauthsize; 4388c2ecf20Sopenharmony_ci alg->encrypt = simd_aead_encrypt; 4398c2ecf20Sopenharmony_ci alg->decrypt = simd_aead_decrypt; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci err = crypto_register_aead(alg); 4428c2ecf20Sopenharmony_ci if (err) 4438c2ecf20Sopenharmony_ci goto out_free_salg; 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ciout_put_tfm: 4468c2ecf20Sopenharmony_ci crypto_free_aead(tfm); 4478c2ecf20Sopenharmony_ci return salg; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ciout_free_salg: 4508c2ecf20Sopenharmony_ci kfree(salg); 4518c2ecf20Sopenharmony_ci salg = ERR_PTR(err); 4528c2ecf20Sopenharmony_ci goto out_put_tfm; 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_aead_create_compat); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_cistruct simd_aead_alg *simd_aead_create(const char *algname, 4578c2ecf20Sopenharmony_ci const char *basename) 4588c2ecf20Sopenharmony_ci{ 4598c2ecf20Sopenharmony_ci char drvname[CRYPTO_MAX_ALG_NAME]; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= 4628c2ecf20Sopenharmony_ci CRYPTO_MAX_ALG_NAME) 4638c2ecf20Sopenharmony_ci return ERR_PTR(-ENAMETOOLONG); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci return simd_aead_create_compat(algname, drvname, basename); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_aead_create); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_civoid simd_aead_free(struct simd_aead_alg *salg) 4708c2ecf20Sopenharmony_ci{ 4718c2ecf20Sopenharmony_ci crypto_unregister_aead(&salg->alg); 4728c2ecf20Sopenharmony_ci kfree(salg); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_aead_free); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ciint simd_register_aeads_compat(struct aead_alg *algs, int count, 4778c2ecf20Sopenharmony_ci struct simd_aead_alg **simd_algs) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci int err; 4808c2ecf20Sopenharmony_ci int i; 4818c2ecf20Sopenharmony_ci const char *algname; 4828c2ecf20Sopenharmony_ci const char *drvname; 4838c2ecf20Sopenharmony_ci const char *basename; 4848c2ecf20Sopenharmony_ci struct simd_aead_alg *simd; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci err = crypto_register_aeads(algs, count); 4878c2ecf20Sopenharmony_ci if (err) 4888c2ecf20Sopenharmony_ci return err; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 4918c2ecf20Sopenharmony_ci WARN_ON(strncmp(algs[i].base.cra_name, "__", 2)); 4928c2ecf20Sopenharmony_ci WARN_ON(strncmp(algs[i].base.cra_driver_name, "__", 2)); 4938c2ecf20Sopenharmony_ci algname = algs[i].base.cra_name + 2; 4948c2ecf20Sopenharmony_ci drvname = algs[i].base.cra_driver_name + 2; 4958c2ecf20Sopenharmony_ci basename = algs[i].base.cra_driver_name; 4968c2ecf20Sopenharmony_ci simd = simd_aead_create_compat(algname, drvname, basename); 4978c2ecf20Sopenharmony_ci err = PTR_ERR(simd); 4988c2ecf20Sopenharmony_ci if (IS_ERR(simd)) 4998c2ecf20Sopenharmony_ci goto err_unregister; 5008c2ecf20Sopenharmony_ci simd_algs[i] = simd; 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci return 0; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cierr_unregister: 5058c2ecf20Sopenharmony_ci simd_unregister_aeads(algs, count, simd_algs); 5068c2ecf20Sopenharmony_ci return err; 5078c2ecf20Sopenharmony_ci} 5088c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_register_aeads_compat); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_civoid simd_unregister_aeads(struct aead_alg *algs, int count, 5118c2ecf20Sopenharmony_ci struct simd_aead_alg **simd_algs) 5128c2ecf20Sopenharmony_ci{ 5138c2ecf20Sopenharmony_ci int i; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci crypto_unregister_aeads(algs, count); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 5188c2ecf20Sopenharmony_ci if (simd_algs[i]) { 5198c2ecf20Sopenharmony_ci simd_aead_free(simd_algs[i]); 5208c2ecf20Sopenharmony_ci simd_algs[i] = NULL; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci} 5248c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(simd_unregister_aeads); 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 527