summaryrefslogtreecommitdiff
path: root/crypto/hash.c
diff options
context:
space:
mode:
authorLoc Ho <lho@amcc.com>2008-05-14 20:41:47 +0800
committerHerbert Xu <herbert@gondor.apana.org.au>2008-07-10 20:35:13 +0800
commit004a403c2e954734090a69aedc7f4f822bdcc142 (patch)
treee8fadd76113132126e308e01e7cd7cdf6b9d44d6 /crypto/hash.c
parent534fe2c1c3ffbbc3db66dba0783c82d3b345fd33 (diff)
[CRYPTO] hash: Add asynchronous hash support
This patch adds asynchronous hash and digest support. Signed-off-by: Loc Ho <lho@amcc.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Diffstat (limited to 'crypto/hash.c')
-rw-r--r--crypto/hash.c102
1 files changed, 93 insertions, 9 deletions
diff --git a/crypto/hash.c b/crypto/hash.c
index 7dcff671c19b..f9400a014e74 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_TYPE_HASH_MASK) != CRYPTO_ALG_TYPE_HASH_MASK)
+ 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)