xref: /linux/arch/x86/crypto/twofish_glue_3way.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
28280daadSJussi Kivilinna /*
38280daadSJussi Kivilinna  * Glue Code for 3-way parallel assembler optimized version of Twofish
48280daadSJussi Kivilinna  *
58280daadSJussi Kivilinna  * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
68280daadSJussi Kivilinna  */
78280daadSJussi Kivilinna 
837992fa4SEric Biggers #include <asm/cpu_device_id.h>
937992fa4SEric Biggers #include <crypto/algapi.h>
108280daadSJussi Kivilinna #include <crypto/twofish.h>
118280daadSJussi Kivilinna #include <linux/crypto.h>
128280daadSJussi Kivilinna #include <linux/export.h>
138280daadSJussi Kivilinna #include <linux/init.h>
1481559f9aSJussi Kivilinna #include <linux/module.h>
15a04ea6f7SArd Biesheuvel #include <linux/types.h>
16165f3573SArd Biesheuvel 
17165f3573SArd Biesheuvel #include "twofish.h"
18107778b5SJohannes Goetzfried #include "ecb_cbc_helpers.h"
19107778b5SJohannes Goetzfried 
208280daadSJussi Kivilinna EXPORT_SYMBOL_GPL(__twofish_enc_blk_3way);
2137992fa4SEric Biggers EXPORT_SYMBOL_GPL(twofish_dec_blk_3way);
2237992fa4SEric Biggers 
twofish_setkey_skcipher(struct crypto_skcipher * tfm,const u8 * key,unsigned int keylen)2337992fa4SEric Biggers static int twofish_setkey_skcipher(struct crypto_skcipher *tfm,
2437992fa4SEric Biggers 				   const u8 *key, unsigned int keylen)
2537992fa4SEric Biggers {
2637992fa4SEric Biggers 	return twofish_setkey(&tfm->base, key, keylen);
279c1e8836SKees Cook }
288280daadSJussi Kivilinna 
twofish_enc_blk_3way(const void * ctx,u8 * dst,const u8 * src)298280daadSJussi Kivilinna static inline void twofish_enc_blk_3way(const void *ctx, u8 *dst, const u8 *src)
308280daadSJussi Kivilinna {
318280daadSJussi Kivilinna 	__twofish_enc_blk_3way(ctx, dst, src, false);
32165f3573SArd Biesheuvel }
338280daadSJussi Kivilinna 
twofish_dec_blk_cbc_3way(const void * ctx,u8 * dst,const u8 * src)34165f3573SArd Biesheuvel void twofish_dec_blk_cbc_3way(const void *ctx, u8 *dst, const u8 *src)
35165f3573SArd Biesheuvel {
368280daadSJussi Kivilinna 	u8 buf[2][TF_BLOCK_SIZE];
37165f3573SArd Biesheuvel 	const u8 *s = src;
38165f3573SArd Biesheuvel 
39165f3573SArd Biesheuvel 	if (dst == src)
40165f3573SArd Biesheuvel 		s = memcpy(buf, src, sizeof(buf));
418280daadSJussi Kivilinna 	twofish_dec_blk_3way(ctx, dst, src);
428280daadSJussi Kivilinna 	crypto_xor(dst + TF_BLOCK_SIZE, s, sizeof(buf));
43a7378d4eSJussi Kivilinna 
448280daadSJussi Kivilinna }
4537992fa4SEric Biggers EXPORT_SYMBOL_GPL(twofish_dec_blk_cbc_3way);
46414cb5e7SJussi Kivilinna 
ecb_encrypt(struct skcipher_request * req)47165f3573SArd Biesheuvel static int ecb_encrypt(struct skcipher_request *req)
48165f3573SArd Biesheuvel {
49165f3573SArd Biesheuvel 	ECB_WALK_START(req, TF_BLOCK_SIZE, -1);
50165f3573SArd Biesheuvel 	ECB_BLOCK(3, twofish_enc_blk_3way);
51414cb5e7SJussi Kivilinna 	ECB_BLOCK(1, twofish_enc_blk);
52414cb5e7SJussi Kivilinna 	ECB_WALK_END();
5337992fa4SEric Biggers }
54414cb5e7SJussi Kivilinna 
ecb_decrypt(struct skcipher_request * req)55165f3573SArd Biesheuvel static int ecb_decrypt(struct skcipher_request *req)
56165f3573SArd Biesheuvel {
57165f3573SArd Biesheuvel 	ECB_WALK_START(req, TF_BLOCK_SIZE, -1);
58165f3573SArd Biesheuvel 	ECB_BLOCK(3, twofish_dec_blk_3way);
59414cb5e7SJussi Kivilinna 	ECB_BLOCK(1, twofish_dec_blk);
60414cb5e7SJussi Kivilinna 	ECB_WALK_END();
6137992fa4SEric Biggers }
62414cb5e7SJussi Kivilinna 
cbc_encrypt(struct skcipher_request * req)63165f3573SArd Biesheuvel static int cbc_encrypt(struct skcipher_request *req)
64165f3573SArd Biesheuvel {
65165f3573SArd Biesheuvel 	CBC_WALK_START(req, TF_BLOCK_SIZE, -1);
66414cb5e7SJussi Kivilinna 	CBC_ENC_BLOCK(twofish_enc_blk);
67414cb5e7SJussi Kivilinna 	CBC_WALK_END();
6837992fa4SEric Biggers }
69414cb5e7SJussi Kivilinna 
cbc_decrypt(struct skcipher_request * req)70165f3573SArd Biesheuvel static int cbc_decrypt(struct skcipher_request *req)
71165f3573SArd Biesheuvel {
72165f3573SArd Biesheuvel 	CBC_WALK_START(req, TF_BLOCK_SIZE, -1);
73165f3573SArd Biesheuvel 	CBC_DEC_BLOCK(3, twofish_dec_blk_cbc_3way);
748280daadSJussi Kivilinna 	CBC_DEC_BLOCK(1, twofish_dec_blk);
758280daadSJussi Kivilinna 	CBC_WALK_END();
7637992fa4SEric Biggers }
7737992fa4SEric Biggers 
7837992fa4SEric Biggers static struct skcipher_alg tf_skciphers[] = {
7937992fa4SEric Biggers 	{
8037992fa4SEric Biggers 		.base.cra_name		= "ecb(twofish)",
8137992fa4SEric Biggers 		.base.cra_driver_name	= "ecb-twofish-3way",
8237992fa4SEric Biggers 		.base.cra_priority	= 300,
8337992fa4SEric Biggers 		.base.cra_blocksize	= TF_BLOCK_SIZE,
8453709ddeSJussi Kivilinna 		.base.cra_ctxsize	= sizeof(struct twofish_ctx),
8553709ddeSJussi Kivilinna 		.base.cra_module	= THIS_MODULE,
8637992fa4SEric Biggers 		.min_keysize		= TF_MIN_KEY_SIZE,
8753709ddeSJussi Kivilinna 		.max_keysize		= TF_MAX_KEY_SIZE,
8853709ddeSJussi Kivilinna 		.setkey			= twofish_setkey_skcipher,
8953709ddeSJussi Kivilinna 		.encrypt		= ecb_encrypt,
9037992fa4SEric Biggers 		.decrypt		= ecb_decrypt,
9137992fa4SEric Biggers 	}, {
9237992fa4SEric Biggers 		.base.cra_name		= "cbc(twofish)",
9337992fa4SEric Biggers 		.base.cra_driver_name	= "cbc-twofish-3way",
9437992fa4SEric Biggers 		.base.cra_priority	= 300,
9537992fa4SEric Biggers 		.base.cra_blocksize	= TF_BLOCK_SIZE,
9653709ddeSJussi Kivilinna 		.base.cra_ctxsize	= sizeof(struct twofish_ctx),
9753709ddeSJussi Kivilinna 		.base.cra_module	= THIS_MODULE,
9853709ddeSJussi Kivilinna 		.min_keysize		= TF_MIN_KEY_SIZE,
9937992fa4SEric Biggers 		.max_keysize		= TF_MAX_KEY_SIZE,
10053709ddeSJussi Kivilinna 		.ivsize			= TF_BLOCK_SIZE,
10153709ddeSJussi Kivilinna 		.setkey			= twofish_setkey_skcipher,
10253709ddeSJussi Kivilinna 		.encrypt		= cbc_encrypt,
10337992fa4SEric Biggers 		.decrypt		= cbc_decrypt,
104bae6d303SJussi Kivilinna 	},
105a522ee85SJussi Kivilinna };
106a522ee85SJussi Kivilinna 
is_blacklisted_cpu(void)107a522ee85SJussi Kivilinna static bool is_blacklisted_cpu(void)
108a522ee85SJussi Kivilinna {
109a522ee85SJussi Kivilinna 	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
110a522ee85SJussi Kivilinna 		return false;
111a522ee85SJussi Kivilinna 
112a522ee85SJussi Kivilinna 	switch (boot_cpu_data.x86_vfm) {
113a522ee85SJussi Kivilinna 	case INTEL_ATOM_BONNELL:
114a522ee85SJussi Kivilinna 	case INTEL_ATOM_BONNELL_MID:
115a522ee85SJussi Kivilinna 	case INTEL_ATOM_SALTWELL:
116a522ee85SJussi Kivilinna 		/*
117a522ee85SJussi Kivilinna 		 * On Atom, twofish-3way is slower than original assembler
118a522ee85SJussi Kivilinna 		 * implementation. Twofish-3way trades off some performance in
119a522ee85SJussi Kivilinna 		 * storing blocks in 64bit registers to allow three blocks to
120d9f6e12fSIngo Molnar 		 * be processed parallel. Parallel operation then allows gaining
121a522ee85SJussi Kivilinna 		 * more performance than was trade off, on out-of-order CPUs.
122a522ee85SJussi Kivilinna 		 * However Atom does not benefit from this parallelism and
123a522ee85SJussi Kivilinna 		 * should be blacklisted.
124a522ee85SJussi Kivilinna 		 */
125a522ee85SJussi Kivilinna 		return true;
126a522ee85SJussi Kivilinna 	}
127a522ee85SJussi Kivilinna 
128a522ee85SJussi Kivilinna 	if (boot_cpu_data.x86 == 0x0f) {
129a522ee85SJussi Kivilinna 		/*
130a522ee85SJussi Kivilinna 		 * On Pentium 4, twofish-3way is slower than original assembler
131a522ee85SJussi Kivilinna 		 * implementation because excessive uses of 64bit rotate and
132a522ee85SJussi Kivilinna 		 * left-shifts (which are really slow on P4) needed to store and
133a522ee85SJussi Kivilinna 		 * handle 128bit block in two 64bit registers.
134a522ee85SJussi Kivilinna 		 */
135a522ee85SJussi Kivilinna 		return true;
136a522ee85SJussi Kivilinna 	}
137a522ee85SJussi Kivilinna 
138a522ee85SJussi Kivilinna 	return false;
139a522ee85SJussi Kivilinna }
140a522ee85SJussi Kivilinna 
141a522ee85SJussi Kivilinna static int force;
142a522ee85SJussi Kivilinna module_param(force, int, 0);
143*f16a005cSRandy Dunlap MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
1448280daadSJussi Kivilinna 
twofish_3way_init(void)145a522ee85SJussi Kivilinna static int __init twofish_3way_init(void)
146a522ee85SJussi Kivilinna {
147a522ee85SJussi Kivilinna 	if (!force && is_blacklisted_cpu()) {
148a522ee85SJussi Kivilinna 		printk(KERN_INFO
149a522ee85SJussi Kivilinna 			"twofish-x86_64-3way: performance on this CPU "
150a522ee85SJussi Kivilinna 			"would be suboptimal: disabling "
151a522ee85SJussi Kivilinna 			"twofish-x86_64-3way.\n");
152a522ee85SJussi Kivilinna 		return -ENODEV;
15337992fa4SEric Biggers 	}
15437992fa4SEric Biggers 
1558280daadSJussi Kivilinna 	return crypto_register_skciphers(tf_skciphers,
1568280daadSJussi Kivilinna 					 ARRAY_SIZE(tf_skciphers));
157*f16a005cSRandy Dunlap }
1588280daadSJussi Kivilinna 
twofish_3way_fini(void)15937992fa4SEric Biggers static void __exit twofish_3way_fini(void)
1608280daadSJussi Kivilinna {
1618280daadSJussi Kivilinna 	crypto_unregister_skciphers(tf_skciphers, ARRAY_SIZE(tf_skciphers));
162*f16a005cSRandy Dunlap }
163*f16a005cSRandy Dunlap 
1648280daadSJussi Kivilinna module_init(twofish_3way_init);
1658280daadSJussi Kivilinna module_exit(twofish_3way_fini);
1668280daadSJussi Kivilinna 
1675d26a105SKees Cook MODULE_LICENSE("GPL");
1685d26a105SKees Cook MODULE_DESCRIPTION("Twofish Cipher Algorithm, 3-way parallel asm optimized");
169 MODULE_ALIAS_CRYPTO("twofish");
170 MODULE_ALIAS_CRYPTO("twofish-asm");
171