Skip to content

feat(edge): compare API keys as fixed-width digests (#24)#37

Merged
JumpTechCode merged 1 commit into
mainfrom
feat/edge-hash-api-keys
Jun 17, 2026
Merged

feat(edge): compare API keys as fixed-width digests (#24)#37
JumpTechCode merged 1 commit into
mainfrom
feat/edge-hash-api-keys

Conversation

@JumpTechCode

Copy link
Copy Markdown
Collaborator

What

Remove the residual key-length timing signal from edge client authentication (issue #24).

authenticate already compares the presented key against every configured key with crypto/subtle.ConstantTimeCompare and no early exit, so response time does not leak which client matched or how far a guessed key got (ADR-0003). One residual signal remained: ConstantTimeCompare returns immediately when two byte slices differ in length, so the comparison cost still varied with the presented key's length relative to the configured keys'.

This PR reduces each configured key to its SHA-256 digest at construction (in set, so SIGHUP reload is covered too), and per request compares sha256(presented) against those 32-byte digests. Every comparison is now equal-width — this removes the length-dependent timing and the early-exit-on-length branch entirely. As a side benefit, the guard no longer retains raw key bytes past construction.

Acceptance criteria (issue #24)

  • Authentication compares fixed-width digests; behavior (which identities authenticate) is unchanged.
  • A brief note records that the length signal has been removed — in authenticate's doc comment and a Consequences bullet in ADR-0003.

Testing

  • The full existing guard behavior suite stays green (auth, origin, reload, concurrency).
  • New TestGuardAuthenticatesVariableLengthKeys pins the property the digest comparison must preserve: keys of very different lengths each resolve to their identity, and a wrong key sharing a real key's length is rejected. (Added and confirmed green against the pre-change code first, then carried through the change.)
  • make verify: build, vet, -race tests, coverage 95.3% (gate 80%), golangci-lint v2.12.2 clean, govulncheck clean.

The public ClientKey type and the NewGuard/Reload signatures are unchanged, so the composition root needs no change.

Closes #24

🤖 Generated with Claude Code

authenticate compared the presented key against every configured key with
crypto/subtle.ConstantTimeCompare and no early exit, so response time did not
leak which client matched or how far a guessed key got (ADR-0003). One
residual signal remained: ConstantTimeCompare returns immediately when two
byte slices differ in length, so the comparison cost still varied with the
presented key's length relative to the configured keys'.

Reduce each configured key to its SHA-256 digest at construction (in set, so
it also covers SIGHUP reload), and per request compare sha256(presented)
against those 32-byte digests. Every comparison is now equal-width, removing
the length-dependent timing and the early-exit-on-length branch entirely. As
a side benefit the guard no longer retains raw key bytes past construction.

Behavior — which identities authenticate — is unchanged: the full existing
guard suite stays green, and a new test pins that keys of very different
lengths each resolve to their identity while a wrong same-length key is
rejected. A note in authenticate and a Consequences bullet in ADR-0003 record
that the length signal is removed.

Closes #24

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JumpTechCode
JumpTechCode merged commit 1d71575 into main Jun 17, 2026
5 checks passed
@JumpTechCode
JumpTechCode deleted the feat/edge-hash-api-keys branch June 17, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

edge: optionally hash API keys to remove residual key-length timing signal

1 participant