162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Glue Code for assembler optimized version of Blowfish 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: 862306a36Sopenharmony_ci * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <crypto/algapi.h> 1262306a36Sopenharmony_ci#include <crypto/blowfish.h> 1362306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 1462306a36Sopenharmony_ci#include <linux/crypto.h> 1562306a36Sopenharmony_ci#include <linux/init.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/types.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "ecb_cbc_helpers.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci/* regular block cipher functions */ 2262306a36Sopenharmony_ciasmlinkage void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src); 2362306a36Sopenharmony_ciasmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* 4-way parallel cipher functions */ 2662306a36Sopenharmony_ciasmlinkage void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst, 2762306a36Sopenharmony_ci const u8 *src); 2862306a36Sopenharmony_ciasmlinkage void __blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst, 2962306a36Sopenharmony_ci const u8 *src, bool cbc); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic inline void blowfish_dec_ecb_4way(struct bf_ctx *ctx, u8 *dst, 3262306a36Sopenharmony_ci const u8 *src) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci return __blowfish_dec_blk_4way(ctx, dst, src, false); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cistatic inline void blowfish_dec_cbc_4way(struct bf_ctx *ctx, u8 *dst, 3862306a36Sopenharmony_ci const u8 *src) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci return __blowfish_dec_blk_4way(ctx, dst, src, true); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic void blowfish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci blowfish_enc_blk(crypto_tfm_ctx(tfm), dst, src); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 4962306a36Sopenharmony_ci{ 5062306a36Sopenharmony_ci blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int blowfish_setkey_skcipher(struct crypto_skcipher *tfm, 5462306a36Sopenharmony_ci const u8 *key, unsigned int keylen) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci return blowfish_setkey(&tfm->base, key, keylen); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic int ecb_encrypt(struct skcipher_request *req) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci ECB_WALK_START(req, BF_BLOCK_SIZE, -1); 6262306a36Sopenharmony_ci ECB_BLOCK(4, blowfish_enc_blk_4way); 6362306a36Sopenharmony_ci ECB_BLOCK(1, blowfish_enc_blk); 6462306a36Sopenharmony_ci ECB_WALK_END(); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int ecb_decrypt(struct skcipher_request *req) 6862306a36Sopenharmony_ci{ 6962306a36Sopenharmony_ci ECB_WALK_START(req, BF_BLOCK_SIZE, -1); 7062306a36Sopenharmony_ci ECB_BLOCK(4, blowfish_dec_ecb_4way); 7162306a36Sopenharmony_ci ECB_BLOCK(1, blowfish_dec_blk); 7262306a36Sopenharmony_ci ECB_WALK_END(); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic int cbc_encrypt(struct skcipher_request *req) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci CBC_WALK_START(req, BF_BLOCK_SIZE, -1); 7862306a36Sopenharmony_ci CBC_ENC_BLOCK(blowfish_enc_blk); 7962306a36Sopenharmony_ci CBC_WALK_END(); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic int cbc_decrypt(struct skcipher_request *req) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci CBC_WALK_START(req, BF_BLOCK_SIZE, -1); 8562306a36Sopenharmony_ci CBC_DEC_BLOCK(4, blowfish_dec_cbc_4way); 8662306a36Sopenharmony_ci CBC_DEC_BLOCK(1, blowfish_dec_blk); 8762306a36Sopenharmony_ci CBC_WALK_END(); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic struct crypto_alg bf_cipher_alg = { 9162306a36Sopenharmony_ci .cra_name = "blowfish", 9262306a36Sopenharmony_ci .cra_driver_name = "blowfish-asm", 9362306a36Sopenharmony_ci .cra_priority = 200, 9462306a36Sopenharmony_ci .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 9562306a36Sopenharmony_ci .cra_blocksize = BF_BLOCK_SIZE, 9662306a36Sopenharmony_ci .cra_ctxsize = sizeof(struct bf_ctx), 9762306a36Sopenharmony_ci .cra_alignmask = 0, 9862306a36Sopenharmony_ci .cra_module = THIS_MODULE, 9962306a36Sopenharmony_ci .cra_u = { 10062306a36Sopenharmony_ci .cipher = { 10162306a36Sopenharmony_ci .cia_min_keysize = BF_MIN_KEY_SIZE, 10262306a36Sopenharmony_ci .cia_max_keysize = BF_MAX_KEY_SIZE, 10362306a36Sopenharmony_ci .cia_setkey = blowfish_setkey, 10462306a36Sopenharmony_ci .cia_encrypt = blowfish_encrypt, 10562306a36Sopenharmony_ci .cia_decrypt = blowfish_decrypt, 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic struct skcipher_alg bf_skcipher_algs[] = { 11162306a36Sopenharmony_ci { 11262306a36Sopenharmony_ci .base.cra_name = "ecb(blowfish)", 11362306a36Sopenharmony_ci .base.cra_driver_name = "ecb-blowfish-asm", 11462306a36Sopenharmony_ci .base.cra_priority = 300, 11562306a36Sopenharmony_ci .base.cra_blocksize = BF_BLOCK_SIZE, 11662306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct bf_ctx), 11762306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 11862306a36Sopenharmony_ci .min_keysize = BF_MIN_KEY_SIZE, 11962306a36Sopenharmony_ci .max_keysize = BF_MAX_KEY_SIZE, 12062306a36Sopenharmony_ci .setkey = blowfish_setkey_skcipher, 12162306a36Sopenharmony_ci .encrypt = ecb_encrypt, 12262306a36Sopenharmony_ci .decrypt = ecb_decrypt, 12362306a36Sopenharmony_ci }, { 12462306a36Sopenharmony_ci .base.cra_name = "cbc(blowfish)", 12562306a36Sopenharmony_ci .base.cra_driver_name = "cbc-blowfish-asm", 12662306a36Sopenharmony_ci .base.cra_priority = 300, 12762306a36Sopenharmony_ci .base.cra_blocksize = BF_BLOCK_SIZE, 12862306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct bf_ctx), 12962306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 13062306a36Sopenharmony_ci .min_keysize = BF_MIN_KEY_SIZE, 13162306a36Sopenharmony_ci .max_keysize = BF_MAX_KEY_SIZE, 13262306a36Sopenharmony_ci .ivsize = BF_BLOCK_SIZE, 13362306a36Sopenharmony_ci .setkey = blowfish_setkey_skcipher, 13462306a36Sopenharmony_ci .encrypt = cbc_encrypt, 13562306a36Sopenharmony_ci .decrypt = cbc_decrypt, 13662306a36Sopenharmony_ci }, 13762306a36Sopenharmony_ci}; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic bool is_blacklisted_cpu(void) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 14262306a36Sopenharmony_ci return false; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci if (boot_cpu_data.x86 == 0x0f) { 14562306a36Sopenharmony_ci /* 14662306a36Sopenharmony_ci * On Pentium 4, blowfish-x86_64 is slower than generic C 14762306a36Sopenharmony_ci * implementation because use of 64bit rotates (which are really 14862306a36Sopenharmony_ci * slow on P4). Therefore blacklist P4s. 14962306a36Sopenharmony_ci */ 15062306a36Sopenharmony_ci return true; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci return false; 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistatic int force; 15762306a36Sopenharmony_cimodule_param(force, int, 0); 15862306a36Sopenharmony_ciMODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic int __init blowfish_init(void) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci int err; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci if (!force && is_blacklisted_cpu()) { 16562306a36Sopenharmony_ci printk(KERN_INFO 16662306a36Sopenharmony_ci "blowfish-x86_64: performance on this CPU " 16762306a36Sopenharmony_ci "would be suboptimal: disabling " 16862306a36Sopenharmony_ci "blowfish-x86_64.\n"); 16962306a36Sopenharmony_ci return -ENODEV; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci err = crypto_register_alg(&bf_cipher_alg); 17362306a36Sopenharmony_ci if (err) 17462306a36Sopenharmony_ci return err; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci err = crypto_register_skciphers(bf_skcipher_algs, 17762306a36Sopenharmony_ci ARRAY_SIZE(bf_skcipher_algs)); 17862306a36Sopenharmony_ci if (err) 17962306a36Sopenharmony_ci crypto_unregister_alg(&bf_cipher_alg); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return err; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic void __exit blowfish_fini(void) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci crypto_unregister_alg(&bf_cipher_alg); 18762306a36Sopenharmony_ci crypto_unregister_skciphers(bf_skcipher_algs, 18862306a36Sopenharmony_ci ARRAY_SIZE(bf_skcipher_algs)); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cimodule_init(blowfish_init); 19262306a36Sopenharmony_cimodule_exit(blowfish_fini); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 19562306a36Sopenharmony_ciMODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized"); 19662306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("blowfish"); 19762306a36Sopenharmony_ciMODULE_ALIAS_CRYPTO("blowfish-asm"); 198