docs: mark the crypto layer (primitives + psk + ecies) complete
ober
a9d2b02e7da13169f15c7d64e0202ae9b56d4529
--- a/README.md +++ b/README.md @@ -120,8 +120,9 @@ then crypto orchestration, then I/O / async / FFI (monitors, server, storage). | `psk::constant_time_eq` | `typed/psk.ss` | ✅ ported, vectors pass | | `psk::from_hex` (hex codec) | `typed/psk.ss` | ✅ hex encode + decode + 32-byte precondition; vectors pass (decode∘encode identity over all 256 byte values) | | `stealth::obfuscate` (compile-time string XOR) | `typed/obfuscate.ss` | ✅ **typed kernel** — keeps sensitive strings out of the binary in plaintext. Lowers secmon's `obfuscate!`/`obfuscate_bytes!` scheme: length-derived wrapping-u8 key (`len*31+42` / `len*37+13`) + XOR. Since XOR preserves length, decode recomputes the key from the buffer — a clean involutive pair, no stored key. `make test` reproduces secmon's `test_obfuscate_roundtrip` + `test_obfuscated_not_plaintext` plus key-derivation and all-256-byte round-trip vectors. | -| `psk` HKDF/SHA256/AES-GCM | — | ⏳ FFI-delegated to vetted crates (not reimplemented) | -| `crypto::ecies` | — | ⏳ FFI-delegated; orchestration only | +| `crypto` primitives (SHA256/HMAC/HKDF/x25519/AES-256-GCM) | `typed/crypto.ss` | ✅ **typed kernel** — FFI-delegated to vetted RustCrypto crates (sha2/hmac/hkdf/x25519-dalek/aes-gcm), never reimplemented; the backend emits the `use … ;` block per primitive and content-scans the Cargo deps. Vector-verified against NIST SP 800-38D GCM, RFC 7748/5869/4231, FIPS 180-4 (`make test`). | +| `psk` key-derivation + proof + transport (`from_bytes`, `compute_proof`, `encrypt_transport`) | `typed/psk.ss` + `jsecmon/crypto-psk.ss` | ✅ **typed kernel + untyped orchestration** — HKDF-derived auth/transport keys, the SHA256 challenge proof + constant-time `verify_proof`, and AES-256-GCM transport (12-byte nonce prepended) are typed kernels (`make test`); `(jsecmon crypto-psk)` adds the effects they omit — `transport-encrypt` draws a random nonce, `generate-challenge`/`respond-to-challenge`/`verify-response` add the random challenge nonce + clock + freshness check (`now` injected for testability). `make crypto-psk-check` pins the FFI path to the `psk_vectors.rs` digests then exercises round-trip / randomization / tamper→#f / wrong-key→#f / stale→#f. | +| `crypto::ecies` (x25519 ECDH + HKDF + AES-GCM) | `typed/ecies.ss` + `jsecmon/crypto-ecies.ss` | ✅ **typed kernel + untyped orchestration** — deterministic `ecies-seal`/`-open` are typed kernels (parity vs an independent Python impl, `ecies_vectors.rs`); `(jsecmon crypto-ecies)` adds `ecies-generate-keypair` + `ecies-encrypt` (random ephemeral keypair + nonce) + `ecies-decrypt`. Frame = `ephemeral_public(32) ‖ nonce(12) ‖ ct` (jsecmon's own concat, not secmon's bincode — wire-compat not required). `make crypto-ecies-check` pins x25519 to RFC 7748 + ecies-seal to the reference vector, then round-trip / randomization / wrong-recipient→#f / tamper→#f. | | `storage` (events table, store/query/filters) | `jsecmon/storage.ss` | ✅ **untyped layer** — SQLite event store on `(std db sqlite-native)` (rusqlite): secmon's schema (events + indexes + collector_state), `store-event` INSERT-OR-IGNORE dedup, and the full EventFilter WHERE builder (host/type/severity/since/until/pid/process_name LIKE/search/exclude_event_ids). `query-events` returns row hashes with `data` parsed from JSON, so detect/triage/analytics consume them directly. `make storage-check` round-trips store→query→detect→analytics (host risk 30, same as `detect-check`). `entity-where`/`entity-timeline` port `storage::entity_timeline`: the per-category WHERE-group builder (Process = `process_name LIKE` + six json fields with LIKE `%value%`; Ip/User/Domain = exact `json_extract` `=` over their field sets) plus the assembled oldest-first query, with the filter clauses continuing the positional `?N` numbering after the category binds (`build-where` gained an optional start index). `make entity-check` pins each category's exact SQL fragment + binds and routes/orders/narrows/limits over a live store (18 cases). | | `storage` SQL-aggregation detectors (brute_force, credential_stuffing, dns_tunnel, suspicious_cron, recon_port_scan, data_exfil) | `jsecmon/threats.ss` | ✅ **untyped layer** — secmon's `run_detections` family: the time-bucket GROUP BY/HAVING rules and the two 5-min sliding-window rules, run as SQL (json_extract) over a `(jsecmon storage)` handle. `make threats-check` reproduces secmon's six detection-rule test vectors. Remaining: the sequence/kill-chain rules (priv_escalation_chain, persistence_after_access, log_cover, lateral_after_shell, impossible_travel) + frequency/severity/off-hours aggregates. | | `storage` sequence/chain detectors (priv_escalation_chain, persistence_after_access, log_cover, lateral_after_shell) | `jsecmon/threats.ss` | ✅ **untyped layer** — secmon's `detect_sequence_pair` family: event A then event B within a window on the same host (auth-success→priv-esc /5min, reverse-shell/webshell→persistence /1h, any-critical→log-tampering /1h, shell→lateral /1h). Reproduces secmon's chain test vectors incl. the outside-window negative. |