diff options
author | Loc Ho <lho@amcc.com> | 2008-05-14 08:41:47 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2008-07-10 08:35:13 -0400 |
commit | 004a403c2e954734090a69aedc7f4f822bdcc142 (patch) | |
tree | e8fadd76113132126e308e01e7cd7cdf6b9d44d6 /crypto | |
parent | 534fe2c1c3ffbbc3db66dba0783c82d3b345fd33 (diff) |
[CRYPTO] hash: Add asynchronous hash support
This patch adds asynchronous hash and digest support.
Signed-off-by: Loc Ho <lho@amcc.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/Makefile | 1 | ||||
-rw-r--r-- | crypto/ahash.c | 106 | ||||
-rw-r--r-- | crypto/api.c | 8 | ||||
-rw-r--r-- | crypto/digest.c | 81 | ||||
-rw-r--r-- | crypto/hash.c | 102 | ||||
-rw-r--r-- | crypto/internal.h | 1 |
6 files changed, 288 insertions, 11 deletions
diff --git a/crypto/Makefile b/crypto/Makefile index 807656b64e02..d4f3ed857df0 100644 --- a/crypto/Makefile +++ b/crypto/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o | |||
19 | obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o | 19 | obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o |
20 | 20 | ||
21 | crypto_hash-objs := hash.o | 21 | crypto_hash-objs := hash.o |
22 | crypto_hash-objs += ahash.o | ||
22 | obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o | 23 | obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o |
23 | 24 | ||
24 | obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o | 25 | obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o |
diff --git a/crypto/ahash.c b/crypto/ahash.c new file mode 100644 index 000000000000..a83e035d9a3f --- /dev/null +++ b/crypto/ahash.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * Asynchronous Cryptographic Hash operations. | ||
3 | * | ||
4 | * This is the asynchronous version of hash.c with notification of | ||
5 | * completion via a callback. | ||
6 | * | ||
7 | * Copyright (c) 2008 Loc Ho <lho@amcc.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify it | ||
10 | * under the terms of the GNU General Public License as published by the Free | ||
11 | * Software Foundation; either version 2 of the License, or (at your option) | ||
12 | * any later version. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <crypto/algapi.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/sched.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/seq_file.h> | ||
23 | |||
24 | #include "internal.h" | ||
25 | |||
26 | static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, | ||
27 | unsigned int keylen) | ||
28 | { | ||
29 | struct ahash_alg *ahash = crypto_ahash_alg(tfm); | ||
30 | unsigned long alignmask = crypto_ahash_alignmask(tfm); | ||
31 | int ret; | ||
32 | u8 *buffer, *alignbuffer; | ||
33 | unsigned long absize; | ||
34 | |||
35 | absize = keylen + alignmask; | ||
36 | buffer = kmalloc(absize, GFP_ATOMIC); | ||
37 | if (!buffer) | ||
38 | return -ENOMEM; | ||
39 | |||
40 | alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); | ||
41 | memcpy(alignbuffer, key, keylen); | ||
42 | ret = ahash->setkey(tfm, alignbuffer, keylen); | ||
43 | memset(alignbuffer, 0, keylen); | ||
44 | kfree(buffer); | ||
45 | return ret; | ||
46 | } | ||
47 | |||
48 | static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, | ||
49 | unsigned int keylen) | ||
50 | { | ||
51 | struct ahash_alg *ahash = crypto_ahash_alg(tfm); | ||
52 | unsigned long alignmask = crypto_ahash_alignmask(tfm); | ||
53 | |||
54 | if ((unsigned long)key & alignmask) | ||
55 | return ahash_setkey_unaligned(tfm, key, keylen); | ||
56 | |||
57 | return ahash->setkey(tfm, key, keylen); | ||
58 | } | ||
59 | |||
60 | static unsigned int crypto_ahash_ctxsize(struct crypto_alg *alg, u32 type, | ||
61 | u32 mask) | ||
62 | { | ||
63 | return alg->cra_ctxsize; | ||
64 | } | ||
65 | |||
66 | static int crypto_init_ahash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) | ||
67 | { | ||
68 | struct ahash_alg *alg = &tfm->__crt_alg->cra_ahash; | ||
69 | struct ahash_tfm *crt = &tfm->crt_ahash; | ||
70 | |||
71 | if (alg->digestsize > crypto_tfm_alg_blocksize(tfm)) | ||
72 | return -EINVAL; | ||
73 | |||
74 | crt->init = alg->init; | ||
75 | crt->update = alg->update; | ||
76 | crt->final = alg->final; | ||
77 | crt->digest = alg->digest; | ||
78 | crt->setkey = ahash_setkey; | ||
79 | crt->base = __crypto_ahash_cast(tfm); | ||
80 | crt->digestsize = alg->digestsize; | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) | ||
86 | __attribute__ ((unused)); | ||
87 | static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) | ||
88 | { | ||
89 | seq_printf(m, "type : ahash\n"); | ||
90 | seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? | ||
91 | "yes" : "no"); | ||
92 | seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); | ||
93 | seq_printf(m, "digestsize : %u\n", alg->cra_hash.digestsize); | ||
94 | } | ||
95 | |||
96 | const struct crypto_type crypto_ahash_type = { | ||
97 | .ctxsize = crypto_ahash_ctxsize, | ||
98 | .init = crypto_init_ahash_ops, | ||
99 | #ifdef CONFIG_PROC_FS | ||
100 | .show = crypto_ahash_show, | ||
101 | #endif | ||
102 | }; | ||
103 | EXPORT_SYMBOL_GPL(crypto_ahash_type); | ||
104 | |||
105 | MODULE_LICENSE("GPL"); | ||
106 | MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); | ||
diff --git a/crypto/api.c b/crypto/api.c index 0a0f41ef255f..d06e33270abe 100644 --- a/crypto/api.c +++ b/crypto/api.c | |||
@@ -235,8 +235,12 @@ static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask) | |||
235 | return crypto_init_cipher_ops(tfm); | 235 | return crypto_init_cipher_ops(tfm); |
236 | 236 | ||
237 | case CRYPTO_ALG_TYPE_DIGEST: | 237 | case CRYPTO_ALG_TYPE_DIGEST: |
238 | return crypto_init_digest_ops(tfm); | 238 | if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) != |
239 | 239 | CRYPTO_ALG_TYPE_HASH_MASK) | |
240 | return crypto_init_digest_ops_async(tfm); | ||
241 | else | ||
242 | return crypto_init_digest_ops(tfm); | ||
243 | |||
240 | case CRYPTO_ALG_TYPE_COMPRESS: | 244 | case CRYPTO_ALG_TYPE_COMPRESS: |
241 | return crypto_init_compress_ops(tfm); | 245 | return crypto_init_compress_ops(tfm); |
242 | 246 | ||
diff --git a/crypto/digest.c b/crypto/digest.c index b526cc348b79..025c9aea24ed 100644 --- a/crypto/digest.c +++ b/crypto/digest.c | |||
@@ -157,3 +157,84 @@ int crypto_init_digest_ops(struct crypto_tfm *tfm) | |||
157 | void crypto_exit_digest_ops(struct crypto_tfm *tfm) | 157 | void crypto_exit_digest_ops(struct crypto_tfm *tfm) |
158 | { | 158 | { |
159 | } | 159 | } |
160 | |||
161 | static int digest_async_nosetkey(struct crypto_ahash *tfm_async, const u8 *key, | ||
162 | unsigned int keylen) | ||
163 | { | ||
164 | crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK); | ||
165 | return -ENOSYS; | ||
166 | } | ||
167 | |||
168 | static int digest_async_setkey(struct crypto_ahash *tfm_async, const u8 *key, | ||
169 | unsigned int keylen) | ||
170 | { | ||
171 | struct crypto_tfm *tfm = crypto_ahash_tfm(tfm_async); | ||
172 | struct digest_alg *dalg = &tfm->__crt_alg->cra_digest; | ||
173 | |||
174 | crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK); | ||
175 | return dalg->dia_setkey(tfm, key, keylen); | ||
176 | } | ||
177 | |||
178 | static int digest_async_init(struct ahash_request *req) | ||
179 | { | ||
180 | struct crypto_tfm *tfm = req->base.tfm; | ||
181 | struct digest_alg *dalg = &tfm->__crt_alg->cra_digest; | ||
182 | |||
183 | dalg->dia_init(tfm); | ||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int digest_async_update(struct ahash_request *req) | ||
188 | { | ||
189 | struct crypto_tfm *tfm = req->base.tfm; | ||
190 | struct hash_desc desc = { | ||
191 | .tfm = __crypto_hash_cast(tfm), | ||
192 | .flags = req->base.flags, | ||
193 | }; | ||
194 | |||
195 | update(&desc, req->src, req->nbytes); | ||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int digest_async_final(struct ahash_request *req) | ||
200 | { | ||
201 | struct crypto_tfm *tfm = req->base.tfm; | ||
202 | struct hash_desc desc = { | ||
203 | .tfm = __crypto_hash_cast(tfm), | ||
204 | .flags = req->base.flags, | ||
205 | }; | ||
206 | |||
207 | final(&desc, req->result); | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int digest_async_digest(struct ahash_request *req) | ||
212 | { | ||
213 | struct crypto_tfm *tfm = req->base.tfm; | ||
214 | struct hash_desc desc = { | ||
215 | .tfm = __crypto_hash_cast(tfm), | ||
216 | .flags = req->base.flags, | ||
217 | }; | ||
218 | |||
219 | return digest(&desc, req->src, req->nbytes, req->result); | ||
220 | } | ||
221 | |||
222 | int crypto_init_digest_ops_async(struct crypto_tfm *tfm) | ||
223 | { | ||
224 | struct ahash_tfm *crt = &tfm->crt_ahash; | ||
225 | struct digest_alg *dalg = &tfm->__crt_alg->cra_digest; | ||
226 | |||
227 | if (dalg->dia_digestsize > crypto_tfm_alg_blocksize(tfm)) | ||
228 | return -EINVAL; | ||
229 | |||
230 | crt->init = digest_async_init; | ||
231 | crt->update = digest_async_update; | ||
232 | crt->final = digest_async_final; | ||
233 | crt->digest = digest_async_digest; | ||
234 | crt->setkey = dalg->dia_setkey ? digest_async_setkey : | ||
235 | digest_async_nosetkey; | ||
236 | crt->digestsize = dalg->dia_digestsize; | ||
237 | crt->base = __crypto_ahash_cast(tfm); | ||
238 | |||
239 | return 0; | ||
240 | } | ||
diff --git a/crypto/hash.c b/crypto/hash.c index 7dcff671c19b..f9400a014e74 100644 --- a/crypto/hash.c +++ b/crypto/hash.c | |||
@@ -59,24 +59,108 @@ static int hash_setkey(struct crypto_hash *crt, const u8 *key, | |||
59 | return alg->setkey(crt, key, keylen); | 59 | return alg->setkey(crt, key, keylen); |
60 | } | 60 | } |
61 | 61 | ||
62 | static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) | 62 | static int hash_async_setkey(struct crypto_ahash *tfm_async, const u8 *key, |
63 | unsigned int keylen) | ||
64 | { | ||
65 | struct crypto_tfm *tfm = crypto_ahash_tfm(tfm_async); | ||
66 | struct crypto_hash *tfm_hash = __crypto_hash_cast(tfm); | ||
67 | struct hash_alg *alg = &tfm->__crt_alg->cra_hash; | ||
68 | |||
69 | return alg->setkey(tfm_hash, key, keylen); | ||
70 | } | ||
71 | |||
72 | static int hash_async_init(struct ahash_request *req) | ||
73 | { | ||
74 | struct crypto_tfm *tfm = req->base.tfm; | ||
75 | struct hash_alg *alg = &tfm->__crt_alg->cra_hash; | ||
76 | struct hash_desc desc = { | ||
77 | .tfm = __crypto_hash_cast(tfm), | ||
78 | .flags = req->base.flags, | ||
79 | }; | ||
80 | |||
81 | return alg->init(&desc); | ||
82 | } | ||
83 | |||
84 | static int hash_async_update(struct ahash_request *req) | ||
85 | { | ||
86 | struct crypto_tfm *tfm = req->base.tfm; | ||
87 | struct hash_alg *alg = &tfm->__crt_alg->cra_hash; | ||
88 | struct hash_desc desc = { | ||
89 | .tfm = __crypto_hash_cast(tfm), | ||
90 | .flags = req->base.flags, | ||
91 | }; | ||
92 | |||
93 | return alg->update(&desc, req->src, req->nbytes); | ||
94 | } | ||
95 | |||
96 | static int hash_async_final(struct ahash_request *req) | ||
97 | { | ||
98 | struct crypto_tfm *tfm = req->base.tfm; | ||
99 | struct hash_alg *alg = &tfm->__crt_alg->cra_hash; | ||
100 | struct hash_desc desc = { | ||
101 | .tfm = __crypto_hash_cast(tfm), | ||
102 | .flags = req->base.flags, | ||
103 | }; | ||
104 | |||
105 | return alg->final(&desc, req->result); | ||
106 | } | ||
107 | |||
108 | static int hash_async_digest(struct ahash_request *req) | ||
109 | { | ||
110 | struct crypto_tfm *tfm = req->base.tfm; | ||
111 | struct hash_alg *alg = &tfm->__crt_alg->cra_hash; | ||
112 | struct hash_desc desc = { | ||
113 | .tfm = __crypto_hash_cast(tfm), | ||
114 | .flags = req->base.flags, | ||
115 | }; | ||
116 | |||
117 | return alg->digest(&desc, req->src, req->nbytes, req->result); | ||
118 | } | ||
119 | |||
120 | static int crypto_init_hash_ops_async(struct crypto_tfm *tfm) | ||
121 | { | ||
122 | struct ahash_tfm *crt = &tfm->crt_ahash; | ||
123 | struct hash_alg *alg = &tfm->__crt_alg->cra_hash; | ||
124 | |||
125 | crt->init = hash_async_init; | ||
126 | crt->update = hash_async_update; | ||
127 | crt->final = hash_async_final; | ||
128 | crt->digest = hash_async_digest; | ||
129 | crt->setkey = hash_async_setkey; | ||
130 | crt->digestsize = alg->digestsize; | ||
131 | crt->base = __crypto_ahash_cast(tfm); | ||
132 | |||
133 | return 0; | ||
134 | } | ||
135 | |||
136 | static int crypto_init_hash_ops_sync(struct crypto_tfm *tfm) | ||
63 | { | 137 | { |
64 | struct hash_tfm *crt = &tfm->crt_hash; | 138 | struct hash_tfm *crt = &tfm->crt_hash; |
65 | struct hash_alg *alg = &tfm->__crt_alg->cra_hash; | 139 | struct hash_alg *alg = &tfm->__crt_alg->cra_hash; |
66 | 140 | ||
67 | if (alg->digestsize > crypto_tfm_alg_blocksize(tfm)) | 141 | crt->init = alg->init; |
68 | return -EINVAL; | 142 | crt->update = alg->update; |
69 | 143 | crt->final = alg->final; | |
70 | crt->init = alg->init; | 144 | crt->digest = alg->digest; |
71 | crt->update = alg->update; | 145 | crt->setkey = hash_setkey; |
72 | crt->final = alg->final; | ||
73 | crt->digest = alg->digest; | ||
74 | crt->setkey = hash_setkey; | ||
75 | crt->digestsize = alg->digestsize; | 146 | crt->digestsize = alg->digestsize; |
76 | 147 | ||
77 | return 0; | 148 | return 0; |
78 | } | 149 | } |
79 | 150 | ||
151 | static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask) | ||
152 | { | ||
153 | struct hash_alg *alg = &tfm->__crt_alg->cra_hash; | ||
154 | |||
155 | if (alg->digestsize > crypto_tfm_alg_blocksize(tfm)) | ||
156 | return -EINVAL; | ||
157 | |||
158 | if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) != CRYPTO_ALG_TYPE_HASH_MASK) | ||
159 | return crypto_init_hash_ops_async(tfm); | ||
160 | else | ||
161 | return crypto_init_hash_ops_sync(tfm); | ||
162 | } | ||
163 | |||
80 | static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg) | 164 | static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg) |
81 | __attribute__ ((unused)); | 165 | __attribute__ ((unused)); |
82 | static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg) | 166 | static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg) |
diff --git a/crypto/internal.h b/crypto/internal.h index 32f4c2145603..683fcb2d91f4 100644 --- a/crypto/internal.h +++ b/crypto/internal.h | |||
@@ -86,6 +86,7 @@ struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask); | |||
86 | struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask); | 86 | struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask); |
87 | 87 | ||
88 | int crypto_init_digest_ops(struct crypto_tfm *tfm); | 88 | int crypto_init_digest_ops(struct crypto_tfm *tfm); |
89 | int crypto_init_digest_ops_async(struct crypto_tfm *tfm); | ||
89 | int crypto_init_cipher_ops(struct crypto_tfm *tfm); | 90 | int crypto_init_cipher_ops(struct crypto_tfm *tfm); |
90 | int crypto_init_compress_ops(struct crypto_tfm *tfm); | 91 | int crypto_init_compress_ops(struct crypto_tfm *tfm); |
91 | 92 | ||