diff mbox series

[v2,09/11] crypto: hash - Add sync hash interface

Message ID d6e10dbf172f0b7c791f5406d55e8f1c74492d57.1739674648.git.herbert@gondor.apana.org.au
State New
Headers show
Series Multibuffer hashing take two | expand

Commit Message

Herbert Xu Feb. 16, 2025, 3:07 a.m. UTC
Introduce a new sync hash interface based on ahash, similar to
sync skcipher.

It will replace shash for existing users.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---
 crypto/ahash.c        |  37 ++++++++++++++++
 include/crypto/hash.h | 100 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 137 insertions(+)
diff mbox series

Patch

diff --git a/crypto/ahash.c b/crypto/ahash.c
index 6b19fa6fc628..fafce2e47a78 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -949,6 +949,27 @@  struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type,
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_ahash);
 
+struct crypto_sync_hash *crypto_alloc_sync_hash(const char *alg_name,
+						u32 type, u32 mask)
+{
+	struct crypto_ahash *tfm;
+
+	/* Only sync algorithms allowed. */
+	mask |= CRYPTO_ALG_ASYNC;
+	type &= ~CRYPTO_ALG_ASYNC;
+
+	tfm = crypto_alloc_ahash(alg_name, type, mask);
+
+	if (!IS_ERR(tfm) && WARN_ON(crypto_ahash_reqsize(tfm) >
+				    MAX_SYNC_HASH_REQSIZE)) {
+		crypto_free_ahash(tfm);
+		return ERR_PTR(-EINVAL);
+	}
+
+	return container_of(tfm, struct crypto_sync_hash, base);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_sync_hash);
+
 int crypto_has_ahash(const char *alg_name, u32 type, u32 mask)
 {
 	return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask);
@@ -1123,5 +1144,21 @@  void ahash_request_free(struct ahash_request *req)
 }
 EXPORT_SYMBOL_GPL(ahash_request_free);
 
