public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/15] AES-CMAC library
@ 2026-02-18 21:34 Eric Biggers
  2026-02-18 21:34 ` [PATCH 01/15] lib/crypto: aes: Add support for CBC-based MACs Eric Biggers
                   ` (16 more replies)
  0 siblings, 17 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

This series can also be retrieved from:

    git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git aes-cmac-v1

This series adds support for AES CBC-based MACs to the crypto library,
specifically AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC.  The
implementation is fully optimized with the existing
architecture-optimized AES code, either single-block AES en/decryption
or arm64's neon_aes_mac_update() and ce_aes_mac_update().  As usual,
optimizations are now enabled by default as well.

AES-CMAC support will be useful for at least the SMB client and server,
and the bluetooth and mac80211 drivers.  Patches 8-15 convert these
users to use the crypto library API instead of crypto_shash, though
these patches will likely go in via subsystem trees later.  They result
in some significant simplifications and performance improvements.

As usual, a KUnit test suite, FIPS self-test, and traditional crypto API
wrapper algorithms are included as well.

Note that I'm also planning to add additional AES modes to the library.
This is just an initial set of AES modes to get things started.
Notably, with the SMB client and server already using the SHA* and MD5
libraries, "cmac(aes)" was the only remaining use of crypto_shash there.
So it makes sense to take care of that.

Eric Biggers (15):
  lib/crypto: aes: Add support for CBC-based MACs
  crypto: aes - Add cmac, xcbc, and cbcmac algorithms using library
  crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit
  lib/crypto: arm64/aes: Move assembly code for AES modes into libaes
  lib/crypto: arm64/aes: Migrate optimized CBC-based MACs into library
  lib/crypto: tests: Add KUnit tests for CBC-based MACs
  lib/crypto: aes: Add FIPS self-test for CMAC
  smb: client: Use AES-CMAC library for SMB3 signature calculation
  smb: client: Remove obsolete cmac(aes) allocation
  smb: client: Make generate_key() return void
  smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature()
  ksmbd: Use AES-CMAC library for SMB3 signature calculation
  Bluetooth: SMP: Use AES-CMAC library API
  wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac()
  wifi: mac80211: Use AES-CMAC library in aes_s2v()

 arch/arm64/crypto/Kconfig                     |   2 +-
 arch/arm64/crypto/Makefile                    |   4 +-
 arch/arm64/crypto/aes-ce-ccm-glue.c           |   4 -
 arch/arm64/crypto/aes-glue.c                  | 260 +-----------------
 arch/arm64/crypto/aes-neonbs-glue.c           |  15 +-
 crypto/Kconfig                                |   2 +
 crypto/aes.c                                  | 183 +++++++++++-
 crypto/testmgr.c                              |  10 +-
 drivers/crypto/starfive/jh7110-aes.c          |   2 +-
 fs/smb/client/Kconfig                         |   2 +-
 fs/smb/client/cifs_unicode.c                  |   1 +
 fs/smb/client/cifsencrypt.c                   |  62 ++---
 fs/smb/client/cifsfs.c                        |   1 -
 fs/smb/client/cifsglob.h                      |   7 +-
 fs/smb/client/cifsproto.h                     |   3 -
 fs/smb/client/misc.c                          |  57 ----
 fs/smb/client/sess.c                          |  11 -
 fs/smb/client/smb2proto.h                     |   1 -
 fs/smb/client/smb2transport.c                 | 113 ++------
 fs/smb/server/Kconfig                         |   2 +-
 fs/smb/server/auth.c                          |  51 +---
 fs/smb/server/auth.h                          |   4 +-
 fs/smb/server/crypto_ctx.c                    |  58 ----
 fs/smb/server/crypto_ctx.h                    |  12 -
 fs/smb/server/server.c                        |   1 -
 fs/smb/server/smb2pdu.c                       |   8 +-
 include/crypto/aes-cbc-macs.h                 | 154 +++++++++++
 include/crypto/aes.h                          |  66 +++++
 lib/crypto/Kconfig                            |  10 +
 lib/crypto/Makefile                           |   4 +-
 lib/crypto/aes.c                              | 231 +++++++++++++++-
 .../crypto => lib/crypto/arm64}/aes-ce.S      |   0
 .../crypto => lib/crypto/arm64}/aes-modes.S   |  23 +-
 .../crypto => lib/crypto/arm64}/aes-neon.S    |   0
 lib/crypto/arm64/aes.h                        |  76 ++++-
 lib/crypto/fips.h                             |   5 +
 lib/crypto/tests/Kconfig                      |  10 +
 lib/crypto/tests/Makefile                     |   1 +
 lib/crypto/tests/aes-cmac-testvecs.h          | 181 ++++++++++++
 lib/crypto/tests/aes_cbc_macs_kunit.c         | 228 +++++++++++++++
 net/bluetooth/Kconfig                         |   3 +-
 net/bluetooth/smp.c                           | 180 +++++-------
 net/mac80211/Kconfig                          |   2 +-
 net/mac80211/aes_cmac.c                       |  65 +----
 net/mac80211/aes_cmac.h                       |  12 +-
 net/mac80211/fils_aead.c                      |  48 ++--
 net/mac80211/key.c                            |  11 +-
 net/mac80211/key.h                            |   3 +-
 net/mac80211/wpa.c                            |  13 +-
 scripts/crypto/gen-fips-testvecs.py           |  10 +
 scripts/crypto/gen-hash-testvecs.py           |  31 ++-
 51 files changed, 1388 insertions(+), 855 deletions(-)
 create mode 100644 include/crypto/aes-cbc-macs.h
 rename {arch/arm64/crypto => lib/crypto/arm64}/aes-ce.S (100%)
 rename {arch/arm64/crypto => lib/crypto/arm64}/aes-modes.S (98%)
 rename {arch/arm64/crypto => lib/crypto/arm64}/aes-neon.S (100%)
 create mode 100644 lib/crypto/tests/aes-cmac-testvecs.h
 create mode 100644 lib/crypto/tests/aes_cbc_macs_kunit.c


base-commit: 2961f841b025fb234860bac26dfb7fa7cb0fb122
prerequisite-patch-id: 8eccdd31739fb317dfda9dddbfc5c3cd64e77331
prerequisite-patch-id: ca782470cef2467042fbe8f0166933d7fa292628
-- 
2.53.0


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH 01/15] lib/crypto: aes: Add support for CBC-based MACs
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:34 ` [PATCH 02/15] crypto: aes - Add cmac, xcbc, and cbcmac algorithms using library Eric Biggers
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Add support for CBC-based MACs to the AES library, specifically
AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC.

Of these three algorithms, AES-CMAC is the most modern and the most
commonly used.  Use cases for the AES-CMAC library include the kernel's
SMB client and server, and the bluetooth and mac80211 drivers.

Support for AES-XCBC-MAC and AES-CBC-MAC is included so that there will
be no performance regression in the "xcbc(aes)" and "ccm(aes)" support
in the traditional crypto API once the arm64-optimized code is migrated
into the library.  AES-XCBC-MAC is given its own key preparation
function but is otherwise identical to AES-CMAC and just reuses the
AES-CMAC structs and functions.

The implementation automatically uses the optimized AES key expansion
and single block en/decryption functions.  It also allows architectures
to provide an optimized implementation of aes_cbcmac_blocks(), which
allows the existing arm64-optimized code for these modes to be used.

Just put the code for these modes directly in the libaes module rather
than in a separate module.  This is simpler, it makes it easier to share
code between AES modes, and it increases the amount of inlining that is
possible.  (Indeed, for these reasons, most of the
architecture-optimized AES code already provides multiple modes per
module.  x86 for example has only a single aesni-intel module.  So to a
large extent, this design choice just reflects the status quo.)

However, since there are a lot of AES modes, there's still some value in
omitting modes that are not needed at all in a given kernel.  Therefore,
make these modes an optional feature of libaes, controlled by
CONFIG_CRYPTO_LIB_AES_CBC_MACS.  This seems like a good middle ground.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 include/crypto/aes-cbc-macs.h | 154 ++++++++++++++++++++++++++
 lib/crypto/Kconfig            |  10 ++
 lib/crypto/aes.c              | 198 ++++++++++++++++++++++++++++++++++
 3 files changed, 362 insertions(+)
 create mode 100644 include/crypto/aes-cbc-macs.h

diff --git a/include/crypto/aes-cbc-macs.h b/include/crypto/aes-cbc-macs.h
new file mode 100644
index 000000000000..e61df108b926
--- /dev/null
+++ b/include/crypto/aes-cbc-macs.h
@@ -0,0 +1,154 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Support for AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC
+ *
+ * Copyright 2026 Google LLC
+ */
+#ifndef _CRYPTO_AES_CBC_MACS_H
+#define _CRYPTO_AES_CBC_MACS_H
+
+#include <crypto/aes.h>
+
+/**
+ * struct aes_cmac_key - Prepared key for AES-CMAC or AES-XCBC-MAC
+ * @aes: The AES key for cipher block chaining
+ * @k_final: Finalization subkeys for the final block.
+ *	     k_final[0] (CMAC K1, XCBC-MAC K2) is used if it's a full block.
+ *	     k_final[1] (CMAC K2, XCBC-MAC K3) is used if it's a partial block.
+ */
+struct aes_cmac_key {
+	struct aes_enckey aes;
+	union {
+		u8 b[AES_BLOCK_SIZE];
+		__be64 w[2];
+	} k_final[2];
+};
+
+/**
+ * struct aes_cmac_ctx - Context for computing an AES-CMAC or AES-XCBC-MAC value
+ * @key: Pointer to the key struct.  A pointer is used rather than a copy of the
+ *	 struct, since the key struct size may be large.  It is assumed that the
+ *	 key lives at least as long as the context.
+ * @partial_len: Number of bytes that have been XOR'ed into @h since the last
+ *		 AES encryption.  This is 0 if no data has been processed yet,
+ *		 or between 1 and AES_BLOCK_SIZE inclusive otherwise.
+ * @h: The current chaining value
+ */
+struct aes_cmac_ctx {
+	const struct aes_cmac_key *key;
+	size_t partial_len;
+	u8 h[AES_BLOCK_SIZE];
+};
+
+/**
+ * aes_cmac_preparekey() - Prepare a key for AES-CMAC
+ * @key: (output) The key struct to initialize
+ * @in_key: The raw AES key
+ * @key_len: Length of the raw key in bytes.  The supported values are
+ *	     AES_KEYSIZE_128, AES_KEYSIZE_192, and AES_KEYSIZE_256.
+ *
+ * Context: Any context.
+ * Return: 0 on success or -EINVAL if the given key length is invalid.  No other
+ *	   errors are possible, so callers that always pass a valid key length
+ *	   don't need to check for errors.
+ */
+int aes_cmac_preparekey(struct aes_cmac_key *key, const u8 *in_key,
+			size_t key_len);
+
+/**
+ * aes_xcbcmac_preparekey() - Prepare a key for AES-XCBC-MAC
+ * @key: (output) The key struct to initialize
+ * @in_key: The raw key.  As per the AES-XCBC-MAC specification (RFC 3566), this
+ *	    is 128 bits, matching the internal use of AES-128.
+ *
+ * AES-XCBC-MAC and AES-CMAC are the same except for the key preparation.  After
+ * that step, AES-XCBC-MAC is supported via the aes_cmac_* functions.
+ *
+ * New users should use AES-CMAC instead of AES-XCBC-MAC.
+ *
+ * Context: Any context.
+ */
+void aes_xcbcmac_preparekey(struct aes_cmac_key *key,
+			    const u8 in_key[at_least AES_KEYSIZE_128]);
+
+/**
+ * aes_cmac_init() - Start computing an AES-CMAC or AES-XCBC-MAC value
+ * @ctx: (output) The context to initialize
+ * @key: The key to use.  Note that a pointer to the key is saved in the
+ *	 context, so the key must live at least as long as the context.
+ *
+ * This supports both AES-CMAC and AES-XCBC-MAC.  Which one is done depends on
+ * whether aes_cmac_preparekey() or aes_xcbcmac_preparekey() was called.
+ */
+static inline void aes_cmac_init(struct aes_cmac_ctx *ctx,
+				 const struct aes_cmac_key *key)
+{
+	*ctx = (struct aes_cmac_ctx){ .key = key };
+}
+
+/**
+ * aes_cmac_update() - Update an AES-CMAC or AES-XCBC-MAC context with more data
+ * @ctx: The context to update; must have been initialized
+ * @data: The message data
+ * @data_len: The data length in bytes.  Doesn't need to be block-aligned.
+ *
+ * This can be called any number of times.
+ *
+ * Context: Any context.
+ */
+void aes_cmac_update(struct aes_cmac_ctx *ctx, const u8 *data, size_t data_len);
+
+/**
+ * aes_cmac_final() - Finish computing an AES-CMAC or AES-XCBC-MAC value
+ * @ctx: The context to finalize; must have been initialized
+ * @out: (output) The resulting MAC
+ *
+ * After finishing, this zeroizes @ctx.  So the caller does not need to do it.
+ *
+ * Context: Any context.
+ */
+void aes_cmac_final(struct aes_cmac_ctx *ctx, u8 out[at_least AES_BLOCK_SIZE]);
+
+/**
+ * aes_cmac() - Compute AES-CMAC or AES-XCBC-MAC in one shot
+ * @key: The key to use
+ * @data: The message data
+ * @data_len: The data length in bytes
+ * @out: (output) The resulting AES-CMAC or AES-XCBC-MAC value
+ *
+ * This supports both AES-CMAC and AES-XCBC-MAC.  Which one is done depends on
+ * whether aes_cmac_preparekey() or aes_xcbcmac_preparekey() was called.
+ *
+ * Context: Any context.
+ */
+static inline void aes_cmac(const struct aes_cmac_key *key, const u8 *data,
+			    size_t data_len, u8 out[at_least AES_BLOCK_SIZE])
+{
+	struct aes_cmac_ctx ctx;
+
+	aes_cmac_init(&ctx, key);
+	aes_cmac_update(&ctx, data, data_len);
+	aes_cmac_final(&ctx, out);
+}
+
+/*
+ * AES-CBC-MAC support.  This is provided only for use by the implementation of
+ * AES-CCM.  It should have no other users.  Warning: unlike AES-CMAC and
+ * AES-XCBC-MAC, AES-CBC-MAC isn't a secure MAC for variable-length messages.
+ */
+struct aes_cbcmac_ctx {
+	const struct aes_enckey *key;
+	size_t partial_len;
+	u8 h[AES_BLOCK_SIZE];
+};
+static inline void aes_cbcmac_init(struct aes_cbcmac_ctx *ctx,
+				   const struct aes_enckey *key)
+{
+	*ctx = (struct aes_cbcmac_ctx){ .key = key };
+}
+void aes_cbcmac_update(struct aes_cbcmac_ctx *ctx, const u8 *data,
+		       size_t data_len);
+void aes_cbcmac_final(struct aes_cbcmac_ctx *ctx,
+		      u8 out[at_least AES_BLOCK_SIZE]);
+
+#endif /* _CRYPTO_AES_CBC_MACS_H */
diff --git a/lib/crypto/Kconfig b/lib/crypto/Kconfig
index 032f9755f999..42ec51645915 100644
--- a/lib/crypto/Kconfig
+++ b/lib/crypto/Kconfig
@@ -8,10 +8,12 @@ config CRYPTO_HASH_INFO
 config CRYPTO_LIB_UTILS
 	tristate
 
 config CRYPTO_LIB_AES
 	tristate
+	# Select dependencies of modes that are part of libaes.
+	select CRYPTO_LIB_UTILS if CRYPTO_LIB_AES_CBC_MACS
 
 config CRYPTO_LIB_AES_ARCH
 	bool
 	depends on CRYPTO_LIB_AES && !UML && !KMSAN
 	default y if ARM
@@ -26,10 +28,18 @@ config CRYPTO_LIB_AES_ARCH
 config CRYPTO_LIB_AESCFB
 	tristate
 	select CRYPTO_LIB_AES
 	select CRYPTO_LIB_UTILS
 
+config CRYPTO_LIB_AES_CBC_MACS
+	tristate
+	select CRYPTO_LIB_AES
+	help
+	  The AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC library functions.  Select
+	  this if your module uses any of the functions from
+	  <crypto/aes-cbc-macs.h>.
+
 config CRYPTO_LIB_AESGCM
 	tristate
 	select CRYPTO_LIB_AES
 	select CRYPTO_LIB_GF128MUL
 	select CRYPTO_LIB_UTILS
diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c
index b73e19f1bb95..39deae6105c0 100644
--- a/lib/crypto/aes.c
+++ b/lib/crypto/aes.c
@@ -2,11 +2,13 @@
 /*
  * Copyright (C) 2017-2019 Linaro Ltd <ard.biesheuvel@linaro.org>
  * Copyright 2026 Google LLC
  */
 
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/aes.h>
+#include <crypto/utils.h>
 #include <linux/cache.h>
 #include <linux/crypto.h>
 #include <linux/export.h>
 #include <linux/module.h>
 #include <linux/unaligned.h>
@@ -510,10 +512,206 @@ void aes_decrypt(const struct aes_key *key, u8 out[AES_BLOCK_SIZE],
 {
 	aes_decrypt_arch(key, out, in);
 }
 EXPORT_SYMBOL(aes_decrypt);
 
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC_MACS)
+
+#ifndef aes_cbcmac_blocks_arch
+static bool aes_cbcmac_blocks_arch(u8 h[AES_BLOCK_SIZE],
+				   const struct aes_enckey *key, const u8 *data,
+				   size_t nblocks, bool enc_before,
+				   bool enc_after)
+{
+	return false;
+}
+#endif
+
+/* This assumes nblocks >= 1. */
+static void aes_cbcmac_blocks(u8 h[AES_BLOCK_SIZE],
+			      const struct aes_enckey *key, const u8 *data,
+			      size_t nblocks, bool enc_before, bool enc_after)
+{
+	if (aes_cbcmac_blocks_arch(h, key, data, nblocks, enc_before,
+				   enc_after))
+		return;
+
+	if (enc_before)
+		aes_encrypt(key, h, h);
+	for (; nblocks > 1; nblocks--) {
+		crypto_xor(h, data, AES_BLOCK_SIZE);
+		data += AES_BLOCK_SIZE;
+		aes_encrypt(key, h, h);
+	}
+	crypto_xor(h, data, AES_BLOCK_SIZE);
+	if (enc_after)
+		aes_encrypt(key, h, h);
+}
+
+int aes_cmac_preparekey(struct aes_cmac_key *key, const u8 *in_key,
+			size_t key_len)
+{
+	u64 hi, lo, mask;
+	int err;
+
+	/* Prepare the AES key. */
+	err = aes_prepareenckey(&key->aes, in_key, key_len);
+	if (err)
+		return err;
+
+	/*
+	 * Prepare the subkeys K1 and K2 by encrypting the all-zeroes block,
+	 * then multiplying by 'x' and 'x^2' (respectively) in GF(2^128).
+	 * Reference: NIST SP 800-38B, Section 6.1 "Subkey Generation".
+	 */
+	memset(key->k_final[0].b, 0, AES_BLOCK_SIZE);
+	aes_encrypt(&key->aes, key->k_final[0].b, key->k_final[0].b);
+	hi = be64_to_cpu(key->k_final[0].w[0]);
+	lo = be64_to_cpu(key->k_final[0].w[1]);
+	for (int i = 0; i < 2; i++) {
+		mask = ((s64)hi >> 63) & 0x87;
+		hi = (hi << 1) ^ (lo >> 63);
+		lo = (lo << 1) ^ mask;
+		key->k_final[i].w[0] = cpu_to_be64(hi);
+		key->k_final[i].w[1] = cpu_to_be64(lo);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(aes_cmac_preparekey);
+
+void aes_xcbcmac_preparekey(struct aes_cmac_key *key,
+			    const u8 in_key[AES_KEYSIZE_128])
+{
+	static const u8 constants[3][AES_BLOCK_SIZE] = {
+		{ [0 ... AES_BLOCK_SIZE - 1] = 0x1 },
+		{ [0 ... AES_BLOCK_SIZE - 1] = 0x2 },
+		{ [0 ... AES_BLOCK_SIZE - 1] = 0x3 },
+	};
+	u8 new_aes_key[AES_BLOCK_SIZE];
+
+	static_assert(AES_BLOCK_SIZE == AES_KEYSIZE_128);
+	aes_prepareenckey(&key->aes, in_key, AES_BLOCK_SIZE);
+	aes_encrypt(&key->aes, new_aes_key, constants[0]);
+	aes_encrypt(&key->aes, key->k_final[0].b, constants[1]);
+	aes_encrypt(&key->aes, key->k_final[1].b, constants[2]);
+	aes_prepareenckey(&key->aes, new_aes_key, AES_BLOCK_SIZE);
+	memzero_explicit(new_aes_key, AES_BLOCK_SIZE);
+}
+EXPORT_SYMBOL_GPL(aes_xcbcmac_preparekey);
+
+void aes_cmac_update(struct aes_cmac_ctx *ctx, const u8 *data, size_t data_len)
+{
+	bool enc_before = false;
+	size_t nblocks;
+
+	if (ctx->partial_len) {
+		/* XOR data into a pending block. */
+		size_t l = min(data_len, AES_BLOCK_SIZE - ctx->partial_len);
+
+		crypto_xor(&ctx->h[ctx->partial_len], data, l);
+		data += l;
+		data_len -= l;
+		ctx->partial_len += l;
+		if (data_len == 0) {
+			/*
+			 * Either the pending block hasn't been filled yet, or
+			 * no more data was given so it's not yet known whether
+			 * the block is the final block.
+			 */
+			return;
+		}
+		/* Pending block has been filled and isn't the final block. */
+		enc_before = true;
+	}
+
+	nblocks = data_len / AES_BLOCK_SIZE;
+	data_len %= AES_BLOCK_SIZE;
+	if (nblocks == 0) {
+		/* 0 additional full blocks, then optionally a partial block */
+		if (enc_before)
+			aes_encrypt(&ctx->key->aes, ctx->h, ctx->h);
+		crypto_xor(ctx->h, data, data_len);
+		ctx->partial_len = data_len;
+	} else if (data_len != 0) {
+		/* 1 or more additional full blocks, then a partial block */
+		aes_cbcmac_blocks(ctx->h, &ctx->key->aes, data, nblocks,
+				  enc_before, /* enc_after= */ true);
+		data += nblocks * AES_BLOCK_SIZE;
+		crypto_xor(ctx->h, data, data_len);
+		ctx->partial_len = data_len;
+	} else {
+		/*
+		 * 1 or more additional full blocks only.  Encryption of the
+		 * last block is delayed until it's known whether it's the final
+		 * block in the message or not.
+		 */
+		aes_cbcmac_blocks(ctx->h, &ctx->key->aes, data, nblocks,
+				  enc_before, /* enc_after= */ false);
+		ctx->partial_len = AES_BLOCK_SIZE;
+	}
+}
+EXPORT_SYMBOL_GPL(aes_cmac_update);
+
+void aes_cmac_final(struct aes_cmac_ctx *ctx, u8 out[AES_BLOCK_SIZE])
+{
+	if (ctx->partial_len == AES_BLOCK_SIZE) {
+		/* Final block is a full block.  Use k_final[0]. */
+		crypto_xor(ctx->h, ctx->key->k_final[0].b, AES_BLOCK_SIZE);
+	} else {
+		/* Final block is a partial block.  Pad, and use k_final[1]. */
+		ctx->h[ctx->partial_len] ^= 0x80;
+		crypto_xor(ctx->h, ctx->key->k_final[1].b, AES_BLOCK_SIZE);
+	}
+	aes_encrypt(&ctx->key->aes, out, ctx->h);
+	memzero_explicit(ctx, sizeof(*ctx));
+}
+EXPORT_SYMBOL_GPL(aes_cmac_final);
+
+void aes_cbcmac_update(struct aes_cbcmac_ctx *ctx, const u8 *data,
+		       size_t data_len)
+{
+	bool enc_before = false;
+	size_t nblocks;
+
+	if (ctx->partial_len) {
+		size_t l = min(data_len, AES_BLOCK_SIZE - ctx->partial_len);
+
+		crypto_xor(&ctx->h[ctx->partial_len], data, l);
+		data += l;
+		data_len -= l;
+		ctx->partial_len += l;
+		if (ctx->partial_len < AES_BLOCK_SIZE)
+			return;
+		enc_before = true;
+	}
+
+	nblocks = data_len / AES_BLOCK_SIZE;
+	data_len %= AES_BLOCK_SIZE;
+	if (nblocks == 0) {
+		if (enc_before)
+			aes_encrypt(ctx->key, ctx->h, ctx->h);
+	} else {
+		aes_cbcmac_blocks(ctx->h, ctx->key, data, nblocks, enc_before,
+				  /* enc_after= */ true);
+		data += nblocks * AES_BLOCK_SIZE;
+	}
+	crypto_xor(ctx->h, data, data_len);
+	ctx->partial_len = data_len;
+}
+EXPORT_SYMBOL_NS_GPL(aes_cbcmac_update, "CRYPTO_INTERNAL");
+
+void aes_cbcmac_final(struct aes_cbcmac_ctx *ctx, u8 out[AES_BLOCK_SIZE])
+{
+	if (ctx->partial_len)
+		aes_encrypt(ctx->key, out, ctx->h);
+	else
+		memcpy(out, ctx->h, AES_BLOCK_SIZE);
+	memzero_explicit(ctx, sizeof(*ctx));
+}
+EXPORT_SYMBOL_NS_GPL(aes_cbcmac_final, "CRYPTO_INTERNAL");
+#endif /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */
+
 #ifdef aes_mod_init_arch
 static int __init aes_mod_init(void)
 {
 	aes_mod_init_arch();
 	return 0;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 02/15] crypto: aes - Add cmac, xcbc, and cbcmac algorithms using library
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
  2026-02-18 21:34 ` [PATCH 01/15] lib/crypto: aes: Add support for CBC-based MACs Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:34 ` [PATCH 03/15] crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit Eric Biggers
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Update the "aes" module to implement "cmac(aes)", "xcbc(aes)", and
"cbcmac(aes)" algorithms using the corresponding library functions, and
register these with the crypto_shash API.  Each algorithm is included
only if the corresponding existing kconfig option is enabled.

This allows the architecture-optimized implementations of these
algorithms to continue to be accessible via the crypto_shash API once
they are migrated into the library.

For "xcbc(aes)", I also fixed the bug where AES key lengths other than
128 bits were allowed, so that this bug didn't have to be implemented in
the library.  The AES-XCBC-MAC specification (RFC 3566) is clear that
key lengths other than 128 bits MUST NOT be supported.  AES-XCBC-MAC
derives a 128-bit subkey internally, so the nonstandard support for
longer AES keys didn't really work: AES-128 was still used internally.

In the unlikely event that someone is actually relying on the broken and
nonstandard support for longer AES-XCBC-MAC keys, we can fairly easily
reintroduce it.  But it seems unnecessary: the only user of "xcbc(aes)"
seems to be IPsec, which uses 128-bit keys with it.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 crypto/Kconfig                       |   2 +
 crypto/aes.c                         | 183 ++++++++++++++++++++++++++-
 crypto/testmgr.c                     |  10 +-
 drivers/crypto/starfive/jh7110-aes.c |   2 +-
 4 files changed, 190 insertions(+), 7 deletions(-)

diff --git a/crypto/Kconfig b/crypto/Kconfig
index e2b4106ac961..256ce4729c8d 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -359,10 +359,12 @@ menu "Block ciphers"
 
 config CRYPTO_AES
 	tristate "AES (Advanced Encryption Standard)"
 	select CRYPTO_ALGAPI
 	select CRYPTO_LIB_AES
+	select CRYPTO_LIB_AES_CBC_MACS if CRYPTO_CMAC || CRYPTO_XCBC || CRYPTO_CCM
+	select CRYPTO_HASH if CRYPTO_CMAC || CRYPTO_XCBC || CRYPTO_CCM
 	help
 	  AES cipher algorithms (Rijndael)(FIPS-197, ISO/IEC 18033-3)
 
 	  Rijndael appears to be consistently a very good performer in
 	  both hardware and software across a wide range of computing
diff --git a/crypto/aes.c b/crypto/aes.c
index ae8385df0ce5..6bf23eb0503f 100644
--- a/crypto/aes.c
+++ b/crypto/aes.c
@@ -3,12 +3,14 @@
  * Crypto API support for AES block cipher
  *
  * Copyright 2026 Google LLC
  */
 
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/aes.h>
 #include <crypto/algapi.h>
+#include <crypto/internal/hash.h>
 #include <linux/module.h>
 
 static_assert(__alignof__(struct aes_key) <= CRYPTO_MINALIGN);
 
 static int crypto_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,
@@ -31,10 +33,102 @@ static void crypto_aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in)
 	const struct aes_key *key = crypto_tfm_ctx(tfm);
 
 	aes_decrypt(key, out, in);
 }
 
+static_assert(__alignof__(struct aes_cmac_key) <= CRYPTO_MINALIGN);
+#define AES_CMAC_KEY(tfm) ((struct aes_cmac_key *)crypto_shash_ctx(tfm))
+#define AES_CMAC_CTX(desc) ((struct aes_cmac_ctx *)shash_desc_ctx(desc))
+
+static int __maybe_unused crypto_aes_cmac_setkey(struct crypto_shash *tfm,
+						 const u8 *in_key,
+						 unsigned int key_len)
+{
+	return aes_cmac_preparekey(AES_CMAC_KEY(tfm), in_key, key_len);
+}
+
+static int __maybe_unused crypto_aes_xcbc_setkey(struct crypto_shash *tfm,
+						 const u8 *in_key,
+						 unsigned int key_len)
+{
+	if (key_len != AES_KEYSIZE_128)
+		return -EINVAL;
+	aes_xcbcmac_preparekey(AES_CMAC_KEY(tfm), in_key);
+	return 0;
+}
+
+static int __maybe_unused crypto_aes_cmac_init(struct shash_desc *desc)
+{
+	aes_cmac_init(AES_CMAC_CTX(desc), AES_CMAC_KEY(desc->tfm));
+	return 0;
+}
+
+static int __maybe_unused crypto_aes_cmac_update(struct shash_desc *desc,
+						 const u8 *data,
+						 unsigned int len)
+{
+	aes_cmac_update(AES_CMAC_CTX(desc), data, len);
+	return 0;
+}
+
+static int __maybe_unused crypto_aes_cmac_final(struct shash_desc *desc,
+						u8 *out)
+{
+	aes_cmac_final(AES_CMAC_CTX(desc), out);
+	return 0;
+}
+
+static int __maybe_unused crypto_aes_cmac_digest(struct shash_desc *desc,
+						 const u8 *data,
+						 unsigned int len, u8 *out)
+{
+	aes_cmac(AES_CMAC_KEY(desc->tfm), data, len, out);
+	return 0;
+}
+
+static_assert(__alignof__(struct aes_enckey) <= CRYPTO_MINALIGN);
+#define AES_CBCMAC_KEY(tfm) ((struct aes_enckey *)crypto_shash_ctx(tfm))
+#define AES_CBCMAC_CTX(desc) ((struct aes_cbcmac_ctx *)shash_desc_ctx(desc))
+
+static int __maybe_unused crypto_aes_cbcmac_setkey(struct crypto_shash *tfm,
+						   const u8 *in_key,
+						   unsigned int key_len)
+{
+	return aes_prepareenckey(AES_CBCMAC_KEY(tfm), in_key, key_len);
+}
+
+static int __maybe_unused crypto_aes_cbcmac_init(struct shash_desc *desc)
+{
+	aes_cbcmac_init(AES_CBCMAC_CTX(desc), AES_CBCMAC_KEY(desc->tfm));
+	return 0;
+}
+
+static int __maybe_unused crypto_aes_cbcmac_update(struct shash_desc *desc,
+						   const u8 *data,
+						   unsigned int len)
+{
+	aes_cbcmac_update(AES_CBCMAC_CTX(desc), data, len);
+	return 0;
+}
+
+static int __maybe_unused crypto_aes_cbcmac_final(struct shash_desc *desc,
+						  u8 *out)
+{
+	aes_cbcmac_final(AES_CBCMAC_CTX(desc), out);
+	return 0;
+}
+
+static int __maybe_unused crypto_aes_cbcmac_digest(struct shash_desc *desc,
+						   const u8 *data,
+						   unsigned int len, u8 *out)
+{
+	aes_cbcmac_init(AES_CBCMAC_CTX(desc), AES_CBCMAC_KEY(desc->tfm));
+	aes_cbcmac_update(AES_CBCMAC_CTX(desc), data, len);
+	aes_cbcmac_final(AES_CBCMAC_CTX(desc), out);
+	return 0;
+}
+
 static struct crypto_alg alg = {
 	.cra_name = "aes",
 	.cra_driver_name = "aes-lib",
 	.cra_priority = 100,
 	.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
@@ -46,21 +140,108 @@ static struct crypto_alg alg = {
 			       .cia_setkey = crypto_aes_setkey,
 			       .cia_encrypt = crypto_aes_encrypt,
 			       .cia_decrypt = crypto_aes_decrypt } }
 };
 
+static struct shash_alg mac_algs[] = {
+#if IS_ENABLED(CONFIG_CRYPTO_CMAC)
+	{
+		.base.cra_name = "cmac(aes)",
+		.base.cra_driver_name = "cmac-aes-lib",
+		.base.cra_priority = 300,
+		.base.cra_blocksize = AES_BLOCK_SIZE,
+		.base.cra_ctxsize = sizeof(struct aes_cmac_key),
+		.base.cra_module = THIS_MODULE,
+		.digestsize = AES_BLOCK_SIZE,
+		.setkey = crypto_aes_cmac_setkey,
+		.init = crypto_aes_cmac_init,
+		.update = crypto_aes_cmac_update,
+		.final = crypto_aes_cmac_final,
+		.digest = crypto_aes_cmac_digest,
+		.descsize = sizeof(struct aes_cmac_ctx),
+	},
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_XCBC)
+	{
+		/*
+		 * Note that the only difference between xcbc(aes) and cmac(aes)
+		 * is the preparekey function.
+		 */
+		.base.cra_name = "xcbc(aes)",
+		.base.cra_driver_name = "xcbc-aes-lib",
+		.base.cra_priority = 300,
+		.base.cra_blocksize = AES_BLOCK_SIZE,
+		.base.cra_ctxsize = sizeof(struct aes_cmac_key),
+		.base.cra_module = THIS_MODULE,
+		.digestsize = AES_BLOCK_SIZE,
+		.setkey = crypto_aes_xcbc_setkey,
+		.init = crypto_aes_cmac_init,
+		.update = crypto_aes_cmac_update,
+		.final = crypto_aes_cmac_final,
+		.digest = crypto_aes_cmac_digest,
+		.descsize = sizeof(struct aes_cmac_ctx),
+	},
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CCM)
+	{
+		.base.cra_name = "cbcmac(aes)",
+		.base.cra_driver_name = "cbcmac-aes-lib",
+		.base.cra_priority = 300,
+		.base.cra_blocksize = AES_BLOCK_SIZE,
+		.base.cra_ctxsize = sizeof(struct aes_enckey),
+		.base.cra_module = THIS_MODULE,
+		.digestsize = AES_BLOCK_SIZE,
+		.setkey = crypto_aes_cbcmac_setkey,
+		.init = crypto_aes_cbcmac_init,
+		.update = crypto_aes_cbcmac_update,
+		.final = crypto_aes_cbcmac_final,
+		.digest = crypto_aes_cbcmac_digest,
+		.descsize = sizeof(struct aes_cbcmac_ctx),
+	},
+#endif
+};
+
 static int __init crypto_aes_mod_init(void)
 {
-	return crypto_register_alg(&alg);
+	int err = crypto_register_alg(&alg);
+
+	if (err)
+		return err;
+
+	if (ARRAY_SIZE(mac_algs) > 0) {
+		err = crypto_register_shashes(mac_algs, ARRAY_SIZE(mac_algs));
+		if (err)
+			goto err_unregister_alg;
+	} /* Else, CONFIG_CRYPTO_HASH might not be enabled. */
+	return 0;
+
+err_unregister_alg:
+	crypto_unregister_alg(&alg);
+	return err;
 }
 module_init(crypto_aes_mod_init);
 
 static void __exit crypto_aes_mod_exit(void)
 {
+	if (ARRAY_SIZE(mac_algs) > 0)
+		crypto_unregister_shashes(mac_algs, ARRAY_SIZE(mac_algs));
 	crypto_unregister_alg(&alg);
 }
 module_exit(crypto_aes_mod_exit);
 
 MODULE_DESCRIPTION("Crypto API support for AES block cipher");
+MODULE_IMPORT_NS("CRYPTO_INTERNAL");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_CRYPTO("aes");
 MODULE_ALIAS_CRYPTO("aes-lib");
+#if IS_ENABLED(CONFIG_CRYPTO_CMAC)
+MODULE_ALIAS_CRYPTO("cmac(aes)");
+MODULE_ALIAS_CRYPTO("cmac-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_XCBC)
+MODULE_ALIAS_CRYPTO("xcbc(aes)");
+MODULE_ALIAS_CRYPTO("xcbc-aes-lib");
+#endif
+#if IS_ENABLED(CONFIG_CRYPTO_CCM)
+MODULE_ALIAS_CRYPTO("cbcmac(aes)");
+MODULE_ALIAS_CRYPTO("cbcmac-aes-lib");
+#endif
diff --git a/crypto/testmgr.c b/crypto/testmgr.c
index b940721447fa..fa7217029f44 100644
--- a/crypto/testmgr.c
+++ b/crypto/testmgr.c
@@ -4386,11 +4386,11 @@ static const struct alg_test_desc alg_test_descs[] = {
 			.cipher = __VECS(aes_cbc_tv_template)
 		}
 	}, {
 #endif
 		.alg = "cbcmac(aes)",
-		.generic_driver = "cbcmac(aes-lib)",
+		.generic_driver = "cbcmac-aes-lib",
 		.test = alg_test_hash,
 		.suite = {
 			.hash = __VECS(aes_cbcmac_tv_template)
 		}
 	}, {
@@ -4399,11 +4399,11 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.suite = {
 			.hash = __VECS(sm4_cbcmac_tv_template)
 		}
 	}, {
 		.alg = "ccm(aes)",
-		.generic_driver = "ccm_base(ctr(aes-lib),cbcmac(aes-lib))",
+		.generic_driver = "ccm_base(ctr(aes-lib),cbcmac-aes-lib)",
 		.test = alg_test_aead,
 		.fips_allowed = 1,
 		.suite = {
 			.aead = {
 				____VECS(aes_ccm_tv_template),
@@ -4427,11 +4427,11 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.suite = {
 			.cipher = __VECS(chacha20_tv_template)
 		},
 	}, {
 		.alg = "cmac(aes)",
-		.generic_driver = "cmac(aes-lib)",
+		.generic_driver = "cmac-aes-lib",
 		.fips_allowed = 1,
 		.test = alg_test_hash,
 		.suite = {
 			.hash = __VECS(aes_cmac128_tv_template)
 		}
@@ -5324,11 +5324,11 @@ static const struct alg_test_desc alg_test_descs[] = {
 				.aad_iv = 1,
 			}
 		}
 	}, {
 		.alg = "rfc4309(ccm(aes))",
-		.generic_driver = "rfc4309(ccm_base(ctr(aes-lib),cbcmac(aes-lib)))",
+		.generic_driver = "rfc4309(ccm_base(ctr(aes-lib),cbcmac-aes-lib))",
 		.test = alg_test_aead,
 		.fips_allowed = 1,
 		.suite = {
 			.aead = {
 				____VECS(aes_ccm_rfc4309_tv_template),
@@ -5513,11 +5513,11 @@ static const struct alg_test_desc alg_test_descs[] = {
 		.suite = {
 			.sig = __VECS(x962_ecdsa_nist_p521_tv_template)
 		}
 	}, {
 		.alg = "xcbc(aes)",
-		.generic_driver = "xcbc(aes-lib)",
+		.generic_driver = "xcbc-aes-lib",
 		.test = alg_test_hash,
 		.suite = {
 			.hash = __VECS(aes_xcbc128_tv_template)
 		}
 	}, {
diff --git a/drivers/crypto/starfive/jh7110-aes.c b/drivers/crypto/starfive/jh7110-aes.c
index c1dc1e43e117..2e2d97d17e6c 100644
--- a/drivers/crypto/starfive/jh7110-aes.c
+++ b/drivers/crypto/starfive/jh7110-aes.c
@@ -1001,11 +1001,11 @@ static int starfive_aes_ctr_init_tfm(struct crypto_skcipher *tfm)
 	return starfive_aes_init_tfm(tfm, "ctr(aes-lib)");
 }
 
 static int starfive_aes_ccm_init_tfm(struct crypto_aead *tfm)
 {
-	return starfive_aes_aead_init_tfm(tfm, "ccm_base(ctr(aes-lib),cbcmac(aes-lib))");
+	return starfive_aes_aead_init_tfm(tfm, "ccm_base(ctr(aes-lib),cbcmac-aes-lib)");
 }
 
 static int starfive_aes_gcm_init_tfm(struct crypto_aead *tfm)
 {
 	return starfive_aes_aead_init_tfm(tfm, "gcm_base(ctr(aes-lib),ghash-generic)");
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 03/15] crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
  2026-02-18 21:34 ` [PATCH 01/15] lib/crypto: aes: Add support for CBC-based MACs Eric Biggers
  2026-02-18 21:34 ` [PATCH 02/15] crypto: aes - Add cmac, xcbc, and cbcmac algorithms using library Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-19  9:23   ` Ard Biesheuvel
  2026-02-18 21:34 ` [PATCH 04/15] lib/crypto: arm64/aes: Move assembly code for AES modes into libaes Eric Biggers
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers,
	stable

Since the 'enc_after' argument to neon_aes_mac_update() and
ce_aes_mac_update() has type 'int', it needs to be accessed using the
corresponding 32-bit register, not the 64-bit register.  The upper half
of the corresponding 64-bit register may contain garbage.

Fixes: 4860620da7e5 ("crypto: arm64/aes - add NEON/Crypto Extensions CBCMAC/CMAC/XCBC driver")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 arch/arm64/crypto/aes-modes.S | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S
index 0e834a2c062c..e793478f37c1 100644
--- a/arch/arm64/crypto/aes-modes.S
+++ b/arch/arm64/crypto/aes-modes.S
@@ -836,11 +836,11 @@ AES_FUNC_START(aes_mac_update)
 	encrypt_block	v0, w2, x1, x7, w8
 	eor		v0.16b, v0.16b, v3.16b
 	encrypt_block	v0, w2, x1, x7, w8
 	eor		v0.16b, v0.16b, v4.16b
 	cmp		w3, wzr
-	csinv		x5, x6, xzr, eq
+	csinv		w5, w6, wzr, eq
 	cbz		w5, .Lmacout
 	encrypt_block	v0, w2, x1, x7, w8
 	st1		{v0.16b}, [x4]			/* return dg */
 	cond_yield	.Lmacout, x7, x8
 	b		.Lmacloop4x
@@ -850,11 +850,11 @@ AES_FUNC_START(aes_mac_update)
 	cbz		w3, .Lmacout
 	ld1		{v1.16b}, [x0], #16		/* get next pt block */
 	eor		v0.16b, v0.16b, v1.16b		/* ..and xor with dg */
 
 	subs		w3, w3, #1
-	csinv		x5, x6, xzr, eq
+	csinv		w5, w6, wzr, eq
 	cbz		w5, .Lmacout
 
 .Lmacenc:
 	encrypt_block	v0, w2, x1, x7, w8
 	b		.Lmacloop
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 04/15] lib/crypto: arm64/aes: Move assembly code for AES modes into libaes
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (2 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 03/15] crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:34 ` [PATCH 05/15] lib/crypto: arm64/aes: Migrate optimized CBC-based MACs into library Eric Biggers
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

