Don't set the focus on the display filter entry when we're passed a
[obnox/wireshark/wip.git] / epan / crypt / airpdcap_ccmp.c
1 /* airpdcap_ccmp.c
2  *
3  * $Id$
4  *
5  * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
6  * Copyright (c) 2006 CACE Technologies, Davis (California)
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission.
19  *
20  * Alternatively, this software may be distributed under the terms of the
21  * GNU General Public License ("GPL") version 2 as published by the Free
22  * Software Foundation.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 /*
37  * Note: This file was derived from the FreeBSD source code, RELENG 6,
38  *              sys/net80211/ieee80211_crypto_ccmp.c
39  */
40
41 /****************************************************************************/
42 /* File includes                                                                */
43
44 #include "airpdcap_system.h"
45 #include "airpdcap_int.h"
46
47 #include "airpdcap_rijndael.h"
48
49 #include "airpdcap_debug.h"
50
51 /****************************************************************************/
52 /*      Internal definitions                                                    */
53
54 #define AES_BLOCK_LEN 16
55
56 /* Note: copied from net80211/ieee80211.h                                       */
57 #define AIRPDCAP_FC1_DIR_MASK                  0x03
58 #define AIRPDCAP_FC1_DIR_DSTODS                0x03    /* AP ->AP  */
59 #define AIRPDCAP_FC0_SUBTYPE_QOS               0x80
60 #define AIRPDCAP_FC0_TYPE_DATA                 0x08
61 #define AIRPDCAP_FC0_TYPE_MASK                 0x0c
62 #define AIRPDCAP_SEQ_FRAG_MASK                 0x000f
63 #define AIRPDCAP_QOS_HAS_SEQ(wh) \
64         (((wh)->fc[0] & \
65         (AIRPDCAP_FC0_TYPE_MASK | AIRPDCAP_FC0_SUBTYPE_QOS)) == \
66         (AIRPDCAP_FC0_TYPE_DATA | AIRPDCAP_FC0_SUBTYPE_QOS))
67
68 /****************************************************************************/
69 /* Internal macros                                                              */
70
71 #define CCMP_DECRYPT(_i, _b, _b0, _pos, _a, _len) {             \
72         /* Decrypt, with counter */                             \
73         _b0[14] = (UINT8)((_i >> 8) & 0xff);                    \
74         _b0[15] = (UINT8)(_i & 0xff);                           \
75         rijndael_encrypt(&key, _b0, _b);                        \
76         XOR_BLOCK(_pos, _b, _len);                              \
77         /* Authentication */                                    \
78         XOR_BLOCK(_a, _pos, _len);                              \
79         rijndael_encrypt(&key, _a, _a);                         \
80 }
81
82 #define READ_6(b0, b1, b2, b3, b4, b5) \
83         ((((UINT64)((UINT16)((b4 << 0) | (b5 << 8)))) << 32) | \
84             ((UINT32)((b0 << 0) | (b1 << 8) | (b2 << 16) | (b3 << 24))))
85
86 #define AIRPDCAP_ADDR_COPY(dst,src)    memcpy(dst,src,AIRPDCAP_MAC_LEN)
87
88 /****************************************************************************/
89 /* Internal function prototypes declarations                                    */
90
91 static void ccmp_init_blocks(
92         rijndael_ctx *ctx,
93         PAIRPDCAP_MAC_FRAME wh,
94         UINT64 pn,
95         size_t dlen,
96         UINT8 b0[AES_BLOCK_LEN],
97         UINT8 aad[2 * AES_BLOCK_LEN],
98         UINT8 a[AES_BLOCK_LEN],
99         UINT8 b[AES_BLOCK_LEN])
100         ;
101
102 /****************************************************************************/
103 /* Function definitions                                                 */
104
105 static void ccmp_init_blocks(
106         rijndael_ctx *ctx,
107         PAIRPDCAP_MAC_FRAME wh,
108         UINT64 pn,
109         size_t dlen,
110         UINT8 b0[AES_BLOCK_LEN],
111         UINT8 aad[2 * AES_BLOCK_LEN],
112         UINT8 a[AES_BLOCK_LEN],
113         UINT8 b[AES_BLOCK_LEN])
114 {
115 #define IS_4ADDRESS(wh) \
116         ((wh->fc[1] & AIRPDCAP_FC1_DIR_MASK) == AIRPDCAP_FC1_DIR_DSTODS)
117 #define IS_QOS_DATA(wh) AIRPDCAP_QOS_HAS_SEQ(wh)
118
119         memset(aad, 0, 2*AES_BLOCK_LEN);
120
121         /* CCM Initial Block:
122         * Flag (Include authentication header, M=3 (8-octet MIC),
123         *       L=1 (2-octet Dlen))
124         * Nonce: 0x00 | A2 | PN
125         * Dlen */
126         b0[0] = 0x59;
127         /* NB: b0[1] set below */
128         AIRPDCAP_ADDR_COPY(b0 + 2, wh->addr2);
129         b0[8] = (UINT8)(pn >> 40);
130         b0[9] = (UINT8)(pn >> 32);
131         b0[10] = (UINT8)(pn >> 24);
132         b0[11] = (UINT8)(pn >> 16);
133         b0[12] = (UINT8)(pn >> 8);
134         b0[13] = (UINT8)(pn >> 0);
135         b0[14] = (UINT8)((UINT8)(dlen >> 8) & 0xff);
136         b0[15] = (UINT8)(dlen & 0xff);
137
138         /* AAD:
139         * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
140         * A1 | A2 | A3
141         * SC with bits 4..15 (seq#) masked to zero
142         * A4 (if present)
143         * QC (if present)
144         */
145         aad[0] = 0;     /* AAD length >> 8 */
146         /* NB: aad[1] set below */
147         aad[2] = (UINT8)(wh->fc[0] & 0x8f);    /* XXX magic #s */
148         aad[3] = (UINT8)(wh->fc[1] & 0xc7);    /* XXX magic #s */
149         /* NB: we know 3 addresses are contiguous */
150         memcpy(aad + 4, wh->addr1, 3 * AIRPDCAP_MAC_LEN);
151         aad[22] = (UINT8)(wh->seq[0] & AIRPDCAP_SEQ_FRAG_MASK);
152         aad[23] = 0; /* all bits masked */
153         /*
154         * Construct variable-length portion of AAD based
155         * on whether this is a 4-address frame/QOS frame.
156         * We always zero-pad to 32 bytes before running it
157         * through the cipher.
158         *
159         * We also fill in the priority bits of the CCM
160         * initial block as we know whether or not we have
161         * a QOS frame.
162         */
163         if (IS_4ADDRESS(wh)) {
164                 AIRPDCAP_ADDR_COPY(aad + 24,
165                         ((PAIRPDCAP_MAC_FRAME_ADDR4)wh)->addr4);
166                 if (IS_QOS_DATA(wh)) {
167                         PAIRPDCAP_MAC_FRAME_ADDR4_QOS qwh4 =
168                                 (PAIRPDCAP_MAC_FRAME_ADDR4_QOS) wh;
169                         aad[30] = (UINT8)(qwh4->qos[0] & 0x0f);/* just priority bits */
170                         aad[31] = 0;
171                         b0[1] = aad[30];
172                         aad[1] = 22 + AIRPDCAP_MAC_LEN + 2;
173                 } else {
174                         memset(&aad[30], 0, 2);
175                         b0[1] = 0;
176                         aad[1] = 22 + AIRPDCAP_MAC_LEN;
177                 }
178         } else {
179                 if (IS_QOS_DATA(wh)) {
180                         PAIRPDCAP_MAC_FRAME_QOS qwh =
181                                 (PAIRPDCAP_MAC_FRAME_QOS) wh;
182                         aad[24] = (UINT8)(qwh->qos[0] & 0x0f); /* just priority bits */
183                         aad[25] = 0;
184                         b0[1] = aad[24];
185                         aad[1] = 22 + 2;
186                 } else {
187                         memset(&aad[24], 0, 2);
188                         b0[1] = 0;
189                         aad[1] = 22;
190                 }
191                 memset(&aad[26], 0, 4);
192         }
193
194         /* Start with the first block and AAD */
195         rijndael_encrypt(ctx, b0, a);
196         XOR_BLOCK(a, aad, AES_BLOCK_LEN);
197         rijndael_encrypt(ctx, a, a);
198         XOR_BLOCK(a, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN);
199         rijndael_encrypt(ctx, a, a);
200         b0[0] &= 0x07;
201         b0[14] = b0[15] = 0;
202         rijndael_encrypt(ctx, b0, b);
203
204         /** //XOR( m + len - 8, b, 8 ); **/
205 #undef  IS_QOS_DATA
206 #undef  IS_4ADDRESS
207 }
208
209 INT AirPDcapCcmpDecrypt(
210         UINT8 *m,
211         INT len,
212         UCHAR TK1[16])
213 {
214         PAIRPDCAP_MAC_FRAME wh;
215         UINT8 aad[2 * AES_BLOCK_LEN];
216         UINT8 b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], a[AES_BLOCK_LEN];
217         UINT8 mic[AES_BLOCK_LEN];
218         size_t data_len;
219         UINT i;
220         UINT8 *pos;
221         UINT space;
222         INT z=AIRPDCAP_HEADER_LEN(m[1]);
223         rijndael_ctx key;
224         UINT64 PN;
225         UINT8 *ivp=m+z;
226
227         PN = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
228
229         /* freebsd      */
230         rijndael_set_key(&key, TK1, 128);
231         wh = (PAIRPDCAP_MAC_FRAME )m;
232         data_len = len - (z + AIRPDCAP_CCMP_HEADER+AIRPDCAP_CCMP_TRAILER);
233         if (data_len < 1)
234             return 0;
235         ccmp_init_blocks(&key, wh, PN, data_len, b0, aad, a, b);
236         memcpy(mic, m+len-AIRPDCAP_CCMP_TRAILER, AIRPDCAP_CCMP_TRAILER);
237         XOR_BLOCK(mic, b, AIRPDCAP_CCMP_TRAILER);
238
239         i = 1;
240         pos = (UINT8 *)m + z + AIRPDCAP_CCMP_HEADER;
241         space = len - (z + AIRPDCAP_CCMP_HEADER);
242
243         if (space > data_len)
244                 space = (UINT)data_len;
245         while (space >= AES_BLOCK_LEN) {
246                 CCMP_DECRYPT(i, b, b0, pos, a, AES_BLOCK_LEN);
247                 pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN;
248                 data_len -= AES_BLOCK_LEN;
249                 i++;
250         }
251
252         if (space != 0)         /* short last block */
253                 CCMP_DECRYPT(i, b, b0, pos, a, space);
254
255         /*      MIC Key ?= MIC                                                                                                                                                          */
256         if (memcmp(mic, a, AIRPDCAP_CCMP_TRAILER) == 0) {
257                 return 0;
258         }
259
260         /* TODO replay check    (IEEE 802.11i-2004, pg. 62)                     */
261         /* TODO PN must be incremental (IEEE 802.11i-2004, pg. 62)              */
262
263         return 1;
264 }