1*64b94ceaSJussi Kivilinna /* 2*64b94ceaSJussi Kivilinna * Glue Code for assembler optimized version of Blowfish 3*64b94ceaSJussi Kivilinna * 4*64b94ceaSJussi Kivilinna * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 5*64b94ceaSJussi Kivilinna * 6*64b94ceaSJussi Kivilinna * This program is free software; you can redistribute it and/or modify 7*64b94ceaSJussi Kivilinna * it under the terms of the GNU General Public License as published by 8*64b94ceaSJussi Kivilinna * the Free Software Foundation; either version 2 of the License, or 9*64b94ceaSJussi Kivilinna * (at your option) any later version. 10*64b94ceaSJussi Kivilinna * 11*64b94ceaSJussi Kivilinna * This program is distributed in the hope that it will be useful, 12*64b94ceaSJussi Kivilinna * but WITHOUT ANY WARRANTY; without even the implied warranty of 13*64b94ceaSJussi Kivilinna * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14*64b94ceaSJussi Kivilinna * GNU General Public License for more details. 15*64b94ceaSJussi Kivilinna * 16*64b94ceaSJussi Kivilinna * You should have received a copy of the GNU General Public License 17*64b94ceaSJussi Kivilinna * along with this program; if not, write to the Free Software 18*64b94ceaSJussi Kivilinna * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 19*64b94ceaSJussi Kivilinna * USA 20*64b94ceaSJussi Kivilinna * 21*64b94ceaSJussi Kivilinna */ 22*64b94ceaSJussi Kivilinna 23*64b94ceaSJussi Kivilinna #include <crypto/blowfish.h> 24*64b94ceaSJussi Kivilinna #include <linux/crypto.h> 25*64b94ceaSJussi Kivilinna #include <linux/init.h> 26*64b94ceaSJussi Kivilinna #include <linux/module.h> 27*64b94ceaSJussi Kivilinna #include <linux/types.h> 28*64b94ceaSJussi Kivilinna #include <crypto/algapi.h> 29*64b94ceaSJussi Kivilinna 30*64b94ceaSJussi Kivilinna /* regular block cipher functions */ 31*64b94ceaSJussi Kivilinna asmlinkage void __blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src, 32*64b94ceaSJussi Kivilinna bool xor); 33*64b94ceaSJussi Kivilinna asmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src); 34*64b94ceaSJussi Kivilinna 35*64b94ceaSJussi Kivilinna /* 4-way parallel cipher functions */ 36*64b94ceaSJussi Kivilinna asmlinkage void __blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst, 37*64b94ceaSJussi Kivilinna const u8 *src, bool xor); 38*64b94ceaSJussi Kivilinna asmlinkage void blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst, 39*64b94ceaSJussi Kivilinna const u8 *src); 40*64b94ceaSJussi Kivilinna 41*64b94ceaSJussi Kivilinna static inline void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src) 42*64b94ceaSJussi Kivilinna { 43*64b94ceaSJussi Kivilinna __blowfish_enc_blk(ctx, dst, src, false); 44*64b94ceaSJussi Kivilinna } 45*64b94ceaSJussi Kivilinna 46*64b94ceaSJussi Kivilinna static inline void blowfish_enc_blk_xor(struct bf_ctx *ctx, u8 *dst, 47*64b94ceaSJussi Kivilinna const u8 *src) 48*64b94ceaSJussi Kivilinna { 49*64b94ceaSJussi Kivilinna __blowfish_enc_blk(ctx, dst, src, true); 50*64b94ceaSJussi Kivilinna } 51*64b94ceaSJussi Kivilinna 52*64b94ceaSJussi Kivilinna static inline void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst, 53*64b94ceaSJussi Kivilinna const u8 *src) 54*64b94ceaSJussi Kivilinna { 55*64b94ceaSJussi Kivilinna __blowfish_enc_blk_4way(ctx, dst, src, false); 56*64b94ceaSJussi Kivilinna } 57*64b94ceaSJussi Kivilinna 58*64b94ceaSJussi Kivilinna static inline void blowfish_enc_blk_xor_4way(struct bf_ctx *ctx, u8 *dst, 59*64b94ceaSJussi Kivilinna const u8 *src) 60*64b94ceaSJussi Kivilinna { 61*64b94ceaSJussi Kivilinna __blowfish_enc_blk_4way(ctx, dst, src, true); 62*64b94ceaSJussi Kivilinna } 63*64b94ceaSJussi Kivilinna 64*64b94ceaSJussi Kivilinna static void blowfish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 65*64b94ceaSJussi Kivilinna { 66*64b94ceaSJussi Kivilinna blowfish_enc_blk(crypto_tfm_ctx(tfm), dst, src); 67*64b94ceaSJussi Kivilinna } 68*64b94ceaSJussi Kivilinna 69*64b94ceaSJussi Kivilinna static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 70*64b94ceaSJussi Kivilinna { 71*64b94ceaSJussi Kivilinna blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src); 72*64b94ceaSJussi Kivilinna } 73*64b94ceaSJussi Kivilinna 74*64b94ceaSJussi Kivilinna static struct crypto_alg bf_alg = { 75*64b94ceaSJussi Kivilinna .cra_name = "blowfish", 76*64b94ceaSJussi Kivilinna .cra_driver_name = "blowfish-asm", 77*64b94ceaSJussi Kivilinna .cra_priority = 200, 78*64b94ceaSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 79*64b94ceaSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 80*64b94ceaSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 81*64b94ceaSJussi Kivilinna .cra_alignmask = 3, 82*64b94ceaSJussi Kivilinna .cra_module = THIS_MODULE, 83*64b94ceaSJussi Kivilinna .cra_list = LIST_HEAD_INIT(bf_alg.cra_list), 84*64b94ceaSJussi Kivilinna .cra_u = { 85*64b94ceaSJussi Kivilinna .cipher = { 86*64b94ceaSJussi Kivilinna .cia_min_keysize = BF_MIN_KEY_SIZE, 87*64b94ceaSJussi Kivilinna .cia_max_keysize = BF_MAX_KEY_SIZE, 88*64b94ceaSJussi Kivilinna .cia_setkey = blowfish_setkey, 89*64b94ceaSJussi Kivilinna .cia_encrypt = blowfish_encrypt, 90*64b94ceaSJussi Kivilinna .cia_decrypt = blowfish_decrypt, 91*64b94ceaSJussi Kivilinna } 92*64b94ceaSJussi Kivilinna } 93*64b94ceaSJussi Kivilinna }; 94*64b94ceaSJussi Kivilinna 95*64b94ceaSJussi Kivilinna static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, 96*64b94ceaSJussi Kivilinna void (*fn)(struct bf_ctx *, u8 *, const u8 *), 97*64b94ceaSJussi Kivilinna void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *)) 98*64b94ceaSJussi Kivilinna { 99*64b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 100*64b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 101*64b94ceaSJussi Kivilinna unsigned int nbytes; 102*64b94ceaSJussi Kivilinna int err; 103*64b94ceaSJussi Kivilinna 104*64b94ceaSJussi Kivilinna err = blkcipher_walk_virt(desc, walk); 105*64b94ceaSJussi Kivilinna 106*64b94ceaSJussi Kivilinna while ((nbytes = walk->nbytes)) { 107*64b94ceaSJussi Kivilinna u8 *wsrc = walk->src.virt.addr; 108*64b94ceaSJussi Kivilinna u8 *wdst = walk->dst.virt.addr; 109*64b94ceaSJussi Kivilinna 110*64b94ceaSJussi Kivilinna /* Process four block batch */ 111*64b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 112*64b94ceaSJussi Kivilinna do { 113*64b94ceaSJussi Kivilinna fn_4way(ctx, wdst, wsrc); 114*64b94ceaSJussi Kivilinna 115*64b94ceaSJussi Kivilinna wsrc += bsize * 4; 116*64b94ceaSJussi Kivilinna wdst += bsize * 4; 117*64b94ceaSJussi Kivilinna nbytes -= bsize * 4; 118*64b94ceaSJussi Kivilinna } while (nbytes >= bsize * 4); 119*64b94ceaSJussi Kivilinna 120*64b94ceaSJussi Kivilinna if (nbytes < bsize) 121*64b94ceaSJussi Kivilinna goto done; 122*64b94ceaSJussi Kivilinna } 123*64b94ceaSJussi Kivilinna 124*64b94ceaSJussi Kivilinna /* Handle leftovers */ 125*64b94ceaSJussi Kivilinna do { 126*64b94ceaSJussi Kivilinna fn(ctx, wdst, wsrc); 127*64b94ceaSJussi Kivilinna 128*64b94ceaSJussi Kivilinna wsrc += bsize; 129*64b94ceaSJussi Kivilinna wdst += bsize; 130*64b94ceaSJussi Kivilinna nbytes -= bsize; 131*64b94ceaSJussi Kivilinna } while (nbytes >= bsize); 132*64b94ceaSJussi Kivilinna 133*64b94ceaSJussi Kivilinna done: 134*64b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, walk, nbytes); 135*64b94ceaSJussi Kivilinna } 136*64b94ceaSJussi Kivilinna 137*64b94ceaSJussi Kivilinna return err; 138*64b94ceaSJussi Kivilinna } 139*64b94ceaSJussi Kivilinna 140*64b94ceaSJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 141*64b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 142*64b94ceaSJussi Kivilinna { 143*64b94ceaSJussi Kivilinna struct blkcipher_walk walk; 144*64b94ceaSJussi Kivilinna 145*64b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 146*64b94ceaSJussi Kivilinna return ecb_crypt(desc, &walk, blowfish_enc_blk, blowfish_enc_blk_4way); 147*64b94ceaSJussi Kivilinna } 148*64b94ceaSJussi Kivilinna 149*64b94ceaSJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 150*64b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 151*64b94ceaSJussi Kivilinna { 152*64b94ceaSJussi Kivilinna struct blkcipher_walk walk; 153*64b94ceaSJussi Kivilinna 154*64b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 155*64b94ceaSJussi Kivilinna return ecb_crypt(desc, &walk, blowfish_dec_blk, blowfish_dec_blk_4way); 156*64b94ceaSJussi Kivilinna } 157*64b94ceaSJussi Kivilinna 158*64b94ceaSJussi Kivilinna static struct crypto_alg blk_ecb_alg = { 159*64b94ceaSJussi Kivilinna .cra_name = "ecb(blowfish)", 160*64b94ceaSJussi Kivilinna .cra_driver_name = "ecb-blowfish-asm", 161*64b94ceaSJussi Kivilinna .cra_priority = 300, 162*64b94ceaSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 163*64b94ceaSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 164*64b94ceaSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 165*64b94ceaSJussi Kivilinna .cra_alignmask = 0, 166*64b94ceaSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 167*64b94ceaSJussi Kivilinna .cra_module = THIS_MODULE, 168*64b94ceaSJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), 169*64b94ceaSJussi Kivilinna .cra_u = { 170*64b94ceaSJussi Kivilinna .blkcipher = { 171*64b94ceaSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 172*64b94ceaSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 173*64b94ceaSJussi Kivilinna .setkey = blowfish_setkey, 174*64b94ceaSJussi Kivilinna .encrypt = ecb_encrypt, 175*64b94ceaSJussi Kivilinna .decrypt = ecb_decrypt, 176*64b94ceaSJussi Kivilinna }, 177*64b94ceaSJussi Kivilinna }, 178*64b94ceaSJussi Kivilinna }; 179*64b94ceaSJussi Kivilinna 180*64b94ceaSJussi Kivilinna static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, 181*64b94ceaSJussi Kivilinna struct blkcipher_walk *walk) 182*64b94ceaSJussi Kivilinna { 183*64b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 184*64b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 185*64b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 186*64b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 187*64b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 188*64b94ceaSJussi Kivilinna u64 *iv = (u64 *)walk->iv; 189*64b94ceaSJussi Kivilinna 190*64b94ceaSJussi Kivilinna do { 191*64b94ceaSJussi Kivilinna *dst = *src ^ *iv; 192*64b94ceaSJussi Kivilinna blowfish_enc_blk(ctx, (u8 *)dst, (u8 *)dst); 193*64b94ceaSJussi Kivilinna iv = dst; 194*64b94ceaSJussi Kivilinna 195*64b94ceaSJussi Kivilinna src += 1; 196*64b94ceaSJussi Kivilinna dst += 1; 197*64b94ceaSJussi Kivilinna nbytes -= bsize; 198*64b94ceaSJussi Kivilinna } while (nbytes >= bsize); 199*64b94ceaSJussi Kivilinna 200*64b94ceaSJussi Kivilinna *(u64 *)walk->iv = *iv; 201*64b94ceaSJussi Kivilinna return nbytes; 202*64b94ceaSJussi Kivilinna } 203*64b94ceaSJussi Kivilinna 204*64b94ceaSJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 205*64b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 206*64b94ceaSJussi Kivilinna { 207*64b94ceaSJussi Kivilinna struct blkcipher_walk walk; 208*64b94ceaSJussi Kivilinna int err; 209*64b94ceaSJussi Kivilinna 210*64b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 211*64b94ceaSJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 212*64b94ceaSJussi Kivilinna 213*64b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes)) { 214*64b94ceaSJussi Kivilinna nbytes = __cbc_encrypt(desc, &walk); 215*64b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 216*64b94ceaSJussi Kivilinna } 217*64b94ceaSJussi Kivilinna 218*64b94ceaSJussi Kivilinna return err; 219*64b94ceaSJussi Kivilinna } 220*64b94ceaSJussi Kivilinna 221*64b94ceaSJussi Kivilinna static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, 222*64b94ceaSJussi Kivilinna struct blkcipher_walk *walk) 223*64b94ceaSJussi Kivilinna { 224*64b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 225*64b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 226*64b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 227*64b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 228*64b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 229*64b94ceaSJussi Kivilinna u64 ivs[4 - 1]; 230*64b94ceaSJussi Kivilinna u64 last_iv; 231*64b94ceaSJussi Kivilinna 232*64b94ceaSJussi Kivilinna /* Start of the last block. */ 233*64b94ceaSJussi Kivilinna src += nbytes / bsize - 1; 234*64b94ceaSJussi Kivilinna dst += nbytes / bsize - 1; 235*64b94ceaSJussi Kivilinna 236*64b94ceaSJussi Kivilinna last_iv = *src; 237*64b94ceaSJussi Kivilinna 238*64b94ceaSJussi Kivilinna /* Process four block batch */ 239*64b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 240*64b94ceaSJussi Kivilinna do { 241*64b94ceaSJussi Kivilinna nbytes -= bsize * 4 - bsize; 242*64b94ceaSJussi Kivilinna src -= 4 - 1; 243*64b94ceaSJussi Kivilinna dst -= 4 - 1; 244*64b94ceaSJussi Kivilinna 245*64b94ceaSJussi Kivilinna ivs[0] = src[0]; 246*64b94ceaSJussi Kivilinna ivs[1] = src[1]; 247*64b94ceaSJussi Kivilinna ivs[2] = src[2]; 248*64b94ceaSJussi Kivilinna 249*64b94ceaSJussi Kivilinna blowfish_dec_blk_4way(ctx, (u8 *)dst, (u8 *)src); 250*64b94ceaSJussi Kivilinna 251*64b94ceaSJussi Kivilinna dst[1] ^= ivs[0]; 252*64b94ceaSJussi Kivilinna dst[2] ^= ivs[1]; 253*64b94ceaSJussi Kivilinna dst[3] ^= ivs[2]; 254*64b94ceaSJussi Kivilinna 255*64b94ceaSJussi Kivilinna nbytes -= bsize; 256*64b94ceaSJussi Kivilinna if (nbytes < bsize) 257*64b94ceaSJussi Kivilinna goto done; 258*64b94ceaSJussi Kivilinna 259*64b94ceaSJussi Kivilinna *dst ^= *(src - 1); 260*64b94ceaSJussi Kivilinna src -= 1; 261*64b94ceaSJussi Kivilinna dst -= 1; 262*64b94ceaSJussi Kivilinna } while (nbytes >= bsize * 4); 263*64b94ceaSJussi Kivilinna 264*64b94ceaSJussi Kivilinna if (nbytes < bsize) 265*64b94ceaSJussi Kivilinna goto done; 266*64b94ceaSJussi Kivilinna } 267*64b94ceaSJussi Kivilinna 268*64b94ceaSJussi Kivilinna /* Handle leftovers */ 269*64b94ceaSJussi Kivilinna for (;;) { 270*64b94ceaSJussi Kivilinna blowfish_dec_blk(ctx, (u8 *)dst, (u8 *)src); 271*64b94ceaSJussi Kivilinna 272*64b94ceaSJussi Kivilinna nbytes -= bsize; 273*64b94ceaSJussi Kivilinna if (nbytes < bsize) 274*64b94ceaSJussi Kivilinna break; 275*64b94ceaSJussi Kivilinna 276*64b94ceaSJussi Kivilinna *dst ^= *(src - 1); 277*64b94ceaSJussi Kivilinna src -= 1; 278*64b94ceaSJussi Kivilinna dst -= 1; 279*64b94ceaSJussi Kivilinna } 280*64b94ceaSJussi Kivilinna 281*64b94ceaSJussi Kivilinna done: 282*64b94ceaSJussi Kivilinna *dst ^= *(u64 *)walk->iv; 283*64b94ceaSJussi Kivilinna *(u64 *)walk->iv = last_iv; 284*64b94ceaSJussi Kivilinna 285*64b94ceaSJussi Kivilinna return nbytes; 286*64b94ceaSJussi Kivilinna } 287*64b94ceaSJussi Kivilinna 288*64b94ceaSJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 289*64b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 290*64b94ceaSJussi Kivilinna { 291*64b94ceaSJussi Kivilinna struct blkcipher_walk walk; 292*64b94ceaSJussi Kivilinna int err; 293*64b94ceaSJussi Kivilinna 294*64b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 295*64b94ceaSJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 296*64b94ceaSJussi Kivilinna 297*64b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes)) { 298*64b94ceaSJussi Kivilinna nbytes = __cbc_decrypt(desc, &walk); 299*64b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 300*64b94ceaSJussi Kivilinna } 301*64b94ceaSJussi Kivilinna 302*64b94ceaSJussi Kivilinna return err; 303*64b94ceaSJussi Kivilinna } 304*64b94ceaSJussi Kivilinna 305*64b94ceaSJussi Kivilinna static struct crypto_alg blk_cbc_alg = { 306*64b94ceaSJussi Kivilinna .cra_name = "cbc(blowfish)", 307*64b94ceaSJussi Kivilinna .cra_driver_name = "cbc-blowfish-asm", 308*64b94ceaSJussi Kivilinna .cra_priority = 300, 309*64b94ceaSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 310*64b94ceaSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 311*64b94ceaSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 312*64b94ceaSJussi Kivilinna .cra_alignmask = 0, 313*64b94ceaSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 314*64b94ceaSJussi Kivilinna .cra_module = THIS_MODULE, 315*64b94ceaSJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), 316*64b94ceaSJussi Kivilinna .cra_u = { 317*64b94ceaSJussi Kivilinna .blkcipher = { 318*64b94ceaSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 319*64b94ceaSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 320*64b94ceaSJussi Kivilinna .ivsize = BF_BLOCK_SIZE, 321*64b94ceaSJussi Kivilinna .setkey = blowfish_setkey, 322*64b94ceaSJussi Kivilinna .encrypt = cbc_encrypt, 323*64b94ceaSJussi Kivilinna .decrypt = cbc_decrypt, 324*64b94ceaSJussi Kivilinna }, 325*64b94ceaSJussi Kivilinna }, 326*64b94ceaSJussi Kivilinna }; 327*64b94ceaSJussi Kivilinna 328*64b94ceaSJussi Kivilinna static void ctr_crypt_final(struct bf_ctx *ctx, struct blkcipher_walk *walk) 329*64b94ceaSJussi Kivilinna { 330*64b94ceaSJussi Kivilinna u8 *ctrblk = walk->iv; 331*64b94ceaSJussi Kivilinna u8 keystream[BF_BLOCK_SIZE]; 332*64b94ceaSJussi Kivilinna u8 *src = walk->src.virt.addr; 333*64b94ceaSJussi Kivilinna u8 *dst = walk->dst.virt.addr; 334*64b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 335*64b94ceaSJussi Kivilinna 336*64b94ceaSJussi Kivilinna blowfish_enc_blk(ctx, keystream, ctrblk); 337*64b94ceaSJussi Kivilinna crypto_xor(keystream, src, nbytes); 338*64b94ceaSJussi Kivilinna memcpy(dst, keystream, nbytes); 339*64b94ceaSJussi Kivilinna 340*64b94ceaSJussi Kivilinna crypto_inc(ctrblk, BF_BLOCK_SIZE); 341*64b94ceaSJussi Kivilinna } 342*64b94ceaSJussi Kivilinna 343*64b94ceaSJussi Kivilinna static unsigned int __ctr_crypt(struct blkcipher_desc *desc, 344*64b94ceaSJussi Kivilinna struct blkcipher_walk *walk) 345*64b94ceaSJussi Kivilinna { 346*64b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 347*64b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 348*64b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 349*64b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 350*64b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 351*64b94ceaSJussi Kivilinna u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv); 352*64b94ceaSJussi Kivilinna __be64 ctrblocks[4]; 353*64b94ceaSJussi Kivilinna 354*64b94ceaSJussi Kivilinna /* Process four block batch */ 355*64b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 356*64b94ceaSJussi Kivilinna do { 357*64b94ceaSJussi Kivilinna if (dst != src) { 358*64b94ceaSJussi Kivilinna dst[0] = src[0]; 359*64b94ceaSJussi Kivilinna dst[1] = src[1]; 360*64b94ceaSJussi Kivilinna dst[2] = src[2]; 361*64b94ceaSJussi Kivilinna dst[3] = src[3]; 362*64b94ceaSJussi Kivilinna } 363*64b94ceaSJussi Kivilinna 364*64b94ceaSJussi Kivilinna /* create ctrblks for parallel encrypt */ 365*64b94ceaSJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 366*64b94ceaSJussi Kivilinna ctrblocks[1] = cpu_to_be64(ctrblk++); 367*64b94ceaSJussi Kivilinna ctrblocks[2] = cpu_to_be64(ctrblk++); 368*64b94ceaSJussi Kivilinna ctrblocks[3] = cpu_to_be64(ctrblk++); 369*64b94ceaSJussi Kivilinna 370*64b94ceaSJussi Kivilinna blowfish_enc_blk_xor_4way(ctx, (u8 *)dst, 371*64b94ceaSJussi Kivilinna (u8 *)ctrblocks); 372*64b94ceaSJussi Kivilinna 373*64b94ceaSJussi Kivilinna src += 4; 374*64b94ceaSJussi Kivilinna dst += 4; 375*64b94ceaSJussi Kivilinna } while ((nbytes -= bsize * 4) >= bsize * 4); 376*64b94ceaSJussi Kivilinna 377*64b94ceaSJussi Kivilinna if (nbytes < bsize) 378*64b94ceaSJussi Kivilinna goto done; 379*64b94ceaSJussi Kivilinna } 380*64b94ceaSJussi Kivilinna 381*64b94ceaSJussi Kivilinna /* Handle leftovers */ 382*64b94ceaSJussi Kivilinna do { 383*64b94ceaSJussi Kivilinna if (dst != src) 384*64b94ceaSJussi Kivilinna *dst = *src; 385*64b94ceaSJussi Kivilinna 386*64b94ceaSJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 387*64b94ceaSJussi Kivilinna 388*64b94ceaSJussi Kivilinna blowfish_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks); 389*64b94ceaSJussi Kivilinna 390*64b94ceaSJussi Kivilinna src += 1; 391*64b94ceaSJussi Kivilinna dst += 1; 392*64b94ceaSJussi Kivilinna } while ((nbytes -= bsize) >= bsize); 393*64b94ceaSJussi Kivilinna 394*64b94ceaSJussi Kivilinna done: 395*64b94ceaSJussi Kivilinna *(__be64 *)walk->iv = cpu_to_be64(ctrblk); 396*64b94ceaSJussi Kivilinna return nbytes; 397*64b94ceaSJussi Kivilinna } 398*64b94ceaSJussi Kivilinna 399*64b94ceaSJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, 400*64b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 401*64b94ceaSJussi Kivilinna { 402*64b94ceaSJussi Kivilinna struct blkcipher_walk walk; 403*64b94ceaSJussi Kivilinna int err; 404*64b94ceaSJussi Kivilinna 405*64b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 406*64b94ceaSJussi Kivilinna err = blkcipher_walk_virt_block(desc, &walk, BF_BLOCK_SIZE); 407*64b94ceaSJussi Kivilinna 408*64b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes) >= BF_BLOCK_SIZE) { 409*64b94ceaSJussi Kivilinna nbytes = __ctr_crypt(desc, &walk); 410*64b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 411*64b94ceaSJussi Kivilinna } 412*64b94ceaSJussi Kivilinna 413*64b94ceaSJussi Kivilinna if (walk.nbytes) { 414*64b94ceaSJussi Kivilinna ctr_crypt_final(crypto_blkcipher_ctx(desc->tfm), &walk); 415*64b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, 0); 416*64b94ceaSJussi Kivilinna } 417*64b94ceaSJussi Kivilinna 418*64b94ceaSJussi Kivilinna return err; 419*64b94ceaSJussi Kivilinna } 420*64b94ceaSJussi Kivilinna 421*64b94ceaSJussi Kivilinna static struct crypto_alg blk_ctr_alg = { 422*64b94ceaSJussi Kivilinna .cra_name = "ctr(blowfish)", 423*64b94ceaSJussi Kivilinna .cra_driver_name = "ctr-blowfish-asm", 424*64b94ceaSJussi Kivilinna .cra_priority = 300, 425*64b94ceaSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 426*64b94ceaSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 427*64b94ceaSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 428*64b94ceaSJussi Kivilinna .cra_alignmask = 0, 429*64b94ceaSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 430*64b94ceaSJussi Kivilinna .cra_module = THIS_MODULE, 431*64b94ceaSJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), 432*64b94ceaSJussi Kivilinna .cra_u = { 433*64b94ceaSJussi Kivilinna .blkcipher = { 434*64b94ceaSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 435*64b94ceaSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 436*64b94ceaSJussi Kivilinna .ivsize = BF_BLOCK_SIZE, 437*64b94ceaSJussi Kivilinna .setkey = blowfish_setkey, 438*64b94ceaSJussi Kivilinna .encrypt = ctr_crypt, 439*64b94ceaSJussi Kivilinna .decrypt = ctr_crypt, 440*64b94ceaSJussi Kivilinna }, 441*64b94ceaSJussi Kivilinna }, 442*64b94ceaSJussi Kivilinna }; 443*64b94ceaSJussi Kivilinna 444*64b94ceaSJussi Kivilinna static int __init init(void) 445*64b94ceaSJussi Kivilinna { 446*64b94ceaSJussi Kivilinna int err; 447*64b94ceaSJussi Kivilinna 448*64b94ceaSJussi Kivilinna err = crypto_register_alg(&bf_alg); 449*64b94ceaSJussi Kivilinna if (err) 450*64b94ceaSJussi Kivilinna goto bf_err; 451*64b94ceaSJussi Kivilinna err = crypto_register_alg(&blk_ecb_alg); 452*64b94ceaSJussi Kivilinna if (err) 453*64b94ceaSJussi Kivilinna goto ecb_err; 454*64b94ceaSJussi Kivilinna err = crypto_register_alg(&blk_cbc_alg); 455*64b94ceaSJussi Kivilinna if (err) 456*64b94ceaSJussi Kivilinna goto cbc_err; 457*64b94ceaSJussi Kivilinna err = crypto_register_alg(&blk_ctr_alg); 458*64b94ceaSJussi Kivilinna if (err) 459*64b94ceaSJussi Kivilinna goto ctr_err; 460*64b94ceaSJussi Kivilinna 461*64b94ceaSJussi Kivilinna return 0; 462*64b94ceaSJussi Kivilinna 463*64b94ceaSJussi Kivilinna ctr_err: 464*64b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 465*64b94ceaSJussi Kivilinna cbc_err: 466*64b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 467*64b94ceaSJussi Kivilinna ecb_err: 468*64b94ceaSJussi Kivilinna crypto_unregister_alg(&bf_alg); 469*64b94ceaSJussi Kivilinna bf_err: 470*64b94ceaSJussi Kivilinna return err; 471*64b94ceaSJussi Kivilinna } 472*64b94ceaSJussi Kivilinna 473*64b94ceaSJussi Kivilinna static void __exit fini(void) 474*64b94ceaSJussi Kivilinna { 475*64b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_ctr_alg); 476*64b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 477*64b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 478*64b94ceaSJussi Kivilinna crypto_unregister_alg(&bf_alg); 479*64b94ceaSJussi Kivilinna } 480*64b94ceaSJussi Kivilinna 481*64b94ceaSJussi Kivilinna module_init(init); 482*64b94ceaSJussi Kivilinna module_exit(fini); 483*64b94ceaSJussi Kivilinna 484*64b94ceaSJussi Kivilinna MODULE_LICENSE("GPL"); 485*64b94ceaSJussi Kivilinna MODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized"); 486*64b94ceaSJussi Kivilinna MODULE_ALIAS("blowfish"); 487*64b94ceaSJussi Kivilinna MODULE_ALIAS("blowfish-asm"); 488