ssh-keygen — Generate, inspect, and manage SSH key pairs across all 5 shells
Equivalents in every shell
ssh-keygen -t ed25519 -C "[email protected]"Part of OpenSSH. `-t ed25519` chooses the Ed25519 curve (default since OpenSSH 9.5 in 2023, and the right choice for new keys — small, fast, modern). `-C` is the key comment (typically your email / host, just a label — never used cryptographically). Default location `~/.ssh/id_ed25519` + `~/.ssh/id_ed25519.pub`. Passphrase prompt is interactive; pass `-N ""` for none (scripts), or `-N "secret"` (still leaks via shell history).
ssh-keygen -t ed25519 -C "[email protected]"Same OpenSSH binary on macOS / Linux. Two common follow-ups: `ssh-keygen -y -f ~/.ssh/id_ed25519` extracts the public key from a private key (useful when you lost the `.pub` half), and `ssh-keygen -lf ~/.ssh/id_ed25519.pub` shows the key fingerprint (the SHA256 hash GitHub / GitLab / etc display when you add the key).
ssh-keygen -t ed25519 -C "[email protected]"Same external. Fish-specific quality-of-life: `funcsave` a wrapper that always passes your preferred flags, e.g. `function newkey; ssh-keygen -t ed25519 -a 100 -C $argv[1]; end`. The `-a 100` flag bumps the KDF rounds (slows brute-force on the passphrase by ~100×; harmless cost since key creation is one-shot).
ssh-keygen -t ed25519 -C "[email protected]"Same `ssh-keygen.exe` binary — Windows OpenSSH client ships built-in since Windows 10 1809 (October 2018). Optional Feature `OpenSSH.Client` may need enabling on older / Server SKUs: `Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0`. No native PowerShell cmdlet equivalent — `New-SshKey` only exists in third-party modules (`Posh-SSH`, `Microsoft.PowerShell.SecretManagement` does NOT cover this).
ssh-keygen -t ed25519 -C "[email protected]"Same OpenSSH binary as pwsh — Windows ships it at `C:\Windows\System32\OpenSSH\ssh-keygen.exe`. Keys live under `%USERPROFILE%\.ssh\` (the Windows equivalent of `~/.ssh/`). cmd.exe doesn't expand `~`, so `ssh-keygen -f ~/.ssh/foo` fails — use `%USERPROFILE%\.ssh\foo` or run from pwsh.
Worked examples
Generate a new Ed25519 SSH key with strong KDF
ssh-keygen -t ed25519 -a 100 -C "alice@laptop"ssh-keygen -t ed25519 -a 100 -C "alice@laptop"ssh-keygen -t ed25519 -a 100 -C "alice@laptop"ssh-keygen -t ed25519 -a 100 -C "alice@laptop"Show fingerprint of a public key
ssh-keygen -lf ~/.ssh/id_ed25519.pubssh-keygen -lf $env:USERPROFILE\.ssh\id_ed25519.pubssh-keygen -lf %USERPROFILE%\.ssh\id_ed25519.pubChange a key's passphrase without regenerating
ssh-keygen -p -f ~/.ssh/id_ed25519ssh-keygen -p -f $env:USERPROFILE\.ssh\id_ed25519ssh-keygen -p -f %USERPROFILE%\.ssh\id_ed25519Gotchas
- Default key type is no longer RSA on modern OpenSSH (9.5+, late 2023): `ssh-keygen` with no `-t` produces an Ed25519 key. Older OpenSSH versions default to RSA 3072. If you script `ssh-keygen` for repeatable output, always pass `-t ed25519` (or `-t rsa -b 4096` if you genuinely need RSA for legacy server compatibility) — never rely on the default.
- Ed25519 is the right modern choice — fast, small, no parameter footguns. RSA below 3072 bits is rejected by current OpenSSH servers (OpenSSH 8.2 removed `ssh-rsa` signature support by default; 8.8 disabled SHA-1 signatures). DSA keys are dead — OpenSSH 9.8 (mid-2024) removed support entirely. If you have a `~/.ssh/id_dsa`, regenerate it as Ed25519.
- Private key file permissions must be 0600 (`u=rw,go=`) on Unix or `ssh` refuses to use the key: "Permissions for '~/.ssh/id_ed25519' are too open". `chmod 600 ~/.ssh/id_ed25519` fixes it. On Windows, the equivalent ACL check requires the file be owned by the current user and inaccessible to others; `icacls $env:USERPROFILE\.ssh\id_ed25519 /inheritance:r /grant:r "$($env:USERNAME):F"` restores it. WSL inherits the Windows file mode, so `chmod 600` from inside WSL on a `/mnt/c/Users/...` path silently no-ops — keep keys in WSL's native filesystem (`~/.ssh/` inside WSL) for SSH from WSL.
- The `.pub` file is NOT a secret and can be public. The other file (no suffix) is the private key and must never leave the machine. Common screw-up: copying the wrong half into `~/.ssh/authorized_keys` on the server. That file expects the PUBLIC half — pasting the private half makes the key useless and exposes it via any server compromise.
- `ssh-keygen -t rsa` with no `-b` creates a 3072-bit key on current OpenSSH; older binaries created 2048-bit which modern hardening guides reject. Specify `-b 4096` explicitly if you need RSA. For Ed25519 there is no `-b` (the curve fixes the size at 256 bits) — the `-a <rounds>` flag is the only tunable, and it only affects the KDF iterations that protect the passphrase, not key strength.