All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Loc Ho" <locnho@sbcglobal.net>
To: "Herbert Xu" <herbert@gondor.apana.org.au>
Cc: <linux-crypto@vger.kernel.org>,
	"'Sebastian Siewior'" <linux-crypto@ml.breakpoint.cc>
Subject: [PATCH 1/1] CryptoAPI: Add Async Hash Support
Date: Thu, 24 Jan 2008 18:45:25 -0800	[thread overview]
Message-ID: <004a01c85efc$56f2ee70$5c05420a@amcc.com> (raw)
In-Reply-To: <004601c85ecd$1eb53d80$5c05420a@amcc.com>

From e5d67c3670f1ec15339a92cc291027c0a059aaed Mon Sep 17 00:00:00 2001
From: Loc Ho <lho@amcc.com>
Date: Thu, 24 Jan 2008 18:13:28 -0800
Subject: [PATCH] Add Async Hash Support

---
 crypto/Makefile               |    1 +
 crypto/ahash.c                |  151 +++++++++++++++++
 crypto/algapi.c               |    2 +-
 crypto/api.c                  |    2 +-
 crypto/cryptd.c               |  220 +++++++++++++++++++++++++
 crypto/digest.c               |    4 +-
 crypto/hash.c                 |  102 +++++++++++-
 crypto/tcrypt.c               |  142 ++++++++++++++++-
 drivers/crypto/Kconfig        |    8 +-
 drivers/crypto/Makefile       |    1 +
 drivers/crypto/ahash_sample.c |  354
+++++++++++++++++++++++++++++++++++++++++
 include/crypto/algapi.h       |   36 ++++
 include/linux/crypto.h        |  183 ++++++++++++++++++++-
 13 files changed, 1183 insertions(+), 23 deletions(-)
 create mode 100644 crypto/ahash.c
 create mode 100644 drivers/crypto/ahash_sample.c

diff --git a/crypto/Makefile b/crypto/Makefile
index 48c7583..a9c3d09 100644
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER) += eseqiv.o
 obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
 
 crypto_hash-objs := hash.o
+crypto_hash-objs += ahash.o
 obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
 
 obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
diff --git a/crypto/ahash.c b/crypto/ahash.c
new file mode 100644
index 0000000..e9bf72f
--- /dev/null
+++ b/crypto/ahash.c
@@ -0,0 +1,151 @@
+/*
+ * Asynchronous Cryptographic Hash operations.
+ *
+ * This is the asynchronous version of hash.c with notification of
+ * completion via a callback.
+ *
+ * Copyright (c) 2008 Loc Ho <lho@amcc.com>
+ *
+ * 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.
+ *
+ */
+
+#include <crypto/algapi.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/seq_file.h>
+
+#include "internal.h"
+
+static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key,
+				unsigned int keylen)
+{
+	struct ahash_alg *ahash = crypto_ahash_alg(tfm);
+	unsigned long alignmask = crypto_ahash_alignmask(tfm);
+	int ret;
+	u8 *buffer, *alignbuffer;
+	unsigned long absize;
+
+	absize = keylen + alignmask;
+	buffer = kmalloc(absize, GFP_ATOMIC);
+	if (!buffer)
+		return -ENOMEM;
+
+	alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+	memcpy(alignbuffer, key, keylen);
+	ret = ahash->setkey(tfm, alignbuffer, keylen);
+	memset(alignbuffer, 0, keylen);
+	kfree(buffer);
+	return ret;
+}
+
+static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
+			unsigned int keylen)
+{
+	struct ahash_alg *ahash = crypto_ahash_alg(tfm);
+	unsigned long alignmask = crypto_ahash_alignmask(tfm);
+
+	if ((unsigned long)key & alignmask)
+		return ahash_setkey_unaligned(tfm, key, keylen);
+
+	return ahash->setkey(tfm, key, keylen);
+}
+
+static unsigned int crypto_ahash_ctxsize(struct crypto_alg *alg, u32 type,
+					u32 mask)
+{
+	return alg->cra_ctxsize;
+}
+
+static int crypto_init_ahash_ops(struct crypto_tfm *tfm, u32 type, u32
mask)
+{
+	struct ahash_alg *alg = &tfm->__crt_alg->cra_ahash;
+	struct ahash_tfm *crt   = &tfm->crt_ahash;
+
+	if (alg->digestsize > crypto_tfm_alg_blocksize(tfm))
+		return -EINVAL;
+
+	crt->init = alg->init;
+	crt->update = alg->update;
+	crt->final  = alg->final;
+	crt->digest = alg->digest;
+	crt->setkey = ahash_setkey;
+	crt->base   = __crypto_ahash_cast(tfm);
+	crt->digestsize = alg->digestsize;
+
+	return 0;
+}
+
+static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
+	__attribute__ ((unused));
+static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
+{
+	seq_printf(m, "type         : hash\n");
+	seq_printf(m, "async        : %s\n", alg->cra_flags &
CRYPTO_ALG_ASYNC ?
+					     "yes" : "no");
+	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
+	seq_printf(m, "digestsize   : %u\n", alg->cra_hash.digestsize);
+}
+
+const struct crypto_type crypto_ahash_type = {
+	.ctxsize = crypto_ahash_ctxsize,
+	.init = crypto_init_ahash_ops,
+#ifdef CONFIG_PROC_FS
+	.show = crypto_ahash_show,
+#endif
+};
+EXPORT_SYMBOL_GPL(crypto_ahash_type);
+
+struct crypto_ahash *crypto_alloc_ahash(const char *alg_name,
+					u32 type, u32 mask)
+{
+	struct crypto_tfm *tfm;
+	int err;
+
+	mask &= ~CRYPTO_ALG_TYPE_MASK;
+	mask |= CRYPTO_ALG_TYPE_HASH_MASK;
+
+	for (;;) {
+		struct crypto_alg *alg;
+
+		type &= ~CRYPTO_ALG_TYPE_MASK;
+		type |= CRYPTO_ALG_TYPE_AHASH;
+		alg = crypto_alg_mod_lookup(alg_name, type, mask);
+		if (IS_ERR(alg)) {
+			type &= ~CRYPTO_ALG_TYPE_MASK;
+			type |= CRYPTO_ALG_TYPE_HASH;
+			alg = crypto_alg_mod_lookup(alg_name, type, mask);
+			if (IS_ERR(alg)) {
+				err = PTR_ERR(alg);
+				goto err;
+			}
+		}
+
+		tfm = __crypto_alloc_tfm(alg, type, mask |
CRYPTO_ALG_ASYNC);
+		if (!IS_ERR(tfm))
+			return __crypto_ahash_cast(tfm);
+
+		crypto_mod_put(alg);
+		err = PTR_ERR(tfm);
+
+err:
+		if (err != -EAGAIN)
+			break;
+		if (signal_pending(current)) {
+			err = -EINTR;
+			break;
+		}
+	}
+
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_ahash);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
diff --git a/crypto/algapi.c b/crypto/algapi.c
index e65cb50..5fdb974 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -182,7 +182,7 @@ static int __crypto_register_alg(struct crypto_alg *alg,
 
 		crypto_remove_spawns(&q->cra_users, list, alg->cra_flags);
 	}
