1 | /* |
---|
2 | * Copyright (c) 2009 Joshua Oreman <oremanj@rwcr.net>. |
---|
3 | * |
---|
4 | * This program is free software; you can redistribute it and/or |
---|
5 | * modify it under the terms of the GNU General Public License as |
---|
6 | * published by the Free Software Foundation; either version 2 of the |
---|
7 | * License, or any later version. |
---|
8 | * |
---|
9 | * This program is distributed in the hope that it will be useful, but |
---|
10 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
12 | * General Public License for more details. |
---|
13 | * |
---|
14 | * You should have received a copy of the GNU General Public License |
---|
15 | * along with this program; if not, write to the Free Software |
---|
16 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
---|
17 | */ |
---|
18 | |
---|
19 | FILE_LICENCE ( GPL2_OR_LATER ); |
---|
20 | |
---|
21 | #include <gpxe/net80211.h> |
---|
22 | #include <gpxe/crypto.h> |
---|
23 | #include <gpxe/hmac.h> |
---|
24 | #include <gpxe/sha1.h> |
---|
25 | #include <gpxe/aes.h> |
---|
26 | #include <gpxe/wpa.h> |
---|
27 | #include <byteswap.h> |
---|
28 | #include <errno.h> |
---|
29 | |
---|
30 | /** @file |
---|
31 | * |
---|
32 | * Backend for WPA using the CCMP encryption method |
---|
33 | */ |
---|
34 | |
---|
35 | /** Context for CCMP encryption and decryption */ |
---|
36 | struct ccmp_ctx |
---|
37 | { |
---|
38 | /** AES context - only ever used for encryption */ |
---|
39 | u8 aes_ctx[AES_CTX_SIZE]; |
---|
40 | |
---|
41 | /** Most recently sent packet number */ |
---|
42 | u64 tx_seq; |
---|
43 | |
---|
44 | /** Most recently received packet number */ |
---|
45 | u64 rx_seq; |
---|
46 | }; |
---|
47 | |
---|
48 | /** Header structure at the beginning of CCMP frame data */ |
---|
49 | struct ccmp_head |
---|
50 | { |
---|
51 | u8 pn_lo[2]; /**< Bytes 0 and 1 of packet number */ |
---|
52 | u8 _rsvd; /**< Reserved byte */ |
---|
53 | u8 kid; /**< Key ID and ExtIV byte */ |
---|
54 | u8 pn_hi[4]; /**< Bytes 2-5 (2 first) of packet number */ |
---|
55 | } __attribute__ (( packed )); |
---|
56 | |
---|
57 | |
---|
58 | /** CCMP header overhead */ |
---|
59 | #define CCMP_HEAD_LEN 8 |
---|
60 | |
---|
61 | /** CCMP MIC trailer overhead */ |
---|
62 | #define CCMP_MIC_LEN 8 |
---|
63 | |
---|
64 | /** CCMP nonce length */ |
---|
65 | #define CCMP_NONCE_LEN 13 |
---|
66 | |
---|
67 | /** CCMP nonce structure */ |
---|
68 | struct ccmp_nonce |
---|
69 | { |
---|
70 | u8 prio; /**< Packet priority, 0 for non-QoS */ |
---|
71 | u8 a2[ETH_ALEN]; /**< Address 2 from packet header (sender) */ |
---|
72 | u8 pn[6]; /**< Packet number */ |
---|
73 | } __attribute__ (( packed )); |
---|
74 | |
---|
75 | /** CCMP additional authentication data length (for non-QoS, non-WDS frames) */ |
---|
76 | #define CCMP_AAD_LEN 22 |
---|
77 | |
---|
78 | /** CCMP additional authentication data structure */ |
---|
79 | struct ccmp_aad |
---|
80 | { |
---|
81 | u16 fc; /**< Frame Control field */ |
---|
82 | u8 a1[6]; /**< Address 1 */ |
---|
83 | u8 a2[6]; /**< Address 2 */ |
---|
84 | u8 a3[6]; /**< Address 3 */ |
---|
85 | u16 seq; /**< Sequence Control field */ |
---|
86 | /* Address 4 and QoS Control are included if present */ |
---|
87 | } __attribute__ (( packed )); |
---|
88 | |
---|
89 | /** Mask for Frame Control field in AAD */ |
---|
90 | #define CCMP_AAD_FC_MASK 0xC38F |
---|
91 | |
---|
92 | /** Mask for Sequence Control field in AAD */ |
---|
93 | #define CCMP_AAD_SEQ_MASK 0x000F |
---|
94 | |
---|
95 | |
---|
96 | /** |
---|
97 | * Convert 6-byte LSB packet number to 64-bit integer |
---|
98 | * |
---|
99 | * @v pn Pointer to 6-byte packet number |
---|
100 | * @ret v 64-bit integer value of @a pn |
---|
101 | */ |
---|
102 | static u64 pn_to_u64 ( const u8 *pn ) |
---|
103 | { |
---|
104 | int i; |
---|
105 | u64 ret = 0; |
---|
106 | |
---|
107 | for ( i = 5; i >= 0; i-- ) { |
---|
108 | ret <<= 8; |
---|
109 | ret |= pn[i]; |
---|
110 | } |
---|
111 | |
---|
112 | return ret; |
---|
113 | } |
---|
114 | |
---|
115 | /** |
---|
116 | * Convert 64-bit integer to 6-byte packet number |
---|
117 | * |
---|
118 | * @v v 64-bit integer |
---|
119 | * @v msb If TRUE, reverse the output PN to be in MSB order |
---|
120 | * @ret pn 6-byte packet number |
---|
121 | * |
---|
122 | * The PN is stored in LSB order in the packet header and in MSB order |
---|
123 | * in the nonce. WHYYYYY? |
---|
124 | */ |
---|
125 | static void u64_to_pn ( u64 v, u8 *pn, int msb ) |
---|
126 | { |
---|
127 | int i; |
---|
128 | u8 *pnp = pn + ( msb ? 5 : 0 ); |
---|
129 | int delta = ( msb ? -1 : +1 ); |
---|
130 | |
---|
131 | for ( i = 0; i < 6; i++ ) { |
---|
132 | *pnp = v & 0xFF; |
---|
133 | pnp += delta; |
---|
134 | v >>= 8; |
---|
135 | } |
---|
136 | } |
---|
137 | |
---|
138 | /** Value for @a msb argument of u64_to_pn() for MSB output */ |
---|
139 | #define PN_MSB 1 |
---|
140 | |
---|
141 | /** Value for @a msb argument of u64_to_pn() for LSB output */ |
---|
142 | #define PN_LSB 0 |
---|
143 | |
---|
144 | |
---|
145 | |
---|
146 | /** |
---|
147 | * Initialise CCMP state and install key |
---|
148 | * |
---|
149 | * @v crypto CCMP cryptosystem structure |
---|
150 | * @v key Pointer to 16-byte temporal key to install |
---|
151 | * @v keylen Length of key (16 bytes) |
---|
152 | * @v rsc Initial receive sequence counter |
---|
153 | */ |
---|
154 | static int ccmp_init ( struct net80211_crypto *crypto, const void *key, |
---|
155 | int keylen, const void *rsc ) |
---|
156 | { |
---|
157 | struct ccmp_ctx *ctx = crypto->priv; |
---|
158 | |
---|
159 | if ( keylen != 16 ) |
---|
160 | return -EINVAL; |
---|
161 | |
---|
162 | if ( rsc ) |
---|
163 | ctx->rx_seq = pn_to_u64 ( rsc ); |
---|
164 | |
---|
165 | cipher_setkey ( &aes_algorithm, ctx->aes_ctx, key, keylen ); |
---|
166 | |
---|
167 | return 0; |
---|
168 | } |
---|
169 | |
---|
170 | |
---|
171 | /** |
---|
172 | * Encrypt or decrypt data stream using AES in Counter mode |
---|
173 | * |
---|
174 | * @v ctx CCMP cryptosystem context |
---|
175 | * @v nonce Nonce value, 13 bytes |
---|
176 | * @v srcv Data to encrypt or decrypt |
---|
177 | * @v len Number of bytes pointed to by @a src |
---|
178 | * @v msrcv MIC value to encrypt or decrypt (may be NULL) |
---|
179 | * @ret destv Encrypted or decrypted data |
---|
180 | * @ret mdestv Encrypted or decrypted MIC value |
---|
181 | * |
---|
182 | * This assumes CCMP parameters of L=2 and M=8. The algorithm is |
---|
183 | * defined in RFC 3610. |
---|
184 | */ |
---|
185 | static void ccmp_ctr_xor ( struct ccmp_ctx *ctx, const void *nonce, |
---|
186 | const void *srcv, void *destv, int len, |
---|
187 | const void *msrcv, void *mdestv ) |
---|
188 | { |
---|
189 | u8 A[16], S[16]; |
---|
190 | u16 ctr; |
---|
191 | int i; |
---|
192 | const u8 *src = srcv, *msrc = msrcv; |
---|
193 | u8 *dest = destv, *mdest = mdestv; |
---|
194 | |
---|
195 | A[0] = 0x01; /* flags, L' = L - 1 = 1, other bits rsvd */ |
---|
196 | memcpy ( A + 1, nonce, CCMP_NONCE_LEN ); |
---|
197 | |
---|
198 | if ( msrcv ) { |
---|
199 | A[14] = A[15] = 0; |
---|
200 | |
---|
201 | cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 ); |
---|
202 | |
---|
203 | for ( i = 0; i < 8; i++ ) { |
---|
204 | *mdest++ = *msrc++ ^ S[i]; |
---|
205 | } |
---|
206 | } |
---|
207 | |
---|
208 | for ( ctr = 1 ;; ctr++ ) { |
---|
209 | A[14] = ctr >> 8; |
---|
210 | A[15] = ctr & 0xFF; |
---|
211 | |
---|
212 | cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, A, S, 16 ); |
---|
213 | |
---|
214 | for ( i = 0; i < len && i < 16; i++ ) |
---|
215 | *dest++ = *src++ ^ S[i]; |
---|
216 | |
---|
217 | if ( len <= 16 ) |
---|
218 | break; /* we're done */ |
---|
219 | |
---|
220 | len -= 16; |
---|
221 | } |
---|
222 | } |
---|
223 | |
---|
224 | |
---|
225 | /** |
---|
226 | * Advance one block in CBC-MAC calculation |
---|
227 | * |
---|
228 | * @v aes_ctx AES encryption context with key set |
---|
229 | * @v B Cleartext block to incorporate (16 bytes) |
---|
230 | * @v X Previous ciphertext block (16 bytes) |
---|
231 | * @ret B Clobbered |
---|
232 | * @ret X New ciphertext block (16 bytes) |
---|
233 | * |
---|
234 | * This function does X := E[key] ( X ^ B ). |
---|
235 | */ |
---|
236 | static void ccmp_feed_cbc_mac ( void *aes_ctx, u8 *B, u8 *X ) |
---|
237 | { |
---|
238 | int i; |
---|
239 | for ( i = 0; i < 16; i++ ) |
---|
240 | B[i] ^= X[i]; |
---|
241 | cipher_encrypt ( &aes_algorithm, aes_ctx, B, X, 16 ); |
---|
242 | } |
---|
243 | |
---|
244 | |
---|
245 | /** |
---|
246 | * Calculate MIC on plaintext data using CBC-MAC |
---|
247 | * |
---|
248 | * @v ctx CCMP cryptosystem context |
---|
249 | * @v nonce Nonce value, 13 bytes |
---|
250 | * @v data Data to calculate MIC over |
---|
251 | * @v datalen Length of @a data |
---|
252 | * @v aad Additional authentication data, for MIC but not encryption |
---|
253 | * @ret mic MIC value (unencrypted), 8 bytes |
---|
254 | * |
---|
255 | * @a aadlen is assumed to be 22 bytes long, as it always is for |
---|
256 | * 802.11 use when transmitting non-QoS, not-between-APs frames (the |
---|
257 | * only type we deal with). |
---|
258 | */ |
---|
259 | static void ccmp_cbc_mac ( struct ccmp_ctx *ctx, const void *nonce, |
---|
260 | const void *data, u16 datalen, |
---|
261 | const void *aad, void *mic ) |
---|
262 | { |
---|
263 | u8 X[16], B[16]; |
---|
264 | |
---|
265 | /* Zeroth block: flags, nonce, length */ |
---|
266 | |
---|
267 | /* Rsv AAD - M'- - L'- |
---|
268 | * 0 1 0 1 1 0 0 1 for an 8-byte MAC and 2-byte message length |
---|
269 | */ |
---|
270 | B[0] = 0x59; |
---|
271 | memcpy ( B + 1, nonce, CCMP_NONCE_LEN ); |
---|
272 | B[14] = datalen >> 8; |
---|
273 | B[15] = datalen & 0xFF; |
---|
274 | |
---|
275 | cipher_encrypt ( &aes_algorithm, ctx->aes_ctx, B, X, 16 ); |
---|
276 | |
---|
277 | /* First block: AAD length field and 14 bytes of AAD */ |
---|
278 | B[0] = 0; |
---|
279 | B[1] = CCMP_AAD_LEN; |
---|
280 | memcpy ( B + 2, aad, 14 ); |
---|
281 | |
---|
282 | ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X ); |
---|
283 | |
---|
284 | /* Second block: Remaining 8 bytes of AAD, 8 bytes zero pad */ |
---|
285 | memcpy ( B, aad + 14, 8 ); |
---|
286 | memset ( B + 8, 0, 8 ); |
---|
287 | |
---|
288 | ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X ); |
---|
289 | |
---|
290 | /* Message blocks */ |
---|
291 | while ( datalen ) { |
---|
292 | if ( datalen >= 16 ) { |
---|
293 | memcpy ( B, data, 16 ); |
---|
294 | datalen -= 16; |
---|
295 | } else { |
---|
296 | memcpy ( B, data, datalen ); |
---|
297 | memset ( B + datalen, 0, 16 - datalen ); |
---|
298 | datalen = 0; |
---|
299 | } |
---|
300 | |
---|
301 | ccmp_feed_cbc_mac ( ctx->aes_ctx, B, X ); |
---|
302 | |
---|
303 | data += 16; |
---|
304 | } |
---|
305 | |
---|
306 | /* Get MIC from final value of X */ |
---|
307 | memcpy ( mic, X, 8 ); |
---|
308 | } |
---|
309 | |
---|
310 | |
---|
311 | /** |
---|
312 | * Encapsulate and encrypt a packet using CCMP |
---|
313 | * |
---|
314 | * @v crypto CCMP cryptosystem |
---|
315 | * @v iob I/O buffer containing cleartext packet |
---|
316 | * @ret eiob I/O buffer containing encrypted packet |
---|
317 | */ |
---|
318 | struct io_buffer * ccmp_encrypt ( struct net80211_crypto *crypto, |
---|
319 | struct io_buffer *iob ) |
---|
320 | { |
---|
321 | struct ccmp_ctx *ctx = crypto->priv; |
---|
322 | struct ieee80211_frame *hdr = iob->data; |
---|
323 | struct io_buffer *eiob; |
---|
324 | const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN; |
---|
325 | int datalen = iob_len ( iob ) - hdrlen; |
---|
326 | struct ccmp_head head; |
---|
327 | struct ccmp_nonce nonce; |
---|
328 | struct ccmp_aad aad; |
---|
329 | u8 mic[8], tx_pn[6]; |
---|
330 | void *edata, *emic; |
---|
331 | |
---|
332 | ctx->tx_seq++; |
---|
333 | u64_to_pn ( ctx->tx_seq, tx_pn, PN_LSB ); |
---|
334 | |
---|
335 | /* Allocate memory */ |
---|
336 | eiob = alloc_iob ( iob_len ( iob ) + CCMP_HEAD_LEN + CCMP_MIC_LEN ); |
---|
337 | if ( ! eiob ) |
---|
338 | return NULL; |
---|
339 | |
---|
340 | /* Copy frame header */ |
---|
341 | memcpy ( iob_put ( eiob, hdrlen ), iob->data, hdrlen ); |
---|
342 | hdr = eiob->data; |
---|
343 | hdr->fc |= IEEE80211_FC_PROTECTED; |
---|
344 | |
---|
345 | /* Fill in packet number and extended IV */ |
---|
346 | memcpy ( head.pn_lo, tx_pn, 2 ); |
---|
347 | memcpy ( head.pn_hi, tx_pn + 2, 4 ); |
---|
348 | head.kid = 0x20; /* have Extended IV, key ID 0 */ |
---|
349 | head._rsvd = 0; |
---|
350 | memcpy ( iob_put ( eiob, sizeof ( head ) ), &head, sizeof ( head ) ); |
---|
351 | |
---|
352 | /* Form nonce */ |
---|
353 | nonce.prio = 0; |
---|
354 | memcpy ( nonce.a2, hdr->addr2, ETH_ALEN ); |
---|
355 | u64_to_pn ( ctx->tx_seq, nonce.pn, PN_MSB ); |
---|
356 | |
---|
357 | /* Form additional authentication data */ |
---|
358 | aad.fc = hdr->fc & CCMP_AAD_FC_MASK; |
---|
359 | memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */ |
---|
360 | aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK; |
---|
361 | |
---|
362 | /* Calculate MIC over the data */ |
---|
363 | ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad, mic ); |
---|
364 | |
---|
365 | /* Copy and encrypt data and MIC */ |
---|
366 | edata = iob_put ( eiob, datalen ); |
---|
367 | emic = iob_put ( eiob, CCMP_MIC_LEN ); |
---|
368 | ccmp_ctr_xor ( ctx, &nonce, |
---|
369 | iob->data + hdrlen, edata, datalen, |
---|
370 | mic, emic ); |
---|
371 | |
---|
372 | /* Done! */ |
---|
373 | DBGC2 ( ctx, "WPA-CCMP %p: encrypted packet %p -> %p\n", ctx, |
---|
374 | iob, eiob ); |
---|
375 | |
---|
376 | return eiob; |
---|
377 | } |
---|
378 | |
---|
379 | /** |
---|
380 | * Decrypt a packet using CCMP |
---|
381 | * |
---|
382 | * @v crypto CCMP cryptosystem |
---|
383 | * @v eiob I/O buffer containing encrypted packet |
---|
384 | * @ret iob I/O buffer containing cleartext packet |
---|
385 | */ |
---|
386 | static struct io_buffer * ccmp_decrypt ( struct net80211_crypto *crypto, |
---|
387 | struct io_buffer *eiob ) |
---|
388 | { |
---|
389 | struct ccmp_ctx *ctx = crypto->priv; |
---|
390 | struct ieee80211_frame *hdr; |
---|
391 | struct io_buffer *iob; |
---|
392 | const int hdrlen = IEEE80211_TYP_FRAME_HEADER_LEN; |
---|
393 | int datalen = iob_len ( eiob ) - hdrlen - CCMP_HEAD_LEN - CCMP_MIC_LEN; |
---|
394 | struct ccmp_head *head; |
---|
395 | struct ccmp_nonce nonce; |
---|
396 | struct ccmp_aad aad; |
---|
397 | u8 rx_pn[6], their_mic[8], our_mic[8]; |
---|
398 | |
---|
399 | iob = alloc_iob ( hdrlen + datalen ); |
---|
400 | if ( ! iob ) |
---|
401 | return NULL; |
---|
402 | |
---|
403 | /* Copy frame header */ |
---|
404 | memcpy ( iob_put ( iob, hdrlen ), eiob->data, hdrlen ); |
---|
405 | hdr = iob->data; |
---|
406 | hdr->fc &= ~IEEE80211_FC_PROTECTED; |
---|
407 | |
---|
408 | /* Check and update RX packet number */ |
---|
409 | head = eiob->data + hdrlen; |
---|
410 | memcpy ( rx_pn, head->pn_lo, 2 ); |
---|
411 | memcpy ( rx_pn + 2, head->pn_hi, 4 ); |
---|
412 | |
---|
413 | if ( pn_to_u64 ( rx_pn ) <= ctx->rx_seq ) { |
---|
414 | DBGC ( ctx, "WPA-CCMP %p: packet received out of order " |
---|
415 | "(%012llx <= %012llx)\n", ctx, pn_to_u64 ( rx_pn ), |
---|
416 | ctx->rx_seq ); |
---|
417 | free_iob ( iob ); |
---|
418 | return NULL; |
---|
419 | } |
---|
420 | |
---|
421 | ctx->rx_seq = pn_to_u64 ( rx_pn ); |
---|
422 | DBGC2 ( ctx, "WPA-CCMP %p: RX packet number %012llx\n", ctx, ctx->rx_seq ); |
---|
423 | |
---|
424 | /* Form nonce */ |
---|
425 | nonce.prio = 0; |
---|
426 | memcpy ( nonce.a2, hdr->addr2, ETH_ALEN ); |
---|
427 | u64_to_pn ( ctx->rx_seq, nonce.pn, PN_MSB ); |
---|
428 | |
---|
429 | /* Form additional authentication data */ |
---|
430 | aad.fc = ( hdr->fc & CCMP_AAD_FC_MASK ) | IEEE80211_FC_PROTECTED; |
---|
431 | memcpy ( aad.a1, hdr->addr1, 3 * ETH_ALEN ); /* all 3 at once */ |
---|
432 | aad.seq = hdr->seq & CCMP_AAD_SEQ_MASK; |
---|
433 | |
---|
434 | /* Copy-decrypt data and MIC */ |
---|
435 | ccmp_ctr_xor ( ctx, &nonce, eiob->data + hdrlen + sizeof ( *head ), |
---|
436 | iob_put ( iob, datalen ), datalen, |
---|
437 | eiob->tail - CCMP_MIC_LEN, their_mic ); |
---|
438 | |
---|
439 | /* Check MIC */ |
---|
440 | ccmp_cbc_mac ( ctx, &nonce, iob->data + hdrlen, datalen, &aad, |
---|
441 | our_mic ); |
---|
442 | |
---|
443 | if ( memcmp ( their_mic, our_mic, CCMP_MIC_LEN ) != 0 ) { |
---|
444 | DBGC2 ( ctx, "WPA-CCMP %p: MIC failure\n", ctx ); |
---|
445 | free_iob ( iob ); |
---|
446 | return NULL; |
---|
447 | } |
---|
448 | |
---|
449 | DBGC2 ( ctx, "WPA-CCMP %p: decrypted packet %p -> %p\n", ctx, |
---|
450 | eiob, iob ); |
---|
451 | |
---|
452 | return iob; |
---|
453 | } |
---|
454 | |
---|
455 | |
---|
456 | /** CCMP cryptosystem */ |
---|
457 | struct net80211_crypto ccmp_crypto __net80211_crypto = { |
---|
458 | .algorithm = NET80211_CRYPT_CCMP, |
---|
459 | .init = ccmp_init, |
---|
460 | .encrypt = ccmp_encrypt, |
---|
461 | .decrypt = ccmp_decrypt, |
---|
462 | .priv_len = sizeof ( struct ccmp_ctx ), |
---|
463 | }; |
---|
464 | |
---|
465 | |
---|
466 | |
---|
467 | |
---|
468 | /** |
---|
469 | * Calculate HMAC-SHA1 MIC for EAPOL-Key frame |
---|
470 | * |
---|
471 | * @v kck Key Confirmation Key, 16 bytes |
---|
472 | * @v msg Message to calculate MIC over |
---|
473 | * @v len Number of bytes to calculate MIC over |
---|
474 | * @ret mic Calculated MIC, 16 bytes long |
---|
475 | */ |
---|
476 | static void ccmp_kie_mic ( const void *kck, const void *msg, size_t len, |
---|
477 | void *mic ) |
---|
478 | { |
---|
479 | u8 sha1_ctx[SHA1_CTX_SIZE]; |
---|
480 | u8 kckb[16]; |
---|
481 | u8 hash[SHA1_SIZE]; |
---|
482 | size_t kck_len = 16; |
---|
483 | |
---|
484 | memcpy ( kckb, kck, kck_len ); |
---|
485 | |
---|
486 | hmac_init ( &sha1_algorithm, sha1_ctx, kckb, &kck_len ); |
---|
487 | hmac_update ( &sha1_algorithm, sha1_ctx, msg, len ); |
---|
488 | hmac_final ( &sha1_algorithm, sha1_ctx, kckb, &kck_len, hash ); |
---|
489 | |
---|
490 | memcpy ( mic, hash, 16 ); |
---|
491 | } |
---|
492 | |
---|
493 | /** |
---|
494 | * Decrypt key data in EAPOL-Key frame |
---|
495 | * |
---|
496 | * @v kek Key Encryption Key, 16 bytes |
---|
497 | * @v iv Initialisation vector, 16 bytes (unused) |
---|
498 | * @v msg Message to decrypt |
---|
499 | * @v len Length of message |
---|
500 | * @ret msg Decrypted message in place of original |
---|
501 | * @ret len Adjusted downward for 8 bytes of overhead |
---|
502 | * @ret rc Return status code |
---|
503 | * |
---|
504 | * The returned message may still contain padding of 0xDD followed by |
---|
505 | * zero or more 0x00 octets. It is impossible to remove the padding |
---|
506 | * without parsing the IEs in the packet (another design decision that |
---|
507 | * tends to make one question the 802.11i committee's intelligence...) |
---|
508 | */ |
---|
509 | static int ccmp_kie_decrypt ( const void *kek, const void *iv __unused, |
---|
510 | void *msg, u16 *len ) |
---|
511 | { |
---|
512 | if ( *len % 8 != 0 ) |
---|
513 | return -EINVAL; |
---|
514 | |
---|
515 | if ( aes_unwrap ( kek, msg, msg, *len / 8 - 1 ) != 0 ) |
---|
516 | return -EINVAL; |
---|
517 | |
---|
518 | *len -= 8; |
---|
519 | |
---|
520 | return 0; |
---|
521 | } |
---|
522 | |
---|
523 | /** CCMP-style key integrity and encryption handler */ |
---|
524 | struct wpa_kie ccmp_kie __wpa_kie = { |
---|
525 | .version = EAPOL_KEY_VERSION_WPA2, |
---|
526 | .mic = ccmp_kie_mic, |
---|
527 | .decrypt = ccmp_kie_decrypt, |
---|
528 | }; |
---|