blob: e0733050ae7179d859342905e24317e34230af48 [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
12#include <linux/config.h>
13#include <linux/version.h>
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/slab.h>
17#include <linux/random.h>
18#include <linux/skbuff.h>
19#include <linux/netdevice.h>
20#include <linux/if_ether.h>
21#include <linux/if_arp.h>
22#include <asm/string.h>
23
24#include <net/ieee80211.h>
25
Jeff Garzikb4538722005-05-12 22:48:20 -040026#include <linux/crypto.h>
27#include <asm/scatterlist.h>
28#include <linux/crc32.h>
29
30MODULE_AUTHOR("Jouni Malinen");
31MODULE_DESCRIPTION("Host AP crypt: TKIP");
32MODULE_LICENSE("GPL");
33
34struct ieee80211_tkip_data {
35#define TKIP_KEY_LEN 32
36 u8 key[TKIP_KEY_LEN];
37 int key_set;
38
39 u32 tx_iv32;
40 u16 tx_iv16;
41 u16 tx_ttak[5];
42 int tx_phase1_done;
43
44 u32 rx_iv32;
45 u16 rx_iv16;
46 u16 rx_ttak[5];
47 int rx_phase1_done;
48 u32 rx_iv32_new;
49 u16 rx_iv16_new;
50
51 u32 dot11RSNAStatsTKIPReplays;
52 u32 dot11RSNAStatsTKIPICVErrors;
53 u32 dot11RSNAStatsTKIPLocalMICFailures;
54
55 int key_idx;
56
57 struct crypto_tfm *tfm_arc4;
58 struct crypto_tfm *tfm_michael;
59
60 /* scratch buffers for virt_to_page() (crypto API) */
61 u8 rx_hdr[16], tx_hdr[16];
James Ketrenos20d64712005-09-21 11:53:43 -050062
63 struct ieee80211_device *ieee;
Jeff Garzikb4538722005-05-12 22:48:20 -040064};
65
James Ketrenos20d64712005-09-21 11:53:43 -050066static void *ieee80211_tkip_init(struct ieee80211_device *ieee, int key_idx)
Jeff Garzikb4538722005-05-12 22:48:20 -040067{
68 struct ieee80211_tkip_data *priv;
69
70 priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
71 if (priv == NULL)
72 goto fail;
73 memset(priv, 0, sizeof(*priv));
James Ketrenos20d64712005-09-21 11:53:43 -050074
75 priv->ieee = ieee;
76
Jeff Garzikb4538722005-05-12 22:48:20 -040077 priv->key_idx = key_idx;
78
79 priv->tfm_arc4 = crypto_alloc_tfm("arc4", 0);
80 if (priv->tfm_arc4 == NULL) {
81 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
82 "crypto API arc4\n");
83 goto fail;
84 }
85
86 priv->tfm_michael = crypto_alloc_tfm("michael_mic", 0);
87 if (priv->tfm_michael == NULL) {
88 printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate "
89 "crypto API michael_mic\n");
90 goto fail;
91 }
92
93 return priv;
94
Jeff Garzik0edd5b42005-09-07 00:48:31 -040095 fail:
Jeff Garzikb4538722005-05-12 22:48:20 -040096 if (priv) {
97 if (priv->tfm_michael)
98 crypto_free_tfm(priv->tfm_michael);
99 if (priv->tfm_arc4)
100 crypto_free_tfm(priv->tfm_arc4);
101 kfree(priv);
102 }
103
104 return NULL;
105}
106
Jeff Garzikb4538722005-05-12 22:48:20 -0400107static void ieee80211_tkip_deinit(void *priv)
108{
109 struct ieee80211_tkip_data *_priv = priv;
110 if (_priv && _priv->tfm_michael)
111 crypto_free_tfm(_priv->tfm_michael);
112 if (_priv && _priv->tfm_arc4)
113 crypto_free_tfm(_priv->tfm_arc4);
114 kfree(priv);
115}
116
Jeff Garzikb4538722005-05-12 22:48:20 -0400117static inline u16 RotR1(u16 val)
118{
119 return (val >> 1) | (val << 15);
120}
121
Jeff Garzikb4538722005-05-12 22:48:20 -0400122static inline u8 Lo8(u16 val)
123{
124 return val & 0xff;
125}
126
Jeff Garzikb4538722005-05-12 22:48:20 -0400127static inline u8 Hi8(u16 val)
128{
129 return val >> 8;
130}
131
Jeff Garzikb4538722005-05-12 22:48:20 -0400132static inline u16 Lo16(u32 val)
133{
134 return val & 0xffff;
135}
136
Jeff Garzikb4538722005-05-12 22:48:20 -0400137static inline u16 Hi16(u32 val)
138{
139 return val >> 16;
140}
141
Jeff Garzikb4538722005-05-12 22:48:20 -0400142static inline u16 Mk16(u8 hi, u8 lo)
143{
144 return lo | (((u16) hi) << 8);
145}
146
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400147static inline u16 Mk16_le(u16 * v)
Jeff Garzikb4538722005-05-12 22:48:20 -0400148{
149 return le16_to_cpu(*v);
150}
151
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400152static const u16 Sbox[256] = {
Jeff Garzikb4538722005-05-12 22:48:20 -0400153 0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
154 0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
155 0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
156 0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
157 0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
158 0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
159 0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
160 0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
161 0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
162 0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
163 0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
164 0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
165 0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
166 0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
167 0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
168 0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
169 0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
170 0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
171 0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
172 0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
173 0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
174 0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
175 0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
176 0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
177 0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
178 0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
179 0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
180 0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
181 0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
182 0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
183 0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
184 0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
185};
186
Jeff Garzikb4538722005-05-12 22:48:20 -0400187static inline u16 _S_(u16 v)
188{
189 u16 t = Sbox[Hi8(v)];
190 return Sbox[Lo8(v)] ^ ((t << 8) | (t >> 8));
191}
192
Jeff Garzikb4538722005-05-12 22:48:20 -0400193#define PHASE1_LOOP_COUNT 8
194
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400195static void tkip_mixing_phase1(u16 * TTAK, const u8 * TK, const u8 * TA,
196 u32 IV32)
Jeff Garzikb4538722005-05-12 22:48:20 -0400197{
198 int i, j;
199
200 /* Initialize the 80-bit TTAK from TSC (IV32) and TA[0..5] */
201 TTAK[0] = Lo16(IV32);
202 TTAK[1] = Hi16(IV32);
203 TTAK[2] = Mk16(TA[1], TA[0]);
204 TTAK[3] = Mk16(TA[3], TA[2]);
205 TTAK[4] = Mk16(TA[5], TA[4]);
206
207 for (i = 0; i < PHASE1_LOOP_COUNT; i++) {
208 j = 2 * (i & 1);
209 TTAK[0] += _S_(TTAK[4] ^ Mk16(TK[1 + j], TK[0 + j]));
210 TTAK[1] += _S_(TTAK[0] ^ Mk16(TK[5 + j], TK[4 + j]));
211 TTAK[2] += _S_(TTAK[1] ^ Mk16(TK[9 + j], TK[8 + j]));
212 TTAK[3] += _S_(TTAK[2] ^ Mk16(TK[13 + j], TK[12 + j]));
213 TTAK[4] += _S_(TTAK[3] ^ Mk16(TK[1 + j], TK[0 + j])) + i;
214 }
215}
216
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400217static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK,
Jeff Garzikb4538722005-05-12 22:48:20 -0400218 u16 IV16)
219{
220 /* Make temporary area overlap WEP seed so that the final copy can be
221 * avoided on little endian hosts. */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400222 u16 *PPK = (u16 *) & WEPSeed[4];
Jeff Garzikb4538722005-05-12 22:48:20 -0400223
224 /* Step 1 - make copy of TTAK and bring in TSC */
225 PPK[0] = TTAK[0];
226 PPK[1] = TTAK[1];
227 PPK[2] = TTAK[2];
228 PPK[3] = TTAK[3];
229 PPK[4] = TTAK[4];
230 PPK[5] = TTAK[4] + IV16;
231
232 /* Step 2 - 96-bit bijective mixing using S-box */
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400233 PPK[0] += _S_(PPK[5] ^ Mk16_le((u16 *) & TK[0]));
234 PPK[1] += _S_(PPK[0] ^ Mk16_le((u16 *) & TK[2]));
235 PPK[2] += _S_(PPK[1] ^ Mk16_le((u16 *) & TK[4]));
236 PPK[3] += _S_(PPK[2] ^ Mk16_le((u16 *) & TK[6]));
237 PPK[4] += _S_(PPK[3] ^ Mk16_le((u16 *) & TK[8]));
238 PPK[5] += _S_(PPK[4] ^ Mk16_le((u16 *) & TK[10]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400239
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400240 PPK[0] += RotR1(PPK[5] ^ Mk16_le((u16 *) & TK[12]));
241 PPK[1] += RotR1(PPK[0] ^ Mk16_le((u16 *) & TK[14]));
Jeff Garzikb4538722005-05-12 22:48:20 -0400242 PPK[2] += RotR1(PPK[1]);
243 PPK[3] += RotR1(PPK[2]);
244 PPK[4] += RotR1(PPK[3]);
245 PPK[5] += RotR1(PPK[4]);
246
247 /* Step 3 - bring in last of TK bits, assign 24-bit WEP IV value
248 * WEPSeed[0..2] is transmitted as WEP IV */
249 WEPSeed[0] = Hi8(IV16);
250 WEPSeed[1] = (Hi8(IV16) | 0x20) & 0x7F;
251 WEPSeed[2] = Lo8(IV16);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400252 WEPSeed[3] = Lo8((PPK[5] ^ Mk16_le((u16 *) & TK[0])) >> 1);
Jeff Garzikb4538722005-05-12 22:48:20 -0400253
254#ifdef __BIG_ENDIAN
255 {
256 int i;
257 for (i = 0; i < 6; i++)
258 PPK[i] = (PPK[i] << 8) | (PPK[i] >> 8);
259 }
260#endif
261}
262
James Ketrenos31b59ea2005-09-21 11:58:49 -0500263static u8 *ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400264{
265 struct ieee80211_tkip_data *tkey = priv;
266 int len;
James Ketrenos31b59ea2005-09-21 11:58:49 -0500267 u8 *rc4key, *pos, *icv;
James Ketrenosee34af32005-09-21 11:54:36 -0500268 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400269 u32 crc;
Jeff Garzikb4538722005-05-12 22:48:20 -0400270
James Ketrenosee34af32005-09-21 11:54:36 -0500271 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500272
James Ketrenos31b59ea2005-09-21 11:58:49 -0500273 if (skb_headroom(skb) < 8 || skb->len < hdr_len)
274 return NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400275
Jeff Garzikb4538722005-05-12 22:48:20 -0400276 if (!tkey->tx_phase1_done) {
277 tkip_mixing_phase1(tkey->tx_ttak, tkey->key, hdr->addr2,
278 tkey->tx_iv32);
279 tkey->tx_phase1_done = 1;
280 }
James Ketrenos31b59ea2005-09-21 11:58:49 -0500281 rc4key = kmalloc(16, GFP_ATOMIC);
282 if (!rc4key)
283 return NULL;
Jeff Garzikb4538722005-05-12 22:48:20 -0400284 tkip_mixing_phase2(rc4key, tkey->key, tkey->tx_ttak, tkey->tx_iv16);
285
286 len = skb->len - hdr_len;
287 pos = skb_push(skb, 8);
288 memmove(pos, pos + 8, hdr_len);
289 pos += hdr_len;
290 icv = skb_put(skb, 4);
291
James Ketrenos31b59ea2005-09-21 11:58:49 -0500292 *pos++ = *rc4key;
293 *pos++ = *(rc4key + 1);
294 *pos++ = *(rc4key + 2);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400295 *pos++ = (tkey->key_idx << 6) | (1 << 5) /* Ext IV included */ ;
Jeff Garzikb4538722005-05-12 22:48:20 -0400296 *pos++ = tkey->tx_iv32 & 0xff;
297 *pos++ = (tkey->tx_iv32 >> 8) & 0xff;
298 *pos++ = (tkey->tx_iv32 >> 16) & 0xff;
299 *pos++ = (tkey->tx_iv32 >> 24) & 0xff;
300
301 crc = ~crc32_le(~0, pos, len);
302 icv[0] = crc;
303 icv[1] = crc >> 8;
304 icv[2] = crc >> 16;
305 icv[3] = crc >> 24;
306
James Ketrenos31b59ea2005-09-21 11:58:49 -0500307 return rc4key;
308}
309
310static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
311{
312 struct ieee80211_tkip_data *tkey = priv;
313 int len;
314 const u8 *rc4key;
315 u8 *pos;
316 struct scatterlist sg;
317
318 if (tkey->ieee->tkip_countermeasures) {
319 if (net_ratelimit()) {
320 struct ieee80211_hdr_4addr *hdr =
321 (struct ieee80211_hdr_4addr *)skb->data;
322 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
323 "TX packet to " MAC_FMT "\n",
324 tkey->ieee->dev->name, MAC_ARG(hdr->addr1));
325 }
326 return -1;
327 }
328
329 if (skb_tailroom(skb) < 4 || skb->len < hdr_len)
330 return -1;
331
332 len = skb->len - hdr_len;
333 pos = skb->data + hdr_len;
334
335 rc4key = ieee80211_tkip_hdr(skb, hdr_len, priv);
336 if (!rc4key)
337 return -1;
338
Jeff Garzikb4538722005-05-12 22:48:20 -0400339 crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
340 sg.page = virt_to_page(pos);
341 sg.offset = offset_in_page(pos);
342 sg.length = len + 4;
343 crypto_cipher_encrypt(tkey->tfm_arc4, &sg, &sg, len + 4);
344
345 tkey->tx_iv16++;
346 if (tkey->tx_iv16 == 0) {
347 tkey->tx_phase1_done = 0;
348 tkey->tx_iv32++;
349 }
350
351 return 0;
352}
353
354static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
355{
356 struct ieee80211_tkip_data *tkey = priv;
357 u8 rc4key[16];
358 u8 keyidx, *pos;
359 u32 iv32;
360 u16 iv16;
James Ketrenosee34af32005-09-21 11:54:36 -0500361 struct ieee80211_hdr_4addr *hdr;
Jeff Garzikb4538722005-05-12 22:48:20 -0400362 u8 icv[4];
363 u32 crc;
364 struct scatterlist sg;
365 int plen;
366
James Ketrenosee34af32005-09-21 11:54:36 -0500367 hdr = (struct ieee80211_hdr_4addr *)skb->data;
James Ketrenos20d64712005-09-21 11:53:43 -0500368
369 if (tkey->ieee->tkip_countermeasures) {
370 if (net_ratelimit()) {
371 printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
372 "received packet from " MAC_FMT "\n",
373 tkey->ieee->dev->name, MAC_ARG(hdr->addr2));
374 }
375 return -1;
376 }
377
Jeff Garzikb4538722005-05-12 22:48:20 -0400378 if (skb->len < hdr_len + 8 + 4)
379 return -1;
380
Jeff Garzikb4538722005-05-12 22:48:20 -0400381 pos = skb->data + hdr_len;
382 keyidx = pos[3];
383 if (!(keyidx & (1 << 5))) {
384 if (net_ratelimit()) {
385 printk(KERN_DEBUG "TKIP: received packet without ExtIV"
386 " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
387 }
388 return -2;
389 }
390 keyidx >>= 6;
391 if (tkey->key_idx != keyidx) {
392 printk(KERN_DEBUG "TKIP: RX tkey->key_idx=%d frame "
393 "keyidx=%d priv=%p\n", tkey->key_idx, keyidx, priv);
394 return -6;
395 }
396 if (!tkey->key_set) {
397 if (net_ratelimit()) {
398 printk(KERN_DEBUG "TKIP: received packet from " MAC_FMT
399 " with keyid=%d that does not have a configured"
400 " key\n", MAC_ARG(hdr->addr2), keyidx);
401 }
402 return -3;
403 }
404 iv16 = (pos[0] << 8) | pos[2];
405 iv32 = pos[4] | (pos[5] << 8) | (pos[6] << 16) | (pos[7] << 24);
406 pos += 8;
407
408 if (iv32 < tkey->rx_iv32 ||
409 (iv32 == tkey->rx_iv32 && iv16 <= tkey->rx_iv16)) {
410 if (net_ratelimit()) {
411 printk(KERN_DEBUG "TKIP: replay detected: STA=" MAC_FMT
412 " previous TSC %08x%04x received TSC "
413 "%08x%04x\n", MAC_ARG(hdr->addr2),
414 tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
415 }
416 tkey->dot11RSNAStatsTKIPReplays++;
417 return -4;
418 }
419
420 if (iv32 != tkey->rx_iv32 || !tkey->rx_phase1_done) {
421 tkip_mixing_phase1(tkey->rx_ttak, tkey->key, hdr->addr2, iv32);
422 tkey->rx_phase1_done = 1;
423 }
424 tkip_mixing_phase2(rc4key, tkey->key, tkey->rx_ttak, iv16);
425
426 plen = skb->len - hdr_len - 12;
427
428 crypto_cipher_setkey(tkey->tfm_arc4, rc4key, 16);
429 sg.page = virt_to_page(pos);
430 sg.offset = offset_in_page(pos);
431 sg.length = plen + 4;
432 crypto_cipher_decrypt(tkey->tfm_arc4, &sg, &sg, plen + 4);
433
434 crc = ~crc32_le(~0, pos, plen);
435 icv[0] = crc;
436 icv[1] = crc >> 8;
437 icv[2] = crc >> 16;
438 icv[3] = crc >> 24;
439 if (memcmp(icv, pos + plen, 4) != 0) {
440 if (iv32 != tkey->rx_iv32) {
441 /* Previously cached Phase1 result was already lost, so
442 * it needs to be recalculated for the next packet. */
443 tkey->rx_phase1_done = 0;
444 }
445 if (net_ratelimit()) {
446 printk(KERN_DEBUG "TKIP: ICV error detected: STA="
447 MAC_FMT "\n", MAC_ARG(hdr->addr2));
448 }
449 tkey->dot11RSNAStatsTKIPICVErrors++;
450 return -5;
451 }
452
453 /* Update real counters only after Michael MIC verification has
454 * completed */
455 tkey->rx_iv32_new = iv32;
456 tkey->rx_iv16_new = iv16;
457
458 /* Remove IV and ICV */
459 memmove(skb->data + 8, skb->data, hdr_len);
460 skb_pull(skb, 8);
461 skb_trim(skb, skb->len - 4);
462
463 return keyidx;
464}
465
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400466static int michael_mic(struct ieee80211_tkip_data *tkey, u8 * key, u8 * hdr,
467 u8 * data, size_t data_len, u8 * mic)
Jeff Garzikb4538722005-05-12 22:48:20 -0400468{
469 struct scatterlist sg[2];
470
471 if (tkey->tfm_michael == NULL) {
472 printk(KERN_WARNING "michael_mic: tfm_michael == NULL\n");
473 return -1;
474 }
475 sg[0].page = virt_to_page(hdr);
476 sg[0].offset = offset_in_page(hdr);
477 sg[0].length = 16;
478
479 sg[1].page = virt_to_page(data);
480 sg[1].offset = offset_in_page(data);
481 sg[1].length = data_len;
482
483 crypto_digest_init(tkey->tfm_michael);
484 crypto_digest_setkey(tkey->tfm_michael, key, 8);
485 crypto_digest_update(tkey->tfm_michael, sg, 2);
486 crypto_digest_final(tkey->tfm_michael, mic);
487
488 return 0;
489}
490
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400491static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr)
Jeff Garzikb4538722005-05-12 22:48:20 -0400492{
James Ketrenosee34af32005-09-21 11:54:36 -0500493 struct ieee80211_hdr_4addr *hdr11;
Jeff Garzikb4538722005-05-12 22:48:20 -0400494
James Ketrenosee34af32005-09-21 11:54:36 -0500495 hdr11 = (struct ieee80211_hdr_4addr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400496 switch (le16_to_cpu(hdr11->frame_ctl) &
497 (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) {
498 case IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400499 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
500 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400501 break;
502 case IEEE80211_FCTL_FROMDS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400503 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
504 memcpy(hdr + ETH_ALEN, hdr11->addr3, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400505 break;
506 case IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400507 memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */
508 memcpy(hdr + ETH_ALEN, hdr11->addr4, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400509 break;
510 case 0:
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400511 memcpy(hdr, hdr11->addr1, ETH_ALEN); /* DA */
512 memcpy(hdr + ETH_ALEN, hdr11->addr2, ETH_ALEN); /* SA */
Jeff Garzikb4538722005-05-12 22:48:20 -0400513 break;
514 }
515
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400516 hdr[12] = 0; /* priority */
517 hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */
Jeff Garzikb4538722005-05-12 22:48:20 -0400518}
519
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400520static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len,
521 void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400522{
523 struct ieee80211_tkip_data *tkey = priv;
524 u8 *pos;
525
526 if (skb_tailroom(skb) < 8 || skb->len < hdr_len) {
527 printk(KERN_DEBUG "Invalid packet for Michael MIC add "
528 "(tailroom=%d hdr_len=%d skb->len=%d)\n",
529 skb_tailroom(skb), hdr_len, skb->len);
530 return -1;
531 }
532
533 michael_mic_hdr(skb, tkey->tx_hdr);
534 pos = skb_put(skb, 8);
535 if (michael_mic(tkey, &tkey->key[16], tkey->tx_hdr,
536 skb->data + hdr_len, skb->len - 8 - hdr_len, pos))
537 return -1;
538
539 return 0;
540}
541
Jeff Garzikb4538722005-05-12 22:48:20 -0400542static void ieee80211_michael_mic_failure(struct net_device *dev,
James Ketrenosee34af32005-09-21 11:54:36 -0500543 struct ieee80211_hdr_4addr *hdr,
544 int keyidx)
Jeff Garzikb4538722005-05-12 22:48:20 -0400545{
546 union iwreq_data wrqu;
547 struct iw_michaelmicfailure ev;
548
549 /* TODO: needed parameters: count, keyid, key type, TSC */
550 memset(&ev, 0, sizeof(ev));
551 ev.flags = keyidx & IW_MICFAILURE_KEY_ID;
552 if (hdr->addr1[0] & 0x01)
553 ev.flags |= IW_MICFAILURE_GROUP;
554 else
555 ev.flags |= IW_MICFAILURE_PAIRWISE;
556 ev.src_addr.sa_family = ARPHRD_ETHER;
557 memcpy(ev.src_addr.sa_data, hdr->addr2, ETH_ALEN);
558 memset(&wrqu, 0, sizeof(wrqu));
559 wrqu.data.length = sizeof(ev);
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400560 wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev);
Jeff Garzikb4538722005-05-12 22:48:20 -0400561}
Jeff Garzikb4538722005-05-12 22:48:20 -0400562
563static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx,
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400564 int hdr_len, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400565{
566 struct ieee80211_tkip_data *tkey = priv;
567 u8 mic[8];
568
569 if (!tkey->key_set)
570 return -1;
571
572 michael_mic_hdr(skb, tkey->rx_hdr);
573 if (michael_mic(tkey, &tkey->key[24], tkey->rx_hdr,
574 skb->data + hdr_len, skb->len - 8 - hdr_len, mic))
575 return -1;
576 if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) {
James Ketrenosee34af32005-09-21 11:54:36 -0500577 struct ieee80211_hdr_4addr *hdr;
578 hdr = (struct ieee80211_hdr_4addr *)skb->data;
Jeff Garzikb4538722005-05-12 22:48:20 -0400579 printk(KERN_DEBUG "%s: Michael MIC verification failed for "
580 "MSDU from " MAC_FMT " keyidx=%d\n",
581 skb->dev ? skb->dev->name : "N/A", MAC_ARG(hdr->addr2),
582 keyidx);
583 if (skb->dev)
584 ieee80211_michael_mic_failure(skb->dev, hdr, keyidx);
585 tkey->dot11RSNAStatsTKIPLocalMICFailures++;
586 return -1;
587 }
588
589 /* Update TSC counters for RX now that the packet verification has
590 * completed. */
591 tkey->rx_iv32 = tkey->rx_iv32_new;
592 tkey->rx_iv16 = tkey->rx_iv16_new;
593
594 skb_trim(skb, skb->len - 8);
595
596 return 0;
597}
598
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400599static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400600{
601 struct ieee80211_tkip_data *tkey = priv;
602 int keyidx;
603 struct crypto_tfm *tfm = tkey->tfm_michael;
604 struct crypto_tfm *tfm2 = tkey->tfm_arc4;
605
606 keyidx = tkey->key_idx;
607 memset(tkey, 0, sizeof(*tkey));
608 tkey->key_idx = keyidx;
609 tkey->tfm_michael = tfm;
610 tkey->tfm_arc4 = tfm2;
611 if (len == TKIP_KEY_LEN) {
612 memcpy(tkey->key, key, TKIP_KEY_LEN);
613 tkey->key_set = 1;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400614 tkey->tx_iv16 = 1; /* TSC is initialized to 1 */
Jeff Garzikb4538722005-05-12 22:48:20 -0400615 if (seq) {
616 tkey->rx_iv32 = (seq[5] << 24) | (seq[4] << 16) |
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400617 (seq[3] << 8) | seq[2];
Jeff Garzikb4538722005-05-12 22:48:20 -0400618 tkey->rx_iv16 = (seq[1] << 8) | seq[0];
619 }
620 } else if (len == 0)
621 tkey->key_set = 0;
622 else
623 return -1;
624
625 return 0;
626}
627
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400628static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400629{
630 struct ieee80211_tkip_data *tkey = priv;
631
632 if (len < TKIP_KEY_LEN)
633 return -1;
634
635 if (!tkey->key_set)
636 return 0;
637 memcpy(key, tkey->key, TKIP_KEY_LEN);
638
639 if (seq) {
640 /* Return the sequence number of the last transmitted frame. */
641 u16 iv16 = tkey->tx_iv16;
642 u32 iv32 = tkey->tx_iv32;
643 if (iv16 == 0)
644 iv32--;
645 iv16--;
646 seq[0] = tkey->tx_iv16;
647 seq[1] = tkey->tx_iv16 >> 8;
648 seq[2] = tkey->tx_iv32;
649 seq[3] = tkey->tx_iv32 >> 8;
650 seq[4] = tkey->tx_iv32 >> 16;
651 seq[5] = tkey->tx_iv32 >> 24;
652 }
653
654 return TKIP_KEY_LEN;
655}
656
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400657static char *ieee80211_tkip_print_stats(char *p, void *priv)
Jeff Garzikb4538722005-05-12 22:48:20 -0400658{
659 struct ieee80211_tkip_data *tkip = priv;
660 p += sprintf(p, "key[%d] alg=TKIP key_set=%d "
661 "tx_pn=%02x%02x%02x%02x%02x%02x "
662 "rx_pn=%02x%02x%02x%02x%02x%02x "
663 "replays=%d icv_errors=%d local_mic_failures=%d\n",
664 tkip->key_idx, tkip->key_set,
665 (tkip->tx_iv32 >> 24) & 0xff,
666 (tkip->tx_iv32 >> 16) & 0xff,
667 (tkip->tx_iv32 >> 8) & 0xff,
668 tkip->tx_iv32 & 0xff,
669 (tkip->tx_iv16 >> 8) & 0xff,
670 tkip->tx_iv16 & 0xff,
671 (tkip->rx_iv32 >> 24) & 0xff,
672 (tkip->rx_iv32 >> 16) & 0xff,
673 (tkip->rx_iv32 >> 8) & 0xff,
674 tkip->rx_iv32 & 0xff,
675 (tkip->rx_iv16 >> 8) & 0xff,
676 tkip->rx_iv16 & 0xff,
677 tkip->dot11RSNAStatsTKIPReplays,
678 tkip->dot11RSNAStatsTKIPICVErrors,
679 tkip->dot11RSNAStatsTKIPLocalMICFailures);
680 return p;
681}
682
Jeff Garzikb4538722005-05-12 22:48:20 -0400683static struct ieee80211_crypto_ops ieee80211_crypt_tkip = {
James Ketrenos74079fd2005-09-13 17:35:21 -0500684 .name = "TKIP",
685 .init = ieee80211_tkip_init,
686 .deinit = ieee80211_tkip_deinit,
687 .encrypt_mpdu = ieee80211_tkip_encrypt,
688 .decrypt_mpdu = ieee80211_tkip_decrypt,
689 .encrypt_msdu = ieee80211_michael_mic_add,
690 .decrypt_msdu = ieee80211_michael_mic_verify,
691 .set_key = ieee80211_tkip_set_key,
692 .get_key = ieee80211_tkip_get_key,
693 .print_stats = ieee80211_tkip_print_stats,
James Ketrenos1264fc02005-09-21 11:54:53 -0500694 .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */
695 .extra_mpdu_postfix_len = 4, /* ICV */
696 .extra_msdu_postfix_len = 8, /* MIC */
James Ketrenos74079fd2005-09-13 17:35:21 -0500697 .owner = THIS_MODULE,
Jeff Garzikb4538722005-05-12 22:48:20 -0400698};
699
Jeff Garzikb4538722005-05-12 22:48:20 -0400700static int __init ieee80211_crypto_tkip_init(void)
701{
702 return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip);
703}
704
Jeff Garzikb4538722005-05-12 22:48:20 -0400705static void __exit ieee80211_crypto_tkip_exit(void)
706{
707 ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip);
708}
709
Jeff Garzikb4538722005-05-12 22:48:20 -0400710module_init(ieee80211_crypto_tkip_init);
711module_exit(ieee80211_crypto_tkip_exit);