RSA vs ECDSA vs Ed25519: Choosing and Formatting Key Pairs

Security strength by key size, when RSA still makes sense, why Ed25519 became the SSH default, and how PEM, PKCS#8, JWK and OpenSSH formats relate.

· 11 min read

Illustration for the RSA and EC Key Pair Generator guide

Generating a key pair takes one click. Choosing which kind, what size, and which of half a dozen file formats to save it in is where people get stuck, and where old advice ("use RSA 4096 to be safe") lingers long after it stopped being the best answer. This guide compares the three key types you are likely to need, explains what security strength means for each, and maps out the formats so you can tell a PKCS#8 file from an OpenSSH one at a glance. Every key type and format discussed here can be produced in the RSA and EC Key Pair Generator.

Three families of public-key cryptography

RSA (Rivest, Shamir and Adleman, 1977) rests on the difficulty of factoring a large number n = p × q into its two prime factors. The public key is n and an exponent e, almost always 65537; the private key is the matching exponent d, plus p, q and some precomputed values that speed up signing. RSA can both sign and encrypt, with different padding schemes for each: PKCS#1 v1.5 or PSS for signatures, OAEP for encryption.

ECDSA signs using points on an elliptic curve. The NIST curves P-256, P-384 and P-521 (FIPS 186-5) are the common ones. The private key is a random number d, and the public key is the point d × G, where G is a fixed generator point. Security rests on the elliptic-curve discrete logarithm problem: given d × G, finding d is infeasible.

Ed25519 (RFC 8032) is an EdDSA signature scheme on the Edwards form of Curve25519, designed by Daniel J. Bernstein and colleagues. It reaches the same security level as P-256 with simpler, faster code that is easier to implement without side channels, and its signatures are deterministic.

Security strength: what the numbers mean

Key sizes are not comparable across families. A 256-bit elliptic-curve key is far stronger than a 256-bit RSA key would be. To compare them, NIST SP 800-57 Part 1 expresses each in bits of security, the work of brute-forcing a symmetric key of that length.

Chart of NIST SP 800-57 comparable strengths: 112 bits of security needs RSA 2048 or a 224-bit curve; 128 bits needs RSA 3072 or P-256 and Ed25519; 192 bits needs RSA 7680 or P-384; 256 bits needs RSA 15360 or P-521
Chart of NIST SP 800-57 comparable strengths: 112 bits of security needs RSA 2048 or a 224-bit curve; 128 bits needs RSA 3072 or P-256 and Ed25519; 192 bits needs RSA 7680 or P-384; 256 bits needs RSA 15360 or P-521
Security bitsRSA modulusElliptic curveExample
1122048224 bitsRSA 2048
1283072256 bitsP-256, Ed25519
1927680384 bitsP-384
25615360512 bits or moreP-521

RSA grows painfully: doubling security from 128 to 256 bits takes the modulus from 3072 to 15360 bits, while the curve only doubles. That is the main reason elliptic curves took over.

NIST's transition guidance (SP 800-131A, with the draft IR 8547 setting later dates) allows 112-bit strength, and therefore RSA 2048, only through 2030. RSA 4096 is not rated higher than 128 bits in the table, because the next row needs 7680. It still has a larger margin than 3072, but it costs noticeably more to generate (seconds rather than a fraction of a second in a browser) and each signature takes several times longer.

All of these, RSA and elliptic curves alike, would fall to a large fault-tolerant quantum computer running Shor's algorithm. NIST published the first post-quantum signature standards, ML-DSA (FIPS 204) and SLH-DSA (FIPS 205), in 2024. They are not yet usable in browsers' Web Crypto or in most SSH and certificate tooling, so the choice today is still among the classical types, with a plan to migrate.

Size and speed in practice

RSA 2048RSA 4096ECDSA P-256Ed25519
Public key256-byte modulus512-byte modulus65 bytes (uncompressed point)32 bytes
Private keyabout 1.2 KB as PKCS#8about 2.4 KB as PKCS#832 bytes32-byte seed
Signature256 bytes512 bytes64 bytes (r and s)64 bytes
Key generationfastslowinstantinstant
Verificationvery fastfastmoderatefast