To migrate the support for CBC-based MACs into libaes, the corresponding
arm64 assembly code needs to be moved there.  However, the arm64 AES
assembly code groups many AES modes together; individual modes aren't
easily separable.  (This isn't unique to arm64; other architectures
organize their AES modes similarly.)

Since the other AES modes will be migrated into the library eventually
too, just move the full assembly files for the AES modes into the
library.  (This is similar to what I already did for PowerPC and SPARC.)

Specifically: move the assembly files aes-ce.S, aes-modes.S, and
aes-neon.S and their build rules; declare the assembly functions in
<crypto/aes.h>; and export the assembly functions from libaes.

Note that the exports and public declarations of the assembly functions
are temporary.  They exist only to keep arch/arm64/crypto/ working until
the AES modes are fully moved into the library.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 arch/arm64/crypto/Makefile                    |  4 +-
 arch/arm64/crypto/aes-ce-ccm-glue.c           |  4 --
 arch/arm64/crypto/aes-glue.c                  | 47 +------------
 arch/arm64/crypto/aes-neonbs-glue.c           | 15 +---
 include/crypto/aes.h                          | 69 +++++++++++++++++++
 lib/crypto/Makefile                           |  4 +-
 .../crypto => lib/crypto/arm64}/aes-ce.S      |  0
 .../crypto => lib/crypto/arm64}/aes-modes.S   |  0
 .../crypto => lib/crypto/arm64}/aes-neon.S    |  0
 lib/crypto/arm64/aes.h                        | 30 ++++++++
 10 files changed, 106 insertions(+), 67 deletions(-)
 rename {arch/arm64/crypto => lib/crypto/arm64}/aes-ce.S (100%)
 rename {arch/arm64/crypto => lib/crypto/arm64}/aes-modes.S (100%)
 rename {arch/arm64/crypto => lib/crypto/arm64}/aes-neon.S (100%)

diff --git a/arch/arm64/crypto/Makefile b/arch/arm64/crypto/Makefile
index 3574e917bc37..8a8e3e551ed3 100644
--- a/arch/arm64/crypto/Makefile
+++ b/arch/arm64/crypto/Makefile
@@ -31,12 +31,12 @@ ghash-ce-y := ghash-ce-glue.o ghash-ce-core.o
 
 obj-$(CONFIG_CRYPTO_AES_ARM64_CE_CCM) += aes-ce-ccm.o
 aes-ce-ccm-y := aes-ce-ccm-glue.o aes-ce-ccm-core.o
 
 obj-$(CONFIG_CRYPTO_AES_ARM64_CE_BLK) += aes-ce-blk.o
-aes-ce-blk-y := aes-glue-ce.o aes-ce.o
+aes-ce-blk-y := aes-glue-ce.o
 
 obj-$(CONFIG_CRYPTO_AES_ARM64_NEON_BLK) += aes-neon-blk.o
-aes-neon-blk-y := aes-glue-neon.o aes-neon.o
+aes-neon-blk-y := aes-glue-neon.o
 
 obj-$(CONFIG_CRYPTO_AES_ARM64_BS) += aes-neon-bs.o
 aes-neon-bs-y := aes-neonbs-core.o aes-neonbs-glue.o
diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c
index db371ac051fc..45aed0073283 100644
--- a/arch/arm64/crypto/aes-ce-ccm-glue.c
+++ b/arch/arm64/crypto/aes-ce-ccm-glue.c
@@ -29,14 +29,10 @@ static int num_rounds(struct crypto_aes_ctx *ctx)
 	 * => n byte key	=> 6 + (n/4) rounds
 	 */
 	return 6 + ctx->key_length / 4;
 }
 
-asmlinkage u32 ce_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
-				 int blocks, u8 dg[], int enc_before,
-				 int enc_after);
-
 asmlinkage void ce_aes_ccm_encrypt(u8 out[], u8 const in[], u32 cbytes,
 				   u32 const rk[], u32 rounds, u8 mac[],
 				   u8 ctr[], u8 const final_iv[]);
 
 asmlinkage void ce_aes_ccm_decrypt(u8 out[], u8 const in[], u32 cbytes,
diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c
index 92f43e1cd097..fd7c3a560a71 100644
--- a/arch/arm64/crypto/aes-glue.c
+++ b/arch/arm64/crypto/aes-glue.c
@@ -69,52 +69,13 @@ MODULE_ALIAS_CRYPTO("essiv(cbc(aes),sha256)");
 MODULE_ALIAS_CRYPTO("cmac(aes)");
 MODULE_ALIAS_CRYPTO("xcbc(aes)");
 MODULE_ALIAS_CRYPTO("cbcmac(aes)");
 
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
+MODULE_IMPORT_NS("CRYPTO_INTERNAL");
 MODULE_LICENSE("GPL v2");
 
-/* defined in aes-modes.S */
-asmlinkage void aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[],
-				int rounds, int blocks);
-asmlinkage void aes_ecb_decrypt(u8 out[], u8 const in[], u32 const rk[],
-				int rounds, int blocks);
-
-asmlinkage void aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[],
-				int rounds, int blocks, u8 iv[]);
-asmlinkage void aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[],
-				int rounds, int blocks, u8 iv[]);
-
-asmlinkage void aes_cbc_cts_encrypt(u8 out[], u8 const in[], u32 const rk[],
-				int rounds, int bytes, u8 const iv[]);
-asmlinkage void aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[],
-				int rounds, int bytes, u8 const iv[]);
-
-asmlinkage void aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
-				int rounds, int bytes, u8 ctr[]);
-
-asmlinkage void aes_xctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
-				 int rounds, int bytes, u8 ctr[], int byte_ctr);
-
-asmlinkage void aes_xts_encrypt(u8 out[], u8 const in[], u32 const rk1[],
-				int rounds, int bytes, u32 const rk2[], u8 iv[],
-				int first);
-asmlinkage void aes_xts_decrypt(u8 out[], u8 const in[], u32 const rk1[],
-				int rounds, int bytes, u32 const rk2[], u8 iv[],
-				int first);
-
-asmlinkage void aes_essiv_cbc_encrypt(u8 out[], u8 const in[], u32 const rk1[],
-				      int rounds, int blocks, u8 iv[],
-				      u32 const rk2[]);
-asmlinkage void aes_essiv_cbc_decrypt(u8 out[], u8 const in[], u32 const rk1[],
-				      int rounds, int blocks, u8 iv[],
-				      u32 const rk2[]);
-
-asmlinkage int aes_mac_update(u8 const in[], u32 const rk[], int rounds,
-			      int blocks, u8 dg[], int enc_before,
-			      int enc_after);
-
 struct crypto_aes_xts_ctx {
 	struct crypto_aes_ctx key1;
 	struct crypto_aes_ctx __aligned(8) key2;
 };
 
@@ -969,15 +930,9 @@ static int __init aes_init(void)
 	return err;
 }
 
 #ifdef USE_V8_CRYPTO_EXTENSIONS
 module_cpu_feature_match(AES, aes_init);
-EXPORT_SYMBOL_NS(ce_aes_mac_update, "CRYPTO_INTERNAL");
 #else
 module_init(aes_init);
-EXPORT_SYMBOL(neon_aes_ecb_encrypt);
-EXPORT_SYMBOL(neon_aes_cbc_encrypt);
-EXPORT_SYMBOL(neon_aes_ctr_encrypt);
-EXPORT_SYMBOL(neon_aes_xts_encrypt);
-EXPORT_SYMBOL(neon_aes_xts_decrypt);
 #endif
 module_exit(aes_exit);
diff --git a/arch/arm64/crypto/aes-neonbs-glue.c b/arch/arm64/crypto/aes-neonbs-glue.c
index cb87c8fc66b3..7630a7bf5da9 100644
--- a/arch/arm64/crypto/aes-neonbs-glue.c
+++ b/arch/arm64/crypto/aes-neonbs-glue.c
@@ -15,10 +15,11 @@
 #include <crypto/xts.h>
 #include <linux/module.h>
 
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_DESCRIPTION("Bit sliced AES using NEON instructions");
+MODULE_IMPORT_NS("CRYPTO_INTERNAL");
 MODULE_LICENSE("GPL v2");
 
 MODULE_ALIAS_CRYPTO("ecb(aes)");
 MODULE_ALIAS_CRYPTO("cbc(aes)");
 MODULE_ALIAS_CRYPTO("ctr(aes)");
@@ -40,24 +41,10 @@ asmlinkage void aesbs_ctr_encrypt(u8 out[], u8 const in[], u8 const rk[],
 asmlinkage void aesbs_xts_encrypt(u8 out[], u8 const in[], u8 const rk[],
 				  int rounds, int blocks, u8 iv[]);
 asmlinkage void aesbs_xts_decrypt(u8 out[], u8 const in[], u8 const rk[],
 				  int rounds, int blocks, u8 iv[]);
 
-/* borrowed from aes-neon-blk.ko */
-asmlinkage void neon_aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[],
-				     int rounds, int blocks);
-asmlinkage void neon_aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[],
-				     int rounds, int blocks, u8 iv[]);
-asmlinkage void neon_aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
-				     int rounds, int bytes, u8 ctr[]);
-asmlinkage void neon_aes_xts_encrypt(u8 out[], u8 const in[],
-				     u32 const rk1[], int rounds, int bytes,
-				     u32 const rk2[], u8 iv[], int first);
-asmlinkage void neon_aes_xts_decrypt(u8 out[], u8 const in[],
-				     u32 const rk1[], int rounds, int bytes,
-				     u32 const rk2[], u8 iv[], int first);
-
 struct aesbs_ctx {
 	u8	rk[13 * (8 * AES_BLOCK_SIZE) + 32];
 	int	rounds;
 } __aligned(AES_BLOCK_SIZE);
 
diff --git a/include/crypto/aes.h b/include/crypto/aes.h
index cbf1cc96db52..91bf4667d3e9 100644
--- a/include/crypto/aes.h
+++ b/include/crypto/aes.h
@@ -165,10 +165,79 @@ int aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
  * that code is migrated into lib/crypto/.
  */
 #ifdef CONFIG_ARM64
 int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
 		     unsigned int key_len);
+asmlinkage void neon_aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[],
+				     int rounds, int blocks);
+asmlinkage void neon_aes_ecb_decrypt(u8 out[], u8 const in[], u32 const rk[],
+				     int rounds, int blocks);
+asmlinkage void neon_aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[],
+				     int rounds, int blocks, u8 iv[]);
+asmlinkage void neon_aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[],
+				     int rounds, int blocks, u8 iv[]);
+asmlinkage void neon_aes_cbc_cts_encrypt(u8 out[], u8 const in[],
+					 u32 const rk[], int rounds, int bytes,
+					 u8 const iv[]);
+asmlinkage void neon_aes_cbc_cts_decrypt(u8 out[], u8 const in[],
+					 u32 const rk[], int rounds, int bytes,
+					 u8 const iv[]);
+asmlinkage void neon_aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
+				     int rounds, int bytes, u8 ctr[]);
+asmlinkage void neon_aes_xctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
+				      int rounds, int bytes, u8 ctr[],
+				      int byte_ctr);
+asmlinkage void neon_aes_xts_encrypt(u8 out[], u8 const in[], u32 const rk1[],
+				     int rounds, int bytes, u32 const rk2[],
+				     u8 iv[], int first);
+asmlinkage void neon_aes_xts_decrypt(u8 out[], u8 const in[], u32 const rk1[],
+				     int rounds, int bytes, u32 const rk2[],
+				     u8 iv[], int first);
+asmlinkage void neon_aes_essiv_cbc_encrypt(u8 out[], u8 const in[],
+					   u32 const rk1[], int rounds,
+					   int blocks, u8 iv[],
+					   u32 const rk2[]);
+asmlinkage void neon_aes_essiv_cbc_decrypt(u8 out[], u8 const in[],
+					   u32 const rk1[], int rounds,
+					   int blocks, u8 iv[],
+					   u32 const rk2[]);
+asmlinkage int neon_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
+				   int blocks, u8 dg[], int enc_before,
+				   int enc_after);
+
+asmlinkage void ce_aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[],
+				   int rounds, int blocks);
+asmlinkage void ce_aes_ecb_decrypt(u8 out[], u8 const in[], u32 const rk[],
+				   int rounds, int blocks);
+asmlinkage void ce_aes_cbc_encrypt(u8 out[], u8 const in[], u32 const rk[],
+				   int rounds, int blocks, u8 iv[]);
+asmlinkage void ce_aes_cbc_decrypt(u8 out[], u8 const in[], u32 const rk[],
+				   int rounds, int blocks, u8 iv[]);
+asmlinkage void ce_aes_cbc_cts_encrypt(u8 out[], u8 const in[], u32 const rk[],
+				       int rounds, int bytes, u8 const iv[]);
+asmlinkage void ce_aes_cbc_cts_decrypt(u8 out[], u8 const in[], u32 const rk[],
+				       int rounds, int bytes, u8 const iv[]);
+asmlinkage void ce_aes_ctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
+				   int rounds, int bytes, u8 ctr[]);
+asmlinkage void ce_aes_xctr_encrypt(u8 out[], u8 const in[], u32 const rk[],
+				    int rounds, int bytes, u8 ctr[],
+				    int byte_ctr);
+asmlinkage void ce_aes_xts_encrypt(u8 out[], u8 const in[], u32 const rk1[],
+				   int rounds, int bytes, u32 const rk2[],
+				   u8 iv[], int first);
+asmlinkage void ce_aes_xts_decrypt(u8 out[], u8 const in[], u32 const rk1[],
+				   int rounds, int bytes, u32 const rk2[],
+				   u8 iv[], int first);
+asmlinkage void ce_aes_essiv_cbc_encrypt(u8 out[], u8 const in[],
+					 u32 const rk1[], int rounds,
+					 int blocks, u8 iv[], u32 const rk2[]);
+asmlinkage void ce_aes_essiv_cbc_decrypt(u8 out[], u8 const in[],
+					 u32 const rk1[], int rounds,
+					 int blocks, u8 iv[], u32 const rk2[]);
+asmlinkage int ce_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
+				 int blocks, u8 dg[], int enc_before,
+				 int enc_after);
 #elif defined(CONFIG_PPC)
 void ppc_expand_key_128(u32 *key_enc, const u8 *key);
 void ppc_expand_key_192(u32 *key_enc, const u8 *key);
 void ppc_expand_key_256(u32 *key_enc, const u8 *key);
 void ppc_generate_decrypt_key(u32 *key_dec, u32 *key_enc, unsigned int key_len);
diff --git a/lib/crypto/Makefile b/lib/crypto/Makefile
index 725eef05b758..c05d4b4e8e82 100644
--- a/lib/crypto/Makefile
+++ b/lib/crypto/Makefile
@@ -24,11 +24,13 @@ CFLAGS_aes.o += -I$(src)/$(SRCARCH)
 
 libaes-$(CONFIG_ARM) += arm/aes-cipher-core.o
 
 ifeq ($(CONFIG_ARM64),y)
 libaes-y += arm64/aes-cipher-core.o
-libaes-$(CONFIG_KERNEL_MODE_NEON) += arm64/aes-ce-core.o
+libaes-$(CONFIG_KERNEL_MODE_NEON) += arm64/aes-ce-core.o \
+				     arm64/aes-ce.o \
+				     arm64/aes-neon.o
 endif
 
 ifeq ($(CONFIG_PPC),y)
 ifeq ($(CONFIG_SPE),y)
 libaes-y += powerpc/aes-spe-core.o \
diff --git a/arch/arm64/crypto/aes-ce.S b/lib/crypto/arm64/aes-ce.S
similarity index 100%
rename from arch/arm64/crypto/aes-ce.S
rename to lib/crypto/arm64/aes-ce.S
diff --git a/arch/arm64/crypto/aes-modes.S b/lib/crypto/arm64/aes-modes.S
similarity index 100%
rename from arch/arm64/crypto/aes-modes.S
rename to lib/crypto/arm64/aes-modes.S
diff --git a/arch/arm64/crypto/aes-neon.S b/lib/crypto/arm64/aes-neon.S
similarity index 100%
rename from arch/arm64/crypto/aes-neon.S
rename to lib/crypto/arm64/aes-neon.S
diff --git a/lib/crypto/arm64/aes.h b/lib/crypto/arm64/aes.h
index 63eea6271ef9..69f465c668f0 100644
--- a/lib/crypto/arm64/aes.h
+++ b/lib/crypto/arm64/aes.h
@@ -124,10 +124,40 @@ int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
 			    6 + key_len / 4);
 	return 0;
 }
 EXPORT_SYMBOL(ce_aes_expandkey);
 
