Skip to content
shellmap

ssh-keygenGenerate, inspect, and manage SSH key pairs across all 5 shells

Equivalents in every shell

Bashunix
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).

Zshunix
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).

Fishunix
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).

PowerShellwindows
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).

cmd.exewindows
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

Bash
ssh-keygen -t ed25519 -a 100 -C "alice@laptop"
Fish
ssh-keygen -t ed25519 -a 100 -C "alice@laptop"
PowerShell
ssh-keygen -t ed25519 -a 100 -C "alice@laptop"
cmd.exe
ssh-keygen -t ed25519 -a 100 -C "alice@laptop"

Show fingerprint of a public key

Bash
ssh-keygen -lf ~/.ssh/id_ed25519.pub
PowerShell
ssh-keygen -lf $env:USERPROFILE\.ssh\id_ed25519.pub
cmd.exe
ssh-keygen -lf %USERPROFILE%\.ssh\id_ed25519.pub

Change a key's passphrase without regenerating

Bash
ssh-keygen -p -f ~/.ssh/id_ed25519
PowerShell
ssh-keygen -p -f $env:USERPROFILE\.ssh\id_ed25519
cmd.exe
ssh-keygen -p -f %USERPROFILE%\.ssh\id_ed25519

Gotchas

  • 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.

WSL & PowerShell Core notes

pwsh`ssh-keygen` is the same binary on Windows (`OpenSSH.Client` capability) and Unix pwsh — no first-party PowerShell cmdlet exists. Two community modules cover key creation: `Posh-SSH` (`New-SSHKey`) and `SSH.PowerShell`. Neither is built-in. The pragmatic pwsh approach: call `ssh-keygen` directly and parse the printed paths if you need them; that script is 100% portable across Windows pwsh, Unix pwsh, and bash.
WSLWSL has its own OpenSSH installation (`apt install openssh-client` in Ubuntu / `dnf install openssh` in Fedora distros). WSL's `~/.ssh/` is INSIDE the VM (`\\wsl$\Ubuntu\home\user\.ssh\` from Windows) and SEPARATE from Windows' `%USERPROFILE%\.ssh\`. Two consequences: (1) keys generated in WSL don't auto-work for Windows `ssh.exe`; (2) `chmod 600` works correctly inside WSL's native FS but not on `/mnt/c/` paths (DrvFs ignores Unix modes). For one-key-everywhere setups, generate in WSL and symlink: `mkdir -p /mnt/c/Users/$YOUR_WIN_USER/.ssh && cp ~/.ssh/id_ed25519* /mnt/c/Users/$YOUR_WIN_USER/.ssh/` then fix Windows ACLs.

Common tasks using ssh-keygen

Related commands