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> 453387e7d6SJussi Kivilinna #include <asm/serpent-sse2.h> 46937c30d7SJussi Kivilinna #include <crypto/scatterwalk.h> 47937c30d7SJussi Kivilinna #include <linux/workqueue.h> 48937c30d7SJussi Kivilinna #include <linux/spinlock.h> 49937c30d7SJussi Kivilinna 50937c30d7SJussi Kivilinna struct async_serpent_ctx { 51937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 52937c30d7SJussi Kivilinna }; 53937c30d7SJussi Kivilinna 54937c30d7SJussi Kivilinna static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes) 55937c30d7SJussi Kivilinna { 56937c30d7SJussi Kivilinna if (fpu_enabled) 57937c30d7SJussi Kivilinna return true; 58937c30d7SJussi Kivilinna 59937c30d7SJussi Kivilinna /* SSE2 is only used when chunk to be processed is large enough, so 60937c30d7SJussi Kivilinna * do not enable FPU until it is necessary. 61937c30d7SJussi Kivilinna */ 62937c30d7SJussi Kivilinna if (nbytes < SERPENT_BLOCK_SIZE * SERPENT_PARALLEL_BLOCKS) 63937c30d7SJussi Kivilinna return false; 64937c30d7SJussi Kivilinna 65937c30d7SJussi Kivilinna kernel_fpu_begin(); 66937c30d7SJussi Kivilinna return true; 67937c30d7SJussi Kivilinna } 68937c30d7SJussi Kivilinna 69937c30d7SJussi Kivilinna static inline void serpent_fpu_end(bool fpu_enabled) 70937c30d7SJussi Kivilinna { 71937c30d7SJussi Kivilinna if (fpu_enabled) 72937c30d7SJussi Kivilinna kernel_fpu_end(); 73937c30d7SJussi Kivilinna } 74937c30d7SJussi Kivilinna 75937c30d7SJussi Kivilinna static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, 76937c30d7SJussi Kivilinna bool enc) 77937c30d7SJussi Kivilinna { 78937c30d7SJussi Kivilinna bool fpu_enabled = false; 79937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 80937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 81937c30d7SJussi Kivilinna unsigned int nbytes; 82937c30d7SJussi Kivilinna int err; 83937c30d7SJussi Kivilinna 84937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, walk); 85937c30d7SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 86937c30d7SJussi Kivilinna 87937c30d7SJussi Kivilinna while ((nbytes = walk->nbytes)) { 88937c30d7SJussi Kivilinna u8 *wsrc = walk->src.virt.addr; 89937c30d7SJussi Kivilinna u8 *wdst = walk->dst.virt.addr; 90937c30d7SJussi Kivilinna 91937c30d7SJussi Kivilinna fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes); 92937c30d7SJussi Kivilinna 93937c30d7SJussi Kivilinna /* Process multi-block batch */ 94937c30d7SJussi Kivilinna if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) { 95937c30d7SJussi Kivilinna do { 96937c30d7SJussi Kivilinna if (enc) 97937c30d7SJussi Kivilinna serpent_enc_blk_xway(ctx, wdst, wsrc); 98937c30d7SJussi Kivilinna else 99937c30d7SJussi Kivilinna serpent_dec_blk_xway(ctx, wdst, wsrc); 100937c30d7SJussi Kivilinna 101937c30d7SJussi Kivilinna wsrc += bsize * SERPENT_PARALLEL_BLOCKS; 102937c30d7SJussi Kivilinna wdst += bsize * SERPENT_PARALLEL_BLOCKS; 103937c30d7SJussi Kivilinna nbytes -= bsize * SERPENT_PARALLEL_BLOCKS; 104937c30d7SJussi Kivilinna } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS); 105937c30d7SJussi Kivilinna 106937c30d7SJussi Kivilinna if (nbytes < bsize) 107937c30d7SJussi Kivilinna goto done; 108937c30d7SJussi Kivilinna } 109937c30d7SJussi Kivilinna 110937c30d7SJussi Kivilinna /* Handle leftovers */ 111937c30d7SJussi Kivilinna do { 112937c30d7SJussi Kivilinna if (enc) 113937c30d7SJussi Kivilinna __serpent_encrypt(ctx, wdst, wsrc); 114937c30d7SJussi Kivilinna else 115937c30d7SJussi Kivilinna __serpent_decrypt(ctx, wdst, wsrc); 116937c30d7SJussi Kivilinna 117937c30d7SJussi Kivilinna wsrc += bsize; 118937c30d7SJussi Kivilinna wdst += bsize; 119937c30d7SJussi Kivilinna nbytes -= bsize; 120937c30d7SJussi Kivilinna } while (nbytes >= bsize); 121937c30d7SJussi Kivilinna 122937c30d7SJussi Kivilinna done: 123937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, walk, nbytes); 124937c30d7SJussi Kivilinna } 125937c30d7SJussi Kivilinna 126937c30d7SJussi Kivilinna serpent_fpu_end(fpu_enabled); 127937c30d7SJussi Kivilinna return err; 128937c30d7SJussi Kivilinna } 129937c30d7SJussi Kivilinna 130937c30d7SJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 131937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 132937c30d7SJussi Kivilinna { 133937c30d7SJussi Kivilinna struct blkcipher_walk walk; 134937c30d7SJussi Kivilinna 135937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 136937c30d7SJussi Kivilinna return ecb_crypt(desc, &walk, true); 137937c30d7SJussi Kivilinna } 138937c30d7SJussi Kivilinna 139937c30d7SJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 140937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 141937c30d7SJussi Kivilinna { 142937c30d7SJussi Kivilinna struct blkcipher_walk walk; 143937c30d7SJussi Kivilinna 144937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 145937c30d7SJussi Kivilinna return ecb_crypt(desc, &walk, false); 146937c30d7SJussi Kivilinna } 147937c30d7SJussi Kivilinna 148937c30d7SJussi Kivilinna static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, 149937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 150937c30d7SJussi Kivilinna { 151937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 152937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 153937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 154937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 155937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 156937c30d7SJussi Kivilinna u128 *iv = (u128 *)walk->iv; 157937c30d7SJussi Kivilinna 158937c30d7SJussi Kivilinna do { 159937c30d7SJussi Kivilinna u128_xor(dst, src, iv); 160937c30d7SJussi Kivilinna __serpent_encrypt(ctx, (u8 *)dst, (u8 *)dst); 161937c30d7SJussi Kivilinna iv = dst; 162937c30d7SJussi Kivilinna 163937c30d7SJussi Kivilinna src += 1; 164937c30d7SJussi Kivilinna dst += 1; 165937c30d7SJussi Kivilinna nbytes -= bsize; 166937c30d7SJussi Kivilinna } while (nbytes >= bsize); 167937c30d7SJussi Kivilinna 168937c30d7SJussi Kivilinna u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv); 169937c30d7SJussi Kivilinna return nbytes; 170937c30d7SJussi Kivilinna } 171937c30d7SJussi Kivilinna 172937c30d7SJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 173937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 174937c30d7SJussi Kivilinna { 175937c30d7SJussi Kivilinna struct blkcipher_walk walk; 176937c30d7SJussi Kivilinna int err; 177937c30d7SJussi Kivilinna 178937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 179937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 180937c30d7SJussi Kivilinna 181937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes)) { 182937c30d7SJussi Kivilinna nbytes = __cbc_encrypt(desc, &walk); 183937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 184937c30d7SJussi Kivilinna } 185937c30d7SJussi Kivilinna 186937c30d7SJussi Kivilinna return err; 187937c30d7SJussi Kivilinna } 188937c30d7SJussi Kivilinna 189937c30d7SJussi Kivilinna static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, 190937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 191937c30d7SJussi Kivilinna { 192937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 193937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 194937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 195937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 196937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 197937c30d7SJussi Kivilinna u128 ivs[SERPENT_PARALLEL_BLOCKS - 1]; 198937c30d7SJussi Kivilinna u128 last_iv; 199937c30d7SJussi Kivilinna int i; 200937c30d7SJussi Kivilinna 201937c30d7SJussi Kivilinna /* Start of the last block. */ 202937c30d7SJussi Kivilinna src += nbytes / bsize - 1; 203937c30d7SJussi Kivilinna dst += nbytes / bsize - 1; 204937c30d7SJussi Kivilinna 205937c30d7SJussi Kivilinna last_iv = *src; 206937c30d7SJussi Kivilinna 207937c30d7SJussi Kivilinna /* Process multi-block batch */ 208937c30d7SJussi Kivilinna if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) { 209937c30d7SJussi Kivilinna do { 210937c30d7SJussi Kivilinna nbytes -= bsize * (SERPENT_PARALLEL_BLOCKS - 1); 211937c30d7SJussi Kivilinna src -= SERPENT_PARALLEL_BLOCKS - 1; 212937c30d7SJussi Kivilinna dst -= SERPENT_PARALLEL_BLOCKS - 1; 213937c30d7SJussi Kivilinna 214937c30d7SJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++) 215937c30d7SJussi Kivilinna ivs[i] = src[i]; 216937c30d7SJussi Kivilinna 217937c30d7SJussi Kivilinna serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); 218937c30d7SJussi Kivilinna 219937c30d7SJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++) 220937c30d7SJussi Kivilinna u128_xor(dst + (i + 1), dst + (i + 1), ivs + i); 221937c30d7SJussi Kivilinna 222937c30d7SJussi Kivilinna nbytes -= bsize; 223937c30d7SJussi Kivilinna if (nbytes < bsize) 224937c30d7SJussi Kivilinna goto done; 225937c30d7SJussi Kivilinna 226937c30d7SJussi Kivilinna u128_xor(dst, dst, src - 1); 227937c30d7SJussi Kivilinna src -= 1; 228937c30d7SJussi Kivilinna dst -= 1; 229937c30d7SJussi Kivilinna } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS); 230937c30d7SJussi Kivilinna 231937c30d7SJussi Kivilinna if (nbytes < bsize) 232937c30d7SJussi Kivilinna goto done; 233937c30d7SJussi Kivilinna } 234937c30d7SJussi Kivilinna 235937c30d7SJussi Kivilinna /* Handle leftovers */ 236937c30d7SJussi Kivilinna for (;;) { 237937c30d7SJussi Kivilinna __serpent_decrypt(ctx, (u8 *)dst, (u8 *)src); 238937c30d7SJussi Kivilinna 239937c30d7SJussi Kivilinna nbytes -= bsize; 240937c30d7SJussi Kivilinna if (nbytes < bsize) 241937c30d7SJussi Kivilinna break; 242937c30d7SJussi Kivilinna 243937c30d7SJussi Kivilinna u128_xor(dst, dst, src - 1); 244937c30d7SJussi Kivilinna src -= 1; 245937c30d7SJussi Kivilinna dst -= 1; 246937c30d7SJussi Kivilinna } 247937c30d7SJussi Kivilinna 248937c30d7SJussi Kivilinna done: 249937c30d7SJussi Kivilinna u128_xor(dst, dst, (u128 *)walk->iv); 250937c30d7SJussi Kivilinna *(u128 *)walk->iv = last_iv; 251937c30d7SJussi Kivilinna 252937c30d7SJussi Kivilinna return nbytes; 253937c30d7SJussi Kivilinna } 254937c30d7SJussi Kivilinna 255937c30d7SJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 256937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 257937c30d7SJussi Kivilinna { 258937c30d7SJussi Kivilinna bool fpu_enabled = false; 259937c30d7SJussi Kivilinna struct blkcipher_walk walk; 260937c30d7SJussi Kivilinna int err; 261937c30d7SJussi Kivilinna 262937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 263937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 264937c30d7SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 265937c30d7SJussi Kivilinna 266937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes)) { 267937c30d7SJussi Kivilinna fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes); 268937c30d7SJussi Kivilinna nbytes = __cbc_decrypt(desc, &walk); 269937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 270937c30d7SJussi Kivilinna } 271937c30d7SJussi Kivilinna 272937c30d7SJussi Kivilinna serpent_fpu_end(fpu_enabled); 273937c30d7SJussi Kivilinna return err; 274937c30d7SJussi Kivilinna } 275937c30d7SJussi Kivilinna 276937c30d7SJussi Kivilinna static inline void u128_to_be128(be128 *dst, const u128 *src) 277937c30d7SJussi Kivilinna { 278937c30d7SJussi Kivilinna dst->a = cpu_to_be64(src->a); 279937c30d7SJussi Kivilinna dst->b = cpu_to_be64(src->b); 280937c30d7SJussi Kivilinna } 281937c30d7SJussi Kivilinna 282937c30d7SJussi Kivilinna static inline void be128_to_u128(u128 *dst, const be128 *src) 283937c30d7SJussi Kivilinna { 284937c30d7SJussi Kivilinna dst->a = be64_to_cpu(src->a); 285937c30d7SJussi Kivilinna dst->b = be64_to_cpu(src->b); 286937c30d7SJussi Kivilinna } 287937c30d7SJussi Kivilinna 288937c30d7SJussi Kivilinna static inline void u128_inc(u128 *i) 289937c30d7SJussi Kivilinna { 290937c30d7SJussi Kivilinna i->b++; 291937c30d7SJussi Kivilinna if (!i->b) 292937c30d7SJussi Kivilinna i->a++; 293937c30d7SJussi Kivilinna } 294937c30d7SJussi Kivilinna 295937c30d7SJussi Kivilinna static void ctr_crypt_final(struct blkcipher_desc *desc, 296937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 297937c30d7SJussi Kivilinna { 298937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 299937c30d7SJussi Kivilinna u8 *ctrblk = walk->iv; 300937c30d7SJussi Kivilinna u8 keystream[SERPENT_BLOCK_SIZE]; 301937c30d7SJussi Kivilinna u8 *src = walk->src.virt.addr; 302937c30d7SJussi Kivilinna u8 *dst = walk->dst.virt.addr; 303937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 304937c30d7SJussi Kivilinna 305937c30d7SJussi Kivilinna __serpent_encrypt(ctx, keystream, ctrblk); 306937c30d7SJussi Kivilinna crypto_xor(keystream, src, nbytes); 307937c30d7SJussi Kivilinna memcpy(dst, keystream, nbytes); 308937c30d7SJussi Kivilinna 309937c30d7SJussi Kivilinna crypto_inc(ctrblk, SERPENT_BLOCK_SIZE); 310937c30d7SJussi Kivilinna } 311937c30d7SJussi Kivilinna 312937c30d7SJussi Kivilinna static unsigned int __ctr_crypt(struct blkcipher_desc *desc, 313937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 314937c30d7SJussi Kivilinna { 315937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 316937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 317937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 318937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 319937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 320937c30d7SJussi Kivilinna u128 ctrblk; 321937c30d7SJussi Kivilinna be128 ctrblocks[SERPENT_PARALLEL_BLOCKS]; 322937c30d7SJussi Kivilinna int i; 323937c30d7SJussi Kivilinna 324937c30d7SJussi Kivilinna be128_to_u128(&ctrblk, (be128 *)walk->iv); 325937c30d7SJussi Kivilinna 326937c30d7SJussi Kivilinna /* Process multi-block batch */ 327937c30d7SJussi Kivilinna if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) { 328937c30d7SJussi Kivilinna do { 329937c30d7SJussi Kivilinna /* create ctrblks for parallel encrypt */ 330937c30d7SJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) { 331937c30d7SJussi Kivilinna if (dst != src) 332937c30d7SJussi Kivilinna dst[i] = src[i]; 333937c30d7SJussi Kivilinna 334937c30d7SJussi Kivilinna u128_to_be128(&ctrblocks[i], &ctrblk); 335937c30d7SJussi Kivilinna u128_inc(&ctrblk); 336937c30d7SJussi Kivilinna } 337937c30d7SJussi Kivilinna 338937c30d7SJussi Kivilinna serpent_enc_blk_xway_xor(ctx, (u8 *)dst, 339937c30d7SJussi Kivilinna (u8 *)ctrblocks); 340937c30d7SJussi Kivilinna 341937c30d7SJussi Kivilinna src += SERPENT_PARALLEL_BLOCKS; 342937c30d7SJussi Kivilinna dst += SERPENT_PARALLEL_BLOCKS; 343937c30d7SJussi Kivilinna nbytes -= bsize * SERPENT_PARALLEL_BLOCKS; 344937c30d7SJussi Kivilinna } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS); 345937c30d7SJussi Kivilinna 346937c30d7SJussi Kivilinna if (nbytes < bsize) 347937c30d7SJussi Kivilinna goto done; 348937c30d7SJussi Kivilinna } 349937c30d7SJussi Kivilinna 350937c30d7SJussi Kivilinna /* Handle leftovers */ 351937c30d7SJussi Kivilinna do { 352937c30d7SJussi Kivilinna if (dst != src) 353937c30d7SJussi Kivilinna *dst = *src; 354937c30d7SJussi Kivilinna 355937c30d7SJussi Kivilinna u128_to_be128(&ctrblocks[0], &ctrblk); 356937c30d7SJussi Kivilinna u128_inc(&ctrblk); 357937c30d7SJussi Kivilinna 358937c30d7SJussi Kivilinna __serpent_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks); 359937c30d7SJussi Kivilinna u128_xor(dst, dst, (u128 *)ctrblocks); 360937c30d7SJussi Kivilinna 361937c30d7SJussi Kivilinna src += 1; 362937c30d7SJussi Kivilinna dst += 1; 363937c30d7SJussi Kivilinna nbytes -= bsize; 364937c30d7SJussi Kivilinna } while (nbytes >= bsize); 365937c30d7SJussi Kivilinna 366937c30d7SJussi Kivilinna done: 367937c30d7SJussi Kivilinna u128_to_be128((be128 *)walk->iv, &ctrblk); 368937c30d7SJussi Kivilinna return nbytes; 369937c30d7SJussi Kivilinna } 370937c30d7SJussi Kivilinna 371937c30d7SJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, 372937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 373937c30d7SJussi Kivilinna { 374937c30d7SJussi Kivilinna bool fpu_enabled = false; 375937c30d7SJussi Kivilinna struct blkcipher_walk walk; 376937c30d7SJussi Kivilinna int err; 377937c30d7SJussi Kivilinna 378937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 379937c30d7SJussi Kivilinna err = blkcipher_walk_virt_block(desc, &walk, SERPENT_BLOCK_SIZE); 380937c30d7SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 381937c30d7SJussi Kivilinna 382937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes) >= SERPENT_BLOCK_SIZE) { 383937c30d7SJussi Kivilinna fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes); 384937c30d7SJussi Kivilinna nbytes = __ctr_crypt(desc, &walk); 385937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 386937c30d7SJussi Kivilinna } 387937c30d7SJussi Kivilinna 388937c30d7SJussi Kivilinna serpent_fpu_end(fpu_enabled); 389937c30d7SJussi Kivilinna 390937c30d7SJussi Kivilinna if (walk.nbytes) { 391937c30d7SJussi Kivilinna ctr_crypt_final(desc, &walk); 392937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, 0); 393937c30d7SJussi Kivilinna } 394937c30d7SJussi Kivilinna 395937c30d7SJussi Kivilinna return err; 396937c30d7SJussi Kivilinna } 397937c30d7SJussi Kivilinna 39818482053SJussi Kivilinna struct crypt_priv { 39918482053SJussi Kivilinna struct serpent_ctx *ctx; 40018482053SJussi Kivilinna bool fpu_enabled; 40118482053SJussi Kivilinna }; 40218482053SJussi Kivilinna 40318482053SJussi Kivilinna static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) 40418482053SJussi Kivilinna { 40518482053SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 40618482053SJussi Kivilinna struct crypt_priv *ctx = priv; 40718482053SJussi Kivilinna int i; 40818482053SJussi Kivilinna 40918482053SJussi Kivilinna ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes); 41018482053SJussi Kivilinna 41118482053SJussi Kivilinna if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) { 41218482053SJussi Kivilinna serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst); 41318482053SJussi Kivilinna return; 41418482053SJussi Kivilinna } 41518482053SJussi Kivilinna 41618482053SJussi Kivilinna for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) 41718482053SJussi Kivilinna __serpent_encrypt(ctx->ctx, srcdst, srcdst); 41818482053SJussi Kivilinna } 41918482053SJussi Kivilinna 42018482053SJussi Kivilinna static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) 42118482053SJussi Kivilinna { 42218482053SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 42318482053SJussi Kivilinna struct crypt_priv *ctx = priv; 42418482053SJussi Kivilinna int i; 42518482053SJussi Kivilinna 42618482053SJussi Kivilinna ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes); 42718482053SJussi Kivilinna 42818482053SJussi Kivilinna if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) { 42918482053SJussi Kivilinna serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst); 43018482053SJussi Kivilinna return; 43118482053SJussi Kivilinna } 43218482053SJussi Kivilinna 43318482053SJussi Kivilinna for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) 43418482053SJussi Kivilinna __serpent_decrypt(ctx->ctx, srcdst, srcdst); 43518482053SJussi Kivilinna } 43618482053SJussi Kivilinna 43718482053SJussi Kivilinna struct serpent_lrw_ctx { 43818482053SJussi Kivilinna struct lrw_table_ctx lrw_table; 43918482053SJussi Kivilinna struct serpent_ctx serpent_ctx; 44018482053SJussi Kivilinna }; 44118482053SJussi Kivilinna 44218482053SJussi Kivilinna static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key, 44318482053SJussi Kivilinna unsigned int keylen) 44418482053SJussi Kivilinna { 44518482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm); 44618482053SJussi Kivilinna int err; 44718482053SJussi Kivilinna 44818482053SJussi Kivilinna err = __serpent_setkey(&ctx->serpent_ctx, key, keylen - 44918482053SJussi Kivilinna SERPENT_BLOCK_SIZE); 45018482053SJussi Kivilinna if (err) 45118482053SJussi Kivilinna return err; 45218482053SJussi Kivilinna 45318482053SJussi Kivilinna return lrw_init_table(&ctx->lrw_table, key + keylen - 45418482053SJussi Kivilinna SERPENT_BLOCK_SIZE); 45518482053SJussi Kivilinna } 45618482053SJussi Kivilinna 45718482053SJussi Kivilinna static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 45818482053SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 45918482053SJussi Kivilinna { 46018482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 46118482053SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 46218482053SJussi Kivilinna struct crypt_priv crypt_ctx = { 46318482053SJussi Kivilinna .ctx = &ctx->serpent_ctx, 46418482053SJussi Kivilinna .fpu_enabled = false, 46518482053SJussi Kivilinna }; 46618482053SJussi Kivilinna struct lrw_crypt_req req = { 46718482053SJussi Kivilinna .tbuf = buf, 46818482053SJussi Kivilinna .tbuflen = sizeof(buf), 46918482053SJussi Kivilinna 47018482053SJussi Kivilinna .table_ctx = &ctx->lrw_table, 47118482053SJussi Kivilinna .crypt_ctx = &crypt_ctx, 47218482053SJussi Kivilinna .crypt_fn = encrypt_callback, 47318482053SJussi Kivilinna }; 47418482053SJussi Kivilinna int ret; 47518482053SJussi Kivilinna 476d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 47718482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 47818482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 47918482053SJussi Kivilinna 48018482053SJussi Kivilinna return ret; 48118482053SJussi Kivilinna } 48218482053SJussi Kivilinna 48318482053SJussi Kivilinna static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 48418482053SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 48518482053SJussi Kivilinna { 48618482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 48718482053SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 48818482053SJussi Kivilinna struct crypt_priv crypt_ctx = { 48918482053SJussi Kivilinna .ctx = &ctx->serpent_ctx, 49018482053SJussi Kivilinna .fpu_enabled = false, 49118482053SJussi Kivilinna }; 49218482053SJussi Kivilinna struct lrw_crypt_req req = { 49318482053SJussi Kivilinna .tbuf = buf, 49418482053SJussi Kivilinna .tbuflen = sizeof(buf), 49518482053SJussi Kivilinna 49618482053SJussi Kivilinna .table_ctx = &ctx->lrw_table, 49718482053SJussi Kivilinna .crypt_ctx = &crypt_ctx, 49818482053SJussi Kivilinna .crypt_fn = decrypt_callback, 49918482053SJussi Kivilinna }; 50018482053SJussi Kivilinna int ret; 50118482053SJussi Kivilinna 502d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 50318482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 50418482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 50518482053SJussi Kivilinna 50618482053SJussi Kivilinna return ret; 50718482053SJussi Kivilinna } 50818482053SJussi Kivilinna 50918482053SJussi Kivilinna static void lrw_exit_tfm(struct crypto_tfm *tfm) 51018482053SJussi Kivilinna { 51118482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm); 51218482053SJussi Kivilinna 51318482053SJussi Kivilinna lrw_free_table(&ctx->lrw_table); 51418482053SJussi Kivilinna } 51518482053SJussi Kivilinna 5165962f8b6SJussi Kivilinna struct serpent_xts_ctx { 5175962f8b6SJussi Kivilinna struct serpent_ctx tweak_ctx; 5185962f8b6SJussi Kivilinna struct serpent_ctx crypt_ctx; 5195962f8b6SJussi Kivilinna }; 5205962f8b6SJussi Kivilinna 5215962f8b6SJussi Kivilinna static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key, 5225962f8b6SJussi Kivilinna unsigned int keylen) 5235962f8b6SJussi Kivilinna { 5245962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm); 5255962f8b6SJussi Kivilinna u32 *flags = &tfm->crt_flags; 5265962f8b6SJussi Kivilinna int err; 5275962f8b6SJussi Kivilinna 5285962f8b6SJussi Kivilinna /* key consists of keys of equal size concatenated, therefore 5295962f8b6SJussi Kivilinna * the length must be even 5305962f8b6SJussi Kivilinna */ 5315962f8b6SJussi Kivilinna if (keylen % 2) { 5325962f8b6SJussi Kivilinna *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 5335962f8b6SJussi Kivilinna return -EINVAL; 5345962f8b6SJussi Kivilinna } 5355962f8b6SJussi Kivilinna 5365962f8b6SJussi Kivilinna /* first half of xts-key is for crypt */ 5375962f8b6SJussi Kivilinna err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2); 5385962f8b6SJussi Kivilinna if (err) 5395962f8b6SJussi Kivilinna return err; 5405962f8b6SJussi Kivilinna 5415962f8b6SJussi Kivilinna /* second half of xts-key is for tweak */ 5425962f8b6SJussi Kivilinna return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2); 5435962f8b6SJussi Kivilinna } 5445962f8b6SJussi Kivilinna 5455962f8b6SJussi Kivilinna static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 5465962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 5475962f8b6SJussi Kivilinna { 5485962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 5495962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 5505962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 5515962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 5525962f8b6SJussi Kivilinna .fpu_enabled = false, 5535962f8b6SJussi Kivilinna }; 5545962f8b6SJussi Kivilinna struct xts_crypt_req req = { 5555962f8b6SJussi Kivilinna .tbuf = buf, 5565962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 5575962f8b6SJussi Kivilinna 5585962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 5595962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 5605962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 5615962f8b6SJussi Kivilinna .crypt_fn = encrypt_callback, 5625962f8b6SJussi Kivilinna }; 5635962f8b6SJussi Kivilinna int ret; 5645962f8b6SJussi Kivilinna 565d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 5665962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 5675962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 5685962f8b6SJussi Kivilinna 5695962f8b6SJussi Kivilinna return ret; 5705962f8b6SJussi Kivilinna } 5715962f8b6SJussi Kivilinna 5725962f8b6SJussi Kivilinna static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 5735962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 5745962f8b6SJussi Kivilinna { 5755962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 5765962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 5775962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 5785962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 5795962f8b6SJussi Kivilinna .fpu_enabled = false, 5805962f8b6SJussi Kivilinna }; 5815962f8b6SJussi Kivilinna struct xts_crypt_req req = { 5825962f8b6SJussi Kivilinna .tbuf = buf, 5835962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 5845962f8b6SJussi Kivilinna 5855962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 5865962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 5875962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 5885962f8b6SJussi Kivilinna .crypt_fn = decrypt_callback, 5895962f8b6SJussi Kivilinna }; 5905962f8b6SJussi Kivilinna int ret; 5915962f8b6SJussi Kivilinna 592d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 5935962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 5945962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 5955962f8b6SJussi Kivilinna 5965962f8b6SJussi Kivilinna return ret; 5975962f8b6SJussi Kivilinna } 5985962f8b6SJussi Kivilinna 599937c30d7SJussi Kivilinna static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, 600937c30d7SJussi Kivilinna unsigned int key_len) 601937c30d7SJussi Kivilinna { 602937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 603937c30d7SJussi Kivilinna struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base; 604937c30d7SJussi Kivilinna int err; 605937c30d7SJussi Kivilinna 606937c30d7SJussi Kivilinna crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); 607937c30d7SJussi Kivilinna crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm) 608937c30d7SJussi Kivilinna & CRYPTO_TFM_REQ_MASK); 609937c30d7SJussi Kivilinna err = crypto_ablkcipher_setkey(child, key, key_len); 610937c30d7SJussi Kivilinna crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child) 611937c30d7SJussi Kivilinna & CRYPTO_TFM_RES_MASK); 612937c30d7SJussi Kivilinna return err; 613937c30d7SJussi Kivilinna } 614937c30d7SJussi Kivilinna 615937c30d7SJussi Kivilinna static int __ablk_encrypt(struct ablkcipher_request *req) 616937c30d7SJussi Kivilinna { 617937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 618937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 619937c30d7SJussi Kivilinna struct blkcipher_desc desc; 620937c30d7SJussi Kivilinna 621937c30d7SJussi Kivilinna desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); 622937c30d7SJussi Kivilinna desc.info = req->info; 623937c30d7SJussi Kivilinna desc.flags = 0; 624937c30d7SJussi Kivilinna 625937c30d7SJussi Kivilinna return crypto_blkcipher_crt(desc.tfm)->encrypt( 626937c30d7SJussi Kivilinna &desc, req->dst, req->src, req->nbytes); 627937c30d7SJussi Kivilinna } 628937c30d7SJussi Kivilinna 629937c30d7SJussi Kivilinna static int ablk_encrypt(struct ablkcipher_request *req) 630937c30d7SJussi Kivilinna { 631937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 632937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 633937c30d7SJussi Kivilinna 634937c30d7SJussi Kivilinna if (!irq_fpu_usable()) { 635937c30d7SJussi Kivilinna struct ablkcipher_request *cryptd_req = 636937c30d7SJussi Kivilinna ablkcipher_request_ctx(req); 637937c30d7SJussi Kivilinna 638937c30d7SJussi Kivilinna memcpy(cryptd_req, req, sizeof(*req)); 639937c30d7SJussi Kivilinna ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); 640937c30d7SJussi Kivilinna 641937c30d7SJussi Kivilinna return crypto_ablkcipher_encrypt(cryptd_req); 642937c30d7SJussi Kivilinna } else { 643937c30d7SJussi Kivilinna return __ablk_encrypt(req); 644937c30d7SJussi Kivilinna } 645937c30d7SJussi Kivilinna } 646937c30d7SJussi Kivilinna 647937c30d7SJussi Kivilinna static int ablk_decrypt(struct ablkcipher_request *req) 648937c30d7SJussi Kivilinna { 649937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 650937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 651937c30d7SJussi Kivilinna 652937c30d7SJussi Kivilinna if (!irq_fpu_usable()) { 653937c30d7SJussi Kivilinna struct ablkcipher_request *cryptd_req = 654937c30d7SJussi Kivilinna ablkcipher_request_ctx(req); 655937c30d7SJussi Kivilinna 656937c30d7SJussi Kivilinna memcpy(cryptd_req, req, sizeof(*req)); 657937c30d7SJussi Kivilinna ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); 658937c30d7SJussi Kivilinna 659937c30d7SJussi Kivilinna return crypto_ablkcipher_decrypt(cryptd_req); 660937c30d7SJussi Kivilinna } else { 661937c30d7SJussi Kivilinna struct blkcipher_desc desc; 662937c30d7SJussi Kivilinna 663937c30d7SJussi Kivilinna desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); 664937c30d7SJussi Kivilinna desc.info = req->info; 665937c30d7SJussi Kivilinna desc.flags = 0; 666937c30d7SJussi Kivilinna 667937c30d7SJussi Kivilinna return crypto_blkcipher_crt(desc.tfm)->decrypt( 668937c30d7SJussi Kivilinna &desc, req->dst, req->src, req->nbytes); 669937c30d7SJussi Kivilinna } 670937c30d7SJussi Kivilinna } 671937c30d7SJussi Kivilinna 672937c30d7SJussi Kivilinna static void ablk_exit(struct crypto_tfm *tfm) 673937c30d7SJussi Kivilinna { 674937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); 675937c30d7SJussi Kivilinna 676937c30d7SJussi Kivilinna cryptd_free_ablkcipher(ctx->cryptd_tfm); 677937c30d7SJussi Kivilinna } 678937c30d7SJussi Kivilinna 679435d3e51SJussi Kivilinna static int ablk_init(struct crypto_tfm *tfm) 680937c30d7SJussi Kivilinna { 681937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); 682435d3e51SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 683435d3e51SJussi Kivilinna char drv_name[CRYPTO_MAX_ALG_NAME]; 684435d3e51SJussi Kivilinna 685435d3e51SJussi Kivilinna snprintf(drv_name, sizeof(drv_name), "__driver-%s", 686435d3e51SJussi Kivilinna crypto_tfm_alg_driver_name(tfm)); 687435d3e51SJussi Kivilinna 688435d3e51SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher(drv_name, 0, 0); 689435d3e51SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 690435d3e51SJussi Kivilinna return PTR_ERR(cryptd_tfm); 691937c30d7SJussi Kivilinna 692937c30d7SJussi Kivilinna ctx->cryptd_tfm = cryptd_tfm; 693937c30d7SJussi Kivilinna tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) + 694937c30d7SJussi Kivilinna crypto_ablkcipher_reqsize(&cryptd_tfm->base); 695937c30d7SJussi Kivilinna 69635474c3bSJussi Kivilinna return 0; 69735474c3bSJussi Kivilinna } 69835474c3bSJussi Kivilinna 69935474c3bSJussi Kivilinna static struct crypto_alg serpent_algs[10] = { { 70035474c3bSJussi Kivilinna .cra_name = "__ecb-serpent-sse2", 70135474c3bSJussi Kivilinna .cra_driver_name = "__driver-ecb-serpent-sse2", 70235474c3bSJussi Kivilinna .cra_priority = 0, 70335474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 70435474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 70535474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 70635474c3bSJussi Kivilinna .cra_alignmask = 0, 70735474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 70835474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 70935474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[0].cra_list), 71035474c3bSJussi Kivilinna .cra_u = { 71135474c3bSJussi Kivilinna .blkcipher = { 71235474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 71335474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 71435474c3bSJussi Kivilinna .setkey = serpent_setkey, 71535474c3bSJussi Kivilinna .encrypt = ecb_encrypt, 71635474c3bSJussi Kivilinna .decrypt = ecb_decrypt, 71735474c3bSJussi Kivilinna }, 71835474c3bSJussi Kivilinna }, 71935474c3bSJussi Kivilinna }, { 72035474c3bSJussi Kivilinna .cra_name = "__cbc-serpent-sse2", 72135474c3bSJussi Kivilinna .cra_driver_name = "__driver-cbc-serpent-sse2", 72235474c3bSJussi Kivilinna .cra_priority = 0, 72335474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 72435474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 72535474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 72635474c3bSJussi Kivilinna .cra_alignmask = 0, 72735474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 72835474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 72935474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[1].cra_list), 73035474c3bSJussi Kivilinna .cra_u = { 73135474c3bSJussi Kivilinna .blkcipher = { 73235474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 73335474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 73435474c3bSJussi Kivilinna .setkey = serpent_setkey, 73535474c3bSJussi Kivilinna .encrypt = cbc_encrypt, 73635474c3bSJussi Kivilinna .decrypt = cbc_decrypt, 73735474c3bSJussi Kivilinna }, 73835474c3bSJussi Kivilinna }, 73935474c3bSJussi Kivilinna }, { 74035474c3bSJussi Kivilinna .cra_name = "__ctr-serpent-sse2", 74135474c3bSJussi Kivilinna .cra_driver_name = "__driver-ctr-serpent-sse2", 74235474c3bSJussi Kivilinna .cra_priority = 0, 74335474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 74435474c3bSJussi Kivilinna .cra_blocksize = 1, 74535474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 74635474c3bSJussi Kivilinna .cra_alignmask = 0, 74735474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 74835474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 74935474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[2].cra_list), 75035474c3bSJussi Kivilinna .cra_u = { 75135474c3bSJussi Kivilinna .blkcipher = { 75235474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 75335474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 75435474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 75535474c3bSJussi Kivilinna .setkey = serpent_setkey, 75635474c3bSJussi Kivilinna .encrypt = ctr_crypt, 75735474c3bSJussi Kivilinna .decrypt = ctr_crypt, 75835474c3bSJussi Kivilinna }, 75935474c3bSJussi Kivilinna }, 76035474c3bSJussi Kivilinna }, { 76135474c3bSJussi Kivilinna .cra_name = "__lrw-serpent-sse2", 76235474c3bSJussi Kivilinna .cra_driver_name = "__driver-lrw-serpent-sse2", 76335474c3bSJussi Kivilinna .cra_priority = 0, 76435474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 76535474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 76635474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_lrw_ctx), 76735474c3bSJussi Kivilinna .cra_alignmask = 0, 76835474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 76935474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 77035474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[3].cra_list), 77135474c3bSJussi Kivilinna .cra_exit = lrw_exit_tfm, 77235474c3bSJussi Kivilinna .cra_u = { 77335474c3bSJussi Kivilinna .blkcipher = { 77435474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 77535474c3bSJussi Kivilinna SERPENT_BLOCK_SIZE, 77635474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 77735474c3bSJussi Kivilinna SERPENT_BLOCK_SIZE, 77835474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 77935474c3bSJussi Kivilinna .setkey = lrw_serpent_setkey, 78035474c3bSJussi Kivilinna .encrypt = lrw_encrypt, 78135474c3bSJussi Kivilinna .decrypt = lrw_decrypt, 78235474c3bSJussi Kivilinna }, 78335474c3bSJussi Kivilinna }, 78435474c3bSJussi Kivilinna }, { 78535474c3bSJussi Kivilinna .cra_name = "__xts-serpent-sse2", 78635474c3bSJussi Kivilinna .cra_driver_name = "__driver-xts-serpent-sse2", 78735474c3bSJussi Kivilinna .cra_priority = 0, 78835474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 78935474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 79035474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_xts_ctx), 79135474c3bSJussi Kivilinna .cra_alignmask = 0, 79235474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 79335474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 79435474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[4].cra_list), 79535474c3bSJussi Kivilinna .cra_u = { 79635474c3bSJussi Kivilinna .blkcipher = { 79735474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 79835474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 79935474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 80035474c3bSJussi Kivilinna .setkey = xts_serpent_setkey, 80135474c3bSJussi Kivilinna .encrypt = xts_encrypt, 80235474c3bSJussi Kivilinna .decrypt = xts_decrypt, 80335474c3bSJussi Kivilinna }, 80435474c3bSJussi Kivilinna }, 80535474c3bSJussi Kivilinna }, { 80635474c3bSJussi Kivilinna .cra_name = "ecb(serpent)", 80735474c3bSJussi Kivilinna .cra_driver_name = "ecb-serpent-sse2", 80835474c3bSJussi Kivilinna .cra_priority = 400, 80935474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 81035474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 81135474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 81235474c3bSJussi Kivilinna .cra_alignmask = 0, 81335474c3bSJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 81435474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 81535474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), 816435d3e51SJussi Kivilinna .cra_init = ablk_init, 81735474c3bSJussi Kivilinna .cra_exit = ablk_exit, 81835474c3bSJussi Kivilinna .cra_u = { 81935474c3bSJussi Kivilinna .ablkcipher = { 82035474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 82135474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 82235474c3bSJussi Kivilinna .setkey = ablk_set_key, 82335474c3bSJussi Kivilinna .encrypt = ablk_encrypt, 82435474c3bSJussi Kivilinna .decrypt = ablk_decrypt, 82535474c3bSJussi Kivilinna }, 82635474c3bSJussi Kivilinna }, 82735474c3bSJussi Kivilinna }, { 82835474c3bSJussi Kivilinna .cra_name = "cbc(serpent)", 82935474c3bSJussi Kivilinna .cra_driver_name = "cbc-serpent-sse2", 83035474c3bSJussi Kivilinna .cra_priority = 400, 83135474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 83235474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 83335474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 83435474c3bSJussi Kivilinna .cra_alignmask = 0, 83535474c3bSJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 83635474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 83735474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), 838435d3e51SJussi Kivilinna .cra_init = ablk_init, 83935474c3bSJussi Kivilinna .cra_exit = ablk_exit, 84035474c3bSJussi Kivilinna .cra_u = { 84135474c3bSJussi Kivilinna .ablkcipher = { 84235474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 84335474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 84435474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 84535474c3bSJussi Kivilinna .setkey = ablk_set_key, 84635474c3bSJussi Kivilinna .encrypt = __ablk_encrypt, 84735474c3bSJussi Kivilinna .decrypt = ablk_decrypt, 84835474c3bSJussi Kivilinna }, 84935474c3bSJussi Kivilinna }, 85035474c3bSJussi Kivilinna }, { 851937c30d7SJussi Kivilinna .cra_name = "ctr(serpent)", 852937c30d7SJussi Kivilinna .cra_driver_name = "ctr-serpent-sse2", 853937c30d7SJussi Kivilinna .cra_priority = 400, 854937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 855937c30d7SJussi Kivilinna .cra_blocksize = 1, 856937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 857937c30d7SJussi Kivilinna .cra_alignmask = 0, 858937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 859937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 86035474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), 861435d3e51SJussi Kivilinna .cra_init = ablk_init, 862937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 863937c30d7SJussi Kivilinna .cra_u = { 864937c30d7SJussi Kivilinna .ablkcipher = { 865937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 866937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 867937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 868937c30d7SJussi Kivilinna .setkey = ablk_set_key, 869937c30d7SJussi Kivilinna .encrypt = ablk_encrypt, 870937c30d7SJussi Kivilinna .decrypt = ablk_encrypt, 871937c30d7SJussi Kivilinna .geniv = "chainiv", 872937c30d7SJussi Kivilinna }, 873937c30d7SJussi Kivilinna }, 87435474c3bSJussi Kivilinna }, { 87518482053SJussi Kivilinna .cra_name = "lrw(serpent)", 87618482053SJussi Kivilinna .cra_driver_name = "lrw-serpent-sse2", 87718482053SJussi Kivilinna .cra_priority = 400, 87818482053SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 87918482053SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 88018482053SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 88118482053SJussi Kivilinna .cra_alignmask = 0, 88218482053SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 88318482053SJussi Kivilinna .cra_module = THIS_MODULE, 88435474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), 885435d3e51SJussi Kivilinna .cra_init = ablk_init, 88618482053SJussi Kivilinna .cra_exit = ablk_exit, 88718482053SJussi Kivilinna .cra_u = { 88818482053SJussi Kivilinna .ablkcipher = { 88918482053SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 89018482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 89118482053SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 89218482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 89318482053SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 89418482053SJussi Kivilinna .setkey = ablk_set_key, 89518482053SJussi Kivilinna .encrypt = ablk_encrypt, 89618482053SJussi Kivilinna .decrypt = ablk_decrypt, 89718482053SJussi Kivilinna }, 89818482053SJussi Kivilinna }, 89935474c3bSJussi Kivilinna }, { 9005962f8b6SJussi Kivilinna .cra_name = "xts(serpent)", 9015962f8b6SJussi Kivilinna .cra_driver_name = "xts-serpent-sse2", 9025962f8b6SJussi Kivilinna .cra_priority = 400, 9035962f8b6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 9045962f8b6SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 9055962f8b6SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 9065962f8b6SJussi Kivilinna .cra_alignmask = 0, 9075962f8b6SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 9085962f8b6SJussi Kivilinna .cra_module = THIS_MODULE, 90935474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), 910435d3e51SJussi Kivilinna .cra_init = ablk_init, 9115962f8b6SJussi Kivilinna .cra_exit = ablk_exit, 9125962f8b6SJussi Kivilinna .cra_u = { 9135962f8b6SJussi Kivilinna .ablkcipher = { 9145962f8b6SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 9155962f8b6SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 9165962f8b6SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 9175962f8b6SJussi Kivilinna .setkey = ablk_set_key, 9185962f8b6SJussi Kivilinna .encrypt = ablk_encrypt, 9195962f8b6SJussi Kivilinna .decrypt = ablk_decrypt, 9205962f8b6SJussi Kivilinna }, 9215962f8b6SJussi Kivilinna }, 92235474c3bSJussi Kivilinna } }; 9235962f8b6SJussi Kivilinna 924937c30d7SJussi Kivilinna static int __init serpent_sse2_init(void) 925937c30d7SJussi Kivilinna { 926937c30d7SJussi Kivilinna if (!cpu_has_xmm2) { 927937c30d7SJussi Kivilinna printk(KERN_INFO "SSE2 instructions are not detected.\n"); 928937c30d7SJussi Kivilinna return -ENODEV; 929937c30d7SJussi Kivilinna } 930937c30d7SJussi Kivilinna 93135474c3bSJussi Kivilinna return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); 932937c30d7SJussi Kivilinna } 933937c30d7SJussi Kivilinna 934937c30d7SJussi Kivilinna static void __exit serpent_sse2_exit(void) 935937c30d7SJussi Kivilinna { 93635474c3bSJussi Kivilinna crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); 937937c30d7SJussi Kivilinna } 938937c30d7SJussi Kivilinna 939937c30d7SJussi Kivilinna module_init(serpent_sse2_init); 940937c30d7SJussi Kivilinna module_exit(serpent_sse2_exit); 941937c30d7SJussi Kivilinna 942937c30d7SJussi Kivilinna MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 943937c30d7SJussi Kivilinna MODULE_LICENSE("GPL"); 944937c30d7SJussi Kivilinna MODULE_ALIAS("serpent"); 945