+#if IS_ENABLED(CONFIG_KERNEL_MODE_NEON)
+EXPORT_SYMBOL_NS_GPL(neon_aes_ecb_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_ecb_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_cbc_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_cbc_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_cbc_cts_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_cbc_cts_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_ctr_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_xctr_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_xts_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_xts_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_essiv_cbc_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_essiv_cbc_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(neon_aes_mac_update, "CRYPTO_INTERNAL");
+
+EXPORT_SYMBOL_NS_GPL(ce_aes_ecb_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_ecb_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_cbc_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_cbc_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_cbc_cts_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_cbc_cts_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_ctr_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_xctr_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_xts_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_xts_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_essiv_cbc_encrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_essiv_cbc_decrypt, "CRYPTO_INTERNAL");
+EXPORT_SYMBOL_NS_GPL(ce_aes_mac_update, "CRYPTO_INTERNAL");
+#endif
+
 static void aes_encrypt_arch(const struct aes_enckey *key,
 			     u8 out[AES_BLOCK_SIZE],
 			     const u8 in[AES_BLOCK_SIZE])
 {
 	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 05/15] lib/crypto: arm64/aes: Migrate optimized CBC-based MACs into library
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (3 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 04/15] lib/crypto: arm64/aes: Move assembly code for AES modes into libaes Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:34 ` [PATCH 06/15] lib/crypto: tests: Add KUnit tests for CBC-based MACs Eric Biggers
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Instead of exposing the arm64-optimized CMAC, XCBC-MAC, and CBC-MAC code
via arm64-specific crypto_shash algorithms, instead just implement the
aes_cbcmac_blocks_arch() library function.  This is much simpler, it
makes the corresponding library functions be arm64-optimized, and it
fixes the longstanding issue where this optimized code was disabled by
default.  The corresponding algorithms still remain available through
crypto_shash, but individual architectures no longer need to handle it.

Note that to be compatible with the library using 'size_t' lengths, the
type of the return value and 'blocks' parameter to the assembly
functions had to be changed to 'size_t', and the assembly code had to be
updated accordingly to use the corresponding 64-bit registers.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 arch/arm64/crypto/Kconfig    |   2 +-
 arch/arm64/crypto/aes-glue.c | 213 +----------------------------------
 include/crypto/aes.h         |   9 +-
 lib/crypto/arm64/aes-modes.S |  19 ++--
 lib/crypto/arm64/aes.h       |  48 +++++++-
 5 files changed, 61 insertions(+), 230 deletions(-)

diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig
index 81ed892b3b72..82794afaffc9 100644
--- a/arch/arm64/crypto/Kconfig
+++ b/arch/arm64/crypto/Kconfig
@@ -142,11 +142,11 @@ config CRYPTO_AES_ARM64_CE_CCM
 	tristate "AEAD cipher: AES in CCM mode (ARMv8 Crypto Extensions)"
 	depends on KERNEL_MODE_NEON
 	select CRYPTO_ALGAPI
 	select CRYPTO_AES_ARM64_CE_BLK
 	select CRYPTO_AEAD
-	select CRYPTO_LIB_AES
+	select CRYPTO_LIB_AES_CBC_MACS
 	help
 	  AEAD cipher: AES cipher algorithms (FIPS-197) with
 	  CCM (Counter with Cipher Block Chaining-Message Authentication Code)
 	  authenticated encryption mode (NIST SP800-38C)
 
diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c
index fd7c3a560a71..e1b88f7e2d39 100644
--- a/arch/arm64/crypto/aes-glue.c
+++ b/arch/arm64/crypto/aes-glue.c
@@ -35,11 +35,10 @@
 #define aes_essiv_cbc_decrypt	ce_aes_essiv_cbc_decrypt
 #define aes_ctr_encrypt		ce_aes_ctr_encrypt
 #define aes_xctr_encrypt	ce_aes_xctr_encrypt
 #define aes_xts_encrypt		ce_aes_xts_encrypt
 #define aes_xts_decrypt		ce_aes_xts_decrypt
-#define aes_mac_update		ce_aes_mac_update
 MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS/XCTR using ARMv8 Crypto Extensions");
 #else
 #define MODE			"neon"
 #define PRIO			200
 #define aes_ecb_encrypt		neon_aes_ecb_encrypt
@@ -52,11 +51,10 @@ MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS/XCTR using ARMv8 Crypto Extensions");
 #define aes_essiv_cbc_decrypt	neon_aes_essiv_cbc_decrypt
 #define aes_ctr_encrypt		neon_aes_ctr_encrypt
 #define aes_xctr_encrypt	neon_aes_xctr_encrypt
 #define aes_xts_encrypt		neon_aes_xts_encrypt
 #define aes_xts_decrypt		neon_aes_xts_decrypt
-#define aes_mac_update		neon_aes_mac_update
 MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS/XCTR using ARMv8 NEON");
 #endif
 #if defined(USE_V8_CRYPTO_EXTENSIONS) || !IS_ENABLED(CONFIG_CRYPTO_AES_ARM64_BS)
 MODULE_ALIAS_CRYPTO("ecb(aes)");
 MODULE_ALIAS_CRYPTO("cbc(aes)");
@@ -64,13 +62,10 @@ MODULE_ALIAS_CRYPTO("ctr(aes)");
 MODULE_ALIAS_CRYPTO("xts(aes)");
 MODULE_ALIAS_CRYPTO("xctr(aes)");
 #endif
 MODULE_ALIAS_CRYPTO("cts(cbc(aes))");
 MODULE_ALIAS_CRYPTO("essiv(cbc(aes),sha256)");
-MODULE_ALIAS_CRYPTO("cmac(aes)");
-MODULE_ALIAS_CRYPTO("xcbc(aes)");
-MODULE_ALIAS_CRYPTO("cbcmac(aes)");
 
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_IMPORT_NS("CRYPTO_INTERNAL");
 MODULE_LICENSE("GPL v2");
 
@@ -82,19 +77,10 @@ struct crypto_aes_xts_ctx {
 struct crypto_aes_essiv_cbc_ctx {
 	struct crypto_aes_ctx key1;
 	struct crypto_aes_ctx __aligned(8) key2;
 };
 
-struct mac_tfm_ctx {
-	struct crypto_aes_ctx key;
-	u8 __aligned(8) consts[];
-};
-
-struct mac_desc_ctx {
-	u8 dg[AES_BLOCK_SIZE];
-};
-
 static int skcipher_aes_setkey(struct crypto_skcipher *tfm, const u8 *in_key,
 			       unsigned int key_len)
 {
 	struct crypto_aes_ctx *ctx = crypto_skcipher_ctx(tfm);
 
@@ -721,215 +707,18 @@ static struct skcipher_alg aes_algs[] = { {
 	.setkey		= essiv_cbc_set_key,
 	.encrypt	= essiv_cbc_encrypt,
 	.decrypt	= essiv_cbc_decrypt,
 } };
 
-static int cbcmac_setkey(struct crypto_shash *tfm, const u8 *in_key,
-			 unsigned int key_len)
-{
-	struct mac_tfm_ctx *ctx = crypto_shash_ctx(tfm);
-
-	return aes_expandkey(&ctx->key, in_key, key_len);
-}
-
-static void cmac_gf128_mul_by_x(be128 *y, const be128 *x)
-{
-	u64 a = be64_to_cpu(x->a);
-	u64 b = be64_to_cpu(x->b);
-
-	y->a = cpu_to_be64((a << 1) | (b >> 63));
-	y->b = cpu_to_be64((b << 1) ^ ((a >> 63) ? 0x87 : 0));
-}
-
-static int cmac_setkey(struct crypto_shash *tfm, const u8 *in_key,
-		       unsigned int key_len)
-{
-	struct mac_tfm_ctx *ctx = crypto_shash_ctx(tfm);
-	be128 *consts = (be128 *)ctx->consts;
-	int rounds = 6 + key_len / 4;
-	int err;
-
-	err = cbcmac_setkey(tfm, in_key, key_len);
-	if (err)
-		return err;
-
-	/* encrypt the zero vector */
-	scoped_ksimd()
-		aes_ecb_encrypt(ctx->consts, (u8[AES_BLOCK_SIZE]){},
-				ctx->key.key_enc, rounds, 1);
-
-	cmac_gf128_mul_by_x(consts, consts);
-	cmac_gf128_mul_by_x(consts + 1, consts);
-
-	return 0;
-}
-
-static int xcbc_setkey(struct crypto_shash *tfm, const u8 *in_key,
-		       unsigned int key_len)
-{
-	static u8 const ks[3][AES_BLOCK_SIZE] = {
-		{ [0 ... AES_BLOCK_SIZE - 1] = 0x1 },
-		{ [0 ... AES_BLOCK_SIZE - 1] = 0x2 },
-		{ [0 ... AES_BLOCK_SIZE - 1] = 0x3 },
-	};
-
-	struct mac_tfm_ctx *ctx = crypto_shash_ctx(tfm);
-	int rounds = 6 + key_len / 4;
-	u8 key[AES_BLOCK_SIZE];
-	int err;
-
-	err = cbcmac_setkey(tfm, in_key, key_len);
-	if (err)
-		return err;
-
-	scoped_ksimd() {
-		aes_ecb_encrypt(key, ks[0], ctx->key.key_enc, rounds, 1);
-		aes_ecb_encrypt(ctx->consts, ks[1], ctx->key.key_enc, rounds, 2);
-	}
-
-	return cbcmac_setkey(tfm, key, sizeof(key));
-}
-
-static int mac_init(struct shash_desc *desc)
-{
-	struct mac_desc_ctx *ctx = shash_desc_ctx(desc);
-
-	memset(ctx->dg, 0, AES_BLOCK_SIZE);
-	return 0;
-}
-
-static void mac_do_update(struct crypto_aes_ctx *ctx, u8 const in[], int blocks,
-			  u8 dg[], int enc_before)
-{
-	int rounds = 6 + ctx->key_length / 4;
-	int rem;
-
-	do {
-		scoped_ksimd()
-			rem = aes_mac_update(in, ctx->key_enc, rounds, blocks,
-					     dg, enc_before, !enc_before);
-		in += (blocks - rem) * AES_BLOCK_SIZE;
-		blocks = rem;
-	} while (blocks);
-}
-
-static int mac_update(struct shash_desc *desc, const u8 *p, unsigned int len)
-{
-	struct mac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
-	struct mac_desc_ctx *ctx = shash_desc_ctx(desc);
-	int blocks = len / AES_BLOCK_SIZE;
-
-	len %= AES_BLOCK_SIZE;
-	mac_do_update(&tctx->key, p, blocks, ctx->dg, 0);
-	return len;
-}
-
-static int cbcmac_finup(struct shash_desc *desc, const u8 *src,
-			unsigned int len, u8 *out)
-{
-	struct mac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
-	struct mac_desc_ctx *ctx = shash_desc_ctx(desc);
-
-	if (len) {
-		crypto_xor(ctx->dg, src, len);
-		mac_do_update(&tctx->key, NULL, 0, ctx->dg, 1);
-	}
-	memcpy(out, ctx->dg, AES_BLOCK_SIZE);
-	return 0;
-}
-
-static int cmac_finup(struct shash_desc *desc, const u8 *src, unsigned int len,
-		      u8 *out)
-{
-	struct mac_tfm_ctx *tctx = crypto_shash_ctx(desc->tfm);
-	struct mac_desc_ctx *ctx = shash_desc_ctx(desc);
-	u8 *consts = tctx->consts;
-
-	crypto_xor(ctx->dg, src, len);
-	if (len != AES_BLOCK_SIZE) {
-		ctx->dg[len] ^= 0x80;
-		consts += AES_BLOCK_SIZE;
-	}
-	mac_do_update(&tctx->key, consts, 1, ctx->dg, 0);
-	memcpy(out, ctx->dg, AES_BLOCK_SIZE);
-	return 0;
-}
-
-static struct shash_alg mac_algs[] = { {
-	.base.cra_name		= "cmac(aes)",
-	.base.cra_driver_name	= "cmac-aes-" MODE,
-	.base.cra_priority	= PRIO,
-	.base.cra_flags		= CRYPTO_AHASH_ALG_BLOCK_ONLY |
-				  CRYPTO_AHASH_ALG_FINAL_NONZERO,
-	.base.cra_blocksize	= AES_BLOCK_SIZE,
-	.base.cra_ctxsize	= sizeof(struct mac_tfm_ctx) +
-				  2 * AES_BLOCK_SIZE,
-	.base.cra_module	= THIS_MODULE,
-
-	.digestsize		= AES_BLOCK_SIZE,
-	.init			= mac_init,
-	.update			= mac_update,
-	.finup			= cmac_finup,
-	.setkey			= cmac_setkey,
-	.descsize		= sizeof(struct mac_desc_ctx),
-}, {
-	.base.cra_name		= "xcbc(aes)",
-	.base.cra_driver_name	= "xcbc-aes-" MODE,
-	.base.cra_priority	= PRIO,
-	.base.cra_flags		= CRYPTO_AHASH_ALG_BLOCK_ONLY |
-				  CRYPTO_AHASH_ALG_FINAL_NONZERO,
-	.base.cra_blocksize	= AES_BLOCK_SIZE,
-	.base.cra_ctxsize	= sizeof(struct mac_tfm_ctx) +
-				  2 * AES_BLOCK_SIZE,
-	.base.cra_module	= THIS_MODULE,
-
-	.digestsize		= AES_BLOCK_SIZE,
-	.init			= mac_init,
-	.update			= mac_update,
-	.finup			= cmac_finup,
-	.setkey			= xcbc_setkey,
-	.descsize		= sizeof(struct mac_desc_ctx),
-}, {
-	.base.cra_name		= "cbcmac(aes)",
-	.base.cra_driver_name	= "cbcmac-aes-" MODE,
-	.base.cra_priority	= PRIO,
-	.base.cra_flags		= CRYPTO_AHASH_ALG_BLOCK_ONLY,
-	.base.cra_blocksize	= AES_BLOCK_SIZE,
-	.base.cra_ctxsize	= sizeof(struct mac_tfm_ctx),
-	.base.cra_module	= THIS_MODULE,
-
-	.digestsize		= AES_BLOCK_SIZE,
-	.init			= mac_init,
-	.update			= mac_update,
-	.finup			= cbcmac_finup,
-	.setkey			= cbcmac_setkey,
-	.descsize		= sizeof(struct mac_desc_ctx),
-} };
-
 static void aes_exit(void)
 {
-	crypto_unregister_shashes(mac_algs, ARRAY_SIZE(mac_algs));
 	crypto_unregister_skciphers(aes_algs, ARRAY_SIZE(aes_algs));
 }
 
 static int __init aes_init(void)
 {
-	int err;
-
-	err = crypto_register_skciphers(aes_algs, ARRAY_SIZE(aes_algs));
-	if (err)
-		return err;
-
-	err = crypto_register_shashes(mac_algs, ARRAY_SIZE(mac_algs));
-	if (err)
-		goto unregister_ciphers;
-
-	return 0;
-
-unregister_ciphers:
-	crypto_unregister_skciphers(aes_algs, ARRAY_SIZE(aes_algs));
-	return err;
+	return crypto_register_skciphers(aes_algs, ARRAY_SIZE(aes_algs));
 }
 
 #ifdef USE_V8_CRYPTO_EXTENSIONS
 module_cpu_feature_match(AES, aes_init);
 #else
diff --git a/include/crypto/aes.h b/include/crypto/aes.h
index 91bf4667d3e9..3feb4105c2a2 100644
--- a/include/crypto/aes.h
+++ b/include/crypto/aes.h
@@ -198,13 +198,10 @@ asmlinkage void neon_aes_essiv_cbc_encrypt(u8 out[], u8 const in[],
 					   u32 const rk2[]);
 asmlinkage void neon_aes_essiv_cbc_decrypt(u8 out[], u8 const in[],
 					   u32 const rk1[], int rounds,
 					   int blocks, u8 iv[],
 					   u32 const rk2[]);
-asmlinkage int neon_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
-				   int blocks, u8 dg[], int enc_before,
-				   int enc_after);
 
 asmlinkage void ce_aes_ecb_encrypt(u8 out[], u8 const in[], u32 const rk[],
 				   int rounds, int blocks);
 asmlinkage void ce_aes_ecb_decrypt(u8 out[], u8 const in[], u32 const rk[],
 				   int rounds, int blocks);
@@ -231,13 +228,13 @@ asmlinkage void ce_aes_essiv_cbc_encrypt(u8 out[], u8 const in[],
 					 u32 const rk1[], int rounds,
 					 int blocks, u8 iv[], u32 const rk2[]);
 asmlinkage void ce_aes_essiv_cbc_decrypt(u8 out[], u8 const in[],
 					 u32 const rk1[], int rounds,
 					 int blocks, u8 iv[], u32 const rk2[]);
-asmlinkage int ce_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
-				 int blocks, u8 dg[], int enc_before,
-				 int enc_after);
+asmlinkage size_t ce_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
+				    size_t blocks, u8 dg[], int enc_before,
+				    int enc_after);
 #elif defined(CONFIG_PPC)
 void ppc_expand_key_128(u32 *key_enc, const u8 *key);
 void ppc_expand_key_192(u32 *key_enc, const u8 *key);
 void ppc_expand_key_256(u32 *key_enc, const u8 *key);
 void ppc_generate_decrypt_key(u32 *key_dec, u32 *key_enc, unsigned int key_len);
diff --git a/lib/crypto/arm64/aes-modes.S b/lib/crypto/arm64/aes-modes.S
index e793478f37c1..fb1332108986 100644
--- a/lib/crypto/arm64/aes-modes.S
+++ b/lib/crypto/arm64/aes-modes.S
@@ -813,54 +813,57 @@ AES_FUNC_START(aes_xts_decrypt)
 	st1		{v2.16b}, [x4]			/* overlapping stores */
 	mov		w4, wzr
 	b		.Lxtsdecctsout
 AES_FUNC_END(aes_xts_decrypt)
 
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC_MACS)
 	/*
-	 * aes_mac_update(u8 const in[], u32 const rk[], int rounds,
-	 *		  int blocks, u8 dg[], int enc_before, int enc_after)
+	 * size_t aes_mac_update(u8 const in[], u32 const rk[], int rounds,
+	 *			 size_t blocks, u8 dg[], int enc_before,
+	 *			 int enc_after);
 	 */
 AES_FUNC_START(aes_mac_update)
 	ld1		{v0.16b}, [x4]			/* get dg */
 	enc_prepare	w2, x1, x7
 	cbz		w5, .Lmacloop4x
 
 	encrypt_block	v0, w2, x1, x7, w8
 
 .Lmacloop4x:
-	subs		w3, w3, #4
+	subs		x3, x3, #4
 	bmi		.Lmac1x
 	ld1		{v1.16b-v4.16b}, [x0], #64	/* get next pt block */
 	eor		v0.16b, v0.16b, v1.16b		/* ..and xor with dg */
 	encrypt_block	v0, w2, x1, x7, w8
 	eor		v0.16b, v0.16b, v2.16b
 	encrypt_block	v0, w2, x1, x7, w8
 	eor		v0.16b, v0.16b, v3.16b
 	encrypt_block	v0, w2, x1, x7, w8
 	eor		v0.16b, v0.16b, v4.16b
-	cmp		w3, wzr
+	cmp		x3, xzr
 	csinv		w5, w6, wzr, eq
 	cbz		w5, .Lmacout
 	encrypt_block	v0, w2, x1, x7, w8
 	st1		{v0.16b}, [x4]			/* return dg */
 	cond_yield	.Lmacout, x7, x8
 	b		.Lmacloop4x
 .Lmac1x:
-	add		w3, w3, #4
+	add		x3, x3, #4
 .Lmacloop:
-	cbz		w3, .Lmacout
+	cbz		x3, .Lmacout
 	ld1		{v1.16b}, [x0], #16		/* get next pt block */
 	eor		v0.16b, v0.16b, v1.16b		/* ..and xor with dg */
 
-	subs		w3, w3, #1
+	subs		x3, x3, #1
 	csinv		w5, w6, wzr, eq
 	cbz		w5, .Lmacout
 
 .Lmacenc:
 	encrypt_block	v0, w2, x1, x7, w8
 	b		.Lmacloop
 
 .Lmacout:
 	st1		{v0.16b}, [x4]			/* return dg */
-	mov		w0, w3
+	mov		x0, x3
 	ret
 AES_FUNC_END(aes_mac_update)
+#endif /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */
diff --git a/lib/crypto/arm64/aes.h b/lib/crypto/arm64/aes.h
index 69f465c668f0..78e7b4e5f120 100644
--- a/lib/crypto/arm64/aes.h
+++ b/lib/crypto/arm64/aes.h
@@ -9,10 +9,11 @@
 #include <asm/neon.h>
 #include <asm/simd.h>
 #include <linux/unaligned.h>
 #include <linux/cpufeature.h>
 
+static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_neon);
 static __ro_after_init DEFINE_STATIC_KEY_FALSE(have_aes);
 
 struct aes_block {
 	u8 b[AES_BLOCK_SIZE];
 };
@@ -26,10 +27,13 @@ asmlinkage void __aes_ce_encrypt(const u32 rk[], u8 out[AES_BLOCK_SIZE],
 asmlinkage void __aes_ce_decrypt(const u32 inv_rk[], u8 out[AES_BLOCK_SIZE],
 				 const u8 in[AES_BLOCK_SIZE], int rounds);
 asmlinkage u32 __aes_ce_sub(u32 l);
 asmlinkage void __aes_ce_invert(struct aes_block *out,
 				const struct aes_block *in);
+asmlinkage size_t neon_aes_mac_update(u8 const in[], u32 const rk[], int rounds,
+				      size_t blocks, u8 dg[], int enc_before,
+				      int enc_after);
 
 /*
  * Expand an AES key using the crypto extensions if supported and usable or
  * generic code otherwise.  The expanded key format is compatible between the
  * two cases.  The outputs are @rndkeys (required) and @inv_rndkeys (optional).
@@ -137,11 +141,10 @@ EXPORT_SYMBOL_NS_GPL(neon_aes_ctr_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(neon_aes_xctr_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(neon_aes_xts_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(neon_aes_xts_decrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(neon_aes_essiv_cbc_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(neon_aes_essiv_cbc_decrypt, "CRYPTO_INTERNAL");
-EXPORT_SYMBOL_NS_GPL(neon_aes_mac_update, "CRYPTO_INTERNAL");
 
 EXPORT_SYMBOL_NS_GPL(ce_aes_ecb_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(ce_aes_ecb_decrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(ce_aes_cbc_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(ce_aes_cbc_decrypt, "CRYPTO_INTERNAL");
@@ -151,10 +154,12 @@ EXPORT_SYMBOL_NS_GPL(ce_aes_ctr_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(ce_aes_xctr_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(ce_aes_xts_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(ce_aes_xts_decrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(ce_aes_essiv_cbc_encrypt, "CRYPTO_INTERNAL");
 EXPORT_SYMBOL_NS_GPL(ce_aes_essiv_cbc_decrypt, "CRYPTO_INTERNAL");
+#endif
+#if IS_MODULE(CONFIG_CRYPTO_AES_ARM64_CE_CCM)
 EXPORT_SYMBOL_NS_GPL(ce_aes_mac_update, "CRYPTO_INTERNAL");
 #endif
 
 static void aes_encrypt_arch(const struct aes_enckey *key,
 			     u8 out[AES_BLOCK_SIZE],
@@ -182,13 +187,50 @@ static void aes_decrypt_arch(const struct aes_key *key,
 		__aes_arm64_decrypt(key->inv_k.inv_rndkeys, out, in,
 				    key->nrounds);
 	}
 }
 
+#if IS_ENABLED(CONFIG_CRYPTO_LIB_AES_CBC_MACS)
+#define aes_cbcmac_blocks_arch aes_cbcmac_blocks_arch
+static bool aes_cbcmac_blocks_arch(u8 h[AES_BLOCK_SIZE],
+				   const struct aes_enckey *key, const u8 *data,
+				   size_t nblocks, bool enc_before,
+				   bool enc_after)
+{
+	if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) &&
+	    static_branch_likely(&have_neon) && likely(may_use_simd())) {
+		do {
+			size_t rem;
+
+			scoped_ksimd() {
+				if (static_branch_likely(&have_aes))
+					rem = ce_aes_mac_update(
+						data, key->k.rndkeys,
+						key->nrounds, nblocks, h,
+						enc_before, enc_after);
+				else
+					rem = neon_aes_mac_update(
+						data, key->k.rndkeys,
+						key->nrounds, nblocks, h,
+						enc_before, enc_after);
+			}
+			data += (nblocks - rem) * AES_BLOCK_SIZE;
+			nblocks = rem;
+			enc_before = false;
+		} while (nblocks);
+		return true;
+	}
+	return false;
+}
+#endif /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */
+
 #ifdef CONFIG_KERNEL_MODE_NEON
 #define aes_mod_init_arch aes_mod_init_arch
 static void aes_mod_init_arch(void)
 {
-	if (cpu_have_named_feature(AES))
-		static_branch_enable(&have_aes);
+	if (cpu_have_named_feature(ASIMD)) {
+		static_branch_enable(&have_neon);
+		if (cpu_have_named_feature(AES))
+			static_branch_enable(&have_aes);
+	}
 }
 #endif /* CONFIG_KERNEL_MODE_NEON */
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 06/15] lib/crypto: tests: Add KUnit tests for CBC-based MACs
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (4 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 05/15] lib/crypto: arm64/aes: Migrate optimized CBC-based MACs into library Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:34 ` [PATCH 07/15] lib/crypto: aes: Add FIPS self-test for CMAC Eric Biggers
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Add a KUnit test suite for the AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC
library functions.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 lib/crypto/tests/Kconfig              |  10 ++
 lib/crypto/tests/Makefile             |   1 +
 lib/crypto/tests/aes-cmac-testvecs.h  | 181 ++++++++++++++++++++
 lib/crypto/tests/aes_cbc_macs_kunit.c | 228 ++++++++++++++++++++++++++
 scripts/crypto/gen-hash-testvecs.py   |  31 +++-
 5 files changed, 448 insertions(+), 3 deletions(-)
 create mode 100644 lib/crypto/tests/aes-cmac-testvecs.h
 create mode 100644 lib/crypto/tests/aes_cbc_macs_kunit.c

diff --git a/lib/crypto/tests/Kconfig b/lib/crypto/tests/Kconfig
index 4970463ea0aa..2433b988bc5b 100644
--- a/lib/crypto/tests/Kconfig
+++ b/lib/crypto/tests/Kconfig
@@ -1,7 +1,17 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
+config CRYPTO_LIB_AES_CBC_MACS_KUNIT_TEST
+	tristate "KUnit tests for AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
+	select CRYPTO_LIB_BENCHMARK_VISIBLE
+	select CRYPTO_LIB_AES_CBC_MACS
+	help
+	  KUnit tests for the AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC message
+	  authentication codes.
+
 config CRYPTO_LIB_BLAKE2B_KUNIT_TEST
 	tristate "KUnit tests for BLAKE2b" if !KUNIT_ALL_TESTS
 	depends on KUNIT
 	default KUNIT_ALL_TESTS || CRYPTO_SELFTESTS
 	select CRYPTO_LIB_BENCHMARK_VISIBLE
diff --git a/lib/crypto/tests/Makefile b/lib/crypto/tests/Makefile
index f4262379f56c..f864e0ffbee4 100644
--- a/lib/crypto/tests/Makefile
+++ b/lib/crypto/tests/Makefile
@@ -1,7 +1,8 @@
 # SPDX-License-Identifier: GPL-2.0-or-later
 
+obj-$(CONFIG_CRYPTO_LIB_AES_CBC_MACS_KUNIT_TEST) += aes_cbc_macs_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_BLAKE2B_KUNIT_TEST) += blake2b_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_BLAKE2S_KUNIT_TEST) += blake2s_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_CURVE25519_KUNIT_TEST) += curve25519_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_MD5_KUNIT_TEST) += md5_kunit.o
 obj-$(CONFIG_CRYPTO_LIB_MLDSA_KUNIT_TEST) += mldsa_kunit.o
