0001
0002
0003
0004
0005
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
0116
0117
0118
0119
0120
0121
0122
0123 return true;
0124 }
0125
0126 if (boot_cpu_data.x86 == 0x0f) {
0127
0128
0129
0130
0131
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");