Blame view

crypto/ahash.c 14.7 KB
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
  /*
   * Asynchronous Cryptographic Hash operations.
   *
   * This is the asynchronous version of hash.c with notification of
   * completion via a callback.
   *
   * Copyright (c) 2008 Loc Ho <lho@amcc.com>
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License as published by the Free
   * Software Foundation; either version 2 of the License, or (at your option)
   * any later version.
   *
   */
20036252f   Herbert Xu   crypto: hash - Ad...
15
16
  #include <crypto/internal/hash.h>
  #include <crypto/scatterwalk.h>
75ecb231f   Herbert Xu   crypto: hash - Ad...
17
  #include <linux/bug.h>
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
18
19
20
21
22
23
  #include <linux/err.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/sched.h>
  #include <linux/slab.h>
  #include <linux/seq_file.h>
6238cbaec   Steffen Klassert   crypto: Add users...
24
25
  #include <linux/cryptouser.h>
  #include <net/netlink.h>
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
26
27
  
  #include "internal.h"
66f6ce5e5   Herbert Xu   crypto: ahash - A...
28
29
30
31
32
33
  struct ahash_request_priv {
  	crypto_completion_t complete;
  	void *data;
  	u8 *result;
  	void *ubuf[] CRYPTO_MINALIGN_ATTR;
  };
88056ec34   Herbert Xu   crypto: ahash - C...
34
35
36
37
38
  static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash)
  {
  	return container_of(crypto_hash_alg_common(hash), struct ahash_alg,
  			    halg);
  }
20036252f   Herbert Xu   crypto: hash - Ad...
39
40
41
42
43
44
  static int hash_walk_next(struct crypto_hash_walk *walk)
  {
  	unsigned int alignmask = walk->alignmask;
  	unsigned int offset = walk->offset;
  	unsigned int nbytes = min(walk->entrylen,
  				  ((unsigned int)(PAGE_SIZE)) - offset);
75ecb231f   Herbert Xu   crypto: hash - Ad...
45
46
47
48
  	if (walk->flags & CRYPTO_ALG_ASYNC)
  		walk->data = kmap(walk->pg);
  	else
  		walk->data = kmap_atomic(walk->pg);
20036252f   Herbert Xu   crypto: hash - Ad...
49
  	walk->data += offset;
23a75eee0   Szilveszter Ördög   crypto: hash - Fi...
50
51
  	if (offset & alignmask) {
  		unsigned int unaligned = alignmask + 1 - (offset & alignmask);
b516d5140   Joshua I. James   crypto: ahash - f...
52

23a75eee0   Szilveszter Ördög   crypto: hash - Fi...
53
54
55
  		if (nbytes > unaligned)
  			nbytes = unaligned;
  	}
20036252f   Herbert Xu   crypto: hash - Ad...
56
57
58
59
60
61
62
63
64
65
  
  	walk->entrylen -= nbytes;
  	return nbytes;
  }
  
  static int hash_walk_new_entry(struct crypto_hash_walk *walk)
  {
  	struct scatterlist *sg;
  
  	sg = walk->sg;
20036252f   Herbert Xu   crypto: hash - Ad...
66
  	walk->offset = sg->offset;
13f4bb78c   Herbert Xu   crypto: hash - Fi...
67
68
  	walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT);
  	walk->offset = offset_in_page(walk->offset);
