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> 42937c30d7SJussi Kivilinna #include <asm/i387.h> 43937c30d7SJussi Kivilinna #include <asm/serpent.h> 44937c30d7SJussi Kivilinna #include <crypto/scatterwalk.h> 45937c30d7SJussi Kivilinna #include <linux/workqueue.h> 46937c30d7SJussi Kivilinna #include <linux/spinlock.h> 47937c30d7SJussi Kivilinna 48937c30d7SJussi Kivilinna struct async_serpent_ctx { 49937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 50937c30d7SJussi Kivilinna }; 51937c30d7SJussi Kivilinna 52937c30d7SJussi Kivilinna static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes) 53937c30d7SJussi Kivilinna { 54937c30d7SJussi Kivilinna if (fpu_enabled) 55937c30d7SJussi Kivilinna return true; 56937c30d7SJussi Kivilinna 57937c30d7SJussi Kivilinna /* SSE2 is only used when chunk to be processed is large enough, so 58937c30d7SJussi Kivilinna * do not enable FPU until it is necessary. 59937c30d7SJussi Kivilinna */ 60937c30d7SJussi Kivilinna if (nbytes < SERPENT_BLOCK_SIZE * SERPENT_PARALLEL_BLOCKS) 61937c30d7SJussi Kivilinna return false; 62937c30d7SJussi Kivilinna 63937c30d7SJussi Kivilinna kernel_fpu_begin(); 64937c30d7SJussi Kivilinna return true; 65937c30d7SJussi Kivilinna } 66937c30d7SJussi Kivilinna 67937c30d7SJussi Kivilinna static inline void serpent_fpu_end(bool fpu_enabled) 68937c30d7SJussi Kivilinna { 69937c30d7SJussi Kivilinna if (fpu_enabled) 70937c30d7SJussi Kivilinna kernel_fpu_end(); 71937c30d7SJussi Kivilinna } 72937c30d7SJussi Kivilinna 73937c30d7SJussi Kivilinna static int ecb_crypt(struct blkcipher_desc *desc, struct blkcipher_walk *walk, 74937c30d7SJussi Kivilinna bool enc) 75937c30d7SJussi Kivilinna { 76937c30d7SJussi Kivilinna bool fpu_enabled = false; 77937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 78937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 79937c30d7SJussi Kivilinna unsigned int nbytes; 80937c30d7SJussi Kivilinna int err; 81937c30d7SJussi Kivilinna 82937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, walk); 83937c30d7SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 84937c30d7SJussi Kivilinna 85937c30d7SJussi Kivilinna while ((nbytes = walk->nbytes)) { 86937c30d7SJussi Kivilinna u8 *wsrc = walk->src.virt.addr; 87937c30d7SJussi Kivilinna u8 *wdst = walk->dst.virt.addr; 88937c30d7SJussi Kivilinna 89937c30d7SJussi Kivilinna fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes); 90937c30d7SJussi Kivilinna 91937c30d7SJussi Kivilinna /* Process multi-block batch */ 92937c30d7SJussi Kivilinna if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) { 93937c30d7SJussi Kivilinna do { 94937c30d7SJussi Kivilinna if (enc) 95937c30d7SJussi Kivilinna serpent_enc_blk_xway(ctx, wdst, wsrc); 96937c30d7SJussi Kivilinna else 97937c30d7SJussi Kivilinna serpent_dec_blk_xway(ctx, wdst, wsrc); 98937c30d7SJussi Kivilinna 99937c30d7SJussi Kivilinna wsrc += bsize * SERPENT_PARALLEL_BLOCKS; 100937c30d7SJussi Kivilinna wdst += bsize * SERPENT_PARALLEL_BLOCKS; 101937c30d7SJussi Kivilinna nbytes -= bsize * SERPENT_PARALLEL_BLOCKS; 102937c30d7SJussi Kivilinna } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS); 103937c30d7SJussi Kivilinna 104937c30d7SJussi Kivilinna if (nbytes < bsize) 105937c30d7SJussi Kivilinna goto done; 106937c30d7SJussi Kivilinna } 107937c30d7SJussi Kivilinna 108937c30d7SJussi Kivilinna /* Handle leftovers */ 109937c30d7SJussi Kivilinna do { 110937c30d7SJussi Kivilinna if (enc) 111937c30d7SJussi Kivilinna __serpent_encrypt(ctx, wdst, wsrc); 112937c30d7SJussi Kivilinna else 113937c30d7SJussi Kivilinna __serpent_decrypt(ctx, wdst, wsrc); 114937c30d7SJussi Kivilinna 115937c30d7SJussi Kivilinna wsrc += bsize; 116937c30d7SJussi Kivilinna wdst += bsize; 117937c30d7SJussi Kivilinna nbytes -= bsize; 118937c30d7SJussi Kivilinna } while (nbytes >= bsize); 119937c30d7SJussi Kivilinna 120937c30d7SJussi Kivilinna done: 121937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, walk, nbytes); 122937c30d7SJussi Kivilinna } 123937c30d7SJussi Kivilinna 124937c30d7SJussi Kivilinna serpent_fpu_end(fpu_enabled); 125937c30d7SJussi Kivilinna return err; 126937c30d7SJussi Kivilinna } 127937c30d7SJussi Kivilinna 128937c30d7SJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 129937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 130937c30d7SJussi Kivilinna { 131937c30d7SJussi Kivilinna struct blkcipher_walk walk; 132937c30d7SJussi Kivilinna 133937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 134937c30d7SJussi Kivilinna return ecb_crypt(desc, &walk, true); 135937c30d7SJussi Kivilinna } 136937c30d7SJussi Kivilinna 137937c30d7SJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 138937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 139937c30d7SJussi Kivilinna { 140937c30d7SJussi Kivilinna struct blkcipher_walk walk; 141937c30d7SJussi Kivilinna 142937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 143937c30d7SJussi Kivilinna return ecb_crypt(desc, &walk, false); 144937c30d7SJussi Kivilinna } 145937c30d7SJussi Kivilinna 146937c30d7SJussi Kivilinna static struct crypto_alg blk_ecb_alg = { 147937c30d7SJussi Kivilinna .cra_name = "__ecb-serpent-sse2", 148937c30d7SJussi Kivilinna .cra_driver_name = "__driver-ecb-serpent-sse2", 149937c30d7SJussi Kivilinna .cra_priority = 0, 150937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 151937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 152937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 153937c30d7SJussi Kivilinna .cra_alignmask = 0, 154937c30d7SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 155937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 156937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_ecb_alg.cra_list), 157937c30d7SJussi Kivilinna .cra_u = { 158937c30d7SJussi Kivilinna .blkcipher = { 159937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 160937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 161937c30d7SJussi Kivilinna .setkey = serpent_setkey, 162937c30d7SJussi Kivilinna .encrypt = ecb_encrypt, 163937c30d7SJussi Kivilinna .decrypt = ecb_decrypt, 164937c30d7SJussi Kivilinna }, 165937c30d7SJussi Kivilinna }, 166937c30d7SJussi Kivilinna }; 167937c30d7SJussi Kivilinna 168937c30d7SJussi Kivilinna static unsigned int __cbc_encrypt(struct blkcipher_desc *desc, 169937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 170937c30d7SJussi Kivilinna { 171937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 172937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 173937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 174937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 175937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 176937c30d7SJussi Kivilinna u128 *iv = (u128 *)walk->iv; 177937c30d7SJussi Kivilinna 178937c30d7SJussi Kivilinna do { 179937c30d7SJussi Kivilinna u128_xor(dst, src, iv); 180937c30d7SJussi Kivilinna __serpent_encrypt(ctx, (u8 *)dst, (u8 *)dst); 181937c30d7SJussi Kivilinna iv = dst; 182937c30d7SJussi Kivilinna 183937c30d7SJussi Kivilinna src += 1; 184937c30d7SJussi Kivilinna dst += 1; 185937c30d7SJussi Kivilinna nbytes -= bsize; 186937c30d7SJussi Kivilinna } while (nbytes >= bsize); 187937c30d7SJussi Kivilinna 188937c30d7SJussi Kivilinna u128_xor((u128 *)walk->iv, (u128 *)walk->iv, iv); 189937c30d7SJussi Kivilinna return nbytes; 190937c30d7SJussi Kivilinna } 191937c30d7SJussi Kivilinna 192937c30d7SJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 193937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 194937c30d7SJussi Kivilinna { 195937c30d7SJussi Kivilinna struct blkcipher_walk walk; 196937c30d7SJussi Kivilinna int err; 197937c30d7SJussi Kivilinna 198937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 199937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 200937c30d7SJussi Kivilinna 201937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes)) { 202937c30d7SJussi Kivilinna nbytes = __cbc_encrypt(desc, &walk); 203937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 204937c30d7SJussi Kivilinna } 205937c30d7SJussi Kivilinna 206937c30d7SJussi Kivilinna return err; 207937c30d7SJussi Kivilinna } 208937c30d7SJussi Kivilinna 209937c30d7SJussi Kivilinna static unsigned int __cbc_decrypt(struct blkcipher_desc *desc, 210937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 211937c30d7SJussi Kivilinna { 212937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 213937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 214937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 215937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 216937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 217937c30d7SJussi Kivilinna u128 ivs[SERPENT_PARALLEL_BLOCKS - 1]; 218937c30d7SJussi Kivilinna u128 last_iv; 219937c30d7SJussi Kivilinna int i; 220937c30d7SJussi Kivilinna 221937c30d7SJussi Kivilinna /* Start of the last block. */ 222937c30d7SJussi Kivilinna src += nbytes / bsize - 1; 223937c30d7SJussi Kivilinna dst += nbytes / bsize - 1; 224937c30d7SJussi Kivilinna 225937c30d7SJussi Kivilinna last_iv = *src; 226937c30d7SJussi Kivilinna 227937c30d7SJussi Kivilinna /* Process multi-block batch */ 228937c30d7SJussi Kivilinna if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) { 229937c30d7SJussi Kivilinna do { 230937c30d7SJussi Kivilinna nbytes -= bsize * (SERPENT_PARALLEL_BLOCKS - 1); 231937c30d7SJussi Kivilinna src -= SERPENT_PARALLEL_BLOCKS - 1; 232937c30d7SJussi Kivilinna dst -= SERPENT_PARALLEL_BLOCKS - 1; 233937c30d7SJussi Kivilinna 234937c30d7SJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++) 235937c30d7SJussi Kivilinna ivs[i] = src[i]; 236937c30d7SJussi Kivilinna 237937c30d7SJussi Kivilinna serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); 238937c30d7SJussi Kivilinna 239937c30d7SJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS - 1; i++) 240937c30d7SJussi Kivilinna u128_xor(dst + (i + 1), dst + (i + 1), ivs + i); 241937c30d7SJussi Kivilinna 242937c30d7SJussi Kivilinna nbytes -= bsize; 243937c30d7SJussi Kivilinna if (nbytes < bsize) 244937c30d7SJussi Kivilinna goto done; 245937c30d7SJussi Kivilinna 246937c30d7SJussi Kivilinna u128_xor(dst, dst, src - 1); 247937c30d7SJussi Kivilinna src -= 1; 248937c30d7SJussi Kivilinna dst -= 1; 249937c30d7SJussi Kivilinna } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS); 250937c30d7SJussi Kivilinna 251937c30d7SJussi Kivilinna if (nbytes < bsize) 252937c30d7SJussi Kivilinna goto done; 253937c30d7SJussi Kivilinna } 254937c30d7SJussi Kivilinna 255937c30d7SJussi Kivilinna /* Handle leftovers */ 256937c30d7SJussi Kivilinna for (;;) { 257937c30d7SJussi Kivilinna __serpent_decrypt(ctx, (u8 *)dst, (u8 *)src); 258937c30d7SJussi Kivilinna 259937c30d7SJussi Kivilinna nbytes -= bsize; 260937c30d7SJussi Kivilinna if (nbytes < bsize) 261937c30d7SJussi Kivilinna break; 262937c30d7SJussi Kivilinna 263937c30d7SJussi Kivilinna u128_xor(dst, dst, src - 1); 264937c30d7SJussi Kivilinna src -= 1; 265937c30d7SJussi Kivilinna dst -= 1; 266937c30d7SJussi Kivilinna } 267937c30d7SJussi Kivilinna 268937c30d7SJussi Kivilinna done: 269937c30d7SJussi Kivilinna u128_xor(dst, dst, (u128 *)walk->iv); 270937c30d7SJussi Kivilinna *(u128 *)walk->iv = last_iv; 271937c30d7SJussi Kivilinna 272937c30d7SJussi Kivilinna return nbytes; 273937c30d7SJussi Kivilinna } 274937c30d7SJussi Kivilinna 275937c30d7SJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 276937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 277937c30d7SJussi Kivilinna { 278937c30d7SJussi Kivilinna bool fpu_enabled = false; 279937c30d7SJussi Kivilinna struct blkcipher_walk walk; 280937c30d7SJussi Kivilinna int err; 281937c30d7SJussi Kivilinna 282937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 283937c30d7SJussi Kivilinna err = blkcipher_walk_virt(desc, &walk); 284937c30d7SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 285937c30d7SJussi Kivilinna 286937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes)) { 287937c30d7SJussi Kivilinna fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes); 288937c30d7SJussi Kivilinna nbytes = __cbc_decrypt(desc, &walk); 289937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 290937c30d7SJussi Kivilinna } 291937c30d7SJussi Kivilinna 292937c30d7SJussi Kivilinna serpent_fpu_end(fpu_enabled); 293937c30d7SJussi Kivilinna return err; 294937c30d7SJussi Kivilinna } 295937c30d7SJussi Kivilinna 296937c30d7SJussi Kivilinna static struct crypto_alg blk_cbc_alg = { 297937c30d7SJussi Kivilinna .cra_name = "__cbc-serpent-sse2", 298937c30d7SJussi Kivilinna .cra_driver_name = "__driver-cbc-serpent-sse2", 299937c30d7SJussi Kivilinna .cra_priority = 0, 300937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 301937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 302937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 303937c30d7SJussi Kivilinna .cra_alignmask = 0, 304937c30d7SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 305937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 306937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_cbc_alg.cra_list), 307937c30d7SJussi Kivilinna .cra_u = { 308937c30d7SJussi Kivilinna .blkcipher = { 309937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 310937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 311937c30d7SJussi Kivilinna .setkey = serpent_setkey, 312937c30d7SJussi Kivilinna .encrypt = cbc_encrypt, 313937c30d7SJussi Kivilinna .decrypt = cbc_decrypt, 314937c30d7SJussi Kivilinna }, 315937c30d7SJussi Kivilinna }, 316937c30d7SJussi Kivilinna }; 317937c30d7SJussi Kivilinna 318937c30d7SJussi Kivilinna static inline void u128_to_be128(be128 *dst, const u128 *src) 319937c30d7SJussi Kivilinna { 320937c30d7SJussi Kivilinna dst->a = cpu_to_be64(src->a); 321937c30d7SJussi Kivilinna dst->b = cpu_to_be64(src->b); 322937c30d7SJussi Kivilinna } 323937c30d7SJussi Kivilinna 324937c30d7SJussi Kivilinna static inline void be128_to_u128(u128 *dst, const be128 *src) 325937c30d7SJussi Kivilinna { 326937c30d7SJussi Kivilinna dst->a = be64_to_cpu(src->a); 327937c30d7SJussi Kivilinna dst->b = be64_to_cpu(src->b); 328937c30d7SJussi Kivilinna } 329937c30d7SJussi Kivilinna 330937c30d7SJussi Kivilinna static inline void u128_inc(u128 *i) 331937c30d7SJussi Kivilinna { 332937c30d7SJussi Kivilinna i->b++; 333937c30d7SJussi Kivilinna if (!i->b) 334937c30d7SJussi Kivilinna i->a++; 335937c30d7SJussi Kivilinna } 336937c30d7SJussi Kivilinna 337937c30d7SJussi Kivilinna static void ctr_crypt_final(struct blkcipher_desc *desc, 338937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 339937c30d7SJussi Kivilinna { 340937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 341937c30d7SJussi Kivilinna u8 *ctrblk = walk->iv; 342937c30d7SJussi Kivilinna u8 keystream[SERPENT_BLOCK_SIZE]; 343937c30d7SJussi Kivilinna u8 *src = walk->src.virt.addr; 344937c30d7SJussi Kivilinna u8 *dst = walk->dst.virt.addr; 345937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 346937c30d7SJussi Kivilinna 347937c30d7SJussi Kivilinna __serpent_encrypt(ctx, keystream, ctrblk); 348937c30d7SJussi Kivilinna crypto_xor(keystream, src, nbytes); 349937c30d7SJussi Kivilinna memcpy(dst, keystream, nbytes); 350937c30d7SJussi Kivilinna 351937c30d7SJussi Kivilinna crypto_inc(ctrblk, SERPENT_BLOCK_SIZE); 352937c30d7SJussi Kivilinna } 353937c30d7SJussi Kivilinna 354937c30d7SJussi Kivilinna static unsigned int __ctr_crypt(struct blkcipher_desc *desc, 355937c30d7SJussi Kivilinna struct blkcipher_walk *walk) 356937c30d7SJussi Kivilinna { 357937c30d7SJussi Kivilinna struct serpent_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 358937c30d7SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 359937c30d7SJussi Kivilinna unsigned int nbytes = walk->nbytes; 360937c30d7SJussi Kivilinna u128 *src = (u128 *)walk->src.virt.addr; 361937c30d7SJussi Kivilinna u128 *dst = (u128 *)walk->dst.virt.addr; 362937c30d7SJussi Kivilinna u128 ctrblk; 363937c30d7SJussi Kivilinna be128 ctrblocks[SERPENT_PARALLEL_BLOCKS]; 364937c30d7SJussi Kivilinna int i; 365937c30d7SJussi Kivilinna 366937c30d7SJussi Kivilinna be128_to_u128(&ctrblk, (be128 *)walk->iv); 367937c30d7SJussi Kivilinna 368937c30d7SJussi Kivilinna /* Process multi-block batch */ 369937c30d7SJussi Kivilinna if (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS) { 370937c30d7SJussi Kivilinna do { 371937c30d7SJussi Kivilinna /* create ctrblks for parallel encrypt */ 372937c30d7SJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) { 373937c30d7SJussi Kivilinna if (dst != src) 374937c30d7SJussi Kivilinna dst[i] = src[i]; 375937c30d7SJussi Kivilinna 376937c30d7SJussi Kivilinna u128_to_be128(&ctrblocks[i], &ctrblk); 377937c30d7SJussi Kivilinna u128_inc(&ctrblk); 378937c30d7SJussi Kivilinna } 379937c30d7SJussi Kivilinna 380937c30d7SJussi Kivilinna serpent_enc_blk_xway_xor(ctx, (u8 *)dst, 381937c30d7SJussi Kivilinna (u8 *)ctrblocks); 382937c30d7SJussi Kivilinna 383937c30d7SJussi Kivilinna src += SERPENT_PARALLEL_BLOCKS; 384937c30d7SJussi Kivilinna dst += SERPENT_PARALLEL_BLOCKS; 385937c30d7SJussi Kivilinna nbytes -= bsize * SERPENT_PARALLEL_BLOCKS; 386937c30d7SJussi Kivilinna } while (nbytes >= bsize * SERPENT_PARALLEL_BLOCKS); 387937c30d7SJussi Kivilinna 388937c30d7SJussi Kivilinna if (nbytes < bsize) 389937c30d7SJussi Kivilinna goto done; 390937c30d7SJussi Kivilinna } 391937c30d7SJussi Kivilinna 392937c30d7SJussi Kivilinna /* Handle leftovers */ 393937c30d7SJussi Kivilinna do { 394937c30d7SJussi Kivilinna if (dst != src) 395937c30d7SJussi Kivilinna *dst = *src; 396937c30d7SJussi Kivilinna 397937c30d7SJussi Kivilinna u128_to_be128(&ctrblocks[0], &ctrblk); 398937c30d7SJussi Kivilinna u128_inc(&ctrblk); 399937c30d7SJussi Kivilinna 400937c30d7SJussi Kivilinna __serpent_encrypt(ctx, (u8 *)ctrblocks, (u8 *)ctrblocks); 401937c30d7SJussi Kivilinna u128_xor(dst, dst, (u128 *)ctrblocks); 402937c30d7SJussi Kivilinna 403937c30d7SJussi Kivilinna src += 1; 404937c30d7SJussi Kivilinna dst += 1; 405937c30d7SJussi Kivilinna nbytes -= bsize; 406937c30d7SJussi Kivilinna } while (nbytes >= bsize); 407937c30d7SJussi Kivilinna 408937c30d7SJussi Kivilinna done: 409937c30d7SJussi Kivilinna u128_to_be128((be128 *)walk->iv, &ctrblk); 410937c30d7SJussi Kivilinna return nbytes; 411937c30d7SJussi Kivilinna } 412937c30d7SJussi Kivilinna 413937c30d7SJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, 414937c30d7SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 415937c30d7SJussi Kivilinna { 416937c30d7SJussi Kivilinna bool fpu_enabled = false; 417937c30d7SJussi Kivilinna struct blkcipher_walk walk; 418937c30d7SJussi Kivilinna int err; 419937c30d7SJussi Kivilinna 420937c30d7SJussi Kivilinna blkcipher_walk_init(&walk, dst, src, nbytes); 421937c30d7SJussi Kivilinna err = blkcipher_walk_virt_block(desc, &walk, SERPENT_BLOCK_SIZE); 422937c30d7SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 423937c30d7SJussi Kivilinna 424937c30d7SJussi Kivilinna while ((nbytes = walk.nbytes) >= SERPENT_BLOCK_SIZE) { 425937c30d7SJussi Kivilinna fpu_enabled = serpent_fpu_begin(fpu_enabled, nbytes); 426937c30d7SJussi Kivilinna nbytes = __ctr_crypt(desc, &walk); 427937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, nbytes); 428937c30d7SJussi Kivilinna } 429937c30d7SJussi Kivilinna 430937c30d7SJussi Kivilinna serpent_fpu_end(fpu_enabled); 431937c30d7SJussi Kivilinna 432937c30d7SJussi Kivilinna if (walk.nbytes) { 433937c30d7SJussi Kivilinna ctr_crypt_final(desc, &walk); 434937c30d7SJussi Kivilinna err = blkcipher_walk_done(desc, &walk, 0); 435937c30d7SJussi Kivilinna } 436937c30d7SJussi Kivilinna 437937c30d7SJussi Kivilinna return err; 438937c30d7SJussi Kivilinna } 439937c30d7SJussi Kivilinna 440937c30d7SJussi Kivilinna static struct crypto_alg blk_ctr_alg = { 441937c30d7SJussi Kivilinna .cra_name = "__ctr-serpent-sse2", 442937c30d7SJussi Kivilinna .cra_driver_name = "__driver-ctr-serpent-sse2", 443937c30d7SJussi Kivilinna .cra_priority = 0, 444937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 445937c30d7SJussi Kivilinna .cra_blocksize = 1, 446937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 447937c30d7SJussi Kivilinna .cra_alignmask = 0, 448937c30d7SJussi Kivilinna .cra_type = &crypto_blkcipher_type, 449937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 450937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(blk_ctr_alg.cra_list), 451937c30d7SJussi Kivilinna .cra_u = { 452937c30d7SJussi Kivilinna .blkcipher = { 453937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 454937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 455937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 456937c30d7SJussi Kivilinna .setkey = serpent_setkey, 457937c30d7SJussi Kivilinna .encrypt = ctr_crypt, 458937c30d7SJussi Kivilinna .decrypt = ctr_crypt, 459937c30d7SJussi Kivilinna }, 460937c30d7SJussi Kivilinna }, 461937c30d7SJussi Kivilinna }; 462937c30d7SJussi Kivilinna 463937c30d7SJussi Kivilinna static int ablk_set_key(struct crypto_ablkcipher *tfm, const u8 *key, 464937c30d7SJussi Kivilinna unsigned int key_len) 465937c30d7SJussi Kivilinna { 466937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 467937c30d7SJussi Kivilinna struct crypto_ablkcipher *child = &ctx->cryptd_tfm->base; 468937c30d7SJussi Kivilinna int err; 469937c30d7SJussi Kivilinna 470937c30d7SJussi Kivilinna crypto_ablkcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); 471937c30d7SJussi Kivilinna crypto_ablkcipher_set_flags(child, crypto_ablkcipher_get_flags(tfm) 472937c30d7SJussi Kivilinna & CRYPTO_TFM_REQ_MASK); 473937c30d7SJussi Kivilinna err = crypto_ablkcipher_setkey(child, key, key_len); 474937c30d7SJussi Kivilinna crypto_ablkcipher_set_flags(tfm, crypto_ablkcipher_get_flags(child) 475937c30d7SJussi Kivilinna & CRYPTO_TFM_RES_MASK); 476937c30d7SJussi Kivilinna return err; 477937c30d7SJussi Kivilinna } 478937c30d7SJussi Kivilinna 479937c30d7SJussi Kivilinna static int __ablk_encrypt(struct ablkcipher_request *req) 480937c30d7SJussi Kivilinna { 481937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 482937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 483937c30d7SJussi Kivilinna struct blkcipher_desc desc; 484937c30d7SJussi Kivilinna 485937c30d7SJussi Kivilinna desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); 486937c30d7SJussi Kivilinna desc.info = req->info; 487937c30d7SJussi Kivilinna desc.flags = 0; 488937c30d7SJussi Kivilinna 489937c30d7SJussi Kivilinna return crypto_blkcipher_crt(desc.tfm)->encrypt( 490937c30d7SJussi Kivilinna &desc, req->dst, req->src, req->nbytes); 491937c30d7SJussi Kivilinna } 492937c30d7SJussi Kivilinna 493937c30d7SJussi Kivilinna static int ablk_encrypt(struct ablkcipher_request *req) 494937c30d7SJussi Kivilinna { 495937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 496937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 497937c30d7SJussi Kivilinna 498937c30d7SJussi Kivilinna if (!irq_fpu_usable()) { 499937c30d7SJussi Kivilinna struct ablkcipher_request *cryptd_req = 500937c30d7SJussi Kivilinna ablkcipher_request_ctx(req); 501937c30d7SJussi Kivilinna 502937c30d7SJussi Kivilinna memcpy(cryptd_req, req, sizeof(*req)); 503937c30d7SJussi Kivilinna ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); 504937c30d7SJussi Kivilinna 505937c30d7SJussi Kivilinna return crypto_ablkcipher_encrypt(cryptd_req); 506937c30d7SJussi Kivilinna } else { 507937c30d7SJussi Kivilinna return __ablk_encrypt(req); 508937c30d7SJussi Kivilinna } 509937c30d7SJussi Kivilinna } 510937c30d7SJussi Kivilinna 511937c30d7SJussi Kivilinna static int ablk_decrypt(struct ablkcipher_request *req) 512937c30d7SJussi Kivilinna { 513937c30d7SJussi Kivilinna struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); 514937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_ablkcipher_ctx(tfm); 515937c30d7SJussi Kivilinna 516937c30d7SJussi Kivilinna if (!irq_fpu_usable()) { 517937c30d7SJussi Kivilinna struct ablkcipher_request *cryptd_req = 518937c30d7SJussi Kivilinna ablkcipher_request_ctx(req); 519937c30d7SJussi Kivilinna 520937c30d7SJussi Kivilinna memcpy(cryptd_req, req, sizeof(*req)); 521937c30d7SJussi Kivilinna ablkcipher_request_set_tfm(cryptd_req, &ctx->cryptd_tfm->base); 522937c30d7SJussi Kivilinna 523937c30d7SJussi Kivilinna return crypto_ablkcipher_decrypt(cryptd_req); 524937c30d7SJussi Kivilinna } else { 525937c30d7SJussi Kivilinna struct blkcipher_desc desc; 526937c30d7SJussi Kivilinna 527937c30d7SJussi Kivilinna desc.tfm = cryptd_ablkcipher_child(ctx->cryptd_tfm); 528937c30d7SJussi Kivilinna desc.info = req->info; 529937c30d7SJussi Kivilinna desc.flags = 0; 530937c30d7SJussi Kivilinna 531937c30d7SJussi Kivilinna return crypto_blkcipher_crt(desc.tfm)->decrypt( 532937c30d7SJussi Kivilinna &desc, req->dst, req->src, req->nbytes); 533937c30d7SJussi Kivilinna } 534937c30d7SJussi Kivilinna } 535937c30d7SJussi Kivilinna 536937c30d7SJussi Kivilinna static void ablk_exit(struct crypto_tfm *tfm) 537937c30d7SJussi Kivilinna { 538937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); 539937c30d7SJussi Kivilinna 540937c30d7SJussi Kivilinna cryptd_free_ablkcipher(ctx->cryptd_tfm); 541937c30d7SJussi Kivilinna } 542937c30d7SJussi Kivilinna 543937c30d7SJussi Kivilinna static void ablk_init_common(struct crypto_tfm *tfm, 544937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm) 545937c30d7SJussi Kivilinna { 546937c30d7SJussi Kivilinna struct async_serpent_ctx *ctx = crypto_tfm_ctx(tfm); 547937c30d7SJussi Kivilinna 548937c30d7SJussi Kivilinna ctx->cryptd_tfm = cryptd_tfm; 549937c30d7SJussi Kivilinna tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) + 550937c30d7SJussi Kivilinna crypto_ablkcipher_reqsize(&cryptd_tfm->base); 551937c30d7SJussi Kivilinna } 552937c30d7SJussi Kivilinna 553937c30d7SJussi Kivilinna static int ablk_ecb_init(struct crypto_tfm *tfm) 554937c30d7SJussi Kivilinna { 555937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 556937c30d7SJussi Kivilinna 557937c30d7SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ecb-serpent-sse2", 0, 0); 558937c30d7SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 559937c30d7SJussi Kivilinna return PTR_ERR(cryptd_tfm); 560937c30d7SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 561937c30d7SJussi Kivilinna return 0; 562937c30d7SJussi Kivilinna } 563937c30d7SJussi Kivilinna 564937c30d7SJussi Kivilinna static struct crypto_alg ablk_ecb_alg = { 565937c30d7SJussi Kivilinna .cra_name = "ecb(serpent)", 566937c30d7SJussi Kivilinna .cra_driver_name = "ecb-serpent-sse2", 567937c30d7SJussi Kivilinna .cra_priority = 400, 568937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 569937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 570937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 571937c30d7SJussi Kivilinna .cra_alignmask = 0, 572937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 573937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 574937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_ecb_alg.cra_list), 575937c30d7SJussi Kivilinna .cra_init = ablk_ecb_init, 576937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 577937c30d7SJussi Kivilinna .cra_u = { 578937c30d7SJussi Kivilinna .ablkcipher = { 579937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 580937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 581937c30d7SJussi Kivilinna .setkey = ablk_set_key, 582937c30d7SJussi Kivilinna .encrypt = ablk_encrypt, 583937c30d7SJussi Kivilinna .decrypt = ablk_decrypt, 584937c30d7SJussi Kivilinna }, 585937c30d7SJussi Kivilinna }, 586937c30d7SJussi Kivilinna }; 587937c30d7SJussi Kivilinna 588937c30d7SJussi Kivilinna static int ablk_cbc_init(struct crypto_tfm *tfm) 589937c30d7SJussi Kivilinna { 590937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 591937c30d7SJussi Kivilinna 592937c30d7SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-cbc-serpent-sse2", 0, 0); 593937c30d7SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 594937c30d7SJussi Kivilinna return PTR_ERR(cryptd_tfm); 595937c30d7SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 596937c30d7SJussi Kivilinna return 0; 597937c30d7SJussi Kivilinna } 598937c30d7SJussi Kivilinna 599937c30d7SJussi Kivilinna static struct crypto_alg ablk_cbc_alg = { 600937c30d7SJussi Kivilinna .cra_name = "cbc(serpent)", 601937c30d7SJussi Kivilinna .cra_driver_name = "cbc-serpent-sse2", 602937c30d7SJussi Kivilinna .cra_priority = 400, 603937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 604937c30d7SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 605937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 606937c30d7SJussi Kivilinna .cra_alignmask = 0, 607937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 608937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 609937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_cbc_alg.cra_list), 610937c30d7SJussi Kivilinna .cra_init = ablk_cbc_init, 611937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 612937c30d7SJussi Kivilinna .cra_u = { 613937c30d7SJussi Kivilinna .ablkcipher = { 614937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 615937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 616937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 617937c30d7SJussi Kivilinna .setkey = ablk_set_key, 618937c30d7SJussi Kivilinna .encrypt = __ablk_encrypt, 619937c30d7SJussi Kivilinna .decrypt = ablk_decrypt, 620937c30d7SJussi Kivilinna }, 621937c30d7SJussi Kivilinna }, 622937c30d7SJussi Kivilinna }; 623937c30d7SJussi Kivilinna 624937c30d7SJussi Kivilinna static int ablk_ctr_init(struct crypto_tfm *tfm) 625937c30d7SJussi Kivilinna { 626937c30d7SJussi Kivilinna struct cryptd_ablkcipher *cryptd_tfm; 627937c30d7SJussi Kivilinna 628937c30d7SJussi Kivilinna cryptd_tfm = cryptd_alloc_ablkcipher("__driver-ctr-serpent-sse2", 0, 0); 629937c30d7SJussi Kivilinna if (IS_ERR(cryptd_tfm)) 630937c30d7SJussi Kivilinna return PTR_ERR(cryptd_tfm); 631937c30d7SJussi Kivilinna ablk_init_common(tfm, cryptd_tfm); 632937c30d7SJussi Kivilinna return 0; 633937c30d7SJussi Kivilinna } 634937c30d7SJussi Kivilinna 635937c30d7SJussi Kivilinna static struct crypto_alg ablk_ctr_alg = { 636937c30d7SJussi Kivilinna .cra_name = "ctr(serpent)", 637937c30d7SJussi Kivilinna .cra_driver_name = "ctr-serpent-sse2", 638937c30d7SJussi Kivilinna .cra_priority = 400, 639937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 640937c30d7SJussi Kivilinna .cra_blocksize = 1, 641937c30d7SJussi Kivilinna .cra_ctxsize = sizeof(struct async_serpent_ctx), 642937c30d7SJussi Kivilinna .cra_alignmask = 0, 643937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 644937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 645937c30d7SJussi Kivilinna .cra_list = LIST_HEAD_INIT(ablk_ctr_alg.cra_list), 646937c30d7SJussi Kivilinna .cra_init = ablk_ctr_init, 647937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 648937c30d7SJussi Kivilinna .cra_u = { 649937c30d7SJussi Kivilinna .ablkcipher = { 650937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 651937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 652937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 653937c30d7SJussi Kivilinna .setkey = ablk_set_key, 654937c30d7SJussi Kivilinna .encrypt = ablk_encrypt, 655937c30d7SJussi Kivilinna .decrypt = ablk_encrypt, 656937c30d7SJussi Kivilinna .geniv = "chainiv", 657937c30d7SJussi Kivilinna }, 658937c30d7SJussi Kivilinna }, 659937c30d7SJussi Kivilinna }; 660937c30d7SJussi Kivilinna 661937c30d7SJussi Kivilinna static int __init serpent_sse2_init(void) 662937c30d7SJussi Kivilinna { 663937c30d7SJussi Kivilinna int err; 664937c30d7SJussi Kivilinna 665937c30d7SJussi Kivilinna if (!cpu_has_xmm2) { 666937c30d7SJussi Kivilinna printk(KERN_INFO "SSE2 instructions are not detected.\n"); 667937c30d7SJussi Kivilinna return -ENODEV; 668937c30d7SJussi Kivilinna } 669937c30d7SJussi Kivilinna 670937c30d7SJussi Kivilinna err = crypto_register_alg(&blk_ecb_alg); 671937c30d7SJussi Kivilinna if (err) 672937c30d7SJussi Kivilinna goto blk_ecb_err; 673937c30d7SJussi Kivilinna err = crypto_register_alg(&blk_cbc_alg); 674937c30d7SJussi Kivilinna if (err) 675937c30d7SJussi Kivilinna goto blk_cbc_err; 676937c30d7SJussi Kivilinna err = crypto_register_alg(&blk_ctr_alg); 677937c30d7SJussi Kivilinna if (err) 678937c30d7SJussi Kivilinna goto blk_ctr_err; 679937c30d7SJussi Kivilinna err = crypto_register_alg(&ablk_ecb_alg); 680937c30d7SJussi Kivilinna if (err) 681937c30d7SJussi Kivilinna goto ablk_ecb_err; 682937c30d7SJussi Kivilinna err = crypto_register_alg(&ablk_cbc_alg); 683937c30d7SJussi Kivilinna if (err) 684937c30d7SJussi Kivilinna goto ablk_cbc_err; 685937c30d7SJussi Kivilinna err = crypto_register_alg(&ablk_ctr_alg); 686937c30d7SJussi Kivilinna if (err) 687937c30d7SJussi Kivilinna goto ablk_ctr_err; 688937c30d7SJussi Kivilinna return err; 689937c30d7SJussi Kivilinna 690937c30d7SJussi Kivilinna ablk_ctr_err: 691937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_cbc_alg); 692937c30d7SJussi Kivilinna ablk_cbc_err: 693937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_ecb_alg); 694937c30d7SJussi Kivilinna ablk_ecb_err: 695937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ctr_alg); 696937c30d7SJussi Kivilinna blk_ctr_err: 697937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 698937c30d7SJussi Kivilinna blk_cbc_err: 699937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 700937c30d7SJussi Kivilinna blk_ecb_err: 701937c30d7SJussi Kivilinna return err; 702937c30d7SJussi Kivilinna } 703937c30d7SJussi Kivilinna 704937c30d7SJussi Kivilinna static void __exit serpent_sse2_exit(void) 705937c30d7SJussi Kivilinna { 706937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_ctr_alg); 707937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_cbc_alg); 708937c30d7SJussi Kivilinna crypto_unregister_alg(&ablk_ecb_alg); 709937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ctr_alg); 710937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_cbc_alg); 711937c30d7SJussi Kivilinna crypto_unregister_alg(&blk_ecb_alg); 712937c30d7SJussi Kivilinna } 713937c30d7SJussi Kivilinna 714937c30d7SJussi Kivilinna module_init(serpent_sse2_init); 715937c30d7SJussi Kivilinna module_exit(serpent_sse2_exit); 716937c30d7SJussi Kivilinna 717937c30d7SJussi Kivilinna MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 718937c30d7SJussi Kivilinna MODULE_LICENSE("GPL"); 719937c30d7SJussi Kivilinna MODULE_ALIAS("serpent"); 720