Path: blob/master/arch/x86/crypto/sm4_aesni_avx_glue.c
170899 views
/* SPDX-License-Identifier: GPL-2.0-or-later */1/*2* SM4 Cipher Algorithm, AES-NI/AVX optimized.3* as specified in4* https://tools.ietf.org/id/draft-ribose-cfrg-sm4-10.html5*6* Copyright (c) 2021, Alibaba Group.7* Copyright (c) 2021 Tianjia Zhang <[email protected]>8*/910#include <asm/fpu/api.h>11#include <linux/module.h>12#include <linux/crypto.h>13#include <linux/export.h>14#include <linux/kernel.h>15#include <crypto/internal/skcipher.h>16#include <crypto/sm4.h>17#include "sm4-avx.h"1819#define SM4_CRYPT8_BLOCK_SIZE (SM4_BLOCK_SIZE * 8)2021asmlinkage void sm4_aesni_avx_crypt4(const u32 *rk, u8 *dst,22const u8 *src, int nblocks);23asmlinkage void sm4_aesni_avx_crypt8(const u32 *rk, u8 *dst,24const u8 *src, int nblocks);25asmlinkage void sm4_aesni_avx_ctr_enc_blk8(const u32 *rk, u8 *dst,26const u8 *src, u8 *iv);27asmlinkage void sm4_aesni_avx_cbc_dec_blk8(const u32 *rk, u8 *dst,28const u8 *src, u8 *iv);2930static int sm4_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key,31unsigned int key_len)32{33struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm);3435return sm4_expandkey(ctx, key, key_len);36}3738static int ecb_do_crypt(struct skcipher_request *req, const u32 *rkey)39{40struct skcipher_walk walk;41unsigned int nbytes;42int err;4344err = skcipher_walk_virt(&walk, req, false);4546while ((nbytes = walk.nbytes) > 0) {47const u8 *src = walk.src.virt.addr;48u8 *dst = walk.dst.virt.addr;4950kernel_fpu_begin();51while (nbytes >= SM4_CRYPT8_BLOCK_SIZE) {52sm4_aesni_avx_crypt8(rkey, dst, src, 8);53dst += SM4_CRYPT8_BLOCK_SIZE;54src += SM4_CRYPT8_BLOCK_SIZE;55nbytes -= SM4_CRYPT8_BLOCK_SIZE;56}57while (nbytes >= SM4_BLOCK_SIZE) {58unsigned int nblocks = min(nbytes >> 4, 4u);59sm4_aesni_avx_crypt4(rkey, dst, src, nblocks);60dst += nblocks * SM4_BLOCK_SIZE;61src += nblocks * SM4_BLOCK_SIZE;62nbytes -= nblocks * SM4_BLOCK_SIZE;63}64kernel_fpu_end();6566err = skcipher_walk_done(&walk, nbytes);67}6869return err;70}7172int sm4_avx_ecb_encrypt(struct skcipher_request *req)73{74struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);75struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm);7677return ecb_do_crypt(req, ctx->rkey_enc);78}79EXPORT_SYMBOL_GPL(sm4_avx_ecb_encrypt);8081int sm4_avx_ecb_decrypt(struct skcipher_request *req)82{83struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);84struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm);8586return ecb_do_crypt(req, ctx->rkey_dec);87}88EXPORT_SYMBOL_GPL(sm4_avx_ecb_decrypt);8990int sm4_cbc_encrypt(struct skcipher_request *req)91{92struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);93struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm);94struct skcipher_walk walk;95unsigned int nbytes;96int err;9798err = skcipher_walk_virt(&walk, req, false);99100while ((nbytes = walk.nbytes) > 0) {101const u8 *iv = walk.iv;102const u8 *src = walk.src.virt.addr;103u8 *dst = walk.dst.virt.addr;104105while (nbytes >= SM4_BLOCK_SIZE) {106crypto_xor_cpy(dst, src, iv, SM4_BLOCK_SIZE);107sm4_crypt_block(ctx->rkey_enc, dst, dst);108iv = dst;109src += SM4_BLOCK_SIZE;110dst += SM4_BLOCK_SIZE;111nbytes -= SM4_BLOCK_SIZE;112}113if (iv != walk.iv)114memcpy(walk.iv, iv, SM4_BLOCK_SIZE);115116err = skcipher_walk_done(&walk, nbytes);117}118119return err;120}121EXPORT_SYMBOL_GPL(sm4_cbc_encrypt);122123int sm4_avx_cbc_decrypt(struct skcipher_request *req,124unsigned int bsize, sm4_crypt_func func)125{126struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);127struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm);128struct skcipher_walk walk;129unsigned int nbytes;130int err;131132err = skcipher_walk_virt(&walk, req, false);133134while ((nbytes = walk.nbytes) > 0) {135const u8 *src = walk.src.virt.addr;136u8 *dst = walk.dst.virt.addr;137138kernel_fpu_begin();139140while (nbytes >= bsize) {141func(ctx->rkey_dec, dst, src, walk.iv);142dst += bsize;143src += bsize;144nbytes -= bsize;145}146147while (nbytes >= SM4_BLOCK_SIZE) {148u8 keystream[SM4_BLOCK_SIZE * 8];149u8 iv[SM4_BLOCK_SIZE];150unsigned int nblocks = min(nbytes >> 4, 8u);151int i;152153sm4_aesni_avx_crypt8(ctx->rkey_dec, keystream,154src, nblocks);155156src += ((int)nblocks - 2) * SM4_BLOCK_SIZE;157dst += (nblocks - 1) * SM4_BLOCK_SIZE;158memcpy(iv, src + SM4_BLOCK_SIZE, SM4_BLOCK_SIZE);159160for (i = nblocks - 1; i > 0; i--) {161crypto_xor_cpy(dst, src,162&keystream[i * SM4_BLOCK_SIZE],163SM4_BLOCK_SIZE);164src -= SM4_BLOCK_SIZE;165dst -= SM4_BLOCK_SIZE;166}167crypto_xor_cpy(dst, walk.iv, keystream, SM4_BLOCK_SIZE);168memcpy(walk.iv, iv, SM4_BLOCK_SIZE);169dst += nblocks * SM4_BLOCK_SIZE;170src += (nblocks + 1) * SM4_BLOCK_SIZE;171nbytes -= nblocks * SM4_BLOCK_SIZE;172}173174kernel_fpu_end();175err = skcipher_walk_done(&walk, nbytes);176}177178return err;179}180EXPORT_SYMBOL_GPL(sm4_avx_cbc_decrypt);181182static int cbc_decrypt(struct skcipher_request *req)183{184return sm4_avx_cbc_decrypt(req, SM4_CRYPT8_BLOCK_SIZE,185sm4_aesni_avx_cbc_dec_blk8);186}187188int sm4_avx_ctr_crypt(struct skcipher_request *req,189unsigned int bsize, sm4_crypt_func func)190{191struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);192struct sm4_ctx *ctx = crypto_skcipher_ctx(tfm);193struct skcipher_walk walk;194unsigned int nbytes;195int err;196197err = skcipher_walk_virt(&walk, req, false);198199while ((nbytes = walk.nbytes) > 0) {200const u8 *src = walk.src.virt.addr;201u8 *dst = walk.dst.virt.addr;202203kernel_fpu_begin();204205while (nbytes >= bsize) {206func(ctx->rkey_enc, dst, src, walk.iv);207dst += bsize;208src += bsize;209nbytes -= bsize;210}211212while (nbytes >= SM4_BLOCK_SIZE) {213u8 keystream[SM4_BLOCK_SIZE * 8];214unsigned int nblocks = min(nbytes >> 4, 8u);215int i;216217for (i = 0; i < nblocks; i++) {218memcpy(&keystream[i * SM4_BLOCK_SIZE],219walk.iv, SM4_BLOCK_SIZE);220crypto_inc(walk.iv, SM4_BLOCK_SIZE);221}222sm4_aesni_avx_crypt8(ctx->rkey_enc, keystream,223keystream, nblocks);224225crypto_xor_cpy(dst, src, keystream,226nblocks * SM4_BLOCK_SIZE);227dst += nblocks * SM4_BLOCK_SIZE;228src += nblocks * SM4_BLOCK_SIZE;229nbytes -= nblocks * SM4_BLOCK_SIZE;230}231232kernel_fpu_end();233234/* tail */235if (walk.nbytes == walk.total && nbytes > 0) {236u8 keystream[SM4_BLOCK_SIZE];237238memcpy(keystream, walk.iv, SM4_BLOCK_SIZE);239crypto_inc(walk.iv, SM4_BLOCK_SIZE);240241sm4_crypt_block(ctx->rkey_enc, keystream, keystream);242243crypto_xor_cpy(dst, src, keystream, nbytes);244dst += nbytes;245src += nbytes;246nbytes = 0;247}248249err = skcipher_walk_done(&walk, nbytes);250}251252return err;253}254EXPORT_SYMBOL_GPL(sm4_avx_ctr_crypt);255256static int ctr_crypt(struct skcipher_request *req)257{258return sm4_avx_ctr_crypt(req, SM4_CRYPT8_BLOCK_SIZE,259sm4_aesni_avx_ctr_enc_blk8);260}261262static struct skcipher_alg sm4_aesni_avx_skciphers[] = {263{264.base = {265.cra_name = "ecb(sm4)",266.cra_driver_name = "ecb-sm4-aesni-avx",267.cra_priority = 400,268.cra_blocksize = SM4_BLOCK_SIZE,269.cra_ctxsize = sizeof(struct sm4_ctx),270.cra_module = THIS_MODULE,271},272.min_keysize = SM4_KEY_SIZE,273.max_keysize = SM4_KEY_SIZE,274.walksize = 8 * SM4_BLOCK_SIZE,275.setkey = sm4_skcipher_setkey,276.encrypt = sm4_avx_ecb_encrypt,277.decrypt = sm4_avx_ecb_decrypt,278}, {279.base = {280.cra_name = "cbc(sm4)",281.cra_driver_name = "cbc-sm4-aesni-avx",282.cra_priority = 400,283.cra_blocksize = SM4_BLOCK_SIZE,284.cra_ctxsize = sizeof(struct sm4_ctx),285.cra_module = THIS_MODULE,286},287.min_keysize = SM4_KEY_SIZE,288.max_keysize = SM4_KEY_SIZE,289.ivsize = SM4_BLOCK_SIZE,290.walksize = 8 * SM4_BLOCK_SIZE,291.setkey = sm4_skcipher_setkey,292.encrypt = sm4_cbc_encrypt,293.decrypt = cbc_decrypt,294}, {295.base = {296.cra_name = "ctr(sm4)",297.cra_driver_name = "ctr-sm4-aesni-avx",298.cra_priority = 400,299.cra_blocksize = 1,300.cra_ctxsize = sizeof(struct sm4_ctx),301.cra_module = THIS_MODULE,302},303.min_keysize = SM4_KEY_SIZE,304.max_keysize = SM4_KEY_SIZE,305.ivsize = SM4_BLOCK_SIZE,306.chunksize = SM4_BLOCK_SIZE,307.walksize = 8 * SM4_BLOCK_SIZE,308.setkey = sm4_skcipher_setkey,309.encrypt = ctr_crypt,310.decrypt = ctr_crypt,311}312};313314static int __init sm4_init(void)315{316const char *feature_name;317318if (!boot_cpu_has(X86_FEATURE_AVX) ||319!boot_cpu_has(X86_FEATURE_AES) ||320!boot_cpu_has(X86_FEATURE_OSXSAVE)) {321pr_info("AVX or AES-NI instructions are not detected.\n");322return -ENODEV;323}324325if (!cpu_has_xfeatures(XFEATURE_MASK_SSE | XFEATURE_MASK_YMM,326&feature_name)) {327pr_info("CPU feature '%s' is not supported.\n", feature_name);328return -ENODEV;329}330331return crypto_register_skciphers(sm4_aesni_avx_skciphers,332ARRAY_SIZE(sm4_aesni_avx_skciphers));333}334335static void __exit sm4_exit(void)336{337crypto_unregister_skciphers(sm4_aesni_avx_skciphers,338ARRAY_SIZE(sm4_aesni_avx_skciphers));339}340341module_init(sm4_init);342module_exit(sm4_exit);343344MODULE_LICENSE("GPL v2");345MODULE_AUTHOR("Tianjia Zhang <[email protected]>");346MODULE_DESCRIPTION("SM4 Cipher Algorithm, AES-NI/AVX optimized");347MODULE_ALIAS_CRYPTO("sm4");348MODULE_ALIAS_CRYPTO("sm4-aesni-avx");349350351