-	
+
 	list_add(&alg->cra_list, &crypto_alg_list);
 
 	crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
diff --git a/crypto/api.c b/crypto/api.c
index a2496d1..c3213f4 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -10,7 +10,7 @@
  *
  * 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) 
+ * Software Foundation; either version 2 of the License, or (at your
option)
  * any later version.
  *
  */
diff --git a/crypto/cryptd.c b/crypto/cryptd.c
index 074298f..cdf57c8 100644
--- a/crypto/cryptd.c
+++ b/crypto/cryptd.c
@@ -45,6 +45,14 @@ struct cryptd_blkcipher_request_ctx {
 	crypto_completion_t complete;
 };
 
+struct cryptd_hash_ctx {
+	struct crypto_hash *child;
+};
+
+struct cryptd_hash_request_ctx {
+	crypto_completion_t complete;
+	struct hash_desc    desc;
+};
 
 static inline struct cryptd_state *cryptd_get_state(struct crypto_tfm *tfm)
 {
@@ -259,6 +267,216 @@ out_put_alg:
 	return inst;
 }
 
+static int cryptd_hash_init_tfm(struct crypto_tfm *tfm)
+{
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
+	struct cryptd_instance_ctx *ictx = crypto_instance_ctx(inst);
+	struct crypto_spawn *spawn = &ictx->spawn;
+	struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct crypto_hash *cipher;
+
+	cipher = crypto_spawn_hash(spawn);
+	if (IS_ERR(cipher))
+		return PTR_ERR(cipher);
+
+	ctx->child = cipher;
+	tfm->crt_ahash.reqsize =
+		sizeof(struct cryptd_hash_request_ctx);
+	return 0;
+}
+
+static void cryptd_hash_exit_tfm(struct crypto_tfm *tfm)
+{
+	struct cryptd_hash_ctx *ctx = crypto_tfm_ctx(tfm);
+	struct cryptd_state *state = cryptd_get_state(tfm);
+	int active;
+
+	mutex_lock(&state->mutex);
+	active = ahash_tfm_in_queue(&state->queue,
+				__crypto_ahash_cast(tfm));
+	mutex_unlock(&state->mutex);
+
+	BUG_ON(active);
+
+	crypto_free_hash(ctx->child);
+}
+
+static int cryptd_hash_setkey(struct crypto_ahash *parent,
+				   const u8 *key, unsigned int keylen)
+{
+	struct cryptd_hash_ctx *ctx   = crypto_ahash_ctx(parent);
+	struct crypto_hash     *child = ctx->child;
+	int err;
+
+	crypto_hash_clear_flags(child, CRYPTO_TFM_REQ_MASK);
+	crypto_hash_set_flags(child, crypto_ahash_get_flags(parent) &
+					  CRYPTO_TFM_REQ_MASK);
+	err = crypto_hash_setkey(child, key, keylen);
+	crypto_ahash_set_flags(parent, crypto_hash_get_flags(child) &
+					    CRYPTO_TFM_RES_MASK);
+	return err;
+}
+
+static int cryptd_hash_init(struct ahash_request *req)
+{
+	struct cryptd_hash_ctx *ctx   = ahash_request_ctx(req);
+	struct crypto_hash     *child = ctx->child;
+	struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+	int err;
+
+	err = crypto_hash_crt(child)->init(&rctx->desc);
+	rctx->desc.flags |= CRYPTO_TFM_REQ_MAY_SLEEP;
+	return err;
+}
+
+static int cryptd_hash_enqueue(struct ahash_request *req,
+				crypto_completion_t complete)
+{
+	struct cryptd_hash_request_ctx *rctx = ahash_request_ctx(req);
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct cryptd_state *state =
+		cryptd_get_state(crypto_ahash_tfm(tfm));
+	int err;
+
+	rctx->complete = req->base.complete;
+	req->base.complete = complete;
+
+	spin_lock_bh(&state->lock);
+	err = ahash_enqueue_request(&state->queue, req);
+	spin_unlock_bh(&state->lock);
+
+	wake_up_process(state->task);
+	return err;
+}
+
+static void cryptd_hash_update(struct crypto_async_request *req_async, int
err)
+{
+	struct cryptd_hash_ctx *ctx   = crypto_tfm_ctx(req_async->tfm);
+	struct crypto_hash     *child = ctx->child;
+	struct ahash_request    *req = ahash_request_cast(req_async);
+	struct cryptd_hash_request_ctx *rctx;
+
+	rctx = ahash_request_ctx(req);
+
+	if (unlikely(err == -EINPROGRESS)) {
+		rctx->complete(&req->base, err);
+		return;
+	}
+
+	err = crypto_hash_crt(child)->update(&rctx->desc,
+						req->src,
+						req->nbytes);
+
+	req->base.complete = rctx->complete;
+
+	local_bh_disable();
+	req->base.complete(&req->base, err);
+	local_bh_enable();
+}
+
+static int cryptd_hash_update_enqueue(struct ahash_request *req)
+{
+	return cryptd_hash_enqueue(req, cryptd_hash_update);
+}
+
+static void cryptd_hash_final(struct crypto_async_request *req_async, int
err)
+{
+	struct cryptd_hash_ctx *ctx   = crypto_tfm_ctx(req_async->tfm);
+	struct crypto_hash     *child = ctx->child;
+	struct ahash_request    *req = ahash_request_cast(req_async);
+	struct cryptd_hash_request_ctx *rctx;
+
+	rctx = ahash_request_ctx(req);
+
+	if (unlikely(err == -EINPROGRESS)) {
+		rctx->complete(&req->base, err);
+		return;
+	}
+
+	err = crypto_hash_crt(child)->final(&rctx->desc, req->result);
+
+	req->base.complete = rctx->complete;
+
+	local_bh_disable();
+	req->base.complete(&req->base, err);
+	local_bh_enable();
+}
+
+static int cryptd_hash_final_enqueue(struct ahash_request *req)
+{
+	return cryptd_hash_enqueue(req, cryptd_hash_final);
+}
+
+static void cryptd_hash_digest(struct crypto_async_request *req_async, int
err)
+{
+	struct cryptd_hash_ctx *ctx   = crypto_tfm_ctx(req_async->tfm);
+	struct crypto_hash     *child = ctx->child;
+	struct ahash_request    *req = ahash_request_cast(req_async);
+	struct cryptd_hash_request_ctx *rctx;
+	struct hash_desc desc;
+
+	rctx = ahash_request_ctx(req);
+
+	if (unlikely(err == -EINPROGRESS)) {
+		rctx->complete(&req->base, err);
+		return;
+	}
+
+	desc.tfm = child;
+	desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	err = crypto_hash_crt(child)->digest(&desc,
+						req->src,
+						req->nbytes,
+						req->result);
+
+	req->base.complete = rctx->complete;
+
+	local_bh_disable();
+	req->base.complete(&req->base, err);
+	local_bh_enable();
+}
+
+static int cryptd_hash_digest_enqueue(struct ahash_request *req)
+{
+	return cryptd_hash_enqueue(req, cryptd_hash_digest);
+}
+
+static struct crypto_instance *cryptd_alloc_hash(
+	struct rtattr **tb, struct cryptd_state *state)
+{
+	struct crypto_instance *inst;
+	struct crypto_alg *alg;
+
+	alg = crypto_get_attr_alg(tb, CRYPTO_ALG_TYPE_HASH,
+				  CRYPTO_ALG_TYPE_MASK);
+	if (IS_ERR(alg))
+		return ERR_PTR(PTR_ERR(alg));
+
+	inst = cryptd_alloc_instance(alg, state);
+	if (IS_ERR(inst))
+		goto out_put_alg;
+
+	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC;
+	inst->alg.cra_type = &crypto_ahash_type;
+
+	inst->alg.cra_ahash.digestsize = alg->cra_hash.digestsize;
+	inst->alg.cra_ctxsize = sizeof(struct cryptd_hash_ctx);
+
+	inst->alg.cra_init = cryptd_hash_init_tfm;
+	inst->alg.cra_exit = cryptd_hash_exit_tfm;
+
+	inst->alg.cra_ahash.init   = cryptd_hash_init;
+	inst->alg.cra_ahash.update = cryptd_hash_update_enqueue;
+	inst->alg.cra_ahash.final  = cryptd_hash_final_enqueue;
+	inst->alg.cra_ahash.setkey = cryptd_hash_setkey;
+	inst->alg.cra_ahash.digest = cryptd_hash_digest_enqueue;
+
+out_put_alg:
+	crypto_mod_put(alg);
+	return inst;
+}
+
 static struct cryptd_state state;
 
 static struct crypto_instance *cryptd_alloc(struct rtattr **tb)
