Skip to content

Commit ed3630b

Browse files
committed
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 <herbert@gondor.apana.org.au> Reviewed-by: Simon Horman <simon.horman@corigine.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
1 parent 3c3a24c commit ed3630b

File tree

5 files changed

+115
-2
lines changed

5 files changed

+115
-2
lines changed

crypto/ahash.c

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,57 @@ int crypto_has_ahash(const char *alg_name, u32 type, u32 mask)
543543
}
544544
EXPORT_SYMBOL_GPL(crypto_has_ahash);
545545

546+
struct crypto_ahash *crypto_clone_ahash(struct crypto_ahash *hash)
547+
{
548+
struct hash_alg_common *halg = crypto_hash_alg_common(hash);
549+
struct crypto_tfm *tfm = crypto_ahash_tfm(hash);
550+
struct crypto_ahash *nhash;
551+
struct ahash_alg *alg;
552+
int err;
553+
554+
if (!crypto_hash_alg_has_setkey(halg)) {
555+
tfm = crypto_tfm_get(tfm);
556+
if (IS_ERR(tfm))
557+
return ERR_CAST(tfm);
558+
559+
return hash;
560+
}
561+
562+
nhash = crypto_clone_tfm(&crypto_ahash_type, tfm);
563+
564+
if (IS_ERR(nhash))
565+
return nhash;
566+
567+
nhash->init = hash->init;
568+
nhash->update = hash->update;
569+
nhash->final = hash->final;
570+
nhash->finup = hash->finup;
571+
nhash->digest = hash->digest;
572+
nhash->export = hash->export;
573+
nhash->import = hash->import;
574+
nhash->setkey = hash->setkey;
575+
nhash->reqsize = hash->reqsize;
576+
577+
if (tfm->__crt_alg->cra_type != &crypto_ahash_type)
578+
return crypto_clone_shash_ops_async(nhash, hash);
579+
580+
err = -ENOSYS;
581+
alg = crypto_ahash_alg(hash);
582+
if (!alg->clone_tfm)
583+
goto out_free_nhash;
584+
585+
err = alg->clone_tfm(nhash, hash);
586+
if (err)
587+
goto out_free_nhash;
588+
589+
return nhash;
590+
591+
out_free_nhash:
592+
crypto_free_ahash(nhash);
593+
return ERR_PTR(err);
594+
}
595+
EXPORT_SYMBOL_GPL(crypto_clone_ahash);
596+
546597
static int ahash_prepare_alg(struct ahash_alg *alg)
547598
{
548599
struct crypto_alg *base = &alg->halg.base;

crypto/hash.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ static inline int crypto_hash_report_stat(struct sk_buff *skb,
3131
return nla_put(skb, CRYPTOCFGA_STAT_HASH, sizeof(rhash), &rhash);
3232
}
3333

34+
int crypto_init_shash_ops_async(struct crypto_tfm *tfm);
35+
struct crypto_ahash *crypto_clone_shash_ops_async(struct crypto_ahash *nhash,
36+
struct crypto_ahash *hash);
37+
3438
int hash_prepare_alg(struct hash_alg_common *alg);
3539

3640
#endif /* _LOCAL_CRYPTO_HASH_H */

crypto/shash.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,24 @@ int crypto_init_shash_ops_async(struct crypto_tfm *tfm)
445445
return 0;
446446
}
447447

448+
struct crypto_ahash *crypto_clone_shash_ops_async(struct crypto_ahash *nhash,
449+
struct crypto_ahash *hash)
450+
{
451+
struct crypto_shash **nctx = crypto_ahash_ctx(nhash);
452+
struct crypto_shash **ctx = crypto_ahash_ctx(hash);
453+
struct crypto_shash *shash;
454+
455+
shash = crypto_clone_shash(*ctx);
456+
if (IS_ERR(shash)) {
457+
crypto_free_ahash(nhash);
458+
return ERR_CAST(shash);
459+
}
460+
461+
*nctx = shash;
462+
463+
return nhash;
464+
}
465+
448466
static void crypto_shash_exit_tfm(struct crypto_tfm *tfm)
449467
{
450468
struct crypto_shash *hash = __crypto_shash_cast(tfm);
@@ -564,6 +582,40 @@ int crypto_has_shash(const char *alg_name, u32 type, u32 mask)
564582
}
565583
EXPORT_SYMBOL_GPL(crypto_has_shash);
566584

