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/types.h> 34937c30d7SJussi Kivilinna #include <linux/crypto.h> 35937c30d7SJussi Kivilinna #include <linux/err.h> 36937c30d7SJussi Kivilinna #include <crypto/algapi.h> 37937c30d7SJussi Kivilinna #include <crypto/b128ops.h> 38e0f409dcSEric Biggers #include <crypto/internal/simd.h> 39e0f409dcSEric Biggers #include <crypto/serpent.h> 40d4af0e9dSJussi Kivilinna #include <asm/crypto/serpent-sse2.h> 41596d8750SJussi Kivilinna #include <asm/crypto/glue_helper.h> 42937c30d7SJussi Kivilinna 43e0f409dcSEric Biggers static int serpent_setkey_skcipher(struct crypto_skcipher *tfm, 44e0f409dcSEric Biggers const u8 *key, unsigned int keylen) 45e0f409dcSEric Biggers { 46e0f409dcSEric Biggers return __serpent_setkey(crypto_skcipher_ctx(tfm), key, keylen); 47e0f409dcSEric Biggers } 48e0f409dcSEric Biggers 49e81792fbSJussi Kivilinna static void serpent_decrypt_cbc_xway(void *ctx, u128 *dst, const u128 *src) 50e81792fbSJussi Kivilinna { 51e81792fbSJussi Kivilinna u128 ivs[SERPENT_PARALLEL_BLOCKS - 1]; 52e81792fbSJussi Kivilinna unsigned int j; 53e81792fbSJussi Kivilinna 54e81792fbSJussi Kivilinna for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++) 55e81792fbSJussi Kivilinna ivs[j] = src[j]; 56e81792fbSJussi Kivilinna 57e81792fbSJussi Kivilinna serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src); 58e81792fbSJussi Kivilinna 59e81792fbSJussi Kivilinna for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++) 60e81792fbSJussi Kivilinna u128_xor(dst + (j + 1), dst + (j + 1), ivs + j); 61e81792fbSJussi Kivilinna } 62e81792fbSJussi Kivilinna 6358990986SJussi Kivilinna static void serpent_crypt_ctr(void *ctx, u128 *dst, const u128 *src, le128 *iv) 64e81792fbSJussi Kivilinna { 65e81792fbSJussi Kivilinna be128 ctrblk; 66e81792fbSJussi Kivilinna 6758990986SJussi Kivilinna le128_to_be128(&ctrblk, iv); 6858990986SJussi Kivilinna le128_inc(iv); 69e81792fbSJussi Kivilinna 70e81792fbSJussi Kivilinna __serpent_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk); 71e81792fbSJussi Kivilinna u128_xor(dst, src, (u128 *)&ctrblk); 72e81792fbSJussi Kivilinna } 73e81792fbSJussi Kivilinna 74e81792fbSJussi Kivilinna static void serpent_crypt_ctr_xway(void *ctx, u128 *dst, const u128 *src, 7558990986SJussi Kivilinna le128 *iv) 76e81792fbSJussi Kivilinna { 77e81792fbSJussi Kivilinna be128 ctrblks[SERPENT_PARALLEL_BLOCKS]; 78e81792fbSJussi Kivilinna unsigned int i; 79e81792fbSJussi Kivilinna 80e81792fbSJussi Kivilinna for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) { 81e81792fbSJussi Kivilinna if (dst != src) 82e81792fbSJussi Kivilinna dst[i] = src[i]; 83e81792fbSJussi Kivilinna 8458990986SJussi Kivilinna le128_to_be128(&ctrblks[i], iv); 8558990986SJussi Kivilinna le128_inc(iv); 86e81792fbSJussi Kivilinna } 87e81792fbSJussi Kivilinna 88e81792fbSJussi Kivilinna serpent_enc_blk_xway_xor(ctx, (u8 *)dst, (u8 *)ctrblks); 89e81792fbSJussi Kivilinna } 90e81792fbSJussi Kivilinna 91e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_enc = { 92e81792fbSJussi Kivilinna .num_funcs = 2, 93e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 94e81792fbSJussi Kivilinna 95e81792fbSJussi Kivilinna .funcs = { { 96e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 97e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_enc_blk_xway) } 98e81792fbSJussi Kivilinna }, { 99e81792fbSJussi Kivilinna .num_blocks = 1, 100e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_encrypt) } 101e81792fbSJussi Kivilinna } } 102e81792fbSJussi Kivilinna }; 103e81792fbSJussi Kivilinna 104e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_ctr = { 105e81792fbSJussi Kivilinna .num_funcs = 2, 106e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 107e81792fbSJussi Kivilinna 108e81792fbSJussi Kivilinna .funcs = { { 109e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 110e81792fbSJussi Kivilinna .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr_xway) } 111e81792fbSJussi Kivilinna }, { 112e81792fbSJussi Kivilinna .num_blocks = 1, 113e81792fbSJussi Kivilinna .fn_u = { .ctr = GLUE_CTR_FUNC_CAST(serpent_crypt_ctr) } 114e81792fbSJussi Kivilinna } } 115e81792fbSJussi Kivilinna }; 116e81792fbSJussi Kivilinna 117e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_dec = { 118e81792fbSJussi Kivilinna .num_funcs = 2, 119e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 120e81792fbSJussi Kivilinna 121e81792fbSJussi Kivilinna .funcs = { { 122e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 123e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(serpent_dec_blk_xway) } 124e81792fbSJussi Kivilinna }, { 125e81792fbSJussi Kivilinna .num_blocks = 1, 126e81792fbSJussi Kivilinna .fn_u = { .ecb = GLUE_FUNC_CAST(__serpent_decrypt) } 127e81792fbSJussi Kivilinna } } 128e81792fbSJussi Kivilinna }; 129e81792fbSJussi Kivilinna 130e81792fbSJussi Kivilinna static const struct common_glue_ctx serpent_dec_cbc = { 131e81792fbSJussi Kivilinna .num_funcs = 2, 132e81792fbSJussi Kivilinna .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS, 133e81792fbSJussi Kivilinna 134e81792fbSJussi Kivilinna .funcs = { { 135e81792fbSJussi Kivilinna .num_blocks = SERPENT_PARALLEL_BLOCKS, 136e81792fbSJussi Kivilinna .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(serpent_decrypt_cbc_xway) } 137e81792fbSJussi Kivilinna }, { 138e81792fbSJussi Kivilinna .num_blocks = 1, 139e81792fbSJussi Kivilinna .fn_u = { .cbc = GLUE_CBC_FUNC_CAST(__serpent_decrypt) } 140e81792fbSJussi Kivilinna } } 141e81792fbSJussi Kivilinna }; 142e81792fbSJussi Kivilinna 143e0f409dcSEric Biggers static int ecb_encrypt(struct skcipher_request *req) 144e81792fbSJussi Kivilinna { 145e0f409dcSEric Biggers return glue_ecb_req_128bit(&serpent_enc, req); 146e81792fbSJussi Kivilinna } 147e81792fbSJussi Kivilinna 148e0f409dcSEric Biggers static int ecb_decrypt(struct skcipher_request *req) 149e81792fbSJussi Kivilinna { 150e0f409dcSEric Biggers return glue_ecb_req_128bit(&serpent_dec, req); 151e81792fbSJussi Kivilinna } 152e81792fbSJussi Kivilinna 153e0f409dcSEric Biggers static int cbc_encrypt(struct skcipher_request *req) 154e81792fbSJussi Kivilinna { 155e0f409dcSEric Biggers return glue_cbc_encrypt_req_128bit(GLUE_FUNC_CAST(__serpent_encrypt), 156e0f409dcSEric Biggers req); 157e81792fbSJussi Kivilinna } 158e81792fbSJussi Kivilinna 159e0f409dcSEric Biggers static int cbc_decrypt(struct skcipher_request *req) 160e81792fbSJussi Kivilinna { 161e0f409dcSEric Biggers return glue_cbc_decrypt_req_128bit(&serpent_dec_cbc, req); 162e81792fbSJussi Kivilinna } 163e81792fbSJussi Kivilinna 164e0f409dcSEric Biggers static int ctr_crypt(struct skcipher_request *req) 165e81792fbSJussi Kivilinna { 166e0f409dcSEric Biggers return glue_ctr_req_128bit(&serpent_ctr, req); 167e81792fbSJussi Kivilinna } 168e81792fbSJussi Kivilinna 169e0f409dcSEric Biggers static struct skcipher_alg serpent_algs[] = { 170e0f409dcSEric Biggers { 171e0f409dcSEric Biggers .base.cra_name = "__ecb(serpent)", 172e0f409dcSEric Biggers .base.cra_driver_name = "__ecb-serpent-sse2", 173e0f409dcSEric Biggers .base.cra_priority = 400, 174e0f409dcSEric Biggers .base.cra_flags = CRYPTO_ALG_INTERNAL, 175e0f409dcSEric Biggers .base.cra_blocksize = SERPENT_BLOCK_SIZE, 176e0f409dcSEric Biggers .base.cra_ctxsize = sizeof(struct serpent_ctx), 177e0f409dcSEric Biggers .base.cra_module = THIS_MODULE, 17835474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 17935474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 180e0f409dcSEric Biggers .setkey = serpent_setkey_skcipher, 18135474c3bSJussi Kivilinna .encrypt = ecb_encrypt, 18235474c3bSJussi Kivilinna .decrypt = ecb_decrypt, 18335474c3bSJussi Kivilinna }, { 184e0f409dcSEric Biggers .base.cra_name = "__cbc(serpent)", 185e0f409dcSEric Biggers .base.cra_driver_name = "__cbc-serpent-sse2", 186e0f409dcSEric Biggers .base.cra_priority = 400, 187e0f409dcSEric Biggers .base.cra_flags = CRYPTO_ALG_INTERNAL, 188e0f409dcSEric Biggers .base.cra_blocksize = SERPENT_BLOCK_SIZE, 189e0f409dcSEric Biggers .base.cra_ctxsize = sizeof(struct serpent_ctx), 190e0f409dcSEric Biggers .base.cra_module = THIS_MODULE, 19135474c3bSJussi Kivilinna .min_keysize = SERPENT_MIN_KEY_SIZE, 19235474c3bSJussi Kivilinna .max_keysize = SERPENT_MAX_KEY_SIZE, 19335474c3bSJussi Kivilinna .ivsize = SERPENT_BLOCK_SIZE, 194e0f409dcSEric Biggers .setkey = serpent_setkey_skcipher, 195e0f409dcSEric Biggers .encrypt = cbc_encrypt, 196e0f409dcSEric Biggers .decrypt = cbc_decrypt, 197e0f409dcSEric Biggers }, { 198e0f409dcSEric Biggers .base.cra_name = "__ctr(serpent)", 199e0f409dcSEric Biggers .base.cra_driver_name = "__ctr-serpent-sse2", 200e0f409dcSEric Biggers .base.cra_priority = 400, 201e0f409dcSEric Biggers .base.cra_flags = CRYPTO_ALG_INTERNAL, 202e0f409dcSEric Biggers .base.cra_blocksize = 1, 203e0f409dcSEric Biggers .base.cra_ctxsize = sizeof(struct serpent_ctx), 204e0f409dcSEric Biggers .base.cra_module = THIS_MODULE, 205e0f409dcSEric Biggers .min_keysize = SERPENT_MIN_KEY_SIZE, 206e0f409dcSEric Biggers .max_keysize = SERPENT_MAX_KEY_SIZE, 207e0f409dcSEric Biggers .ivsize = SERPENT_BLOCK_SIZE, 208e0f409dcSEric Biggers .chunksize = SERPENT_BLOCK_SIZE, 209e0f409dcSEric Biggers .setkey = serpent_setkey_skcipher, 21035474c3bSJussi Kivilinna .encrypt = ctr_crypt, 21135474c3bSJussi Kivilinna .decrypt = ctr_crypt, 21235474c3bSJussi Kivilinna }, 213e0f409dcSEric Biggers }; 214e0f409dcSEric Biggers 215e0f409dcSEric Biggers static struct simd_skcipher_alg *serpent_simd_algs[ARRAY_SIZE(serpent_algs)]; 2165962f8b6SJussi Kivilinna 217937c30d7SJussi Kivilinna static int __init serpent_sse2_init(void) 218937c30d7SJussi Kivilinna { 219054efb64SBorislav Petkov if (!boot_cpu_has(X86_FEATURE_XMM2)) { 220937c30d7SJussi Kivilinna printk(KERN_INFO "SSE2 instructions are not detected.\n"); 221937c30d7SJussi Kivilinna return -ENODEV; 222937c30d7SJussi Kivilinna } 223937c30d7SJussi Kivilinna 224e0f409dcSEric Biggers return simd_register_skciphers_compat(serpent_algs, 225e0f409dcSEric Biggers ARRAY_SIZE(serpent_algs), 226e0f409dcSEric Biggers serpent_simd_algs); 227937c30d7SJussi Kivilinna } 228937c30d7SJussi Kivilinna 229937c30d7SJussi Kivilinna static void __exit serpent_sse2_exit(void) 230937c30d7SJussi Kivilinna { 231e0f409dcSEric Biggers simd_unregister_skciphers(serpent_algs, ARRAY_SIZE(serpent_algs), 232e0f409dcSEric Biggers serpent_simd_algs); 233937c30d7SJussi Kivilinna } 234937c30d7SJussi Kivilinna 235937c30d7SJussi Kivilinna module_init(serpent_sse2_init); 236937c30d7SJussi Kivilinna module_exit(serpent_sse2_exit); 237937c30d7SJussi Kivilinna 238937c30d7SJussi Kivilinna MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 239937c30d7SJussi Kivilinna MODULE_LICENSE("GPL"); 2405d26a105SKees Cook MODULE_ALIAS_CRYPTO("serpent"); 241