diff --git a/wlantest/ccmp.c b/wlantest/ccmp.c index f0d265ab3..d7a0e6584 100644 --- a/wlantest/ccmp.c +++ b/wlantest/ccmp.c @@ -175,3 +175,93 @@ u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos, return crypt; } + + +u8 * ccmp_256_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr, + const u8 *data, size_t data_len, size_t *decrypted_len) +{ + u8 aad[30], nonce[13]; + size_t aad_len; + size_t mlen; + u8 *plain; + + if (data_len < 8 + 16) + return NULL; + + plain = os_malloc(data_len + AES_BLOCK_SIZE); + if (plain == NULL) + return NULL; + + mlen = data_len - 8 - 16; + + os_memset(aad, 0, sizeof(aad)); + ccmp_aad_nonce(hdr, data, aad, &aad_len, nonce); + wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 AAD", aad, aad_len); + wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 nonce", nonce, 13); + + if (aes_ccm_ad(tk, 16, nonce, 16, data + 8, mlen, aad, aad_len, + data + 8 + mlen, plain) < 0) { + u16 seq_ctrl = le_to_host16(hdr->seq_ctrl); + wpa_printf(MSG_INFO, "Invalid CCMP-256 MIC in frame: A1=" MACSTR + " A2=" MACSTR " A3=" MACSTR " seq=%u frag=%u", + MAC2STR(hdr->addr1), MAC2STR(hdr->addr2), + MAC2STR(hdr->addr3), + WLAN_GET_SEQ_SEQ(seq_ctrl), + WLAN_GET_SEQ_FRAG(seq_ctrl)); + os_free(plain); + return NULL; + } + wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 decrypted", plain, mlen); + + *decrypted_len = mlen; + return plain; +} + + +u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, + u8 *qos, u8 *pn, int keyid, size_t *encrypted_len) +{ + u8 aad[30], nonce[13]; + size_t aad_len, plen; + u8 *crypt, *pos; + struct ieee80211_hdr *hdr; + + if (len < hdrlen || hdrlen < 24) + return NULL; + plen = len - hdrlen; + + crypt = os_malloc(hdrlen + 8 + plen + 16 + AES_BLOCK_SIZE); + if (crypt == NULL) + return NULL; + + os_memcpy(crypt, frame, hdrlen); + hdr = (struct ieee80211_hdr *) crypt; + hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP); + pos = crypt + hdrlen; + *pos++ = pn[5]; /* PN0 */ + *pos++ = pn[4]; /* PN1 */ + *pos++ = 0x00; /* Rsvd */ + *pos++ = 0x20 | (keyid << 6); + *pos++ = pn[3]; /* PN2 */ + *pos++ = pn[2]; /* PN3 */ + *pos++ = pn[1]; /* PN4 */ + *pos++ = pn[0]; /* PN5 */ + + os_memset(aad, 0, sizeof(aad)); + ccmp_aad_nonce(hdr, crypt + hdrlen, aad, &aad_len, nonce); + wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 AAD", aad, aad_len); + wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 nonce", nonce, 13); + + if (aes_ccm_ae(tk, 16, nonce, 16, frame + hdrlen, plen, aad, aad_len, + pos, pos + plen) < 0) { + os_free(crypt); + return NULL; + } + + wpa_hexdump(MSG_EXCESSIVE, "CCMP-256 encrypted", crypt + hdrlen + 8, + plen); + + *encrypted_len = hdrlen + 8 + plen + 16; + + return crypt; +} diff --git a/wlantest/test_vectors.c b/wlantest/test_vectors.c index 6a0283d3c..968ce9932 100644 --- a/wlantest/test_vectors.c +++ b/wlantest/test_vectors.c @@ -350,6 +350,64 @@ static void test_vector_gcmp_256(void) } +static void test_vector_ccmp_256(void) +{ + u8 tk[] = { 0xc9, 0x7c, 0x1f, 0x67, 0xce, 0x37, 0x11, 0x85, + 0x51, 0x4a, 0x8a, 0x19, 0xf2, 0xbd, 0xd5, 0x2f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; + u8 pn[] = { 0xB5, 0x03, 0x97, 0x76, 0xE7, 0x0C }; + u8 frame[] = { + 0x08, 0x48, 0xc3, 0x2c, 0x0f, 0xd2, 0xe1, 0x28, + 0xa5, 0x7c, 0x50, 0x30, 0xf1, 0x84, 0x44, 0x08, + 0xab, 0xae, 0xa5, 0xb8, 0xfc, 0xba, 0x80, 0x33, + 0xf8, 0xba, 0x1a, 0x55, 0xd0, 0x2f, 0x85, 0xae, + 0x96, 0x7b, 0xb6, 0x2f, 0xb6, 0xcd, 0xa8, 0xeb, + 0x7e, 0x78, 0xa0, 0x50 + }; + u8 *enc, *plain; + size_t enc_len, plain_len; + u8 fcs[4]; + + wpa_printf(MSG_INFO, "\nCCMP-256 test vector\n"); + + wpa_hexdump(MSG_INFO, "TK", tk, sizeof(tk)); + wpa_hexdump(MSG_INFO, "PN", pn, sizeof(pn)); + wpa_hexdump(MSG_INFO, "802.11 Header", frame, 24); + wpa_hexdump(MSG_INFO, "Plaintext Data", frame + 24, sizeof(frame) - 24); + + enc = ccmp_256_encrypt(tk, frame, sizeof(frame), 24, NULL, pn, 0, + &enc_len); + if (enc == NULL) { + wpa_printf(MSG_ERROR, "Failed to encrypt CCMP frame"); + return; + } + + wpa_hexdump(MSG_INFO, "Encrypted MPDU (without FCS)", enc, enc_len); + WPA_PUT_LE32(fcs, crc32(enc, enc_len)); + wpa_hexdump(MSG_INFO, "FCS", fcs, sizeof(fcs)); + + wpa_debug_level = MSG_INFO; + plain = ccmp_256_decrypt(tk, (const struct ieee80211_hdr *) enc, + enc + 24, enc_len - 24, &plain_len); + wpa_debug_level = MSG_EXCESSIVE; + os_free(enc); + + if (plain == NULL) { + wpa_printf(MSG_ERROR, "Failed to decrypt CCMP-256 frame"); + return; + } + + if (plain_len != sizeof(frame) - 24 || + os_memcmp(plain, frame + 24, plain_len) != 0) { + wpa_hexdump(MSG_ERROR, "Decryption result did not match", + plain, plain_len); + } + + os_free(plain); +} + + int main(int argc, char *argv[]) { wpa_debug_level = MSG_EXCESSIVE; @@ -364,6 +422,7 @@ int main(int argc, char *argv[]) test_vector_ccmp_mgmt(); test_vector_gcmp(); test_vector_gcmp_256(); + test_vector_ccmp_256(); os_program_deinit(); diff --git a/wlantest/wlantest.h b/wlantest/wlantest.h index a2a0a6245..a8db20b99 100644 --- a/wlantest/wlantest.h +++ b/wlantest/wlantest.h @@ -227,6 +227,10 @@ u8 * ccmp_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr, u8 * ccmp_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos, u8 *pn, int keyid, size_t *encrypted_len); void ccmp_get_pn(u8 *pn, const u8 *data); +u8 * ccmp_256_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr, + const u8 *data, size_t data_len, size_t *decrypted_len); +u8 * ccmp_256_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, + u8 *qos, u8 *pn, int keyid, size_t *encrypted_len); u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr, const u8 *data, size_t data_len, size_t *decrypted_len);