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