164d85cc9SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2*dbb153c0SAditya Srivastava /*
38c755aceSMarcelo H. Cerri * AES CBC routines supporting VMX instructions on the Power 8
48c755aceSMarcelo H. Cerri *
58c755aceSMarcelo H. Cerri * Copyright (C) 2015 International Business Machines Inc.
68c755aceSMarcelo H. Cerri *
78c755aceSMarcelo H. Cerri * Author: Marcelo Henrique Cerri <mhcerri@br.ibm.com>
88c755aceSMarcelo H. Cerri */
98c755aceSMarcelo H. Cerri
10626ddb2fSEric Biggers #include <asm/simd.h>
118c755aceSMarcelo H. Cerri #include <asm/switch_to.h>
128c755aceSMarcelo H. Cerri #include <crypto/aes.h>
13626ddb2fSEric Biggers #include <crypto/internal/simd.h>
142621a869SEric Biggers #include <crypto/internal/skcipher.h>
158c755aceSMarcelo H. Cerri
168c755aceSMarcelo H. Cerri #include "aesp8-ppc.h"
178c755aceSMarcelo H. Cerri
188c755aceSMarcelo H. Cerri struct p8_aes_cbc_ctx {
192621a869SEric Biggers struct crypto_skcipher *fallback;
208c755aceSMarcelo H. Cerri struct aes_key enc_key;
218c755aceSMarcelo H. Cerri struct aes_key dec_key;
228c755aceSMarcelo H. Cerri };
238c755aceSMarcelo H. Cerri
p8_aes_cbc_init(struct crypto_skcipher * tfm)242621a869SEric Biggers static int p8_aes_cbc_init(struct crypto_skcipher *tfm)
258c755aceSMarcelo H. Cerri {
262621a869SEric Biggers struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
272621a869SEric Biggers struct crypto_skcipher *fallback;
288c755aceSMarcelo H. Cerri
292621a869SEric Biggers fallback = crypto_alloc_skcipher("cbc(aes)", 0,
302621a869SEric Biggers CRYPTO_ALG_NEED_FALLBACK |
312621a869SEric Biggers CRYPTO_ALG_ASYNC);
328c755aceSMarcelo H. Cerri if (IS_ERR(fallback)) {
332621a869SEric Biggers pr_err("Failed to allocate cbc(aes) fallback: %ld\n",
342621a869SEric Biggers PTR_ERR(fallback));
358c755aceSMarcelo H. Cerri return PTR_ERR(fallback);
368c755aceSMarcelo H. Cerri }
37c96d0a1cSPaulo Flabiano Smorigo
382621a869SEric Biggers crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
392621a869SEric Biggers crypto_skcipher_reqsize(fallback));
408c755aceSMarcelo H. Cerri ctx->fallback = fallback;
418c755aceSMarcelo H. Cerri return 0;
428c755aceSMarcelo H. Cerri }
438c755aceSMarcelo H. Cerri
p8_aes_cbc_exit(struct crypto_skcipher * tfm)442621a869SEric Biggers static void p8_aes_cbc_exit(struct crypto_skcipher *tfm)
458c755aceSMarcelo H. Cerri {
462621a869SEric Biggers struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
478c755aceSMarcelo H. Cerri
482621a869SEric Biggers crypto_free_skcipher(ctx->fallback);
498c755aceSMarcelo H. Cerri }
508c755aceSMarcelo H. Cerri
p8_aes_cbc_setkey(struct crypto_skcipher * tfm,const u8 * key,unsigned int keylen)512621a869SEric Biggers static int p8_aes_cbc_setkey(struct crypto_skcipher *tfm, const u8 *key,
528c755aceSMarcelo H. Cerri unsigned int keylen)
538c755aceSMarcelo H. Cerri {
542621a869SEric Biggers struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
558c755aceSMarcelo H. Cerri int ret;
568c755aceSMarcelo H. Cerri
575f76eea8SDavid Hildenbrand preempt_disable();
588c755aceSMarcelo H. Cerri pagefault_disable();
592d6f0600SLeonidas Da Silva Barbosa enable_kernel_vsx();
608c755aceSMarcelo H. Cerri ret = aes_p8_set_encrypt_key(key, keylen * 8, &ctx->enc_key);
61694e0db6SEric Biggers ret |= aes_p8_set_decrypt_key(key, keylen * 8, &ctx->dec_key);
62dc4fbba1SAnton Blanchard disable_kernel_vsx();
638c755aceSMarcelo H. Cerri pagefault_enable();
645f76eea8SDavid Hildenbrand preempt_enable();
658c755aceSMarcelo H. Cerri
662621a869SEric Biggers ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen);
67694e0db6SEric Biggers
68694e0db6SEric Biggers return ret ? -EINVAL : 0;
698c755aceSMarcelo H. Cerri }
708c755aceSMarcelo H. Cerri
p8_aes_cbc_crypt(struct skcipher_request * req,int enc)712621a869SEric Biggers static int p8_aes_cbc_crypt(struct skcipher_request *req, int enc)
728c755aceSMarcelo H. Cerri {
732621a869SEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
742621a869SEric Biggers const struct p8_aes_cbc_ctx *ctx = crypto_skcipher_ctx(tfm);
752621a869SEric Biggers struct skcipher_walk walk;
762621a869SEric Biggers unsigned int nbytes;
778c755aceSMarcelo H. Cerri int ret;
788c755aceSMarcelo H. Cerri
79626ddb2fSEric Biggers if (!crypto_simd_usable()) {
802621a869SEric Biggers struct skcipher_request *subreq = skcipher_request_ctx(req);
812621a869SEric Biggers
822621a869SEric Biggers *subreq = *req;
832621a869SEric Biggers skcipher_request_set_tfm(subreq, ctx->fallback);
842621a869SEric Biggers return enc ? crypto_skcipher_encrypt(subreq) :
852621a869SEric Biggers crypto_skcipher_decrypt(subreq);
862621a869SEric Biggers }
872621a869SEric Biggers
882621a869SEric Biggers ret = skcipher_walk_virt(&walk, req, false);
892621a869SEric Biggers while ((nbytes = walk.nbytes) != 0) {
900522236dSOndrej Mosnacek preempt_disable();
910522236dSOndrej Mosnacek pagefault_disable();
920522236dSOndrej Mosnacek enable_kernel_vsx();
934beb1060SHerbert Xu aes_p8_cbc_encrypt(walk.src.virt.addr,
944beb1060SHerbert Xu walk.dst.virt.addr,
952621a869SEric Biggers round_down(nbytes, AES_BLOCK_SIZE),
962621a869SEric Biggers enc ? &ctx->enc_key : &ctx->dec_key,
972621a869SEric Biggers walk.iv, enc);
98dc4fbba1SAnton Blanchard disable_kernel_vsx();
998c755aceSMarcelo H. Cerri pagefault_enable();
1005f76eea8SDavid Hildenbrand preempt_enable();
1010522236dSOndrej Mosnacek
1022621a869SEric Biggers ret = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
1030522236dSOndrej Mosnacek }
1048c755aceSMarcelo H. Cerri return ret;
1058c755aceSMarcelo H. Cerri }
1068c755aceSMarcelo H. Cerri
p8_aes_cbc_encrypt(struct skcipher_request * req)1072621a869SEric Biggers static int p8_aes_cbc_encrypt(struct skcipher_request *req)
1088c755aceSMarcelo H. Cerri {
1092621a869SEric Biggers return p8_aes_cbc_crypt(req, 1);
1108c755aceSMarcelo H. Cerri }
1118c755aceSMarcelo H. Cerri
p8_aes_cbc_decrypt(struct skcipher_request * req)1122621a869SEric Biggers static int p8_aes_cbc_decrypt(struct skcipher_request *req)
1132621a869SEric Biggers {
1142621a869SEric Biggers return p8_aes_cbc_crypt(req, 0);
1158c755aceSMarcelo H. Cerri }
1168c755aceSMarcelo H. Cerri
1172621a869SEric Biggers struct skcipher_alg p8_aes_cbc_alg = {
1182621a869SEric Biggers .base.cra_name = "cbc(aes)",
1192621a869SEric Biggers .base.cra_driver_name = "p8_aes_cbc",
1202621a869SEric Biggers .base.cra_module = THIS_MODULE,
1212621a869SEric Biggers .base.cra_priority = 2000,
1222621a869SEric Biggers .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK,
1232621a869SEric Biggers .base.cra_blocksize = AES_BLOCK_SIZE,
1242621a869SEric Biggers .base.cra_ctxsize = sizeof(struct p8_aes_cbc_ctx),
1258c755aceSMarcelo H. Cerri .setkey = p8_aes_cbc_setkey,
1268c755aceSMarcelo H. Cerri .encrypt = p8_aes_cbc_encrypt,
1278c755aceSMarcelo H. Cerri .decrypt = p8_aes_cbc_decrypt,
1282621a869SEric Biggers .init = p8_aes_cbc_init,
1292621a869SEric Biggers .exit = p8_aes_cbc_exit,
1302621a869SEric Biggers .min_keysize = AES_MIN_KEY_SIZE,
1312621a869SEric Biggers .max_keysize = AES_MAX_KEY_SIZE,
1322621a869SEric Biggers .ivsize = AES_BLOCK_SIZE,
1338c755aceSMarcelo H. Cerri };
134