About RSA Key Pair Generator
This generates a fresh RSA key pair in your browser: a private key you keep and a public key you can hand out. Key generation searches for two large random primes, so it is noticeably slower than other crypto operations - a few hundred milliseconds for 2048 bits, and several seconds for 4096.
2048 bits is the practical minimum today and remains appropriate for most uses. 3072 and 4096 buy a longer margin, at a cost that grows faster than the key size - RSA operations scale roughly with the cube of the modulus, so 4096-bit signing is several times slower than 2048. For new systems that are not constrained by an existing spec, elliptic-curve keys (Ed25519 or ECDSA P-256) give equivalent strength at a fraction of the size and cost.
The public exponent is 65537. It is large enough to avoid the attacks that affect e=3 and cheap to compute because it has only two set bits, and there is no good reason to change it.
Keys are emitted as PEM: the public key as SPKI (-----BEGIN PUBLIC KEY-----) and the private key as PKCS#8 (-----BEGIN PRIVATE KEY-----), which is what Web Crypto, Java and modern OpenSSL expect. If a tool demands the older PKCS#1 form (-----BEGIN RSA PRIVATE KEY-----), convert it rather than regenerating.
Generation happens locally and nothing is transmitted. Keys produced in a browser tab are ideal for development and testing; for a key that will protect production data, generate it with your own tooling in the environment where it will live.
How to use the RSA Key Pair Generator
- Choose a key size - 2048 for general use, 3072 or 4096 where you want a longer margin and can accept slower operations.
- Generate. Expect a short pause: finding two large primes is genuinely expensive work.
- Copy the public key to whoever needs to encrypt for you or verify your signatures.
- Store the private key somewhere secret. If a library rejects the format, convert between PKCS#8 and PKCS#1 with openssl rather than generating a new pair.
RSA Key Pair Generator in code
The same operation this tool performs, in the languages you are most likely to need it.
// Generate a key pair
const kp = await crypto.subtle.generateKey(
{
name: "RSA-OAEP",
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]), // 65537
hash: "SHA-256",
},
true,
["encrypt", "decrypt"]
);
const ct = await crypto.subtle.encrypt(
{ name: "RSA-OAEP" }, kp.publicKey,
new TextEncoder().encode("short secret")
);
const pt = await crypto.subtle.decrypt({ name: "RSA-OAEP" }, kp.privateKey, ct);
console.log(new TextDecoder().decode(pt));
// Export: Web Crypto uses SPKI for public keys, PKCS#8 for private.
const spki = await crypto.subtle.exportKey("spki", kp.publicKey);
import { generateKeyPairSync, publicEncrypt, privateDecrypt, constants } from "node:crypto";
const { publicKey, privateKey } = generateKeyPairSync("rsa", {
modulusLength: 2048,
publicKeyEncoding: { type: "spki", format: "pem" },
privateKeyEncoding: { type: "pkcs8", format: "pem" },
});
const opts = {
padding: constants.RSA_PKCS1_OAEP_PADDING,
oaepHash: "sha256", // must match on both sides
};
const ct = publicEncrypt({ key: publicKey, ...opts }, Buffer.from("short secret"));
const pt = privateDecrypt({ key: privateKey, ...opts }, ct);
console.log(pt.toString());
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()
pad = padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None,
)
ct = public_key.encrypt(b"short secret", pad)
print(private_key.decrypt(ct, pad))
pem = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
# Generate a 2048-bit key pair
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private.pem
openssl rsa -in private.pem -pubout -out public.pem
# Encrypt with OAEP + SHA-256 (defaults to SHA-1 without the pkeyopt!)
openssl pkeyutl -encrypt -pubin -inkey public.pem \
-pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 \
-in plain.txt -out cipher.bin
# Decrypt
openssl pkeyutl -decrypt -inkey private.pem \
-pkeyopt rsa_padding_mode:oaep -pkeyopt rsa_oaep_md:sha256 \
-in cipher.bin
# Convert PKCS#1 -> PKCS#8 if a library rejects your key
openssl pkcs8 -topk8 -nocrypt -in pkcs1.pem -out pkcs8.pem
// This is how TLS, PGP and every real system encrypt large payloads:
// RSA protects a random AES key; AES protects the data.
const aesKey = await crypto.subtle.generateKey(
{ name: "AES-GCM", length: 256 }, true, ["encrypt", "decrypt"]
);
const iv = crypto.getRandomValues(new Uint8Array(12));
const payload = await crypto.subtle.encrypt(
{ name: "AES-GCM", iv }, aesKey, new TextEncoder().encode(bigDocument)
);
// Wrap the 32-byte AES key with RSA - well under the size limit.
const raw = await crypto.subtle.exportKey("raw", aesKey);
const wrapped = await crypto.subtle.encrypt({ name: "RSA-OAEP" }, publicKey, raw);
// Send { wrapped, iv, payload }. The recipient unwraps with RSA,
// then decrypts the payload with AES.
When you need this
- Creating a throwaway key pair for local development or a test suite.
- Producing a key pair to exchange with a partner during integration work.
- Generating a key to sign JWTs with RS256 rather than a shared HS256 secret.
- Getting a correctly formatted PEM to test a parser or a deployment secret.
Common problems and what causes them
- "Data too large for key size" / "message too long"
- RSA cannot encrypt data longer than its key. With OAEP and SHA-256 the limit is the modulus size minus 66 bytes - 2048-bit key: 190 bytes; 3072-bit key: 318 bytes; 4096-bit key: 446 bytes. If you need to encrypt more than that, you do not want plain RSA; see hybrid encryption below.
- Mixing OAEP and PKCS#1 v1.5 padding between the two sides
- A ciphertext padded with OAEP cannot be decrypted as PKCS#1 v1.5 or vice versa - you get a decryption error or garbage. Both sides must agree on the padding scheme and, for OAEP, on the hash function. OAEP with SHA-256 is the right default; PKCS#1 v1.5 encryption is vulnerable to Bleichenbacher-style attacks and should only be used for compatibility.
- PEM header mismatch: PKCS#1 vs PKCS#8 vs SPKI
- A key starting "-----BEGIN RSA PRIVATE KEY-----" is PKCS#1; "-----BEGIN PRIVATE KEY-----" is PKCS#8; "-----BEGIN PUBLIC KEY-----" is SPKI. Libraries are picky: Web Crypto wants PKCS#8 and SPKI, OpenSSL will read all of them, and Java wants PKCS#8. Converting is a one-line openssl command, not a reason to regenerate the key.
- Encrypting with the private key to 'sign'
- Signing is a separate operation with its own padding (RSASSA-PKCS1-v1_5 or RSASSA-PSS), not 'encryption with the private key'. Use the sign/verify APIs; do not invert encrypt/decrypt.
- Ciphertext encoding confusion
- RSA output is exactly as many bytes as the modulus (256 bytes for a 2048-bit key), and is then usually Base64'd for transport. If your Base64 decodes to a length that is not the modulus size, the ciphertext is truncated or double-encoded.
- Line endings and whitespace in a pasted PEM
- PEM parsers expect the base64 body wrapped at 64 characters with the exact header and footer lines. A PEM pasted from a JSON string with literal \n sequences, or with the newlines stripped, will fail to parse - convert the escapes back to real newlines first.
FAQ
- Why is generation so much slower than encrypting?
- Because it has to find two large random primes, which means generating candidates and running primality tests until they pass. 2048 bits is usually a few hundred milliseconds; 4096 bits can take several seconds. Encryption afterwards is a single modular exponentiation and is fast.
- Should I use RSA or an elliptic-curve key?
- If nothing constrains you, prefer Ed25519 for signing or X25519 for key exchange: far smaller keys, much faster operations, and fewer ways to misuse them. Choose RSA when you need to interoperate with something that requires it - many enterprise systems, older TLS stacks, and specifications that predate EdDSA.
- Why can't RSA encrypt my file or long string?
- RSA can only encrypt data smaller than its key. With OAEP and SHA-256 the maximum is the modulus size minus 66 bytes - 2048-bit key: 190 bytes; 3072-bit key: 318 bytes; 4096-bit key: 446 bytes. Real systems never encrypt bulk data with RSA: they generate a random AES key, encrypt the data with AES, and use RSA only to encrypt that key. That is called hybrid encryption and there is a worked example in the code section above.
- OAEP or PKCS#1 v1.5?
- OAEP with SHA-256 for anything new. PKCS#1 v1.5 encryption padding is vulnerable to Bleichenbacher-style chosen-ciphertext attacks and survives only for compatibility with old systems. Whichever you pick, both sides must match exactly, including the OAEP hash.
- How big should an RSA key be?
- 2048 bits is the practical minimum today and is fine for most purposes; 3072 or 4096 gives a longer margin. Note that RSA cost grows steeply - 4096-bit operations are several times slower than 2048 - and that modern systems increasingly prefer elliptic-curve keys (Ed25519, ECDSA P-256) for equivalent strength at far smaller sizes.
- What is the public exponent 65537 and should I change it?
- 65537 (0x10001) is the standard public exponent: large enough to avoid the small-exponent attacks that affect e=3, and cheap to compute because it has only two set bits. Leave it alone unless a specification tells you otherwise.
- Can I recover the public key from the private key?
- Yes - a private key contains everything needed, and `openssl rsa -in private.pem -pubout` extracts it. The reverse is not possible, which is the entire point.
- Is my private key safe to paste into this page?
- The operations run in your browser through the Web Crypto API and nothing is uploaded. That said, the safest habit with a production private key is to not paste it into any web page at all - generate a throwaway key here for testing, and keep real keys in your own tooling.
Related reading
- PEM validator check a key's format
- AES-GCM encrypt for bulk data