How Croc's Code Phrase PAKE Authentication Works

Croc uses Password-Authenticated Key Exchange (PAKE) to convert the human-readable code phrase into a strong symmetric session key without ever transmitting the password over the network.

The open-source file transfer tool croc (github.com/schollz/croc) secures peer-to-peer connections using a shared code phrase that acts as a password. Through croc code phrase PAKE authentication, this human-readable secret transforms into a cryptographically strong key that encrypts all subsequent data, ensuring that even the relay server cannot read the transferred files.

Deriving the Room and Password from the Code Phrase

Room Name Generation and Secret Extraction

In src/croc/croc.go, the New function validates that the code phrase contains at least six characters. The implementation hashes the first four bytes to generate the room name used for rendezvous, while the remaining bytes (starting at index 5) serve as the weak password fed into the PAKE algorithm.

Role-Based PAKE Initialization

Both peers initialize the PAKE object from the github.com/schollz/pake/v3 library using the same password but with opposite roles. The receiver uses role 0 and the sender uses role 1. The elliptic curve defaults to p256 but is configurable via the --curve CLI flag defined in src/cli/cli.go.

The PAKE Handshake Sequence

The handshake occurs before any file data transmission, establishing an encrypted channel through a two-message exchange.

Step 1: Sender Initiates PAKE

In senderWaitForHandshake (src/croc/croc.go), the sender creates a PAKE instance with role 1 and transmits its public value via SimpleMessage{Kind:"pake1", Bytes:B.Bytes()} to the receiver.

Step 2: Receiver Responds

Upon receiving "pake1", the receiver calls A.Update(dataMessage.Bytes) and derives the session key kB via A.SessionKey(). It replies with SimpleMessage{Kind:"pake2", Bytes:A.Bytes()} containing its own public value.

Step 3: Key Confirmation

The sender processes "pake2" by calling B.Update(dataMessage.Bytes) and computing kA via B.SessionKey(). At this point, both sides hold the identical session key (kA == kB), though neither has transmitted the original code phrase.

Step 4: Channel Encryption

All subsequent communication uses crypt.Encrypt and crypt.Decrypt from src/crypt/crypt.go with the derived session key. The first encrypted message is the handshakeRequest, signaling the completion of the PAKE exchange.

Security Properties

Zero Password Transmission

The raw code phrase never leaves the client devices. Only public PAKE values (A.Bytes() and B.Bytes()) traverse the network, rendering eavesdropping attacks ineffective.

Authenticated Encryption

The derived session key provides both confidentiality and integrity through the crypt package, preventing man-in-the-middle tampering with file metadata or chunks.

CLI Usage and Configuration

Practical examples of invoking croc with custom code phrases and curves:


# Sender specifies custom code phrase

croc send --code "my secret phrase" file.txt

# Receiver joins with matching phrase

croc receive --code "my secret phrase"

# Use alternative elliptic curve for PAKE

croc send --curve p384 --code "another secret" file.txt

Core Implementation Files

  • src/croc/croc.go: Contains New, senderWaitForHandshake, and the PAKE handshake orchestration logic.
  • src/message/message.go: Defines message.TypePAKE and the SimpleMessage structure used for PAKE value exchange.
  • src/crypt/crypt.go: Implements Encrypt and Decrypt functions that protect data using the PAKE-derived key.
  • src/cli/cli.go: Exposes the --curve parameter allowing selection of elliptic curves like p256, p384, or p521.

Summary

  • Croc requires code phrases of at least six characters, using the first four bytes for room identification and the remainder for PAKE authentication.
  • The PAKE exchange assigns role 0 to receivers and role 1 to senders, defaulting to the p256 elliptic curve.
  • Public PAKE values are exchanged via "pake1" and "pake2" messages in senderWaitForHandshake, resulting in identical session keys on both peers.
  • No password material ever transmits over the network; only public cryptographic values leave the client.
  • Post-handshake communication uses authenticated encryption via the crypt package with the derived session key.

Frequently Asked Questions

What is PAKE and why does croc use it?

PAKE (Password-Authenticated Key Exchange) is a cryptographic protocol that allows two parties to establish a shared secret key using a weak password, without transmitting the password itself. Croc uses PAKE to ensure that the human-readable code phrase never appears on the wire, preventing relay operators or network eavesdroppers from capturing authentication credentials.

How does croc prevent man-in-the-middle attacks during the handshake?

Croc mitigates man-in-the-middle attacks through the PAKE protocol's mathematical properties: the session key derivation depends on both the shared secret (code phrase) and the public values exchanged. An attacker without the code phrase cannot compute the correct session key, and the subsequent authenticated encryption in src/crypt/crypt.go rejects any tampered messages.

Can I use a custom elliptic curve for the PAKE exchange?

Yes. While croc defaults to the p256 curve for balanced security and performance, you can specify alternatives like p384 or p521 using the --curve flag. The CLI parser in src/cli/cli.go passes this parameter to the PAKE constructor in src/croc/croc.go.

What happens if the code phrase is shorter than six characters?

The New function in src/croc/croc.go enforces a minimum length of six characters for the code phrase. This requirement ensures sufficient entropy for the room name (first four bytes) and the PAKE password (remaining bytes) to maintain security.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →