lacs-project / lacs-project/sysknife
audit export publishes request_hash, an unsalted hash over unredacted params, with no statement of its sensitivity
- Dominant language
- Rust
- Stars
- 12
- Forks
- 19
- Avg merge
- 18h 57m
- Merged PRs (30d)
- 116
Description
`request_hash` is a column of every signed chain row, and `sysknife audit export` (#260) now serialises it. The hash commits to the **unredacted** request:
```
crates/sysknife-daemon/src/dispatcher.rs:2001 let request_hash = compute_request_hash(action_name, params);
crates/sysknife-daemon/src/dispatcher.rs:2041 let redacted_params = redact_params(action_name, params);
```
Redaction runs 40 lines after the hash, and `compute_request_hash` is one unsalted round:
```rust
hasher.update(action_name.as_bytes());
hasher.update(b"\x00");
hasher.update(canonical.as_bytes());
```
## Why it matters
For `ConfigureWifi` the credential params are `password` and `ssid`. The SSID is broadcast, so the only unknown in the preimage is the passphrase, and a single unsalted SHA-256 is the cheapest thing a GPU cracks. The daemon keeps the database 0600 inside a 0700 directory precisely so this content does not travel; an export moves it across that boundary by design, into a SIEM, a ticket, or an auditor's laptop.
High-entropy credentials such as `ProAttach` tokens are unaffected. The problem is the low-entropy human-chosen ones.
The column cannot simply be dropped: `request_hash` is part of `ChainContent::canonical_bytes` (`crates/sysknife-daemon/src/audit_chain.rs:508`), so an offline verifier needs it to rebuild the signed bytes.
## Scope
Two parts, and the first is the one that matters today:
1. Say plainly in `docs/cli.md` and `docs/the-audit-chain.md` that an export inherits the database's confidentiality class and is not a redacted artifact. The docs currently enumerate what export omits (`argv`, `outcome`, a separate `signature`) and say nothing about what it carries.
2. Consider replacing the bare hash with an HMAC keyed by the audit key. That keeps the binding an offline verifier needs while removing the offline-crackable commitment, at the cost of a `chain_version` bump and a verifier that has the key.
## Tests first
For part 1 the check is the claim guard: the export section has to state the confidentiality class. For part 2, a round-trip test that an HMAC-bound row still verifies, plus a migration test across `chain_version`.
## Difficulty
`medium` for the documentation half alone; `hard` if the HMAC change is taken, because it touches the signed encoding.
## Getting started
[CONTRIBUTING.md](https://github.com/lacs-project/sysknife/blob/main/CONTRIBUTING.md) has the build and test commands, and [docs/developer-guide.md](https://github.com/lacs-project/sysknife/blob/main/docs/developer-guide.md) covers the setup steps and how to reproduce each required check locally. No CLA and no copyright waiver. The project is MIT.
Contributor guide
Research direction
Start with the export sections in docs/cli.md and docs/the-audit-chain.md, then read compute_request_hash and ChainContent::canonical_bytes in crates/sysknife-daemon/src/dispatcher.rs and crates/sysknife-daemon/src/audit_chain.rs. For the documentation scope, done means the export confidentiality claim is explicit; if the HMAC scope is taken, add round-trip and chain_version migration coverage showing verification still works.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cryptography, documentation, security
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100