如何用Python计算消息完整性码(MIC)?WPA2四次握手消息2失败的MIC计算问题排查
It sounds like you're hitting some common pitfalls with WPA2's PTK/MIC calculation—let's walk through the likely issues in your code and fix them step by step.
1. Critical Binary vs. String Confusion (The Biggest Culprit)
Your code is treating keys and packet data as ASCII strings, but WPA2 relies entirely on binary data for all cryptographic operations. This is almost certainly causing incorrect calculations.
Example Fixes:
PMK Generation
Ensure your passphrase and SSID are passed as bytes to PBKDF2, and keep the PMK as binary (not a string):
import hmac import hashlib from pbkdf2 import PBKDF2 import struct # Convert passphrase and SSID to bytes first psk = "your_wifi_password" ssid = "your_wifi_ssid" pmk = PBKDF2(psk.encode('utf-8'), ssid.encode('utf-8'), iterations=4096).read(32) # 32-byte binary PMK
Note: Yes, WPA2 requires exactly 4096 iterations for PBKDF2—your iteration count is correct here.
PRF-384 Implementation
Your current PRF code uses string concatenation and hex digests, which mangles the binary data. Here's the correct binary-focused implementation:
def customPRF384(key, A, B): blen = 48 # 384 bits = 48 bytes i = 0 R = b'' # Store result as binary bytes, not a string # Calculate how many HMAC-SHA1 rounds we need while i <= ((blen * 8 + 159) // 160): # Construct input as binary: A + 0x00 + B + 1-byte counter i hmac_input = A + b'\x00' + B + struct.pack('B', i) hmac_sha1 = hmac.new(key, hmac_input, hashlib.sha1) R += hmac_sha1.digest() # Append binary digest, not hex string i += 1 return R[:blen] # Return first 48 bytes of the concatenated digests
2. Incorrect Key Data Construction
You're using string comparisons for MAC addresses and nonces, but you need to compare their binary values instead. String dictionary order doesn't match binary byte order, which will produce the wrong key_data.
Fix for Key Data:
# Convert MAC addresses from string (e.g., "aa:bb:cc:dd:ee:ff") to binary bytes mac_ap = "00:11:22:33:44:55" mac_cl = "aa:bb:cc:dd:ee:ff" mac_ap_bytes = bytes.fromhex(mac_ap.replace(':', '')) mac_cl_bytes = bytes.fromhex(mac_cl.replace(':', '')) # Compare binary values to get min/max mac_min = min(mac_ap_bytes, mac_cl_bytes) mac_max = max(mac_ap_bytes, mac_cl_bytes) # Same for nonces (convert hex strings from handshake to binary) anonce_hex = "abcdef123456..." # From message 1 snonce_hex = "fedcba654321..." # From message 2 anonce_bytes = bytes.fromhex(anonce_hex) snonce_bytes = bytes.fromhex(snonce_hex) nonce_min = min(anonce_bytes, snonce_bytes) nonce_max = max(anonce_bytes, snonce_bytes) # Build key_data as binary concatenation key_data = mac_min + mac_max + nonce_min + nonce_max
3. Wrong KCK Extraction & MIC Calculation
Your code takes the first 16 characters of the PTK hex string (which is 8 bytes) and encodes it as ASCII—this is completely wrong. The KCK (Key Confirmation Key) is the first 16 bytes of the binary PTK (32 hex characters).
Fix for MIC Calculation:
# Generate binary PTK pke = b"Pairwise key expansion" # Fixed string as bytes ptk = customPRF384(pmk, pke, key_data) # 48-byte binary PTK kck = ptk[:16] # Extract first 16 bytes for KCK # Prepare payload: Replace MIC field in the 802.1X packet with 16 bytes of 0x00 # You'll need to find the offset of the MIC field in your captured payload (binary) mic_offset = 100 # Example offset—adjust based on your packet structure payload = b"your_captured_message_2_binary" # Raw packet data from handshake payload_with_zero_mic = payload[:mic_offset] + b'\x00'*16 + payload[mic_offset+16:] # Calculate MIC: HMAC-SHA1 of the zeroed payload, take first 16 bytes (32 hex chars) calculated_mic = hmac.new(kck, payload_with_zero_mic, hashlib.sha1).digest()[:16].hex()
Final Checks to Verify
- Double-check that your captured payload includes the entire 802.1X header and body, with the MIC field correctly replaced by 16 null bytes.
- Ensure nonces and MAC addresses are exactly as captured from the handshake (no extra characters or missing bytes).
- Confirm that the PTK is 48 bytes long (binary) before extracting the KCK.
内容的提问来源于stack exchange,提问作者Gfddre

