linux/arch/x86/crypto/des3_ede_glue.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Glue Code for assembler optimized version of 3DES
   4 *
   5 * Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@mbnet.fi>
   6 *
   7 * CBC & ECB parts based on code (crypto/cbc.c,ecb.c) by:
   8 *   Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
   9 */
  10
  11#include <crypto/algapi.h>
  12#include <crypto/des.h>
  13#include <crypto/internal/skcipher.h>
  14#include <linux/crypto.h>
  15#include <linux/init.h>
  16#include <linux/module.h>
  17#include <linux/types.h>
  18
  19struct des3_ede_x86_ctx {
  20        struct des3_ede_ctx enc;
  21        struct des3_ede_ctx dec;
  22};
  23
  24/* regular block cipher functions */
  25asmlinkage void des3_ede_x86_64_crypt_blk(const u32 *expkey, u8 *dst,
  26                                          const u8 *src);
  27
  28/* 3-way parallel cipher functions */
  29asmlinkage void des3_ede_x86_64_crypt_blk_3way(const u32 *expkey, u8 *dst,
  30                                               const u8 *src);
  31
  32static inline void des3_ede_enc_blk(struct des3_ede_x86_ctx *ctx, u8 *dst,
  33                                    const u8 *src)
  34{
  35        u32 *enc_ctx = ctx->enc.expkey;
  36
  37        des3_ede_x86_64_crypt_blk(enc_ctx, dst, src);
  38}
  39
  40static inline void des3_ede_dec_blk(struct des3_ede_x86_ctx *ctx, u8 *dst,
  41                                    const u8 *src)
  42{
  43        u32 *dec_ctx = ctx->dec.expkey;
  44
  45        des3_ede_x86_64_crypt_blk(dec_ctx, dst, src);
  46}
  47
  48static inline void des3_ede_enc_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst,
  49                                         const u8 *src)
  50{
  51        u32 *enc_ctx = ctx->enc.expkey;
  52
  53        des3_ede_x86_64_crypt_blk_3way(enc_ctx, dst, src);
  54}
  55
  56static inline void des3_ede_dec_blk_3way(struct des3_ede_x86_ctx *ctx, u8 *dst,
  57                                         const u8 *src)
  58{
  59        u32 *dec_ctx = ctx->dec.expkey;
  60
  61        des3_ede_x86_64_crypt_blk_3way(dec_ctx, dst, src);
  62}
  63
  64static void des3_ede_x86_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
  65{
  66        des3_ede_enc_blk(crypto_tfm_ctx(tfm), dst, src);
  67}
  68
  69static void des3_ede_x86_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
  70{
  71        des3_ede_dec_blk(crypto_tfm_ctx(tfm), dst, src);
  72}
  73
  74static int ecb_crypt(struct skcipher_request *req, const u32 *expkey)
  75{
  76        const unsigned int bsize = DES3_EDE_BLOCK_SIZE;
  77        struct skcipher_walk walk;
  78        unsigned int nbytes;
  79        int err;
  80
  81        err = skcipher_walk_virt(&walk, req, false);
  82
  83        while ((nbytes = walk.nbytes)) {
  84                u8 *wsrc = walk.src.virt.addr;
  85                u8 *wdst = walk.dst.virt.addr;
  86
  87                /* Process four block batch */
  88                if (nbytes >= bsize * 3) {
  89                        do {
  90                                des3_ede_x86_64_crypt_blk_3way(expkey, wdst,
  91                                                               wsrc);
  92
  93                                wsrc += bsize * 3;
  94                                wdst += bsize * 3;
  95                                nbytes -= bsize * 3;
  96                        } while (nbytes >= bsize * 3);
  97
  98                        if (nbytes < bsize)
  99                                goto done;
 100                }
 101
 102                /* Handle leftovers */
 103                do {
 104                        des3_ede_x86_64_crypt_blk(expkey, wdst, wsrc);
 105
 106                        wsrc += bsize;
 107                        wdst += bsize;
 108                        nbytes -= bsize;
 109                } while (nbytes >= bsize);
 110
 111done:
 112                err = skcipher_walk_done(&walk, nbytes);
 113        }
 114
 115        return err;
 116}
 117
 118static int ecb_encrypt(struct skcipher_request *req)
 119{
 120        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 121        struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
 122
 123        return ecb_crypt(req, ctx->enc.expkey);
 124}
 125
 126static int ecb_decrypt(struct skcipher_request *req)
 127{
 128        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 129        struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
 130
 131        return ecb_crypt(req, ctx->dec.expkey);
 132}
 133
 134static unsigned int __cbc_encrypt(struct des3_ede_x86_ctx *ctx,
 135                                  struct skcipher_walk *walk)
 136{
 137        unsigned int bsize = DES3_EDE_BLOCK_SIZE;
 138        unsigned int nbytes = walk->nbytes;
 139        u64 *src = (u64 *)walk->src.virt.addr;
 140        u64 *dst = (u64 *)walk->dst.virt.addr;
 141        u64 *iv = (u64 *)walk->iv;
 142
 143        do {
 144                *dst = *src ^ *iv;
 145                des3_ede_enc_blk(ctx, (u8 *)dst, (u8 *)dst);
 146                iv = dst;
 147
 148                src += 1;
 149                dst += 1;
 150                nbytes -= bsize;
 151        } while (nbytes >= bsize);
 152
 153        *(u64 *)walk->iv = *iv;
 154        return nbytes;
 155}
 156
 157static int cbc_encrypt(struct skcipher_request *req)
 158{
 159        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 160        struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
 161        struct skcipher_walk walk;
 162        unsigned int nbytes;
 163        int err;
 164
 165        err = skcipher_walk_virt(&walk, req, false);
 166
 167        while ((nbytes = walk.nbytes)) {
 168                nbytes = __cbc_encrypt(ctx, &walk);
 169                err = skcipher_walk_done(&walk, nbytes);
 170        }
 171
 172        return err;
 173}
 174
 175static unsigned int __cbc_decrypt(struct des3_ede_x86_ctx *ctx,
 176                                  struct skcipher_walk *walk)
 177{
 178        unsigned int bsize = DES3_EDE_BLOCK_SIZE;
 179        unsigned int nbytes = walk->nbytes;
 180        u64 *src = (u64 *)walk->src.virt.addr;
 181        u64 *dst = (u64 *)walk->dst.virt.addr;
 182        u64 ivs[3 - 1];
 183        u64 last_iv;
 184
 185        /* Start of the last block. */
 186        src += nbytes / bsize - 1;
 187        dst += nbytes / bsize - 1;
 188
 189        last_iv = *src;
 190
 191        /* Process four block batch */
 192        if (nbytes >= bsize * 3) {
 193                do {
 194                        nbytes -= bsize * 3 - bsize;
 195                        src -= 3 - 1;
 196                        dst -= 3 - 1;
 197
 198                        ivs[0] = src[0];
 199                        ivs[1] = src[1];
 200
 201                        des3_ede_dec_blk_3way(ctx, (u8 *)dst, (u8 *)src);
 202
 203                        dst[1] ^= ivs[0];
 204                        dst[2] ^= ivs[1];
 205
 206                        nbytes -= bsize;
 207                        if (nbytes < bsize)
 208                                goto done;
 209
 210                        *dst ^= *(src - 1);
 211                        src -= 1;
 212                        dst -= 1;
 213                } while (nbytes >= bsize * 3);
 214        }
 215
 216        /* Handle leftovers */
 217        for (;;) {
 218                des3_ede_dec_blk(ctx, (u8 *)dst, (u8 *)src);
 219
 220                nbytes -= bsize;
 221                if (nbytes < bsize)
 222                        break;
 223
 224                *dst ^= *(src - 1);
 225                src -= 1;
 226                dst -= 1;
 227        }
 228
 229done:
 230        *dst ^= *(u64 *)walk->iv;
 231        *(u64 *)walk->iv = last_iv;
 232
 233        return nbytes;
 234}
 235
 236static int cbc_decrypt(struct skcipher_request *req)
 237{
 238        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
 239        struct des3_ede_x86_ctx *ctx = crypto_skcipher_ctx(tfm);
 240        struct skcipher_walk walk;
 241        unsigned int nbytes;
 242        int err;
 243
 244        err = skcipher_walk_virt(&walk, req, false);
 245
 246        while ((nbytes = walk.nbytes)) {
 247                nbytes = __cbc_decrypt(ctx, &walk);
 248                err = skcipher_walk_done(&walk, nbytes);
 249        }
 250
 251        return err;
 252}
 253
 254static int des3_ede_x86_setkey(struct crypto_tfm *tfm, const u8 *key,
 255                               unsigned int keylen)
 256{
 257        struct des3_ede_x86_ctx *ctx = crypto_tfm_ctx(tfm);
 258        u32 i, j, tmp;
 259        int err;
 260
 261        err = des3_ede_expand_key(&ctx->enc, key, keylen);
 262        if (err == -ENOKEY) {
 263                if (crypto_tfm_get_flags(tfm) & CRYPTO_TFM_REQ_FORBID_WEAK_KEYS)
 264                        err = -EINVAL;
 265                else
 266                        err = 0;
 267        }
 268
 269        if (err) {
 270                memset(ctx, 0, sizeof(*ctx));
 271                return err;
 272        }
 273
 274        /* Fix encryption context for this implementation and form decryption
 275         * context. */
 276        j = DES3_EDE_EXPKEY_WORDS - 2;
 277        for (i = 0; i < DES3_EDE_EXPKEY_WORDS; i += 2, j -= 2) {
 278                tmp = ror32(ctx->enc.expkey[i + 1], 4);
 279                ctx->enc.expkey[i + 1] = tmp;
 280
 281                ctx->dec.expkey[j + 0] = ctx->enc.expkey[i + 0];
 282                ctx->dec.expkey[j + 1] = tmp;
 283        }
 284
 285        return 0;
 286}
 287
 288static int des3_ede_x86_setkey_skcipher(struct crypto_skcipher *tfm,
 289                                        const u8 *key,
 290                                        unsigned int keylen)
 291{
 292        return des3_ede_x86_setkey(&tfm->base, key, keylen);
 293}
 294
 295static struct crypto_alg des3_ede_cipher = {
 296        .cra_name               = "des3_ede",
 297        .cra_driver_name        = "des3_ede-asm",
 298        .cra_priority           = 200,
 299        .cra_flags              = CRYPTO_ALG_TYPE_CIPHER,
 300        .cra_blocksize          = DES3_EDE_BLOCK_SIZE,
 301        .cra_ctxsize            = sizeof(struct des3_ede_x86_ctx),
 302        .cra_alignmask          = 0,
 303        .cra_module             = THIS_MODULE,
 304        .cra_u = {
 305                .cipher = {
 306                        .cia_min_keysize        = DES3_EDE_KEY_SIZE,
 307                        .cia_max_keysize        = DES3_EDE_KEY_SIZE,
 308                        .cia_setkey             = des3_ede_x86_setkey,
 309                        .cia_encrypt            = des3_ede_x86_encrypt,
 310                        .cia_decrypt            = des3_ede_x86_decrypt,
 311                }
 312        }
 313};
 314
 315static struct skcipher_alg des3_ede_skciphers[] = {
 316        {
 317                .base.cra_name          = "ecb(des3_ede)",
 318                .base.cra_driver_name   = "ecb-des3_ede-asm",
 319                .base.cra_priority      = 300,
 320                .base.cra_blocksize     = DES3_EDE_BLOCK_SIZE,
 321                .base.cra_ctxsize       = sizeof(struct des3_ede_x86_ctx),
 322                .base.cra_module        = THIS_MODULE,
 323                .min_keysize            = DES3_EDE_KEY_SIZE,
 324                .max_keysize            = DES3_EDE_KEY_SIZE,
 325                .setkey                 = des3_ede_x86_setkey_skcipher,
 326                .encrypt                = ecb_encrypt,
 327                .decrypt                = ecb_decrypt,
 328        }, {
 329                .base.cra_name          = "cbc(des3_ede)",
 330                .base.cra_driver_name   = "cbc-des3_ede-asm",
 331                .base.cra_priority      = 300,
 332                .base.cra_blocksize     = DES3_EDE_BLOCK_SIZE,
 333                .base.cra_ctxsize       = sizeof(struct des3_ede_x86_ctx),
 334                .base.cra_module        = THIS_MODULE,
 335                .min_keysize            = DES3_EDE_KEY_SIZE,
 336                .max_keysize            = DES3_EDE_KEY_SIZE,
 337                .ivsize                 = DES3_EDE_BLOCK_SIZE,
 338                .setkey                 = des3_ede_x86_setkey_skcipher,
 339                .encrypt                = cbc_encrypt,
 340                .decrypt                = cbc_decrypt,
 341        }
 342};
 343
 344static bool is_blacklisted_cpu(void)
 345{
 346        if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
 347                return false;
 348
 349        if (boot_cpu_data.x86 == 0x0f) {
 350                /*
 351                 * On Pentium 4, des3_ede-x86_64 is slower than generic C
 352                 * implementation because use of 64bit rotates (which are really
 353                 * slow on P4). Therefore blacklist P4s.
 354                 */
 355                return true;
 356        }
 357
 358        return false;
 359}
 360
 361static int force;
 362module_param(force, int, 0);
 363MODULE_PARM_DESC(force, "Force module load, ignore CPU blacklist");
 364
 365static int __init des3_ede_x86_init(void)
 366{
 367        int err;
 368
 369        if (!force && is_blacklisted_cpu()) {
 370                pr_info("des3_ede-x86_64: performance on this CPU would be suboptimal: disabling des3_ede-x86_64.\n");
 371                return -ENODEV;
 372        }
 373
 374        err = crypto_register_alg(&des3_ede_cipher);
 375        if (err)
 376                return err;
 377
 378        err = crypto_register_skciphers(des3_ede_skciphers,
 379                                        ARRAY_SIZE(des3_ede_skciphers));
 380        if (err)
 381                crypto_unregister_alg(&des3_ede_cipher);
 382
 383        return err;
 384}
 385
 386static void __exit des3_ede_x86_fini(void)
 387{
 388        crypto_unregister_alg(&des3_ede_cipher);
 389        crypto_unregister_skciphers(des3_ede_skciphers,
 390                                    ARRAY_SIZE(des3_ede_skciphers));
 391}
 392
 393module_init(des3_ede_x86_init);
 394module_exit(des3_ede_x86_fini);
 395
 396MODULE_LICENSE("GPL");
 397MODULE_DESCRIPTION("Triple DES EDE Cipher Algorithm, asm optimized");
 398MODULE_ALIAS_CRYPTO("des3_ede");
 399MODULE_ALIAS_CRYPTO("des3_ede-asm");
 400MODULE_AUTHOR("Jussi Kivilinna <jussi.kivilinna@iki.fi>");
 401