Skip to contentSkip to conversation

crypto: spacc - Add SPAcc Crypto Driver

PATCH New Pavitrakumar Managutte 2 participants 7 messages Oct 30

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

v27 cover crypto: spacc - Add SPAcc Crypto Driver

Add the driver for SPAcc(Security Protocol Accelerator), which is a crypto acceleration IP from Synopsys. The SPAcc supports multiple ciphers, hashes and AEAD algorithms with various modes. The driver currently supports below

hash:
- cmac(sm4)
- xcbc(sm4)
- hmac(md5)
- md5
- hmac(sha1)
- sha1
- sha224
- sha256
- sha384
- sha512
- hmac(sha224)
- hmac(sha256)
- hmac(sha384)
- hmac(sha512)
- sha3-224
- sha3-256
- sha3-384
- sha3-512

changelog:
v1->v2 changes:
- Added local_bh_disable() and local_bh_enable() for the below calls. a. for ciphers skcipher_request_complete()
b. for aead aead_request_complete()
c. for hash ahash_request_complete()
- dt-bindings updates
a. removed snps,vspacc-priority and made it into config option b. renamed snps,spacc-wdtimer to snps,spacc-internal-counter c. Added description to all properties
- Updated corresponding dt-binding changes to code

v2->v3 changes:
- cra_init and cra_exit replaced with init_tfm and exit_tfm for hashes.
- removed mutex_lock/unlock for spacc_skcipher_fallback call
- dt-bindings updates
a. updated SOC related information
b. renamed compatible string as per SOC
- Updated corresponding dt-binding changes to code

v3->v4 changes:
- removed snps,vspacc-id from the dt-bindings
- removed mutex_lock from ciphers
- replaced magic numbers with macros
- removed sw_fb variable from struct mode_tab and associated code from the hashes
- polling code is replaced by wait_event_interruptible

v4->v5 changes:
- Updated to register with the crypto-engine
- Used semaphore to manage SPAcc device hardware context pool
- This patchset supports Hashes only
- Dropping the support for Ciphers and AEADs in this patchset
- Added Reviewed-by tag on the Device tree patch since it was reviewed on v4 patch by Krzysztof Kozlowski and Rob Herring (Arm)

v5->v6 changes:
- Removed CRYPTO_DEV_SPACC_CIPHER and CRYPTO_DEV_SPACC_AEAD Kconfig options, since the cipher and aead support is not part of this patchset
- Dropped spacc_skcipher.o and spacc_aead.o from Makefile to fix build errors reported by kernel test robot
- Added Reported-by and Closes tags as suggested

v6->v7 changes:
- Fixed build error reported by Kernel test robot
- Added Reported-by and Closes tags as suggested

v7->v8 changes:
- Fixed misleading comment: Clarified that only HMAC key pre-processing is done in software, while the actual HMAC operation is performed by hardware
- Simplified do_shash() function signature by removing unused parameters
- Updated all do_shash() call sites to use new simplified signature
- Fixed commit message formatting by adding "crypto: spacc - <subject>" to all patches
- used __free() for scope based resource management

v8->v9 changes:
- Updated the software fallback implementation to use HASH_FBREQ_ON_STACK
- Corrected dynamic allocation of statesize and reqsize in init_tfm
- Fixed synchronization issues in the digest request

v9->v10 changes:
- Fixed unused variable warning

v10->v11 changes:
- Removed the redundant crypto_alloc_ahash in the init_tfm function
- Removed the redundant crypto_free_ahash in exit_tfm function
- Removed the redundant crypto_ahash_setkey call in setkey function

v11->v12 changes:
- Removed do_shash() and switched to lib/crypto API in spacc_hash_setkey
- Dropped support for SM3 algorithm
- Improved multi-device safety by encapsulating handling within priv
- Added memzero_explicit() in sensitive paths
- Minor code cleanups and style fixes
- Algorithm registration cleanups

v12->v13 changes:
- Removed all the sleep function from setkey function
- Added shash implemntation for aes algorthims

v13->v14 changes:
-Added fixes based on the reports by Sashiko
-Removed the spacc_is_mode_keysize_supported call from do_one_request

v14->v15 changes:
-Added fixes based on the reports by Sashiko on 19/jun/2026 -Fixed styling in the Kconfig

v15->v16 changes:
-Added fixes based on the reports by Sashiko

v16->v17 changes:
-Added fixes based on the reports by Sashiko

v17->v18 changes:
-Added fixes based on the reports by Sashiko

v18->v19 changes:
-Added fixes based on the reports by Sashiko

v19->v20 changes:
-Added fixes based on the reports by Sashiko

v20->v21 changes:
-Added fixes based on the reports by Sashiko

v21->v22 changes:
-Added fixes based on the reports by Sashiko

v22->v23 changes:
-Added fixes based on the reports by Sashiko

v23->v24 changes:
-Added fixes based on the reports by Sashiko

v24->v25 changes:
-Added fixes based on the reports by Sashiko

v25->v26 changes:
-Added fixes based on the reports by Sashiko -Removed the additional fallback
-Added the CRYPTO_AHASH_ALG_BLOCK_ONLY flag to the cra_flags -Minor code cleanups and style fixes

v26->v27 changes:
-Added fixes based on the reports by Sashiko

Pavitrakumar Managutte (4):
dt-bindings: crypto: Document support for SPAcc
crypto: spacc - Add SPAcc ahash support
crypto: spacc - add spacc autodetect support
crypto: spacc - Add SPAcc Kconfig and Makefile

 .../bindings/crypto/snps,dwc-spacc.yaml       |   50 +
 drivers/crypto/Kconfig                        |    1 +
 drivers/crypto/Makefile                       |    1 +
 drivers/crypto/dwc-spacc/Kconfig              |   64 +
 drivers/crypto/dwc-spacc/Makefile             |    7 +
 drivers/crypto/dwc-spacc/spacc_ahash.c        |  857 ++++++
 drivers/crypto/dwc-spacc/spacc_core.c         | 2529 +++++++++++++++++
 drivers/crypto/dwc-spacc/spacc_core.h         |  863 ++++++
 drivers/crypto/dwc-spacc/spacc_device.c       |  324 +++
 drivers/crypto/dwc-spacc/spacc_device.h       |  181 ++
 drivers/crypto/dwc-spacc/spacc_hal.c          |  349 +++
 drivers/crypto/dwc-spacc/spacc_hal.h          |  113 +
 drivers/crypto/dwc-spacc/spacc_interrupt.c    |  360 +++
 drivers/crypto/dwc-spacc/spacc_manager.c      |  657 +++++
 14 files changed, 6356 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml
 create mode 100644 drivers/crypto/dwc-spacc/Kconfig
 create mode 100644 drivers/crypto/dwc-spacc/Makefile
 create mode 100644 drivers/crypto/dwc-spacc/spacc_ahash.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_core.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_core.h
 create mode 100644 drivers/crypto/dwc-spacc/spacc_device.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_device.h
 create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.h
 create mode 100644 drivers/crypto/dwc-spacc/spacc_interrupt.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_manager.c

base-commit: 178aff4cf425b3fc51ff09c571fa1bfbc1eb8ea4 --
2.25.1

#1 lore raw

PATCH v27 1/4 dt-bindings: crypto: Document support for SPAcc

Add DT bindings related to the SPAcc driver for Documentation. DWC Synopsys Security Protocol Accelerator(SPAcc) Hardware Crypto Engine is a crypto IP designed by Synopsys.

---
 .../bindings/crypto/snps,dwc-spacc.yaml       | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml
Documentation/devicetree/bindings/crypto/snps,dwc-spacc.yaml new file +50 -0
new file mode 100644
index 0000000000000..a337f7b473cc7
@@ -0,0 +1,50 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/crypto/snps,dwc-spacc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Synopsys DesignWare Security Protocol Accelerator (SPAcc) Crypto Engine
+
+maintainers:
+  - Ross Bannerman <[email protected]>
+
+description: |
+  The Synopsys DWC Security Protocol Accelerator (SPAcc) is a
+  semiconductor IP designed to accelerate cryptographic operations,
+  such as encryption, decryption, and hashing.
+
+  In this configuration, the SPAcc IP is instantiated within the Synopsys
+  NSIMOSCI virtual SoC platform, a SystemC simulation environment used for
+  software development and testing. The device is accessed as a memory-mapped
+  peripheral and generates interrupts to the ARC interrupt controller.
+
+properties:
+  compatible:
+    items:
+      - const: snps,nsimosci-hs-spacc
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+
+additionalProperties: false
+
+examples:
+  - |
+    crypto@40000000 {
+        compatible = "snps,nsimosci-hs-spacc";
+        reg = <0x40000000 0x40000>;
+        interrupts = <28>;
+        clocks = <&clock>;
+    };

--
2.25.1

#2 lore raw

PATCH v27 2/4 crypto: spacc - Add SPAcc ahash support

In reply to Pavitrakumar Managutte

Add ahash support to SPAcc driver.
Below are the hash algos supported:
- cmac(sm4)
- xcbc(sm4)
- hmac(md5)
- md5
- hmac(sha1)
- sha1
- sha224
- sha256
- sha384
- sha512
- hmac(sha224)
- hmac(sha256)
- hmac(sha384)
- hmac(sha512)
- sha3-224
- sha3-256
- sha3-384
- sha3-512

---
 drivers/crypto/dwc-spacc/spacc_ahash.c     |  857 +++++++++++++
 drivers/crypto/dwc-spacc/spacc_core.c      | 1337 ++++++++++++++++++++
 drivers/crypto/dwc-spacc/spacc_core.h      |  863 +++++++++++++
 drivers/crypto/dwc-spacc/spacc_device.c    |  324 +++++
 drivers/crypto/dwc-spacc/spacc_device.h    |  181 +++
 drivers/crypto/dwc-spacc/spacc_hal.c       |  349 +++++
 drivers/crypto/dwc-spacc/spacc_hal.h       |  113 ++
 drivers/crypto/dwc-spacc/spacc_interrupt.c |  360 ++++++
 drivers/crypto/dwc-spacc/spacc_manager.c   |  657 ++++++++++
 9 files changed, 5041 insertions(+)
 create mode 100644 drivers/crypto/dwc-spacc/spacc_ahash.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_core.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_core.h
 create mode 100644 drivers/crypto/dwc-spacc/spacc_device.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_device.h
 create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_hal.h
 create mode 100644 drivers/crypto/dwc-spacc/spacc_interrupt.c
 create mode 100644 drivers/crypto/dwc-spacc/spacc_manager.c
