chore(i18n): finish translating code comments and scripts to English
CI / Format and clippy (push) Successful in 1m13s
CI / Dependency audit (push) Successful in 13s
CI / Tests (Linux) (push) Successful in 1m35s
Release / Create release (push) Successful in 7s
CI / Check desktop app (Linux) (push) Successful in 3m19s
Release / CLI (linux-aarch64) (push) Successful in 1m3s
Release / CLI (linux-x86_64) (push) Successful in 1m28s
Release / Desktop app (linux-aarch64) (push) Successful in 7m16s
Release / Desktop app (linux-x86_64) (push) Successful in 10m17s
Release / Desktop app (windows) (push) Successful in 4m54s
CI / Format and clippy (push) Successful in 1m13s
CI / Dependency audit (push) Successful in 13s
CI / Tests (Linux) (push) Successful in 1m35s
Release / Create release (push) Successful in 7s
CI / Check desktop app (Linux) (push) Successful in 3m19s
Release / CLI (linux-aarch64) (push) Successful in 1m3s
Release / CLI (linux-x86_64) (push) Successful in 1m28s
Release / Desktop app (linux-aarch64) (push) Successful in 7m16s
Release / Desktop app (linux-x86_64) (push) Successful in 10m17s
Release / Desktop app (windows) (push) Successful in 4m54s
Completes the English-only standardization for code, comments, scripts and CI templates (UI/CLI-facing strings stay bilingual pt-BR/en, untouched). Covers the remaining crates/, apps/gui/ui/ and apps/gui/src-tauri/ comments, .gitea/ workflow and template comments, .githooks/ hooks, and the scripts/ source comments for the files already renamed in a prior commit (check.sh, generate-logo.py, install-hooks.sh). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
This commit is contained in:
1 parent
bf059fd0bc
commit
55e19a8e5b
59 files changed
+935
-879
No files matched your search
@@ -1,6 +1,6 @@
|
||||
//! Integração: trilha de auditoria encadeada por hash — grava entradas,
|
||||
//! confirma que a cadeia valida, depois adultera um registro no disco e
|
||||
//! confirma que a verificação detecta a falha.
|
||||
//! Integration test: hash-chained audit trail — appends entries, verifies
|
||||
//! chain integrity, then tampers with a middle record on disk and confirms
|
||||
//! verification pinpoints the corrupted entry.
|
||||
|
||||
mod common;
|
||||
|
||||
@@ -26,7 +26,7 @@ fn chain_validates_after_recording_entries() {
|
||||
assert_eq!(entries.len(), 3);
|
||||
assert_eq!(entries[0].action, "monitor-on");
|
||||
assert_eq!(entries[2].action, "deauth");
|
||||
// cadeia encadeada corretamente
|
||||
// each entry's `prev_hash` matches the preceding entry's `hash`
|
||||
assert_eq!(entries[1].prev_hash, entries[0].hash);
|
||||
assert_eq!(entries[2].prev_hash, entries[1].hash);
|
||||
|
||||
@@ -52,11 +52,11 @@ fn tampering_with_an_entry_breaks_verification() {
|
||||
.expect("record 3");
|
||||
}
|
||||
|
||||
// Confirma que, intacta, a cadeia passa.
|
||||
// Intact chain verifies cleanly.
|
||||
assert_eq!(AuditLog::verify(&path).expect("verify ok"), None);
|
||||
|
||||
// Adultera o "detail" da segunda entrada sem recalcular o hash,
|
||||
// simulando uma edição retroativa do log.
|
||||
// Tamper with the second entry's `detail` field without recomputing its hash.
|
||||
//
|
||||
let contents = std::fs::read_to_string(&path).expect("read");
|
||||
let mut lines: Vec<String> = contents.lines().map(|l| l.to_string()).collect();
|
||||
assert_eq!(lines.len(), 3);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#![allow(dead_code)]
|
||||
//! Helpers de teste de integração: quadros 802.11/EAPOL sintéticos,
|
||||
//! radiotap e handshakes válidos gerados a partir de uma senha conhecida.
|
||||
//! Integration-test helpers: synthetic Radiotap/802.11/EAPOL frames and
|
||||
//! valid 4-way handshakes generated from a known passphrase.
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//! Porta a lógica de `crates/sabia-core/src/testutil.rs` (que só existe em
|
||||
//! `#[cfg(test)]` e por isso não fica visível aqui), usando só a API
|
||||
//! pública de `sabia_core`.
|
||||
|
||||
use sabia_core::crack::{compute_mic, compute_pmkid, compute_ptk, derive_pmk};
|
||||
use sabia_core::dot11;
|
||||
@@ -58,11 +58,11 @@ pub fn frame_with_eapol(
|
||||
f.extend_from_slice(&fc.to_le_bytes());
|
||||
f.extend_from_slice(&0u16.to_le_bytes());
|
||||
if from_ap {
|
||||
f.extend_from_slice(&sta); // addr1 = destino
|
||||
f.extend_from_slice(&sta); // addr1 = destination
|
||||
f.extend_from_slice(&ap); // addr2 = BSSID
|
||||
} else {
|
||||
f.extend_from_slice(&ap); // addr1 = BSSID
|
||||
f.extend_from_slice(&sta); // addr2 = origem
|
||||
f.extend_from_slice(&sta); // addr2 = source
|
||||
}
|
||||
f.extend_from_slice(&da);
|
||||
f.extend_from_slice(&[0u8; 2]);
|
||||
@@ -160,7 +160,7 @@ pub fn data_frame(
|
||||
f
|
||||
}
|
||||
|
||||
/// Gera (msg1, msg2) válidas para a senha informada, com MIC correto.
|
||||
/// Generates a valid `(msg1, msg2)` EAPOL-Key pair with a verified MIC for `passphrase`.
|
||||
pub fn handshake_frames(
|
||||
ssid: &str,
|
||||
password: &str,
|
||||
@@ -184,8 +184,8 @@ pub fn handshake_frames(
|
||||
(m1, m2)
|
||||
}
|
||||
|
||||
/// Monta quadros radiotap+802.11 completos (prontos para `ScanTable::ingest`)
|
||||
/// com o 4-way handshake entre `AP` e `STA` para o SSID/senha dados.
|
||||
/// Builds complete Radiotap + 802.11 frames (ready for `ScanTable::ingest`)
|
||||
/// carrying the 4-way handshake between `AP` and `STA` for `ssid`/`passphrase`.
|
||||
pub fn handshake_radiotap_frames(
|
||||
ssid: &str,
|
||||
password: &str,
|
||||
@@ -198,8 +198,8 @@ pub fn handshake_radiotap_frames(
|
||||
(radiotap_wrap(&f1, 2437, -40), radiotap_wrap(&f2, 2437, -42))
|
||||
}
|
||||
|
||||
/// Monta um `Handshake` diretamente dos quadros EAPOL, para testes de quebra
|
||||
/// sem depender do pipeline de captura.
|
||||
/// Assembles a `Handshake` directly from synthetic EAPOL frames for cracking tests.
|
||||
///
|
||||
pub fn synthetic_handshake(
|
||||
ssid: &str,
|
||||
bssid: &str,
|
||||
@@ -233,7 +233,7 @@ pub fn synthetic_handshake(
|
||||
password: None,
|
||||
tk: None,
|
||||
};
|
||||
// Exercita o parser de MAC do alvo.
|
||||
// Exercises MAC address parsing.
|
||||
assert!(dot11::parse_mac(&hs.bssid).is_some());
|
||||
assert!(dot11::parse_mac(&hs.station).is_some());
|
||||
hs
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! 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.
|
||||
//! Integration test: synthetic handshake -> `CrackTarget` -> `verify()` and
|
||||
//! dictionary cracking across both EAPOL 4-way and PMKID modes.
|
||||
//!
|
||||
|
||||
mod common;
|
||||
|
||||
@@ -45,7 +45,7 @@ fn tkip_keyversion_roundtrip_verifies_password() {
|
||||
#[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.
|
||||
// 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());
|
||||
}
|
||||
@@ -60,17 +60,17 @@ fn derive_pmk_compute_ptk_and_mic_are_consistent() {
|
||||
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.
|
||||
// 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);
|
||||
|
||||
// Recalculando o MIC sobre o quadro já preenchido deve bater de novo
|
||||
// (compute_mic zera o campo internamente antes de recalcular).
|
||||
// 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);
|
||||
|
||||
// PMKID direto também deve ser determinístico e usável no verify().
|
||||
// Direct PMKID computation is deterministic and verifies via `CrackTarget::Pmkid`.
|
||||
let pmkid = compute_pmkid(&pmk, &common::ap(), &common::sta());
|
||||
assert_eq!(
|
||||
pmkid,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Integração: grava quadros com `PcapWriter`, lê de volta com
|
||||
//! `PcapReader` e confere que batem byte a byte; depois confirma que
|
||||
//! `Engine::analyze_pcap` encontra redes e handshakes no arquivo recém-escrito.
|
||||
//! Integration test: writes frames with `PcapWriter`, reads them back with
|
||||
//! `PcapReader`, and verifies `Engine::analyze_pcap` reconstructs the AP and handshake.
|
||||
//!
|
||||
|
||||
mod common;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Integração: beacon + probe + handshake completo passando pelo caminho
|
||||
//! público de agregação (`ScanTable`), verificando que AP, cliente e
|
||||
//! handshake são detectados de ponta a ponta.
|
||||
//! End-to-end integration test: ingests beacon, probe, and 4-way handshake
|
||||
//! frames into `ScanTable` and verifies AP, client, handshake, and live CCMP
|
||||
//! data frame decryption.
|
||||
|
||||
mod common;
|
||||
|
||||
@@ -10,7 +10,7 @@ use sabia_core::scan::ScanTable;
|
||||
fn detects_ap_client_and_handshake_end_to_end() {
|
||||
let mut table = ScanTable::new();
|
||||
|
||||
// RSN com AKM PSK (2) para que a rede apareça como WPA2-PSK.
|
||||
// Include an RSN IE with PSK AKM (2) so the AP is classified as WPA2-PSK.
|
||||
let beacon = common::beacon_frame(common::ap(), "RedeTeste", 6, &[2]);
|
||||
table.ingest(&common::radiotap_wrap(&beacon, 2437, -35));
|
||||
|
||||
@@ -58,7 +58,7 @@ fn detects_ap_client_and_handshake_end_to_end() {
|
||||
fn hidden_ssid_beacon_is_marked_hidden() {
|
||||
let mut table = ScanTable::new();
|
||||
|
||||
// SSID vazio = rede oculta.
|
||||
// Empty 0-length SSID IE = hidden network.
|
||||
let beacon = common::beacon_frame(common::ap(), "", 11, &[2]);
|
||||
table.ingest(&common::radiotap_wrap(&beacon, 2462, -60));
|
||||
|
||||
@@ -67,11 +67,11 @@ fn hidden_ssid_beacon_is_marked_hidden() {
|
||||
assert!(aps[0].hidden);
|
||||
}
|
||||
|
||||
/// Depois que a senha de uma rede WPA2/CCMP é conhecida (quebrada), o
|
||||
/// tráfego de dados do cliente cujo handshake foi capturado passa a ser
|
||||
/// decifrado em tempo real pelo pipeline de ingestão — e a identidade
|
||||
/// (aqui, o IP de origem, que exercita o parser de IPv4 por trás do LLC)
|
||||
/// aparece mesmo com o bit "Protected" ligado.
|
||||
/// Once a WPA2/CCMP handshake has been cracked, subsequent protected QoS Data
|
||||
/// frames from that station are decrypted on the fly using its derived TK to
|
||||
/// populate client identity fields (such as its IPv4 address).
|
||||
///
|
||||
///
|
||||
#[test]
|
||||
fn decrypts_ccmp_traffic_once_password_is_known_and_fills_client_identity() {
|
||||
use sabia_core::crack::{compute_ptk, derive_pmk};
|
||||
@@ -91,8 +91,8 @@ fn decrypts_ccmp_traffic_once_password_is_known_and_fills_client_identity() {
|
||||
let station_str = sabia_core::dot11::mac_to_string(&common::sta());
|
||||
table.set_password(&bssid_str, &station_str, password);
|
||||
|
||||
// A TK derivada pelo pipeline tem que bater com a calculada à parte, com
|
||||
// os mesmos nonces fixos (0xaa/0xbb) que handshake_radiotap_frames usa.
|
||||
// The pipeline-derived TK must match the TK computed directly from the same nonces.
|
||||
//
|
||||
let anonce = [0xaa; 32];
|
||||
let snonce = [0xbb; 32];
|
||||
let pmk = derive_pmk(password, ssid);
|
||||
@@ -107,16 +107,16 @@ fn decrypts_ccmp_traffic_once_password_is_known_and_fills_client_identity() {
|
||||
"TK deveria ser derivada ao quebrar a senha"
|
||||
);
|
||||
|
||||
// Monta um quadro QoS Data, STA->AP, protegido, com CCMP header (PN=1,
|
||||
// ExtIV ligado) e cifra um payload LLC/SNAP+IPv4 "na mão" — o CTR do
|
||||
// CCMP é simétrico, então usar decrypt_data pra cifrar é válido aqui.
|
||||
// Build a protected STA->AP QoS Data frame (CCMP PN=1, ExtIV=1) carrying an
|
||||
// encrypted LLC/SNAP + IPv4 packet.
|
||||
//
|
||||
let llc_ipv4 = {
|
||||
let mut v = vec![0xAA, 0xAA, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00];
|
||||
let mut ip = vec![
|
||||
0x45, 0x00, 0x00, 20, 0x00, 0x00, 0x00, 0x00, 64, 17, 0x00, 0x00,
|
||||
];
|
||||
ip.extend_from_slice(&[192, 168, 1, 50]); // origem privada
|
||||
ip.extend_from_slice(&[192, 168, 1, 1]); // destino
|
||||
ip.extend_from_slice(&[192, 168, 1, 50]); // private source IPv4
|
||||
ip.extend_from_slice(&[192, 168, 1, 1]); // destination IPv4
|
||||
v.extend_from_slice(&ip);
|
||||
v
|
||||
};
|
||||
@@ -124,22 +124,22 @@ fn decrypts_ccmp_traffic_once_password_is_known_and_fills_client_identity() {
|
||||
let mut to_cipher = Vec::new();
|
||||
to_cipher.extend_from_slice(&ccmp_header);
|
||||
to_cipher.extend_from_slice(&llc_ipv4);
|
||||
to_cipher.extend_from_slice(&[0u8; 8]); // placeholder pro MIC, ignorado
|
||||
to_cipher.extend_from_slice(&[0u8; 8]); // 8-byte MIC placeholder
|
||||
let ciphertext = sabia_core::ccmp::decrypt_data(&expected_tk, &common::sta(), 0, &to_cipher)
|
||||
.expect("cifra via CTR simétrico");
|
||||
|
||||
let mut body = Vec::new();
|
||||
body.extend_from_slice(&ccmp_header);
|
||||
body.extend_from_slice(&ciphertext);
|
||||
body.extend_from_slice(&[0u8; 8]); // MIC cifrado — não conferido na decriptação
|
||||
body.extend_from_slice(&[0u8; 8]); // trailing 8-byte MIC
|
||||
|
||||
let mut frame = Vec::new();
|
||||
let fc: u16 = 0x0088 | 0x0100 | 0x4000; // QoS Data, to_ds, protected
|
||||
frame.extend_from_slice(&fc.to_le_bytes());
|
||||
frame.extend_from_slice(&0u16.to_le_bytes()); // duration
|
||||
frame.extend_from_slice(&common::ap()); // addr1 = BSSID
|
||||
frame.extend_from_slice(&common::sta()); // addr2 = transmissor (estação)
|
||||
frame.extend_from_slice(&common::ap()); // addr3 = destino (irrelevante aqui)
|
||||
frame.extend_from_slice(&common::sta()); // addr2 = transmitter (station)
|
||||
frame.extend_from_slice(&common::ap()); // addr3 = destination
|
||||
frame.extend_from_slice(&[0u8; 2]); // sequence control
|
||||
frame.extend_from_slice(&[0u8; 2]); // QoS control, TID 0
|
||||
frame.extend_from_slice(&body);
|
||||
@@ -163,11 +163,11 @@ fn decrypts_ccmp_traffic_once_password_is_known_and_fills_client_identity() {
|
||||
fn pmkid_only_handshake_is_detected_and_crackable() {
|
||||
let mut table = ScanTable::new();
|
||||
|
||||
// Beacon com SSID visível, para que o handshake herde o SSID via hint.
|
||||
// Beacon with visible SSID so the PMKID handshake inherits the SSID hint.
|
||||
let beacon = common::beacon_frame(common::ap(), "RedePmkid", 11, &[2]);
|
||||
table.ingest_at(&common::radiotap_wrap(&beacon, 2462, -60), 1);
|
||||
|
||||
// Handshake via PMKID (só msg1, sem msg2/snonce).
|
||||
// PMKID-only handshake (message 1 with PMKID KDE, no message 2).
|
||||
let (m1, _m2) = common::handshake_frames("RedePmkid", "outra-senha", 2, true);
|
||||
let f1 = common::frame_with_eapol(true, common::ap(), common::sta(), common::sta(), &m1);
|
||||
let ev = table.ingest_at(&common::radiotap_wrap(&f1, 2462, -55), 20);
|
||||
|
||||
Reference in new issue
Block a user