1937c30d7SJussi Kivilinna /* 2937c30d7SJussi Kivilinna * Glue Code for SSE2 assembler versions of Serpent Cipher 3937c30d7SJussi Kivilinna * 4937c30d7SJussi Kivilinna * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 5937c30d7SJussi Kivilinna * 6937c30d7SJussi Kivilinna * Glue code based on aesni-intel_glue.c by: 7937c30d7SJussi Kivilinna * Copyright (C) 2008, Intel Corp. 8937c30d7SJussi Kivilinna * Author: Huang Ying <ying.huang@intel.com> 9937c30d7SJussi Kivilinna * 10937c30d7SJussi Kivilinna * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: 11937c30d7SJussi Kivilinna * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> 12937c30d7SJussi Kivilinna * CTR part based on code (crypto/ctr.c) by: 13937c30d7SJussi Kivilinna * (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com> 14937c30d7SJussi Kivilinna * 15937c30d7SJussi Kivilinna * This program is free software; you can redistribute it and/or modify 16937c30d7SJussi Kivilinna * it under the terms of the GNU General Public License as published by 17937c30d7SJussi Kivilinna * the Free Software Foundation; either version 2 of the License, or 18937c30d7SJussi Kivilinna * (at your option) any later version. 19937c30d7SJussi Kivilinna * 20937c30d7SJussi Kivilinna * This program is distributed in the hope that it will be useful, 21937c30d7SJussi Kivilinna * but WITHOUT ANY WARRANTY; without even the implied warranty of 22937c30d7SJussi Kivilinna * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23937c30d7SJussi Kivilinna * GNU General Public License for more details. 24937c30d7SJussi Kivilinna * 25937c30d7SJussi Kivilinna * You should have received a copy of the GNU General Public License 26937c30d7SJussi Kivilinna * along with this program; if not, write to the Free Software 27937c30d7SJussi Kivilinna * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 28937c30d7SJussi Kivilinna * USA 29937c30d7SJussi Kivilinna * 30937c30d7SJussi Kivilinna */ 31937c30d7SJussi Kivilinna 32937c30d7SJussi Kivilinna #include <linux/module.h> 33937c30d7SJussi Kivilinna #include <linux/hardirq.h> 34937c30d7SJussi Kivilinna #include <linux/types.h> 35937c30d7SJussi Kivilinna #include <linux/crypto.h> 36937c30d7SJussi Kivilinna #include <linux/err.h> 37937c30d7SJussi Kivilinna #include <crypto/algapi.h> 38937c30d7SJussi Kivilinna #include <crypto/serpent.h> 39937c30d7SJussi Kivilinna #include <crypto/cryptd.h> 40937c30d7SJussi Kivilinna #include <crypto/b128ops.h> 41937c30d7SJussi Kivilinna #include <crypto/ctr.h> 4218482053SJussi Kivilinna #include <crypto/lrw.h> 435962f8b6SJussi Kivilinna #include <crypto/xts.h> 44937c30d7SJussi Kivilinna #include <asm/i387.h> 45937c30d7SJussi Kivilinna #include <asm/serpent.h> 46937c30d7SJussi Kivilinna #include <crypto/scatterwalk.h> 47937c30d7SJussi Kivilinna #include <linux/workqueue.h> 48937c30d7SJussi Kivilinna #include <linux/spinlock.h> 49937c30d7SJussi Kivilinna 5018482053SJussi Kivilinna #if defined(CONFIG_CRYPTO_LRW) || defined(CONFIG_CRYPTO_LRW_MODULE) 5118482053SJussi Kivilinna #define HAS_LRW 5218482053SJussi Kivilinna #endif 5318482053SJussi Kivilinna 545962f8b6SJussi Kivilinna #if defined(CONFIG_CRYPTO_XTS) || defined(CONFIG_CRYPTO_XTS_MODULE) 555962f8b6SJussi Kivilinna #define HAS_XTS 565962f8b6SJussi Kivilinna #endif 575962f8b6SJussi Kivilinna 58937c30d7SJussi Kivilinna struct async_serpent_ctx { 59937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 60937c30d7SJussi Kivilinna }; 61937c30d7SJussi Kivilinna 62937c30d7SJussi Kivilinna static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes) 63937c30d7SJussi Kivilinna { 64937c30d7SJussi Kivilinna if (fpu_enabled) 65937c30d7SJussi Kivilinna return true; 66937c30d7SJussi Kivilinna 67937c30d7SJussi Kivilinna /* SSE2 is only used when chunk to be processed is large enough, so 68937c30d7SJussi Kivilinna * do not enable FPU until it is necessary. 69937c30d7SJussi Kivilinna */ 70937c30d7SJussi Kivilinna if (nbytes < SERPENT_BLOCK_SIZE * SERPENT_PARALLEL_BLOCKS) 71937c30d7SJussi Kivilinna return false; 72937c30d7SJussi Kivilinna 73937c30d7SJussi Kivilinna kernel_fpu_begin(); 74937c30d7SJussi Kivilinna return true; 75937c30d7SJussi Kivilinna } 76937c30d7SJussi Kivilinna 77937c30d7SJussi Kivilinna static inline void serpent_fpu_end(bool fpu_enabled) 78937c30d7SJussi Kivilinna { 79937c30d7SJussi Kivilinna if (fpu_enabled) 80937c30d7SJussi Kivilinna kernel_fpu_end(); 81937c30d7SJussi Kivilinna } 82937c30d7SJussi Kivilinna 83937c30d7SJussi Kivilinna static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, 84937c30d7SJussi Kivilinna bool enc) 85937c30d7SJussi Kivilinna { 86937c30d7SJussi Kivilinna bool fpu_enabled = false; 87937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 88937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 89937c30d7SJussi Kivilinna unsigned int nbytes; 90937c30d7SJussi Kivilinna int err; 91937c30d7SJussi Kivilinna 92937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, walk); 93937c30d7SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 94937c30d7SJussi Kivilinna 95937c30d7SJussi Kivilinna while ((nbytes = walk->nbytes)) { 96937c30d7SJussi Kivilinna u8 *wsrc = walk->src.virt.addr; 97937c30d7SJussi Kivilinna u8 *wdst = walk->dst.virt.addr; 98937c30d7SJussi Kivilinna 99937c30d7SJussi Kivilinna fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes); 100937c30d7SJussi Kivilinna 101937c30d7SJussi Kivilinna /* Process multi-block batch */ 102937c30d7SJussi Kivilinna if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) { 103937c30d7SJussi Kivilinna do { 104937c30d7SJussi Kivilinna if (enc) 105937c30d7SJussi Kivilinna serpent_enc_blk_xway(ctx, wdst, wsrc); 106937c30d7SJussi Kivilinna else 107937c30d7SJussi Kivilinna serpent_dec_blk_xway(ctx, wdst, wsrc); 108937c30d7SJussi Kivilinna 109937c30d7SJussi Kivilinna wsrc += bsize * SERPENT_PARALLEL_BLOCKS; 110937c30d7SJussi Kivilinna wdst += bsize * SERPENT_PARALLEL_BLOCKS; 111937c30d7SJussi Kivilinna nbytes -= bsize * SERPENT_PARALLEL_BLOCKS; 112937c30d7SJussi Kivilinna } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS); 113937c30d7SJussi Kivilinna 114937c30d7SJussi Kivilinna if (nbytes < bsize) 115937c30d7SJussi Kivilinna goto done; 116937c30d7SJussi Kivilinna } 117937c30d7SJussi Kivilinna 118937c30d7SJussi Kivilinna /* Handle leftovers */ 119937c30d7SJussi Kivilinna do { 120937c30d7SJussi Kivilinna if (enc) 121937c30d7SJussi Kivilinna __serpent_encrypt(ctx, wdst, wsrc); 122937c30d7SJussi Kivilinna else 123937c30d7SJussi Kivilinna __serpent_decrypt(ctx, wdst, wsrc); 124937c30d7SJussi Kivilinna 125937c30d7SJussi Kivilinna wsrc += bsize; 126937c30d7SJussi Kivilinna wdst += bsize; 127937c30d7SJussi Kivilinna nbytes -= bsize; 128937c30d7SJussi Kivilinna } while (nbytes >= bsize); 129937c30d7SJussi Kivilinna 130937c30d7SJussi Kivilinna done: 131937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, walk, nbytes); 132937c30d7SJussi Kivilinna } 133937c30d7SJussi Kivilinna 134937c30d7SJussi Kivilinna serpent_fpu_end(fpu_enabled); 135937c30d7SJussi Kivilinna return err; 136937c30d7SJussi Kivilinna } 137937c30d7SJussi Kivilinna 138937c30d7SJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 139937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 140937c30d7SJussi Kivilinna { 141937c30d7SJussi Kivilinna struct blkcipher_walk walk; 142937c30d7SJussi Kivilinna 143937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 144937c30d7SJussi Kivilinna return ecb_crypt(desc, &walk, true); 145937c30d7SJussi Kivilinna } 146937c30d7SJussi Kivilinna 147937c30d7SJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 148937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 149937c30d7SJussi Kivilinna { 150937c30d7SJussi Kivilinna struct blkcipher_walk walk; 151937c30d7SJussi Kivilinna 152937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 153937c30d7SJussi Kivilinna return ecb_crypt(desc, &walk, false); 154937c30d7SJussi Kivilinna } 155937c30d7SJussi Kivilinna 156937c30d7SJussi Kivilinna static struct crypto_alg blk_ecb_alg = { 157937c30d7SJussi Kivilinna .cra_name = "__ecb-serpent-sse2", 158937c30d7SJussi Kivilinna .cra_driver_name = "__driver-ecb-serpent-sse2", 159937c30d7SJussi Kivilinna .cra_priority = 0, 160937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 161937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 162937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 163937c30d7SJussi Kivilinna .cra_alignmask = 0, 164937c30d7SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 165937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 166937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), 167937c30d7SJussi Kivilinna .cra_u = { 168937c30d7SJussi Kivilinna .blkcipher = { 169937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 170937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 171937c30d7SJussi Kivilinna .setkey = serpent_setkey, 172937c30d7SJussi Kivilinna .encrypt = ecb_encrypt, 173937c30d7SJussi Kivilinna .decrypt = ecb_decrypt, 174937c30d7SJussi Kivilinna }, 175937c30d7SJussi Kivilinna }, 176937c30d7SJussi Kivilinna }; 177937c30d7SJussi Kivilinna 178937c30d7SJussi Kivilinna static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, 179937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 180937c30d7SJussi Kivilinna { 181937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 182937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 183937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 184937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 185937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 186937c30d7SJussi Kivilinna u128 *iv = (u128 *)walk->iv; 187937c30d7SJussi Kivilinna 188937c30d7SJussi Kivilinna do { 189937c30d7SJussi Kivilinna u128_xor(dst, src, iv); 190937c30d7SJussi Kivilinna __serpent_encrypt(ctx, (u8 *)dst, (u8 *)dst); 191937c30d7SJussi Kivilinna iv = dst; 192937c30d7SJussi Kivilinna 193937c30d7SJussi Kivilinna src += 1; 194937c30d7SJussi Kivilinna dst += 1; 195937c30d7SJussi Kivilinna nbytes -= bsize; 196937c30d7SJussi Kivilinna } while (nbytes >= bsize); 197937c30d7SJussi Kivilinna 198937c30d7SJussi Kivilinna u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv); 199937c30d7SJussi Kivilinna return nbytes; 200937c30d7SJussi Kivilinna } 201937c30d7SJussi Kivilinna 202937c30d7SJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 203937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 204937c30d7SJussi Kivilinna { 205937c30d7SJussi Kivilinna struct blkcipher_walk walk; 206937c30d7SJussi Kivilinna int err; 207937c30d7SJussi Kivilinna 208937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 209937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 210937c30d7SJussi Kivilinna 211937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes)) { 212937c30d7SJussi Kivilinna nbytes = __cbc_encrypt(desc, &walk); 213937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 214937c30d7SJussi Kivilinna } 215937c30d7SJussi Kivilinna 216937c30d7SJussi Kivilinna return err; 217937c30d7SJussi Kivilinna } 218937c30d7SJussi Kivilinna 219937c30d7SJussi Kivilinna static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, 220937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 221937c30d7SJussi Kivilinna { 222937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 223937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 224937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 225937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 226937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 227937c30d7SJussi Kivilinna u128 ivs[SERPENT_PARALLEL_BLOCKS - 1]; 228937c30d7SJussi Kivilinna u128 last_iv; 229937c30d7SJussi Kivilinna int i; 230937c30d7SJussi Kivilinna 231937c30d7SJussi Kivilinna /* Start of the last block. */ 232937c30d7SJussi Kivilinna src += nbytes / bsize - 1; 233937c30d7SJussi Kivilinna dst += nbytes / bsize - 1; 234937c30d7SJussi Kivilinna 235937c30d7SJussi Kivilinna last_iv = *src; 236937c30d7SJussi Kivilinna 237937c30d7SJussi Kivilinna /* Process multi-block batch */ 238937c30d7SJussi Kivilinna if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) { 239937c30d7SJussi Kivilinna do { 240937c30d7SJussi Kivilinna nbytes -= bsize * (SERPENT_PARALLEL_BLOCKS - 1); 241937c30d7SJussi Kivilinna src -= SERPENT_PARALLEL_BLOCKS - 1; 242937c30d7SJussi Kivilinna dst -= SERPENT_PARALLEL_BLOCKS - 1; 243937c30d7SJussi Kivilinna 244937c30d7SJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++) 245937c30d7SJussi Kivilinna ivs[i] = src[i]; 246937c30d7SJussi Kivilinna 247937c30d7SJussi Kivilinna serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); 248937c30d7SJussi Kivilinna 249937c30d7SJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++) 250937c30d7SJussi Kivilinna u128_xor(dst + (i + 1), dst + (i + 1), ivs + i); 251937c30d7SJussi Kivilinna 252937c30d7SJussi Kivilinna nbytes -= bsize; 253937c30d7SJussi Kivilinna if (nbytes < bsize) 254937c30d7SJussi Kivilinna goto done; 255937c30d7SJussi Kivilinna 256937c30d7SJussi Kivilinna u128_xor(dst, dst, src - 1); 257937c30d7SJussi Kivilinna src -= 1; 258937c30d7SJussi Kivilinna dst -= 1; 259937c30d7SJussi Kivilinna } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS); 260937c30d7SJussi Kivilinna 261937c30d7SJussi Kivilinna if (nbytes < bsize) 262937c30d7SJussi Kivilinna goto done; 263937c30d7SJussi Kivilinna } 264937c30d7SJussi Kivilinna 265937c30d7SJussi Kivilinna /* Handle leftovers */ 266937c30d7SJussi Kivilinna for (;;) { 267937c30d7SJussi Kivilinna __serpent_decrypt(ctx, (u8 *)dst, (u8 *)src); 268937c30d7SJussi Kivilinna 269937c30d7SJussi Kivilinna nbytes -= bsize; 270937c30d7SJussi Kivilinna if (nbytes < bsize) 271937c30d7SJussi Kivilinna break; 272937c30d7SJussi Kivilinna 273937c30d7SJussi Kivilinna u128_xor(dst, dst, src - 1); 274937c30d7SJussi Kivilinna src -= 1; 275937c30d7SJussi Kivilinna dst -= 1; 276937c30d7SJussi Kivilinna } 277937c30d7SJussi Kivilinna 278937c30d7SJussi Kivilinna done: 279937c30d7SJussi Kivilinna u128_xor(dst, dst, (u128 *)walk->iv); 280937c30d7SJussi Kivilinna *(u128 *)walk->iv = last_iv; 281937c30d7SJussi Kivilinna 282937c30d7SJussi Kivilinna return nbytes; 283937c30d7SJussi Kivilinna } 284937c30d7SJussi Kivilinna 285937c30d7SJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 286937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 287937c30d7SJussi Kivilinna { 288937c30d7SJussi Kivilinna bool fpu_enabled = false; 289937c30d7SJussi Kivilinna struct blkcipher_walk walk; 290937c30d7SJussi Kivilinna int err; 291937c30d7SJussi Kivilinna 292937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 293937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 294937c30d7SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 295937c30d7SJussi Kivilinna 296937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes)) { 297937c30d7SJussi Kivilinna fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes); 298937c30d7SJussi Kivilinna nbytes = __cbc_decrypt(desc, &walk); 299937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 300937c30d7SJussi Kivilinna } 301937c30d7SJussi Kivilinna 302937c30d7SJussi Kivilinna serpent_fpu_end(fpu_enabled); 303937c30d7SJussi Kivilinna return err; 304937c30d7SJussi Kivilinna } 305937c30d7SJussi Kivilinna 306937c30d7SJussi Kivilinna static struct crypto_alg blk_cbc_alg = { 307937c30d7SJussi Kivilinna .cra_name = "__cbc-serpent-sse2", 308937c30d7SJussi Kivilinna .cra_driver_name = "__driver-cbc-serpent-sse2", 309937c30d7SJussi Kivilinna .cra_priority = 0, 310937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 311937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 312937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 313937c30d7SJussi Kivilinna .cra_alignmask = 0, 314937c30d7SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 315937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 316937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), 317937c30d7SJussi Kivilinna .cra_u = { 318937c30d7SJussi Kivilinna .blkcipher = { 319937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 320937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 321937c30d7SJussi Kivilinna .setkey = serpent_setkey, 322937c30d7SJussi Kivilinna .encrypt = cbc_encrypt, 323937c30d7SJussi Kivilinna .decrypt = cbc_decrypt, 324937c30d7SJussi Kivilinna }, 325937c30d7SJussi Kivilinna }, 326937c30d7SJussi Kivilinna }; 327937c30d7SJussi Kivilinna 328937c30d7SJussi Kivilinna static inline void u128_to_be128(be128 *dst, const u128 *src) 329937c30d7SJussi Kivilinna { 330937c30d7SJussi Kivilinna dst->a = cpu_to_be64(src->a); 331937c30d7SJussi Kivilinna dst->b = cpu_to_be64(src->b); 332937c30d7SJussi Kivilinna } 333937c30d7SJussi Kivilinna 334937c30d7SJussi Kivilinna static inline void be128_to_u128(u128 *dst, const be128 *src) 335937c30d7SJussi Kivilinna { 336937c30d7SJussi Kivilinna dst->a = be64_to_cpu(src->a); 337937c30d7SJussi Kivilinna dst->b = be64_to_cpu(src->b); 338937c30d7SJussi Kivilinna } 339937c30d7SJussi Kivilinna 340937c30d7SJussi Kivilinna static inline void u128_inc(u128 *i) 341937c30d7SJussi Kivilinna { 342937c30d7SJussi Kivilinna i->b++; 343937c30d7SJussi Kivilinna if (!i->b) 344937c30d7SJussi Kivilinna i->a++; 345937c30d7SJussi Kivilinna } 346937c30d7SJussi Kivilinna 347937c30d7SJussi Kivilinna static void ctr_crypt_final(struct blkcipher_desc *desc, 348937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 349937c30d7SJussi Kivilinna { 350937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 351937c30d7SJussi Kivilinna u8 *ctrblk = walk->iv; 352937c30d7SJussi Kivilinna u8 keystream[SERPENT_BLOCK_SIZE]; 353937c30d7SJussi Kivilinna u8 *src = walk->src.virt.addr; 354937c30d7SJussi Kivilinna u8 *dst = walk->dst.virt.addr; 355937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 356937c30d7SJussi Kivilinna 357937c30d7SJussi Kivilinna __serpent_encrypt(ctx, keystream, ctrblk); 358937c30d7SJussi Kivilinna crypto_xor(keystream, src, nbytes); 359937c30d7SJussi Kivilinna memcpy(dst, keystream, nbytes); 360937c30d7SJussi Kivilinna 361937c30d7SJussi Kivilinna crypto_inc(ctrblk, SERPENT_BLOCK_SIZE); 362937c30d7SJussi Kivilinna } 363937c30d7SJussi Kivilinna 364937c30d7SJussi Kivilinna static unsigned int __ctr_crypt(struct blkcipher_desc *desc, 365937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 366937c30d7SJussi Kivilinna { 367937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 368937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 369937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 370937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 371937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 372937c30d7SJussi Kivilinna u128 ctrblk; 373937c30d7SJussi Kivilinna be128 ctrblocks[SERPENT_PARALLEL_BLOCKS]; 374937c30d7SJussi Kivilinna int i; 375937c30d7SJussi Kivilinna 376937c30d7SJussi Kivilinna be128_to_u128(&ctrblk, (be128 *)walk->iv); 377937c30d7SJussi Kivilinna 378937c30d7SJussi Kivilinna /* Process multi-block batch */ 379937c30d7SJussi Kivilinna if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) { 380937c30d7SJussi Kivilinna do { 381937c30d7SJussi Kivilinna /* create ctrblks for parallel encrypt */ 382937c30d7SJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) { 383937c30d7SJussi Kivilinna if (dst != src) 384937c30d7SJussi Kivilinna dst[i] = src[i]; 385937c30d7SJussi Kivilinna 386937c30d7SJussi Kivilinna u128_to_be128(&ctrblocks[i], &ctrblk); 387937c30d7SJussi Kivilinna u128_inc(&ctrblk); 388937c30d7SJussi Kivilinna } 389937c30d7SJussi Kivilinna 390937c30d7SJussi Kivilinna serpent_enc_blk_xway_xor(ctx, (u8 *)dst, 391937c30d7SJussi Kivilinna (u8 *)ctrblocks); 392937c30d7SJussi Kivilinna 393937c30d7SJussi Kivilinna src += SERPENT_PARALLEL_BLOCKS; 394937c30d7SJussi Kivilinna dst += SERPENT_PARALLEL_BLOCKS; 395937c30d7SJussi Kivilinna nbytes -= bsize * SERPENT_PARALLEL_BLOCKS; 396937c30d7SJussi Kivilinna } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS); 397937c30d7SJussi Kivilinna 398937c30d7SJussi Kivilinna if (nbytes < bsize) 399937c30d7SJussi Kivilinna goto done; 400937c30d7SJussi Kivilinna } 401937c30d7SJussi Kivilinna 402937c30d7SJussi Kivilinna /* Handle leftovers */ 403937c30d7SJussi Kivilinna do { 404937c30d7SJussi Kivilinna if (dst != src) 405937c30d7SJussi Kivilinna *dst = *src; 406937c30d7SJussi Kivilinna 407937c30d7SJussi Kivilinna u128_to_be128(&ctrblocks[0], &ctrblk); 408937c30d7SJussi Kivilinna u128_inc(&ctrblk); 409937c30d7SJussi Kivilinna 410937c30d7SJussi Kivilinna __serpent_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks); 411937c30d7SJussi Kivilinna u128_xor(dst, dst, (u128 *)ctrblocks); 412937c30d7SJussi Kivilinna 413937c30d7SJussi Kivilinna src += 1; 414937c30d7SJussi Kivilinna dst += 1; 415937c30d7SJussi Kivilinna nbytes -= bsize; 416937c30d7SJussi Kivilinna } while (nbytes >= bsize); 417937c30d7SJussi Kivilinna 418937c30d7SJussi Kivilinna done: 419937c30d7SJussi Kivilinna u128_to_be128((be128 *)walk->iv, &ctrblk); 420937c30d7SJussi Kivilinna return nbytes; 421937c30d7SJussi Kivilinna } 422937c30d7SJussi Kivilinna 423937c30d7SJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, 424937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 425937c30d7SJussi Kivilinna { 426937c30d7SJussi Kivilinna bool fpu_enabled = false; 427937c30d7SJussi Kivilinna struct blkcipher_walk walk; 428937c30d7SJussi Kivilinna int err; 429937c30d7SJussi Kivilinna 430937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 431937c30d7SJussi Kivilinna err = blkcipher_walk_virt_block(desc, &walk, SERPENT_BLOCK_SIZE); 432937c30d7SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 433937c30d7SJussi Kivilinna 434937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes) >= SERPENT_BLOCK_SIZE) { 435937c30d7SJussi Kivilinna fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes); 436937c30d7SJussi Kivilinna nbytes = __ctr_crypt(desc, &walk); 437937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 438937c30d7SJussi Kivilinna } 439937c30d7SJussi Kivilinna 440937c30d7SJussi Kivilinna serpent_fpu_end(fpu_enabled); 441937c30d7SJussi Kivilinna 442937c30d7SJussi Kivilinna if (walk.nbytes) { 443937c30d7SJussi Kivilinna ctr_crypt_final(desc, &walk); 444937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, 0); 445937c30d7SJussi Kivilinna } 446937c30d7SJussi Kivilinna 447937c30d7SJussi Kivilinna return err; 448937c30d7SJussi Kivilinna } 449937c30d7SJussi Kivilinna 450937c30d7SJussi Kivilinna static struct crypto_alg blk_ctr_alg = { 451937c30d7SJussi Kivilinna .cra_name = "__ctr-serpent-sse2", 452937c30d7SJussi Kivilinna .cra_driver_name = "__driver-ctr-serpent-sse2", 453937c30d7SJussi Kivilinna .cra_priority = 0, 454937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 455937c30d7SJussi Kivilinna .cra_blocksize = 1, 456937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 457937c30d7SJussi Kivilinna .cra_alignmask = 0, 458937c30d7SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 459937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 460937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), 461937c30d7SJussi Kivilinna .cra_u = { 462937c30d7SJussi Kivilinna .blkcipher = { 463937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 464937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 465937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 466937c30d7SJussi Kivilinna .setkey = serpent_setkey, 467937c30d7SJussi Kivilinna .encrypt = ctr_crypt, 468937c30d7SJussi Kivilinna .decrypt = ctr_crypt, 469937c30d7SJussi Kivilinna }, 470937c30d7SJussi Kivilinna }, 471937c30d7SJussi Kivilinna }; 472937c30d7SJussi Kivilinna 4735962f8b6SJussi Kivilinna #if defined(HAS_LRW) || defined(HAS_XTS) 47418482053SJussi Kivilinna 47518482053SJussi Kivilinna struct crypt_priv { 47618482053SJussi Kivilinna struct serpent_ctx *ctx; 47718482053SJussi Kivilinna bool fpu_enabled; 47818482053SJussi Kivilinna }; 47918482053SJussi Kivilinna 48018482053SJussi Kivilinna static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) 48118482053SJussi Kivilinna { 48218482053SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 48318482053SJussi Kivilinna struct crypt_priv *ctx = priv; 48418482053SJussi Kivilinna int i; 48518482053SJussi Kivilinna 48618482053SJussi Kivilinna ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes); 48718482053SJussi Kivilinna 48818482053SJussi Kivilinna if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) { 48918482053SJussi Kivilinna serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst); 49018482053SJussi Kivilinna return; 49118482053SJussi Kivilinna } 49218482053SJussi Kivilinna 49318482053SJussi Kivilinna for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) 49418482053SJussi Kivilinna __serpent_encrypt(ctx->ctx, srcdst, srcdst); 49518482053SJussi Kivilinna } 49618482053SJussi Kivilinna 49718482053SJussi Kivilinna static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) 49818482053SJussi Kivilinna { 49918482053SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 50018482053SJussi Kivilinna struct crypt_priv *ctx = priv; 50118482053SJussi Kivilinna int i; 50218482053SJussi Kivilinna 50318482053SJussi Kivilinna ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes); 50418482053SJussi Kivilinna 50518482053SJussi Kivilinna if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) { 50618482053SJussi Kivilinna serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst); 50718482053SJussi Kivilinna return; 50818482053SJussi Kivilinna } 50918482053SJussi Kivilinna 51018482053SJussi Kivilinna for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) 51118482053SJussi Kivilinna __serpent_decrypt(ctx->ctx, srcdst, srcdst); 51218482053SJussi Kivilinna } 51318482053SJussi Kivilinna 5145962f8b6SJussi Kivilinna #endif 5155962f8b6SJussi Kivilinna 5165962f8b6SJussi Kivilinna #ifdef HAS_LRW 5175962f8b6SJussi Kivilinna 51818482053SJussi Kivilinna struct serpent_lrw_ctx { 51918482053SJussi Kivilinna struct lrw_table_ctx lrw_table; 52018482053SJussi Kivilinna struct serpent_ctx serpent_ctx; 52118482053SJussi Kivilinna }; 52218482053SJussi Kivilinna 52318482053SJussi Kivilinna static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key, 52418482053SJussi Kivilinna unsigned int keylen) 52518482053SJussi Kivilinna { 52618482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm); 52718482053SJussi Kivilinna int err; 52818482053SJussi Kivilinna 52918482053SJussi Kivilinna err = __serpent_setkey(&ctx->serpent_ctx, key, keylen - 53018482053SJussi Kivilinna SERPENT_BLOCK_SIZE); 53118482053SJussi Kivilinna if (err) 53218482053SJussi Kivilinna return err; 53318482053SJussi Kivilinna 53418482053SJussi Kivilinna return lrw_init_table(&ctx->lrw_table, key + keylen - 53518482053SJussi Kivilinna SERPENT_BLOCK_SIZE); 53618482053SJussi Kivilinna } 53718482053SJussi Kivilinna 53818482053SJussi Kivilinna static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 53918482053SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 54018482053SJussi Kivilinna { 54118482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 54218482053SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 54318482053SJussi Kivilinna struct crypt_priv crypt_ctx = { 54418482053SJussi Kivilinna .ctx = &ctx->serpent_ctx, 54518482053SJussi Kivilinna .fpu_enabled = false, 54618482053SJussi Kivilinna }; 54718482053SJussi Kivilinna struct lrw_crypt_req req = { 54818482053SJussi Kivilinna .tbuf = buf, 54918482053SJussi Kivilinna .tbuflen = sizeof(buf), 55018482053SJussi Kivilinna 55118482053SJussi Kivilinna .table_ctx = &ctx->lrw_table, 55218482053SJussi Kivilinna .crypt_ctx = &crypt_ctx, 55318482053SJussi Kivilinna .crypt_fn = encrypt_callback, 55418482053SJussi Kivilinna }; 55518482053SJussi Kivilinna int ret; 55618482053SJussi Kivilinna 557d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 55818482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 55918482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 56018482053SJussi Kivilinna 56118482053SJussi Kivilinna return ret; 56218482053SJussi Kivilinna } 56318482053SJussi Kivilinna 56418482053SJussi Kivilinna static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 56518482053SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 56618482053SJussi Kivilinna { 56718482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 56818482053SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 56918482053SJussi Kivilinna struct crypt_priv crypt_ctx = { 57018482053SJussi Kivilinna .ctx = &ctx->serpent_ctx, 57118482053SJussi Kivilinna .fpu_enabled = false, 57218482053SJussi Kivilinna }; 57318482053SJussi Kivilinna struct lrw_crypt_req req = { 57418482053SJussi Kivilinna .tbuf = buf, 57518482053SJussi Kivilinna .tbuflen = sizeof(buf), 57618482053SJussi Kivilinna 57718482053SJussi Kivilinna .table_ctx = &ctx->lrw_table, 57818482053SJussi Kivilinna .crypt_ctx = &crypt_ctx, 57918482053SJussi Kivilinna .crypt_fn = decrypt_callback, 58018482053SJussi Kivilinna }; 58118482053SJussi Kivilinna int ret; 58218482053SJussi Kivilinna 583d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 58418482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 58518482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 58618482053SJussi Kivilinna 58718482053SJussi Kivilinna return ret; 58818482053SJussi Kivilinna } 58918482053SJussi Kivilinna 59018482053SJussi Kivilinna static void lrw_exit_tfm(struct crypto_tfm *tfm) 59118482053SJussi Kivilinna { 59218482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm); 59318482053SJussi Kivilinna 59418482053SJussi Kivilinna lrw_free_table(&ctx->lrw_table); 59518482053SJussi Kivilinna } 59618482053SJussi Kivilinna 59718482053SJussi Kivilinna static struct crypto_alg blk_lrw_alg = { 59818482053SJussi Kivilinna .cra_name = "__lrw-serpent-sse2", 59918482053SJussi Kivilinna .cra_driver_name = "__driver-lrw-serpent-sse2", 60018482053SJussi Kivilinna .cra_priority = 0, 60118482053SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 60218482053SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 60318482053SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_lrw_ctx), 60418482053SJussi Kivilinna .cra_alignmask = 0, 60518482053SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 60618482053SJussi Kivilinna .cra_module = THIS_MODULE, 60718482053SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_lrw_alg.cra_list), 60818482053SJussi Kivilinna .cra_exit = lrw_exit_tfm, 60918482053SJussi Kivilinna .cra_u = { 61018482053SJussi Kivilinna .blkcipher = { 61118482053SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 61218482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 61318482053SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 61418482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 61518482053SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 61618482053SJussi Kivilinna .setkey = lrw_serpent_setkey, 61718482053SJussi Kivilinna .encrypt = lrw_encrypt, 61818482053SJussi Kivilinna .decrypt = lrw_decrypt, 61918482053SJussi Kivilinna }, 62018482053SJussi Kivilinna }, 62118482053SJussi Kivilinna }; 62218482053SJussi Kivilinna 62318482053SJussi Kivilinna #endif 62418482053SJussi Kivilinna 6255962f8b6SJussi Kivilinna #ifdef HAS_XTS 6265962f8b6SJussi Kivilinna 6275962f8b6SJussi Kivilinna struct serpent_xts_ctx { 6285962f8b6SJussi Kivilinna struct serpent_ctx tweak_ctx; 6295962f8b6SJussi Kivilinna struct serpent_ctx crypt_ctx; 6305962f8b6SJussi Kivilinna }; 6315962f8b6SJussi Kivilinna 6325962f8b6SJussi Kivilinna static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key, 6335962f8b6SJussi Kivilinna unsigned int keylen) 6345962f8b6SJussi Kivilinna { 6355962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm); 6365962f8b6SJussi Kivilinna u32 *flags = &tfm->crt_flags; 6375962f8b6SJussi Kivilinna int err; 6385962f8b6SJussi Kivilinna 6395962f8b6SJussi Kivilinna /* key consists of keys of equal size concatenated, therefore 6405962f8b6SJussi Kivilinna * the length must be even 6415962f8b6SJussi Kivilinna */ 6425962f8b6SJussi Kivilinna if (keylen % 2) { 6435962f8b6SJussi Kivilinna *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 6445962f8b6SJussi Kivilinna return -EINVAL; 6455962f8b6SJussi Kivilinna } 6465962f8b6SJussi Kivilinna 6475962f8b6SJussi Kivilinna /* first half of xts-key is for crypt */ 6485962f8b6SJussi Kivilinna err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2); 6495962f8b6SJussi Kivilinna if (err) 6505962f8b6SJussi Kivilinna return err; 6515962f8b6SJussi Kivilinna 6525962f8b6SJussi Kivilinna /* second half of xts-key is for tweak */ 6535962f8b6SJussi Kivilinna return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2); 6545962f8b6SJussi Kivilinna } 6555962f8b6SJussi Kivilinna 6565962f8b6SJussi Kivilinna static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 6575962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 6585962f8b6SJussi Kivilinna { 6595962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 6605962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 6615962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 6625962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 6635962f8b6SJussi Kivilinna .fpu_enabled = false, 6645962f8b6SJussi Kivilinna }; 6655962f8b6SJussi Kivilinna struct xts_crypt_req req = { 6665962f8b6SJussi Kivilinna .tbuf = buf, 6675962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 6685962f8b6SJussi Kivilinna 6695962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 6705962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 6715962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 6725962f8b6SJussi Kivilinna .crypt_fn = encrypt_callback, 6735962f8b6SJussi Kivilinna }; 6745962f8b6SJussi Kivilinna int ret; 6755962f8b6SJussi Kivilinna 676d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 6775962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 6785962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 6795962f8b6SJussi Kivilinna 6805962f8b6SJussi Kivilinna return ret; 6815962f8b6SJussi Kivilinna } 6825962f8b6SJussi Kivilinna 6835962f8b6SJussi Kivilinna static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 6845962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 6855962f8b6SJussi Kivilinna { 6865962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 6875962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 6885962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 6895962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 6905962f8b6SJussi Kivilinna .fpu_enabled = false, 6915962f8b6SJussi Kivilinna }; 6925962f8b6SJussi Kivilinna struct xts_crypt_req req = { 6935962f8b6SJussi Kivilinna .tbuf = buf, 6945962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 6955962f8b6SJussi Kivilinna 6965962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 6975962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 6985962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 6995962f8b6SJussi Kivilinna .crypt_fn = decrypt_callback, 7005962f8b6SJussi Kivilinna }; 7015962f8b6SJussi Kivilinna int ret; 7025962f8b6SJussi Kivilinna 703d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 7045962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 7055962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 7065962f8b6SJussi Kivilinna 7075962f8b6SJussi Kivilinna return ret; 7085962f8b6SJussi Kivilinna } 7095962f8b6SJussi Kivilinna 7105962f8b6SJussi Kivilinna static struct crypto_alg blk_xts_alg = { 7115962f8b6SJussi Kivilinna .cra_name = "__xts-serpent-sse2", 7125962f8b6SJussi Kivilinna .cra_driver_name = "__driver-xts-serpent-sse2", 7135962f8b6SJussi Kivilinna .cra_priority = 0, 7145962f8b6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 7155962f8b6SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 7165962f8b6SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_xts_ctx), 7175962f8b6SJussi Kivilinna .cra_alignmask = 0, 7185962f8b6SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 7195962f8b6SJussi Kivilinna .cra_module = THIS_MODULE, 7205962f8b6SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), 7215962f8b6SJussi Kivilinna .cra_u = { 7225962f8b6SJussi Kivilinna .blkcipher = { 7235962f8b6SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 7245962f8b6SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 7255962f8b6SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 7265962f8b6SJussi Kivilinna .setkey = xts_serpent_setkey, 7275962f8b6SJussi Kivilinna .encrypt = xts_encrypt, 7285962f8b6SJussi Kivilinna .decrypt = xts_decrypt, 7295962f8b6SJussi Kivilinna }, 7305962f8b6SJussi Kivilinna }, 7315962f8b6SJussi Kivilinna }; 7325962f8b6SJussi Kivilinna 7335962f8b6SJussi Kivilinna #endif 7345962f8b6SJussi Kivilinna 735937c30d7SJussi Kivilinna static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, 736937c30d7SJussi Kivilinna unsigned int key_len) 737937c30d7SJussi Kivilinna { 738937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 739937c30d7SJussi Kivilinna struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base; 740937c30d7SJussi Kivilinna int err; 741937c30d7SJussi Kivilinna 742937c30d7SJussi Kivilinna crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); 743937c30d7SJussi Kivilinna crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm) 744937c30d7SJussi Kivilinna & CRYPTO_TFM_REQ_MASK); 745937c30d7SJussi Kivilinna err = crypto_ablkcipher_setkey(child, key, key_len); 746937c30d7SJussi Kivilinna crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child) 747937c30d7SJussi Kivilinna & CRYPTO_TFM_RES_MASK); 748937c30d7SJussi Kivilinna return err; 749937c30d7SJussi Kivilinna } 750937c30d7SJussi Kivilinna 751937c30d7SJussi Kivilinna static int __ablk_encrypt(struct ablkcipher_request *req) 752937c30d7SJussi Kivilinna { 753937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 754937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 755937c30d7SJussi Kivilinna struct blkcipher_desc desc; 756937c30d7SJussi Kivilinna 757937c30d7SJussi Kivilinna desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); 758937c30d7SJussi Kivilinna desc.info = req->info; 759937c30d7SJussi Kivilinna desc.flags = 0; 760937c30d7SJussi Kivilinna 761937c30d7SJussi Kivilinna return crypto_blkcipher_crt(desc.tfm)->encrypt( 762937c30d7SJussi Kivilinna &desc, req->dst, req->src, req->nbytes); 763937c30d7SJussi Kivilinna } 764937c30d7SJussi Kivilinna 765937c30d7SJussi Kivilinna static int ablk_encrypt(struct ablkcipher_request *req) 766937c30d7SJussi Kivilinna { 767937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 768937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 769937c30d7SJussi Kivilinna 770937c30d7SJussi Kivilinna if (!irq_fpu_usable()) { 771937c30d7SJussi Kivilinna struct ablkcipher_request *cryptd_req = 772937c30d7SJussi Kivilinna ablkcipher_request_ctx(req); 773937c30d7SJussi Kivilinna 774937c30d7SJussi Kivilinna memcpy(cryptd_req, req, sizeof(*req)); 775937c30d7SJussi Kivilinna ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); 776937c30d7SJussi Kivilinna 777937c30d7SJussi Kivilinna return crypto_ablkcipher_encrypt(cryptd_req); 778937c30d7SJussi Kivilinna } else { 779937c30d7SJussi Kivilinna return __ablk_encrypt(req); 780937c30d7SJussi Kivilinna } 781937c30d7SJussi Kivilinna } 782937c30d7SJussi Kivilinna 783937c30d7SJussi Kivilinna static int ablk_decrypt(struct ablkcipher_request *req) 784937c30d7SJussi Kivilinna { 785937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 786937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 787937c30d7SJussi Kivilinna 788937c30d7SJussi Kivilinna if (!irq_fpu_usable()) { 789937c30d7SJussi Kivilinna struct ablkcipher_request *cryptd_req = 790937c30d7SJussi Kivilinna ablkcipher_request_ctx(req); 791937c30d7SJussi Kivilinna 792937c30d7SJussi Kivilinna memcpy(cryptd_req, req, sizeof(*req)); 793937c30d7SJussi Kivilinna ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); 794937c30d7SJussi Kivilinna 795937c30d7SJussi Kivilinna return crypto_ablkcipher_decrypt(cryptd_req); 796937c30d7SJussi Kivilinna } else { 797937c30d7SJussi Kivilinna struct blkcipher_desc desc; 798937c30d7SJussi Kivilinna 799937c30d7SJussi Kivilinna desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); 800937c30d7SJussi Kivilinna desc.info = req->info; 801937c30d7SJussi Kivilinna desc.flags = 0; 802937c30d7SJussi Kivilinna 803937c30d7SJussi Kivilinna return crypto_blkcipher_crt(desc.tfm)->decrypt( 804937c30d7SJussi Kivilinna &desc, req->dst, req->src, req->nbytes); 805937c30d7SJussi Kivilinna } 806937c30d7SJussi Kivilinna } 807937c30d7SJussi Kivilinna 808937c30d7SJussi Kivilinna static void ablk_exit(struct crypto_tfm *tfm) 809937c30d7SJussi Kivilinna { 810937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); 811937c30d7SJussi Kivilinna 812937c30d7SJussi Kivilinna cryptd_free_ablkcipher(ctx->cryptd_tfm); 813937c30d7SJussi Kivilinna } 814937c30d7SJussi Kivilinna 815937c30d7SJussi Kivilinna static void ablk_init_common(struct crypto_tfm *tfm, 816937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm) 817937c30d7SJussi Kivilinna { 818937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); 819937c30d7SJussi Kivilinna 820937c30d7SJussi Kivilinna ctx->cryptd_tfm = cryptd_tfm; 821937c30d7SJussi Kivilinna tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) + 822937c30d7SJussi Kivilinna crypto_ablkcipher_reqsize(&cryptd_tfm->base); 823937c30d7SJussi Kivilinna } 824937c30d7SJussi Kivilinna 825937c30d7SJussi Kivilinna static int ablk_ecb_init(struct crypto_tfm *tfm) 826937c30d7SJussi Kivilinna { 827937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 828937c30d7SJussi Kivilinna 829937c30d7SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-serpent-sse2", 0, 0); 830937c30d7SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 831937c30d7SJussi Kivilinna return PTR_ERR(cryptd_tfm); 832937c30d7SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 833937c30d7SJussi Kivilinna return 0; 834937c30d7SJussi Kivilinna } 835937c30d7SJussi Kivilinna 836937c30d7SJussi Kivilinna static struct crypto_alg ablk_ecb_alg = { 837937c30d7SJussi Kivilinna .cra_name = "ecb(serpent)", 838937c30d7SJussi Kivilinna .cra_driver_name = "ecb-serpent-sse2", 839937c30d7SJussi Kivilinna .cra_priority = 400, 840937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 841937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 842937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 843937c30d7SJussi Kivilinna .cra_alignmask = 0, 844937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 845937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 846937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list), 847937c30d7SJussi Kivilinna .cra_init = ablk_ecb_init, 848937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 849937c30d7SJussi Kivilinna .cra_u = { 850937c30d7SJussi Kivilinna .ablkcipher = { 851937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 852937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 853937c30d7SJussi Kivilinna .setkey = ablk_set_key, 854937c30d7SJussi Kivilinna .encrypt = ablk_encrypt, 855937c30d7SJussi Kivilinna .decrypt = ablk_decrypt, 856937c30d7SJussi Kivilinna }, 857937c30d7SJussi Kivilinna }, 858937c30d7SJussi Kivilinna }; 859937c30d7SJussi Kivilinna 860937c30d7SJussi Kivilinna static int ablk_cbc_init(struct crypto_tfm *tfm) 861937c30d7SJussi Kivilinna { 862937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 863937c30d7SJussi Kivilinna 864937c30d7SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-serpent-sse2", 0, 0); 865937c30d7SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 866937c30d7SJussi Kivilinna return PTR_ERR(cryptd_tfm); 867937c30d7SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 868937c30d7SJussi Kivilinna return 0; 869937c30d7SJussi Kivilinna } 870937c30d7SJussi Kivilinna 871937c30d7SJussi Kivilinna static struct crypto_alg ablk_cbc_alg = { 872937c30d7SJussi Kivilinna .cra_name = "cbc(serpent)", 873937c30d7SJussi Kivilinna .cra_driver_name = "cbc-serpent-sse2", 874937c30d7SJussi Kivilinna .cra_priority = 400, 875937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 876937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 877937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 878937c30d7SJussi Kivilinna .cra_alignmask = 0, 879937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 880937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 881937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list), 882937c30d7SJussi Kivilinna .cra_init = ablk_cbc_init, 883937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 884937c30d7SJussi Kivilinna .cra_u = { 885937c30d7SJussi Kivilinna .ablkcipher = { 886937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 887937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 888937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 889937c30d7SJussi Kivilinna .setkey = ablk_set_key, 890937c30d7SJussi Kivilinna .encrypt = __ablk_encrypt, 891937c30d7SJussi Kivilinna .decrypt = ablk_decrypt, 892937c30d7SJussi Kivilinna }, 893937c30d7SJussi Kivilinna }, 894937c30d7SJussi Kivilinna }; 895937c30d7SJussi Kivilinna 896937c30d7SJussi Kivilinna static int ablk_ctr_init(struct crypto_tfm *tfm) 897937c30d7SJussi Kivilinna { 898937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 899937c30d7SJussi Kivilinna 900937c30d7SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-serpent-sse2", 0, 0); 901937c30d7SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 902937c30d7SJussi Kivilinna return PTR_ERR(cryptd_tfm); 903937c30d7SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 904937c30d7SJussi Kivilinna return 0; 905937c30d7SJussi Kivilinna } 906937c30d7SJussi Kivilinna 907937c30d7SJussi Kivilinna static struct crypto_alg ablk_ctr_alg = { 908937c30d7SJussi Kivilinna .cra_name = "ctr(serpent)", 909937c30d7SJussi Kivilinna .cra_driver_name = "ctr-serpent-sse2", 910937c30d7SJussi Kivilinna .cra_priority = 400, 911937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 912937c30d7SJussi Kivilinna .cra_blocksize = 1, 913937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 914937c30d7SJussi Kivilinna .cra_alignmask = 0, 915937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 916937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 917937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list), 918937c30d7SJussi Kivilinna .cra_init = ablk_ctr_init, 919937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 920937c30d7SJussi Kivilinna .cra_u = { 921937c30d7SJussi Kivilinna .ablkcipher = { 922937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 923937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 924937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 925937c30d7SJussi Kivilinna .setkey = ablk_set_key, 926937c30d7SJussi Kivilinna .encrypt = ablk_encrypt, 927937c30d7SJussi Kivilinna .decrypt = ablk_encrypt, 928937c30d7SJussi Kivilinna .geniv = "chainiv", 929937c30d7SJussi Kivilinna }, 930937c30d7SJussi Kivilinna }, 931937c30d7SJussi Kivilinna }; 932937c30d7SJussi Kivilinna 93318482053SJussi Kivilinna #ifdef HAS_LRW 93418482053SJussi Kivilinna 93518482053SJussi Kivilinna static int ablk_lrw_init(struct crypto_tfm *tfm) 93618482053SJussi Kivilinna { 93718482053SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 93818482053SJussi Kivilinna 93918482053SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-lrw-serpent-sse2", 0, 0); 94018482053SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 94118482053SJussi Kivilinna return PTR_ERR(cryptd_tfm); 94218482053SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 94318482053SJussi Kivilinna return 0; 94418482053SJussi Kivilinna } 94518482053SJussi Kivilinna 94618482053SJussi Kivilinna static struct crypto_alg ablk_lrw_alg = { 94718482053SJussi Kivilinna .cra_name = "lrw(serpent)", 94818482053SJussi Kivilinna .cra_driver_name = "lrw-serpent-sse2", 94918482053SJussi Kivilinna .cra_priority = 400, 95018482053SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 95118482053SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 95218482053SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 95318482053SJussi Kivilinna .cra_alignmask = 0, 95418482053SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 95518482053SJussi Kivilinna .cra_module = THIS_MODULE, 95618482053SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list), 95718482053SJussi Kivilinna .cra_init = ablk_lrw_init, 95818482053SJussi Kivilinna .cra_exit = ablk_exit, 95918482053SJussi Kivilinna .cra_u = { 96018482053SJussi Kivilinna .ablkcipher = { 96118482053SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 96218482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 96318482053SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 96418482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 96518482053SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 96618482053SJussi Kivilinna .setkey = ablk_set_key, 96718482053SJussi Kivilinna .encrypt = ablk_encrypt, 96818482053SJussi Kivilinna .decrypt = ablk_decrypt, 96918482053SJussi Kivilinna }, 97018482053SJussi Kivilinna }, 97118482053SJussi Kivilinna }; 97218482053SJussi Kivilinna 97318482053SJussi Kivilinna #endif 97418482053SJussi Kivilinna 9755962f8b6SJussi Kivilinna #ifdef HAS_XTS 9765962f8b6SJussi Kivilinna 9775962f8b6SJussi Kivilinna static int ablk_xts_init(struct crypto_tfm *tfm) 9785962f8b6SJussi Kivilinna { 9795962f8b6SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 9805962f8b6SJussi Kivilinna 9815962f8b6SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-xts-serpent-sse2", 0, 0); 9825962f8b6SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 9835962f8b6SJussi Kivilinna return PTR_ERR(cryptd_tfm); 9845962f8b6SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 9855962f8b6SJussi Kivilinna return 0; 9865962f8b6SJussi Kivilinna } 9875962f8b6SJussi Kivilinna 9885962f8b6SJussi Kivilinna static struct crypto_alg ablk_xts_alg = { 9895962f8b6SJussi Kivilinna .cra_name = "xts(serpent)", 9905962f8b6SJussi Kivilinna .cra_driver_name = "xts-serpent-sse2", 9915962f8b6SJussi Kivilinna .cra_priority = 400, 9925962f8b6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 9935962f8b6SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 9945962f8b6SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 9955962f8b6SJussi Kivilinna .cra_alignmask = 0, 9965962f8b6SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 9975962f8b6SJussi Kivilinna .cra_module = THIS_MODULE, 9985962f8b6SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list), 9995962f8b6SJussi Kivilinna .cra_init = ablk_xts_init, 10005962f8b6SJussi Kivilinna .cra_exit = ablk_exit, 10015962f8b6SJussi Kivilinna .cra_u = { 10025962f8b6SJussi Kivilinna .ablkcipher = { 10035962f8b6SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 10045962f8b6SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 10055962f8b6SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 10065962f8b6SJussi Kivilinna .setkey = ablk_set_key, 10075962f8b6SJussi Kivilinna .encrypt = ablk_encrypt, 10085962f8b6SJussi Kivilinna .decrypt = ablk_decrypt, 10095962f8b6SJussi Kivilinna }, 10105962f8b6SJussi Kivilinna }, 10115962f8b6SJussi Kivilinna }; 10125962f8b6SJussi Kivilinna 10135962f8b6SJussi Kivilinna #endif 10145962f8b6SJussi Kivilinna 1015937c30d7SJussi Kivilinna static int __init serpent_sse2_init(void) 1016937c30d7SJussi Kivilinna { 1017937c30d7SJussi Kivilinna int err; 1018937c30d7SJussi Kivilinna 1019937c30d7SJussi Kivilinna if (!cpu_has_xmm2) { 1020937c30d7SJussi Kivilinna printk(KERN_INFO "SSE2 instructions are not detected.\n"); 1021937c30d7SJussi Kivilinna return -ENODEV; 1022937c30d7SJussi Kivilinna } 1023937c30d7SJussi Kivilinna 1024937c30d7SJussi Kivilinna err = crypto_register_alg(&blk_ecb_alg); 1025937c30d7SJussi Kivilinna if (err) 1026937c30d7SJussi Kivilinna goto blk_ecb_err; 1027937c30d7SJussi Kivilinna err = crypto_register_alg(&blk_cbc_alg); 1028937c30d7SJussi Kivilinna if (err) 1029937c30d7SJussi Kivilinna goto blk_cbc_err; 1030937c30d7SJussi Kivilinna err = crypto_register_alg(&blk_ctr_alg); 1031937c30d7SJussi Kivilinna if (err) 1032937c30d7SJussi Kivilinna goto blk_ctr_err; 1033937c30d7SJussi Kivilinna err = crypto_register_alg(&ablk_ecb_alg); 1034937c30d7SJussi Kivilinna if (err) 1035937c30d7SJussi Kivilinna goto ablk_ecb_err; 1036937c30d7SJussi Kivilinna err = crypto_register_alg(&ablk_cbc_alg); 1037937c30d7SJussi Kivilinna if (err) 1038937c30d7SJussi Kivilinna goto ablk_cbc_err; 1039937c30d7SJussi Kivilinna err = crypto_register_alg(&ablk_ctr_alg); 1040937c30d7SJussi Kivilinna if (err) 1041937c30d7SJussi Kivilinna goto ablk_ctr_err; 104218482053SJussi Kivilinna #ifdef HAS_LRW 104318482053SJussi Kivilinna err = crypto_register_alg(&blk_lrw_alg); 104418482053SJussi Kivilinna if (err) 104518482053SJussi Kivilinna goto blk_lrw_err; 104618482053SJussi Kivilinna err = crypto_register_alg(&ablk_lrw_alg); 104718482053SJussi Kivilinna if (err) 104818482053SJussi Kivilinna goto ablk_lrw_err; 104918482053SJussi Kivilinna #endif 10505962f8b6SJussi Kivilinna #ifdef HAS_XTS 10515962f8b6SJussi Kivilinna err = crypto_register_alg(&blk_xts_alg); 10525962f8b6SJussi Kivilinna if (err) 10535962f8b6SJussi Kivilinna goto blk_xts_err; 10545962f8b6SJussi Kivilinna err = crypto_register_alg(&ablk_xts_alg); 10555962f8b6SJussi Kivilinna if (err) 10565962f8b6SJussi Kivilinna goto ablk_xts_err; 10575962f8b6SJussi Kivilinna #endif 1058937c30d7SJussi Kivilinna return err; 1059937c30d7SJussi Kivilinna 10605962f8b6SJussi Kivilinna #ifdef HAS_XTS 10615962f8b6SJussi Kivilinna crypto_unregister_alg(&ablk_xts_alg); 10625962f8b6SJussi Kivilinna ablk_xts_err: 10635962f8b6SJussi Kivilinna crypto_unregister_alg(&blk_xts_alg); 10645962f8b6SJussi Kivilinna blk_xts_err: 10655962f8b6SJussi Kivilinna #endif 106618482053SJussi Kivilinna #ifdef HAS_LRW 10675962f8b6SJussi Kivilinna crypto_unregister_alg(&ablk_lrw_alg); 106818482053SJussi Kivilinna ablk_lrw_err: 106918482053SJussi Kivilinna crypto_unregister_alg(&blk_lrw_alg); 107018482053SJussi Kivilinna blk_lrw_err: 107118482053SJussi Kivilinna #endif 10725962f8b6SJussi Kivilinna crypto_unregister_alg(&ablk_ctr_alg); 1073937c30d7SJussi Kivilinna ablk_ctr_err: 1074937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_cbc_alg); 1075937c30d7SJussi Kivilinna ablk_cbc_err: 1076937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_ecb_alg); 1077937c30d7SJussi Kivilinna ablk_ecb_err: 1078937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ctr_alg); 1079937c30d7SJussi Kivilinna blk_ctr_err: 1080937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 1081937c30d7SJussi Kivilinna blk_cbc_err: 1082937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 1083937c30d7SJussi Kivilinna blk_ecb_err: 1084937c30d7SJussi Kivilinna return err; 1085937c30d7SJussi Kivilinna } 1086937c30d7SJussi Kivilinna 1087937c30d7SJussi Kivilinna static void __exit serpent_sse2_exit(void) 1088937c30d7SJussi Kivilinna { 10895962f8b6SJussi Kivilinna #ifdef HAS_XTS 10905962f8b6SJussi Kivilinna crypto_unregister_alg(&ablk_xts_alg); 10915962f8b6SJussi Kivilinna crypto_unregister_alg(&blk_xts_alg); 10925962f8b6SJussi Kivilinna #endif 109318482053SJussi Kivilinna #ifdef HAS_LRW 109418482053SJussi Kivilinna crypto_unregister_alg(&ablk_lrw_alg); 109518482053SJussi Kivilinna crypto_unregister_alg(&blk_lrw_alg); 109618482053SJussi Kivilinna #endif 1097937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_ctr_alg); 1098937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_cbc_alg); 1099937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_ecb_alg); 1100937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ctr_alg); 1101937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 1102937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 1103937c30d7SJussi Kivilinna } 1104937c30d7SJussi Kivilinna 1105937c30d7SJussi Kivilinna module_init(serpent_sse2_init); 1106937c30d7SJussi Kivilinna module_exit(serpent_sse2_exit); 1107937c30d7SJussi Kivilinna 1108937c30d7SJussi Kivilinna MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 1109937c30d7SJussi Kivilinna MODULE_LICENSE("GPL"); 1110937c30d7SJussi Kivilinna MODULE_ALIAS("serpent"); 1111