Skip to content

Free Online RSA Key Pair Generator — ECDSA and Ed25519

Generate an RSA key pair online — the private key never leaves your browser. RSA 2048/4096, ECDSA and Ed25519, in PKCS#8 or PKCS#1 PEM, with JWK and fingerprint.

No Tracking Runs in Browser Free
Key pairs are generated inside your browser with the Web Crypto API, and no network request is made while generating. Disconnect and this page still works.

PKCS#8 (BEGIN PRIVATE KEY) is the modern default and what the JDK expects. PKCS#1 (BEGIN RSA PRIVATE KEY) is OpenSSL's traditional form, still required by some gateways. Switching re-encodes the same key.

Keep this secret. Anyone holding it can impersonate you.

Public key fingerprint — SHA-256 of the SPKI DER
JWK (JSON Web Key)
Private JWK — never publish this one
 
Public JWK
 

Generate the same kind of key pair with OpenSSL

Reviewed for RFC 5958/5208 (PKCS#8), RFC 8017 (PKCS#1), RFC 8410 (Ed25519) and RFC 7468 PEM encoding correctness, and for Web Crypto API behaviour across RSA, ECDSA and Ed25519. — Go Tools Security Tooling Team · Aug 10, 2026

Our team verifies the PKCS#8 to PKCS#1 conversion byte for byte against reference output from Node's crypto module, so a key exported here is identical to one OpenSSL would produce for the same material.

What Is an RSA Key Generator?

An RSA key generator produces a mathematically linked pair: a private key you keep and a public key you hand out. Anything signed with the private half can be verified with the public half, and only the public half is safe to publish. That asymmetry is the whole point — it is what lets a verifier check your signatures without gaining the ability to forge them, which a shared secret can never offer.

This generator runs inside your browser through the Web Crypto API, so the private key is created in the tab and the page makes no network request while generating. Beyond RSA it also produces ECDSA and Ed25519 pairs, which serve the same purpose with much shorter keys: an Ed25519 private key is 48 bytes in PKCS#8 where a 2048-bit RSA key runs past 1.2 KB.

The part that trips people up is not the mathematics but the packaging. The same key can be written as PKCS#8, PKCS#1, SPKI or JWK, and a library that rejects one will often accept another with no clearer message than a parse error. The table further down maps each container to the ecosystems that expect it.

// Verify a downloaded key pair matches, using OpenSSL:
openssl pkey -in rsa-2048-private.pem -pubout | diff - rsa-2048-public.pem
// No output means the public key really belongs to that private key.

Key Features

Generated in your browser

Keys come from the Web Crypto API in your own tab, and the page makes no network request while generating. Turn off your connection and it keeps working, which shows the tool needs no server to do its job.

RSA, ECDSA and Ed25519

RSA 2048, 3072 and 4096; ECDSA on P-256, P-384 and P-521; and Ed25519, all from one page with the same export options.

PKCS#8 and PKCS#1 output

Switch between BEGIN PRIVATE KEY and the traditional BEGIN RSA PRIVATE KEY layout without touching OpenSSL. The switch re-encodes the key already on screen, so it stays the same key.

JWK export

Both halves are available as JSON Web Keys. The public JWK is what goes into a JWKS document or a JOSE verifier; the private JWK is for your signer alone and must never be published.

SHA-256 fingerprint

Every pair comes with a fingerprint of its public key so you can verify out of band that both sides hold the same key.

Matching OpenSSL commands

The equivalent commands for generating the same kind of key locally are shown beneath the output, so you can move to the command line whenever you prefer.

Downloads with sensible names

Files save as rsa-2048-private.pem and rsa-2048-public.pem rather than a generic download name you have to rename.

No account, no rate limit

There is no server involved, so there is nothing to sign up for and no quota to exhaust.

Worked Examples

Ed25519 pair, shown in full

Algorithm: Ed25519
-----BEGIN PRIVATE KEY-----
MC4CAQAwBQYDK2VwBCIEIA2HJVU1qChbOJN8XksXVhyD0IjYVt0UU6Mwz814rOFf
-----END PRIVATE KEY-----

-----BEGIN PUBLIC KEY-----
MCowBQYDK2VwAyEAV5uB7UaPJrtncx3SXNtNzn1ZXjF1ApwvzBZ8nFzT5eU=
-----END PUBLIC KEY-----

An Ed25519 private key is 48 bytes in PKCS#8 and the public key is 44 bytes, so each PEM holds a single line of base64. This is a throwaway demonstration pair — generate your own rather than copying it.

PKCS#8 and PKCS#1 headers differ

Algorithm: RSA 2048, structure toggled
PKCS#8:  -----BEGIN PRIVATE KEY-----
PKCS#1:  -----BEGIN RSA PRIVATE KEY-----

Same key, two wrappers. PKCS#8 adds an algorithm identifier around the RSA structure, which is why it works for every algorithm while PKCS#1 exists only for RSA. Toggling the switch re-encodes the key already on screen, so the fingerprint does not change.

RSA 2048 public key

Algorithm: RSA 2048
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtuvUHLjyK9zje2aaNIni
eSccN1uleXFRBb1g2TN6bk/fbpPCGDyh71m73oB9Bk8+fKVkSThXyWTtpgblB7pX
iQBtTvSWVZGHprkLgMGkU2Yw8Z43m1WpoRuYyXNFe92S5viIdVuKTj/VEUuEpzHd
ffWMIUw70LaUdTP04iQdkNVeS3M6VHkpTwsPSQfsFSwObtLVNy2Lf+ODwJRqCk2r
C749hgKqBdJqkcIj49R7UP4SMQ/9V3yy8DFMrIcgsjC4tHwlQSCGeXNxTNlapGSa
ke55LUR83FASryVJRbUs678SCZSFkyGcT0qLZ/olu/e7Jj2lB0Qy/SJawkrs9hPE
4QIDAQAB
-----END PUBLIC KEY-----

The MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A prefix is the rsaEncryption algorithm identifier, which is how you can recognise an RSA SPKI key on sight.

Public key as JWK

Algorithm: Ed25519, JWK panel
{
  "key_ops": [
    "verify"
  ],
  "ext": true,
  "alg": "Ed25519",
  "crv": "Ed25519",
  "x": "V5uB7UaPJrtncx3SXNtNzn1ZXjF1ApwvzBZ8nFzT5eU",
  "kty": "OKP"
}

This is the export verbatim, including the key_ops and ext members that Web Crypto always adds. A JWKS entry does not want them — drop both, and add kid and use instead so verifiers can select the right key during rotation. Ed25519 lands in the OKP key type; RSA keys appear as kty RSA with n and e members.

SHA-256 fingerprint

Algorithm: Ed25519
SHA256(SPKI) = KAXVxapxpG4zLsTVMpPafovT+X1NLWc8fsOXqtrb59o=

A SHA-256 digest of the public key structure, short enough to read over the phone. Note this is not the value ssh-keygen prints — OpenSSH hashes its own wire format, so the two never agree for the same key.

How to Use the RSA Key Generator

  1. 1

    Pick the algorithm

    RSA covers the widest range of legacy systems. ECDSA gives equivalent strength in far smaller keys. Ed25519 is the modern default for new signing work.

  2. 2

    Choose the key size

    RSA 2048 meets current guidance; 3072 and 4096 add margin for long-lived keys. ECDSA offers P-256, P-384 and P-521. Ed25519 has one fixed size.

  3. 3

    Select the PEM structure

    PKCS#8 emits BEGIN PRIVATE KEY and works nearly everywhere, including the JDK. Switch to PKCS#1 only when something specifically demands BEGIN RSA PRIVATE KEY.

  4. 4

    Copy or download both halves

    The private key goes into your secret store. The public key goes to whoever verifies your signatures. Never send the private half anywhere.

  5. 5

    Verify the fingerprint

    Compare the SHA-256 fingerprint over a separate channel to confirm the other side installed the public key you actually generated.

Common Key Format Mistakes

Pasting the public key where the private key belongs

Signing needs the private half. A library given BEGIN PUBLIC KEY where it expected a private key usually reports an unhelpful parse error rather than naming the real problem.

✗ Wrong
-----BEGIN PUBLIC KEY-----
✓ Correct
-----BEGIN PRIVATE KEY-----

Wrong PEM structure for the library

A few ecosystems read only the traditional RSA layout — OpenSSL's own -traditional output, some payment-gateway SDKs, older Ruby and Perl tooling. Most modern libraries, and the JDK in particular, expect PKCS#8. Switch the PEM structure toggle instead of hunting for a conversion command.

✗ Wrong
-----BEGIN RSA PRIVATE KEY-----
✓ Correct
-----BEGIN PRIVATE KEY-----

Losing the trailing newline

PEM files end with a newline after the final delimiter. Copying through a form field that trims whitespace produces a file some parsers reject outright — and because the missing character is invisible, the file looks correct in an editor.

✗ Wrong
-----END PRIVATE KEY-----[EOF]
✓ Correct
-----END PRIVATE KEY-----↵[EOF]

A character lost in transit

What breaks a PEM is a lost, inserted or substituted character, not the line width — most parsers accept any wrapping. A copy through a chat client or a form field can silently turn a line break into a space, and base64 gives no hint which character went wrong; the key simply fails to load. Use the copy button rather than selecting by hand.

✗ Wrong
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtuvUHLjyK9zje2aaNIni eSccN1uleXFRBb1g2TN6bk
✓ Correct
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtuvUHLjyK9zje2aaNIni
eSccN1uleXFRBb1g2TN6bk

Using an HS256 secret where RS256 is configured

HS256 takes one shared secret; RS256 takes a key pair. Feeding a random string to an RS256 signer fails at the parse step. Generate the pair here, or use our JWT secret generator if you meant HS256.

✗ Wrong
alg: RS256, key: 8f3a9c2e1b7d
✓ Correct
alg: RS256, key: -----BEGIN PRIVATE KEY-----

Pasting a PEM into authorized_keys

An SSH public key is OpenSSH's one-line ssh-ed25519 AAAA… format, not a PEM block, so pasting the public key from this page into authorized_keys will not work. For an RSA key you can derive the right line locally with ssh-keygen -y; for SSH access generally, generating on the target machine is better still.

✗ Wrong
-----BEGIN PUBLIC KEY-----
✓ Correct
ssh-keygen -y -f rsa-2048-private.pem > id_rsa.pub

Who Uses This Tool

Signing JWTs with RS256 or EdDSA
Asymmetric JWT algorithms need a key pair rather than a shared secret. Sign with the private key, publish the public key, and verifiers never hold anything that lets them mint tokens. Our JWT encoder accepts the keys this page produces.
Signing webhooks and releases
Publish the public key once, sign every payload with the private key, and consumers can verify authenticity without a shared credential to leak.
Local development and tests
Test suites that exercise signature verification need a throwaway key pair. Generating one here is faster than remembering the OpenSSL invocation.
Learning what a key pair looks like
Switching between algorithms and PEM structures side by side makes the differences concrete in a way that reading a specification does not.
Preparing a JWKS endpoint
The public JWK drops straight into a keys array for an OpenID Connect discovery document. Add a kid so verifiers can select it during rotation, and keep the private JWK out of that file.
Migrating away from RSA
Generate the Ed25519 replacement next to the RSA original and compare the sizes before committing to the change.
Fixing a format mismatch
When a library rejects a key with a parse error, re-emitting it in the other PEM structure is usually the whole fix.

PEM Formats and How the Generator Works

Which container goes where
One key, five packages. Picking the wrong one is the most common reason a key is rejected, and the error message is rarely more specific than a parse failure.
ContainerPEM headerHoldsWhere you meet it
PKCS#8BEGIN PRIVATE KEYAny algorithmWeb Crypto, the JDK, Go, .NET — most modern libraries
PKCS#1BEGIN RSA PRIVATE KEYRSA onlyOpenSSL traditional output, some payment gateways, older Ruby and Perl tooling
SPKI / X.509BEGIN PUBLIC KEYAny algorithm, public halfThe public key nearly every library expects
PKCS#1 publicBEGIN RSA PUBLIC KEYRSA only, public halfLegacy RSA tooling
JWKnone — it is JSONAny algorithmJWKS endpoints, OIDC discovery, JOSE libraries
To convert files you already have, openssl pkcs8 -topk8 -nocrypt -in pkcs1.pem -out pkcs8.pem goes one way and openssl rsa -traditional -in pkcs8.pem -out pkcs1.pem goes the other.
Randomness comes from the operating system
Web Crypto seeds key generation from the platform entropy source — getrandom on Linux, and the system CSPRNG on Windows and macOS. It is the same class of source OpenSSL draws from, not a JavaScript pseudo-random generator.
Generation does not freeze the page
crypto.subtle.generateKey is asynchronous, and in the major browser engines the search for primes happens off the main thread, so the interface stays responsive while a 4096-bit modulus is being found. The page shows a spinner regardless, because how long that search takes depends on the luck of the draw.
PKCS#8 wraps PKCS#1
A PKCS#8 PrivateKeyInfo is a version number, an algorithm identifier and an OCTET STRING. For an unencrypted rsaEncryption key, that OCTET STRING contains a complete PKCS#1 RSAPrivateKey, which is exactly how this page converts between the two without re-deriving anything.
Public keys use SubjectPublicKeyInfo
BEGIN PUBLIC KEY is an X.509 SubjectPublicKeyInfo: an algorithm identifier plus a BIT STRING. What sits in those bits depends on the algorithm — for RSA it is a PKCS#1 RSAPublicKey, which is why BEGIN RSA PUBLIC KEY is shorter; for ECDSA it is the uncompressed curve point, and for Ed25519 the raw 32-byte key.
The public exponent is 65537
Every RSA key here uses e = 65537, written 0x010001. It is large enough to avoid small-exponent attacks and has only two set bits, so verification costs 16 squarings and a single multiply.
Fingerprints digest the DER, not the PEM
The SHA-256 fingerprint is taken over the binary SubjectPublicKeyInfo. Fingerprinting the base64 text instead would change whenever line wrapping changed. The equivalent locally is openssl pkey -in private.pem -pubout -outform DER | openssl dgst -sha256 -binary | openssl base64.

Key Management Best Practices

Generate keys where they will be used
A private key that travels across a network has been exposed to every hop along the way. Generating in the browser keeps the key itself off the network, though the page's own code still arrives over it; generating on the target host removes even the copy step. For a key protecting production systems, prefer the host.
Prefer Ed25519 unless something requires RSA
Ed25519 gives strong security in a 32-byte key with fast signing and no parameter choices to get wrong. Reach for RSA when a counterparty or an old library leaves you no option.
Treat 2048 bits as the floor
NIST SP 800-131A has disallowed RSA below 2048 bits for signature generation since 2013, and no public certificate authority will issue against a smaller key. Choose 3072 or 4096 for keys expected to stay in service for many years.
Never commit a private key
Put private keys in a secret manager or an environment variable loaded at runtime. Once a key reaches a repository, rotating it is the only safe response.
Rotate on a schedule, not only after an incident
Publish new public keys with a key ID before retiring the old ones so verifiers can accept both during the overlap. Rotation practised routinely is rotation that works under pressure.

Frequently Asked Questions

Is it safe to generate a private key on a website?
The key is generated by the Web Crypto API in your own browser, and this page makes no network request while generating — you can watch the Network panel, or disconnect and see that generation still works. Be clear about what that shows and what it does not: it demonstrates the page needs no server, but it is not proof against a compromised script, since the JavaScript is re-fetched from our server on every visit. The risks that remain are the browser's rather than the network's — a malicious extension can read the page and your clipboard, and anyone with access to the machine can read the downloaded file. For a key protecting production systems, generate it on the host that will use it; the OpenSSL commands below do exactly that. This page is the right tool for development, testing, learning, and anywhere a browser-generated key is acceptable.
What is the difference between PKCS#8 and PKCS#1?
They are two containers for the same RSA key. PKCS#1, marked BEGIN RSA PRIVATE KEY, holds the RSA numbers directly and exists only for RSA. PKCS#8, marked BEGIN PRIVATE KEY, wraps those same numbers in an algorithm identifier, which lets one format carry RSA, ECDSA and Ed25519 alike. Most modern libraries expect PKCS#8 — the JDK, notably, reads only PKCS#8 without an extra library — while a number of payment gateways and older OpenSSL-era tooling still require PKCS#1. Switching the toggle on this page re-encodes the key already on screen, so no information is added or lost and the fingerprint stays the same.
How do I convert a PKCS#1 key to PKCS#8, or back?
Switch the PEM structure toggle on this page and the same key is re-emitted in the other container. For a file you already have, OpenSSL converts locally: openssl pkcs8 -topk8 -nocrypt -in pkcs1.pem -out pkcs8.pem turns a BEGIN RSA PRIVATE KEY file into BEGIN PRIVATE KEY, and openssl rsa -traditional -in pkcs8.pem -out pkcs1.pem goes the other way. Neither direction adds or removes key material; only the wrapper changes, which is why both files describe the identical key and produce the identical fingerprint.
How do I get the public key from an RSA private key?
The public key is derivable from the private key, never the reverse. This page shows both halves at once, so there is nothing to derive. For a private key you already have on disk, openssl pkey -in private.pem -pubout -out public.pem writes the matching BEGIN PUBLIC KEY file. That is also how you check whether a pair belongs together — regenerate the public half and compare it against the file you were given.
Should I choose RSA or Ed25519?
Choose Ed25519 when nothing forces your hand. It reaches security comparable to RSA 3072 with a 32-byte key, signs faster, and has no parameters to misconfigure. Choose RSA when a counterparty, a certificate authority or an old library requires it, which is still common in enterprise and payment systems. ECDSA sits between the two and is widely supported in TLS.
Is 2048-bit RSA still strong enough?
Yes, for most purposes today. NIST rates 2048-bit RSA at 112-bit security strength and carries it through 2030 in SP 800-57; 3072-bit reaches 128-bit strength and is what NIST points to beyond that. So: 2048 for anything you will rotate within a few years, 3072 or 4096 for a key you expect still in service in the 2030s or where a certificate authority requires it. The cost of the larger key is slower signing and larger signatures, not weaker security.
Can I use these keys to sign JWTs?
Yes. RSA keys work with RS256, RS384 and RS512 as well as the PSS variants; ECDSA P-256 pairs with ES256; and Ed25519 is the EdDSA algorithm. Sign with the private key and publish the public key so verifiers can check signatures without being able to create them. One caveat if you use the JWK panel rather than the PEM: Web Crypto stamps an RSA JWK with alg RS256, and strict libraries refuse to load it for PS256 or RS512 — delete the alg member, or use the PEM. Our JWT encoder accepts these keys, and the decoder shows what the resulting token contains.
Can this generate an SSH key?
Not directly. OpenSSH's own private key file is a different container, and this page does not write it. An RSA key from here is still usable: ssh-keygen -y -f rsa-2048-private.pem > id_rsa.pub derives the authorized_keys line from the file you downloaded. Ed25519 keys from here are not, because OpenSSH rejects the PKCS#8 form. For SSH access the better answer remains ssh-keygen -t ed25519 on the machine that needs the key, which avoids moving a private key at all. For JWT signing, CI release signing and webhook verification, the PKCS#8 key this page produces is exactly what those tools want.
Can I protect the private key with a passphrase?
Not here. Encrypted PKCS#8 requires a key derivation step that the Web Crypto API does not expose, so implementing it would mean hand-rolling cryptography in JavaScript. Add the passphrase locally instead: openssl pkcs8 -topk8 -in private.pem -out encrypted.pem reads the file you downloaded and prompts for one.
What is the fingerprint for?
It is a SHA-256 digest of the public key structure, short enough to compare by voice or in a chat message. When you send someone a public key, comparing fingerprints over a separate channel confirms that what arrived is what you sent. It identifies the public key only and reveals nothing about the private half. Note that it is not the number ssh-keygen -l prints: OpenSSH hashes its own wire format rather than the SPKI structure, so the two never match for the same key.

Related Tools

View all tools →