@@ -272,6 +490,8 @@ static struct crypto_instance *cryptd_alloc(struct
rtattr **tb)
 	switch (algt->type & algt->mask & CRYPTO_ALG_TYPE_MASK) {
 	case CRYPTO_ALG_TYPE_BLKCIPHER:
 		return cryptd_alloc_blkcipher(tb, &state);
+	case CRYPTO_ALG_TYPE_HASH:
+		return cryptd_alloc_hash(tb, &state);
 	}
 
 	return ERR_PTR(-EINVAL);
diff --git a/crypto/digest.c b/crypto/digest.c
index 6fd43bd..19b7ade 100644
--- a/crypto/digest.c
+++ b/crypto/digest.c
@@ -141,14 +141,14 @@ int crypto_init_digest_ops(struct crypto_tfm *tfm)
 
 	if (dalg->dia_digestsize > crypto_tfm_alg_blocksize(tfm))
 		return -EINVAL;
-	
+
 	ops->init	= init;
 	ops->update	= update;
 	ops->final	= final;
 	ops->digest	= digest;
 	ops->setkey	= dalg->dia_setkey ? setkey : nosetkey;
 	ops->digestsize	= dalg->dia_digestsize;
-	
+
 	return 0;
 }
 
diff --git a/crypto/hash.c b/crypto/hash.c
index 7dcff67..6df8a8c 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -59,24 +59,108 @@ static int hash_setkey(struct crypto_hash *crt, const
u8 *key,
 	return alg->setkey(crt, key, keylen);
 }
 
-static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+static int hash_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
+			unsigned int keylen)
+{
+	struct crypto_tfm  *tfm      = crypto_ahash_tfm(tfm_async);
+	struct crypto_hash *tfm_hash = __crypto_hash_cast(tfm);
+	struct hash_alg    *alg      = &tfm->__crt_alg->cra_hash;
+
+	return alg->setkey(tfm_hash, key, keylen);
+}
+
+static int hash_async_init(struct ahash_request *req)
+{
+	struct crypto_tfm *tfm = req->base.tfm;
+	struct hash_alg   *alg = &tfm->__crt_alg->cra_hash;
+	struct hash_desc  desc = {
+		.tfm = __crypto_hash_cast(tfm),
+		.flags = req->base.flags,
+	};
+
+	return alg->init(&desc);
+}
+
+static int hash_async_update(struct ahash_request *req)
+{
+	struct crypto_tfm *tfm = req->base.tfm;
+	struct hash_alg   *alg = &tfm->__crt_alg->cra_hash;
+	struct hash_desc  desc = {
+		.tfm = __crypto_hash_cast(tfm),
+		.flags = req->base.flags,
+	};
+
+	return alg->update(&desc, req->src, req->nbytes);
+}
+
+static int hash_async_final(struct ahash_request *req)
+{
+	struct crypto_tfm *tfm = req->base.tfm;
+	struct hash_alg   *alg = &tfm->__crt_alg->cra_hash;
+	struct hash_desc  desc = {
+		.tfm = __crypto_hash_cast(tfm),
+		.flags = req->base.flags,
+	};
+
+	return alg->final(&desc, req->result);
+}
+
+static int hash_async_digest(struct ahash_request *req)
+{
+	struct crypto_tfm *tfm = req->base.tfm;
+	struct hash_alg   *alg = &tfm->__crt_alg->cra_hash;
+	struct hash_desc  desc = {
+		.tfm = __crypto_hash_cast(tfm),
+		.flags = req->base.flags,
+	};
+
+	return alg->digest(&desc, req->src, req->nbytes, req->result);
+}
+
+static int crypto_init_hash_ops_async(struct crypto_tfm *tfm)
+{
+	struct ahash_tfm *crt = &tfm->crt_ahash;
+	struct hash_alg  *alg = &tfm->__crt_alg->cra_hash;
+
+	crt->init       = hash_async_init;
+	crt->update     = hash_async_update;
+	crt->final      = hash_async_final;
+	crt->digest     = hash_async_digest;
+	crt->setkey     = hash_async_setkey;
+	crt->digestsize = alg->digestsize;
+	crt->base       = __crypto_ahash_cast(tfm);
+
+	return 0;
+}
+
+static int crypto_init_hash_ops_sync(struct crypto_tfm *tfm)
 {
 	struct hash_tfm *crt = &tfm->crt_hash;
 	struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
 
-	if (alg->digestsize > crypto_tfm_alg_blocksize(tfm))
-		return -EINVAL;
-
-	crt->init = alg->init;
-	crt->update = alg->update;
-	crt->final = alg->final;
-	crt->digest = alg->digest;
-	crt->setkey = hash_setkey;
+	crt->init       = alg->init;
+	crt->update     = alg->update;
+	crt->final      = alg->final;
+	crt->digest     = alg->digest;
+	crt->setkey     = hash_setkey;
 	crt->digestsize = alg->digestsize;
 
 	return 0;
 }
 
+static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
+{
+	struct hash_alg *alg = &tfm->__crt_alg->cra_hash;
+
+	if (alg->digestsize > crypto_tfm_alg_blocksize(tfm))
+		return -EINVAL;
+
+	if (mask & CRYPTO_ALG_ASYNC)
+		return crypto_init_hash_ops_async(tfm);
+	else
+		return crypto_init_hash_ops_sync(tfm);
+}
+
 static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
 	__attribute__ ((unused));
 static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
