diff mbox series

[RFC,01/18] crypto: shash - add plumbing for operating on scatterlists

Message ID 20190925161255.1871-2-ard.biesheuvel@linaro.org
State New
Headers show
Series crypto: wireguard using the existing crypto API | expand

Commit Message

Ard Biesheuvel Sept. 25, 2019, 4:12 p.m. UTC
Add an internal method to the shash interface that permits templates
to invoke it with a scatterlist. Drivers implementing the shash
interface can opt into using this method, making it more straightforward
for templates to pass down data provided via scatterlists without forcing
the underlying shash to process each scatterlist entry with a discrete
update() call. This will be used later in the SIMD accelerated Poly1305
to amortize SIMD begin()/end() calls over the entire input.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>

---
 crypto/ahash.c                 | 18 +++++++++++++++
 crypto/shash.c                 | 24 ++++++++++++++++++++
 include/crypto/hash.h          |  3 +++
 include/crypto/internal/hash.h | 19 ++++++++++++++++
 4 files changed, 64 insertions(+)

-- 
2.20.1
diff mbox series

Patch

diff --git a/crypto/ahash.c b/crypto/ahash.c
index 3815b363a693..aecb48f0f50c 100644
--- a/crypto/ahash.c
+++ b/crypto/ahash.c
@@ -144,6 +144,24 @@  int crypto_hash_walk_first(struct ahash_request *req,
 }
 EXPORT_SYMBOL_GPL(crypto_hash_walk_first);
 
+int crypto_shash_walk_sg(struct shash_desc *desc, struct scatterlist *sg,
+			 int nbytes, struct crypto_hash_walk *walk, int flags)
+{
+	walk->total = nbytes;
+
+	if (!walk->total) {
+		walk->entrylen = 0;
+		return 0;
+	}
+
+	walk->alignmask = crypto_shash_alignmask(desc->tfm);
+	walk->sg = sg;
+	walk->flags = flags;
+
+	return hash_walk_new_entry(walk);
+}
+EXPORT_SYMBOL_GPL(crypto_shash_walk_sg);
+
 int crypto_ahash_walk_first(struct ahash_request *req,
 			    struct crypto_hash_walk *walk)
 {
diff --git a/crypto/shash.c b/crypto/shash.c
index e83c5124f6eb..b16ab5590dc4 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -121,6 +121,30 @@  int crypto_shash_update(struct shash_desc *desc, const u8 *data,
 }
 EXPORT_SYMBOL_GPL(crypto_shash_update);
 
+int crypto_shash_update_from_sg(struct shash_desc *desc, struct scatterlist *sg,
+				unsigned int len, bool atomic)
+{
+	struct crypto_shash *tfm = desc->tfm;
+	struct shash_alg *shash = crypto_shash_alg(tfm);
+	struct crypto_hash_walk walk;
+	int flags = 0;
+	int nbytes;
+
+	if (!atomic)
+		flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	if (shash->update_from_sg)
+		return shash->update_from_sg(desc, sg, len, flags);
+
+	for (nbytes = crypto_shash_walk_sg(desc, sg, len, &walk, flags);
+	     nbytes > 0;
+	     nbytes = crypto_hash_walk_done(&walk, nbytes))
+		nbytes = crypto_shash_update(desc, walk.data, nbytes);
+
+	return nbytes;
+}
+EXPORT_SYMBOL_GPL(crypto_shash_update_from_sg);
+
 static int shash_final_unaligned(struct shash_desc *desc, u8 *out)
 {
 	struct crypto_shash *tfm = desc->tfm;
diff --git a/include/crypto/hash.h b/include/crypto/hash.h
index ef10c370605a..0b83d85a3828 100644
--- a/include/crypto/hash.h
+++ b/include/crypto/hash.h
@@ -158,6 +158,7 @@  struct shash_desc {
  * struct shash_alg - synchronous message digest definition
  * @init: see struct ahash_alg
  * @update: see struct ahash_alg
+ * @update_from_sg: variant of update() taking a scatterlist as input [optional]
  * @final: see struct ahash_alg
  * @finup: see struct ahash_alg
  * @digest: see struct ahash_alg
@@ -175,6 +176,8 @@  struct shash_alg {
 	int (*init)(struct shash_desc *desc);
 	int (*update)(struct shash_desc *desc, const u8 *data,
 		      unsigned int len);
+	int (*update_from_sg)(struct shash_desc *desc, struct scatterlist *sg,
+			      unsigned int len, int flags);
 	int (*final)(struct shash_desc *desc, u8 *out);
 	int (*finup)(struct shash_desc *desc, const u8 *data,
 		     unsigned int len, u8 *out);
diff --git a/include/crypto/internal/hash.h b/include/crypto/internal/hash.h
index bfc9db7b100d..6f4bfa057bea 100644
--- a/include/crypto/internal/hash.h
+++ b/include/crypto/internal/hash.h
@@ -50,6 +50,8 @@  extern const struct crypto_type crypto_ahash_type;
 int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err);
 int crypto_hash_walk_first(struct ahash_request *req,
 			   struct crypto_hash_walk *walk);
+int crypto_shash_walk_sg(struct shash_desc *desc, struct scatterlist *sg,
+			 int nbytes, struct crypto_hash_walk *walk, int flags);
 int crypto_ahash_walk_first(struct ahash_request *req,
 			   struct crypto_hash_walk *walk);
 
@@ -242,5 +244,22 @@  static inline struct crypto_shash *__crypto_shash_cast(struct crypto_tfm *tfm)
 	return container_of(tfm, struct crypto_shash, base);
 }
 
+/**
+ * crypto_shash_update_from_sg() - add data from a scatterlist to message digest
+ * 				   for processing
+ * @desc: operational state handle that is already initialized
+ * @data: scatterlist with input data to be added to the message digest
+ * @len: length of the input data
+ * @atomic: whether or not the call is permitted to sleep
+ *
+ * Updates the message digest state of the operational state handle.
+ *
+ * Context: Any context.
+ * Return: 0 if the message digest update was successful; < 0 if an error
+ *	   occurred
+ */
+int crypto_shash_update_from_sg(struct shash_desc *desc, struct scatterlist *sg,
+				unsigned int len, bool atomic);
+
 #endif	/* _CRYPTO_INTERNAL_HASH_H */