drivers/crypto/dwc-spacc/spacc_ahash.c new file +857 -0
new file mode 100644
index 0000000000000..4437abd02176a
@@ -0,0 +1,857 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/dmapool.h>
+#include <crypto/sha1.h>
+#include <crypto/sm4.h>
+#include <crypto/sha2.h>
+#include <crypto/sha3.h>
+#include <crypto/md5.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/scatterlist.h>
+#include <crypto/scatterwalk.h>
+#include <crypto/internal/hash.h>
+#include <crypto/engine.h>
+#include <linux/delay.h>
+#include <linux/atomic.h>
+
+#include "spacc_device.h"
+#include "spacc_core.h"
+
+#define PPP_BUF_SIZE 128
+
+static struct mode_tab possible_hashes[] = {
+	{ MODE_TAB_HASH("cmac(sm4)",	MAC_SM4_CMAC, 16, 16) },
+	{ .keylen[0] = 32 | MODE_TAB_HASH_XCBC, MODE_TAB_HASH("xcbc(sm4)",
+	MAC_SM4_XCBC, 16, 16) },
+
+	{ MODE_TAB_HASH("hmac(md5)",	HMAC_MD5, MD5_DIGEST_SIZE,
+	MD5_HMAC_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("md5",		HASH_MD5, MD5_DIGEST_SIZE,
+	MD5_HMAC_BLOCK_SIZE) },
+
+	{ MODE_TAB_HASH("hmac(sha1)",	HMAC_SHA1, SHA1_DIGEST_SIZE,
+	SHA1_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("sha1",		HASH_SHA1, SHA1_DIGEST_SIZE,
+	SHA1_BLOCK_SIZE) },
+
+	{ MODE_TAB_HASH("sha224",	HASH_SHA224, SHA224_DIGEST_SIZE,
+	SHA224_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("sha256",	HASH_SHA256, SHA256_DIGEST_SIZE,
+	SHA256_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("sha384",	HASH_SHA384, SHA384_DIGEST_SIZE,
+	SHA384_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("sha512",	HASH_SHA512, SHA512_DIGEST_SIZE,
+	SHA512_BLOCK_SIZE) },
+
+	{ MODE_TAB_HASH("hmac(sha512)",	HMAC_SHA512, SHA512_DIGEST_SIZE,
+	SHA512_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("hmac(sha224)",	HMAC_SHA224, SHA224_DIGEST_SIZE,
+	SHA224_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("hmac(sha256)",	HMAC_SHA256, SHA256_DIGEST_SIZE,
+	SHA256_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("hmac(sha384)",	HMAC_SHA384, SHA384_DIGEST_SIZE,
+	SHA384_BLOCK_SIZE) },
+
+	{ MODE_TAB_HASH("sha3-224",	HASH_SHA3_224, SHA3_224_DIGEST_SIZE,
+	SHA3_224_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("sha3-256",	HASH_SHA3_256, SHA3_256_DIGEST_SIZE,
+	SHA3_256_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("sha3-384",	HASH_SHA3_384, SHA3_384_DIGEST_SIZE,
+	SHA3_384_BLOCK_SIZE) },
+	{ MODE_TAB_HASH("sha3-512",	HASH_SHA3_512, SHA3_512_DIGEST_SIZE,
+	SHA3_512_BLOCK_SIZE) },
+};
+
+static void spacc_hash_cleanup_dma_dst(struct ahash_request *req)
+{
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+	pdu_ddt_free(&ctx->dst);
+}
+
+static void spacc_hash_cleanup_dma_src(struct spacc_crypto_ctx *tctx,
+				       struct ahash_request *req)
+{
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+	if (tctx->tmp_sgl && tctx->tmp_sgl[0].length != 0) {
+		dma_unmap_sg(tctx->dev, tctx->tmp_sgl, ctx->src_nents,
+			     DMA_TO_DEVICE);
+		tctx->tmp_sgl[0].length = 0;
+	} else {
+		dma_unmap_sg(tctx->dev, req->src, ctx->src_nents,
+			     DMA_TO_DEVICE);
+	}
+
+	pdu_ddt_free(&ctx->src);
+}
+
+static int spacc_init_calg(struct crypto_alg *calg,
+			   const struct mode_tab *mode)
+{
+	if (strscpy(calg->cra_name, mode->name) < 0)
+		return -ENAMETOOLONG;
+
+	if (snprintf(calg->cra_driver_name, CRYPTO_MAX_ALG_NAME,
+			"spacc-%s", mode->name) >= CRYPTO_MAX_ALG_NAME)
+		return -ENAMETOOLONG;
+
+	calg->cra_blocksize = mode->blocklen;
+
+	return 0;
+}
+
+static int spacc_ctx_clone_handle(struct ahash_request *req)
+{
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+	struct spacc_priv *priv = dev_get_drvdata(tctx->dev);
+
+	if (tctx->handle < 0)
+		return -EINVAL;
+
+	if (!priv)
+		return -ENODEV;
+
+	ctx->acb.new_handle = spacc_clone_handle(&priv->spacc, tctx->handle,
+						 &ctx->acb);
+
+	if (ctx->acb.new_handle < 0)
+		return -ENOMEM;
+
+	ctx->acb.tctx  = tctx;
+	ctx->acb.ctx   = ctx;
+	ctx->acb.req   = req;
+	ctx->acb.spacc = &priv->spacc;
+
+	return 0;
+}
+
+static int spacc_hash_init_dma(struct device *dev, struct ahash_request *req)
+{
+	int rc = -1;
+	struct crypto_ahash *tfm = crypto_ahash_reqtfm(req);
+	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+	struct spacc_priv *priv = dev_get_drvdata(dev);
+
+	/*
+	 * do_one_request runs in a sleepable context,
+	 * so GFP_KERNEL is always safe here.
+	 */
+	gfp_t mflags = GFP_KERNEL;
+
+	ctx->acb.new_handle = -1;
+	ctx->digest_buf = dma_pool_alloc(priv->hash_pool, mflags,
+					 &ctx->digest_dma);
+
+	if (!ctx->digest_buf)
+		return -ENOMEM;
+
+	rc = pdu_ddt_init(dev, &ctx->dst, 1 | 0x80000000);
+	if (rc < 0) {
+		dev_err(dev, "ERR: PDU DDT init error\n");
+		rc = -EIO;
+		goto err_free_digest;
+	}
+
+	pdu_ddt_add(dev, &ctx->dst, ctx->digest_dma, SPACC_MAX_DIGEST_SIZE);
+
+	if (ctx->total_nents > 0 && ctx->single_shot) {
+		/* single shot */
+		rc = spacc_ctx_clone_handle(req);
+		if (rc < 0)
+			goto err_free_dst;
+
+		if (req->nbytes) {
+			rc = spacc_sg_to_ddt(dev, req->src, req->nbytes,
+					&ctx->src, DMA_TO_DEVICE);
+		} else {
+			memset(tctx->tmp_buffer, '\0', PPP_BUF_SIZE);
+			sg_set_buf(&tctx->tmp_sgl[0], tctx->tmp_buffer,
+					PPP_BUF_SIZE);
+			rc = spacc_sg_to_ddt(dev, &tctx->tmp_sgl[0],
+					tctx->tmp_sgl[0].length,
+					&ctx->src, DMA_TO_DEVICE);
+		}
+	} else if (ctx->total_nents == 0 && req->nbytes == 0) {
+		rc = spacc_ctx_clone_handle(req);
+		if (rc < 0)
+			goto err_free_dst;
+
+		/* zero length case */
+		memset(tctx->tmp_buffer, '\0', PPP_BUF_SIZE);
+		sg_set_buf(&tctx->tmp_sgl[0], tctx->tmp_buffer, PPP_BUF_SIZE);
+		rc = spacc_sg_to_ddt(dev, &tctx->tmp_sgl[0],
+					tctx->tmp_sgl[0].length,
+					&ctx->src, DMA_TO_DEVICE);
+	} else {
+		/*
+		 * ctx->total_nents == 0 with req->nbytes > 0: an empty
+		 * scatterlist can't supply the bytes the request claims to
+		 * have. Fail explicitly instead of silently falling through
+		 * with a stale `rc`.
+		 */
+		dev_err(dev, "ERR: empty src sg with nbytes=%u\n", req->nbytes);
+		rc = -EINVAL;
+		goto err_free_dst;
+	}
+
+	if (rc < 0)
+		goto err_free_dst;
+
+	ctx->src_nents = rc;
+	return rc;
+
+err_free_dst:
+	/*
+	 * If the handle was already cloned (semaphore count and job slot
+	 * taken) before this failure, release it.
+	 */
+	if (ctx->acb.new_handle >= 0) {
+		spacc_close(&priv->spacc, ctx->acb.new_handle);
+		ctx->acb.new_handle = -1;
+	}
+	pdu_ddt_free(&ctx->dst);
+
+err_free_digest:
+	dma_pool_free(priv->hash_pool, ctx->digest_buf, ctx->digest_dma);
+
+	return rc;
+}
+
+static void spacc_free_mems(struct spacc_crypto_reqctx *ctx,
+			    struct spacc_crypto_ctx *tctx,
+			    struct ahash_request *req)
+{
+	spacc_hash_cleanup_dma_dst(req);
+	spacc_hash_cleanup_dma_src(tctx, req);
+
+	if (ctx->single_shot) {
+		kfree(tctx->tmp_sgl);
+		tctx->tmp_sgl = NULL;
+
+		ctx->single_shot = 0;
+		if (ctx->total_nents)
+			ctx->total_nents = 0;
+	}
+}
+
+static void spacc_digest_cb(void *spacc, void *tfm)
+{
+	int err;
+	int dig_sz;
+	struct ahash_cb_data *cb = tfm;
+	struct spacc_device *device = spacc;
+	struct spacc_priv *priv = container_of(device, struct spacc_priv,
+					       spacc);
+
+	dig_sz = crypto_ahash_digestsize(crypto_ahash_reqtfm(cb->req));
+
+	err = cb->spacc->job[cb->new_handle].job_err;
+
+	if (!err)
+		memcpy(cb->req->result, cb->ctx->digest_buf, dig_sz);
+
+	dma_pool_free(priv->hash_pool, cb->ctx->digest_buf,
+			cb->ctx->digest_dma);
+
+	spacc_free_mems(cb->ctx, cb->tctx, cb->req);
+	spacc_close(cb->spacc, cb->new_handle);
+
+	local_bh_disable();
+	crypto_finalize_hash_request(priv->engine, cb->req, err);
+	local_bh_enable();
+
+	/*
+	 * This decrement must run exactly once for every enqueued job (it
+	 * balances the atomic_inc in spacc_hash_do_one_request and releases
+	 * the drain in spacc_crypto_remove).
+	 */
+	if (atomic_dec_and_test(&priv->dma_ref_cnt))
+		wake_up(&priv->drain_wq);
+}
+
+static int spacc_hash_commit_key(struct crypto_ahash *tfm,
+				 struct spacc_priv *priv,
+				 const u8 *key, unsigned int keylen,
+				 const u8 *keybuf, unsigned int klen)
+{
+	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct crypto_ahash *fb;
+	int ret;
+
+	guard(mutex)(&tctx->lock);
+
+	fb = crypto_ahash_fb(tfm);
+	if (fb) {
+		ret = crypto_ahash_setkey(fb, key, keylen);
+		if (ret)
+			return ret;
+	}
+
+	memcpy(tctx->ipad, keybuf, klen);
+	tctx->keylen = klen;
+
+	/* Invalidate any cached HW context - key has changed. */
+	if (tctx->handle >= 0) {
+		spacc_close(&priv->spacc, tctx->handle);
+		tctx->handle = -1;
+	}
+
+	tctx->ctx_valid = false;
+	return 0;
+}
+
+static int spacc_hash_setkey(struct crypto_ahash *tfm, const u8 *key,
+			     unsigned int keylen)
+{
+	unsigned int block_size;
+	unsigned int digest_size;
+	const struct spacc_alg *salg = spacc_tfm_ahash(&tfm->base);
+	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct spacc_priv *priv = dev_get_drvdata(salg->dev);
+	u8 keybuf[sizeof(tctx->ipad)];
+	unsigned int klen;
+	int ret = 0;
+
+	if (!priv)
+		return -ENODEV;
+
+	block_size = crypto_tfm_alg_blocksize(&tfm->base);
+	digest_size = crypto_ahash_digestsize(tfm);
+
+	/*
+	 * We are using hardware for HMAC operations. The software fallback is
+	 * only for key pre-processing in case of HMACs.
+	 * This was meant for hashes but it also works for cmac/xcbc.
+	 */
+	if (keylen > block_size) {
+		dev_dbg(salg->dev, "Exceeds keylen: %u\n", keylen);
+		dev_dbg(salg->dev, "Req. keylen hashing %s\n",
+				salg->calg->cra_name);
+
+		switch (salg->mode->id) {
+		case CRYPTO_MODE_HMAC_SHA224:
+			sha224(key, keylen, keybuf);
+			break;
+
+		case CRYPTO_MODE_HMAC_SHA256:
+			sha256(key, keylen, keybuf);
+			break;
+
+		case CRYPTO_MODE_HMAC_SHA384:
+			sha384(key, keylen, keybuf);
+			break;
+
+		case CRYPTO_MODE_HMAC_SHA512:
+			sha512(key, keylen, keybuf);
+			break;
+
+		case CRYPTO_MODE_HMAC_MD5:
+			md5(key, keylen, keybuf);
+			break;
+
+		case CRYPTO_MODE_HMAC_SHA1:
+			sha1(key, keylen, keybuf);
+			break;
+		default:
+			ret = -EINVAL;
+			goto out;
+		}
+
+		klen = digest_size;
+		dev_dbg(salg->dev, "updated keylen: %u\n", keylen);
+	} else {
+		/*
+		 * CMAC/XCBC skip the hashing path above, and via AF_ALG the
+		 * key length is fully user-controlled.  tctx->ipad is a fixed
+		 * 128-byte buffer, so reject anything that would not fit
+		 * before copying to prevent a heap buffer overflow.
+		 */
+		if (keylen > sizeof(keybuf)) {
+			ret = -EINVAL;
+			goto out;
+		}
+
+		/*
+		 * Enforcing valid block-cipher key sizes supported by SPAcc:
+		 *  - AES-CMAC accepts 16/24/32,
+		 *  - SM4-CMAC/XCBC/SM4-XCBC only 16.
+		 */
+		memcpy(keybuf, key, keylen);
+		klen = keylen;
+
+		/*
+		 * An empty HMAC key is the same as an all-zero key, because
+		 * HMAC pads the key with zeros. Program one zero byte so a
+		 * key is always written to the hardware context.
+		 */
+		if (!klen) {
+			keybuf[0] = 0;
+			klen = 1;
+		}
+	}
+
+	if (!spacc_is_mode_keysize_supported(&priv->spacc, salg->mode->id,
+				klen, 1)) {
+		dev_dbg(salg->dev, "keylen %u not supported for mode %d\n",
+				klen, salg->mode->id);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = spacc_hash_commit_key(tfm, priv, key, keylen, keybuf, klen);
+
+out:
+	memzero_explicit(keybuf, sizeof(keybuf));
+	return ret;
+}
+
+static int spacc_hash_try_hw(struct spacc_crypto_ctx *tctx,
+			     struct spacc_priv *priv,
+			     const struct spacc_alg *salg,
+			     struct crypto_ahash *reqtfm,
+			     struct ahash_request *req)
+{
+	int rc;
+
+	guard(mutex)(&tctx->lock);
+
+	if (tctx->handle < 0 || !tctx->ctx_valid) {
+		/*
+		 * spacc_open() acquires ctx_sem which may sleep;
+		 * do_one_request runs in the crypto_engine workqueue
+		 * which is a sleepable context, so this is safe.
+		 */
+		tctx->handle = spacc_open(&priv->spacc,
+					  CRYPTO_MODE_NULL, salg->mode->id,
+					  -1, 0, spacc_digest_cb, reqtfm);
+		if (tctx->handle < 0) {
+			dev_dbg(salg->dev, "context open failed, fallback\n");
+			return tctx->handle;
+		}
+
+		rc = spacc_set_operation(&priv->spacc, tctx->handle,
+				OP_ENCRYPT, ICV_HASH, IP_ICV_OFFSET, 0, 0, 0);
+		if (rc < 0) {
+			spacc_close(&priv->spacc, tctx->handle);
+			tctx->handle = -1;
+			return rc;
+		}
+
+		if (tctx->keylen > 0) {
+			u32 mode_id = salg->mode->id;
+
+			if (mode_id == CRYPTO_MODE_MAC_SM4_XCBC) {
+				rc = spacc_compute_xcbc_key(&priv->spacc,
+							    mode_id,
+							    tctx->handle,
+							    tctx->ipad,
+							    tctx->keylen,
+							    tctx->ipad);
+				if (rc < 0) {
+					spacc_close(&priv->spacc, tctx->handle);
+					tctx->handle = -1;
+					return rc;
+				}
+
+				rc = spacc_write_context(&priv->spacc,
+							 tctx->handle,
+							 SPACC_HASH_OPERATION,
+							 tctx->ipad,
+							 32 + tctx->keylen,
+							 NULL, 0);
+			} else {
+				rc = spacc_write_context(&priv->spacc,
+							 tctx->handle,
+							 SPACC_HASH_OPERATION,
+							 tctx->ipad,
+							 tctx->keylen,
+							 NULL, 0);
+			}
+
+			if (rc < 0) {
+				spacc_close(&priv->spacc, tctx->handle);
+				tctx->handle = -1;
+				return rc;
+			}
+		}
+
+		memzero_explicit(tctx->ipad, sizeof(tctx->ipad));
+		tctx->ctx_valid = true;
+	}
+
+	rc = spacc_hash_init_dma(tctx->dev, req);
+	if (rc < 0) {
+		dev_dbg(salg->dev, "DMA init failed (%d), falling back\n", rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+/* Crypto engine hash operation */
+static int spacc_hash_do_one_request(struct crypto_engine *engine, void *areq)
+{
+	int rc = 0;
+	struct ahash_request *req = ahash_request_cast(areq);
+	struct crypto_ahash *reqtfm = crypto_ahash_reqtfm(req);
+	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(reqtfm);
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+	const struct spacc_alg *salg = spacc_tfm_ahash(&reqtfm->base);
+
+	/*
+	 * Derive priv from the algorithm's stable device, not tctx->dev --
+	 * the latter is mutated by setkey() concurrently with this
+	 * function and is not safe to read outside tctx->lock.
+	 */
+	struct spacc_priv *priv = dev_get_drvdata(salg->dev);
+
+	ctx->single_shot = 1;
+	ctx->total_nents = sg_nents(req->src);
+	if (req->nbytes > priv->max_msg_len)
+		goto fallback;
+
+	tctx->tmp_sgl = kmalloc_array(2, sizeof(*tctx->tmp_sgl), GFP_KERNEL);
+	if (!tctx->tmp_sgl)
+		goto fallback;
+
+	sg_init_table(tctx->tmp_sgl, 2);
+	tctx->tmp_sgl[0].length = 0;
+
+	if (spacc_hash_try_hw(tctx, priv, salg, reqtfm, req) < 0)
+		goto fallback;
+
+	atomic_inc(&priv->dma_ref_cnt);
+
+	rc = spacc_packet_enqueue_ddt(&priv->spacc, ctx->acb.new_handle,
+			&ctx->src, &ctx->dst, req->nbytes,
+			0, req->nbytes, 0, 0, 0, false);
+	if (rc < 0) {
+
+		spacc_free_mems(ctx, tctx, req);
+		dma_pool_free(priv->hash_pool, ctx->digest_buf,
+				ctx->digest_dma);
+		pdu_ddt_free(&ctx->dst);
+
+		if (ctx->acb.new_handle >= 0) {
+			spacc_close(&priv->spacc, ctx->acb.new_handle);
+			ctx->acb.new_handle = -1;
+		}
+
+		if (rc == -EBUSY)
+			dev_dbg(salg->dev, "HW full, failing request\n");
+
+		local_bh_disable();
+		crypto_finalize_hash_request(priv->engine, req, rc);
+		local_bh_enable();
+
+		if (atomic_dec_and_test(&priv->dma_ref_cnt))
+			wake_up(&priv->drain_wq);
+
+		return 0;
+	}
+
+	return 0;
+
+fallback:
+	kfree(tctx->tmp_sgl);
+	tctx->tmp_sgl = NULL;
+
+	HASH_FBREQ_ON_STACK(fbreq, req);
+	rc = crypto_ahash_digest(fbreq);
+	HASH_REQUEST_ZERO(fbreq);
+
+	local_bh_disable();
+	crypto_finalize_hash_request(engine, req, rc);
+	local_bh_enable();
+
+	return 0;
+}
+
+static int spacc_hash_init_tfm(struct crypto_ahash *tfm)
+{
+	const struct spacc_alg *salg = container_of(crypto_ahash_alg(tfm),
+						    struct spacc_alg,
+						    alg.hash.base);
+	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+
+	tctx->handle    = -1;
+	tctx->ctx_valid = false;
+	tctx->dev       = get_device(salg->dev);
+	mutex_init(&tctx->lock);
+
+	return 0;
+}
+
+static void spacc_hash_exit_tfm(struct crypto_ahash *tfm)
+{
+	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct spacc_priv *priv = dev_get_drvdata(tctx->dev);
+
+	if (priv && tctx->handle >= 0)
+		spacc_close(&priv->spacc, tctx->handle);
+
+	put_device(tctx->dev);
+	mutex_destroy(&tctx->lock);
+}
+
+static int spacc_hash_init(struct ahash_request *req)
+{
+	int rc;
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+	memset(ctx->state_buffer, 0, sizeof(ctx->state_buffer));
+
+	HASH_FBREQ_ON_STACK(fbreq, req);
+	rc = crypto_ahash_init(fbreq);
+	if (!rc)
+		rc = crypto_ahash_export(fbreq, ctx->state_buffer);
+	HASH_REQUEST_ZERO(fbreq);
+
+	return rc;
+}
+
+static int spacc_hash_update(struct ahash_request *req)
+{
+	int rc;
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+	if (!req->nbytes)
+		return 0;
+
+	HASH_FBREQ_ON_STACK(fbreq, req);
+
+	rc = crypto_ahash_import(fbreq, ctx->state_buffer);
+	if (!rc)
+		rc = crypto_ahash_update(fbreq);
+	if (!rc)
+		rc = crypto_ahash_export(fbreq, ctx->state_buffer);
+
+	HASH_REQUEST_ZERO(fbreq);
+
+	return rc;
+}
+
+static int spacc_hash_final(struct ahash_request *req)
+{
+	int rc;
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+	HASH_FBREQ_ON_STACK(fbreq, req);
+	rc = crypto_ahash_import(fbreq, ctx->state_buffer);
+	if (!rc)
+		rc = crypto_ahash_final(fbreq);
+	HASH_REQUEST_ZERO(fbreq);
+
+	return rc;
+}
+
+static int spacc_hash_digest(struct ahash_request *req)
+{
+	struct crypto_ahash *reqtfm = crypto_ahash_reqtfm(req);
+	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(reqtfm);
+	struct spacc_priv *priv = dev_get_drvdata(tctx->dev);
+	unsigned long flags;
+	bool removing;
+
+	if (!priv || !priv->engine)
+		return -ENODEV;
+
+	spin_lock_irqsave(&priv->spacc.lock, flags);
+	removing = priv->removing;
+	spin_unlock_irqrestore(&priv->spacc.lock, flags);
+
+	if (removing)
+		return -ENODEV;
+
+	return crypto_transfer_hash_request_to_engine(priv->engine, req);
+}
+
+static int spacc_hash_finup(struct ahash_request *req)
+{
+	int rc;
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+	HASH_FBREQ_ON_STACK(fbreq, req);
+	rc = crypto_ahash_import(fbreq, ctx->state_buffer);
+	if (!rc)
+		rc = crypto_ahash_finup(fbreq);
+	HASH_REQUEST_ZERO(fbreq);
+
+	return rc;
+}
+
+static int spacc_hash_export(struct ahash_request *req, void *out)
+{
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+	memcpy(out, ctx->state_buffer, HASH_MAX_STATESIZE);
+	return 0;
+}
+
+static int spacc_hash_import(struct ahash_request *req, const void *in)
+{
+	struct spacc_crypto_reqctx *ctx = ahash_request_ctx(req);
+
+	memcpy(ctx->state_buffer, in, HASH_MAX_STATESIZE);
+	return 0;
+}
+
+static void spacc_hash_alg_destroy(struct crypto_alg *alg)
+{
+	struct spacc_alg *salg = container_of(alg, struct spacc_alg,
+					      alg.hash.base.halg.base);
+
+	kfree(salg);
+}
+
+static const struct ahash_engine_alg spacc_hash_template = {
+	.base = {
+		.init		= spacc_hash_init,
+		.update		= spacc_hash_update,
+		.final		= spacc_hash_final,
+		.finup		= spacc_hash_finup,
+		.digest		= spacc_hash_digest,
+		.setkey		= spacc_hash_setkey,
+		.export		= spacc_hash_export,
+		.import		= spacc_hash_import,
+		.init_tfm	= spacc_hash_init_tfm,
+		.exit_tfm	= spacc_hash_exit_tfm,
+
+		.halg.base = {
+			.cra_priority	= 300,
+			.cra_module	= THIS_MODULE,
+			.cra_ctxsize	= sizeof(struct spacc_crypto_ctx),
+			.cra_reqsize	= sizeof(struct spacc_crypto_reqctx),
+			.cra_destroy	= spacc_hash_alg_destroy,
+			.cra_flags	= CRYPTO_ALG_TYPE_AHASH		|
+					  CRYPTO_ALG_ASYNC		|
+					  CRYPTO_AHASH_ALG_BLOCK_ONLY
+		},
+	},
+	.op = {
+		.do_one_request = spacc_hash_do_one_request,
+	},
+};
+
+/* Keyed algorithms need a setkey(); plain digests must not have one. */
+static bool spacc_mode_is_keyed(int id)
+{
+	switch (id) {
+	case CRYPTO_MODE_HMAC_MD5:
+	case CRYPTO_MODE_HMAC_SHA1:
+	case CRYPTO_MODE_HMAC_SHA224:
+	case CRYPTO_MODE_HMAC_SHA256:
+	case CRYPTO_MODE_HMAC_SHA384:
+	case CRYPTO_MODE_HMAC_SHA512:
+	case CRYPTO_MODE_MAC_SM4_CMAC:
+	case CRYPTO_MODE_MAC_SM4_XCBC:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static int spacc_register_hash(struct spacc_alg *salg)
+{
+	int rc = 0;
+	struct spacc_priv *priv = dev_get_drvdata(salg->dev);
+
+	salg->calg = &salg->alg.hash.base.halg.base;
+	salg->alg.hash = spacc_hash_template;
+
+	/* Unkeyed digests must not advertise a setkey. */
+	if (!spacc_mode_is_keyed(salg->mode->id))
+		salg->alg.hash.base.setkey = NULL;
+
+	rc = spacc_init_calg(salg->calg, salg->mode);
+	if (rc)
+		return rc;
+
+	salg->alg.hash.base.halg.digestsize = salg->mode->hashlen;
+	salg->alg.hash.base.halg.statesize = HASH_MAX_STATESIZE;
+
+	rc = crypto_engine_register_ahash(&salg->alg.hash);
+	if (rc < 0)
+		return rc;
+
+	guard(mutex)(&priv->hash_alg_mutex);
+	list_add(&salg->list, &priv->hash_alg_list);
+
+	return 0;
+}
+
+int spacc_probe_hashes(struct platform_device *spacc_pdev)
+{
+	int rc = 0;
+	unsigned int index;
+	int registered = 0;
+	struct spacc_alg *salg;
+	struct spacc_priv *priv = dev_get_drvdata(&spacc_pdev->dev);
+	const char *name = NULL;
+
+	INIT_LIST_HEAD(&priv->hash_alg_list);
+	mutex_init(&priv->hash_alg_mutex);
+
+	/* Create per-device DMA pool */
+	priv->hash_pool = dma_pool_create("spacc-digest", &spacc_pdev->dev,
+			SPACC_MAX_DIGEST_SIZE,
+			SPACC_DMA_ALIGN, SPACC_DMA_BOUNDARY);
+
+	if (!priv->hash_pool)
+		return -ENOMEM;
+
+	for (index = 0; index < ARRAY_SIZE(possible_hashes); index++) {
+		name = possible_hashes[index].name;
+
+		if (!crypto_has_ahash(name, 0, 0))
+			continue;
+
+		if (spacc_is_mode_keysize_supported(&priv->spacc,
+					possible_hashes[index].id & 0xFF,
+					possible_hashes[index].hashlen, 1)) {
+			salg = kmalloc_obj(*salg, GFP_KERNEL);
+			if (!salg) {
+				rc = -ENOMEM;
+				goto err_unregister;
+			}
+
+			salg->mode = &possible_hashes[index];
+			salg->dev = &spacc_pdev->dev;
+
+			rc = spacc_register_hash(salg);
+			if (rc < 0)
+				continue;
+
+			registered++;
+		}
+	}
+
+	return registered;
+
+err_unregister:
+	spacc_unregister_hash_algs(priv);
+	return rc;
+}
+
+int spacc_unregister_hash_algs(struct spacc_priv *priv)
+{
+	struct spacc_alg *salg, *tmp;
+
+	if (!priv)
+		return 0;
+
+	guard(mutex)(&priv->hash_alg_mutex);
+
+	list_for_each_entry_safe(salg, tmp, &priv->hash_alg_list, list) {
+		list_del(&salg->list);
+		crypto_engine_unregister_ahash(&salg->alg.hash);
+	}
+
+	return 0;
+}
drivers/crypto/dwc-spacc/spacc_core.c new file +1337 -0

1,337 lines not on this page · raw message

drivers/crypto/dwc-spacc/spacc_core.h new file +863 -0

806 lines not on this page · raw message

drivers/crypto/dwc-spacc/spacc_device.c new file +324 -0

324 lines not on this page · raw message

drivers/crypto/dwc-spacc/spacc_device.h new file +181 -0

181 lines not on this page · raw message

drivers/crypto/dwc-spacc/spacc_hal.c new file +349 -0

349 lines not on this page · raw message

drivers/crypto/dwc-spacc/spacc_hal.h new file +113 -0

113 lines not on this page · raw message

drivers/crypto/dwc-spacc/spacc_interrupt.c new file +360 -0

360 lines not on this page · raw message

drivers/crypto/dwc-spacc/spacc_manager.c new file +657 -0

657 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

--
2.25.1

Part of the diff is not shown here. View the raw message.

#3 lore raw

Re: [PATCH v27 2/4] crypto: spacc - Add SPAcc ahash support

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider: - [High] crypto: spacc: statesize overflow and broken BLOCK_ONLY in spacc_register_hash() - [High] crypto…

Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
- [High] crypto: spacc: statesize overflow and broken BLOCK_ONLY in spacc_register_hash()
- [High] crypto: spacc: teardown race and use-after-free in spacc_crypto_remove()
- [High] crypto: spacc - unsplit >64KB or boundary-crossing SG entries in spacc_sg_to_ddt()
- [High] crypto: spacc - hardirq livelock in spacc_process_irq() in IRQ mode
- [Medium] crypto: spacc: sleeping lock in spacc_hash_setkey() and persistent hw handle
- [Medium] crypto: spacc - unlocked IRQ state and register setup in spacc_init_device() --

commit 39aecabd458071b66bf2f10317714fe1849c6141
Author: Pavitrakumar Managutte <[email protected]>

crypto: spacc - Add SPAcc ahash support

This commit adds core SPAcc driver infrastructure and ahash algorithm support for MD5, SHA-1, SHA-2, SHA-3, HMAC, and SM4 CMAC/XCBC.

Quoted 5 lines
drivers/crypto/dwc-spacc/spacc_ahash.c new file +0 -0
new file mode 100644
index 0000000000000..4437abd02176a

[ ... ]

Quoted 10 lines
drivers/crypto/dwc-spacc/spacc_ahash.c new file +10 -0
+static int spacc_hash_commit_key(struct crypto_ahash *tfm,
+				 struct spacc_priv *priv,
+				 const u8 *key, unsigned int keylen,
+				 const u8 *keybuf, unsigned int klen)
+{
+	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
+	struct crypto_ahash *fb;
+	int ret;
+
+	guard(mutex)(&tctx->lock);

[ ... ]

Quoted 19 lines
drivers/crypto/dwc-spacc/spacc_ahash.c new file +19 -0
+static int spacc_hash_try_hw(struct spacc_crypto_ctx *tctx,
+			     struct spacc_priv *priv,
+			     const struct spacc_alg *salg,
+			     struct crypto_ahash *reqtfm,
+			     struct ahash_request *req)
+{
+	int rc;
+
+	guard(mutex)(&tctx->lock);
+
+	if (tctx->handle < 0 || !tctx->ctx_valid) {
+		/*
+		 * spacc_open() acquires ctx_sem which may sleep;
+		 * do_one_request runs in the crypto_engine workqueue
+		 * which is a sleepable context, so this is safe.
+		 */
+		tctx->handle = spacc_open(&priv->spacc,
+					  CRYPTO_MODE_NULL, salg->mode->id,
+					  -1, 0, spacc_digest_cb, reqtfm);

[ ... ]

drivers/crypto/dwc-spacc/spacc_ahash.c line 486

Quoted 3 lines
drivers/crypto/dwc-spacc/spacc_ahash.c new file +3 -0
+		memzero_explicit(tctx->ipad, sizeof(tctx->ipad));
+		tctx->ctx_valid = true;
+	}

[Severity: Medium]
As reported by Herbert Xu on v12 [1], crypto_ahash_setkey() should not sleep, and hardware handles can be allocated and released per request in spacc_hash_do_one_request().

In spacc_hash_setkey() -> spacc_hash_commit_key(), acquiring tctx->lock still sleeps if crypto_ahash_setkey() is called from atomic context.

Additionally, spacc_hash_try_hw() opens a persistent tctx->handle on the transform context, zeroes tctx->ipad, and clones a second job slot (ctx->acb.new_handle) via spacc_hash_init_dma() -> spacc_ctx_clone_handle(). When the request completes, spacc_digest_cb() only closes cb->new_handle, leaving tctx->handle and its scarce hardware context slot pinned across idle transforms until spacc_hash_exit_tfm() or a subsequent setkey.

Could tctx->ipad be retained across requests and the hardware handle opened and closed per request inside spacc_hash_do_one_request() / spacc_digest_cb() so that setkey does not need a sleeping lock or persistent context?

[ ... ]

Quoted 28 lines
drivers/crypto/dwc-spacc/spacc_ahash.c new file +28 -0
+static const struct ahash_engine_alg spacc_hash_template = {
+	.base = {
+		.init		= spacc_hash_init,
+		.update		= spacc_hash_update,
+		.final		= spacc_hash_final,
+		.finup		= spacc_hash_finup,
+		.digest		= spacc_hash_digest,
+		.setkey		= spacc_hash_setkey,
+		.export		= spacc_hash_export,
+		.import		= spacc_hash_import,
+		.init_tfm	= spacc_hash_init_tfm,
+		.exit_tfm	= spacc_hash_exit_tfm,
+
+		.halg.base = {
+			.cra_priority	= 300,
+			.cra_module	= THIS_MODULE,
+			.cra_ctxsize	= sizeof(struct spacc_crypto_ctx),
+			.cra_reqsize	= sizeof(struct spacc_crypto_reqctx),
+			.cra_destroy	= spacc_hash_alg_destroy,
+			.cra_flags	= CRYPTO_ALG_TYPE_AHASH		|
+					  CRYPTO_ALG_ASYNC		|
+					  CRYPTO_AHASH_ALG_BLOCK_ONLY
+		},
+	},
+	.op = {
+		.do_one_request = spacc_hash_do_one_request,
+	},
+};

[ ... ]

Quoted 10 lines
drivers/crypto/dwc-spacc/spacc_ahash.c new file +10 -0
+static int spacc_register_hash(struct spacc_alg *salg)
+{
+	int rc = 0;
+	struct spacc_priv *priv = dev_get_drvdata(salg->dev);
+
+	salg->calg = &salg->alg.hash.base.halg.base;
+	salg->alg.hash = spacc_hash_template;
+
+	/* Unkeyed digests must not advertise a setkey. */
+	if (!spacc_mode_is_keyed(salg->mode->id))

drivers/crypto/dwc-spacc/spacc_ahash.c line 779

Quoted 10 lines
drivers/crypto/dwc-spacc/spacc_ahash.c new file +10 -0
+		salg->alg.hash.base.setkey = NULL;
+
+	rc = spacc_init_calg(salg->calg, salg->mode);
+	if (rc)
+		return rc;
+
+	salg->alg.hash.base.halg.digestsize = salg->mode->hashlen;
+	salg->alg.hash.base.halg.statesize = HASH_MAX_STATESIZE;
+
+	rc = crypto_engine_register_ahash(&salg->alg.hash);

[Severity: High]
As reported by Sashiko on v26 [2], does setting CRYPTO_AHASH_ALG_BLOCK_ONLY on spacc_hash_template combined with halg.statesize = HASH_MAX_STATESIZE in spacc_register_hash() break state export/import and virtual-address requests?

In spacc_ahash.c, spacc_hash_init(), spacc_hash_update(), spacc_hash_final(), spacc_hash_finup(), spacc_hash_export(), and spacc_hash_import() delegate full-state operations to the software fallback (fbreq) rather than implementing block-only core state operations (for instance, spacc_hash_update() delegates to crypto_ahash_update(fbreq) and returns 0 rather than returning the leftover partial-block byte count expected by CRYPTO_AHASH_ALG_BLOCK_ONLY).

When spacc_register_hash() calls crypto_engine_register_ahash() -> crypto_register_ahash() -> ahash_prepare_alg() with CRYPTO_AHASH_ALG_BLOCK_ONLY set, ahash_prepare_alg() adds cra_blocksize + 1 to alg->halg.statesize:

crypto_ahash_statesize(tfm) = HASH_MAX_STATESIZE + cra_blocksize + 1

This exceeds HASH_MAX_STATESIZE for every registered SPAcc algorithm, which causes:

1. ahash_do_req_chain() to reject all virtual-address requests (CRYPTO_AHASH_REQ_VIRT, including testmgr virtual-address tests and crypto/hmac.c wrapping unkeyed SPAcc hashes) with -ENOSYS because crypto_ahash_statesize(tfm) > HASH_MAX_STATESIZE.

2. crypto_ahash_export() to write cra_blocksize + 1 bytes at
out + HASH_MAX_STATESIZE after spacc_hash_export() copies HASH_MAX_STATESIZE bytes, overflowing any HASH_MAX_STATESIZE-sized export buffer.

Should CRYPTO_AHASH_ALG_BLOCK_ONLY be dropped from spacc_hash_template since incremental hashing is handled entirely by the software fallback?

Quoted 5 lines
drivers/crypto/dwc-spacc/spacc_core.c new file +0 -0
new file mode 100644
index 0000000000000..d26b5e30777e9

[ ... ]

Quoted 22 lines
drivers/crypto/dwc-spacc/spacc_core.c new file +22 -0
+int spacc_sg_to_ddt(struct device *dev, struct scatterlist *sg,
+		    int nbytes, struct pdu_ddt *ddt, int dma_direction)
+{
+	int i;
+	int nents;
+	int rc = 0;
+	int orig_nents;
+	struct scatterlist *sg_entry;
+
+	/* Count the SG entries needed to cover the requested length. */
+	orig_nents = sg_nents_for_len(sg, nbytes);
+	if (orig_nents <= 0)
+		return orig_nents;
+
+	nents = dma_map_sg(dev, sg, orig_nents, dma_direction);
+	if (nents <= 0)
+		return -ENOMEM;
+
+	rc = pdu_ddt_init(dev, ddt, nents | 0x80000000);
+	if (rc < 0) {
+		dma_unmap_sg(dev, sg, orig_nents, dma_direction);
+		return -EIO;

drivers/crypto/dwc-spacc/spacc_core.c line 235

Quoted 10 lines
drivers/crypto/dwc-spacc/spacc_core.c new file +10 -0
+	}
+
+	/* Populate the descriptor table with the DMA-mapped SG entries. */
+	for_each_sg(sg, sg_entry, nents, i) {
+		pdu_ddt_add(dev, ddt, sg_dma_address(sg_entry),
+			    sg_dma_len(sg_entry));
+	}
+
+	return orig_nents;
+}

[Severity: High]
What happens in spacc_sg_to_ddt() when an input scatterlist entry is larger than 64KB (SPACC_DMA_BOUNDARY) or straddles a 64KB DMA address boundary?

In spacc_init_device(), the driver notes that each DDT fragment must be <= 64KB and must not straddle a 64KB boundary, and sets priv->max_msg_len to priv->spacc.config.max_msg_size (up to 512KB) while relying on dma_set_max_seg_size() and dma_set_seg_boundary().

However, dma_map_sg() maps entries in-place into the caller-supplied sg array of orig_nents elements; while those DMA parameters prevent an IOMMU from merging adjacent SG entries across a 64KB boundary, dma_map_sg() cannot split a single scatterlist entry that is already > 64KB (such as a high-order folio or kmalloc buffer) or that crosses a 64KB boundary on a dma-direct system.

Since spacc_sg_to_ddt() passes each mapped sg_entry directly to pdu_ddt_add(), won't such requests violate the hardware's 64KB DDT fragment limit and trigger SPACC_MEMERR or DMA-API debug warnings?

Quoted 5 lines
drivers/crypto/dwc-spacc/spacc_device.c new file +0 -0
new file mode 100644
index 0000000000000..4620281d3e1a9

[ ... ]

Quoted 9 lines
drivers/crypto/dwc-spacc/spacc_device.c new file +9 -0
+	irq_ret = devm_request_irq(&pdev->dev, irq_num, spacc_irq_handler,
+			     IRQF_SHARED, dev_name(&pdev->dev),
+			     &pdev->dev);
+	if (irq_ret) {
+		dev_err(&pdev->dev, "Failed to request IRQ : %d\n", irq_ret);
+		err = irq_ret;
+		goto free_spacc_workq;
+	}
+

drivers/crypto/dwc-spacc/spacc_device.c line 166

Quoted 10 lines
drivers/crypto/dwc-spacc/spacc_device.c new file +10 -0
+	priv->spacc.irq_cb_stat	= spacc_stat_process;
+	priv->spacc.irq_cb_cmdx	= spacc_cmd_process;
+	oldmode			= priv->spacc.op_mode;
+	priv->spacc.op_mode	= SPACC_OP_MODE_IRQ;
+
+	/* Enable STAT and CMD interrupts */
+	spacc_irq_stat_enable(&priv->spacc, 1);
+	spacc_irq_cmdx_enable(&priv->spacc, 0, 1);
+	spacc_irq_stat_wd_disable(&priv->spacc);
+	spacc_irq_glbl_enable(&priv->spacc);

[Severity: Medium]
As reported by Sashiko on v26 [2], in spacc_init_device(), after devm_request_irq() registers spacc_irq_handler() with IRQF_SHARED, can a shared interrupt (or an immediate CMD0 interrupt once SPACC_IRQ_EN_CMD(0) is enabled) race with this unlocked initialization block?

spacc_process_irq() runs under priv->spacc.lock, reads spacc->op_mode and spacc->irq_cb_*, and performs read-modify-write updates on SPACC_REG_IRQ_CTRL and SPACC_REG_IRQ_EN, whereas spacc_init_device() updates irq_cb_stat, irq_cb_cmdx, op_mode, SPACC_REG_IRQ_CTRL, and SPACC_REG_IRQ_EN here without holding priv->spacc.lock (unlike the second IRQ configuration block further down in spacc_init_device()).

[ ... ]

Quoted 31 lines
drivers/crypto/dwc-spacc/spacc_device.c new file +31 -0
+static void spacc_crypto_remove(struct platform_device *pdev)
+{
+	struct spacc_priv *priv = platform_get_drvdata(pdev);
+	unsigned long flags;
+
+	/*
+	 * Set before anything else: sysfs unbind (unlike rmmod) has no
+	 * built-in wait for existing tfms to be freed, so a request can
+	 * reach spacc_hash_digest() at any point during this function.
+	 * This flag, checked under the same lock there, blocks any new
+	 * submission attempt from this point on.
+	 */
+	spin_lock_irqsave(&priv->spacc.lock, flags);
+	priv->removing = true;
+	spin_unlock_irqrestore(&priv->spacc.lock, flags);
+
+	/* Stop the crypto API from handing out any new tfms. */
+	spacc_unregister_algs(priv);
+
+	wait_event(priv->drain_wq, !atomic_read(&priv->dma_ref_cnt));
+
+	if (priv->engine)
+		crypto_engine_exit(priv->engine);
+
+	/* Nothing can dispatch new work past this point. */
+	spin_lock_irqsave(&priv->spacc.lock, flags);
+	spacc_irq_glbl_disable(&priv->spacc);
+	spin_unlock_irqrestore(&priv->spacc.lock, flags);
+
+	devm_free_irq(&pdev->dev, priv->irq, &pdev->dev);
+

drivers/crypto/dwc-spacc/spacc_device.c line 283

Quoted 10 lines
drivers/crypto/dwc-spacc/spacc_device.c new file +10 -0
+	if (priv->spacc_wq)
+		destroy_workqueue(priv->spacc_wq);
+
+	/* No job can still reference this pool past the drain above. */
+	dma_pool_destroy(priv->hash_pool);
+	priv->hash_pool = NULL;
+
+	spacc_remove(pdev);
+	platform_set_drvdata(pdev, NULL);
+}

[Severity: High]
As reported by Sashiko on v26 [2], can spacc_crypto_remove() race with in-flight requests and surviving transforms during sysfs unbind, leading to a use-after-free of priv, priv->engine, spacc->job, and spacc->ctx?

First, in spacc_hash_digest(), priv->removing is checked under priv->spacc.lock, and the lock is dropped before calling crypto_transfer_hash_request_to_engine(priv->engine, req):

	spin_lock_irqsave(&priv->spacc.lock, flags);
	removing = priv->removing;
	spin_unlock_irqrestore(&priv->spacc.lock, flags);

	if (removing)
		return -ENODEV;

	return crypto_transfer_hash_request_to_engine(priv->engine, req);

Meanwhile, priv->dma_ref_cnt is not incremented until the crypto_engine worker runs spacc_hash_do_one_request() and finishes spacc_hash_try_hw(). Because spacc_crypto_remove() waits on drain_wq before calling crypto_engine_exit(priv->engine), any request that has passed the priv->removing check in spacc_hash_digest(), is queued in priv->engine, or is inside spacc_hash_try_hw() has not incremented dma_ref_cnt yet, allowing wait_event(priv->drain_wq, ...) to return prematurely.

Second, on sysfs unbind, existing crypto_ahash transforms remain alive after spacc_crypto_remove() returns. While spacc_hash_init_tfm() calls get_device(salg->dev), that only pins the struct device kobject and does not prevent devres from freeing devm_kzalloc()-allocated priv when spacc_crypto_remove() finishes. In addition, spacc_remove(pdev) frees spacc->ctx and spacc->job before platform_set_drvdata(pdev, NULL) is called, and concurrent calls to spacc_hash_exit_tfm(), spacc_hash_setkey(), or spacc_hash_digest() read dev_get_drvdata(tctx->dev) without synchronization against teardown.

Quoted 5 lines
drivers/crypto/dwc-spacc/spacc_interrupt.c new file +0 -0
new file mode 100644
index 0000000000000..863b8c0b32402

[ ... ]

Quoted 28 lines
drivers/crypto/dwc-spacc/spacc_interrupt.c new file +28 -0
+	/* clear interrupt pin and run registered callback */
+	if (irq_status & SPACC_IRQ_STAT_STAT) {
+		handled |= SPACC_IRQ_STAT_STAT;
+		SPACC_IRQ_STAT_CLEAR_STAT(spacc);
+		if (spacc->op_mode == SPACC_OP_MODE_IRQ &&
+				spacc->wd_cnt_limit) {
+			spacc_irq_cmdx_disable(spacc, 0);
+			spacc_irq_stat_enable(spacc,
+					spacc->config.ideal_stat_level);
+			spacc_irq_stat_wd_enable(spacc);
+			spacc->wdcnt = 0;
+			spacc->op_mode = SPACC_OP_MODE_WD;
+			spacc->wd_cnt_limit = false;
+		} else if (spacc->op_mode == SPACC_OP_MODE_IRQ) {
+			spacc->config.fifo_cnt <<= 2;
+			spacc->config.fifo_cnt = min(spacc->config.fifo_cnt,
+					spacc->config.stat_fifo_depth);
+
+			/* update fifo count to allow more stats to pile up */
+			spacc_irq_stat_enable(spacc, spacc->config.fifo_cnt);
+
+
+			/* re-enable CMD0 empty interrupt */
+			spacc_irq_cmdx_enable(spacc, 0, 0);
+		}
+		if (spacc->irq_cb_stat)
+			spacc->irq_cb_stat(spacc);
+	}

[ ... ]

Quoted 11 lines
drivers/crypto/dwc-spacc/spacc_interrupt.c new file +11 -0
+	if (spacc->op_mode == SPACC_OP_MODE_IRQ) {
+		cmd_max = (spacc->config.is_qos ? SPACC_CMDX_MAX_QOS :
+				SPACC_CMDX_MAX);
+		for (x = 0; x < cmd_max; x++) {
+			if (irq_status & SPACC_IRQ_STAT_CMDX(x)) {
+				handled |= SPACC_IRQ_STAT_CMDX(x);
+				spacc->config.fifo_cnt = 1;
+
+				/* disable CMD0 interrupt since STAT=1 */
+				spacc_irq_cmdx_disable(spacc, x);
+				spacc_irq_stat_enable(spacc,

drivers/crypto/dwc-spacc/spacc_interrupt.c line 262

Quoted 10 lines
drivers/crypto/dwc-spacc/spacc_interrupt.c new file +10 -0
+						spacc->config.fifo_cnt);
+
+				SPACC_IRQ_STAT_CLEAR_CMDX(spacc, x);
+
+				/* run registered callback */
+				if (spacc->irq_cb_cmdx)
+					spacc->irq_cb_cmdx(spacc, x);
+			}
+		}
+	}

[Severity: High]
Won't spacc_process_irq() livelock in hardirq context when operating in SPACC_OP_MODE_IRQ?

In spacc_device.c, spacc_stat_process() and spacc_cmd_process() defer popping the STATUS FIFO to priv->pop_jobs on the priv->spacc_wq workqueue rather than draining the FIFO in the interrupt handler.

When a job completes in SPACC_OP_MODE_IRQ (STATUS FIFO count is 1, CMD0 FIFO is empty), the SPACC_IRQ_STAT_STAT branch raises spacc->config.fifo_cnt, calls spacc_irq_stat_enable(spacc, spacc->config.fifo_cnt), and enables the CMD0 empty interrupt via spacc_irq_cmdx_enable(spacc, 0, 0).

Because CMD0 is currently empty, enabling CMD0 IRQ with threshold 0 immediately asserts SPACC_IRQ_STAT_CMDX(0) before the workqueue can run. The next hardirq enters the SPACC_IRQ_STAT_CMDX(0) branch, disables CMD0 IRQ, and lowers the STAT threshold back to 1 via spacc_irq_stat_enable(spacc, 1). Because the completed job is still unpopped in the STATUS FIFO, lowering the STAT threshold to 1 immediately re-asserts SPACC_IRQ_STAT_STAT, which re-enables CMD0 IRQ and traps the CPU in an infinite interrupt loop.

[1] https://lore.kernel.org/r/[email protected]
[2] https://lore.kernel.org/r/[email protected]

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=2
#4 lore raw

PATCH v27 3/4 crypto: spacc - add spacc autodetect support

In reply to Pavitrakumar Managutte

SPAcc is configurable and it supports the below modes:
1. AUTODETECT configuration - Autodetects the supported algos.
2. Static configuration - The algo support is defined statically.

---
 drivers/crypto/dwc-spacc/spacc_core.c | 1192 +++++++++++++++++++++++++
 1 file changed, 1192 insertions(+)
drivers/crypto/dwc-spacc/spacc_core.c +1192 -0
index d26b5e30777e9..66505566ed3cc 100644
@@ -201,6 +201,922 @@ static const unsigned char template[] = {
 	[CRYPTO_MODE_MAC_SM4_CMAC]      = 130,
 };
 
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_AUTODETECT)
+static const struct {
+	unsigned int min_version;
+	struct {
+		int outlen;
+		unsigned char data[64];
+	} test[7];
+} testdata[CRYPTO_MODE_LAST] = {
+	[CRYPTO_MODE_NULL] = {
+		.min_version = 0x65,
+		.test[0].outlen = 0
+	},
+
+	[CRYPTO_MODE_AES_ECB] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0xc6, 0xa1, 0x3b, 0x37,
+			0x87, 0x8f, 0x5b, 0x82, 0x6f, 0x4f, 0x81, 0x62, 0xa1,
+			0xc8, 0xd8, 0x79,  },
+		.test[3].outlen = 16, .test[3].data = { 0x91, 0x62, 0x51, 0x82,
+			0x1c, 0x73, 0xa5, 0x22, 0xc3, 0x96, 0xd6, 0x27, 0x38,
+			0x01, 0x96, 0x07,  },
+		.test[4].outlen = 16, .test[4].data = { 0xf2, 0x90, 0x00, 0xb6,
+			0x2a, 0x49, 0x9f, 0xd0, 0xa9, 0xf3, 0x9a, 0x6a, 0xdd,
+			0x2e, 0x77, 0x80,  },
+	},
+
+	[CRYPTO_MODE_AES_CBC] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x0a, 0x94, 0x0b, 0xb5,
+			0x41, 0x6e, 0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6,
+			0x53, 0xea, 0x5a,  },
+		.test[3].outlen = 16, .test[3].data = { 0x00, 0x60, 0xbf, 0xfe,
+			0x46, 0x83, 0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f,
+			0xf2, 0x20, 0xae,  },
+		.test[4].outlen = 16, .test[4].data = { 0x5a, 0x6e, 0x04, 0x57,
+			0x08, 0xfb, 0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02,
+			0xc3, 0xa6, 0x92,  },
+	},
+
+	[CRYPTO_MODE_AES_CTR] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x0a, 0x94, 0x0b, 0xb5,
+			0x41, 0x6e, 0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6,
+			0x53, 0xea, 0x5a,  },
+		.test[3].outlen = 16, .test[3].data = { 0x00, 0x60, 0xbf, 0xfe,
+			0x46, 0x83, 0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f,
+			0xf2, 0x20, 0xae,  },
+		.test[4].outlen = 16, .test[4].data = { 0x5a, 0x6e, 0x04, 0x57,
+			0x08, 0xfb, 0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02,
+			0xc3, 0xa6, 0x92,  },
+	},
+
+	[CRYPTO_MODE_AES_CCM] = {
+		.min_version = 0x65,
+		.test[2].outlen = 32, .test[2].data = { 0x02, 0x63, 0xec, 0x94,
+			0x66, 0x18, 0x72, 0x96, 0x9a, 0xda, 0xfd, 0x0f, 0x4b,
+			0xa4, 0x0f, 0xdc, 0xa5, 0x09, 0x92, 0x93, 0xb6, 0xb4,
+			0x38, 0x34, 0x63, 0x72, 0x50, 0x4c, 0xfc, 0x8a, 0x63,
+			0x02,  },
+		.test[3].outlen = 32, .test[3].data = { 0x29, 0xf7, 0x63, 0xe8,
+			0xa1, 0x75, 0xc6, 0xbf, 0xa5, 0x54, 0x94, 0x89, 0x12,
+			0x84, 0x45, 0xf5, 0x9b, 0x27, 0xeb, 0xb1, 0xa4, 0x65,
+			0x93, 0x6e, 0x5a, 0xc0, 0xa2, 0xa3, 0xe2, 0x6c, 0x46,
+			0x29,  },
+		.test[4].outlen = 32, .test[4].data = { 0x60, 0xf3, 0x10, 0xd5,
+			0xc3, 0x85, 0x58, 0x5d, 0x55, 0x16, 0xfb, 0x51, 0x72,
+			0xe5, 0x20, 0xcf, 0x8e, 0x87, 0x6d, 0x72, 0xc8, 0x44,
+			0xbe, 0x6d, 0xa2, 0xd6, 0xf4, 0xba, 0xec, 0xb4, 0xec,
+			0x39,  },
+	},
+
+	[CRYPTO_MODE_AES_GCM] = {
+		.min_version = 0x65,
+		.test[2].outlen = 32, .test[2].data = { 0x93, 0x6c, 0xa7, 0xce,
+			0x66, 0x1b, 0xf7, 0x54, 0x4b, 0xd2, 0x61, 0x8a, 0x36,
+			0xa3, 0x70, 0x08, 0xc0, 0xd7, 0xd0, 0x77, 0xc5, 0x64,
+			0x76, 0xdb, 0x48, 0x4a, 0x53, 0xe3, 0x6c, 0x93, 0x34,
+			0x0f,  },
+		.test[3].outlen = 32, .test[3].data = { 0xe6, 0xf9, 0x22, 0x9b,
+			0x99, 0xb9, 0xc9, 0x0e, 0xd0, 0x33, 0xdc, 0x82, 0xff,
+			0xa9, 0xdc, 0x70, 0x4c, 0xcd, 0xc4, 0x1b, 0xa3, 0x5a,
+			0x87, 0x5d, 0xd8, 0xef, 0xb6, 0x48, 0xbb, 0x0c, 0x92,
+			0x60,  },
+		.test[4].outlen = 32, .test[4].data = { 0x47, 0x02, 0xd6, 0x1b,
+			0xc5, 0xe5, 0xc2, 0x1b, 0x8d, 0x41, 0x97, 0x8b, 0xb1,
+			0xe9, 0x78, 0x6d, 0x48, 0x6f, 0x78, 0x81, 0xc7, 0x98,
+			0xcc, 0xf5, 0x28, 0xf1, 0x01, 0x7c, 0xe8, 0xf6, 0x09,
+			0x78,  },
+	},
+
+	[CRYPTO_MODE_AES_F8] = {
+		.min_version = 0x65,
+		.test[0].outlen = 0
+	},
+
+	[CRYPTO_MODE_AES_XTS] = {
+		.min_version = 0x65,
+		.test[2].outlen = 32, .test[2].data = { 0xa0, 0x1a, 0x6f, 0x09,
+			0xfa, 0xef, 0xd2, 0x72, 0xc3, 0x9b, 0xad, 0x35, 0x52,
+			0xfc, 0xa1, 0xcb, 0x33, 0x69, 0x51, 0xc5, 0x23, 0xbe,
+			0xac, 0xa5, 0x4a, 0xf2, 0xfc, 0x77, 0x71, 0x6f, 0x9a,
+			0x86,  },
+		.test[4].outlen = 32, .test[4].data = { 0x05, 0x45, 0x91, 0x86,
+			0xf2, 0x2d, 0x97, 0x93, 0xf3, 0xa0, 0xbb, 0x29, 0xc7,
+			0x9c, 0xc1, 0x4c, 0x3b, 0x8f, 0xdd, 0x9d, 0xda, 0xc7,
+			0xb5, 0xaa, 0xc2, 0x7c, 0x2e, 0x71, 0xce, 0x7f, 0xce,
+			0x0e,  },
+	},
+
+	[CRYPTO_MODE_AES_CFB] = {
+		.min_version = 0x65,
+		.test[0].outlen = 0
+	},
+
+	[CRYPTO_MODE_AES_OFB] = {
+		.min_version = 0x65,
+		.test[0].outlen = 0
+	},
+
+	[CRYPTO_MODE_AES_CS1] = {
+		.min_version = 0x65,
+		.test[2].outlen = 31, .test[2].data = { 0x0a, 0x94, 0x0b, 0xb5,
+			0x41, 0x6e, 0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6,
+			0x53, 0xea, 0xae, 0xe7, 0x1e, 0xa5, 0x41, 0xd7, 0xae,
+			0x4b, 0xeb, 0x60, 0xbe, 0xcc, 0x59, 0x3f, 0xb6, 0x63,
+		},
+		.test[3].outlen = 31, .test[3].data = { 0x00, 0x60, 0xbf, 0xfe,
+			0x46, 0x83, 0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f,
+			0xf2, 0x20, 0x2e, 0x84, 0xcb, 0x12, 0xa3, 0x59, 0x17,
+			0xb0, 0x9e, 0x25, 0xa2, 0xa2, 0x3d, 0xf1, 0x9f, 0xdc,
+		},
+		.test[4].outlen = 31, .test[4].data = { 0x5a, 0x6e, 0x04, 0x57,
+			0x08, 0xfb, 0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02,
+			0xc3, 0xa6, 0xcd, 0xfc, 0x25, 0x35, 0x31, 0x0b, 0xf5,
+			0x6b, 0x2e, 0xb7, 0x8a, 0xa2, 0x5a, 0xdd, 0x77, 0x51,
+		},
+	},
+
+	[CRYPTO_MODE_AES_CS2] = {
+		.min_version = 0x65,
+		.test[2].outlen = 31, .test[2].data = { 0xae, 0xe7, 0x1e, 0xa5,
+			0x41, 0xd7, 0xae, 0x4b, 0xeb, 0x60, 0xbe, 0xcc, 0x59,
+			0x3f, 0xb6, 0x63, 0x0a, 0x94, 0x0b, 0xb5, 0x41, 0x6e,
+			0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6, 0x53, 0xea,
+		},
+		.test[3].outlen = 31, .test[3].data = { 0x2e, 0x84, 0xcb, 0x12,
+			0xa3, 0x59, 0x17, 0xb0, 0x9e, 0x25, 0xa2, 0xa2, 0x3d,
+			0xf1, 0x9f, 0xdc, 0x00, 0x60, 0xbf, 0xfe, 0x46, 0x83,
+			0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f, 0xf2, 0x20,
+		},
+		.test[4].outlen = 31, .test[4].data = { 0xcd, 0xfc, 0x25, 0x35,
+			0x31, 0x0b, 0xf5, 0x6b, 0x2e, 0xb7, 0x8a, 0xa2, 0x5a,
+			0xdd, 0x77, 0x51, 0x5a, 0x6e, 0x04, 0x57, 0x08, 0xfb,
+			0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02, 0xc3, 0xa6,
+		},
+	},
+
+	[CRYPTO_MODE_AES_CS3] = {
+		.min_version = 0x65,
+		.test[2].outlen = 31, .test[2].data = { 0xae, 0xe7, 0x1e, 0xa5,
+			0x41, 0xd7, 0xae, 0x4b, 0xeb, 0x60, 0xbe, 0xcc, 0x59,
+			0x3f, 0xb6, 0x63, 0x0a, 0x94, 0x0b, 0xb5, 0x41, 0x6e,
+			0xf0, 0x45, 0xf1, 0xc3, 0x94, 0x58, 0xc6, 0x53, 0xea,
+		},
+		.test[3].outlen = 31, .test[3].data = { 0x2e, 0x84, 0xcb, 0x12,
+			0xa3, 0x59, 0x17, 0xb0, 0x9e, 0x25, 0xa2, 0xa2, 0x3d,
+			0xf1, 0x9f, 0xdc, 0x00, 0x60, 0xbf, 0xfe, 0x46, 0x83,
+			0x4b, 0xb8, 0xda, 0x5c, 0xf9, 0xa6, 0x1f, 0xf2, 0x20,
+		},
+		.test[4].outlen = 31, .test[4].data = { 0xcd, 0xfc, 0x25, 0x35,
+			0x31, 0x0b, 0xf5, 0x6b, 0x2e, 0xb7, 0x8a, 0xa2, 0x5a,
+			0xdd, 0x77, 0x51, 0x5a, 0x6e, 0x04, 0x57, 0x08, 0xfb,
+			0x71, 0x96, 0xf0, 0x2e, 0x55, 0x3d, 0x02, 0xc3, 0xa6,
+		},
+	},
+
+	[CRYPTO_MODE_MULTI2_ECB] = {
+		.min_version = 0x65,
+		.test[0].outlen = 0
+	},
+
+	[CRYPTO_MODE_MULTI2_CBC] = {
+		.min_version = 0x65,
+		.test[0].outlen = 0
+	},
+
+	[CRYPTO_MODE_MULTI2_OFB] = {
+		.min_version = 0x65,
+		.test[0].outlen = 0
+	},
+
+	[CRYPTO_MODE_MULTI2_CFB] = {
+		.min_version = 0x65,
+		.test[0].outlen = 0
+	},
+
+	[CRYPTO_MODE_3DES_CBC] = {
+		.min_version = 0x65,
+		.test[3].outlen = 16, .test[3].data = { 0x58, 0xed, 0x24, 0x8f,
+			0x77, 0xf6, 0xb1, 0x9e, 0x47, 0xd9, 0xb7, 0x4a, 0x4f,
+			0x5a, 0xe6, 0x6d,  }
+	},
+
+	[CRYPTO_MODE_3DES_ECB] = {
+		.min_version = 0x65,
+		.test[3].outlen = 16, .test[3].data = { 0x89, 0x4b, 0xc3, 0x08,
+			0x54, 0x26, 0xa4, 0x41, 0x89, 0x4b, 0xc3, 0x08, 0x54,
+			0x26, 0xa4, 0x41,  }
+	},
+
+	[CRYPTO_MODE_DES_CBC] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0xe1, 0xb2, 0x46, 0xe5,
+			0xa7, 0xc7, 0x4c, 0xbc, 0xd5, 0xf0, 0x8e, 0x25, 0x3b,
+			0xfa, 0x23, 0x80,  }
+	},
+
+	[CRYPTO_MODE_DES_ECB] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0xa5, 0x17, 0x3a,
+			0xd5, 0x95, 0x7b, 0x43, 0x70, 0xa5, 0x17, 0x3a, 0xd5,
+			0x95, 0x7b, 0x43, 0x70,  }
+	},
+
+	[CRYPTO_MODE_KASUMI_ECB] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x04, 0x7d, 0x5d,
+			0x2c, 0x8c, 0x2e, 0x91, 0xb3, 0x04, 0x7d, 0x5d, 0x2c,
+			0x8c, 0x2e, 0x91, 0xb3,  }
+	},
+
+	[CRYPTO_MODE_KASUMI_F8] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0xfc, 0xf7, 0x45,
+			0xee, 0x1d, 0xbb, 0xa4, 0x57, 0xa7, 0x45, 0xdc, 0x6b,
+			0x2a, 0x1b, 0x50, 0x88,  }
+	},
+
+	[CRYPTO_MODE_SNOW3G_UEA2] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x95, 0xd3, 0xc8,
+			0x13, 0xc0, 0x20, 0x24, 0xa3, 0x76, 0x24, 0xd1, 0x98,
+			0xb6, 0x67, 0x4d, 0x4c,  }
+	},
+
+	[CRYPTO_MODE_ZUC_UEA3] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0xda, 0xdf, 0xb6,
+			0xa2, 0xac, 0x9d, 0xba, 0xfe, 0x18, 0x9c, 0x0c, 0x75,
+			0x79, 0xc6, 0xe0, 0x4e,  }
+	},
+
+	[CRYPTO_MODE_CHACHA20_STREAM] = {
+		.min_version = 0x65,
+		.test[4].outlen = 16, .test[4].data = { 0x55, 0xdf, 0x91,
+			0xe9, 0x27, 0x01, 0x37, 0x69, 0xdb, 0x38, 0xd4, 0x28,
+			0x01, 0x79, 0x76, 0x64 }
+	},
+
+	[CRYPTO_MODE_CHACHA20_POLY1305] = {
+		.min_version = 0x65,
+		.test[4].outlen = 16, .test[4].data = { 0x89, 0xfb, 0x08,
+			0x00, 0x29, 0x17, 0xa5, 0x40, 0xb7, 0x83, 0x3f, 0xf3,
+			0x98, 0x1d, 0x0e, 0x63 }
+	},
+
+	[CRYPTO_MODE_SM4_ECB] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x1e, 0x96, 0x34,
+			0xb7, 0x70, 0xf9, 0xae, 0xba, 0xa9, 0x34, 0x4f, 0x5a,
+			0xff, 0x9f, 0x82, 0xa3 }
+	},
+
+	[CRYPTO_MODE_SM4_CBC] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76,
+			0x3e, 0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42,
+			0x8f, 0xd0, 0x52, 0x8d }
+	},
+
+	[CRYPTO_MODE_SM4_CFB] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76,
+			0x3e, 0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42,
+			0x8f, 0xd0, 0x52, 0x8d }
+	},
+
+	[CRYPTO_MODE_SM4_OFB] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76, 0x3e,
+			0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42, 0x8f,
+			0xd0, 0x52, 0x8d }
+	},
+
+	[CRYPTO_MODE_SM4_CTR] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76, 0x3e,
+			0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42, 0x8f,
+			0xd0, 0x52, 0x8d }
+	},
+
+	[CRYPTO_MODE_SM4_CCM] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x8e, 0x25, 0x5a,
+			0x13, 0xc7, 0x43, 0x4d, 0x95, 0xef, 0x14, 0x15, 0x11,
+			0xd0, 0xb9, 0x60, 0x5b }
+	},
+
+	[CRYPTO_MODE_SM4_GCM] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x97, 0x46, 0xde,
+			0xfb, 0xc9, 0x6a, 0x85, 0x00, 0xff, 0x9c, 0x74, 0x4d,
+			0xd1, 0xbb, 0xf9, 0x66 }
+	},
+
+	[CRYPTO_MODE_SM4_F8] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x77, 0x30, 0xff,
+			0x70, 0x46, 0xbc, 0xf4, 0xe3, 0x11, 0xf6, 0x27, 0xe2,
+			0xff, 0xd7, 0xc4, 0x2e }
+	},
+
+	[CRYPTO_MODE_SM4_XTS] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x05, 0x3f, 0xb6,
+			0xe9, 0xb1, 0xff, 0x09, 0x4f, 0x9d, 0x69, 0x4d, 0xc2,
+			0xb6, 0xa1, 0x15, 0xde }
+	},
+
+	[CRYPTO_MODE_SM4_CS1] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0x8f, 0x78, 0x76,
+			0x3e, 0xe0, 0x60, 0x13, 0xe0, 0xb7, 0x62, 0x2c, 0x42,
+			0x8f, 0xd0, 0x52, 0xa0 }
+	},
+
+	[CRYPTO_MODE_SM4_CS2] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0xa0, 0x1c, 0xfe,
+			0x91, 0xaa, 0x7e, 0xf1, 0x75, 0x6a, 0xe8, 0xbc, 0xe1,
+			0x55, 0x08, 0xda, 0x71 }
+	},
+
+	[CRYPTO_MODE_SM4_CS3] = {
+		.min_version = 0x65,
+		.test[2].outlen = 16, .test[2].data = { 0xa0, 0x1c, 0xfe,
+			0x91, 0xaa, 0x7e, 0xf1, 0x75, 0x6a, 0xe8, 0xbc, 0xe1,
+			0x55, 0x08, 0xda, 0x71 }
+	},
+
+	/*
+	 * Hashes ... note they use the 2nd keysize
+	 * array so the indices mean different sizes!!!
+	 */
+
+	[CRYPTO_MODE_HASH_MD5] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0x70, 0xbc, 0x8f, 0x4b,
+			0x72, 0xa8, 0x69, 0x21, 0x46, 0x8b, 0xf8, 0xe8, 0x44,
+			0x1d, 0xce, 0x51,  }
+	},
+
+	[CRYPTO_MODE_HMAC_MD5] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0xb6, 0x39, 0xc8, 0x73,
+			0x16, 0x38, 0x61, 0x8b, 0x70, 0x79, 0x72, 0xaa, 0x6e,
+			0x96, 0xcf, 0x90,  },
+		.test[4].outlen = 16, .test[4].data = { 0xb7, 0x79, 0x68, 0xea,
+			0x17, 0x32, 0x1e, 0x32, 0x13, 0x90, 0x6c, 0x2e, 0x9f,
+			0xd5, 0xc8, 0xb3,  },
+		.test[5].outlen = 16, .test[5].data = { 0x80, 0x3e, 0x0a, 0x2f,
+			0x8a, 0xd8, 0x31, 0x8f, 0x8e, 0x12, 0x28, 0x86, 0x22,
+			0x59, 0x6b, 0x05,  },
+		.test[6].outlen = 16, .test[6].data = { 0x48, 0x8d, 0xca, 0xb3,
+			0x65, 0xf0, 0x64, 0x5f, 0xca, 0x8e, 0x22, 0xf5, 0x05,
+			0xd7, 0xa0, 0x1c,  },
+	},
+
+	[CRYPTO_MODE_HASH_SHA1] = {
+		.min_version = 0x65,
+		.test[1].outlen = 20, .test[1].data = { 0xde, 0x8a, 0x84, 0x7b,
+			0xff, 0x8c, 0x34, 0x3d, 0x69, 0xb8, 0x53, 0xa2, 0x15,
+			0xe6, 0xee, 0x77, 0x5e, 0xf2, 0xef, 0x96,  }
+	},
+
+	[CRYPTO_MODE_HMAC_SHA1] = {
+		.min_version = 0x65,
+		.test[1].outlen = 20, .test[1].data = { 0xf8, 0x54, 0x60, 0x50,
+			0x49, 0x56, 0xd1, 0xcd, 0x55, 0x5c, 0x5d, 0xcd, 0x24,
+			0x33, 0xbf, 0xdc, 0x5c, 0x99, 0x54, 0xc8,  },
+		.test[4].outlen = 20, .test[4].data = { 0x66, 0x3f, 0x3a, 0x3c,
+			0x08, 0xb6, 0x87, 0xb2, 0xd3, 0x0c, 0x5a, 0xa7, 0xcc,
+			0x5c, 0xc3, 0x99, 0xb2, 0xb4, 0x58, 0x55,  },
+		.test[5].outlen = 20, .test[5].data = { 0x9a, 0x28, 0x54, 0x2f,
+			0xaf, 0xa7, 0x0b, 0x37, 0xbe, 0x2d, 0x3e, 0xd9, 0xd4,
+			0x70, 0xbc, 0xdc, 0x0b, 0x54, 0x20, 0x06,  },
+		.test[6].outlen = 20, .test[6].data = { 0x1d, 0x8e, 0x20, 0xcd,
+			0x5e, 0x6b, 0x4e, 0x32, 0x64, 0x8e, 0x99, 0xfb, 0xa3,
+			0x7e, 0x74, 0xb4, 0x9c, 0x0c, 0x00, 0x9d,  },
+	},
+
+	[CRYPTO_MODE_HASH_SHA224] = {
+		.min_version = 0x65,
+		.test[1].outlen = 28, .test[1].data = { 0xb3, 0x38, 0xc7, 0x6b,
+			0xcf, 0xfa, 0x1a, 0x0b, 0x3e, 0xad, 0x8d, 0xe5, 0x8d,
+			0xfb, 0xff, 0x47, 0xb6, 0x3a, 0xb1, 0x15, 0x0e, 0x10,
+			0xd8, 0xf1, 0x7f, 0x2b, 0xaf, 0xdf,  }
+	},
+
+	[CRYPTO_MODE_HMAC_SHA224] = {
+		.min_version = 0x65,
+		.test[1].outlen = 28, .test[1].data = { 0xf3, 0xb4, 0x33, 0x78,
+			0x53, 0x4c, 0x0c, 0x4a, 0x1e, 0x31, 0xc2, 0xce, 0xda,
+			0xc8, 0xfe, 0x74, 0x4a, 0xd2, 0x9b, 0x7c, 0x1d, 0x2f,
+			0x5e, 0xa1, 0xaa, 0x31, 0xb9, 0xf5,  },
+		.test[4].outlen = 28, .test[4].data = { 0x4b, 0x6b, 0x3f, 0x9a,
+			0x66, 0x47, 0x45, 0xe2, 0x60, 0xc9, 0x53, 0x86, 0x7a,
+			0x34, 0x65, 0x7d, 0xe2, 0x24, 0x06, 0xcc, 0xf9, 0x17,
+			0x20, 0x5d, 0xc2, 0xb6, 0x97, 0x9a,  },
+		.test[5].outlen = 28, .test[5].data = { 0x90, 0xb0, 0x6e, 0xee,
+			0x21, 0x57, 0x38, 0xc7, 0x65, 0xbb, 0x9a, 0xf5, 0xb4,
+			0x31, 0x0a, 0x0e, 0xe5, 0x64, 0xc4, 0x49, 0x9d, 0xbd,
+			0xe9, 0xf7, 0xac, 0x9f, 0xf8, 0x05,  },
+		.test[6].outlen = 28, .test[6].data = { 0x5a, 0x1f, 0x21, 0xaf,
+			0xd5, 0x8a, 0x54, 0x5e, 0x74, 0xd7, 0x21, 0x76, 0x25,
+			0x06, 0x70, 0x81, 0x3e, 0x51, 0xef, 0x38, 0xdc, 0x78,
+			0x97, 0x54, 0xe6, 0xb3, 0xa4, 0x3e,  },
+	},
+
+	[CRYPTO_MODE_HASH_SHA256] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0x66, 0x68, 0x7a, 0xad,
+			0xf8, 0x62, 0xbd, 0x77, 0x6c, 0x8f, 0xc1, 0x8b, 0x8e,
+			0x9f, 0x8e, 0x20, 0x08, 0x97, 0x14, 0x85, 0x6e, 0xe2,
+			0x33, 0xb3, 0x90, 0x2a, 0x59, 0x1d, 0x0d, 0x5f, 0x29,
+			0x25,  }
+	},
+
+	[CRYPTO_MODE_HMAC_SHA256] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0x75, 0x40, 0x84, 0x49,
+			0x54, 0x0a, 0xf9, 0x80, 0x99, 0xeb, 0x93, 0x6b, 0xf6,
+			0xd3, 0xff, 0x41, 0x05, 0x47, 0xcc, 0x82, 0x62, 0x76,
+			0x32, 0xf3, 0x43, 0x74, 0x70, 0x54, 0xe2, 0x3b, 0xc0,
+			0x90,  },
+		.test[4].outlen = 32, .test[4].data = { 0x41, 0x6c, 0x53, 0x92,
+			0xb9, 0xf3, 0x6d, 0xf1, 0x88, 0xe9, 0x0e, 0xb1, 0x4d,
+			0x17, 0xbf, 0x0d, 0xa1, 0x90, 0xbf, 0xdb, 0x7f, 0x1f,
+			0x49, 0x56, 0xe6, 0xe5, 0x66, 0xa5, 0x69, 0xc8, 0xb1,
+			0x5c,  },
+		.test[5].outlen = 32, .test[5].data = { 0x49, 0x1f, 0x58, 0x3b,
+			0x05, 0xe2, 0x3a, 0x72, 0x1d, 0x11, 0x6d, 0xc1, 0x08,
+			0xa0, 0x3f, 0x30, 0x37, 0x98, 0x36, 0x8a, 0x49, 0x4c,
+			0x21, 0x1d, 0x56, 0xa5, 0x2a, 0xf3, 0x68, 0x28, 0xb7,
+			0x69,  },
+		.test[6].outlen = 32, .test[6].data = { 0x76, 0xf8, 0x88, 0xed,
+			0x39, 0xed, 0xf8, 0xe0, 0x31, 0x68, 0x3a, 0x33, 0xcf,
+			0xaf, 0x20, 0x62, 0x96, 0xdc, 0x06, 0xf9, 0xa9, 0xb1,
+			0xfe, 0x88, 0x25, 0xef, 0x96, 0x69, 0xa0, 0x66, 0x1e,
+			0x53,  },
+	},
+
+	[CRYPTO_MODE_HASH_SHA384] = {
+		.min_version = 0x65,
+		.test[1].outlen = 48, .test[1].data = { 0xa3, 0x8f, 0xff, 0x4b,
+			0xa2, 0x6c, 0x15, 0xe4, 0xac, 0x9c, 0xde, 0x8c, 0x03,
+			0x10, 0x3a, 0xc8, 0x90, 0x80, 0xfd, 0x47, 0x54, 0x5f,
+			0xde, 0x94, 0x46, 0xc8, 0xf1, 0x92, 0x72, 0x9e, 0xab,
+			0x7b, 0xd0, 0x3a, 0x4d, 0x5c, 0x31, 0x87, 0xf7, 0x5f,
+			0xe2, 0xa7, 0x1b, 0x0e, 0xe5, 0x0a, 0x4a, 0x40,  }
+	},
+
+	[CRYPTO_MODE_HMAC_SHA384] = {
+		.min_version = 0x65,
+		.test[1].outlen = 48, .test[1].data = { 0x6c, 0xd8, 0x89, 0xa0,
+			0xca, 0x54, 0xa6, 0x1d, 0x24, 0xc4, 0x1d, 0xa1, 0x77,
+			0x50, 0xd6, 0xf2, 0xf3, 0x43, 0x23, 0x0d, 0xb1, 0xf5,
+			0xf7, 0xfc, 0xc0, 0x8c, 0xf6, 0xdf, 0x3c, 0x61, 0xfc,
+			0x8a, 0xb9, 0xda, 0x12, 0x75, 0x97, 0xac, 0x51, 0x88,
+			0x59, 0x19, 0x44, 0x13, 0xc0, 0x78, 0xa5, 0xa8,  },
+		.test[4].outlen = 48, .test[4].data = { 0x0c, 0x91, 0x36, 0x46,
+			0xd9, 0x17, 0x81, 0x46, 0x1d, 0x42, 0xb1, 0x00, 0xaa,
+			0xfa, 0x26, 0x92, 0x9f, 0x05, 0xc0, 0x91, 0x8e, 0x20,
+			0xd7, 0x75, 0x9d, 0xd2, 0xc8, 0x9b, 0x02, 0x18, 0x20,
+			0x1f, 0xdd, 0xa3, 0x32, 0xe3, 0x1e, 0xa4, 0x2b, 0xc3,
+			0xc8, 0xb9, 0xb1, 0x53, 0x4e, 0x6a, 0x49, 0xd2,  },
+		.test[5].outlen = 48, .test[5].data = { 0x84, 0x78, 0xd2, 0xf1,
+			0x44, 0x95, 0x6a, 0x22, 0x2d, 0x08, 0x19, 0xe8, 0xea,
+			0x61, 0xb4, 0x86, 0xe8, 0xc6, 0xb0, 0x40, 0x51, 0x28,
+			0x22, 0x54, 0x48, 0xc0, 0x70, 0x09, 0x81, 0xf9, 0xf5,
+			0x47, 0x9e, 0xb3, 0x2c, 0x69, 0x19, 0xd5, 0x8d, 0x03,
+			0x5d, 0x24, 0xca, 0x90, 0xa6, 0x9d, 0x80, 0x2a,  },
+		.test[6].outlen = 48, .test[6].data = { 0x0e, 0x68, 0x17, 0x31,
+			0x01, 0xa8, 0x28, 0x0a, 0x4e, 0x47, 0x22, 0xa6, 0x89,
+			0xf0, 0xc6, 0xcd, 0x4e, 0x8c, 0x19, 0x4c, 0x44, 0x3d,
+			0xb5, 0xa5, 0xf9, 0xfe, 0xea, 0xc7, 0x84, 0x0b, 0x57,
+			0x0d, 0xd4, 0xe4, 0x8a, 0x3f, 0x68, 0x31, 0x20, 0xd9,
+			0x1f, 0xc4, 0xa3, 0x76, 0xcf, 0xdd, 0x07, 0xa6,  },
+	},
+
+	[CRYPTO_MODE_HASH_SHA512] = {
+		.min_version = 0x65,
+		.test[1].outlen = 64, .test[1].data = { 0x50, 0x46, 0xad, 0xc1,
+			0xdb, 0xa8, 0x38, 0x86, 0x7b, 0x2b, 0xbb, 0xfd, 0xd0,
+			0xc3, 0x42, 0x3e, 0x58, 0xb5, 0x79, 0x70, 0xb5, 0x26,
+			0x7a, 0x90, 0xf5, 0x79, 0x60, 0x92, 0x4a, 0x87, 0xf1,
+			0x96, 0x0a, 0x6a, 0x85, 0xea, 0xa6, 0x42, 0xda, 0xc8,
+			0x35, 0x42, 0x4b, 0x5d, 0x7c, 0x8d, 0x63, 0x7c, 0x00,
+			0x40, 0x8c, 0x7a, 0x73, 0xda, 0x67, 0x2b, 0x7f, 0x49,
+			0x85, 0x21, 0x42, 0x0b, 0x6d, 0xd3,  }
+	},
+
+	[CRYPTO_MODE_HMAC_SHA512] = {
+		.min_version = 0x65,
+		.test[1].outlen = 64, .test[1].data = { 0xec, 0xfd, 0x83, 0x74,
+			0xc8, 0xa9, 0x2f, 0xd7, 0x71, 0x94, 0xd1, 0x1e, 0xe7,
+			0x0f, 0x0f, 0x5e, 0x11, 0x29, 0x58, 0xb8, 0x36, 0xc6,
+			0x39, 0xbc, 0xd6, 0x88, 0x6e, 0xdb, 0xc8, 0x06, 0x09,
+			0x30, 0x27, 0xaa, 0x69, 0xb9, 0x2a, 0xd4, 0x67, 0x06,
+			0x5c, 0x82, 0x8e, 0x90, 0xe9, 0x3e, 0x55, 0x88, 0x7d,
+			0xb2, 0x2b, 0x48, 0xa2, 0x28, 0x92, 0x6c, 0x0f, 0xf1,
+			0x57, 0xb5, 0xd0, 0x06, 0x1d, 0xf3,  },
+		.test[4].outlen = 64, .test[4].data = { 0x47, 0x88, 0x91, 0xe9,
+			0x12, 0x3e, 0xfd, 0xdc, 0x26, 0x29, 0x08, 0xd6, 0x30,
+			0x8f, 0xcc, 0xb6, 0x93, 0x30, 0x58, 0x69, 0x4e, 0x81,
+			0xee, 0x9d, 0xb6, 0x0f, 0xc5, 0x54, 0xe6, 0x7c, 0x84,
+			0xc5, 0xbc, 0x89, 0x99, 0xf0, 0xf3, 0x7f, 0x6f, 0x3f,
+			0xf5, 0x04, 0x2c, 0xdf, 0x76, 0x72, 0x6a, 0xbe, 0x28,
+			0x3b, 0xb8, 0x05, 0xb3, 0x47, 0x45, 0xf5, 0x7f, 0xb1,
+			0x21, 0x2d, 0xe0, 0x8d, 0x1e, 0x29,  },
+		.test[5].outlen = 64, .test[5].data = { 0x7e, 0x55, 0xda, 0x88,
+			0x28, 0xc1, 0x6e, 0x9a, 0x6a, 0x99, 0xa0, 0x37, 0x68,
+			0xf0, 0x28, 0x5e, 0xe2, 0xbe, 0x00, 0xac, 0x76, 0x89,
+			0x76, 0xcc, 0x5d, 0x98, 0x1b, 0x32, 0x1a, 0x14, 0xc4,
+			0x2e, 0x9c, 0xe4, 0xf3, 0x3f, 0x5f, 0xa0, 0xae, 0x95,
+			0x16, 0x0b, 0x14, 0xf5, 0xf5, 0x45, 0x29, 0xd8, 0xc9,
+			0x43, 0xf2, 0xa9, 0xbc, 0xdc, 0x03, 0x81, 0x0d, 0x36,
+			0x2f, 0xb1, 0x22, 0xe8, 0x13, 0xf8,  },
+		.test[6].outlen = 64, .test[6].data = { 0x5d, 0xc4, 0x80, 0x90,
+			0x6b, 0x00, 0x17, 0x04, 0x34, 0x63, 0x93, 0xf1, 0xad,
+			0x9a, 0x3e, 0x13, 0x37, 0x6b, 0x86, 0xd7, 0xc4, 0x2b,
+			0x22, 0x9c, 0x2e, 0xf2, 0x1d, 0xde, 0x35, 0x39, 0x03,
+			0x3f, 0x2b, 0x3a, 0xc3, 0x49, 0xb3, 0x32, 0x86, 0x63,
+			0x6b, 0x0f, 0x27, 0x95, 0x97, 0xe5, 0xe7, 0x2b, 0x9b,
+			0x80, 0xea, 0x94, 0x4d, 0x84, 0x2e, 0x39, 0x44, 0x8f,
+			0x56, 0xe3, 0xcd, 0xa7, 0x12, 0x3e,  },
+	},
+
+	[CRYPTO_MODE_HASH_SHA512_224] = {
+		.min_version = 0x65,
+		.test[1].outlen = 28, .test[1].data = { 0x9e, 0x7d, 0x60, 0x80,
+			0xde, 0xf4, 0xe1, 0xcc, 0xf4, 0xae, 0xaa, 0xc6, 0xf7,
+			0xfa, 0xd0, 0x08, 0xd0, 0x60, 0xa6, 0xcf, 0x87, 0x06,
+			0x20, 0x38, 0xd6, 0x16, 0x67, 0x74,  }
+	},
+
+	[CRYPTO_MODE_HMAC_SHA512_224] = {
+		.min_version = 0x65,
+		.test[1].outlen = 28, .test[1].data = { 0xff, 0xfb, 0x43, 0x27,
+			0xdd, 0x2e, 0x39, 0xa0, 0x18, 0xa8, 0xaf, 0xde, 0x84,
+			0x0b, 0x5d, 0x0f, 0x3d, 0xdc, 0xc6, 0x17, 0xd1, 0xb6,
+			0x2f, 0x8c, 0xf8, 0x7e, 0x34, 0x34,  },
+		.test[4].outlen = 28, .test[4].data = { 0x00, 0x19, 0xe2, 0x2d,
+			0x44, 0x80, 0x2d, 0xd8, 0x1c, 0x57, 0xf5, 0x57, 0x92,
+			0x08, 0x13, 0xe7, 0x9d, 0xbb, 0x2b, 0xc2, 0x8d, 0x77,
+			0xc1, 0xff, 0x71, 0x4c, 0xf0, 0xa9,  },
+		.test[5].outlen = 28, .test[5].data = { 0x6a, 0xc4, 0xa8, 0x73,
+			0x21, 0x54, 0xb2, 0x82, 0xee, 0x89, 0x8d, 0x45, 0xd4,
+			0xe3, 0x76, 0x3e, 0x04, 0x03, 0xc9, 0x71, 0xee, 0x01,
+			0x25, 0xd2, 0x7b, 0xa1, 0x20, 0xc4,  },
+		.test[6].outlen = 28, .test[6].data = { 0x0f, 0x98, 0x15, 0x9b,
+			0x11, 0xca, 0x60, 0xc7, 0x82, 0x39, 0x1a, 0x50, 0x8c,
+			0xe4, 0x79, 0xfa, 0xa8, 0x0e, 0xc7, 0x12, 0xfd, 0x8c,
+			0x9c, 0x99, 0x7a, 0xe8, 0x7e, 0x92,  },
+	},
+
+	[CRYPTO_MODE_HASH_SHA512_256] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0xaf, 0x13, 0xc0, 0x48,
+			0x99, 0x12, 0x24, 0xa5, 0xe4, 0xc6, 0x64, 0x44, 0x6b,
+			0x68, 0x8a, 0xaf, 0x48, 0xfb, 0x54, 0x56, 0xdb, 0x36,
+			0x29, 0x60, 0x1b, 0x00, 0xec, 0x16, 0x0c, 0x74, 0xe5,
+			0x54,  }
+	},
+
+	[CRYPTO_MODE_HMAC_SHA512_256] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0x3a, 0x2c, 0xd0, 0x2b,
+			0xfa, 0xa6, 0x72, 0xe4, 0xf1, 0xab, 0x0a, 0x3e, 0x70,
+			0xe4, 0x88, 0x1a, 0x92, 0xe1, 0x3b, 0x64, 0x5a, 0x9b,
+			0xed, 0xb3, 0x97, 0xc0, 0x17, 0x1f, 0xd4, 0x05, 0xf1,
+			0x72,  },
+		.test[4].outlen = 32, .test[4].data = { 0x6f, 0x2d, 0xae, 0xc6,
+			0xe4, 0xa6, 0x5b, 0x52, 0x0f, 0x26, 0x16, 0xf6, 0xa9,
+			0xc1, 0x23, 0xc2, 0xb3, 0x67, 0xfc, 0x69, 0xac, 0x73,
+			0x87, 0xa2, 0x5b, 0x6c, 0x44, 0xad, 0xc5, 0x26, 0x2b,
+			0x10,  },
+		.test[5].outlen = 32, .test[5].data = { 0x63, 0xe7, 0xb8, 0xd1,
+			0x76, 0x33, 0x56, 0x29, 0xba, 0x99, 0x86, 0x42, 0x0d,
+			0x4f, 0xf7, 0x54, 0x8c, 0xb9, 0x39, 0xf2, 0x72, 0x1d,
+			0x0e, 0x9d, 0x80, 0x67, 0xd9, 0xab, 0x15, 0xb0, 0x68,
+			0x18,  },
+		.test[6].outlen = 32, .test[6].data = { 0x64, 0x78, 0x56, 0xd7,
+			0xaf, 0x5b, 0x56, 0x08, 0xf1, 0x44, 0xf7, 0x4f, 0xa1,
+			0xa1, 0x13, 0x79, 0x6c, 0xb1, 0x31, 0x11, 0xf3, 0x75,
+			0xf4, 0x8c, 0xb4, 0x9f, 0xbf, 0xb1, 0x60, 0x38, 0x3d,
+			0x28,  },
+	},
+
+	[CRYPTO_MODE_MAC_XCBC] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0x35, 0xd9, 0xdc, 0xdb,
+			0x82, 0x9f, 0xec, 0x33, 0x52, 0xe7, 0xbf, 0x10, 0xb8,
+			0x4b, 0xe4, 0xa5,  },
+		.test[3].outlen = 16, .test[3].data = { 0x39, 0x6f, 0x99, 0xb5,
+			0x43, 0x33, 0x67, 0x4e, 0xd4, 0x45, 0x8f, 0x80, 0x77,
+			0xe4, 0xd4, 0x14,  },
+		.test[4].outlen = 16, .test[4].data = { 0x73, 0xd4, 0x7c, 0x38,
+			0x37, 0x4f, 0x73, 0xd0, 0x78, 0xa8, 0xc6, 0xec, 0x05,
+			0x67, 0xca, 0x5e,  },
+	},
+
+	[CRYPTO_MODE_MAC_CMAC] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0x15, 0xbe, 0x1b, 0xfd,
+			0x8c, 0xbb, 0xaf, 0x8b, 0x51, 0x9a, 0x64, 0x3b, 0x1b,
+			0x46, 0xc1, 0x8f,  },
+		.test[3].outlen = 16, .test[3].data = { 0x4e, 0x02, 0xd6, 0xec,
+			0x92, 0x75, 0x88, 0xb4, 0x3e, 0x83, 0xa7, 0xac, 0x32,
+			0xb6, 0x2b, 0xdb,  },
+		.test[4].outlen = 16, .test[4].data = { 0xa7, 0x37, 0x01, 0xbe,
+			0xe8, 0xce, 0xed, 0x44, 0x49, 0x4a, 0xbb, 0xf6, 0x9e,
+			0xd9, 0x31, 0x3e,  },
+	},
+
+	[CRYPTO_MODE_MAC_KASUMI_F9] = {
+		.min_version = 0x65,
+		.test[1].outlen = 4, .test[1].data = { 0x5b, 0x26, 0x81, 0x06 }
+	},
+
+	[CRYPTO_MODE_MAC_SNOW3G_UIA2] = {
+		.min_version = 0x65,
+		.test[1].outlen = 4, .test[1].data = { 0x08, 0xed, 0x2c, 0x76, }
+	},
+
+	[CRYPTO_MODE_MAC_ZUC_UIA3] = {
+		.min_version = 0x65,
+		.test[1].outlen = 4, .test[1].data = { 0x6a, 0x2b, 0x4c, 0x3a, }
+	},
+
+	[CRYPTO_MODE_MAC_POLY1305] = {
+		.min_version = 0x65,
+		.test[4].outlen = 16, .test[4].data = { 0xef, 0x91, 0x06, 0x4e,
+			0xce, 0x99, 0x9c, 0x4e, 0xfd, 0x05, 0x6a, 0x8c, 0xe6,
+			0x18, 0x23, 0xad }
+	},
+
+	[CRYPTO_MODE_SSLMAC_MD5] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0x0e, 0xf4, 0xca, 0x32,
+			0x32, 0x40, 0x1d, 0x1b, 0xaa, 0xfd, 0x6d, 0xa8, 0x01,
+			0x79, 0xed, 0xcd,  },
+	},
+
+	[CRYPTO_MODE_SSLMAC_SHA1] = {
+		.min_version = 0x65,
+		.test[2].outlen = 20, .test[2].data = { 0x05, 0x9d, 0x99, 0xb4,
+			0xf3, 0x03, 0x1e, 0xc5, 0x24, 0xbf, 0xec, 0xdf, 0x64,
+			0x8e, 0x37, 0x2e, 0xf0, 0xef, 0x93, 0xa0,  },
+	},
+
+	[CRYPTO_MODE_HASH_CRC32] = {
+		.min_version = 0x65,
+		.test[0].outlen = 0
+	},
+
+	[CRYPTO_MODE_MAC_MICHAEL] = {
+		.min_version = 0x65,
+		.test[0].outlen = 8, .test[0].data = { 0x16, 0xfb, 0xa0,
+			0x0e, 0xe2, 0xab, 0x6c, 0x97,  }
+	},
+
+	[CRYPTO_MODE_HASH_SHA3_224] = {
+		.min_version = 0x65,
+		.test[1].outlen = 28, .test[1].data = { 0x73, 0xe0, 0x87,
+			0xae, 0x12, 0x71, 0xb2, 0xc5, 0xf6, 0x85, 0x46, 0xc9,
+			0x3a, 0xb4, 0x25, 0x14, 0xa6, 0x9e, 0xef, 0x25, 0x2b,
+			0xfd, 0xd1, 0x37, 0x55, 0x74, 0x8a, 0x00,  }
+	},
+
+	[CRYPTO_MODE_HASH_SHA3_256] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0x9e, 0x62, 0x91, 0x97,
+			0x0c, 0xb4, 0x4d, 0xd9, 0x40, 0x08, 0xc7, 0x9b, 0xca,
+			0xf9, 0xd8, 0x6f, 0x18, 0xb4, 0xb4, 0x9b, 0xa5, 0xb2,
+			0xa0, 0x47, 0x81, 0xdb, 0x71, 0x99, 0xed, 0x3b, 0x9e,
+			0x4e,  }
+	},
+
+	[CRYPTO_MODE_HASH_SHA3_384] = {
+		.min_version = 0x65,
+		.test[1].outlen = 48, .test[1].data = { 0x4b, 0xda, 0xab,
+			0xf7, 0x88, 0xd3, 0xad, 0x1a, 0xd8, 0x3d, 0x6d, 0x93,
+			0xc7, 0xe4, 0x49, 0x37, 0xc2, 0xe6, 0x49, 0x6a, 0xf2,
+			0x3b, 0xe3, 0x35, 0x4d, 0x75, 0x69, 0x87, 0xf4, 0x51,
+			0x60, 0xfc, 0x40, 0x23, 0xbd, 0xa9, 0x5e, 0xcd, 0xcb,
+			0x3c, 0x7e, 0x31, 0xa6, 0x2f, 0x72, 0x6d, 0x70, 0x2c,
+		}
+	},
+
+	[CRYPTO_MODE_HASH_SHA3_512] = {
+		.min_version = 0x65,
+		.test[1].outlen = 64, .test[1].data = { 0xad, 0x56, 0xc3, 0x5c,
+			0xab, 0x50, 0x63, 0xb9, 0xe7, 0xea, 0x56, 0x83, 0x14,
+			0xec, 0x81, 0xc4, 0x0b, 0xa5, 0x77, 0xaa, 0xe6, 0x30,
+			0xde, 0x90, 0x20, 0x04, 0x00, 0x9e, 0x88, 0xf1, 0x8d,
+			0xa5, 0x7b, 0xbd, 0xfd, 0xaa, 0xa0, 0xfc, 0x18, 0x9c,
+			0x66, 0xc8, 0xd8, 0x53, 0x24, 0x8b, 0x6b, 0x11, 0x88,
+			0x44, 0xd5, 0x3f, 0x7d, 0x0b, 0xa1, 0x1d, 0xe0, 0xf3,
+			0xbf, 0xaf, 0x4c, 0xdd, 0x9b, 0x3f,  }
+	},
+
+	[CRYPTO_MODE_HASH_SHAKE128] = {
+		.min_version = 0x65,
+		.test[4].outlen = 16, .test[4].data = { 0x24, 0xa7, 0xca,
+			0x4b, 0x75, 0xe3, 0x89, 0x8d, 0x4f, 0x12, 0xe7, 0x4d,
+			0xea, 0x8c, 0xbb, 0x65 }
+	},
+
+	[CRYPTO_MODE_HASH_SHAKE256] = {
+		.min_version = 0x65,
+		.test[4].outlen = 32, .test[4].data = { 0xf5, 0x97, 0x7c,
+			0x82, 0x83, 0x54, 0x6a, 0x63, 0x72, 0x3b, 0xc3, 0x1d,
+			0x26, 0x19, 0x12, 0x4f,
+			0x11, 0xdb, 0x46, 0x58, 0x64, 0x33, 0x36, 0x74, 0x1d,
+			0xf8, 0x17, 0x57, 0xd5, 0xad, 0x30, 0x62 }
+	},
+
+	[CRYPTO_MODE_HASH_CSHAKE128] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0xe0, 0x6f, 0xd8,
+			0x50, 0x57, 0x6f, 0xe4, 0xfa, 0x7e, 0x13, 0x42, 0xb5,
+			0xf8, 0x13, 0xeb, 0x23 }
+	},
+
+	[CRYPTO_MODE_HASH_CSHAKE256] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0xf3, 0xf2, 0xb5,
+			0x47, 0xf2, 0x16, 0xba, 0x6f, 0x49, 0x83, 0x3e, 0xad,
+			0x1e, 0x46, 0x85, 0x54,
+			0xd0, 0xd7, 0xf9, 0xc6, 0x7e, 0xe9, 0x27, 0xc6, 0xc3,
+			0xc3, 0xdb, 0x91, 0xdb, 0x97, 0x04, 0x0f }
+	},
+
+	[CRYPTO_MODE_MAC_KMAC128] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0x6c, 0x3f, 0x29,
+			0xfe, 0x01, 0x96, 0x59, 0x36, 0xb7, 0xae, 0xb7, 0xff,
+			0x71, 0xe0, 0x3d, 0xff },
+		.test[4].outlen = 16, .test[4].data = { 0x58, 0xd9, 0x8d,
+			0xe8, 0x1f, 0x64, 0xb4, 0xa3, 0x9f, 0x63, 0xaf, 0x21,
+			0x99, 0x03, 0x97, 0x06 },
+		.test[5].outlen = 16, .test[5].data = { 0xf8, 0xf9, 0xb7,
+			0xa4, 0x05, 0x3d, 0x90, 0x7c, 0xf2, 0xa1, 0x7c, 0x34,
+			0x39, 0xc2, 0x87, 0x4b },
+		.test[6].outlen = 16, .test[6].data = { 0xef, 0x4a, 0xd5,
+			0x1d, 0xd7, 0x83, 0x56, 0xd3, 0xa8, 0x3c, 0xf5, 0xf8,
+			0xd1, 0x12, 0xf4, 0x44 }
+	},
+
+	[CRYPTO_MODE_MAC_KMAC256] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0x0d, 0x86, 0xfa,
+			0x92, 0x92, 0xe4, 0x77, 0x24, 0x6a, 0xcc, 0x79, 0xa0,
+			0x1e, 0xb4, 0xc3, 0xac,
+			0xfc, 0x56, 0xbc, 0x63, 0xcc, 0x1b, 0x6e, 0xf6, 0xc8,
+			0x99, 0xa5, 0x3a, 0x38, 0x14, 0xa2, 0x40 },
+		.test[4].outlen = 32, .test[4].data = { 0xad, 0x99, 0xed,
+			0x20, 0x1f, 0xbe, 0x45, 0x07, 0x3d, 0xf4, 0xae, 0x9f,
+			0xc2, 0xd8, 0x06, 0x18,
+			0x31, 0x4e, 0x8c, 0xb6, 0x33, 0xe8, 0x31, 0x36, 0x00,
+			0xdd, 0x42, 0x20, 0xda, 0x2b, 0xd5, 0x2b },
+		.test[5].outlen = 32, .test[5].data = { 0xf9, 0xc6, 0x2b,
+			0x17, 0xa0, 0x04, 0xd9, 0xf2, 0x6c, 0xbf, 0x5d, 0xa5,
+			0x9a, 0xd7, 0x36, 0x1d,
+			0xad, 0x66, 0x6b, 0x3d, 0xb1, 0x52, 0xd3, 0x81, 0x39,
+			0x20, 0xd4, 0xf0, 0x43, 0x72, 0x2c, 0xb7 },
+		.test[6].outlen = 32, .test[6].data = { 0xcc, 0x89, 0xe4,
+			0x05, 0x58, 0x77, 0x38, 0x8b, 0x18, 0xa0, 0x7c, 0x8d,
+			0x20, 0x99, 0xea, 0x6e,
+			0x6b, 0xe9, 0xf7, 0x0c, 0xe1, 0xe5, 0xce, 0xbc, 0x55,
+			0x4c, 0x80, 0xa5, 0xdc, 0xae, 0xf7, 0x94 }
+	},
+
+	[CRYPTO_MODE_MAC_KMACXOF128] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = { 0x84, 0x07, 0x89,
+			0x29, 0xa7, 0xf4, 0x98, 0x91, 0xf5, 0x64, 0x61, 0x8d,
+			0xa5, 0x93, 0x00, 0x31 },
+		.test[4].outlen = 16, .test[4].data = { 0xf0, 0xa4, 0x1b,
+			0x98, 0x0f, 0xb3, 0xf2, 0xbd, 0xc3, 0xfc, 0x64, 0x1f,
+			0x73, 0x1f, 0xd4, 0x74 },
+		.test[5].outlen = 16, .test[5].data = { 0xa5, 0xc5, 0xad,
+			0x25, 0x59, 0xf1, 0x5d, 0xea, 0x5b, 0x18, 0x0a, 0x52,
+			0xce, 0x6c, 0xc0, 0x88 },
+		.test[6].outlen = 16, .test[6].data = { 0x1a, 0x81, 0xdd,
+			0x81, 0x47, 0x89, 0xf4, 0x15, 0xcc, 0x18, 0x05, 0x81,
+			0xe3, 0x95, 0x21, 0xc3 }
+	},
+
+	[CRYPTO_MODE_MAC_KMACXOF256] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0xff, 0x85, 0xe9,
+			0x61, 0x67, 0x96, 0x35, 0x58, 0x33, 0x38, 0x2c, 0xe8,
+			0x25, 0x77, 0xbe, 0x63,
+			0xd5, 0x2c, 0xa7, 0xef, 0xce, 0x9b, 0x63, 0x71, 0xb2,
+			0x09, 0x7c, 0xd8, 0x60, 0x4e, 0x5a, 0xfa },
+		.test[4].outlen = 32, .test[4].data = { 0x86, 0x89, 0xc2,
+			0x4a, 0xe8, 0x18, 0x46, 0x10, 0x6b, 0xf2, 0x09, 0xd7,
+			0x37, 0x83, 0xab, 0x77,
+			0xb5, 0xce, 0x7c, 0x96, 0x9c, 0xfa, 0x0f, 0xa0, 0xd8,
+			0xde, 0xb5, 0xb7, 0xc6, 0xcd, 0xa9, 0x8f },
+		.test[5].outlen = 32, .test[5].data = { 0x4d, 0x71, 0x81,
+			0x5a, 0x5f, 0xac, 0x3b, 0x29, 0xf2, 0x5f, 0xb6, 0x56,
+			0xf1, 0x76, 0xcf, 0xdc,
+			0x51, 0x56, 0xd7, 0x3c, 0x47, 0xec, 0x6d, 0xea, 0xc6,
+			0x3e, 0x54, 0xe7, 0x6f, 0xdc, 0xe8, 0x39 },
+		.test[6].outlen = 32, .test[6].data = { 0x5f, 0xc5, 0xe1,
+			0x1e, 0xe7, 0x55, 0x0f, 0x62, 0x71, 0x29, 0xf3, 0x0a,
+			0xb3, 0x30, 0x68, 0x06,
+			0xea, 0xec, 0xe4, 0x37, 0x17, 0x37, 0x2d, 0x5d, 0x64,
+			0x09, 0x70, 0x63, 0x94, 0x80, 0x9b, 0x80 }
+	},
+
+	[CRYPTO_MODE_HASH_SM3] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0xe0, 0xba, 0xb8,
+			0xf4, 0xd8, 0x17, 0x2b, 0xa2, 0x45, 0x19, 0x0d, 0x13,
+			0xc9, 0x41, 0x17, 0xe9,
+			0x3b, 0x82, 0x16, 0x6c, 0x25, 0xb2, 0xb6, 0x98, 0x83,
+			0x35, 0x0c, 0x19, 0x2c, 0x90, 0x51, 0x40 },
+		.test[4].outlen = 32, .test[4].data = { 0xe0, 0xba, 0xb8,
+			0xf4, 0xd8, 0x17, 0x2b, 0xa2, 0x45, 0x19, 0x0d, 0x13,
+			0xc9, 0x41, 0x17, 0xe9,
+			0x3b, 0x82, 0x16, 0x6c, 0x25, 0xb2, 0xb6, 0x98, 0x83,
+			0x35, 0x0c, 0x19, 0x2c, 0x90, 0x51, 0x40 },
+		.test[5].outlen = 32, .test[5].data = { 0xe0, 0xba, 0xb8,
+			0xf4, 0xd8, 0x17, 0x2b, 0xa2, 0x45, 0x19, 0x0d, 0x13,
+			0xc9, 0x41, 0x17, 0xe9,
+			0x3b, 0x82, 0x16, 0x6c, 0x25, 0xb2, 0xb6, 0x98, 0x83,
+			0x35, 0x0c, 0x19, 0x2c, 0x90, 0x51, 0x40 },
+		.test[6].outlen = 32, .test[6].data = { 0xe0, 0xba, 0xb8,
+			0xf4, 0xd8, 0x17, 0x2b, 0xa2, 0x45, 0x19, 0x0d, 0x13,
+			0xc9, 0x41, 0x17, 0xe9,
+			0x3b, 0x82, 0x16, 0x6c, 0x25, 0xb2, 0xb6, 0x98, 0x83,
+			0x35, 0x0c, 0x19, 0x2c, 0x90, 0x51, 0x40 }
+	},
+
+	[CRYPTO_MODE_HMAC_SM3] = {
+		.min_version = 0x65,
+		.test[1].outlen = 32, .test[1].data = { 0x68, 0xf0, 0x65,
+			0xd8, 0xd8, 0xc9, 0xc2, 0x0e, 0x10, 0xfd, 0x52, 0x7c,
+			0xf2, 0xd7, 0x42, 0xd3,
+			0x08, 0x44, 0x22, 0xbc, 0xf0, 0x9d, 0xcc, 0x34, 0x7b,
+			0x76, 0x13, 0x91, 0xba, 0xce, 0x4d, 0x17 },
+		.test[4].outlen = 32, .test[4].data = { 0xd8, 0xab, 0x2a,
+			0x7b, 0x56, 0x21, 0xb1, 0x59, 0x64, 0xb2, 0xa3, 0xd6,
+			0x72, 0xb3, 0x95, 0x81,
+			0xa0, 0xcd, 0x96, 0x47, 0xf0, 0xbc, 0x8c, 0x16, 0x5b,
+			0x9b, 0x7d, 0x2f, 0x71, 0x3f, 0x23, 0x19 },
+		.test[5].outlen = 32, .test[5].data = { 0xa0, 0xd1, 0xd5,
+			0xa0, 0x9e, 0x4c, 0xca, 0x8c, 0x7b, 0xe0, 0x8f, 0x70,
+			0x92, 0x2e, 0x3f, 0x4c,
+			0xa0, 0xca, 0xef, 0xa1, 0x86, 0x9d, 0xb2, 0xe1, 0xc5,
+			0xfa, 0x9d, 0xfa, 0xbc, 0x11, 0xcb, 0x1f },
+		.test[6].outlen = 32, .test[6].data = { 0xa0, 0xd1, 0xd5,
+			0xa0, 0x9e, 0x4c, 0xca, 0x8c, 0x7b, 0xe0, 0x8f, 0x70,
+			0x92, 0x2e, 0x3f, 0x4c,
+			0xa0, 0xca, 0xef, 0xa1, 0x86, 0x9d, 0xb2, 0xe1, 0xc5,
+			0xfa, 0x9d, 0xfa, 0xbc, 0x11, 0xcb, 0x1f }
+	},
+
+	[CRYPTO_MODE_MAC_SM4_XCBC] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = {0xb5, 0x42, 0xd0, 0xbf,
+			0x93, 0x57, 0x65, 0x69, 0x32, 0xb1, 0x4e, 0x4d, 0x8e,
+			0xe4, 0xae, 0x51, },
+		.test[4].outlen = 16, .test[4].data = { 0x69, 0xaf, 0x45,
+			0xe6, 0x0c, 0x78, 0x71, 0x7e, 0x44, 0x6c, 0xfe, 0x68,
+			0xd4, 0xfe, 0x20, 0x8b },
+		.test[5].outlen = 16, .test[5].data = { 0x69, 0xaf, 0x45,
+			0xe6, 0x0c, 0x78, 0x71, 0x7e, 0x44, 0x6c, 0xfe, 0x68,
+			0xd4, 0xfe, 0x20, 0x8b },
+		.test[6].outlen = 16, .test[6].data = { 0x69, 0xaf, 0x45,
+			0xe6, 0x0c, 0x78, 0x71, 0x7e, 0x44, 0x6c, 0xfe, 0x68,
+			0xd4, 0xfe, 0x20, 0x8b }
+	},
+
+	[CRYPTO_MODE_MAC_SM4_CMAC] = {
+		.min_version = 0x65,
+		.test[1].outlen = 16, .test[1].data = {0x3d, 0x19, 0x10, 0x8e,
+			0x5d, 0xd2, 0x2e, 0x96, 0x92, 0x1c, 0xeb, 0xea, 0x1d,
+			0xb5, 0x1a, 0x4b, },
+		.test[4].outlen = 16, .test[4].data = { 0x36, 0xbe, 0xec,
+			0x03, 0x9c, 0xc7, 0x0c, 0x28, 0x23, 0xdd, 0x71, 0x8b,
+			0x3c, 0xbd, 0x7f, 0x37 },
+		.test[5].outlen = 16, .test[5].data = { 0x36, 0xbe, 0xec,
+			0x03, 0x9c, 0xc7, 0x0c, 0x28, 0x23, 0xdd, 0x71, 0x8b,
+			0x3c, 0xbd, 0x7f, 0x37 },
+		.test[6].outlen = 16, .test[6].data = { 0x36, 0xbe, 0xec,
+			0x03, 0x9c, 0xc7, 0x0c, 0x28, 0x23, 0xdd, 0x71, 0x8b,
+			0x3c, 0xbd, 0x7f, 0x37 }
+	},
+};
+#endif
+
 int spacc_sg_to_ddt(struct device *dev, struct scatterlist *sg,
 		    int nbytes, struct pdu_ddt *ddt, int dma_direction)
 {
@@ -561,6 +1477,281 @@ int spacc_close(struct spacc_device *dev, int handle)
 	return spacc_job_release(dev, handle);
 }
 
