Skip to content

KOSync credential comparison is not constant-time, creating a timing oracle #374

Description

@forkwright

Finding

The three KOSync handlers that authenticate a caller (auth_user, put_progress, get_progress) compare the stored SHA1 hex hash against the caller-supplied x-auth-key with String's != operator. That comparison is byte-by-byte and short-circuits on the first differing byte, leaking timing proportional to the length of the correct prefix.

Evidence

crates/paroche/src/routes/kosync.rs:152 — the comparison, with the same pattern repeated at lines 186 and 251:

if user.password_hash != provided_key {

The preceding comment at crates/paroche/src/routes/kosync.rs:151 claims the opposite of what the code does:

// Constant-time comparison to prevent timing attacks

The implementation directly contradicts the stated invariant at all three sites.

Why this matters

With enough requests an adversary recovers a valid SHA1 hash nibble-by-nibble off the timing signal. Because the KOSync protocol uses SHA1(password) as a bearer credential in every request header, a recovered hash grants full impersonation without ever learning the password. A capable adversary on the network can automate this oracle; the misleading comment also means a future reviewer may assume the path is already safe.

Desired correction

Replace != with a constant-time comparison — subtle::ConstantTimeEq or hmac::Mac::verify_slice — at all three sites (lines 152, 186, 251), comparing the raw bytes after equal-length normalization. Keep the comment accurate to the implementation.

Done when: the credential comparison path uses a constant-time byte-comparison function at all three KOSync auth sites, verified by a timing-invariant test.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions