summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2017-02-06 05:49:28 -0500
committerJohannes Berg <johannes.berg@intel.com>2017-02-08 03:19:33 -0500
commit26717828b75dd5c46e97f7f4a9b937d038bb2852 (patch)
treecb192493dd8bb60c52260932877cd7e23de96a81
parentfe8de3da13bdbcbe8b583a3bbadf677da0f04f83 (diff)
mac80211: aes-cmac: switch to shash CMAC driver
Instead of open coding the CMAC algorithm in the mac80211 driver using byte wide xors and calls into the crypto layer for each block of data, instantiate a cmac(aes) synchronous hash and pass all the data into it directly. This does not only simplify the code, it also allows the use of more efficient and more secure implementations, especially on platforms where SIMD ciphers have a considerable setup cost. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-rw-r--r--net/mac80211/aes_cmac.c126
-rw-r--r--net/mac80211/aes_cmac.h11
-rw-r--r--net/mac80211/key.h2
3 files changed, 32 insertions, 107 deletions
diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c
index d0bd5fff5f0a..2fb65588490c 100644
--- a/net/mac80211/aes_cmac.c
+++ b/net/mac80211/aes_cmac.c
@@ -22,126 +22,50 @@
22#define CMAC_TLEN_256 16 /* CMAC TLen = 128 bits (16 octets) */ 22#define CMAC_TLEN_256 16 /* CMAC TLen = 128 bits (16 octets) */
23#define AAD_LEN 20 23#define AAD_LEN 20
24 24
25static const u8 zero[CMAC_TLEN_256];
25 26
26void gf_mulx(u8 *pad) 27void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad,
27{
28 int i, carry;
29
30 carry = pad[0] & 0x80;
31 for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
32 pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
33 pad[AES_BLOCK_SIZE - 1] <<= 1;
34 if (carry)
35 pad[AES_BLOCK_SIZE - 1] ^= 0x87;
36}
37
38void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem,
39 const u8 *addr[], const size_t *len, u8 *mac,
40 size_t mac_len)
41{
42 u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
43 const u8 *pos, *end;
44 size_t i, e, left, total_len;
45
46 memset(cbc, 0, AES_BLOCK_SIZE);
47
48 total_len = 0;
49 for (e = 0; e < num_elem; e++)
50 total_len += len[e];
51 left = total_len;
52
53 e = 0;
54 pos = addr[0];
55 end = pos + len[0];
56
57 while (left >= AES_BLOCK_SIZE) {
58 for (i = 0; i < AES_BLOCK_SIZE; i++) {
59 cbc[i] ^= *pos++;
60 if (pos >= end) {
61 e++;
62 pos = addr[e];
63 end = pos + len[e];
64 }
65 }
66 if (left > AES_BLOCK_SIZE)
67 crypto_cipher_encrypt_one(tfm, cbc, cbc);
68 left -= AES_BLOCK_SIZE;
69 }
70
71 memset(pad, 0, AES_BLOCK_SIZE);
72 crypto_cipher_encrypt_one(tfm, pad, pad);
73 gf_mulx(pad);
74
75 if (left || total_len == 0) {
76 for (i = 0; i < left; i++) {
77 cbc[i] ^= *pos++;
78 if (pos >= end) {
79 e++;
80 pos = addr[e];
81 end = pos + len[e];
82 }
83 }
84 cbc[left] ^= 0x80;
85 gf_mulx(pad);
86 }
87
88 for (i = 0; i < AES_BLOCK_SIZE; i++)
89 pad[i] ^= cbc[i];
90 crypto_cipher_encrypt_one(tfm, pad, pad);
91 memcpy(mac, pad, mac_len);
92}
93
94
95void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
96 const u8 *data, size_t data_len, u8 *mic) 28 const u8 *data, size_t data_len, u8 *mic)
97{ 29{
98 const u8 *addr[3]; 30 SHASH_DESC_ON_STACK(desc, tfm);
99 size_t len[3]; 31 u8 out[AES_BLOCK_SIZE];
100 u8 zero[CMAC_TLEN];
101 32
102 memset(zero, 0, CMAC_TLEN); 33 desc->tfm = tfm;
103 addr[0] = aad;
104 len[0] = AAD_LEN;
105 addr[1] = data;
106 len[1] = data_len - CMAC_TLEN;
107 addr[2] = zero;
108 len[2] = CMAC_TLEN;
109 34
110 aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN); 35 crypto_shash_init(desc);
36 crypto_shash_update(desc, aad, AAD_LEN);
37 crypto_shash_update(desc, data, data_len - CMAC_TLEN);
38 crypto_shash_finup(desc, zero, CMAC_TLEN, out);
39
40 memcpy(mic, out, CMAC_TLEN);
111} 41}
112 42
113void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad, 43void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad,
114 const u8 *data, size_t data_len, u8 *mic) 44 const u8 *data, size_t data_len, u8 *mic)
115{ 45{
116 const u8 *addr[3]; 46 SHASH_DESC_ON_STACK(desc, tfm);
117 size_t len[3];
118 u8 zero[CMAC_TLEN_256];
119 47
120 memset(zero, 0, CMAC_TLEN_256); 48 desc->tfm = tfm;
121 addr[0] = aad;
122 len[0] = AAD_LEN;
123 addr[1] = data;
124 len[1] = data_len - CMAC_TLEN_256;
125 addr[2] = zero;
126 len[2] = CMAC_TLEN_256;
127 49
128 aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN_256); 50 crypto_shash_init(desc);
51 crypto_shash_update(desc, aad, AAD_LEN);
52 crypto_shash_update(desc, data, data_len - CMAC_TLEN_256);
53 crypto_shash_finup(desc, zero, CMAC_TLEN_256, mic);
129} 54}
130 55
131struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[], 56struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[],
132 size_t key_len) 57 size_t key_len)
133{ 58{
134 struct crypto_cipher *tfm; 59 struct crypto_shash *tfm;
135 60
136 tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); 61 tfm = crypto_alloc_shash("cmac(aes)", 0, 0);
137 if (!IS_ERR(tfm)) 62 if (!IS_ERR(tfm))
138 crypto_cipher_setkey(tfm, key, key_len); 63 crypto_shash_setkey(tfm, key, key_len);
139 64
140 return tfm; 65 return tfm;
141} 66}
142 67
143 68void ieee80211_aes_cmac_key_free(struct crypto_shash *tfm)
144void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm)
145{ 69{
146 crypto_free_cipher(tfm); 70 crypto_free_shash(tfm);
147} 71}
diff --git a/net/mac80211/aes_cmac.h b/net/mac80211/aes_cmac.h
index 3702041f44fd..fef531f42003 100644
--- a/net/mac80211/aes_cmac.h
+++ b/net/mac80211/aes_cmac.h
@@ -10,13 +10,14 @@
10#define AES_CMAC_H 10#define AES_CMAC_H
11 11
12#include <linux/crypto.h> 12#include <linux/crypto.h>
13#include <crypto/hash.h>
13 14
14struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[], 15struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[],
15 size_t key_len); 16 size_t key_len);
16void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, 17void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad,
17 const u8 *data, size_t data_len, u8 *mic); 18 const u8 *data, size_t data_len, u8 *mic);
18void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad, 19void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad,
19 const u8 *data, size_t data_len, u8 *mic); 20 const u8 *data, size_t data_len, u8 *mic);
20void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); 21void ieee80211_aes_cmac_key_free(struct crypto_shash *tfm);
21 22
22#endif /* AES_CMAC_H */ 23#endif /* AES_CMAC_H */
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 4aa20cef0859..ebdb80b85dc3 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -93,7 +93,7 @@ struct ieee80211_key {
93 } ccmp; 93 } ccmp;
94 struct { 94 struct {
95 u8 rx_pn[IEEE80211_CMAC_PN_LEN]; 95 u8 rx_pn[IEEE80211_CMAC_PN_LEN];
96 struct crypto_cipher *tfm; 96 struct crypto_shash *tfm;
97 u32 replays; /* dot11RSNAStatsCMACReplays */ 97 u32 replays; /* dot11RSNAStatsCMACReplays */
98 u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ 98 u32 icverrors; /* dot11RSNAStatsCMACICVErrors */
99 } aes_cmac; 99 } aes_cmac;