Commit 20036252fc61c624a49770fb89684ea5cfdfa05e

Authored by Herbert Xu
1 parent b8454eebe3

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

... ... @@ -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 */