20036252f   Herbert Xu   crypto: hash - Ad...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
  	walk->entrylen = sg->length;
  
  	if (walk->entrylen > walk->total)
  		walk->entrylen = walk->total;
  	walk->total -= walk->entrylen;
  
  	return hash_walk_next(walk);
  }
  
  int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err)
  {
  	unsigned int alignmask = walk->alignmask;
  	unsigned int nbytes = walk->entrylen;
  
  	walk->data -= walk->offset;
  
  	if (nbytes && walk->offset & alignmask && !err) {
20036252f   Herbert Xu   crypto: hash - Ad...
86
87
88
89
90
91
92
93
94
  		walk->offset = ALIGN(walk->offset, alignmask + 1);
  		walk->data += walk->offset;
  
  		nbytes = min(nbytes,
  			     ((unsigned int)(PAGE_SIZE)) - walk->offset);
  		walk->entrylen -= nbytes;
  
  		return nbytes;
  	}
75ecb231f   Herbert Xu   crypto: hash - Ad...
95
96
97
98
99
100
101
102
103
104
  	if (walk->flags & CRYPTO_ALG_ASYNC)
  		kunmap(walk->pg);
  	else {
  		kunmap_atomic(walk->data);
  		/*
  		 * The may sleep test only makes sense for sync users.
  		 * Async users don't need to sleep here anyway.
  		 */
  		crypto_yield(walk->flags);
  	}
20036252f   Herbert Xu   crypto: hash - Ad...
105
106
107
  
  	if (err)
  		return err;
d315a0e09   Herbert Xu   crypto: hash - Fi...
108
109
110
  	if (nbytes) {
  		walk->offset = 0;
  		walk->pg++;
20036252f   Herbert Xu   crypto: hash - Ad...
111
  		return hash_walk_next(walk);
d315a0e09   Herbert Xu   crypto: hash - Fi...
112
  	}
20036252f   Herbert Xu   crypto: hash - Ad...
113
114
115
  
  	if (!walk->total)
  		return 0;
5be4d4c94   Cristian Stoica   crypto: replace s...
116
  	walk->sg = sg_next(walk->sg);
20036252f   Herbert Xu   crypto: hash - Ad...
117
118
119
120
121
122
123
124
125
  
  	return hash_walk_new_entry(walk);
  }
  EXPORT_SYMBOL_GPL(crypto_hash_walk_done);
  
  int crypto_hash_walk_first(struct ahash_request *req,
  			   struct crypto_hash_walk *walk)
  {
  	walk->total = req->nbytes;
6d9529c58   Tim Chen   crypto: hash - in...
126
127
  	if (!walk->total) {
  		walk->entrylen = 0;
20036252f   Herbert Xu   crypto: hash - Ad...
128
  		return 0;
6d9529c58   Tim Chen   crypto: hash - in...
129
  	}
20036252f   Herbert Xu   crypto: hash - Ad...
130
131
132
  
  	walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req));
  	walk->sg = req->src;
75ecb231f   Herbert Xu   crypto: hash - Ad...
133
  	walk->flags = req->base.flags & CRYPTO_TFM_REQ_MASK;
20036252f   Herbert Xu   crypto: hash - Ad...
134
135
136
137
  
  	return hash_walk_new_entry(walk);
  }
  EXPORT_SYMBOL_GPL(crypto_hash_walk_first);
75ecb231f   Herbert Xu   crypto: hash - Ad...
138
139
140
141
  int crypto_ahash_walk_first(struct ahash_request *req,
  			    struct crypto_hash_walk *walk)
  {
  	walk->total = req->nbytes;
6d9529c58   Tim Chen   crypto: hash - in...
142
143
  	if (!walk->total) {
  		walk->entrylen = 0;
75ecb231f   Herbert Xu   crypto: hash - Ad...
144
  		return 0;
6d9529c58   Tim Chen   crypto: hash - in...
145
  	}
75ecb231f   Herbert Xu   crypto: hash - Ad...
146
147
148
149
150
151
152
153
154
155
156
  
  	walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req));
  	walk->sg = req->src;
  	walk->flags = req->base.flags & CRYPTO_TFM_REQ_MASK;
  	walk->flags |= CRYPTO_ALG_ASYNC;
  
  	BUILD_BUG_ON(CRYPTO_TFM_REQ_MASK & CRYPTO_ALG_ASYNC);
  
  	return hash_walk_new_entry(walk);
  }
  EXPORT_SYMBOL_GPL(crypto_ahash_walk_first);
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
157
158
159
  static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
  				unsigned int keylen)
  {
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
160
161
162
163
164
165
  	unsigned long alignmask = crypto_ahash_alignmask(tfm);
  	int ret;
  	u8 *buffer, *alignbuffer;
  	unsigned long absize;
  
  	absize = keylen + alignmask;
093900c2b   Herbert Xu   crypto: ahash - U...
166
  	buffer = kmalloc(absize, GFP_KERNEL);
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
167
168
169
170
171
  	if (!buffer)
  		return -ENOMEM;
  
  	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
  	memcpy(alignbuffer, key, keylen);
a70c52252   Herbert Xu   crypto: ahash - F...
172
  	ret = tfm->setkey(tfm, alignbuffer, keylen);
8c32c516e   Herbert Xu   crypto: hash - Za...
173
  	kzfree(buffer);
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
174
175
  	return ret;
  }
66f6ce5e5   Herbert Xu   crypto: ahash - A...
176
  int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
