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 2864b94ceaSJussi Kivilinna #include <crypto/blowfish.h> 2964b94ceaSJussi Kivilinna #include <linux/crypto.h> 3064b94ceaSJussi Kivilinna #include <linux/init.h> 3164b94ceaSJussi Kivilinna #include <linux/module.h> 3264b94ceaSJussi Kivilinna #include <linux/types.h> 3364b94ceaSJussi Kivilinna #include <crypto/algapi.h> 3464b94ceaSJussi Kivilinna 3564b94ceaSJussi Kivilinna /* regular block cipher functions */ 3664b94ceaSJussi Kivilinna asmlinkage void __blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src, 3764b94ceaSJussi Kivilinna bool xor); 3864b94ceaSJussi Kivilinna asmlinkage void blowfish_dec_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src); 3964b94ceaSJussi Kivilinna 4064b94ceaSJussi Kivilinna /* 4-way parallel cipher functions */ 4164b94ceaSJussi Kivilinna asmlinkage void __blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst, 4264b94ceaSJussi Kivilinna const u8 *src, bool xor); 4364b94ceaSJussi Kivilinna asmlinkage void blowfish_dec_blk_4way(struct bf_ctx *ctx, u8 *dst, 4464b94ceaSJussi Kivilinna const u8 *src); 4564b94ceaSJussi Kivilinna 4664b94ceaSJussi Kivilinna static inline void blowfish_enc_blk(struct bf_ctx *ctx, u8 *dst, const u8 *src) 4764b94ceaSJussi Kivilinna { 4864b94ceaSJussi Kivilinna __blowfish_enc_blk(ctx, dst, src, false); 4964b94ceaSJussi Kivilinna } 5064b94ceaSJussi Kivilinna 5164b94ceaSJussi Kivilinna static inline void blowfish_enc_blk_xor(struct bf_ctx *ctx, u8 *dst, 5264b94ceaSJussi Kivilinna const u8 *src) 5364b94ceaSJussi Kivilinna { 5464b94ceaSJussi Kivilinna __blowfish_enc_blk(ctx, dst, src, true); 5564b94ceaSJussi Kivilinna } 5664b94ceaSJussi Kivilinna 5764b94ceaSJussi Kivilinna static inline void blowfish_enc_blk_4way(struct bf_ctx *ctx, u8 *dst, 5864b94ceaSJussi Kivilinna const u8 *src) 5964b94ceaSJussi Kivilinna { 6064b94ceaSJussi Kivilinna __blowfish_enc_blk_4way(ctx, dst, src, false); 6164b94ceaSJussi Kivilinna } 6264b94ceaSJussi Kivilinna 6364b94ceaSJussi Kivilinna static inline void blowfish_enc_blk_xor_4way(struct bf_ctx *ctx, u8 *dst, 6464b94ceaSJussi Kivilinna const u8 *src) 6564b94ceaSJussi Kivilinna { 6664b94ceaSJussi Kivilinna __blowfish_enc_blk_4way(ctx, dst, src, true); 6764b94ceaSJussi Kivilinna } 6864b94ceaSJussi Kivilinna 6964b94ceaSJussi Kivilinna static void blowfish_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 7064b94ceaSJussi Kivilinna { 7164b94ceaSJussi Kivilinna blowfish_enc_blk(crypto_tfm_ctx(tfm), dst, src); 7264b94ceaSJussi Kivilinna } 7364b94ceaSJussi Kivilinna 7464b94ceaSJussi Kivilinna static void blowfish_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) 7564b94ceaSJussi Kivilinna { 7664b94ceaSJussi Kivilinna blowfish_dec_blk(crypto_tfm_ctx(tfm), dst, src); 7764b94ceaSJussi Kivilinna } 7864b94ceaSJussi Kivilinna 7964b94ceaSJussi Kivilinna static struct crypto_alg bf_alg = { 8064b94ceaSJussi Kivilinna .cra_name = "blowfish", 8164b94ceaSJussi Kivilinna .cra_driver_name = "blowfish-asm", 8264b94ceaSJussi Kivilinna .cra_priority = 200, 8364b94ceaSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_CIPHER, 8464b94ceaSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 8564b94ceaSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 8664b94ceaSJussi Kivilinna .cra_alignmask = 3, 8764b94ceaSJussi Kivilinna .cra_module = THIS_MODULE, 8864b94ceaSJussi Kivilinna .cra_list = LIST_HEAD_INIT(bf_alg.cra_list), 8964b94ceaSJussi Kivilinna .cra_u = { 9064b94ceaSJussi Kivilinna .cipher = { 9164b94ceaSJussi Kivilinna .cia_min_keysize = BF_MIN_KEY_SIZE, 9264b94ceaSJussi Kivilinna .cia_max_keysize = BF_MAX_KEY_SIZE, 9364b94ceaSJussi Kivilinna .cia_setkey = blowfish_setkey, 9464b94ceaSJussi Kivilinna .cia_encrypt = blowfish_encrypt, 9564b94ceaSJussi Kivilinna .cia_decrypt = blowfish_decrypt, 9664b94ceaSJussi Kivilinna } 9764b94ceaSJussi Kivilinna } 9864b94ceaSJussi Kivilinna }; 9964b94ceaSJussi Kivilinna 10064b94ceaSJussi Kivilinna static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, 10164b94ceaSJussi Kivilinna void (*fn)(struct bf_ctx *, u8 *, const u8 *), 10264b94ceaSJussi Kivilinna void (*fn_4way)(struct bf_ctx *, u8 *, const u8 *)) 10364b94ceaSJussi Kivilinna { 10464b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 10564b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 10664b94ceaSJussi Kivilinna unsigned int nbytes; 10764b94ceaSJussi Kivilinna int err; 10864b94ceaSJussi Kivilinna 10964b94ceaSJussi Kivilinna err = blkcipher_walk_virt(desc, walk); 11064b94ceaSJussi Kivilinna 11164b94ceaSJussi Kivilinna while ((nbytes = walk->nbytes)) { 11264b94ceaSJussi Kivilinna u8 *wsrc = walk->src.virt.addr; 11364b94ceaSJussi Kivilinna u8 *wdst = walk->dst.virt.addr; 11464b94ceaSJussi Kivilinna 11564b94ceaSJussi Kivilinna /* Process four block batch */ 11664b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 11764b94ceaSJussi Kivilinna do { 11864b94ceaSJussi Kivilinna fn_4way(ctx, wdst, wsrc); 11964b94ceaSJussi Kivilinna 12064b94ceaSJussi Kivilinna wsrc += bsize * 4; 12164b94ceaSJussi Kivilinna wdst += bsize * 4; 12264b94ceaSJussi Kivilinna nbytes -= bsize * 4; 12364b94ceaSJussi Kivilinna } while (nbytes >= bsize * 4); 12464b94ceaSJussi Kivilinna 12564b94ceaSJussi Kivilinna if (nbytes < bsize) 12664b94ceaSJussi Kivilinna goto done; 12764b94ceaSJussi Kivilinna } 12864b94ceaSJussi Kivilinna 12964b94ceaSJussi Kivilinna /* Handle leftovers */ 13064b94ceaSJussi Kivilinna do { 13164b94ceaSJussi Kivilinna fn(ctx, wdst, wsrc); 13264b94ceaSJussi Kivilinna 13364b94ceaSJussi Kivilinna wsrc += bsize; 13464b94ceaSJussi Kivilinna wdst += bsize; 13564b94ceaSJussi Kivilinna nbytes -= bsize; 13664b94ceaSJussi Kivilinna } while (nbytes >= bsize); 13764b94ceaSJussi Kivilinna 13864b94ceaSJussi Kivilinna done: 13964b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, walk, nbytes); 14064b94ceaSJussi Kivilinna } 14164b94ceaSJussi Kivilinna 14264b94ceaSJussi Kivilinna return err; 14364b94ceaSJussi Kivilinna } 14464b94ceaSJussi Kivilinna 14564b94ceaSJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 14664b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 14764b94ceaSJussi Kivilinna { 14864b94ceaSJussi Kivilinna struct blkcipher_walk walk; 14964b94ceaSJussi Kivilinna 15064b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 15164b94ceaSJussi Kivilinna return ecb_crypt(desc, &walk, blowfish_enc_blk, blowfish_enc_blk_4way); 15264b94ceaSJussi Kivilinna } 15364b94ceaSJussi Kivilinna 15464b94ceaSJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 15564b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 15664b94ceaSJussi Kivilinna { 15764b94ceaSJussi Kivilinna struct blkcipher_walk walk; 15864b94ceaSJussi Kivilinna 15964b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 16064b94ceaSJussi Kivilinna return ecb_crypt(desc, &walk, blowfish_dec_blk, blowfish_dec_blk_4way); 16164b94ceaSJussi Kivilinna } 16264b94ceaSJussi Kivilinna 16364b94ceaSJussi Kivilinna static struct crypto_alg blk_ecb_alg = { 16464b94ceaSJussi Kivilinna .cra_name = "ecb(blowfish)", 16564b94ceaSJussi Kivilinna .cra_driver_name = "ecb-blowfish-asm", 16664b94ceaSJussi Kivilinna .cra_priority = 300, 16764b94ceaSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 16864b94ceaSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 16964b94ceaSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 17064b94ceaSJussi Kivilinna .cra_alignmask = 0, 17164b94ceaSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 17264b94ceaSJussi Kivilinna .cra_module = THIS_MODULE, 17364b94ceaSJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), 17464b94ceaSJussi Kivilinna .cra_u = { 17564b94ceaSJussi Kivilinna .blkcipher = { 17664b94ceaSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 17764b94ceaSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 17864b94ceaSJussi Kivilinna .setkey = blowfish_setkey, 17964b94ceaSJussi Kivilinna .encrypt = ecb_encrypt, 18064b94ceaSJussi Kivilinna .decrypt = ecb_decrypt, 18164b94ceaSJussi Kivilinna }, 18264b94ceaSJussi Kivilinna }, 18364b94ceaSJussi Kivilinna }; 18464b94ceaSJussi Kivilinna 18564b94ceaSJussi Kivilinna static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, 18664b94ceaSJussi Kivilinna struct blkcipher_walk *walk) 18764b94ceaSJussi Kivilinna { 18864b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 18964b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 19064b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 19164b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 19264b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 19364b94ceaSJussi Kivilinna u64 *iv = (u64 *)walk->iv; 19464b94ceaSJussi Kivilinna 19564b94ceaSJussi Kivilinna do { 19664b94ceaSJussi Kivilinna *dst = *src ^ *iv; 19764b94ceaSJussi Kivilinna blowfish_enc_blk(ctx, (u8 *)dst, (u8 *)dst); 19864b94ceaSJussi Kivilinna iv = dst; 19964b94ceaSJussi Kivilinna 20064b94ceaSJussi Kivilinna src += 1; 20164b94ceaSJussi Kivilinna dst += 1; 20264b94ceaSJussi Kivilinna nbytes -= bsize; 20364b94ceaSJussi Kivilinna } while (nbytes >= bsize); 20464b94ceaSJussi Kivilinna 20564b94ceaSJussi Kivilinna *(u64 *)walk->iv = *iv; 20664b94ceaSJussi Kivilinna return nbytes; 20764b94ceaSJussi Kivilinna } 20864b94ceaSJussi Kivilinna 20964b94ceaSJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 21064b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 21164b94ceaSJussi Kivilinna { 21264b94ceaSJussi Kivilinna struct blkcipher_walk walk; 21364b94ceaSJussi Kivilinna int err; 21464b94ceaSJussi Kivilinna 21564b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 21664b94ceaSJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 21764b94ceaSJussi Kivilinna 21864b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes)) { 21964b94ceaSJussi Kivilinna nbytes = __cbc_encrypt(desc, &walk); 22064b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 22164b94ceaSJussi Kivilinna } 22264b94ceaSJussi Kivilinna 22364b94ceaSJussi Kivilinna return err; 22464b94ceaSJussi Kivilinna } 22564b94ceaSJussi Kivilinna 22664b94ceaSJussi Kivilinna static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, 22764b94ceaSJussi Kivilinna struct blkcipher_walk *walk) 22864b94ceaSJussi Kivilinna { 22964b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 23064b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 23164b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 23264b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 23364b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 23464b94ceaSJussi Kivilinna u64 ivs[4 - 1]; 23564b94ceaSJussi Kivilinna u64 last_iv; 23664b94ceaSJussi Kivilinna 23764b94ceaSJussi Kivilinna /* Start of the last block. */ 23864b94ceaSJussi Kivilinna src += nbytes / bsize - 1; 23964b94ceaSJussi Kivilinna dst += nbytes / bsize - 1; 24064b94ceaSJussi Kivilinna 24164b94ceaSJussi Kivilinna last_iv = *src; 24264b94ceaSJussi Kivilinna 24364b94ceaSJussi Kivilinna /* Process four block batch */ 24464b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 24564b94ceaSJussi Kivilinna do { 24664b94ceaSJussi Kivilinna nbytes -= bsize * 4 - bsize; 24764b94ceaSJussi Kivilinna src -= 4 - 1; 24864b94ceaSJussi Kivilinna dst -= 4 - 1; 24964b94ceaSJussi Kivilinna 25064b94ceaSJussi Kivilinna ivs[0] = src[0]; 25164b94ceaSJussi Kivilinna ivs[1] = src[1]; 25264b94ceaSJussi Kivilinna ivs[2] = src[2]; 25364b94ceaSJussi Kivilinna 25464b94ceaSJussi Kivilinna blowfish_dec_blk_4way(ctx, (u8 *)dst, (u8 *)src); 25564b94ceaSJussi Kivilinna 25664b94ceaSJussi Kivilinna dst[1] ^= ivs[0]; 25764b94ceaSJussi Kivilinna dst[2] ^= ivs[1]; 25864b94ceaSJussi Kivilinna dst[3] ^= ivs[2]; 25964b94ceaSJussi Kivilinna 26064b94ceaSJussi Kivilinna nbytes -= bsize; 26164b94ceaSJussi Kivilinna if (nbytes < bsize) 26264b94ceaSJussi Kivilinna goto done; 26364b94ceaSJussi Kivilinna 26464b94ceaSJussi Kivilinna *dst ^= *(src - 1); 26564b94ceaSJussi Kivilinna src -= 1; 26664b94ceaSJussi Kivilinna dst -= 1; 26764b94ceaSJussi Kivilinna } while (nbytes >= bsize * 4); 26864b94ceaSJussi Kivilinna 26964b94ceaSJussi Kivilinna if (nbytes < bsize) 27064b94ceaSJussi Kivilinna goto done; 27164b94ceaSJussi Kivilinna } 27264b94ceaSJussi Kivilinna 27364b94ceaSJussi Kivilinna /* Handle leftovers */ 27464b94ceaSJussi Kivilinna for (;;) { 27564b94ceaSJussi Kivilinna blowfish_dec_blk(ctx, (u8 *)dst, (u8 *)src); 27664b94ceaSJussi Kivilinna 27764b94ceaSJussi Kivilinna nbytes -= bsize; 27864b94ceaSJussi Kivilinna if (nbytes < bsize) 27964b94ceaSJussi Kivilinna break; 28064b94ceaSJussi Kivilinna 28164b94ceaSJussi Kivilinna *dst ^= *(src - 1); 28264b94ceaSJussi Kivilinna src -= 1; 28364b94ceaSJussi Kivilinna dst -= 1; 28464b94ceaSJussi Kivilinna } 28564b94ceaSJussi Kivilinna 28664b94ceaSJussi Kivilinna done: 28764b94ceaSJussi Kivilinna *dst ^= *(u64 *)walk->iv; 28864b94ceaSJussi Kivilinna *(u64 *)walk->iv = last_iv; 28964b94ceaSJussi Kivilinna 29064b94ceaSJussi Kivilinna return nbytes; 29164b94ceaSJussi Kivilinna } 29264b94ceaSJussi Kivilinna 29364b94ceaSJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 29464b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 29564b94ceaSJussi Kivilinna { 29664b94ceaSJussi Kivilinna struct blkcipher_walk walk; 29764b94ceaSJussi Kivilinna int err; 29864b94ceaSJussi Kivilinna 29964b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 30064b94ceaSJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 30164b94ceaSJussi Kivilinna 30264b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes)) { 30364b94ceaSJussi Kivilinna nbytes = __cbc_decrypt(desc, &walk); 30464b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 30564b94ceaSJussi Kivilinna } 30664b94ceaSJussi Kivilinna 30764b94ceaSJussi Kivilinna return err; 30864b94ceaSJussi Kivilinna } 30964b94ceaSJussi Kivilinna 31064b94ceaSJussi Kivilinna static struct crypto_alg blk_cbc_alg = { 31164b94ceaSJussi Kivilinna .cra_name = "cbc(blowfish)", 31264b94ceaSJussi Kivilinna .cra_driver_name = "cbc-blowfish-asm", 31364b94ceaSJussi Kivilinna .cra_priority = 300, 31464b94ceaSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 31564b94ceaSJussi Kivilinna .cra_blocksize = BF_BLOCK_SIZE, 31664b94ceaSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 31764b94ceaSJussi Kivilinna .cra_alignmask = 0, 31864b94ceaSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 31964b94ceaSJussi Kivilinna .cra_module = THIS_MODULE, 32064b94ceaSJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), 32164b94ceaSJussi Kivilinna .cra_u = { 32264b94ceaSJussi Kivilinna .blkcipher = { 32364b94ceaSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 32464b94ceaSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 32564b94ceaSJussi Kivilinna .ivsize = BF_BLOCK_SIZE, 32664b94ceaSJussi Kivilinna .setkey = blowfish_setkey, 32764b94ceaSJussi Kivilinna .encrypt = cbc_encrypt, 32864b94ceaSJussi Kivilinna .decrypt = cbc_decrypt, 32964b94ceaSJussi Kivilinna }, 33064b94ceaSJussi Kivilinna }, 33164b94ceaSJussi Kivilinna }; 33264b94ceaSJussi Kivilinna 33364b94ceaSJussi Kivilinna static void ctr_crypt_final(struct bf_ctx *ctx, struct blkcipher_walk *walk) 33464b94ceaSJussi Kivilinna { 33564b94ceaSJussi Kivilinna u8 *ctrblk = walk->iv; 33664b94ceaSJussi Kivilinna u8 keystream[BF_BLOCK_SIZE]; 33764b94ceaSJussi Kivilinna u8 *src = walk->src.virt.addr; 33864b94ceaSJussi Kivilinna u8 *dst = walk->dst.virt.addr; 33964b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 34064b94ceaSJussi Kivilinna 34164b94ceaSJussi Kivilinna blowfish_enc_blk(ctx, keystream, ctrblk); 34264b94ceaSJussi Kivilinna crypto_xor(keystream, src, nbytes); 34364b94ceaSJussi Kivilinna memcpy(dst, keystream, nbytes); 34464b94ceaSJussi Kivilinna 34564b94ceaSJussi Kivilinna crypto_inc(ctrblk, BF_BLOCK_SIZE); 34664b94ceaSJussi Kivilinna } 34764b94ceaSJussi Kivilinna 34864b94ceaSJussi Kivilinna static unsigned int __ctr_crypt(struct blkcipher_desc *desc, 34964b94ceaSJussi Kivilinna struct blkcipher_walk *walk) 35064b94ceaSJussi Kivilinna { 35164b94ceaSJussi Kivilinna struct bf_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 35264b94ceaSJussi Kivilinna unsigned int bsize = BF_BLOCK_SIZE; 35364b94ceaSJussi Kivilinna unsigned int nbytes = walk->nbytes; 35464b94ceaSJussi Kivilinna u64 *src = (u64 *)walk->src.virt.addr; 35564b94ceaSJussi Kivilinna u64 *dst = (u64 *)walk->dst.virt.addr; 35664b94ceaSJussi Kivilinna u64 ctrblk = be64_to_cpu(*(__be64 *)walk->iv); 35764b94ceaSJussi Kivilinna __be64 ctrblocks[4]; 35864b94ceaSJussi Kivilinna 35964b94ceaSJussi Kivilinna /* Process four block batch */ 36064b94ceaSJussi Kivilinna if (nbytes >= bsize * 4) { 36164b94ceaSJussi Kivilinna do { 36264b94ceaSJussi Kivilinna if (dst != src) { 36364b94ceaSJussi Kivilinna dst[0] = src[0]; 36464b94ceaSJussi Kivilinna dst[1] = src[1]; 36564b94ceaSJussi Kivilinna dst[2] = src[2]; 36664b94ceaSJussi Kivilinna dst[3] = src[3]; 36764b94ceaSJussi Kivilinna } 36864b94ceaSJussi Kivilinna 36964b94ceaSJussi Kivilinna /* create ctrblks for parallel encrypt */ 37064b94ceaSJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 37164b94ceaSJussi Kivilinna ctrblocks[1] = cpu_to_be64(ctrblk++); 37264b94ceaSJussi Kivilinna ctrblocks[2] = cpu_to_be64(ctrblk++); 37364b94ceaSJussi Kivilinna ctrblocks[3] = cpu_to_be64(ctrblk++); 37464b94ceaSJussi Kivilinna 37564b94ceaSJussi Kivilinna blowfish_enc_blk_xor_4way(ctx, (u8 *)dst, 37664b94ceaSJussi Kivilinna (u8 *)ctrblocks); 37764b94ceaSJussi Kivilinna 37864b94ceaSJussi Kivilinna src += 4; 37964b94ceaSJussi Kivilinna dst += 4; 38064b94ceaSJussi Kivilinna } while ((nbytes -= bsize * 4) >= bsize * 4); 38164b94ceaSJussi Kivilinna 38264b94ceaSJussi Kivilinna if (nbytes < bsize) 38364b94ceaSJussi Kivilinna goto done; 38464b94ceaSJussi Kivilinna } 38564b94ceaSJussi Kivilinna 38664b94ceaSJussi Kivilinna /* Handle leftovers */ 38764b94ceaSJussi Kivilinna do { 38864b94ceaSJussi Kivilinna if (dst != src) 38964b94ceaSJussi Kivilinna *dst = *src; 39064b94ceaSJussi Kivilinna 39164b94ceaSJussi Kivilinna ctrblocks[0] = cpu_to_be64(ctrblk++); 39264b94ceaSJussi Kivilinna 39364b94ceaSJussi Kivilinna blowfish_enc_blk_xor(ctx, (u8 *)dst, (u8 *)ctrblocks); 39464b94ceaSJussi Kivilinna 39564b94ceaSJussi Kivilinna src += 1; 39664b94ceaSJussi Kivilinna dst += 1; 39764b94ceaSJussi Kivilinna } while ((nbytes -= bsize) >= bsize); 39864b94ceaSJussi Kivilinna 39964b94ceaSJussi Kivilinna done: 40064b94ceaSJussi Kivilinna *(__be64 *)walk->iv = cpu_to_be64(ctrblk); 40164b94ceaSJussi Kivilinna return nbytes; 40264b94ceaSJussi Kivilinna } 40364b94ceaSJussi Kivilinna 40464b94ceaSJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, 40564b94ceaSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 40664b94ceaSJussi Kivilinna { 40764b94ceaSJussi Kivilinna struct blkcipher_walk walk; 40864b94ceaSJussi Kivilinna int err; 40964b94ceaSJussi Kivilinna 41064b94ceaSJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 41164b94ceaSJussi Kivilinna err = blkcipher_walk_virt_block(desc, &walk, BF_BLOCK_SIZE); 41264b94ceaSJussi Kivilinna 41364b94ceaSJussi Kivilinna while ((nbytes = walk.nbytes) >= BF_BLOCK_SIZE) { 41464b94ceaSJussi Kivilinna nbytes = __ctr_crypt(desc, &walk); 41564b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 41664b94ceaSJussi Kivilinna } 41764b94ceaSJussi Kivilinna 41864b94ceaSJussi Kivilinna if (walk.nbytes) { 41964b94ceaSJussi Kivilinna ctr_crypt_final(crypto_blkcipher_ctx(desc->tfm), &walk); 42064b94ceaSJussi Kivilinna err = blkcipher_walk_done(desc, &walk, 0); 42164b94ceaSJussi Kivilinna } 42264b94ceaSJussi Kivilinna 42364b94ceaSJussi Kivilinna return err; 42464b94ceaSJussi Kivilinna } 42564b94ceaSJussi Kivilinna 42664b94ceaSJussi Kivilinna static struct crypto_alg blk_ctr_alg = { 42764b94ceaSJussi Kivilinna .cra_name = "ctr(blowfish)", 42864b94ceaSJussi Kivilinna .cra_driver_name = "ctr-blowfish-asm", 42964b94ceaSJussi Kivilinna .cra_priority = 300, 43064b94ceaSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 431*a516ebafSJussi Kivilinna .cra_blocksize = 1, 43264b94ceaSJussi Kivilinna .cra_ctxsize = sizeof(struct bf_ctx), 43364b94ceaSJussi Kivilinna .cra_alignmask = 0, 43464b94ceaSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 43564b94ceaSJussi Kivilinna .cra_module = THIS_MODULE, 43664b94ceaSJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), 43764b94ceaSJussi Kivilinna .cra_u = { 43864b94ceaSJussi Kivilinna .blkcipher = { 43964b94ceaSJussi Kivilinna .min_keysize = BF_MIN_KEY_SIZE, 44064b94ceaSJussi Kivilinna .max_keysize = BF_MAX_KEY_SIZE, 44164b94ceaSJussi Kivilinna .ivsize = BF_BLOCK_SIZE, 44264b94ceaSJussi Kivilinna .setkey = blowfish_setkey, 44364b94ceaSJussi Kivilinna .encrypt = ctr_crypt, 44464b94ceaSJussi Kivilinna .decrypt = ctr_crypt, 44564b94ceaSJussi Kivilinna }, 44664b94ceaSJussi Kivilinna }, 44764b94ceaSJussi Kivilinna }; 44864b94ceaSJussi Kivilinna 44964b94ceaSJussi Kivilinna static int __init init(void) 45064b94ceaSJussi Kivilinna { 45164b94ceaSJussi Kivilinna int err; 45264b94ceaSJussi Kivilinna 45364b94ceaSJussi Kivilinna err = crypto_register_alg(&bf_alg); 45464b94ceaSJussi Kivilinna if (err) 45564b94ceaSJussi Kivilinna goto bf_err; 45664b94ceaSJussi Kivilinna err = crypto_register_alg(&blk_ecb_alg); 45764b94ceaSJussi Kivilinna if (err) 45864b94ceaSJussi Kivilinna goto ecb_err; 45964b94ceaSJussi Kivilinna err = crypto_register_alg(&blk_cbc_alg); 46064b94ceaSJussi Kivilinna if (err) 46164b94ceaSJussi Kivilinna goto cbc_err; 46264b94ceaSJussi Kivilinna err = crypto_register_alg(&blk_ctr_alg); 46364b94ceaSJussi Kivilinna if (err) 46464b94ceaSJussi Kivilinna goto ctr_err; 46564b94ceaSJussi Kivilinna 46664b94ceaSJussi Kivilinna return 0; 46764b94ceaSJussi Kivilinna 46864b94ceaSJussi Kivilinna ctr_err: 46964b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 47064b94ceaSJussi Kivilinna cbc_err: 47164b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 47264b94ceaSJussi Kivilinna ecb_err: 47364b94ceaSJussi Kivilinna crypto_unregister_alg(&bf_alg); 47464b94ceaSJussi Kivilinna bf_err: 47564b94ceaSJussi Kivilinna return err; 47664b94ceaSJussi Kivilinna } 47764b94ceaSJussi Kivilinna 47864b94ceaSJussi Kivilinna static void __exit fini(void) 47964b94ceaSJussi Kivilinna { 48064b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_ctr_alg); 48164b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 48264b94ceaSJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 48364b94ceaSJussi Kivilinna crypto_unregister_alg(&bf_alg); 48464b94ceaSJussi Kivilinna } 48564b94ceaSJussi Kivilinna 48664b94ceaSJussi Kivilinna module_init(init); 48764b94ceaSJussi Kivilinna module_exit(fini); 48864b94ceaSJussi Kivilinna 48964b94ceaSJussi Kivilinna MODULE_LICENSE("GPL"); 49064b94ceaSJussi Kivilinna MODULE_DESCRIPTION("Blowfish Cipher Algorithm, asm optimized"); 49164b94ceaSJussi Kivilinna MODULE_ALIAS("blowfish"); 49264b94ceaSJussi Kivilinna MODULE_ALIAS("blowfish-asm"); 493