# PAKE Initialization Details in src/croc/croc.go: How croc Bootstraps Encryption

> Discover PAKE initialization details in src croc croc.go. Learn how croc bootstraps encryption using role-specific curve initialization and sliced shared secrets for secure session key derivation.

- Repository: [Zack/croc](https://github.com/schollz/croc)
- Tags: internals
- Published: 2026-07-26

---

**The croc client initializes Password-Authenticated Key Exchange (PAKE) through three distinct code paths in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go), using role-specific curve initialization with sliced shared secrets to derive symmetric session keys before any file data traverses the network.**

The croc secure file transfer tool (github.com/schollz/croc) leverages the `github.com/schollz/pake/v3` library to establish encrypted channels between sender and receiver without pre-shared certificates. Examining the PAKE initialization details in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) reveals how the tool transforms a human-readable code into a cryptographically secure session key that protects data even against compromised relay servers.

## PAKE Initialization Flow in src/croc/croc.go

The `croc` client performs PAKE initialization in three specific scenarios within [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go). Each invocation uses `pake.InitCurve` with distinct role parameters to establish the cryptographic handshake.

### Receiver Initialization (Role 0)

When a client operates as a receiver (`c.Options.IsSender == false`), the constructor initializes PAKE with role **0**. This occurs in the `New` function where the client trims the first five characters from the shared secret and passes the remainder to the PAKE library.

```go
// New establishes the client configuration
func New(ops Options) (*Client, error) {
    // ...
    if !c.Options.IsSender {
        c.Pake, err = pake.InitCurve([]byte(c.Options.SharedSecret[5:]), 0, c.Options.Curve)
    }
    // ...
}

```

This initialization happens at **lines 128-132** of [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go). The role flag `0` designates this instance as the receiver in the key exchange protocol.

### Sender Handshake Initialization (Role 1)

During the sender's handshake phase, the `senderWaitForHandshake` function creates a temporary PAKE instance with role **1** to initiate the cryptographic exchange. The sender uses the same secret slicing logic as the receiver.

```go
func (c *Client) senderWaitForHandshake(conn *comm.Comm) error {
    // ...
    B, err := pake.InitCurve([]byte(c.Options.SharedSecret[5:]), 1, c.Options.Curve)
    // ...
}

```

Located at **lines 144-148**, this code path executes when the sender connects to the relay and prepares to transmit PAKE bytes to the receiver.

### Reconnection Recovery

If a transfer interruption triggers a reconnect attempt, the `resetForReconnectAttempt` function re-initializes the PAKE instance with role **0** to restart the key exchange fresh.

```go
c.Pake, err = pake.InitCurve([]byte(c.Options.SharedSecret[5:]), 0, c.Options.Curve)

```

This re-initialization appears at **lines 546-550**, ensuring that resumed transfers generate new session keys rather than reusing potentially compromised previous states.

## Technical Implementation Details

The PAKE initialization relies on several critical implementation choices that ensure cryptographic security across different network conditions.

### Secret Slicing and Code Extraction

The first five characters of the user-provided secret represent the **connection code** used for relay identification. The actual cryptographic entropy comes from `c.Options.SharedSecret[5:]`, which passes to `pake.InitCurve` as the password material. This separation ensures that the human-visible code does not directly serve as the PAKE password, adding a layer of abstraction between the relay routing identifier and the encryption key material.

### Curve Selection and Role Flags

The third parameter to `pake.InitCurve` specifies the **elliptic curve** (e.g., `"ed25519"`, `"p256"`, `"p521"`), determined by `c.Options.Curve`. The second parameter defines the **role flag**:

- **0**: Receiver (waiter) role
- **1**: Sender (initiator) role

This distinction ensures that both parties generate complementary key shares that combine into a single shared secret, preventing role confusion attacks.

### Session Key Derivation

After the initial PAKE message exchange, both client instances call `SessionKey()` to derive the symmetric encryption key. The croc implementation stores this as `kA` (sender) or `kB` (receiver), subsequently using it via the `crypt` package to encrypt control messages such as IP address requests and file metadata before the actual payload transfer begins.

## Summary

- **Three initialization points**: [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go) initializes PAKE in the `New` constructor for receivers (lines 128-132), in `senderWaitForHandshake` for senders (lines 144-148), and in `resetForReconnectAttempt` for reconnections (lines 546-550).
- **Role-based differentiation**: Receivers use role `0` while senders use role `1` in the `pake.InitCurve` call.
- **Secret trimming**: The implementation slices `SharedSecret[5:]` to exclude the five-character connection code from the cryptographic material.
- **Curve flexibility**: The curve parameter supports multiple elliptic curves based on user configuration via `c.Options.Curve`.
- **Secure bootstrapping**: PAKE establishes encryption keys before any file data transmission, ensuring confidentiality even if the relay server is compromised.

## Frequently Asked Questions

### How does croc derive the encryption key from the shared secret?

The croc client extracts the password material by removing the first five characters from the shared secret using `c.Options.SharedSecret[5:]`. This sliced byte array feeds into `pake.InitCurve` along with the role flag and curve type. After the PAKE handshake completes, both parties call `SessionKey()` to generate the symmetric key used for encrypting subsequent communications.

### What is the difference between role 0 and role 1 in croc's PAKE implementation?

Role **0** designates the receiver (the client waiting to accept files), initialized in the `New` function and during reconnections. Role **1** designates the sender (the client transmitting files), initialized in `senderWaitForHandshake`. These role flags ensure the PAKE library generates complementary key shares that properly combine into a shared session key.

### Which elliptic curves does croc support for PAKE?

According to the source code in [`src/croc/croc.go`](https://github.com/schollz/croc/blob/main/src/croc/croc.go), croc supports multiple curves including **ed25519**, **p256**, **p384**, and **p521**, passed through `c.Options.Curve` to `pake.InitCurve`. The default curve depends on the croc version and build configuration, but users can specify alternatives via the `--curve` command-line flag.

### Why does croc re-initialize PAKE during reconnection attempts?

The `resetForReconnectAttempt` function re-initializes the PAKE instance to ensure that interrupted transfers generate fresh session keys rather than reusing previous cryptographic states. This prevents potential key reuse vulnerabilities and ensures that each connection attempt establishes independent encryption contexts, maintaining forward secrecy across multiple connection attempts.