linux/arch/x86/crypto/serpent_sse2_glue.c
<<
>>
Prefs
   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 * CTR part based on code (crypto/ctr.c) by:
  14 *   (C) Copyright IBM Corp. 2007 - Joy Latten <latten@us.ibm.com>
  15 */
  16
  17#include <linux/module.h>
  18#include <linux/types.h>
  19#include <linux/crypto.h>
  20#include <linux/err.h>
  21#include <crypto/algapi.h>
  22#include <crypto/b128ops.h>
  23#include <crypto/internal/simd.h>
  24#include <crypto/serpent.h>
  25#include <asm/crypto/serpent-sse2.h>
  26#include <asm/crypto/glue_helper.h>
  27
  28static int serpent_setkey_skcipher(struct crypto_skcipher *tfm,
  29                                   const u8 *key, unsigned int keylen)
  30{
  31        return __serpent_setkey(crypto_skcipher_ctx(tfm), key, keylen);
  32}
  33
  34static void serpent_decrypt_cbc_xway(const void *ctx, u8 *d, const u8 *s)
  35{
  36        u128 ivs[SERPENT_PARALLEL_BLOCKS - 1];
  37        u128 *dst = (u128 *)d;
  38        const u128 *src = (const u128 *)s;
  39        unsigned int j;
  40
  41        for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++)
  42                ivs[j] = src[j];
  43
  44        serpent_dec_blk_xway(ctx, (u8 *)dst, (u8 *)src);
  45
  46        for (j = 0; j < SERPENT_PARALLEL_BLOCKS - 1; j++)
  47                u128_xor(dst + (j + 1), dst + (j + 1), ivs + j);
  48}
  49
  50static void serpent_crypt_ctr(const void *ctx, u8 *d, const u8 *s, le128 *iv)
  51{
  52        be128 ctrblk;
  53        u128 *dst = (u128 *)d;
  54        const u128 *src = (const u128 *)s;
  55
  56        le128_to_be128(&ctrblk, iv);
  57        le128_inc(iv);
  58
  59        __serpent_encrypt(ctx, (u8 *)&ctrblk, (u8 *)&ctrblk);
  60        u128_xor(dst, src, (u128 *)&ctrblk);
  61}
  62
  63static void serpent_crypt_ctr_xway(const void *ctx, u8 *d, const u8 *s,
  64                                   le128 *iv)
  65{
  66        be128 ctrblks[SERPENT_PARALLEL_BLOCKS];
  67        u128 *dst = (u128 *)d;
  68        const u128 *src = (const u128 *)s;
  69        unsigned int i;
  70
  71        for (i = 0; i < SERPENT_PARALLEL_BLOCKS; i++) {
  72                if (dst != src)
  73                        dst[i] = src[i];
  74
  75                le128_to_be128(&ctrblks[i], iv);
  76                le128_inc(iv);
  77        }
  78
  79        serpent_enc_blk_xway_xor(ctx, (u8 *)dst, (u8 *)ctrblks);
  80}
  81
  82static const struct common_glue_ctx serpent_enc = {
  83        .num_funcs = 2,
  84        .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
  85
  86        .funcs = { {
  87                .num_blocks = SERPENT_PARALLEL_BLOCKS,
  88                .fn_u = { .ecb = serpent_enc_blk_xway }
  89        }, {
  90                .num_blocks = 1,
  91                .fn_u = { .ecb = __serpent_encrypt }
  92        } }
  93};
  94
  95static const struct common_glue_ctx serpent_ctr = {
  96        .num_funcs = 2,
  97        .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
  98
  99        .funcs = { {
 100                .num_blocks = SERPENT_PARALLEL_BLOCKS,
 101                .fn_u = { .ctr = serpent_crypt_ctr_xway }
 102        }, {
 103                .num_blocks = 1,
 104                .fn_u = { .ctr = serpent_crypt_ctr }
 105        } }
 106};
 107
 108static const struct common_glue_ctx serpent_dec = {
 109        .num_funcs = 2,
 110        .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
 111
 112        .funcs = { {
 113                .num_blocks = SERPENT_PARALLEL_BLOCKS,
 114                .fn_u = { .ecb = serpent_dec_blk_xway }
 115        }, {
 116                .num_blocks = 1,
 117                .fn_u = { .ecb = __serpent_decrypt }
 118        } }
 119};
 120
 121static const struct common_glue_ctx serpent_dec_cbc = {
 122        .num_funcs = 2,
 123        .fpu_blocks_limit = SERPENT_PARALLEL_BLOCKS,
 124
 125        .funcs = { {
 126                .num_blocks = SERPENT_PARALLEL_BLOCKS,
 127                .fn_u = { .cbc = serpent_decrypt_cbc_xway }
 128        }, {
 129                .num_blocks = 1,
 130                .fn_u = { .cbc = __serpent_decrypt }
 131        } }
 132};
 133
 134static int ecb_encrypt(struct skcipher_request *req)
 135{
 136        return glue_ecb_req_128bit(&serpent_enc, req);
 137}
 138
 139static int ecb_decrypt(struct skcipher_request *req)
 140{
 141        return glue_ecb_req_128bit(&serpent_dec, req);
 142}
 143
 144static int cbc_encrypt(struct skcipher_request *req)
 145{
 146        return glue_cbc_encrypt_req_128bit(__serpent_encrypt,
 147                                           req);
 148}
 149
 150static int cbc_decrypt(struct skcipher_request *req)
 151{
 152        return glue_cbc_decrypt_req_128bit(&serpent_dec_cbc, req);
 153}
 154
 155static int ctr_crypt(struct skcipher_request *req)
 156{
 157        return glue_ctr_req_128bit(&serpent_ctr, req);
 158}
 159
 160static struct skcipher_alg serpent_algs[] = {
 161        {
 162                .base.cra_name          = "__ecb(serpent)",
 163                .base.cra_driver_name   = "__ecb-serpent-sse2",
 164                .base.cra_priority      = 400,
 165                .base.cra_flags         = CRYPTO_ALG_INTERNAL,
 166                .base.cra_blocksize     = SERPENT_BLOCK_SIZE,
 167                .base.cra_ctxsize       = sizeof(struct serpent_ctx),
 168                .base.cra_module        = THIS_MODULE,
 169                .min_keysize            = SERPENT_MIN_KEY_SIZE,
 170                .max_keysize            = SERPENT_MAX_KEY_SIZE,
 171                .setkey                 = serpent_setkey_skcipher,
 172                .encrypt                = ecb_encrypt,
 173                .decrypt                = ecb_decrypt,
 174        }, {
 175                .base.cra_name          = "__cbc(serpent)",
 176                .base.cra_driver_name   = "__cbc-serpent-sse2",
 177                .base.cra_priority      = 400,
 178                .base.cra_flags         = CRYPTO_ALG_INTERNAL,
 179                .base.cra_blocksize     = SERPENT_BLOCK_SIZE,
 180                .base.cra_ctxsize       = sizeof(struct serpent_ctx),
 181                .base.cra_module        = THIS_MODULE,
 182                .min_keysize            = SERPENT_MIN_KEY_SIZE,
 183                .max_keysize            = SERPENT_MAX_KEY_SIZE,
 184                .ivsize                 = SERPENT_BLOCK_SIZE,
 185                .setkey                 = serpent_setkey_skcipher,
 186                .encrypt                = cbc_encrypt,
 187                .decrypt                = cbc_decrypt,
 188        }, {
 189                .base.cra_name          = "__ctr(serpent)",
 190                .base.cra_driver_name   = "__ctr-serpent-sse2",
 191                .base.cra_priority      = 400,
 192                .base.cra_flags         = CRYPTO_ALG_INTERNAL,
 193                .base.cra_blocksize     = 1,
 194                .base.cra_ctxsize       = sizeof(struct serpent_ctx),
 195                .base.cra_module        = THIS_MODULE,
 196                .min_keysize            = SERPENT_MIN_KEY_SIZE,
 197                .max_keysize            = SERPENT_MAX_KEY_SIZE,
 198                .ivsize                 = SERPENT_BLOCK_SIZE,
 199                .chunksize              = SERPENT_BLOCK_SIZE,
 200                .setkey                 = serpent_setkey_skcipher,
 201                .encrypt                = ctr_crypt,
 202                .decrypt                = ctr_crypt,
 203        },
 204};
 205
 206static struct simd_skcipher_alg *serpent_simd_algs[ARRAY_SIZE(serpent_algs)];
 207
 208static int __init serpent_sse2_init(void)
 209{
 210        if (!boot_cpu_has(X86_FEATURE_XMM2)) {
 211                printk(KERN_INFO "SSE2 instructions are not detected.\n");
 212                return -ENODEV;
 213        }
 214
 215        return simd_register_skciphers_compat(serpent_algs,
 216                                              ARRAY_SIZE(serpent_algs),
 217                                              serpent_simd_algs);
 218}
 219
 220static void __exit serpent_sse2_exit(void)
 221{
 222        simd_unregister_skciphers(serpent_algs, ARRAY_SIZE(serpent_algs),
 223                                  serpent_simd_algs);
 224}
 225
 226module_init(serpent_sse2_init);
 227module_exit(serpent_sse2_exit);
 228
 229MODULE_DESCRIPTION("Serpent Cipher Algorithm, SSE2 optimized");
 230MODULE_LICENSE("GPL");
 231MODULE_ALIAS_CRYPTO("serpent");
 232