127ba4debSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2*dbb153c0SAditya Srivastava /*
3c07f5d3dSLeonidas S. Barbosa * AES XTS routines supporting VMX In-core instructions on Power 8
4c07f5d3dSLeonidas S. Barbosa *
5c07f5d3dSLeonidas S. Barbosa * Copyright (C) 2015 International Business Machines Inc.
6c07f5d3dSLeonidas S. Barbosa *
7c07f5d3dSLeonidas S. Barbosa * Author: Leonidas S. Barbosa <leosilva@linux.vnet.ibm.com>
8c07f5d3dSLeonidas S. Barbosa */
9c07f5d3dSLeonidas S. Barbosa
10626ddb2fSEric Biggers #include <asm/simd.h>
11c07f5d3dSLeonidas S. Barbosa #include <asm/switch_to.h>
12c07f5d3dSLeonidas S. Barbosa #include <crypto/aes.h>
13626ddb2fSEric Biggers #include <crypto/internal/simd.h>
142621a869SEric Biggers #include <crypto/internal/skcipher.h>
15c07f5d3dSLeonidas S. Barbosa #include <crypto/xts.h>
16c07f5d3dSLeonidas S. Barbosa
17c07f5d3dSLeonidas S. Barbosa #include "aesp8-ppc.h"
18c07f5d3dSLeonidas S. Barbosa
19c07f5d3dSLeonidas S. Barbosa struct p8_aes_xts_ctx {
202621a869SEric Biggers struct crypto_skcipher *fallback;
21c07f5d3dSLeonidas S. Barbosa struct aes_key enc_key;
22c07f5d3dSLeonidas S. Barbosa struct aes_key dec_key;
23c07f5d3dSLeonidas S. Barbosa struct aes_key tweak_key;
24c07f5d3dSLeonidas S. Barbosa };
25c07f5d3dSLeonidas S. Barbosa
p8_aes_xts_init(struct crypto_skcipher * tfm)262621a869SEric Biggers static int p8_aes_xts_init(struct crypto_skcipher *tfm)
27c07f5d3dSLeonidas S. Barbosa {
282621a869SEric Biggers struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
292621a869SEric Biggers struct crypto_skcipher *fallback;
30c07f5d3dSLeonidas S. Barbosa
312621a869SEric Biggers fallback = crypto_alloc_skcipher("xts(aes)", 0,
322621a869SEric Biggers CRYPTO_ALG_NEED_FALLBACK |
332621a869SEric Biggers CRYPTO_ALG_ASYNC);
34c07f5d3dSLeonidas S. Barbosa if (IS_ERR(fallback)) {
352621a869SEric Biggers pr_err("Failed to allocate xts(aes) fallback: %ld\n",
362621a869SEric Biggers PTR_ERR(fallback));
37c07f5d3dSLeonidas S. Barbosa return PTR_ERR(fallback);
38c07f5d3dSLeonidas S. Barbosa }
39c07f5d3dSLeonidas S. Barbosa
402621a869SEric Biggers crypto_skcipher_set_reqsize(tfm, sizeof(struct skcipher_request) +
412621a869SEric Biggers crypto_skcipher_reqsize(fallback));
42c07f5d3dSLeonidas S. Barbosa ctx->fallback = fallback;
43c07f5d3dSLeonidas S. Barbosa return 0;
44c07f5d3dSLeonidas S. Barbosa }
45c07f5d3dSLeonidas S. Barbosa
p8_aes_xts_exit(struct crypto_skcipher * tfm)462621a869SEric Biggers static void p8_aes_xts_exit(struct crypto_skcipher *tfm)
47c07f5d3dSLeonidas S. Barbosa {
482621a869SEric Biggers struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
49c07f5d3dSLeonidas S. Barbosa
502621a869SEric Biggers crypto_free_skcipher(ctx->fallback);
51c07f5d3dSLeonidas S. Barbosa }
52c07f5d3dSLeonidas S. Barbosa
p8_aes_xts_setkey(struct crypto_skcipher * tfm,const u8 * key,unsigned int keylen)532621a869SEric Biggers static int p8_aes_xts_setkey(struct crypto_skcipher *tfm, const u8 *key,
54c07f5d3dSLeonidas S. Barbosa unsigned int keylen)
55c07f5d3dSLeonidas S. Barbosa {
562621a869SEric Biggers struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
57c07f5d3dSLeonidas S. Barbosa int ret;
58c07f5d3dSLeonidas S. Barbosa
592621a869SEric Biggers ret = xts_verify_key(tfm, key, keylen);
60c07f5d3dSLeonidas S. Barbosa if (ret)
61c07f5d3dSLeonidas S. Barbosa return ret;
62c07f5d3dSLeonidas S. Barbosa
63c07f5d3dSLeonidas S. Barbosa preempt_disable();
64c07f5d3dSLeonidas S. Barbosa pagefault_disable();
65c07f5d3dSLeonidas S. Barbosa enable_kernel_vsx();
66c07f5d3dSLeonidas S. Barbosa ret = aes_p8_set_encrypt_key(key + keylen/2, (keylen/2) * 8, &ctx->tweak_key);
67694e0db6SEric Biggers ret |= aes_p8_set_encrypt_key(key, (keylen/2) * 8, &ctx->enc_key);
68694e0db6SEric Biggers ret |= aes_p8_set_decrypt_key(key, (keylen/2) * 8, &ctx->dec_key);
69c07f5d3dSLeonidas S. Barbosa disable_kernel_vsx();
70c07f5d3dSLeonidas S. Barbosa pagefault_enable();
71c07f5d3dSLeonidas S. Barbosa preempt_enable();
72c07f5d3dSLeonidas S. Barbosa
732621a869SEric Biggers ret |= crypto_skcipher_setkey(ctx->fallback, key, keylen);
74694e0db6SEric Biggers
75694e0db6SEric Biggers return ret ? -EINVAL : 0;
76c07f5d3dSLeonidas S. Barbosa }
77c07f5d3dSLeonidas S. Barbosa
p8_aes_xts_crypt(struct skcipher_request * req,int enc)782621a869SEric Biggers static int p8_aes_xts_crypt(struct skcipher_request *req, int enc)
79c07f5d3dSLeonidas S. Barbosa {
802621a869SEric Biggers struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
812621a869SEric Biggers const struct p8_aes_xts_ctx *ctx = crypto_skcipher_ctx(tfm);
822621a869SEric Biggers struct skcipher_walk walk;
832621a869SEric Biggers unsigned int nbytes;
84c07f5d3dSLeonidas S. Barbosa u8 tweak[AES_BLOCK_SIZE];
852621a869SEric Biggers int ret;
86c07f5d3dSLeonidas S. Barbosa
871372a51bSDaniel Axtens if (req->cryptlen < AES_BLOCK_SIZE)
881372a51bSDaniel Axtens return -EINVAL;
891372a51bSDaniel Axtens
9023966841SArd Biesheuvel if (!crypto_simd_usable() || (req->cryptlen % XTS_BLOCK_SIZE) != 0) {
912621a869SEric Biggers struct skcipher_request *subreq = skcipher_request_ctx(req);
920522236dSOndrej Mosnacek
932621a869SEric Biggers *subreq = *req;
942621a869SEric Biggers skcipher_request_set_tfm(subreq, ctx->fallback);
952621a869SEric Biggers return enc ? crypto_skcipher_encrypt(subreq) :
962621a869SEric Biggers crypto_skcipher_decrypt(subreq);
972621a869SEric Biggers }
982621a869SEric Biggers
992621a869SEric Biggers ret = skcipher_walk_virt(&walk, req, false);
1002621a869SEric Biggers if (ret)
1012621a869SEric Biggers return ret;
1020522236dSOndrej Mosnacek
103c07f5d3dSLeonidas S. Barbosa preempt_disable();
104c07f5d3dSLeonidas S. Barbosa pagefault_disable();
105c07f5d3dSLeonidas S. Barbosa enable_kernel_vsx();
106c07f5d3dSLeonidas S. Barbosa
1072621a869SEric Biggers aes_p8_encrypt(walk.iv, tweak, &ctx->tweak_key);
108c07f5d3dSLeonidas S. Barbosa
1090522236dSOndrej Mosnacek disable_kernel_vsx();
1100522236dSOndrej Mosnacek pagefault_enable();
1110522236dSOndrej Mosnacek preempt_enable();
1120522236dSOndrej Mosnacek
1132621a869SEric Biggers while ((nbytes = walk.nbytes) != 0) {
1140522236dSOndrej Mosnacek preempt_disable();
1150522236dSOndrej Mosnacek pagefault_disable();
1160522236dSOndrej Mosnacek enable_kernel_vsx();
117c07f5d3dSLeonidas S. Barbosa if (enc)
1182621a869SEric Biggers aes_p8_xts_encrypt(walk.src.virt.addr,
1192621a869SEric Biggers walk.dst.virt.addr,
1202621a869SEric Biggers round_down(nbytes, AES_BLOCK_SIZE),
1212621a869SEric Biggers &ctx->enc_key, NULL, tweak);
122c07f5d3dSLeonidas S. Barbosa else
1232621a869SEric Biggers aes_p8_xts_decrypt(walk.src.virt.addr,
1242621a869SEric Biggers walk.dst.virt.addr,
1252621a869SEric Biggers round_down(nbytes, AES_BLOCK_SIZE),
1262621a869SEric Biggers &ctx->dec_key, NULL, tweak);
1270522236dSOndrej Mosnacek disable_kernel_vsx();
1280522236dSOndrej Mosnacek pagefault_enable();
1290522236dSOndrej Mosnacek preempt_enable();
130c07f5d3dSLeonidas S. Barbosa
1312621a869SEric Biggers ret = skcipher_walk_done(&walk, nbytes % AES_BLOCK_SIZE);
132c07f5d3dSLeonidas S. Barbosa }
133c07f5d3dSLeonidas S. Barbosa return ret;
134c07f5d3dSLeonidas S. Barbosa }
135c07f5d3dSLeonidas S. Barbosa
p8_aes_xts_encrypt(struct skcipher_request * req)1362621a869SEric Biggers static int p8_aes_xts_encrypt(struct skcipher_request *req)
137c07f5d3dSLeonidas S. Barbosa {
1382621a869SEric Biggers return p8_aes_xts_crypt(req, 1);
139c07f5d3dSLeonidas S. Barbosa }
140c07f5d3dSLeonidas S. Barbosa
p8_aes_xts_decrypt(struct skcipher_request * req)1412621a869SEric Biggers static int p8_aes_xts_decrypt(struct skcipher_request *req)
142c07f5d3dSLeonidas S. Barbosa {
1432621a869SEric Biggers return p8_aes_xts_crypt(req, 0);
144c07f5d3dSLeonidas S. Barbosa }
145c07f5d3dSLeonidas S. Barbosa
1462621a869SEric Biggers struct skcipher_alg p8_aes_xts_alg = {
1472621a869SEric Biggers .base.cra_name = "xts(aes)",
1482621a869SEric Biggers .base.cra_driver_name = "p8_aes_xts",
1492621a869SEric Biggers .base.cra_module = THIS_MODULE,
1502621a869SEric Biggers .base.cra_priority = 2000,
1512621a869SEric Biggers .base.cra_flags = CRYPTO_ALG_NEED_FALLBACK,
1522621a869SEric Biggers .base.cra_blocksize = AES_BLOCK_SIZE,
1532621a869SEric Biggers .base.cra_ctxsize = sizeof(struct p8_aes_xts_ctx),
154c07f5d3dSLeonidas S. Barbosa .setkey = p8_aes_xts_setkey,
155c07f5d3dSLeonidas S. Barbosa .encrypt = p8_aes_xts_encrypt,
156c07f5d3dSLeonidas S. Barbosa .decrypt = p8_aes_xts_decrypt,
1572621a869SEric Biggers .init = p8_aes_xts_init,
1582621a869SEric Biggers .exit = p8_aes_xts_exit,
1592621a869SEric Biggers .min_keysize = 2 * AES_MIN_KEY_SIZE,
1602621a869SEric Biggers .max_keysize = 2 * AES_MAX_KEY_SIZE,
1612621a869SEric Biggers .ivsize = AES_BLOCK_SIZE,
162c07f5d3dSLeonidas S. Barbosa };
163