177
178
  			unsigned int keylen)
  {
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
179
180
181
182
  	unsigned long alignmask = crypto_ahash_alignmask(tfm);
  
  	if ((unsigned long)key & alignmask)
  		return ahash_setkey_unaligned(tfm, key, keylen);
a70c52252   Herbert Xu   crypto: ahash - F...
183
  	return tfm->setkey(tfm, key, keylen);
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
184
  }
66f6ce5e5   Herbert Xu   crypto: ahash - A...
185
  EXPORT_SYMBOL_GPL(crypto_ahash_setkey);
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
186

3751f402e   Herbert Xu   crypto: hash - Ma...
187
188
189
190
191
  static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key,
  			  unsigned int keylen)
  {
  	return -ENOSYS;
  }
66f6ce5e5   Herbert Xu   crypto: ahash - A...
192
193
194
195
196
  static inline unsigned int ahash_align_buffer_size(unsigned len,
  						   unsigned long mask)
  {
  	return len + (mask & ~(crypto_tfm_ctx_alignment() - 1));
  }
1ffc9fbd1   Marek Vasut   crypto: hash - Pu...
197
  static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt)
66f6ce5e5   Herbert Xu   crypto: ahash - A...
198
199
200
201
202
  {
  	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
  	unsigned long alignmask = crypto_ahash_alignmask(tfm);
  	unsigned int ds = crypto_ahash_digestsize(tfm);
  	struct ahash_request_priv *priv;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
203
204
205
  
  	priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask),
  		       (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ?
5befbd5a7   Steffen Klassert   crypto: ahash - U...
206
  		       GFP_KERNEL : GFP_ATOMIC);
66f6ce5e5   Herbert Xu   crypto: ahash - A...
207
208
  	if (!priv)
  		return -ENOMEM;
ab6bf4e5e   Marek Vasut   crypto: hash - Fi...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  	/*
  	 * WARNING: Voodoo programming below!
  	 *
  	 * The code below is obscure and hard to understand, thus explanation
  	 * is necessary. See include/crypto/hash.h and include/linux/crypto.h
  	 * to understand the layout of structures used here!
  	 *
  	 * The code here will replace portions of the ORIGINAL request with
  	 * pointers to new code and buffers so the hashing operation can store
  	 * the result in aligned buffer. We will call the modified request
  	 * an ADJUSTED request.
  	 *
  	 * The newly mangled request will look as such:
  	 *
  	 * req {
  	 *   .result        = ADJUSTED[new aligned buffer]
  	 *   .base.complete = ADJUSTED[pointer to completion function]
  	 *   .base.data     = ADJUSTED[*req (pointer to self)]
  	 *   .priv          = ADJUSTED[new priv] {
  	 *           .result   = ORIGINAL(result)
  	 *           .complete = ORIGINAL(base.complete)
  	 *           .data     = ORIGINAL(base.data)
  	 *   }
  	 */
66f6ce5e5   Herbert Xu   crypto: ahash - A...
233
234
235
  	priv->result = req->result;
  	priv->complete = req->base.complete;
  	priv->data = req->base.data;
ab6bf4e5e   Marek Vasut   crypto: hash - Fi...
236
237
238
239
240
  	/*
  	 * WARNING: We do not backup req->priv here! The req->priv
  	 *          is for internal use of the Crypto API and the
  	 *          user must _NOT_ _EVER_ depend on it's content!
  	 */
66f6ce5e5   Herbert Xu   crypto: ahash - A...
241
242
  
  	req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1);
1ffc9fbd1   Marek Vasut   crypto: hash - Pu...
243
  	req->base.complete = cplt;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
244
245
  	req->base.data = req;
  	req->priv = priv;