+int crypto_sync_hash_digest(struct crypto_sync_hash *tfm, const u8 *data,
+			    unsigned int len, u8 *out)
+{
+	SYNC_HASH_REQUEST_ON_STACK(req, tfm);
+	int err;
+
+	ahash_request_set_callback(req, 0, NULL, NULL);
+	ahash_request_set_virt(req, data, out, len);
+	err = crypto_ahash_digest(req);
+
+	ahash_request_zero(req);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(crypto_shash_tfm_digest);
+
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Asynchronous cryptographic hash type");
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index 2aa83ee0ec98..f6e0c44331a3 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -8,6 +8,7 @@ 
 #ifndef _CRYPTO_HASH_H
 #define _CRYPTO_HASH_H
 
+#include <linux/align.h>
 #include <linux/atomic.h>
 #include <linux/crypto.h>
 #include <linux/string.h>
@@ -162,6 +163,8 @@  struct shash_desc {
 	void *__ctx[] __aligned(ARCH_SLAB_MINALIGN);
 };
 
+struct sync_hash_requests;
+
 #define HASH_MAX_DIGESTSIZE	 64
 
 /*
@@ -169,12 +172,30 @@  struct shash_desc {
  * containing a 'struct sha3_state'.
  */
 #define HASH_MAX_DESCSIZE	(sizeof(struct shash_desc) + 360)
+#define MAX_SYNC_HASH_REQSIZE	HASH_MAX_DESCSIZE
 
 #define SHASH_DESC_ON_STACK(shash, ctx)					     \
 	char __##shash##_desc[sizeof(struct shash_desc) + HASH_MAX_DESCSIZE] \
 		__aligned(__alignof__(struct shash_desc));		     \
 	struct shash_desc *shash = (struct shash_desc *)__##shash##_desc
 
+#define SYNC_HASH_REQUEST_ON_STACK(name, _tfm) \
+	char __##name##_req[sizeof(struct ahash_request) + \
+			     MAX_SYNC_HASH_REQSIZE \
+			    ] CRYPTO_MINALIGN_ATTR; \
+	struct ahash_request *name = \
+		(((struct ahash_request *)__##name##_req)->base.tfm = \
+			crypto_sync_hash_tfm((_tfm)), \
+		 (void *)__##name##_req)
+
+#define SYNC_HASH_REQUESTS_ON_STACK(name, _n, _tfm) \
+	char __##name##_req[(_n) * ALIGN(sizeof(struct ahash_request) + \
+					  MAX_SYNC_HASH_REQSIZE, \
+					  CRYPTO_MINALIGN) \
+			    ] CRYPTO_MINALIGN_ATTR; \
+	struct sync_hash_requests *name = sync_hash_requests_on_stack_init( \
+		__##name##_req, sizeof(__##name##_req), (_tfm))
+
 /**
  * struct shash_alg - synchronous message digest definition
  * @init: see struct ahash_alg
@@ -241,6 +262,10 @@  struct crypto_shash {
 	struct crypto_tfm base;
 };
 
+struct crypto_sync_hash {
+	struct crypto_ahash base;
+};
+
 /**
  * DOC: Asynchronous Message Digest API
  *
@@ -273,6 +298,9 @@  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_sync_hash *crypto_alloc_sync_hash(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)
@@ -280,6 +308,12 @@  static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm)
 	return &tfm->base;
 }
 
+static inline struct crypto_tfm *crypto_sync_hash_tfm(
+	struct crypto_sync_hash *tfm)
+{
+	return crypto_ahash_tfm(&tfm->base);
+}
+
 /**
  * crypto_free_ahash() - zeroize and free the ahash handle
  * @tfm: cipher handle to be freed
@@ -291,6 +325,11 @@  static inline void crypto_free_ahash(struct crypto_ahash *tfm)
 	crypto_destroy_tfm(tfm, crypto_ahash_tfm(tfm));
 }
 
+static inline void crypto_free_sync_hash(struct crypto_sync_hash *tfm)
+{
+	crypto_free_ahash(&tfm->base);
+}
+
 /**
  * crypto_has_ahash() - Search for the availability of an ahash.
  * @alg_name: is the cra_name / name or cra_driver_name / driver name of the
@@ -313,6 +352,12 @@  static inline const char *crypto_ahash_driver_name(struct crypto_ahash *tfm)
 	return crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm));
 }
 
+static inline const char *crypto_sync_hash_driver_name(
+	struct crypto_sync_hash *tfm)
+{
+	return crypto_ahash_driver_name(&tfm->base);
+}
+
 /**
  * crypto_ahash_blocksize() - obtain block size for cipher
  * @tfm: cipher handle
@@ -327,6 +372,12 @@  static inline unsigned int crypto_ahash_blocksize(struct crypto_ahash *tfm)
 	return crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm));
 }
 
+static inline unsigned int crypto_sync_hash_blocksize(
+	struct crypto_sync_hash *tfm)
+{
+	return crypto_ahash_blocksize(&tfm->base);
+}
+
 static inline struct hash_alg_common *__crypto_hash_alg_common(
 	struct crypto_alg *alg)
 {
@@ -354,6 +405,12 @@  static inline unsigned int crypto_ahash_digestsize(struct crypto_ahash *tfm)
 	return crypto_hash_alg_common(tfm)->digestsize;
 }
 
+static inline unsigned int crypto_sync_hash_digestsize(
+	struct crypto_sync_hash *tfm)
+{
+	return crypto_ahash_digestsize(&tfm->base);
+}
+
 /**
  * crypto_ahash_statesize() - obtain size of the ahash state
  * @tfm: cipher handle
@@ -369,6 +426,12 @@  static inline unsigned int crypto_ahash_statesize(struct crypto_ahash *tfm)
 	return tfm->statesize;
 }
 
+static inline unsigned int crypto_sync_hash_statesize(
+	struct crypto_sync_hash *tfm)
+{
+	return crypto_ahash_statesize(&tfm->base);
+}
+
 static inline u32 crypto_ahash_get_flags(struct crypto_ahash *tfm)
 {
 	return crypto_tfm_get_flags(crypto_ahash_tfm(tfm));
@@ -877,6 +940,9 @@  int crypto_shash_digest(struct shash_desc *desc, const u8 *data,
 int crypto_shash_tfm_digest(struct crypto_shash *tfm, const u8 *data,
 			    unsigned int len, u8 *out);
 
+int crypto_sync_hash_digest(struct crypto_sync_hash *tfm, const u8 *data,
+			    unsigned int len, u8 *out);
+
 /**
  * crypto_shash_export() - extract operational state for message digest
  * @desc: reference to the operational state handle whose state is exported
@@ -982,6 +1048,13 @@  static inline void shash_desc_zero(struct shash_desc *desc)
 			 sizeof(*desc) + crypto_shash_descsize(desc->tfm));
 }
 
+static inline void ahash_request_zero(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+
+	memzero_explicit(req, sizeof(*req) + crypto_ahash_reqsize(tfm));
+}
+
 static inline int ahash_request_err(struct ahash_request *req)
 {
 	return req->base.err;
@@ -992,4 +1065,31 @@  static inline bool ahash_is_async(struct crypto_ahash *tfm)
 	return crypto_tfm_is_async(&tfm->base);
 }
 
+static inline struct ahash_request *sync_hash_requests(
+	struct sync_hash_requests *reqs, int i)
+{
+	unsigned unit = sizeof(struct ahash_request) + MAX_SYNC_HASH_REQSIZE;
+	unsigned alunit = ALIGN(unit, CRYPTO_MINALIGN);
+
+	return (void *)((char *)reqs + i * alunit);
+}
+
+static inline struct sync_hash_requests *sync_hash_requests_on_stack_init(
+	char *buf, unsigned len, struct crypto_sync_hash *tfm)
+{
+	unsigned unit = sizeof(struct ahash_request) + MAX_SYNC_HASH_REQSIZE;
+	unsigned alunit = ALIGN(unit, CRYPTO_MINALIGN);
+	struct sync_hash_requests *reqs = (void *)buf;
+	int n = len / alunit;
+	int i;
+
+	for (i = 0; i < n; i++) {
+		struct ahash_request *req = sync_hash_requests(reqs, i);
+
+		req->base.tfm = crypto_sync_hash_tfm(tfm);
+	}
+
+	return reqs;
+}
+
 #endif	/* _CRYPTO_HASH_H */