xref: /openbmc/linux/drivers/crypto/vmx/aes_cbc.c (revision dbb153c0)
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