1ffc9fbd1   Marek Vasut   crypto: hash - Pu...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
  	return 0;
  }
  
  static void ahash_restore_req(struct ahash_request *req)
  {
  	struct ahash_request_priv *priv = req->priv;
  
  	/* Restore the original crypto request. */
  	req->result = priv->result;
  	req->base.complete = priv->complete;
  	req->base.data = priv->data;
  	req->priv = NULL;
  
  	/* Free the req->priv.priv from the ADJUSTED request. */
  	kzfree(priv);
  }
  
  static void ahash_op_unaligned_finish(struct ahash_request *req, int err)
  {
  	struct ahash_request_priv *priv = req->priv;
  
  	if (err == -EINPROGRESS)
  		return;
  
  	if (!err)
  		memcpy(priv->result, req->result,
  		       crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
  
  	ahash_restore_req(req);
  }
  
  static void ahash_op_unaligned_done(struct crypto_async_request *req, int err)
  {
  	struct ahash_request *areq = req->data;
  
  	/*
  	 * Restore the original request, see ahash_op_unaligned() for what
  	 * goes where.
  	 *
  	 * The "struct ahash_request *req" here is in fact the "req.base"
  	 * from the ADJUSTED request from ahash_op_unaligned(), thus as it
  	 * is a pointer to self, it is also the ADJUSTED "req" .
  	 */
  
  	/* First copy req->result into req->priv.result */
  	ahash_op_unaligned_finish(areq, err);
  
  	/* Complete the ORIGINAL request. */
  	areq->base.complete(&areq->base, err);
  }
  
  static int ahash_op_unaligned(struct ahash_request *req,
  			      int (*op)(struct ahash_request *))
  {
  	int err;
  
  	err = ahash_save_req(req, ahash_op_unaligned_done);
  	if (err)
  		return err;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
  	err = op(req);
  	ahash_op_unaligned_finish(req, err);
  
  	return err;
  }
  
  static int crypto_ahash_op(struct ahash_request *req,
  			   int (*op)(struct ahash_request *))
  {
  	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
  	unsigned long alignmask = crypto_ahash_alignmask(tfm);
  
  	if ((unsigned long)req->result & alignmask)
  		return ahash_op_unaligned(req, op);
  
  	return op(req);
  }
  
  int crypto_ahash_final(struct ahash_request *req)
  {
  	return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final);
  }
  EXPORT_SYMBOL_GPL(crypto_ahash_final);
  
  int crypto_ahash_finup(struct ahash_request *req)
  {
  	return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup);
  }
  EXPORT_SYMBOL_GPL(crypto_ahash_finup);
  
  int crypto_ahash_digest(struct ahash_request *req)
  {
  	return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest);
  }
  EXPORT_SYMBOL_GPL(crypto_ahash_digest);
  
  static void ahash_def_finup_finish2(struct ahash_request *req, int err)
  {
  	struct ahash_request_priv *priv = req->priv;
  
  	if (err == -EINPROGRESS)
  		return;
  
  	if (!err)
  		memcpy(priv->result, req->result,
  		       crypto_ahash_digestsize(crypto_ahash_reqtfm(req)));
d4a7a0fbe   Marek Vasut   crypto: hash - Si...
351
  	ahash_restore_req(req);
66f6ce5e5   Herbert Xu   crypto: ahash - A...
352
353
354
355
356
  }
  
  static void ahash_def_finup_done2(struct crypto_async_request *req, int err)
  {
  	struct ahash_request *areq = req->data;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
357
358
  
  	ahash_def_finup_finish2(areq, err);
d4a7a0fbe   Marek Vasut   crypto: hash - Si...
359
  	areq->base.complete(&areq->base, err);
66f6ce5e5   Herbert Xu   crypto: ahash - A...
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
  }
  
  static int ahash_def_finup_finish1(struct ahash_request *req, int err)
  {
  	if (err)
  		goto out;
  
  	req->base.complete = ahash_def_finup_done2;
  	req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP;
  	err = crypto_ahash_reqtfm(req)->final(req);
  
  out:
  	ahash_def_finup_finish2(req, err);
  	return err;
  }
  
  static void ahash_def_finup_done1(struct crypto_async_request *req, int err)
  {
  	struct ahash_request *areq = req->data;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
379
380
  
  	err = ahash_def_finup_finish1(areq, err);
d4a7a0fbe   Marek Vasut   crypto: hash - Si...
381
  	areq->base.complete(&areq->base, err);
66f6ce5e5   Herbert Xu   crypto: ahash - A...
382
383
384
385
386
  }
  
  static int ahash_def_finup(struct ahash_request *req)
  {
  	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
d4a7a0fbe   Marek Vasut   crypto: hash - Si...
387
  	int err;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
388

d4a7a0fbe   Marek Vasut   crypto: hash - Si...
389
390
391
  	err = ahash_save_req(req, ahash_def_finup_done1);
  	if (err)
  		return err;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
392

d4a7a0fbe   Marek Vasut   crypto: hash - Si...
393
394
  	err = tfm->update(req);
  	return ahash_def_finup_finish1(req, err);
66f6ce5e5   Herbert Xu   crypto: ahash - A...
395
396
397
398
399
400
401
402
403
404
405
  }
  
  static int ahash_no_export(struct ahash_request *req, void *out)
  {
  	return -ENOSYS;
  }
  
  static int ahash_no_import(struct ahash_request *req, const void *in)
  {
  	return -ENOSYS;
  }
