OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [net/] [ieee80211/] [ieee80211_crypt_ccmp.c] - Blame information for rev 67

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.