+#if IS_ENABLED(CONFIG_CRYPTO_DEV_SPACC_AUTODETECT)
+static int spacc_set_auxinfo(struct spacc_device *spacc, int jobid,
+			     u32 direction, u32 bitsize)
+{
+	int ret = 0;
+	struct spacc_job *job;
+
+	if (jobid < 0 || jobid >= SPACC_MAX_JOBS)
+		return -EINVAL;
+
+	job = &spacc->job[jobid];
+	job->auxinfo_dir = direction;
+	job->auxinfo_bit_align = bitsize;
+
+	return ret;
+}
+
+static int spacc_check_modes(struct spacc_device *spacc, int algo_mode,
+			     int keysz_idx, void *virt, char *key,
+			     struct pdu_ddt *ddt)
+{
+	int enc;
+	int hash;
+	int aadlen;
+	int ivsize;
+	int proclen;
+	int rc = 0;
+	int err = 0;
+	bool output_zero_len;
+	bool output_mismatch;
+	struct spacc_job *job;
+
+	if ((template[algo_mode] & (1 << keysz_idx)) == 0)
+		return 0;
+
+	if (!testdata[algo_mode].test[keysz_idx].outlen) {
+		spacc->config.modes[algo_mode] &= ~(1 << keysz_idx);
+		return 0;
+	}
+
+	/*
+	 * Testing keysizes[keysz_idx] with algo 'algo_mode' which
+	 * should match the ENUMs above
+	 */
+	if (template[algo_mode] & 128) {
+		enc = 0;
+		hash = algo_mode;
+	} else {
+		enc = algo_mode;
+		hash = 0;
+	}
+
+	rc = spacc_open(spacc, enc, hash, -1, 0, NULL, NULL);
+	if (rc < 0) {
+		spacc->config.modes[algo_mode] &= ~(1 << keysz_idx);
+		return 0;
+	}
+
+	if (template[algo_mode] & 128) {
+		/* hash-only: digest written at offset 0 in dst, proclen=32 */
+		spacc_set_operation(spacc, rc, OP_ENCRYPT, ICV_HASH,
+				IP_ICV_OFFSET, 0,
+				testdata[algo_mode].test[keysz_idx].outlen, 0);
+	} else {
+		spacc_set_operation(spacc, rc, OP_ENCRYPT, 0, IP_ICV_APPEND, 0,
+				0, 0);
+	}
+
+	/* if this is a hash or mac */
+	if (template[algo_mode] & 128) {
+		const unsigned char *hash_key = key;
+		unsigned char local_key[128];
+		int klen;
+
+		switch (algo_mode) {
+		case CRYPTO_MODE_HASH_CSHAKE128:
+		case CRYPTO_MODE_HASH_CSHAKE256:
+		case CRYPTO_MODE_MAC_KMAC128:
+		case CRYPTO_MODE_MAC_KMAC256:
+		case CRYPTO_MODE_MAC_KMACXOF128:
+		case CRYPTO_MODE_MAC_KMACXOF256:
+			/*
+			 * Special initial bytes to encode
+			 * length for cust strings
+			 */
+			memcpy(local_key, key, sizeof(local_key));
+			local_key[0] = 0x01;
+			local_key[1] = 0x70;
+			hash_key = local_key;
+			break;
+		}
+
+		klen = keysizes[1][keysz_idx] +
+		       ((algo_mode == CRYPTO_MODE_MAC_XCBC ||
+			 algo_mode == CRYPTO_MODE_MAC_SM4_XCBC) ? 32 : 0);
+
+		if (klen > sizeof(local_key)) {
+			spacc->config.modes[algo_mode] &= ~(1 << keysz_idx);
+			spacc_close(spacc, rc);
+			return 0;
+		}
+
+		spacc_write_context(spacc, rc, SPACC_HASH_OPERATION,
+				hash_key, klen, hash_key, 16);
+	} else {
+		u32 keysize;
+
+		ivsize = 16;
+		keysize = keysizes[0][keysz_idx];
+
+		switch (algo_mode) {
+		case CRYPTO_MODE_CHACHA20_STREAM:
+		case CRYPTO_MODE_AES_CCM:
+		case CRYPTO_MODE_SM4_CCM:
+			ivsize = 16;
+			break;
+		case CRYPTO_MODE_SM4_GCM:
+		case CRYPTO_MODE_CHACHA20_POLY1305:
+		case CRYPTO_MODE_AES_GCM:
+			ivsize = 12;
+			break;
+		case CRYPTO_MODE_KASUMI_ECB:
+		case CRYPTO_MODE_KASUMI_F8:
+		case CRYPTO_MODE_3DES_CBC:
+		case CRYPTO_MODE_3DES_ECB:
+		case CRYPTO_MODE_DES_CBC:
+		case CRYPTO_MODE_DES_ECB:
+			ivsize = 8;
+			break;
+		case CRYPTO_MODE_SM4_XTS:
+		case CRYPTO_MODE_AES_XTS:
+			keysize <<= 1;
+			break;
+		}
+
+		spacc_write_context(spacc, rc, SPACC_CRYPTO_OPERATION,
+				key, keysize, key, ivsize);
+	}
+
+	spacc_set_key_exp(spacc, rc);
+
+	switch (algo_mode) {
+	case CRYPTO_MODE_ZUC_UEA3:
+	case CRYPTO_MODE_SNOW3G_UEA2:
+	case CRYPTO_MODE_MAC_SNOW3G_UIA2:
+	case CRYPTO_MODE_MAC_ZUC_UIA3:
+	case CRYPTO_MODE_KASUMI_F8:
+		spacc_set_auxinfo(spacc, rc, 0, 0);
+		break;
+	case CRYPTO_MODE_MAC_KASUMI_F9:
+		spacc_set_auxinfo(spacc, rc, 0, 8);
+		break;
+	}
+
+	memset(virt, 0, 256);
+
+	aadlen  = 16;
+	proclen = 32;
+
+	if (!enc) {
+		aadlen  = 0;
+		proclen = 32;
+	}
+
+	switch (algo_mode) {
+	case CRYPTO_MODE_SM4_CS1:
+	case CRYPTO_MODE_SM4_CS2:
+	case CRYPTO_MODE_SM4_CS3:
+	case CRYPTO_MODE_AES_CS1:
+	case CRYPTO_MODE_AES_CS2:
+	case CRYPTO_MODE_AES_CS3:
+		proclen = 31;
+		fallthrough;
+	case CRYPTO_MODE_SM4_XTS:
+	case CRYPTO_MODE_AES_XTS:
+		aadlen = 0;
+	}
+
+	err = spacc_packet_enqueue_ddt(spacc, rc, ddt, ddt, proclen, 0,
+				       aadlen, 0, 0, 0, false);
+	job = &spacc->job[rc];
+
+	if (err == 0) {
+		/*
+		 * No timeout, not interruptible: this only returns once
+		 * job_done is actually true, i.e. the hardware has
+		 * genuinely relinquished the job. That guarantees it is
+		 * always safe to close the job/context and (via the
+		 * caller) free the DMA buffer immediately below --
+		 * there is no "unconfirmed" case left to handle.
+		 *
+		 * Tradeoff: if the hardware ever genuinely fails to
+		 * complete a submitted job, this hangs here
+		 * unkillably (TASK_UNINTERRUPTIBLE, no timeout) for the
+		 * rest of probe. Accepted deliberately in place of the
+		 * abandoned-job/UAF risk of giving up early with no
+		 * hardware cancel available.
+		 */
+		wait_event(job->waitq, smp_load_acquire(&job->job_done));
+
+		job->job_done = 0;
+		err = job->job_err;
+	}
+
+	output_zero_len = !testdata[algo_mode].test[keysz_idx].outlen;
+	output_mismatch = memcmp(testdata[algo_mode].test[keysz_idx].data, virt,
+			testdata[algo_mode].test[keysz_idx].outlen);
+
+	if (err != 0 || output_zero_len || output_mismatch)
+		spacc->config.modes[algo_mode] &= ~(1 << keysz_idx);
+
+	spacc_close(spacc, rc);
+
+	return 0;
+}
+
+int spacc_autodetect(struct spacc_device *spacc)
+{
+	int x, y;
+	void *virt;
+	dma_addr_t dma;
+	struct pdu_ddt ddt;
+	unsigned char key[128];
+
+	spacc->autodetect = true;
+
+	virt = dma_alloc_coherent(spacc->dptr, SPACC_TEST_DMA_BUFF_SIZE,
+			&dma, GFP_KERNEL);
+	if (!virt)
+		return -ENOMEM;
+
+	/* DDT is guaranteed by the dma_type gate in spacc_init() */
+	if (pdu_ddt_init(spacc->dptr, &ddt, 1)) {
+		dma_free_coherent(spacc->dptr, SPACC_TEST_DMA_BUFF_SIZE,
+				virt, dma);
+		return -EIO;
+	}
+
+	pdu_ddt_add(spacc->dptr, &ddt, dma, SPACC_TEST_DMA_BUFF_SIZE);
+
+	/* loop through and create a key for autodetect */
+	for (x = 0; x < sizeof(key); x++)
+		key[x] = x & 0xff;
+
+	for (x = 0; x < ARRAY_SIZE(template); x++) {
+		if (!template[x] ||
+		    spacc->config.version < testdata[x].min_version) {
+			spacc->config.modes[x] = 0;
+			continue;
+		}
+
+		spacc->config.modes[x] = template[x];
+		for (y = 0; y < ARRAY_SIZE(keysizes[0]); y++) {
+			/*
+			 * spacc_check_modes() now always returns 0 --
+			 * it only comes back once the job is confirmed
+			 * done, closes itself, and disables the mode
+			 * bit internally on any failure/mismatch.
+			 */
+			spacc_check_modes(spacc, x, y, virt, key, &ddt);
+		}
+
+		if (!(spacc->config.modes[x] & 0x7F))
+			spacc->config.modes[x] &= ~128;
+	}
+
+	pdu_ddt_free(&ddt);
+	dma_free_coherent(spacc->dptr, SPACC_TEST_DMA_BUFF_SIZE, virt, dma);
+	spacc->autodetect = false;
+
+	return 0;
+}
+
+#else
+
 static void spacc_static_modes(struct spacc_device *spacc, int x, int y)
 {
 	/* disable the algos that are not supported here */
@@ -597,6 +1788,7 @@ int spacc_static_config(struct spacc_device *spacc)
 
 	return 0;
 }
+#endif
 
 int spacc_clone_handle(struct spacc_device *spacc, int old_handle,
 		       void *cbdata)

--
2.25.1

#5 lore raw

PATCH v27 4/4 crypto: spacc - Add SPAcc Kconfig and Makefile

In reply to Pavitrakumar Managutte

Add Makefile and Kconfig for SPAcc driver.

---
 drivers/crypto/Kconfig            |  1 +
 drivers/crypto/Makefile           |  1 +
 drivers/crypto/dwc-spacc/Kconfig  | 64 +++++++++++++++++++++++++++++++
 drivers/crypto/dwc-spacc/Makefile |  7 ++++
 4 files changed, 73 insertions(+)
 create mode 100644 drivers/crypto/dwc-spacc/Kconfig
 create mode 100644 drivers/crypto/dwc-spacc/Makefile
drivers/crypto/Kconfig +1 -0
index 0189dfdcbbe11..e0a8de643d6fa 100644
@@ -734,6 +734,7 @@ config CRYPTO_DEV_BCM_SPU
 	  ahash, and aead algorithms with the kernel cryptographic API.
 
 source "drivers/crypto/stm32/Kconfig"
+source "drivers/crypto/dwc-spacc/Kconfig"
 
 config CRYPTO_DEV_SAFEXCEL
 	tristate "Inside Secure's SafeXcel cryptographic engine driver"
