Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / drivers / crypto / vmx / aes_cbc.c
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 };