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> 44d4af0e9dSJussi Kivilinna #include <asm/crypto/serpent-sse2.h> 45ffaf9156SJussi Kivilinna #include <asm/crypto/ablk_helper.h> 46596d8750SJussi Kivilinna #include <asm/crypto/glue_helper.h> 47937c30d7SJussi Kivilinna 48e81792fbSJussi Kivilinna static void serpent_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src) 49e81792fbSJussi Kivilinna { 50e81792fbSJussi Kivilinna u128 ivs[SERPENT_PARALLEL_BLOCKS - 1]; 51e81792fbSJussi Kivilinna unsigned int j; 52e81792fbSJussi Kivilinna 53e81792fbSJussi Kivilinna for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++) 54e81792fbSJussi Kivilinna ivs[j] = src[j]; 55e81792fbSJussi Kivilinna 56e81792fbSJussi Kivilinna serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); 57e81792fbSJussi Kivilinna 58e81792fbSJussi Kivilinna for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++) 59e81792fbSJussi Kivilinna u128_xor(dst + (j + 1), dst + (j + 1), ivs + j); 60e81792fbSJussi Kivilinna } 61e81792fbSJussi Kivilinna 62e81792fbSJussi Kivilinna static void serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src, u128 *iv) 63e81792fbSJussi Kivilinna { 64e81792fbSJussi Kivilinna be128 ctrblk; 65e81792fbSJussi Kivilinna 66e81792fbSJussi Kivilinna u128_to_be128(&ctrblk, iv); 67e81792fbSJussi Kivilinna u128_inc(iv); 68e81792fbSJussi Kivilinna 69e81792fbSJussi Kivilinna __serpent_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk); 70e81792fbSJussi Kivilinna u128_xor(dst, src, (u128 *)&ctrblk); 71e81792fbSJussi Kivilinna } 72e81792fbSJussi Kivilinna 73e81792fbSJussi Kivilinna static void serpent_crypt_ctr_xway(void *ctx, u128 *dst, const u128 *src, 74e81792fbSJussi Kivilinna u128 *iv) 75e81792fbSJussi Kivilinna { 76e81792fbSJussi Kivilinna be128 ctrblks[SERPENT_PARALLEL_BLOCKS]; 77e81792fbSJussi Kivilinna unsigned int i; 78e81792fbSJussi Kivilinna 79e81792fbSJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) { 80e81792fbSJussi Kivilinna if (dst != src) 81e81792fbSJussi Kivilinna dst[i] = src[i]; 82e81792fbSJussi Kivilinna 83e81792fbSJussi Kivilinna u128_to_be128(&ctrblks[i], iv); 84e81792fbSJussi Kivilinna u128_inc(iv); 85e81792fbSJussi Kivilinna } 86e81792fbSJussi Kivilinna 87e81792fbSJussi Kivilinna serpent_enc_blk_xway_xor(ctx, (u8 *)dst, (u8 *)ctrblks); 88e81792fbSJussi Kivilinna } 89e81792fbSJussi Kivilinna 90e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_enc = { 91e81792fbSJussi Kivilinna .num_funcs = 2, 92e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 93e81792fbSJussi Kivilinna 94e81792fbSJussi Kivilinna .funcs = { { 95e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 96e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_enc_blk_xway) } 97e81792fbSJussi Kivilinna }, { 98e81792fbSJussi Kivilinna .num_blocks = 1, 99e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_encrypt) } 100e81792fbSJussi Kivilinna } } 101e81792fbSJussi Kivilinna }; 102e81792fbSJussi Kivilinna 103e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_ctr = { 104e81792fbSJussi Kivilinna .num_funcs = 2, 105e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 106e81792fbSJussi Kivilinna 107e81792fbSJussi Kivilinna .funcs = { { 108e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 109e81792fbSJussi Kivilinna .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr_xway) } 110e81792fbSJussi Kivilinna }, { 111e81792fbSJussi Kivilinna .num_blocks = 1, 112e81792fbSJussi Kivilinna .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr) } 113e81792fbSJussi Kivilinna } } 114e81792fbSJussi Kivilinna }; 115e81792fbSJussi Kivilinna 116e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_dec = { 117e81792fbSJussi Kivilinna .num_funcs = 2, 118e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 119e81792fbSJussi Kivilinna 120e81792fbSJussi Kivilinna .funcs = { { 121e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 122e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_dec_blk_xway) } 123e81792fbSJussi Kivilinna }, { 124e81792fbSJussi Kivilinna .num_blocks = 1, 125e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_decrypt) } 126e81792fbSJussi Kivilinna } } 127e81792fbSJussi Kivilinna }; 128e81792fbSJussi Kivilinna 129e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_dec_cbc = { 130e81792fbSJussi Kivilinna .num_funcs = 2, 131e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 132e81792fbSJussi Kivilinna 133e81792fbSJussi Kivilinna .funcs = { { 134e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 135e81792fbSJussi Kivilinna .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_decrypt_cbc_xway) } 136e81792fbSJussi Kivilinna }, { 137e81792fbSJussi Kivilinna .num_blocks = 1, 138e81792fbSJussi Kivilinna .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__serpent_decrypt) } 139e81792fbSJussi Kivilinna } } 140e81792fbSJussi Kivilinna }; 141e81792fbSJussi Kivilinna 142e81792fbSJussi Kivilinna static int ecb_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 143e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 144e81792fbSJussi Kivilinna { 145e81792fbSJussi Kivilinna return glue_ecb_crypt_128bit(&serpent_enc, desc, dst, src, nbytes); 146e81792fbSJussi Kivilinna } 147e81792fbSJussi Kivilinna 148e81792fbSJussi Kivilinna static int ecb_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 149e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 150e81792fbSJussi Kivilinna { 151e81792fbSJussi Kivilinna return glue_ecb_crypt_128bit(&serpent_dec, desc, dst, src, nbytes); 152e81792fbSJussi Kivilinna } 153e81792fbSJussi Kivilinna 154e81792fbSJussi Kivilinna static int cbc_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 155e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 156e81792fbSJussi Kivilinna { 157e81792fbSJussi Kivilinna return glue_cbc_encrypt_128bit(GLUE_FUNC_CAST(__serpent_encrypt), desc, 158e81792fbSJussi Kivilinna dst, src, nbytes); 159e81792fbSJussi Kivilinna } 160e81792fbSJussi Kivilinna 161e81792fbSJussi Kivilinna static int cbc_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 162e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 163e81792fbSJussi Kivilinna { 164e81792fbSJussi Kivilinna return glue_cbc_decrypt_128bit(&serpent_dec_cbc, desc, dst, src, 165e81792fbSJussi Kivilinna nbytes); 166e81792fbSJussi Kivilinna } 167e81792fbSJussi Kivilinna 168e81792fbSJussi Kivilinna static int ctr_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, 169e81792fbSJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 170e81792fbSJussi Kivilinna { 171e81792fbSJussi Kivilinna return glue_ctr_crypt_128bit(&serpent_ctr, desc, dst, src, nbytes); 172e81792fbSJussi Kivilinna } 173e81792fbSJussi Kivilinna 174e81792fbSJussi Kivilinna static inline bool serpent_fpu_begin(bool fpu_enabled, unsigned int nbytes) 175e81792fbSJussi Kivilinna { 176e81792fbSJussi Kivilinna return glue_fpu_begin(SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS, 177e81792fbSJussi Kivilinna NULL, fpu_enabled, nbytes); 178e81792fbSJussi Kivilinna } 179e81792fbSJussi Kivilinna 180e81792fbSJussi Kivilinna static inline void serpent_fpu_end(bool fpu_enabled) 181e81792fbSJussi Kivilinna { 182e81792fbSJussi Kivilinna glue_fpu_end(fpu_enabled); 183e81792fbSJussi Kivilinna } 184e81792fbSJussi Kivilinna 18518482053SJussi Kivilinna struct crypt_priv { 18618482053SJussi Kivilinna struct serpent_ctx *ctx; 18718482053SJussi Kivilinna bool fpu_enabled; 18818482053SJussi Kivilinna }; 18918482053SJussi Kivilinna 19018482053SJussi Kivilinna static void encrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) 19118482053SJussi Kivilinna { 19218482053SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 19318482053SJussi Kivilinna struct crypt_priv *ctx = priv; 19418482053SJussi Kivilinna int i; 19518482053SJussi Kivilinna 19618482053SJussi Kivilinna ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes); 19718482053SJussi Kivilinna 19818482053SJussi Kivilinna if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) { 19918482053SJussi Kivilinna serpent_enc_blk_xway(ctx->ctx, srcdst, srcdst); 20018482053SJussi Kivilinna return; 20118482053SJussi Kivilinna } 20218482053SJussi Kivilinna 20318482053SJussi Kivilinna for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) 20418482053SJussi Kivilinna __serpent_encrypt(ctx->ctx, srcdst, srcdst); 20518482053SJussi Kivilinna } 20618482053SJussi Kivilinna 20718482053SJussi Kivilinna static void decrypt_callback(void *priv, u8 *srcdst, unsigned int nbytes) 20818482053SJussi Kivilinna { 20918482053SJussi Kivilinna const unsigned int bsize = SERPENT_BLOCK_SIZE; 21018482053SJussi Kivilinna struct crypt_priv *ctx = priv; 21118482053SJussi Kivilinna int i; 21218482053SJussi Kivilinna 21318482053SJussi Kivilinna ctx->fpu_enabled = serpent_fpu_begin(ctx->fpu_enabled, nbytes); 21418482053SJussi Kivilinna 21518482053SJussi Kivilinna if (nbytes == bsize * SERPENT_PARALLEL_BLOCKS) { 21618482053SJussi Kivilinna serpent_dec_blk_xway(ctx->ctx, srcdst, srcdst); 21718482053SJussi Kivilinna return; 21818482053SJussi Kivilinna } 21918482053SJussi Kivilinna 22018482053SJussi Kivilinna for (i = 0; i < nbytes / bsize; i++, srcdst += bsize) 22118482053SJussi Kivilinna __serpent_decrypt(ctx->ctx, srcdst, srcdst); 22218482053SJussi Kivilinna } 22318482053SJussi Kivilinna 22418482053SJussi Kivilinna struct serpent_lrw_ctx { 22518482053SJussi Kivilinna struct lrw_table_ctx lrw_table; 22618482053SJussi Kivilinna struct serpent_ctx serpent_ctx; 22718482053SJussi Kivilinna }; 22818482053SJussi Kivilinna 22918482053SJussi Kivilinna static int lrw_serpent_setkey(struct crypto_tfm *tfm, const u8 *key, 23018482053SJussi Kivilinna unsigned int keylen) 23118482053SJussi Kivilinna { 23218482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm); 23318482053SJussi Kivilinna int err; 23418482053SJussi Kivilinna 23518482053SJussi Kivilinna err = __serpent_setkey(&ctx->serpent_ctx, key, keylen - 23618482053SJussi Kivilinna SERPENT_BLOCK_SIZE); 23718482053SJussi Kivilinna if (err) 23818482053SJussi Kivilinna return err; 23918482053SJussi Kivilinna 24018482053SJussi Kivilinna return lrw_init_table(&ctx->lrw_table, key + keylen - 24118482053SJussi Kivilinna SERPENT_BLOCK_SIZE); 24218482053SJussi Kivilinna } 24318482053SJussi Kivilinna 24418482053SJussi Kivilinna static int lrw_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 24518482053SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 24618482053SJussi Kivilinna { 24718482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 24818482053SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 24918482053SJussi Kivilinna struct crypt_priv crypt_ctx = { 25018482053SJussi Kivilinna .ctx = &ctx->serpent_ctx, 25118482053SJussi Kivilinna .fpu_enabled = false, 25218482053SJussi Kivilinna }; 25318482053SJussi Kivilinna struct lrw_crypt_req req = { 25418482053SJussi Kivilinna .tbuf = buf, 25518482053SJussi Kivilinna .tbuflen = sizeof(buf), 25618482053SJussi Kivilinna 25718482053SJussi Kivilinna .table_ctx = &ctx->lrw_table, 25818482053SJussi Kivilinna .crypt_ctx = &crypt_ctx, 25918482053SJussi Kivilinna .crypt_fn = encrypt_callback, 26018482053SJussi Kivilinna }; 26118482053SJussi Kivilinna int ret; 26218482053SJussi Kivilinna 263d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 26418482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 26518482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 26618482053SJussi Kivilinna 26718482053SJussi Kivilinna return ret; 26818482053SJussi Kivilinna } 26918482053SJussi Kivilinna 27018482053SJussi Kivilinna static int lrw_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 27118482053SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 27218482053SJussi Kivilinna { 27318482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 27418482053SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 27518482053SJussi Kivilinna struct crypt_priv crypt_ctx = { 27618482053SJussi Kivilinna .ctx = &ctx->serpent_ctx, 27718482053SJussi Kivilinna .fpu_enabled = false, 27818482053SJussi Kivilinna }; 27918482053SJussi Kivilinna struct lrw_crypt_req req = { 28018482053SJussi Kivilinna .tbuf = buf, 28118482053SJussi Kivilinna .tbuflen = sizeof(buf), 28218482053SJussi Kivilinna 28318482053SJussi Kivilinna .table_ctx = &ctx->lrw_table, 28418482053SJussi Kivilinna .crypt_ctx = &crypt_ctx, 28518482053SJussi Kivilinna .crypt_fn = decrypt_callback, 28618482053SJussi Kivilinna }; 28718482053SJussi Kivilinna int ret; 28818482053SJussi Kivilinna 289d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 29018482053SJussi Kivilinna ret = lrw_crypt(desc, dst, src, nbytes, &req); 29118482053SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 29218482053SJussi Kivilinna 29318482053SJussi Kivilinna return ret; 29418482053SJussi Kivilinna } 29518482053SJussi Kivilinna 29618482053SJussi Kivilinna static void lrw_exit_tfm(struct crypto_tfm *tfm) 29718482053SJussi Kivilinna { 29818482053SJussi Kivilinna struct serpent_lrw_ctx *ctx = crypto_tfm_ctx(tfm); 29918482053SJussi Kivilinna 30018482053SJussi Kivilinna lrw_free_table(&ctx->lrw_table); 30118482053SJussi Kivilinna } 30218482053SJussi Kivilinna 3035962f8b6SJussi Kivilinna struct serpent_xts_ctx { 3045962f8b6SJussi Kivilinna struct serpent_ctx tweak_ctx; 3055962f8b6SJussi Kivilinna struct serpent_ctx crypt_ctx; 3065962f8b6SJussi Kivilinna }; 3075962f8b6SJussi Kivilinna 3085962f8b6SJussi Kivilinna static int xts_serpent_setkey(struct crypto_tfm *tfm, const u8 *key, 3095962f8b6SJussi Kivilinna unsigned int keylen) 3105962f8b6SJussi Kivilinna { 3115962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_tfm_ctx(tfm); 3125962f8b6SJussi Kivilinna u32 *flags = &tfm->crt_flags; 3135962f8b6SJussi Kivilinna int err; 3145962f8b6SJussi Kivilinna 3155962f8b6SJussi Kivilinna /* key consists of keys of equal size concatenated, therefore 3165962f8b6SJussi Kivilinna * the length must be even 3175962f8b6SJussi Kivilinna */ 3185962f8b6SJussi Kivilinna if (keylen % 2) { 3195962f8b6SJussi Kivilinna *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; 3205962f8b6SJussi Kivilinna return -EINVAL; 3215962f8b6SJussi Kivilinna } 3225962f8b6SJussi Kivilinna 3235962f8b6SJussi Kivilinna /* first half of xts-key is for crypt */ 3245962f8b6SJussi Kivilinna err = __serpent_setkey(&ctx->crypt_ctx, key, keylen / 2); 3255962f8b6SJussi Kivilinna if (err) 3265962f8b6SJussi Kivilinna return err; 3275962f8b6SJussi Kivilinna 3285962f8b6SJussi Kivilinna /* second half of xts-key is for tweak */ 3295962f8b6SJussi Kivilinna return __serpent_setkey(&ctx->tweak_ctx, key + keylen / 2, keylen / 2); 3305962f8b6SJussi Kivilinna } 3315962f8b6SJussi Kivilinna 3325962f8b6SJussi Kivilinna static int xts_encrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 3335962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 3345962f8b6SJussi Kivilinna { 3355962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 3365962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 3375962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 3385962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 3395962f8b6SJussi Kivilinna .fpu_enabled = false, 3405962f8b6SJussi Kivilinna }; 3415962f8b6SJussi Kivilinna struct xts_crypt_req req = { 3425962f8b6SJussi Kivilinna .tbuf = buf, 3435962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 3445962f8b6SJussi Kivilinna 3455962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 3465962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 3475962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 3485962f8b6SJussi Kivilinna .crypt_fn = encrypt_callback, 3495962f8b6SJussi Kivilinna }; 3505962f8b6SJussi Kivilinna int ret; 3515962f8b6SJussi Kivilinna 352d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 3535962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 3545962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 3555962f8b6SJussi Kivilinna 3565962f8b6SJussi Kivilinna return ret; 3575962f8b6SJussi Kivilinna } 3585962f8b6SJussi Kivilinna 3595962f8b6SJussi Kivilinna static int xts_decrypt(struct blkcipher_desc *desc, struct scatterlist *dst, 3605962f8b6SJussi Kivilinna struct scatterlist *src, unsigned int nbytes) 3615962f8b6SJussi Kivilinna { 3625962f8b6SJussi Kivilinna struct serpent_xts_ctx *ctx = crypto_blkcipher_ctx(desc->tfm); 3635962f8b6SJussi Kivilinna be128 buf[SERPENT_PARALLEL_BLOCKS]; 3645962f8b6SJussi Kivilinna struct crypt_priv crypt_ctx = { 3655962f8b6SJussi Kivilinna .ctx = &ctx->crypt_ctx, 3665962f8b6SJussi Kivilinna .fpu_enabled = false, 3675962f8b6SJussi Kivilinna }; 3685962f8b6SJussi Kivilinna struct xts_crypt_req req = { 3695962f8b6SJussi Kivilinna .tbuf = buf, 3705962f8b6SJussi Kivilinna .tbuflen = sizeof(buf), 3715962f8b6SJussi Kivilinna 3725962f8b6SJussi Kivilinna .tweak_ctx = &ctx->tweak_ctx, 3735962f8b6SJussi Kivilinna .tweak_fn = XTS_TWEAK_CAST(__serpent_encrypt), 3745962f8b6SJussi Kivilinna .crypt_ctx = &crypt_ctx, 3755962f8b6SJussi Kivilinna .crypt_fn = decrypt_callback, 3765962f8b6SJussi Kivilinna }; 3775962f8b6SJussi Kivilinna int ret; 3785962f8b6SJussi Kivilinna 379d3564338SJussi Kivilinna desc->flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; 3805962f8b6SJussi Kivilinna ret = xts_crypt(desc, dst, src, nbytes, &req); 3815962f8b6SJussi Kivilinna serpent_fpu_end(crypt_ctx.fpu_enabled); 3825962f8b6SJussi Kivilinna 3835962f8b6SJussi Kivilinna return ret; 3845962f8b6SJussi Kivilinna } 3855962f8b6SJussi Kivilinna 38635474c3bSJussi Kivilinna static struct crypto_alg serpent_algs[10] = { { 38735474c3bSJussi Kivilinna .cra_name = "__ecb-serpent-sse2", 38835474c3bSJussi Kivilinna .cra_driver_name = "__driver-ecb-serpent-sse2", 38935474c3bSJussi Kivilinna .cra_priority = 0, 39035474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 39135474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 39235474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 39335474c3bSJussi Kivilinna .cra_alignmask = 0, 39435474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 39535474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 39635474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[0].cra_list), 39735474c3bSJussi Kivilinna .cra_u = { 39835474c3bSJussi Kivilinna .blkcipher = { 39935474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 40035474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 40135474c3bSJussi Kivilinna .setkey = serpent_setkey, 40235474c3bSJussi Kivilinna .encrypt = ecb_encrypt, 40335474c3bSJussi Kivilinna .decrypt = ecb_decrypt, 40435474c3bSJussi Kivilinna }, 40535474c3bSJussi Kivilinna }, 40635474c3bSJussi Kivilinna }, { 40735474c3bSJussi Kivilinna .cra_name = "__cbc-serpent-sse2", 40835474c3bSJussi Kivilinna .cra_driver_name = "__driver-cbc-serpent-sse2", 40935474c3bSJussi Kivilinna .cra_priority = 0, 41035474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 41135474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 41235474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 41335474c3bSJussi Kivilinna .cra_alignmask = 0, 41435474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 41535474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 41635474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[1].cra_list), 41735474c3bSJussi Kivilinna .cra_u = { 41835474c3bSJussi Kivilinna .blkcipher = { 41935474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 42035474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 42135474c3bSJussi Kivilinna .setkey = serpent_setkey, 42235474c3bSJussi Kivilinna .encrypt = cbc_encrypt, 42335474c3bSJussi Kivilinna .decrypt = cbc_decrypt, 42435474c3bSJussi Kivilinna }, 42535474c3bSJussi Kivilinna }, 42635474c3bSJussi Kivilinna }, { 42735474c3bSJussi Kivilinna .cra_name = "__ctr-serpent-sse2", 42835474c3bSJussi Kivilinna .cra_driver_name = "__driver-ctr-serpent-sse2", 42935474c3bSJussi Kivilinna .cra_priority = 0, 43035474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 43135474c3bSJussi Kivilinna .cra_blocksize = 1, 43235474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_ctx), 43335474c3bSJussi Kivilinna .cra_alignmask = 0, 43435474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 43535474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 43635474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[2].cra_list), 43735474c3bSJussi Kivilinna .cra_u = { 43835474c3bSJussi Kivilinna .blkcipher = { 43935474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 44035474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 44135474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 44235474c3bSJussi Kivilinna .setkey = serpent_setkey, 44335474c3bSJussi Kivilinna .encrypt = ctr_crypt, 44435474c3bSJussi Kivilinna .decrypt = ctr_crypt, 44535474c3bSJussi Kivilinna }, 44635474c3bSJussi Kivilinna }, 44735474c3bSJussi Kivilinna }, { 44835474c3bSJussi Kivilinna .cra_name = "__lrw-serpent-sse2", 44935474c3bSJussi Kivilinna .cra_driver_name = "__driver-lrw-serpent-sse2", 45035474c3bSJussi Kivilinna .cra_priority = 0, 45135474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 45235474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 45335474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_lrw_ctx), 45435474c3bSJussi Kivilinna .cra_alignmask = 0, 45535474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 45635474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 45735474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[3].cra_list), 45835474c3bSJussi Kivilinna .cra_exit = lrw_exit_tfm, 45935474c3bSJussi Kivilinna .cra_u = { 46035474c3bSJussi Kivilinna .blkcipher = { 46135474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 46235474c3bSJussi Kivilinna SERPENT_BLOCK_SIZE, 46335474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 46435474c3bSJussi Kivilinna SERPENT_BLOCK_SIZE, 46535474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 46635474c3bSJussi Kivilinna .setkey = lrw_serpent_setkey, 46735474c3bSJussi Kivilinna .encrypt = lrw_encrypt, 46835474c3bSJussi Kivilinna .decrypt = lrw_decrypt, 46935474c3bSJussi Kivilinna }, 47035474c3bSJussi Kivilinna }, 47135474c3bSJussi Kivilinna }, { 47235474c3bSJussi Kivilinna .cra_name = "__xts-serpent-sse2", 47335474c3bSJussi Kivilinna .cra_driver_name = "__driver-xts-serpent-sse2", 47435474c3bSJussi Kivilinna .cra_priority = 0, 47535474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, 47635474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 47735474c3bSJussi Kivilinna .cra_ctxsize = sizeof(struct serpent_xts_ctx), 47835474c3bSJussi Kivilinna .cra_alignmask = 0, 47935474c3bSJussi Kivilinna .cra_type = &crypto_blkcipher_type, 48035474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 48135474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[4].cra_list), 48235474c3bSJussi Kivilinna .cra_u = { 48335474c3bSJussi Kivilinna .blkcipher = { 48435474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 48535474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 48635474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 48735474c3bSJussi Kivilinna .setkey = xts_serpent_setkey, 48835474c3bSJussi Kivilinna .encrypt = xts_encrypt, 48935474c3bSJussi Kivilinna .decrypt = xts_decrypt, 49035474c3bSJussi Kivilinna }, 49135474c3bSJussi Kivilinna }, 49235474c3bSJussi Kivilinna }, { 49335474c3bSJussi Kivilinna .cra_name = "ecb(serpent)", 49435474c3bSJussi Kivilinna .cra_driver_name = "ecb-serpent-sse2", 49535474c3bSJussi Kivilinna .cra_priority = 400, 49635474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 49735474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 498ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 49935474c3bSJussi Kivilinna .cra_alignmask = 0, 50035474c3bSJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 50135474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 50235474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[5].cra_list), 503435d3e51SJussi Kivilinna .cra_init = ablk_init, 50435474c3bSJussi Kivilinna .cra_exit = ablk_exit, 50535474c3bSJussi Kivilinna .cra_u = { 50635474c3bSJussi Kivilinna .ablkcipher = { 50735474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 50835474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 50935474c3bSJussi Kivilinna .setkey = ablk_set_key, 51035474c3bSJussi Kivilinna .encrypt = ablk_encrypt, 51135474c3bSJussi Kivilinna .decrypt = ablk_decrypt, 51235474c3bSJussi Kivilinna }, 51335474c3bSJussi Kivilinna }, 51435474c3bSJussi Kivilinna }, { 51535474c3bSJussi Kivilinna .cra_name = "cbc(serpent)", 51635474c3bSJussi Kivilinna .cra_driver_name = "cbc-serpent-sse2", 51735474c3bSJussi Kivilinna .cra_priority = 400, 51835474c3bSJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 51935474c3bSJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 520ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 52135474c3bSJussi Kivilinna .cra_alignmask = 0, 52235474c3bSJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 52335474c3bSJussi Kivilinna .cra_module = THIS_MODULE, 52435474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[6].cra_list), 525435d3e51SJussi Kivilinna .cra_init = ablk_init, 52635474c3bSJussi Kivilinna .cra_exit = ablk_exit, 52735474c3bSJussi Kivilinna .cra_u = { 52835474c3bSJussi Kivilinna .ablkcipher = { 52935474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 53035474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 53135474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 53235474c3bSJussi Kivilinna .setkey = ablk_set_key, 53335474c3bSJussi Kivilinna .encrypt = __ablk_encrypt, 53435474c3bSJussi Kivilinna .decrypt = ablk_decrypt, 53535474c3bSJussi Kivilinna }, 53635474c3bSJussi Kivilinna }, 53735474c3bSJussi Kivilinna }, { 538937c30d7SJussi Kivilinna .cra_name = "ctr(serpent)", 539937c30d7SJussi Kivilinna .cra_driver_name = "ctr-serpent-sse2", 540937c30d7SJussi Kivilinna .cra_priority = 400, 541937c30d7SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 542937c30d7SJussi Kivilinna .cra_blocksize = 1, 543ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 544937c30d7SJussi Kivilinna .cra_alignmask = 0, 545937c30d7SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 546937c30d7SJussi Kivilinna .cra_module = THIS_MODULE, 54735474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[7].cra_list), 548435d3e51SJussi Kivilinna .cra_init = ablk_init, 549937c30d7SJussi Kivilinna .cra_exit = ablk_exit, 550937c30d7SJussi Kivilinna .cra_u = { 551937c30d7SJussi Kivilinna .ablkcipher = { 552937c30d7SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 553937c30d7SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 554937c30d7SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 555937c30d7SJussi Kivilinna .setkey = ablk_set_key, 556937c30d7SJussi Kivilinna .encrypt = ablk_encrypt, 557937c30d7SJussi Kivilinna .decrypt = ablk_encrypt, 558937c30d7SJussi Kivilinna .geniv = "chainiv", 559937c30d7SJussi Kivilinna }, 560937c30d7SJussi Kivilinna }, 56135474c3bSJussi Kivilinna }, { 56218482053SJussi Kivilinna .cra_name = "lrw(serpent)", 56318482053SJussi Kivilinna .cra_driver_name = "lrw-serpent-sse2", 56418482053SJussi Kivilinna .cra_priority = 400, 56518482053SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 56618482053SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 567ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 56818482053SJussi Kivilinna .cra_alignmask = 0, 56918482053SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 57018482053SJussi Kivilinna .cra_module = THIS_MODULE, 57135474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[8].cra_list), 572435d3e51SJussi Kivilinna .cra_init = ablk_init, 57318482053SJussi Kivilinna .cra_exit = ablk_exit, 57418482053SJussi Kivilinna .cra_u = { 57518482053SJussi Kivilinna .ablkcipher = { 57618482053SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE + 57718482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 57818482053SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE + 57918482053SJussi Kivilinna SERPENT_BLOCK_SIZE, 58018482053SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 58118482053SJussi Kivilinna .setkey = ablk_set_key, 58218482053SJussi Kivilinna .encrypt = ablk_encrypt, 58318482053SJussi Kivilinna .decrypt = ablk_decrypt, 58418482053SJussi Kivilinna }, 58518482053SJussi Kivilinna }, 58635474c3bSJussi Kivilinna }, { 5875962f8b6SJussi Kivilinna .cra_name = "xts(serpent)", 5885962f8b6SJussi Kivilinna .cra_driver_name = "xts-serpent-sse2", 5895962f8b6SJussi Kivilinna .cra_priority = 400, 5905962f8b6SJussi Kivilinna .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, 5915962f8b6SJussi Kivilinna .cra_blocksize = SERPENT_BLOCK_SIZE, 592ffaf9156SJussi Kivilinna .cra_ctxsize = sizeof(struct async_helper_ctx), 5935962f8b6SJussi Kivilinna .cra_alignmask = 0, 5945962f8b6SJussi Kivilinna .cra_type = &crypto_ablkcipher_type, 5955962f8b6SJussi Kivilinna .cra_module = THIS_MODULE, 59635474c3bSJussi Kivilinna .cra_list = LIST_HEAD_INIT(serpent_algs[9].cra_list), 597435d3e51SJussi Kivilinna .cra_init = ablk_init, 5985962f8b6SJussi Kivilinna .cra_exit = ablk_exit, 5995962f8b6SJussi Kivilinna .cra_u = { 6005962f8b6SJussi Kivilinna .ablkcipher = { 6015962f8b6SJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE * 2, 6025962f8b6SJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE * 2, 6035962f8b6SJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 6045962f8b6SJussi Kivilinna .setkey = ablk_set_key, 6055962f8b6SJussi Kivilinna .encrypt = ablk_encrypt, 6065962f8b6SJussi Kivilinna .decrypt = ablk_decrypt, 6075962f8b6SJussi Kivilinna }, 6085962f8b6SJussi Kivilinna }, 60935474c3bSJussi Kivilinna } }; 6105962f8b6SJussi Kivilinna 611937c30d7SJussi Kivilinna static int __init serpent_sse2_init(void) 612937c30d7SJussi Kivilinna { 613937c30d7SJussi Kivilinna if (!cpu_has_xmm2) { 614937c30d7SJussi Kivilinna printk(KERN_INFO "SSE2 instructions are not detected.\n"); 615937c30d7SJussi Kivilinna return -ENODEV; 616937c30d7SJussi Kivilinna } 617937c30d7SJussi Kivilinna 61835474c3bSJussi Kivilinna return crypto_register_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); 619937c30d7SJussi Kivilinna } 620937c30d7SJussi Kivilinna 621937c30d7SJussi Kivilinna static void __exit serpent_sse2_exit(void) 622937c30d7SJussi Kivilinna { 62335474c3bSJussi Kivilinna crypto_unregister_algs(serpent_algs, ARRAY_SIZE(serpent_algs)); 624937c30d7SJussi Kivilinna } 625937c30d7SJussi Kivilinna 626937c30d7SJussi Kivilinna module_init(serpent_sse2_init); 627937c30d7SJussi Kivilinna module_exit(serpent_sse2_exit); 628937c30d7SJussi Kivilinna 629937c30d7SJussi Kivilinna MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 630937c30d7SJussi Kivilinna MODULE_LICENSE("GPL"); 631937c30d7SJussi Kivilinna MODULE_ALIAS("serpent"); 632