diff --git a/lib/crypto/tests/aes-cmac-testvecs.h b/lib/crypto/tests/aes-cmac-testvecs.h
new file mode 100644
index 000000000000..8177862ba5a3
--- /dev/null
+++ b/lib/crypto/tests/aes-cmac-testvecs.h
@@ -0,0 +1,181 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/* This file was generated by: ./scripts/crypto/gen-hash-testvecs.py aes-cmac */
+
+static const struct {
+	size_t data_len;
+	u8 digest[AES_BLOCK_SIZE];
+} hash_testvecs[] = {
+	{
+		.data_len = 0,
+		.digest = {
+			0x9a, 0xeb, 0x94, 0xc1, 0xe9, 0xc1, 0x57, 0x49,
+			0x7e, 0xba, 0x66, 0x47, 0x9f, 0x03, 0x2c, 0x5b,
+		},
+	},
+	{
+		.data_len = 1,
+		.digest = {
+			0x52, 0xef, 0x65, 0xda, 0x7b, 0x92, 0x0c, 0x0f,
+			0xdd, 0xd6, 0xb9, 0x68, 0x3f, 0xcc, 0x5f, 0xea,
+		},
+	},
+	{
+		.data_len = 2,
+		.digest = {
+			0xc3, 0x95, 0x15, 0xea, 0x16, 0x33, 0xbe, 0x5a,
+			0xd4, 0x2c, 0x25, 0x06, 0x15, 0xc6, 0x10, 0x19,
+		},
+	},
+	{
+		.data_len = 3,
+		.digest = {
+			0x82, 0x41, 0x41, 0xd5, 0x33, 0x26, 0x0b, 0xb6,
+			0xc8, 0xf7, 0x8d, 0x76, 0x8a, 0xfc, 0x0e, 0xe4,
+		},
+	},
+	{
+		.data_len = 16,
+		.digest = {
+			0x94, 0x09, 0x80, 0x07, 0xba, 0x7c, 0xed, 0xd2,
+			0x74, 0x72, 0x30, 0x26, 0xb5, 0x11, 0x64, 0xc1,
+		},
+	},
+	{
+		.data_len = 32,
+		.digest = {
+			0xeb, 0xcf, 0x1e, 0x67, 0x21, 0x64, 0x93, 0xa0,
+			0xea, 0xc4, 0xb9, 0x2d, 0x55, 0xc8, 0xac, 0x99,
+		},
+	},
+	{
+		.data_len = 48,
+		.digest = {
+			0xd0, 0xd6, 0xdb, 0xe2, 0x45, 0x98, 0x6a, 0x7a,
+			0x5f, 0xd6, 0xcd, 0x9d, 0x12, 0x26, 0x20, 0x87,
+		},
+	},
+	{
+		.data_len = 49,
+		.digest = {
+			0x63, 0x25, 0x3c, 0xe2, 0x2a, 0xfa, 0xe3, 0x1e,
+			0x54, 0x10, 0x18, 0x28, 0xc6, 0xb8, 0xcb, 0x58,
+		},
+	},
+	{
+		.data_len = 63,
+		.digest = {
+			0x4d, 0xab, 0xae, 0x99, 0x90, 0x13, 0x3f, 0x4f,
+			0x42, 0x0f, 0x19, 0x94, 0xa2, 0x52, 0xfd, 0xaf,
+		},
+	},
+	{
+		.data_len = 64,
+		.digest = {
+			0xf7, 0x49, 0xb9, 0xa7, 0xf9, 0x3e, 0xa0, 0xca,
+			0xb2, 0x6c, 0xd7, 0x87, 0x7d, 0x1e, 0xd2, 0xcb,
+		},
+	},
+	{
+		.data_len = 65,
+		.digest = {
+			0x27, 0x2c, 0xb7, 0xc8, 0xdd, 0x26, 0xa9, 0xfe,
+			0x37, 0x64, 0x84, 0x38, 0xa5, 0x7e, 0xbc, 0x04,
+		},
+	},
+	{
+		.data_len = 127,
+		.digest = {
+			0xfd, 0x1f, 0x01, 0xa4, 0xea, 0x9b, 0xbd, 0xef,
+			0x09, 0x97, 0x57, 0x60, 0x95, 0x23, 0xcc, 0x71,
+		},
+	},
+	{
+		.data_len = 128,
+		.digest = {
+			0x28, 0x21, 0xee, 0x56, 0x9f, 0x38, 0xd6, 0x0e,
+			0xe3, 0x22, 0x06, 0x20, 0xad, 0xd8, 0x33, 0x74,
+		},
+	},
+	{
+		.data_len = 129,
+		.digest = {
+			0x07, 0x28, 0x4a, 0x2a, 0xd3, 0x85, 0xa6, 0x87,
+			0x5c, 0x01, 0x8c, 0xb9, 0xd3, 0x4b, 0xce, 0x20,
+		},
+	},
+	{
+		.data_len = 256,
+		.digest = {
+			0xe6, 0x12, 0x25, 0x6b, 0xf9, 0x69, 0x4d, 0x5a,
+			0x1a, 0xb0, 0xe6, 0x11, 0x46, 0x24, 0x08, 0xdf,
+		},
+	},
+	{
+		.data_len = 511,
+		.digest = {
+			0xce, 0x28, 0x1f, 0x14, 0xb9, 0xcc, 0x7e, 0x1f,
+			0xb5, 0x13, 0x2b, 0x45, 0x04, 0x54, 0xe9, 0x5f,
+		},
+	},
+	{
+		.data_len = 513,
+		.digest = {
+			0x63, 0x12, 0xbd, 0x85, 0x60, 0x1b, 0x99, 0x7e,
+			0x0a, 0xf7, 0x0f, 0xc1, 0xb5, 0x66, 0xf8, 0x9a,
+		},
+	},
+	{
+		.data_len = 1000,
+		.digest = {
+			0xbd, 0x49, 0x5e, 0x21, 0xc6, 0x58, 0x74, 0x6b,
+			0x21, 0xc2, 0x62, 0x6a, 0x15, 0xca, 0x1d, 0x8a,
+		},
+	},
+	{
+		.data_len = 3333,
+		.digest = {
+			0xfe, 0x6b, 0xfa, 0xfc, 0x4c, 0x0b, 0x63, 0x0d,
+			0x41, 0x7f, 0xa9, 0xd8, 0xba, 0xe3, 0xce, 0xce,
+		},
+	},
+	{
+		.data_len = 4096,
+		.digest = {
+			0x41, 0x7c, 0xbc, 0x2e, 0x2f, 0xff, 0xdf, 0x09,
+			0x31, 0xc5, 0x79, 0x0a, 0x1d, 0x6e, 0x46, 0xec,
+		},
+	},
+	{
+		.data_len = 4128,
+		.digest = {
+			0x6a, 0x9d, 0x86, 0xa8, 0xab, 0xa5, 0xc1, 0xc5,
+			0x0d, 0x54, 0xf3, 0x51, 0x10, 0x46, 0x25, 0x5a,
+		},
+	},
+	{
+		.data_len = 4160,
+		.digest = {
+			0x4c, 0x50, 0xff, 0x2a, 0xe9, 0xca, 0x9e, 0x07,
+			0x8a, 0x86, 0x67, 0x5e, 0xe5, 0x0a, 0xfd, 0x69,
+		},
+	},
+	{
+		.data_len = 4224,
+		.digest = {
+			0x3a, 0xfa, 0x80, 0x9d, 0x80, 0xe3, 0x1e, 0x95,
+			0x53, 0x93, 0x39, 0x17, 0xd3, 0xda, 0x49, 0x15,
+		},
+	},
+	{
+		.data_len = 16384,
+		.digest = {
+			0x48, 0xf4, 0x4f, 0x2d, 0x5d, 0xf2, 0x02, 0xcf,
+			0x51, 0x3c, 0x1b, 0x12, 0x80, 0x8f, 0xb0, 0xd6,
+		},
+	},
+};
+
+static const u8 hash_testvec_consolidated[AES_BLOCK_SIZE] = {
+	0x41, 0xad, 0x25, 0xa1, 0xeb, 0xce, 0x6b, 0x9c,
+	0x06, 0xdf, 0x47, 0xc4, 0x3a, 0x59, 0x50, 0x07,
+};
diff --git a/lib/crypto/tests/aes_cbc_macs_kunit.c b/lib/crypto/tests/aes_cbc_macs_kunit.c
new file mode 100644
index 000000000000..ae3745212f03
--- /dev/null
+++ b/lib/crypto/tests/aes_cbc_macs_kunit.c
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2026 Google LLC
+ */
+#include <crypto/aes-cbc-macs.h>
+#include "aes-cmac-testvecs.h"
+
+/*
+ * A fixed key used when presenting AES-CMAC as an unkeyed hash function in
+ * order to reuse hash-test-template.h.  At the beginning of the test suite,
+ * this is initialized to a key prepared from bytes generated from a fixed seed.
+ */
+static struct aes_cmac_key test_key;
+
+static void aes_cmac_init_withtestkey(struct aes_cmac_ctx *ctx)
+{
+	aes_cmac_init(ctx, &test_key);
+}
+
+static void aes_cmac_withtestkey(const u8 *data, size_t data_len,
+				 u8 out[AES_BLOCK_SIZE])
+{
+	aes_cmac(&test_key, data, data_len, out);
+}
+
+#define HASH aes_cmac_withtestkey
+#define HASH_CTX aes_cmac_ctx
+#define HASH_SIZE AES_BLOCK_SIZE
+#define HASH_INIT aes_cmac_init_withtestkey
+#define HASH_UPDATE aes_cmac_update
+#define HASH_FINAL aes_cmac_final
+#include "hash-test-template.h"
+
+static int aes_cbc_macs_suite_init(struct kunit_suite *suite)
+{
+	u8 raw_key[AES_KEYSIZE_256];
+	int err;
+
+	rand_bytes_seeded_from_len(raw_key, sizeof(raw_key));
+	err = aes_cmac_preparekey(&test_key, raw_key, sizeof(raw_key));
+	if (err)
+		return err;
+	return hash_suite_init(suite);
+}
+
+static void aes_cbc_macs_suite_exit(struct kunit_suite *suite)
+{
+	hash_suite_exit(suite);
+}
+
+/* Verify compatibility of the AES-CMAC implementation with RFC 4493. */
+static void test_aes_cmac_rfc4493(struct kunit *test)
+{
+	static const u8 raw_key[AES_KEYSIZE_128] = {
+		0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+		0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c,
+	};
+	static const struct {
+		size_t data_len;
+		const u8 data[40];
+		const u8 mac[AES_BLOCK_SIZE];
+	} testvecs[] = {
+		{
+			/* Example 1 from RFC 4493 */
+			.data_len = 0,
+			.mac = {
+				0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+				0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46,
+			},
+
+		},
+		{
+			/* Example 2 from RFC 4493 */
+			.data = {
+				0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+				0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+			},
+			.data_len = 16,
+			.mac = {
+				0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+				0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c,
+			},
+		},
+		{
+			/* Example 3 from RFC 4493 */
+			.data = {
+				0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+				0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+				0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+				0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+				0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+			},
+			.data_len = 40,
+			.mac = {
+				0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+				0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27,
+			},
+		},
+	};
+	struct aes_cmac_key key;
+	int err;
+
+	err = aes_cmac_preparekey(&key, raw_key, sizeof(raw_key));
+	KUNIT_ASSERT_EQ(test, err, 0);
+
+	for (size_t i = 0; i < ARRAY_SIZE(testvecs); i++) {
+		u8 mac[AES_BLOCK_SIZE];
+
+		aes_cmac(&key, testvecs[i].data, testvecs[i].data_len, mac);
+		KUNIT_ASSERT_MEMEQ(test, mac, testvecs[i].mac, AES_BLOCK_SIZE);
+	}
+}
+
+/*
+ * Verify compatibility of the AES-XCBC-MAC implementation with RFC 3566.
+ *
+ * Additional AES-XCBC-MAC tests are not necessary, since the AES-XCBC-MAC
+ * implementation is well covered by the AES-CMAC tests already.  Only the key
+ * preparation function differs; the rest of the code is shared.
+ */
+static void test_aes_xcbcmac_rfc3566(struct kunit *test)
+{
+	struct aes_cmac_key key;
+	/* AES-XCBC-MAC Test Case #4 from RFC 3566 */
+	static const u8 raw_key[AES_KEYSIZE_128] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+		0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+	};
+	static const u8 message[20] = {
+		0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
+		0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+	};
+	static const u8 expected_mac[AES_BLOCK_SIZE] = {
+		0x47, 0xf5, 0x1b, 0x45, 0x64, 0x96, 0x62, 0x15,
+		0xb8, 0x98, 0x5c, 0x63, 0x05, 0x5e, 0xd3, 0x08,
+	};
+	u8 actual_mac[AES_BLOCK_SIZE];
+
+	aes_xcbcmac_preparekey(&key, raw_key);
+	aes_cmac(&key, message, sizeof(message), actual_mac);
+	KUNIT_ASSERT_MEMEQ(test, actual_mac, expected_mac, AES_BLOCK_SIZE);
+}
+
+static void test_aes_cbcmac_rfc3610(struct kunit *test)
+{
+	/*
+	 * The following AES-CBC-MAC test vector is extracted from RFC 3610
+	 * Packet Vector #11.  It required some rearrangement to get the actual
+	 * input to AES-CBC-MAC from the values given.
+	 */
+	static const u8 raw_key[AES_KEYSIZE_128] = {
+		0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+		0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+	};
+	const size_t unpadded_data_len = 52;
+	static const u8 data[64] = {
+		/* clang-format off */
+		/* CCM header */
+		0x61, 0x00, 0x00, 0x00, 0x0d, 0x0c, 0x0b, 0x0a,
+		0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x14,
+		/* CCM additional authentication blocks */
+		0x00, 0x0c, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
+		0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x00, 0x00,
+		/* CCM message blocks */
+		0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+		0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b,
+		0x1c, 0x1d, 0x1e, 0x1f, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		/* clang-format on */
+	};
+	static const u8 expected_mac[AES_BLOCK_SIZE] = {
+		0x6b, 0x5e, 0x24, 0x34, 0x12, 0xcc, 0xc2, 0xad,
+		0x6f, 0x1b, 0x11, 0xc3, 0xa1, 0xa9, 0xd8, 0xbc,
+	};
+	struct aes_enckey key;
+	struct aes_cbcmac_ctx ctx;
+	u8 actual_mac[AES_BLOCK_SIZE];
+	int err;
+
+	err = aes_prepareenckey(&key, raw_key, sizeof(raw_key));
+	KUNIT_ASSERT_EQ(test, err, 0);
+
+	/*
+	 * Trailing zeroes should not affect the CBC-MAC value, up to the next
+	 * AES block boundary.
+	 */
+	for (size_t data_len = unpadded_data_len; data_len <= sizeof(data);
+	     data_len++) {
+		aes_cbcmac_init(&ctx, &key);
+		aes_cbcmac_update(&ctx, data, data_len);
+		aes_cbcmac_final(&ctx, actual_mac);
+		KUNIT_ASSERT_MEMEQ(test, actual_mac, expected_mac,
+				   AES_BLOCK_SIZE);
+
+		/* Incremental computations should produce the same result. */
+		for (size_t part1_len = 0; part1_len <= data_len; part1_len++) {
+			aes_cbcmac_init(&ctx, &key);
+			aes_cbcmac_update(&ctx, data, part1_len);
+			aes_cbcmac_update(&ctx, &data[part1_len],
+					  data_len - part1_len);
+			aes_cbcmac_final(&ctx, actual_mac);
+			KUNIT_ASSERT_MEMEQ(test, actual_mac, expected_mac,
+					   AES_BLOCK_SIZE);
+		}
+	}
+}
+
+static struct kunit_case aes_cbc_macs_test_cases[] = {
+	HASH_KUNIT_CASES,
+	KUNIT_CASE(test_aes_cmac_rfc4493),
+	KUNIT_CASE(test_aes_xcbcmac_rfc3566),
+	KUNIT_CASE(test_aes_cbcmac_rfc3610),
+	KUNIT_CASE(benchmark_hash),
+	{},
+};
+
+static struct kunit_suite aes_cbc_macs_test_suite = {
+	.name = "aes_cbc_macs",
+	.test_cases = aes_cbc_macs_test_cases,
+	.suite_init = aes_cbc_macs_suite_init,
+	.suite_exit = aes_cbc_macs_suite_exit,
+};
+kunit_test_suite(aes_cbc_macs_test_suite);
+
+MODULE_DESCRIPTION(
+	"KUnit tests and benchmark for AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC");
+MODULE_IMPORT_NS("CRYPTO_INTERNAL");
+MODULE_LICENSE("GPL");
diff --git a/scripts/crypto/gen-hash-testvecs.py b/scripts/crypto/gen-hash-testvecs.py
index 8eeb650fcada..34b7c48f3456 100755
--- a/scripts/crypto/gen-hash-testvecs.py
+++ b/scripts/crypto/gen-hash-testvecs.py
@@ -1,12 +1,16 @@
 #!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Script that generates test vectors for the given hash function.
 #
+# Requires that python-cryptography be installed.
+#
 # Copyright 2025 Google LLC
 
+import cryptography.hazmat.primitives.ciphers
+import cryptography.hazmat.primitives.cmac
 import hashlib
 import hmac
 import sys
 
 DATA_LENS = [0, 1, 2, 3, 16, 32, 48, 49, 63, 64, 65, 127, 128, 129, 256, 511,
@@ -22,10 +26,24 @@ def rand_bytes(length):
     for _ in range(length):
         seed = (seed * 25214903917 + 11) % 2**48
         out.append((seed >> 16) % 256)
     return bytes(out)
 
+AES_256_KEY_SIZE = 32
+
+# AES-CMAC.  Just wraps the implementation from python-cryptography.
+class AesCmac:
+    def __init__(self, key):
+        aes = cryptography.hazmat.primitives.ciphers.algorithms.AES(key)
+        self.cmac = cryptography.hazmat.primitives.cmac.CMAC(aes)
+
+    def update(self, data):
+        self.cmac.update(data)
+
+    def digest(self):
+        return self.cmac.finalize()
+
 POLY1305_KEY_SIZE = 32
 
 # A straightforward, unoptimized implementation of Poly1305.
 # Reference: https://cr.yp.to/mac/poly1305-20050329.pdf
 class Poly1305:
@@ -78,13 +96,16 @@ class Polyval:
 
     def digest(self):
         return self.acc.to_bytes(16, byteorder='little')
 
 def hash_init(alg):
+    # The keyed hash functions are assigned a fixed random key here, to present
+    # them as unkeyed hash functions.  This allows all the test cases for
+    # unkeyed hash functions to work on them.
+    if alg == 'aes-cmac':
+        return AesCmac(rand_bytes(AES_256_KEY_SIZE))
     if alg == 'poly1305':
-        # Use a fixed random key here, to present Poly1305 as an unkeyed hash.
-        # This allows all the test cases for unkeyed hashes to work on Poly1305.
         return Poly1305(rand_bytes(POLY1305_KEY_SIZE))
     if alg == 'polyval':
         return Polyval(rand_bytes(POLYVAL_BLOCK_SIZE))
     return hashlib.new(alg)
 
@@ -114,10 +135,12 @@ def print_c_struct_u8_array_field(name, value):
     print(f'\t\t.{name} = {{')
     print_bytes('\t\t\t', value, 8)
     print('\t\t},')
 
 def alg_digest_size_const(alg):
+    if alg == 'aes-cmac':
+        return 'AES_BLOCK_SIZE'
     if alg.startswith('blake2'):
         return f'{alg.upper()}_HASH_SIZE'
     return f"{alg.upper().replace('-', '_')}_DIGEST_SIZE"
 
 def gen_unkeyed_testvecs(alg):
@@ -250,11 +273,13 @@ if len(sys.argv) != 2:
     sys.exit(1)
 
 alg = sys.argv[1]
 print('/* SPDX-License-Identifier: GPL-2.0-or-later */')
 print(f'/* This file was generated by: {sys.argv[0]} {" ".join(sys.argv[1:])} */')
-if alg.startswith('blake2'):
+if alg == 'aes-cmac':
+    gen_unkeyed_testvecs(alg)
+elif alg.startswith('blake2'):
     gen_unkeyed_testvecs(alg)
     gen_additional_blake2_testvecs(alg)
 elif alg == 'nh':
     gen_nh_testvecs()
 elif alg == 'poly1305':
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 07/15] lib/crypto: aes: Add FIPS self-test for CMAC
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (5 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 06/15] lib/crypto: tests: Add KUnit tests for CBC-based MACs Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:34 ` [PATCH 08/15] smb: client: Use AES-CMAC library for SMB3 signature calculation Eric Biggers
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Add a FIPS cryptographic algorithm self-test for AES-CMAC to fulfill the
self-test requirement when this code is built into a FIPS 140
cryptographic module.  This provides parity with the traditional crypto
API, which uses crypto/testmgr.c to meet the FIPS self-test requirement.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 lib/crypto/aes.c                    | 35 ++++++++++++++++++++++++++---
 lib/crypto/fips.h                   |  5 +++++
 scripts/crypto/gen-fips-testvecs.py | 10 +++++++++
 3 files changed, 47 insertions(+), 3 deletions(-)

diff --git a/lib/crypto/aes.c b/lib/crypto/aes.c
index 39deae6105c0..ca733f15b2a8 100644
--- a/lib/crypto/aes.c
+++ b/lib/crypto/aes.c
@@ -10,10 +10,11 @@
 #include <linux/cache.h>
 #include <linux/crypto.h>
 #include <linux/export.h>
 #include <linux/module.h>
 #include <linux/unaligned.h>
+#include "fips.h"
 
 static const u8 ____cacheline_aligned aes_sbox[] = {
 	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
 	0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
 	0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
@@ -706,25 +707,53 @@ void aes_cbcmac_final(struct aes_cbcmac_ctx *ctx, u8 out[AES_BLOCK_SIZE])
 	else
 		memcpy(out, ctx->h, AES_BLOCK_SIZE);
 	memzero_explicit(ctx, sizeof(*ctx));
 }
 EXPORT_SYMBOL_NS_GPL(aes_cbcmac_final, "CRYPTO_INTERNAL");
-#endif /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */
 
-#ifdef aes_mod_init_arch
+/*
+ * FIPS cryptographic algorithm self-test for AES-CMAC.  As per the FIPS 140-3
+ * Implementation Guidance, a cryptographic algorithm self-test for at least one
+ * of AES-GCM, AES-CCM, AES-CMAC, or AES-GMAC is required if any of those modes
+ * is implemented.  This fulfills that requirement via AES-CMAC.
+ *
+ * This is just for FIPS.  The full tests are in the KUnit test suite.
+ */
+static void __init aes_cmac_fips_test(void)
+{
+	struct aes_cmac_key key;
+	u8 mac[AES_BLOCK_SIZE];
+
+	if (aes_cmac_preparekey(&key, fips_test_key, sizeof(fips_test_key)) !=
+	    0)
+		panic("aes: CMAC FIPS self-test failed (preparekey)\n");
+	aes_cmac(&key, fips_test_data, sizeof(fips_test_data), mac);
+	if (memcmp(fips_test_aes_cmac_value, mac, sizeof(mac)) != 0)
+		panic("aes: CMAC FIPS self-test failed (wrong MAC)\n");
+	memzero_explicit(&key, sizeof(key));
+}
+#else /* CONFIG_CRYPTO_LIB_AES_CBC_MACS */
+static inline void aes_cmac_fips_test(void)
+{
+}
+#endif /* !CONFIG_CRYPTO_LIB_AES_CBC_MACS */
+
 static int __init aes_mod_init(void)
 {
+#ifdef aes_mod_init_arch
 	aes_mod_init_arch();
+#endif
+	if (fips_enabled)
+		aes_cmac_fips_test();
 	return 0;
 }
 subsys_initcall(aes_mod_init);
 
 static void __exit aes_mod_exit(void)
 {
 }
 module_exit(aes_mod_exit);
-#endif
 
 MODULE_DESCRIPTION("AES block cipher");
 MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
 MODULE_AUTHOR("Eric Biggers <ebiggers@kernel.org>");
 MODULE_LICENSE("GPL v2");
diff --git a/lib/crypto/fips.h b/lib/crypto/fips.h
index 023410c2e0db..9fc49747db64 100644
--- a/lib/crypto/fips.h
+++ b/lib/crypto/fips.h
@@ -41,5 +41,10 @@ static const u8 fips_test_sha3_256_value[] __initconst __maybe_unused = {
 	0x77, 0xc4, 0x8b, 0x69, 0x70, 0x5f, 0x0a, 0xb1,
 	0xb1, 0xa5, 0x82, 0x0a, 0x22, 0x2b, 0x49, 0x31,
 	0xba, 0x9b, 0xb6, 0xaa, 0x32, 0xa7, 0x97, 0x00,
 	0x98, 0xdb, 0xff, 0xe7, 0xc6, 0xde, 0xb5, 0x82,
 };
+
+static const u8 fips_test_aes_cmac_value[] __initconst __maybe_unused = {
+	0xc5, 0x88, 0x28, 0x55, 0xd7, 0x2c, 0x00, 0xb6,
+	0x6a, 0xa7, 0xfc, 0x82, 0x90, 0x81, 0xcf, 0x18,
+};
diff --git a/scripts/crypto/gen-fips-testvecs.py b/scripts/crypto/gen-fips-testvecs.py
index db873f88619a..9f18bcb97412 100755
--- a/scripts/crypto/gen-fips-testvecs.py
+++ b/scripts/crypto/gen-fips-testvecs.py
@@ -1,12 +1,16 @@
 #!/usr/bin/env python3
 # SPDX-License-Identifier: GPL-2.0-or-later
 #
 # Script that generates lib/crypto/fips.h
 #
+# Requires that python-cryptography be installed.
+#
 # Copyright 2025 Google LLC
 
+import cryptography.hazmat.primitives.ciphers
+import cryptography.hazmat.primitives.cmac
 import hashlib
 import hmac
 
 fips_test_data = b"fips test data\0\0"
 fips_test_key = b"fips test key\0\0\0"
@@ -32,5 +36,11 @@ for alg in 'sha1', 'sha256', 'sha512':
     ctx.update(fips_test_data)
     print_static_u8_array_definition(f'fips_test_hmac_{alg}_value', ctx.digest())
 
 print_static_u8_array_definition(f'fips_test_sha3_256_value',
                                  hashlib.sha3_256(fips_test_data).digest())
+
+aes = cryptography.hazmat.primitives.ciphers.algorithms.AES(fips_test_key)
+aes_cmac = cryptography.hazmat.primitives.cmac.CMAC(aes)
+aes_cmac.update(fips_test_data)
+print_static_u8_array_definition('fips_test_aes_cmac_value',
+                                 aes_cmac.finalize())
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 08/15] smb: client: Use AES-CMAC library for SMB3 signature calculation
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (6 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 07/15] lib/crypto: aes: Add FIPS self-test for CMAC Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:34 ` [PATCH 09/15] smb: client: Remove obsolete cmac(aes) allocation Eric Biggers
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Convert smb3_calc_signature() to use the AES-CMAC library instead of a
"cmac(aes)" crypto_shash.

The result is simpler and faster code.  With the library there's no need
to allocate memory, no need to handle errors except for key preparation,
and the AES-CMAC code is accessed directly without inefficient indirect
calls and other unnecessary API overhead.

For now a "cmac(aes)" crypto_shash is still being allocated in
'struct cifs_secmech'.  Later commits will remove that, simplifying the
code even further.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 fs/smb/client/Kconfig         |  1 +
 fs/smb/client/cifsencrypt.c   | 60 ++++++++++++-----------------------
 fs/smb/client/cifsglob.h      |  2 +-
 fs/smb/client/smb2transport.c | 41 +++++-------------------
 4 files changed, 30 insertions(+), 74 deletions(-)

diff --git a/fs/smb/client/Kconfig b/fs/smb/client/Kconfig
index 17bd368574e9..64afd302202f 100644
--- a/fs/smb/client/Kconfig
+++ b/fs/smb/client/Kconfig
@@ -9,10 +9,11 @@ config CIFS
 	select CRYPTO_AEAD2
 	select CRYPTO_CCM
 	select CRYPTO_GCM
 	select CRYPTO_ECB
 	select CRYPTO_AES
+	select CRYPTO_LIB_AES_CBC_MACS
 	select CRYPTO_LIB_ARC4
 	select CRYPTO_LIB_MD5
 	select CRYPTO_LIB_SHA256
 	select CRYPTO_LIB_SHA512
 	select KEYS
diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c
index 50b7ec39053c..f39894113821 100644
--- a/fs/smb/client/cifsencrypt.c
+++ b/fs/smb/client/cifsencrypt.c
@@ -20,66 +20,49 @@
 #include <linux/random.h>
 #include <linux/highmem.h>
 #include <linux/fips.h>
 #include <linux/iov_iter.h>
 #include <crypto/aead.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/arc4.h>
 #include <crypto/md5.h>
 #include <crypto/sha2.h>
 
-static int cifs_sig_update(struct cifs_calc_sig_ctx *ctx,
-			   const u8 *data, size_t len)
+static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len,
+			    void *priv, void *priv2)
 {
-	if (ctx->md5) {
-		md5_update(ctx->md5, data, len);
-		return 0;
-	}
-	if (ctx->hmac) {
-		hmac_sha256_update(ctx->hmac, data, len);
-		return 0;
-	}
-	return crypto_shash_update(ctx->shash, data, len);
+	struct cifs_calc_sig_ctx *ctx = priv;
+
+	if (ctx->md5)
+		md5_update(ctx->md5, iter_base, len);
+	else if (ctx->hmac)
+		hmac_sha256_update(ctx->hmac, iter_base, len);
+	else
+		aes_cmac_update(ctx->cmac, iter_base, len);
+	return 0; /* Return value is length *not* processed, i.e. 0. */
 }
 
-static int cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out)
+static void cifs_sig_final(struct cifs_calc_sig_ctx *ctx, u8 *out)
 {
-	if (ctx->md5) {
+	if (ctx->md5)
 		md5_final(ctx->md5, out);
-		return 0;
-	}
-	if (ctx->hmac) {
+	else if (ctx->hmac)
 		hmac_sha256_final(ctx->hmac, out);
-		return 0;
-	}
-	return crypto_shash_final(ctx->shash, out);
-}
-
-static size_t cifs_sig_step(void *iter_base, size_t progress, size_t len,
-			    void *priv, void *priv2)
-{
-	struct cifs_calc_sig_ctx *ctx = priv;
-	int ret, *pret = priv2;
-
-	ret = cifs_sig_update(ctx, iter_base, len);
-	if (ret < 0) {
-		*pret = ret;
-		return len;
-	}
-	return 0;
+	else
+		aes_cmac_final(ctx->cmac, out);
 }
 
 /*
  * Pass the data from an iterator into a hash.
  */
 static int cifs_sig_iter(const struct iov_iter *iter, size_t maxsize,
 			 struct cifs_calc_sig_ctx *ctx)
 {
 	struct iov_iter tmp_iter = *iter;
 	size_t did;
-	int err;
 
-	did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, &err,
+	did = iterate_and_advance_kernel(&tmp_iter, maxsize, ctx, NULL,
 					 cifs_sig_step);
 	if (did != maxsize)
 		return smb_EIO2(smb_eio_trace_sig_iter, did, maxsize);
 	return 0;
 }
@@ -106,15 +89,12 @@ int __cifs_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 
 	rc = cifs_sig_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), ctx);
 	if (rc < 0)
 		return rc;
 
