blob: 4200ec509866581c60c6faeb07fa973f97528048 [file] [log] [blame]
Jeff Garzikb4538722005-05-12 22:48:20 -04001/*
2 * Host AP crypt: host-based TKIP encryption implementation for Host AP driver
3 *
4 * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation. See README and COPYING for
9 * more details.
10 */
11
Herbert Xuf12cc202006-08-22 20:36:13 +100012#include <linux/err.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040013#include <linux/module.h>
14#include <linux/init.h>
15#include <linux/slab.h>
16#include <linux/random.h>
17#include <linux/skbuff.h>
18#include <linux/netdevice.h>
19#include <linux/if_ether.h>
20#include <linux/if_arp.h>
21#include <asm/string.h>
22
23#include <net/ieee80211.h>
24
Jeff Garzikb4538722005-05-12 22:48:20 -040025#include <linux/crypto.h>
26#include <asm/scatterlist.h>
27#include <linux/crc32.h>
28
29MODULE_AUTHOR("Jouni Malinen");
30MODULE_DESCRIPTION("Host AP crypt: TKIP");
31MODULE_LICENSE("GPL");
32
33struct ieee80211_tkip_data {
34#define TKIP_KEY_LEN 32
35 u8 key[TKIP_KEY_LEN];
36 int key_set;
37
38 u32 tx_iv32;
39 u16 tx_iv16;
40 u16 tx_ttak[5];
41 int tx_phase1_done;
42
43 u32 rx_iv32;
44 u16 rx_iv16;
45 u16 rx_ttak[5];
46 int rx_phase1_done;
47 u32 rx_iv32_new;
48 u16 rx_iv16_new;
49
50 u32 dot11RSNAStatsTKIPReplays;
51 u32 dot11RSNAStatsTKIPICVErrors;
52 u32 dot11RSNAStatsTKIPLocalMICFailures;
53
54 int key_idx;
55
Jeff Garzik28eb1772006-09-22 20:10:23 -040056 struct crypto_blkcipher *rx_tfm_arc4;
57 struct crypto_hash *rx_tfm_michael;
58 struct crypto_blkcipher *tx_tfm_arc4;
59 struct crypto_hash *tx_tfm_michael;
Jeff Garzikb4538722005-05-12 22:48:20 -040060
61 /* scratch buffers for virt_to_page() (crypto API) */
62 u8 rx_hdr[16], tx_hdr[16];
James Ketrenos20d64712005-09-21 11:53:43 -050063
James Ketrenos6eb6edf2005-09-22 10:34:15 +000064 unsigned long flags;
Jeff Garzikb4538722005-05-12 22:48:20 -040065};
66
James Ketrenos6eb6edf2005-09-22 10:34:15 +000067static unsigned long ieee80211_tkip_set_flags(unsigned long flags, void *priv)
68{
69 struct ieee80211_tkip_data *_priv = priv;
70 unsigned long old_flags = _priv->flags;
71 _priv->flags = flags;
72 return old_flags;
73}
74
75static unsigned long ieee80211_tkip_get_flags(void *priv)
76{
77 struct ieee80211_tkip_data *_priv = priv;
78 return _priv->flags;
79}
80
81static void *ieee80211_tkip_init(int key_idx)
Jeff Garzikb4538722005-05-12 22:48:20 -040082{
83 struct ieee80211_tkip_data *priv;
84
Zhu Yi8aa914b2006-01-19 16:22:07 +080085 priv = kzalloc(sizeof(*priv), GFP_ATOMIC);
Jeff Garzikb4538722005-05-12 22:48:20 -040086 if (priv == NULL)
87 goto fail;
James Ketrenos20d64712005-09-21 11:53:43 -050088
Jeff Garzikb4538722005-05-12 22:48:20 -040089 priv->key_idx = key_idx;
90
Jeff Garzik28eb1772006-09-22 20:10:23 -040091 priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
Herbert Xuf12cc202006-08-22 20:36:13 +100092 CRYPTO_ALG_ASYNC);
Jeff Garzik28eb1772006-09-22 20:10:23 -040093 if (IS_ERR(priv->tx_tfm_arc4)) {
Jeff Garzikb4538722005-05-12 22:48:20 -040094 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
95 "crypto API arc4\n");
Jeff Garzik18379872006-09-22 21:19:05 -040096 priv->tx_tfm_arc4 = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -040097 goto fail;
98 }
99
Jeff Garzik28eb1772006-09-22 20:10:23 -0400100 priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
101 CRYPTO_ALG_ASYNC);
102 if (IS_ERR(priv->tx_tfm_michael)) {
Zhu Yi5a656942006-08-21 11:33:56 +0800103 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
104 "crypto API michael_mic\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400105 priv->tx_tfm_michael = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800106 goto fail;
107 }
108
Jeff Garzik28eb1772006-09-22 20:10:23 -0400109 priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
110 CRYPTO_ALG_ASYNC);
111 if (IS_ERR(priv->rx_tfm_arc4)) {
Zhu Yi5a656942006-08-21 11:33:56 +0800112 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
113 "crypto API arc4\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400114 priv->rx_tfm_arc4 = NULL;
Zhu Yi5a656942006-08-21 11:33:56 +0800115 goto fail;
116 }
117
Jeff Garzik28eb1772006-09-22 20:10:23 -0400118 priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
119 CRYPTO_ALG_ASYNC);
120 if (IS_ERR(priv->rx_tfm_michael)) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400121 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
122 "crypto API michael_mic\n");
Jeff Garzik18379872006-09-22 21:19:05 -0400123 priv->rx_tfm_michael = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400124 goto fail;
125 }
126
127 return priv;
128
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400129 fail:
Jeff Garzikb4538722005-05-12 22:48:20 -0400130 if (priv) {
Zhu Yi5a656942006-08-21 11:33:56 +0800131 if (priv->tx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400132 crypto_free_hash(priv->tx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800133 if (priv->tx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400134 crypto_free_blkcipher(priv->tx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800135 if (priv->rx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400136 crypto_free_hash(priv->rx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800137 if (priv->rx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400138 crypto_free_blkcipher(priv->rx_tfm_arc4);
Jeff Garzikb4538722005-05-12 22:48:20 -0400139 kfree(priv);
140 }
141
142 return NULL;
143}
144
Jeff Garzikb4538722005-05-12 22:48:20 -0400145static void ieee80211_tkip_deinit(void *priv)
146{
147 struct ieee80211_tkip_data *_priv = priv;
Zhu Yi5a656942006-08-21 11:33:56 +0800148 if (_priv) {
149 if (_priv->tx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400150 crypto_free_hash(_priv->tx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800151 if (_priv->tx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400152 crypto_free_blkcipher(_priv->tx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800153 if (_priv->rx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400154 crypto_free_hash(_priv->rx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800155 if (_priv->rx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400156 crypto_free_blkcipher(_priv->rx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800157 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400158 kfree(priv);
159}
160
Jeff Garzikb4538722005-05-12 22:48:20 -0400161static inline u16 RotR1(u16 val)
162{
163 return (val >> 1) | (val << 15);
164}
165
Jeff Garzikb4538722005-05-12 22:48:20 -0400166static inline u8 Lo8(u16 val)
167{
168 return val & 0xff;
169}
170
Jeff Garzikb4538722005-05-12 22:48:20 -0400171static inline u8 Hi8(u16 val)
172{
173 return val >> 8;
174}
175
Jeff Garzikb4538722005-05-12 22:48:20 -0400176static inline u16 Lo16(u32 val)
177{
178 return val & 0xffff;
179}
180
Jeff Garzikb4538722005-05-12 22:48:20 -0400181static inline u16 Hi16(u32 val)
182{
183 return val >> 16;
184}
185
Jeff Garzikb4538722005-05-12 22:48:20 -0400186static inline u16 Mk16(u8 hi, u8 lo)
187{
188 return lo | (((u16) hi) << 8);
189}
190
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400191static inline u16 Mk16_le(u16 * v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400192{
193 return le16_to_cpu(*v);
194}
195
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400196static const u16 Sbox[256] = {
Jeff Garzikb4538722005-05-12 22:48:20 -0400197 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
198 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
199 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
200 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
201 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
202 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
203 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
204 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
205 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
206 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
207 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
208 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
209 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
210 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
211 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
212 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
213 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
214 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
215 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
216 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
217 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
218 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
219 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
220 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
221 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
222 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
223 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
224 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
225 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
226 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
227 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
228 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
229};
230
Jeff Garzikb4538722005-05-12 22:48:20 -0400231static inline u16 _S_(u16 v)
232{
233 u16 t = Sbox[Hi8(v)];
234 return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
235}
236
Jeff Garzikb4538722005-05-12 22:48:20 -0400237#define PHASE1_LOOP_COUNT 8
238
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400239static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
240 u32 IV32)
Jeff Garzikb4538722005-05-12 22:48:20 -0400241{
242 int i, j;
243
244 /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
245 TTAK[0] = Lo16(IV32);
246 TTAK[1] = Hi16(IV32);
247 TTAK[2] = Mk16(TA[1], TA[0]);
248 TTAK[3] = Mk16(TA[3], TA[2]);
249 TTAK[4] = Mk16(TA[5], TA[4]);
250
251 for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
252 j = 2 * (i & 1);
253 TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
254 TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
255 TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
256 TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
257 TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
258 }
259}
260
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400261static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
Jeff Garzikb4538722005-05-12 22:48:20 -0400262 u16 IV16)
263{
264 /* Make temporary area overlap WEP seed so that the final copy can be
265 * avoided on little endian hosts. */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400266 u16 *PPK = (u16 *) & WEPSeed[4];
Jeff Garzikb4538722005-05-12 22:48:20 -0400267
268 /* Step 1 - make copy of TTAK and bring in TSC */
269 PPK[0] = TTAK[0];
270 PPK[1] = TTAK[1];
271 PPK[2] = TTAK[2];
272 PPK[3] = TTAK[3];
273 PPK[4] = TTAK[4];
274 PPK[5] = TTAK[4] + IV16;
275
276 /* Step 2 - 96-bit bijective mixing using S-box */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400277 PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) & TK[0]));
278 PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) & TK[2]));
279 PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) & TK[4]));
280 PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) & TK[6]));
281 PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) & TK[8]));
282 PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) & TK[10]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400283
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400284 PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) & TK[12]));
285 PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) & TK[14]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400286 PPK[2] += RotR1(PPK[1]);
287 PPK[3] += RotR1(PPK[2]);
288 PPK[4] += RotR1(PPK[3]);
289 PPK[5] += RotR1(PPK[4]);
290
291 /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
292 * WEPSeed[0..2] is transmitted as WEP IV */
293 WEPSeed[0] = Hi8(IV16);
294 WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
295 WEPSeed[2] = Lo8(IV16);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400296 WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) & TK[0])) >> 1);
Jeff Garzikb4538722005-05-12 22:48:20 -0400297
298#ifdef __BIG_ENDIAN
299 {
300 int i;
301 for (i = 0; i < 6; i++)
302 PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
303 }
304#endif
305}
306
Zhu Yi9184d932006-01-19 16:22:32 +0800307static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
308 u8 * rc4key, int keylen, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400309{
310 struct ieee80211_tkip_data *tkey = priv;
311 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800312 u8 *pos;
James Ketrenosee34af32005-09-21 11:54:36 -0500313 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400314
James Ketrenosee34af32005-09-21 11:54:36 -0500315 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500316
James Ketrenos31b59ea2005-09-21 11:58:49 -0500317 if (skb_headroom(skb) < 8 || skb->len < hdr_len)
Zhu Yi9184d932006-01-19 16:22:32 +0800318 return -1;
319
320 if (rc4key == NULL || keylen < 16)
321 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400322
Jeff Garzikb4538722005-05-12 22:48:20 -0400323 if (!tkey->tx_phase1_done) {
324 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
325 tkey->tx_iv32);
326 tkey->tx_phase1_done = 1;
327 }
328 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
329
330 len = skb->len - hdr_len;
331 pos = skb_push(skb, 8);
332 memmove(pos, pos + 8, hdr_len);
333 pos += hdr_len;
Jeff Garzikb4538722005-05-12 22:48:20 -0400334
James Ketrenos31b59ea2005-09-21 11:58:49 -0500335 *pos++ = *rc4key;
336 *pos++ = *(rc4key + 1);
337 *pos++ = *(rc4key + 2);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400338 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
Jeff Garzikb4538722005-05-12 22:48:20 -0400339 *pos++ = tkey->tx_iv32 & 0xff;
340 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
341 *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
342 *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
343
Zhu Yi9184d932006-01-19 16:22:32 +0800344 tkey->tx_iv16++;
345 if (tkey->tx_iv16 == 0) {
346 tkey->tx_phase1_done = 0;
347 tkey->tx_iv32++;
348 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400349
Zhu Yi9184d932006-01-19 16:22:32 +0800350 return 8;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500351}
352
353static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
354{
355 struct ieee80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400356 struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 };
James Ketrenos31b59ea2005-09-21 11:58:49 -0500357 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800358 u8 rc4key[16], *pos, *icv;
359 u32 crc;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500360 struct scatterlist sg;
361
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000362 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
James Ketrenos31b59ea2005-09-21 11:58:49 -0500363 if (net_ratelimit()) {
364 struct ieee80211_hdr_4addr *hdr =
365 (struct ieee80211_hdr_4addr *)skb->data;
Zhu Yi9184d932006-01-19 16:22:32 +0800366 printk(KERN_DEBUG ": TKIP countermeasures: dropped "
James Ketrenos31b59ea2005-09-21 11:58:49 -0500367 "TX packet to " MAC_FMT "\n",
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000368 MAC_ARG(hdr->addr1));
James Ketrenos31b59ea2005-09-21 11:58:49 -0500369 }
370 return -1;
371 }
372
373 if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
374 return -1;
375
376 len = skb->len - hdr_len;
377 pos = skb->data + hdr_len;
378
Zhu Yi9184d932006-01-19 16:22:32 +0800379 if ((ieee80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500380 return -1;
381
Zhu Yi9184d932006-01-19 16:22:32 +0800382 icv = skb_put(skb, 4);
383
384 crc = ~crc32_le(~0, pos, len);
385 icv[0] = crc;
386 icv[1] = crc >> 8;
387 icv[2] = crc >> 16;
388 icv[3] = crc >> 24;
389
Jeff Garzik28eb1772006-09-22 20:10:23 -0400390 crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
Jeff Garzikb4538722005-05-12 22:48:20 -0400391 sg.page = virt_to_page(pos);
392 sg.offset = offset_in_page(pos);
393 sg.length = len + 4;
Herbert Xuf12cc202006-08-22 20:36:13 +1000394 return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
Zhu Yib4328d82006-08-21 11:33:09 +0800395}
396
Jeff Garzik18379872006-09-22 21:19:05 -0400397/*
398 * deal with seq counter wrapping correctly.
399 * refer to timer_after() for jiffies wrapping handling
400 */
401static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n,
402 u32 iv32_o, u16 iv16_o)
403{
404 if ((s32)iv32_n - (s32)iv32_o < 0 ||
405 (iv32_n == iv32_o && iv16_n <= iv16_o))
406 return 1;
407 return 0;
408}
409
Jeff Garzikb4538722005-05-12 22:48:20 -0400410static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
411{
412 struct ieee80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400413 struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 };
Jeff Garzikb4538722005-05-12 22:48:20 -0400414 u8 rc4key[16];
415 u8 keyidx, *pos;
416 u32 iv32;
417 u16 iv16;
James Ketrenosee34af32005-09-21 11:54:36 -0500418 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400419 u8 icv[4];
420 u32 crc;
421 struct scatterlist sg;
422 int plen;
423
James Ketrenosee34af32005-09-21 11:54:36 -0500424 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500425
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000426 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
James Ketrenos20d64712005-09-21 11:53:43 -0500427 if (net_ratelimit()) {
Zhu Yi9184d932006-01-19 16:22:32 +0800428 printk(KERN_DEBUG ": TKIP countermeasures: dropped "
James Ketrenos20d64712005-09-21 11:53:43 -0500429 "received packet from " MAC_FMT "\n",
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000430 MAC_ARG(hdr->addr2));
James Ketrenos20d64712005-09-21 11:53:43 -0500431 }
432 return -1;
433 }
434
Jeff Garzikb4538722005-05-12 22:48:20 -0400435 if (skb->len < hdr_len + 8 + 4)
436 return -1;
437
Jeff Garzikb4538722005-05-12 22:48:20 -0400438 pos = skb->data + hdr_len;
439 keyidx = pos[3];
440 if (!(keyidx & (1 << 5))) {
441 if (net_ratelimit()) {
442 printk(KERN_DEBUG "TKIP: received packet without ExtIV"
443 " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
444 }
445 return -2;
446 }
447 keyidx >>= 6;
448 if (tkey->key_idx != keyidx) {
449 printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
450 "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
451 return -6;
452 }
453 if (!tkey->key_set) {
454 if (net_ratelimit()) {
455 printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
456 " with keyid=%d that does not have a configured"
457 " key\n", MAC_ARG(hdr->addr2), keyidx);
458 }
459 return -3;
460 }
461 iv16 = (pos[0] << 8) | pos[2];
462 iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
463 pos += 8;
464
Zhu Yib4328d82006-08-21 11:33:09 +0800465 if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400466 if (net_ratelimit()) {
467 printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
468 " previous TSC %08x%04x received TSC "
469 "%08x%04x\n", MAC_ARG(hdr->addr2),
470 tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
471 }
472 tkey->dot11RSNAStatsTKIPReplays++;
473 return -4;
474 }
475
476 if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
477 tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
478 tkey->rx_phase1_done = 1;
479 }
480 tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
481
482 plen = skb->len - hdr_len - 12;
483
Jeff Garzik28eb1772006-09-22 20:10:23 -0400484 crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
Jeff Garzikb4538722005-05-12 22:48:20 -0400485 sg.page = virt_to_page(pos);
486 sg.offset = offset_in_page(pos);
487 sg.length = plen + 4;
Herbert Xuf12cc202006-08-22 20:36:13 +1000488 if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
489 if (net_ratelimit()) {
490 printk(KERN_DEBUG ": TKIP: failed to decrypt "
491 "received packet from " MAC_FMT "\n",
492 MAC_ARG(hdr->addr2));
493 }
494 return -7;
495 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400496
497 crc = ~crc32_le(~0, pos, plen);
498 icv[0] = crc;
499 icv[1] = crc >> 8;
500 icv[2] = crc >> 16;
501 icv[3] = crc >> 24;
502 if (memcmp(icv, pos + plen, 4) != 0) {
503 if (iv32 != tkey->rx_iv32) {
504 /* Previously cached Phase1 result was already lost, so
505 * it needs to be recalculated for the next packet. */
506 tkey->rx_phase1_done = 0;
507 }
508 if (net_ratelimit()) {
509 printk(KERN_DEBUG "TKIP: ICV error detected: STA="
510 MAC_FMT "\n", MAC_ARG(hdr->addr2));
511 }
512 tkey->dot11RSNAStatsTKIPICVErrors++;
513 return -5;
514 }
515
516 /* Update real counters only after Michael MIC verification has
517 * completed */
518 tkey->rx_iv32_new = iv32;
519 tkey->rx_iv16_new = iv16;
520
521 /* Remove IV and ICV */
522 memmove(skb->data + 8, skb->data, hdr_len);
523 skb_pull(skb, 8);
524 skb_trim(skb, skb->len - 4);
525
526 return keyidx;
527}
528
Jeff Garzik28eb1772006-09-22 20:10:23 -0400529static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400530 u8 * data, size_t data_len, u8 * mic)
Jeff Garzikb4538722005-05-12 22:48:20 -0400531{
Herbert Xu35058682006-08-24 19:10:20 +1000532 struct hash_desc desc;
Jeff Garzikb4538722005-05-12 22:48:20 -0400533 struct scatterlist sg[2];
534
Zhu Yi5a656942006-08-21 11:33:56 +0800535 if (tfm_michael == NULL) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400536 printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
537 return -1;
538 }
539 sg[0].page = virt_to_page(hdr);
540 sg[0].offset = offset_in_page(hdr);
541 sg[0].length = 16;
542
543 sg[1].page = virt_to_page(data);
544 sg[1].offset = offset_in_page(data);
545 sg[1].length = data_len;
546
Jeff Garzik28eb1772006-09-22 20:10:23 -0400547 if (crypto_hash_setkey(tfm_michael, key, 8))
Herbert Xu35058682006-08-24 19:10:20 +1000548 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400549
Jeff Garzik28eb1772006-09-22 20:10:23 -0400550 desc.tfm = tfm_michael;
Herbert Xu35058682006-08-24 19:10:20 +1000551 desc.flags = 0;
552 return crypto_hash_digest(&desc, sg, data_len + 16, mic);
Jeff Garzikb4538722005-05-12 22:48:20 -0400553}
554
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400555static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
Jeff Garzikb4538722005-05-12 22:48:20 -0400556{
James Ketrenosee34af32005-09-21 11:54:36 -0500557 struct ieee80211_hdr_4addr *hdr11;
Zhu Yiea284152006-04-13 17:17:06 +0800558 u16 stype;
Jeff Garzikb4538722005-05-12 22:48:20 -0400559
James Ketrenosee34af32005-09-21 11:54:36 -0500560 hdr11 = (struct ieee80211_hdr_4addr *)skb->data;
Zhu Yiea284152006-04-13 17:17:06 +0800561 stype = WLAN_FC_GET_STYPE(le16_to_cpu(hdr11->frame_ctl));
562
Jeff Garzikb4538722005-05-12 22:48:20 -0400563 switch (le16_to_cpu(hdr11->frame_ctl) &
564 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
565 case IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400566 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
567 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400568 break;
569 case IEEE80211_FCTL_FROMDS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400570 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
571 memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400572 break;
573 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400574 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
575 memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400576 break;
577 case 0:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400578 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
579 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400580 break;
581 }
582
Zhu Yiea284152006-04-13 17:17:06 +0800583 if (stype & IEEE80211_STYPE_QOS_DATA) {
584 const struct ieee80211_hdr_3addrqos *qoshdr =
585 (struct ieee80211_hdr_3addrqos *)skb->data;
Zhu Yi65b6a272006-08-21 11:32:31 +0800586 hdr[12] = qoshdr->qos_ctl & cpu_to_le16(IEEE80211_QCTL_TID);
Zhu Yiea284152006-04-13 17:17:06 +0800587 } else
588 hdr[12] = 0; /* priority */
589
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400590 hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
Jeff Garzikb4538722005-05-12 22:48:20 -0400591}
592
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400593static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
594 void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400595{
596 struct ieee80211_tkip_data *tkey = priv;
597 u8 *pos;
598
599 if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
600 printk(KERN_DEBUG "Invalid packet for Michael MIC add "
601 "(tailroom=%d hdr_len=%d skb->len=%d)\n",
602 skb_tailroom(skb), hdr_len, skb->len);
603 return -1;
604 }
605
606 michael_mic_hdr(skb, tkey->tx_hdr);
607 pos = skb_put(skb, 8);
Zhu Yi5a656942006-08-21 11:33:56 +0800608 if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400609 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
610 return -1;
611
612 return 0;
613}
614
Jeff Garzikb4538722005-05-12 22:48:20 -0400615static void ieee80211_michael_mic_failure(struct net_device *dev,
James Ketrenosee34af32005-09-21 11:54:36 -0500616 struct ieee80211_hdr_4addr *hdr,
617 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400618{
619 union iwreq_data wrqu;
620 struct iw_michaelmicfailure ev;
621
622 /* TODO: needed parameters: count, keyid, key type, TSC */
623 memset(&ev, 0, sizeof(ev));
624 ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
625 if (hdr->addr1[0] & 0x01)
626 ev.flags |= IW_MICFAILURE_GROUP;
627 else
628 ev.flags |= IW_MICFAILURE_PAIRWISE;
629 ev.src_addr.sa_family = ARPHRD_ETHER;
630 memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
631 memset(&wrqu, 0, sizeof(wrqu));
632 wrqu.data.length = sizeof(ev);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400633 wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400634}
Jeff Garzikb4538722005-05-12 22:48:20 -0400635
636static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400637 int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400638{
639 struct ieee80211_tkip_data *tkey = priv;
640 u8 mic[8];
641
642 if (!tkey->key_set)
643 return -1;
644
645 michael_mic_hdr(skb, tkey->rx_hdr);
Zhu Yi5a656942006-08-21 11:33:56 +0800646 if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400647 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
648 return -1;
649 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
James Ketrenosee34af32005-09-21 11:54:36 -0500650 struct ieee80211_hdr_4addr *hdr;
651 hdr = (struct ieee80211_hdr_4addr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400652 printk(KERN_DEBUG "%s: Michael MIC verification failed for "
653 "MSDU from " MAC_FMT " keyidx=%d\n",
654 skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
655 keyidx);
656 if (skb->dev)
657 ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
658 tkey->dot11RSNAStatsTKIPLocalMICFailures++;
659 return -1;
660 }
661
662 /* Update TSC counters for RX now that the packet verification has
663 * completed. */
664 tkey->rx_iv32 = tkey->rx_iv32_new;
665 tkey->rx_iv16 = tkey->rx_iv16_new;
666
667 skb_trim(skb, skb->len - 8);
668
669 return 0;
670}
671
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400672static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400673{
674 struct ieee80211_tkip_data *tkey = priv;
675 int keyidx;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400676 struct crypto_hash *tfm = tkey->tx_tfm_michael;
677 struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
678 struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
679 struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400680
681 keyidx = tkey->key_idx;
682 memset(tkey, 0, sizeof(*tkey));
683 tkey->key_idx = keyidx;
Zhu Yi5a656942006-08-21 11:33:56 +0800684 tkey->tx_tfm_michael = tfm;
685 tkey->tx_tfm_arc4 = tfm2;
686 tkey->rx_tfm_michael = tfm3;
687 tkey->rx_tfm_arc4 = tfm4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400688 if (len == TKIP_KEY_LEN) {
689 memcpy(tkey->key, key, TKIP_KEY_LEN);
690 tkey->key_set = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400691 tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400692 if (seq) {
693 tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400694 (seq[3] << 8) | seq[2];
Jeff Garzikb4538722005-05-12 22:48:20 -0400695 tkey->rx_iv16 = (seq[1] << 8) | seq[0];
696 }
697 } else if (len == 0)
698 tkey->key_set = 0;
699 else
700 return -1;
701
702 return 0;
703}
704
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400705static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400706{
707 struct ieee80211_tkip_data *tkey = priv;
708
709 if (len < TKIP_KEY_LEN)
710 return -1;
711
712 if (!tkey->key_set)
713 return 0;
714 memcpy(key, tkey->key, TKIP_KEY_LEN);
715
716 if (seq) {
717 /* Return the sequence number of the last transmitted frame. */
718 u16 iv16 = tkey->tx_iv16;
719 u32 iv32 = tkey->tx_iv32;
720 if (iv16 == 0)
721 iv32--;
722 iv16--;
723 seq[0] = tkey->tx_iv16;
724 seq[1] = tkey->tx_iv16 >> 8;
725 seq[2] = tkey->tx_iv32;
726 seq[3] = tkey->tx_iv32 >> 8;
727 seq[4] = tkey->tx_iv32 >> 16;
728 seq[5] = tkey->tx_iv32 >> 24;
729 }
730
731 return TKIP_KEY_LEN;
732}
733
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400734static char *ieee80211_tkip_print_stats(char *p, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400735{
736 struct ieee80211_tkip_data *tkip = priv;
737 p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
738 "tx_pn=%02x%02x%02x%02x%02x%02x "
739 "rx_pn=%02x%02x%02x%02x%02x%02x "
740 "replays=%d icv_errors=%d local_mic_failures=%d\n",
741 tkip->key_idx, tkip->key_set,
742 (tkip->tx_iv32 >> 24) & 0xff,
743 (tkip->tx_iv32 >> 16) & 0xff,
744 (tkip->tx_iv32 >> 8) & 0xff,
745 tkip->tx_iv32 & 0xff,
746 (tkip->tx_iv16 >> 8) & 0xff,
747 tkip->tx_iv16 & 0xff,
748 (tkip->rx_iv32 >> 24) & 0xff,
749 (tkip->rx_iv32 >> 16) & 0xff,
750 (tkip->rx_iv32 >> 8) & 0xff,
751 tkip->rx_iv32 & 0xff,
752 (tkip->rx_iv16 >> 8) & 0xff,
753 tkip->rx_iv16 & 0xff,
754 tkip->dot11RSNAStatsTKIPReplays,
755 tkip->dot11RSNAStatsTKIPICVErrors,
756 tkip->dot11RSNAStatsTKIPLocalMICFailures);
757 return p;
758}
759
Jeff Garzikb4538722005-05-12 22:48:20 -0400760static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
James Ketrenos74079fd2005-09-13 17:35:21 -0500761 .name = "TKIP",
762 .init = ieee80211_tkip_init,
763 .deinit = ieee80211_tkip_deinit,
Zhu Yi9184d932006-01-19 16:22:32 +0800764 .build_iv = ieee80211_tkip_hdr,
James Ketrenos74079fd2005-09-13 17:35:21 -0500765 .encrypt_mpdu = ieee80211_tkip_encrypt,
766 .decrypt_mpdu = ieee80211_tkip_decrypt,
767 .encrypt_msdu = ieee80211_michael_mic_add,
768 .decrypt_msdu = ieee80211_michael_mic_verify,
769 .set_key = ieee80211_tkip_set_key,
770 .get_key = ieee80211_tkip_get_key,
771 .print_stats = ieee80211_tkip_print_stats,
James Ketrenos1264fc02005-09-21 11:54:53 -0500772 .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
773 .extra_mpdu_postfix_len = 4, /* ICV */
774 .extra_msdu_postfix_len = 8, /* MIC */
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000775 .get_flags = ieee80211_tkip_get_flags,
776 .set_flags = ieee80211_tkip_set_flags,
James Ketrenos74079fd2005-09-13 17:35:21 -0500777 .owner = THIS_MODULE,
Jeff Garzikb4538722005-05-12 22:48:20 -0400778};
779
Jeff Garzikb4538722005-05-12 22:48:20 -0400780static int __init ieee80211_crypto_tkip_init(void)
781{
782 return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
783}
784
Jeff Garzikb4538722005-05-12 22:48:20 -0400785static void __exit ieee80211_crypto_tkip_exit(void)
786{
787 ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
788}
789
Jeff Garzikb4538722005-05-12 22:48:20 -0400790module_init(ieee80211_crypto_tkip_init);
791module_exit(ieee80211_crypto_tkip_exit);