drivers/crypto/Makefile +1 -0
index 2c33b83f3cfa6..b80f211598bbc 100644
@@ -40,6 +40,7 @@ obj-$(CONFIG_CRYPTO_DEV_BCM_SPU) += bcm/
 obj-y += inside-secure/
 obj-$(CONFIG_CRYPTO_DEV_ARTPEC6) += axis/
 obj-y += xilinx/
+obj-y += dwc-spacc/
 obj-y += hisilicon/
 obj-$(CONFIG_CRYPTO_DEV_AMLOGIC_GXL) += amlogic/
 obj-y += intel/
drivers/crypto/dwc-spacc/Kconfig new file +64 -0

64 lines not on this page · raw message

drivers/crypto/dwc-spacc/Makefile new file +7 -0
new file mode 100644
index 0000000000000..b7125a7797ba0
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_CRYPTO_DEV_SPACC) += snps-spacc.o
+
+snps-spacc-y := spacc_hal.o spacc_core.o \
+spacc_manager.o spacc_interrupt.o spacc_device.o
+
+snps-spacc-$(CONFIG_CRYPTO_DEV_SPACC_HASH) += spacc_ahash.o

--
2.25.1

#6 lore raw

Re: [PATCH v27 4/4] crypto: spacc - Add SPAcc Kconfig and Makefile

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [High] crypto: spacc - CRYPTO_AHASH_ALG_BLOCK_ONLY inflates statesize past limit - [High] crypto: spacc…

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] crypto: spacc - CRYPTO_AHASH_ALG_BLOCK_ONLY inflates statesize past limit
- [High] crypto: spacc - use-after-free in spacc_hash_exit_tfm() and spacc_hash_setkey() --