diff --git a/crypto/tcrypt.c b/crypto/tcrypt.c
index 1ab8c01..784f0b5 100644
--- a/crypto/tcrypt.c
+++ b/crypto/tcrypt.c
@@ -35,6 +35,7 @@
 #include <linux/jiffies.h>
 #include <linux/timex.h>
 #include <linux/interrupt.h>
+#include <linux/delay.h>
 #include "tcrypt.h"
 
 /*
@@ -220,6 +221,98 @@ out:
 	crypto_free_hash(tfm);
 }
 
+static void test_ahash(char *algo, struct hash_testvec *template,
+		      unsigned int tcount)
+{
+	struct hash_testvec  *hash_tv;
+	struct crypto_ahash  *tfm = NULL;
+	struct ahash_request *req = NULL;
+	struct tcrypt_result result;
+	struct scatterlist   sg[8];
+	char 		digest_result[tcount][4*16];
+	unsigned int 	tsize;
+	unsigned int 	i;
+	int 		ret;
+
+	printk(KERN_INFO "\ntesting %s\n", algo);
+
+	tsize = sizeof(struct hash_testvec);
+	tsize *= tcount;
+	if (tsize > TVMEMSIZE) {
+		printk(KERN_ERR "template (%u) too big for tvmem (%u)\n",
+			tsize, TVMEMSIZE);
+		return;
+	}
+	memcpy(tvmem, template, tsize);
+	hash_tv = (void *)tvmem;
+
+	init_completion(&result.completion);
+
+	tfm = crypto_alloc_ahash(algo, 0, 0);
+	if (IS_ERR(tfm)) {
+		printk(KERN_ERR "failed to load transform for %s: %ld\n",
algo,
+		       PTR_ERR(tfm));
+		return;
+	}
+	req = ahash_request_alloc(tfm, GFP_KERNEL);
+	if (!req) {
+		printk(KERN_ERR "failed to allocate request for %s\n",
algo);
+		goto out;
+	}
+	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
+				tcrypt_complete, &result);
+
+	for (i = 0; i < tcount; i++) {
+		printk(KERN_INFO "test %u:\n", i + 1);
+		memset(&digest_result[i], 0, 4*16);
+		crypto_ahash_clear_flags(tfm, ~0);
+		if (hash_tv[i].ksize) {
+			ret = crypto_ahash_setkey(tfm, hash_tv[i].key,
+						 hash_tv[i].ksize);
+			if (ret) {
+				printk(KERN_ERR "setkey() failed error
%d\n",
+					ret);
+				goto out;
+			}
+		}
+
+		sg_init_one(&sg[0], hash_tv[i].plaintext, hash_tv[i].psize);
+
+		ahash_request_set_crypt(req, sg, digest_result[i],
+					hash_tv[i].psize);
+
+		ret = crypto_ahash_digest(req);
+		switch (ret) {
+		case 0:
+			break;
+		case -EINPROGRESS:
+		case -EBUSY:
+			ret = wait_for_completion_interruptible(
+				&result.completion);
+			if (!ret && !((ret = result.err))) {
+				INIT_COMPLETION(result.completion);
+				break;
+			}
+			/* fall through */
+		default:
+			printk(KERN_ERR "hash() failed error %d\n", ret);
+			goto out;
+		}
+
+		hexdump(digest_result[i], crypto_ahash_digestsize(tfm));
+		printk(KERN_INFO "%s\n",
+		       memcmp(digest_result[i], hash_tv[i].digest,
+			      crypto_ahash_digestsize(tfm)) ?
+		       "fail" : "pass");
+	}
+
+out:
+	if (req)
+		ahash_request_free(req);
+
+	crypto_free_ahash(tfm);
+}
+
 static void test_aead(char *algo, int enc, struct aead_testvec *template,
 		      unsigned int tcount)
 {
@@ -471,7 +564,7 @@ static void test_cipher(char *algo, int enc,
 	else
 		e = "decryption";
 
-	printk("\ntesting %s %s\n", algo, e);
+	printk(KERN_INFO "\ntesting cipher %s %s\n", algo, e);
 
 	tsize = sizeof (struct cipher_testvec);
 	if (tsize > TVMEMSIZE) {
@@ -1619,6 +1712,51 @@ static void do_test(void)
 			  XCBC_AES_TEST_VECTORS);
 		break;
 
+	case 110:
+		test_ahash("hmac(md5)", hmac_md5_tv_template,
+			  HMAC_MD5_TEST_VECTORS);
+		break;
+
+	case 111:
+		test_ahash("hmac(sha1)", hmac_sha1_tv_template,
+			  HMAC_SHA1_TEST_VECTORS);
+		break;
+
+	case 112:
+		test_ahash("hmac(sha256)", hmac_sha256_tv_template,
+			  HMAC_SHA256_TEST_VECTORS);
+		break;
+
+	case 113:
+		test_ahash("hmac(sha384)", hmac_sha384_tv_template,
+			  HMAC_SHA384_TEST_VECTORS);
+		break;
+
+	case 114:
+		test_ahash("hmac(sha512)", hmac_sha512_tv_template,
+			  HMAC_SHA512_TEST_VECTORS);
+		break;
+
+	case 115:
+		test_ahash("hmac(sha224)", hmac_sha224_tv_template,
+			  HMAC_SHA224_TEST_VECTORS);
+		break;
+
+	case 120:
+		test_ahash("hmac(md5)", hmac_md5_tv_template,
+			  HMAC_MD5_TEST_VECTORS);
+		test_ahash("hmac(sha1)", hmac_sha1_tv_template,
+			  HMAC_SHA1_TEST_VECTORS);
+		test_ahash("hmac(sha224)", hmac_sha224_tv_template,
+			  HMAC_SHA224_TEST_VECTORS);
+		test_ahash("hmac(sha256)", hmac_sha256_tv_template,
+			  HMAC_SHA256_TEST_VECTORS);
+		test_ahash("hmac(sha384)", hmac_sha384_tv_template,
+			  HMAC_SHA384_TEST_VECTORS);
+		test_ahash("hmac(sha512)", hmac_sha512_tv_template,
+			  HMAC_SHA512_TEST_VECTORS);
+		break;
+
 	case 200:
 		test_cipher_speed("ecb(aes)", ENCRYPT, sec, NULL, 0,
 				  aes_speed_template);
@@ -1795,7 +1933,7 @@ static int __init init(void)
 
 	/* We intentionaly return -EAGAIN to prevent keeping
 	 * the module. It does all its work from init()
-	 * and doesn't offer any runtime functionality 
+	 * and doesn't offer any runtime functionality
 	 * => we don't need it in the memory, do we?
 	 *                                        -- mludvig
 	 */
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index d8c7040..21e4234 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -92,6 +92,12 @@ config CRYPTO_DEV_HIFN_795X
 	help
 	  This option allows you to have support for HIFN 795x crypto
adapters.
 
-
+config CRYPTO_DEV_AHASH_SAMPLE
+	tristate "Asynchronous HASH sample driver over software synchronous
HASH"
+	select CRYPTO_HASH
+	select CRYPTO_ALGAPI
+	help
+	  This is a sample asynchronous HASH device driver over synchronous
software
+          HASH.
 
 endif # CRYPTO_HW
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index c0327f0..0b1cc2f 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o
 obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o
 obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o
 obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o
+obj-$(CONFIG_CRYPTO_DEV_AHASH_SAMPLE) += ahash_sample.o
diff --git a/drivers/crypto/ahash_sample.c b/drivers/crypto/ahash_sample.c
new file mode 100644
index 0000000..0c1ad60
--- /dev/null
+++ b/drivers/crypto/ahash_sample.c
@@ -0,0 +1,354 @@
+/*
+ * Sample Asynchronous device driver that wraps around software sync HASH
+ *
+ * 2008 Copyright (c) Loc Ho <lho@amcc.com>
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
USA
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mod_devicetable.h>
+#include <linux/interrupt.h>
+#include <linux/highmem.h>
+#include <linux/scatterlist.h>
+#include <linux/crypto.h>
+#include <crypto/algapi.h>
+
+struct ahash_sample_device {
+	char			name[64];
+	struct tasklet_struct	tasklet;
+	struct crypto_queue 	queue;
+	spinlock_t		lock;		/**< Queue lock protection
*/
+	struct list_head	alg_list;
+};
+
+#define AHASH_SAMPLE_OP_DIGEST	0
+#define AHASH_SAMPLE_OP_UPDATE	1
+#define AHASH_SAMPLE_OP_FINAL	2
+
+struct ahash_sample_context {
+	struct ahash_sample_device *dev;
+	u8			key[16];
+	unsigned int		keysize;
+	struct crypto_hash 	*sync_tfm;
+	struct hash_desc 	desc;
+	u8	ops;
+};
+
+struct ahash_sample_alg {
+	struct list_head    	entry;
+	struct crypto_alg   	alg;
+	struct ahash_sample_device *dev;
+};
+
+static struct ahash_sample_device *ahash_sample_dev;
+
+#define crypto_alg_to_ahash_sample_alg(a)	container_of(a, \
+						struct ahash_sample_alg, \
+						alg)
+
+static int ahash_sample_alg_init(struct crypto_tfm *tfm)
+{
+	struct crypto_alg    *alg          = tfm->__crt_alg;
+	struct ahash_sample_alg *ahash_alg = crypto_alg_to_ahash_sample_alg(
+
alg);
+	struct ahash_sample_context *ctx   = crypto_tfm_ctx(tfm);
+
+	ctx->dev      = ahash_alg->dev;
+	ctx->sync_tfm = crypto_alloc_hash(alg->cra_name, 0,
CRYPTO_ALG_ASYNC);
+	if (IS_ERR(ctx->sync_tfm)) {
+		printk(KERN_ERR
+			"AHASH_SAMPLE: failed to load transform for %s:
%ld\n",
+			alg->cra_name, PTR_ERR(ctx->sync_tfm));
+		return -ENOMEM;
+	}
+	printk(KERN_INFO "AHASH_SAMPLE: initialize alg %s\n",
alg->cra_name);
+	return 0;
+}
+
+static void ahash_sample_alg_exit(struct crypto_tfm *tfm)
+{
+	struct crypto_alg           *alg = tfm->__crt_alg;
+	struct ahash_sample_context *ctx = crypto_tfm_ctx(tfm);
+
+	printk(KERN_INFO "AHASH_SAMPLE: exit alg %s\n", alg->cra_name);
+
+	if (ctx->sync_tfm) {
+		crypto_free_hash(ctx->sync_tfm);
+		ctx->sync_tfm = NULL;
+		ctx->dev      = NULL;
+	}
+}
+
+static int ahash_sample_ops_setkey(struct crypto_ahash *cipher, const u8
*key,
+			unsigned int keylen)
+{
+	struct crypto_tfm           *tfm = crypto_ahash_tfm(cipher);
+	struct ahash_sample_context *ctx = crypto_tfm_ctx(tfm);
+	int    ret;
+
+	printk(KERN_INFO "AHASH_SAMPLE: setkey\n");
+
+	ret = crypto_hash_setkey(ctx->sync_tfm, key, keylen);
+	if (ret) {
+		printk(KERN_ERR
+			"aynchronous hash generic setkey failed error %d\n",
+			ret);
+		return -1;
+	}
+	return ret;
+}
+
+static inline int ahash_sample_ops_init(struct ahash_request *req)
+{
+	struct ahash_sample_context *ctx = crypto_tfm_ctx(req->base.tfm);
+
+	printk(KERN_INFO "AHASH_SAMPLE: init\n");
+
+	ctx->desc.tfm   = ctx->sync_tfm;
+	ctx->desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+	return crypto_hash_init(&ctx->desc);
+}
+
+static inline int ahash_sample_ops_update(struct ahash_request *req)
+{
+	struct ahash_sample_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	unsigned long flags;
+	int ret;
+
+	printk(KERN_INFO "AHASH_SAMPLE: update\n");
+
+	ctx->ops = AHASH_SAMPLE_OP_UPDATE;
+	spin_lock_irqsave(&ctx->dev->lock, flags);
+	ret = ahash_enqueue_request(&ctx->dev->queue, req);
+	spin_unlock_irqrestore(&ctx->dev->lock, flags);
+
+	tasklet_schedule(&ctx->dev->tasklet);
+	return ret;
+}
+
+static inline int ahash_sample_ops_final(struct ahash_request *req)
+{
+	struct ahash_sample_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	unsigned long flags;
+	int ret;
+
+	printk(KERN_INFO "AHASH_SAMPLE: final\n");
+
+	ctx->ops = AHASH_SAMPLE_OP_FINAL;
+	spin_lock_irqsave(&ctx->dev->lock, flags);
+	ret = ahash_enqueue_request(&ctx->dev->queue, req);
+	spin_unlock_irqrestore(&ctx->dev->lock, flags);
+
+	tasklet_schedule(&ctx->dev->tasklet);
+	return ret;
+}
+
+static inline int ahash_sample_ops_digest(struct ahash_request *req)
+{
+	struct ahash_sample_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	unsigned long flags;
+	int ret;
+
+	printk(KERN_INFO "AHASH_SAMPLE: digest\n");
+
+	ctx->ops = AHASH_SAMPLE_OP_DIGEST;
+	spin_lock_irqsave(&ctx->dev->lock, flags);
+	ret = ahash_enqueue_request(&ctx->dev->queue, req);
+	spin_unlock_irqrestore(&ctx->dev->lock, flags);
+
+	tasklet_schedule(&ctx->dev->tasklet);
+	return ret;
+}
+
+static int ahash_sample_handle_req(struct ahash_request *req)
+{
+	struct ahash_sample_context *ctx = crypto_tfm_ctx(req->base.tfm);
+	struct hash_desc desc;
+	int    ret;
+
+	desc.tfm   = ctx->sync_tfm;
+	desc.flags = 0;
+	switch (ctx->ops) {
+	case AHASH_SAMPLE_OP_UPDATE:
+		ret = crypto_hash_update(&desc, req->src, req->nbytes);
+		break;
+	case AHASH_SAMPLE_OP_FINAL:
+		ret = crypto_hash_final(&desc, req->result);
+		break;
+	case AHASH_SAMPLE_OP_DIGEST:
+	default:
+		ret = crypto_hash_digest(&desc, req->src,
+					req->nbytes, req->result);
+		break;
+	}
+	if (ret) {
+		printk(KERN_ERR "AHASH_SAMPLE: "
+			"asynchronous hash generic digest failed error
%d\n",
+			ret);
+		return ret;
+	}
+	return 0;
+}
+
+static void ahash_sample_bh_tasklet_cb(unsigned long data)
+{
+	struct ahash_sample_device  *dev = (struct ahash_sample_device *)
data;
+	struct crypto_async_request *async_req;
+	struct ahash_sample_context *ctx;
+	struct ahash_request        *req;
+	unsigned long 	flags;
+	int 		err;
+
+	while (1) {
+		spin_lock_irqsave(&dev->lock, flags);
+		async_req = crypto_dequeue_request(&dev->queue);
+		spin_unlock_irqrestore(&dev->lock, flags);
+
+		if (!async_req)
+			break;
+
+		ctx = crypto_tfm_ctx(async_req->tfm);
+		req = container_of(async_req, struct ahash_request, base);
+
+		/* Process the request */
+		err = ahash_sample_handle_req(req);
+
+		/* Notify packet completed */
+		req->base.complete(&req->base, err);
+	}
+}
+
+static struct crypto_alg ahash_sample_alg_tbl[] =
+{
+	{ .cra_name		= "hmac(md5)",
+	  .cra_driver_name	= "ahash-md5",
+	  .cra_priority		= 300,
+	  .cra_flags		= CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC,
+	  .cra_blocksize	= 64, /* MD5-HMAC block size is 512-bits */
+	  .cra_ctxsize		= sizeof(struct ahash_sample_context),
+	  .cra_alignmask 	= 0,
+	  .cra_type		= &crypto_ahash_type,
+	  .cra_module		= THIS_MODULE,
+	  .cra_u		= { .ahash = {
+	  .digestsize		= 16, /* Disgest is 128-bits */
+	  .init   		= ahash_sample_ops_init,
+	  .update   		= ahash_sample_ops_update,
+	  .final   		= ahash_sample_ops_final,
+	  .digest 		= ahash_sample_ops_digest,
+	  .setkey		= ahash_sample_ops_setkey,
+	  } },
+	},
+	{ .cra_name		= "" }
+};
+
+static void ahash_sample_unregister_alg(struct ahash_sample_device *dev)
+{
+	struct ahash_sample_alg *alg, *tmp;
+
+	list_for_each_entry_safe(alg, tmp, &dev->alg_list, entry) {
+		list_del(&alg->entry);
+		crypto_unregister_alg(&alg->alg);
+		kfree(alg);
+	}
+}
+
+static int ahash_sample_register_alg(struct ahash_sample_device *dev)
+{
+	struct ahash_sample_alg *alg;
+	int i;
+	int rc = 0;
+
+	for (i = 0; ahash_sample_alg_tbl[i].cra_name[0] != '\0'; i++) {
+		alg = kzalloc(sizeof(struct ahash_sample_alg), GFP_KERNEL);
+		if (!alg)
+			return -ENOMEM;
+
+		alg->alg 		= ahash_sample_alg_tbl[i];
+		INIT_LIST_HEAD(&alg->alg.cra_list);
+		alg->dev 		= dev;
+		alg->alg.cra_init	= ahash_sample_alg_init;
+		alg->alg.cra_exit	= ahash_sample_alg_exit;
+		list_add_tail(&alg->entry, &dev->alg_list);
+		rc = crypto_register_alg(&alg->alg);
+		if (rc) {
+			printk(KERN_ERR
+				"AHASH_SAMPLE: failed to register alg
%s.%s",
+				ahash_sample_alg_tbl[i].cra_driver_name,
+				ahash_sample_alg_tbl[i].cra_name);
+
+			list_del(&alg->entry);
+			kfree(alg);
+			return rc;
+		}
+	}
+	return rc;
+}
+
+static int __devinit ahash_sample_init(void)
+{
+	int err;
+
+	ahash_sample_dev = kzalloc(sizeof(struct ahash_sample_device) +
+				sizeof(struct crypto_alg),
+				GFP_KERNEL);
+	if (!ahash_sample_dev) {
+		err = -ENOMEM;
+		goto err_nomem;
+	}
+
+	INIT_LIST_HEAD(&ahash_sample_dev->alg_list);
+	strncpy(ahash_sample_dev->name, "AHASH_generic",
+		sizeof(ahash_sample_dev->name));
+
+	err = ahash_sample_register_alg(ahash_sample_dev);
+	if (err)
+		goto err_register_alg;
+
+	/* Init tasklet for asynchronous processing */
+	tasklet_init(&ahash_sample_dev->tasklet, ahash_sample_bh_tasklet_cb,
+		(unsigned long) ahash_sample_dev);
+	crypto_init_queue(&ahash_sample_dev->queue, 64*1024);
+
+	printk(KERN_INFO "AHASH_SAMPLE: Asynchronous "
+		"hashing sample driver successfully registered.\n");
+	return 0;
+
+err_register_alg:
+	kfree(ahash_sample_dev);
+	ahash_sample_dev = NULL;
+
+err_nomem:
+	return err;
+}
+
+static void __devexit ahash_sample_fini(void)
+{
+	ahash_sample_unregister_alg(ahash_sample_dev);
+	kfree(ahash_sample_dev);
+	ahash_sample_dev = NULL;
+	printk(KERN_INFO
+		"AHASH_SAMPLE: Driver for testing asynchronous hash support
"
+		"framework has been successfully unregistered.\n");
+}
+
+module_init(ahash_sample_init);
+module_exit(ahash_sample_fini);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Loc Ho <lho@amcc.com>");
+MODULE_DESCRIPTION("Sample asynchronous hash driver");
diff --git a/include/crypto/algapi.h b/include/crypto/algapi.h
index 60d06e7..fef272a 100644
--- a/include/crypto/algapi.h
+++ b/include/crypto/algapi.h
@@ -98,6 +98,7 @@ extern const struct crypto_type crypto_ablkcipher_type;
 extern const struct crypto_type crypto_aead_type;
 extern const struct crypto_type crypto_blkcipher_type;
 extern const struct crypto_type crypto_hash_type;