-	rc = cifs_sig_final(ctx, signature);
-	if (rc)
-		cifs_dbg(VFS, "%s: Could not generate hash\n", __func__);
-
-	return rc;
+	cifs_sig_final(ctx, signature);
+	return 0;
 }
 
 /* Build a proper attribute value/target info pairs blob.
  * Fill in netbios and dns domain name and workstation name
  * and client time (total five av pairs and + one end of fields indicator.
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 080ea601c209..2ff43bd35c5f 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -2285,11 +2285,11 @@ static inline void mid_execute_callback(struct TCP_Server_Info *server,
 	  FILE_SUPPORTS_REPARSE_POINTS))
 
 struct cifs_calc_sig_ctx {
 	struct md5_ctx *md5;
 	struct hmac_sha256_ctx *hmac;
-	struct shash_desc *shash;
+	struct aes_cmac_ctx *cmac;
 };
 
 #define CIFS_RECONN_DELAY_SECS	30
 #define CIFS_MAX_RECONN_DELAY	(4 * CIFS_RECONN_DELAY_SECS)
 
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 81be2b226e26..b233e0cd9152 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -17,10 +17,11 @@
 #include <linux/uaccess.h>
 #include <asm/processor.h>
 #include <linux/mempool.h>
 #include <linux/highmem.h>
 #include <crypto/aead.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/sha2.h>
 #include <crypto/utils.h>
 #include "cifsglob.h"
 #include "cifsproto.h"
 #include "smb2proto.h"
@@ -472,11 +473,12 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 {
 	int rc;
 	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
 	struct kvec *iov = rqst->rq_iov;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
-	struct shash_desc *shash = NULL;
+	struct aes_cmac_key cmac_key;
+	struct aes_cmac_ctx cmac_ctx;
 	struct smb_rqst drqst;
 	u8 key[SMB3_SIGN_KEY_SIZE];
 
 	if (server->vals->protocol_id <= SMB21_PROT_ID)
 		return smb2_calc_signature(rqst, server, allocate_crypto);
@@ -485,67 +487,40 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 	if (unlikely(rc)) {
 		cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__);
 		return rc;
 	}
 
-	if (allocate_crypto) {
-		rc = cifs_alloc_hash("cmac(aes)", &shash);
-		if (rc)
-			return rc;
-	} else {
-		shash = server->secmech.aes_cmac;
-	}
-
 	memset(smb3_signature, 0x0, SMB2_CMACAES_SIZE);
 	memset(shdr->Signature, 0x0, SMB2_SIGNATURE_SIZE);
 
-	rc = crypto_shash_setkey(shash->tfm, key, SMB2_CMACAES_SIZE);
+	rc = aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE);
 	if (rc) {
 		cifs_server_dbg(VFS, "%s: Could not set key for cmac aes\n", __func__);
-		goto out;
+		return rc;
 	}
 
-	/*
-	 * we already allocate aes_cmac when we init smb3 signing key,
-	 * so unlike smb2 case we do not have to check here if secmech are
-	 * initialized
-	 */
-	rc = crypto_shash_init(shash);
-	if (rc) {
-		cifs_server_dbg(VFS, "%s: Could not init cmac aes\n", __func__);
-		goto out;
-	}
+	aes_cmac_init(&cmac_ctx, &cmac_key);
 
 	/*
 	 * For SMB2+, __cifs_calc_signature() expects to sign only the actual
 	 * data, that is, iov[0] should not contain a rfc1002 length.
 	 *
 	 * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to
 	 * __cifs_calc_signature().
 	 */
 	drqst = *rqst;
 	if (drqst.rq_nvec >= 2 && iov[0].iov_len == 4) {
-		rc = crypto_shash_update(shash, iov[0].iov_base,
-					 iov[0].iov_len);
-		if (rc) {
-			cifs_server_dbg(VFS, "%s: Could not update with payload\n",
-				 __func__);
-			goto out;
-		}
+		aes_cmac_update(&cmac_ctx, iov[0].iov_base, iov[0].iov_len);
 		drqst.rq_iov++;
 		drqst.rq_nvec--;
 	}
 
 	rc = __cifs_calc_signature(
 		&drqst, server, smb3_signature,
-		&(struct cifs_calc_sig_ctx){ .shash = shash });
+		&(struct cifs_calc_sig_ctx){ .cmac = &cmac_ctx });
 	if (!rc)
 		memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE);
-
-out:
-	if (allocate_crypto)
-		cifs_free_hash(&shash);
 	return rc;
 }
 
 /* must be called with server->srv_mutex held */
 static int
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 09/15] smb: client: Remove obsolete cmac(aes) allocation
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (7 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 08/15] smb: client: Use AES-CMAC library for SMB3 signature calculation Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:34 ` [PATCH 10/15] smb: client: Make generate_key() return void Eric Biggers
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Since the crypto library API is now being used instead of crypto_shash,
the "cmac(aes)" crypto_shash that is being allocated and stored in
'struct cifs_secmech' is no longer used.  Remove it.

That makes the kconfig selection of CRYPTO_CMAC and the module softdep
on "cmac" unnecessary.  So remove those too.

Finally, since this removes the last use of crypto_shash from the smb
client, also remove the remaining crypto_shash-related helper functions.

Note: cifs_unicode.c was relying on <linux/unaligned.h> being included
transitively via <crypto/internal/hash.h>.  Since the latter include is
removed, make cifs_unicode.c include <linux/unaligned.h> explicitly.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 fs/smb/client/Kconfig         |  1 -
 fs/smb/client/cifs_unicode.c  |  1 +
 fs/smb/client/cifsencrypt.c   |  2 --
 fs/smb/client/cifsfs.c        |  1 -
 fs/smb/client/cifsglob.h      |  5 +--
 fs/smb/client/cifsproto.h     |  3 --
 fs/smb/client/misc.c          | 57 -----------------------------------
 fs/smb/client/sess.c          | 11 -------
 fs/smb/client/smb2proto.h     |  1 -
 fs/smb/client/smb2transport.c | 15 ---------
 10 files changed, 2 insertions(+), 95 deletions(-)

diff --git a/fs/smb/client/Kconfig b/fs/smb/client/Kconfig
index 64afd302202f..29d7dffab51b 100644
--- a/fs/smb/client/Kconfig
+++ b/fs/smb/client/Kconfig
@@ -3,11 +3,10 @@ config CIFS
 	tristate "SMB3 and CIFS support (advanced network filesystem)"
 	depends on INET
 	select NLS
 	select NLS_UCS2_UTILS
 	select CRYPTO
-	select CRYPTO_CMAC
 	select CRYPTO_AEAD2
 	select CRYPTO_CCM
 	select CRYPTO_GCM
 	select CRYPTO_ECB
 	select CRYPTO_AES
diff --git a/fs/smb/client/cifs_unicode.c b/fs/smb/client/cifs_unicode.c
index e7891b4406f2..c6e81ba011bb 100644
--- a/fs/smb/client/cifs_unicode.c
+++ b/fs/smb/client/cifs_unicode.c
@@ -4,10 +4,11 @@
  *   Copyright (c) International Business Machines  Corp., 2000,2009
  *   Modified by Steve French (sfrench@us.ibm.com)
  */
 #include <linux/fs.h>
 #include <linux/slab.h>
+#include <linux/unaligned.h>
 #include "cifs_fs_sb.h"
 #include "cifs_unicode.h"
 #include "cifsglob.h"
 #include "cifs_debug.h"
 
diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c
index f39894113821..a566ce2ae9f8 100644
--- a/fs/smb/client/cifsencrypt.c
+++ b/fs/smb/client/cifsencrypt.c
@@ -501,12 +501,10 @@ calc_seckey(struct cifs_ses *ses)
 }
 
 void
 cifs_crypto_secmech_release(struct TCP_Server_Info *server)
 {
-	cifs_free_hash(&server->secmech.aes_cmac);
-
 	if (server->secmech.enc) {
 		crypto_free_aead(server->secmech.enc);
 		server->secmech.enc = NULL;
 	}
 	if (server->secmech.dec) {
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index afda1d7c1ee1..46499bdcebfe 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -2142,11 +2142,10 @@ MODULE_DESCRIPTION
 	"also older servers complying with the SNIA CIFS Specification)");
 MODULE_VERSION(CIFS_VERSION);
 MODULE_SOFTDEP("ecb");
 MODULE_SOFTDEP("nls");
 MODULE_SOFTDEP("aes");
-MODULE_SOFTDEP("cmac");
 MODULE_SOFTDEP("aead2");
 MODULE_SOFTDEP("ccm");
 MODULE_SOFTDEP("gcm");
 module_init(init_cifs)
 module_exit(exit_cifs)
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 2ff43bd35c5f..24f2a367aad5 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -20,11 +20,10 @@
 #include <linux/utsname.h>
 #include <linux/sched/mm.h>
 #include <linux/netfs.h>
 #include "cifs_fs_sb.h"
 #include "cifsacl.h"
-#include <crypto/internal/hash.h>
 #include <uapi/linux/cifs/cifs_mount.h>
 #include "../common/smbglob.h"
 #include "../common/smb2pdu.h"
 #include "../common/fscc.h"
 #include "smb2pdu.h"
@@ -218,14 +217,12 @@ static inline const char *cifs_symlink_type_str(enum cifs_symlink_type type)
 struct session_key {
 	unsigned int len;
 	char *response;
 };
 
-/* crypto hashing related structure/fields, not specific to a sec mech */
+/* encryption related structure/fields, not specific to a sec mech */
 struct cifs_secmech {
-	struct shash_desc *aes_cmac; /* block-cipher based MAC function, for SMB3 signatures */
-
 	struct crypto_aead *enc; /* smb3 encryption AEAD TFM (AES-CCM and AES-GCM) */
 	struct crypto_aead *dec; /* smb3 decryption AEAD TFM (AES-CCM and AES-GCM) */
 };
 
 /* per smb session structure/fields */
diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h
index 96d6b5325aa3..025db2285968 100644
--- a/fs/smb/client/cifsproto.h
+++ b/fs/smb/client/cifsproto.h
@@ -345,13 +345,10 @@ int __cifs_calc_signature(struct smb_rqst *rqst,
 			  struct TCP_Server_Info *server, char *signature,
 			  struct cifs_calc_sig_ctx *ctx);
 enum securityEnum cifs_select_sectype(struct TCP_Server_Info *server,
 				      enum securityEnum requested);
 
-int cifs_alloc_hash(const char *name, struct shash_desc **sdesc);
-void cifs_free_hash(struct shash_desc **sdesc);
-
 int cifs_try_adding_channels(struct cifs_ses *ses);
 int smb3_update_ses_channels(struct cifs_ses *ses,
 			     struct TCP_Server_Info *server,
 			     bool from_reconnect, bool disable_mchan);
 bool is_ses_using_iface(struct cifs_ses *ses, struct cifs_server_iface *iface);
diff --git a/fs/smb/client/misc.c b/fs/smb/client/misc.c
index 1773e3b471aa..d7300d224a63 100644
--- a/fs/smb/client/misc.c
+++ b/fs/smb/client/misc.c
@@ -736,67 +736,10 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size,
 		*num_of_nodes = 0;
 	}
 	return rc;
 }
 
-/**
- * cifs_alloc_hash - allocate hash and hash context together
- * @name: The name of the crypto hash algo
- * @sdesc: SHASH descriptor where to put the pointer to the hash TFM
- *
- * The caller has to make sure @sdesc is initialized to either NULL or
- * a valid context. It can be freed via cifs_free_hash().
- */
-int
-cifs_alloc_hash(const char *name, struct shash_desc **sdesc)
-{
-	int rc = 0;
-	struct crypto_shash *alg = NULL;
-
-	if (*sdesc)
-		return 0;
-
-	alg = crypto_alloc_shash(name, 0, 0);
-	if (IS_ERR(alg)) {
-		cifs_dbg(VFS, "Could not allocate shash TFM '%s'\n", name);
-		rc = PTR_ERR(alg);
-		*sdesc = NULL;
-		return rc;
-	}
-
-	*sdesc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(alg), GFP_KERNEL);
-	if (*sdesc == NULL) {
-		cifs_dbg(VFS, "no memory left to allocate shash TFM '%s'\n", name);
-		crypto_free_shash(alg);
-		return -ENOMEM;
-	}
-
-	(*sdesc)->tfm = alg;
-	return 0;
-}
-
-/**
- * cifs_free_hash - free hash and hash context together
- * @sdesc: Where to find the pointer to the hash TFM
- *
- * Freeing a NULL descriptor is safe.
- */
-void
-cifs_free_hash(struct shash_desc **sdesc)
-{
-	if (unlikely(!sdesc) || !*sdesc)
-		return;
-
-	if ((*sdesc)->tfm) {
-		crypto_free_shash((*sdesc)->tfm);
-		(*sdesc)->tfm = NULL;
-	}
-
-	kfree_sensitive(*sdesc);
-	*sdesc = NULL;
-}
-
 void extract_unc_hostname(const char *unc, const char **h, size_t *len)
 {
 	const char *end;
 
 	/* skip initial slashes */
diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c
index d523540565ef..11a09a1d8806 100644
--- a/fs/smb/client/sess.c
+++ b/fs/smb/client/sess.c
@@ -593,21 +593,10 @@ cifs_ses_add_channel(struct cifs_ses *ses,
 	cifs_chan_set_need_reconnect(ses, chan->server);
 
 	spin_unlock(&ses->chan_lock);
 
 	mutex_lock(&ses->session_mutex);
-	/*
-	 * We need to allocate the server crypto now as we will need
-	 * to sign packets before we generate the channel signing key
-	 * (we sign with the session key)
-	 */
-	rc = smb3_crypto_shash_allocate(chan->server);
-	if (rc) {
-		cifs_dbg(VFS, "%s: crypto alloc failed\n", __func__);
-		mutex_unlock(&ses->session_mutex);
-		goto out;
-	}
 
 	rc = cifs_negotiate_protocol(xid, ses, chan->server);
 	if (!rc)
 		rc = cifs_setup_session(xid, ses, chan->server, ses->local_nls);
 
diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h
index 881e42cf66ce..e7b35d500943 100644
--- a/fs/smb/client/smb2proto.h
+++ b/fs/smb/client/smb2proto.h
@@ -253,11 +253,10 @@ int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,
 int smb2_validate_and_copy_iov(unsigned int offset, unsigned int buffer_length,
 			       struct kvec *iov, unsigned int minbufsize,
 			       char *data);
 void smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_size_info *pfs_inf,
 				  struct kstatfs *kst);
-int smb3_crypto_shash_allocate(struct TCP_Server_Info *server);
 void smb311_update_preauth_hash(struct cifs_ses *ses,
 				struct TCP_Server_Info *server,
 				struct kvec *iov, int nvec);
 int smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 			     const char *path, u32 desired_access, u32 class,
diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index b233e0cd9152..716e58d1b1c9 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -27,18 +27,10 @@
 #include "smb2proto.h"
 #include "cifs_debug.h"
 #include "../common/smb2status.h"
 #include "smb2glob.h"
 
-int
-smb3_crypto_shash_allocate(struct TCP_Server_Info *server)
-{
-	struct cifs_secmech *p = &server->secmech;
-
-	return cifs_alloc_hash("cmac(aes)", &p->aes_cmac);
-}
-
 static
 int smb3_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *key)
 {
 	struct cifs_chan *chan;
 	struct TCP_Server_Info *pserver;
@@ -264,24 +256,17 @@ static int generate_key(struct cifs_ses *ses, struct kvec label,
 {
 	unsigned char zero = 0x0;
 	__u8 i[4] = {0, 0, 0, 1};
 	__u8 L128[4] = {0, 0, 0, 128};
 	__u8 L256[4] = {0, 0, 1, 0};
-	int rc = 0;
 	unsigned char prfhash[SMB2_HMACSHA256_SIZE];
 	struct TCP_Server_Info *server = ses->server;
 	struct hmac_sha256_ctx hmac_ctx;
 
 	memset(prfhash, 0x0, SMB2_HMACSHA256_SIZE);
 	memset(key, 0x0, key_size);
 
-	rc = smb3_crypto_shash_allocate(server);
-	if (rc) {
-		cifs_server_dbg(VFS, "%s: crypto alloc failed\n", __func__);
-		return rc;
-	}
-
 	hmac_sha256_init_usingrawkey(&hmac_ctx, ses->auth_key.response,
 				     SMB2_NTLMV2_SESSKEY_SIZE);
 	hmac_sha256_update(&hmac_ctx, i, 4);
 	hmac_sha256_update(&hmac_ctx, label.iov_base, label.iov_len);
 	hmac_sha256_update(&hmac_ctx, &zero, 1);
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 10/15] smb: client: Make generate_key() return void
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (8 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 09/15] smb: client: Remove obsolete cmac(aes) allocation Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:34 ` [PATCH 11/15] smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature() Eric Biggers
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Since the crypto library API is now being used instead of crypto_shash,
generate_key() can no longer fail.  Make it return void and simplify the
callers accordingly.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 fs/smb/client/smb2transport.c | 45 +++++++++++++----------------------
 1 file changed, 16 insertions(+), 29 deletions(-)

diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 716e58d1b1c9..0176185a1efc 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -249,12 +249,12 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 		memcpy(shdr->Signature, smb2_signature, SMB2_SIGNATURE_SIZE);
 
 	return rc;
 }
 
-static int generate_key(struct cifs_ses *ses, struct kvec label,
-			struct kvec context, __u8 *key, unsigned int key_size)
+static void generate_key(struct cifs_ses *ses, struct kvec label,
+			 struct kvec context, __u8 *key, unsigned int key_size)
 {
 	unsigned char zero = 0x0;
 	__u8 i[4] = {0, 0, 0, 1};
 	__u8 L128[4] = {0, 0, 0, 128};
 	__u8 L256[4] = {0, 0, 1, 0};
@@ -279,11 +279,10 @@ static int generate_key(struct cifs_ses *ses, struct kvec label,
 		hmac_sha256_update(&hmac_ctx, L128, 4);
 	}
 	hmac_sha256_final(&hmac_ctx, prfhash);
 
 	memcpy(key, prfhash, key_size);
-	return 0;
 }
 
 struct derivation {
 	struct kvec label;
 	struct kvec context;
@@ -298,11 +297,10 @@ struct derivation_triplet {
 static int
 generate_smb3signingkey(struct cifs_ses *ses,
 			struct TCP_Server_Info *server,
 			const struct derivation_triplet *ptriplet)
 {
-	int rc;
 	bool is_binding = false;
 	int chan_index = 0;
 
 	spin_lock(&ses->ses_lock);
 	spin_lock(&ses->chan_lock);
@@ -329,42 +327,31 @@ generate_smb3signingkey(struct cifs_ses *ses,
 	 * key and store it in the channel as to not overwrite the
 	 * master connection signing key stored in the session
 	 */
 
 	if (is_binding) {
-		rc = generate_key(ses, ptriplet->signing.label,
-				  ptriplet->signing.context,
-				  ses->chans[chan_index].signkey,
-				  SMB3_SIGN_KEY_SIZE);
-		if (rc)
-			return rc;
+		generate_key(ses, ptriplet->signing.label,
+			     ptriplet->signing.context,
+			     ses->chans[chan_index].signkey,
+			     SMB3_SIGN_KEY_SIZE);
 	} else {
-		rc = generate_key(ses, ptriplet->signing.label,
-				  ptriplet->signing.context,
-				  ses->smb3signingkey,
-				  SMB3_SIGN_KEY_SIZE);
-		if (rc)
-			return rc;
+		generate_key(ses, ptriplet->signing.label,
+			     ptriplet->signing.context,
+			     ses->smb3signingkey, SMB3_SIGN_KEY_SIZE);
 
 		/* safe to access primary channel, since it will never go away */
 		spin_lock(&ses->chan_lock);
 		memcpy(ses->chans[chan_index].signkey, ses->smb3signingkey,
 		       SMB3_SIGN_KEY_SIZE);
 		spin_unlock(&ses->chan_lock);
 
-		rc = generate_key(ses, ptriplet->encryption.label,
-				  ptriplet->encryption.context,
-				  ses->smb3encryptionkey,
-				  SMB3_ENC_DEC_KEY_SIZE);
-		if (rc)
-			return rc;
-		rc = generate_key(ses, ptriplet->decryption.label,
-				  ptriplet->decryption.context,
-				  ses->smb3decryptionkey,
-				  SMB3_ENC_DEC_KEY_SIZE);
-		if (rc)
-			return rc;
+		generate_key(ses, ptriplet->encryption.label,
+			     ptriplet->encryption.context,
+			     ses->smb3encryptionkey, SMB3_ENC_DEC_KEY_SIZE);
+		generate_key(ses, ptriplet->decryption.label,
+			     ptriplet->decryption.context,
+			     ses->smb3decryptionkey, SMB3_ENC_DEC_KEY_SIZE);
 	}
 
 #ifdef CONFIG_CIFS_DEBUG_DUMP_KEYS
 	cifs_dbg(VFS, "%s: dumping generated AES session keys\n", __func__);
 	/*
@@ -389,11 +376,11 @@ generate_smb3signingkey(struct cifs_ses *ses,
 				SMB3_GCM128_CRYPTKEY_SIZE, ses->smb3encryptionkey);
 		cifs_dbg(VFS, "ServerOut Key %*ph\n",
 				SMB3_GCM128_CRYPTKEY_SIZE, ses->smb3decryptionkey);
 	}
 #endif
-	return rc;
+	return 0;
 }
 
 int
 generate_smb30signingkey(struct cifs_ses *ses,
 			 struct TCP_Server_Info *server)
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 11/15] smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature()
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (9 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 10/15] smb: client: Make generate_key() return void Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:42   ` Steve French
  2026-02-18 21:34 ` [PATCH 12/15] ksmbd: Use AES-CMAC library for SMB3 signature calculation Eric Biggers
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Since the crypto library API is now being used instead of crypto_shash,
all structs for MAC computation are now just fixed-size structs
allocated on the stack; no dynamic allocations are ever required.
Besides being much more efficient, this also means that the
'allocate_crypto' argument to smb2_calc_signature() and
smb3_calc_signature() is no longer used.  Remove this unused argument.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 fs/smb/client/smb2transport.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
index 0176185a1efc..41009039b4cb 100644
--- a/fs/smb/client/smb2transport.c
+++ b/fs/smb/client/smb2transport.c
@@ -202,12 +202,11 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32  tid)
 
 	return tcon;
 }
 
 static int
-smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
-		    bool allocate_crypto)
+smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
 	int rc;
 	unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
 	struct kvec *iov = rqst->rq_iov;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
@@ -438,12 +437,11 @@ generate_smb311signingkey(struct cifs_ses *ses,
 
 	return generate_smb3signingkey(ses, server, &triplet);
 }
 
 static int
-smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
-		    bool allocate_crypto)
+smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
 	int rc;
 	unsigned char smb3_signature[SMB2_CMACAES_SIZE];
 	struct kvec *iov = rqst->rq_iov;
 	struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
@@ -451,11 +449,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
 	struct aes_cmac_ctx cmac_ctx;
 	struct smb_rqst drqst;
 	u8 key[SMB3_SIGN_KEY_SIZE];
 
 	if (server->vals->protocol_id <= SMB21_PROT_ID)
-		return smb2_calc_signature(rqst, server, allocate_crypto);
+		return smb2_calc_signature(rqst, server);
 
 	rc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key);
 	if (unlikely(rc)) {
 		cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__);
 		return rc;
@@ -522,11 +520,11 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 	if (!is_binding && !server->session_estab) {
 		strscpy(shdr->Signature, "BSRSPYL");
 		return 0;
 	}
 
-	return smb3_calc_signature(rqst, server, false);
+	return smb3_calc_signature(rqst, server);
 }
 
 int
 smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 {
@@ -558,11 +556,11 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
 	 */
 	memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE);
 
 	memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 
-	rc = smb3_calc_signature(rqst, server, true);
+	rc = smb3_calc_signature(rqst, server);
 
 	if (rc)
 		return rc;
 
 	if (crypto_memneq(server_response_sig, shdr->Signature,
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 12/15] ksmbd: Use AES-CMAC library for SMB3 signature calculation
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (10 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 11/15] smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature() Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-19  1:49   ` Namjae Jeon
  2026-02-18 21:34 ` [PATCH 13/15] Bluetooth: SMP: Use AES-CMAC library API Eric Biggers
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Now that AES-CMAC has a library API, convert ksmbd_sign_smb3_pdu() to
use it instead of a "cmac(aes)" crypto_shash.

The result is simpler and faster code.  With the library there's no need
to dynamically allocate memory, no need to handle errors, and the
AES-CMAC code is accessed directly without inefficient indirect calls
and other unnecessary API overhead.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 fs/smb/server/Kconfig      |  2 +-
 fs/smb/server/auth.c       | 51 +++++++++------------------------
 fs/smb/server/auth.h       |  4 +--
 fs/smb/server/crypto_ctx.c | 58 --------------------------------------
 fs/smb/server/crypto_ctx.h | 12 --------
 fs/smb/server/server.c     |  1 -
 fs/smb/server/smb2pdu.c    |  8 ++----
 7 files changed, 19 insertions(+), 117 deletions(-)

diff --git a/fs/smb/server/Kconfig b/fs/smb/server/Kconfig
index 12594879cb64..eae3728cff54 100644
--- a/fs/smb/server/Kconfig
+++ b/fs/smb/server/Kconfig
@@ -6,17 +6,17 @@ config SMB_SERVER
 	select NLS
 	select NLS_UTF8
 	select NLS_UCS2_UTILS
 	select CRYPTO
 	select CRYPTO_ECB
+	select CRYPTO_LIB_AES_CBC_MACS
 	select CRYPTO_LIB_ARC4
 	select CRYPTO_LIB_DES
 	select CRYPTO_LIB_MD5
 	select CRYPTO_LIB_SHA256
 	select CRYPTO_LIB_SHA512
 	select CRYPTO_LIB_UTILS
-	select CRYPTO_CMAC
 	select CRYPTO_AEAD2
 	select CRYPTO_CCM
 	select CRYPTO_GCM
 	select ASN1
 	select OID_REGISTRY
diff --git a/fs/smb/server/auth.c b/fs/smb/server/auth.c
index a69e8694605a..05234e5bd16e 100644
--- a/fs/smb/server/auth.c
+++ b/fs/smb/server/auth.c
@@ -9,12 +9,12 @@
 #include <linux/uaccess.h>
 #include <linux/backing-dev.h>
 #include <linux/writeback.h>
 #include <linux/uio.h>
 #include <linux/xattr.h>
-#include <crypto/hash.h>
 #include <crypto/aead.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/md5.h>
 #include <crypto/sha2.h>
 #include <crypto/utils.h>
 #include <linux/random.h>
 #include <linux/scatterlist.h>
@@ -488,50 +488,25 @@ void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
  * @iov:        buffer iov array
  * @n_vec:	number of iovecs
  * @sig:	signature value generated for client request packet
  *
  */
-int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
-			int n_vec, char *sig)
+void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
+			 int n_vec, char *sig)
 {
-	struct ksmbd_crypto_ctx *ctx;
-	int rc, i;
-
-	ctx = ksmbd_crypto_ctx_find_cmacaes();
-	if (!ctx) {
-		ksmbd_debug(AUTH, "could not crypto alloc cmac\n");
-		return -ENOMEM;
-	}
-
-	rc = crypto_shash_setkey(CRYPTO_CMACAES_TFM(ctx),
-				 key,
-				 SMB2_CMACAES_SIZE);
-	if (rc)
-		goto out;
-
-	rc = crypto_shash_init(CRYPTO_CMACAES(ctx));
-	if (rc) {
-		ksmbd_debug(AUTH, "cmaces init error %d\n", rc);
-		goto out;
-	}
+	struct aes_cmac_key cmac_key;
+	struct aes_cmac_ctx cmac_ctx;
+	int i;
 
-	for (i = 0; i < n_vec; i++) {
-		rc = crypto_shash_update(CRYPTO_CMACAES(ctx),
-					 iov[i].iov_base,
-					 iov[i].iov_len);
-		if (rc) {
-			ksmbd_debug(AUTH, "cmaces update error %d\n", rc);
-			goto out;
-		}
-	}
+	/* This cannot fail, since we always pass a valid key length. */
+	static_assert(SMB2_CMACAES_SIZE == AES_KEYSIZE_128);
+	aes_cmac_preparekey(&cmac_key, key, SMB2_CMACAES_SIZE);
 
-	rc = crypto_shash_final(CRYPTO_CMACAES(ctx), sig);
-	if (rc)
-		ksmbd_debug(AUTH, "cmaces generation error %d\n", rc);
-out:
-	ksmbd_release_crypto_ctx(ctx);
-	return rc;
+	aes_cmac_init(&cmac_ctx, &cmac_key);
+	for (i = 0; i < n_vec; i++)
+		aes_cmac_update(&cmac_ctx, iov[i].iov_base, iov[i].iov_len);
+	aes_cmac_final(&cmac_ctx, sig);
 }
 
 struct derivation {
 	struct kvec label;
 	struct kvec context;
diff --git a/fs/smb/server/auth.h b/fs/smb/server/auth.h
index 6d351d61b0e5..5767aabc63c9 100644
--- a/fs/smb/server/auth.h
+++ b/fs/smb/server/auth.h
@@ -52,12 +52,12 @@ ksmbd_build_ntlmssp_challenge_blob(struct challenge_message *chgblob,
 				   struct ksmbd_conn *conn);
 int ksmbd_krb5_authenticate(struct ksmbd_session *sess, char *in_blob,
 			    int in_len,	char *out_blob, int *out_len);
 void ksmbd_sign_smb2_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
 			 int n_vec, char *sig);
-int ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
-			int n_vec, char *sig);
+void ksmbd_sign_smb3_pdu(struct ksmbd_conn *conn, char *key, struct kvec *iov,
+			 int n_vec, char *sig);
 int ksmbd_gen_smb30_signingkey(struct ksmbd_session *sess,
 			       struct ksmbd_conn *conn);
 int ksmbd_gen_smb311_signingkey(struct ksmbd_session *sess,
 				struct ksmbd_conn *conn);
 void ksmbd_gen_smb30_encryptionkey(struct ksmbd_conn *conn,
diff --git a/fs/smb/server/crypto_ctx.c b/fs/smb/server/crypto_ctx.c
index fe29d186baf6..1cb0ea2042b5 100644
--- a/fs/smb/server/crypto_ctx.c
+++ b/fs/smb/server/crypto_ctx.c
@@ -26,18 +26,10 @@ static inline void free_aead(struct crypto_aead *aead)
 {
 	if (aead)
 		crypto_free_aead(aead);
 }
 
-static void free_shash(struct shash_desc *shash)
-{
-	if (shash) {
-		crypto_free_shash(shash->tfm);
-		kfree(shash);
-	}
-}
-
 static struct crypto_aead *alloc_aead(int id)
 {
 	struct crypto_aead *tfm = NULL;
 
 	switch (id) {
@@ -58,41 +50,14 @@ static struct crypto_aead *alloc_aead(int id)
 	}
 
 	return tfm;
 }
 
-static struct shash_desc *alloc_shash_desc(int id)
-{
-	struct crypto_shash *tfm = NULL;
-	struct shash_desc *shash;
-
-	switch (id) {
-	case CRYPTO_SHASH_CMACAES:
-		tfm = crypto_alloc_shash("cmac(aes)", 0, 0);
-		break;
-	default:
-		return NULL;
-	}
-
-	if (IS_ERR(tfm))
-		return NULL;
-
-	shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm),
-			KSMBD_DEFAULT_GFP);
-	if (!shash)
-		crypto_free_shash(tfm);
-	else
-		shash->tfm = tfm;
-	return shash;
-}
-
 static void ctx_free(struct ksmbd_crypto_ctx *ctx)
 {
 	int i;
 
-	for (i = 0; i < CRYPTO_SHASH_MAX; i++)
-		free_shash(ctx->desc[i]);
 	for (i = 0; i < CRYPTO_AEAD_MAX; i++)
 		free_aead(ctx->ccmaes[i]);
 	kfree(ctx);
 }
 
