xref: /openbmc/linux/arch/x86/crypto/blowfish_glue.c (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
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 
blowfish_dec_ecb_4way(struct bf_ctx * ctx,u8 * dst,const u8 * src)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 
blowfish_dec_cbc_4way(struct bf_ctx * ctx,u8 * dst,const u8 * src)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 
blowfish_encrypt(struct crypto_tfm * tfm,u8 * dst,const u8 * src)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 
blowfish_decrypt(struct crypto_tfm * tfm,u8 * dst,const u8 * src)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 
blowfish_setkey_skcipher(struct crypto_skcipher * tfm,const u8 * key,unsigned int keylen)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 
ecb_encrypt(struct skcipher_request * req)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 
ecb_decrypt(struct skcipher_request * req)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 
cbc_encrypt(struct skcipher_request * req)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 
cbc_decrypt(struct skcipher_request * req)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 
is_blacklisted_cpu(void)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 
blowfish_init(void)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 
blowfish_fini(void)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