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 55718482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 55818482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 55918482053SJussi Kivilinna 56018482053SJussi Kivilinna return ret; 56118482053SJussi Kivilinna } 56218482053SJussi Kivilinna 56318482053SJussi Kivilinna static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 56418482053SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 56518482053SJussi Kivilinna { 56618482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 56718482053SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 56818482053SJussi Kivilinna struct crypt_priv crypt_ctx = { 56918482053SJussi Kivilinna .ctx = &ctx->serpent_ctx, 57018482053SJussi Kivilinna .fpu_enabled = false, 57118482053SJussi Kivilinna }; 57218482053SJussi Kivilinna struct lrw_crypt_req req = { 57318482053SJussi Kivilinna .tbuf = buf, 57418482053SJussi Kivilinna .tbuflen = sizeof(buf), 57518482053SJussi Kivilinna 57618482053SJussi Kivilinna .table_ctx = &ctx->lrw_table, 57718482053SJussi Kivilinna .crypt_ctx = &crypt_ctx, 57818482053SJussi Kivilinna .crypt_fn = decrypt_callback, 57918482053SJussi Kivilinna }; 58018482053SJussi Kivilinna int ret; 58118482053SJussi Kivilinna 58218482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 58318482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 58418482053SJussi Kivilinna 58518482053SJussi Kivilinna return ret; 58618482053SJussi Kivilinna } 58718482053SJussi Kivilinna 58818482053SJussi Kivilinna static void lrw_exit_tfm(struct crypto_tfm *tfm) 58918482053SJussi Kivilinna { 59018482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm); 59118482053SJussi Kivilinna 59218482053SJussi Kivilinna lrw_free_table(&ctx->lrw_table); 59318482053SJussi Kivilinna } 59418482053SJussi Kivilinna 59518482053SJussi Kivilinna static struct crypto_alg blk_lrw_alg = { 59618482053SJussi Kivilinna .cra_name = "__lrw-serpent-sse2", 59718482053SJussi Kivilinna .cra_driver_name = "__driver-lrw-serpent-sse2", 59818482053SJussi Kivilinna .cra_priority = 0, 59918482053SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 60018482053SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 60118482053SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_lrw_ctx), 60218482053SJussi Kivilinna .cra_alignmask = 0, 60318482053SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 60418482053SJussi Kivilinna .cra_module = THIS_MODULE, 60518482053SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_lrw_alg.cra_list), 60618482053SJussi Kivilinna .cra_exit = lrw_exit_tfm, 60718482053SJussi Kivilinna .cra_u = { 60818482053SJussi Kivilinna .blkcipher = { 60918482053SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 61018482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 61118482053SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 61218482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 61318482053SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 61418482053SJussi Kivilinna .setkey = lrw_serpent_setkey, 61518482053SJussi Kivilinna .encrypt = lrw_encrypt, 61618482053SJussi Kivilinna .decrypt = lrw_decrypt, 61718482053SJussi Kivilinna }, 61818482053SJussi Kivilinna }, 61918482053SJussi Kivilinna }; 62018482053SJussi Kivilinna 62118482053SJussi Kivilinna #endif 62218482053SJussi Kivilinna 6235962f8b6SJussi Kivilinna #ifdef HAS_XTS 6245962f8b6SJussi Kivilinna 6255962f8b6SJussi Kivilinna struct serpent_xts_ctx { 6265962f8b6SJussi Kivilinna struct serpent_ctx tweak_ctx; 6275962f8b6SJussi Kivilinna struct serpent_ctx crypt_ctx; 6285962f8b6SJussi Kivilinna }; 6295962f8b6SJussi Kivilinna 6305962f8b6SJussi Kivilinna static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key, 6315962f8b6SJussi Kivilinna unsigned int keylen) 6325962f8b6SJussi Kivilinna { 6335962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm); 6345962f8b6SJussi Kivilinna u32 *flags = &tfm->crt_flags; 6355962f8b6SJussi Kivilinna int err; 6365962f8b6SJussi Kivilinna 6375962f8b6SJussi Kivilinna /* key consists of keys of equal size concatenated, therefore 6385962f8b6SJussi Kivilinna * the length must be even 6395962f8b6SJussi Kivilinna */ 6405962f8b6SJussi Kivilinna if (keylen % 2) { 6415962f8b6SJussi Kivilinna *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 6425962f8b6SJussi Kivilinna return -EINVAL; 6435962f8b6SJussi Kivilinna } 6445962f8b6SJussi Kivilinna 6455962f8b6SJussi Kivilinna /* first half of xts-key is for crypt */ 6465962f8b6SJussi Kivilinna err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2); 6475962f8b6SJussi Kivilinna if (err) 6485962f8b6SJussi Kivilinna return err; 6495962f8b6SJussi Kivilinna 6505962f8b6SJussi Kivilinna /* second half of xts-key is for tweak */ 6515962f8b6SJussi Kivilinna return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2); 6525962f8b6SJussi Kivilinna } 6535962f8b6SJussi Kivilinna 6545962f8b6SJussi Kivilinna static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 6555962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 6565962f8b6SJussi Kivilinna { 6575962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 6585962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 6595962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 6605962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 6615962f8b6SJussi Kivilinna .fpu_enabled = false, 6625962f8b6SJussi Kivilinna }; 6635962f8b6SJussi Kivilinna struct xts_crypt_req req = { 6645962f8b6SJussi Kivilinna .tbuf = buf, 6655962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 6665962f8b6SJussi Kivilinna 6675962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 6685962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 6695962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 6705962f8b6SJussi Kivilinna .crypt_fn = encrypt_callback, 6715962f8b6SJussi Kivilinna }; 6725962f8b6SJussi Kivilinna int ret; 6735962f8b6SJussi Kivilinna 6745962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 6755962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 6765962f8b6SJussi Kivilinna 6775962f8b6SJussi Kivilinna return ret; 6785962f8b6SJussi Kivilinna } 6795962f8b6SJussi Kivilinna 6805962f8b6SJussi Kivilinna static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 6815962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 6825962f8b6SJussi Kivilinna { 6835962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 6845962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 6855962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 6865962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 6875962f8b6SJussi Kivilinna .fpu_enabled = false, 6885962f8b6SJussi Kivilinna }; 6895962f8b6SJussi Kivilinna struct xts_crypt_req req = { 6905962f8b6SJussi Kivilinna .tbuf = buf, 6915962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 6925962f8b6SJussi Kivilinna 6935962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 6945962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 6955962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 6965962f8b6SJussi Kivilinna .crypt_fn = decrypt_callback, 6975962f8b6SJussi Kivilinna }; 6985962f8b6SJussi Kivilinna int ret; 6995962f8b6SJussi Kivilinna 7005962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 7015962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 7025962f8b6SJussi Kivilinna 7035962f8b6SJussi Kivilinna return ret; 7045962f8b6SJussi Kivilinna } 7055962f8b6SJussi Kivilinna 7065962f8b6SJussi Kivilinna static struct crypto_alg blk_xts_alg = { 7075962f8b6SJussi Kivilinna .cra_name = "__xts-serpent-sse2", 7085962f8b6SJussi Kivilinna .cra_driver_name = "__driver-xts-serpent-sse2", 7095962f8b6SJussi Kivilinna .cra_priority = 0, 7105962f8b6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 7115962f8b6SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 7125962f8b6SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_xts_ctx), 7135962f8b6SJussi Kivilinna .cra_alignmask = 0, 7145962f8b6SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 7155962f8b6SJussi Kivilinna .cra_module = THIS_MODULE, 7165962f8b6SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_xts_alg.cra_list), 7175962f8b6SJussi Kivilinna .cra_u = { 7185962f8b6SJussi Kivilinna .blkcipher = { 7195962f8b6SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 7205962f8b6SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 7215962f8b6SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 7225962f8b6SJussi Kivilinna .setkey = xts_serpent_setkey, 7235962f8b6SJussi Kivilinna .encrypt = xts_encrypt, 7245962f8b6SJussi Kivilinna .decrypt = xts_decrypt, 7255962f8b6SJussi Kivilinna }, 7265962f8b6SJussi Kivilinna }, 7275962f8b6SJussi Kivilinna }; 7285962f8b6SJussi Kivilinna 7295962f8b6SJussi Kivilinna #endif 7305962f8b6SJussi Kivilinna 731937c30d7SJussi Kivilinna static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, 732937c30d7SJussi Kivilinna unsigned int key_len) 733937c30d7SJussi Kivilinna { 734937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 735937c30d7SJussi Kivilinna struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base; 736937c30d7SJussi Kivilinna int err; 737937c30d7SJussi Kivilinna 738937c30d7SJussi Kivilinna crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); 739937c30d7SJussi Kivilinna crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm) 740937c30d7SJussi Kivilinna & CRYPTO_TFM_REQ_MASK); 741937c30d7SJussi Kivilinna err = crypto_ablkcipher_setkey(child, key, key_len); 742937c30d7SJussi Kivilinna crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child) 743937c30d7SJussi Kivilinna & CRYPTO_TFM_RES_MASK); 744937c30d7SJussi Kivilinna return err; 745937c30d7SJussi Kivilinna } 746937c30d7SJussi Kivilinna 747937c30d7SJussi Kivilinna static int __ablk_encrypt(struct ablkcipher_request *req) 748937c30d7SJussi Kivilinna { 749937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 750937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 751937c30d7SJussi Kivilinna struct blkcipher_desc desc; 752937c30d7SJussi Kivilinna 753937c30d7SJussi Kivilinna desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); 754937c30d7SJussi Kivilinna desc.info = req->info; 755937c30d7SJussi Kivilinna desc.flags = 0; 756937c30d7SJussi Kivilinna 757937c30d7SJussi Kivilinna return crypto_blkcipher_crt(desc.tfm)->encrypt( 758937c30d7SJussi Kivilinna &desc, req->dst, req->src, req->nbytes); 759937c30d7SJussi Kivilinna } 760937c30d7SJussi Kivilinna 761937c30d7SJussi Kivilinna static int ablk_encrypt(struct ablkcipher_request *req) 762937c30d7SJussi Kivilinna { 763937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 764937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 765937c30d7SJussi Kivilinna 766937c30d7SJussi Kivilinna if (!irq_fpu_usable()) { 767937c30d7SJussi Kivilinna struct ablkcipher_request *cryptd_req = 768937c30d7SJussi Kivilinna ablkcipher_request_ctx(req); 769937c30d7SJussi Kivilinna 770937c30d7SJussi Kivilinna memcpy(cryptd_req, req, sizeof(*req)); 771937c30d7SJussi Kivilinna ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); 772937c30d7SJussi Kivilinna 773937c30d7SJussi Kivilinna return crypto_ablkcipher_encrypt(cryptd_req); 774937c30d7SJussi Kivilinna } else { 775937c30d7SJussi Kivilinna return __ablk_encrypt(req); 776937c30d7SJussi Kivilinna } 777937c30d7SJussi Kivilinna } 778937c30d7SJussi Kivilinna 779937c30d7SJussi Kivilinna static int ablk_decrypt(struct ablkcipher_request *req) 780937c30d7SJussi Kivilinna { 781937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 782937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 783937c30d7SJussi Kivilinna 784937c30d7SJussi Kivilinna if (!irq_fpu_usable()) { 785937c30d7SJussi Kivilinna struct ablkcipher_request *cryptd_req = 786937c30d7SJussi Kivilinna ablkcipher_request_ctx(req); 787937c30d7SJussi Kivilinna 788937c30d7SJussi Kivilinna memcpy(cryptd_req, req, sizeof(*req)); 789937c30d7SJussi Kivilinna ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); 790937c30d7SJussi Kivilinna 791937c30d7SJussi Kivilinna return crypto_ablkcipher_decrypt(cryptd_req); 792937c30d7SJussi Kivilinna } else { 793937c30d7SJussi Kivilinna struct blkcipher_desc desc; 794937c30d7SJussi Kivilinna 795937c30d7SJussi Kivilinna desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); 796937c30d7SJussi Kivilinna desc.info = req->info; 797937c30d7SJussi Kivilinna desc.flags = 0; 798937c30d7SJussi Kivilinna 799937c30d7SJussi Kivilinna return crypto_blkcipher_crt(desc.tfm)->decrypt( 800937c30d7SJussi Kivilinna &desc, req->dst, req->src, req->nbytes); 801937c30d7SJussi Kivilinna } 802937c30d7SJussi Kivilinna } 803937c30d7SJussi Kivilinna 804937c30d7SJussi Kivilinna static void ablk_exit(struct crypto_tfm *tfm) 805937c30d7SJussi Kivilinna { 806937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); 807937c30d7SJussi Kivilinna 808937c30d7SJussi Kivilinna cryptd_free_ablkcipher(ctx->cryptd_tfm); 809937c30d7SJussi Kivilinna } 810937c30d7SJussi Kivilinna 811937c30d7SJussi Kivilinna static void ablk_init_common(struct crypto_tfm *tfm, 812937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm) 813937c30d7SJussi Kivilinna { 814937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); 815937c30d7SJussi Kivilinna 816937c30d7SJussi Kivilinna ctx->cryptd_tfm = cryptd_tfm; 817937c30d7SJussi Kivilinna tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) + 818937c30d7SJussi Kivilinna crypto_ablkcipher_reqsize(&cryptd_tfm->base); 819937c30d7SJussi Kivilinna } 820937c30d7SJussi Kivilinna 821937c30d7SJussi Kivilinna static int ablk_ecb_init(struct crypto_tfm *tfm) 822937c30d7SJussi Kivilinna { 823937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 824937c30d7SJussi Kivilinna 825937c30d7SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-serpent-sse2", 0, 0); 826937c30d7SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 827937c30d7SJussi Kivilinna return PTR_ERR(cryptd_tfm); 828937c30d7SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 829937c30d7SJussi Kivilinna return 0; 830937c30d7SJussi Kivilinna } 831937c30d7SJussi Kivilinna 832937c30d7SJussi Kivilinna static struct crypto_alg ablk_ecb_alg = { 833937c30d7SJussi Kivilinna .cra_name = "ecb(serpent)", 834937c30d7SJussi Kivilinna .cra_driver_name = "ecb-serpent-sse2", 835937c30d7SJussi Kivilinna .cra_priority = 400, 836937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 837937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 838937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 839937c30d7SJussi Kivilinna .cra_alignmask = 0, 840937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 841937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 842937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list), 843937c30d7SJussi Kivilinna .cra_init = ablk_ecb_init, 844937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 845937c30d7SJussi Kivilinna .cra_u = { 846937c30d7SJussi Kivilinna .ablkcipher = { 847937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 848937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 849937c30d7SJussi Kivilinna .setkey = ablk_set_key, 850937c30d7SJussi Kivilinna .encrypt = ablk_encrypt, 851937c30d7SJussi Kivilinna .decrypt = ablk_decrypt, 852937c30d7SJussi Kivilinna }, 853937c30d7SJussi Kivilinna }, 854937c30d7SJussi Kivilinna }; 855937c30d7SJussi Kivilinna 856937c30d7SJussi Kivilinna static int ablk_cbc_init(struct crypto_tfm *tfm) 857937c30d7SJussi Kivilinna { 858937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 859937c30d7SJussi Kivilinna 860937c30d7SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-serpent-sse2", 0, 0); 861937c30d7SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 862937c30d7SJussi Kivilinna return PTR_ERR(cryptd_tfm); 863937c30d7SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 864937c30d7SJussi Kivilinna return 0; 865937c30d7SJussi Kivilinna } 866937c30d7SJussi Kivilinna 867937c30d7SJussi Kivilinna static struct crypto_alg ablk_cbc_alg = { 868937c30d7SJussi Kivilinna .cra_name = "cbc(serpent)", 869937c30d7SJussi Kivilinna .cra_driver_name = "cbc-serpent-sse2", 870937c30d7SJussi Kivilinna .cra_priority = 400, 871937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 872937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 873937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 874937c30d7SJussi Kivilinna .cra_alignmask = 0, 875937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 876937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 877937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list), 878937c30d7SJussi Kivilinna .cra_init = ablk_cbc_init, 879937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 880937c30d7SJussi Kivilinna .cra_u = { 881937c30d7SJussi Kivilinna .ablkcipher = { 882937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 883937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 884937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 885937c30d7SJussi Kivilinna .setkey = ablk_set_key, 886937c30d7SJussi Kivilinna .encrypt = __ablk_encrypt, 887937c30d7SJussi Kivilinna .decrypt = ablk_decrypt, 888937c30d7SJussi Kivilinna }, 889937c30d7SJussi Kivilinna }, 890937c30d7SJussi Kivilinna }; 891937c30d7SJussi Kivilinna 892937c30d7SJussi Kivilinna static int ablk_ctr_init(struct crypto_tfm *tfm) 893937c30d7SJussi Kivilinna { 894937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 895937c30d7SJussi Kivilinna 896937c30d7SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-serpent-sse2", 0, 0); 897937c30d7SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 898937c30d7SJussi Kivilinna return PTR_ERR(cryptd_tfm); 899937c30d7SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 900937c30d7SJussi Kivilinna return 0; 901937c30d7SJussi Kivilinna } 902937c30d7SJussi Kivilinna 903937c30d7SJussi Kivilinna static struct crypto_alg ablk_ctr_alg = { 904937c30d7SJussi Kivilinna .cra_name = "ctr(serpent)", 905937c30d7SJussi Kivilinna .cra_driver_name = "ctr-serpent-sse2", 906937c30d7SJussi Kivilinna .cra_priority = 400, 907937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 908937c30d7SJussi Kivilinna .cra_blocksize = 1, 909937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 910937c30d7SJussi Kivilinna .cra_alignmask = 0, 911937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 912937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 913937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list), 914937c30d7SJussi Kivilinna .cra_init = ablk_ctr_init, 915937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 916937c30d7SJussi Kivilinna .cra_u = { 917937c30d7SJussi Kivilinna .ablkcipher = { 918937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 919937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 920937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 921937c30d7SJussi Kivilinna .setkey = ablk_set_key, 922937c30d7SJussi Kivilinna .encrypt = ablk_encrypt, 923937c30d7SJussi Kivilinna .decrypt = ablk_encrypt, 924937c30d7SJussi Kivilinna .geniv = "chainiv", 925937c30d7SJussi Kivilinna }, 926937c30d7SJussi Kivilinna }, 927937c30d7SJussi Kivilinna }; 928937c30d7SJussi Kivilinna 92918482053SJussi Kivilinna #ifdef HAS_LRW 93018482053SJussi Kivilinna 93118482053SJussi Kivilinna static int ablk_lrw_init(struct crypto_tfm *tfm) 93218482053SJussi Kivilinna { 93318482053SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 93418482053SJussi Kivilinna 93518482053SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-lrw-serpent-sse2", 0, 0); 93618482053SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 93718482053SJussi Kivilinna return PTR_ERR(cryptd_tfm); 93818482053SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 93918482053SJussi Kivilinna return 0; 94018482053SJussi Kivilinna } 94118482053SJussi Kivilinna 94218482053SJussi Kivilinna static struct crypto_alg ablk_lrw_alg = { 94318482053SJussi Kivilinna .cra_name = "lrw(serpent)", 94418482053SJussi Kivilinna .cra_driver_name = "lrw-serpent-sse2", 94518482053SJussi Kivilinna .cra_priority = 400, 94618482053SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 94718482053SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 94818482053SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 94918482053SJussi Kivilinna .cra_alignmask = 0, 95018482053SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 95118482053SJussi Kivilinna .cra_module = THIS_MODULE, 95218482053SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_lrw_alg.cra_list), 95318482053SJussi Kivilinna .cra_init = ablk_lrw_init, 95418482053SJussi Kivilinna .cra_exit = ablk_exit, 95518482053SJussi Kivilinna .cra_u = { 95618482053SJussi Kivilinna .ablkcipher = { 95718482053SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 95818482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 95918482053SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 96018482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 96118482053SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 96218482053SJussi Kivilinna .setkey = ablk_set_key, 96318482053SJussi Kivilinna .encrypt = ablk_encrypt, 96418482053SJussi Kivilinna .decrypt = ablk_decrypt, 96518482053SJussi Kivilinna }, 96618482053SJussi Kivilinna }, 96718482053SJussi Kivilinna }; 96818482053SJussi Kivilinna 96918482053SJussi Kivilinna #endif 97018482053SJussi Kivilinna 9715962f8b6SJussi Kivilinna #ifdef HAS_XTS 9725962f8b6SJussi Kivilinna 9735962f8b6SJussi Kivilinna static int ablk_xts_init(struct crypto_tfm *tfm) 9745962f8b6SJussi Kivilinna { 9755962f8b6SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 9765962f8b6SJussi Kivilinna 9775962f8b6SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-xts-serpent-sse2", 0, 0); 9785962f8b6SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 9795962f8b6SJussi Kivilinna return PTR_ERR(cryptd_tfm); 9805962f8b6SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 9815962f8b6SJussi Kivilinna return 0; 9825962f8b6SJussi Kivilinna } 9835962f8b6SJussi Kivilinna 9845962f8b6SJussi Kivilinna static struct crypto_alg ablk_xts_alg = { 9855962f8b6SJussi Kivilinna .cra_name = "xts(serpent)", 9865962f8b6SJussi Kivilinna .cra_driver_name = "xts-serpent-sse2", 9875962f8b6SJussi Kivilinna .cra_priority = 400, 9885962f8b6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 9895962f8b6SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 9905962f8b6SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 9915962f8b6SJussi Kivilinna .cra_alignmask = 0, 9925962f8b6SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 9935962f8b6SJussi Kivilinna .cra_module = THIS_MODULE, 9945962f8b6SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_xts_alg.cra_list), 9955962f8b6SJussi Kivilinna .cra_init = ablk_xts_init, 9965962f8b6SJussi Kivilinna .cra_exit = ablk_exit, 9975962f8b6SJussi Kivilinna .cra_u = { 9985962f8b6SJussi Kivilinna .ablkcipher = { 9995962f8b6SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 10005962f8b6SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 10015962f8b6SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 10025962f8b6SJussi Kivilinna .setkey = ablk_set_key, 10035962f8b6SJussi Kivilinna .encrypt = ablk_encrypt, 10045962f8b6SJussi Kivilinna .decrypt = ablk_decrypt, 10055962f8b6SJussi Kivilinna }, 10065962f8b6SJussi Kivilinna }, 10075962f8b6SJussi Kivilinna }; 10085962f8b6SJussi Kivilinna 10095962f8b6SJussi Kivilinna #endif 10105962f8b6SJussi Kivilinna 1011937c30d7SJussi Kivilinna static int __init serpent_sse2_init(void) 1012937c30d7SJussi Kivilinna { 1013937c30d7SJussi Kivilinna int err; 1014937c30d7SJussi Kivilinna 1015937c30d7SJussi Kivilinna if (!cpu_has_xmm2) { 1016937c30d7SJussi Kivilinna printk(KERN_INFO "SSE2 instructions are not detected.\n"); 1017937c30d7SJussi Kivilinna return -ENODEV; 1018937c30d7SJussi Kivilinna } 1019937c30d7SJussi Kivilinna 1020937c30d7SJussi Kivilinna err = crypto_register_alg(&blk_ecb_alg); 1021937c30d7SJussi Kivilinna if (err) 1022937c30d7SJussi Kivilinna goto blk_ecb_err; 1023937c30d7SJussi Kivilinna err = crypto_register_alg(&blk_cbc_alg); 1024937c30d7SJussi Kivilinna if (err) 1025937c30d7SJussi Kivilinna goto blk_cbc_err; 1026937c30d7SJussi Kivilinna err = crypto_register_alg(&blk_ctr_alg); 1027937c30d7SJussi Kivilinna if (err) 1028937c30d7SJussi Kivilinna goto blk_ctr_err; 1029937c30d7SJussi Kivilinna err = crypto_register_alg(&ablk_ecb_alg); 1030937c30d7SJussi Kivilinna if (err) 1031937c30d7SJussi Kivilinna goto ablk_ecb_err; 1032937c30d7SJussi Kivilinna err = crypto_register_alg(&ablk_cbc_alg); 1033937c30d7SJussi Kivilinna if (err) 1034937c30d7SJussi Kivilinna goto ablk_cbc_err; 1035937c30d7SJussi Kivilinna err = crypto_register_alg(&ablk_ctr_alg); 1036937c30d7SJussi Kivilinna if (err) 1037937c30d7SJussi Kivilinna goto ablk_ctr_err; 103818482053SJussi Kivilinna #ifdef HAS_LRW 103918482053SJussi Kivilinna err = crypto_register_alg(&blk_lrw_alg); 104018482053SJussi Kivilinna if (err) 104118482053SJussi Kivilinna goto blk_lrw_err; 104218482053SJussi Kivilinna err = crypto_register_alg(&ablk_lrw_alg); 104318482053SJussi Kivilinna if (err) 104418482053SJussi Kivilinna goto ablk_lrw_err; 104518482053SJussi Kivilinna #endif 10465962f8b6SJussi Kivilinna #ifdef HAS_XTS 10475962f8b6SJussi Kivilinna err = crypto_register_alg(&blk_xts_alg); 10485962f8b6SJussi Kivilinna if (err) 10495962f8b6SJussi Kivilinna goto blk_xts_err; 10505962f8b6SJussi Kivilinna err = crypto_register_alg(&ablk_xts_alg); 10515962f8b6SJussi Kivilinna if (err) 10525962f8b6SJussi Kivilinna goto ablk_xts_err; 10535962f8b6SJussi Kivilinna #endif 1054937c30d7SJussi Kivilinna return err; 1055937c30d7SJussi Kivilinna 10565962f8b6SJussi Kivilinna #ifdef HAS_XTS 10575962f8b6SJussi Kivilinna crypto_unregister_alg(&ablk_xts_alg); 10585962f8b6SJussi Kivilinna ablk_xts_err: 10595962f8b6SJussi Kivilinna crypto_unregister_alg(&blk_xts_alg); 10605962f8b6SJussi Kivilinna blk_xts_err: 10615962f8b6SJussi Kivilinna #endif 106218482053SJussi Kivilinna #ifdef HAS_LRW 10635962f8b6SJussi Kivilinna crypto_unregister_alg(&ablk_lrw_alg); 106418482053SJussi Kivilinna ablk_lrw_err: 106518482053SJussi Kivilinna crypto_unregister_alg(&blk_lrw_alg); 106618482053SJussi Kivilinna blk_lrw_err: 106718482053SJussi Kivilinna #endif 10685962f8b6SJussi Kivilinna crypto_unregister_alg(&ablk_ctr_alg); 1069937c30d7SJussi Kivilinna ablk_ctr_err: 1070937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_cbc_alg); 1071937c30d7SJussi Kivilinna ablk_cbc_err: 1072937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_ecb_alg); 1073937c30d7SJussi Kivilinna ablk_ecb_err: 1074937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ctr_alg); 1075937c30d7SJussi Kivilinna blk_ctr_err: 1076937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 1077937c30d7SJussi Kivilinna blk_cbc_err: 1078937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 1079937c30d7SJussi Kivilinna blk_ecb_err: 1080937c30d7SJussi Kivilinna return err; 1081937c30d7SJussi Kivilinna } 1082937c30d7SJussi Kivilinna 1083937c30d7SJussi Kivilinna static void __exit serpent_sse2_exit(void) 1084937c30d7SJussi Kivilinna { 10855962f8b6SJussi Kivilinna #ifdef HAS_XTS 10865962f8b6SJussi Kivilinna crypto_unregister_alg(&ablk_xts_alg); 10875962f8b6SJussi Kivilinna crypto_unregister_alg(&blk_xts_alg); 10885962f8b6SJussi Kivilinna #endif 108918482053SJussi Kivilinna #ifdef HAS_LRW 109018482053SJussi Kivilinna crypto_unregister_alg(&ablk_lrw_alg); 109118482053SJussi Kivilinna crypto_unregister_alg(&blk_lrw_alg); 109218482053SJussi Kivilinna #endif 1093937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_ctr_alg); 1094937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_cbc_alg); 1095937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_ecb_alg); 1096937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ctr_alg); 1097937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 1098937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 1099937c30d7SJussi Kivilinna } 1100937c30d7SJussi Kivilinna 1101937c30d7SJussi Kivilinna module_init(serpent_sse2_init); 1102937c30d7SJussi Kivilinna module_exit(serpent_sse2_exit); 1103937c30d7SJussi Kivilinna 1104937c30d7SJussi Kivilinna MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 1105937c30d7SJussi Kivilinna MODULE_LICENSE("GPL"); 1106937c30d7SJussi Kivilinna MODULE_ALIAS("serpent"); 1107