RSA verification is quick because the public exponent 65537 is small, which is one reason RSA remains popular for certificates that are verified millions of times. For SSH logins and API signing, where both signing and verification happen often and keys are pasted around by hand, Ed25519's 68-character public key is hard to beat.

The nonce problem, and why Ed25519 avoids it

ECDSA needs a fresh secret random number k for every signature. If k is ever reused, or even slightly biased, the private key can be computed from the signatures. This is not theoretical: in 2010 the fail0verflow group recovered Sony's PlayStation 3 signing key because the same k was used for every signature, and weak random number generators on Android led to stolen Bitcoin in 2013.

RFC 6979 fixes this for ECDSA by deriving k deterministically from the private key and the message. Ed25519 builds the same idea into the standard: the per-signature secret comes from a hash of part of the private key and the message, so signing needs no randomness at all and the same message always produces the same signature. Key generation still needs good randomness, which Web Crypto takes from the operating system.

Which one should you choose?

  • SSH keys: Ed25519. OpenSSH has supported it since 6.5 (2014), and ssh-keygen creates it by default since OpenSSH 9.5. Fall back to RSA 3072 only for old servers or network devices that lack Ed25519. OpenSSH 8.8 disabled the old SHA-1 "ssh-rsa" signature algorithm by default, but RSA keys still work through rsa-sha2-256 and rsa-sha2-512.
  • TLS certificates: ECDSA P-256 is widely supported and makes handshakes smaller; RSA 2048 or 3072 for maximum compatibility. Ed25519 certificates are not accepted by browsers.
  • JWT signing: ES256 (P-256) or EdDSA where your libraries support it; RS256 (RSA PKCS#1 v1.5) is the most universally supported; PS256 if you want RSA with the PSS padding that has the stronger security proof.
  • Encryption with a public key: RSA-OAEP for small payloads such as wrapping an AES key; for anything else use a hybrid scheme (ECDH plus AES-GCM) rather than encrypting data with RSA directly.
  • Code signing, package repositories, hardware tokens: follow what the platform requires; many still mandate RSA.

Key formats: same numbers, different wrappers

A private key is a handful of integers. The formats differ only in how those integers are packaged, which is why converting between them is lossless.

Map of key formats: an RSA or EC key pair can be written as PKCS#8 PEM (BEGIN PRIVATE KEY), SPKI PEM (BEGIN PUBLIC KEY), JWK JSON with Base64url fields, an OpenSSH public line such as ssh-ed25519 AAAA, or an OpenSSH private key file (BEGIN OPENSSH PRIVATE KEY)
Map of key formats: an RSA or EC key pair can be written as PKCS#8 PEM (BEGIN PRIVATE KEY), SPKI PEM (BEGIN PUBLIC KEY), JWK JSON with Base64url fields, an OpenSSH public line such as ssh-ed25519 AAAA, or an OpenSSH private key file (BEGIN OPENSSH PRIVATE KEY)

PEM is Base64 of DER-encoded ASN.1 between -----BEGIN ...----- and -----END ...----- lines, wrapped at 64 characters. The label tells you the structure inside:

PEM labelStructureHolds
PRIVATE KEYPKCS#8 (RFC 5208, 5958)any algorithm, with an algorithm identifier
ENCRYPTED PRIVATE KEYPKCS#8, password-protectedany algorithm
RSA PRIVATE KEYPKCS#1 (RFC 8017)RSA only
EC PRIVATE KEYSEC 1 (RFC 5915)EC only
PUBLIC KEYSubjectPublicKeyInfo (RFC 5280)any algorithm
RSA PUBLIC KEYPKCS#1RSA only
OPENSSH PRIVATE KEYopenssh-key-v1 (OpenSSH PROTOCOL.key)any SSH key type

PKCS#8 and SPKI are the modern defaults: OpenSSL 3, Java, .NET, Go and Web Crypto all read them. The generator exports those two.

JWK (RFC 7517 and 7518) writes the same integers as Base64url strings in JSON: n and e for an RSA public key, plus d, p, q, dp, dq and qi for the private key; crv, x and y for an EC public key, plus d for the private one; crv: "Ed25519" and x (and d) for Ed25519, which uses key type OKP from RFC 8037. JWKs are what OAuth and OpenID Connect servers publish at their JWKS endpoints.

A JWK thumbprint (RFC 7638) is the SHA-256 of the key's required members in a fixed order, Base64url-encoded. For the RSA example key in RFC 7638 it is NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs. Many identity providers use the thumbprint as the kid, so the key ID is derived from the key and cannot drift.

OpenSSH public keys are one line: the type, the Base64 of a binary blob in the SSH wire format (RFC 4253), and a comment. The blob begins with the type name, so the Base64 begins predictably: AAAAB3NzaC1yc2E for ssh-rsa, AAAAE2VjZHNhLXNoYTItbmlzdHAyNTY for ecdsa-sha2-nistp256 and AAAAC3NzaC1lZDI1NTE5 for ssh-ed25519.

OpenSSH private keys have used their own openssh-key-v1 container since OpenSSH 6.5. It holds the public blob, then a private section with two copies of a random check value, the key's numbers, the comment and padding. When a passphrase is set, the private section is encrypted (aes256-ctr) with a key derived by bcrypt-pbkdf. The files from the generator are unencrypted; add a passphrase with ssh-keygen -p -f ~/.ssh/id_ed25519.

Fingerprints

When GitHub or a server shows "SHA256:..." for your key, that is the SHA-256 of the OpenSSH public blob, Base64-encoded without the trailing =. ssh-keygen -l -f key.pub prints the same value, and so does the generator. Older tools showed an MD5 fingerprint as colon-separated hex (ssh-keygen -l -E md5); it identifies the same key but should not be relied on for anything security sensitive.

Converting between formats

TaskCommand
Public key from a private PEMopenssl pkey -in private.pem -pubout -out public.pem
Add a passphrase to PKCS#8openssl pkcs8 -topk8 -v2 aes-256-cbc -in private.pem -out private-enc.pem
SPKI PEM to OpenSSH public linessh-keygen -i -m PKCS8 -f public.pem
OpenSSH public line to SPKI PEMssh-keygen -e -m PKCS8 -f id_ed25519.pub
Public key from an OpenSSH private filessh-keygen -y -f id_ed25519
Inspect any PEMopenssl pkey -in private.pem -text -noout

For JWK conversions, Web Crypto's importKey('jwk', ...) followed by exportKey('spki' | 'pkcs8', ...) does the job in a browser, which is what the JWK Tool uses.

Handling private keys safely

  • Generate long-lived production keys on the machine or HSM that will use them, so the private key never travels. A browser generator is convenient for SSH keys on a personal machine, development and test keys, and learning.
  • Encrypt private keys at rest with a passphrase or keep them in an agent, keychain or secrets manager.
  • Set file permissions to 600; OpenSSH refuses to use a private key that other users can read.
  • Never commit private keys. Secret-scanning services find them in public repositories within minutes.
  • Rotate keys you suspect have leaked, and remove the old public key from every authorized_keys file and JWKS endpoint.

To inspect an existing certificate's key, the X.509 Parser shows the algorithm and size, and the Digital Signature Validator verifies signatures made with these keys.

Sources

  • NIST SP 800-57 Part 1 Rev. 5, Recommendation for Key Management, Table 2 (comparable strengths).
  • NIST SP 800-131A Rev. 2 and draft NIST IR 8547, transition of cryptographic algorithms and key lengths.
  • FIPS 186-5, Digital Signature Standard; RFC 8032, Edwards-Curve Digital Signature Algorithm; RFC 6979, deterministic ECDSA.
  • RFC 5208 and 5958 (PKCS#8), RFC 5280 (SubjectPublicKeyInfo), RFC 8017 (PKCS#1), RFC 7517, 7518, 7638 and 8037 (JWK).
  • RFC 4253 (SSH transport, public key format) and OpenSSH PROTOCOL.key; OpenSSH 8.8 and 9.5 release notes.

Related searches

  • rsa vs ecdsa
  • ed25519 vs rsa
  • rsa key size
  • pem vs jwk
  • pkcs8 vs pkcs1
  • openssh private key format
  • ssh key fingerprint
  • rsa 2048 security bits
  • jwk thumbprint

Open the RSA and EC Key Pair Generator