]>
Commit | Line | Data |
---|---|---|
266d0516 HX |
1 | /* |
2 | * Shared crypto simd helpers | |
3 | * | |
4 | * Copyright (c) 2012 Jussi Kivilinna <[email protected]> | |
5 | * Copyright (c) 2016 Herbert Xu <[email protected]> | |
6 | * | |
7 | * Based on aesni-intel_glue.c by: | |
8 | * Copyright (C) 2008, Intel Corp. | |
9 | * Author: Huang Ying <[email protected]> | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License as published by | |
13 | * the Free Software Foundation; either version 2 of the License, or | |
14 | * (at your option) any later version. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, | |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | * GNU General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
1af39daa | 22 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
266d0516 HX |
23 | * |
24 | */ | |
25 | ||
26 | #include <crypto/cryptd.h> | |
27 | #include <crypto/internal/simd.h> | |
28 | #include <crypto/internal/skcipher.h> | |
29 | #include <linux/kernel.h> | |
30 | #include <linux/module.h> | |
31 | #include <linux/preempt.h> | |
32 | #include <asm/simd.h> | |
33 | ||
34 | struct simd_skcipher_alg { | |
35 | const char *ialg_name; | |
36 | struct skcipher_alg alg; | |
37 | }; | |
38 | ||
39 | struct simd_skcipher_ctx { | |
40 | struct cryptd_skcipher *cryptd_tfm; | |
41 | }; | |
42 | ||
43 | static int simd_skcipher_setkey(struct crypto_skcipher *tfm, const u8 *key, | |
44 | unsigned int key_len) | |
45 | { | |
46 | struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); | |
47 | struct crypto_skcipher *child = &ctx->cryptd_tfm->base; | |
48 | int err; | |
49 | ||
50 | crypto_skcipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); | |
51 | crypto_skcipher_set_flags(child, crypto_skcipher_get_flags(tfm) & | |
52 | CRYPTO_TFM_REQ_MASK); | |
53 | err = crypto_skcipher_setkey(child, key, key_len); | |
54 | crypto_skcipher_set_flags(tfm, crypto_skcipher_get_flags(child) & | |
55 | CRYPTO_TFM_RES_MASK); | |
56 | return err; | |
57 | } | |
58 | ||
59 | static int simd_skcipher_encrypt(struct skcipher_request *req) | |
60 | { | |
61 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); | |
62 | struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); | |
63 | struct skcipher_request *subreq; | |
64 | struct crypto_skcipher *child; | |
65 | ||
66 | subreq = skcipher_request_ctx(req); | |
67 | *subreq = *req; | |
68 | ||
69 | if (!may_use_simd() || | |
70 | (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) | |
71 | child = &ctx->cryptd_tfm->base; | |
72 | else | |
73 | child = cryptd_skcipher_child(ctx->cryptd_tfm); | |
74 | ||
75 | skcipher_request_set_tfm(subreq, child); | |
76 | ||
77 | return crypto_skcipher_encrypt(subreq); | |
78 | } | |
79 | ||
80 | static int simd_skcipher_decrypt(struct skcipher_request *req) | |
81 | { | |
82 | struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); | |
83 | struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); | |
84 | struct skcipher_request *subreq; | |
85 | struct crypto_skcipher *child; | |
86 | ||
87 | subreq = skcipher_request_ctx(req); | |
88 | *subreq = *req; | |
89 | ||
90 | if (!may_use_simd() || | |
91 | (in_atomic() && cryptd_skcipher_queued(ctx->cryptd_tfm))) | |
92 | child = &ctx->cryptd_tfm->base; | |
93 | else | |
94 | child = cryptd_skcipher_child(ctx->cryptd_tfm); | |
95 | ||
96 | skcipher_request_set_tfm(subreq, child); | |
97 | ||
98 | return crypto_skcipher_decrypt(subreq); | |
99 | } | |
100 | ||
101 | static void simd_skcipher_exit(struct crypto_skcipher *tfm) | |
102 | { | |
103 | struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); | |
104 | ||
105 | cryptd_free_skcipher(ctx->cryptd_tfm); | |
106 | } | |
107 | ||
108 | static int simd_skcipher_init(struct crypto_skcipher *tfm) | |
109 | { | |
110 | struct simd_skcipher_ctx *ctx = crypto_skcipher_ctx(tfm); | |
111 | struct cryptd_skcipher *cryptd_tfm; | |
112 | struct simd_skcipher_alg *salg; | |
113 | struct skcipher_alg *alg; | |
114 | unsigned reqsize; | |
115 | ||
116 | alg = crypto_skcipher_alg(tfm); | |
117 | salg = container_of(alg, struct simd_skcipher_alg, alg); | |
118 | ||
119 | cryptd_tfm = cryptd_alloc_skcipher(salg->ialg_name, | |
120 | CRYPTO_ALG_INTERNAL, | |
121 | CRYPTO_ALG_INTERNAL); | |
122 | if (IS_ERR(cryptd_tfm)) | |
123 | return PTR_ERR(cryptd_tfm); | |
124 | ||
125 | ctx->cryptd_tfm = cryptd_tfm; | |
126 | ||
508a1c4d AB |
127 | reqsize = crypto_skcipher_reqsize(cryptd_skcipher_child(cryptd_tfm)); |
128 | reqsize = max(reqsize, crypto_skcipher_reqsize(&cryptd_tfm->base)); | |
129 | reqsize += sizeof(struct skcipher_request); | |
266d0516 HX |
130 | |
131 | crypto_skcipher_set_reqsize(tfm, reqsize); | |
132 | ||
133 | return 0; | |
134 | } | |
135 | ||
136 | struct simd_skcipher_alg *simd_skcipher_create_compat(const char *algname, | |
137 | const char *drvname, | |
138 | const char *basename) | |
139 | { | |
140 | struct simd_skcipher_alg *salg; | |
141 | struct crypto_skcipher *tfm; | |
142 | struct skcipher_alg *ialg; | |
143 | struct skcipher_alg *alg; | |
144 | int err; | |
145 | ||
146 | tfm = crypto_alloc_skcipher(basename, CRYPTO_ALG_INTERNAL, | |
147 | CRYPTO_ALG_INTERNAL | CRYPTO_ALG_ASYNC); | |
148 | if (IS_ERR(tfm)) | |
149 | return ERR_CAST(tfm); | |
150 | ||
151 | ialg = crypto_skcipher_alg(tfm); | |
152 | ||
153 | salg = kzalloc(sizeof(*salg), GFP_KERNEL); | |
154 | if (!salg) { | |
155 | salg = ERR_PTR(-ENOMEM); | |
156 | goto out_put_tfm; | |
157 | } | |
158 | ||
159 | salg->ialg_name = basename; | |
160 | alg = &salg->alg; | |
161 | ||
162 | err = -ENAMETOOLONG; | |
163 | if (snprintf(alg->base.cra_name, CRYPTO_MAX_ALG_NAME, "%s", algname) >= | |
164 | CRYPTO_MAX_ALG_NAME) | |
165 | goto out_free_salg; | |
166 | ||
167 | if (snprintf(alg->base.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s", | |
168 | drvname) >= CRYPTO_MAX_ALG_NAME) | |
169 | goto out_free_salg; | |
170 | ||
171 | alg->base.cra_flags = CRYPTO_ALG_ASYNC; | |
172 | alg->base.cra_priority = ialg->base.cra_priority; | |
173 | alg->base.cra_blocksize = ialg->base.cra_blocksize; | |
174 | alg->base.cra_alignmask = ialg->base.cra_alignmask; | |
175 | alg->base.cra_module = ialg->base.cra_module; | |
176 | alg->base.cra_ctxsize = sizeof(struct simd_skcipher_ctx); | |
177 | ||
178 | alg->ivsize = ialg->ivsize; | |
179 | alg->chunksize = ialg->chunksize; | |
180 | alg->min_keysize = ialg->min_keysize; | |
181 | alg->max_keysize = ialg->max_keysize; | |
182 | ||
183 | alg->init = simd_skcipher_init; | |
184 | alg->exit = simd_skcipher_exit; | |
185 | ||
186 | alg->setkey = simd_skcipher_setkey; | |
187 | alg->encrypt = simd_skcipher_encrypt; | |
188 | alg->decrypt = simd_skcipher_decrypt; | |
189 | ||
190 | err = crypto_register_skcipher(alg); | |
191 | if (err) | |
192 | goto out_free_salg; | |
193 | ||
194 | out_put_tfm: | |
195 | crypto_free_skcipher(tfm); | |
196 | return salg; | |
197 | ||
198 | out_free_salg: | |
199 | kfree(salg); | |
200 | salg = ERR_PTR(err); | |
201 | goto out_put_tfm; | |
202 | } | |
203 | EXPORT_SYMBOL_GPL(simd_skcipher_create_compat); | |
204 | ||
205 | struct simd_skcipher_alg *simd_skcipher_create(const char *algname, | |
206 | const char *basename) | |
207 | { | |
208 | char drvname[CRYPTO_MAX_ALG_NAME]; | |
209 | ||
210 | if (snprintf(drvname, CRYPTO_MAX_ALG_NAME, "simd-%s", basename) >= | |
211 | CRYPTO_MAX_ALG_NAME) | |
212 | return ERR_PTR(-ENAMETOOLONG); | |
213 | ||
214 | return simd_skcipher_create_compat(algname, drvname, basename); | |
215 | } | |
216 | EXPORT_SYMBOL_GPL(simd_skcipher_create); | |
217 | ||
218 | void simd_skcipher_free(struct simd_skcipher_alg *salg) | |
219 | { | |
220 | crypto_unregister_skcipher(&salg->alg); | |
221 | kfree(salg); | |
222 | } | |
223 | EXPORT_SYMBOL_GPL(simd_skcipher_free); | |
224 | ||
d14f0a1f EB |
225 | int simd_register_skciphers_compat(struct skcipher_alg *algs, int count, |
226 | struct simd_skcipher_alg **simd_algs) | |
227 | { | |
228 | int err; | |
229 | int i; | |
230 | const char *algname; | |
231 | const char *drvname; | |
232 | const char *basename; | |
233 | struct simd_skcipher_alg *simd; | |
234 | ||
235 | err = crypto_register_skciphers(algs, count); | |
236 | if (err) | |
237 | return err; | |
238 | ||
239 | for (i = 0; i < count; i++) { | |
240 | WARN_ON(strncmp(algs[i].base.cra_name, "__", 2)); | |
241 | WARN_ON(strncmp(algs[i].base.cra_driver_name, "__", 2)); | |
242 | algname = algs[i].base.cra_name + 2; | |
243 | drvname = algs[i].base.cra_driver_name + 2; | |
244 | basename = algs[i].base.cra_driver_name; | |
245 | simd = simd_skcipher_create_compat(algname, drvname, basename); | |
246 | err = PTR_ERR(simd); | |
247 | if (IS_ERR(simd)) | |
248 | goto err_unregister; | |
249 | simd_algs[i] = simd; | |
250 | } | |
251 | return 0; | |
252 | ||
253 | err_unregister: | |
254 | simd_unregister_skciphers(algs, count, simd_algs); | |
255 | return err; | |
256 | } | |
257 | EXPORT_SYMBOL_GPL(simd_register_skciphers_compat); | |
258 | ||
259 | void simd_unregister_skciphers(struct skcipher_alg *algs, int count, | |
260 | struct simd_skcipher_alg **simd_algs) | |
261 | { | |
262 | int i; | |
263 | ||
264 | crypto_unregister_skciphers(algs, count); | |
265 | ||
266 | for (i = 0; i < count; i++) { | |
267 | if (simd_algs[i]) { | |
268 | simd_skcipher_free(simd_algs[i]); | |
269 | simd_algs[i] = NULL; | |
270 | } | |
271 | } | |
272 | } | |
273 | EXPORT_SYMBOL_GPL(simd_unregister_skciphers); | |
274 | ||
266d0516 | 275 | MODULE_LICENSE("GPL"); |