mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 01:11:14 +00:00
bf6f7cf29b
The removed patches were applied upstream. Remove the 300-mac80211-optimize-skb-resizing.patch. This patch was not applied upstream, but it conflicts with upstream changes and needs bigger changes. It was applied with Felix to remove this patch for now. It should be reworked and then send upstream later. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
699 lines
18 KiB
Diff
699 lines
18 KiB
Diff
--- 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 \
|
|
@@ -18,8 +17,8 @@ mac80211-y := \
|
|
rate.o \
|
|
michael.o \
|
|
tkip.o \
|
|
+ aes_ccm.o \
|
|
aes_cmac.o \
|
|
- aes_gmac.o \
|
|
fils_aead.o \
|
|
cfg.o \
|
|
ethtool.o \
|
|
--- a/net/mac80211/aead_api.c
|
|
+++ /dev/null
|
|
@@ -1,112 +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@linaro.org>
|
|
- */
|
|
-
|
|
-#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;
|
|
-
|
|
- 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);
|
|
-
|
|
- crypto_aead_encrypt(aead_req);
|
|
- kfree_sensitive(aead_req);
|
|
-
|
|
- return 0;
|
|
-}
|
|
-
|
|
-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);
|
|
-}
|
|
--- 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 */
|
|
--- a/net/mac80211/aes_ccm.h
|
|
+++ b/net/mac80211/aes_ccm.h
|
|
@@ -7,39 +7,17 @@
|
|
#ifndef AES_CCM_H
|
|
#define AES_CCM_H
|
|
|
|
-#include "aead_api.h"
|
|
+#include <linux/crypto.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)
|
|
-{
|
|
- return aead_key_setup_encrypt("ccm(aes)", key, key_len, mic_len);
|
|
-}
|
|
-
|
|
-static inline int
|
|
-ieee80211_aes_ccm_encrypt(struct crypto_aead *tfm,
|
|
- u8 *b_0, u8 *aad, u8 *data,
|
|
- size_t data_len, 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);
|
|
-}
|
|
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[],
|
|
+ size_t key_len,
|
|
+ size_t mic_len);
|
|
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
|
|
+ u8 *data, size_t data_len, u8 *mic,
|
|
+ size_t mic_len);
|
|
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
|
|
+ u8 *data, size_t data_len, u8 *mic,
|
|
+ size_t mic_len);
|
|
+void ieee80211_aes_key_free(struct crypto_cipher *tfm);
|
|
|
|
#endif /* AES_CCM_H */
|
|
--- /dev/null
|
|
+++ b/net/mac80211/aes_gcm.c
|
|
@@ -0,0 +1,109 @@
|
|
+/*
|
|
+ * Copyright 2014-2015, Qualcomm Atheros, Inc.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/err.h>
|
|
+#include <crypto/aead.h>
|
|
+
|
|
+#include <net/mac80211.h>
|
|
+#include "key.h"
|
|
+#include "aes_gcm.h"
|
|
+
|
|
+int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
|
+ u8 *data, size_t data_len, u8 *mic)
|
|
+{
|
|
+ struct scatterlist sg[3];
|
|
+ struct aead_request *aead_req;
|
|
+ int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm);
|
|
+ u8 *__aad;
|
|
+
|
|
+ aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC);
|
|
+ if (!aead_req)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ __aad = (u8 *)aead_req + reqsize;
|
|
+ memcpy(__aad, aad, GCM_AAD_LEN);
|
|
+
|
|
+ sg_init_table(sg, 3);
|
|
+ sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
|
+ sg_set_buf(&sg[1], data, data_len);
|
|
+ sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN);
|
|
+
|
|
+ aead_request_set_tfm(aead_req, tfm);
|
|
+ aead_request_set_crypt(aead_req, sg, sg, data_len, j_0);
|
|
+ aead_request_set_ad(aead_req, sg[0].length);
|
|
+
|
|
+ crypto_aead_encrypt(aead_req);
|
|
+ kzfree(aead_req);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
|
+ u8 *data, size_t data_len, u8 *mic)
|
|
+{
|
|
+ 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 + GCM_AAD_LEN, GFP_ATOMIC);
|
|
+ if (!aead_req)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ __aad = (u8 *)aead_req + reqsize;
|
|
+ memcpy(__aad, aad, GCM_AAD_LEN);
|
|
+
|
|
+ sg_init_table(sg, 3);
|
|
+ sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad));
|
|
+ sg_set_buf(&sg[1], data, data_len);
|
|
+ sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN);
|
|
+
|
|
+ aead_request_set_tfm(aead_req, tfm);
|
|
+ aead_request_set_crypt(aead_req, sg, sg,
|
|
+ data_len + IEEE80211_GCMP_MIC_LEN, j_0);
|
|
+ aead_request_set_ad(aead_req, sg[0].length);
|
|
+
|
|
+ err = crypto_aead_decrypt(aead_req);
|
|
+ kzfree(aead_req);
|
|
+
|
|
+ return err;
|
|
+}
|
|
+
|
|
+struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[],
|
|
+ size_t key_len)
|
|
+{
|
|
+ struct crypto_aead *tfm;
|
|
+ int err;
|
|
+
|
|
+ tfm = crypto_alloc_aead("gcm(aes)", 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, IEEE80211_GCMP_MIC_LEN);
|
|
+ if (err)
|
|
+ goto free_aead;
|
|
+
|
|
+ return tfm;
|
|
+
|
|
+free_aead:
|
|
+ crypto_free_aead(tfm);
|
|
+ return ERR_PTR(err);
|
|
+}
|
|
+
|
|
+void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm)
|
|
+{
|
|
+ crypto_free_aead(tfm);
|
|
+}
|
|
--- a/net/mac80211/aes_gcm.h
|
|
+++ b/net/mac80211/aes_gcm.h
|
|
@@ -6,38 +6,30 @@
|
|
#ifndef AES_GCM_H
|
|
#define AES_GCM_H
|
|
|
|
-#include "aead_api.h"
|
|
+#include <linux/crypto.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(struct crypto_aead *tfm, u8 *j_0, 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);
|
|
}
|
|
|
|
-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(struct crypto_aead *tfm, u8 *j_0, u8 *aad,
|
|
+ u8 *data, size_t data_len, u8 *mic)
|
|
{
|
|
- return aead_decrypt(tfm, j_0, aad + 2,
|
|
- be16_to_cpup((__be16 *)aad),
|
|
- data, data_len, mic);
|
|
+ return -EOPNOTSUPP;
|
|
}
|
|
|
|
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);
|
|
+ return NULL;
|
|
}
|
|
|
|
-static inline void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm)
|
|
+static inline void
|
|
+ieee80211_aes_gcm_key_free(struct crypto_aead *tfm)
|
|
{
|
|
- return aead_key_free(tfm);
|
|
}
|
|
|
|
#endif /* AES_GCM_H */
|
|
--- a/net/mac80211/wpa.c
|
|
+++ b/net/mac80211/wpa.c
|
|
@@ -311,7 +311,8 @@ ieee80211_crypto_tkip_decrypt(struct iee
|
|
}
|
|
|
|
|
|
-static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad)
|
|
+static void ccmp_special_blocks(struct sk_buff *skb, u8 *pn, u8 *b_0, u8 *aad,
|
|
+ u16 data_len)
|
|
{
|
|
__le16 mask_fc;
|
|
int a4_included, mgmt;
|
|
@@ -341,14 +342,8 @@ static void ccmp_special_blocks(struct s
|
|
else
|
|
qos_tid = 0;
|
|
|
|
- /* In CCM, the initial vectors (IV) used for CTR mode encryption and CBC
|
|
- * mode authentication are not allowed to collide, yet both are derived
|
|
- * from this vector b_0. We only set L := 1 here to indicate that the
|
|
- * data size can be represented in (L+1) bytes. The CCM layer will take
|
|
- * care of storing the data length in the top (L+1) bytes and setting
|
|
- * and clearing the other bits as is required to derive the two IVs.
|
|
- */
|
|
- b_0[0] = 0x1;
|
|
+ /* First block, b_0 */
|
|
+ b_0[0] = 0x59; /* flags: Adata: 1, M: 011, L: 001 */
|
|
|
|
/* Nonce: Nonce Flags | A2 | PN
|
|
* Nonce Flags: Priority (b0..b3) | Management (b4) | Reserved (b5..b7)
|
|
@@ -356,6 +351,8 @@ static void ccmp_special_blocks(struct s
|
|
b_0[1] = qos_tid | (mgmt << 4);
|
|
memcpy(&b_0[2], hdr->addr2, ETH_ALEN);
|
|
memcpy(&b_0[8], pn, IEEE80211_CCMP_PN_LEN);
|
|
+ /* l(m) */
|
|
+ put_unaligned_be16(data_len, &b_0[14]);
|
|
|
|
/* AAD (extra authenticate-only data) / masked 802.11 header
|
|
* FC | A1 | A2 | A3 | SC | [A4] | [QC] */
|
|
@@ -412,7 +409,7 @@ static int ccmp_encrypt_skb(struct ieee8
|
|
u8 *pos;
|
|
u8 pn[6];
|
|
u64 pn64;
|
|
- u8 aad[CCM_AAD_LEN];
|
|
+ u8 aad[2 * AES_BLOCK_SIZE];
|
|
u8 b_0[AES_BLOCK_SIZE];
|
|
|
|
if (info->control.hw_key &&
|
|
@@ -467,9 +464,11 @@ static int ccmp_encrypt_skb(struct ieee8
|
|
return 0;
|
|
|
|
pos += IEEE80211_CCMP_HDR_LEN;
|
|
- ccmp_special_blocks(skb, pn, b_0, aad);
|
|
- return ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
|
|
- skb_put(skb, mic_len));
|
|
+ ccmp_special_blocks(skb, pn, b_0, aad, len);
|
|
+ ieee80211_aes_ccm_encrypt(key->u.ccmp.tfm, b_0, aad, pos, len,
|
|
+ skb_put(skb, mic_len), mic_len);
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
|
|
@@ -542,13 +541,13 @@ ieee80211_crypto_ccmp_decrypt(struct iee
|
|
u8 aad[2 * AES_BLOCK_SIZE];
|
|
u8 b_0[AES_BLOCK_SIZE];
|
|
/* hardware didn't decrypt/verify MIC */
|
|
- ccmp_special_blocks(skb, pn, b_0, aad);
|
|
+ ccmp_special_blocks(skb, pn, b_0, aad, data_len);
|
|
|
|
if (ieee80211_aes_ccm_decrypt(
|
|
key->u.ccmp.tfm, b_0, aad,
|
|
skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN,
|
|
data_len,
|
|
- skb->data + skb->len - mic_len))
|
|
+ skb->data + skb->len - mic_len, mic_len))
|
|
return RX_DROP_UNUSABLE;
|
|
}
|
|
|
|
@@ -643,7 +642,7 @@ static int gcmp_encrypt_skb(struct ieee8
|
|
u8 *pos;
|
|
u8 pn[6];
|
|
u64 pn64;
|
|
- u8 aad[GCM_AAD_LEN];
|
|
+ u8 aad[2 * AES_BLOCK_SIZE];
|
|
u8 j_0[AES_BLOCK_SIZE];
|
|
|
|
if (info->control.hw_key &&
|
|
@@ -700,8 +699,10 @@ static int gcmp_encrypt_skb(struct ieee8
|
|
|
|
pos += IEEE80211_GCMP_HDR_LEN;
|
|
gcmp_special_blocks(skb, pn, j_0, aad);
|
|
- 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.tfm, j_0, aad, pos, len,
|
|
+ skb_put(skb, IEEE80211_GCMP_MIC_LEN));
|
|
+
|
|
+ return 0;
|
|
}
|
|
|
|
ieee80211_tx_result
|
|
@@ -1128,9 +1129,9 @@ ieee80211_crypto_aes_gmac_encrypt(struct
|
|
struct ieee80211_key *key = tx->key;
|
|
struct ieee80211_mmie_16 *mmie;
|
|
struct ieee80211_hdr *hdr;
|
|
- u8 aad[GMAC_AAD_LEN];
|
|
+ u8 aad[20];
|
|
u64 pn64;
|
|
- u8 nonce[GMAC_NONCE_LEN];
|
|
+ u8 nonce[12];
|
|
|
|
if (WARN_ON(skb_queue_len(&tx->skbs) != 1))
|
|
return TX_DROP;
|
|
@@ -1176,7 +1177,7 @@ ieee80211_crypto_aes_gmac_decrypt(struct
|
|
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
|
|
struct ieee80211_key *key = rx->key;
|
|
struct ieee80211_mmie_16 *mmie;
|
|
- u8 aad[GMAC_AAD_LEN], *mic, ipn[6], nonce[GMAC_NONCE_LEN];
|
|
+ u8 aad[20], *mic, ipn[6], nonce[12];
|
|
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
|
|
|
if (!ieee80211_is_mgmt(hdr->frame_control))
|
|
--- /dev/null
|
|
+++ b/net/mac80211/aes_ccm.c
|
|
@@ -0,0 +1,144 @@
|
|
+/*
|
|
+ * Copyright 2003-2004, Instant802 Networks, Inc.
|
|
+ * Copyright 2005-2006, Devicescape Software, Inc.
|
|
+ *
|
|
+ * Rewrite: Copyright (C) 2013 Linaro Ltd <ard.biesheuvel@linaro.org>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
+ * published by the Free Software Foundation.
|
|
+ */
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/types.h>
|
|
+#include <linux/err.h>
|
|
+#include <crypto/aead.h>
|
|
+#include <crypto/aes.h>
|
|
+
|
|
+#include <net/mac80211.h>
|
|
+#include "key.h"
|
|
+#include "aes_ccm.h"
|
|
+
|
|
+static void aes_ccm_prepare(struct crypto_cipher *tfm, u8 *b_0, u8 *aad, u8 *s_0,
|
|
+ u8 *a, u8 *b)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ crypto_cipher_encrypt_one(tfm, b, b_0);
|
|
+
|
|
+ /* Extra Authenticate-only data (always two AES blocks) */
|
|
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
|
|
+ aad[i] ^= b[i];
|
|
+ crypto_cipher_encrypt_one(tfm, b, aad);
|
|
+
|
|
+ aad += AES_BLOCK_SIZE;
|
|
+
|
|
+ for (i = 0; i < AES_BLOCK_SIZE; i++)
|
|
+ aad[i] ^= b[i];
|
|
+ crypto_cipher_encrypt_one(tfm, a, aad);
|
|
+
|
|
+ /* Mask out bits from auth-only-b_0 */
|
|
+ b_0[0] &= 0x07;
|
|
+
|
|
+ /* S_0 is used to encrypt T (= MIC) */
|
|
+ b_0[14] = 0;
|
|
+ b_0[15] = 0;
|
|
+ crypto_cipher_encrypt_one(tfm, s_0, b_0);
|
|
+}
|
|
+
|
|
+
|
|
+void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
|
|
+ u8 *data, size_t data_len, u8 *mic,
|
|
+ size_t mic_len)
|
|
+{
|
|
+ int i, j, last_len, num_blocks;
|
|
+ u8 b[AES_BLOCK_SIZE];
|
|
+ u8 s_0[AES_BLOCK_SIZE];
|
|
+ u8 e[AES_BLOCK_SIZE];
|
|
+ u8 *pos, *cpos;
|
|
+
|
|
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
|
+ last_len = data_len % AES_BLOCK_SIZE;
|
|
+ aes_ccm_prepare(tfm, b_0, aad, s_0, b, b);
|
|
+
|
|
+ /* Process payload blocks */
|
|
+ pos = data;
|
|
+ cpos = data;
|
|
+ for (j = 1; j <= num_blocks; j++) {
|
|
+ int blen = (j == num_blocks && last_len) ?
|
|
+ last_len : AES_BLOCK_SIZE;
|
|
+
|
|
+ /* Authentication followed by encryption */
|
|
+ for (i = 0; i < blen; i++)
|
|
+ b[i] ^= pos[i];
|
|
+ crypto_cipher_encrypt_one(tfm, b, b);
|
|
+
|
|
+ b_0[14] = (j >> 8) & 0xff;
|
|
+ b_0[15] = j & 0xff;
|
|
+ crypto_cipher_encrypt_one(tfm, e, b_0);
|
|
+ for (i = 0; i < blen; i++)
|
|
+ *cpos++ = *pos++ ^ e[i];
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < mic_len; i++)
|
|
+ mic[i] = b[i] ^ s_0[i];
|
|
+}
|
|
+
|
|
+int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *b_0, u8 *aad,
|
|
+ u8 *data, size_t data_len, u8 *mic,
|
|
+ size_t mic_len)
|
|
+{
|
|
+ int i, j, last_len, num_blocks;
|
|
+ u8 *pos, *cpos;
|
|
+ u8 a[AES_BLOCK_SIZE];
|
|
+ u8 b[AES_BLOCK_SIZE];
|
|
+ u8 s_0[AES_BLOCK_SIZE];
|
|
+
|
|
+ num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_SIZE);
|
|
+ last_len = data_len % AES_BLOCK_SIZE;
|
|
+ aes_ccm_prepare(tfm, b_0, aad, s_0, a, b);
|
|
+
|
|
+ /* Process payload blocks */
|
|
+ cpos = data;
|
|
+ pos = data;
|
|
+ for (j = 1; j <= num_blocks; j++) {
|
|
+ int blen = (j == num_blocks && last_len) ?
|
|
+ last_len : AES_BLOCK_SIZE;
|
|
+
|
|
+ /* Decryption followed by authentication */
|
|
+ b_0[14] = (j >> 8) & 0xff;
|
|
+ b_0[15] = j & 0xff;
|
|
+ crypto_cipher_encrypt_one(tfm, b, b_0);
|
|
+ for (i = 0; i < blen; i++) {
|
|
+ *pos = *cpos++ ^ b[i];
|
|
+ a[i] ^= *pos++;
|
|
+ }
|
|
+ crypto_cipher_encrypt_one(tfm, a, a);
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < mic_len; i++) {
|
|
+ if ((mic[i] ^ s_0[i]) != a[i])
|
|
+ return -1;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+struct crypto_cipher *ieee80211_aes_key_setup_encrypt(const u8 key[],
|
|
+ size_t key_len,
|
|
+ size_t mic_len)
|
|
+{
|
|
+ struct crypto_cipher *tfm;
|
|
+
|
|
+ tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
|
|
+ if (!IS_ERR(tfm))
|
|
+ crypto_cipher_setkey(tfm, key, key_len);
|
|
+
|
|
+ return tfm;
|
|
+}
|
|
+
|
|
+
|
|
+void ieee80211_aes_key_free(struct crypto_cipher *tfm)
|
|
+{
|
|
+ crypto_free_cipher(tfm);
|
|
+}
|
|
--- a/net/mac80211/Kconfig
|
|
+++ b/net/mac80211/Kconfig
|
|
@@ -6,8 +6,6 @@ config MAC80211
|
|
depends on CRYPTO
|
|
select BPAUTO_CRYPTO_LIB_ARC4
|
|
depends on CRYPTO_AES
|
|
- depends on CRYPTO_CCM
|
|
- depends on CRYPTO_GCM
|
|
depends on CRYPTO_CMAC
|
|
depends on CRC32
|
|
help
|
|
--- a/net/mac80211/aes_gmac.h
|
|
+++ b/net/mac80211/aes_gmac.h
|
|
@@ -12,10 +12,22 @@
|
|
#define GMAC_MIC_LEN 16
|
|
#define GMAC_NONCE_LEN 12
|
|
|
|
-struct crypto_aead *ieee80211_aes_gmac_key_setup(const u8 key[],
|
|
- size_t key_len);
|
|
-int ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
|
|
- const u8 *data, size_t data_len, u8 *mic);
|
|
-void ieee80211_aes_gmac_key_free(struct crypto_aead *tfm);
|
|
+static inline struct crypto_aead *
|
|
+ieee80211_aes_gmac_key_setup(const u8 key[], size_t key_len)
|
|
+{
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+static inline int
|
|
+ieee80211_aes_gmac(struct crypto_aead *tfm, const u8 *aad, u8 *nonce,
|
|
+ const u8 *data, size_t data_len, u8 *mic)
|
|
+{
|
|
+ return -EOPNOTSUPP;
|
|
+}
|
|
+
|
|
+static inline void
|
|
+ieee80211_aes_gmac_key_free(struct crypto_aead *tfm)
|
|
+{
|
|
+}
|
|
|
|
#endif /* AES_GMAC_H */
|
|
--- a/net/mac80211/key.h
|
|
+++ b/net/mac80211/key.h
|
|
@@ -89,7 +89,7 @@ struct ieee80211_key {
|
|
* Management frames.
|
|
*/
|
|
u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN];
|
|
- struct crypto_aead *tfm;
|
|
+ struct crypto_cipher *tfm;
|
|
u32 replays; /* dot11RSNAStatsCCMPReplays */
|
|
} ccmp;
|
|
struct {
|