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