88056ec34   Herbert Xu   crypto: ahash - C...
406
407
408
409
  static int crypto_ahash_init_tfm(struct crypto_tfm *tfm)
  {
  	struct crypto_ahash *hash = __crypto_ahash_cast(tfm);
  	struct ahash_alg *alg = crypto_ahash_alg(hash);
88056ec34   Herbert Xu   crypto: ahash - C...
410

66f6ce5e5   Herbert Xu   crypto: ahash - A...
411
  	hash->setkey = ahash_nosetkey;
a5596d633   Herbert Xu   crypto: hash - Ad...
412
  	hash->has_setkey = false;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
413
414
  	hash->export = ahash_no_export;
  	hash->import = ahash_no_import;
88056ec34   Herbert Xu   crypto: ahash - C...
415
416
  	if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
  		return crypto_init_shash_ops_async(tfm);
88056ec34   Herbert Xu   crypto: ahash - C...
417
418
  	hash->init = alg->init;
  	hash->update = alg->update;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
419
420
  	hash->final = alg->final;
  	hash->finup = alg->finup ?: ahash_def_finup;
88056ec34   Herbert Xu   crypto: ahash - C...
421
  	hash->digest = alg->digest;
66f6ce5e5   Herbert Xu   crypto: ahash - A...
422

a5596d633   Herbert Xu   crypto: hash - Ad...
423
  	if (alg->setkey) {
66f6ce5e5   Herbert Xu   crypto: ahash - A...
424
  		hash->setkey = alg->setkey;
a5596d633   Herbert Xu   crypto: hash - Ad...
425
426
  		hash->has_setkey = true;
  	}
66f6ce5e5   Herbert Xu   crypto: ahash - A...
427
428
429
430
  	if (alg->export)
  		hash->export = alg->export;
  	if (alg->import)
  		hash->import = alg->import;
88056ec34   Herbert Xu   crypto: ahash - C...
431
432
433
434
435
436
  
  	return 0;
  }
  
  static unsigned int crypto_ahash_extsize(struct crypto_alg *alg)
  {
2495cf25f   Herbert Xu   crypto: ahash - A...
437
438
  	if (alg->cra_type != &crypto_ahash_type)
  		return sizeof(struct crypto_shash *);
88056ec34   Herbert Xu   crypto: ahash - C...
439

2495cf25f   Herbert Xu   crypto: ahash - A...
440
  	return crypto_alg_extsize(alg);
88056ec34   Herbert Xu   crypto: ahash - C...
441
  }
3acc84739   Herbert Xu   crypto: algapi - ...
442
  #ifdef CONFIG_NET
6238cbaec   Steffen Klassert   crypto: Add users...
443
444
445
  static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
  {
  	struct crypto_report_hash rhash;
9a5467bf7   Mathias Krause   crypto: user - fi...
446
  	strncpy(rhash.type, "ahash", sizeof(rhash.type));
6238cbaec   Steffen Klassert   crypto: Add users...
447
448
449
  
  	rhash.blocksize = alg->cra_blocksize;
  	rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize;
6662df33f   David S. Miller   crypto: Stop usin...
450
451
452
  	if (nla_put(skb, CRYPTOCFGA_REPORT_HASH,
  		    sizeof(struct crypto_report_hash), &rhash))
  		goto nla_put_failure;
6238cbaec   Steffen Klassert   crypto: Add users...
453
454
455
456
457
  	return 0;
  
  nla_put_failure:
  	return -EMSGSIZE;
  }
3acc84739   Herbert Xu   crypto: algapi - ...
458
459
460
461
462
463
  #else
  static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg)
  {
  	return -ENOSYS;
  }
  #endif
6238cbaec   Steffen Klassert   crypto: Add users...
464

