# Key Pair Generator

> RSA, ECDSA, Ed25519 and X25519 keys as PEM and OpenSSH, with CSRs and self-signed certs.

Category: Keys & Certificates · Page: https://util.caruana.me/tools/keys/

This tool has no API: it runs only in your browser.

## User guide

The tool sits in a window that works like a desktop app: menus on the top row and the **full-screen** icon at its right (**Esc** leaves full screen). The set-up options described below are in **Settings → Options…**, an overlay, and the **Settings** menu also lists the common choices directly. To keep the options in view instead, choose **View → Inline config**; the page remembers that choice. **Help → Keyboard shortcuts…** lists the keys.

1. **Choose a key type.** If you are unsure, use **Ed25519**. Types your browser cannot generate are crossed out.
2. Set the options: **RSA** size, **ECDSA** curve, and an optional **SSH comment** such as `you@laptop`.
3. Optionally **encrypt the private key** with a passphrase, and/or create a **CSR** (to send to a certificate authority) or a **self-signed certificate** (for testing and internal services).
4. Click **Generate key pair**. Every output can be copied or downloaded as a file; downloads are built in the page and saved by your browser.
5. **Store the private key safely now.** The page keeps no copy: reload or close it and the key is gone.

**Which key type?**

| Use                                                  | Choose                                                              |
| ---------------------------------------------------- | ------------------------------------------------------------------- |
| SSH (personal keys, deploy keys, host keys)          | Ed25519                                                             |
| TLS certificates for public websites                 | ECDSA P-256 (widest support), or RSA 2048/3072 for very old clients |
| Code or document signing with older tooling          | RSA 3072                                                            |
| Key agreement (age, HPKE, WireGuard-style protocols) | X25519                                                              |

**Using the output.**

- **SSH:** save the _OpenSSH private key_ as `~/.ssh/id_ed25519` (permissions `600`) and add the _OpenSSH public key_ line to the server's `~/.ssh/authorized_keys` (or to GitHub/GitLab). Add a passphrase with `ssh-keygen -p -f ~/.ssh/id_ed25519`.
- **OpenSSL / TLS servers:** use `private.pem` (PKCS#8) and `public.pem`. For a certificate authority, send `request.csr`.
- **Encrypted private key:** the page outputs `ENCRYPTED PRIVATE KEY`. Read it with `openssl pkey -in private.pem` (you will be asked for the passphrase). No unencrypted OpenSSH copy is produced in this mode, because it would defeat the passphrase.

**Check your work.** The _Equivalent commands_ box shows how to produce the same kind of key with OpenSSL and OpenSSH, if you prefer to generate it offline yourself.

## Specification

**Key generation** (Web Crypto, CSPRNG-backed).

| Type    | Parameters                                                                                           | Security level       |
| ------- | ---------------------------------------------------------------------------------------------------- | -------------------- |
| Ed25519 | RFC 8032 EdDSA over Curve25519                                                                       | ~128-bit             |
| ECDSA   | P-256, P-384 or P-521 (FIPS 186-5), with signature hash SHA-256, SHA-384 or SHA-512 respectively     | ~128 / 192 / 256-bit |
| RSA     | 2048, 3072 or 4096-bit modulus, public exponent 65537; signatures use RSASSA-PKCS1-v1_5 with SHA-256 | ~112 / 128 / 152-bit |
| X25519  | RFC 7748 key agreement; cannot sign                                                                  | ~128-bit             |

**Output formats.**

| Output                  | Format                                                                                                                                                                                                                                                                                                                                             |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Private key             | `PRIVATE KEY` PEM: PKCS#8 / RFC 5958 OneAsymmetricKey, unencrypted                                                                                                                                                                                                                                                                                 |
| Encrypted private key   | `ENCRYPTED PRIVATE KEY` PEM: RFC 5958 EncryptedPrivateKeyInfo with PBES2 (RFC 8018). Key derivation is PBKDF2 with HMAC-SHA256, 600,000 iterations by default (configurable from 100,000 to 10,000,000), and a 16-byte random salt. Encryption is AES-256-CBC with a 16-byte random IV and PKCS#7 padding. Passphrase: minimum 8 characters, UTF-8 |
| Public key              | `PUBLIC KEY` PEM: X.509 SubjectPublicKeyInfo (RFC 5280)                                                                                                                                                                                                                                                                                            |
| OpenSSH public key      | `<type> <base64> [comment]` (RFC 4253 §6.6, RFC 5656, RFC 8709)                                                                                                                                                                                                                                                                                    |
| OpenSSH private key     | `OPENSSH PRIVATE KEY` (`openssh-key-v1`), cipher `none`, random 32-bit check integers, padded to 8 bytes. Only produced without a passphrase                                                                                                                                                                                                       |
| CSR                     | PKCS#10 (RFC 2986), signed by the new key, carrying SANs in an `extensionRequest` attribute                                                                                                                                                                                                                                                        |
| Self-signed certificate | X.509 v3, details below                                                                                                                                                                                                                                                                                                                            |

**Self-signed certificate contents.**

- **Serial number:** 128 random bits, top bit cleared so the number is positive.
- **Validity:** from now, for 1 to 3650 days (365 by default).
- **Basic constraints:** `CA:FALSE`, critical.
- **Key usage:** `digitalSignature`, plus `keyEncipherment` for RSA. Critical.
- **Extended key usage:** TLS server and client authentication.
- **Subject key identifier.**
- **Subject alternative names:** the ones you entered. If you give only a common name that looks like a domain, it is also added as a DNS SAN, because browsers ignore the CN.

**Subject fields.**

- **Order:** C, ST, L, O, OU, CN, as `openssl req -subj` writes them.
- **Country:** must be a two-letter ISO 3166 code.
- **SANs:** each is classified automatically as an IPv4/IPv6 address, an email address (contains `@`) or a DNS name (LDH labels; `*` allowed as the left-most label).

**Verified compatibility.** The project's tests produced keys with this code and checked them with OpenSSL 3 and OpenSSH:

- `openssl pkey` reads every private-key format, and the public key it derives matches byte-for-byte.
- Encrypted keys decrypt with the passphrase and are rejected with a wrong one.
- `ssh-keygen -y` reads the OpenSSH private keys.
- `ssh-keygen -l` fingerprints match the ones shown here.
- `openssl verify` accepts the self-signed certificates.
- `openssl req -verify` accepts the CSRs.

**No API, by design.** Key generation is not available through the API, MCP or A2A, and never will be. A key generated on a server has been seen by that server, and this service's rule is that it never creates or receives secrets. The equivalent commands above produce the same formats offline.
