162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * SM4 Cipher Algorithm, AES-NI/AVX2 optimized.
462306a36Sopenharmony_ci * as specified in
562306a36Sopenharmony_ci * https://tools.ietf.org/id/draft-ribose-cfrg-sm4-10.html
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (c) 2021, Alibaba Group.
862306a36Sopenharmony_ci * Copyright (c) 2021 Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/crypto.h>
1362306a36Sopenharmony_ci#include <linux/kernel.h>
1462306a36Sopenharmony_ci#include <asm/simd.h>
1562306a36Sopenharmony_ci#include <crypto/internal/simd.h>
1662306a36Sopenharmony_ci#include <crypto/internal/skcipher.h>
1762306a36Sopenharmony_ci#include <crypto/sm4.h>
1862306a36Sopenharmony_ci#include "sm4-avx.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define SM4_CRYPT16_BLOCK_SIZE	(SM4_BLOCK_SIZE * 16)
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciasmlinkage void sm4_aesni_avx2_ctr_enc_blk16(const u32 *rk, u8 *dst,
2362306a36Sopenharmony_ci					const u8 *src, u8 *iv);
2462306a36Sopenharmony_ciasmlinkage void sm4_aesni_avx2_cbc_dec_blk16(const u32 *rk, u8 *dst,
2562306a36Sopenharmony_ci					const u8 *src, u8 *iv);
2662306a36Sopenharmony_ciasmlinkage void sm4_aesni_avx2_cfb_dec_blk16(const u32 *rk, u8 *dst,
2762306a36Sopenharmony_ci					const u8 *src, u8 *iv);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int sm4_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
3062306a36Sopenharmony_ci			unsigned int key_len)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	return sm4_expandkey(ctx, key, key_len);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int cbc_decrypt(struct skcipher_request *req)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	return sm4_avx_cbc_decrypt(req, SM4_CRYPT16_BLOCK_SIZE,
4062306a36Sopenharmony_ci				sm4_aesni_avx2_cbc_dec_blk16);
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic int cfb_decrypt(struct skcipher_request *req)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	return sm4_avx_cfb_decrypt(req, SM4_CRYPT16_BLOCK_SIZE,
4762306a36Sopenharmony_ci				sm4_aesni_avx2_cfb_dec_blk16);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic int ctr_crypt(struct skcipher_request *req)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	return sm4_avx_ctr_crypt(req, SM4_CRYPT16_BLOCK_SIZE,
5362306a36Sopenharmony_ci				sm4_aesni_avx2_ctr_enc_blk16);
5462306a36Sopenharmony_ci}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistatic struct skcipher_alg sm4_aesni_avx2_skciphers[] = {
5762306a36Sopenharmony_ci	{
5862306a36Sopenharmony_ci		.base = {
5962306a36Sopenharmony_ci			.cra_name		= "__ecb(sm4)",
6062306a36Sopenharmony_ci			.cra_driver_name	= "__ecb-sm4-aesni-avx2",
6162306a36Sopenharmony_ci			.cra_priority		= 500,
6262306a36Sopenharmony_ci			.cra_flags		= CRYPTO_ALG_INTERNAL,
6362306a36Sopenharmony_ci			.cra_blocksize		= SM4_BLOCK_SIZE,
6462306a36Sopenharmony_ci			.cra_ctxsize		= sizeof(struct sm4_ctx),
6562306a36Sopenharmony_ci			.cra_module		= THIS_MODULE,
6662306a36Sopenharmony_ci		},
6762306a36Sopenharmony_ci		.min_keysize	= SM4_KEY_SIZE,
6862306a36Sopenharmony_ci		.max_keysize	= SM4_KEY_SIZE,
6962306a36Sopenharmony_ci		.walksize	= 16 * SM4_BLOCK_SIZE,
7062306a36Sopenharmony_ci		.setkey		= sm4_skcipher_setkey,
7162306a36Sopenharmony_ci		.encrypt	= sm4_avx_ecb_encrypt,
7262306a36Sopenharmony_ci		.decrypt	= sm4_avx_ecb_decrypt,
7362306a36Sopenharmony_ci	}, {
7462306a36Sopenharmony_ci		.base = {
7562306a36Sopenharmony_ci			.cra_name		= "__cbc(sm4)",
7662306a36Sopenharmony_ci			.cra_driver_name	= "__cbc-sm4-aesni-avx2",
7762306a36Sopenharmony_ci			.cra_priority		= 500,
7862306a36Sopenharmony_ci			.cra_flags		= CRYPTO_ALG_INTERNAL,
7962306a36Sopenharmony_ci			.cra_blocksize		= SM4_BLOCK_SIZE,
8062306a36Sopenharmony_ci			.cra_ctxsize		= sizeof(struct sm4_ctx),
8162306a36Sopenharmony_ci			.cra_module		= THIS_MODULE,
8262306a36Sopenharmony_ci		},
8362306a36Sopenharmony_ci		.min_keysize	= SM4_KEY_SIZE,
8462306a36Sopenharmony_ci		.max_keysize	= SM4_KEY_SIZE,
8562306a36Sopenharmony_ci		.ivsize		= SM4_BLOCK_SIZE,
8662306a36Sopenharmony_ci		.walksize	= 16 * SM4_BLOCK_SIZE,
8762306a36Sopenharmony_ci		.setkey		= sm4_skcipher_setkey,
8862306a36Sopenharmony_ci		.encrypt	= sm4_cbc_encrypt,
8962306a36Sopenharmony_ci		.decrypt	= cbc_decrypt,
9062306a36Sopenharmony_ci	}, {
9162306a36Sopenharmony_ci		.base = {
9262306a36Sopenharmony_ci			.cra_name		= "__cfb(sm4)",
9362306a36Sopenharmony_ci			.cra_driver_name	= "__cfb-sm4-aesni-avx2",
9462306a36Sopenharmony_ci			.cra_priority		= 500,
9562306a36Sopenharmony_ci			.cra_flags		= CRYPTO_ALG_INTERNAL,
9662306a36Sopenharmony_ci			.cra_blocksize		= 1,
9762306a36Sopenharmony_ci			.cra_ctxsize		= sizeof(struct sm4_ctx),
9862306a36Sopenharmony_ci			.cra_module		= THIS_MODULE,
9962306a36Sopenharmony_ci		},
10062306a36Sopenharmony_ci		.min_keysize	= SM4_KEY_SIZE,
10162306a36Sopenharmony_ci		.max_keysize	= SM4_KEY_SIZE,
10262306a36Sopenharmony_ci		.ivsize		= SM4_BLOCK_SIZE,
10362306a36Sopenharmony_ci		.chunksize	= SM4_BLOCK_SIZE,
10462306a36Sopenharmony_ci		.walksize	= 16 * SM4_BLOCK_SIZE,
10562306a36Sopenharmony_ci		.setkey		= sm4_skcipher_setkey,
10662306a36Sopenharmony_ci		.encrypt	= sm4_cfb_encrypt,
10762306a36Sopenharmony_ci		.decrypt	= cfb_decrypt,
10862306a36Sopenharmony_ci	}, {
10962306a36Sopenharmony_ci		.base = {
11062306a36Sopenharmony_ci			.cra_name		= "__ctr(sm4)",
11162306a36Sopenharmony_ci			.cra_driver_name	= "__ctr-sm4-aesni-avx2",
11262306a36Sopenharmony_ci			.cra_priority		= 500,
11362306a36Sopenharmony_ci			.cra_flags		= CRYPTO_ALG_INTERNAL,
11462306a36Sopenharmony_ci			.cra_blocksize		= 1,
11562306a36Sopenharmony_ci			.cra_ctxsize		= sizeof(struct sm4_ctx),
11662306a36Sopenharmony_ci			.cra_module		= THIS_MODULE,
11762306a36Sopenharmony_ci		},
11862306a36Sopenharmony_ci		.min_keysize	= SM4_KEY_SIZE,
11962306a36Sopenharmony_ci		.max_keysize	= SM4_KEY_SIZE,
12062306a36Sopenharmony_ci		.ivsize		= SM4_BLOCK_SIZE,
12162306a36Sopenharmony_ci		.chunksize	= SM4_BLOCK_SIZE,
12262306a36Sopenharmony_ci		.walksize	= 16 * SM4_BLOCK_SIZE,
12362306a36Sopenharmony_ci		.setkey		= sm4_skcipher_setkey,
12462306a36Sopenharmony_ci		.encrypt	= ctr_crypt,
12562306a36Sopenharmony_ci		.decrypt	= ctr_crypt,
12662306a36Sopenharmony_ci	}
12762306a36Sopenharmony_ci};
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic struct simd_skcipher_alg *
13062306a36Sopenharmony_cisimd_sm4_aesni_avx2_skciphers[ARRAY_SIZE(sm4_aesni_avx2_skciphers)];
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int __init sm4_init(void)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci	const char *feature_name;
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	if (!boot_cpu_has(X86_FEATURE_AVX) ||
13762306a36Sopenharmony_ci	    !boot_cpu_has(X86_FEATURE_AVX2) ||
13862306a36Sopenharmony_ci	    !boot_cpu_has(X86_FEATURE_AES) ||
13962306a36Sopenharmony_ci	    !boot_cpu_has(X86_FEATURE_OSXSAVE)) {
14062306a36Sopenharmony_ci		pr_info("AVX2 or AES-NI instructions are not detected.\n");
14162306a36Sopenharmony_ci		return -ENODEV;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (!cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM,
14562306a36Sopenharmony_ci				&feature_name)) {
14662306a36Sopenharmony_ci		pr_info("CPU feature '%s' is not supported.\n", feature_name);
14762306a36Sopenharmony_ci		return -ENODEV;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return simd_register_skciphers_compat(sm4_aesni_avx2_skciphers,
15162306a36Sopenharmony_ci					ARRAY_SIZE(sm4_aesni_avx2_skciphers),
15262306a36Sopenharmony_ci					simd_sm4_aesni_avx2_skciphers);
15362306a36Sopenharmony_ci}
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_cistatic void __exit sm4_exit(void)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	simd_unregister_skciphers(sm4_aesni_avx2_skciphers,
15862306a36Sopenharmony_ci				ARRAY_SIZE(sm4_aesni_avx2_skciphers),
15962306a36Sopenharmony_ci				simd_sm4_aesni_avx2_skciphers);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cimodule_init(sm4_init);
16362306a36Sopenharmony_cimodule_exit(sm4_exit);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
16662306a36Sopenharmony_ciMODULE_AUTHOR("Tianjia Zhang <tianjia.zhang@linux.alibaba.com>");
16762306a36Sopenharmony_ciMODULE_DESCRIPTION("SM4 Cipher Algorithm, AES-NI/AVX2 optimized");
16862306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sm4");
16962306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("sm4-aesni-avx2");
170