Skip to content

Commit

Permalink
crypto: hash - Export shash through ahash
Browse files Browse the repository at this point in the history
This patch allows shash algorithms to be used through the ahash
interface.  This is required before we can convert digest algorithms
over to shash.

Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
herbertx committed Dec 25, 2008
1 parent 7b5a080 commit 3b2f6df
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 1 deletion.
143 changes: 143 additions & 0 deletions crypto/shash.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,23 @@
*
*/

#include <crypto/scatterwalk.h>
#include <crypto/internal/hash.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/seq_file.h>

static const struct crypto_type crypto_shash_type;

static inline struct crypto_shash *__crypto_shash_cast(struct crypto_tfm *tfm)
{
return container_of(tfm, struct crypto_shash, base);
}

#include "internal.h"

static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key,
unsigned int keylen)
{
Expand Down Expand Up @@ -167,6 +172,142 @@ int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
}
EXPORT_SYMBOL_GPL(crypto_shash_digest);

static int shash_async_setkey(struct crypto_ahash *tfm, const u8 *key,
unsigned int keylen)
{
struct crypto_shash **ctx = crypto_ahash_ctx(tfm);

return crypto_shash_setkey(*ctx, key, keylen);
}

static int shash_async_init(struct ahash_request *req)
{
struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
struct shash_desc *desc = ahash_request_ctx(req);

desc->tfm = *ctx;
desc->flags = req->base.flags;

return crypto_shash_init(desc);
}

static int shash_async_update(struct ahash_request *req)
{
struct shash_desc *desc = ahash_request_ctx(req);
struct crypto_hash_walk walk;
int nbytes;

for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0;
nbytes = crypto_hash_walk_done(&walk, nbytes))
nbytes = crypto_shash_update(desc, walk.data, nbytes);

return nbytes;
}

static int shash_async_final(struct ahash_request *req)
{
return crypto_shash_final(ahash_request_ctx(req), req->result);
}

static int shash_async_digest(struct ahash_request *req)
{
struct scatterlist *sg = req->src;
unsigned int offset = sg->offset;
unsigned int nbytes = req->nbytes;
int err;

if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) {
struct crypto_shash **ctx =
crypto_ahash_ctx(crypto_ahash_reqtfm(req));
struct shash_desc *desc = ahash_request_ctx(req);
void *data;

desc->tfm = *ctx;
desc->flags = req->base.flags;

data = crypto_kmap(sg_page(sg), 0);
err = crypto_shash_digest(desc, data + offset, nbytes,
req->result);
crypto_kunmap(data, 0);
crypto_yield(desc->flags);
goto out;
}

err = shash_async_init(req);
if (err)
goto out;

err = shash_async_update(req);
if (err)
goto out;

err = shash_async_final(req);

out:
return err;
}

static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm)
{
struct crypto_shash **ctx = crypto_tfm_ctx(tfm);

crypto_free_shash(*ctx);
}

static int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
{
struct crypto_alg *calg = tfm->__crt_alg;
struct shash_alg *alg = __crypto_shash_alg(calg);
struct ahash_tfm *crt = &tfm->crt_ahash;
struct crypto_shash **ctx = crypto_tfm_ctx(tfm);
struct crypto_shash *shash;

if (!crypto_mod_get(calg))
return -EAGAIN;

shash = __crypto_shash_cast(crypto_create_tfm(
calg, &crypto_shash_type));
if (IS_ERR(shash)) {
crypto_mod_put(calg);
return PTR_ERR(shash);
}

*ctx = shash;
tfm->exit = crypto_exit_shash_ops_async;

crt->init = shash_async_init;
crt->update = shash_async_update;
crt->final = shash_async_final;
crt->digest = shash_async_digest;
crt->setkey = shash_async_setkey;

crt->digestsize = alg->digestsize;
crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash);

return 0;
}

static int crypto_init_shash_ops(struct crypto_tfm *tfm, u32 type, u32 mask)
{
switch (mask & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_AHASH_MASK:
return crypto_init_shash_ops_async(tfm);
}

return -EINVAL;
}

static unsigned int crypto_shash_ctxsize(struct crypto_alg *alg, u32 type,
u32 mask)
{
switch (mask & CRYPTO_ALG_TYPE_MASK) {
case CRYPTO_ALG_TYPE_AHASH_MASK:
return sizeof(struct crypto_shash *);
}

return 0;
}

static int crypto_shash_init_tfm(struct crypto_tfm *tfm,
const struct crypto_type *frontend)
{
Expand Down Expand Up @@ -194,7 +335,9 @@ static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg)
}

static const struct crypto_type crypto_shash_type = {
.ctxsize = crypto_shash_ctxsize,
.extsize = crypto_shash_extsize,
.init = crypto_init_shash_ops,
.init_tfm = crypto_shash_init_tfm,
#ifdef CONFIG_PROC_FS
.show = crypto_shash_show,
Expand Down
2 changes: 1 addition & 1 deletion include/linux/crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
#define CRYPTO_ALG_TYPE_DIGEST 0x00000008
#define CRYPTO_ALG_TYPE_HASH 0x00000009
#define CRYPTO_ALG_TYPE_AHASH 0x0000000a
#define CRYPTO_ALG_TYPE_SHASH 0x0000000b
#define CRYPTO_ALG_TYPE_RNG 0x0000000c
#define CRYPTO_ALG_TYPE_SHASH 0x0000000d

#define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e
#define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000c
Expand Down

0 comments on commit 3b2f6df

Please sign in to comment.