10922a916e3c235fd588a56b051915e8f23e8e78
[safe/jmp/linux-2.6] / drivers / staging / rtl8192su / ieee80211 / ieee80211_crypt_ccmp.c
1 /*
2  * Host AP crypt: host-based CCMP 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 #include <linux/wireless.h>
24
25 #include "ieee80211.h"
26
27 #include <linux/crypto.h>
28 #include <linux/scatterlist.h>
29
30 MODULE_AUTHOR("Jouni Malinen");
31 MODULE_DESCRIPTION("Host AP crypt: CCMP");
32 MODULE_LICENSE("GPL");
33
34 #ifndef OPENSUSE_SLED
35 #define OPENSUSE_SLED 0
36 #endif
37
38 #define AES_BLOCK_LEN 16
39 #define CCMP_HDR_LEN 8
40 #define CCMP_MIC_LEN 8
41 #define CCMP_TK_LEN 16
42 #define CCMP_PN_LEN 6
43
44 struct ieee80211_ccmp_data {
45         u8 key[CCMP_TK_LEN];
46         int key_set;
47
48         u8 tx_pn[CCMP_PN_LEN];
49         u8 rx_pn[CCMP_PN_LEN];
50
51         u32 dot11RSNAStatsCCMPFormatErrors;
52         u32 dot11RSNAStatsCCMPReplays;
53         u32 dot11RSNAStatsCCMPDecryptErrors;
54
55         int key_idx;
56
57         struct crypto_tfm *tfm;
58
59         /* scratch buffers for virt_to_page() (crypto API) */
60         u8 tx_b0[AES_BLOCK_LEN], tx_b[AES_BLOCK_LEN],
61                 tx_e[AES_BLOCK_LEN], tx_s0[AES_BLOCK_LEN];
62         u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN];
63 };
64
65 void ieee80211_ccmp_aes_encrypt(struct crypto_tfm *tfm,
66                              const u8 pt[16], u8 ct[16])
67 {
68         crypto_cipher_encrypt_one((void*)tfm, ct, pt);
69 }
70
71 static void * ieee80211_ccmp_init(int key_idx)
72 {
73         struct ieee80211_ccmp_data *priv;
74
75         priv = kmalloc(sizeof(*priv), GFP_ATOMIC);
76         if (priv == NULL)
77                 goto fail;
78         memset(priv, 0, sizeof(*priv));
79         priv->key_idx = key_idx;
80
81         priv->tfm = (void *)crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC);
82         if (IS_ERR(priv->tfm)) {
83                 printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate "
84                        "crypto API aes\n");
85                 priv->tfm = NULL;
86                 goto fail;
87         }
88
89         return priv;
90
91 fail:
92         if (priv) {
93                 if (priv->tfm)
94                         crypto_free_cipher((void*)priv->tfm);
95                 kfree(priv);
96         }
97
98         return NULL;
99 }
100
101
102 static void ieee80211_ccmp_deinit(void *priv)
103 {
104         struct ieee80211_ccmp_data *_priv = priv;
105
106         if (_priv && _priv->tfm)
107                 crypto_free_cipher((void*)_priv->tfm);
108         kfree(priv);
109 }
110
111
112 static inline void xor_block(u8 *b, u8 *a, size_t len)
113 {
114         int i;
115         for (i = 0; i < len; i++)
116                 b[i] ^= a[i];
117 }
118
119
120
121 static void ccmp_init_blocks(struct crypto_tfm *tfm,
122                              struct ieee80211_hdr_4addr *hdr,
123                              u8 *pn, size_t dlen, u8 *b0, u8 *auth,
124                              u8 *s0)
125 {
126         u8 *pos, qc = 0;
127         size_t aad_len;
128         u16 fc;
129         int a4_included, qc_included;
130         u8 aad[2 * AES_BLOCK_LEN];
131
132         fc = le16_to_cpu(hdr->frame_ctl);
133         a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
134                        (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS));
135         /*
136         qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) &&
137                        (WLAN_FC_GET_STYPE(fc) & 0x08));
138         */
139         // fixed by David :2006.9.6
140         qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) &&
141                        (WLAN_FC_GET_STYPE(fc) & 0x80));
142         aad_len = 22;
143         if (a4_included)
144                 aad_len += 6;
145         if (qc_included) {
146                 pos = (u8 *) &hdr->addr4;
147                 if (a4_included)
148                         pos += 6;
149                 qc = *pos & 0x0f;
150                 aad_len += 2;
151         }
152         /* CCM Initial Block:
153          * Flag (Include authentication header, M=3 (8-octet MIC),
154          *       L=1 (2-octet Dlen))
155          * Nonce: 0x00 | A2 | PN
156          * Dlen */
157         b0[0] = 0x59;
158         b0[1] = qc;
159         memcpy(b0 + 2, hdr->addr2, ETH_ALEN);
160         memcpy(b0 + 8, pn, CCMP_PN_LEN);
161         b0[14] = (dlen >> 8) & 0xff;
162         b0[15] = dlen & 0xff;
163
164         /* AAD:
165          * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
166          * A1 | A2 | A3
167          * SC with bits 4..15 (seq#) masked to zero
168          * A4 (if present)
169          * QC (if present)
170          */
171         pos = (u8 *) hdr;
172         aad[0] = 0; /* aad_len >> 8 */
173         aad[1] = aad_len & 0xff;
174         aad[2] = pos[0] & 0x8f;
175         aad[3] = pos[1] & 0xc7;
176         memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN);
177         pos = (u8 *) &hdr->seq_ctl;
178         aad[22] = pos[0] & 0x0f;
179         aad[23] = 0; /* all bits masked */
180         memset(aad + 24, 0, 8);
181         if (a4_included)
182                 memcpy(aad + 24, hdr->addr4, ETH_ALEN);
183         if (qc_included) {
184                 aad[a4_included ? 30 : 24] = qc;
185                 /* rest of QC masked */
186         }
187
188         /* Start with the first block and AAD */
189         ieee80211_ccmp_aes_encrypt(tfm, b0, auth);
190         xor_block(auth, aad, AES_BLOCK_LEN);
191         ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
192         xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
193         ieee80211_ccmp_aes_encrypt(tfm, auth, auth);
194         b0[0] &= 0x07;
195         b0[14] = b0[15] = 0;
196         ieee80211_ccmp_aes_encrypt(tfm, b0, s0);
197 }
198
199
200
201 static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv)
202 {
203         struct ieee80211_ccmp_data *key = priv;
204         int data_len, i;
205         u8 *pos;
206         struct ieee80211_hdr_4addr *hdr;
207         cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
208
209         if (skb_headroom(skb) < CCMP_HDR_LEN ||
210             skb_tailroom(skb) < CCMP_MIC_LEN ||
211             skb->len < hdr_len)
212                 return -1;
213
214         data_len = skb->len - hdr_len;
215         pos = skb_push(skb, CCMP_HDR_LEN);
216         memmove(pos, pos + CCMP_HDR_LEN, hdr_len);
217         pos += hdr_len;
218 //      mic = skb_put(skb, CCMP_MIC_LEN);
219
220         i = CCMP_PN_LEN - 1;
221         while (i >= 0) {
222                 key->tx_pn[i]++;
223                 if (key->tx_pn[i] != 0)
224                         break;
225                 i--;
226         }
227
228         *pos++ = key->tx_pn[5];
229         *pos++ = key->tx_pn[4];
230         *pos++ = 0;
231         *pos++ = (key->key_idx << 6) | (1 << 5) /* Ext IV included */;
232         *pos++ = key->tx_pn[3];
233         *pos++ = key->tx_pn[2];
234         *pos++ = key->tx_pn[1];
235         *pos++ = key->tx_pn[0];
236
237
238         hdr = (struct ieee80211_hdr_4addr *) skb->data;
239         if (!tcb_desc->bHwSec)
240         {
241                 int blocks, last, len;
242                 u8 *mic;
243                 u8 *b0 = key->tx_b0;
244                 u8 *b = key->tx_b;
245                 u8 *e = key->tx_e;
246                 u8 *s0 = key->tx_s0;
247
248                 //mic is moved to here by john
249                 mic = skb_put(skb, CCMP_MIC_LEN);
250
251                 ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0);
252
253                 blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
254                 last = data_len % AES_BLOCK_LEN;
255
256                 for (i = 1; i <= blocks; i++) {
257                         len = (i == blocks && last) ? last : AES_BLOCK_LEN;
258                         /* Authentication */
259                         xor_block(b, pos, len);
260                         ieee80211_ccmp_aes_encrypt(key->tfm, b, b);
261                         /* Encryption, with counter */
262                         b0[14] = (i >> 8) & 0xff;
263                         b0[15] = i & 0xff;
264                         ieee80211_ccmp_aes_encrypt(key->tfm, b0, e);
265                         xor_block(pos, e, len);
266                         pos += len;
267                 }
268
269                 for (i = 0; i < CCMP_MIC_LEN; i++)
270                         mic[i] = b[i] ^ s0[i];
271         }
272         return 0;
273 }
274
275
276 static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
277 {
278         struct ieee80211_ccmp_data *key = priv;
279         u8 keyidx, *pos;
280         struct ieee80211_hdr_4addr *hdr;
281         cb_desc *tcb_desc = (cb_desc *)(skb->cb + MAX_DEV_ADDR_SIZE);
282         u8 pn[6];
283
284         if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) {
285                 key->dot11RSNAStatsCCMPFormatErrors++;
286                 return -1;
287         }
288
289         hdr = (struct ieee80211_hdr_4addr *) skb->data;
290         pos = skb->data + hdr_len;
291         keyidx = pos[3];
292         if (!(keyidx & (1 << 5))) {
293                 if (net_ratelimit()) {
294                         printk(KERN_DEBUG "CCMP: received packet without ExtIV"
295                                " flag from " MAC_FMT "\n", MAC_ARG(hdr->addr2));
296                 }
297                 key->dot11RSNAStatsCCMPFormatErrors++;
298                 return -2;
299         }
300         keyidx >>= 6;
301         if (key->key_idx != keyidx) {
302                 printk(KERN_DEBUG "CCMP: RX tkey->key_idx=%d frame "
303                        "keyidx=%d priv=%p\n", key->key_idx, keyidx, priv);
304                 return -6;
305         }
306         if (!key->key_set) {
307                 if (net_ratelimit()) {
308                         printk(KERN_DEBUG "CCMP: received packet from " MAC_FMT
309                                " with keyid=%d that does not have a configured"
310                                " key\n", MAC_ARG(hdr->addr2), keyidx);
311                 }
312                 return -3;
313         }
314
315         pn[0] = pos[7];
316         pn[1] = pos[6];
317         pn[2] = pos[5];
318         pn[3] = pos[4];
319         pn[4] = pos[1];
320         pn[5] = pos[0];
321         pos += 8;
322
323         if (memcmp(pn, key->rx_pn, CCMP_PN_LEN) <= 0) {
324                 if (net_ratelimit()) {
325                         printk(KERN_DEBUG "CCMP: replay detected: STA=" MAC_FMT
326                                " previous PN %02x%02x%02x%02x%02x%02x "
327                                "received PN %02x%02x%02x%02x%02x%02x\n",
328                                MAC_ARG(hdr->addr2), MAC_ARG(key->rx_pn),
329                                MAC_ARG(pn));
330                 }
331                 key->dot11RSNAStatsCCMPReplays++;
332                 return -4;
333         }
334         if (!tcb_desc->bHwSec)
335         {
336                 size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN;
337                 u8 *mic = skb->data + skb->len - CCMP_MIC_LEN;
338                 u8 *b0 = key->rx_b0;
339                 u8 *b = key->rx_b;
340                 u8 *a = key->rx_a;
341                 int i, blocks, last, len;
342
343
344                 ccmp_init_blocks(key->tfm, hdr, pn, data_len, b0, a, b);
345                 xor_block(mic, b, CCMP_MIC_LEN);
346
347                 blocks = (data_len + AES_BLOCK_LEN - 1) / AES_BLOCK_LEN;
348                 last = data_len % AES_BLOCK_LEN;
349
350                 for (i = 1; i <= blocks; i++) {
351                         len = (i == blocks && last) ? last : AES_BLOCK_LEN;
352                         /* Decrypt, with counter */
353                         b0[14] = (i >> 8) & 0xff;
354                         b0[15] = i & 0xff;
355                         ieee80211_ccmp_aes_encrypt(key->tfm, b0, b);
356                         xor_block(pos, b, len);
357                         /* Authentication */
358                         xor_block(a, pos, len);
359                         ieee80211_ccmp_aes_encrypt(key->tfm, a, a);
360                         pos += len;
361                 }
362
363                 if (memcmp(mic, a, CCMP_MIC_LEN) != 0) {
364                         if (net_ratelimit()) {
365                                 printk(KERN_DEBUG "CCMP: decrypt failed: STA="
366                                 MAC_FMT "\n", MAC_ARG(hdr->addr2));
367                         }
368                         key->dot11RSNAStatsCCMPDecryptErrors++;
369                         return -5;
370                 }
371
372                 memcpy(key->rx_pn, pn, CCMP_PN_LEN);
373         }
374         /* Remove hdr and MIC */
375         memmove(skb->data + CCMP_HDR_LEN, skb->data, hdr_len);
376         skb_pull(skb, CCMP_HDR_LEN);
377         skb_trim(skb, skb->len - CCMP_MIC_LEN);
378
379         return keyidx;
380 }
381
382
383 static int ieee80211_ccmp_set_key(void *key, int len, u8 *seq, void *priv)
384 {
385         struct ieee80211_ccmp_data *data = priv;
386         int keyidx;
387         struct crypto_tfm *tfm = data->tfm;
388
389         keyidx = data->key_idx;
390         memset(data, 0, sizeof(*data));
391         data->key_idx = keyidx;
392         data->tfm = tfm;
393         if (len == CCMP_TK_LEN) {
394                 memcpy(data->key, key, CCMP_TK_LEN);
395                 data->key_set = 1;
396                 if (seq) {
397                         data->rx_pn[0] = seq[5];
398                         data->rx_pn[1] = seq[4];
399                         data->rx_pn[2] = seq[3];
400                         data->rx_pn[3] = seq[2];
401                         data->rx_pn[4] = seq[1];
402                         data->rx_pn[5] = seq[0];
403                 }
404                 crypto_cipher_setkey((void*)data->tfm, data->key, CCMP_TK_LEN);
405         } else if (len == 0)
406                 data->key_set = 0;
407         else
408                 return -1;
409
410         return 0;
411 }
412
413
414 static int ieee80211_ccmp_get_key(void *key, int len, u8 *seq, void *priv)
415 {
416         struct ieee80211_ccmp_data *data = priv;
417
418         if (len < CCMP_TK_LEN)
419                 return -1;
420
421         if (!data->key_set)
422                 return 0;
423         memcpy(key, data->key, CCMP_TK_LEN);
424
425         if (seq) {
426                 seq[0] = data->tx_pn[5];
427                 seq[1] = data->tx_pn[4];
428                 seq[2] = data->tx_pn[3];
429                 seq[3] = data->tx_pn[2];
430                 seq[4] = data->tx_pn[1];
431                 seq[5] = data->tx_pn[0];
432         }
433
434         return CCMP_TK_LEN;
435 }
436
437
438 static char * ieee80211_ccmp_print_stats(char *p, void *priv)
439 {
440         struct ieee80211_ccmp_data *ccmp = priv;
441         p += sprintf(p, "key[%d] alg=CCMP key_set=%d "
442                      "tx_pn=%02x%02x%02x%02x%02x%02x "
443                      "rx_pn=%02x%02x%02x%02x%02x%02x "
444                      "format_errors=%d replays=%d decrypt_errors=%d\n",
445                      ccmp->key_idx, ccmp->key_set,
446                      MAC_ARG(ccmp->tx_pn), MAC_ARG(ccmp->rx_pn),
447                      ccmp->dot11RSNAStatsCCMPFormatErrors,
448                      ccmp->dot11RSNAStatsCCMPReplays,
449                      ccmp->dot11RSNAStatsCCMPDecryptErrors);
450
451         return p;
452 }
453
454 void ieee80211_ccmp_null(void)
455 {
456 //    printk("============>%s()\n", __FUNCTION__);
457         return;
458 }
459
460 static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = {
461         .name                   = "CCMP",
462         .init                   = ieee80211_ccmp_init,
463         .deinit                 = ieee80211_ccmp_deinit,
464         .encrypt_mpdu           = ieee80211_ccmp_encrypt,
465         .decrypt_mpdu           = ieee80211_ccmp_decrypt,
466         .encrypt_msdu           = NULL,
467         .decrypt_msdu           = NULL,
468         .set_key                = ieee80211_ccmp_set_key,
469         .get_key                = ieee80211_ccmp_get_key,
470         .print_stats            = ieee80211_ccmp_print_stats,
471         .extra_prefix_len       = CCMP_HDR_LEN,
472         .extra_postfix_len      = CCMP_MIC_LEN,
473         .owner                  = THIS_MODULE,
474 };
475
476 int __init ieee80211_crypto_ccmp_init(void)
477 {
478         return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp);
479 }
480
481 void __exit ieee80211_crypto_ccmp_exit(void)
482 {
483         ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp);
484 }