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/serpent.h> 22 23 #include "serpent-sse2.h" 24 #include "ecb_cbc_helpers.h" 25 26 static int serpent_setkey_skcipher(struct crypto_skcipher *tfm, 27 const u8 *key, unsigned int keylen) 28 { 29 return __serpent_setkey(crypto_skcipher_ctx(tfm), key, keylen); 30 } 31 32 static void serpent_decrypt_cbc_xway(const void *ctx, u8 *dst, const u8 *src) 33 { 34 u8 buf[SERPENT_PARALLEL_BLOCKS - 1][SERPENT_BLOCK_SIZE]; 35 const u8 *s = src; 36 37 if (dst == src) 38 s = memcpy(buf, src, sizeof(buf)); 39 serpent_dec_blk_xway(ctx, dst, src); 40 crypto_xor(dst + SERPENT_BLOCK_SIZE, s, sizeof(buf)); 41 } 42 43 static int ecb_encrypt(struct skcipher_request *req) 44 { 45 ECB_WALK_START(req, SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS); 46 ECB_BLOCK(SERPENT_PARALLEL_BLOCKS, serpent_enc_blk_xway); 47 ECB_BLOCK(1, __serpent_encrypt); 48 ECB_WALK_END(); 49 } 50 51 static int ecb_decrypt(struct skcipher_request *req) 52 { 53 ECB_WALK_START(req, SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS); 54 ECB_BLOCK(SERPENT_PARALLEL_BLOCKS, serpent_dec_blk_xway); 55 ECB_BLOCK(1, __serpent_decrypt); 56 ECB_WALK_END(); 57 } 58 59 static int cbc_encrypt(struct skcipher_request *req) 60 { 61 CBC_WALK_START(req, SERPENT_BLOCK_SIZE, -1); 62 CBC_ENC_BLOCK(__serpent_encrypt); 63 CBC_WALK_END(); 64 } 65 66 static int cbc_decrypt(struct skcipher_request *req) 67 { 68 CBC_WALK_START(req, SERPENT_BLOCK_SIZE, SERPENT_PARALLEL_BLOCKS); 69 CBC_DEC_BLOCK(SERPENT_PARALLEL_BLOCKS, serpent_decrypt_cbc_xway); 70 CBC_DEC_BLOCK(1, __serpent_decrypt); 71 CBC_WALK_END(); 72 } 73 74 static struct skcipher_alg serpent_algs[] = { 75 { 76 .base.cra_name = "ecb(serpent)", 77 .base.cra_driver_name = "ecb-serpent-sse2", 78 .base.cra_priority = 400, 79 .base.cra_blocksize = SERPENT_BLOCK_SIZE, 80 .base.cra_ctxsize = sizeof(struct serpent_ctx), 81 .base.cra_module = THIS_MODULE, 82 .min_keysize = SERPENT_MIN_KEY_SIZE, 83 .max_keysize = SERPENT_MAX_KEY_SIZE, 84 .setkey = serpent_setkey_skcipher, 85 .encrypt = ecb_encrypt, 86 .decrypt = ecb_decrypt, 87 }, { 88 .base.cra_name = "cbc(serpent)", 89 .base.cra_driver_name = "cbc-serpent-sse2", 90 .base.cra_priority = 400, 91 .base.cra_blocksize = SERPENT_BLOCK_SIZE, 92 .base.cra_ctxsize = sizeof(struct serpent_ctx), 93 .base.cra_module = THIS_MODULE, 94 .min_keysize = SERPENT_MIN_KEY_SIZE, 95 .max_keysize = SERPENT_MAX_KEY_SIZE, 96 .ivsize = SERPENT_BLOCK_SIZE, 97 .setkey = serpent_setkey_skcipher, 98 .encrypt = cbc_encrypt, 99 .decrypt = cbc_decrypt, 100 }, 101 }; 102 103 static int __init serpent_sse2_init(void) 104 { 105 if (!boot_cpu_has(X86_FEATURE_XMM2)) { 106 printk(KERN_INFO "SSE2 instructions are not detected.\n"); 107 return -ENODEV; 108 } 109 110 return crypto_register_skciphers(serpent_algs, 111 ARRAY_SIZE(serpent_algs)); 112 } 113 114 static void __exit serpent_sse2_exit(void) 115 { 116 crypto_unregister_skciphers(serpent_algs, ARRAY_SIZE(serpent_algs)); 117 } 118 119 module_init(serpent_sse2_init); 120 module_exit(serpent_sse2_exit); 121 122 MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 123 MODULE_LICENSE("GPL"); 124 MODULE_ALIAS_CRYPTO("serpent"); 125