aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2009-07-15 00:40:40 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2009-07-15 00:40:40 -0400
commit66f6ce5e52f2f209d5bf1f06167cec888f4f4c13 (patch)
treeaa7b21af00649d2f458b72ebfba071816cb340c3
parent093900c2b964da73daf234374225b5ce5d49f941 (diff)
crypto: ahash - Add unaligned handling and default operations
This patch exports the finup operation where available and adds a default finup operation for ahash. The operations final, finup and digest also will now deal with unaligned result pointers by copying it. Finally export/import operations are will now be exported too. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
-rw-r--r--crypto/ahash.c204
-rw-r--r--crypto/shash.c52
-rw-r--r--include/crypto/hash.h23
-rw-r--r--include/crypto/internal/hash.h6
4 files changed, 263 insertions, 22 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
27struct ahash_request_priv {
28 crypto_completion_t complete;
29 void *data;
30 u8 *result;
31 void *ubuf[] CRYPTO_MINALIGN_ATTR;
32};
33
27static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) 34static 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
159static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key, 166int 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}
177EXPORT_SYMBOL_GPL(crypto_ahash_setkey);
170 178
171static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, 179static 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
185static 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
191static 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
205static 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
217static 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
247static 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
259int crypto_ahash_final(struct ahash_request *req)
260{
261 return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final);
262}
263EXPORT_SYMBOL_GPL(crypto_ahash_final);
264
265int crypto_ahash_finup(struct ahash_request *req)
266{
267 return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup);
268}
269EXPORT_SYMBOL_GPL(crypto_ahash_finup);
270
271int crypto_ahash_digest(struct ahash_request *req)
272{
273 return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest);
274}
275EXPORT_SYMBOL_GPL(crypto_ahash_digest);
276
277static 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
291static 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
303static 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
312out:
313 ahash_def_finup_finish2(req, err);
314 return err;
315}
316
317static 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
329static 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
354static int ahash_no_export(struct ahash_request *req, void *out)
355{
356 return -ENOSYS;
357}
358
359static int ahash_no_import(struct ahash_request *req, const void *in)
360{
361 return -ENOSYS;
362}
363
177static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) 364static 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}
diff --git a/crypto/shash.c b/crypto/shash.c
index 171c8f052f89..834d9d24cdae 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -235,6 +235,33 @@ static int shash_async_final(struct ahash_request *req)
235 return crypto_shash_final(ahash_request_ctx(req), req->result); 235 return crypto_shash_final(ahash_request_ctx(req), req->result);
236} 236}
237 237
238int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc)
239{
240 struct crypto_hash_walk walk;
241 int nbytes;
242
243 for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0;
244 nbytes = crypto_hash_walk_done(&walk, nbytes))
245 nbytes = crypto_hash_walk_last(&walk) ?
246 crypto_shash_finup(desc, walk.data, nbytes,
247 req->result) :
248 crypto_shash_update(desc, walk.data, nbytes);
249
250 return nbytes;
251}
252EXPORT_SYMBOL_GPL(shash_ahash_finup);
253
254static int shash_async_finup(struct ahash_request *req)
255{
256 struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
257 struct shash_desc *desc = ahash_request_ctx(req);
258
259 desc->tfm = *ctx;
260 desc->flags = req->base.flags;
261
262 return shash_ahash_finup(req, desc);
263}
264
238int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) 265int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc)
239{ 266{
240 struct scatterlist *sg = req->src; 267 struct scatterlist *sg = req->src;
@@ -252,8 +279,7 @@ int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc)
252 crypto_yield(desc->flags); 279 crypto_yield(desc->flags);
253 } else 280 } else
254 err = crypto_shash_init(desc) ?: 281 err = crypto_shash_init(desc) ?:
255 shash_ahash_update(req, desc) ?: 282 shash_ahash_finup(req, desc);
256 crypto_shash_final(desc, req->result);
257 283
258 return err; 284 return err;
259} 285}
@@ -270,6 +296,16 @@ static int shash_async_digest(struct ahash_request *req)
270 return shash_ahash_digest(req, desc); 296 return shash_ahash_digest(req, desc);
271} 297}
272 298
299static int shash_async_export(struct ahash_request *req, void *out)
300{
301 return crypto_shash_export(ahash_request_ctx(req), out);
302}
303
304static int shash_async_import(struct ahash_request *req, const void *in)
305{
306 return crypto_shash_import(ahash_request_ctx(req), in);
307}
308
273static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm) 309static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm)
274{ 310{
275 struct crypto_shash **ctx = crypto_tfm_ctx(tfm); 311 struct crypto_shash **ctx = crypto_tfm_ctx(tfm);
@@ -280,6 +316,7 @@ static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm)
280int crypto_init_shash_ops_async(struct crypto_tfm *tfm) 316int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
281{ 317{
282 struct crypto_alg *calg = tfm->__crt_alg; 318 struct crypto_alg *calg = tfm->__crt_alg;
319 struct shash_alg *alg = __crypto_shash_alg(calg);
283 struct crypto_ahash *crt = __crypto_ahash_cast(tfm); 320 struct crypto_ahash *crt = __crypto_ahash_cast(tfm);
284 struct crypto_shash **ctx = crypto_tfm_ctx(tfm); 321 struct crypto_shash **ctx = crypto_tfm_ctx(tfm);
285 struct crypto_shash *shash; 322 struct crypto_shash *shash;
@@ -298,9 +335,16 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
298 335
299 crt->init = shash_async_init; 336 crt->init = shash_async_init;
300 crt->update = shash_async_update; 337 crt->update = shash_async_update;
301 crt->final = shash_async_final; 338 crt->final = shash_async_final;
339 crt->finup = shash_async_finup;
302 crt->digest = shash_async_digest; 340 crt->digest = shash_async_digest;
303 crt->setkey = shash_async_setkey; 341
342 if (alg->setkey)
343 crt->setkey = shash_async_setkey;
344 if (alg->export)
345 crt->export = shash_async_export;
346 if (alg->setkey)
347 crt->import = shash_async_import;
304 348
305 crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash); 349 crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash);
306 350
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 45c2bddfdf32..3e89ce16b59c 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -31,6 +31,9 @@ struct ahash_request {
31 struct scatterlist *src; 31 struct scatterlist *src;
32 u8 *result; 32 u8 *result;
33 33
34 /* This field may only be used by the ahash API code. */
35 void *priv;
36
34 void *__ctx[] CRYPTO_MINALIGN_ATTR; 37 void *__ctx[] CRYPTO_MINALIGN_ATTR;
35}; 38};
36 39
@@ -175,16 +178,11 @@ static inline void *ahash_request_ctx(struct ahash_request *req)
175 return req->__ctx; 178 return req->__ctx;
176} 179}
177 180
178static inline int crypto_ahash_setkey(struct crypto_ahash *tfm, 181int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
179 const u8 *key, unsigned int keylen) 182 unsigned int keylen);
180{ 183int crypto_ahash_finup(struct ahash_request *req);
181 return tfm->setkey(tfm, key, keylen); 184int crypto_ahash_final(struct ahash_request *req);
182} 185int crypto_ahash_digest(struct ahash_request *req);
183
184static inline int crypto_ahash_digest(struct ahash_request *req)
185{
186 return crypto_ahash_reqtfm(req)->digest(req);
187}
188 186
189static inline int crypto_ahash_export(struct ahash_request *req, void *out) 187static inline int crypto_ahash_export(struct ahash_request *req, void *out)
190{ 188{
@@ -206,11 +204,6 @@ static inline int crypto_ahash_update(struct ahash_request *req)
206 return crypto_ahash_reqtfm(req)->update(req); 204 return crypto_ahash_reqtfm(req)->update(req);
207} 205}
208 206
209static inline int crypto_ahash_final(struct ahash_request *req)
210{
211 return crypto_ahash_reqtfm(req)->final(req);
212}
213
214static inline void ahash_request_set_tfm(struct ahash_request *req, 207static inline void ahash_request_set_tfm(struct ahash_request *req,
215 struct crypto_ahash *tfm) 208 struct crypto_ahash *tfm)
216{ 209{
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index 179dd8fdfa14..5bfad8c80595 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -59,6 +59,11 @@ int crypto_hash_walk_first_compat(struct hash_desc *hdesc,
59 struct crypto_hash_walk *walk, 59 struct crypto_hash_walk *walk,
60 struct scatterlist *sg, unsigned int len); 60 struct scatterlist *sg, unsigned int len);
61 61
62static inline int crypto_hash_walk_last(struct crypto_hash_walk *walk)
63{
64 return !(walk->entrylen | walk->total);
65}
66
62int crypto_register_ahash(struct ahash_alg *alg); 67int crypto_register_ahash(struct ahash_alg *alg);
63int crypto_unregister_ahash(struct ahash_alg *alg); 68int crypto_unregister_ahash(struct ahash_alg *alg);
64int ahash_register_instance(struct crypto_template *tmpl, 69int ahash_register_instance(struct crypto_template *tmpl,
@@ -94,6 +99,7 @@ static inline void crypto_drop_shash(struct crypto_shash_spawn *spawn)
94struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask); 99struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask);
95 100
96int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc); 101int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc);
102int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc);
97int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc); 103int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc);
98 104
99int crypto_init_shash_ops_async(struct crypto_tfm *tfm); 105int crypto_init_shash_ops_async(struct crypto_tfm *tfm);