schollz/croc · error · Error

Sender PAKE confirmation failed

Error message

Sender PAKE confirmation failed

What it means

Thrown by the recipient when the sender's pake-confirm token fails wasm confirmPeerKey — the cryptographic proof that both parties derived the same shared key did not verify. This means the negotiated keys differ, almost always because the PAKE inputs (passphrase, room, purpose, curve, identities) were not identical on both sides. The channel is deliberately not established.

Source

Thrown at web/src/protocol/client.ts:713

      peerPake.b2,
      PAKE_PURPOSE_TRANSFER,
      room,
      curve,
      pake.bytes,
      peerPake.b,
    );
    await sendControl(control, {
      t: "pake-confirm",
      v: PAKE_PROTOCOL_VERSION,
      b: peerKeys.confirmationA,
    });
    const confirmationB = await receiveControl(control);
    if (confirmationB.t !== "pake-confirm" || !confirmationB.b) {
      throw new Error("Sender did not confirm the croc PAKE handshake");
    }
    requirePakeVersion(confirmationB.v);
    if (!(await wasm().confirmPeerKey(peerKeys.confirmationB, confirmationB.b))) {
      throw new Error("Sender PAKE confirmation failed");
    }
    key = peerKeys.key;
    data = await openDataConnections(
      settings,
      room,
      dataPorts(relay.banner),
      signal,
    );
    await sendControl(control, {
      t: "externalip",
      m: relay.externalIP,
      b: peerPake.b,
    }, key);
    const peerIP = await receiveControl(control, key);
    if (peerIP.t !== "externalip") throw new Error("Sender did not secure the channel");

    const fileInfo = await receiveControl(control, key);
    if (fileInfo.t === "error") throw new Error(fileInfo.m || "Sender cancelled");

View on GitHub (pinned to e25f1bdc04)

Solutions

  1. Regenerate and re-share the code phrase; both peers must enter the exact same string (validateSecret enforces printable ASCII >=6 chars, but equality is on the users)
  2. Verify codeComponents output (room + passphrase) is identical on both peers — log the room hash, not the secret
  3. Ensure PAKE_PURPOSE_TRANSFER and curve p256 are unchanged in any fork; both are hard-coded inputs to derivation
  4. If it persists with identical phrases, suspect wasm build skew and rebuild/upgrade both clients
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight both sides derive identical components before connecting
const { room, passphrase } = await wasm().codeComponents(secret);
// compare a hash of room+passphrase out-of-band (never send the secret itself)
const digest = await wasm().hashFinal(await wasm().hashInit()); // illustrative

Try / catch

catch (e) {
  if (e instanceof Error && e.message === "Sender PAKE confirmation failed") {
    // keys diverged: almost always a code-phrase mismatch; re-share the code and retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Different passphrases derived from slightly different code phrases; room string differs (e.g. code phrase parsed differently by peers); PAKE purpose ('peer-transfer') or curve ('p256') mismatch between implementations; corrupted confirmation bytes in transit; wasm engine version skew changing key derivation.

Common situations: Users mistype or variant-type the code phrase (trailing spaces, unicode look-alikes); one peer uses a croc build whose codeComponents parses rooms differently; forked clients changing the PAKE purpose string; bit corruption on the relay path (rare since encryption would usually fail earlier).

Related errors


AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15). Data as JSON: /api/errors/c88a8e6b8ec88e0f. Report an issue: GitHub.