585+
struct crypto_shash *crypto_clone_shash(struct crypto_shash *hash)
586+
{
587+
struct crypto_tfm *tfm = crypto_shash_tfm(hash);
588+
struct shash_alg *alg = crypto_shash_alg(hash);
589+
struct crypto_shash *nhash;
590+
int err;
591+
592+
if (!crypto_shash_alg_has_setkey(alg)) {
593+
tfm = crypto_tfm_get(tfm);
594+
if (IS_ERR(tfm))
595+
return ERR_CAST(tfm);
596+
597+
return hash;
598+
}
599+
600+
if (!alg->clone_tfm)
601+
return ERR_PTR(-ENOSYS);
602+
603+
nhash = crypto_clone_tfm(&crypto_shash_type, tfm);
604+
if (IS_ERR(nhash))
605+
return nhash;
606+
607+
nhash->descsize = hash->descsize;
608+
609+
err = alg->clone_tfm(nhash, hash);
610+
if (err) {
611+
crypto_free_shash(nhash);
612+
return ERR_PTR(err);
613+
}
614+
615+
return nhash;
616+
}
617+
EXPORT_SYMBOL_GPL(crypto_clone_shash);
618+
567619
int hash_prepare_alg(struct hash_alg_common *alg)
568620
{
569621
struct crypto_istat_hash *istat = hash_get_stat(alg);

include/crypto/hash.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ struct ahash_request {
152152
* @exit_tfm: Deinitialize the cryptographic transformation object.
153153
* This is a counterpart to @init_tfm, used to remove
154154
* various changes set in @init_tfm.
155+
* @clone_tfm: Copy transform into new object, may allocate memory.
155156
* @halg: see struct hash_alg_common
156157
*/
157158
struct ahash_alg {
@@ -166,6 +167,7 @@ struct ahash_alg {
166167
unsigned int keylen);
167168
int (*init_tfm)(struct crypto_ahash *tfm);
168169
void (*exit_tfm)(struct crypto_ahash *tfm);
170+
int (*clone_tfm)(struct crypto_ahash *dst, struct crypto_ahash *src);
169171

170172
struct hash_alg_common halg;
171173
};
@@ -209,6 +211,7 @@ struct shash_desc {
209211
* @exit_tfm: Deinitialize the cryptographic transformation object.
210212
* This is a counterpart to @init_tfm, used to remove
211213
* various changes set in @init_tfm.
214+
* @clone_tfm: Copy transform into new object, may allocate memory.
212215
* @digestsize: see struct ahash_alg
213216
* @statesize: see struct ahash_alg
214217
* @descsize: Size of the operational state for the message digest. This state
@@ -234,6 +237,7 @@ struct shash_alg {
234237
unsigned int keylen);
235238
int (*init_tfm)(struct crypto_shash *tfm);
236239
void (*exit_tfm)(struct crypto_shash *tfm);
240+
int (*clone_tfm)(struct crypto_shash *dst, struct crypto_shash *src);
237241

238242
unsigned int descsize;
239243

@@ -297,6 +301,8 @@ static inline struct crypto_ahash *__crypto_ahash_cast(struct crypto_tfm *tfm)
297301
struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type,
298302
u32 mask);
299303

304+
struct crypto_ahash *crypto_clone_ahash(struct crypto_ahash *tfm);
305+
300306
static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm)
301307
{
302308
return &tfm->base;
@@ -761,6 +767,8 @@ static inline void ahash_request_set_crypt(struct ahash_request *req,
761767
struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type,
762768
u32 mask);
763769

770+
struct crypto_shash *crypto_clone_shash(struct crypto_shash *tfm);
771+
764772
int crypto_has_shash(const char *alg_name, u32 type, u32 mask);
765773

766774
static inline struct crypto_tfm *crypto_shash_tfm(struct crypto_shash *tfm)

include/crypto/internal/hash.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,6 @@ int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc);
133133
int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc);
134134
int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc);
135135

136-
int crypto_init_shash_ops_async(struct crypto_tfm *tfm);
137-
138136
static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm)
139137
{
140138
return crypto_tfm_ctx(crypto_ahash_tfm(tfm));

0 commit comments

Comments
 (0)