Skip to content

Commit

Permalink
crypto: hash - Added scatter list walking helper
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
herbertx committed Jul 10, 2008
1 parent b8454ee commit 2003625
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 1 deletion.
91 changes: 90 additions & 1 deletion crypto/ahash.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
*
*/

#include <crypto/algapi.h>
#include <crypto/internal/hash.h>
#include <crypto/scatterwalk.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
Expand All @@ -23,6 +24,94 @@

#include "internal.h"

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);

walk->data = crypto_kmap(walk->pg, 0);
walk->data += offset;

if (offset & alignmask)
nbytes = alignmask + 1 - (offset & alignmask);

walk->entrylen -= nbytes;
return nbytes;
}

static int hash_walk_new_entry(struct crypto_hash_walk *walk)
{
struct scatterlist *sg;

sg = walk->sg;
walk->pg = sg_page(sg);
walk->offset = sg->offset;
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) {
walk->offset += alignmask - 1;
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;
}

crypto_kunmap(walk->data, 0);
crypto_yield(walk->flags);

if (err)
return err;

walk->offset = 0;

if (nbytes)
return hash_walk_next(walk);

if (!walk->total)
return 0;

walk->sg = scatterwalk_sg_next(walk->sg);

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;

if (!walk->total)
return 0;

walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req));
walk->sg = req->src;
walk->flags = req->base.flags;

return hash_walk_new_entry(walk);
}
EXPORT_SYMBOL_GPL(crypto_hash_walk_first);

static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen)
{
Expand Down
41 changes: 41 additions & 0 deletions include/crypto/internal/hash.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Hash algorithms.
*
* Copyright (c) 2008 Herbert Xu <[email protected]>
*
* 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.
*
*/

#ifndef _CRYPTO_INTERNAL_HASH_H
#define _CRYPTO_INTERNAL_HASH_H

#include <crypto/algapi.h>

struct ahash_request;
struct scatterlist;

struct crypto_hash_walk {
char *data;

unsigned int offset;
unsigned int alignmask;

struct page *pg;
unsigned int entrylen;

unsigned int total;
struct scatterlist *sg;

unsigned int flags;
};

int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err);
int crypto_hash_walk_first(struct ahash_request *req,
struct crypto_hash_walk *walk);

#endif /* _CRYPTO_INTERNAL_HASH_H */

0 comments on commit 2003625

Please sign in to comment.