Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Glue Code for 3-way parallel assembler optimized version of Twofish
0004  *
0005  * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
0006  */
0007 
0008 #include <crypto/algapi.h>
0009 #include <crypto/twofish.h>
0010 #include <linux/crypto.h>
0011 #include <linux/init.h>
0012 #include <linux/module.h>
0013 #include <linux/types.h>
0014 
0015 #include "twofish.h"
0016 #include "ecb_cbc_helpers.h"
0017 
0018 EXPORT_SYMBOL_GPL(__twofish_enc_blk_3way);
0019 EXPORT_SYMBOL_GPL(twofish_dec_blk_3way);
0020 
0021 static int twofish_setkey_skcipher(struct crypto_skcipher *tfm,
0022                    const u8 *key, unsigned int keylen)
0023 {
0024     return twofish_setkey(&tfm->base, key, keylen);
0025 }
0026 
0027 static inline void twofish_enc_blk_3way(const void *ctx, u8 *dst, const u8 *src)
0028 {
0029     __twofish_enc_blk_3way(ctx, dst, src, false);
0030 }
0031 
0032 void twofish_dec_blk_cbc_3way(const void *ctx, u8 *dst, const u8 *src)
0033 {
0034     u8 buf[2][TF_BLOCK_SIZE];
0035     const u8 *s = src;
0036 
0037     if (dst == src)
0038         s = memcpy(buf, src, sizeof(buf));
0039     twofish_dec_blk_3way(ctx, dst, src);
0040     crypto_xor(dst + TF_BLOCK_SIZE, s, sizeof(buf));
0041 
0042 }
0043 EXPORT_SYMBOL_GPL(twofish_dec_blk_cbc_3way);
0044 
0045 static int ecb_encrypt(struct skcipher_request *req)
0046 {
0047     ECB_WALK_START(req, TF_BLOCK_SIZE, -1);
0048     ECB_BLOCK(3, twofish_enc_blk_3way);
0049     ECB_BLOCK(1, twofish_enc_blk);
0050     ECB_WALK_END();
0051 }
0052 
0053 static int ecb_decrypt(struct skcipher_request *req)
0054 {
0055     ECB_WALK_START(req, TF_BLOCK_SIZE, -1);
0056     ECB_BLOCK(3, twofish_dec_blk_3way);
0057     ECB_BLOCK(1, twofish_dec_blk);
0058     ECB_WALK_END();
0059 }
0060 
0061 static int cbc_encrypt(struct skcipher_request *req)
0062 {
0063     CBC_WALK_START(req, TF_BLOCK_SIZE, -1);
0064     CBC_ENC_BLOCK(twofish_enc_blk);
0065     CBC_WALK_END();
0066 }
0067 
0068 static int cbc_decrypt(struct skcipher_request *req)
0069 {
0070     CBC_WALK_START(req, TF_BLOCK_SIZE, -1);
0071     CBC_DEC_BLOCK(3, twofish_dec_blk_cbc_3way);
0072     CBC_DEC_BLOCK(1, twofish_dec_blk);
0073     CBC_WALK_END();
0074 }
0075 
0076 static struct skcipher_alg tf_skciphers[] = {
0077     {
0078         .base.cra_name      = "ecb(twofish)",
0079         .base.cra_driver_name   = "ecb-twofish-3way",
0080         .base.cra_priority  = 300,
0081         .base.cra_blocksize = TF_BLOCK_SIZE,
0082         .base.cra_ctxsize   = sizeof(struct twofish_ctx),
0083         .base.cra_module    = THIS_MODULE,
0084         .min_keysize        = TF_MIN_KEY_SIZE,
0085         .max_keysize        = TF_MAX_KEY_SIZE,
0086         .setkey         = twofish_setkey_skcipher,
0087         .encrypt        = ecb_encrypt,
0088         .decrypt        = ecb_decrypt,
0089     }, {
0090         .base.cra_name      = "cbc(twofish)",
0091         .base.cra_driver_name   = "cbc-twofish-3way",
0092         .base.cra_priority  = 300,
0093         .base.cra_blocksize = TF_BLOCK_SIZE,
0094         .base.cra_ctxsize   = sizeof(struct twofish_ctx),
0095         .base.cra_module    = THIS_MODULE,
0096         .min_keysize        = TF_MIN_KEY_SIZE,
0097         .max_keysize        = TF_MAX_KEY_SIZE,
0098         .ivsize         = TF_BLOCK_SIZE,
0099         .setkey         = twofish_setkey_skcipher,
0100         .encrypt        = cbc_encrypt,
0101         .decrypt        = cbc_decrypt,
0102     },
0103 };
0104 
0105 static bool is_blacklisted_cpu(void)
0106 {
0107     if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
0108         return false;
0109 
0110     if (boot_cpu_data.x86 == 0x06 &&
0111         (boot_cpu_data.x86_model == 0x1c ||
0112          boot_cpu_data.x86_model == 0x26 ||
0113          boot_cpu_data.x86_model == 0x36)) {
0114         /*
0115          * On Atom, twofish-3way is slower than original assembler
0116          * implementation. Twofish-3way trades off some performance in
0117          * storing blocks in 64bit registers to allow three blocks to
0118          * be processed parallel. Parallel operation then allows gaining
0119          * more performance than was trade off, on out-of-order CPUs.
0120          * However Atom does not benefit from this parallelism and
0121          * should be blacklisted.
0122          */
0123         return true;
0124     }
0125 
0126     if (boot_cpu_data.x86 == 0x0f) {
0127         /*
0128          * On Pentium 4, twofish-3way is slower than original assembler
0129          * implementation because excessive uses of 64bit rotate and
0130          * left-shifts (which are really slow on P4) needed to store and
0131          * handle 128bit block in two 64bit registers.
0132          */
0133         return true;
0134     }
0135 
0136     return false;
0137 }
0138 
0139 static int force;
0140 module_param(force, int, 0);
0141 MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
0142 
0143 static int __init twofish_3way_init(void)
0144 {
0145     if (!force && is_blacklisted_cpu()) {
0146         printk(KERN_INFO
0147             "twofish-x86_64-3way: performance on this CPU "
0148             "would be suboptimal: disabling "
0149             "twofish-x86_64-3way.\n");
0150         return -ENODEV;
0151     }
0152 
0153     return crypto_register_skciphers(tf_skciphers,
0154                      ARRAY_SIZE(tf_skciphers));
0155 }
0156 
0157 static void __exit twofish_3way_fini(void)
0158 {
0159     crypto_unregister_skciphers(tf_skciphers, ARRAY_SIZE(tf_skciphers));
0160 }
0161 
0162 module_init(twofish_3way_init);
0163 module_exit(twofish_3way_fini);
0164 
0165 MODULE_LICENSE("GPL");
0166 MODULE_DESCRIPTION("Twofish Cipher Algorithm, 3-way parallel asm optimized");
0167 MODULE_ALIAS_CRYPTO("twofish");
0168 MODULE_ALIAS_CRYPTO("twofish-asm");