Skip to content

Commit

Permalink
[CRYPTO] digest: Added user API for new hash type
Browse files Browse the repository at this point in the history
The existing digest user interface is inadequate for support asynchronous
operations.  For one it doesn't return a value to indicate success or
failure, nor does it take a per-operation descriptor which is essential
for the issuing of requests while other requests are still outstanding.

This patch is the first in a series of steps to remodel the interface
for asynchronous operations.

For the ease of transition the new interface will be known as "hash"
while the old one will remain as "digest".

This patch also changes sg_next to allow chaining.

Signed-off-by: Herbert Xu <[email protected]>
  • Loading branch information
herbertx committed Sep 21, 2006
1 parent 7226bc8 commit 055bcee
Show file tree
Hide file tree
Showing 8 changed files with 321 additions and 70 deletions.
4 changes: 4 additions & 0 deletions crypto/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ config CRYPTO_BLKCIPHER
tristate
select CRYPTO_ALGAPI

config CRYPTO_HASH
tristate
select CRYPTO_ALGAPI

config CRYPTO_MANAGER
tristate "Cryptographic algorithm manager"
select CRYPTO_ALGAPI
Expand Down
3 changes: 3 additions & 0 deletions crypto/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ obj-$(CONFIG_CRYPTO_ALGAPI) += crypto_algapi.o

obj-$(CONFIG_CRYPTO_BLKCIPHER) += blkcipher.o

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

obj-$(CONFIG_CRYPTO_MANAGER) += cryptomgr.o
obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
obj-$(CONFIG_CRYPTO_NULL) += crypto_null.o
Expand Down
129 changes: 102 additions & 27 deletions crypto/digest.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,89 @@
* any later version.
*
*/
#include <linux/crypto.h>

#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/highmem.h>
#include <asm/scatterlist.h>
#include <linux/module.h>
#include <linux/scatterlist.h>

#include "internal.h"
#include "scatterwalk.h"

static void init(struct crypto_tfm *tfm)
void crypto_digest_init(struct crypto_tfm *tfm)
{
tfm->__crt_alg->cra_digest.dia_init(tfm);
struct crypto_hash *hash = crypto_hash_cast(tfm);
struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };

crypto_hash_init(&desc);
}
EXPORT_SYMBOL_GPL(crypto_digest_init);

static void update(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg)
void crypto_digest_update(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg)
{
struct crypto_hash *hash = crypto_hash_cast(tfm);
struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
unsigned int nbytes = 0;
unsigned int i;

for (i = 0; i < nsg; i++)
nbytes += sg[i].length;

crypto_hash_update(&desc, sg, nbytes);
}
EXPORT_SYMBOL_GPL(crypto_digest_update);

void crypto_digest_final(struct crypto_tfm *tfm, u8 *out)
{
struct crypto_hash *hash = crypto_hash_cast(tfm);
struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };

crypto_hash_final(&desc, out);
}
EXPORT_SYMBOL_GPL(crypto_digest_final);

void crypto_digest_digest(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg, u8 *out)
{
struct crypto_hash *hash = crypto_hash_cast(tfm);
struct hash_desc desc = { .tfm = hash, .flags = tfm->crt_flags };
unsigned int nbytes = 0;
unsigned int i;

for (i = 0; i < nsg; i++)
nbytes += sg[i].length;

crypto_hash_digest(&desc, sg, nbytes, out);
}
EXPORT_SYMBOL_GPL(crypto_digest_digest);

static int init(struct hash_desc *desc)
{
struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);

tfm->__crt_alg->cra_digest.dia_init(tfm);
return 0;
}

static int update(struct hash_desc *desc,
struct scatterlist *sg, unsigned int nbytes)
{
struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);

for (i = 0; i < nsg; i++) {
if (!nbytes)
return 0;

for (;;) {
struct page *pg = sg->page;
unsigned int offset = sg->offset;
unsigned int l = sg->length;

struct page *pg = sg[i].page;
unsigned int offset = sg[i].offset;
unsigned int l = sg[i].length;
if (unlikely(l > nbytes))
l = nbytes;
nbytes -= l;

do {
unsigned int bytes_from_page = min(l, ((unsigned int)
Expand All @@ -55,16 +115,23 @@ static void update(struct crypto_tfm *tfm,
tfm->__crt_alg->cra_digest.dia_update(tfm, p,
bytes_from_page);
crypto_kunmap(src, 0);
crypto_yield(tfm->crt_flags);
crypto_yield(desc->flags);
offset = 0;
pg++;
l -= bytes_from_page;
} while (l > 0);

if (!nbytes)
break;
sg = sg_next(sg);
}

return 0;
}

static void final(struct crypto_tfm *tfm, u8 *out)
static int final(struct hash_desc *desc, u8 *out)
{
struct crypto_tfm *tfm = crypto_hash_tfm(desc->tfm);
unsigned long alignmask = crypto_tfm_alg_alignmask(tfm);
struct digest_alg *digest = &tfm->__crt_alg->cra_digest;

Expand All @@ -78,26 +145,30 @@ static void final(struct crypto_tfm *tfm, u8 *out)
memcpy(out, dst, digest->dia_digestsize);
} else
digest->dia_final(tfm, out);

return 0;
}

static int nosetkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen)
{
tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK);
return -ENOSYS;
}

