Help us shape the future of Go! Take the 2026 Go Developer Survey

ptransfer

module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 7, 2026 License: MIT

README

ptransfer

Go Reference

Send files and folders between two computers with a short code phrase, in the style of croc and Magic Wormhole. The sender gets a code like 4821-lamp-gold-lake, the receiver types it, and the files arrive encrypted end to end, through a relay or directly over the LAN when possible.

Who it's for

People who want to move a file between their own machines (or to a friend) without accounts, cloud storage or setting up SSH, and who would like to run their own relay. It's also a compact, readable example of how a PAKE-based transfer tool is put together.

Install

Prebuilt binaries for Linux, macOS and Windows (amd64 and arm64) are on the releases page. Each archive contains the ptransfer binary, the README and the license; checksums.txt has the SHA-256 sums. For example, on Linux amd64:

curl -LO https://github.com/AbdeldjalilChougui/ptransfer/releases/download/v0.1.0/ptransfer_0.1.0_linux_amd64.tar.gz
tar xzf ptransfer_0.1.0_linux_amd64.tar.gz

Or build from source with Go:

go install github.com/AbdeldjalilChougui/ptransfer/cmd/ptransfer@latest

Quick start

go build -o ptransfer ./cmd/ptransfer

# somewhere both machines can reach (a VPS, or one of the two machines)
./ptransfer relay -addr 0.0.0.0:9009

# machine A
./ptransfer send -relay relay.example.org:9009 holiday-photos/ notes.pdf
#   Code: 4821-lamp-gold-lake

# machine B
./ptransfer receive -relay relay.example.org:9009 -out ~/Downloads 4821-lamp-gold-lake

PTRANSFER_RELAY sets the default relay. If a transfer is interrupted (Ctrl-C, network drop), run it again with a new code: files that already arrived are skipped and partial files resume where they stopped.

How it works

sender                         relay                         receiver
  │ hello{room=H(4821), send}    │   hello{room=H(4821), recv}   │
  │─────────────────────────────►│◄──────────────────────────────│
  │◄──────────── ok ─────────────┤────────────── ok ────────────►│
  │              (from here the relay is a dumb pipe)            │
  │ PAKE (schollz/pake/v3, P-256), password = whole code         │
  │◄────────────────────────────────────────────────────────────►│
  │ key confirmation (HMAC), wrong code → both sides stop        │
  │ AES-256-GCM from now on, key = HKDF(PAKE secret)             │
  │ "direct?" + LAN addresses ─────────────────────────────────► │
  │◄═══════ receiver dials, proves the key with an encrypted ping│
  │ offer: paths, sizes, modes, SHA-256 ──────────────────────►  │
  │◄─ accept: per file, resume offset + hash of the partial data │
  │ data chunks (256 KiB) ───────────────────────────────────►   │
  │                     receiver: write *.ptpart, verify SHA-256,│
  │                     then rename into place                   │
  │◄──────────────────────────────── done ───────────────────────│
  • Code phrase: a number plus three words from a 256-word list. The number only picks the relay room (the relay sees a hash of it). The whole phrase is the PAKE password, so the relay can't decrypt anything, and someone guessing the code gets one try per session.
  • Crypto comes from vetted code: the PAKE is github.com/schollz/pake/v3 (the one croc uses) with participant identities bound into the key; the rest is Go's standard crypto/hkdf, crypto/hmac and AES-GCM. Nothing is hand-rolled beyond the framing. Nonces are a direction tag plus a counter, so a modified, dropped, reordered, replayed or reflected frame fails authentication.
  • Direct connection: the sender listens on a random port and advertises its private LAN addresses over the encrypted channel. If the receiver can connect and the encrypted ping/pong works, the data moves over that connection; otherwise it stays on the relay.
  • Resume: the receiver reports how much of each .ptpart file it has and its SHA-256; the sender only resumes if that matches the start of its own file. Every finished file is verified against the sender's SHA-256 before it gets its real name.
  • Safety on receive: paths are checked (no absolute paths, .., backslashes or NULs) and must stay inside the output directory; existing different files are not replaced without -overwrite.

Tests

go test -race ./...
  • code: generation, normalisation (case, spaces), shared rooms with different passwords, rejection of malformed codes.
  • secure: both sides derive the same key; a wrong code fails on both sides with ErrWrongCode; flipped bits, dropped frames and reflected frames are rejected; a malformed PAKE message doesn't crash the process.
  • relay: pairing and piping, a second sender for the same room is refused, an abandoned room is freed, bad hellos, wait timeouts.
  • transfer, end to end through a local relay on 127.0.0.1:
    • a folder with nested directories, an empty file and binary files arrives byte for byte with its file modes, and progress reaches 100 %;
    • the direct connection is used when reachable (one advertised address is dead on purpose) and the relay then carries almost nothing;
    • a wrong code stops both sides and writes nothing;
    • a tampering proxy that flips one bit in the middle of the stream is detected (ErrTampered) and no unverified file is put in place;
    • resume from a partial file sends only the rest; a partial file that doesn't match is discarded; re-sending a file the receiver already has transfers nothing;
    • existing files are protected unless Overwrite is set;
    • path validation rejects traversal attempts.

Status and limitations

Early but working. Use it for your own files.

  • The code has about 37 bits of entropy. That's plenty against online guessing (one guess per session, and the sender notices failures), but don't reuse codes.
  • The sender hashes every file before the offer, so very large folders take a moment to start.
  • Direct connections need the receiver to reach the sender's private address (same LAN, no client isolation). There's no NAT traversal (STUN, hole punching) and IPv6 link-local addresses aren't advertised. During a transfer with direct mode on, the sender listens on all interfaces on a random port.
  • The relay has no authentication, rate limiting or bandwidth caps. Put it behind a firewall or add limits before exposing it widely.
  • Only regular files are sent: symlinks, empty directories, ownership and timestamps are not preserved (permission bits are).
  • One sender and one receiver per code; no multicast, no pausing.
  • This hasn't been audited. The design is close to croc's, but treat it as a personal project.

License

MIT. See LICENSE.

Directories

Path Synopsis
cmd
ptransfer command
Command ptransfer sends files and folders between two computers using a short code phrase.
Command ptransfer sends files and folders between two computers using a short code phrase.
Package code makes and parses the human code phrases used to pair a sender with a receiver, e.g.
Package code makes and parses the human code phrases used to pair a sender with a receiver, e.g.
Package relay is the rendezvous server.
Package relay is the rendezvous server.
Package secure turns a byte stream into an authenticated, encrypted message channel, keyed by a password-authenticated key exchange.
Package secure turns a byte stream into an authenticated, encrypted message channel, keyed by a password-authenticated key exchange.
Package transfer sends files and folders between two machines that share a code phrase: they meet on a relay, run a PAKE, try a direct LAN connection, then stream the files encrypted, resuming partial files and verifying every file's SHA-256.
Package transfer sends files and folders between two machines that share a code phrase: they meet on a relay, run a PAKE, try a direct LAN connection, then stream the files encrypted, resuming partial files and verifying every file's SHA-256.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL