From 42808e5dc602c12ef3eb42cf96cb416b55205fa4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 16 Feb 2023 18:35:15 +0800 Subject: crypto: hash - Count error stats differently Move all stat code specific to hash into the hash code. While we're at it, change the stats so that bytes and counts are always incremented even in case of error. This allows the reference counting to be removed as we can now increment the counters prior to the operation. After the operation we simply increase the error count if necessary. This is safe as errors can only occur synchronously (or rather, the existing code already ignored asynchronous errors which are only visible to the callback function). Signed-off-by: Herbert Xu --- crypto/ahash.c | 81 ++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 33 deletions(-) (limited to 'crypto/ahash.c') diff --git a/crypto/ahash.c b/crypto/ahash.c index ff8c79d975c1..c886cec64c23 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -8,19 +8,18 @@ * Copyright (c) 2008 Loc Ho */ -#include #include +#include #include #include #include #include #include #include -#include -#include +#include #include -#include "internal.h" +#include "hash.h" static const struct crypto_type crypto_ahash_type; @@ -296,55 +295,60 @@ static int crypto_ahash_op(struct ahash_request *req, { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); unsigned long alignmask = crypto_ahash_alignmask(tfm); + int err; if ((unsigned long)req->result & alignmask) - return ahash_op_unaligned(req, op, has_state); + err = ahash_op_unaligned(req, op, has_state); + else + err = op(req); - return op(req); + return crypto_hash_errstat(crypto_hash_alg_common(tfm), err); } int crypto_ahash_final(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct crypto_alg *alg = tfm->base.__crt_alg; - unsigned int nbytes = req->nbytes; - int ret; + struct hash_alg_common *alg = crypto_hash_alg_common(tfm); - crypto_stats_get(alg); - ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final, true); - crypto_stats_ahash_final(nbytes, ret, alg); - return ret; + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) + atomic64_inc(&hash_get_stat(alg)->hash_cnt); + + return crypto_ahash_op(req, tfm->final, true); } EXPORT_SYMBOL_GPL(crypto_ahash_final); int crypto_ahash_finup(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct crypto_alg *alg = tfm->base.__crt_alg; - unsigned int nbytes = req->nbytes; - int ret; + struct hash_alg_common *alg = crypto_hash_alg_common(tfm); - crypto_stats_get(alg); - ret = crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup, true); - crypto_stats_ahash_final(nbytes, ret, alg); - return ret; + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_hash *istat = hash_get_stat(alg); + + atomic64_inc(&istat->hash_cnt); + atomic64_add(req->nbytes, &istat->hash_tlen); + } + + return crypto_ahash_op(req, tfm->finup, true); } EXPORT_SYMBOL_GPL(crypto_ahash_finup); int crypto_ahash_digest(struct ahash_request *req) { struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - struct crypto_alg *alg = tfm->base.__crt_alg; - unsigned int nbytes = req->nbytes; - int ret; + struct hash_alg_common *alg = crypto_hash_alg_common(tfm); + + if (IS_ENABLED(CONFIG_CRYPTO_STATS)) { + struct crypto_istat_hash *istat = hash_get_stat(alg); + + atomic64_inc(&istat->hash_cnt); + atomic64_add(req->nbytes, &istat->hash_tlen); + } - crypto_stats_get(alg); if (crypto_ahash_get_flags(tfm) & CRYPTO_TFM_NEED_KEY) - ret = -ENOKEY; - else - ret = crypto_ahash_op(req, tfm->digest, false); - crypto_stats_ahash_final(nbytes, ret, alg); - return ret; + return crypto_hash_errstat(alg, -ENOKEY); + + return crypto_ahash_op(req, tfm->digest, false); } EXPORT_SYMBOL_GPL(crypto_ahash_digest); @@ -498,6 +502,12 @@ static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) __crypto_hash_alg_common(alg)->digestsize); } +static int __maybe_unused crypto_ahash_report_stat( + struct sk_buff *skb, struct crypto_alg *alg) +{ + return crypto_hash_report_stat(skb, alg, "ahash"); +} + static const struct crypto_type crypto_ahash_type = { .extsize = crypto_ahash_extsize, .init_tfm = crypto_ahash_init_tfm, @@ -506,6 +516,9 @@ static const struct crypto_type crypto_ahash_type = { .show = crypto_ahash_show, #endif .report = crypto_ahash_report, +#ifdef CONFIG_CRYPTO_STATS + .report_stat = crypto_ahash_report_stat, +#endif .maskclear = ~CRYPTO_ALG_TYPE_MASK, .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, .type = CRYPTO_ALG_TYPE_AHASH, @@ -537,14 +550,16 @@ EXPORT_SYMBOL_GPL(crypto_has_ahash); static int ahash_prepare_alg(struct ahash_alg *alg) { struct crypto_alg *base = &alg->halg.base; + int err; - if (alg->halg.digestsize > HASH_MAX_DIGESTSIZE || - alg->halg.statesize > HASH_MAX_STATESIZE || - alg->halg.statesize == 0) + if (alg->halg.statesize == 0) return -EINVAL; + err = hash_prepare_alg(&alg->halg); + if (err) + return err; + base->cra_type = &crypto_ahash_type; - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; base->cra_flags |= CRYPTO_ALG_TYPE_AHASH; return 0; -- cgit v1.2.3-58-ga151 From c0f9e01dd266b8a8f674d9f6a388972b81be1641 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 16 Feb 2023 18:35:28 +0800 Subject: crypto: api - Check CRYPTO_USER instead of NET for report The report function is currently conditionalised on CONFIG_NET. As it's only used by CONFIG_CRYPTO_USER, conditionalising on that instead of CONFIG_NET makes more sense. This gets rid of a rarely used code-path. Signed-off-by: Herbert Xu --- crypto/acompress.c | 12 ++++-------- crypto/aead.c | 12 ++++-------- crypto/ahash.c | 12 ++++-------- crypto/akcipher.c | 12 ++++-------- crypto/kpp.c | 12 ++++-------- crypto/rng.c | 12 ++++-------- crypto/scompress.c | 12 ++++-------- crypto/shash.c | 12 ++++-------- crypto/skcipher.c | 12 ++++-------- 9 files changed, 36 insertions(+), 72 deletions(-) (limited to 'crypto/ahash.c') diff --git a/crypto/acompress.c b/crypto/acompress.c index 022839ab457a..82a290df2822 100644 --- a/crypto/acompress.c +++ b/crypto/acompress.c @@ -33,8 +33,8 @@ static inline struct acomp_alg *crypto_acomp_alg(struct crypto_acomp *tfm) return __crypto_acomp_alg(crypto_acomp_tfm(tfm)->__crt_alg); } -#ifdef CONFIG_NET -static int crypto_acomp_report(struct sk_buff *skb, struct crypto_alg *alg) +static int __maybe_unused crypto_acomp_report( + struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_acomp racomp; @@ -44,12 +44,6 @@ static int crypto_acomp_report(struct sk_buff *skb, struct crypto_alg *alg) return nla_put(skb, CRYPTOCFGA_REPORT_ACOMP, sizeof(racomp), &racomp); } -#else -static int crypto_acomp_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif static void crypto_acomp_show(struct seq_file *m, struct crypto_alg *alg) __maybe_unused; @@ -131,7 +125,9 @@ static const struct crypto_type crypto_acomp_type = { #ifdef CONFIG_PROC_FS .show = crypto_acomp_show, #endif +#ifdef CONFIG_CRYPTO_USER .report = crypto_acomp_report, +#endif #ifdef CONFIG_CRYPTO_STATS .report_stat = crypto_acomp_report_stat, #endif diff --git a/crypto/aead.c b/crypto/aead.c index 5ea65c433608..ffc48a7dfb34 100644 --- a/crypto/aead.c +++ b/crypto/aead.c @@ -175,8 +175,8 @@ static int crypto_aead_init_tfm(struct crypto_tfm *tfm) return 0; } -#ifdef CONFIG_NET -static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) +static int __maybe_unused crypto_aead_report( + struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_aead raead; struct aead_alg *aead = container_of(alg, struct aead_alg, base); @@ -192,12 +192,6 @@ static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) return nla_put(skb, CRYPTOCFGA_REPORT_AEAD, sizeof(raead), &raead); } -#else -static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) __maybe_unused; @@ -248,7 +242,9 @@ static const struct crypto_type crypto_aead_type = { #ifdef CONFIG_PROC_FS .show = crypto_aead_show, #endif +#ifdef CONFIG_CRYPTO_USER .report = crypto_aead_report, +#endif #ifdef CONFIG_CRYPTO_STATS .report_stat = crypto_aead_report_stat, #endif diff --git a/crypto/ahash.c b/crypto/ahash.c index c886cec64c23..2d858d7fd1bb 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -469,8 +469,8 @@ static void crypto_ahash_free_instance(struct crypto_instance *inst) ahash->free(ahash); } -#ifdef CONFIG_NET -static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg) +static int __maybe_unused crypto_ahash_report( + struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_hash rhash; @@ -483,12 +483,6 @@ static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg) return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash); } -#else -static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) __maybe_unused; @@ -515,7 +509,9 @@ static const struct crypto_type crypto_ahash_type = { #ifdef CONFIG_PROC_FS .show = crypto_ahash_show, #endif +#ifdef CONFIG_CRYPTO_USER .report = crypto_ahash_report, +#endif #ifdef CONFIG_CRYPTO_STATS .report_stat = crypto_ahash_report_stat, #endif diff --git a/crypto/akcipher.c b/crypto/akcipher.c index 61d7c8b2d76e..186e762b509a 100644 --- a/crypto/akcipher.c +++ b/crypto/akcipher.c @@ -17,8 +17,8 @@ #include "internal.h" -#ifdef CONFIG_NET -static int crypto_akcipher_report(struct sk_buff *skb, struct crypto_alg *alg) +static int __maybe_unused crypto_akcipher_report( + struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_akcipher rakcipher; @@ -29,12 +29,6 @@ static int crypto_akcipher_report(struct sk_buff *skb, struct crypto_alg *alg) return nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER, sizeof(rakcipher), &rakcipher); } -#else -static int crypto_akcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif static void crypto_akcipher_show(struct seq_file *m, struct crypto_alg *alg) __maybe_unused; @@ -104,7 +98,9 @@ static const struct crypto_type crypto_akcipher_type = { #ifdef CONFIG_PROC_FS .show = crypto_akcipher_show, #endif +#ifdef CONFIG_CRYPTO_USER .report = crypto_akcipher_report, +#endif #ifdef CONFIG_CRYPTO_STATS .report_stat = crypto_akcipher_report_stat, #endif diff --git a/crypto/kpp.c b/crypto/kpp.c index 3e19c2f2cf94..74f2e8e918fa 100644 --- a/crypto/kpp.c +++ b/crypto/kpp.c @@ -17,8 +17,8 @@ #include "internal.h" -#ifdef CONFIG_NET -static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg) +static int __maybe_unused crypto_kpp_report( + struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_kpp rkpp; @@ -28,12 +28,6 @@ static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg) return nla_put(skb, CRYPTOCFGA_REPORT_KPP, sizeof(rkpp), &rkpp); } -#else -static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif static void crypto_kpp_show(struct seq_file *m, struct crypto_alg *alg) __maybe_unused; @@ -102,7 +96,9 @@ static const struct crypto_type crypto_kpp_type = { #ifdef CONFIG_PROC_FS .show = crypto_kpp_show, #endif +#ifdef CONFIG_CRYPTO_USER .report = crypto_kpp_report, +#endif #ifdef CONFIG_CRYPTO_STATS .report_stat = crypto_kpp_report_stat, #endif diff --git a/crypto/rng.c b/crypto/rng.c index ef56c71bda50..ffde0f64fb25 100644 --- a/crypto/rng.c +++ b/crypto/rng.c @@ -69,8 +69,8 @@ static unsigned int seedsize(struct crypto_alg *alg) return ralg->seedsize; } -#ifdef CONFIG_NET -static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg) +static int __maybe_unused crypto_rng_report( + struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_rng rrng; @@ -82,12 +82,6 @@ static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg) return nla_put(skb, CRYPTOCFGA_REPORT_RNG, sizeof(rrng), &rrng); } -#else -static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) __maybe_unused; @@ -124,7 +118,9 @@ static const struct crypto_type crypto_rng_type = { #ifdef CONFIG_PROC_FS .show = crypto_rng_show, #endif +#ifdef CONFIG_CRYPTO_USER .report = crypto_rng_report, +#endif #ifdef CONFIG_CRYPTO_STATS .report_stat = crypto_rng_report_stat, #endif diff --git a/crypto/scompress.c b/crypto/scompress.c index 214283f7730a..24138b42a648 100644 --- a/crypto/scompress.c +++ b/crypto/scompress.c @@ -37,8 +37,8 @@ static const struct crypto_type crypto_scomp_type; static int scomp_scratch_users; static DEFINE_MUTEX(scomp_lock); -#ifdef CONFIG_NET -static int crypto_scomp_report(struct sk_buff *skb, struct crypto_alg *alg) +static int __maybe_unused crypto_scomp_report( + struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_comp rscomp; @@ -49,12 +49,6 @@ static int crypto_scomp_report(struct sk_buff *skb, struct crypto_alg *alg) return nla_put(skb, CRYPTOCFGA_REPORT_COMPRESS, sizeof(rscomp), &rscomp); } -#else -static int crypto_scomp_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif static void crypto_scomp_show(struct seq_file *m, struct crypto_alg *alg) __maybe_unused; @@ -246,7 +240,9 @@ static const struct crypto_type crypto_scomp_type = { #ifdef CONFIG_PROC_FS .show = crypto_scomp_show, #endif +#ifdef CONFIG_CRYPTO_USER .report = crypto_scomp_report, +#endif #ifdef CONFIG_CRYPTO_STATS .report_stat = crypto_acomp_report_stat, #endif diff --git a/crypto/shash.c b/crypto/shash.c index 1f3454736f6e..dcc6a7170ce4 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -490,8 +490,8 @@ static void crypto_shash_free_instance(struct crypto_instance *inst) shash->free(shash); } -#ifdef CONFIG_NET -static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg) +static int __maybe_unused crypto_shash_report( + struct sk_buff *skb, struct crypto_alg *alg) { struct crypto_report_hash rhash; struct shash_alg *salg = __crypto_shash_alg(alg); @@ -505,12 +505,6 @@ static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg) return nla_put(skb, CRYPTOCFGA_REPORT_HASH, sizeof(rhash), &rhash); } -#else -static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg) __maybe_unused; @@ -536,7 +530,9 @@ static const struct crypto_type crypto_shash_type = { #ifdef CONFIG_PROC_FS .show = crypto_shash_show, #endif +#ifdef CONFIG_CRYPTO_USER .report = crypto_shash_report, +#endif #ifdef CONFIG_CRYPTO_STATS .report_stat = crypto_shash_report_stat, #endif diff --git a/crypto/skcipher.c b/crypto/skcipher.c index 0139f3416339..6caca02d7e55 100644 --- a/crypto/skcipher.c +++ b/crypto/skcipher.c @@ -727,8 +727,8 @@ static void crypto_skcipher_show(struct seq_file *m, struct crypto_alg *alg) seq_printf(m, "walksize : %u\n", skcipher->walksize); } -#ifdef CONFIG_NET -static int crypto_skcipher_report(struct sk_buff *skb, struct crypto_alg *alg) +static int __maybe_unused crypto_skcipher_report( + struct sk_buff *skb, struct crypto_alg *alg) { struct skcipher_alg *skcipher = __crypto_skcipher_alg(alg); struct crypto_report_blkcipher rblkcipher; @@ -746,12 +746,6 @@ static int crypto_skcipher_report(struct sk_buff *skb, struct crypto_alg *alg) return nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER, sizeof(rblkcipher), &rblkcipher); } -#else -static int crypto_skcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif static int __maybe_unused crypto_skcipher_report_stat( struct sk_buff *skb, struct crypto_alg *alg) @@ -782,7 +776,9 @@ static const struct crypto_type crypto_skcipher_type = { #ifdef CONFIG_PROC_FS .show = crypto_skcipher_show, #endif +#ifdef CONFIG_CRYPTO_USER .report = crypto_skcipher_report, +#endif #ifdef CONFIG_CRYPTO_STATS .report_stat = crypto_skcipher_report_stat, #endif -- cgit v1.2.3-58-ga151 From ed3630b83e9394acef27041de7a2223f1e875e9a Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Thu, 13 Apr 2023 14:24:19 +0800 Subject: crypto: hash - Add crypto_clone_ahash/shash This patch adds the helpers crypto_clone_ahash and crypto_clone_shash. They are the hash-specific counterparts of crypto_clone_tfm. This allows code paths that cannot otherwise allocate a hash tfm object to do so. Once a new tfm has been obtained its key could then be changed without impacting other users. Note that only algorithms that implement clone_tfm can be cloned. However, all keyless hashes can be cloned by simply reusing the tfm object. Signed-off-by: Herbert Xu Reviewed-by: Simon Horman Signed-off-by: Herbert Xu --- crypto/ahash.c | 51 +++++++++++++++++++++++++++++++++++++++++ crypto/hash.h | 4 ++++ crypto/shash.c | 52 ++++++++++++++++++++++++++++++++++++++++++ include/crypto/hash.h | 8 +++++++ include/crypto/internal/hash.h | 2 -- 5 files changed, 115 insertions(+), 2 deletions(-) (limited to 'crypto/ahash.c') diff --git a/crypto/ahash.c b/crypto/ahash.c index 2d858d7fd1bb..b8a607928e72 100644 --- a/crypto/ahash.c +++ b/crypto/ahash.c @@ -543,6 +543,57 @@ int crypto_has_ahash(const char *alg_name, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(crypto_has_ahash); +struct crypto_ahash *crypto_clone_ahash(struct crypto_ahash *hash) +{ + struct hash_alg_common *halg = crypto_hash_alg_common(hash); + struct crypto_tfm *tfm = crypto_ahash_tfm(hash); + struct crypto_ahash *nhash; + struct ahash_alg *alg; + int err; + + if (!crypto_hash_alg_has_setkey(halg)) { + tfm = crypto_tfm_get(tfm); + if (IS_ERR(tfm)) + return ERR_CAST(tfm); + + return hash; + } + + nhash = crypto_clone_tfm(&crypto_ahash_type, tfm); + + if (IS_ERR(nhash)) + return nhash; + + nhash->init = hash->init; + nhash->update = hash->update; + nhash->final = hash->final; + nhash->finup = hash->finup; + nhash->digest = hash->digest; + nhash->export = hash->export; + nhash->import = hash->import; + nhash->setkey = hash->setkey; + nhash->reqsize = hash->reqsize; + + if (tfm->__crt_alg->cra_type != &crypto_ahash_type) + return crypto_clone_shash_ops_async(nhash, hash); + + err = -ENOSYS; + alg = crypto_ahash_alg(hash); + if (!alg->clone_tfm) + goto out_free_nhash; + + err = alg->clone_tfm(nhash, hash); + if (err) + goto out_free_nhash; + + return nhash; + +out_free_nhash: + crypto_free_ahash(nhash); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(crypto_clone_ahash); + static int ahash_prepare_alg(struct ahash_alg *alg) { struct crypto_alg *base = &alg->halg.base; diff --git a/crypto/hash.h b/crypto/hash.h index 57b28a986d69..7e6c1a948692 100644 --- a/crypto/hash.h +++ b/crypto/hash.h @@ -31,6 +31,10 @@ static inline int crypto_hash_report_stat(struct sk_buff *skb, return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash); } +int crypto_init_shash_ops_async(struct crypto_tfm *tfm); +struct crypto_ahash *crypto_clone_shash_ops_async(struct crypto_ahash *nhash, + struct crypto_ahash *hash); + int hash_prepare_alg(struct hash_alg_common *alg); #endif /* _LOCAL_CRYPTO_HASH_H */ diff --git a/crypto/shash.c b/crypto/shash.c index 4cefa614dbbd..5845b7d59b2f 100644 --- a/crypto/shash.c +++ b/crypto/shash.c @@ -445,6 +445,24 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm) return 0; } +struct crypto_ahash *crypto_clone_shash_ops_async(struct crypto_ahash *nhash, + struct crypto_ahash *hash) +{ + struct crypto_shash **nctx = crypto_ahash_ctx(nhash); + struct crypto_shash **ctx = crypto_ahash_ctx(hash); + struct crypto_shash *shash; + + shash = crypto_clone_shash(*ctx); + if (IS_ERR(shash)) { + crypto_free_ahash(nhash); + return ERR_CAST(shash); + } + + *nctx = shash; + + return nhash; +} + static void crypto_shash_exit_tfm(struct crypto_tfm *tfm) { struct crypto_shash *hash = __crypto_shash_cast(tfm); @@ -564,6 +582,40 @@ int crypto_has_shash(const char *alg_name, u32 type, u32 mask) } EXPORT_SYMBOL_GPL(crypto_has_shash); +struct crypto_shash *crypto_clone_shash(struct crypto_shash *hash) +{ + struct crypto_tfm *tfm = crypto_shash_tfm(hash); + struct shash_alg *alg = crypto_shash_alg(hash); + struct crypto_shash *nhash; + int err; + + if (!crypto_shash_alg_has_setkey(alg)) { + tfm = crypto_tfm_get(tfm); + if (IS_ERR(tfm)) + return ERR_CAST(tfm); + + return hash; + } + + if (!alg->clone_tfm) + return ERR_PTR(-ENOSYS); + + nhash = crypto_clone_tfm(&crypto_shash_type, tfm); + if (IS_ERR(nhash)) + return nhash; + + nhash->descsize = hash->descsize; + + err = alg->clone_tfm(nhash, hash); + if (err) { + crypto_free_shash(nhash); + return ERR_PTR(err); + } + + return nhash; +} +EXPORT_SYMBOL_GPL(crypto_clone_shash); + int hash_prepare_alg(struct hash_alg_common *alg) { struct crypto_istat_hash *istat = hash_get_stat(alg); diff --git a/include/crypto/hash.h b/include/crypto/hash.h index 3a04e601ad6a..e69542d86a2b 100644 --- a/include/crypto/hash.h +++ b/include/crypto/hash.h @@ -152,6 +152,7 @@ struct ahash_request { * @exit_tfm: Deinitialize the cryptographic transformation object. * This is a counterpart to @init_tfm, used to remove * various changes set in @init_tfm. + * @clone_tfm: Copy transform into new object, may allocate memory. * @halg: see struct hash_alg_common */ struct ahash_alg { @@ -166,6 +167,7 @@ struct ahash_alg { unsigned int keylen); int (*init_tfm)(struct crypto_ahash *tfm); void (*exit_tfm)(struct crypto_ahash *tfm); + int (*clone_tfm)(struct crypto_ahash *dst, struct crypto_ahash *src); struct hash_alg_common halg; }; @@ -209,6 +211,7 @@ struct shash_desc { * @exit_tfm: Deinitialize the cryptographic transformation object. * This is a counterpart to @init_tfm, used to remove * various changes set in @init_tfm. + * @clone_tfm: Copy transform into new object, may allocate memory. * @digestsize: see struct ahash_alg * @statesize: see struct ahash_alg * @descsize: Size of the operational state for the message digest. This state @@ -234,6 +237,7 @@ struct shash_alg { unsigned int keylen); int (*init_tfm)(struct crypto_shash *tfm); void (*exit_tfm)(struct crypto_shash *tfm); + int (*clone_tfm)(struct crypto_shash *dst, struct crypto_shash *src); unsigned int descsize; @@ -297,6 +301,8 @@ static inline struct crypto_ahash *__crypto_ahash_cast(struct crypto_tfm *tfm) struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, u32 mask); +struct crypto_ahash *crypto_clone_ahash(struct crypto_ahash *tfm); + static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm) { return &tfm->base; @@ -761,6 +767,8 @@ static inline void ahash_request_set_crypt(struct ahash_request *req, struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type, u32 mask); +struct crypto_shash *crypto_clone_shash(struct crypto_shash *tfm); + int crypto_has_shash(const char *alg_name, u32 type, u32 mask); static inline struct crypto_tfm *crypto_shash_tfm(struct crypto_shash *tfm) diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h index 0b259dbb97af..37edf3f4e8af 100644 --- a/include/crypto/internal/hash.h +++ b/include/crypto/internal/hash.h @@ -133,8 +133,6 @@ int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc); int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc); int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc); -int crypto_init_shash_ops_async(struct crypto_tfm *tfm); - static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm) { return crypto_tfm_ctx(crypto_ahash_tfm(tfm)); -- cgit v1.2.3-58-ga151