@@ -151,33 +116,10 @@ void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx)
 	ctx_list.avail_ctx--;
 	spin_unlock(&ctx_list.ctx_lock);
 	ctx_free(ctx);
 }
 
-static struct ksmbd_crypto_ctx *____crypto_shash_ctx_find(int id)
-{
-	struct ksmbd_crypto_ctx *ctx;
-
-	if (id >= CRYPTO_SHASH_MAX)
-		return NULL;
-
-	ctx = ksmbd_find_crypto_ctx();
-	if (ctx->desc[id])
-		return ctx;
-
-	ctx->desc[id] = alloc_shash_desc(id);
-	if (ctx->desc[id])
-		return ctx;
-	ksmbd_release_crypto_ctx(ctx);
-	return NULL;
-}
-
-struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void)
-{
-	return ____crypto_shash_ctx_find(CRYPTO_SHASH_CMACAES);
-}
-
 static struct ksmbd_crypto_ctx *____crypto_aead_ctx_find(int id)
 {
 	struct ksmbd_crypto_ctx *ctx;
 
 	if (id >= CRYPTO_AEAD_MAX)
diff --git a/fs/smb/server/crypto_ctx.h b/fs/smb/server/crypto_ctx.h
index b9476ed520ae..02d2893665a4 100644
--- a/fs/smb/server/crypto_ctx.h
+++ b/fs/smb/server/crypto_ctx.h
@@ -4,18 +4,12 @@
  */
 
 #ifndef __CRYPTO_CTX_H__
 #define __CRYPTO_CTX_H__
 
-#include <crypto/hash.h>
 #include <crypto/aead.h>
 
-enum {
-	CRYPTO_SHASH_CMACAES	= 0,
-	CRYPTO_SHASH_MAX,
-};
-
 enum {
 	CRYPTO_AEAD_AES_GCM = 16,
 	CRYPTO_AEAD_AES_CCM,
 	CRYPTO_AEAD_MAX,
 };
@@ -26,23 +20,17 @@ enum {
 };
 
 struct ksmbd_crypto_ctx {
 	struct list_head		list;
 
-	struct shash_desc		*desc[CRYPTO_SHASH_MAX];
 	struct crypto_aead		*ccmaes[CRYPTO_AEAD_MAX];
 };
 
-#define CRYPTO_CMACAES(c)	((c)->desc[CRYPTO_SHASH_CMACAES])
-
-#define CRYPTO_CMACAES_TFM(c)	((c)->desc[CRYPTO_SHASH_CMACAES]->tfm)
-
 #define CRYPTO_GCM(c)		((c)->ccmaes[CRYPTO_AEAD_AES_GCM])
 #define CRYPTO_CCM(c)		((c)->ccmaes[CRYPTO_AEAD_AES_CCM])
 
 void ksmbd_release_crypto_ctx(struct ksmbd_crypto_ctx *ctx);
-struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_cmacaes(void);
 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_gcm(void);
 struct ksmbd_crypto_ctx *ksmbd_crypto_ctx_find_ccm(void);
 void ksmbd_crypto_destroy(void);
 int ksmbd_crypto_create(void);
 
diff --git a/fs/smb/server/server.c b/fs/smb/server/server.c
index c2c074346da1..cc15d9d8468f 100644
--- a/fs/smb/server/server.c
+++ b/fs/smb/server/server.c
@@ -631,11 +631,10 @@ MODULE_AUTHOR("Namjae Jeon <linkinjeon@kernel.org>");
 MODULE_DESCRIPTION("Linux kernel CIFS/SMB SERVER");
 MODULE_LICENSE("GPL");
 MODULE_SOFTDEP("pre: ecb");
 MODULE_SOFTDEP("pre: nls");
 MODULE_SOFTDEP("pre: aes");
-MODULE_SOFTDEP("pre: cmac");
 MODULE_SOFTDEP("pre: aead2");
 MODULE_SOFTDEP("pre: ccm");
 MODULE_SOFTDEP("pre: gcm");
 module_init(ksmbd_server_init)
 module_exit(ksmbd_server_exit)
diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c
index 7a88cf3bd29e..02bfe15edcab 100644
--- a/fs/smb/server/smb2pdu.c
+++ b/fs/smb/server/smb2pdu.c
@@ -8964,12 +8964,11 @@ int smb3_check_sign_req(struct ksmbd_work *work)
 	memcpy(signature_req, hdr->Signature, SMB2_SIGNATURE_SIZE);
 	memset(hdr->Signature, 0, SMB2_SIGNATURE_SIZE);
 	iov[0].iov_base = (char *)&hdr->ProtocolId;
 	iov[0].iov_len = len;
 
-	if (ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature))
-		return 0;
+	ksmbd_sign_smb3_pdu(conn, signing_key, iov, 1, signature);
 
 	if (crypto_memneq(signature, signature_req, SMB2_SIGNATURE_SIZE)) {
 		pr_err("bad smb2 signature\n");
 		return 0;
 	}
@@ -9016,13 +9015,12 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
 		n_vec++;
 	} else {
 		iov = &work->iov[work->iov_idx];
 	}
 
-	if (!ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec,
-				 signature))
-		memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE);
+	ksmbd_sign_smb3_pdu(conn, signing_key, iov, n_vec, signature);
+	memcpy(hdr->Signature, signature, SMB2_SIGNATURE_SIZE);
 }
 
 /**
  * smb3_preauth_hash_rsp() - handler for computing preauth hash on response
  * @work:   smb work containing response buffer
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 13/15] Bluetooth: SMP: Use AES-CMAC library API
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (11 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 12/15] ksmbd: Use AES-CMAC library for SMB3 signature calculation Eric Biggers
@ 2026-02-18 21:34 ` Eric Biggers
  2026-02-18 21:35 ` [PATCH 14/15] wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac() Eric Biggers
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:34 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Now that AES-CMAC has a library API, convert net/bluetooth/smp.c to use
it instead of the "cmac(aes)" crypto_shash.  Since the library API
doesn't require dynamic memory allocation, we no longer need to pass a
crypto_shash object down the call stack and can simply allocate the
aes_cmac_key on the stack in smp_aes_cmac() (renamed from aes_cmac()).

The result is simpler and faster code that no longer relies on the
error-prone loading of algorithms by name.

Note that the maximum stack usage actually decreases slightly, despite
the expanded AES key being moved to the stack.  This is because the old
code called crypto_shash_tfm_digest(), which allocates 384 bytes on the
stack for a maximally-sized hash descriptor for any algorithm.  The new
code instead declares a 288-byte aes_cmac_key, then calls aes_cmac()
which declares a 32-byte aes_cmac_ctx.  Since 288 + 32 < 384, the
maximum stack usage decreases.  I.e. the entire expanded AES key easily
fits in the space that the generic crypto API was wasting before.

I didn't add zeroization of the aes_cmac_key, since smp_aes_cmac()
already copies the raw key to the stack without zeroizing it.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 net/bluetooth/Kconfig |   3 +-
 net/bluetooth/smp.c   | 180 +++++++++++++++---------------------------
 2 files changed, 65 insertions(+), 118 deletions(-)

diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
index 6b2b65a66700..48972f7790ec 100644
--- a/net/bluetooth/Kconfig
+++ b/net/bluetooth/Kconfig
@@ -9,12 +9,11 @@ menuconfig BT
 	depends on RFKILL || !RFKILL
 	select CRC16
 	select CRYPTO
 	select CRYPTO_SKCIPHER
 	select CRYPTO_LIB_AES
-	imply CRYPTO_AES
-	select CRYPTO_CMAC
+	select CRYPTO_LIB_AES_CBC_MACS
 	select CRYPTO_ECB
 	select CRYPTO_SHA256
 	select CRYPTO_ECDH
 	help
 	  Bluetooth is low-cost, low-power, short-range wireless technology.
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index bf61e8841535..fd2cd7f1b12a 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -20,12 +20,12 @@
    SOFTWARE IS DISCLAIMED.
 */
 
 #include <linux/debugfs.h>
 #include <linux/scatterlist.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/aes.h>
-#include <crypto/hash.h>
 #include <crypto/kpp.h>
 #include <crypto/utils.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -61,11 +61,11 @@
 
 #define AUTH_REQ_MASK(dev)	(hci_dev_test_flag(dev, HCI_SC_ENABLED) ? \
 				 0x3f : 0x07)
 #define KEY_DIST_MASK		0x07
 
-/* Maximum message length that can be passed to aes_cmac */
+/* Maximum message length that can be passed to smp_aes_cmac */
 #define CMAC_MSG_MAX	80
 
 enum {
 	SMP_FLAG_TK_VALID,
 	SMP_FLAG_CFM_PENDING,
@@ -87,11 +87,10 @@ struct smp_dev {
 	bool			local_oob;
 	u8			local_pk[64];
 	u8			local_rand[16];
 	bool			debug_key;
 
-	struct crypto_shash	*tfm_cmac;
 	struct crypto_kpp	*tfm_ecdh;
 };
 
 struct smp_chan {
 	struct l2cap_conn	*conn;
@@ -125,11 +124,10 @@ struct smp_chan {
 	u8			local_pk[64];
 	u8			remote_pk[64];
 	u8			dhkey[32];
 	u8			mackey[16];
 
-	struct crypto_shash	*tfm_cmac;
 	struct crypto_kpp	*tfm_ecdh;
 };
 
 /* These debug key values are defined in the SMP section of the core
  * specification. debug_pk is the public debug key and debug_sk the
@@ -164,52 +162,40 @@ static inline void swap_buf(const u8 *src, u8 *dst, size_t len)
 
 /* The following functions map to the LE SC SMP crypto functions
  * AES-CMAC, f4, f5, f6, g2 and h6.
  */
 
-static int aes_cmac(struct crypto_shash *tfm, const u8 k[16], const u8 *m,
-		    size_t len, u8 mac[16])
+static int smp_aes_cmac(const u8 k[16], const u8 *m, size_t len, u8 mac[16])
 {
 	uint8_t tmp[16], mac_msb[16], msg_msb[CMAC_MSG_MAX];
+	struct aes_cmac_key key;
 	int err;
 
 	if (len > CMAC_MSG_MAX)
 		return -EFBIG;
 
-	if (!tfm) {
-		BT_ERR("tfm %p", tfm);
-		return -EINVAL;
-	}
-
 	/* Swap key and message from LSB to MSB */
 	swap_buf(k, tmp, 16);
 	swap_buf(m, msg_msb, len);
 
 	SMP_DBG("msg (len %zu) %*phN", len, (int) len, m);
 	SMP_DBG("key %16phN", k);
 
-	err = crypto_shash_setkey(tfm, tmp, 16);
-	if (err) {
-		BT_ERR("cipher setkey failed: %d", err);
+	err = aes_cmac_preparekey(&key, tmp, 16);
+	if (WARN_ON_ONCE(err)) /* Should never happen, as 16 is valid keylen */
 		return err;
-	}
-
-	err = crypto_shash_tfm_digest(tfm, msg_msb, len, mac_msb);
-	if (err) {
-		BT_ERR("Hash computation error %d", err);
-		return err;
-	}
+	aes_cmac(&key, msg_msb, len, mac_msb);
 
 	swap_buf(mac_msb, mac, 16);
 
 	SMP_DBG("mac %16phN", mac);
 
 	return 0;
 }
 
-static int smp_f4(struct crypto_shash *tfm_cmac, const u8 u[32],
-		  const u8 v[32], const u8 x[16], u8 z, u8 res[16])
+static int smp_f4(const u8 u[32], const u8 v[32], const u8 x[16], u8 z,
+		  u8 res[16])
 {
 	u8 m[65];
 	int err;
 
 	SMP_DBG("u %32phN", u);
@@ -218,22 +204,21 @@ static int smp_f4(struct crypto_shash *tfm_cmac, const u8 u[32],
 
 	m[0] = z;
 	memcpy(m + 1, v, 32);
 	memcpy(m + 33, u, 32);
 
-	err = aes_cmac(tfm_cmac, x, m, sizeof(m), res);
+	err = smp_aes_cmac(x, m, sizeof(m), res);
 	if (err)
 		return err;
 
 	SMP_DBG("res %16phN", res);
 
 	return err;
 }
 
-static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32],
-		  const u8 n1[16], const u8 n2[16], const u8 a1[7],
-		  const u8 a2[7], u8 mackey[16], u8 ltk[16])
+static int smp_f5(const u8 w[32], const u8 n1[16], const u8 n2[16],
+		  const u8 a1[7], const u8 a2[7], u8 mackey[16], u8 ltk[16])
 {
 	/* The btle, salt and length "magic" values are as defined in
 	 * the SMP section of the Bluetooth core specification. In ASCII
 	 * the btle value ends up being 'btle'. The salt is just a
 	 * random number whereas length is the value 256 in little
@@ -248,11 +233,11 @@ static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32],
 
 	SMP_DBG("w %32phN", w);
 	SMP_DBG("n1 %16phN n2 %16phN", n1, n2);
 	SMP_DBG("a1 %7phN a2 %7phN", a1, a2);
 
-	err = aes_cmac(tfm_cmac, salt, w, 32, t);
+	err = smp_aes_cmac(salt, w, 32, t);
 	if (err)
 		return err;
 
 	SMP_DBG("t %16phN", t);
 
@@ -263,31 +248,30 @@ static int smp_f5(struct crypto_shash *tfm_cmac, const u8 w[32],
 	memcpy(m + 32, n1, 16);
 	memcpy(m + 48, btle, 4);
 
 	m[52] = 0; /* Counter */
 
-	err = aes_cmac(tfm_cmac, t, m, sizeof(m), mackey);
+	err = smp_aes_cmac(t, m, sizeof(m), mackey);
 	if (err)
 		return err;
 
 	SMP_DBG("mackey %16phN", mackey);
 
 	m[52] = 1; /* Counter */
 
-	err = aes_cmac(tfm_cmac, t, m, sizeof(m), ltk);
+	err = smp_aes_cmac(t, m, sizeof(m), ltk);
 	if (err)
 		return err;
 
 	SMP_DBG("ltk %16phN", ltk);
 
 	return 0;
 }
 
-static int smp_f6(struct crypto_shash *tfm_cmac, const u8 w[16],
-		  const u8 n1[16], const u8 n2[16], const u8 r[16],
-		  const u8 io_cap[3], const u8 a1[7], const u8 a2[7],
-		  u8 res[16])
+static int smp_f6(const u8 w[16], const u8 n1[16], const u8 n2[16],
+		  const u8 r[16], const u8 io_cap[3], const u8 a1[7],
+		  const u8 a2[7], u8 res[16])
 {
 	u8 m[65];
 	int err;
 
 	SMP_DBG("w %16phN", w);
@@ -299,21 +283,21 @@ static int smp_f6(struct crypto_shash *tfm_cmac, const u8 w[16],
 	memcpy(m + 14, io_cap, 3);
 	memcpy(m + 17, r, 16);
 	memcpy(m + 33, n2, 16);
 	memcpy(m + 49, n1, 16);
 
-	err = aes_cmac(tfm_cmac, w, m, sizeof(m), res);
+	err = smp_aes_cmac(w, m, sizeof(m), res);
 	if (err)
 		return err;
 
 	SMP_DBG("res %16phN", res);
 
 	return err;
 }
 
-static int smp_g2(struct crypto_shash *tfm_cmac, const u8 u[32], const u8 v[32],
-		  const u8 x[16], const u8 y[16], u32 *val)
+static int smp_g2(const u8 u[32], const u8 v[32], const u8 x[16],
+		  const u8 y[16], u32 *val)
 {
 	u8 m[80], tmp[16];
 	int err;
 
 	SMP_DBG("u %32phN", u);
@@ -322,11 +306,11 @@ static int smp_g2(struct crypto_shash *tfm_cmac, const u8 u[32], const u8 v[32],
 
 	memcpy(m, y, 16);
 	memcpy(m + 16, v, 32);
 	memcpy(m + 48, u, 32);
 
-	err = aes_cmac(tfm_cmac, x, m, sizeof(m), tmp);
+	err = smp_aes_cmac(x, m, sizeof(m), tmp);
 	if (err)
 		return err;
 
 	*val = get_unaligned_le32(tmp);
 	*val %= 1000000;
@@ -334,34 +318,32 @@ static int smp_g2(struct crypto_shash *tfm_cmac, const u8 u[32], const u8 v[32],
 	SMP_DBG("val %06u", *val);
 
 	return 0;
 }
 
-static int smp_h6(struct crypto_shash *tfm_cmac, const u8 w[16],
-		  const u8 key_id[4], u8 res[16])
+static int smp_h6(const u8 w[16], const u8 key_id[4], u8 res[16])
 {
 	int err;
 
 	SMP_DBG("w %16phN key_id %4phN", w, key_id);
 
-	err = aes_cmac(tfm_cmac, w, key_id, 4, res);
+	err = smp_aes_cmac(w, key_id, 4, res);
 	if (err)
 		return err;
 
 	SMP_DBG("res %16phN", res);
 
 	return err;
 }
 
-static int smp_h7(struct crypto_shash *tfm_cmac, const u8 w[16],
-		  const u8 salt[16], u8 res[16])
+static int smp_h7(const u8 w[16], const u8 salt[16], u8 res[16])
 {
 	int err;
 
 	SMP_DBG("w %16phN salt %16phN", w, salt);
 
-	err = aes_cmac(tfm_cmac, salt, w, 16, res);
+	err = smp_aes_cmac(salt, w, 16, res);
 	if (err)
 		return err;
 
 	SMP_DBG("res %16phN", res);
 
@@ -572,12 +554,11 @@ int smp_generate_oob(struct hci_dev *hdev, u8 hash[16], u8 rand[16])
 	SMP_DBG("OOB Public Key X: %32phN", smp->local_pk);
 	SMP_DBG("OOB Public Key Y: %32phN", smp->local_pk + 32);
 
 	get_random_bytes(smp->local_rand, 16);
 
-	err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->local_pk,
-		     smp->local_rand, 0, hash);
+	err = smp_f4(smp->local_pk, smp->local_pk, smp->local_rand, 0, hash);
 	if (err < 0)
 		return err;
 
 	memcpy(rand, smp->local_rand, 16);
 
@@ -755,11 +736,10 @@ static void smp_chan_destroy(struct l2cap_conn *conn)
 
 	kfree_sensitive(smp->csrk);
 	kfree_sensitive(smp->responder_csrk);
 	kfree_sensitive(smp->link_key);
 
-	crypto_free_shash(smp->tfm_cmac);
 	crypto_free_kpp(smp->tfm_ecdh);
 
 	/* Ensure that we don't leave any debug key around if debug key
 	 * support hasn't been explicitly enabled.
 	 */
@@ -1161,27 +1141,27 @@ static void sc_generate_link_key(struct smp_chan *smp)
 
 	if (test_bit(SMP_FLAG_CT2, &smp->flags)) {
 		/* SALT = 0x000000000000000000000000746D7031 */
 		const u8 salt[16] = { 0x31, 0x70, 0x6d, 0x74 };
 
-		if (smp_h7(smp->tfm_cmac, smp->tk, salt, smp->link_key)) {
+		if (smp_h7(smp->tk, salt, smp->link_key)) {
 			kfree_sensitive(smp->link_key);
 			smp->link_key = NULL;
 			return;
 		}
 	} else {
 		/* From core spec. Spells out in ASCII as 'tmp1'. */
 		const u8 tmp1[4] = { 0x31, 0x70, 0x6d, 0x74 };
 
-		if (smp_h6(smp->tfm_cmac, smp->tk, tmp1, smp->link_key)) {
+		if (smp_h6(smp->tk, tmp1, smp->link_key)) {
 			kfree_sensitive(smp->link_key);
 			smp->link_key = NULL;
 			return;
 		}
 	}
 
-	if (smp_h6(smp->tfm_cmac, smp->link_key, lebr, smp->link_key)) {
+	if (smp_h6(smp->link_key, lebr, smp->link_key)) {
 		kfree_sensitive(smp->link_key);
 		smp->link_key = NULL;
 		return;
 	}
 }
@@ -1219,21 +1199,21 @@ static void sc_generate_ltk(struct smp_chan *smp)
 
 	if (test_bit(SMP_FLAG_CT2, &smp->flags)) {
 		/* SALT = 0x000000000000000000000000746D7032 */
 		const u8 salt[16] = { 0x32, 0x70, 0x6d, 0x74 };
 
-		if (smp_h7(smp->tfm_cmac, key->val, salt, smp->tk))
+		if (smp_h7(key->val, salt, smp->tk))
 			return;
 	} else {
 		/* From core spec. Spells out in ASCII as 'tmp2'. */
 		const u8 tmp2[4] = { 0x32, 0x70, 0x6d, 0x74 };
 
-		if (smp_h6(smp->tfm_cmac, key->val, tmp2, smp->tk))
+		if (smp_h6(key->val, tmp2, smp->tk))
 			return;
 	}
 
-	if (smp_h6(smp->tfm_cmac, smp->tk, brle, smp->tk))
+	if (smp_h6(smp->tk, brle, smp->tk))
 		return;
 
 	sc_add_ltk(smp);
 }
 
@@ -1390,20 +1370,14 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 
 	smp = kzalloc(sizeof(*smp), GFP_ATOMIC);
 	if (!smp)
 		return NULL;
 
-	smp->tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(smp->tfm_cmac)) {
-		bt_dev_err(hcon->hdev, "Unable to create CMAC crypto context");
-		goto zfree_smp;
-	}
-
 	smp->tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0);
 	if (IS_ERR(smp->tfm_ecdh)) {
 		bt_dev_err(hcon->hdev, "Unable to create ECDH crypto context");
-		goto free_shash;
+		goto zfree_smp;
 	}
 
 	smp->conn = conn;
 	chan->data = smp;
 
@@ -1413,12 +1387,10 @@ static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
 
 	hci_conn_hold(hcon);
 
 	return smp;
 
-free_shash:
-	crypto_free_shash(smp->tfm_cmac);
 zfree_smp:
 	kfree_sensitive(smp);
 	return NULL;
 }
 
@@ -1438,11 +1410,11 @@ static int sc_mackey_and_ltk(struct smp_chan *smp, u8 mackey[16], u8 ltk[16])
 	memcpy(a, &hcon->init_addr, 6);
 	memcpy(b, &hcon->resp_addr, 6);
 	a[6] = hcon->init_addr_type;
 	b[6] = hcon->resp_addr_type;
 
-	return smp_f5(smp->tfm_cmac, smp->dhkey, na, nb, a, b, mackey, ltk);
+	return smp_f5(smp->dhkey, na, nb, a, b, mackey, ltk);
 }
 
 static void sc_dhkey_check(struct smp_chan *smp)
 {
 	struct hci_conn *hcon = smp->conn->hcon;
@@ -1471,12 +1443,12 @@ static void sc_dhkey_check(struct smp_chan *smp)
 		put_unaligned_le32(hcon->passkey_notify, r);
 
 	if (smp->method == REQ_OOB)
 		memcpy(r, smp->rr, 16);
 
-	smp_f6(smp->tfm_cmac, smp->mackey, smp->prnd, smp->rrnd, r, io_cap,
-	       local_addr, remote_addr, check.e);
+	smp_f6(smp->mackey, smp->prnd, smp->rrnd, r, io_cap, local_addr,
+	       remote_addr, check.e);
 
 	smp_send_cmd(smp->conn, SMP_CMD_DHKEY_CHECK, sizeof(check), &check);
 }
 
 static u8 sc_passkey_send_confirm(struct smp_chan *smp)
@@ -1489,11 +1461,11 @@ static u8 sc_passkey_send_confirm(struct smp_chan *smp)
 	r = ((hcon->passkey_notify >> smp->passkey_round) & 0x01);
 	r |= 0x80;
 
 	get_random_bytes(smp->prnd, sizeof(smp->prnd));
 
-	if (smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd, r,
+	if (smp_f4(smp->local_pk, smp->remote_pk, smp->prnd, r,
 		   cfm.confirm_val))
 		return SMP_UNSPECIFIED;
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cfm), &cfm);
 
@@ -1514,12 +1486,11 @@ static u8 sc_passkey_round(struct smp_chan *smp, u8 smp_op)
 	switch (smp_op) {
 	case SMP_CMD_PAIRING_RANDOM:
 		r = ((hcon->passkey_notify >> smp->passkey_round) & 0x01);
 		r |= 0x80;
 
-		if (smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk,
-			   smp->rrnd, r, cfm))
+		if (smp_f4(smp->remote_pk, smp->local_pk, smp->rrnd, r, cfm))
 			return SMP_UNSPECIFIED;
 
 		if (crypto_memneq(smp->pcnf, cfm, 16))
 			return SMP_CONFIRM_FAILED;
 
@@ -2175,12 +2146,11 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 		return sc_passkey_round(smp, SMP_CMD_PAIRING_RANDOM);
 
 	if (test_bit(SMP_FLAG_INITIATOR, &smp->flags)) {
 		u8 cfm[16];
 
-		err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->local_pk,
-			     smp->rrnd, 0, cfm);
+		err = smp_f4(smp->remote_pk, smp->local_pk, smp->rrnd, 0, cfm);
 		if (err)
 			return SMP_UNSPECIFIED;
 
 		if (crypto_memneq(smp->pcnf, cfm, 16))
 			return SMP_CONFIRM_FAILED;
@@ -2202,11 +2172,11 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 			SMP_ALLOW_CMD(smp, SMP_CMD_DHKEY_CHECK);
 		}
 		return 0;
 	}
 
-	err = smp_g2(smp->tfm_cmac, pkax, pkbx, na, nb, &passkey);
+	err = smp_g2(pkax, pkbx, na, nb, &passkey);
 	if (err)
 		return SMP_UNSPECIFIED;
 
 	/* Always require user confirmation for Just-Works pairing to prevent
 	 * impersonation attacks, or in case of a legitimate device that is
@@ -2747,12 +2717,12 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 	}
 
 	memcpy(smp->remote_pk, key, 64);
 
 	if (test_bit(SMP_FLAG_REMOTE_OOB, &smp->flags)) {
-		err = smp_f4(smp->tfm_cmac, smp->remote_pk, smp->remote_pk,
-			     smp->rr, 0, cfm.confirm_val);
+		err = smp_f4(smp->remote_pk, smp->remote_pk, smp->rr, 0,
+			     cfm.confirm_val);
 		if (err)
 			return SMP_UNSPECIFIED;
 
 		if (crypto_memneq(cfm.confirm_val, smp->pcnf, 16))
 			return SMP_CONFIRM_FAILED;
@@ -2848,12 +2818,12 @@ static int smp_cmd_public_key(struct l2cap_conn *conn, struct sk_buff *skb)
 	 * send the confirm value.
 	 */
 	if (test_bit(SMP_FLAG_INITIATOR, &smp->flags))
 		return 0;
 
-	err = smp_f4(smp->tfm_cmac, smp->local_pk, smp->remote_pk, smp->prnd,
-		     0, cfm.confirm_val);
+	err = smp_f4(smp->local_pk, smp->remote_pk, smp->prnd, 0,
+		     cfm.confirm_val);
 	if (err)
 		return SMP_UNSPECIFIED;
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cfm), &cfm);
 	SMP_ALLOW_CMD(smp, SMP_CMD_PAIRING_RANDOM);
@@ -2896,12 +2866,12 @@ static int smp_cmd_dhkey_check(struct l2cap_conn *conn, struct sk_buff *skb)
 	if (smp->method == REQ_PASSKEY || smp->method == DSP_PASSKEY)
 		put_unaligned_le32(hcon->passkey_notify, r);
 	else if (smp->method == REQ_OOB)
 		memcpy(r, smp->lr, 16);
 
-	err = smp_f6(smp->tfm_cmac, smp->mackey, smp->rrnd, smp->prnd, r,
-		     io_cap, remote_addr, local_addr, e);
+	err = smp_f6(smp->mackey, smp->rrnd, smp->prnd, r, io_cap, remote_addr,
+		     local_addr, e);
 	if (err)
 		return SMP_UNSPECIFIED;
 
 	if (crypto_memneq(check->e, e, 16))
 		return SMP_DHKEY_CHECK_FAILED;