+extern const struct crypto_type crypto_ahash_type;
 
 void crypto_mod_put(struct crypto_alg *alg);
 
@@ -314,5 +315,40 @@ static inline int crypto_requires_sync(u32 type, u32
mask)
 	return (type ^ CRYPTO_ALG_ASYNC) & mask & CRYPTO_ALG_ASYNC;
 }
 
+static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm)
+{
+	return crypto_tfm_ctx(&tfm->base);
+}
+
+static inline struct ahash_alg *crypto_ahash_alg(
+	struct crypto_ahash *tfm)
+{
+	return &crypto_ahash_tfm(tfm)->__crt_alg->cra_ahash;
+}
+
+static inline int ahash_enqueue_request(struct crypto_queue *queue,
+					     struct ahash_request *request)
+{
+	return crypto_enqueue_request(queue, &request->base);
+}
+
+static inline struct ahash_request *ahash_dequeue_request(
+	struct crypto_queue *queue)
+{
+	return ahash_request_cast(crypto_dequeue_request(queue));
+}
+
+static inline void *ahash_request_ctx(struct ahash_request *req)
+{
+	return req->__ctx;
+}
+
+static inline int ahash_tfm_in_queue(struct crypto_queue *queue,
+					  struct crypto_ahash *tfm)
+{
+	return crypto_tfm_in_queue(queue, crypto_ahash_tfm(tfm));
+}
+
+
 #endif	/* _CRYPTO_ALGAPI_H */
 
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 5e02d1b..fe9a5c2 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -7,10 +7,10 @@
  *
  * Portions derived from Cryptoapi, by Alexander Kjeldaas <astor@fast.no>
  * and Nettle, by Niels Möller.
