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 18 struct p8_aes_cbc_ctx { 19 struct crypto_skcipher *fallback; 20 struct aes_key enc_key; 21 struct aes_key dec_key; 22 }; 23 24 static 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 44 static 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 51 static 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 71 static 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 107 static int p8_aes_cbc_encrypt(struct skcipher_request *req) 108 { 109 return p8_aes_cbc_crypt(req, 1); 110 } 111 112 static int p8_aes_cbc_decrypt(struct skcipher_request *req) 113 { 114 return p8_aes_cbc_crypt(req, 0); 115 } 116 117 struct 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.