164b94ceaSJussi Kivilinna /* 264b94ceaSJussi Kivilinna * Glue Code for assembler optimized version of Blowfish 364b94ceaSJussi Kivilinna * 43d387ef0SJussi Kivilinna * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 564b94ceaSJussi Kivilinna * 6a071d06eSJussi Kivilinna * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: 7a071d06eSJussi Kivilinna * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> 8a071d06eSJussi Kivilinna * CTR part based on code (crypto/ctr.c) by: 9a071d06eSJussi Kivilinna * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com> 10a071d06eSJussi Kivilinna * 1164b94ceaSJussi Kivilinna * This program is free software; you can redistribute it and/or modify 1264b94ceaSJussi Kivilinna * it under the terms of the GNU General Public License as published by 1364b94ceaSJussi Kivilinna * the Free Software Foundation; either version 2 of the License, or 1464b94ceaSJussi Kivilinna * (at your option) any later version. 1564b94ceaSJussi Kivilinna * 1664b94ceaSJussi Kivilinna * This program is distributed in the hope that it will be useful, 1764b94ceaSJussi Kivilinna * but WITHOUT ANY WARRANTY; without even the implied warranty of 1864b94ceaSJussi Kivilinna * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1964b94ceaSJussi Kivilinna * GNU General Public License for more details. 2064b94ceaSJussi Kivilinna * 2164b94ceaSJussi Kivilinna * You should have received a copy of the GNU General Public License 2264b94ceaSJussi Kivilinna * along with this program; if not, write to the Free Software 2364b94ceaSJussi Kivilinna * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 2464b94ceaSJussi Kivilinna * USA 2564b94ceaSJussi Kivilinna * 2664b94ceaSJussi Kivilinna */ 2764b94ceaSJussi Kivilinna 28*c1679171SEric Biggers #include <crypto/algapi.h> 2964b94ceaSJussi Kivilinna #include <crypto/blowfish.h> 30*c1679171SEric Biggers #include <crypto/internal/skcipher.h> 3164b94ceaSJussi Kivilinna #include <linux/crypto.h> 3264b94ceaSJussi Kivilinna #include <linux/init.h> 3364b94ceaSJussi Kivilinna #include <linux/module.h> 3464b94ceaSJussi Kivilinna #include <linux/types.h> 3564b94ceaSJussi Kivilinna 3664b94ceaSJussi Kivilinna /* regular block cipher functions */ 3764b94ceaSJussi Kivilinna asmlinkage void __blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src, 3864b94ceaSJussi Kivilinna bool xor); 3964b94ceaSJussi Kivilinna asmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src); 4064b94ceaSJussi Kivilinna 4164b94ceaSJussi Kivilinna /* 4-way parallel cipher functions */ 4264b94ceaSJussi Kivilinna asmlinkage void __blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst, 4364b94ceaSJussi Kivilinna const u8 *src, bool xor); 4464b94ceaSJussi Kivilinna asmlinkage void blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst, 4564b94ceaSJussi Kivilinna const u8 *src); 463d387ef0SJussi Kivilinna 473d387ef0SJussi Kivilinna static inline void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src) 483d387ef0SJussi Kivilinna { 493d387ef0SJussi Kivilinna __blowfish_enc_blk(ctx, dst, src, false); 503d387ef0SJussi Kivilinna } 513d387ef0SJussi Kivilinna 523d387ef0SJussi Kivilinna static inline void blowfish_enc_blk_xor(struct bf_ctx *ctx, u8 *dst, 533d387ef0SJussi Kivilinna const u8 *src) 543d387ef0SJussi Kivilinna { 553d387ef0SJussi Kivilinna __blowfish_enc_blk(ctx, dst, src, true); 563d387ef0SJussi Kivilinna } 573d387ef0SJussi Kivilinna 583d387ef0SJussi Kivilinna static inline void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst, 593d387ef0SJussi Kivilinna const u8 *src) 603d387ef0SJussi Kivilinna { 613d387ef0SJussi Kivilinna __blowfish_enc_blk_4way(ctx, dst, src, false); 623d387ef0SJussi Kivilinna } 633d387ef0SJussi Kivilinna 643d387ef0SJussi Kivilinna static inline void blowfish_enc_blk_xor_4way(struct bf_ctx *ctx, u8 *dst, 653d387ef0SJussi Kivilinna const u8 *src) 663d387ef0SJussi Kivilinna { 673d387ef0SJussi Kivilinna __blowfish_enc_blk_4way(ctx, dst, src, true); 683d387ef0SJussi Kivilinna } 6964b94ceaSJussi Kivilinna 7064b94ceaSJussi Kivilinna static void blowfish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 7164b94ceaSJussi Kivilinna { 7264b94ceaSJussi Kivilinna blowfish_enc_blk(crypto_tfm_ctx(tfm), dst, src); 7364b94ceaSJussi Kivilinna } 7464b94ceaSJussi Kivilinna 7564b94ceaSJussi Kivilinna static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 7664b94ceaSJussi Kivilinna { 7764b94ceaSJussi Kivilinna blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src); 7864b94ceaSJussi Kivilinna } 7964b94ceaSJussi Kivilinna 80*c1679171SEric Biggers static int blowfish_setkey_skcipher(struct crypto_skcipher *tfm, 81*c1679171SEric Biggers const u8 *key, unsigned int keylen) 82*c1679171SEric Biggers { 83*c1679171SEric Biggers return blowfish_setkey(&tfm->base, key, keylen); 84*c1679171SEric Biggers } 85*c1679171SEric Biggers 86*c1679171SEric Biggers static int ecb_crypt(struct skcipher_request *req, 8764b94ceaSJussi Kivilinna void (*fn)(struct bf_ctx *, u8 *, const u8 *), 8864b94ceaSJussi Kivilinna void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *)) 8964b94ceaSJussi Kivilinna { 9064b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 91*c1679171SEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 92*c1679171SEric Biggers struct bf_ctx *ctx = crypto_skcipher_ctx(tfm); 93*c1679171SEric Biggers struct skcipher_walk walk; 9464b94ceaSJussi Kivilinna unsigned int nbytes; 9564b94ceaSJussi Kivilinna int err; 9664b94ceaSJussi Kivilinna 97*c1679171SEric Biggers err = skcipher_walk_virt(&walk, req, false); 9864b94ceaSJussi Kivilinna 99*c1679171SEric Biggers while ((nbytes = walk.nbytes)) { 100*c1679171SEric Biggers u8 *wsrc = walk.src.virt.addr; 101*c1679171SEric Biggers u8 *wdst = walk.dst.virt.addr; 10264b94ceaSJussi Kivilinna 10364b94ceaSJussi Kivilinna /* Process four block batch */ 10464b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 10564b94ceaSJussi Kivilinna do { 10664b94ceaSJussi Kivilinna fn_4way(ctx, wdst, wsrc); 10764b94ceaSJussi Kivilinna 10864b94ceaSJussi Kivilinna wsrc += bsize * 4; 10964b94ceaSJussi Kivilinna wdst += bsize * 4; 11064b94ceaSJussi Kivilinna nbytes -= bsize * 4; 11164b94ceaSJussi Kivilinna } while (nbytes >= bsize * 4); 11264b94ceaSJussi Kivilinna 11364b94ceaSJussi Kivilinna if (nbytes < bsize) 11464b94ceaSJussi Kivilinna goto done; 11564b94ceaSJussi Kivilinna } 11664b94ceaSJussi Kivilinna 11764b94ceaSJussi Kivilinna /* Handle leftovers */ 11864b94ceaSJussi Kivilinna do { 11964b94ceaSJussi Kivilinna fn(ctx, wdst, wsrc); 12064b94ceaSJussi Kivilinna 12164b94ceaSJussi Kivilinna wsrc += bsize; 12264b94ceaSJussi Kivilinna wdst += bsize; 12364b94ceaSJussi Kivilinna nbytes -= bsize; 12464b94ceaSJussi Kivilinna } while (nbytes >= bsize); 12564b94ceaSJussi Kivilinna 12664b94ceaSJussi Kivilinna done: 127*c1679171SEric Biggers err = skcipher_walk_done(&walk, nbytes); 12864b94ceaSJussi Kivilinna } 12964b94ceaSJussi Kivilinna 13064b94ceaSJussi Kivilinna return err; 13164b94ceaSJussi Kivilinna } 13264b94ceaSJussi Kivilinna 133*c1679171SEric Biggers static int ecb_encrypt(struct skcipher_request *req) 13464b94ceaSJussi Kivilinna { 135*c1679171SEric Biggers return ecb_crypt(req, blowfish_enc_blk, blowfish_enc_blk_4way); 13664b94ceaSJussi Kivilinna } 13764b94ceaSJussi Kivilinna 138*c1679171SEric Biggers static int ecb_decrypt(struct skcipher_request *req) 13964b94ceaSJussi Kivilinna { 140*c1679171SEric Biggers return ecb_crypt(req, blowfish_dec_blk, blowfish_dec_blk_4way); 14164b94ceaSJussi Kivilinna } 14264b94ceaSJussi Kivilinna 143*c1679171SEric Biggers static unsigned int __cbc_encrypt(struct bf_ctx *ctx, 144*c1679171SEric Biggers struct skcipher_walk *walk) 14564b94ceaSJussi Kivilinna { 14664b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 14764b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 14864b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 14964b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 15064b94ceaSJussi Kivilinna u64 *iv = (u64 *)walk->iv; 15164b94ceaSJussi Kivilinna 15264b94ceaSJussi Kivilinna do { 15364b94ceaSJussi Kivilinna *dst = *src ^ *iv; 15464b94ceaSJussi Kivilinna blowfish_enc_blk(ctx, (u8 *)dst, (u8 *)dst); 15564b94ceaSJussi Kivilinna iv = dst; 15664b94ceaSJussi Kivilinna 15764b94ceaSJussi Kivilinna src += 1; 15864b94ceaSJussi Kivilinna dst += 1; 15964b94ceaSJussi Kivilinna nbytes -= bsize; 16064b94ceaSJussi Kivilinna } while (nbytes >= bsize); 16164b94ceaSJussi Kivilinna 16264b94ceaSJussi Kivilinna *(u64 *)walk->iv = *iv; 16364b94ceaSJussi Kivilinna return nbytes; 16464b94ceaSJussi Kivilinna } 16564b94ceaSJussi Kivilinna 166*c1679171SEric Biggers static int cbc_encrypt(struct skcipher_request *req) 16764b94ceaSJussi Kivilinna { 168*c1679171SEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 169*c1679171SEric Biggers struct bf_ctx *ctx = crypto_skcipher_ctx(tfm); 170*c1679171SEric Biggers struct skcipher_walk walk; 171*c1679171SEric Biggers unsigned int nbytes; 17264b94ceaSJussi Kivilinna int err; 17364b94ceaSJussi Kivilinna 174*c1679171SEric Biggers err = skcipher_walk_virt(&walk, req, false); 17564b94ceaSJussi Kivilinna 17664b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes)) { 177*c1679171SEric Biggers nbytes = __cbc_encrypt(ctx, &walk); 178*c1679171SEric Biggers err = skcipher_walk_done(&walk, nbytes); 17964b94ceaSJussi Kivilinna } 18064b94ceaSJussi Kivilinna 18164b94ceaSJussi Kivilinna return err; 18264b94ceaSJussi Kivilinna } 18364b94ceaSJussi Kivilinna 184*c1679171SEric Biggers static unsigned int __cbc_decrypt(struct bf_ctx *ctx, 185*c1679171SEric Biggers struct skcipher_walk *walk) 18664b94ceaSJussi Kivilinna { 18764b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 18864b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 18964b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 19064b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 19164b94ceaSJussi Kivilinna u64 ivs[4 - 1]; 19264b94ceaSJussi Kivilinna u64 last_iv; 19364b94ceaSJussi Kivilinna 19464b94ceaSJussi Kivilinna /* Start of the last block. */ 19564b94ceaSJussi Kivilinna src += nbytes / bsize - 1; 19664b94ceaSJussi Kivilinna dst += nbytes / bsize - 1; 19764b94ceaSJussi Kivilinna 19864b94ceaSJussi Kivilinna last_iv = *src; 19964b94ceaSJussi Kivilinna 20064b94ceaSJussi Kivilinna /* Process four block batch */ 20164b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 20264b94ceaSJussi Kivilinna do { 20364b94ceaSJussi Kivilinna nbytes -= bsize * 4 - bsize; 20464b94ceaSJussi Kivilinna src -= 4 - 1; 20564b94ceaSJussi Kivilinna dst -= 4 - 1; 20664b94ceaSJussi Kivilinna 20764b94ceaSJussi Kivilinna ivs[0] = src[0]; 20864b94ceaSJussi Kivilinna ivs[1] = src[1]; 20964b94ceaSJussi Kivilinna ivs[2] = src[2]; 21064b94ceaSJussi Kivilinna 21164b94ceaSJussi Kivilinna blowfish_dec_blk_4way(ctx, (u8 *)dst, (u8 *)src); 21264b94ceaSJussi Kivilinna 21364b94ceaSJussi Kivilinna dst[1] ^= ivs[0]; 21464b94ceaSJussi Kivilinna dst[2] ^= ivs[1]; 21564b94ceaSJussi Kivilinna dst[3] ^= ivs[2]; 21664b94ceaSJussi Kivilinna 21764b94ceaSJussi Kivilinna nbytes -= bsize; 21864b94ceaSJussi Kivilinna if (nbytes < bsize) 21964b94ceaSJussi Kivilinna goto done; 22064b94ceaSJussi Kivilinna 22164b94ceaSJussi Kivilinna *dst ^= *(src - 1); 22264b94ceaSJussi Kivilinna src -= 1; 22364b94ceaSJussi Kivilinna dst -= 1; 22464b94ceaSJussi Kivilinna } while (nbytes >= bsize * 4); 22564b94ceaSJussi Kivilinna } 22664b94ceaSJussi Kivilinna 22764b94ceaSJussi Kivilinna /* Handle leftovers */ 22864b94ceaSJussi Kivilinna for (;;) { 22964b94ceaSJussi Kivilinna blowfish_dec_blk(ctx, (u8 *)dst, (u8 *)src); 23064b94ceaSJussi Kivilinna 23164b94ceaSJussi Kivilinna nbytes -= bsize; 23264b94ceaSJussi Kivilinna if (nbytes < bsize) 23364b94ceaSJussi Kivilinna break; 23464b94ceaSJussi Kivilinna 23564b94ceaSJussi Kivilinna *dst ^= *(src - 1); 23664b94ceaSJussi Kivilinna src -= 1; 23764b94ceaSJussi Kivilinna dst -= 1; 23864b94ceaSJussi Kivilinna } 23964b94ceaSJussi Kivilinna 24064b94ceaSJussi Kivilinna done: 24164b94ceaSJussi Kivilinna *dst ^= *(u64 *)walk->iv; 24264b94ceaSJussi Kivilinna *(u64 *)walk->iv = last_iv; 24364b94ceaSJussi Kivilinna 24464b94ceaSJussi Kivilinna return nbytes; 24564b94ceaSJussi Kivilinna } 24664b94ceaSJussi Kivilinna 247*c1679171SEric Biggers static int cbc_decrypt(struct skcipher_request *req) 24864b94ceaSJussi Kivilinna { 249*c1679171SEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 250*c1679171SEric Biggers struct bf_ctx *ctx = crypto_skcipher_ctx(tfm); 251*c1679171SEric Biggers struct skcipher_walk walk; 252*c1679171SEric Biggers unsigned int nbytes; 25364b94ceaSJussi Kivilinna int err; 25464b94ceaSJussi Kivilinna 255*c1679171SEric Biggers err = skcipher_walk_virt(&walk, req, false); 25664b94ceaSJussi Kivilinna 25764b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes)) { 258*c1679171SEric Biggers nbytes = __cbc_decrypt(ctx, &walk); 259*c1679171SEric Biggers err = skcipher_walk_done(&walk, nbytes); 26064b94ceaSJussi Kivilinna } 26164b94ceaSJussi Kivilinna 26264b94ceaSJussi Kivilinna return err; 26364b94ceaSJussi Kivilinna } 26464b94ceaSJussi Kivilinna 265*c1679171SEric Biggers static void ctr_crypt_final(struct bf_ctx *ctx, struct skcipher_walk *walk) 26664b94ceaSJussi Kivilinna { 26764b94ceaSJussi Kivilinna u8 *ctrblk = walk->iv; 26864b94ceaSJussi Kivilinna u8 keystream[BF_BLOCK_SIZE]; 26964b94ceaSJussi Kivilinna u8 *src = walk->src.virt.addr; 27064b94ceaSJussi Kivilinna u8 *dst = walk->dst.virt.addr; 27164b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 27264b94ceaSJussi Kivilinna 27364b94ceaSJussi Kivilinna blowfish_enc_blk(ctx, keystream, ctrblk); 27445fe93dfSArd Biesheuvel crypto_xor_cpy(dst, keystream, src, nbytes); 27564b94ceaSJussi Kivilinna 27664b94ceaSJussi Kivilinna crypto_inc(ctrblk, BF_BLOCK_SIZE); 27764b94ceaSJussi Kivilinna } 27864b94ceaSJussi Kivilinna 279*c1679171SEric Biggers static unsigned int __ctr_crypt(struct bf_ctx *ctx, struct skcipher_walk *walk) 28064b94ceaSJussi Kivilinna { 28164b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 28264b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 28364b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 28464b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 28564b94ceaSJussi Kivilinna u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv); 28664b94ceaSJussi Kivilinna __be64 ctrblocks[4]; 28764b94ceaSJussi Kivilinna 28864b94ceaSJussi Kivilinna /* Process four block batch */ 28964b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 29064b94ceaSJussi Kivilinna do { 29164b94ceaSJussi Kivilinna if (dst != src) { 29264b94ceaSJussi Kivilinna dst[0] = src[0]; 29364b94ceaSJussi Kivilinna dst[1] = src[1]; 29464b94ceaSJussi Kivilinna dst[2] = src[2]; 29564b94ceaSJussi Kivilinna dst[3] = src[3]; 29664b94ceaSJussi Kivilinna } 29764b94ceaSJussi Kivilinna 29864b94ceaSJussi Kivilinna /* create ctrblks for parallel encrypt */ 29964b94ceaSJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 30064b94ceaSJussi Kivilinna ctrblocks[1] = cpu_to_be64(ctrblk++); 30164b94ceaSJussi Kivilinna ctrblocks[2] = cpu_to_be64(ctrblk++); 30264b94ceaSJussi Kivilinna ctrblocks[3] = cpu_to_be64(ctrblk++); 30364b94ceaSJussi Kivilinna 30464b94ceaSJussi Kivilinna blowfish_enc_blk_xor_4way(ctx, (u8 *)dst, 30564b94ceaSJussi Kivilinna (u8 *)ctrblocks); 30664b94ceaSJussi Kivilinna 30764b94ceaSJussi Kivilinna src += 4; 30864b94ceaSJussi Kivilinna dst += 4; 30964b94ceaSJussi Kivilinna } while ((nbytes -= bsize * 4) >= bsize * 4); 31064b94ceaSJussi Kivilinna 31164b94ceaSJussi Kivilinna if (nbytes < bsize) 31264b94ceaSJussi Kivilinna goto done; 31364b94ceaSJussi Kivilinna } 31464b94ceaSJussi Kivilinna 31564b94ceaSJussi Kivilinna /* Handle leftovers */ 31664b94ceaSJussi Kivilinna do { 31764b94ceaSJussi Kivilinna if (dst != src) 31864b94ceaSJussi Kivilinna *dst = *src; 31964b94ceaSJussi Kivilinna 32064b94ceaSJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 32164b94ceaSJussi Kivilinna 32264b94ceaSJussi Kivilinna blowfish_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks); 32364b94ceaSJussi Kivilinna 32464b94ceaSJussi Kivilinna src += 1; 32564b94ceaSJussi Kivilinna dst += 1; 32664b94ceaSJussi Kivilinna } while ((nbytes -= bsize) >= bsize); 32764b94ceaSJussi Kivilinna 32864b94ceaSJussi Kivilinna done: 32964b94ceaSJussi Kivilinna *(__be64 *)walk->iv = cpu_to_be64(ctrblk); 33064b94ceaSJussi Kivilinna return nbytes; 33164b94ceaSJussi Kivilinna } 33264b94ceaSJussi Kivilinna 333*c1679171SEric Biggers static int ctr_crypt(struct skcipher_request *req) 33464b94ceaSJussi Kivilinna { 335*c1679171SEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 336*c1679171SEric Biggers struct bf_ctx *ctx = crypto_skcipher_ctx(tfm); 337*c1679171SEric Biggers struct skcipher_walk walk; 338*c1679171SEric Biggers unsigned int nbytes; 33964b94ceaSJussi Kivilinna int err; 34064b94ceaSJussi Kivilinna 341*c1679171SEric Biggers err = skcipher_walk_virt(&walk, req, false); 34264b94ceaSJussi Kivilinna 34364b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes) >= BF_BLOCK_SIZE) { 344*c1679171SEric Biggers nbytes = __ctr_crypt(ctx, &walk); 345*c1679171SEric Biggers err = skcipher_walk_done(&walk, nbytes); 34664b94ceaSJussi Kivilinna } 34764b94ceaSJussi Kivilinna 348*c1679171SEric Biggers if (nbytes) { 349*c1679171SEric Biggers ctr_crypt_final(ctx, &walk); 350*c1679171SEric Biggers err = skcipher_walk_done(&walk, 0); 35164b94ceaSJussi Kivilinna } 35264b94ceaSJussi Kivilinna 35364b94ceaSJussi Kivilinna return err; 35464b94ceaSJussi Kivilinna } 35564b94ceaSJussi Kivilinna 356*c1679171SEric Biggers static struct crypto_alg bf_cipher_alg = { 357d433208cSJussi Kivilinna .cra_name = "blowfish", 358d433208cSJussi Kivilinna .cra_driver_name = "blowfish-asm", 359d433208cSJussi Kivilinna .cra_priority = 200, 360d433208cSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 361d433208cSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 362d433208cSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 363919e2c32SJussi Kivilinna .cra_alignmask = 0, 364d433208cSJussi Kivilinna .cra_module = THIS_MODULE, 365d433208cSJussi Kivilinna .cra_u = { 366d433208cSJussi Kivilinna .cipher = { 367d433208cSJussi Kivilinna .cia_min_keysize = BF_MIN_KEY_SIZE, 368d433208cSJussi Kivilinna .cia_max_keysize = BF_MAX_KEY_SIZE, 369d433208cSJussi Kivilinna .cia_setkey = blowfish_setkey, 370d433208cSJussi Kivilinna .cia_encrypt = blowfish_encrypt, 371d433208cSJussi Kivilinna .cia_decrypt = blowfish_decrypt, 372d433208cSJussi Kivilinna } 373d433208cSJussi Kivilinna } 374*c1679171SEric Biggers }; 375*c1679171SEric Biggers 376*c1679171SEric Biggers static struct skcipher_alg bf_skcipher_algs[] = { 377*c1679171SEric Biggers { 378*c1679171SEric Biggers .base.cra_name = "ecb(blowfish)", 379*c1679171SEric Biggers .base.cra_driver_name = "ecb-blowfish-asm", 380*c1679171SEric Biggers .base.cra_priority = 300, 381*c1679171SEric Biggers .base.cra_blocksize = BF_BLOCK_SIZE, 382*c1679171SEric Biggers .base.cra_ctxsize = sizeof(struct bf_ctx), 383*c1679171SEric Biggers .base.cra_module = THIS_MODULE, 384d433208cSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 385d433208cSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 386*c1679171SEric Biggers .setkey = blowfish_setkey_skcipher, 387d433208cSJussi Kivilinna .encrypt = ecb_encrypt, 388d433208cSJussi Kivilinna .decrypt = ecb_decrypt, 389d433208cSJussi Kivilinna }, { 390*c1679171SEric Biggers .base.cra_name = "cbc(blowfish)", 391*c1679171SEric Biggers .base.cra_driver_name = "cbc-blowfish-asm", 392*c1679171SEric Biggers .base.cra_priority = 300, 393*c1679171SEric Biggers .base.cra_blocksize = BF_BLOCK_SIZE, 394*c1679171SEric Biggers .base.cra_ctxsize = sizeof(struct bf_ctx), 395*c1679171SEric Biggers .base.cra_module = THIS_MODULE, 396d433208cSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 397d433208cSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 398d433208cSJussi Kivilinna .ivsize = BF_BLOCK_SIZE, 399*c1679171SEric Biggers .setkey = blowfish_setkey_skcipher, 400d433208cSJussi Kivilinna .encrypt = cbc_encrypt, 401d433208cSJussi Kivilinna .decrypt = cbc_decrypt, 402d433208cSJussi Kivilinna }, { 403*c1679171SEric Biggers .base.cra_name = "ctr(blowfish)", 404*c1679171SEric Biggers .base.cra_driver_name = "ctr-blowfish-asm", 405*c1679171SEric Biggers .base.cra_priority = 300, 406*c1679171SEric Biggers .base.cra_blocksize = 1, 407*c1679171SEric Biggers .base.cra_ctxsize = sizeof(struct bf_ctx), 408*c1679171SEric Biggers .base.cra_module = THIS_MODULE, 40964b94ceaSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 41064b94ceaSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 41164b94ceaSJussi Kivilinna .ivsize = BF_BLOCK_SIZE, 412*c1679171SEric Biggers .chunksize = BF_BLOCK_SIZE, 413*c1679171SEric Biggers .setkey = blowfish_setkey_skcipher, 41464b94ceaSJussi Kivilinna .encrypt = ctr_crypt, 41564b94ceaSJussi Kivilinna .decrypt = ctr_crypt, 41664b94ceaSJussi Kivilinna }, 417*c1679171SEric Biggers }; 41864b94ceaSJussi Kivilinna 4194c58464bSJussi Kivilinna static bool is_blacklisted_cpu(void) 4204c58464bSJussi Kivilinna { 4214c58464bSJussi Kivilinna if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 4224c58464bSJussi Kivilinna return false; 4234c58464bSJussi Kivilinna 4244c58464bSJussi Kivilinna if (boot_cpu_data.x86 == 0x0f) { 4254c58464bSJussi Kivilinna /* 4264c58464bSJussi Kivilinna * On Pentium 4, blowfish-x86_64 is slower than generic C 4274c58464bSJussi Kivilinna * implementation because use of 64bit rotates (which are really 4284c58464bSJussi Kivilinna * slow on P4). Therefore blacklist P4s. 4294c58464bSJussi Kivilinna */ 4304c58464bSJussi Kivilinna return true; 4314c58464bSJussi Kivilinna } 4324c58464bSJussi Kivilinna 4334c58464bSJussi Kivilinna return false; 4344c58464bSJussi Kivilinna } 4354c58464bSJussi Kivilinna 4364c58464bSJussi Kivilinna static int force; 4374c58464bSJussi Kivilinna module_param(force, int, 0); 4384c58464bSJussi Kivilinna MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); 4394c58464bSJussi Kivilinna 44064b94ceaSJussi Kivilinna static int __init init(void) 44164b94ceaSJussi Kivilinna { 442*c1679171SEric Biggers int err; 443*c1679171SEric Biggers 4444c58464bSJussi Kivilinna if (!force && is_blacklisted_cpu()) { 4454c58464bSJussi Kivilinna printk(KERN_INFO 4464c58464bSJussi Kivilinna "blowfish-x86_64: performance on this CPU " 4474c58464bSJussi Kivilinna "would be suboptimal: disabling " 4484c58464bSJussi Kivilinna "blowfish-x86_64.\n"); 4494c58464bSJussi Kivilinna return -ENODEV; 4504c58464bSJussi Kivilinna } 4514c58464bSJussi Kivilinna 452*c1679171SEric Biggers err = crypto_register_alg(&bf_cipher_alg); 453*c1679171SEric Biggers if (err) 454*c1679171SEric Biggers return err; 455*c1679171SEric Biggers 456*c1679171SEric Biggers err = crypto_register_skciphers(bf_skcipher_algs, 457*c1679171SEric Biggers ARRAY_SIZE(bf_skcipher_algs)); 458*c1679171SEric Biggers if (err) 459*c1679171SEric Biggers crypto_unregister_alg(&bf_cipher_alg); 460*c1679171SEric Biggers 461*c1679171SEric Biggers return err; 46264b94ceaSJussi Kivilinna } 46364b94ceaSJussi Kivilinna 46464b94ceaSJussi Kivilinna static void __exit fini(void) 46564b94ceaSJussi Kivilinna { 466*c1679171SEric Biggers crypto_unregister_alg(&bf_cipher_alg); 467*c1679171SEric Biggers crypto_unregister_skciphers(bf_skcipher_algs, 468*c1679171SEric Biggers ARRAY_SIZE(bf_skcipher_algs)); 46964b94ceaSJussi Kivilinna } 47064b94ceaSJussi Kivilinna 47164b94ceaSJussi Kivilinna module_init(init); 47264b94ceaSJussi Kivilinna module_exit(fini); 47364b94ceaSJussi Kivilinna 47464b94ceaSJussi Kivilinna MODULE_LICENSE("GPL"); 47564b94ceaSJussi Kivilinna MODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized"); 4765d26a105SKees Cook MODULE_ALIAS_CRYPTO("blowfish"); 4775d26a105SKees Cook MODULE_ALIAS_CRYPTO("blowfish-asm"); 478