- * 
+ *
  * 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) 
+ * Software Foundation; either version 2 of the License, or (at your
option)
  * any later version.
  *
  */
@@ -37,6 +37,7 @@
 #define CRYPTO_ALG_TYPE_GIVCIPHER	0x00000006
 #define CRYPTO_ALG_TYPE_COMPRESS	0x00000008
 #define CRYPTO_ALG_TYPE_AEAD		0x00000009
+#define CRYPTO_ALG_TYPE_AHASH		0x0000000A
 
 #define CRYPTO_ALG_TYPE_HASH_MASK	0x0000000e
 #define CRYPTO_ALG_TYPE_BLKCIPHER_MASK	0x0000000c
@@ -102,6 +103,7 @@ struct crypto_async_request;
 struct crypto_aead;
 struct crypto_blkcipher;
 struct crypto_hash;
+struct crypto_ahash;
 struct crypto_tfm;
 struct crypto_type;
 struct aead_givcrypt_request;
@@ -131,6 +133,16 @@ struct ablkcipher_request {
 	void *__ctx[] CRYPTO_MINALIGN_ATTR;
 };
 
+struct ahash_request {
+	struct crypto_async_request base;
+
+	unsigned int nbytes;
+	struct scatterlist *src;
+	u8		   *result;
+
+	void *__ctx[] CRYPTO_MINALIGN_ATTR;
+};
+
 /**
  *	struct aead_request - AEAD request
  *	@base: Common attributes for async crypto requests
@@ -195,6 +207,17 @@ struct ablkcipher_alg {
 	unsigned int ivsize;
 };
 
+struct ahash_alg {
+	int (*init)(struct ahash_request *req);
+	int (*update)(struct ahash_request *req);
+	int (*final)(struct ahash_request *req);
+	int (*digest)(struct ahash_request *req);
+	int (*setkey)(struct crypto_ahash *tfm, const u8 *key,
+			unsigned int keylen);
+
+	unsigned int digestsize;
+};
+
 struct aead_alg {
 	int (*setkey)(struct crypto_aead *tfm, const u8 *key,
 	              unsigned int keylen);
@@ -272,6 +295,7 @@ struct compress_alg {
 #define cra_cipher	cra_u.cipher
 #define cra_digest	cra_u.digest
 #define cra_hash	cra_u.hash
+#define cra_ahash	cra_u.ahash
 #define cra_compress	cra_u.compress
 
 struct crypto_alg {
@@ -298,13 +322,14 @@ struct crypto_alg {
 		struct cipher_alg cipher;
 		struct digest_alg digest;
 		struct hash_alg hash;
+		struct ahash_alg ahash;
 		struct compress_alg compress;
 	} cra_u;
 
 	int (*cra_init)(struct crypto_tfm *tfm);
 	void (*cra_exit)(struct crypto_tfm *tfm);
 	void (*cra_destroy)(struct crypto_alg *alg);
-	
+
 	struct module *cra_module;
 };
 
@@ -390,6 +415,19 @@ struct hash_tfm {
 	unsigned int digestsize;
 };
 
+struct ahash_tfm {
+	int (*init)(struct ahash_request *req);
+	int (*update)(struct ahash_request *req);
+	int (*final)(struct ahash_request *req);
+	int (*digest)(struct ahash_request *req);
+	int (*setkey)(struct crypto_ahash *tfm, const u8 *key,
+			unsigned int keylen);
+
+	unsigned int digestsize;
+	struct crypto_ahash *base;
+	unsigned int reqsize;
+};
+
 struct compress_tfm {
 	int (*cot_compress)(struct crypto_tfm *tfm,
 	                    const u8 *src, unsigned int slen,
@@ -404,21 +442,23 @@ struct compress_tfm {
 #define crt_blkcipher	crt_u.blkcipher
 #define crt_cipher	crt_u.cipher
 #define crt_hash	crt_u.hash
+#define crt_ahash	crt_u.ahash
 #define crt_compress	crt_u.compress
 
 struct crypto_tfm {
 
 	u32 crt_flags;
-	
+
 	union {
 		struct ablkcipher_tfm ablkcipher;
 		struct aead_tfm aead;
 		struct blkcipher_tfm blkcipher;
 		struct cipher_tfm cipher;
 		struct hash_tfm hash;
+		struct ahash_tfm ahash;
 		struct compress_tfm compress;
 	} crt_u;
-	
+
 	struct crypto_alg *__crt_alg;
 
 	void *__crt_ctx[] CRYPTO_MINALIGN_ATTR;
@@ -448,6 +488,10 @@ struct crypto_hash {
 	struct crypto_tfm base;
 };
 
+struct crypto_ahash {
+	struct crypto_tfm base;
+};
+
 enum {
 	CRYPTOA_UNSPEC,
 	CRYPTOA_ALG,
@@ -477,7 +521,7 @@ struct crypto_attr_u32 {
 /* 
  * Transform user interface.
  */
