//! Integration test: synthetic handshake -> `CrackTarget` -> `verify()` and //! dictionary cracking across both EAPOL 4-way and PMKID modes. //! mod common; use sabia_core::crack::{compute_mic, compute_pmkid, compute_ptk, derive_pmk, CrackTarget}; const BSSID: &str = "00:11:22:33:44:55"; const STATION: &str = "66:77:88:99:aa:bb"; #[test] fn eapol_4way_roundtrip_verifies_password() { let (m1, m2) = common::handshake_frames("MinhaRede", "senha-correta", 2, false); let hs = common::synthetic_handshake("MinhaRede", BSSID, STATION, &m1, &m2); let target = CrackTarget::from_handshake(&hs).expect("alvo EAPOL válido"); assert_eq!(target.method(), "EAPOL/CCMP"); assert!(target.verify("senha-correta")); assert!(!target.verify("senha-errada")); } #[test] fn pmkid_roundtrip_verifies_password() { let (m1, _m2) = common::handshake_frames("MinhaRede", "senha-correta", 2, true); let hs = common::synthetic_handshake("MinhaRede", BSSID, STATION, &m1, &[]); let target = CrackTarget::from_handshake(&hs).expect("alvo PMKID válido"); assert_eq!(target.method(), "PMKID"); assert!(target.verify("senha-correta")); assert!(!target.verify("senha-errada")); } #[test] fn tkip_keyversion_roundtrip_verifies_password() { let (m1, m2) = common::handshake_frames("RedeAntiga", "outra-senha", 1, false); let hs = common::synthetic_handshake("RedeAntiga", BSSID, STATION, &m1, &m2); let target = CrackTarget::from_handshake(&hs).expect("alvo EAPOL/TKIP válido"); assert_eq!(target.method(), "EAPOL/TKIP"); assert!(target.verify("outra-senha")); assert!(!target.verify("senha-errada")); } #[test] fn incomplete_handshake_without_pmkid_or_msg2_has_no_target() { let (m1, _m2) = common::handshake_frames("MinhaRede", "senha-correta", 2, false); // Without message 2 or a PMKID, the handshake is not yet crackable. let hs = common::synthetic_handshake("MinhaRede", BSSID, STATION, &m1, &[]); assert!(CrackTarget::from_handshake(&hs).is_none()); } #[test] fn derive_pmk_compute_ptk_and_mic_are_consistent() { let ssid = "VetorDireto"; let password = "senha-direta"; let anonce = [0xaa; 32]; let snonce = [0xbb; 32]; let pmk = derive_pmk(password, ssid); let ptk = compute_ptk(&pmk, &common::ap(), &common::sta(), &anonce, &snonce); // Compute the MIC over a message 2 frame with its MIC field zeroed. let mut m2 = common::key_frame(2, 2, snonce, &[]); let mic = compute_mic(2, &ptk[..16], &m2, sabia_core::eapol::MIC_OFFSET).expect("mic"); m2[sabia_core::eapol::MIC_OFFSET..sabia_core::eapol::MIC_OFFSET + 16].copy_from_slice(&mic); // Recomputing the MIC over the already-signed frame must yield the same digest // (`compute_mic` zeroes the MIC slice before hashing). let mic_again = compute_mic(2, &ptk[..16], &m2, sabia_core::eapol::MIC_OFFSET).expect("mic"); assert_eq!(mic, mic_again); // Direct PMKID computation is deterministic and verifies via `CrackTarget::Pmkid`. let pmkid = compute_pmkid(&pmk, &common::ap(), &common::sta()); assert_eq!( pmkid, compute_pmkid(&pmk, &common::ap(), &common::sta()), "PMKID deve ser determinístico" ); }