Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 004a403c authored by Loc Ho's avatar Loc Ho Committed by Herbert Xu
Browse files

[CRYPTO] hash: Add asynchronous hash support



This patch adds asynchronous hash and digest support.

Signed-off-by: default avatarLoc Ho <lho@amcc.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 534fe2c1
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ obj-$(CONFIG_CRYPTO_BLKCIPHER) += crypto_blkcipher.o
obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o
obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o


crypto_hash-objs := hash.o
crypto_hash-objs := hash.o
crypto_hash-objs += ahash.o
obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o
obj-$(CONFIG_CRYPTO_HASH) += crypto_hash.o


obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o

crypto/ahash.c

0 → 100644
+106 −0
Original line number Original line Diff line number Diff line
/*
 * 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         : ahash\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);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
+6 −2
Original line number Original line Diff line number Diff line
@@ -235,6 +235,10 @@ static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
		return crypto_init_cipher_ops(tfm);
		return crypto_init_cipher_ops(tfm);
		
		
	case CRYPTO_ALG_TYPE_DIGEST:
	case CRYPTO_ALG_TYPE_DIGEST:
		if ((mask & CRYPTO_ALG_TYPE_HASH_MASK) !=
		    CRYPTO_ALG_TYPE_HASH_MASK)
			return crypto_init_digest_ops_async(tfm);
		else
			return crypto_init_digest_ops(tfm);
			return crypto_init_digest_ops(tfm);


	case CRYPTO_ALG_TYPE_COMPRESS:
	case CRYPTO_ALG_TYPE_COMPRESS:
+81 −0
Original line number Original line Diff line number Diff line
@@ -157,3 +157,84 @@ int crypto_init_digest_ops(struct crypto_tfm *tfm)
void crypto_exit_digest_ops(struct crypto_tfm *tfm)
void crypto_exit_digest_ops(struct crypto_tfm *tfm)
{
{
}
}

static int digest_async_nosetkey(struct crypto_ahash *tfm_async, const u8 *key,
			unsigned int keylen)
{
	crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
	return -ENOSYS;
}

static int digest_async_setkey(struct crypto_ahash *tfm_async, const u8 *key,
			unsigned int keylen)
{
	struct crypto_tfm    *tfm        = crypto_ahash_tfm(tfm_async);
	struct digest_alg    *dalg       = &tfm->__crt_alg->cra_digest;

	crypto_ahash_clear_flags(tfm_async, CRYPTO_TFM_RES_MASK);
	return dalg->dia_setkey(tfm, key, keylen);
}

static int digest_async_init(struct ahash_request *req)
{
	struct crypto_tfm *tfm  = req->base.tfm;
	struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;

	dalg->dia_init(tfm);
	return 0;
}

static int digest_async_update(struct ahash_request *req)
{
	struct crypto_tfm *tfm = req->base.tfm;
	struct hash_desc  desc = {
		.tfm   = __crypto_hash_cast(tfm),
		.flags = req->base.flags,
	};

	update(&desc, req->src, req->nbytes);
	return 0;
}

static int digest_async_final(struct ahash_request *req)
{
	struct crypto_tfm *tfm  = req->base.tfm;
	struct hash_desc  desc = {
		.tfm   = __crypto_hash_cast(tfm),
		.flags = req->base.flags,
	};

	final(&desc, req->result);
	return 0;
}

static int digest_async_digest(struct ahash_request *req)
{
	struct crypto_tfm *tfm  = req->base.tfm;
	struct hash_desc  desc = {
		.tfm   = __crypto_hash_cast(tfm),
		.flags = req->base.flags,
	};

	return digest(&desc, req->src, req->nbytes, req->result);
}

int crypto_init_digest_ops_async(struct crypto_tfm *tfm)
{
	struct ahash_tfm  *crt  = &tfm->crt_ahash;
	struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;

	if (dalg->dia_digestsize > crypto_tfm_alg_blocksize(tfm))
		return -EINVAL;

	crt->init       = digest_async_init;
	crt->update     = digest_async_update;
	crt->final      = digest_async_final;
	crt->digest     = digest_async_digest;
	crt->setkey     = dalg->dia_setkey ? digest_async_setkey :
						digest_async_nosetkey;
	crt->digestsize = dalg->dia_digestsize;
	crt->base       = __crypto_ahash_cast(tfm);

	return 0;
}
+93 −9
Original line number Original line Diff line number Diff line
@@ -59,13 +59,84 @@ static int hash_setkey(struct crypto_hash *crt, const u8 *key,
	return alg->setkey(crt, key, keylen);
	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 hash_tfm *crt = &tfm->crt_hash;
	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;
	struct hash_alg    *alg      = &tfm->__crt_alg->cra_hash;


	if (alg->digestsize > crypto_tfm_alg_blocksize(tfm))
	return alg->setkey(tfm_hash, key, keylen);
		return -EINVAL;
}

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;


	crt->init       = alg->init;
	crt->init       = alg->init;
	crt->update     = alg->update;
	crt->update     = alg->update;
@@ -77,6 +148,19 @@ static int crypto_init_hash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
	return 0;
	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)
static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
	__attribute__ ((unused));
	__attribute__ ((unused));
static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
Loading