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(alg_name: "cbc(aes)" , type: 0, |
30 | CRYPTO_ALG_NEED_FALLBACK | |
31 | CRYPTO_ALG_ASYNC); |
32 | if (IS_ERR(ptr: fallback)) { |
33 | pr_err("Failed to allocate cbc(aes) fallback: %ld\n" , |
34 | PTR_ERR(fallback)); |
35 | return PTR_ERR(ptr: fallback); |
36 | } |
37 | |
38 | crypto_skcipher_set_reqsize(skcipher: tfm, reqsize: sizeof(struct skcipher_request) + |
39 | crypto_skcipher_reqsize(tfm: 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(tfm: 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(userKey: key, bits: keylen * 8, key: &ctx->enc_key); |
61 | ret |= aes_p8_set_decrypt_key(userKey: key, bits: keylen * 8, key: &ctx->dec_key); |
62 | disable_kernel_vsx(); |
63 | pagefault_enable(); |
64 | preempt_enable(); |
65 | |
66 | ret |= crypto_skcipher_setkey(tfm: 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(req: subreq, tfm: ctx->fallback); |
84 | return enc ? crypto_skcipher_encrypt(req: subreq) : |
85 | crypto_skcipher_decrypt(req: subreq); |
86 | } |
87 | |
88 | ret = skcipher_walk_virt(walk: &walk, req, atomic: false); |
89 | while ((nbytes = walk.nbytes) != 0) { |
90 | preempt_disable(); |
91 | pagefault_disable(); |
92 | enable_kernel_vsx(); |
93 | aes_p8_cbc_encrypt(in: walk.src.virt.addr, |
94 | out: walk.dst.virt.addr, |
95 | round_down(nbytes, AES_BLOCK_SIZE), |
96 | key: enc ? &ctx->enc_key : &ctx->dec_key, |
97 | iv: walk.iv, enc); |
98 | disable_kernel_vsx(); |
99 | pagefault_enable(); |
100 | preempt_enable(); |
101 | |
102 | ret = skcipher_walk_done(walk: &walk, err: 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, enc: 1); |
110 | } |
111 | |
112 | static int p8_aes_cbc_decrypt(struct skcipher_request *req) |
113 | { |
114 | return p8_aes_cbc_crypt(req, enc: 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 | |