blob: 259572dfd4f1923fdab04ff0d5e1d719094754da [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");
Herbert Xuf12cc202006-08-22 20:36:13 +100096 priv->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");
105 goto fail;
106 }
107
Jeff Garzik28eb1772006-09-22 20:10:23 -0400108 priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0,
109 CRYPTO_ALG_ASYNC);
110 if (IS_ERR(priv->rx_tfm_arc4)) {
Zhu Yi5a656942006-08-21 11:33:56 +0800111 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
112 "crypto API arc4\n");
113 goto fail;
114 }
115
Jeff Garzik28eb1772006-09-22 20:10:23 -0400116 priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0,
117 CRYPTO_ALG_ASYNC);
118 if (IS_ERR(priv->rx_tfm_michael)) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400119 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
120 "crypto API michael_mic\n");
Herbert Xu35058682006-08-24 19:10:20 +1000121 priv->tfm_michael = NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400122 goto fail;
123 }
124
125 return priv;
126
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400127 fail:
Jeff Garzikb4538722005-05-12 22:48:20 -0400128 if (priv) {
Zhu Yi5a656942006-08-21 11:33:56 +0800129 if (priv->tx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400130 crypto_free_hash(priv->tx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800131 if (priv->tx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400132 crypto_free_blkcipher(priv->tx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800133 if (priv->rx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400134 crypto_free_hash(priv->rx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800135 if (priv->rx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400136 crypto_free_blkcipher(priv->rx_tfm_arc4);
Jeff Garzikb4538722005-05-12 22:48:20 -0400137 kfree(priv);
138 }
139
140 return NULL;
141}
142
Jeff Garzikb4538722005-05-12 22:48:20 -0400143static void ieee80211_tkip_deinit(void *priv)
144{
145 struct ieee80211_tkip_data *_priv = priv;
Zhu Yi5a656942006-08-21 11:33:56 +0800146 if (_priv) {
147 if (_priv->tx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400148 crypto_free_hash(_priv->tx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800149 if (_priv->tx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400150 crypto_free_blkcipher(_priv->tx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800151 if (_priv->rx_tfm_michael)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400152 crypto_free_hash(_priv->rx_tfm_michael);
Zhu Yi5a656942006-08-21 11:33:56 +0800153 if (_priv->rx_tfm_arc4)
Jeff Garzik28eb1772006-09-22 20:10:23 -0400154 crypto_free_blkcipher(_priv->rx_tfm_arc4);
Zhu Yi5a656942006-08-21 11:33:56 +0800155 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400156 kfree(priv);
157}
158
Jeff Garzikb4538722005-05-12 22:48:20 -0400159static inline u16 RotR1(u16 val)
160{
161 return (val >> 1) | (val << 15);
162}
163
Jeff Garzikb4538722005-05-12 22:48:20 -0400164static inline u8 Lo8(u16 val)
165{
166 return val & 0xff;
167}
168
Jeff Garzikb4538722005-05-12 22:48:20 -0400169static inline u8 Hi8(u16 val)
170{
171 return val >> 8;
172}
173
Jeff Garzikb4538722005-05-12 22:48:20 -0400174static inline u16 Lo16(u32 val)
175{
176 return val & 0xffff;
177}
178
Jeff Garzikb4538722005-05-12 22:48:20 -0400179static inline u16 Hi16(u32 val)
180{
181 return val >> 16;
182}
183
Jeff Garzikb4538722005-05-12 22:48:20 -0400184static inline u16 Mk16(u8 hi, u8 lo)
185{
186 return lo | (((u16) hi) << 8);
187}
188
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400189static inline u16 Mk16_le(u16 * v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400190{
191 return le16_to_cpu(*v);
192}
193
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400194static const u16 Sbox[256] = {
Jeff Garzikb4538722005-05-12 22:48:20 -0400195 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
196 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
197 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
198 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
199 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
200 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
201 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
202 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
203 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
204 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
205 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
206 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
207 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
208 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
209 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
210 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
211 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
212 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
213 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
214 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
215 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
216 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
217 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
218 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
219 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
220 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
221 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
222 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
223 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
224 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
225 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
226 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
227};
228
Jeff Garzikb4538722005-05-12 22:48:20 -0400229static inline u16 _S_(u16 v)
230{
231 u16 t = Sbox[Hi8(v)];
232 return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
233}
234
Jeff Garzikb4538722005-05-12 22:48:20 -0400235#define PHASE1_LOOP_COUNT 8
236
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400237static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
238 u32 IV32)
Jeff Garzikb4538722005-05-12 22:48:20 -0400239{
240 int i, j;
241
242 /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
243 TTAK[0] = Lo16(IV32);
244 TTAK[1] = Hi16(IV32);
245 TTAK[2] = Mk16(TA[1], TA[0]);
246 TTAK[3] = Mk16(TA[3], TA[2]);
247 TTAK[4] = Mk16(TA[5], TA[4]);
248
249 for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
250 j = 2 * (i & 1);
251 TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
252 TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
253 TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
254 TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
255 TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
256 }
257}
258
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400259static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
Jeff Garzikb4538722005-05-12 22:48:20 -0400260 u16 IV16)
261{
262 /* Make temporary area overlap WEP seed so that the final copy can be
263 * avoided on little endian hosts. */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400264 u16 *PPK = (u16 *) & WEPSeed[4];
Jeff Garzikb4538722005-05-12 22:48:20 -0400265
266 /* Step 1 - make copy of TTAK and bring in TSC */
267 PPK[0] = TTAK[0];
268 PPK[1] = TTAK[1];
269 PPK[2] = TTAK[2];
270 PPK[3] = TTAK[3];
271 PPK[4] = TTAK[4];
272 PPK[5] = TTAK[4] + IV16;
273
274 /* Step 2 - 96-bit bijective mixing using S-box */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400275 PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) & TK[0]));
276 PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) & TK[2]));
277 PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) & TK[4]));
278 PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) & TK[6]));
279 PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) & TK[8]));
280 PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) & TK[10]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400281
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400282 PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) & TK[12]));
283 PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) & TK[14]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400284 PPK[2] += RotR1(PPK[1]);
285 PPK[3] += RotR1(PPK[2]);
286 PPK[4] += RotR1(PPK[3]);
287 PPK[5] += RotR1(PPK[4]);
288
289 /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
290 * WEPSeed[0..2] is transmitted as WEP IV */
291 WEPSeed[0] = Hi8(IV16);
292 WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
293 WEPSeed[2] = Lo8(IV16);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400294 WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) & TK[0])) >> 1);
Jeff Garzikb4538722005-05-12 22:48:20 -0400295
296#ifdef __BIG_ENDIAN
297 {
298 int i;
299 for (i = 0; i < 6; i++)
300 PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
301 }
302#endif
303}
304
Zhu Yi9184d932006-01-19 16:22:32 +0800305static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len,
306 u8 * rc4key, int keylen, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400307{
308 struct ieee80211_tkip_data *tkey = priv;
309 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800310 u8 *pos;
James Ketrenosee34af32005-09-21 11:54:36 -0500311 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400312
James Ketrenosee34af32005-09-21 11:54:36 -0500313 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500314
James Ketrenos31b59ea2005-09-21 11:58:49 -0500315 if (skb_headroom(skb) < 8 || skb->len < hdr_len)
Zhu Yi9184d932006-01-19 16:22:32 +0800316 return -1;
317
318 if (rc4key == NULL || keylen < 16)
319 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400320
Jeff Garzikb4538722005-05-12 22:48:20 -0400321 if (!tkey->tx_phase1_done) {
322 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
323 tkey->tx_iv32);
324 tkey->tx_phase1_done = 1;
325 }
326 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
327
328 len = skb->len - hdr_len;
329 pos = skb_push(skb, 8);
330 memmove(pos, pos + 8, hdr_len);
331 pos += hdr_len;
Jeff Garzikb4538722005-05-12 22:48:20 -0400332
James Ketrenos31b59ea2005-09-21 11:58:49 -0500333 *pos++ = *rc4key;
334 *pos++ = *(rc4key + 1);
335 *pos++ = *(rc4key + 2);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400336 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
Jeff Garzikb4538722005-05-12 22:48:20 -0400337 *pos++ = tkey->tx_iv32 & 0xff;
338 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
339 *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
340 *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
341
Zhu Yi9184d932006-01-19 16:22:32 +0800342 tkey->tx_iv16++;
343 if (tkey->tx_iv16 == 0) {
344 tkey->tx_phase1_done = 0;
345 tkey->tx_iv32++;
346 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400347
Zhu Yi9184d932006-01-19 16:22:32 +0800348 return 8;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500349}
350
351static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
352{
353 struct ieee80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400354 struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 };
James Ketrenos31b59ea2005-09-21 11:58:49 -0500355 int len;
Zhu Yi9184d932006-01-19 16:22:32 +0800356 u8 rc4key[16], *pos, *icv;
357 u32 crc;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500358 struct scatterlist sg;
359
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000360 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
James Ketrenos31b59ea2005-09-21 11:58:49 -0500361 if (net_ratelimit()) {
362 struct ieee80211_hdr_4addr *hdr =
363 (struct ieee80211_hdr_4addr *)skb->data;
Zhu Yi9184d932006-01-19 16:22:32 +0800364 printk(KERN_DEBUG ": TKIP countermeasures: dropped "
James Ketrenos31b59ea2005-09-21 11:58:49 -0500365 "TX packet to " MAC_FMT "\n",
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000366 MAC_ARG(hdr->addr1));
James Ketrenos31b59ea2005-09-21 11:58:49 -0500367 }
368 return -1;
369 }
370
371 if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
372 return -1;
373
374 len = skb->len - hdr_len;
375 pos = skb->data + hdr_len;
376
Zhu Yi9184d932006-01-19 16:22:32 +0800377 if ((ieee80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0)
James Ketrenos31b59ea2005-09-21 11:58:49 -0500378 return -1;
379
Zhu Yi9184d932006-01-19 16:22:32 +0800380 icv = skb_put(skb, 4);
381
382 crc = ~crc32_le(~0, pos, len);
383 icv[0] = crc;
384 icv[1] = crc >> 8;
385 icv[2] = crc >> 16;
386 icv[3] = crc >> 24;
387
Jeff Garzik28eb1772006-09-22 20:10:23 -0400388 crypto_blkcipher_setkey(tkey->tx_tfm_arc4, rc4key, 16);
Jeff Garzikb4538722005-05-12 22:48:20 -0400389 sg.page = virt_to_page(pos);
390 sg.offset = offset_in_page(pos);
391 sg.length = len + 4;
Herbert Xuf12cc202006-08-22 20:36:13 +1000392 return crypto_blkcipher_encrypt(&desc, &sg, &sg, len + 4);
Zhu Yib4328d82006-08-21 11:33:09 +0800393}
394
Jeff Garzikb4538722005-05-12 22:48:20 -0400395static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
396{
397 struct ieee80211_tkip_data *tkey = priv;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400398 struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 };
Jeff Garzikb4538722005-05-12 22:48:20 -0400399 u8 rc4key[16];
400 u8 keyidx, *pos;
401 u32 iv32;
402 u16 iv16;
James Ketrenosee34af32005-09-21 11:54:36 -0500403 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400404 u8 icv[4];
405 u32 crc;
406 struct scatterlist sg;
407 int plen;
408
James Ketrenosee34af32005-09-21 11:54:36 -0500409 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500410
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000411 if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) {
James Ketrenos20d64712005-09-21 11:53:43 -0500412 if (net_ratelimit()) {
Zhu Yi9184d932006-01-19 16:22:32 +0800413 printk(KERN_DEBUG ": TKIP countermeasures: dropped "
James Ketrenos20d64712005-09-21 11:53:43 -0500414 "received packet from " MAC_FMT "\n",
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000415 MAC_ARG(hdr->addr2));
James Ketrenos20d64712005-09-21 11:53:43 -0500416 }
417 return -1;
418 }
419
Jeff Garzikb4538722005-05-12 22:48:20 -0400420 if (skb->len < hdr_len + 8 + 4)
421 return -1;
422
Jeff Garzikb4538722005-05-12 22:48:20 -0400423 pos = skb->data + hdr_len;
424 keyidx = pos[3];
425 if (!(keyidx & (1 << 5))) {
426 if (net_ratelimit()) {
427 printk(KERN_DEBUG "TKIP: received packet without ExtIV"
428 " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
429 }
430 return -2;
431 }
432 keyidx >>= 6;
433 if (tkey->key_idx != keyidx) {
434 printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
435 "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
436 return -6;
437 }
438 if (!tkey->key_set) {
439 if (net_ratelimit()) {
440 printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
441 " with keyid=%d that does not have a configured"
442 " key\n", MAC_ARG(hdr->addr2), keyidx);
443 }
444 return -3;
445 }
446 iv16 = (pos[0] << 8) | pos[2];
447 iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
448 pos += 8;
449
Zhu Yib4328d82006-08-21 11:33:09 +0800450 if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400451 if (net_ratelimit()) {
452 printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
453 " previous TSC %08x%04x received TSC "
454 "%08x%04x\n", MAC_ARG(hdr->addr2),
455 tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
456 }
457 tkey->dot11RSNAStatsTKIPReplays++;
458 return -4;
459 }
460
461 if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
462 tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
463 tkey->rx_phase1_done = 1;
464 }
465 tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
466
467 plen = skb->len - hdr_len - 12;
468
Jeff Garzik28eb1772006-09-22 20:10:23 -0400469 crypto_blkcipher_setkey(tkey->rx_tfm_arc4, rc4key, 16);
Jeff Garzikb4538722005-05-12 22:48:20 -0400470 sg.page = virt_to_page(pos);
471 sg.offset = offset_in_page(pos);
472 sg.length = plen + 4;
Herbert Xuf12cc202006-08-22 20:36:13 +1000473 if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) {
474 if (net_ratelimit()) {
475 printk(KERN_DEBUG ": TKIP: failed to decrypt "
476 "received packet from " MAC_FMT "\n",
477 MAC_ARG(hdr->addr2));
478 }
479 return -7;
480 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400481
482 crc = ~crc32_le(~0, pos, plen);
483 icv[0] = crc;
484 icv[1] = crc >> 8;
485 icv[2] = crc >> 16;
486 icv[3] = crc >> 24;
487 if (memcmp(icv, pos + plen, 4) != 0) {
488 if (iv32 != tkey->rx_iv32) {
489 /* Previously cached Phase1 result was already lost, so
490 * it needs to be recalculated for the next packet. */
491 tkey->rx_phase1_done = 0;
492 }
493 if (net_ratelimit()) {
494 printk(KERN_DEBUG "TKIP: ICV error detected: STA="
495 MAC_FMT "\n", MAC_ARG(hdr->addr2));
496 }
497 tkey->dot11RSNAStatsTKIPICVErrors++;
498 return -5;
499 }
500
501 /* Update real counters only after Michael MIC verification has
502 * completed */
503 tkey->rx_iv32_new = iv32;
504 tkey->rx_iv16_new = iv16;
505
506 /* Remove IV and ICV */
507 memmove(skb->data + 8, skb->data, hdr_len);
508 skb_pull(skb, 8);
509 skb_trim(skb, skb->len - 4);
510
511 return keyidx;
512}
513
Jeff Garzik28eb1772006-09-22 20:10:23 -0400514static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400515 u8 * data, size_t data_len, u8 * mic)
Jeff Garzikb4538722005-05-12 22:48:20 -0400516{
Herbert Xu35058682006-08-24 19:10:20 +1000517 struct hash_desc desc;
Jeff Garzikb4538722005-05-12 22:48:20 -0400518 struct scatterlist sg[2];
519
Zhu Yi5a656942006-08-21 11:33:56 +0800520 if (tfm_michael == NULL) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400521 printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
522 return -1;
523 }
524 sg[0].page = virt_to_page(hdr);
525 sg[0].offset = offset_in_page(hdr);
526 sg[0].length = 16;
527
528 sg[1].page = virt_to_page(data);
529 sg[1].offset = offset_in_page(data);
530 sg[1].length = data_len;
531
Jeff Garzik28eb1772006-09-22 20:10:23 -0400532 if (crypto_hash_setkey(tfm_michael, key, 8))
Herbert Xu35058682006-08-24 19:10:20 +1000533 return -1;
Jeff Garzikb4538722005-05-12 22:48:20 -0400534
Jeff Garzik28eb1772006-09-22 20:10:23 -0400535 desc.tfm = tfm_michael;
Herbert Xu35058682006-08-24 19:10:20 +1000536 desc.flags = 0;
537 return crypto_hash_digest(&desc, sg, data_len + 16, mic);
Jeff Garzikb4538722005-05-12 22:48:20 -0400538}
539
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400540static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
Jeff Garzikb4538722005-05-12 22:48:20 -0400541{
James Ketrenosee34af32005-09-21 11:54:36 -0500542 struct ieee80211_hdr_4addr *hdr11;
Zhu Yiea284152006-04-13 17:17:06 +0800543 u16 stype;
Jeff Garzikb4538722005-05-12 22:48:20 -0400544
James Ketrenosee34af32005-09-21 11:54:36 -0500545 hdr11 = (struct ieee80211_hdr_4addr *)skb->data;
Zhu Yiea284152006-04-13 17:17:06 +0800546 stype = WLAN_FC_GET_STYPE(le16_to_cpu(hdr11->frame_ctl));
547
Jeff Garzikb4538722005-05-12 22:48:20 -0400548 switch (le16_to_cpu(hdr11->frame_ctl) &
549 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
550 case IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400551 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
552 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400553 break;
554 case IEEE80211_FCTL_FROMDS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400555 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
556 memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400557 break;
558 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400559 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
560 memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400561 break;
562 case 0:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400563 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
564 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400565 break;
566 }
567
Zhu Yiea284152006-04-13 17:17:06 +0800568 if (stype & IEEE80211_STYPE_QOS_DATA) {
569 const struct ieee80211_hdr_3addrqos *qoshdr =
570 (struct ieee80211_hdr_3addrqos *)skb->data;
Zhu Yi65b6a272006-08-21 11:32:31 +0800571 hdr[12] = qoshdr->qos_ctl & cpu_to_le16(IEEE80211_QCTL_TID);
Zhu Yiea284152006-04-13 17:17:06 +0800572 } else
573 hdr[12] = 0; /* priority */
574
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400575 hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
Jeff Garzikb4538722005-05-12 22:48:20 -0400576}
577
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400578static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
579 void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400580{
581 struct ieee80211_tkip_data *tkey = priv;
582 u8 *pos;
583
584 if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
585 printk(KERN_DEBUG "Invalid packet for Michael MIC add "
586 "(tailroom=%d hdr_len=%d skb->len=%d)\n",
587 skb_tailroom(skb), hdr_len, skb->len);
588 return -1;
589 }
590
591 michael_mic_hdr(skb, tkey->tx_hdr);
592 pos = skb_put(skb, 8);
Zhu Yi5a656942006-08-21 11:33:56 +0800593 if (michael_mic(tkey->tx_tfm_michael, &tkey->key[16], tkey->tx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400594 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
595 return -1;
596
597 return 0;
598}
599
Jeff Garzikb4538722005-05-12 22:48:20 -0400600static void ieee80211_michael_mic_failure(struct net_device *dev,
James Ketrenosee34af32005-09-21 11:54:36 -0500601 struct ieee80211_hdr_4addr *hdr,
602 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400603{
604 union iwreq_data wrqu;
605 struct iw_michaelmicfailure ev;
606
607 /* TODO: needed parameters: count, keyid, key type, TSC */
608 memset(&ev, 0, sizeof(ev));
609 ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
610 if (hdr->addr1[0] & 0x01)
611 ev.flags |= IW_MICFAILURE_GROUP;
612 else
613 ev.flags |= IW_MICFAILURE_PAIRWISE;
614 ev.src_addr.sa_family = ARPHRD_ETHER;
615 memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
616 memset(&wrqu, 0, sizeof(wrqu));
617 wrqu.data.length = sizeof(ev);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400618 wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400619}
Jeff Garzikb4538722005-05-12 22:48:20 -0400620
621static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400622 int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400623{
624 struct ieee80211_tkip_data *tkey = priv;
625 u8 mic[8];
626
627 if (!tkey->key_set)
628 return -1;
629
630 michael_mic_hdr(skb, tkey->rx_hdr);
Zhu Yi5a656942006-08-21 11:33:56 +0800631 if (michael_mic(tkey->rx_tfm_michael, &tkey->key[24], tkey->rx_hdr,
Jeff Garzikb4538722005-05-12 22:48:20 -0400632 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
633 return -1;
634 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
James Ketrenosee34af32005-09-21 11:54:36 -0500635 struct ieee80211_hdr_4addr *hdr;
636 hdr = (struct ieee80211_hdr_4addr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400637 printk(KERN_DEBUG "%s: Michael MIC verification failed for "
638 "MSDU from " MAC_FMT " keyidx=%d\n",
639 skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
640 keyidx);
641 if (skb->dev)
642 ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
643 tkey->dot11RSNAStatsTKIPLocalMICFailures++;
644 return -1;
645 }
646
647 /* Update TSC counters for RX now that the packet verification has
648 * completed. */
649 tkey->rx_iv32 = tkey->rx_iv32_new;
650 tkey->rx_iv16 = tkey->rx_iv16_new;
651
652 skb_trim(skb, skb->len - 8);
653
654 return 0;
655}
656
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400657static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400658{
659 struct ieee80211_tkip_data *tkey = priv;
660 int keyidx;
Jeff Garzik28eb1772006-09-22 20:10:23 -0400661 struct crypto_hash *tfm = tkey->tx_tfm_michael;
662 struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4;
663 struct crypto_hash *tfm3 = tkey->rx_tfm_michael;
664 struct crypto_blkcipher *tfm4 = tkey->rx_tfm_arc4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400665
666 keyidx = tkey->key_idx;
667 memset(tkey, 0, sizeof(*tkey));
668 tkey->key_idx = keyidx;
Zhu Yi5a656942006-08-21 11:33:56 +0800669 tkey->tx_tfm_michael = tfm;
670 tkey->tx_tfm_arc4 = tfm2;
671 tkey->rx_tfm_michael = tfm3;
672 tkey->rx_tfm_arc4 = tfm4;
Jeff Garzikb4538722005-05-12 22:48:20 -0400673 if (len == TKIP_KEY_LEN) {
674 memcpy(tkey->key, key, TKIP_KEY_LEN);
675 tkey->key_set = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400676 tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400677 if (seq) {
678 tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400679 (seq[3] << 8) | seq[2];
Jeff Garzikb4538722005-05-12 22:48:20 -0400680 tkey->rx_iv16 = (seq[1] << 8) | seq[0];
681 }
682 } else if (len == 0)
683 tkey->key_set = 0;
684 else
685 return -1;
686
687 return 0;
688}
689
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400690static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400691{
692 struct ieee80211_tkip_data *tkey = priv;
693
694 if (len < TKIP_KEY_LEN)
695 return -1;
696
697 if (!tkey->key_set)
698 return 0;
699 memcpy(key, tkey->key, TKIP_KEY_LEN);
700
701 if (seq) {
702 /* Return the sequence number of the last transmitted frame. */
703 u16 iv16 = tkey->tx_iv16;
704 u32 iv32 = tkey->tx_iv32;
705 if (iv16 == 0)
706 iv32--;
707 iv16--;
708 seq[0] = tkey->tx_iv16;
709 seq[1] = tkey->tx_iv16 >> 8;
710 seq[2] = tkey->tx_iv32;
711 seq[3] = tkey->tx_iv32 >> 8;
712 seq[4] = tkey->tx_iv32 >> 16;
713 seq[5] = tkey->tx_iv32 >> 24;
714 }
715
716 return TKIP_KEY_LEN;
717}
718
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400719static char *ieee80211_tkip_print_stats(char *p, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400720{
721 struct ieee80211_tkip_data *tkip = priv;
722 p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
723 "tx_pn=%02x%02x%02x%02x%02x%02x "
724 "rx_pn=%02x%02x%02x%02x%02x%02x "
725 "replays=%d icv_errors=%d local_mic_failures=%d\n",
726 tkip->key_idx, tkip->key_set,
727 (tkip->tx_iv32 >> 24) & 0xff,
728 (tkip->tx_iv32 >> 16) & 0xff,
729 (tkip->tx_iv32 >> 8) & 0xff,
730 tkip->tx_iv32 & 0xff,
731 (tkip->tx_iv16 >> 8) & 0xff,
732 tkip->tx_iv16 & 0xff,
733 (tkip->rx_iv32 >> 24) & 0xff,
734 (tkip->rx_iv32 >> 16) & 0xff,
735 (tkip->rx_iv32 >> 8) & 0xff,
736 tkip->rx_iv32 & 0xff,
737 (tkip->rx_iv16 >> 8) & 0xff,
738 tkip->rx_iv16 & 0xff,
739 tkip->dot11RSNAStatsTKIPReplays,
740 tkip->dot11RSNAStatsTKIPICVErrors,
741 tkip->dot11RSNAStatsTKIPLocalMICFailures);
742 return p;
743}
744
Jeff Garzikb4538722005-05-12 22:48:20 -0400745static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
James Ketrenos74079fd2005-09-13 17:35:21 -0500746 .name = "TKIP",
747 .init = ieee80211_tkip_init,
748 .deinit = ieee80211_tkip_deinit,
Zhu Yi9184d932006-01-19 16:22:32 +0800749 .build_iv = ieee80211_tkip_hdr,
James Ketrenos74079fd2005-09-13 17:35:21 -0500750 .encrypt_mpdu = ieee80211_tkip_encrypt,
751 .decrypt_mpdu = ieee80211_tkip_decrypt,
752 .encrypt_msdu = ieee80211_michael_mic_add,
753 .decrypt_msdu = ieee80211_michael_mic_verify,
754 .set_key = ieee80211_tkip_set_key,
755 .get_key = ieee80211_tkip_get_key,
756 .print_stats = ieee80211_tkip_print_stats,
James Ketrenos1264fc02005-09-21 11:54:53 -0500757 .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
758 .extra_mpdu_postfix_len = 4, /* ICV */
759 .extra_msdu_postfix_len = 8, /* MIC */
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000760 .get_flags = ieee80211_tkip_get_flags,
761 .set_flags = ieee80211_tkip_set_flags,
James Ketrenos74079fd2005-09-13 17:35:21 -0500762 .owner = THIS_MODULE,
Jeff Garzikb4538722005-05-12 22:48:20 -0400763};
764
Jeff Garzikb4538722005-05-12 22:48:20 -0400765static int __init ieee80211_crypto_tkip_init(void)
766{
767 return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
768}
769
Jeff Garzikb4538722005-05-12 22:48:20 -0400770static void __exit ieee80211_crypto_tkip_exit(void)
771{
772 ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
773}
774
Jeff Garzikb4538722005-05-12 22:48:20 -0400775module_init(ieee80211_crypto_tkip_init);
776module_exit(ieee80211_crypto_tkip_exit);