root/arch/x86/crypto/sm4_aesni_avx2_glue.c
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * SM4 Cipher Algorithm, AES-NI/AVX2 optimized.
 * as specified in
 * https://tools.ietf.org/id/draft-ribose-cfrg-sm4-10.html
 *
 * Copyright (c) 2021, Alibaba Group.
 * Copyright (c) 2021 Tianjia Zhang <tianjia.zhang@linux.alibaba.com>
 */

#include <asm/fpu/api.h>
#include <linux/module.h>
#include <linux/crypto.h>
#include <linux/kernel.h>
#include <crypto/internal/skcipher.h>
#include <crypto/sm4.h>
#include "sm4-avx.h"

#define SM4_CRYPT16_BLOCK_SIZE  (SM4_BLOCK_SIZE * 16)

asmlinkage void sm4_aesni_avx2_ctr_enc_blk16(const u32 *rk, u8 *dst,
                                        const u8 *src, u8 *iv);
asmlinkage void sm4_aesni_avx2_cbc_dec_blk16(const u32 *rk, u8 *dst,
                                        const u8 *src, u8 *iv);

static int sm4_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,
                        unsigned int key_len)
{
        struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm);

        return sm4_expandkey(ctx, key, key_len);
}

static int cbc_decrypt(struct skcipher_request *req)
{
        return sm4_avx_cbc_decrypt(req, SM4_CRYPT16_BLOCK_SIZE,
                                sm4_aesni_avx2_cbc_dec_blk16);
}


static int ctr_crypt(struct skcipher_request *req)
{
        return sm4_avx_ctr_crypt(req, SM4_CRYPT16_BLOCK_SIZE,
                                sm4_aesni_avx2_ctr_enc_blk16);
}

static struct skcipher_alg sm4_aesni_avx2_skciphers[] = {
        {
                .base = {
                        .cra_name               = "ecb(sm4)",
                        .cra_driver_name        = "ecb-sm4-aesni-avx2",
                        .cra_priority           = 500,
                        .cra_blocksize          = SM4_BLOCK_SIZE,
                        .cra_ctxsize            = sizeof(struct sm4_ctx),
                        .cra_module             = THIS_MODULE,
                },
                .min_keysize    = SM4_KEY_SIZE,
                .max_keysize    = SM4_KEY_SIZE,
                .walksize       = 16 * SM4_BLOCK_SIZE,
                .setkey         = sm4_skcipher_setkey,
                .encrypt        = sm4_avx_ecb_encrypt,
                .decrypt        = sm4_avx_ecb_decrypt,
        }, {
                .base = {
                        .cra_name               = "cbc(sm4)",
                        .cra_driver_name        = "cbc-sm4-aesni-avx2",
                        .cra_priority           = 500,
                        .cra_blocksize          = SM4_BLOCK_SIZE,
                        .cra_ctxsize            = sizeof(struct sm4_ctx),
                        .cra_module             = THIS_MODULE,
                },
                .min_keysize    = SM4_KEY_SIZE,
                .max_keysize    = SM4_KEY_SIZE,
                .ivsize         = SM4_BLOCK_SIZE,
                .walksize       = 16 * SM4_BLOCK_SIZE,
                .setkey         = sm4_skcipher_setkey,
                .encrypt        = sm4_cbc_encrypt,
                .decrypt        = cbc_decrypt,
        }, {
                .base = {
                        .cra_name               = "ctr(sm4)",
                        .cra_driver_name        = "ctr-sm4-aesni-avx2",
                        .cra_priority           = 500,
                        .cra_blocksize          = 1,
                        .cra_ctxsize            = sizeof(struct sm4_ctx),
                        .cra_module             = THIS_MODULE,
                },
                .min_keysize    = SM4_KEY_SIZE,
                .max_keysize    = SM4_KEY_SIZE,
                .ivsize         = SM4_BLOCK_SIZE,
                .chunksize      = SM4_BLOCK_SIZE,
                .walksize       = 16 * SM4_BLOCK_SIZE,
                .setkey         = sm4_skcipher_setkey,
                .encrypt        = ctr_crypt,
                .decrypt        = ctr_crypt,
        }
};

static int __init sm4_init(void)
{
        const char *feature_name;

        if (!boot_cpu_has(X86_FEATURE_AVX) ||
            !boot_cpu_has(X86_FEATURE_AVX2) ||
            !boot_cpu_has(X86_FEATURE_AES) ||
            !boot_cpu_has(X86_FEATURE_OSXSAVE)) {
                pr_info("AVX2 or AES-NI instructions are not detected.\n");
                return -ENODEV;
        }

        if (!cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM,
                                &feature_name)) {
                pr_info("CPU feature '%s' is not supported.\n", feature_name);
                return -ENODEV;
        }

        return crypto_register_skciphers(sm4_aesni_avx2_skciphers,
                                         ARRAY_SIZE(sm4_aesni_avx2_skciphers));
}

static void __exit sm4_exit(void)
{
        crypto_unregister_skciphers(sm4_aesni_avx2_skciphers,
                                    ARRAY_SIZE(sm4_aesni_avx2_skciphers));
}

module_init(sm4_init);
module_exit(sm4_exit);

MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Tianjia Zhang <tianjia.zhang@linux.alibaba.com>");
MODULE_DESCRIPTION("SM4 Cipher Algorithm, AES-NI/AVX2 optimized");
MODULE_ALIAS_CRYPTO("sm4");
MODULE_ALIAS_CRYPTO("sm4-aesni-avx2");