Skip to content

PGP Key Generator — TypeScript source

Generate PGP key pairs (ECC or RSA) in your browser. Download your public and private keys. Powered by OpenPGP.js.

This is the TypeScript implementation — the same logic the interactive tool runs, in a shareable, citable form.

import { generateKey, readKey } from 'openpgp';

/**
 * PGP key pair generation (pure lib, no React/DOM) — a thin wrapper around
 * openpgp.js `generateKey`. Keys are generated in the caller's context; the
 * island runs this entirely client-side, so the private key never leaves the
 * browser.
 */

/** Algorithm choices: ECC Curve25519 (default), RSA-2048, or RSA-4096. */
export type PGPKeyGenAlgorithm = 'ecc' | 'rsa2048' | 'rsa4096';

export interface PGPKeyGenOptions {
  /** User's real name (goes into the key's user ID packet). */
  name: string;
  /** User's email (goes into the key's user ID packet). */
  email: string;
  /** Optional passphrase. If given, the private key is encrypted with it. */
  passphrase?: string;
  algorithm: PGPKeyGenAlgorithm;
}

export interface PGPKeyPair {
  /** ASCII-armored public key (BEGIN PGP PUBLIC KEY BLOCK). */
  publicKey: string;
  /** ASCII-armored private key (BEGIN PGP PRIVATE KEY BLOCK). */
  privateKey: string;
  /** v4 fingerprint, 40 lowercase hex chars, no spaces. */
  fingerprint: string;
  /** ASCII-armored revocation certificate. */
  revocationCertificate: string;
}

/** Accepts `foo@bar.tld`-style addresses: one @, non-empty local + domain, a dot in the domain. */
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;

/** Validate the identity that goes into the key's user ID. Throws on invalid input. */
export function validateKeyGenIdentity(name: string, email: string): void {
  if (!name.trim()) throw new Error('Name is required.');
  if (!email.trim()) throw new Error('Email is required.');
  if (!EMAIL_RE.test(email.trim())) throw new Error('Invalid email address.');
}

/** Generate an ASCII-armored PGP key pair. ECC (Curve25519) is fast; RSA-4096 can take a few seconds. */
export async function generatePGPKeyPair(options: PGPKeyGenOptions): Promise<PGPKeyPair> {
  const { name, email, passphrase, algorithm } = options;
  validateKeyGenIdentity(name, email);

  // Concrete literal params per branch — generateKey's overloads reject a
  // spread of the ecc/rsa param union.
  const userID = { name: name.trim(), email: email.trim() };
  // An empty-string passphrase would still encrypt the key; only a real
  // passphrase should.
  const pass = passphrase ? passphrase : undefined;

  const { publicKey, privateKey, revocationCertificate } =
    algorithm === 'ecc'
      ? // v6 API: modern X25519/Ed25519 keys are requested via type 'curve25519'
        // (the `curve` field is for legacy named curves only).
        await generateKey({
          type: 'curve25519',
          userIDs: [userID],
          passphrase: pass,
          format: 'armored',
        })
      : await generateKey({
          type: 'rsa',
          rsaBits: algorithm === 'rsa4096' ? 4096 : 2048,
          userIDs: [userID],
          passphrase: pass,
          format: 'armored',
        });

  // With format 'armored' generateKey returns only the armored strings — parse
  // the public key back to read its fingerprint.
  const key = await readKey({ armoredKey: publicKey });

  return {
    publicKey,
    privateKey,
    fingerprint: key.getFingerprint(),
    revocationCertificate,
  };
}

Also available in 8 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →