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> 46ffaf9156SJussi Kivilinna #include <asm/crypto/ablk_helper.h> 47937c30d7SJussi Kivilinna #include <crypto/scatterwalk.h> 48937c30d7SJussi Kivilinna #include <linux/workqueue.h> 49937c30d7SJussi Kivilinna #include <linux/spinlock.h> 50937c30d7SJussi Kivilinna 51e81792fbSJussi Kivilinna typedef void (*common_glue_func_t)(void *ctx, u8 *dst, const u8 *src); 52e81792fbSJussi Kivilinna typedef void (*common_glue_cbc_func_t)(void *ctx, u128 *dst, const u128 *src); 53e81792fbSJussi Kivilinna typedef void (*common_glue_ctr_func_t)(void *ctx, u128 *dst, const u128 *src, 54e81792fbSJussi Kivilinna u128 *iv); 55e81792fbSJussi Kivilinna 56e81792fbSJussi Kivilinna #define GLUE_FUNC_CAST(fn) ((common_glue_func_t)(fn)) 57e81792fbSJussi Kivilinna #define GLUE_CBC_FUNC_CAST(fn) ((common_glue_cbc_func_t)(fn)) 58e81792fbSJussi Kivilinna #define GLUE_CTR_FUNC_CAST(fn) ((common_glue_ctr_func_t)(fn)) 59e81792fbSJussi Kivilinna 60e81792fbSJussi Kivilinna struct common_glue_func_entry { 61e81792fbSJussi Kivilinna unsigned int num_blocks; /* number of blocks that @fn will process */ 62e81792fbSJussi Kivilinna union { 63e81792fbSJussi Kivilinna common_glue_func_t ecb; 64e81792fbSJussi Kivilinna common_glue_cbc_func_t cbc; 65e81792fbSJussi Kivilinna common_glue_ctr_func_t ctr; 66e81792fbSJussi Kivilinna } fn_u; 67e81792fbSJussi Kivilinna }; 68e81792fbSJussi Kivilinna 69e81792fbSJussi Kivilinna struct common_glue_ctx { 70e81792fbSJussi Kivilinna unsigned int num_funcs; 71e81792fbSJussi Kivilinna int fpu_blocks_limit; /* -1 means fpu not needed at all */ 72e81792fbSJussi Kivilinna 73e81792fbSJussi Kivilinna /* 74e81792fbSJussi Kivilinna * First funcs entry must have largest num_blocks and last funcs entry 75e81792fbSJussi Kivilinna * must have num_blocks == 1! 76e81792fbSJussi Kivilinna */ 77e81792fbSJussi Kivilinna struct common_glue_func_entry funcs[]; 78e81792fbSJussi Kivilinna }; 79e81792fbSJussi Kivilinna 80e81792fbSJussi Kivilinna static inline bool glue_fpu_begin(unsigned int bsize, int fpu_blocks_limit, 81e81792fbSJussi Kivilinna struct blkcipher_desc *desc, 82e81792fbSJussi Kivilinna bool fpu_enabled, unsigned int nbytes) 83937c30d7SJussi Kivilinna { 84e81792fbSJussi Kivilinna if (likely(fpu_blocks_limit < 0)) 85e81792fbSJussi Kivilinna return false; 86e81792fbSJussi Kivilinna 87937c30d7SJussi Kivilinna if (fpu_enabled) 88937c30d7SJussi Kivilinna return true; 89937c30d7SJussi Kivilinna 90e81792fbSJussi Kivilinna /* 91e81792fbSJussi Kivilinna * Vector-registers are only used when chunk to be processed is large 92e81792fbSJussi Kivilinna * enough, so do not enable FPU until it is necessary. 93937c30d7SJussi Kivilinna */ 94e81792fbSJussi Kivilinna if (nbytes < bsize * (unsigned int)fpu_blocks_limit) 95937c30d7SJussi Kivilinna return false; 96937c30d7SJussi Kivilinna 97e81792fbSJussi Kivilinna if (desc) { 98e81792fbSJussi Kivilinna /* prevent sleeping if FPU is in use */ 99e81792fbSJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 100e81792fbSJussi Kivilinna } 101e81792fbSJussi Kivilinna 102937c30d7SJussi Kivilinna kernel_fpu_begin(); 103937c30d7SJussi Kivilinna return true; 104937c30d7SJussi Kivilinna } 105937c30d7SJussi Kivilinna 106e81792fbSJussi Kivilinna static inline void glue_fpu_end(bool fpu_enabled) 107937c30d7SJussi Kivilinna { 108937c30d7SJussi Kivilinna if (fpu_enabled) 109937c30d7SJussi Kivilinna kernel_fpu_end(); 110937c30d7SJussi Kivilinna } 111937c30d7SJussi Kivilinna 112e81792fbSJussi Kivilinna static int __glue_ecb_crypt_128bit(const struct common_glue_ctx *gctx, 113e81792fbSJussi Kivilinna struct blkcipher_desc *desc, 114e81792fbSJussi Kivilinna struct blkcipher_walk *walk) 115937c30d7SJussi Kivilinna { 116e81792fbSJussi Kivilinna void *ctx = crypto_blkcipher_ctx(desc->tfm); 117e81792fbSJussi Kivilinna const unsigned int bsize = 128 / 8; 118e81792fbSJussi Kivilinna unsigned int nbytes, i, func_bytes; 119937c30d7SJussi Kivilinna bool fpu_enabled = false; 120937c30d7SJussi Kivilinna int err; 121937c30d7SJussi Kivilinna 122937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, walk); 123937c30d7SJussi Kivilinna 124937c30d7SJussi Kivilinna while ((nbytes = walk->nbytes)) { 125937c30d7SJussi Kivilinna u8 *wsrc = walk->src.virt.addr; 126937c30d7SJussi Kivilinna u8 *wdst = walk->dst.virt.addr; 127937c30d7SJussi Kivilinna 128e81792fbSJussi Kivilinna fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit, 129e81792fbSJussi Kivilinna desc, fpu_enabled, nbytes); 130e81792fbSJussi Kivilinna 131e81792fbSJussi Kivilinna for (i = 0; i < gctx->num_funcs; i++) { 132e81792fbSJussi Kivilinna func_bytes = bsize * gctx->funcs[i].num_blocks; 133937c30d7SJussi Kivilinna 134937c30d7SJussi Kivilinna /* Process multi-block batch */ 135e81792fbSJussi Kivilinna if (nbytes >= func_bytes) { 136937c30d7SJussi Kivilinna do { 137e81792fbSJussi Kivilinna gctx->funcs[i].fn_u.ecb(ctx, wdst, 138e81792fbSJussi Kivilinna wsrc); 139937c30d7SJussi Kivilinna 140e81792fbSJussi Kivilinna wsrc += func_bytes; 141e81792fbSJussi Kivilinna wdst += func_bytes; 142e81792fbSJussi Kivilinna nbytes -= func_bytes; 143e81792fbSJussi Kivilinna } while (nbytes >= func_bytes); 144937c30d7SJussi Kivilinna 145937c30d7SJussi Kivilinna if (nbytes < bsize) 146937c30d7SJussi Kivilinna goto done; 147937c30d7SJussi Kivilinna } 148e81792fbSJussi Kivilinna } 149937c30d7SJussi Kivilinna 150937c30d7SJussi Kivilinna done: 151937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, walk, nbytes); 152937c30d7SJussi Kivilinna } 153937c30d7SJussi Kivilinna 154e81792fbSJussi Kivilinna glue_fpu_end(fpu_enabled); 155937c30d7SJussi Kivilinna return err; 156937c30d7SJussi Kivilinna } 157937c30d7SJussi Kivilinna 158e81792fbSJussi Kivilinna int glue_ecb_crypt_128bit(const struct common_glue_ctx *gctx, 159e81792fbSJussi Kivilinna struct blkcipher_desc *desc, struct scatterlist *dst, 160937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 161937c30d7SJussi Kivilinna { 162937c30d7SJussi Kivilinna struct blkcipher_walk walk; 163937c30d7SJussi Kivilinna 164937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 165e81792fbSJussi Kivilinna return __glue_ecb_crypt_128bit(gctx, desc, &walk); 166937c30d7SJussi Kivilinna } 167937c30d7SJussi Kivilinna 168e81792fbSJussi Kivilinna static unsigned int __glue_cbc_encrypt_128bit(const common_glue_func_t fn, 169e81792fbSJussi Kivilinna struct blkcipher_desc *desc, 170937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 171937c30d7SJussi Kivilinna { 172e81792fbSJussi Kivilinna void *ctx = crypto_blkcipher_ctx(desc->tfm); 173e81792fbSJussi Kivilinna const unsigned int bsize = 128 / 8; 174937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 175937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 176937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 177937c30d7SJussi Kivilinna u128 *iv = (u128 *)walk->iv; 178937c30d7SJussi Kivilinna 179937c30d7SJussi Kivilinna do { 180937c30d7SJussi Kivilinna u128_xor(dst, src, iv); 181e81792fbSJussi Kivilinna fn(ctx, (u8 *)dst, (u8 *)dst); 182937c30d7SJussi Kivilinna iv = dst; 183937c30d7SJussi Kivilinna 184937c30d7SJussi Kivilinna src += 1; 185937c30d7SJussi Kivilinna dst += 1; 186937c30d7SJussi Kivilinna nbytes -= bsize; 187937c30d7SJussi Kivilinna } while (nbytes >= bsize); 188937c30d7SJussi Kivilinna 189937c30d7SJussi Kivilinna u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv); 190937c30d7SJussi Kivilinna return nbytes; 191937c30d7SJussi Kivilinna } 192937c30d7SJussi Kivilinna 193e81792fbSJussi Kivilinna int glue_cbc_encrypt_128bit(const common_glue_func_t fn, 194e81792fbSJussi Kivilinna struct blkcipher_desc *desc, 195e81792fbSJussi Kivilinna struct scatterlist *dst, 196937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 197937c30d7SJussi Kivilinna { 198937c30d7SJussi Kivilinna struct blkcipher_walk walk; 199937c30d7SJussi Kivilinna int err; 200937c30d7SJussi Kivilinna 201937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 202937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 203937c30d7SJussi Kivilinna 204937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes)) { 205e81792fbSJussi Kivilinna nbytes = __glue_cbc_encrypt_128bit(fn, desc, &walk); 206937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 207937c30d7SJussi Kivilinna } 208937c30d7SJussi Kivilinna 209937c30d7SJussi Kivilinna return err; 210937c30d7SJussi Kivilinna } 211937c30d7SJussi Kivilinna 212e81792fbSJussi Kivilinna static unsigned int 213e81792fbSJussi Kivilinna __glue_cbc_decrypt_128bit(const struct common_glue_ctx *gctx, 214e81792fbSJussi Kivilinna struct blkcipher_desc *desc, 215937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 216937c30d7SJussi Kivilinna { 217e81792fbSJussi Kivilinna void *ctx = crypto_blkcipher_ctx(desc->tfm); 218e81792fbSJussi Kivilinna const unsigned int bsize = 128 / 8; 219937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 220937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 221937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 222937c30d7SJussi Kivilinna u128 last_iv; 223e81792fbSJussi Kivilinna unsigned int num_blocks, func_bytes; 224e81792fbSJussi Kivilinna unsigned int i; 225937c30d7SJussi Kivilinna 226937c30d7SJussi Kivilinna /* Start of the last block. */ 227937c30d7SJussi Kivilinna src += nbytes / bsize - 1; 228937c30d7SJussi Kivilinna dst += nbytes / bsize - 1; 229937c30d7SJussi Kivilinna 230937c30d7SJussi Kivilinna last_iv = *src; 231937c30d7SJussi Kivilinna 232e81792fbSJussi Kivilinna for (i = 0; i < gctx->num_funcs; i++) { 233e81792fbSJussi Kivilinna num_blocks = gctx->funcs[i].num_blocks; 234e81792fbSJussi Kivilinna func_bytes = bsize * num_blocks; 235e81792fbSJussi Kivilinna 236937c30d7SJussi Kivilinna /* Process multi-block batch */ 237e81792fbSJussi Kivilinna if (nbytes >= func_bytes) { 238937c30d7SJussi Kivilinna do { 239e81792fbSJussi Kivilinna nbytes -= func_bytes - bsize; 240e81792fbSJussi Kivilinna src -= num_blocks - 1; 241e81792fbSJussi Kivilinna dst -= num_blocks - 1; 242937c30d7SJussi Kivilinna 243e81792fbSJussi Kivilinna gctx->funcs[i].fn_u.cbc(ctx, dst, src); 244937c30d7SJussi Kivilinna 245937c30d7SJussi Kivilinna nbytes -= bsize; 246937c30d7SJussi Kivilinna if (nbytes < bsize) 247937c30d7SJussi Kivilinna goto done; 248937c30d7SJussi Kivilinna 249937c30d7SJussi Kivilinna u128_xor(dst, dst, src - 1); 250937c30d7SJussi Kivilinna src -= 1; 251937c30d7SJussi Kivilinna dst -= 1; 252e81792fbSJussi Kivilinna } while (nbytes >= func_bytes); 253937c30d7SJussi Kivilinna 254937c30d7SJussi Kivilinna if (nbytes < bsize) 255937c30d7SJussi Kivilinna goto done; 256937c30d7SJussi Kivilinna } 257937c30d7SJussi Kivilinna } 258937c30d7SJussi Kivilinna 259937c30d7SJussi Kivilinna done: 260937c30d7SJussi Kivilinna u128_xor(dst, dst, (u128 *)walk->iv); 261937c30d7SJussi Kivilinna *(u128 *)walk->iv = last_iv; 262937c30d7SJussi Kivilinna 263937c30d7SJussi Kivilinna return nbytes; 264937c30d7SJussi Kivilinna } 265937c30d7SJussi Kivilinna 266e81792fbSJussi Kivilinna int glue_cbc_decrypt_128bit(const struct common_glue_ctx *gctx, 267e81792fbSJussi Kivilinna struct blkcipher_desc *desc, 268e81792fbSJussi Kivilinna struct scatterlist *dst, 269937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 270937c30d7SJussi Kivilinna { 271e81792fbSJussi Kivilinna const unsigned int bsize = 128 / 8; 272937c30d7SJussi Kivilinna bool fpu_enabled = false; 273937c30d7SJussi Kivilinna struct blkcipher_walk walk; 274937c30d7SJussi Kivilinna int err; 275937c30d7SJussi Kivilinna 276937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 277937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 278937c30d7SJussi Kivilinna 279937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes)) { 280e81792fbSJussi Kivilinna fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit, 281e81792fbSJussi Kivilinna desc, fpu_enabled, nbytes); 282e81792fbSJussi Kivilinna nbytes = __glue_cbc_decrypt_128bit(gctx, desc, &walk); 283937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 284937c30d7SJussi Kivilinna } 285937c30d7SJussi Kivilinna 286e81792fbSJussi Kivilinna glue_fpu_end(fpu_enabled); 287937c30d7SJussi Kivilinna return err; 288937c30d7SJussi Kivilinna } 289937c30d7SJussi Kivilinna 290937c30d7SJussi Kivilinna static inline void u128_to_be128(be128 *dst, const u128 *src) 291937c30d7SJussi Kivilinna { 292937c30d7SJussi Kivilinna dst->a = cpu_to_be64(src->a); 293937c30d7SJussi Kivilinna dst->b = cpu_to_be64(src->b); 294937c30d7SJussi Kivilinna } 295937c30d7SJussi Kivilinna 296937c30d7SJussi Kivilinna static inline void be128_to_u128(u128 *dst, const be128 *src) 297937c30d7SJussi Kivilinna { 298937c30d7SJussi Kivilinna dst->a = be64_to_cpu(src->a); 299937c30d7SJussi Kivilinna dst->b = be64_to_cpu(src->b); 300937c30d7SJussi Kivilinna } 301937c30d7SJussi Kivilinna 302937c30d7SJussi Kivilinna static inline void u128_inc(u128 *i) 303937c30d7SJussi Kivilinna { 304937c30d7SJussi Kivilinna i->b++; 305937c30d7SJussi Kivilinna if (!i->b) 306937c30d7SJussi Kivilinna i->a++; 307937c30d7SJussi Kivilinna } 308937c30d7SJussi Kivilinna 309e81792fbSJussi Kivilinna static void glue_ctr_crypt_final_128bit(const common_glue_ctr_func_t fn_ctr, 310e81792fbSJussi Kivilinna struct blkcipher_desc *desc, 311937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 312937c30d7SJussi Kivilinna { 313e81792fbSJussi Kivilinna void *ctx = crypto_blkcipher_ctx(desc->tfm); 314e81792fbSJussi Kivilinna u8 *src = (u8 *)walk->src.virt.addr; 315e81792fbSJussi Kivilinna u8 *dst = (u8 *)walk->dst.virt.addr; 316937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 317e81792fbSJussi Kivilinna u128 ctrblk; 318e81792fbSJussi Kivilinna u128 tmp; 319937c30d7SJussi Kivilinna 320e81792fbSJussi Kivilinna be128_to_u128(&ctrblk, (be128 *)walk->iv); 321937c30d7SJussi Kivilinna 322e81792fbSJussi Kivilinna memcpy(&tmp, src, nbytes); 323e81792fbSJussi Kivilinna fn_ctr(ctx, &tmp, &tmp, &ctrblk); 324e81792fbSJussi Kivilinna memcpy(dst, &tmp, nbytes); 325e81792fbSJussi Kivilinna 326e81792fbSJussi Kivilinna u128_to_be128((be128 *)walk->iv, &ctrblk); 327937c30d7SJussi Kivilinna } 328937c30d7SJussi Kivilinna 329e81792fbSJussi Kivilinna static unsigned int __glue_ctr_crypt_128bit(const struct common_glue_ctx *gctx, 330e81792fbSJussi Kivilinna struct blkcipher_desc *desc, 331937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 332937c30d7SJussi Kivilinna { 333e81792fbSJussi Kivilinna const unsigned int bsize = 128 / 8; 334e81792fbSJussi Kivilinna void *ctx = crypto_blkcipher_ctx(desc->tfm); 335937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 336937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 337937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 338937c30d7SJussi Kivilinna u128 ctrblk; 339e81792fbSJussi Kivilinna unsigned int num_blocks, func_bytes; 340e81792fbSJussi Kivilinna unsigned int i; 341937c30d7SJussi Kivilinna 342937c30d7SJussi Kivilinna be128_to_u128(&ctrblk, (be128 *)walk->iv); 343937c30d7SJussi Kivilinna 344937c30d7SJussi Kivilinna /* Process multi-block batch */ 345e81792fbSJussi Kivilinna for (i = 0; i < gctx->num_funcs; i++) { 346e81792fbSJussi Kivilinna num_blocks = gctx->funcs[i].num_blocks; 347e81792fbSJussi Kivilinna func_bytes = bsize * num_blocks; 348e81792fbSJussi Kivilinna 349e81792fbSJussi Kivilinna if (nbytes >= func_bytes) { 350937c30d7SJussi Kivilinna do { 351e81792fbSJussi Kivilinna gctx->funcs[i].fn_u.ctr(ctx, dst, src, &ctrblk); 352937c30d7SJussi Kivilinna 353e81792fbSJussi Kivilinna src += num_blocks; 354e81792fbSJussi Kivilinna dst += num_blocks; 355e81792fbSJussi Kivilinna nbytes -= func_bytes; 356e81792fbSJussi Kivilinna } while (nbytes >= func_bytes); 357937c30d7SJussi Kivilinna 358937c30d7SJussi Kivilinna if (nbytes < bsize) 359937c30d7SJussi Kivilinna goto done; 360937c30d7SJussi Kivilinna } 361e81792fbSJussi Kivilinna } 362937c30d7SJussi Kivilinna 363937c30d7SJussi Kivilinna done: 364937c30d7SJussi Kivilinna u128_to_be128((be128 *)walk->iv, &ctrblk); 365937c30d7SJussi Kivilinna return nbytes; 366937c30d7SJussi Kivilinna } 367937c30d7SJussi Kivilinna 368e81792fbSJussi Kivilinna int glue_ctr_crypt_128bit(const struct common_glue_ctx *gctx, 369e81792fbSJussi Kivilinna struct blkcipher_desc *desc, struct scatterlist *dst, 370937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 371937c30d7SJussi Kivilinna { 372e81792fbSJussi Kivilinna const unsigned int bsize = 128 / 8; 373937c30d7SJussi Kivilinna bool fpu_enabled = false; 374937c30d7SJussi Kivilinna struct blkcipher_walk walk; 375937c30d7SJussi Kivilinna int err; 376937c30d7SJussi Kivilinna 377937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 378e81792fbSJussi Kivilinna err = blkcipher_walk_virt_block(desc, &walk, bsize); 379937c30d7SJussi Kivilinna 380e81792fbSJussi Kivilinna while ((nbytes = walk.nbytes) >= bsize) { 381e81792fbSJussi Kivilinna fpu_enabled = glue_fpu_begin(bsize, gctx->fpu_blocks_limit, 382e81792fbSJussi Kivilinna desc, fpu_enabled, nbytes); 383e81792fbSJussi Kivilinna nbytes = __glue_ctr_crypt_128bit(gctx, desc, &walk); 384937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 385937c30d7SJussi Kivilinna } 386937c30d7SJussi Kivilinna 387e81792fbSJussi Kivilinna glue_fpu_end(fpu_enabled); 388937c30d7SJussi Kivilinna 389937c30d7SJussi Kivilinna if (walk.nbytes) { 390e81792fbSJussi Kivilinna glue_ctr_crypt_final_128bit( 391e81792fbSJussi Kivilinna gctx->funcs[gctx->num_funcs - 1].fn_u.ctr, desc, &walk); 392937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, 0); 393937c30d7SJussi Kivilinna } 394937c30d7SJussi Kivilinna 395937c30d7SJussi Kivilinna return err; 396937c30d7SJussi Kivilinna } 397937c30d7SJussi Kivilinna 398e81792fbSJussi Kivilinna static void serpent_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src) 399e81792fbSJussi Kivilinna { 400e81792fbSJussi Kivilinna u128 ivs[SERPENT_PARALLEL_BLOCKS - 1]; 401e81792fbSJussi Kivilinna unsigned int j; 402e81792fbSJussi Kivilinna 403e81792fbSJussi Kivilinna for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++) 404e81792fbSJussi Kivilinna ivs[j] = src[j]; 405e81792fbSJussi Kivilinna 406e81792fbSJussi Kivilinna serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); 407e81792fbSJussi Kivilinna 408e81792fbSJussi Kivilinna for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++) 409e81792fbSJussi Kivilinna u128_xor(dst + (j + 1), dst + (j + 1), ivs + j); 410e81792fbSJussi Kivilinna } 411e81792fbSJussi Kivilinna 412e81792fbSJussi Kivilinna static void serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src, u128 *iv) 413e81792fbSJussi Kivilinna { 414e81792fbSJussi Kivilinna be128 ctrblk; 415e81792fbSJussi Kivilinna 416e81792fbSJussi Kivilinna u128_to_be128(&ctrblk, iv); 417e81792fbSJussi Kivilinna u128_inc(iv); 418e81792fbSJussi Kivilinna 419e81792fbSJussi Kivilinna __serpent_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk); 420e81792fbSJussi Kivilinna u128_xor(dst, src, (u128 *)&ctrblk); 421e81792fbSJussi Kivilinna } 422e81792fbSJussi Kivilinna 423e81792fbSJussi Kivilinna static void serpent_crypt_ctr_xway(void *ctx, u128 *dst, const u128 *src, 424e81792fbSJussi Kivilinna u128 *iv) 425e81792fbSJussi Kivilinna { 426e81792fbSJussi Kivilinna be128 ctrblks[SERPENT_PARALLEL_BLOCKS]; 427e81792fbSJussi Kivilinna unsigned int i; 428e81792fbSJussi Kivilinna 429e81792fbSJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) { 430e81792fbSJussi Kivilinna if (dst != src) 431e81792fbSJussi Kivilinna dst[i] = src[i]; 432e81792fbSJussi Kivilinna 433e81792fbSJussi Kivilinna u128_to_be128(&ctrblks[i], iv); 434e81792fbSJussi Kivilinna u128_inc(iv); 435e81792fbSJussi Kivilinna } 436e81792fbSJussi Kivilinna 437e81792fbSJussi Kivilinna serpent_enc_blk_xway_xor(ctx, (u8 *)dst, (u8 *)ctrblks); 438e81792fbSJussi Kivilinna } 439e81792fbSJussi Kivilinna 440e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_enc = { 441e81792fbSJussi Kivilinna .num_funcs = 2, 442e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 443e81792fbSJussi Kivilinna 444e81792fbSJussi Kivilinna .funcs = { { 445e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 446e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_enc_blk_xway) } 447e81792fbSJussi Kivilinna }, { 448e81792fbSJussi Kivilinna .num_blocks = 1, 449e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_encrypt) } 450e81792fbSJussi Kivilinna } } 451e81792fbSJussi Kivilinna }; 452e81792fbSJussi Kivilinna 453e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_ctr = { 454e81792fbSJussi Kivilinna .num_funcs = 2, 455e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 456e81792fbSJussi Kivilinna 457e81792fbSJussi Kivilinna .funcs = { { 458e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 459e81792fbSJussi Kivilinna .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr_xway) } 460e81792fbSJussi Kivilinna }, { 461e81792fbSJussi Kivilinna .num_blocks = 1, 462e81792fbSJussi Kivilinna .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr) } 463e81792fbSJussi Kivilinna } } 464e81792fbSJussi Kivilinna }; 465e81792fbSJussi Kivilinna 466e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_dec = { 467e81792fbSJussi Kivilinna .num_funcs = 2, 468e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 469e81792fbSJussi Kivilinna 470e81792fbSJussi Kivilinna .funcs = { { 471e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 472e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_dec_blk_xway) } 473e81792fbSJussi Kivilinna }, { 474e81792fbSJussi Kivilinna .num_blocks = 1, 475e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_decrypt) } 476e81792fbSJussi Kivilinna } } 477e81792fbSJussi Kivilinna }; 478e81792fbSJussi Kivilinna 479e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_dec_cbc = { 480e81792fbSJussi Kivilinna .num_funcs = 2, 481e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 482e81792fbSJussi Kivilinna 483e81792fbSJussi Kivilinna .funcs = { { 484e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 485e81792fbSJussi Kivilinna .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_decrypt_cbc_xway) } 486e81792fbSJussi Kivilinna }, { 487e81792fbSJussi Kivilinna .num_blocks = 1, 488e81792fbSJussi Kivilinna .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__serpent_decrypt) } 489e81792fbSJussi Kivilinna } } 490e81792fbSJussi Kivilinna }; 491e81792fbSJussi Kivilinna 492e81792fbSJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 493e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 494e81792fbSJussi Kivilinna { 495e81792fbSJussi Kivilinna return glue_ecb_crypt_128bit(&serpent_enc, desc, dst, src, nbytes); 496e81792fbSJussi Kivilinna } 497e81792fbSJussi Kivilinna 498e81792fbSJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 499e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 500e81792fbSJussi Kivilinna { 501e81792fbSJussi Kivilinna return glue_ecb_crypt_128bit(&serpent_dec, desc, dst, src, nbytes); 502e81792fbSJussi Kivilinna } 503e81792fbSJussi Kivilinna 504e81792fbSJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 505e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 506e81792fbSJussi Kivilinna { 507e81792fbSJussi Kivilinna return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__serpent_encrypt), desc, 508e81792fbSJussi Kivilinna dst, src, nbytes); 509e81792fbSJussi Kivilinna } 510e81792fbSJussi Kivilinna 511e81792fbSJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 512e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 513e81792fbSJussi Kivilinna { 514e81792fbSJussi Kivilinna return glue_cbc_decrypt_128bit(&serpent_dec_cbc, desc, dst, src, 515e81792fbSJussi Kivilinna nbytes); 516e81792fbSJussi Kivilinna } 517e81792fbSJussi Kivilinna 518e81792fbSJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, 519e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 520e81792fbSJussi Kivilinna { 521e81792fbSJussi Kivilinna return glue_ctr_crypt_128bit(&serpent_ctr, desc, dst, src, nbytes); 522e81792fbSJussi Kivilinna } 523e81792fbSJussi Kivilinna 524e81792fbSJussi Kivilinna static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes) 525e81792fbSJussi Kivilinna { 526e81792fbSJussi Kivilinna return glue_fpu_begin(SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS, 527e81792fbSJussi Kivilinna NULL, fpu_enabled, nbytes); 528e81792fbSJussi Kivilinna } 529e81792fbSJussi Kivilinna 530e81792fbSJussi Kivilinna static inline void serpent_fpu_end(bool fpu_enabled) 531e81792fbSJussi Kivilinna { 532e81792fbSJussi Kivilinna glue_fpu_end(fpu_enabled); 533e81792fbSJussi Kivilinna } 534e81792fbSJussi Kivilinna 53518482053SJussi Kivilinna struct crypt_priv { 53618482053SJussi Kivilinna struct serpent_ctx *ctx; 53718482053SJussi Kivilinna bool fpu_enabled; 53818482053SJussi Kivilinna }; 53918482053SJussi Kivilinna 54018482053SJussi Kivilinna static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) 54118482053SJussi Kivilinna { 54218482053SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 54318482053SJussi Kivilinna struct crypt_priv *ctx = priv; 54418482053SJussi Kivilinna int i; 54518482053SJussi Kivilinna 54618482053SJussi Kivilinna ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes); 54718482053SJussi Kivilinna 54818482053SJussi Kivilinna if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) { 54918482053SJussi Kivilinna serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst); 55018482053SJussi Kivilinna return; 55118482053SJussi Kivilinna } 55218482053SJussi Kivilinna 55318482053SJussi Kivilinna for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) 55418482053SJussi Kivilinna __serpent_encrypt(ctx->ctx, srcdst, srcdst); 55518482053SJussi Kivilinna } 55618482053SJussi Kivilinna 55718482053SJussi Kivilinna static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) 55818482053SJussi Kivilinna { 55918482053SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 56018482053SJussi Kivilinna struct crypt_priv *ctx = priv; 56118482053SJussi Kivilinna int i; 56218482053SJussi Kivilinna 56318482053SJussi Kivilinna ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes); 56418482053SJussi Kivilinna 56518482053SJussi Kivilinna if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) { 56618482053SJussi Kivilinna serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst); 56718482053SJussi Kivilinna return; 56818482053SJussi Kivilinna } 56918482053SJussi Kivilinna 57018482053SJussi Kivilinna for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) 57118482053SJussi Kivilinna __serpent_decrypt(ctx->ctx, srcdst, srcdst); 57218482053SJussi Kivilinna } 57318482053SJussi Kivilinna 57418482053SJussi Kivilinna struct serpent_lrw_ctx { 57518482053SJussi Kivilinna struct lrw_table_ctx lrw_table; 57618482053SJussi Kivilinna struct serpent_ctx serpent_ctx; 57718482053SJussi Kivilinna }; 57818482053SJussi Kivilinna 57918482053SJussi Kivilinna static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key, 58018482053SJussi Kivilinna unsigned int keylen) 58118482053SJussi Kivilinna { 58218482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm); 58318482053SJussi Kivilinna int err; 58418482053SJussi Kivilinna 58518482053SJussi Kivilinna err = __serpent_setkey(&ctx->serpent_ctx, key, keylen - 58618482053SJussi Kivilinna SERPENT_BLOCK_SIZE); 58718482053SJussi Kivilinna if (err) 58818482053SJussi Kivilinna return err; 58918482053SJussi Kivilinna 59018482053SJussi Kivilinna return lrw_init_table(&ctx->lrw_table, key + keylen - 59118482053SJussi Kivilinna SERPENT_BLOCK_SIZE); 59218482053SJussi Kivilinna } 59318482053SJussi Kivilinna 59418482053SJussi Kivilinna static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 59518482053SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 59618482053SJussi Kivilinna { 59718482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 59818482053SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 59918482053SJussi Kivilinna struct crypt_priv crypt_ctx = { 60018482053SJussi Kivilinna .ctx = &ctx->serpent_ctx, 60118482053SJussi Kivilinna .fpu_enabled = false, 60218482053SJussi Kivilinna }; 60318482053SJussi Kivilinna struct lrw_crypt_req req = { 60418482053SJussi Kivilinna .tbuf = buf, 60518482053SJussi Kivilinna .tbuflen = sizeof(buf), 60618482053SJussi Kivilinna 60718482053SJussi Kivilinna .table_ctx = &ctx->lrw_table, 60818482053SJussi Kivilinna .crypt_ctx = &crypt_ctx, 60918482053SJussi Kivilinna .crypt_fn = encrypt_callback, 61018482053SJussi Kivilinna }; 61118482053SJussi Kivilinna int ret; 61218482053SJussi Kivilinna 613d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 61418482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 61518482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 61618482053SJussi Kivilinna 61718482053SJussi Kivilinna return ret; 61818482053SJussi Kivilinna } 61918482053SJussi Kivilinna 62018482053SJussi Kivilinna static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 62118482053SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 62218482053SJussi Kivilinna { 62318482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 62418482053SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 62518482053SJussi Kivilinna struct crypt_priv crypt_ctx = { 62618482053SJussi Kivilinna .ctx = &ctx->serpent_ctx, 62718482053SJussi Kivilinna .fpu_enabled = false, 62818482053SJussi Kivilinna }; 62918482053SJussi Kivilinna struct lrw_crypt_req req = { 63018482053SJussi Kivilinna .tbuf = buf, 63118482053SJussi Kivilinna .tbuflen = sizeof(buf), 63218482053SJussi Kivilinna 63318482053SJussi Kivilinna .table_ctx = &ctx->lrw_table, 63418482053SJussi Kivilinna .crypt_ctx = &crypt_ctx, 63518482053SJussi Kivilinna .crypt_fn = decrypt_callback, 63618482053SJussi Kivilinna }; 63718482053SJussi Kivilinna int ret; 63818482053SJussi Kivilinna 639d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 64018482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 64118482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 64218482053SJussi Kivilinna 64318482053SJussi Kivilinna return ret; 64418482053SJussi Kivilinna } 64518482053SJussi Kivilinna 64618482053SJussi Kivilinna static void lrw_exit_tfm(struct crypto_tfm *tfm) 64718482053SJussi Kivilinna { 64818482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm); 64918482053SJussi Kivilinna 65018482053SJussi Kivilinna lrw_free_table(&ctx->lrw_table); 65118482053SJussi Kivilinna } 65218482053SJussi Kivilinna 6535962f8b6SJussi Kivilinna struct serpent_xts_ctx { 6545962f8b6SJussi Kivilinna struct serpent_ctx tweak_ctx; 6555962f8b6SJussi Kivilinna struct serpent_ctx crypt_ctx; 6565962f8b6SJussi Kivilinna }; 6575962f8b6SJussi Kivilinna 6585962f8b6SJussi Kivilinna static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key, 6595962f8b6SJussi Kivilinna unsigned int keylen) 6605962f8b6SJussi Kivilinna { 6615962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm); 6625962f8b6SJussi Kivilinna u32 *flags = &tfm->crt_flags; 6635962f8b6SJussi Kivilinna int err; 6645962f8b6SJussi Kivilinna 6655962f8b6SJussi Kivilinna /* key consists of keys of equal size concatenated, therefore 6665962f8b6SJussi Kivilinna * the length must be even 6675962f8b6SJussi Kivilinna */ 6685962f8b6SJussi Kivilinna if (keylen % 2) { 6695962f8b6SJussi Kivilinna *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 6705962f8b6SJussi Kivilinna return -EINVAL; 6715962f8b6SJussi Kivilinna } 6725962f8b6SJussi Kivilinna 6735962f8b6SJussi Kivilinna /* first half of xts-key is for crypt */ 6745962f8b6SJussi Kivilinna err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2); 6755962f8b6SJussi Kivilinna if (err) 6765962f8b6SJussi Kivilinna return err; 6775962f8b6SJussi Kivilinna 6785962f8b6SJussi Kivilinna /* second half of xts-key is for tweak */ 6795962f8b6SJussi Kivilinna return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2); 6805962f8b6SJussi Kivilinna } 6815962f8b6SJussi Kivilinna 6825962f8b6SJussi Kivilinna static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 6835962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 6845962f8b6SJussi Kivilinna { 6855962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 6865962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 6875962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 6885962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 6895962f8b6SJussi Kivilinna .fpu_enabled = false, 6905962f8b6SJussi Kivilinna }; 6915962f8b6SJussi Kivilinna struct xts_crypt_req req = { 6925962f8b6SJussi Kivilinna .tbuf = buf, 6935962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 6945962f8b6SJussi Kivilinna 6955962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 6965962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 6975962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 6985962f8b6SJussi Kivilinna .crypt_fn = encrypt_callback, 6995962f8b6SJussi Kivilinna }; 7005962f8b6SJussi Kivilinna int ret; 7015962f8b6SJussi Kivilinna 702d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 7035962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 7045962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 7055962f8b6SJussi Kivilinna 7065962f8b6SJussi Kivilinna return ret; 7075962f8b6SJussi Kivilinna } 7085962f8b6SJussi Kivilinna 7095962f8b6SJussi Kivilinna static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 7105962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 7115962f8b6SJussi Kivilinna { 7125962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 7135962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 7145962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 7155962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 7165962f8b6SJussi Kivilinna .fpu_enabled = false, 7175962f8b6SJussi Kivilinna }; 7185962f8b6SJussi Kivilinna struct xts_crypt_req req = { 7195962f8b6SJussi Kivilinna .tbuf = buf, 7205962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 7215962f8b6SJussi Kivilinna 7225962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 7235962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 7245962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 7255962f8b6SJussi Kivilinna .crypt_fn = decrypt_callback, 7265962f8b6SJussi Kivilinna }; 7275962f8b6SJussi Kivilinna int ret; 7285962f8b6SJussi Kivilinna 729d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 7305962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 7315962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 7325962f8b6SJussi Kivilinna 7335962f8b6SJussi Kivilinna return ret; 7345962f8b6SJussi Kivilinna } 7355962f8b6SJussi Kivilinna 73635474c3bSJussi Kivilinna static struct crypto_alg serpent_algs[10] = { { 73735474c3bSJussi Kivilinna .cra_name = "__ecb-serpent-sse2", 73835474c3bSJussi Kivilinna .cra_driver_name = "__driver-ecb-serpent-sse2", 73935474c3bSJussi Kivilinna .cra_priority = 0, 74035474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 74135474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 74235474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 74335474c3bSJussi Kivilinna .cra_alignmask = 0, 74435474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 74535474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 74635474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[0].cra_list), 74735474c3bSJussi Kivilinna .cra_u = { 74835474c3bSJussi Kivilinna .blkcipher = { 74935474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 75035474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 75135474c3bSJussi Kivilinna .setkey = serpent_setkey, 75235474c3bSJussi Kivilinna .encrypt = ecb_encrypt, 75335474c3bSJussi Kivilinna .decrypt = ecb_decrypt, 75435474c3bSJussi Kivilinna }, 75535474c3bSJussi Kivilinna }, 75635474c3bSJussi Kivilinna }, { 75735474c3bSJussi Kivilinna .cra_name = "__cbc-serpent-sse2", 75835474c3bSJussi Kivilinna .cra_driver_name = "__driver-cbc-serpent-sse2", 75935474c3bSJussi Kivilinna .cra_priority = 0, 76035474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 76135474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 76235474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 76335474c3bSJussi Kivilinna .cra_alignmask = 0, 76435474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 76535474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 76635474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[1].cra_list), 76735474c3bSJussi Kivilinna .cra_u = { 76835474c3bSJussi Kivilinna .blkcipher = { 76935474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 77035474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 77135474c3bSJussi Kivilinna .setkey = serpent_setkey, 77235474c3bSJussi Kivilinna .encrypt = cbc_encrypt, 77335474c3bSJussi Kivilinna .decrypt = cbc_decrypt, 77435474c3bSJussi Kivilinna }, 77535474c3bSJussi Kivilinna }, 77635474c3bSJussi Kivilinna }, { 77735474c3bSJussi Kivilinna .cra_name = "__ctr-serpent-sse2", 77835474c3bSJussi Kivilinna .cra_driver_name = "__driver-ctr-serpent-sse2", 77935474c3bSJussi Kivilinna .cra_priority = 0, 78035474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 78135474c3bSJussi Kivilinna .cra_blocksize = 1, 78235474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 78335474c3bSJussi Kivilinna .cra_alignmask = 0, 78435474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 78535474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 78635474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[2].cra_list), 78735474c3bSJussi Kivilinna .cra_u = { 78835474c3bSJussi Kivilinna .blkcipher = { 78935474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 79035474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 79135474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 79235474c3bSJussi Kivilinna .setkey = serpent_setkey, 79335474c3bSJussi Kivilinna .encrypt = ctr_crypt, 79435474c3bSJussi Kivilinna .decrypt = ctr_crypt, 79535474c3bSJussi Kivilinna }, 79635474c3bSJussi Kivilinna }, 79735474c3bSJussi Kivilinna }, { 79835474c3bSJussi Kivilinna .cra_name = "__lrw-serpent-sse2", 79935474c3bSJussi Kivilinna .cra_driver_name = "__driver-lrw-serpent-sse2", 80035474c3bSJussi Kivilinna .cra_priority = 0, 80135474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 80235474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 80335474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_lrw_ctx), 80435474c3bSJussi Kivilinna .cra_alignmask = 0, 80535474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 80635474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 80735474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[3].cra_list), 80835474c3bSJussi Kivilinna .cra_exit = lrw_exit_tfm, 80935474c3bSJussi Kivilinna .cra_u = { 81035474c3bSJussi Kivilinna .blkcipher = { 81135474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 81235474c3bSJussi Kivilinna SERPENT_BLOCK_SIZE, 81335474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 81435474c3bSJussi Kivilinna SERPENT_BLOCK_SIZE, 81535474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 81635474c3bSJussi Kivilinna .setkey = lrw_serpent_setkey, 81735474c3bSJussi Kivilinna .encrypt = lrw_encrypt, 81835474c3bSJussi Kivilinna .decrypt = lrw_decrypt, 81935474c3bSJussi Kivilinna }, 82035474c3bSJussi Kivilinna }, 82135474c3bSJussi Kivilinna }, { 82235474c3bSJussi Kivilinna .cra_name = "__xts-serpent-sse2", 82335474c3bSJussi Kivilinna .cra_driver_name = "__driver-xts-serpent-sse2", 82435474c3bSJussi Kivilinna .cra_priority = 0, 82535474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 82635474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 82735474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_xts_ctx), 82835474c3bSJussi Kivilinna .cra_alignmask = 0, 82935474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 83035474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 83135474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[4].cra_list), 83235474c3bSJussi Kivilinna .cra_u = { 83335474c3bSJussi Kivilinna .blkcipher = { 83435474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 83535474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 83635474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 83735474c3bSJussi Kivilinna .setkey = xts_serpent_setkey, 83835474c3bSJussi Kivilinna .encrypt = xts_encrypt, 83935474c3bSJussi Kivilinna .decrypt = xts_decrypt, 84035474c3bSJussi Kivilinna }, 84135474c3bSJussi Kivilinna }, 84235474c3bSJussi Kivilinna }, { 84335474c3bSJussi Kivilinna .cra_name = "ecb(serpent)", 84435474c3bSJussi Kivilinna .cra_driver_name = "ecb-serpent-sse2", 84535474c3bSJussi Kivilinna .cra_priority = 400, 84635474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 84735474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 848ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 84935474c3bSJussi Kivilinna .cra_alignmask = 0, 85035474c3bSJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 85135474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 85235474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), 853435d3e51SJussi Kivilinna .cra_init = ablk_init, 85435474c3bSJussi Kivilinna .cra_exit = ablk_exit, 85535474c3bSJussi Kivilinna .cra_u = { 85635474c3bSJussi Kivilinna .ablkcipher = { 85735474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 85835474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 85935474c3bSJussi Kivilinna .setkey = ablk_set_key, 86035474c3bSJussi Kivilinna .encrypt = ablk_encrypt, 86135474c3bSJussi Kivilinna .decrypt = ablk_decrypt, 86235474c3bSJussi Kivilinna }, 86335474c3bSJussi Kivilinna }, 86435474c3bSJussi Kivilinna }, { 86535474c3bSJussi Kivilinna .cra_name = "cbc(serpent)", 86635474c3bSJussi Kivilinna .cra_driver_name = "cbc-serpent-sse2", 86735474c3bSJussi Kivilinna .cra_priority = 400, 86835474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 86935474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 870ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 87135474c3bSJussi Kivilinna .cra_alignmask = 0, 87235474c3bSJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 87335474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 87435474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), 875435d3e51SJussi Kivilinna .cra_init = ablk_init, 87635474c3bSJussi Kivilinna .cra_exit = ablk_exit, 87735474c3bSJussi Kivilinna .cra_u = { 87835474c3bSJussi Kivilinna .ablkcipher = { 87935474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 88035474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 88135474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 88235474c3bSJussi Kivilinna .setkey = ablk_set_key, 88335474c3bSJussi Kivilinna .encrypt = __ablk_encrypt, 88435474c3bSJussi Kivilinna .decrypt = ablk_decrypt, 88535474c3bSJussi Kivilinna }, 88635474c3bSJussi Kivilinna }, 88735474c3bSJussi Kivilinna }, { 888937c30d7SJussi Kivilinna .cra_name = "ctr(serpent)", 889937c30d7SJussi Kivilinna .cra_driver_name = "ctr-serpent-sse2", 890937c30d7SJussi Kivilinna .cra_priority = 400, 891937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 892937c30d7SJussi Kivilinna .cra_blocksize = 1, 893ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 894937c30d7SJussi Kivilinna .cra_alignmask = 0, 895937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 896937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 89735474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), 898435d3e51SJussi Kivilinna .cra_init = ablk_init, 899937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 900937c30d7SJussi Kivilinna .cra_u = { 901937c30d7SJussi Kivilinna .ablkcipher = { 902937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 903937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 904937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 905937c30d7SJussi Kivilinna .setkey = ablk_set_key, 906937c30d7SJussi Kivilinna .encrypt = ablk_encrypt, 907937c30d7SJussi Kivilinna .decrypt = ablk_encrypt, 908937c30d7SJussi Kivilinna .geniv = "chainiv", 909937c30d7SJussi Kivilinna }, 910937c30d7SJussi Kivilinna }, 91135474c3bSJussi Kivilinna }, { 91218482053SJussi Kivilinna .cra_name = "lrw(serpent)", 91318482053SJussi Kivilinna .cra_driver_name = "lrw-serpent-sse2", 91418482053SJussi Kivilinna .cra_priority = 400, 91518482053SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 91618482053SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 917ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 91818482053SJussi Kivilinna .cra_alignmask = 0, 91918482053SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 92018482053SJussi Kivilinna .cra_module = THIS_MODULE, 92135474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), 922435d3e51SJussi Kivilinna .cra_init = ablk_init, 92318482053SJussi Kivilinna .cra_exit = ablk_exit, 92418482053SJussi Kivilinna .cra_u = { 92518482053SJussi Kivilinna .ablkcipher = { 92618482053SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 92718482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 92818482053SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 92918482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 93018482053SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 93118482053SJussi Kivilinna .setkey = ablk_set_key, 93218482053SJussi Kivilinna .encrypt = ablk_encrypt, 93318482053SJussi Kivilinna .decrypt = ablk_decrypt, 93418482053SJussi Kivilinna }, 93518482053SJussi Kivilinna }, 93635474c3bSJussi Kivilinna }, { 9375962f8b6SJussi Kivilinna .cra_name = "xts(serpent)", 9385962f8b6SJussi Kivilinna .cra_driver_name = "xts-serpent-sse2", 9395962f8b6SJussi Kivilinna .cra_priority = 400, 9405962f8b6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 9415962f8b6SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 942ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 9435962f8b6SJussi Kivilinna .cra_alignmask = 0, 9445962f8b6SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 9455962f8b6SJussi Kivilinna .cra_module = THIS_MODULE, 94635474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), 947435d3e51SJussi Kivilinna .cra_init = ablk_init, 9485962f8b6SJussi Kivilinna .cra_exit = ablk_exit, 9495962f8b6SJussi Kivilinna .cra_u = { 9505962f8b6SJussi Kivilinna .ablkcipher = { 9515962f8b6SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 9525962f8b6SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 9535962f8b6SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 9545962f8b6SJussi Kivilinna .setkey = ablk_set_key, 9555962f8b6SJussi Kivilinna .encrypt = ablk_encrypt, 9565962f8b6SJussi Kivilinna .decrypt = ablk_decrypt, 9575962f8b6SJussi Kivilinna }, 9585962f8b6SJussi Kivilinna }, 95935474c3bSJussi Kivilinna } }; 9605962f8b6SJussi Kivilinna 961937c30d7SJussi Kivilinna static int __init serpent_sse2_init(void) 962937c30d7SJussi Kivilinna { 963937c30d7SJussi Kivilinna if (!cpu_has_xmm2) { 964937c30d7SJussi Kivilinna printk(KERN_INFO "SSE2 instructions are not detected.\n"); 965937c30d7SJussi Kivilinna return -ENODEV; 966937c30d7SJussi Kivilinna } 967937c30d7SJussi Kivilinna 96835474c3bSJussi Kivilinna return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); 969937c30d7SJussi Kivilinna } 970937c30d7SJussi Kivilinna 971937c30d7SJussi Kivilinna static void __exit serpent_sse2_exit(void) 972937c30d7SJussi Kivilinna { 97335474c3bSJussi Kivilinna crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); 974937c30d7SJussi Kivilinna } 975937c30d7SJussi Kivilinna 976937c30d7SJussi Kivilinna module_init(serpent_sse2_init); 977937c30d7SJussi Kivilinna module_exit(serpent_sse2_exit); 978937c30d7SJussi Kivilinna 979937c30d7SJussi Kivilinna MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 980937c30d7SJussi Kivilinna MODULE_LICENSE("GPL"); 981937c30d7SJussi Kivilinna MODULE_ALIAS("serpent"); 982