v0.1.0: logo, i18n pt/en, CI com caches, testes e documentação

- Logo oficial (sabia.png) e conjunto de ícones do app desktop.
- Interface em português e inglês: tradutor por observação do DOM, seletor
  de idioma e checagem de cobertura de tradução no CI.
- CI/CD com caches (rust-cache, .deb do Tauri em cache) e pipeline de release
  multiplataforma (CLI em 5 alvos + app desktop via tauri-action), templates
  de issue/PR.
- Suíte de testes de integração do sabia-core (scan e2e, handshake/crack
  4-way e PMKID, pcap, trilha de auditoria) — 46 testes verdes.
- Documentação completa pt/en: README, ROADMAP, SECURITY, CONTRIBUTING,
  CHANGELOG e docs/ (cli, interface, arquitetura), com enquadramento de uso
  autorizado.
- Correções de clippy (-D warnings) e formatação em toda a árvore.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas RayanandClaude Opus 5.5 committed 2026-10-23 12:46:19 -03:00
1 parent df27974359
commit 791538c9d9
112 files changed
+15620 -494

No files matched your search

@@ -0,0 +1,80 @@
//! Integração: handshake sintético (gerado com senha conhecida) -> montagem
//! de `CrackTarget` -> `verify()`, para os dois métodos (EAPOL 4-way e
//! PMKID), cobrindo senha certa e errada.
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);
// Sem msg2 e sem PMKID: não há prova suficiente para quebrar.
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);
// MIC calculado sobre um quadro msg2 qualquer, zerando o campo MIC antes.
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);
// Recalculando o MIC sobre o quadro já preenchido deve bater de novo
// (compute_mic zera o campo internamente antes de recalcular).
let mic_again = compute_mic(2, &ptk[..16], &m2, sabia_core::eapol::MIC_OFFSET).expect("mic");
assert_eq!(mic, mic_again);
// PMKID direto também deve ser determinístico e usável no verify().
let pmkid = compute_pmkid(&pmk, &common::ap(), &common::sta());
assert_eq!(
pmkid,
compute_pmkid(&pmk, &common::ap(), &common::sta()),
"PMKID deve ser determinístico"
);
}