11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 264b94ceaSJussi Kivilinna /* 364b94ceaSJussi Kivilinna * Glue Code for assembler optimized version of Blowfish 464b94ceaSJussi Kivilinna * 53d387ef0SJussi Kivilinna * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 664b94ceaSJussi Kivilinna * 7a071d06eSJussi Kivilinna * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: 8a071d06eSJussi Kivilinna * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> 964b94ceaSJussi Kivilinna */ 1064b94ceaSJussi Kivilinna 11c1679171SEric Biggers #include <crypto/algapi.h> 1264b94ceaSJussi Kivilinna #include <crypto/blowfish.h> 13c1679171SEric Biggers #include <crypto/internal/skcipher.h> 1464b94ceaSJussi Kivilinna #include <linux/crypto.h> 1564b94ceaSJussi Kivilinna #include <linux/init.h> 1664b94ceaSJussi Kivilinna #include <linux/module.h> 1764b94ceaSJussi Kivilinna #include <linux/types.h> 1864b94ceaSJussi Kivilinna 19*bc3f42acSPeter Lafreniere #include "ecb_cbc_helpers.h" 20*bc3f42acSPeter Lafreniere 2164b94ceaSJussi Kivilinna /* regular block cipher functions */ 22b529ea65SPeter Lafreniere asmlinkage void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src); 2364b94ceaSJussi Kivilinna asmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src); 2464b94ceaSJussi Kivilinna 2564b94ceaSJussi Kivilinna /* 4-way parallel cipher functions */ 26b529ea65SPeter Lafreniere asmlinkage void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst, 27b529ea65SPeter Lafreniere const u8 *src); 28*bc3f42acSPeter Lafreniere asmlinkage void __blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst, 29*bc3f42acSPeter Lafreniere const u8 *src, bool cbc); 30*bc3f42acSPeter Lafreniere 31*bc3f42acSPeter Lafreniere static inline void blowfish_dec_ecb_4way(struct bf_ctx *ctx, u8 *dst, 32*bc3f42acSPeter Lafreniere const u8 *src) 33*bc3f42acSPeter Lafreniere { 34*bc3f42acSPeter Lafreniere return __blowfish_dec_blk_4way(ctx, dst, src, false); 35*bc3f42acSPeter Lafreniere } 36*bc3f42acSPeter Lafreniere 37*bc3f42acSPeter Lafreniere static inline void blowfish_dec_cbc_4way(struct bf_ctx *ctx, u8 *dst, 38*bc3f42acSPeter Lafreniere const u8 *src) 39*bc3f42acSPeter Lafreniere { 40*bc3f42acSPeter Lafreniere return __blowfish_dec_blk_4way(ctx, dst, src, true); 41*bc3f42acSPeter Lafreniere } 423d387ef0SJussi Kivilinna 4364b94ceaSJussi Kivilinna static void blowfish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 4464b94ceaSJussi Kivilinna { 4564b94ceaSJussi Kivilinna blowfish_enc_blk(crypto_tfm_ctx(tfm), dst, src); 4664b94ceaSJussi Kivilinna } 4764b94ceaSJussi Kivilinna 4864b94ceaSJussi Kivilinna static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 4964b94ceaSJussi Kivilinna { 5064b94ceaSJussi Kivilinna blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src); 5164b94ceaSJussi Kivilinna } 5264b94ceaSJussi Kivilinna 53c1679171SEric Biggers static int blowfish_setkey_skcipher(struct crypto_skcipher *tfm, 54c1679171SEric Biggers const u8 *key, unsigned int keylen) 55c1679171SEric Biggers { 56c1679171SEric Biggers return blowfish_setkey(&tfm->base, key, keylen); 57c1679171SEric Biggers } 58c1679171SEric Biggers 59c1679171SEric Biggers static int ecb_encrypt(struct skcipher_request *req) 6064b94ceaSJussi Kivilinna { 61*bc3f42acSPeter Lafreniere ECB_WALK_START(req, BF_BLOCK_SIZE, -1); 62*bc3f42acSPeter Lafreniere ECB_BLOCK(4, blowfish_enc_blk_4way); 63*bc3f42acSPeter Lafreniere ECB_BLOCK(1, blowfish_enc_blk); 64*bc3f42acSPeter Lafreniere ECB_WALK_END(); 6564b94ceaSJussi Kivilinna } 6664b94ceaSJussi Kivilinna 67c1679171SEric Biggers static int ecb_decrypt(struct skcipher_request *req) 6864b94ceaSJussi Kivilinna { 69*bc3f42acSPeter Lafreniere ECB_WALK_START(req, BF_BLOCK_SIZE, -1); 70*bc3f42acSPeter Lafreniere ECB_BLOCK(4, blowfish_dec_ecb_4way); 71*bc3f42acSPeter Lafreniere ECB_BLOCK(1, blowfish_dec_blk); 72*bc3f42acSPeter Lafreniere ECB_WALK_END(); 7364b94ceaSJussi Kivilinna } 7464b94ceaSJussi Kivilinna 75c1679171SEric Biggers static int cbc_encrypt(struct skcipher_request *req) 7664b94ceaSJussi Kivilinna { 77*bc3f42acSPeter Lafreniere CBC_WALK_START(req, BF_BLOCK_SIZE, -1); 78*bc3f42acSPeter Lafreniere CBC_ENC_BLOCK(blowfish_enc_blk); 79*bc3f42acSPeter Lafreniere CBC_WALK_END(); 8064b94ceaSJussi Kivilinna } 8164b94ceaSJussi Kivilinna 82c1679171SEric Biggers static int cbc_decrypt(struct skcipher_request *req) 8364b94ceaSJussi Kivilinna { 84*bc3f42acSPeter Lafreniere CBC_WALK_START(req, BF_BLOCK_SIZE, -1); 85*bc3f42acSPeter Lafreniere CBC_DEC_BLOCK(4, blowfish_dec_cbc_4way); 86*bc3f42acSPeter Lafreniere CBC_DEC_BLOCK(1, blowfish_dec_blk); 87*bc3f42acSPeter Lafreniere CBC_WALK_END(); 8864b94ceaSJussi Kivilinna } 8964b94ceaSJussi Kivilinna 90c1679171SEric Biggers static struct crypto_alg bf_cipher_alg = { 91d433208cSJussi Kivilinna .cra_name = "blowfish", 92d433208cSJussi Kivilinna .cra_driver_name = "blowfish-asm", 93d433208cSJussi Kivilinna .cra_priority = 200, 94d433208cSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 95d433208cSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 96d433208cSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 97919e2c32SJussi Kivilinna .cra_alignmask = 0, 98d433208cSJussi Kivilinna .cra_module = THIS_MODULE, 99d433208cSJussi Kivilinna .cra_u = { 100d433208cSJussi Kivilinna .cipher = { 101d433208cSJussi Kivilinna .cia_min_keysize = BF_MIN_KEY_SIZE, 102d433208cSJussi Kivilinna .cia_max_keysize = BF_MAX_KEY_SIZE, 103d433208cSJussi Kivilinna .cia_setkey = blowfish_setkey, 104d433208cSJussi Kivilinna .cia_encrypt = blowfish_encrypt, 105d433208cSJussi Kivilinna .cia_decrypt = blowfish_decrypt, 106d433208cSJussi Kivilinna } 107d433208cSJussi Kivilinna } 108c1679171SEric Biggers }; 109c1679171SEric Biggers 110c1679171SEric Biggers static struct skcipher_alg bf_skcipher_algs[] = { 111c1679171SEric Biggers { 112c1679171SEric Biggers .base.cra_name = "ecb(blowfish)", 113c1679171SEric Biggers .base.cra_driver_name = "ecb-blowfish-asm", 114c1679171SEric Biggers .base.cra_priority = 300, 115c1679171SEric Biggers .base.cra_blocksize = BF_BLOCK_SIZE, 116c1679171SEric Biggers .base.cra_ctxsize = sizeof(struct bf_ctx), 117c1679171SEric Biggers .base.cra_module = THIS_MODULE, 118d433208cSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 119d433208cSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 120c1679171SEric Biggers .setkey = blowfish_setkey_skcipher, 121d433208cSJussi Kivilinna .encrypt = ecb_encrypt, 122d433208cSJussi Kivilinna .decrypt = ecb_decrypt, 123d433208cSJussi Kivilinna }, { 124c1679171SEric Biggers .base.cra_name = "cbc(blowfish)", 125c1679171SEric Biggers .base.cra_driver_name = "cbc-blowfish-asm", 126c1679171SEric Biggers .base.cra_priority = 300, 127c1679171SEric Biggers .base.cra_blocksize = BF_BLOCK_SIZE, 128c1679171SEric Biggers .base.cra_ctxsize = sizeof(struct bf_ctx), 129c1679171SEric Biggers .base.cra_module = THIS_MODULE, 130d433208cSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 131d433208cSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 132d433208cSJussi Kivilinna .ivsize = BF_BLOCK_SIZE, 133c1679171SEric Biggers .setkey = blowfish_setkey_skcipher, 134d433208cSJussi Kivilinna .encrypt = cbc_encrypt, 135d433208cSJussi Kivilinna .decrypt = cbc_decrypt, 13664b94ceaSJussi Kivilinna }, 137c1679171SEric Biggers }; 13864b94ceaSJussi Kivilinna 1394c58464bSJussi Kivilinna static bool is_blacklisted_cpu(void) 1404c58464bSJussi Kivilinna { 1414c58464bSJussi Kivilinna if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 1424c58464bSJussi Kivilinna return false; 1434c58464bSJussi Kivilinna 1444c58464bSJussi Kivilinna if (boot_cpu_data.x86 == 0x0f) { 1454c58464bSJussi Kivilinna /* 1464c58464bSJussi Kivilinna * On Pentium 4, blowfish-x86_64 is slower than generic C 1474c58464bSJussi Kivilinna * implementation because use of 64bit rotates (which are really 1484c58464bSJussi Kivilinna * slow on P4). Therefore blacklist P4s. 1494c58464bSJussi Kivilinna */ 1504c58464bSJussi Kivilinna return true; 1514c58464bSJussi Kivilinna } 1524c58464bSJussi Kivilinna 1534c58464bSJussi Kivilinna return false; 1544c58464bSJussi Kivilinna } 1554c58464bSJussi Kivilinna 1564c58464bSJussi Kivilinna static int force; 1574c58464bSJussi Kivilinna module_param(force, int, 0); 1584c58464bSJussi Kivilinna MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); 1594c58464bSJussi Kivilinna 160f16a005cSRandy Dunlap static int __init blowfish_init(void) 16164b94ceaSJussi Kivilinna { 162c1679171SEric Biggers int err; 163c1679171SEric Biggers 1644c58464bSJussi Kivilinna if (!force && is_blacklisted_cpu()) { 1654c58464bSJussi Kivilinna printk(KERN_INFO 1664c58464bSJussi Kivilinna "blowfish-x86_64: performance on this CPU " 1674c58464bSJussi Kivilinna "would be suboptimal: disabling " 1684c58464bSJussi Kivilinna "blowfish-x86_64.\n"); 1694c58464bSJussi Kivilinna return -ENODEV; 1704c58464bSJussi Kivilinna } 1714c58464bSJussi Kivilinna 172c1679171SEric Biggers err = crypto_register_alg(&bf_cipher_alg); 173c1679171SEric Biggers if (err) 174c1679171SEric Biggers return err; 175c1679171SEric Biggers 176c1679171SEric Biggers err = crypto_register_skciphers(bf_skcipher_algs, 177c1679171SEric Biggers ARRAY_SIZE(bf_skcipher_algs)); 178c1679171SEric Biggers if (err) 179c1679171SEric Biggers crypto_unregister_alg(&bf_cipher_alg); 180c1679171SEric Biggers 181c1679171SEric Biggers return err; 18264b94ceaSJussi Kivilinna } 18364b94ceaSJussi Kivilinna 184f16a005cSRandy Dunlap static void __exit blowfish_fini(void) 18564b94ceaSJussi Kivilinna { 186c1679171SEric Biggers crypto_unregister_alg(&bf_cipher_alg); 187c1679171SEric Biggers crypto_unregister_skciphers(bf_skcipher_algs, 188c1679171SEric Biggers ARRAY_SIZE(bf_skcipher_algs)); 18964b94ceaSJussi Kivilinna } 19064b94ceaSJussi Kivilinna 191f16a005cSRandy Dunlap module_init(blowfish_init); 192f16a005cSRandy Dunlap module_exit(blowfish_fini); 19364b94ceaSJussi Kivilinna 19464b94ceaSJussi Kivilinna MODULE_LICENSE("GPL"); 19564b94ceaSJussi Kivilinna MODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized"); 1965d26a105SKees Cook MODULE_ALIAS_CRYPTO("blowfish"); 1975d26a105SKees Cook MODULE_ALIAS_CRYPTO("blowfish-asm"); 198