wifi: mac80211: Use AES-CMAC library in ieee80211_aes_cmac()
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>master
parent
2505f9157e
commit
c9de7246d5
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -20,65 +19,25 @@
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue