linux/drivers/crypto/vmx/aes_cbc.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * AES CBC routines supporting VMX instructions on the Power 8
   4 *
   5 * Copyright (C) 2015 International Business Machines Inc.
   6 *
   7 * Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com>
   8 */
   9
  10#include <asm/simd.h>
  11#include <asm/switch_to.h>
  12#include <crypto/aes.h>
  13#include <crypto/internal/simd.h>
  14#include <crypto/internal/skcipher.h>
  15
  16#include "aesp8-ppc.h"
  17
  18struct p8_aes_cbc_ctx {
  19        struct crypto_skcipher *fallback;
  20        struct aes_key enc_key;
  21        struct aes_key dec_key;
  22};
  23
  24static int p8_aes_cbc_init(struct crypto_skcipher *tfm)
  25{
  26        struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
  27        struct crypto_skcipher *fallback;
  28
  29        fallback = crypto_alloc_skcipher("cbc(aes)", 0,
  30                                         CRYPTO_ALG_NEED_FALLBACK |
  31                                         CRYPTO_ALG_ASYNC);
  32        if (IS_ERR(fallback)) {
  33                pr_err("Failed to allocate cbc(aes) fallback: %ld\n",
  34                       PTR_ERR(fallback));
  35                return PTR_ERR(fallback);
  36        }
  37
  38        crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
  39                                    crypto_skcipher_reqsize(fallback));
  40        ctx->fallback = fallback;
  41        return 0;
  42}
  43
  44static void p8_aes_cbc_exit(struct crypto_skcipher *tfm)
  45{
  46        struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
  47
  48        crypto_free_skcipher(ctx->fallback);
  49}
  50
  51static int p8_aes_cbc_setkey(struct crypto_skcipher *tfm, const u8 *key,
  52                             unsigned int keylen)
  53{
  54        struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
  55        int ret;
  56
  57        preempt_disable();
  58        pagefault_disable();
  59        enable_kernel_vsx();
  60        ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
  61        ret |= aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
  62        disable_kernel_vsx();
  63        pagefault_enable();
  64        preempt_enable();
  65
  66        ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen);
  67
  68        return ret ? -EINVAL : 0;
  69}
  70
  71static int p8_aes_cbc_crypt(struct skcipher_request *req, int enc)
  72{
  73        struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
  74        const struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
  75        struct skcipher_walk walk;
  76        unsigned int nbytes;
  77        int ret;
  78
  79        if (!crypto_simd_usable()) {
  80                struct skcipher_request *subreq = skcipher_request_ctx(req);
  81
  82                *subreq = *req;
  83                skcipher_request_set_tfm(subreq, ctx->fallback);
  84                return enc ? crypto_skcipher_encrypt(subreq) :
  85                             crypto_skcipher_decrypt(subreq);
  86        }
  87
  88        ret = skcipher_walk_virt(&walk, req, false);
  89        while ((nbytes = walk.nbytes) != 0) {
  90                preempt_disable();
  91                pagefault_disable();
  92                enable_kernel_vsx();
  93                aes_p8_cbc_encrypt(walk.src.virt.addr,
  94                                   walk.dst.virt.addr,
  95                                   round_down(nbytes, AES_BLOCK_SIZE),
  96                                   enc ? &ctx->enc_key : &ctx->dec_key,
  97                                   walk.iv, enc);
  98                disable_kernel_vsx();
  99                pagefault_enable();
 100                preempt_enable();
 101
 102                ret = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
 103        }
 104        return ret;
 105}
 106
 107static int p8_aes_cbc_encrypt(struct skcipher_request *req)
 108{
 109        return p8_aes_cbc_crypt(req, 1);
 110}
 111
 112static int p8_aes_cbc_decrypt(struct skcipher_request *req)
 113{
 114        return p8_aes_cbc_crypt(req, 0);
 115}
 116
 117struct skcipher_alg p8_aes_cbc_alg = {
 118        .base.cra_name = "cbc(aes)",
 119        .base.cra_driver_name = "p8_aes_cbc",
 120        .base.cra_module = THIS_MODULE,
 121        .base.cra_priority = 2000,
 122        .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK,
 123        .base.cra_blocksize = AES_BLOCK_SIZE,
 124        .base.cra_ctxsize = sizeof(struct p8_aes_cbc_ctx),
 125        .setkey = p8_aes_cbc_setkey,
 126        .encrypt = p8_aes_cbc_encrypt,
 127        .decrypt = p8_aes_cbc_decrypt,
 128        .init = p8_aes_cbc_init,
 129        .exit = p8_aes_cbc_exit,
 130        .min_keysize = AES_MIN_KEY_SIZE,
 131        .max_keysize = AES_MAX_KEY_SIZE,
 132        .ivsize = AES_BLOCK_SIZE,
 133};
 134