]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wlantest/tkip.c
Prepare for hostapd/wpa_supplicant v2.0 release
[thirdparty/hostap.git] / wlantest / tkip.c
index eb26dfa31143d33f522a3cd56184df677703b38f..ed3d60146b5160d57cfe210fa15c48ce074a1206 100644 (file)
@@ -2,14 +2,8 @@
  * Temporal Key Integrity Protocol (CCMP)
  * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
  */
 
 #include "utils/includes.h"
@@ -19,6 +13,9 @@
 #include "wlantest.h"
 
 
+void wep_crypt(u8 *key, u8 *buf, size_t plen);
+
+
 static inline u16 RotR1(u16 val)
 {
        return (val >> 1) | (val << 15);
@@ -172,35 +169,6 @@ static void tkip_mixing_phase2(u8 *WEPSeed, const u8 *TK, const u16 *TTAK,
 }
 
 
-static void wep_crypt(u8 *key, u8 *buf, size_t plen)
-{
-       u32 i, j, k;
-       u8 S[256];
-#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
-       u8 *pos;
-
-       /* Setup RC4 state */
-       for (i = 0; i < 256; i++)
-               S[i] = i;
-       j = 0;
-       for (i = 0; i < 256; i++) {
-               j = (j + S[i] + key[i & 0x0f]) & 0xff;
-               S_SWAP(i, j);
-       }
-
-       /* Apply RC4 to data */
-       pos = buf;
-       i = j = 0;
-       for (k = 0; k < plen; k++) {
-               i = (i + 1) & 0xff;
-               j = (j + S[i]) & 0xff;
-               S_SWAP(i, j);
-               *pos ^= S[(S[i] + S[j]) & 0xff];
-               pos++;
-       }
-}
-
-
 static inline u32 rotl(u32 val, int bits)
 {
        return (val << bits) | (val >> (32 - bits));
@@ -392,3 +360,69 @@ u8 * tkip_decrypt(const u8 *tk, const struct ieee80211_hdr *hdr,
        *decrypted_len = plain_len - 8;
        return plain;
 }
+
+
+void tkip_get_pn(u8 *pn, const u8 *data)
+{
+       pn[0] = data[7]; /* PN5 */
+       pn[1] = data[6]; /* PN4 */
+       pn[2] = data[5]; /* PN3 */
+       pn[3] = data[4]; /* PN2 */
+       pn[4] = data[0]; /* PN1 */
+       pn[5] = data[2]; /* PN0 */
+}
+
+
+u8 * tkip_encrypt(const u8 *tk, u8 *frame, size_t len, size_t hdrlen, u8 *qos,
+                 u8 *pn, int keyid, size_t *encrypted_len)
+{
+       u8 michael_hdr[16];
+       u8 mic[8];
+       struct ieee80211_hdr *hdr;
+       u16 fc;
+       const u8 *mic_key;
+       u8 *crypt, *pos;
+       u16 iv16;
+       u32 iv32;
+       u16 ttak[5];
+       u8 rc4key[16];
+
+       if (len < sizeof(*hdr) || len < hdrlen)
+               return NULL;
+       hdr = (struct ieee80211_hdr *) frame;
+       fc = le_to_host16(hdr->frame_control);
+
+       michael_mic_hdr(hdr, michael_hdr);
+       mic_key = tk + ((fc & WLAN_FC_FROMDS) ? 16 : 24);
+       michael_mic(mic_key, michael_hdr, frame + hdrlen, len - hdrlen, mic);
+       wpa_hexdump(MSG_EXCESSIVE, "TKIP: MIC", mic, sizeof(mic));
+
+       iv32 = WPA_GET_BE32(pn);
+       iv16 = WPA_GET_BE16(pn + 4);
+       tkip_mixing_phase1(ttak, tk, hdr->addr2, iv32);
+       wpa_hexdump(MSG_EXCESSIVE, "TKIP TTAK", (u8 *) ttak, sizeof(ttak));
+       tkip_mixing_phase2(rc4key, tk, ttak, iv16);
+       wpa_hexdump(MSG_EXCESSIVE, "TKIP RC4KEY", rc4key, sizeof(rc4key));
+
+       crypt = os_malloc(len + 8 + sizeof(mic) + 4);
+       if (crypt == NULL)
+               return NULL;
+       os_memcpy(crypt, frame, hdrlen);
+       pos = crypt + hdrlen;
+       os_memcpy(pos, rc4key, 3);
+       pos += 3;
+       *pos++ = keyid << 6 | BIT(5);
+       *pos++ = pn[3];
+       *pos++ = pn[2];
+       *pos++ = pn[1];
+       *pos++ = pn[0];
+
+       os_memcpy(pos, frame + hdrlen, len - hdrlen);
+       os_memcpy(pos + len - hdrlen, mic, sizeof(mic));
+       WPA_PUT_LE32(pos + len - hdrlen + sizeof(mic),
+                    crc32(pos, len - hdrlen + sizeof(mic)));
+       wep_crypt(rc4key, pos, len - hdrlen + sizeof(mic) + 4);
+
+       *encrypted_len = len + 8 + sizeof(mic) + 4;
+       return crypt;
+}