>From e5d67c3670f1ec15339a92cc291027c0a059aaed Mon Sep 17 00:00:00 2001
From: Loc Ho <[EMAIL PROTECTED]>
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 <[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.
+ *
+ */
+
+#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 <[EMAIL PROTECTED]>
+ * 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 <[EMAIL PROTECTED]>");
+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 <[EMAIL PROTECTED]>
* 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
-
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html