164b94ceaSJussi Kivilinna /* 264b94ceaSJussi Kivilinna * Glue Code for assembler optimized version of Blowfish 364b94ceaSJussi Kivilinna * 464b94ceaSJussi 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 284c58464bSJussi Kivilinna #include <asm/processor.h> 2964b94ceaSJussi Kivilinna #include <crypto/blowfish.h> 3064b94ceaSJussi Kivilinna #include <linux/crypto.h> 3164b94ceaSJussi Kivilinna #include <linux/init.h> 3264b94ceaSJussi Kivilinna #include <linux/module.h> 3364b94ceaSJussi Kivilinna #include <linux/types.h> 3464b94ceaSJussi Kivilinna #include <crypto/algapi.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); 4664b94ceaSJussi Kivilinna 4764b94ceaSJussi Kivilinna static inline void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src) 4864b94ceaSJussi Kivilinna { 4964b94ceaSJussi Kivilinna __blowfish_enc_blk(ctx, dst, src, false); 5064b94ceaSJussi Kivilinna } 5164b94ceaSJussi Kivilinna 5264b94ceaSJussi Kivilinna static inline void blowfish_enc_blk_xor(struct bf_ctx *ctx, u8 *dst, 5364b94ceaSJussi Kivilinna const u8 *src) 5464b94ceaSJussi Kivilinna { 5564b94ceaSJussi Kivilinna __blowfish_enc_blk(ctx, dst, src, true); 5664b94ceaSJussi Kivilinna } 5764b94ceaSJussi Kivilinna 5864b94ceaSJussi Kivilinna static inline void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst, 5964b94ceaSJussi Kivilinna const u8 *src) 6064b94ceaSJussi Kivilinna { 6164b94ceaSJussi Kivilinna __blowfish_enc_blk_4way(ctx, dst, src, false); 6264b94ceaSJussi Kivilinna } 6364b94ceaSJussi Kivilinna 6464b94ceaSJussi Kivilinna static inline void blowfish_enc_blk_xor_4way(struct bf_ctx *ctx, u8 *dst, 6564b94ceaSJussi Kivilinna const u8 *src) 6664b94ceaSJussi Kivilinna { 6764b94ceaSJussi Kivilinna __blowfish_enc_blk_4way(ctx, dst, src, true); 6864b94ceaSJussi 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 8064b94ceaSJussi Kivilinna static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, 8164b94ceaSJussi Kivilinna void (*fn)(struct bf_ctx *, u8 *, const u8 *), 8264b94ceaSJussi Kivilinna void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *)) 8364b94ceaSJussi Kivilinna { 8464b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 8564b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 8664b94ceaSJussi Kivilinna unsigned int nbytes; 8764b94ceaSJussi Kivilinna int err; 8864b94ceaSJussi Kivilinna 8964b94ceaSJussi Kivilinna err = blkcipher_walk_virt(desc, walk); 9064b94ceaSJussi Kivilinna 9164b94ceaSJussi Kivilinna while ((nbytes = walk->nbytes)) { 9264b94ceaSJussi Kivilinna u8 *wsrc = walk->src.virt.addr; 9364b94ceaSJussi Kivilinna u8 *wdst = walk->dst.virt.addr; 9464b94ceaSJussi Kivilinna 9564b94ceaSJussi Kivilinna /* Process four block batch */ 9664b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 9764b94ceaSJussi Kivilinna do { 9864b94ceaSJussi Kivilinna fn_4way(ctx, wdst, wsrc); 9964b94ceaSJussi Kivilinna 10064b94ceaSJussi Kivilinna wsrc += bsize * 4; 10164b94ceaSJussi Kivilinna wdst += bsize * 4; 10264b94ceaSJussi Kivilinna nbytes -= bsize * 4; 10364b94ceaSJussi Kivilinna } while (nbytes >= bsize * 4); 10464b94ceaSJussi Kivilinna 10564b94ceaSJussi Kivilinna if (nbytes < bsize) 10664b94ceaSJussi Kivilinna goto done; 10764b94ceaSJussi Kivilinna } 10864b94ceaSJussi Kivilinna 10964b94ceaSJussi Kivilinna /* Handle leftovers */ 11064b94ceaSJussi Kivilinna do { 11164b94ceaSJussi Kivilinna fn(ctx, wdst, wsrc); 11264b94ceaSJussi Kivilinna 11364b94ceaSJussi Kivilinna wsrc += bsize; 11464b94ceaSJussi Kivilinna wdst += bsize; 11564b94ceaSJussi Kivilinna nbytes -= bsize; 11664b94ceaSJussi Kivilinna } while (nbytes >= bsize); 11764b94ceaSJussi Kivilinna 11864b94ceaSJussi Kivilinna done: 11964b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, walk, nbytes); 12064b94ceaSJussi Kivilinna } 12164b94ceaSJussi Kivilinna 12264b94ceaSJussi Kivilinna return err; 12364b94ceaSJussi Kivilinna } 12464b94ceaSJussi Kivilinna 12564b94ceaSJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 12664b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 12764b94ceaSJussi Kivilinna { 12864b94ceaSJussi Kivilinna struct blkcipher_walk walk; 12964b94ceaSJussi Kivilinna 13064b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 13164b94ceaSJussi Kivilinna return ecb_crypt(desc, &walk, blowfish_enc_blk, blowfish_enc_blk_4way); 13264b94ceaSJussi Kivilinna } 13364b94ceaSJussi Kivilinna 13464b94ceaSJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 13564b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 13664b94ceaSJussi Kivilinna { 13764b94ceaSJussi Kivilinna struct blkcipher_walk walk; 13864b94ceaSJussi Kivilinna 13964b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 14064b94ceaSJussi Kivilinna return ecb_crypt(desc, &walk, blowfish_dec_blk, blowfish_dec_blk_4way); 14164b94ceaSJussi Kivilinna } 14264b94ceaSJussi Kivilinna 14364b94ceaSJussi Kivilinna static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, 14464b94ceaSJussi Kivilinna struct blkcipher_walk *walk) 14564b94ceaSJussi Kivilinna { 14664b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 14764b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 14864b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 14964b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 15064b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 15164b94ceaSJussi Kivilinna u64 *iv = (u64 *)walk->iv; 15264b94ceaSJussi Kivilinna 15364b94ceaSJussi Kivilinna do { 15464b94ceaSJussi Kivilinna *dst = *src ^ *iv; 15564b94ceaSJussi Kivilinna blowfish_enc_blk(ctx, (u8 *)dst, (u8 *)dst); 15664b94ceaSJussi Kivilinna iv = dst; 15764b94ceaSJussi Kivilinna 15864b94ceaSJussi Kivilinna src += 1; 15964b94ceaSJussi Kivilinna dst += 1; 16064b94ceaSJussi Kivilinna nbytes -= bsize; 16164b94ceaSJussi Kivilinna } while (nbytes >= bsize); 16264b94ceaSJussi Kivilinna 16364b94ceaSJussi Kivilinna *(u64 *)walk->iv = *iv; 16464b94ceaSJussi Kivilinna return nbytes; 16564b94ceaSJussi Kivilinna } 16664b94ceaSJussi Kivilinna 16764b94ceaSJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 16864b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 16964b94ceaSJussi Kivilinna { 17064b94ceaSJussi Kivilinna struct blkcipher_walk walk; 17164b94ceaSJussi Kivilinna int err; 17264b94ceaSJussi Kivilinna 17364b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 17464b94ceaSJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 17564b94ceaSJussi Kivilinna 17664b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes)) { 17764b94ceaSJussi Kivilinna nbytes = __cbc_encrypt(desc, &walk); 17864b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 17964b94ceaSJussi Kivilinna } 18064b94ceaSJussi Kivilinna 18164b94ceaSJussi Kivilinna return err; 18264b94ceaSJussi Kivilinna } 18364b94ceaSJussi Kivilinna 18464b94ceaSJussi Kivilinna static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, 18564b94ceaSJussi Kivilinna struct blkcipher_walk *walk) 18664b94ceaSJussi Kivilinna { 18764b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 18864b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 18964b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 19064b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 19164b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 19264b94ceaSJussi Kivilinna u64 ivs[4 - 1]; 19364b94ceaSJussi Kivilinna u64 last_iv; 19464b94ceaSJussi Kivilinna 19564b94ceaSJussi Kivilinna /* Start of the last block. */ 19664b94ceaSJussi Kivilinna src += nbytes / bsize - 1; 19764b94ceaSJussi Kivilinna dst += nbytes / bsize - 1; 19864b94ceaSJussi Kivilinna 19964b94ceaSJussi Kivilinna last_iv = *src; 20064b94ceaSJussi Kivilinna 20164b94ceaSJussi Kivilinna /* Process four block batch */ 20264b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 20364b94ceaSJussi Kivilinna do { 20464b94ceaSJussi Kivilinna nbytes -= bsize * 4 - bsize; 20564b94ceaSJussi Kivilinna src -= 4 - 1; 20664b94ceaSJussi Kivilinna dst -= 4 - 1; 20764b94ceaSJussi Kivilinna 20864b94ceaSJussi Kivilinna ivs[0] = src[0]; 20964b94ceaSJussi Kivilinna ivs[1] = src[1]; 21064b94ceaSJussi Kivilinna ivs[2] = src[2]; 21164b94ceaSJussi Kivilinna 21264b94ceaSJussi Kivilinna blowfish_dec_blk_4way(ctx, (u8 *)dst, (u8 *)src); 21364b94ceaSJussi Kivilinna 21464b94ceaSJussi Kivilinna dst[1] ^= ivs[0]; 21564b94ceaSJussi Kivilinna dst[2] ^= ivs[1]; 21664b94ceaSJussi Kivilinna dst[3] ^= ivs[2]; 21764b94ceaSJussi Kivilinna 21864b94ceaSJussi Kivilinna nbytes -= bsize; 21964b94ceaSJussi Kivilinna if (nbytes < bsize) 22064b94ceaSJussi Kivilinna goto done; 22164b94ceaSJussi Kivilinna 22264b94ceaSJussi Kivilinna *dst ^= *(src - 1); 22364b94ceaSJussi Kivilinna src -= 1; 22464b94ceaSJussi Kivilinna dst -= 1; 22564b94ceaSJussi Kivilinna } while (nbytes >= bsize * 4); 22664b94ceaSJussi Kivilinna 22764b94ceaSJussi Kivilinna if (nbytes < bsize) 22864b94ceaSJussi Kivilinna goto done; 22964b94ceaSJussi Kivilinna } 23064b94ceaSJussi Kivilinna 23164b94ceaSJussi Kivilinna /* Handle leftovers */ 23264b94ceaSJussi Kivilinna for (;;) { 23364b94ceaSJussi Kivilinna blowfish_dec_blk(ctx, (u8 *)dst, (u8 *)src); 23464b94ceaSJussi Kivilinna 23564b94ceaSJussi Kivilinna nbytes -= bsize; 23664b94ceaSJussi Kivilinna if (nbytes < bsize) 23764b94ceaSJussi Kivilinna break; 23864b94ceaSJussi Kivilinna 23964b94ceaSJussi Kivilinna *dst ^= *(src - 1); 24064b94ceaSJussi Kivilinna src -= 1; 24164b94ceaSJussi Kivilinna dst -= 1; 24264b94ceaSJussi Kivilinna } 24364b94ceaSJussi Kivilinna 24464b94ceaSJussi Kivilinna done: 24564b94ceaSJussi Kivilinna *dst ^= *(u64 *)walk->iv; 24664b94ceaSJussi Kivilinna *(u64 *)walk->iv = last_iv; 24764b94ceaSJussi Kivilinna 24864b94ceaSJussi Kivilinna return nbytes; 24964b94ceaSJussi Kivilinna } 25064b94ceaSJussi Kivilinna 25164b94ceaSJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 25264b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 25364b94ceaSJussi Kivilinna { 25464b94ceaSJussi Kivilinna struct blkcipher_walk walk; 25564b94ceaSJussi Kivilinna int err; 25664b94ceaSJussi Kivilinna 25764b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 25864b94ceaSJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 25964b94ceaSJussi Kivilinna 26064b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes)) { 26164b94ceaSJussi Kivilinna nbytes = __cbc_decrypt(desc, &walk); 26264b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 26364b94ceaSJussi Kivilinna } 26464b94ceaSJussi Kivilinna 26564b94ceaSJussi Kivilinna return err; 26664b94ceaSJussi Kivilinna } 26764b94ceaSJussi Kivilinna 26864b94ceaSJussi Kivilinna static void ctr_crypt_final(struct bf_ctx *ctx, struct blkcipher_walk *walk) 26964b94ceaSJussi Kivilinna { 27064b94ceaSJussi Kivilinna u8 *ctrblk = walk->iv; 27164b94ceaSJussi Kivilinna u8 keystream[BF_BLOCK_SIZE]; 27264b94ceaSJussi Kivilinna u8 *src = walk->src.virt.addr; 27364b94ceaSJussi Kivilinna u8 *dst = walk->dst.virt.addr; 27464b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 27564b94ceaSJussi Kivilinna 27664b94ceaSJussi Kivilinna blowfish_enc_blk(ctx, keystream, ctrblk); 27764b94ceaSJussi Kivilinna crypto_xor(keystream, src, nbytes); 27864b94ceaSJussi Kivilinna memcpy(dst, keystream, nbytes); 27964b94ceaSJussi Kivilinna 28064b94ceaSJussi Kivilinna crypto_inc(ctrblk, BF_BLOCK_SIZE); 28164b94ceaSJussi Kivilinna } 28264b94ceaSJussi Kivilinna 28364b94ceaSJussi Kivilinna static unsigned int __ctr_crypt(struct blkcipher_desc *desc, 28464b94ceaSJussi Kivilinna struct blkcipher_walk *walk) 28564b94ceaSJussi Kivilinna { 28664b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 28764b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 28864b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 28964b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 29064b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 29164b94ceaSJussi Kivilinna u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv); 29264b94ceaSJussi Kivilinna __be64 ctrblocks[4]; 29364b94ceaSJussi Kivilinna 29464b94ceaSJussi Kivilinna /* Process four block batch */ 29564b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 29664b94ceaSJussi Kivilinna do { 29764b94ceaSJussi Kivilinna if (dst != src) { 29864b94ceaSJussi Kivilinna dst[0] = src[0]; 29964b94ceaSJussi Kivilinna dst[1] = src[1]; 30064b94ceaSJussi Kivilinna dst[2] = src[2]; 30164b94ceaSJussi Kivilinna dst[3] = src[3]; 30264b94ceaSJussi Kivilinna } 30364b94ceaSJussi Kivilinna 30464b94ceaSJussi Kivilinna /* create ctrblks for parallel encrypt */ 30564b94ceaSJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 30664b94ceaSJussi Kivilinna ctrblocks[1] = cpu_to_be64(ctrblk++); 30764b94ceaSJussi Kivilinna ctrblocks[2] = cpu_to_be64(ctrblk++); 30864b94ceaSJussi Kivilinna ctrblocks[3] = cpu_to_be64(ctrblk++); 30964b94ceaSJussi Kivilinna 31064b94ceaSJussi Kivilinna blowfish_enc_blk_xor_4way(ctx, (u8 *)dst, 31164b94ceaSJussi Kivilinna (u8 *)ctrblocks); 31264b94ceaSJussi Kivilinna 31364b94ceaSJussi Kivilinna src += 4; 31464b94ceaSJussi Kivilinna dst += 4; 31564b94ceaSJussi Kivilinna } while ((nbytes -= bsize * 4) >= bsize * 4); 31664b94ceaSJussi Kivilinna 31764b94ceaSJussi Kivilinna if (nbytes < bsize) 31864b94ceaSJussi Kivilinna goto done; 31964b94ceaSJussi Kivilinna } 32064b94ceaSJussi Kivilinna 32164b94ceaSJussi Kivilinna /* Handle leftovers */ 32264b94ceaSJussi Kivilinna do { 32364b94ceaSJussi Kivilinna if (dst != src) 32464b94ceaSJussi Kivilinna *dst = *src; 32564b94ceaSJussi Kivilinna 32664b94ceaSJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 32764b94ceaSJussi Kivilinna 32864b94ceaSJussi Kivilinna blowfish_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks); 32964b94ceaSJussi Kivilinna 33064b94ceaSJussi Kivilinna src += 1; 33164b94ceaSJussi Kivilinna dst += 1; 33264b94ceaSJussi Kivilinna } while ((nbytes -= bsize) >= bsize); 33364b94ceaSJussi Kivilinna 33464b94ceaSJussi Kivilinna done: 33564b94ceaSJussi Kivilinna *(__be64 *)walk->iv = cpu_to_be64(ctrblk); 33664b94ceaSJussi Kivilinna return nbytes; 33764b94ceaSJussi Kivilinna } 33864b94ceaSJussi Kivilinna 33964b94ceaSJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, 34064b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 34164b94ceaSJussi Kivilinna { 34264b94ceaSJussi Kivilinna struct blkcipher_walk walk; 34364b94ceaSJussi Kivilinna int err; 34464b94ceaSJussi Kivilinna 34564b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 34664b94ceaSJussi Kivilinna err = blkcipher_walk_virt_block(desc, &walk, BF_BLOCK_SIZE); 34764b94ceaSJussi Kivilinna 34864b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes) >= BF_BLOCK_SIZE) { 34964b94ceaSJussi Kivilinna nbytes = __ctr_crypt(desc, &walk); 35064b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 35164b94ceaSJussi Kivilinna } 35264b94ceaSJussi Kivilinna 35364b94ceaSJussi Kivilinna if (walk.nbytes) { 35464b94ceaSJussi Kivilinna ctr_crypt_final(crypto_blkcipher_ctx(desc->tfm), &walk); 35564b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, 0); 35664b94ceaSJussi Kivilinna } 35764b94ceaSJussi Kivilinna 35864b94ceaSJussi Kivilinna return err; 35964b94ceaSJussi Kivilinna } 36064b94ceaSJussi Kivilinna 361d433208cSJussi Kivilinna static struct crypto_alg bf_algs[4] = { { 362d433208cSJussi Kivilinna .cra_name = "blowfish", 363d433208cSJussi Kivilinna .cra_driver_name = "blowfish-asm", 364d433208cSJussi Kivilinna .cra_priority = 200, 365d433208cSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 366d433208cSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 367d433208cSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 368*919e2c32SJussi Kivilinna .cra_alignmask = 0, 369d433208cSJussi Kivilinna .cra_module = THIS_MODULE, 370d433208cSJussi Kivilinna .cra_list = LIST_HEAD_INIT(bf_algs[0].cra_list), 371d433208cSJussi Kivilinna .cra_u = { 372d433208cSJussi Kivilinna .cipher = { 373d433208cSJussi Kivilinna .cia_min_keysize = BF_MIN_KEY_SIZE, 374d433208cSJussi Kivilinna .cia_max_keysize = BF_MAX_KEY_SIZE, 375d433208cSJussi Kivilinna .cia_setkey = blowfish_setkey, 376d433208cSJussi Kivilinna .cia_encrypt = blowfish_encrypt, 377d433208cSJussi Kivilinna .cia_decrypt = blowfish_decrypt, 378d433208cSJussi Kivilinna } 379d433208cSJussi Kivilinna } 380d433208cSJussi Kivilinna }, { 381d433208cSJussi Kivilinna .cra_name = "ecb(blowfish)", 382d433208cSJussi Kivilinna .cra_driver_name = "ecb-blowfish-asm", 383d433208cSJussi Kivilinna .cra_priority = 300, 384d433208cSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 385d433208cSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 386d433208cSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 387d433208cSJussi Kivilinna .cra_alignmask = 0, 388d433208cSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 389d433208cSJussi Kivilinna .cra_module = THIS_MODULE, 390d433208cSJussi Kivilinna .cra_list = LIST_HEAD_INIT(bf_algs[1].cra_list), 391d433208cSJussi Kivilinna .cra_u = { 392d433208cSJussi Kivilinna .blkcipher = { 393d433208cSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 394d433208cSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 395d433208cSJussi Kivilinna .setkey = blowfish_setkey, 396d433208cSJussi Kivilinna .encrypt = ecb_encrypt, 397d433208cSJussi Kivilinna .decrypt = ecb_decrypt, 398d433208cSJussi Kivilinna }, 399d433208cSJussi Kivilinna }, 400d433208cSJussi Kivilinna }, { 401d433208cSJussi Kivilinna .cra_name = "cbc(blowfish)", 402d433208cSJussi Kivilinna .cra_driver_name = "cbc-blowfish-asm", 403d433208cSJussi Kivilinna .cra_priority = 300, 404d433208cSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 405d433208cSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 406d433208cSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 407d433208cSJussi Kivilinna .cra_alignmask = 0, 408d433208cSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 409d433208cSJussi Kivilinna .cra_module = THIS_MODULE, 410d433208cSJussi Kivilinna .cra_list = LIST_HEAD_INIT(bf_algs[2].cra_list), 411d433208cSJussi Kivilinna .cra_u = { 412d433208cSJussi Kivilinna .blkcipher = { 413d433208cSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 414d433208cSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 415d433208cSJussi Kivilinna .ivsize = BF_BLOCK_SIZE, 416d433208cSJussi Kivilinna .setkey = blowfish_setkey, 417d433208cSJussi Kivilinna .encrypt = cbc_encrypt, 418d433208cSJussi Kivilinna .decrypt = cbc_decrypt, 419d433208cSJussi Kivilinna }, 420d433208cSJussi Kivilinna }, 421d433208cSJussi Kivilinna }, { 42264b94ceaSJussi Kivilinna .cra_name = "ctr(blowfish)", 42364b94ceaSJussi Kivilinna .cra_driver_name = "ctr-blowfish-asm", 42464b94ceaSJussi Kivilinna .cra_priority = 300, 42564b94ceaSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 426a516ebafSJussi Kivilinna .cra_blocksize = 1, 42764b94ceaSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 42864b94ceaSJussi Kivilinna .cra_alignmask = 0, 42964b94ceaSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 43064b94ceaSJussi Kivilinna .cra_module = THIS_MODULE, 431d433208cSJussi Kivilinna .cra_list = LIST_HEAD_INIT(bf_algs[3].cra_list), 43264b94ceaSJussi Kivilinna .cra_u = { 43364b94ceaSJussi Kivilinna .blkcipher = { 43464b94ceaSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 43564b94ceaSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 43664b94ceaSJussi Kivilinna .ivsize = BF_BLOCK_SIZE, 43764b94ceaSJussi Kivilinna .setkey = blowfish_setkey, 43864b94ceaSJussi Kivilinna .encrypt = ctr_crypt, 43964b94ceaSJussi Kivilinna .decrypt = ctr_crypt, 44064b94ceaSJussi Kivilinna }, 44164b94ceaSJussi Kivilinna }, 442d433208cSJussi Kivilinna } }; 44364b94ceaSJussi Kivilinna 4444c58464bSJussi Kivilinna static bool is_blacklisted_cpu(void) 4454c58464bSJussi Kivilinna { 4464c58464bSJussi Kivilinna if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL) 4474c58464bSJussi Kivilinna return false; 4484c58464bSJussi Kivilinna 4494c58464bSJussi Kivilinna if (boot_cpu_data.x86 == 0x0f) { 4504c58464bSJussi Kivilinna /* 4514c58464bSJussi Kivilinna * On Pentium 4, blowfish-x86_64 is slower than generic C 4524c58464bSJussi Kivilinna * implementation because use of 64bit rotates (which are really 4534c58464bSJussi Kivilinna * slow on P4). Therefore blacklist P4s. 4544c58464bSJussi Kivilinna */ 4554c58464bSJussi Kivilinna return true; 4564c58464bSJussi Kivilinna } 4574c58464bSJussi Kivilinna 4584c58464bSJussi Kivilinna return false; 4594c58464bSJussi Kivilinna } 4604c58464bSJussi Kivilinna 4614c58464bSJussi Kivilinna static int force; 4624c58464bSJussi Kivilinna module_param(force, int, 0); 4634c58464bSJussi Kivilinna MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist"); 4644c58464bSJussi Kivilinna 46564b94ceaSJussi Kivilinna static int __init init(void) 46664b94ceaSJussi Kivilinna { 4674c58464bSJussi Kivilinna if (!force && is_blacklisted_cpu()) { 4684c58464bSJussi Kivilinna printk(KERN_INFO 4694c58464bSJussi Kivilinna "blowfish-x86_64: performance on this CPU " 4704c58464bSJussi Kivilinna "would be suboptimal: disabling " 4714c58464bSJussi Kivilinna "blowfish-x86_64.\n"); 4724c58464bSJussi Kivilinna return -ENODEV; 4734c58464bSJussi Kivilinna } 4744c58464bSJussi Kivilinna 475d433208cSJussi Kivilinna return crypto_register_algs(bf_algs, ARRAY_SIZE(bf_algs)); 47664b94ceaSJussi Kivilinna } 47764b94ceaSJussi Kivilinna 47864b94ceaSJussi Kivilinna static void __exit fini(void) 47964b94ceaSJussi Kivilinna { 480d433208cSJussi Kivilinna crypto_unregister_algs(bf_algs, ARRAY_SIZE(bf_algs)); 48164b94ceaSJussi Kivilinna } 48264b94ceaSJussi Kivilinna 48364b94ceaSJussi Kivilinna module_init(init); 48464b94ceaSJussi Kivilinna module_exit(fini); 48564b94ceaSJussi Kivilinna 48664b94ceaSJussi Kivilinna MODULE_LICENSE("GPL"); 48764b94ceaSJussi Kivilinna MODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized"); 48864b94ceaSJussi Kivilinna MODULE_ALIAS("blowfish"); 48964b94ceaSJussi Kivilinna MODULE_ALIAS("blowfish-asm"); 490