@@ -3283,11 +3253,10 @@ static const struct l2cap_ops smp_root_chan_ops = {
 
 static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
 {
 	struct l2cap_chan *chan;
 	struct smp_dev *smp;
-	struct crypto_shash *tfm_cmac;
 	struct crypto_kpp *tfm_ecdh;
 
 	if (cid == L2CAP_CID_SMP_BREDR) {
 		smp = NULL;
 		goto create_chan;
@@ -3295,34 +3264,24 @@ static struct l2cap_chan *smp_add_cid(struct hci_dev *hdev, u16 cid)
 
 	smp = kzalloc(sizeof(*smp), GFP_KERNEL);
 	if (!smp)
 		return ERR_PTR(-ENOMEM);
 
-	tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(tfm_cmac)) {
-		bt_dev_err(hdev, "Unable to create CMAC crypto context");
-		kfree_sensitive(smp);
-		return ERR_CAST(tfm_cmac);
-	}
-
 	tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0);
 	if (IS_ERR(tfm_ecdh)) {
 		bt_dev_err(hdev, "Unable to create ECDH crypto context");
-		crypto_free_shash(tfm_cmac);
 		kfree_sensitive(smp);
 		return ERR_CAST(tfm_ecdh);
 	}
 
 	smp->local_oob = false;
-	smp->tfm_cmac = tfm_cmac;
 	smp->tfm_ecdh = tfm_ecdh;
 
 create_chan:
 	chan = l2cap_chan_create();
 	if (!chan) {
 		if (smp) {
-			crypto_free_shash(smp->tfm_cmac);
 			crypto_free_kpp(smp->tfm_ecdh);
 			kfree_sensitive(smp);
 		}
 		return ERR_PTR(-ENOMEM);
 	}
@@ -3365,11 +3324,10 @@ static void smp_del_chan(struct l2cap_chan *chan)
 	BT_DBG("chan %p", chan);
 
 	smp = chan->data;
 	if (smp) {
 		chan->data = NULL;
-		crypto_free_shash(smp->tfm_cmac);
 		crypto_free_kpp(smp->tfm_ecdh);
 		kfree_sensitive(smp);
 	}
 
 	l2cap_chan_put(chan);
@@ -3562,11 +3520,11 @@ static int __init test_s1(void)
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_f4(struct crypto_shash *tfm_cmac)
+static int __init test_f4(void)
 {
 	const u8 u[32] = {
 			0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
 			0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
 			0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
@@ -3584,21 +3542,21 @@ static int __init test_f4(struct crypto_shash *tfm_cmac)
 			0x2d, 0x87, 0x74, 0xa9, 0xbe, 0xa1, 0xed, 0xf1,
 			0x1c, 0xbd, 0xa9, 0x07, 0xf1, 0x16, 0xc9, 0xf2 };
 	u8 res[16];
 	int err;
 
-	err = smp_f4(tfm_cmac, u, v, x, z, res);
+	err = smp_f4(u, v, x, z, res);
 	if (err)
 		return err;
 
 	if (crypto_memneq(res, exp, 16))
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_f5(struct crypto_shash *tfm_cmac)
+static int __init test_f5(void)
 {
 	const u8 w[32] = {
 			0x98, 0xa6, 0xbf, 0x73, 0xf3, 0x34, 0x8d, 0x86,
 			0xf1, 0x66, 0xf8, 0xb4, 0x13, 0x6b, 0x79, 0x99,
 			0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,
@@ -3618,11 +3576,11 @@ static int __init test_f5(struct crypto_shash *tfm_cmac)
 			0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,
 			0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 };
 	u8 mackey[16], ltk[16];
 	int err;
 
-	err = smp_f5(tfm_cmac, w, n1, n2, a1, a2, mackey, ltk);
+	err = smp_f5(w, n1, n2, a1, a2, mackey, ltk);
 	if (err)
 		return err;
 
 	if (crypto_memneq(mackey, exp_mackey, 16))
 		return -EINVAL;
@@ -3631,11 +3589,11 @@ static int __init test_f5(struct crypto_shash *tfm_cmac)
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_f6(struct crypto_shash *tfm_cmac)
+static int __init test_f6(void)
 {
 	const u8 w[16] = {
 			0x20, 0x6e, 0x63, 0xce, 0x20, 0x6a, 0x3f, 0xfd,
 			0x02, 0x4a, 0x08, 0xa1, 0x76, 0xf1, 0x65, 0x29 };
 	const u8 n1[16] = {
@@ -3654,21 +3612,21 @@ static int __init test_f6(struct crypto_shash *tfm_cmac)
 			0x61, 0x8f, 0x95, 0xda, 0x09, 0x0b, 0x6c, 0xd2,
 			0xc5, 0xe8, 0xd0, 0x9c, 0x98, 0x73, 0xc4, 0xe3 };
 	u8 res[16];
 	int err;
 
-	err = smp_f6(tfm_cmac, w, n1, n2, r, io_cap, a1, a2, res);
+	err = smp_f6(w, n1, n2, r, io_cap, a1, a2, res);
 	if (err)
 		return err;
 
 	if (crypto_memneq(res, exp, 16))
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_g2(struct crypto_shash *tfm_cmac)
+static int __init test_g2(void)
 {
 	const u8 u[32] = {
 			0xe6, 0x9d, 0x35, 0x0e, 0x48, 0x01, 0x03, 0xcc,
 			0xdb, 0xfd, 0xf4, 0xac, 0x11, 0x91, 0xf4, 0xef,
 			0xb9, 0xa5, 0xf9, 0xe9, 0xa7, 0x83, 0x2c, 0x5e,
@@ -3686,21 +3644,21 @@ static int __init test_g2(struct crypto_shash *tfm_cmac)
 			0x6e, 0x5f, 0xa7, 0x25, 0xcc, 0xe7, 0xe8, 0xa6 };
 	const u32 exp_val = 0x2f9ed5ba % 1000000;
 	u32 val;
 	int err;
 
-	err = smp_g2(tfm_cmac, u, v, x, y, &val);
+	err = smp_g2(u, v, x, y, &val);
 	if (err)
 		return err;
 
 	if (val != exp_val)
 		return -EINVAL;
 
 	return 0;
 }
 
-static int __init test_h6(struct crypto_shash *tfm_cmac)
+static int __init test_h6(void)
 {
 	const u8 w[16] = {
 			0x9b, 0x7d, 0x39, 0x0a, 0xa6, 0x10, 0x10, 0x34,
 			0x05, 0xad, 0xc8, 0x57, 0xa3, 0x34, 0x02, 0xec };
 	const u8 key_id[4] = { 0x72, 0x62, 0x65, 0x6c };
@@ -3708,11 +3666,11 @@ static int __init test_h6(struct crypto_shash *tfm_cmac)
 			0x99, 0x63, 0xb1, 0x80, 0xe2, 0xa9, 0xd3, 0xe8,
 			0x1c, 0xc9, 0x6d, 0xe7, 0x02, 0xe1, 0x9a, 0x2d };
 	u8 res[16];
 	int err;
 
-	err = smp_h6(tfm_cmac, w, key_id, res);
+	err = smp_h6(w, key_id, res);
 	if (err)
 		return err;
 
 	if (crypto_memneq(res, exp, 16))
 		return -EINVAL;
@@ -3733,12 +3691,11 @@ static const struct file_operations test_smp_fops = {
 	.open		= simple_open,
 	.read		= test_smp_read,
 	.llseek		= default_llseek,
 };
 
-static int __init run_selftests(struct crypto_shash *tfm_cmac,
-				struct crypto_kpp *tfm_ecdh)
+static int __init run_selftests(struct crypto_kpp *tfm_ecdh)
 {
 	ktime_t calltime, delta, rettime;
 	unsigned long long duration;
 	int err;
 
@@ -3766,35 +3723,35 @@ static int __init run_selftests(struct crypto_shash *tfm_cmac,
 	if (err) {
 		BT_ERR("smp_s1 test failed");
 		goto done;
 	}
 
-	err = test_f4(tfm_cmac);
+	err = test_f4();
 	if (err) {
 		BT_ERR("smp_f4 test failed");
 		goto done;
 	}
 
-	err = test_f5(tfm_cmac);
+	err = test_f5();
 	if (err) {
 		BT_ERR("smp_f5 test failed");
 		goto done;
 	}
 
-	err = test_f6(tfm_cmac);
+	err = test_f6();
 	if (err) {
 		BT_ERR("smp_f6 test failed");
 		goto done;
 	}
 
-	err = test_g2(tfm_cmac);
+	err = test_g2();
 	if (err) {
 		BT_ERR("smp_g2 test failed");
 		goto done;
 	}
 
-	err = test_h6(tfm_cmac);
+	err = test_h6();
 	if (err) {
 		BT_ERR("smp_h6 test failed");
 		goto done;
 	}
 
@@ -3817,30 +3774,21 @@ static int __init run_selftests(struct crypto_shash *tfm_cmac,
 	return err;
 }
 
 int __init bt_selftest_smp(void)
 {
-	struct crypto_shash *tfm_cmac;
 	struct crypto_kpp *tfm_ecdh;
 	int err;
 
-	tfm_cmac = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(tfm_cmac)) {
-		BT_ERR("Unable to create CMAC crypto context");
-		return PTR_ERR(tfm_cmac);
-	}
-
 	tfm_ecdh = crypto_alloc_kpp("ecdh-nist-p256", 0, 0);
 	if (IS_ERR(tfm_ecdh)) {
 		BT_ERR("Unable to create ECDH crypto context");
-		crypto_free_shash(tfm_cmac);
 		return PTR_ERR(tfm_ecdh);
 	}
 
-	err = run_selftests(tfm_cmac, tfm_ecdh);
+	err = run_selftests(tfm_ecdh);
 
-	crypto_free_shash(tfm_cmac);
 	crypto_free_kpp(tfm_ecdh);
 
 	return err;
 }
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 14/15] wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac()
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (12 preceding siblings ...)
  2026-02-18 21:34 ` [PATCH 13/15] Bluetooth: SMP: Use AES-CMAC library API Eric Biggers
@ 2026-02-18 21:35 ` Eric Biggers
  2026-02-19 11:00   ` Johannes Berg
  2026-02-18 21:35 ` [PATCH 15/15] wifi: mac80211: Use AES-CMAC library in aes_s2v() Eric Biggers
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:35 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Now that AES-CMAC has a library API, convert the mac80211 AES-CMAC
packet authentication code to use it instead of a "cmac(aes)"
crypto_shash.  This has multiple benefits, such as:

- It's faster.  The AES-CMAC code is now called directly, without
  unnecessary overhead such as indirect calls.

- MAC calculation can no longer fail.

- The AES-CMAC key struct is now a fixed size, allowing it to be
  embedded directly into 'struct ieee80211_key' rather than using a
  separate allocation.  Note that although this increases the size of
  the 'u.cmac' field of 'struct ieee80211_key', it doesn't cause it to
  exceed the size of the largest variant of the union 'u'.  Therefore,
  the size of 'struct ieee80211_key' itself is unchanged.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 net/mac80211/Kconfig    |  1 +
 net/mac80211/aes_cmac.c | 65 ++++++++---------------------------------
 net/mac80211/aes_cmac.h | 12 +++-----
 net/mac80211/key.c      | 11 ++-----
 net/mac80211/key.h      |  3 +-
 net/mac80211/wpa.c      | 13 +++------
 6 files changed, 26 insertions(+), 79 deletions(-)

diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index cf0f7780fb10..0afbe4f4f976 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -1,10 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
 config MAC80211
 	tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
 	depends on CFG80211
 	select CRYPTO
+	select CRYPTO_LIB_AES_CBC_MACS
 	select CRYPTO_LIB_ARC4
 	select CRYPTO_AES
 	select CRYPTO_CCM
 	select CRYPTO_GCM
 	select CRYPTO_CMAC
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c
index 0827965455dc..55b674ad7d7a 100644
--- a/net/mac80211/aes_cmac.c
+++ b/net/mac80211/aes_cmac.c
@@ -5,80 +5,39 @@
  * Copyright (C) 2020 Intel Corporation
  */
 
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/crypto.h>
 #include <linux/export.h>
 #include <linux/err.h>
-#include <crypto/aes.h>
+#include <crypto/aes-cbc-macs.h>
 
 #include <net/mac80211.h>
 #include "key.h"
 #include "aes_cmac.h"
 
 #define AAD_LEN 20
 
 static const u8 zero[IEEE80211_CMAC_256_MIC_LEN];
 
-int ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad,
-		       const u8 *data, size_t data_len, u8 *mic,
-		       unsigned int mic_len)
+void ieee80211_aes_cmac(const struct aes_cmac_key *key, const u8 *aad,
+			const u8 *data, size_t data_len, u8 *mic,
+			unsigned int mic_len)
 {
-	int err;
-	SHASH_DESC_ON_STACK(desc, tfm);
+	struct aes_cmac_ctx ctx;
 	u8 out[AES_BLOCK_SIZE];
 	const __le16 *fc;
 
-	desc->tfm = tfm;
-
-	err = crypto_shash_init(desc);
-	if (err)
-		return err;
-	err = crypto_shash_update(desc, aad, AAD_LEN);
-	if (err)
-		return err;
+	aes_cmac_init(&ctx, key);
+	aes_cmac_update(&ctx, aad, AAD_LEN);
 	fc = (const __le16 *)aad;
 	if (ieee80211_is_beacon(*fc)) {
 		/* mask Timestamp field to zero */
-		err = crypto_shash_update(desc, zero, 8);
-		if (err)
-			return err;
-		err = crypto_shash_update(desc, data + 8,
-					  data_len - 8 - mic_len);
-		if (err)
-			return err;
+		aes_cmac_update(&ctx, zero, 8);
+		aes_cmac_update(&ctx, data + 8, data_len - 8 - mic_len);
 	} else {
-		err = crypto_shash_update(desc, data, data_len - mic_len);
-		if (err)
-			return err;
+		aes_cmac_update(&ctx, data, data_len - mic_len);
 	}
-	err = crypto_shash_finup(desc, zero, mic_len, out);
-	if (err)
-		return err;
+	aes_cmac_update(&ctx, zero, mic_len);
+	aes_cmac_final(&ctx, out);
 	memcpy(mic, out, mic_len);
-
-	return 0;
-}
-
-struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[],
-						  size_t key_len)
-{
-	struct crypto_shash *tfm;
-
-	tfm = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (!IS_ERR(tfm)) {
-		int err = crypto_shash_setkey(tfm, key, key_len);
-
-		if (err) {
-			crypto_free_shash(tfm);
-			return ERR_PTR(err);
-		}
-	}
-
-	return tfm;
-}
-
-void ieee80211_aes_cmac_key_free(struct crypto_shash *tfm)
-{
-	crypto_free_shash(tfm);
 }
diff --git a/net/mac80211/aes_cmac.h b/net/mac80211/aes_cmac.h
index 5f971a8298cb..c7a6df47b327 100644
--- a/net/mac80211/aes_cmac.h
+++ b/net/mac80211/aes_cmac.h
@@ -4,16 +4,12 @@
  */
 
 #ifndef AES_CMAC_H
 #define AES_CMAC_H
 
-#include <linux/crypto.h>
-#include <crypto/hash.h>
+#include <crypto/aes-cbc-macs.h>
 
-struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[],
-						  size_t key_len);
-int ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad,
-		       const u8 *data, size_t data_len, u8 *mic,
-		       unsigned int mic_len);
-void ieee80211_aes_cmac_key_free(struct crypto_shash *tfm);
+void ieee80211_aes_cmac(const struct aes_cmac_key *key, const u8 *aad,
+			const u8 *data, size_t data_len, u8 *mic,
+			unsigned int mic_len);
 
 #endif /* AES_CMAC_H */
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 04c8809173d7..4b8965633df3 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -688,14 +688,13 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
 					seq[IEEE80211_CMAC_PN_LEN - j - 1];
 		/*
 		 * Initialize AES key state here as an optimization so that
 		 * it does not need to be initialized for every packet.
 		 */
-		key->u.aes_cmac.tfm =
-			ieee80211_aes_cmac_key_setup(key_data, key_len);
-		if (IS_ERR(key->u.aes_cmac.tfm)) {
-			err = PTR_ERR(key->u.aes_cmac.tfm);
+		err = aes_cmac_preparekey(&key->u.aes_cmac.key, key_data,
+					  key_len);
+		if (err) {
 			kfree(key);
 			return ERR_PTR(err);
 		}
 		break;
 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
@@ -748,14 +747,10 @@ static void ieee80211_key_free_common(struct ieee80211_key *key)
 	switch (key->conf.cipher) {
 	case WLAN_CIPHER_SUITE_CCMP:
 	case WLAN_CIPHER_SUITE_CCMP_256:
 		ieee80211_aes_key_free(key->u.ccmp.tfm);
 		break;
-	case WLAN_CIPHER_SUITE_AES_CMAC:
-	case WLAN_CIPHER_SUITE_BIP_CMAC_256:
-		ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
-		break;
 	case WLAN_CIPHER_SUITE_BIP_GMAC_128:
 	case WLAN_CIPHER_SUITE_BIP_GMAC_256:
 		ieee80211_aes_gmac_key_free(key->u.aes_gmac.tfm);
 		break;
 	case WLAN_CIPHER_SUITE_GCMP:
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 1fa0f4f78962..826e4e9387c5 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -10,10 +10,11 @@
 
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/crypto.h>
 #include <linux/rcupdate.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/arc4.h>
 #include <net/mac80211.h>
 
 #define NUM_DEFAULT_KEYS 4
 #define NUM_DEFAULT_MGMT_KEYS 2
@@ -91,11 +92,11 @@ struct ieee80211_key {
 			struct crypto_aead *tfm;
 			u32 replays; /* dot11RSNAStatsCCMPReplays */
 		} ccmp;
 		struct {
 			u8 rx_pn[IEEE80211_CMAC_PN_LEN];
-			struct crypto_shash *tfm;
+			struct aes_cmac_key key;
 			u32 replays; /* dot11RSNAStatsCMACReplays */
 			u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
 		} aes_cmac;
 		struct {
 			u8 rx_pn[IEEE80211_GMAC_PN_LEN];
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index fdf98c21d32c..59324b367bdd 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -870,15 +870,12 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx,
 	if (info->control.hw_key)
 		return TX_CONTINUE;
 
 	bip_aad(skb, aad);
 
-	if (ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad,
-			       skb->data + 24, skb->len - 24,
-			       mmie->mic, mic_len))
-		return TX_DROP;
-
+	ieee80211_aes_cmac(&key->u.aes_cmac.key, aad, skb->data + 24,
+			   skb->len - 24, mmie->mic, mic_len);
 	return TX_CONTINUE;
 }
 
 ieee80211_rx_result
 ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx,
@@ -916,14 +913,12 @@ ieee80211_crypto_aes_cmac_decrypt(struct ieee80211_rx_data *rx,
 	}
 
 	if (!(status->flag & RX_FLAG_DECRYPTED)) {
 		/* hardware didn't decrypt/verify MIC */
 		bip_aad(skb, aad);
-		if (ieee80211_aes_cmac(key->u.aes_cmac.tfm, aad,
-				       skb->data + 24, skb->len - 24,
-				       mic, mic_len))
-			return RX_DROP_U_DECRYPT_FAIL;
+		ieee80211_aes_cmac(&key->u.aes_cmac.key, aad, skb->data + 24,
+				   skb->len - 24, mic, mic_len);
 		if (crypto_memneq(mic, mmie->mic, mic_len)) {
 			key->u.aes_cmac.icverrors++;
 			return RX_DROP_U_MIC_FAIL;
 		}
 	}
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* [PATCH 15/15] wifi: mac80211: Use AES-CMAC library in aes_s2v()
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (13 preceding siblings ...)
  2026-02-18 21:35 ` [PATCH 14/15] wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac() Eric Biggers
@ 2026-02-18 21:35 ` Eric Biggers
  2026-02-19 11:01   ` Johannes Berg
  2026-02-19  9:25 ` [PATCH 00/15] AES-CMAC library Ard Biesheuvel
  2026-02-23 21:28 ` Eric Biggers
  16 siblings, 1 reply; 28+ messages in thread
From: Eric Biggers @ 2026-02-18 21:35 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, Eric Biggers

Now that AES-CMAC has a library API, convert aes_s2v() to use it instead
of a "cmac(aes)" crypto_shash.  The result is faster and simpler code.

It's also more reliable, since with the library the only step that can
fail is preparing the key.  In contrast, crypto_shash_digest(),
crypto_shash_init(), crypto_shash_update(), and crypto_shash_final()
could all fail and return an errno value.  aes_s2v() ignored these
errors, which was a bug.  So that bug is fixed as well.

As part of this, change the prototype of aes_s2v() to take the raw key
directly instead of a prepared key.  Its only two callers prepare a key
for each call, so it might as well be done directly in aes_s2v().

Since this removes the last dependency on the "cmac(aes)" crypto_shash
from mac80211, also remove the 'select CRYPTO_CMAC'.

Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
 net/mac80211/Kconfig     |  1 -
 net/mac80211/fils_aead.c | 48 ++++++++++++++--------------------------
 2 files changed, 17 insertions(+), 32 deletions(-)

diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 0afbe4f4f976..d6bc295e23a1 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -6,11 +6,10 @@ config MAC80211
 	select CRYPTO_LIB_AES_CBC_MACS
 	select CRYPTO_LIB_ARC4
 	select CRYPTO_AES
 	select CRYPTO_CCM
 	select CRYPTO_GCM
-	select CRYPTO_CMAC
 	select CRC32
 	help
 	  This option enables the hardware independent IEEE 802.11
 	  networking stack.
 
diff --git a/net/mac80211/fils_aead.c b/net/mac80211/fils_aead.c
index 912c46f74d24..d2f4a17eab99 100644
--- a/net/mac80211/fils_aead.c
+++ b/net/mac80211/fils_aead.c
@@ -2,17 +2,15 @@
 /*
  * FILS AEAD for (Re)Association Request/Response frames
  * Copyright 2016, Qualcomm Atheros, Inc.
  */
 
-#include <crypto/aes.h>
-#include <crypto/hash.h>
+#include <crypto/aes-cbc-macs.h>
 #include <crypto/skcipher.h>
 #include <crypto/utils.h>
 
 #include "ieee80211_i.h"
-#include "aes_cmac.h"
 #include "fils_aead.h"
 
 static void gf_mulx(u8 *pad)
 {
 	u64 a = get_unaligned_be64(pad);
@@ -20,58 +18,63 @@ static void gf_mulx(u8 *pad)
 
 	put_unaligned_be64((a << 1) | (b >> 63), pad);
 	put_unaligned_be64((b << 1) ^ ((a >> 63) ? 0x87 : 0), pad + 8);
 }
 
-static int aes_s2v(struct crypto_shash *tfm,
+static int aes_s2v(const u8 *in_key, size_t key_len,
 		   size_t num_elem, const u8 *addr[], size_t len[], u8 *v)
 {
 	u8 d[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE] = {};
-	SHASH_DESC_ON_STACK(desc, tfm);
+	struct aes_cmac_key key;
+	struct aes_cmac_ctx ctx;
 	size_t i;
+	int res;
 
-	desc->tfm = tfm;
+	res = aes_cmac_preparekey(&key, in_key, key_len);
+	if (res)
+		return res;
 
 	/* D = AES-CMAC(K, <zero>) */
-	crypto_shash_digest(desc, tmp, AES_BLOCK_SIZE, d);
+	aes_cmac(&key, tmp, AES_BLOCK_SIZE, d);
 
 	for (i = 0; i < num_elem - 1; i++) {
 		/* D = dbl(D) xor AES_CMAC(K, Si) */
 		gf_mulx(d); /* dbl */
-		crypto_shash_digest(desc, addr[i], len[i], tmp);
+		aes_cmac(&key, addr[i], len[i], tmp);
 		crypto_xor(d, tmp, AES_BLOCK_SIZE);
 	}
 
-	crypto_shash_init(desc);
+	aes_cmac_init(&ctx, &key);
 
 	if (len[i] >= AES_BLOCK_SIZE) {
 		/* len(Sn) >= 128 */
 		/* T = Sn xorend D */
-		crypto_shash_update(desc, addr[i], len[i] - AES_BLOCK_SIZE);
+		aes_cmac_update(&ctx, addr[i], len[i] - AES_BLOCK_SIZE);
 		crypto_xor(d, addr[i] + len[i] - AES_BLOCK_SIZE,
 			   AES_BLOCK_SIZE);
 	} else {
 		/* len(Sn) < 128 */
 		/* T = dbl(D) xor pad(Sn) */
 		gf_mulx(d); /* dbl */
 		crypto_xor(d, addr[i], len[i]);
 		d[len[i]] ^= 0x80;
 	}
 	/* V = AES-CMAC(K, T) */
-	crypto_shash_finup(desc, d, AES_BLOCK_SIZE, v);
+	aes_cmac_update(&ctx, d, AES_BLOCK_SIZE);
+	aes_cmac_final(&ctx, v);
 
+	memzero_explicit(&key, sizeof(key));
 	return 0;
 }
 
 /* Note: addr[] and len[] needs to have one extra slot at the end. */
 static int aes_siv_encrypt(const u8 *key, size_t key_len,
 			   const u8 *plain, size_t plain_len,
 			   size_t num_elem, const u8 *addr[],
 			   size_t len[], u8 *out)
 {
 	u8 v[AES_BLOCK_SIZE];
-	struct crypto_shash *tfm;
 	struct crypto_skcipher *tfm2;
 	struct skcipher_request *req;
 	int res;
 	struct scatterlist src[1], dst[1];
 	u8 *tmp;
@@ -81,19 +84,11 @@ static int aes_siv_encrypt(const u8 *key, size_t key_len,
 	addr[num_elem] = plain;
 	len[num_elem] = plain_len;
 	num_elem++;
 
 	/* S2V */
-
-	tfm = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(tfm))
-		return PTR_ERR(tfm);
-	/* K1 for S2V */
-	res = crypto_shash_setkey(tfm, key, key_len);
-	if (!res)
-		res = aes_s2v(tfm, num_elem, addr, len, v);
-	crypto_free_shash(tfm);
+	res = aes_s2v(key /* K1 */, key_len, num_elem, addr, len, v);
 	if (res)
 		return res;
 
 	/* Use a temporary buffer of the plaintext to handle need for
 	 * overwriting this during AES-CTR.
@@ -144,11 +139,10 @@ static int aes_siv_encrypt(const u8 *key, size_t key_len,
 static int aes_siv_decrypt(const u8 *key, size_t key_len,
 			   const u8 *iv_crypt, size_t iv_c_len,
 			   size_t num_elem, const u8 *addr[], size_t len[],
 			   u8 *out)
 {
-	struct crypto_shash *tfm;
 	struct crypto_skcipher *tfm2;
 	struct skcipher_request *req;
 	struct scatterlist src[1], dst[1];
 	size_t crypt_len;
 	int res;
@@ -196,19 +190,11 @@ static int aes_siv_decrypt(const u8 *key, size_t key_len,
 	crypto_free_skcipher(tfm2);
 	if (res)
 		return res;
 
 	/* S2V */
-
-	tfm = crypto_alloc_shash("cmac(aes)", 0, 0);
-	if (IS_ERR(tfm))
-		return PTR_ERR(tfm);
-	/* K1 for S2V */
-	res = crypto_shash_setkey(tfm, key, key_len);
-	if (!res)
-		res = aes_s2v(tfm, num_elem, addr, len, check);
-	crypto_free_shash(tfm);
+	res = aes_s2v(key /* K1 */, key_len, num_elem, addr, len, check);
 	if (res)
 		return res;
 	if (memcmp(check, frame_iv, AES_BLOCK_SIZE) != 0)
 		return -EINVAL;
 	return 0;
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 28+ messages in thread

* Re: [PATCH 11/15] smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature()
  2026-02-18 21:34 ` [PATCH 11/15] smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature() Eric Biggers
@ 2026-02-18 21:42   ` Steve French
  0 siblings, 0 replies; 28+ messages in thread
From: Steve French @ 2026-02-18 21:42 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-crypto, linux-kernel, Ard Biesheuvel, Jason A . Donenfeld,
	Herbert Xu, linux-arm-kernel, linux-cifs, linux-wireless

Acked-by: Steve French <stfrench@microsoft.com>

On Wed, Feb 18, 2026 at 3:38 PM Eric Biggers <ebiggers@kernel.org> wrote:
>
> Since the crypto library API is now being used instead of crypto_shash,
> all structs for MAC computation are now just fixed-size structs
> allocated on the stack; no dynamic allocations are ever required.
> Besides being much more efficient, this also means that the
> 'allocate_crypto' argument to smb2_calc_signature() and
> smb3_calc_signature() is no longer used.  Remove this unused argument.
>
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
> ---
>  fs/smb/client/smb2transport.c | 12 +++++-------
>  1 file changed, 5 insertions(+), 7 deletions(-)
>
> diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c
> index 0176185a1efc..41009039b4cb 100644
> --- a/fs/smb/client/smb2transport.c
> +++ b/fs/smb/client/smb2transport.c
> @@ -202,12 +202,11 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32  tid)
>
>         return tcon;
>  }
>
>  static int
> -smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
> -                   bool allocate_crypto)
> +smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
>  {
>         int rc;
>         unsigned char smb2_signature[SMB2_HMACSHA256_SIZE];
>         struct kvec *iov = rqst->rq_iov;
>         struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
> @@ -438,12 +437,11 @@ generate_smb311signingkey(struct cifs_ses *ses,
>
>         return generate_smb3signingkey(ses, server, &triplet);
>  }
>
>  static int
> -smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
> -                   bool allocate_crypto)
> +smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
>  {
>         int rc;
>         unsigned char smb3_signature[SMB2_CMACAES_SIZE];
>         struct kvec *iov = rqst->rq_iov;
>         struct smb2_hdr *shdr = (struct smb2_hdr *)iov[0].iov_base;
> @@ -451,11 +449,11 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server,
>         struct aes_cmac_ctx cmac_ctx;
>         struct smb_rqst drqst;
>         u8 key[SMB3_SIGN_KEY_SIZE];
>
>         if (server->vals->protocol_id <= SMB21_PROT_ID)
> -               return smb2_calc_signature(rqst, server, allocate_crypto);
> +               return smb2_calc_signature(rqst, server);
>
>         rc = smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key);
>         if (unlikely(rc)) {
>                 cifs_server_dbg(FYI, "%s: Could not get signing key\n", __func__);
>                 return rc;
> @@ -522,11 +520,11 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server)
>         if (!is_binding && !server->session_estab) {
>                 strscpy(shdr->Signature, "BSRSPYL");
>                 return 0;
>         }
>
> -       return smb3_calc_signature(rqst, server, false);
> +       return smb3_calc_signature(rqst, server);
>  }
>
>  int
>  smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
>  {
> @@ -558,11 +556,11 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server)
>          */
>         memcpy(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SIZE);
>
>         memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE);
>
> -       rc = smb3_calc_signature(rqst, server, true);
> +       rc = smb3_calc_signature(rqst, server);
>
>         if (rc)
>                 return rc;
>
>         if (crypto_memneq(server_response_sig, shdr->Signature,
> --
> 2.53.0
>
>


-- 
Thanks,

Steve

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 12/15] ksmbd: Use AES-CMAC library for SMB3 signature calculation
  2026-02-18 21:34 ` [PATCH 12/15] ksmbd: Use AES-CMAC library for SMB3 signature calculation Eric Biggers
@ 2026-02-19  1:49   ` Namjae Jeon
  0 siblings, 0 replies; 28+ messages in thread
From: Namjae Jeon @ 2026-02-19  1:49 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-crypto, linux-kernel, Ard Biesheuvel, Jason A . Donenfeld,
	Herbert Xu, linux-arm-kernel, linux-cifs, linux-wireless

On Thu, Feb 19, 2026 at 6:42 AM Eric Biggers <ebiggers@kernel.org> wrote:
>
> Now that AES-CMAC has a library API, convert ksmbd_sign_smb3_pdu() to
> use it instead of a "cmac(aes)" crypto_shash.
>
> The result is simpler and faster code.  With the library there's no need
> to dynamically allocate memory, no need to handle errors, and the
> AES-CMAC code is accessed directly without inefficient indirect calls
> and other unnecessary API overhead.
>
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Thanks!

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 03/15] crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit
  2026-02-18 21:34 ` [PATCH 03/15] crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit Eric Biggers
@ 2026-02-19  9:23   ` Ard Biesheuvel
  2026-02-19 21:26     ` Eric Biggers
  0 siblings, 1 reply; 28+ messages in thread
From: Ard Biesheuvel @ 2026-02-19  9:23 UTC (permalink / raw)
  To: Eric Biggers, linux-crypto
  Cc: linux-kernel, Jason A . Donenfeld, Herbert Xu, linux-arm-kernel,
	linux-cifs, linux-wireless, stable



On Wed, 18 Feb 2026, at 22:34, Eric Biggers wrote:
> Since the 'enc_after' argument to neon_aes_mac_update() and
> ce_aes_mac_update() has type 'int', it needs to be accessed using the
> corresponding 32-bit register, not the 64-bit register.  The upper half
> of the corresponding 64-bit register may contain garbage.
>

How could that happen? Setting the 32-bit alias of a GPR clears the upper half.

> Fixes: 4860620da7e5 ("crypto: arm64/aes - add NEON/Crypto Extensions 
> CBCMAC/CMAC/XCBC driver")
> Cc: stable@vger.kernel.org
> Signed-off-by: Eric Biggers <ebiggers@kernel.org>

Agree with the change but I don't think this needs a cc:stable (or a fixes tag)

> ---
>  arch/arm64/crypto/aes-modes.S | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/crypto/aes-modes.S b/arch/arm64/crypto/aes-modes.S
> index 0e834a2c062c..e793478f37c1 100644
> --- a/arch/arm64/crypto/aes-modes.S
> +++ b/arch/arm64/crypto/aes-modes.S
> @@ -836,11 +836,11 @@ AES_FUNC_START(aes_mac_update)
>  	encrypt_block	v0, w2, x1, x7, w8
>  	eor		v0.16b, v0.16b, v3.16b
>  	encrypt_block	v0, w2, x1, x7, w8
>  	eor		v0.16b, v0.16b, v4.16b
>  	cmp		w3, wzr
> -	csinv		x5, x6, xzr, eq
> +	csinv		w5, w6, wzr, eq
>  	cbz		w5, .Lmacout
>  	encrypt_block	v0, w2, x1, x7, w8
>  	st1		{v0.16b}, [x4]			/* return dg */
>  	cond_yield	.Lmacout, x7, x8
>  	b		.Lmacloop4x
> @@ -850,11 +850,11 @@ AES_FUNC_START(aes_mac_update)
>  	cbz		w3, .Lmacout
>  	ld1		{v1.16b}, [x0], #16		/* get next pt block */
>  	eor		v0.16b, v0.16b, v1.16b		/* ..and xor with dg */
> 
>  	subs		w3, w3, #1
> -	csinv		x5, x6, xzr, eq
> +	csinv		w5, w6, wzr, eq
>  	cbz		w5, .Lmacout
> 
>  .Lmacenc:
>  	encrypt_block	v0, w2, x1, x7, w8
>  	b		.Lmacloop
> -- 
> 2.53.0

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 00/15] AES-CMAC library
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (14 preceding siblings ...)
  2026-02-18 21:35 ` [PATCH 15/15] wifi: mac80211: Use AES-CMAC library in aes_s2v() Eric Biggers
@ 2026-02-19  9:25 ` Ard Biesheuvel
  2026-02-23 21:28 ` Eric Biggers
  16 siblings, 0 replies; 28+ messages in thread
From: Ard Biesheuvel @ 2026-02-19  9:25 UTC (permalink / raw)
  To: Eric Biggers, linux-crypto
  Cc: linux-kernel, Jason A . Donenfeld, Herbert Xu, linux-arm-kernel,
	linux-cifs, linux-wireless



On Wed, 18 Feb 2026, at 22:34, Eric Biggers wrote:
> This series can also be retrieved from:
>
>     git fetch 
> https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git 
> aes-cmac-v1
>
> This series adds support for AES CBC-based MACs to the crypto library,
> specifically AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC.  The
> implementation is fully optimized with the existing
> architecture-optimized AES code, either single-block AES en/decryption
> or arm64's neon_aes_mac_update() and ce_aes_mac_update().  As usual,
> optimizations are now enabled by default as well.
>
> AES-CMAC support will be useful for at least the SMB client and server,
> and the bluetooth and mac80211 drivers.  Patches 8-15 convert these
> users to use the crypto library API instead of crypto_shash, though
> these patches will likely go in via subsystem trees later.  They result
> in some significant simplifications and performance improvements.
>
> As usual, a KUnit test suite, FIPS self-test, and traditional crypto API
> wrapper algorithms are included as well.
>
> Note that I'm also planning to add additional AES modes to the library.
> This is just an initial set of AES modes to get things started.
> Notably, with the SMB client and server already using the SHA* and MD5
> libraries, "cmac(aes)" was the only remaining use of crypto_shash there.
> So it makes sense to take care of that.
>
> Eric Biggers (15):
>   lib/crypto: aes: Add support for CBC-based MACs
>   crypto: aes - Add cmac, xcbc, and cbcmac algorithms using library
>   crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit
>   lib/crypto: arm64/aes: Move assembly code for AES modes into libaes
>   lib/crypto: arm64/aes: Migrate optimized CBC-based MACs into library
>   lib/crypto: tests: Add KUnit tests for CBC-based MACs
>   lib/crypto: aes: Add FIPS self-test for CMAC
>   smb: client: Use AES-CMAC library for SMB3 signature calculation
>   smb: client: Remove obsolete cmac(aes) allocation
>   smb: client: Make generate_key() return void
>   smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature()
>   ksmbd: Use AES-CMAC library for SMB3 signature calculation
>   Bluetooth: SMP: Use AES-CMAC library API
>   wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac()
>   wifi: mac80211: Use AES-CMAC library in aes_s2v()
>

Reviewed-by: Ard Biesheuvel <ardb@kernel.org>

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 14/15] wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac()
  2026-02-18 21:35 ` [PATCH 14/15] wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac() Eric Biggers
@ 2026-02-19 11:00   ` Johannes Berg
  2026-02-19 22:02     ` Eric Biggers
  0 siblings, 1 reply; 28+ messages in thread
From: Johannes Berg @ 2026-02-19 11:00 UTC (permalink / raw)
  To: Eric Biggers, linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless

On Wed, 2026-02-18 at 13:35 -0800, Eric Biggers wrote:
> Now that AES-CMAC has a library API, convert the mac80211 AES-CMAC
> packet authentication code to use it instead of a "cmac(aes)"
> crypto_shash.  This has multiple benefits, such as:
> 
> - It's faster.  The AES-CMAC code is now called directly, without
>   unnecessary overhead such as indirect calls.
> 
> - MAC calculation can no longer fail.
> 
> - The AES-CMAC key struct is now a fixed size, allowing it to be
>   embedded directly into 'struct ieee80211_key' rather than using a
>   separate allocation.  Note that although this increases the size of
>   the 'u.cmac' field of 'struct ieee80211_key', it doesn't cause it to
>   exceed the size of the largest variant of the union 'u'.  Therefore,
>   the size of 'struct ieee80211_key' itself is unchanged.
> 

Looks good to me in principle, I suppose we should test it? :)