static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen)
{
tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK;
struct crypto_tfm *tfm = crypto_hash_tfm(hash);

crypto_hash_clear_flags(hash, CRYPTO_TFM_RES_MASK);
return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen);
}

static void digest(struct crypto_tfm *tfm,
struct scatterlist *sg, unsigned int nsg, u8 *out)
static int digest(struct hash_desc *desc,
struct scatterlist *sg, unsigned int nbytes, u8 *out)
{
init(tfm);
update(tfm, sg, nsg);
final(tfm, out);
init(desc);
update(desc, sg, nbytes);
return final(desc, out);
}

int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
Expand All @@ -107,14 +178,18 @@ int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)

int crypto_init_digest_ops(struct crypto_tfm *tfm)
{
struct digest_tfm *ops = &tfm->crt_digest;
struct hash_tfm *ops = &tfm->crt_hash;
struct digest_alg *dalg = &tfm->__crt_alg->cra_digest;

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

ops->dit_init = init;
ops->dit_update = update;
ops->dit_final = final;
ops->dit_digest = digest;
ops->dit_setkey = dalg->dia_setkey ? setkey : nosetkey;
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 crypto_alloc_hmac_block(tfm);
}
Expand Down
61 changes: 61 additions & 0 deletions crypto/hash.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Cryptographic Hash operations.
*
* Copyright (c) 2006 Herbert Xu <[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 <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/seq_file.h>

#include "internal.h"

static unsigned int crypto_hash_ctxsize(struct crypto_alg *alg)
{
return alg->cra_ctxsize;
}

static int crypto_init_hash_ops(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 = alg->setkey;
crt->digestsize = alg->digestsize;

return 0;
}

static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
__attribute_used__;
static void crypto_hash_show(struct seq_file *m, struct crypto_alg *alg)
{
seq_printf(m, "type : hash\n");
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
seq_printf(m, "digestsize : %u\n", alg->cra_hash.digestsize);
}

const struct crypto_type crypto_hash_type = {
.ctxsize = crypto_hash_ctxsize,
.init = crypto_init_hash_ops,
#ifdef CONFIG_PROC_FS
.show = crypto_hash_show,
#endif
};
EXPORT_SYMBOL_GPL(crypto_hash_type);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Generic cryptographic hash type");
12 changes: 6 additions & 6 deletions crypto/hmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ int crypto_alloc_hmac_block(struct crypto_tfm *tfm)

BUG_ON(!crypto_tfm_alg_blocksize(tfm));

tfm->crt_digest.dit_hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm),
GFP_KERNEL);
if (tfm->crt_digest.dit_hmac_block == NULL)
tfm->crt_hash.hmac_block = kmalloc(crypto_tfm_alg_blocksize(tfm),
GFP_KERNEL);
if (tfm->crt_hash.hmac_block == NULL)
ret = -ENOMEM;

return ret;
Expand All @@ -46,14 +46,14 @@ int crypto_alloc_hmac_block(struct crypto_tfm *tfm)

void crypto_free_hmac_block(struct crypto_tfm *tfm)
{
kfree(tfm->crt_digest.dit_hmac_block);
kfree(tfm->crt_hash.hmac_block);
}

void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
{
unsigned int i;
struct scatterlist tmp;
char *ipad = tfm->crt_digest.dit_hmac_block;
char *ipad = tfm->crt_hash.hmac_block;

if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
hash_key(tfm, key, *keylen);
Expand Down Expand Up @@ -83,7 +83,7 @@ void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
{
unsigned int i;
struct scatterlist tmp;
char *opad = tfm->crt_digest.dit_hmac_block;
char *opad = tfm->crt_hash.hmac_block;

if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
hash_key(tfm, key, *keylen);
Expand Down
4 changes: 1 addition & 3 deletions crypto/scatterwalk.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@

#include "internal.h"

/* Define sg_next is an inline routine now in case we want to change
scatterlist to a linked list later. */
static inline struct scatterlist *sg_next(struct scatterlist *sg)
{
return sg + 1;
return (++sg)->length ? sg : (void *)sg->page;
}

static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in,
Expand Down
6 changes: 6 additions & 0 deletions include/crypto/algapi.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ struct blkcipher_walk {
};

extern const struct crypto_type crypto_blkcipher_type;
extern const struct crypto_type crypto_hash_type;

void crypto_mod_put(struct crypto_alg *alg);

Expand Down Expand Up @@ -136,6 +137,11 @@ static inline struct cipher_alg *crypto_cipher_alg(struct crypto_cipher *tfm)
return &crypto_cipher_tfm(tfm)->__crt_alg->cra_cipher;
}

static inline void *crypto_hash_ctx_aligned(struct crypto_hash *tfm)
{
return crypto_tfm_ctx_aligned(&tfm->base);
}

static inline void blkcipher_walk_init(struct blkcipher_walk *walk,
struct scatterlist *dst,
struct scatterlist *src,
Expand Down
Loading

0 comments on commit 055bcee

Please sign in to comment.