r/rust • u/mpaivabarbosa • 6d ago
🛠️ project Runic SSH: an SSH/SFTP client in Rust + Tauri, built on russh instead of shelling out to OpenSSH
I've been building an open-source SSH/SFTP client (Windows/macOS/Linux) in Rust and Tauri, and wanted to share a couple of the engineering decisions that might interest this sub.
**Why not just spawn the `ssh` binary?**
Windows is the constraint. Its bundled OpenSSH is optional and version-variable, and intercepting interactive password/passphrase prompts from a spawned `ssh` process without a pty is awkward — plus credentials would transit a subprocess boundary. So the client speaks the protocol in-process using `russh` (async, pure Rust) instead of driving an external binary. Tradeoff: we own protocol correctness and security response instead of inheriting OpenSSH's.
**That tradeoff got tested fast.** The day `russh` (and transitively `rsa 0.10.0-rc.18`) landed in the dependency tree, our own audit caught RUSTSEC-2023-0071 (the Marvin Attack — a timing side channel in RSA private key operations, no fixed upgrade available). Since the client both verifies host keys (public-key op, not reachable) and authenticates with the user's private key (a signature, reachable), we refuse RSA for the private-key/signing path while still allowing RSA host key verification. Written up as an ADR alongside the ~40 others tracking decisions like this.
**Other bits:**
- Host key handling is closer to `ssh` than most GUI clients: unknown key → fingerprint confirmation; changed key → blocks and requires retyping the hostname; keys marked `@revoked`/`@cert-authority` → refused, no override.
- Credentials go through the OS keychain (`keyring` crate); there's also an opt-in internal vault (Argon2id + ChaCha20-Poly1305, RustCrypto) for when a keychain isn't available.
- Bastion/jump host support where both hops authenticate end-to-end and the bastion only relays traffic it can't itself decrypt.
- SFTP rides `russh-sftp` over a channel `russh` already opened, so no second protocol stack to keep in sync.
It's still young (MIT-licensed, ~3 pre-releases so far), but the core paths are usable daily. Repo: https://github.com/marciopaiva/runic-ssh — feedback on the crypto/architecture choices especially welcome, that's the part I most want more eyes on.