X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=crypto%2Fdigest.c;h=1bf7414aeb9e4e212beda804cf270aa310548c5d;hb=b91cba52e9b7b3f1c0037908a192d93a869ca9e5;hp=603006a7bef2abad1452b1336337065eb166fef2;hpb=b20e481ab595e9667c33e2393bdfe9a31870d11f;p=pandora-kernel.git diff --git a/crypto/digest.c b/crypto/digest.c index 603006a7bef2..1bf7414aeb9e 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -11,29 +11,43 @@ * any later version. * */ -#include + #include #include +#include #include -#include +#include +#include +#include + #include "internal.h" +#include "scatterwalk.h" -static void init(struct crypto_tfm *tfm) +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 void update(struct crypto_tfm *tfm, - struct scatterlist *sg, unsigned int nsg) +static int update2(struct hash_desc *desc, + struct scatterlist *sg, unsigned int nbytes) { - unsigned int i; + 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) @@ -55,62 +69,91 @@ 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); + 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 update(struct hash_desc *desc, + struct scatterlist *sg, unsigned int nbytes) { + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + return update2(desc, sg, nbytes); +} + +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; + if (unlikely((unsigned long)out & alignmask)) { - unsigned int size = crypto_tfm_alg_digestsize(tfm); - u8 buffer[size + alignmask]; - u8 *dst = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - tfm->__crt_alg->cra_digest.dia_final(tfm, dst); - memcpy(out, dst, size); + unsigned long align = alignmask + 1; + unsigned long addr = (unsigned long)crypto_tfm_ctx(tfm); + u8 *dst = (u8 *)ALIGN(addr, align) + + ALIGN(tfm->__crt_alg->cra_ctxsize, align); + + digest->dia_final(tfm, dst); + memcpy(out, dst, digest->dia_digestsize); } else - tfm->__crt_alg->cra_digest.dia_final(tfm, out); + digest->dia_final(tfm, out); + + return 0; } -static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) +static int nosetkey(struct crypto_hash *tfm, const u8 *key, unsigned int keylen) { - u32 flags; - if (tfm->__crt_alg->cra_digest.dia_setkey == NULL) - return -ENOSYS; - return tfm->__crt_alg->cra_digest.dia_setkey(tfm, key, keylen, &flags); + crypto_hash_clear_flags(tfm, CRYPTO_TFM_RES_MASK); + return -ENOSYS; } -static void digest(struct crypto_tfm *tfm, - struct scatterlist *sg, unsigned int nsg, u8 *out) +static int setkey(struct crypto_hash *hash, const u8 *key, unsigned int keylen) { - init(tfm); - update(tfm, sg, nsg); - final(tfm, out); + 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); } -int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags) +static int digest(struct hash_desc *desc, + struct scatterlist *sg, unsigned int nbytes, u8 *out) { - return flags ? -EINVAL : 0; + if (WARN_ON_ONCE(in_irq())) + return -EDEADLK; + + init(desc); + update2(desc, sg, nbytes); + return final(desc, out); } 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 = setkey; + 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); + return 0; } void crypto_exit_digest_ops(struct crypto_tfm *tfm) { - crypto_free_hmac_block(tfm); }