Complete technical guide
PPK vs PEM: SSH Private Key Formats Explained
What Is a PPK File?
A .ppk file is PuTTY's own private key container, introduced alongside the PuTTY SSH client for Windows. It's a plain-text format: a header line naming the key algorithm and format version, an Encryption: field, a free-text Comment:, the public key as base64 (Public-Lines), the private key material as base64 (Private-Lines, encrypted if a passphrase was set), and — for format v2 — a Private-MAC line that lets PuTTY detect a corrupted file or wrong passphrase before it ever tries to use the key. Format v3 (introduced in 2017 after weaknesses were found in v2's SHA-1-based key derivation) replaces that scheme with the memory-hard Argon2 password-hashing function for anything encrypted.
What Is a PEM File?
PEM (Privacy-Enhanced Mail) is a much older, general-purpose container format — originally designed for email encryption in the late 1980s, but now the near-universal way to store X.509 certificates and private keys as base64 text wrapped in -----BEGIN ... ----- / -----END ... ----- lines. An RSA private key in PEM form is typically PKCS#1 (-----BEGIN RSA PRIVATE KEY-----); other algorithms and passphrase-encrypted keys generally use the more generic PKCS#8 container (-----BEGIN PRIVATE KEY----- or -----BEGIN ENCRYPTED PRIVATE KEY-----). This is the format OpenSSH, cloud providers, and essentially all Linux/macOS SSH tooling expect.
PPK vs PEM: The Real Difference
Neither format is more "secure" than the other in principle — they're both just containers around the same underlying RSA, ECDSA, or Ed25519 key material, using well-understood encryption schemes when a passphrase is set. The practical difference is ecosystem: PPK is essentially PuTTY-only, while PEM (and the closely related modern OpenSSH format) is what everything else — ssh, scp, git, cloud consoles, infrastructure-as-code tools — expects. Converting a key doesn't change what it can do; it only changes which tools can read the file directly.
PuTTY vs OpenSSH: Two Ecosystems, One Underlying Protocol
Both implement the same SSH protocol (RFC 4251-4254 and successors), so a key generated in one is cryptographically usable by the other — only the private key file's container differs. PuTTY ships as a Windows-native GUI toolkit (PuTTY, PuTTYgen, Pageant, WinSCP, FileZilla) that predates OpenSSH's widespread availability on Windows. OpenSSH is the reference implementation bundled with virtually every Linux distribution, macOS, and — since Windows 10 1809 — Windows itself. Many teams end up needing both: PuTTY/WinSCP for a Windows workstation, and PEM/OpenSSH format for servers, CI pipelines, and cloud provisioning.
How SSH Keys Work
SSH key authentication uses asymmetric (public-key) cryptography: a mathematically linked key pair where the public key can be shared freely (placed in a server's ~/.ssh/authorized_keys, or uploaded to GitHub/GitLab/a cloud console) while the private key never leaves your machine. During authentication, the server issues a challenge that only someone holding the matching private key can correctly sign; the server verifies that signature against the public key it already has on file. No secret ever crosses the network — which is exactly why protecting the private key file itself (via file permissions, and ideally a passphrase) matters so much.
Public Key vs Private Key
The private key is the secret half — it's what proves your identity and must never be shared, uploaded, or committed to a repository. The public key is derived from the private key (for RSA and EC, via the underlying math; for Ed25519, directly as part of key generation) and is safe to distribute widely — that's literally its purpose. This tool always keeps decrypted private key material in memory only for as long as the conversion takes, and never transmits it.
RSA
RSA is the oldest and most widely compatible SSH key algorithm, based on the difficulty of factoring the product of two large primes. A modern RSA key should be at least 2048 bits (3072+ increasingly recommended for long-lived keys); it's supported by essentially every SSH client and server ever built, which is why it remains the default choice for maximum compatibility with older infrastructure.
ECDSA
ECDSA (Elliptic Curve Digital Signature Algorithm) uses elliptic-curve cryptography to achieve equivalent security to RSA with much smaller keys and faster operations — a 256-bit ECDSA key (nistp256) is roughly as strong as a 3072-bit RSA key. SSH supports the NIST curves P-256, P-384, and P-521 (named nistp256/384/521 in key files). All three are supported by this converter.
Ed25519
Ed25519 is a modern EdDSA signature scheme over Curve25519, designed specifically to avoid several classes of implementation pitfalls that affected earlier ECDSA deployments (weak randomness in signing, in particular). It produces small, fast keys and is now the recommended default for new SSH keys wherever compatibility allows. Because Ed25519 has no legacy PKCS#1-style PEM form, this tool always outputs it as PKCS#8 (-----BEGIN PRIVATE KEY-----) or OpenSSH format.
Why Convert PPK to PEM?
The single most common trigger is moving between operating systems or tools: a key generated years ago in PuTTYgen on a Windows machine now needs to authenticate from a Linux CI runner, a macOS terminal, or a cloud provider's console that only accepts PEM. Rather than regenerating a new key pair (which means updating every server's authorized_keys, every Git host, every CI secret), converting the existing key preserves its identity — its fingerprint stays the same — while making it usable everywhere PEM is expected.
AWS EC2
EC2 instance SSH access is authenticated with a PEM key pair (traditionally PKCS#1 for RSA) supplied at launch or imported into the console. If your existing key lives only as a .ppk file, convert it to PEM here, keep the .pem extension, and set restrictive file permissions (chmod 400 on Linux/macOS) before use with ssh -i key.pem.
Google Cloud & Azure
Both GCP's gcloud compute ssh / metadata-based SSH keys and Azure's VM SSH key resources expect standard OpenSSH public/private key pairs — PEM or OpenSSH-format private keys work directly with their CLI tooling and consoles, sidestepping any PuTTY-specific setup.
DigitalOcean
DigitalOcean droplets are provisioned with a public key uploaded to your account and use the corresponding PEM/OpenSSH private key locally for ssh root@your-droplet-ip -i key.pem — the same conversion applies if your only copy is a PuTTY .ppk file.
GitHub SSH & GitLab SSH
Both platforms authenticate Git operations over SSH using your public key, added once under account settings; your local Git client then uses the matching private key (PEM or OpenSSH format) automatically via your SSH agent or ~/.ssh/config. PuTTY users on Windows historically used Pageant instead — converting to PEM/OpenSSH format lets the same key work with Git for Windows' built-in OpenSSH client too.
Linux Servers
Any Linux server's sshd authenticates against public keys listed in each user's ~/.ssh/authorized_keys; the corresponding private key, wherever you connect from, needs to be in PEM or OpenSSH format for the standard ssh/scp/rsync command-line tools (PuTTY's own .ppk format is only understood by the PuTTY family of clients).
CI/CD Pipelines
Build systems like GitHub Actions, GitLab CI, Jenkins, and CircleCI universally expect an SSH private key secret in PEM or OpenSSH format to be injected into the job environment (e.g. via ssh-agent or a mounted file) for deploying to servers or pulling private dependencies — a .ppk file is not directly usable in these pipelines without conversion first.
Terraform
Terraform's connection blocks (for provisioners) and many providers' resource arguments expect a private_key value that's a standard PEM or OpenSSH-format string — exactly what this tool's PEM/OpenSSH output can be pasted directly into or loaded from a file via file("~/.ssh/key.pem").
Ansible
Ansible's ansible_ssh_private_key_file inventory variable (or the --private-key CLI flag) points at a PEM/OpenSSH-format file used to authenticate to managed hosts — a PuTTY .ppk file must be converted first, since Ansible relies on the system's OpenSSH client under the hood.
Docker
Dockerfiles and container build contexts that need SSH access (for private Git dependencies via BuildKit's --ssh flag, or SSH-based deployment scripts) expect a standard PEM/OpenSSH private key mounted or forwarded into the build — never a .ppk file, since the SSH client inside the container is OpenSSH.
Kubernetes
SSH private keys used by Kubernetes (as Secrets for Git-sync sidecars, SSH-based deploy jobs, or bastion-host access) are stored and mounted as plain PEM/OpenSSH text — the same format this tool produces, ready to kubectl create secret generic ssh-key --from-file=id_rsa=./key.pem.
Jenkins
Jenkins' SSH Credentials plugin stores a private key directly (pasted or uploaded) in PEM format for use by SSH-based build steps, Publish-over-SSH, or the SSH Agent plugin — a .ppk file needs converting first, since Jenkins runs on the JVM's own SSH implementations, not PuTTY.
Common Errors
- "Invalid format" when uploading a key to a cloud console — almost always means you uploaded a
.ppkfile where a PEM/OpenSSH key was expected; convert it here first. - "Load key: invalid format" in OpenSSH — the classic symptom of pointing
ssh -iat a raw PPK file, since OpenSSH's client has never understood PuTTY's native format. - Passphrase prompt loops or silently fails — usually a typo'd passphrase; this tool's structural validation after decryption catches this and reports it clearly instead of producing a corrupted key.
- Fingerprint doesn't match what you expected — check whether you're comparing an MD5 fingerprint against a SHA256 one, or a public-key fingerprint against a private-key one; this tool always shows both.
- "UNPROTECTED PRIVATE KEY FILE" warning from OpenSSH — appears when the downloaded key's file permissions are too open (e.g. group/world-readable); run
chmod 600(or400) on Linux/macOS after downloading.
Security Best Practices
- Always set a strong passphrase on a private key that will live on disk for any length of time — an unencrypted private key is a single point of compromise if the file is ever exposed.
- Set restrictive file permissions immediately after downloading a converted key (
chmod 600or400on Linux/macOS); Windows users should restrict NTFS permissions to their own account. - Never commit a private key (PPK or PEM) to a Git repository, even a private one — use a secrets manager or CI-native secret storage instead.
- Prefer Ed25519 for new keys where compatibility allows, and RSA 3072+/ECDSA nistp256+ otherwise; avoid RSA keys smaller than 2048 bits.
- Rotate keys periodically and immediately after any suspected exposure, and remove unused public keys from
authorized_keysand cloud consoles promptly.
Passphrase Protection
A passphrase encrypts the private key material at rest — even if the file is copied or stolen, it's useless without the passphrase (subject to how strong that passphrase is). This tool fully supports decrypting passphrase-protected PPK v2 (AES-256-CBC) and v3 (Argon2id/i/d) keys, and can add a fresh passphrase to your PEM output using standard PKCS#8 encryption (AES-256, PBKDF2-SHA256) — openable by OpenSSL and any standards-compliant SSH tooling.
Fingerprint Verification
Before trusting a converted key, compare its fingerprint against a fingerprint you already trust (from your original PuTTYgen session, a server's known fingerprint, or your cloud provider's console) — a mismatch means something changed, and you should investigate before proceeding. This tool computes both the SHA256 fingerprint (the modern default, shown as SHA256:base64…) and the legacy MD5 fingerprint (colon-separated hex) directly from the public key blob, matching what ssh-keygen -lf would report.
Developer Tips
- Keep both the PEM and OpenSSH outputs from a single conversion — some older tools still prefer the traditional PKCS#1 RSA PEM, while modern OpenSSH generates (and prefers) its own format by default.
- When scripting key rotation across a large fleet, verify the fingerprint programmatically after each conversion rather than eyeballing it — a single transposed character is easy to miss visually.
- For CI secrets, store the PEM output as a single-line base64 or a properly-escaped multi-line secret depending on your CI platform's requirements — most support multi-line secrets natively now.
- If a PPK v3 encrypted key takes several seconds to unlock, that's Argon2 working as designed — don't mistake it for the page hanging.