*
*/
+#include <crypto/internal/hash.h>
+#include <crypto/scatterwalk.h>
#include <linux/mm.h>
#include <linux/errno.h>
+#include <linux/hardirq.h>
#include <linux/highmem.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include "internal.h"
-#include "scatterwalk.h"
-
-void crypto_digest_init(struct crypto_tfm *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);
-
-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)
{
return 0;
}
-static int update(struct hash_desc *desc,
- struct scatterlist *sg, unsigned int nbytes)
+static int update2(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);
return 0;
for (;;) {
- struct page *pg = sg->page;
+ struct page *pg = sg_page(sg);
unsigned int offset = sg->offset;
unsigned int l = sg->length;
if (!nbytes)
break;
- sg = sg_next(sg);
+ sg = scatterwalk_sg_next(sg);
}
return 0;
}
+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);
static int digest(struct hash_desc *desc,
struct scatterlist *sg, unsigned int nbytes, u8 *out)
{
+ if (WARN_ON_ONCE(in_irq()))
+ return -EDEADLK;
+
init(desc);
- update(desc, sg, nbytes);
+ update2(desc, sg, nbytes);
return final(desc, out);
}
-int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
-{
- return flags ? -EINVAL : 0;
-}
-
int crypto_init_digest_ops(struct crypto_tfm *tfm)
{
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))
+ if (dalg->dia_digestsize > PAGE_SIZE / 8)
return -EINVAL;
ops->init = init;
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 > PAGE_SIZE / 8)
+ 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;
+
+ return 0;
+}