> +		err = aes_cmac_preparekey(&key->u.aes_cmac.key, key_data,
> +					  key_len);
> +		if (err) {
>  			kfree(key);
>  			return ERR_PTR(err);
>  		}

Pretty sure that can't fail, per the documentation for
aes_prepareenckey() and then aes_cmac_preparekey(), but it doesn't
really matter. We can only get here with a key with size checked by
cfg80211_validate_key_settings() already.


Since you're probably going to send it through the crypto tree:

Acked-by: Johannes Berg <johannes@sipsolutions.net>

johannes

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 15/15] wifi: mac80211: Use AES-CMAC library in aes_s2v()
  2026-02-18 21:35 ` [PATCH 15/15] wifi: mac80211: Use AES-CMAC library in aes_s2v() Eric Biggers
@ 2026-02-19 11:01   ` Johannes Berg
  2026-02-19 22:15     ` Eric Biggers
  0 siblings, 1 reply; 28+ messages in thread
From: Johannes Berg @ 2026-02-19 11:01 UTC (permalink / raw)
  To: Eric Biggers, linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless

On Wed, 2026-02-18 at 13:35 -0800, Eric Biggers wrote:
> Now that AES-CMAC has a library API, convert aes_s2v() to use it instead
> of a "cmac(aes)" crypto_shash.  The result is faster and simpler code.
> 
> It's also more reliable, since with the library the only step that can
> fail is preparing the key.  In contrast, crypto_shash_digest(),
> crypto_shash_init(), crypto_shash_update(), and crypto_shash_final()
> could all fail and return an errno value.  aes_s2v() ignored these
> errors, which was a bug.  So that bug is fixed as well.
> 
> As part of this, change the prototype of aes_s2v() to take the raw key
> directly instead of a prepared key.  Its only two callers prepare a key
> for each call, so it might as well be done directly in aes_s2v().
> 
> Since this removes the last dependency on the "cmac(aes)" crypto_shash
> from mac80211, also remove the 'select CRYPTO_CMAC'.
> 



> -static int aes_s2v(struct crypto_shash *tfm,
> +static int aes_s2v(const u8 *in_key, size_t key_len,
>  		   size_t num_elem, const u8 *addr[], size_t len[], u8 *v)
>  {
>  	u8 d[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE] = {};
> -	SHASH_DESC_ON_STACK(desc, tfm);
> +	struct aes_cmac_key key;
> +	struct aes_cmac_ctx ctx;
>  	size_t i;
> +	int res;
>  
> -	desc->tfm = tfm;
> +	res = aes_cmac_preparekey(&key, in_key, key_len);
> +	if (res)
> +		return res;

Same here, maybe, technically, but also doesn't matter.

Acked-by: Johannes Berg <johannes@sipsolutions.net>

johannes

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 03/15] crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit
  2026-02-19  9:23   ` Ard Biesheuvel
@ 2026-02-19 21:26     ` Eric Biggers
  0 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-19 21:26 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: linux-crypto, linux-kernel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless, stable

On Thu, Feb 19, 2026 at 10:23:39AM +0100, Ard Biesheuvel wrote:
> On Wed, 18 Feb 2026, at 22:34, Eric Biggers wrote:
> > Since the 'enc_after' argument to neon_aes_mac_update() and
> > ce_aes_mac_update() has type 'int', it needs to be accessed using the
> > corresponding 32-bit register, not the 64-bit register.  The upper half
> > of the corresponding 64-bit register may contain garbage.
> 
> How could that happen? Setting the 32-bit alias of a GPR clears the upper half.

The ABI doesn't guarantee that the upper 32 bits are cleared.  Try the
following:

void g(unsigned int a);

void f(unsigned long long a)
{
	g((unsigned int)a);
}

Both gcc and clang generate code that simply tail-calls g(), leaving the
upper 32 bits unchanged rather than zeroing them as per the cast:

0000000000000000 <f>:
       0: 14000000     	b	0x0 <f>

So it's possible.  Now, it's certainly unlikely to happen in practice,
as the real code doesn't use truncating casts like that, and the
instructions that write to the 32-bit registers clear the upper 64 bits
-- as you noted and as I've noted before in similar fixes (e.g.
https://lore.kernel.org/r/20251102234209.62133-2-ebiggers@kernel.org/).

So does it really matter?  Probably not.  However, given that the
correct behavior wasn't *guaranteed*, I think that to be safe we should
continue to consider patches like this to be bugfixes.

- Eric

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 14/15] wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac()
  2026-02-19 11:00   ` Johannes Berg
@ 2026-02-19 22:02     ` Eric Biggers
  2026-02-20  9:01       ` Johannes Berg
  0 siblings, 1 reply; 28+ messages in thread
From: Eric Biggers @ 2026-02-19 22:02 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-crypto, linux-kernel, Ard Biesheuvel, Jason A . Donenfeld,
	Herbert Xu, linux-arm-kernel, linux-cifs, linux-wireless

On Thu, Feb 19, 2026 at 12:00:03PM +0100, Johannes Berg wrote:
> On Wed, 2026-02-18 at 13:35 -0800, Eric Biggers wrote:
> > Now that AES-CMAC has a library API, convert the mac80211 AES-CMAC
> > packet authentication code to use it instead of a "cmac(aes)"
> > crypto_shash.  This has multiple benefits, such as:
> > 
> > - It's faster.  The AES-CMAC code is now called directly, without
> >   unnecessary overhead such as indirect calls.
> > 
> > - MAC calculation can no longer fail.
> > 
> > - The AES-CMAC key struct is now a fixed size, allowing it to be
> >   embedded directly into 'struct ieee80211_key' rather than using a
> >   separate allocation.  Note that although this increases the size of
> >   the 'u.cmac' field of 'struct ieee80211_key', it doesn't cause it to
> >   exceed the size of the largest variant of the union 'u'.  Therefore,
> >   the size of 'struct ieee80211_key' itself is unchanged.
> > 
> 
> Looks good to me in principle, I suppose we should test it? :)

Yes, I don't expect any issues, but testing of this patch would be
appreciated.  I don't know how to test every kernel subsystem.

> > +		err = aes_cmac_preparekey(&key->u.aes_cmac.key, key_data,
> > +					  key_len);
> > +		if (err) {
> >  			kfree(key);
> >  			return ERR_PTR(err);
> >  		}
> 
> Pretty sure that can't fail, per the documentation for
> aes_prepareenckey() and then aes_cmac_preparekey(), but it doesn't
> really matter. We can only get here with a key with size checked by
> cfg80211_validate_key_settings() already.

aes_cmac_preparekey() indeed always succeeds when passed a valid key
length, as documented in its kerneldoc.  But in this case I recommend
just checking the error code anyway, since ieee80211_key_alloc() can
already fail for other reasons (i.e., it needs the ability to report
errors anyway) and the key length isn't a compile-time constant here.

> Since you're probably going to send it through the crypto tree:
> 
> Acked-by: Johannes Berg <johannes@sipsolutions.net>

For library conversions like this I've usually been taking the library
itself through libcrypto-next, then sending the subsystem conversions
afterwards for subsystem maintainers to take in the next release.  But
I'd also be glad to just take this alongside the library itself.

- Eric

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 15/15] wifi: mac80211: Use AES-CMAC library in aes_s2v()
  2026-02-19 11:01   ` Johannes Berg
@ 2026-02-19 22:15     ` Eric Biggers
  2026-02-20  8:47       ` Johannes Berg
  0 siblings, 1 reply; 28+ messages in thread
From: Eric Biggers @ 2026-02-19 22:15 UTC (permalink / raw)
  To: Johannes Berg
  Cc: linux-crypto, linux-kernel, Ard Biesheuvel, Jason A . Donenfeld,
	Herbert Xu, linux-arm-kernel, linux-cifs, linux-wireless

On Thu, Feb 19, 2026 at 12:01:14PM +0100, Johannes Berg wrote:
> On Wed, 2026-02-18 at 13:35 -0800, Eric Biggers wrote:
> > Now that AES-CMAC has a library API, convert aes_s2v() to use it instead
> > of a "cmac(aes)" crypto_shash.  The result is faster and simpler code.
> > 
> > It's also more reliable, since with the library the only step that can
> > fail is preparing the key.  In contrast, crypto_shash_digest(),
> > crypto_shash_init(), crypto_shash_update(), and crypto_shash_final()
> > could all fail and return an errno value.  aes_s2v() ignored these
> > errors, which was a bug.  So that bug is fixed as well.
> > 
> > As part of this, change the prototype of aes_s2v() to take the raw key
> > directly instead of a prepared key.  Its only two callers prepare a key
> > for each call, so it might as well be done directly in aes_s2v().
> > 
> > Since this removes the last dependency on the "cmac(aes)" crypto_shash
> > from mac80211, also remove the 'select CRYPTO_CMAC'.
> > 
> 
> > -static int aes_s2v(struct crypto_shash *tfm,
> > +static int aes_s2v(const u8 *in_key, size_t key_len,
> >  		   size_t num_elem, const u8 *addr[], size_t len[], u8 *v)
> >  {
> >  	u8 d[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE] = {};
> > -	SHASH_DESC_ON_STACK(desc, tfm);
> > +	struct aes_cmac_key key;
> > +	struct aes_cmac_ctx ctx;
> >  	size_t i;
> > +	int res;
> >  
> > -	desc->tfm = tfm;
> > +	res = aes_cmac_preparekey(&key, in_key, key_len);
> > +	if (res)
> > +		return res;
> 
> Same here, maybe, technically, but also doesn't matter.
> 
> Acked-by: Johannes Berg <johannes@sipsolutions.net>
> 
> johannes

In this case aes_s2v() wouldn't otherwise be able to fail, so ignoring
the aes_cmac_preparekey() return value would indeed be a simplification.

However, since the key length isn't a compile-time constant here, we'd
have to rely on non-local validation, which isn't ideal.

To ignore the return value entirely I'd prefer a static_assert that the
length is equal to one of AES_KEYSIZE_*, which isn't possible here.

It's actually not clear to me where the length validation happens before
here.  nl80211_associate() for example just copies the length from
userspace without validating it.  ieee80211_mgd_assoc() only checks that
the length is at most FILS_MAX_KEK_LEN (64).

- Eric

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 15/15] wifi: mac80211: Use AES-CMAC library in aes_s2v()
  2026-02-19 22:15     ` Eric Biggers
@ 2026-02-20  8:47       ` Johannes Berg
  0 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2026-02-20  8:47 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-crypto, linux-kernel, Ard Biesheuvel, Jason A . Donenfeld,
	Herbert Xu, linux-arm-kernel, linux-cifs, linux-wireless

On Thu, 2026-02-19 at 14:15 -0800, Eric Biggers wrote:
> > > -static int aes_s2v(struct crypto_shash *tfm,
> > > +static int aes_s2v(const u8 *in_key, size_t key_len,
> > >  		   size_t num_elem, const u8 *addr[], size_t len[], u8 *v)
> > >  {
> > >  	u8 d[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE] = {};
> > > -	SHASH_DESC_ON_STACK(desc, tfm);
> > > +	struct aes_cmac_key key;
> > > +	struct aes_cmac_ctx ctx;
> > >  	size_t i;
> > > +	int res;
> > >  
> > > -	desc->tfm = tfm;
> > > +	res = aes_cmac_preparekey(&key, in_key, key_len);
> > > +	if (res)
> > > +		return res;
> > 
> > Same here, maybe, technically, but also doesn't matter.
> > 
> > Acked-by: Johannes Berg <johannes@sipsolutions.net>
> > 
> > johannes
> 
> In this case aes_s2v() wouldn't otherwise be able to fail, so ignoring
> the aes_cmac_preparekey() return value would indeed be a simplification.

Right.

> However, since the key length isn't a compile-time constant here, we'd
> have to rely on non-local validation, which isn't ideal.

That's true.

> To ignore the return value entirely I'd prefer a static_assert that the
> length is equal to one of AES_KEYSIZE_*, which isn't possible here.

Indeed.

> It's actually not clear to me where the length validation happens before
> here.  nl80211_associate() for example just copies the length from
> userspace without validating it.  ieee80211_mgd_assoc() only checks that
> the length is at most FILS_MAX_KEK_LEN (64).

Oh, right, I forgot this was FILS and mixed it up with the previous
patch. We probably _should_ check it earlier there, but it won't be
local here either way, and we have the error paths already so that's
fine.

johannes

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 14/15] wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac()
  2026-02-19 22:02     ` Eric Biggers
@ 2026-02-20  9:01       ` Johannes Berg
  0 siblings, 0 replies; 28+ messages in thread
From: Johannes Berg @ 2026-02-20  9:01 UTC (permalink / raw)
  To: Eric Biggers
  Cc: linux-crypto, linux-kernel, Ard Biesheuvel, Jason A . Donenfeld,
	Herbert Xu, linux-arm-kernel, linux-cifs, linux-wireless

On Thu, 2026-02-19 at 14:02 -0800, Eric Biggers wrote:
> > Looks good to me in principle, I suppose we should test it? :)
> 
> Yes, I don't expect any issues, but testing of this patch would be
> appreciated.  I don't know how to test every kernel subsystem.

Done, works fine. I checked FILS (which is against hostapd userspace
implementation) and validated the MME MIC against wlantest.

> > > +		err = aes_cmac_preparekey(&key->u.aes_cmac.key, key_data,
> > > +					  key_len);
> > > +		if (err) {
> > >  			kfree(key);
> > >  			return ERR_PTR(err);
> > >  		}
> > 
> > Pretty sure that can't fail, per the documentation for
> > aes_prepareenckey() and then aes_cmac_preparekey(), but it doesn't
> > really matter. We can only get here with a key with size checked by
> > cfg80211_validate_key_settings() already.
> 
> aes_cmac_preparekey() indeed always succeeds when passed a valid key
> length, as documented in its kerneldoc.  But in this case I recommend
> just checking the error code anyway, since ieee80211_key_alloc() can
> already fail for other reasons (i.e., it needs the ability to report
> errors anyway) and the key length isn't a compile-time constant here.

Right, sure.

> > Since you're probably going to send it through the crypto tree:
> > 
> > Acked-by: Johannes Berg <johannes@sipsolutions.net>
> 
> For library conversions like this I've usually been taking the library
> itself through libcrypto-next, then sending the subsystem conversions
> afterwards for subsystem maintainers to take in the next release.  But
> I'd also be glad to just take this alongside the library itself.

OK, whichever you prefer. Feel free to take it, this code did change
recently for some additional error checking, but it otherwise almost
never changes, so there shouldn't be conflicts.

johannes

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH 00/15] AES-CMAC library
  2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
                   ` (15 preceding siblings ...)
  2026-02-19  9:25 ` [PATCH 00/15] AES-CMAC library Ard Biesheuvel
@ 2026-02-23 21:28 ` Eric Biggers
  16 siblings, 0 replies; 28+ messages in thread
From: Eric Biggers @ 2026-02-23 21:28 UTC (permalink / raw)
  To: linux-crypto
  Cc: linux-kernel, Ard Biesheuvel, Jason A . Donenfeld, Herbert Xu,
	linux-arm-kernel, linux-cifs, linux-wireless

On Wed, Feb 18, 2026 at 01:34:46PM -0800, Eric Biggers wrote:
> This series can also be retrieved from:
> 
>     git fetch https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git aes-cmac-v1
> 
> This series adds support for AES CBC-based MACs to the crypto library,
> specifically AES-CMAC, AES-XCBC-MAC, and AES-CBC-MAC.  The
> implementation is fully optimized with the existing
> architecture-optimized AES code, either single-block AES en/decryption
> or arm64's neon_aes_mac_update() and ce_aes_mac_update().  As usual,
> optimizations are now enabled by default as well.
> 
> AES-CMAC support will be useful for at least the SMB client and server,
> and the bluetooth and mac80211 drivers.  Patches 8-15 convert these
> users to use the crypto library API instead of crypto_shash, though
> these patches will likely go in via subsystem trees later.  They result
> in some significant simplifications and performance improvements.
> 
> As usual, a KUnit test suite, FIPS self-test, and traditional crypto API
> wrapper algorithms are included as well.
> 
> Note that I'm also planning to add additional AES modes to the library.
> This is just an initial set of AES modes to get things started.
> Notably, with the SMB client and server already using the SHA* and MD5
> libraries, "cmac(aes)" was the only remaining use of crypto_shash there.
> So it makes sense to take care of that.
> 
> Eric Biggers (15):
>   lib/crypto: aes: Add support for CBC-based MACs
>   crypto: aes - Add cmac, xcbc, and cbcmac algorithms using library
>   crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit
>   lib/crypto: arm64/aes: Move assembly code for AES modes into libaes
>   lib/crypto: arm64/aes: Migrate optimized CBC-based MACs into library
>   lib/crypto: tests: Add KUnit tests for CBC-based MACs
>   lib/crypto: aes: Add FIPS self-test for CMAC
>   smb: client: Use AES-CMAC library for SMB3 signature calculation
>   smb: client: Remove obsolete cmac(aes) allocation
>   smb: client: Make generate_key() return void
>   smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature()
>   ksmbd: Use AES-CMAC library for SMB3 signature calculation
>   Bluetooth: SMP: Use AES-CMAC library API
>   wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac()
>   wifi: mac80211: Use AES-CMAC library in aes_s2v()

Applied patches 1-7 and 14-15 to
https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=libcrypto-next

Patches 8-13 (smb client, smb server, and bluetooth) can go in via
subsystem trees later.

I edited "lib/crypto: arm64/aes: Move assembly code for AES modes into
libaes" to update the file comments to remove the file paths.

- Eric

^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2026-02-23 21:28 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-18 21:34 [PATCH 00/15] AES-CMAC library Eric Biggers
2026-02-18 21:34 ` [PATCH 01/15] lib/crypto: aes: Add support for CBC-based MACs Eric Biggers
2026-02-18 21:34 ` [PATCH 02/15] crypto: aes - Add cmac, xcbc, and cbcmac algorithms using library Eric Biggers
2026-02-18 21:34 ` [PATCH 03/15] crypto: arm64/aes - Fix 32-bit aes_mac_update() arg treated as 64-bit Eric Biggers
2026-02-19  9:23   ` Ard Biesheuvel
2026-02-19 21:26     ` Eric Biggers
2026-02-18 21:34 ` [PATCH 04/15] lib/crypto: arm64/aes: Move assembly code for AES modes into libaes Eric Biggers
2026-02-18 21:34 ` [PATCH 05/15] lib/crypto: arm64/aes: Migrate optimized CBC-based MACs into library Eric Biggers
2026-02-18 21:34 ` [PATCH 06/15] lib/crypto: tests: Add KUnit tests for CBC-based MACs Eric Biggers
2026-02-18 21:34 ` [PATCH 07/15] lib/crypto: aes: Add FIPS self-test for CMAC Eric Biggers
2026-02-18 21:34 ` [PATCH 08/15] smb: client: Use AES-CMAC library for SMB3 signature calculation Eric Biggers
2026-02-18 21:34 ` [PATCH 09/15] smb: client: Remove obsolete cmac(aes) allocation Eric Biggers
2026-02-18 21:34 ` [PATCH 10/15] smb: client: Make generate_key() return void Eric Biggers
2026-02-18 21:34 ` [PATCH 11/15] smb: client: Drop 'allocate_crypto' arg from smb*_calc_signature() Eric Biggers
2026-02-18 21:42   ` Steve French
2026-02-18 21:34 ` [PATCH 12/15] ksmbd: Use AES-CMAC library for SMB3 signature calculation Eric Biggers
2026-02-19  1:49   ` Namjae Jeon
2026-02-18 21:34 ` [PATCH 13/15] Bluetooth: SMP: Use AES-CMAC library API Eric Biggers
2026-02-18 21:35 ` [PATCH 14/15] wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac() Eric Biggers
2026-02-19 11:00   ` Johannes Berg
2026-02-19 22:02     ` Eric Biggers
2026-02-20  9:01       ` Johannes Berg
2026-02-18 21:35 ` [PATCH 15/15] wifi: mac80211: Use AES-CMAC library in aes_s2v() Eric Biggers
2026-02-19 11:01   ` Johannes Berg
2026-02-19 22:15     ` Eric Biggers
2026-02-20  8:47       ` Johannes Berg
2026-02-19  9:25 ` [PATCH 00/15] AES-CMAC library Ard Biesheuvel
2026-02-23 21:28 ` Eric Biggers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox