INT AirPDcapCcmpDecrypt( UINT8 *m, gint mac_header_len, INT len, UCHAR TK1[16]) { PAIRPDCAP_MAC_FRAME wh; UINT8 aad[2 * AES_BLOCK_LEN]; UINT8 b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], a[AES_BLOCK_LEN]; UINT8 mic[AES_BLOCK_LEN]; size_t data_len; UINT i; UINT8 *pos; UINT space; INT z = mac_header_len; rijndael_ctx key; UINT64 PN; UINT8 *ivp=m+z; PN = READ_6(ivp[0], ivp[1], ivp[4], ivp[5], ivp[6], ivp[7]); /* freebsd */ rijndael_set_key(&key, TK1, 128); wh = (PAIRPDCAP_MAC_FRAME )m; data_len = len - (z + AIRPDCAP_CCMP_HEADER+AIRPDCAP_CCMP_TRAILER); if (data_len < 1) return 0; ccmp_init_blocks(&key, wh, PN, data_len, b0, aad, a, b); memcpy(mic, m+len-AIRPDCAP_CCMP_TRAILER, AIRPDCAP_CCMP_TRAILER); XOR_BLOCK(mic, b, AIRPDCAP_CCMP_TRAILER); i = 1; pos = (UINT8 *)m + z + AIRPDCAP_CCMP_HEADER; space = len - (z + AIRPDCAP_CCMP_HEADER); if (space > data_len) space = (UINT)data_len; while (space >= AES_BLOCK_LEN) { CCMP_DECRYPT(i, b, b0, pos, a, AES_BLOCK_LEN); pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN; data_len -= AES_BLOCK_LEN; i++; } if (space != 0) /* short last block */ CCMP_DECRYPT(i, b, b0, pos, a, space); /* MIC Key ?= MIC */ if (memcmp(mic, a, AIRPDCAP_CCMP_TRAILER) == 0) { return 0; } /* TODO replay check (IEEE 802.11i-2004, pg. 62) */ /* TODO PN must be incremental (IEEE 802.11i-2004, pg. 62) */ return 1; }
int ccmp_encrypt(struct ieee80211_key *key, wbuf_t wbuf0, int hdrlen, int mfp) { struct ccmp_ctx *ctx = key->wk_private; struct ieee80211_frame *wh; wbuf_t wbuf = wbuf0; int data_len, i, space; uint8_t aad[2 * AES_BLOCK_LEN], b0[AES_BLOCK_LEN], b[AES_BLOCK_LEN], e[AES_BLOCK_LEN], s0[AES_BLOCK_LEN]; uint8_t *pos; ctx->cc_vap->iv_stats.is_crypto_ccmp++; wh = (struct ieee80211_frame *)wbuf_header(wbuf); data_len = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header); ccmp_init_blocks(&ctx->cc_aes, wh, key->wk_keytsc, data_len, b0, aad, b, s0, mfp); i = 1; pos = (u_int8_t *)wbuf_header(wbuf) + hdrlen + ccmp.ic_header; /* NB: assumes header is entirely in first mbuf */ space = wbuf_get_pktlen(wbuf) - (hdrlen + ccmp.ic_header); for (;;) { if (space > data_len) space = data_len; /* * Do full blocks. */ while (space >= AES_BLOCK_LEN) { CCMP_ENCRYPT(i, b, b0, pos, e, AES_BLOCK_LEN); pos += AES_BLOCK_LEN, space -= AES_BLOCK_LEN; data_len -= AES_BLOCK_LEN; i++; } if (data_len <= 0) /* no more data */ break; wbuf = wbuf_next(wbuf); if (wbuf == NULL) { /* last buffer */ if (space != 0) { /* * Short last block. */ CCMP_ENCRYPT(i, b, b0, pos, e, space); } break; } #if 1 /* assume only one chunk */ break; #else if (space != 0) { uint8_t *pos_next; int space_next; int len, dl, sp; wbuf_t wbufi_new; /* * Block straddles one or more mbufs, gather data * into the block buffer b, apply the cipher, then * scatter the results back into the mbuf chain. * The buffer will automatically get space bytes * of data at offset 0 copied in+out by the * CCMP_ENCRYPT request so we must take care of * the remaining data. */ wbuf_new = wbuf; dl = data_len; sp = space; for (;;) { pos_next = (u_int8_t *)wbuf_header(wbuf_new); len = min(dl, AES_BLOCK_LEN); space_next = len > sp ? len - sp : 0; if (wbuf_get_len(wbuf_new) >= space_next) { /* * This mbuf has enough data; just grab * what we need and stop. */ xor_block(b+sp, pos_next, space_next); break; } /* * This mbuf's contents are insufficient, * take 'em all and prepare to advance to * the next mbuf. */ xor_block(b+sp, pos_next, n->m_len); sp += wbuf_get_len(wbuf_new), dl -= wbuf_get_len(wbuf_new); wbuf_next = m_next; if (n == NULL) break; } CCMP_ENCRYPT(i, b, b0, pos, e, space); /* NB: just like above, but scatter data to mbufs */ dl = data_len; sp = space; for (;;) { pos_next = mtod(m, uint8_t *); len = min(dl, AES_BLOCK_LEN); space_next = len > sp ? len - sp : 0; if (m->m_len >= space_next) { xor_block(pos_next, e+sp, space_next); break; } xor_block(pos_next, e+sp, m->m_len); sp += m->m_len, dl -= m->m_len; m = m->m_next; if (m == NULL) goto done; } /* * Do bookkeeping. m now points to the last mbuf * we grabbed data from. We know we consumed a * full block of data as otherwise we'd have hit * the end of the mbuf chain, so deduct from data_len. * Otherwise advance the block number (i) and setup * pos+space to reflect contents of the new mbuf. */ data_len -= AES_BLOCK_LEN; i++; pos = pos_next + space_next; space = m->m_len - space_next; } else {