162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AES XTS routines supporting VMX In-core instructions on Power 8 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2015 International Business Machines Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Author: Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <asm/simd.h> 1162306a36Sopenharmony_ci#include <asm/switch_to.h> 1262306a36Sopenharmony_ci#include <crypto/aes.h> 1362306a36Sopenharmony_ci#include <crypto/internal/simd.h> 1462306a36Sopenharmony_ci#include <crypto/internal/skcipher.h> 1562306a36Sopenharmony_ci#include <crypto/xts.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include "aesp8-ppc.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct p8_aes_xts_ctx { 2062306a36Sopenharmony_ci struct crypto_skcipher *fallback; 2162306a36Sopenharmony_ci struct aes_key enc_key; 2262306a36Sopenharmony_ci struct aes_key dec_key; 2362306a36Sopenharmony_ci struct aes_key tweak_key; 2462306a36Sopenharmony_ci}; 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic int p8_aes_xts_init(struct crypto_skcipher *tfm) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 2962306a36Sopenharmony_ci struct crypto_skcipher *fallback; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci fallback = crypto_alloc_skcipher("xts(aes)", 0, 3262306a36Sopenharmony_ci CRYPTO_ALG_NEED_FALLBACK | 3362306a36Sopenharmony_ci CRYPTO_ALG_ASYNC); 3462306a36Sopenharmony_ci if (IS_ERR(fallback)) { 3562306a36Sopenharmony_ci pr_err("Failed to allocate xts(aes) fallback: %ld\n", 3662306a36Sopenharmony_ci PTR_ERR(fallback)); 3762306a36Sopenharmony_ci return PTR_ERR(fallback); 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) + 4162306a36Sopenharmony_ci crypto_skcipher_reqsize(fallback)); 4262306a36Sopenharmony_ci ctx->fallback = fallback; 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void p8_aes_xts_exit(struct crypto_skcipher *tfm) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci crypto_free_skcipher(ctx->fallback); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int p8_aes_xts_setkey(struct crypto_skcipher *tfm, const u8 *key, 5462306a36Sopenharmony_ci unsigned int keylen) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 5762306a36Sopenharmony_ci int ret; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci ret = xts_verify_key(tfm, key, keylen); 6062306a36Sopenharmony_ci if (ret) 6162306a36Sopenharmony_ci return ret; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci preempt_disable(); 6462306a36Sopenharmony_ci pagefault_disable(); 6562306a36Sopenharmony_ci enable_kernel_vsx(); 6662306a36Sopenharmony_ci ret = aes_p8_set_encrypt_key(key + keylen/2, (keylen/2) * 8, &ctx->tweak_key); 6762306a36Sopenharmony_ci ret |= aes_p8_set_encrypt_key(key, (keylen/2) * 8, &ctx->enc_key); 6862306a36Sopenharmony_ci ret |= aes_p8_set_decrypt_key(key, (keylen/2) * 8, &ctx->dec_key); 6962306a36Sopenharmony_ci disable_kernel_vsx(); 7062306a36Sopenharmony_ci pagefault_enable(); 7162306a36Sopenharmony_ci preempt_enable(); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return ret ? -EINVAL : 0; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cistatic int p8_aes_xts_crypt(struct skcipher_request *req, int enc) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); 8162306a36Sopenharmony_ci const struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm); 8262306a36Sopenharmony_ci struct skcipher_walk walk; 8362306a36Sopenharmony_ci unsigned int nbytes; 8462306a36Sopenharmony_ci u8 tweak[AES_BLOCK_SIZE]; 8562306a36Sopenharmony_ci int ret; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci if (req->cryptlen < AES_BLOCK_SIZE) 8862306a36Sopenharmony_ci return -EINVAL; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (!crypto_simd_usable() || (req->cryptlen % XTS_BLOCK_SIZE) != 0) { 9162306a36Sopenharmony_ci struct skcipher_request *subreq = skcipher_request_ctx(req); 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci *subreq = *req; 9462306a36Sopenharmony_ci skcipher_request_set_tfm(subreq, ctx->fallback); 9562306a36Sopenharmony_ci return enc ? crypto_skcipher_encrypt(subreq) : 9662306a36Sopenharmony_ci crypto_skcipher_decrypt(subreq); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci ret = skcipher_walk_virt(&walk, req, false); 10062306a36Sopenharmony_ci if (ret) 10162306a36Sopenharmony_ci return ret; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci preempt_disable(); 10462306a36Sopenharmony_ci pagefault_disable(); 10562306a36Sopenharmony_ci enable_kernel_vsx(); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci aes_p8_encrypt(walk.iv, tweak, &ctx->tweak_key); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci disable_kernel_vsx(); 11062306a36Sopenharmony_ci pagefault_enable(); 11162306a36Sopenharmony_ci preempt_enable(); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci while ((nbytes = walk.nbytes) != 0) { 11462306a36Sopenharmony_ci preempt_disable(); 11562306a36Sopenharmony_ci pagefault_disable(); 11662306a36Sopenharmony_ci enable_kernel_vsx(); 11762306a36Sopenharmony_ci if (enc) 11862306a36Sopenharmony_ci aes_p8_xts_encrypt(walk.src.virt.addr, 11962306a36Sopenharmony_ci walk.dst.virt.addr, 12062306a36Sopenharmony_ci round_down(nbytes, AES_BLOCK_SIZE), 12162306a36Sopenharmony_ci &ctx->enc_key, NULL, tweak); 12262306a36Sopenharmony_ci else 12362306a36Sopenharmony_ci aes_p8_xts_decrypt(walk.src.virt.addr, 12462306a36Sopenharmony_ci walk.dst.virt.addr, 12562306a36Sopenharmony_ci round_down(nbytes, AES_BLOCK_SIZE), 12662306a36Sopenharmony_ci &ctx->dec_key, NULL, tweak); 12762306a36Sopenharmony_ci disable_kernel_vsx(); 12862306a36Sopenharmony_ci pagefault_enable(); 12962306a36Sopenharmony_ci preempt_enable(); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci ret = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE); 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci return ret; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int p8_aes_xts_encrypt(struct skcipher_request *req) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci return p8_aes_xts_crypt(req, 1); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic int p8_aes_xts_decrypt(struct skcipher_request *req) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci return p8_aes_xts_crypt(req, 0); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistruct skcipher_alg p8_aes_xts_alg = { 14762306a36Sopenharmony_ci .base.cra_name = "xts(aes)", 14862306a36Sopenharmony_ci .base.cra_driver_name = "p8_aes_xts", 14962306a36Sopenharmony_ci .base.cra_module = THIS_MODULE, 15062306a36Sopenharmony_ci .base.cra_priority = 2000, 15162306a36Sopenharmony_ci .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK, 15262306a36Sopenharmony_ci .base.cra_blocksize = AES_BLOCK_SIZE, 15362306a36Sopenharmony_ci .base.cra_ctxsize = sizeof(struct p8_aes_xts_ctx), 15462306a36Sopenharmony_ci .setkey = p8_aes_xts_setkey, 15562306a36Sopenharmony_ci .encrypt = p8_aes_xts_encrypt, 15662306a36Sopenharmony_ci .decrypt = p8_aes_xts_decrypt, 15762306a36Sopenharmony_ci .init = p8_aes_xts_init, 15862306a36Sopenharmony_ci .exit = p8_aes_xts_exit, 15962306a36Sopenharmony_ci .min_keysize = 2 * AES_MIN_KEY_SIZE, 16062306a36Sopenharmony_ci .max_keysize = 2 * AES_MAX_KEY_SIZE, 16162306a36Sopenharmony_ci .ivsize = AES_BLOCK_SIZE, 16262306a36Sopenharmony_ci}; 163