serpent_sse2_glue.c (3777B)
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 27static 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 33static 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 44static 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 52static 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 60static 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 67static 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 75static 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 106static struct simd_skcipher_alg *serpent_simd_algs[ARRAY_SIZE(serpent_algs)]; 107 108static 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 120static void __exit serpent_sse2_exit(void) 121{ 122 simd_unregister_skciphers(serpent_algs, ARRAY_SIZE(serpent_algs), 123 serpent_simd_algs); 124} 125 126module_init(serpent_sse2_init); 127module_exit(serpent_sse2_exit); 128 129MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized"); 130MODULE_LICENSE("GPL"); 131MODULE_ALIAS_CRYPTO("serpent");