|  | // SPDX-License-Identifier: GPL-2.0-or-later | 
|  | /* | 
|  | * Glue Code for AVX assembler versions of Serpent Cipher | 
|  | * | 
|  | * Copyright (C) 2012 Johannes Goetzfried | 
|  | *     <Johannes.Goetzfried@informatik.stud.uni-erlangen.de> | 
|  | * | 
|  | * Copyright © 2011-2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> | 
|  | */ | 
|  |  | 
|  | #include <linux/module.h> | 
|  | #include <linux/types.h> | 
|  | #include <linux/crypto.h> | 
|  | #include <linux/err.h> | 
|  | #include <crypto/algapi.h> | 
|  | #include <crypto/internal/simd.h> | 
|  | #include <crypto/serpent.h> | 
|  |  | 
|  | #include "serpent-avx.h" | 
|  | #include "ecb_cbc_helpers.h" | 
|  |  | 
|  | /* 8-way parallel cipher functions */ | 
|  | asmlinkage void serpent_ecb_enc_8way_avx(const void *ctx, u8 *dst, | 
|  | const u8 *src); | 
|  | EXPORT_SYMBOL_GPL(serpent_ecb_enc_8way_avx); | 
|  |  | 
|  | asmlinkage void serpent_ecb_dec_8way_avx(const void *ctx, u8 *dst, | 
|  | const u8 *src); | 
|  | EXPORT_SYMBOL_GPL(serpent_ecb_dec_8way_avx); | 
|  |  | 
|  | asmlinkage void serpent_cbc_dec_8way_avx(const void *ctx, u8 *dst, | 
|  | const u8 *src); | 
|  | EXPORT_SYMBOL_GPL(serpent_cbc_dec_8way_avx); | 
|  |  | 
|  | static int serpent_setkey_skcipher(struct crypto_skcipher *tfm, | 
|  | const u8 *key, unsigned int keylen) | 
|  | { | 
|  | return __serpent_setkey(crypto_skcipher_ctx(tfm), key, keylen); | 
|  | } | 
|  |  | 
|  | static int ecb_encrypt(struct skcipher_request *req) | 
|  | { | 
|  | ECB_WALK_START(req, SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS); | 
|  | ECB_BLOCK(SERPENT_PARALLEL_BLOCKS, serpent_ecb_enc_8way_avx); | 
|  | ECB_BLOCK(1, __serpent_encrypt); | 
|  | ECB_WALK_END(); | 
|  | } | 
|  |  | 
|  | static int ecb_decrypt(struct skcipher_request *req) | 
|  | { | 
|  | ECB_WALK_START(req, SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS); | 
|  | ECB_BLOCK(SERPENT_PARALLEL_BLOCKS, serpent_ecb_dec_8way_avx); | 
|  | ECB_BLOCK(1, __serpent_decrypt); | 
|  | ECB_WALK_END(); | 
|  | } | 
|  |  | 
|  | static int cbc_encrypt(struct skcipher_request *req) | 
|  | { | 
|  | CBC_WALK_START(req, SERPENT_BLOCK_SIZE, -1); | 
|  | CBC_ENC_BLOCK(__serpent_encrypt); | 
|  | CBC_WALK_END(); | 
|  | } | 
|  |  | 
|  | static int cbc_decrypt(struct skcipher_request *req) | 
|  | { | 
|  | CBC_WALK_START(req, SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS); | 
|  | CBC_DEC_BLOCK(SERPENT_PARALLEL_BLOCKS, serpent_cbc_dec_8way_avx); | 
|  | CBC_DEC_BLOCK(1, __serpent_decrypt); | 
|  | CBC_WALK_END(); | 
|  | } | 
|  |  | 
|  | static struct skcipher_alg serpent_algs[] = { | 
|  | { | 
|  | .base.cra_name		= "__ecb(serpent)", | 
|  | .base.cra_driver_name	= "__ecb-serpent-avx", | 
|  | .base.cra_priority	= 500, | 
|  | .base.cra_flags		= CRYPTO_ALG_INTERNAL, | 
|  | .base.cra_blocksize	= SERPENT_BLOCK_SIZE, | 
|  | .base.cra_ctxsize	= sizeof(struct serpent_ctx), | 
|  | .base.cra_module	= THIS_MODULE, | 
|  | .min_keysize		= SERPENT_MIN_KEY_SIZE, | 
|  | .max_keysize		= SERPENT_MAX_KEY_SIZE, | 
|  | .setkey			= serpent_setkey_skcipher, | 
|  | .encrypt		= ecb_encrypt, | 
|  | .decrypt		= ecb_decrypt, | 
|  | }, { | 
|  | .base.cra_name		= "__cbc(serpent)", | 
|  | .base.cra_driver_name	= "__cbc-serpent-avx", | 
|  | .base.cra_priority	= 500, | 
|  | .base.cra_flags		= CRYPTO_ALG_INTERNAL, | 
|  | .base.cra_blocksize	= SERPENT_BLOCK_SIZE, | 
|  | .base.cra_ctxsize	= sizeof(struct serpent_ctx), | 
|  | .base.cra_module	= THIS_MODULE, | 
|  | .min_keysize		= SERPENT_MIN_KEY_SIZE, | 
|  | .max_keysize		= SERPENT_MAX_KEY_SIZE, | 
|  | .ivsize			= SERPENT_BLOCK_SIZE, | 
|  | .setkey			= serpent_setkey_skcipher, | 
|  | .encrypt		= cbc_encrypt, | 
|  | .decrypt		= cbc_decrypt, | 
|  | }, | 
|  | }; | 
|  |  | 
|  | static struct simd_skcipher_alg *serpent_simd_algs[ARRAY_SIZE(serpent_algs)]; | 
|  |  | 
|  | static int __init serpent_init(void) | 
|  | { | 
|  | const char *feature_name; | 
|  |  | 
|  | 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 simd_register_skciphers_compat(serpent_algs, | 
|  | ARRAY_SIZE(serpent_algs), | 
|  | serpent_simd_algs); | 
|  | } | 
|  |  | 
|  | static void __exit serpent_exit(void) | 
|  | { | 
|  | simd_unregister_skciphers(serpent_algs, ARRAY_SIZE(serpent_algs), | 
|  | serpent_simd_algs); | 
|  | } | 
|  |  | 
|  | module_init(serpent_init); | 
|  | module_exit(serpent_exit); | 
|  |  | 
|  | MODULE_DESCRIPTION("Serpent Cipher Algorithm, AVX optimized"); | 
|  | MODULE_LICENSE("GPL"); | 
|  | MODULE_ALIAS_CRYPTO("serpent"); |