5 * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
6 * Copyright (c) 2006 CACE Technologies, Davis (California)
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
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.
37 * Note: This file was derived from the FreeBSD source code, RELENG 6,
38 * sys/net80211/ieee80211_crypto_ccmp.c
41 /****************************************************************************/
44 #include "airpdcap_system.h"
45 #include "airpdcap_int.h"
47 #include "airpdcap_rijndael.h"
49 #include "airpdcap_debug.h"
51 /****************************************************************************/
52 /* Internal definitions */
54 #define AES_BLOCK_LEN 16
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) \
65 (AIRPDCAP_FC0_TYPE_MASK | AIRPDCAP_FC0_SUBTYPE_QOS)) == \
66 (AIRPDCAP_FC0_TYPE_DATA | AIRPDCAP_FC0_SUBTYPE_QOS))
68 /****************************************************************************/
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); \
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))))
86 #define AIRPDCAP_ADDR_COPY(dst,src) memcpy(dst,src,AIRPDCAP_MAC_LEN)
88 /****************************************************************************/
89 /* Internal function prototypes declarations */
91 static void ccmp_init_blocks(
93 PAIRPDCAP_MAC_FRAME wh,
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])
102 /****************************************************************************/
103 /* Function definitions */
105 static void ccmp_init_blocks(
107 PAIRPDCAP_MAC_FRAME wh,
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])
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)
119 memset(aad, 0, 2*AES_BLOCK_LEN);
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
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);
139 * FC with bits 4..6 and 11..13 masked to zero; 14 is always one
141 * SC with bits 4..15 (seq#) masked to zero
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 */
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.
159 * We also fill in the priority bits of the CCM
160 * initial block as we know whether or not we have
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 */
172 aad[1] = 22 + AIRPDCAP_MAC_LEN + 2;
174 memset(&aad[30], 0, 2);
176 aad[1] = 22 + AIRPDCAP_MAC_LEN;
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 */
187 memset(&aad[24], 0, 2);
191 memset(&aad[26], 0, 4);
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);
202 rijndael_encrypt(ctx, b0, b);
204 /** //XOR( m + len - 8, b, 8 ); **/
209 INT AirPDcapCcmpDecrypt(
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];
222 INT z=AIRPDCAP_HEADER_LEN(m[1]);
227 PN = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]);
230 rijndael_set_key(&key, TK1, 128);
231 wh = (PAIRPDCAP_MAC_FRAME )m;
232 data_len = len - (z + AIRPDCAP_CCMP_HEADER+AIRPDCAP_CCMP_TRAILER);
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);
240 pos = (UINT8 *)m + z + AIRPDCAP_CCMP_HEADER;
241 space = len - (z + AIRPDCAP_CCMP_HEADER);
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;
252 if (space != 0) /* short last block */
253 CCMP_DECRYPT(i, b, b0, pos, a, space);
256 if (memcmp(mic, a, AIRPDCAP_CCMP_TRAILER) == 0) {
260 /* TODO replay check (IEEE 802.11i-2004, pg. 62) */
261 /* TODO PN must be incremental (IEEE 802.11i-2004, pg. 62) */