commit c650f028323b3118ec1e7adfa8aafa6c190ddd1d
Author: Pavitrakumar Managutte <[email protected]>

crypto: spacc - Add SPAcc Kconfig and Makefile

This commit adds the Kconfig and Makefile for the Synopsys DesignWare SPAcc driver and hooks them into drivers/crypto/.

[ ... ]

drivers/crypto/dwc-spacc/Makefile line 7

Quoted 13 lines
drivers/crypto/dwc-spacc/Makefile new file +7 -0
new file mode 100644
index 0000000000000..b7125a7797ba0
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0-only
+obj-$(CONFIG_CRYPTO_DEV_SPACC) += snps-spacc.o
+
+snps-spacc-y := spacc_hal.o spacc_core.o \
+spacc_manager.o spacc_interrupt.o spacc_device.o
+
+snps-spacc-$(CONFIG_CRYPTO_DEV_SPACC_HASH) += spacc_ahash.o

[Severity: High]
As reported by Sashiko on v26 [1], enabling spacc_ahash.o builds spacc_hash_template and spacc_register_hash() in drivers/crypto/dwc-spacc/spacc_ahash.c with both CRYPTO_AHASH_ALG_BLOCK_ONLY and statesize set to HASH_MAX_STATESIZE:

drivers/crypto/dwc-spacc/spacc_ahash.c:spacc_hash_template:

		.halg.base = {
			...
			.cra_flags	= CRYPTO_ALG_TYPE_AHASH		|
					  CRYPTO_ALG_ASYNC		|
					  CRYPTO_AHASH_ALG_BLOCK_ONLY
		},
