//! Exports captured WPA/WPA2 material in hashcat `.hc22000` format (`-m 22000`). //! //! Emits both record types supported by `hcxtools` / `hashcat`: //! //! * `WPA*01*PMKID*AP*STA*SSID***` //! * `WPA*02*MIC*AP*STA*SSID*ANONCE*EAPOL*MESSAGEPAIR` //! //! The exported EAPOL field contains the full message 2 frame (802.1X header + //! key descriptor) expected by hashcat's `EAPOL_CLIENT` field. use crate::eapol::MIC_OFFSET; use crate::handshake::Handshake; fn mac_hex(mac: &str) -> Option { let bytes: Vec = mac .split(':') .map(|part| part.trim().to_ascii_lowercase()) .collect(); if bytes.len() != 6 || !bytes .iter() .all(|b| b.len() == 2 && b.chars().all(|c| c.is_ascii_hexdigit())) { return None; } Some(bytes.concat()) } fn ssid_hex(ssid: &str) -> String { ssid.as_bytes().iter().map(|b| format!("{b:02x}")).collect() } fn hex(bytes: &[u8]) -> String { bytes.iter().map(|b| format!("{b:02x}")).collect() } pub fn hashcat_line(hs: &Handshake) -> Option { let ssid = hs.ssid.as_deref().filter(|s| !s.is_empty())?; let ap = mac_hex(&hs.bssid)?; let sta = mac_hex(&hs.station)?; let ssid = ssid_hex(ssid); if let Some(pmkid) = hs.pmkid { return Some(format!("WPA*01*{}*{ap}*{sta}*{ssid}***", hex(&pmkid))); } let eapol = hs.eapol_msg2.as_deref()?; let anonce = hs.anonce?; let mic = eapol.get(MIC_OFFSET..MIC_OFFSET + 16)?; Some(format!( "WPA*02*{}*{ap}*{sta}*{ssid}*{}*{}*00", hex(mic), hex(&anonce), hex(eapol), )) } /// Formats deduplicated `.hc22000` lines for all crackable handshakes. pub fn export<'a>(handshakes: impl IntoIterator) -> Vec { let mut lines: Vec = handshakes.into_iter().filter_map(hashcat_line).collect(); lines.sort(); lines.dedup(); lines } #[cfg(test)] mod tests { use super::*; use crate::handshake::Handshake; #[test] fn exports_pmkid_line() { let hs = Handshake { bssid: "00:11:22:33:44:55".into(), station: "66:77:88:99:aa:bb".into(), ssid: Some("Casa".into()), pmkid: Some([0xcd; 16]), ..Default::default() }; let line = hashcat_line(&hs).expect("linha"); assert_eq!( line, "WPA*01*cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd*001122334455*66778899aabb*43617361***" ); } }