diff options
Diffstat (limited to 'crypto/ahash.c')
-rw-r--r-- | crypto/ahash.c | 204 |
1 files changed, 201 insertions, 3 deletions
diff --git a/crypto/ahash.c b/crypto/ahash.c index a196055b73d3..ac0798d2824e 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c | |||
@@ -24,6 +24,13 @@ | |||
24 | 24 | ||
25 | #include "internal.h" | 25 | #include "internal.h" |
26 | 26 | ||
27 | struct ahash_request_priv { | ||
28 | crypto_completion_t complete; | ||
29 | void *data; | ||
30 | u8 *result; | ||
31 | void *ubuf[] CRYPTO_MINALIGN_ATTR; | ||
32 | }; | ||
33 | |||
27 | static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) | 34 | static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) |
28 | { | 35 | { |
29 | return container_of(crypto_hash_alg_common(hash), struct ahash_alg, | 36 | return container_of(crypto_hash_alg_common(hash), struct ahash_alg, |
@@ -156,7 +163,7 @@ static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, | |||
156 | return ret; | 163 | return ret; |
157 | } | 164 | } |
158 | 165 | ||
159 | static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, | 166 | int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, |
160 | unsigned int keylen) | 167 | unsigned int keylen) |
161 | { | 168 | { |
162 | struct ahash_alg *ahash = crypto_ahash_alg(tfm); | 169 | struct ahash_alg *ahash = crypto_ahash_alg(tfm); |
@@ -167,6 +174,7 @@ static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, | |||
167 | 174 | ||
168 | return ahash->setkey(tfm, key, keylen); | 175 | return ahash->setkey(tfm, key, keylen); |
169 | } | 176 | } |
177 | EXPORT_SYMBOL_GPL(crypto_ahash_setkey); | ||
170 | 178 | ||
171 | static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, | 179 | static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, |
172 | unsigned int keylen) | 180 | unsigned int keylen) |
@@ -174,19 +182,209 @@ static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, | |||
174 | return -ENOSYS; | 182 | return -ENOSYS; |
175 | } | 183 | } |
176 | 184 | ||
185 | static inline unsigned int ahash_align_buffer_size(unsigned len, | ||
186 | unsigned long mask) | ||
187 | { | ||
188 | return len + (mask & ~(crypto_tfm_ctx_alignment() - 1)); | ||
189 | } | ||
190 | |||
191 | static void ahash_op_unaligned_finish(struct ahash_request *req, int err) | ||
192 | { | ||
193 | struct ahash_request_priv *priv = req->priv; | ||
194 | |||
195 | if (err == -EINPROGRESS) | ||
196 | return; | ||
197 | |||
198 | if (!err) | ||
199 | memcpy(priv->result, req->result, | ||
200 | crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
201 | |||
202 | kzfree(priv); | ||
203 | } | ||
204 | |||
205 | static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) | ||
206 | { | ||
207 | struct ahash_request *areq = req->data; | ||
208 | struct ahash_request_priv *priv = areq->priv; | ||
209 | crypto_completion_t complete = priv->complete; | ||
210 | void *data = priv->data; | ||
211 | |||
212 | ahash_op_unaligned_finish(areq, err); | ||
213 | |||
214 | complete(data, err); | ||
215 | } | ||
216 | |||
217 | static int ahash_op_unaligned(struct ahash_request *req, | ||
218 | int (*op)(struct ahash_request *)) | ||
219 | { | ||
220 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | ||
221 | unsigned long alignmask = crypto_ahash_alignmask(tfm); | ||
222 | unsigned int ds = crypto_ahash_digestsize(tfm); | ||
223 | struct ahash_request_priv *priv; | ||
224 | int err; | ||
225 | |||
226 | priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), | ||
227 | (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? | ||
228 | GFP_ATOMIC : GFP_ATOMIC); | ||
229 | if (!priv) | ||
230 | return -ENOMEM; | ||
231 | |||
232 | priv->result = req->result; | ||
233 | priv->complete = req->base.complete; | ||
234 | priv->data = req->base.data; | ||
235 | |||
236 | req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); | ||
237 | req->base.complete = ahash_op_unaligned_done; | ||
238 | req->base.data = req; | ||
239 | req->priv = priv; | ||
240 | |||
241 | err = op(req); | ||
242 | ahash_op_unaligned_finish(req, err); | ||
243 | |||
244 | return err; | ||
245 | } | ||
246 | |||
247 | static int crypto_ahash_op(struct ahash_request *req, | ||
248 | int (*op)(struct ahash_request *)) | ||
249 | { | ||
250 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | ||
251 | unsigned long alignmask = crypto_ahash_alignmask(tfm); | ||
252 | |||
253 | if ((unsigned long)req->result & alignmask) | ||
254 | return ahash_op_unaligned(req, op); | ||
255 | |||
256 | return op(req); | ||
257 | } | ||
258 | |||
259 | int crypto_ahash_final(struct ahash_request *req) | ||
260 | { | ||
261 | return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final); | ||
262 | } | ||
263 | EXPORT_SYMBOL_GPL(crypto_ahash_final); | ||
264 | |||
265 | int crypto_ahash_finup(struct ahash_request *req) | ||
266 | { | ||
267 | return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup); | ||
268 | } | ||
269 | EXPORT_SYMBOL_GPL(crypto_ahash_finup); | ||
270 | |||
271 | int crypto_ahash_digest(struct ahash_request *req) | ||
272 | { | ||
273 | return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest); | ||
274 | } | ||
275 | EXPORT_SYMBOL_GPL(crypto_ahash_digest); | ||
276 | |||
277 | static void ahash_def_finup_finish2(struct ahash_request *req, int err) | ||
278 | { | ||
279 | struct ahash_request_priv *priv = req->priv; | ||
280 | |||
281 | if (err == -EINPROGRESS) | ||
282 | return; | ||
283 | |||
284 | if (!err) | ||
285 | memcpy(priv->result, req->result, | ||
286 | crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); | ||
287 | |||
288 | kzfree(priv); | ||
289 | } | ||
290 | |||
291 | static void ahash_def_finup_done2(struct crypto_async_request *req, int err) | ||
292 | { | ||
293 | struct ahash_request *areq = req->data; | ||
294 | struct ahash_request_priv *priv = areq->priv; | ||
295 | crypto_completion_t complete = priv->complete; | ||
296 | void *data = priv->data; | ||
297 | |||
298 | ahash_def_finup_finish2(areq, err); | ||
299 | |||
300 | complete(data, err); | ||
301 | } | ||
302 | |||
303 | static int ahash_def_finup_finish1(struct ahash_request *req, int err) | ||
304 | { | ||
305 | if (err) | ||
306 | goto out; | ||
307 | |||
308 | req->base.complete = ahash_def_finup_done2; | ||
309 | req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; | ||
310 | err = crypto_ahash_reqtfm(req)->final(req); | ||
311 | |||
312 | out: | ||
313 | ahash_def_finup_finish2(req, err); | ||
314 | return err; | ||
315 | } | ||
316 | |||
317 | static void ahash_def_finup_done1(struct crypto_async_request *req, int err) | ||
318 | { | ||
319 | struct ahash_request *areq = req->data; | ||
320 | struct ahash_request_priv *priv = areq->priv; | ||
321 | crypto_completion_t complete = priv->complete; | ||
322 | void *data = priv->data; | ||
323 | |||
324 | err = ahash_def_finup_finish1(areq, err); | ||
325 | |||
326 | complete(data, err); | ||
327 | } | ||
328 | |||
329 | static int ahash_def_finup(struct ahash_request *req) | ||
330 | { | ||
331 | struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); | ||
332 | unsigned long alignmask = crypto_ahash_alignmask(tfm); | ||
333 | unsigned int ds = crypto_ahash_digestsize(tfm); | ||
334 | struct ahash_request_priv *priv; | ||
335 | |||
336 | priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), | ||
337 | (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? | ||
338 | GFP_ATOMIC : GFP_ATOMIC); | ||
339 | if (!priv) | ||
340 | return -ENOMEM; | ||
341 | |||
342 | priv->result = req->result; | ||
343 | priv->complete = req->base.complete; | ||
344 | priv->data = req->base.data; | ||
345 | |||
346 | req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); | ||
347 | req->base.complete = ahash_def_finup_done1; | ||
348 | req->base.data = req; | ||
349 | req->priv = priv; | ||
350 | |||
351 | return ahash_def_finup_finish1(req, tfm->update(req)); | ||
352 | } | ||
353 | |||
354 | static int ahash_no_export(struct ahash_request *req, void *out) | ||
355 | { | ||
356 | return -ENOSYS; | ||
357 | } | ||
358 | |||
359 | static int ahash_no_import(struct ahash_request *req, const void *in) | ||
360 | { | ||
361 | return -ENOSYS; | ||
362 | } | ||
363 | |||
177 | static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) | 364 | static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) |
178 | { | 365 | { |
179 | struct crypto_ahash *hash = __crypto_ahash_cast(tfm); | 366 | struct crypto_ahash *hash = __crypto_ahash_cast(tfm); |
180 | struct ahash_alg *alg = crypto_ahash_alg(hash); | 367 | struct ahash_alg *alg = crypto_ahash_alg(hash); |
181 | 368 | ||
369 | hash->setkey = ahash_nosetkey; | ||
370 | hash->export = ahash_no_export; | ||
371 | hash->import = ahash_no_import; | ||
372 | |||
182 | if (tfm->__crt_alg->cra_type != &crypto_ahash_type) | 373 | if (tfm->__crt_alg->cra_type != &crypto_ahash_type) |
183 | return crypto_init_shash_ops_async(tfm); | 374 | return crypto_init_shash_ops_async(tfm); |
184 | 375 | ||
185 | hash->init = alg->init; | 376 | hash->init = alg->init; |
186 | hash->update = alg->update; | 377 | hash->update = alg->update; |
187 | hash->final = alg->final; | 378 | hash->final = alg->final; |
379 | hash->finup = alg->finup ?: ahash_def_finup; | ||
188 | hash->digest = alg->digest; | 380 | hash->digest = alg->digest; |
189 | hash->setkey = alg->setkey ? ahash_setkey : ahash_nosetkey; | 381 | |
382 | if (alg->setkey) | ||
383 | hash->setkey = alg->setkey; | ||
384 | if (alg->export) | ||
385 | hash->export = alg->export; | ||
386 | if (alg->import) | ||
387 | hash->import = alg->import; | ||
190 | 388 | ||
191 | return 0; | 389 | return 0; |
192 | } | 390 | } |