Commit 20036252fc61c624a49770fb89684ea5cfdfa05e
1 parent
b8454eebe3
Exists in
master
and in
39 other branches
crypto: hash - Added scatter list walking helper
This patch adds the walking helpers for hash algorithms akin to those of block ciphers. This is a necessary step before we can reimplement existing hash algorithms using the new ahash interface. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Showing 2 changed files with 131 additions and 1 deletions Side-by-side Diff
crypto/ahash.c
... | ... | @@ -13,7 +13,8 @@ |
13 | 13 | * |
14 | 14 | */ |
15 | 15 | |
16 | -#include <crypto/algapi.h> | |
16 | +#include <crypto/internal/hash.h> | |
17 | +#include <crypto/scatterwalk.h> | |
17 | 18 | #include <linux/err.h> |
18 | 19 | #include <linux/kernel.h> |
19 | 20 | #include <linux/module.h> |
... | ... | @@ -22,6 +23,94 @@ |
22 | 23 | #include <linux/seq_file.h> |
23 | 24 | |
24 | 25 | #include "internal.h" |
26 | + | |
27 | +static int hash_walk_next(struct crypto_hash_walk *walk) | |
28 | +{ | |
29 | + unsigned int alignmask = walk->alignmask; | |
30 | + unsigned int offset = walk->offset; | |
31 | + unsigned int nbytes = min(walk->entrylen, | |
32 | + ((unsigned int)(PAGE_SIZE)) - offset); | |
33 | + | |
34 | + walk->data = crypto_kmap(walk->pg, 0); | |
35 | + walk->data += offset; | |
36 | + | |
37 | + if (offset & alignmask) | |
38 | + nbytes = alignmask + 1 - (offset & alignmask); | |
39 | + | |
40 | + walk->entrylen -= nbytes; | |
41 | + return nbytes; | |
42 | +} | |
43 | + | |
44 | +static int hash_walk_new_entry(struct crypto_hash_walk *walk) | |
45 | +{ | |
46 | + struct scatterlist *sg; | |
47 | + | |
48 | + sg = walk->sg; | |
49 | + walk->pg = sg_page(sg); | |
50 | + walk->offset = sg->offset; | |
51 | + walk->entrylen = sg->length; | |
52 | + | |
53 | + if (walk->entrylen > walk->total) | |
54 | + walk->entrylen = walk->total; | |
55 | + walk->total -= walk->entrylen; | |
56 | + | |
57 | + return hash_walk_next(walk); | |
58 | +} | |
59 | + | |
60 | +int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) | |
61 | +{ | |
62 | + unsigned int alignmask = walk->alignmask; | |
63 | + unsigned int nbytes = walk->entrylen; | |
64 | + | |
65 | + walk->data -= walk->offset; | |
66 | + | |
67 | + if (nbytes && walk->offset & alignmask && !err) { | |
68 | + walk->offset += alignmask - 1; | |
69 | + walk->offset = ALIGN(walk->offset, alignmask + 1); | |
70 | + walk->data += walk->offset; | |
71 | + | |
72 | + nbytes = min(nbytes, | |
73 | + ((unsigned int)(PAGE_SIZE)) - walk->offset); | |
74 | + walk->entrylen -= nbytes; | |
75 | + | |
76 | + return nbytes; | |
77 | + } | |
78 | + | |
79 | + crypto_kunmap(walk->data, 0); | |
80 | + crypto_yield(walk->flags); | |
81 | + | |
82 | + if (err) | |
83 | + return err; | |
84 | + | |
85 | + walk->offset = 0; | |
86 | + | |
87 | + if (nbytes) | |
88 | + return hash_walk_next(walk); | |
89 | + | |
90 | + if (!walk->total) | |
91 | + return 0; | |
92 | + | |
93 | + walk->sg = scatterwalk_sg_next(walk->sg); | |
94 | + | |
95 | + return hash_walk_new_entry(walk); | |
96 | +} | |
97 | +EXPORT_SYMBOL_GPL(crypto_hash_walk_done); | |
98 | + | |
99 | +int crypto_hash_walk_first(struct ahash_request *req, | |
100 | + struct crypto_hash_walk *walk) | |
101 | +{ | |
102 | + walk->total = req->nbytes; | |
103 | + | |
104 | + if (!walk->total) | |
105 | + return 0; | |
106 | + | |
107 | + walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req)); | |
108 | + walk->sg = req->src; | |
109 | + walk->flags = req->base.flags; | |
110 | + | |
111 | + return hash_walk_new_entry(walk); | |
112 | +} | |
113 | +EXPORT_SYMBOL_GPL(crypto_hash_walk_first); | |
25 | 114 | |
26 | 115 | static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, |
27 | 116 | unsigned int keylen) |
include/crypto/internal/hash.h
1 | +/* | |
2 | + * Hash algorithms. | |
3 | + * | |
4 | + * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au> | |
5 | + * | |
6 | + * This program is free software; you can redistribute it and/or modify it | |
7 | + * under the terms of the GNU General Public License as published by the Free | |
8 | + * Software Foundation; either version 2 of the License, or (at your option) | |
9 | + * any later version. | |
10 | + * | |
11 | + */ | |
12 | + | |
13 | +#ifndef _CRYPTO_INTERNAL_HASH_H | |
14 | +#define _CRYPTO_INTERNAL_HASH_H | |
15 | + | |
16 | +#include <crypto/algapi.h> | |
17 | + | |
18 | +struct ahash_request; | |
19 | +struct scatterlist; | |
20 | + | |
21 | +struct crypto_hash_walk { | |
22 | + char *data; | |
23 | + | |
24 | + unsigned int offset; | |
25 | + unsigned int alignmask; | |
26 | + | |
27 | + struct page *pg; | |
28 | + unsigned int entrylen; | |
29 | + | |
30 | + unsigned int total; | |
31 | + struct scatterlist *sg; | |
32 | + | |
33 | + unsigned int flags; | |
34 | +}; | |
35 | + | |
36 | +int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err); | |
37 | +int crypto_hash_walk_first(struct ahash_request *req, | |
38 | + struct crypto_hash_walk *walk); | |
39 | + | |
40 | +#endif /* _CRYPTO_INTERNAL_HASH_H */ |