drivers/crypto/dwc-spacc/spacc_ahash.c:spacc_register_hash() {
	...
	salg->alg.hash.base.halg.digestsize = salg->mode->hashlen;
	salg->alg.hash.base.halg.statesize = HASH_MAX_STATESIZE;

	rc = crypto_engine_register_ahash(&salg->alg.hash);
}

When crypto_engine_register_ahash() -> crypto_register_ahash() -> ahash_prepare_alg() sees CRYPTO_AHASH_ALG_BLOCK_ONLY, it adds cra_blocksize + 1 to statesize:

crypto/ahash.c:ahash_prepare_alg() {
	...
	if (base->cra_flags & CRYPTO_AHASH_ALG_BLOCK_ONLY) {
		...
		alg->halg.statesize += base->cra_blocksize + 1;
	}
}

This inflates crypto_ahash_statesize(tfm) to HASH_MAX_STATESIZE + cra_blocksize + 1 for every registered SPAcc hash algorithm.

As a result, any virtual-address request reaching ahash_do_req_chain() (such as the generic hmac template wrapping an unkeyed SPAcc hash like sha3-256) hits:

	if (crypto_ahash_statesize(tfm) > HASH_MAX_STATESIZE)
		return -ENOSYS;

and fails with -ENOSYS. In addition, callers allocating a buffer of size HASH_MAX_STATESIZE and calling crypto_ahash_export() will overflow that buffer by cra_blocksize + 1 bytes when crypto_ahash_export() appends the block-only partial block buffer at out + ss - plen.

