iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Asymmetric / Public Key

Asymmetric (public-key) crypto uses a key pair: encrypt with the public key, decrypt with the private; sign with private, verify with public. Modern choices: ECDSA / EdDSA for signatures, X25519 / RSA-OAEP for key exchange / encryption.

RSA, ECDSA, Ed25519, X25519

EXAMPLE
// 1) Generate an RSA key pair — Node
import crypto from 'node:crypto';

const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
    modulusLength: 4096,
    publicKeyEncoding:  { type: 'spki',   format: 'pem' },
    privateKeyEncoding: { type: 'pkcs8',  format: 'pem' },
});

// Encrypt with PUBLIC — only PRIVATE can decrypt
const ct = crypto.publicEncrypt({
    key: publicKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256',
}, Buffer.from('hello'));

const pt = crypto.privateDecrypt({
    key: privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256',
}, ct);

// 2) Sign with PRIVATE — verify with PUBLIC (RSA-PSS preferred over PKCS1v1.5)
const sig = crypto.sign('sha256', Buffer.from(message), {
    key: privateKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
});
const ok = crypto.verify('sha256', Buffer.from(message), {
    key: publicKey, padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
}, sig);

// 3) Elliptic-curve — ECDSA (P-256) is the de-facto default
const { publicKey: ecPub, privateKey: ecPriv } = crypto.generateKeyPairSync('ec', {
    namedCurve: 'P-256',
    publicKeyEncoding:  { type: 'spki',  format: 'pem' },
    privateKeyEncoding: { type: 'pkcs8', format: 'pem' },
});

const ecSig = crypto.sign('sha256', Buffer.from(message), ecPriv);
const ecOk  = crypto.verify('sha256', Buffer.from(message), ecPub, ecSig);

// 4) Ed25519 — modern signature standard, fast, small keys
const { publicKey: edPub, privateKey: edPriv } = crypto.generateKeyPairSync('ed25519');
const edSig = crypto.sign(null, Buffer.from(message), edPriv);   // hash baked in
const edOk  = crypto.verify(null, Buffer.from(message), edPub, edSig);

// 5) X25519 — key agreement (Diffie-Hellman), pair with ChaCha20-Poly1305 for messaging
const alice = crypto.generateKeyPairSync('x25519');
const bob   = crypto.generateKeyPairSync('x25519');
const sharedA = crypto.diffieHellman({ privateKey: alice.privateKey, publicKey: bob.publicKey });
const sharedB = crypto.diffieHellman({ privateKey: bob.privateKey,   publicKey: alice.publicKey });
// sharedA == sharedB
// Pass through HKDF before using as a symmetric key

// 6) Hybrid encryption — encrypt symmetric key with RSA / ECIES,
// encrypt data with AES-GCM
// This is what TLS / signal / JWE essentially do.

// 7) Python — cryptography library
from cryptography.hazmat.primitives.asymmetric import rsa, padding, ed25519, x25519
from cryptography.hazmat.primitives import serialization, hashes

priv = rsa.generate_private_key(public_exponent=65537, key_size=4096)
pub  = priv.public_key()

ciphertext = pub.encrypt(b'hello', padding.OAEP(
    mgf=padding.MGF1(algorithm=hashes.SHA256()),
    algorithm=hashes.SHA256(), label=None,
))
plaintext = priv.decrypt(ciphertext, padding.OAEP(
    mgf=padding.MGF1(algorithm=hashes.SHA256()),
    algorithm=hashes.SHA256(), label=None,
))

# Ed25519
sk = ed25519.Ed25519PrivateKey.generate()
vk = sk.public_key()
sig = sk.sign(b'message')
vk.verify(sig, b'message')

// 8) Choose by use case
//   Signing — small, fast       → Ed25519
//   Signing — must use FIPS     → ECDSA P-256
//   Encrypting small data       → RSA-OAEP (or hybrid)
//   Encrypting large data       → AES-GCM with key from key exchange
//   Key exchange (modern)       → X25519 + HKDF
//   Long-term legacy interop    → RSA-OAEP / RSA-PSS

// 9) Storage + transport
//   PEM (text) for files
//   PKCS#8 for private keys
//   SPKI / X.509 SubjectPublicKeyInfo for public keys
//   JWK / JWKS for HTTP API exposure

// 10) Common mistakes
//   • Using public to encrypt big payloads — RSA can encrypt at most ~250 bytes (4096-bit key)
//   • Using PKCS1v1.5 padding instead of OAEP / PSS — known weaknesses
//   • Reusing the same key for signing AND encryption — separate the keys by use
//   • Storing private keys in env vars — use KMS / HSM / OS keychain
//   • Rolling your own elliptic curve code — use vetted libraries

// 11) JWT example — RS256 / ES256 / EdDSA
import jwt from 'jsonwebtoken';
const token = jwt.sign({ uid: 42 }, privateKey, { algorithm: 'EdDSA', expiresIn: '15m' });
const payload = jwt.verify(token, publicKey, { algorithms: ['EdDSA'] });

// 12) Post-quantum (PQ) — start watching
//   • NIST has selected ML-KEM (Kyber), ML-DSA (Dilithium), SLH-DSA (SPHINCS+)
//   • Hybrid schemes (X25519 + ML-KEM) are rolling out in TLS 1.3 (e.g. X25519MLKEM768)
//   • Migrating long-term signed data (PDFs, contracts) is a 5-10 year project — plan now

Why it matters

Ed25519 + X25519 + ChaCha20-Poly1305 is the modern toolchain — fast, small keys, no padding-oracle pitfalls. Reach for RSA only when you need legacy interop or FIPS compliance.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Two keys: public (share) and private (keep secret).
// Use cases: digital signatures, key exchange, sealing messages to a recipient.
// Modern picks: Ed25519 (sign), X25519 (key exchange), RSA-2048+ (legacy).
Try it Yourself »

Discussion

Loading…