- 
+
 struct crypto_tfm *crypto_alloc_tfm(const char *alg_name, u32 tfm_flags);
 struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32
mask);
 void crypto_free_tfm(struct crypto_tfm *tfm);
@@ -1112,7 +1156,7 @@ static inline struct crypto_hash
*crypto_alloc_hash(const char *alg_name,
 						    u32 type, u32 mask)
 {
 	type &= ~CRYPTO_ALG_TYPE_MASK;
-	mask &= ~CRYPTO_ALG_TYPE_MASK;
+	mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
 	type |= CRYPTO_ALG_TYPE_HASH;
 	mask |= CRYPTO_ALG_TYPE_HASH_MASK;
 
@@ -1271,5 +1315,130 @@ static inline int crypto_comp_decompress(struct
crypto_comp *tfm,
 						    src, slen, dst, dlen);
 }
 
+static inline struct crypto_tfm *crypto_ahash_tfm(
+	struct crypto_ahash *tfm)
+{
+	return &tfm->base;
+}
+
+struct crypto_ahash *crypto_alloc_ahash(const char *alg_name,
+					u32 type, u32 mask);
+
+static inline void crypto_free_ahash(struct crypto_ahash *tfm)
+{
+	crypto_free_tfm(crypto_ahash_tfm(tfm));
+}
+
+static inline struct crypto_ahash *__crypto_ahash_cast(struct crypto_tfm
*tfm)
+{
+	return (struct crypto_ahash *) tfm;
+}
+
+static inline unsigned int crypto_ahash_alignmask(
+	struct crypto_ahash *tfm)
+{
+	return crypto_tfm_alg_alignmask(crypto_ahash_tfm(tfm));
+}
+
+static inline struct ahash_tfm *crypto_ahash_crt(struct crypto_ahash *tfm)
+{
+	return &crypto_ahash_tfm(tfm)->crt_ahash;
+}
+
+static inline unsigned int crypto_ahash_digestsize(struct crypto_ahash
*tfm)
+{
+	return crypto_ahash_crt(tfm)->digestsize;
+}
+
+static inline u32 crypto_ahash_get_flags(struct crypto_ahash *tfm)
+{
+	return crypto_tfm_get_flags(crypto_ahash_tfm(tfm));
+}
+
+static inline void crypto_ahash_set_flags(struct crypto_ahash *tfm, u32
flags)
+{
+	crypto_tfm_set_flags(crypto_ahash_tfm(tfm), flags);
+}
+
+static inline void crypto_ahash_clear_flags(struct crypto_ahash *tfm, u32
flags)
+{
+	crypto_tfm_clear_flags(crypto_ahash_tfm(tfm), flags);
+}
+
+static inline struct crypto_ahash *crypto_ahash_reqtfm(
+	struct ahash_request *req)
+{
+	return __crypto_ahash_cast(req->base.tfm);
+}
+
+static inline unsigned int crypto_ahash_reqsize(struct crypto_ahash *tfm)
+{
+	return crypto_ahash_crt(tfm)->reqsize;
+}
+
+static inline int crypto_ahash_setkey(struct crypto_ahash *tfm,
+					const u8 *key, unsigned int keylen)
+{
+	struct ahash_tfm *crt = crypto_ahash_crt(tfm);
+
+	return crt->setkey(crt->base, key, keylen);
+}
+
+static inline int crypto_ahash_digest(struct ahash_request *req)
+{
+	struct ahash_tfm *crt = crypto_ahash_crt(crypto_ahash_reqtfm(req));
+	return crt->digest(req);
+}
+
+static inline void ahash_request_set_tfm(
+	struct ahash_request *req, struct crypto_ahash *tfm)
+{
+	req->base.tfm = crypto_ahash_tfm(crypto_ahash_crt(tfm)->base);
+}
+
+static inline struct ahash_request *ahash_request_alloc(
+	struct crypto_ahash *tfm, gfp_t gfp)
+{
+	struct ahash_request *req;
+
+	req = kmalloc(sizeof(struct ahash_request) +
+		      crypto_ahash_reqsize(tfm), gfp);
+
+	if (likely(req))
+		ahash_request_set_tfm(req, tfm);
+
+	return req;
+}
+
+static inline void ahash_request_free(struct ahash_request *req)
+{
+	kfree(req);
+}
+
+static inline struct ahash_request *ahash_request_cast(
+	struct crypto_async_request *req)
+{
+	return container_of(req, struct ahash_request, base);
+}
+
+static inline void ahash_request_set_callback(
+	struct ahash_request *req,
+	u32 flags, crypto_completion_t complete, void *data)
+{
+	req->base.complete = complete;
+	req->base.data = data;
+	req->base.flags = flags;
+}
+
+static inline void ahash_request_set_crypt(
+	struct ahash_request *req,
+	struct scatterlist *src, u8 *result,
+	unsigned int nbytes)
+{
+	req->src = src;
+	req->nbytes = nbytes;
+	req->result = result;
+}
+
 #endif	/* _LINUX_CRYPTO_H */
 
