[PATCH 25/33] wifi: mac80211: Use crypto libraries for GCMP and CCMP suites
From: Eric Biggers
Date: Tue Jul 07 2026 - 01:43:22 EST
Now that there are library APIs for AES-GCM and AES-CCM, for the GCMP
and CCMP cipher suites use them instead of "gcm(aes)" and "ccm(aes)"
crypto_aeads. This significantly simplifies the code and eliminates
per-skb heap allocations.
Signed-off-by: Eric Biggers <ebiggers@xxxxxxxxxx>
---
net/mac80211/Kconfig | 5 +-
net/mac80211/Makefile | 1 -
net/mac80211/aead_api.c | 113 ----------------------------------------
net/mac80211/aead_api.h | 23 --------
net/mac80211/aes_ccm.h | 39 +++++---------
net/mac80211/aes_gcm.h | 38 +++++---------
net/mac80211/key.c | 31 ++++-------
net/mac80211/key.h | 5 +-
net/mac80211/wpa.c | 11 ++--
9 files changed, 45 insertions(+), 221 deletions(-)
delete mode 100644 net/mac80211/aead_api.c
delete mode 100644 net/mac80211/aead_api.h
diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig
index 32808c5de0fb..5658f089d915 100644
--- a/net/mac80211/Kconfig
+++ b/net/mac80211/Kconfig
@@ -2,14 +2,11 @@
config MAC80211
tristate "Generic IEEE 802.11 Networking Stack (mac80211)"
depends on CFG80211
- select CRYPTO
select CRYPTO_LIB_AES_CBC_MACS
+ select CRYPTO_LIB_AES_CCM
select CRYPTO_LIB_AES_CTR
select CRYPTO_LIB_AES_GCM
select CRYPTO_LIB_ARC4
- select CRYPTO_AES
- select CRYPTO_CCM
- select CRYPTO_GCM
select CRC32
help
This option enables the hardware independent IEEE 802.11
diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile
index 36f1e3e2222b..2ae7a57565cd 100644
--- a/net/mac80211/Makefile
+++ b/net/mac80211/Makefile
@@ -7,7 +7,6 @@ mac80211-y := \
driver-ops.o \
sta_info.o \
wep.o \
- aead_api.o \
wpa.o \
scan.o offchannel.o \
ht.o agg-tx.o agg-rx.o \
diff --git a/net/mac80211/aead_api.c b/net/mac80211/aead_api.c
deleted file mode 100644
index b00d6f5b33f4..000000000000
--- a/net/mac80211/aead_api.c
+++ /dev/null
@@ -1,113 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * Copyright 2003-2004, Instant802 Networks, Inc.
- * Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright 2014-2015, Qualcomm Atheros, Inc.
- *
- * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@xxxxxxxxxx>
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/err.h>
-#include <linux/scatterlist.h>
-#include <crypto/aead.h>
-
-#include "aead_api.h"
-
-int aead_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len,
- u8 *data, size_t data_len, u8 *mic)
-{
- size_t mic_len = crypto_aead_authsize(tfm);
- struct scatterlist sg[3];
- struct aead_request *aead_req;
- int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
- u8 *__aad;
- int ret;
-
- aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC);
- if (!aead_req)
- return -ENOMEM;
-
- __aad = (u8 *)aead_req + reqsize;
- memcpy(__aad, aad, aad_len);
-
- sg_init_table(sg, 3);
- sg_set_buf(&sg[0], __aad, aad_len);
- sg_set_buf(&sg[1], data, data_len);
- sg_set_buf(&sg[2], mic, mic_len);
-
- aead_request_set_tfm(aead_req, tfm);
- aead_request_set_crypt(aead_req, sg, sg, data_len, b_0);
- aead_request_set_ad(aead_req, sg[0].length);
-
- ret = crypto_aead_encrypt(aead_req);
- kfree_sensitive(aead_req);
-
- return ret;
-}
-
-int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len,
- u8 *data, size_t data_len, u8 *mic)
-{
- size_t mic_len = crypto_aead_authsize(tfm);
- struct scatterlist sg[3];
- struct aead_request *aead_req;
- int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
- u8 *__aad;
- int err;
-
- if (data_len == 0)
- return -EINVAL;
-
- aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC);
- if (!aead_req)
- return -ENOMEM;
-
- __aad = (u8 *)aead_req + reqsize;
- memcpy(__aad, aad, aad_len);
-
- sg_init_table(sg, 3);
- sg_set_buf(&sg[0], __aad, aad_len);
- sg_set_buf(&sg[1], data, data_len);
- sg_set_buf(&sg[2], mic, mic_len);
-
- aead_request_set_tfm(aead_req, tfm);
- aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0);
- aead_request_set_ad(aead_req, sg[0].length);
-
- err = crypto_aead_decrypt(aead_req);
- kfree_sensitive(aead_req);
-
- return err;
-}
-
-struct crypto_aead *
-aead_key_setup_encrypt(const char *alg, const u8 key[],
- size_t key_len, size_t mic_len)
-{
- struct crypto_aead *tfm;
- int err;
-
- tfm = crypto_alloc_aead(alg, 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(tfm))
- return tfm;
-
- err = crypto_aead_setkey(tfm, key, key_len);
- if (err)
- goto free_aead;
- err = crypto_aead_setauthsize(tfm, mic_len);
- if (err)
- goto free_aead;
-
- return tfm;
-
-free_aead:
- crypto_free_aead(tfm);
- return ERR_PTR(err);
-}
-
-void aead_key_free(struct crypto_aead *tfm)
-{
- crypto_free_aead(tfm);
-}
diff --git a/net/mac80211/aead_api.h b/net/mac80211/aead_api.h
deleted file mode 100644
index 7d463b80926a..000000000000
--- a/net/mac80211/aead_api.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-
-#ifndef _AEAD_API_H
-#define _AEAD_API_H
-
-#include <crypto/aead.h>
-#include <linux/crypto.h>
-
-struct crypto_aead *
-aead_key_setup_encrypt(const char *alg, const u8 key[],
- size_t key_len, size_t mic_len);
-
-int aead_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
- size_t aad_len, u8 *data,
- size_t data_len, u8 *mic);
-
-int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad,
- size_t aad_len, u8 *data,
- size_t data_len, u8 *mic);
-
-void aead_key_free(struct crypto_aead *tfm);
-
-#endif /* _AEAD_API_H */
diff --git a/net/mac80211/aes_ccm.h b/net/mac80211/aes_ccm.h
index 96256193cf49..f8d5e9cbf0dc 100644
--- a/net/mac80211/aes_ccm.h
+++ b/net/mac80211/aes_ccm.h
@@ -7,39 +7,26 @@
#ifndef AES_CCM_H
#define AES_CCM_H
-#include "aead_api.h"
+#include <asm/byteorder.h>
+#include <crypto/aes-ccm.h>
#define CCM_AAD_LEN 32
-static inline struct crypto_aead *
-ieee80211_aes_key_setup_encrypt(const u8 key[], size_t key_len, size_t mic_len)
+static inline int ieee80211_aes_ccm_encrypt(const struct aes_ccm_key *key,
+ const u8 *b_0, const u8 *aad,
+ u8 *data, size_t data_len, u8 *mic)
{
- return aead_key_setup_encrypt("ccm(aes)", key, key_len, mic_len);
+ return aes_ccm_encrypt(data, mic, data, data_len, aad + 2,
+ be16_to_cpup((__be16 *)aad), b_0 + 1, 13, key);
}
-static inline int
-ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm,
- u8 *b_0, u8 *aad, u8 *data,
- size_t data_len, u8 *mic)
+static inline int ieee80211_aes_ccm_decrypt(const struct aes_ccm_key *key,
+ const u8 *b_0, const u8 *aad,
+ u8 *data, size_t data_len,
+ const u8 *mic)
{
- return aead_encrypt(tfm, b_0, aad + 2,
- be16_to_cpup((__be16 *)aad),
- data, data_len, mic);
-}
-
-static inline int
-ieee80211_aes_ccm_decrypt(struct crypto_aead *tfm,
- u8 *b_0, u8 *aad, u8 *data,
- size_t data_len, u8 *mic)
-{
- return aead_decrypt(tfm, b_0, aad + 2,
- be16_to_cpup((__be16 *)aad),
- data, data_len, mic);
-}
-
-static inline void ieee80211_aes_key_free(struct crypto_aead *tfm)
-{
- return aead_key_free(tfm);
+ return aes_ccm_decrypt(data, data, mic, data_len, aad + 2,
+ be16_to_cpup((__be16 *)aad), b_0 + 1, 13, key);
}
#endif /* AES_CCM_H */
diff --git a/net/mac80211/aes_gcm.h b/net/mac80211/aes_gcm.h
index b14093b2f7a9..ba13617aeb75 100644
--- a/net/mac80211/aes_gcm.h
+++ b/net/mac80211/aes_gcm.h
@@ -6,38 +6,26 @@
#ifndef AES_GCM_H
#define AES_GCM_H
-#include "aead_api.h"
+#include <asm/byteorder.h>
+#include <crypto/aes-gcm.h>
#define GCM_AAD_LEN 32
-static inline int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm,
- u8 *j_0, u8 *aad, u8 *data,
- size_t data_len, u8 *mic)
+static inline void ieee80211_aes_gcm_encrypt(const struct aes_gcm_key *key,
+ const u8 *j_0, const u8 *aad,
+ u8 *data, size_t data_len, u8 *mic)
{
- return aead_encrypt(tfm, j_0, aad + 2,
- be16_to_cpup((__be16 *)aad),
- data, data_len, mic);
+ aes_gcm_encrypt(data, mic, data, data_len, aad + 2,
+ be16_to_cpup((__be16 *)aad), j_0, key);
}
-static inline int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm,
- u8 *j_0, u8 *aad, u8 *data,
- size_t data_len, u8 *mic)
+static inline int ieee80211_aes_gcm_decrypt(const struct aes_gcm_key *key,
+ const u8 *j_0, const u8 *aad,
+ u8 *data, size_t data_len,
+ const u8 *mic)
{
- return aead_decrypt(tfm, j_0, aad + 2,
- be16_to_cpup((__be16 *)aad),
- data, data_len, mic);
-}
-
-static inline struct crypto_aead *
-ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], size_t key_len)
-{
- return aead_key_setup_encrypt("gcm(aes)", key,
- key_len, IEEE80211_GCMP_MIC_LEN);
-}
-
-static inline void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm)
-{
- return aead_key_free(tfm);
+ return aes_gcm_decrypt(data, data, mic, data_len, aad + 2,
+ be16_to_cpup((__be16 *)aad), j_0, key);
}
#endif /* AES_GCM_H */
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 48404097e4f1..8c8a82d91bf2 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -652,10 +652,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.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
- key_data, key_len, IEEE80211_CCMP_MIC_LEN);
- if (IS_ERR(key->u.ccmp.tfm)) {
- err = PTR_ERR(key->u.ccmp.tfm);
+ err = aes_ccm_preparekey(&key->u.ccmp.key, key_data, key_len,
+ IEEE80211_CCMP_MIC_LEN);
+ if (err) {
kfree(key);
return ERR_PTR(err);
}
@@ -670,10 +669,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.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
- key_data, key_len, IEEE80211_CCMP_256_MIC_LEN);
- if (IS_ERR(key->u.ccmp.tfm)) {
- err = PTR_ERR(key->u.ccmp.tfm);
+ err = aes_ccm_preparekey(&key->u.ccmp.key, key_data, key_len,
+ IEEE80211_CCMP_256_MIC_LEN);
+ if (err) {
kfree(key);
return ERR_PTR(err);
}
@@ -729,10 +727,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.gcmp.tfm = ieee80211_aes_gcm_key_setup_encrypt(key_data,
- key_len);
- if (IS_ERR(key->u.gcmp.tfm)) {
- err = PTR_ERR(key->u.gcmp.tfm);
+ err = aes_gcm_preparekey(&key->u.gcmp.key, key_data, key_len,
+ IEEE80211_GCMP_MIC_LEN);
+ if (err) {
kfree(key);
return ERR_PTR(err);
}
@@ -746,16 +743,6 @@ ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
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_GCMP:
- case WLAN_CIPHER_SUITE_GCMP_256:
- ieee80211_aes_gcm_key_free(key->u.gcmp.tfm);
- break;
- }
kfree_sensitive(key);
}
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index d2dd2a76fa25..a43db120f61c 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -13,6 +13,7 @@
#include <linux/crypto.h>
#include <linux/rcupdate.h>
#include <crypto/aes-cbc-macs.h>
+#include <crypto/aes-ccm.h>
#include <crypto/aes-gcm.h>
#include <crypto/arc4.h>
#include <net/mac80211.h>
@@ -90,7 +91,7 @@ struct ieee80211_key {
* Management frames.
*/
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
- struct crypto_aead *tfm;
+ struct aes_ccm_key key;
u32 replays; /* dot11RSNAStatsCCMPReplays */
} ccmp;
struct {
@@ -112,7 +113,7 @@ struct ieee80211_key {
* Management frames.
*/
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_GCMP_PN_LEN];
- struct crypto_aead *tfm;
+ struct aes_gcm_key key;
u32 replays; /* dot11RSNAStatsGCMPReplays */
} gcmp;
struct {
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index eb4a98537395..db57d383606f 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -492,7 +492,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb,
ccmp_special_blocks(skb, pn, b_0, aad,
key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU,
false);
- return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
+ return ieee80211_aes_ccm_encrypt(&key->u.ccmp.key, b_0, aad, pos, len,
skb_put(skb, mic_len));
}
@@ -587,7 +587,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx,
aad_nonce_computed);
if (ieee80211_aes_ccm_decrypt(
- key->u.ccmp.tfm, b_0, aad,
+ &key->u.ccmp.key, b_0, aad,
skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN,
data_len,
skb->data + skb->len - mic_len))
@@ -709,8 +709,9 @@ static int gcmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
gcmp_special_blocks(skb, pn, j_0, aad,
key->conf.flags & IEEE80211_KEY_FLAG_SPP_AMSDU,
false);
- return ieee80211_aes_gcm_encrypt(key->u.gcmp.tfm, j_0, aad, pos, len,
- skb_put(skb, IEEE80211_GCMP_MIC_LEN));
+ ieee80211_aes_gcm_encrypt(&key->u.gcmp.key, j_0, aad, pos, len,
+ skb_put(skb, IEEE80211_GCMP_MIC_LEN));
+ return 0;
}
ieee80211_tx_result
@@ -798,7 +799,7 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx)
aad_nonce_computed);
if (ieee80211_aes_gcm_decrypt(
- key->u.gcmp.tfm, j_0, aad,
+ &key->u.gcmp.key, j_0, aad,
skb->data + hdrlen + IEEE80211_GCMP_HDR_LEN,
data_len,
skb->data + skb->len -
--
2.54.0