v0.1: Replace SHA-256 local auth with argon2id #1

Closed
opened 2026-07-18 20:16:42 +00:00 by Cordy · 1 comment
Owner

Blocking for v0.1 / any real deployment.

Local auth currently stores passwords as unsalted SHA-256 hex digests (internal/auth/auth.go) — a deliberate placeholder to keep the scaffold at zero dependencies.

Replace with argon2id via golang.org/x/crypto/argon2:

  • Config format: PHC string ($argon2id$v=19$m=65536,t=3,p=4$<salt>$<hash>) in place of passwordSha256
  • Add a cairnd hash-password subcommand so users can generate hashes without external tools
  • Keep constant-time comparison and the dummy-verify-on-unknown-user anti-enumeration behavior
  • Remove the passwordSha256 field entirely (no backward compat needed pre-release)

This is the first third-party dependency added to the project — note it in ARCHITECTURE.md §1 point 4.

**Blocking for v0.1 / any real deployment.** Local auth currently stores passwords as unsalted SHA-256 hex digests (`internal/auth/auth.go`) — a deliberate placeholder to keep the scaffold at zero dependencies. Replace with argon2id via `golang.org/x/crypto/argon2`: - [ ] Config format: PHC string (`$argon2id$v=19$m=65536,t=3,p=4$<salt>$<hash>`) in place of `passwordSha256` - [ ] Add a `cairnd hash-password` subcommand so users can generate hashes without external tools - [ ] Keep constant-time comparison and the dummy-verify-on-unknown-user anti-enumeration behavior - [ ] Remove the `passwordSha256` field entirely (no backward compat needed pre-release) This is the first third-party dependency added to the project — note it in ARCHITECTURE.md §1 point 4.
Cordy referenced this issue from a commit 2026-07-18 21:21:57 +00:00
Author
Owner

Implemented and pushed to main:

  • internal/auth/argon2.go — argon2id via x/crypto/argon2, PHC string format, RFC 9106 second recommended parameters (m=64MiB, t=3, p=4). Verification reads parameters from the stored hash, rejects degenerate/absurd params (t=0/p=0 would panic the library; huge m would be a memory DoS), constant-time compare.
  • cairnd hash-password subcommand — reads stdin only, so passwords stay out of shell history and ps output.
  • Unknown-username requests burn an identical argon2 cost against a dummy hash (timing-oracle closure preserved from the old implementation).
  • passwordSha256 removed entirely; config field is now passwordHash.
  • Tests: hash/verify roundtrip, salt uniqueness, 9 malformed-hash rejection cases. Full suite green; smoke-tested end to end (correct/wrong/unknown credentials + WebDAV).

One manual step left for you: go.sum couldn't be generated from my sandbox (no module-proxy access), so run go mod tidy once locally and commit the resulting go.sum. CI has a go mod tidy step as a stopgap until then.

Implemented and pushed to main: - `internal/auth/argon2.go` — argon2id via `x/crypto/argon2`, PHC string format, RFC 9106 second recommended parameters (m=64MiB, t=3, p=4). Verification reads parameters from the stored hash, rejects degenerate/absurd params (t=0/p=0 would panic the library; huge m would be a memory DoS), constant-time compare. - `cairnd hash-password` subcommand — reads stdin only, so passwords stay out of shell history and `ps` output. - Unknown-username requests burn an identical argon2 cost against a dummy hash (timing-oracle closure preserved from the old implementation). - `passwordSha256` removed entirely; config field is now `passwordHash`. - Tests: hash/verify roundtrip, salt uniqueness, 9 malformed-hash rejection cases. Full suite green; smoke-tested end to end (correct/wrong/unknown credentials + WebDAV). **One manual step left for you:** go.sum couldn't be generated from my sandbox (no module-proxy access), so run `go mod tidy` once locally and commit the resulting `go.sum`. CI has a `go mod tidy` step as a stopgap until then.
Cordy closed this issue 2026-07-18 21:28:05 +00:00
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#1
No description provided.