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