004a403c2   Loc Ho   [CRYPTO] hash: Ad...
465
466
467
468
469
470
471
472
473
474
475
  static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
  	__attribute__ ((unused));
  static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
  {
  	seq_printf(m, "type         : ahash
  ");
  	seq_printf(m, "async        : %s
  ", alg->cra_flags & CRYPTO_ALG_ASYNC ?
  					     "yes" : "no");
  	seq_printf(m, "blocksize    : %u
  ", alg->cra_blocksize);
88056ec34   Herbert Xu   crypto: ahash - C...
476
477
478
  	seq_printf(m, "digestsize   : %u
  ",
  		   __crypto_hash_alg_common(alg)->digestsize);
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
479
480
481
  }
  
  const struct crypto_type crypto_ahash_type = {
88056ec34   Herbert Xu   crypto: ahash - C...
482
483
  	.extsize = crypto_ahash_extsize,
  	.init_tfm = crypto_ahash_init_tfm,
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
484
485
486
  #ifdef CONFIG_PROC_FS
  	.show = crypto_ahash_show,
  #endif
6238cbaec   Steffen Klassert   crypto: Add users...
487
  	.report = crypto_ahash_report,
88056ec34   Herbert Xu   crypto: ahash - C...
488
489
490
491
  	.maskclear = ~CRYPTO_ALG_TYPE_MASK,
  	.maskset = CRYPTO_ALG_TYPE_AHASH_MASK,
  	.type = CRYPTO_ALG_TYPE_AHASH,
  	.tfmsize = offsetof(struct crypto_ahash, base),
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
492
493
  };
  EXPORT_SYMBOL_GPL(crypto_ahash_type);
88056ec34   Herbert Xu   crypto: ahash - C...
494
495
496
497
498
499
  struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type,
  					u32 mask)
  {
  	return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask);
  }
  EXPORT_SYMBOL_GPL(crypto_alloc_ahash);
8d18e34c1   Herbert Xu   crypto: hash - Ad...
500
501
502
503
504
  int crypto_has_ahash(const char *alg_name, u32 type, u32 mask)
  {
  	return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask);
  }
  EXPORT_SYMBOL_GPL(crypto_has_ahash);
01c2dece4   Herbert Xu   crypto: ahash - A...
505
506
507
508
509
  static int ahash_prepare_alg(struct ahash_alg *alg)
  {
  	struct crypto_alg *base = &alg->halg.base;
  
  	if (alg->halg.digestsize > PAGE_SIZE / 8 ||
8996eafdc   Russell King   crypto: ahash - e...
510
511
  	    alg->halg.statesize > PAGE_SIZE / 8 ||
  	    alg->halg.statesize == 0)
01c2dece4   Herbert Xu   crypto: ahash - A...
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
  		return -EINVAL;
  
  	base->cra_type = &crypto_ahash_type;
  	base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK;
  	base->cra_flags |= CRYPTO_ALG_TYPE_AHASH;
  
  	return 0;
  }
  
  int crypto_register_ahash(struct ahash_alg *alg)
  {
  	struct crypto_alg *base = &alg->halg.base;
  	int err;
  
  	err = ahash_prepare_alg(alg);
  	if (err)
  		return err;
  
  	return crypto_register_alg(base);
  }
  EXPORT_SYMBOL_GPL(crypto_register_ahash);
  
  int crypto_unregister_ahash(struct ahash_alg *alg)
  {
  	return crypto_unregister_alg(&alg->halg.base);
  }
  EXPORT_SYMBOL_GPL(crypto_unregister_ahash);
  
  int ahash_register_instance(struct crypto_template *tmpl,
  			    struct ahash_instance *inst)
  {
  	int err;
  
  	err = ahash_prepare_alg(&inst->alg);
  	if (err)
  		return err;
  
  	return crypto_register_instance(tmpl, ahash_crypto_instance(inst));
  }
  EXPORT_SYMBOL_GPL(ahash_register_instance);
  
  void ahash_free_instance(struct crypto_instance *inst)
  {
  	crypto_drop_spawn(crypto_instance_ctx(inst));
  	kfree(ahash_instance(inst));
  }
  EXPORT_SYMBOL_GPL(ahash_free_instance);
  
  int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn,
  			    struct hash_alg_common *alg,
  			    struct crypto_instance *inst)
  {
  	return crypto_init_spawn2(&spawn->base, &alg->base, inst,
  				  &crypto_ahash_type);
  }
  EXPORT_SYMBOL_GPL(crypto_init_ahash_spawn);
  
  struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask)
  {
  	struct crypto_alg *alg;
  
  	alg = crypto_attr_alg2(rta, &crypto_ahash_type, type, mask);
  	return IS_ERR(alg) ? ERR_CAST(alg) : __crypto_hash_alg_common(alg);
  }
  EXPORT_SYMBOL_GPL(ahash_attr_alg);
004a403c2   Loc Ho   [CRYPTO] hash: Ad...
577
578
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Asynchronous cryptographic hash type");