18280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna/*
28280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * Glue Code for 3-way parallel assembler optimized version of Twofish
38280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna *
48280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
58280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna *
68280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
78280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
88280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * CTR part based on code (crypto/ctr.c) by:
98280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
108280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna *
118280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * This program is free software; you can redistribute it and/or modify
128280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * it under the terms of the GNU General Public License as published by
138280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * the Free Software Foundation; either version 2 of the License, or
148280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * (at your option) any later version.
158280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna *
168280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * This program is distributed in the hope that it will be useful,
178280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * but WITHOUT ANY WARRANTY; without even the implied warranty of
188280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
198280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * GNU General Public License for more details.
208280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna *
218280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * You should have received a copy of the GNU General Public License
228280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * along with this program; if not, write to the Free Software
238280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
248280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna * USA
258280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna *
268280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna */
278280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
28a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna#include <asm/processor.h>
298280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna#include <linux/crypto.h>
308280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna#include <linux/init.h>
318280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna#include <linux/module.h>
328280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna#include <linux/types.h>
338280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna#include <crypto/algapi.h>
348280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna#include <crypto/twofish.h>
358280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna#include <crypto/b128ops.h>
3681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna#include <crypto/lrw.h>
37bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna#include <crypto/xts.h>
3881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
398280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna/* regular block cipher functions from twofish_x86_64 module */
408280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnaasmlinkage void twofish_enc_blk(struct twofish_ctx *ctx, u8 *dst,
418280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				const u8 *src);
428280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnaasmlinkage void twofish_dec_blk(struct twofish_ctx *ctx, u8 *dst,
438280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				const u8 *src);
448280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
458280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna/* 3-way parallel cipher functions */
468280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnaasmlinkage void __twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
478280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				       const u8 *src, bool xor);
488280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnaasmlinkage void twofish_dec_blk_3way(struct twofish_ctx *ctx, u8 *dst,
498280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				     const u8 *src);
508280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
518280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic inline void twofish_enc_blk_3way(struct twofish_ctx *ctx, u8 *dst,
528280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna					const u8 *src)
538280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
548280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	__twofish_enc_blk_3way(ctx, dst, src, false);
558280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
568280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
578280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic inline void twofish_enc_blk_xor_3way(struct twofish_ctx *ctx, u8 *dst,
588280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna					    const u8 *src)
598280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
608280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	__twofish_enc_blk_3way(ctx, dst, src, true);
618280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
628280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
638280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk,
648280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		     void (*fn)(struct twofish_ctx *, u8 *, const u8 *),
658280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		     void (*fn_3way)(struct twofish_ctx *, u8 *, const u8 *))
668280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
678280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
688280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	unsigned int bsize = TF_BLOCK_SIZE;
698280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	unsigned int nbytes;
708280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	int err;
718280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
728280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	err = blkcipher_walk_virt(desc, walk);
738280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
748280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	while ((nbytes = walk->nbytes)) {
758280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		u8 *wsrc = walk->src.virt.addr;
768280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		u8 *wdst = walk->dst.virt.addr;
778280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
788280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		/* Process three block batch */
798280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		if (nbytes >= bsize * 3) {
808280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			do {
818280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				fn_3way(ctx, wdst, wsrc);
828280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
838280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				wsrc += bsize * 3;
848280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				wdst += bsize * 3;
858280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				nbytes -= bsize * 3;
868280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			} while (nbytes >= bsize * 3);
878280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
888280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			if (nbytes < bsize)
898280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				goto done;
908280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		}
918280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
928280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		/* Handle leftovers */
938280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		do {
948280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			fn(ctx, wdst, wsrc);
958280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
968280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			wsrc += bsize;
978280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			wdst += bsize;
988280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			nbytes -= bsize;
998280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		} while (nbytes >= bsize);
1008280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1018280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnadone:
1028280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		err = blkcipher_walk_done(desc, walk, nbytes);
1038280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	}
1048280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1058280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	return err;
1068280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
1078280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1088280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
1098280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		       struct scatterlist *src, unsigned int nbytes)
1108280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
1118280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct blkcipher_walk walk;
1128280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1138280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	blkcipher_walk_init(&walk, dst, src, nbytes);
1148280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	return ecb_crypt(desc, &walk, twofish_enc_blk, twofish_enc_blk_3way);
1158280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
1168280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1178280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
1188280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		       struct scatterlist *src, unsigned int nbytes)
1198280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
1208280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct blkcipher_walk walk;
1218280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1228280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	blkcipher_walk_init(&walk, dst, src, nbytes);
1238280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	return ecb_crypt(desc, &walk, twofish_dec_blk, twofish_dec_blk_3way);
1248280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
1258280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1268280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic unsigned int __cbc_encrypt(struct blkcipher_desc *desc,
1278280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				  struct blkcipher_walk *walk)
1288280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
1298280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
1308280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	unsigned int bsize = TF_BLOCK_SIZE;
1318280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	unsigned int nbytes = walk->nbytes;
1328280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 *src = (u128 *)walk->src.virt.addr;
1338280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 *dst = (u128 *)walk->dst.virt.addr;
1348280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 *iv = (u128 *)walk->iv;
1358280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1368280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	do {
1378280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		u128_xor(dst, src, iv);
1388280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		twofish_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
1398280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		iv = dst;
1408280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1418280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		src += 1;
1428280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		dst += 1;
1438280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		nbytes -= bsize;
1448280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	} while (nbytes >= bsize);
1458280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1468280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv);
1478280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	return nbytes;
1488280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
1498280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1508280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
1518280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		       struct scatterlist *src, unsigned int nbytes)
1528280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
1538280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct blkcipher_walk walk;
1548280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	int err;
1558280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1568280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	blkcipher_walk_init(&walk, dst, src, nbytes);
1578280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	err = blkcipher_walk_virt(desc, &walk);
1588280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1598280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	while ((nbytes = walk.nbytes)) {
1608280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		nbytes = __cbc_encrypt(desc, &walk);
1618280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		err = blkcipher_walk_done(desc, &walk, nbytes);
1628280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	}
1638280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1648280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	return err;
1658280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
1668280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1678280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic unsigned int __cbc_decrypt(struct blkcipher_desc *desc,
1688280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				  struct blkcipher_walk *walk)
1698280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
1708280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
1718280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	unsigned int bsize = TF_BLOCK_SIZE;
1728280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	unsigned int nbytes = walk->nbytes;
1738280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 *src = (u128 *)walk->src.virt.addr;
1748280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 *dst = (u128 *)walk->dst.virt.addr;
1758280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 ivs[3 - 1];
1768280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 last_iv;
1778280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1788280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	/* Start of the last block. */
1798280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	src += nbytes / bsize - 1;
1808280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	dst += nbytes / bsize - 1;
1818280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1828280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	last_iv = *src;
1838280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1848280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	/* Process three block batch */
1858280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	if (nbytes >= bsize * 3) {
1868280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		do {
1878280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			nbytes -= bsize * (3 - 1);
1888280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			src -= 3 - 1;
1898280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			dst -= 3 - 1;
1908280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1918280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			ivs[0] = src[0];
1928280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			ivs[1] = src[1];
1938280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1948280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			twofish_dec_blk_3way(ctx, (u8 *)dst, (u8 *)src);
1958280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1968280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			u128_xor(dst + 1, dst + 1, ivs + 0);
1978280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			u128_xor(dst + 2, dst + 2, ivs + 1);
1988280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
1998280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			nbytes -= bsize;
2008280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			if (nbytes < bsize)
2018280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				goto done;
2028280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2038280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			u128_xor(dst, dst, src - 1);
2048280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			src -= 1;
2058280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			dst -= 1;
2068280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		} while (nbytes >= bsize * 3);
2078280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2088280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		if (nbytes < bsize)
2098280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			goto done;
2108280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	}
2118280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2128280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	/* Handle leftovers */
2138280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	for (;;) {
2148280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		twofish_dec_blk(ctx, (u8 *)dst, (u8 *)src);
2158280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2168280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		nbytes -= bsize;
2178280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		if (nbytes < bsize)
2188280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			break;
2198280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2208280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		u128_xor(dst, dst, src - 1);
2218280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		src -= 1;
2228280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		dst -= 1;
2238280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	}
2248280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2258280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnadone:
2268280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128_xor(dst, dst, (u128 *)walk->iv);
2278280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	*(u128 *)walk->iv = last_iv;
2288280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2298280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	return nbytes;
2308280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
2318280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2328280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
2338280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		       struct scatterlist *src, unsigned int nbytes)
2348280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
2358280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct blkcipher_walk walk;
2368280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	int err;
2378280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2388280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	blkcipher_walk_init(&walk, dst, src, nbytes);
2398280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	err = blkcipher_walk_virt(desc, &walk);
2408280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2418280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	while ((nbytes = walk.nbytes)) {
2428280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		nbytes = __cbc_decrypt(desc, &walk);
2438280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		err = blkcipher_walk_done(desc, &walk, nbytes);
2448280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	}
2458280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2468280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	return err;
2478280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
2488280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2498280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic inline void u128_to_be128(be128 *dst, const u128 *src)
2508280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
2518280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	dst->a = cpu_to_be64(src->a);
2528280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	dst->b = cpu_to_be64(src->b);
2538280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
2548280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2558280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic inline void be128_to_u128(u128 *dst, const be128 *src)
2568280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
2578280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	dst->a = be64_to_cpu(src->a);
2588280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	dst->b = be64_to_cpu(src->b);
2598280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
2608280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2618280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic inline void u128_inc(u128 *i)
2628280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
2638280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	i->b++;
2648280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	if (!i->b)
2658280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		i->a++;
2668280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
2678280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2688280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic void ctr_crypt_final(struct blkcipher_desc *desc,
2698280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			    struct blkcipher_walk *walk)
2708280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
2718280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
2728280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u8 *ctrblk = walk->iv;
2738280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u8 keystream[TF_BLOCK_SIZE];
2748280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u8 *src = walk->src.virt.addr;
2758280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u8 *dst = walk->dst.virt.addr;
2768280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	unsigned int nbytes = walk->nbytes;
2778280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2788280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	twofish_enc_blk(ctx, keystream, ctrblk);
2798280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	crypto_xor(keystream, src, nbytes);
2808280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	memcpy(dst, keystream, nbytes);
2818280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2828280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	crypto_inc(ctrblk, TF_BLOCK_SIZE);
2838280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
2848280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2858280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic unsigned int __ctr_crypt(struct blkcipher_desc *desc,
2868280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				struct blkcipher_walk *walk)
2878280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
2888280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct twofish_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
2898280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	unsigned int bsize = TF_BLOCK_SIZE;
2908280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	unsigned int nbytes = walk->nbytes;
2918280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 *src = (u128 *)walk->src.virt.addr;
2928280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 *dst = (u128 *)walk->dst.virt.addr;
2938280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128 ctrblk;
2948280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	be128 ctrblocks[3];
2958280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2968280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	be128_to_u128(&ctrblk, (be128 *)walk->iv);
2978280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
2988280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	/* Process three block batch */
2998280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	if (nbytes >= bsize * 3) {
3008280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		do {
3018280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			if (dst != src) {
3028280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				dst[0] = src[0];
3038280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				dst[1] = src[1];
3048280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna				dst[2] = src[2];
3058280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			}
3068280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3078280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			/* create ctrblks for parallel encrypt */
3088280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			u128_to_be128(&ctrblocks[0], &ctrblk);
3098280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			u128_inc(&ctrblk);
3108280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			u128_to_be128(&ctrblocks[1], &ctrblk);
3118280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			u128_inc(&ctrblk);
3128280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			u128_to_be128(&ctrblocks[2], &ctrblk);
3138280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			u128_inc(&ctrblk);
3148280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3158280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			twofish_enc_blk_xor_3way(ctx, (u8 *)dst,
3168280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna						 (u8 *)ctrblocks);
3178280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3188280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			src += 3;
3198280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			dst += 3;
3208280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			nbytes -= bsize * 3;
3218280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		} while (nbytes >= bsize * 3);
3228280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3238280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		if (nbytes < bsize)
3248280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			goto done;
3258280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	}
3268280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3278280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	/* Handle leftovers */
3288280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	do {
3298280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		if (dst != src)
3308280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna			*dst = *src;
3318280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3328280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		u128_to_be128(&ctrblocks[0], &ctrblk);
3338280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		u128_inc(&ctrblk);
3348280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3358280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		twofish_enc_blk(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks);
3368280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		u128_xor(dst, dst, (u128 *)ctrblocks);
3378280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3388280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		src += 1;
3398280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		dst += 1;
3408280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		nbytes -= bsize;
3418280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	} while (nbytes >= bsize);
3428280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3438280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnadone:
3448280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	u128_to_be128((be128 *)walk->iv, &ctrblk);
3458280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	return nbytes;
3468280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
3478280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3488280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnastatic int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst,
3498280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		     struct scatterlist *src, unsigned int nbytes)
3508280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
3518280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	struct blkcipher_walk walk;
3528280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	int err;
3538280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3548280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	blkcipher_walk_init(&walk, dst, src, nbytes);
3558280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	err = blkcipher_walk_virt_block(desc, &walk, TF_BLOCK_SIZE);
3568280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3578280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	while ((nbytes = walk.nbytes) >= TF_BLOCK_SIZE) {
3588280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		nbytes = __ctr_crypt(desc, &walk);
3598280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		err = blkcipher_walk_done(desc, &walk, nbytes);
3608280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	}
3618280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3628280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	if (walk.nbytes) {
3638280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		ctr_crypt_final(desc, &walk);
3648280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna		err = blkcipher_walk_done(desc, &walk, 0);
3658280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	}
3668280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
3678280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna	return err;
3688280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
3698280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
37081559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinnastatic void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
37181559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna{
37281559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	const unsigned int bsize = TF_BLOCK_SIZE;
37381559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct twofish_ctx *ctx = priv;
37481559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	int i;
37581559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
37681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	if (nbytes == 3 * bsize) {
37781559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		twofish_enc_blk_3way(ctx, srcdst, srcdst);
37881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		return;
37981559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	}
38081559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
38181559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
38281559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		twofish_enc_blk(ctx, srcdst, srcdst);
38381559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna}
38481559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
38581559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinnastatic void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes)
38681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna{
38781559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	const unsigned int bsize = TF_BLOCK_SIZE;
38881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct twofish_ctx *ctx = priv;
38981559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	int i;
39081559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
39181559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	if (nbytes == 3 * bsize) {
39281559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		twofish_dec_blk_3way(ctx, srcdst, srcdst);
39381559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		return;
39481559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	}
39581559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
39681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	for (i = 0; i < nbytes / bsize; i++, srcdst += bsize)
39781559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		twofish_dec_blk(ctx, srcdst, srcdst);
39881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna}
39981559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
40081559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinnastruct twofish_lrw_ctx {
40181559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct lrw_table_ctx lrw_table;
40281559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct twofish_ctx twofish_ctx;
40381559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna};
40481559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
40581559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinnastatic int lrw_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
40681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna			      unsigned int keylen)
40781559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna{
40881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
40981559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	int err;
41081559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
41181559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	err = __twofish_setkey(&ctx->twofish_ctx, key, keylen - TF_BLOCK_SIZE,
41281559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna			       &tfm->crt_flags);
41381559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	if (err)
41481559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		return err;
41581559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
41681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	return lrw_init_table(&ctx->lrw_table, key + keylen - TF_BLOCK_SIZE);
41781559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna}
41881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
41981559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinnastatic int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
42081559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		       struct scatterlist *src, unsigned int nbytes)
42181559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna{
42281559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
42381559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	be128 buf[3];
42481559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct lrw_crypt_req req = {
42581559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.tbuf = buf,
42681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.tbuflen = sizeof(buf),
42781559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
42881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.table_ctx = &ctx->lrw_table,
42981559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.crypt_ctx = &ctx->twofish_ctx,
43081559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.crypt_fn = encrypt_callback,
43181559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	};
43281559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
43381559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	return lrw_crypt(desc, dst, src, nbytes, &req);
43481559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna}
43581559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
43681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinnastatic int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
43781559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		       struct scatterlist *src, unsigned int nbytes)
43881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna{
43981559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct twofish_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
44081559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	be128 buf[3];
44181559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct lrw_crypt_req req = {
44281559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.tbuf = buf,
44381559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.tbuflen = sizeof(buf),
44481559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
44581559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.table_ctx = &ctx->lrw_table,
44681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.crypt_ctx = &ctx->twofish_ctx,
44781559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna		.crypt_fn = decrypt_callback,
44881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	};
44981559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
45081559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	return lrw_crypt(desc, dst, src, nbytes, &req);
45181559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna}
45281559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
45381559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinnastatic void lrw_exit_tfm(struct crypto_tfm *tfm)
45481559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna{
45581559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	struct twofish_lrw_ctx *ctx = crypto_tfm_ctx(tfm);
45681559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
45781559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna	lrw_free_table(&ctx->lrw_table);
45881559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna}
45981559f9ad3d88c033e4ec3b6468012dbfda3b31dJussi Kivilinna
460bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinnastruct twofish_xts_ctx {
461bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	struct twofish_ctx tweak_ctx;
462bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	struct twofish_ctx crypt_ctx;
463bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna};
464bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
465bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinnastatic int xts_twofish_setkey(struct crypto_tfm *tfm, const u8 *key,
466bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna			      unsigned int keylen)
467bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna{
468bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	struct twofish_xts_ctx *ctx = crypto_tfm_ctx(tfm);
469bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	u32 *flags = &tfm->crt_flags;
470bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	int err;
471bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
472bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	/* key consists of keys of equal size concatenated, therefore
473bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	 * the length must be even
474bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	 */
475bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	if (keylen % 2) {
476bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
477bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		return -EINVAL;
478bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	}
479bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
480bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	/* first half of xts-key is for crypt */
481bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	err = __twofish_setkey(&ctx->crypt_ctx, key, keylen / 2, flags);
482bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	if (err)
483bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		return err;
484bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
485bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	/* second half of xts-key is for tweak */
486bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	return __twofish_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2,
487bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna				flags);
488bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna}
489bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
490bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinnastatic int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
491bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		       struct scatterlist *src, unsigned int nbytes)
492bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna{
493bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
494bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	be128 buf[3];
495bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	struct xts_crypt_req req = {
496bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.tbuf = buf,
497bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.tbuflen = sizeof(buf),
498bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
499bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.tweak_ctx = &ctx->tweak_ctx,
500bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk),
501bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.crypt_ctx = &ctx->crypt_ctx,
502bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.crypt_fn = encrypt_callback,
503bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	};
504bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
505bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	return xts_crypt(desc, dst, src, nbytes, &req);
506bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna}
507bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
508bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinnastatic int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst,
509bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		       struct scatterlist *src, unsigned int nbytes)
510bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna{
511bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	struct twofish_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm);
512bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	be128 buf[3];
513bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	struct xts_crypt_req req = {
514bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.tbuf = buf,
515bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.tbuflen = sizeof(buf),
516bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
517bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.tweak_ctx = &ctx->tweak_ctx,
518bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.tweak_fn = XTS_TWEAK_CAST(twofish_enc_blk),
519bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.crypt_ctx = &ctx->crypt_ctx,
520bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.crypt_fn = decrypt_callback,
521bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	};
522bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
523bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	return xts_crypt(desc, dst, src, nbytes, &req);
524bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna}
525bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
52653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinnastatic struct crypto_alg tf_algs[5] = { {
52753709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_name		= "ecb(twofish)",
52853709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_driver_name	= "ecb-twofish-3way",
52953709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_priority		= 300,
53053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
53153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_blocksize		= TF_BLOCK_SIZE,
53253709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_ctxsize		= sizeof(struct twofish_ctx),
53353709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_alignmask		= 0,
53453709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_type		= &crypto_blkcipher_type,
53553709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_module		= THIS_MODULE,
53653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_list		= LIST_HEAD_INIT(tf_algs[0].cra_list),
53753709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_u = {
53853709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna		.blkcipher = {
53953709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.min_keysize	= TF_MIN_KEY_SIZE,
54053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.max_keysize	= TF_MAX_KEY_SIZE,
54153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.setkey		= twofish_setkey,
54253709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.encrypt	= ecb_encrypt,
54353709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.decrypt	= ecb_decrypt,
54453709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna		},
54553709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	},
54653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna}, {
54753709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_name		= "cbc(twofish)",
54853709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_driver_name	= "cbc-twofish-3way",
54953709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_priority		= 300,
55053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
55153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_blocksize		= TF_BLOCK_SIZE,
55253709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_ctxsize		= sizeof(struct twofish_ctx),
55353709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_alignmask		= 0,
55453709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_type		= &crypto_blkcipher_type,
55553709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_module		= THIS_MODULE,
55653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_list		= LIST_HEAD_INIT(tf_algs[1].cra_list),
55753709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_u = {
55853709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna		.blkcipher = {
55953709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.min_keysize	= TF_MIN_KEY_SIZE,
56053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.max_keysize	= TF_MAX_KEY_SIZE,
56153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.ivsize		= TF_BLOCK_SIZE,
56253709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.setkey		= twofish_setkey,
56353709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.encrypt	= cbc_encrypt,
56453709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.decrypt	= cbc_decrypt,
56553709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna		},
56653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	},
56753709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna}, {
56853709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_name		= "ctr(twofish)",
56953709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_driver_name	= "ctr-twofish-3way",
57053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_priority		= 300,
57153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
57253709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_blocksize		= 1,
57353709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_ctxsize		= sizeof(struct twofish_ctx),
57453709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_alignmask		= 0,
57553709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_type		= &crypto_blkcipher_type,
57653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_module		= THIS_MODULE,
57753709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_list		= LIST_HEAD_INIT(tf_algs[2].cra_list),
57853709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_u = {
57953709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna		.blkcipher = {
58053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.min_keysize	= TF_MIN_KEY_SIZE,
58153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.max_keysize	= TF_MAX_KEY_SIZE,
58253709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.ivsize		= TF_BLOCK_SIZE,
58353709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.setkey		= twofish_setkey,
58453709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.encrypt	= ctr_crypt,
58553709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.decrypt	= ctr_crypt,
58653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna		},
58753709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	},
58853709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna}, {
58953709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_name		= "lrw(twofish)",
59053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_driver_name	= "lrw-twofish-3way",
59153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_priority		= 300,
59253709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
59353709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_blocksize		= TF_BLOCK_SIZE,
59453709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_ctxsize		= sizeof(struct twofish_lrw_ctx),
59553709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_alignmask		= 0,
59653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_type		= &crypto_blkcipher_type,
59753709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_module		= THIS_MODULE,
59853709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_list		= LIST_HEAD_INIT(tf_algs[3].cra_list),
59953709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_exit		= lrw_exit_tfm,
60053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_u = {
60153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna		.blkcipher = {
60253709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.min_keysize	= TF_MIN_KEY_SIZE + TF_BLOCK_SIZE,
60353709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.max_keysize	= TF_MAX_KEY_SIZE + TF_BLOCK_SIZE,
60453709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.ivsize		= TF_BLOCK_SIZE,
60553709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.setkey		= lrw_twofish_setkey,
60653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.encrypt	= lrw_encrypt,
60753709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna			.decrypt	= lrw_decrypt,
60853709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna		},
60953709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	},
61053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna}, {
611bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_name		= "xts(twofish)",
612bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_driver_name	= "xts-twofish-3way",
613bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_priority		= 300,
614bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_flags		= CRYPTO_ALG_TYPE_BLKCIPHER,
615bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_blocksize		= TF_BLOCK_SIZE,
616bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_ctxsize		= sizeof(struct twofish_xts_ctx),
617bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_alignmask		= 0,
618bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_type		= &crypto_blkcipher_type,
619bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_module		= THIS_MODULE,
62053709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	.cra_list		= LIST_HEAD_INIT(tf_algs[4].cra_list),
621bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	.cra_u = {
622bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		.blkcipher = {
623bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna			.min_keysize	= TF_MIN_KEY_SIZE * 2,
624bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna			.max_keysize	= TF_MAX_KEY_SIZE * 2,
625bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna			.ivsize		= TF_BLOCK_SIZE,
626bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna			.setkey		= xts_twofish_setkey,
627bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna			.encrypt	= xts_encrypt,
628bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna			.decrypt	= xts_decrypt,
629bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna		},
630bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna	},
63153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna} };
632bae6d3038b7faff187f4207448a40b9912cf787dJussi Kivilinna
633a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinnastatic bool is_blacklisted_cpu(void)
634a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna{
635a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna	if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
636a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		return false;
637a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna
638a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna	if (boot_cpu_data.x86 == 0x06 &&
639a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		(boot_cpu_data.x86_model == 0x1c ||
640a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 boot_cpu_data.x86_model == 0x26 ||
641a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 boot_cpu_data.x86_model == 0x36)) {
642a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		/*
643a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * On Atom, twofish-3way is slower than original assembler
644a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * implementation. Twofish-3way trades off some performance in
645a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * storing blocks in 64bit registers to allow three blocks to
646a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * be processed parallel. Parallel operation then allows gaining
647a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * more performance than was trade off, on out-of-order CPUs.
648a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * However Atom does not benefit from this parallellism and
649a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * should be blacklisted.
650a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 */
651a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		return true;
652a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna	}
653a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna
654a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna	if (boot_cpu_data.x86 == 0x0f) {
655a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		/*
656a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * On Pentium 4, twofish-3way is slower than original assembler
657a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * implementation because excessive uses of 64bit rotate and
658a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * left-shifts (which are really slow on P4) needed to store and
659a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 * handle 128bit block in two 64bit registers.
660a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		 */
661a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		return true;
662a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna	}
663a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna
664a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna	return false;
665a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna}
666a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna
667a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinnastatic int force;
668a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinnamodule_param(force, int, 0);
669a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi KivilinnaMODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
670a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna
671ff0a70fe053614e763eb3ac88bfea9c5615fce3bJussi Kivilinnastatic int __init init(void)
6728280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
673a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna	if (!force && is_blacklisted_cpu()) {
674a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		printk(KERN_INFO
675a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna			"twofish-x86_64-3way: performance on this CPU "
676a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna			"would be suboptimal: disabling "
677a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna			"twofish-x86_64-3way.\n");
678a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna		return -ENODEV;
679a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna	}
680a522ee85ba979e7897a75b1c97db1b0304b68b5cJussi Kivilinna
68153709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	return crypto_register_algs(tf_algs, ARRAY_SIZE(tf_algs));
6828280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
6838280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
684ff0a70fe053614e763eb3ac88bfea9c5615fce3bJussi Kivilinnastatic void __exit fini(void)
6858280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna{
68653709ddee36cbd19434aa0f0ac8c1e27b92aca33Jussi Kivilinna	crypto_unregister_algs(tf_algs, ARRAY_SIZE(tf_algs));
6878280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna}
6888280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
6898280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnamodule_init(init);
6908280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinnamodule_exit(fini);
6918280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi Kivilinna
6928280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi KivilinnaMODULE_LICENSE("GPL");
6938280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi KivilinnaMODULE_DESCRIPTION("Twofish Cipher Algorithm, 3-way parallel asm optimized");
6948280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi KivilinnaMODULE_ALIAS("twofish");
6958280daad436edb7dd9e7e06fc13bcecb6b2a885cJussi KivilinnaMODULE_ALIAS("twofish-asm");
696