terminalphone/CLAUDE.md
2026-02-26 09:39:50 -05:00

4.3 KiB

terminalphone

encrypted, anonymous walkie-talkie over tor. single bash script (~3k lines), no servers, no accounts. your .onion address is your identity.

what it does

two parties share a secret, connect via tor hidden services, and talk using push-to-talk voice (opus-encoded, aes-encrypted). also supports encrypted text chat mid-call.

audio pipeline

mic → raw pcm (8khz mono) → opus encode (16kbps) → aes encrypt → base64 → socat → tor
tor → socat → base64 decode → aes decrypt → opus decode → speaker

record-then-send model (not streaming) - irregular transmission patterns make traffic analysis harder.

wire protocol

text-based, line-delimited over socat/tor:

  • ID:<onion> - caller id exchange
  • CIPHER:<name> - cipher negotiation
  • PTT_START / PTT_STOP - recording state
  • AUDIO:<base64> - encrypted audio payload
  • MSG:<base64> - encrypted text message
  • HANGUP / PING - control signals

optional HMAC-SHA256 signing with nonce replay protection (both sides must match).

project structure

terminalphone.sh    the whole thing. single script
README.md           usage docs
CHANGELOG           version history
LICENSE             MIT
CLI.png             screenshot

runtime data lives in .terminalphone/ (auto-created):

  • tor_data/ - tor hidden service keys
  • audio/ - temp audio files (cleaned on exit)
  • pids/ - process id tracking
  • run/ - named pipes, flags, cipher state
  • shared_secret - encrypted pre-shared key
  • torrc - generated tor config
  • config - user settings

dependencies

core: tor, opus-tools, sox, socat, openssl, arecord/aplay optional: snowflake-client, qrencode, jq (termux vol-ptt) platforms: linux (deb/fed/arch), android (termux + termux:api from f-droid)

running it

bash terminalphone.sh              # interactive menu
bash terminalphone.sh listen       # listen mode
bash terminalphone.sh call ADDR    # call a .onion address
bash terminalphone.sh install      # install deps
bash terminalphone.sh test         # audio loopback test
bash terminalphone.sh status       # show status

in-call: SPACE=ptt, T=text msg, S=settings, Q=hangup

key code areas

the script is organized roughly as:

  • config (~line 1-150): load_config/save_config, defaults
  • deps/install (~150-400): install_deps, check_dep, platform detection
  • tor management (~400-700): setup_tor, start/stop/restart, get_onion, rotate_onion
  • encryption (~700-900): encrypt_file/decrypt_file, PBKDF2 key derivation, fd passing
  • protocol (~900-1050): proto_send/proto_verify, HMAC auth, nonce tracking
  • audio (~1050-1400): audio_record, start_recording, stop_and_send, audio_play, voice effects
  • call flow (~1400-1900): listen_for_call, call_remote, in_call_session, cleanup_call
  • settings menus (~1900-2600): cipher (21 options), opus quality, snowflake, voice effects, tor, security
  • auto-listen (~2600-2750): background listener management
  • main menu (~2750-3079): interactive menu loop, cli arg parsing

config options

stored in .terminalphone/config:

  • LISTEN_PORT (7777), TOR_SOCKS_PORT (9050)
  • OPUS_BITRATE (16kbps), CIPHER (aes-256-cbc)
  • SNOWFLAKE_ENABLED, AUTO_LISTEN, PTT_KEY
  • SHOW_CIRCUIT, EXCLUDE_NODES, HMAC_AUTH
  • VOICE_EFFECT (none/deep/high/robot/echo/whisper/custom)

security model

  • e2e encryption with 21 cipher options (aes, chacha20, camellia, aria)
  • secrets passed via file descriptors (not visible in process table)
  • tor hidden service per instance (no ip exposure)
  • passphrase-protected secrets at rest (aes-256-cbc + 100k pbkdf2)
  • opaque temp filenames (random hex, generic .tmp extension)
  • country exclusion for tor circuits (five/nine/fourteen eyes presets)

hacking notes

  • it's all bash - no build step, no transpilation
  • named pipes (fifos) are the ipc mechanism between socat and the call session
  • uid() generates random hex from /dev/urandom
  • platform branching happens via is_termux() checks throughout
  • cleanup_call() is critical - handles pipe/process/file cleanup on disconnect
  • the settings system uses a simple key=value flat file
  • no test framework exists yet - testing is manual via loopback (option 5)

style

  • bash with #!/usr/bin/env bash
  • functions use snake_case
  • log_info/log_warn/log_error/log_debug for output
  • match existing formatting and comment style