Furthermore, spacc_hash_init(), spacc_hash_update(), spacc_hash_final(), and spacc_hash_finup() delegate directly to the software fallback fbreq rather than performing block-only hardware hashing:

drivers/crypto/dwc-spacc/spacc_ahash.c:spacc_hash_update() {
	...
	rc = crypto_ahash_import(fbreq, ctx->state_buffer);
	if (!rc)
		rc = crypto_ahash_update(fbreq);
	if (!rc)
		rc = crypto_ahash_export(fbreq, ctx->state_buffer);

	HASH_REQUEST_ZERO(fbreq);

	return rc;
}

Because spacc_hash_update() consumes trailing bytes into ctx->state_buffer via the fallback and returns 0 instead of returning the unprocessed tail length expected by ahash_update_finish(), partial blocks are split between the core block-only buffer and ctx->state_buffer.

Should CRYPTO_AHASH_ALG_BLOCK_ONLY be dropped from spacc_hash_template?

[Severity: High]
Can spacc_hash_exit_tfm() and spacc_hash_setkey() race with spacc_crypto_remove() and trigger a use-after-free on priv->spacc?

In drivers/crypto/dwc-spacc/spacc_device.c, spacc_crypto_remove() notes that sysfs unbind does not wait for existing transforms to be freed. At the end of spacc_crypto_remove(), spacc_remove() frees spacc->ctx and spacc->job via spacc_fini() before clearing drvdata:

drivers/crypto/dwc-spacc/spacc_device.c:spacc_crypto_remove() {
	...
	spacc_remove(pdev);
	platform_set_drvdata(pdev, NULL);
}

However, in drivers/crypto/dwc-spacc/spacc_ahash.c, neither spacc_hash_exit_tfm() nor spacc_hash_setkey() -> spacc_hash_commit_key() checks priv->removing or serializes against spacc_crypto_remove():

drivers/crypto/dwc-spacc/spacc_ahash.c:spacc_hash_exit_tfm() {
	struct spacc_crypto_ctx *tctx = crypto_ahash_ctx(tfm);
	struct spacc_priv *priv = dev_get_drvdata(tctx->dev);

	if (priv && tctx->handle >= 0)
		spacc_close(&priv->spacc, tctx->handle);
	...
}
drivers/crypto/dwc-spacc/spacc_ahash.c:spacc_hash_setkey() {
	...
	struct spacc_priv *priv = dev_get_drvdata(salg->dev);
	...
	if (!spacc_is_mode_keysize_supported(&priv->spacc, salg->mode->id,
				klen, 1)) {
	...
	ret = spacc_hash_commit_key(tfm, priv, key, keylen, keybuf, klen);
}

If an existing transform calls crypto_free_ahash() or crypto_ahash_setkey() concurrently with sysfs unbind and reads priv before platform_set_drvdata(pdev, NULL), won't spacc_close() or spacc_is_mode_keysize_supported() access spacc->job, spacc->ctx, and devm-managed priv after they have been freed?

[1] https://lore.kernel.org/r/[email protected]

Signature · 1 line
Sashiko AI review · https://sashiko.dev/#/patchset/[email protected]?part=4