]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac()
authorEric Biggers <ebiggers@kernel.org>
Wed, 18 Feb 2026 21:35:00 +0000 (13:35 -0800)
committerEric Biggers <ebiggers@kernel.org>
Mon, 9 Mar 2026 20:27:21 +0000 (13:27 -0700)
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.

Acked-by: Johannes Berg <johannes@sipsolutions.net>
Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
Link: https://lore.kernel.org/r/20260218213501.136844-15-ebiggers@kernel.org
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
net/mac80211/Kconfig
net/mac80211/aes_cmac.c
net/mac80211/aes_cmac.h
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/wpa.c

index cf0f7780fb109e1c063826760aef36cb61bb9062..0afbe4f4f97646937e4f599d4edbc2318a5a12d6 100644 (file)
@@ -3,6 +3,7 @@ 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
index 0827965455dc0916bb698693013a5cf6ff0266e9..55b674ad7d7a4328add12b574d1bdb3beecfab21 100644 (file)
@@ -7,10 +7,9 @@
 
 #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"
 
 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);
 }
index 5f971a8298cbed64f14372a8d5cf7d5b02c85055..c7a6df47b3271412ddbd7bddceb72e76259f1fd3 100644 (file)
@@ -6,14 +6,10 @@
 #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 */
index 04c8809173d7f564b8f4e02e564be16eca6e63bd..4b8965633df34c9e5a12f55017de33e2fb4f1bd9 100644 (file)
@@ -690,10 +690,9 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                 * 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);
                }
@@ -750,10 +749,6 @@ static void ieee80211_key_free_common(struct ieee80211_key *key)
        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);
index 1fa0f4f78962ed87a4b74a621d533071a55a81c3..826e4e9387c55f4757884779767b1ae909862faf 100644 (file)
@@ -12,6 +12,7 @@
 #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>
 
@@ -93,7 +94,7 @@ struct ieee80211_key {
                } 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;
index fdf98c21d32c0bef54f66c6704b8c973ab14b52b..59324b367bddcf77d969b8343e6726bebe408c73 100644 (file)
@@ -872,11 +872,8 @@ ieee80211_crypto_aes_cmac_encrypt(struct ieee80211_tx_data *tx,
 
        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;
 }
 
@@ -918,10 +915,8 @@ 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;