1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Glue Code for SSE2 assembler versions of Serpent Cipher 4 * 5 * Copyright (c) 2011 Jussi Kivilinna <jussi.kivilinna@mbnet.fi> 6 * 7 * Glue code based on aesni-intel_glue.c by: 8 * Copyright (C) 2008, Intel Corp. 9 * Author: Huang Ying <ying.huang@intel.com> 10 * 11 * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by: 12 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> 13 */ 14 15 #include <linux/module.h> 16 #include <linux/types.h> 17 #include <linux/crypto.h> 18 #include <linux/err.h> 19 #include <crypto/algapi.h> 20 #include <crypto/b128ops.h> 21 #include <crypto/internal/simd.h> 22 #include <crypto/serpent.h> 23 24 #include "serpent-sse2.h" 25 #include "ecb_cbc_helpers.h" 26 27 static int serpent_setkey_skcipher(struct crypto_skcipher *tfm, 28 const u8 *key, unsigned int keylen) 29 { 30 return __serpent_setkey(crypto_skcipher_ctx(tfm), key, keylen); 31 } 32 33 static void serpent_decrypt_cbc_xway(const void *ctx, u8 *dst, const u8 *src) 34 { 35 u8 buf[SERPENT_PARALLEL_BLOCKS - 1][SERPENT_BLOCK_SIZE]; 36 const u8 *s = src; 37 38 if (dst == src) 39 s = memcpy(buf, src, sizeof(buf)); 40 serpent_dec_blk_xway(ctx, dst, src); 41 crypto_xor(dst + SERPENT_BLOCK_SIZE, s, sizeof(buf)); 42 } 43 44 static int ecb_encrypt(struct skcipher_request *req) 45 { 46 ECB_WALK_START(req, SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS); 47 ECB_BLOCK(SERPENT_PARALLEL_BLOCKS, serpent_enc_blk_xway); 48 ECB_BLOCK(1, __serpent_encrypt); 49 ECB_WALK_END(); 50 } 51 52 static int ecb_decrypt(struct skcipher_request *req) 53 { 54 ECB_WALK_START(req, SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS); 55 ECB_BLOCK(SERPENT_PARALLEL_BLOCKS, serpent_dec_blk_xway); 56 ECB_BLOCK(1, __serpent_decrypt); 57 ECB_WALK_END(); 58 } 59 60 static int cbc_encrypt(struct skcipher_request *req) 61 { 62 CBC_WALK_START(req, SERPENT_BLOCK_SIZE, -1); 63 CBC_ENC_BLOCK(__serpent_encrypt); 64 CBC_WALK_END(); 65 } 66 67 static int cbc_decrypt(struct skcipher_request *req) 68 { 69 CBC_WALK_START(req, SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS); 70 CBC_DEC_BLOCK(SERPENT_PARALLEL_BLOCKS, serpent_decrypt_cbc_xway); 71 CBC_DEC_BLOCK(1, __serpent_decrypt); 72 CBC_WALK_END(); 73 } 74 75 static struct skcipher_alg serpent_algs[] = { 76 { 77 .base.cra_name = "__ecb(serpent)", 78 .base.cra_driver_name = "__ecb-serpent-sse2", 79 .base.cra_priority = 400, 80 .base.cra_flags = CRYPTO_ALG_INTERNAL, 81 .base.cra_blocksize = SERPENT_BLOCK_SIZE, 82 .base.cra_ctxsize = sizeof(struct serpent_ctx), 83 .base.cra_module = THIS_MODULE, 84 .min_keysize = SERPENT_MIN_KEY_SIZE, 85 .max_keysize = SERPENT_MAX_KEY_SIZE, 86 .setkey = serpent_setkey_skcipher, 87 .encrypt = ecb_encrypt, 88 .decrypt = ecb_decrypt, 89 }, { 90 .base.cra_name = "__cbc(serpent)", 91 .base.cra_driver_name = "__cbc-serpent-sse2", 92 .base.cra_priority = 400, 93 .base.cra_flags = CRYPTO_ALG_INTERNAL, 94 .base.cra_blocksize = SERPENT_BLOCK_SIZE, 95 .base.cra_ctxsize = sizeof(struct serpent_ctx), 96 .base.cra_module = THIS_MODULE, 97 .min_keysize = SERPENT_MIN_KEY_SIZE, 98 .max_keysize = SERPENT_MAX_KEY_SIZE, 99 .ivsize = SERPENT_BLOCK_SIZE, 100 .setkey = serpent_setkey_skcipher, 101 .encrypt = cbc_encrypt, 102 .decrypt = cbc_decrypt, 103 }, 104 }; 105 106 static struct simd_skcipher_alg *serpent_simd_algs[ARRAY_SIZE(serpent_algs)]; 107 108 static int __init serpent_sse2_init(void) 109 { 110 if (!boot_cpu_has(X86_FEATURE_XMM2)) { 111 printk(KERN_INFO "SSE2 instructions are not detected.\n"); 112 return -ENODEV; 113 } 114 115 return simd_register_skciphers_compat(serpent_algs, 116 ARRAY_SIZE(serpent_algs), 117 serpent_simd_algs); 118 } 119 120 static void __exit serpent_sse2_exit(void) 121 { 122 simd_unregister_skciphers(serpent_algs, ARRAY_SIZE(serpent_algs), 123 serpent_simd_algs); 124 } 125 126 module_init(serpent_sse2_init); 127 module_exit(serpent_sse2_exit); 128 129 MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 130 MODULE_LICENSE("GPL"); 131 MODULE_ALIAS_CRYPTO("serpent"); 132