-- 
1.5.3

  parent reply	other threads:[~2008-01-25  2:45 UTC|newest]

Thread overview: 28+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <0CA0A16855646F4FA96D25A158E299D603B5A5EB@SDCEXCHANGE01.ad.amcc.com>
2007-11-12 18:19 ` New Crypto Hardware Loc Ho
2007-11-13  1:41   ` Herbert Xu
     [not found]     ` <0CA0A16855646F4FA96D25A158E299D603EB866F@SDCEXCHANGE01.ad.amcc.com>
2007-12-25  7:32       ` Herbert Xu
     [not found]         ` <0CA0A16855646F4FA96D25A158E299D603FCC15D@SDCEXCHANGE01.ad.amcc.com>
2008-01-17 11:23           ` Herbert Xu
2008-01-17 18:37             ` Loc Ho
2008-01-17 20:27               ` Sebastian Siewior
     [not found]                 ` <0CA0A16855646F4FA96D25A158E299D603FCC4D7@SDCEXCHANGE01.ad.amcc.com>
2008-01-18 23:07                   ` Sebastian Siewior
2008-01-22  1:29                     ` Loc Ho
2008-01-22 23:18                       ` Sebastian Siewior
2008-01-23  2:17                         ` Loc Ho
2008-01-24 21:07                           ` RFC: Async Hash Support Loc Ho
2008-01-24 23:09                             ` Sebastian Siewior
2008-01-25  2:45                             ` Loc Ho [this message]
2008-03-13 11:42                               ` [PATCH 1/1] CryptoAPI: Add " Herbert Xu
2008-03-13 17:39                                 ` Loc Ho
2008-04-10  2:03                                 ` Loc Ho
2008-04-10  2:29                                   ` Herbert Xu
2008-04-22 11:16                                   ` Herbert Xu
2008-04-22 17:23                                     ` Loc Ho
2008-05-07 13:00                                       ` Herbert Xu
2008-05-07 13:09                                         ` Patrick McHardy
2008-05-07 13:15                                           ` Herbert Xu
2008-05-13 20:27                                         ` [PATCH 1/3] [CRYPTO] hash: " Loc Ho
2008-05-14 12:40                                           ` Herbert Xu
2008-05-14 12:44                                             ` Herbert Xu
2008-05-14 13:26                                           ` Herbert Xu
2008-05-13 20:29                                         ` [PATCH 2/3] [CRYPTO] cryptd: " Loc Ho
2008-05-13 20:30                                         ` [PATCH 3/3] [CRYPTO] tcrypt: " Loc Ho

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='004a01c85efc$56f2ee70$5c05420a@amcc.com' \
    --to=locnho@sbcglobal.net \
    --cc=herbert@gondor.apana.org.au \
    --cc=linux-crypto@ml.breakpoint.cc \
    --cc=linux-crypto@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.