Skip to content
Unverified — AI-generated content. Help verify this page

Cryptography for Engineers

Cryptography is the foundation of every secure system. TLS, SSH, JWTs, code signing, certificate pinning, end-to-end encryption — they all rely on a small set of cryptographic primitives. Most engineers use these primitives through libraries without understanding what they do. That works until something breaks: a certificate chain fails validation, a signature verification returns false when it should not, or someone asks you to choose between RSA-2048 and Ed25519 and you have no basis for the decision.

This page covers the primitives that matter in production: key exchange, digital signatures, certificate chains, and the post-quantum algorithms that will replace today's cryptography within the next decade.

Asymmetric Algorithm Comparison

Before diving deep, here is the landscape:

AlgorithmTypeKey Size (128-bit security)Signature SizeSpeedStatus
RSA-3072Factoring3072-bit public key384 bytesSlowLegacy, still widely used
ECDSA (P-256)Elliptic curve256-bit public key64 bytesFastStandard, widely deployed
Ed25519Edwards curve256-bit public key64 bytesVery fastModern default
X25519Montgomery curve256-bitN/A (key exchange only)Very fastModern DH default
DilithiumLattice-based~1.3 KB public key~2.4 KBModerateNIST PQC standard

The Modern Default

For new systems in 2026, use Ed25519 for signatures and X25519 for key exchange unless you have a specific compliance requirement mandating RSA or ECDSA. Ed25519 is faster, has smaller keys, avoids entire classes of implementation bugs, and is supported by OpenSSH, TLS 1.3, and every major crypto library.

RSA: The Factoring Problem

RSA, published in 1977 by Rivest, Shamir, and Adleman, is based on the difficulty of factoring the product of two large primes.

RSA Key Generation

  1. Choose two large primes p and q (each ~1536 bits for RSA-3072)
  2. Compute n=pq (this is the modulus, part of the public key)
  3. Compute ϕ(n)=(p1)(q1) (Euler's totient)
  4. Choose public exponent e such that 1<e<ϕ(n) and gcd(e,ϕ(n))=1 (typically e=65537)
  5. Compute private exponent d=e1modϕ(n) (modular inverse)

Public key: (n,e)Private key: (n,d)

RSA Operations

Encryption:

C=Memodn

Decryption:

M=Cdmodn

Signing:

σ=H(M)dmodn

Verification:

H(M)=?σemodn

Where H(M) is a cryptographic hash (SHA-256) of the message.

Why RSA Is Slow

RSA operations involve modular exponentiation with 3072+ bit numbers. Even with optimizations (Chinese Remainder Theorem for decryption, small public exponent for encryption), RSA is roughly 1000x slower than symmetric encryption.

Benchmark (typical modern CPU):
  RSA-2048 sign:    ~1.5 ms
  RSA-2048 verify:  ~0.04 ms
  Ed25519 sign:     ~0.02 ms
  Ed25519 verify:   ~0.06 ms
  AES-256-GCM:      ~3 GB/s

RSA Padding Matters

Never use "textbook RSA" (C=Memodn). Without proper padding, RSA is vulnerable to chosen-ciphertext attacks. Always use:

  • OAEP (Optimal Asymmetric Encryption Padding) for encryption
  • PSS (Probabilistic Signature Scheme) for signatures
  • Never use PKCS#1 v1.5 padding in new systems (Bleichenbacher attack)

Elliptic Curve Cryptography

Elliptic curves provide the same security as RSA with dramatically smaller keys. An EC key of 256 bits provides roughly the same security as a 3072-bit RSA key.

The Math (Simplified)

An elliptic curve over a finite field Fp is the set of points (x,y) satisfying:

y2=x3+ax+b(modp)

Plus a special "point at infinity" O that acts as the identity element.

The key insight is point addition: given two points P and Q on the curve, there is a geometric operation that produces a third point P+Q also on the curve. This enables scalar multiplication: kP=P+P++P (k times).

The Elliptic Curve Discrete Logarithm Problem (ECDLP): Given P and Q=kP, finding k is computationally infeasible for large curves. This is the trapdoor.

ECDSA vs Ed25519

FeatureECDSA (P-256)Ed25519
CurveNIST P-256 (Weierstrass)Curve25519 (Edwards)
Randomness needed for signingYes (fatal if broken)No (deterministic)
Constant-time implementationHard to get rightBuilt into the design
Side-channel resistanceRequires careful implementationResistant by construction
Signature malleabilityMalleable without normalizationNon-malleable
PerformanceFastFaster
AdoptionTLS, Bitcoin (secp256k1), PKISSH, Signal, Wireguard, TLS 1.3

ECDSA's Fatal Flaw: Nonce Reuse

ECDSA requires a random nonce k for every signature. If the same k is used twice with different messages, the private key can be recovered algebraically. This is not theoretical — the PlayStation 3 code signing key was extracted exactly this way in 2010 (fail0verflow). Sony used the same k for every signature.

Ed25519 avoids this entirely by deriving the nonce deterministically from the private key and message using a hash function.

Ed25519 Internals

Ed25519 uses a twisted Edwards curve:

x2+y2=1+dx2y2

where d=121665/121666 over the prime field p=225519.

Key generation:

  1. Generate 32 random bytes as seed s
  2. Hash: h=SHA-512(s), take first 32 bytes, clamp (clear/set specific bits) to get scalar a
  3. Public key: A=aB where B is the base point

Signing message M:

  1. Compute r=SHA-512(h32..63M) (deterministic nonce from second half of hash and message)
  2. Compute R=rB
  3. Compute S=r+SHA-512(RAM)a(mod) where is the group order
  4. Signature is (R,S) — 64 bytes

Verification: Check that 8SB=8R+8SHA-512(RAM)A

Diffie-Hellman Key Exchange

Diffie-Hellman (1976) allows two parties to establish a shared secret over an insecure channel. It is the foundation of TLS, SSH, and virtually every encrypted connection.

Classical DH (Finite Field)

The security relies on the Discrete Logarithm Problem: given g, p, and gamodp, computing a is infeasible.

The Math

Alice and Bob agree on public parameters:

  • A large prime p (at least 2048 bits)
  • A generator g of the multiplicative group modulo p
Alice computes: A=gamodpBob computes: B=gbmodpShared secret: K=gabmodp

Alice computes K=Ba=(gb)a=gabmodp

Bob computes K=Ab=(ga)b=gabmodp

An eavesdropper sees g, p, A=ga, and B=gb but cannot compute gab without knowing a or b.

ECDH (Elliptic Curve Diffie-Hellman)

Modern systems use X25519 (ECDH over Curve25519) instead of classical DH:

javascript
import { createECDH } from 'crypto';

// Alice
const alice = createECDH('prime256v1');
alice.generateKeys();
const alicePublic = alice.getPublicKey();

// Bob
const bob = createECDH('prime256v1');
bob.generateKeys();
const bobPublic = bob.getPublicKey();

// Both compute the same shared secret
const aliceSecret = alice.computeSecret(bobPublic);
const bobSecret = bob.computeSecret(alicePublic);

console.log(aliceSecret.equals(bobSecret)); // true

DH Is Vulnerable to Man-in-the-Middle

Plain Diffie-Hellman provides no authentication. An attacker can perform two separate DH exchanges — one with Alice and one with Bob — and relay modified messages between them. This is why DH is always combined with authentication (digital signatures, certificates) in protocols like TLS.

Digital Signatures

A digital signature proves three things:

  1. Authentication — The message was created by the claimed sender
  2. Integrity — The message was not altered in transit
  3. Non-repudiation — The sender cannot deny having sent the message

How Signing Works

Practical Example: Signing a JWT

javascript
import { createSign, createVerify, generateKeyPairSync } from 'crypto';

// Generate Ed25519 key pair
const { publicKey, privateKey } = generateKeyPairSync('ed25519');

// Sign
const message = '{"sub":"user123","exp":1700000000}';
const sign = createSign('SHA512'); // Ed25519 ignores this, uses EdDSA internally
sign.update(message);
const signature = sign.sign(privateKey);

console.log(`Signature: ${signature.toString('base64')}`);
// Output: 64-byte Ed25519 signature

// Verify
const verify = createVerify('SHA512');
verify.update(message);
const isValid = verify.verify(publicKey, signature);

console.log(`Valid: ${isValid}`); // true

// Tamper with message
const verify2 = createVerify('SHA512');
verify2.update(message + 'tampered');
const isValid2 = verify2.verify(publicKey, signature);

console.log(`Valid after tampering: ${isValid2}`); // false

Certificate Chains and PKI

The Trust Problem

Digital signatures prove a message came from a specific key, but how do you know the key belongs to who you think it does? This is the key distribution problem, and Public Key Infrastructure (PKI) solves it using a hierarchy of trust.

X.509 Certificate Structure

An X.509 certificate binds an identity to a public key:

Certificate:
    Data:
        Version: 3
        Serial Number: 04:e2:8a:...
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: CN=DigiCert Global G2 TLS RSA SHA256 2020 CA1, O=DigiCert Inc
        Validity:
            Not Before: Jan 15 00:00:00 2026 GMT
            Not After:  Feb 14 23:59:59 2027 GMT
        Subject: CN=*.example.com, O=Example Inc
        Subject Public Key Info:
            Algorithm: id-ecPublicKey (P-256)
            Public Key: 04:a3:b5:...
        X509v3 Extensions:
            Subject Alternative Name:
                DNS:*.example.com, DNS:example.com
            Key Usage: Digital Signature
            Extended Key Usage: TLS Web Server Authentication
    Signature Algorithm: ecdsa-with-SHA384
    Signature Value: 30:45:02:21:...

Certificate Chain Validation

Validation steps:

  1. Chain building: Construct a path from leaf certificate to a trusted root
  2. Signature verification: Each certificate's signature is verified with its issuer's public key
  3. Validity period: Check that every certificate in the chain is within its validity window
  4. Revocation check: Query CRL (Certificate Revocation List) or OCSP (Online Certificate Status Protocol)
  5. Name matching: Verify the leaf certificate's SAN (Subject Alternative Name) matches the requested hostname
  6. Key usage: Verify the certificate is authorized for the intended purpose (e.g., TLS server auth)

Certificate Transparency

Certificate Transparency (CT) is a public audit log for certificates. Every CA must submit certificates to CT logs before issuance. This allows domain owners to detect misissued certificates:

bash
# Check CT logs for your domain
curl -s "https://crt.sh/?q=%.example.com&output=json" | jq '.[0:5]'

Certificate Pinning Is Risky

Certificate pinning (hardcoding expected certificates or public keys) prevents MITM attacks but creates operational nightmares. If the pinned certificate expires or you need to rotate keys, pinned clients break with no recovery path. HPKP (HTTP Public Key Pinning) was deprecated in Chrome 72 for this reason. Prefer Certificate Transparency monitoring over pinning.

Post-Quantum Cryptography

Quantum computers with sufficient qubits will break RSA, ECDSA, Ed25519, and Diffie-Hellman using Shor's algorithm. While large-scale quantum computers do not exist yet, the threat is real because of harvest now, decrypt later — adversaries can record encrypted traffic today and decrypt it once quantum computers arrive.

What Breaks and What Survives

AlgorithmQuantum ImpactTimeline
RSABroken by Shor's algorithmWhen ~4000 logical qubits exist
ECDSA / Ed25519Broken by Shor's algorithmSame
Diffie-HellmanBroken by Shor's algorithmSame
AES-256Weakened to 128-bit (Grover's)Still secure with larger keys
SHA-256Weakened to 128-bit (Grover's)Still secure
HMACUnaffectedSecure

NIST Post-Quantum Standards (2024)

NIST selected four algorithms after an 8-year evaluation:

Key Exchange / Encryption:

  • ML-KEM (CRYSTALS-Kyber) — Lattice-based key encapsulation mechanism. Fast, small keys (~1.5 KB). The recommended default for post-quantum key exchange.

Digital Signatures:

  • ML-DSA (CRYSTALS-Dilithium) — Lattice-based signatures. Moderate size (~2.4 KB signatures). General-purpose default.
  • SLH-DSA (SPHINCS+) — Hash-based signatures. Larger but relies only on hash function security (most conservative choice).
  • FN-DSA (FALCON) — Lattice-based, smaller signatures than Dilithium but harder to implement safely.

Lattice-Based Cryptography: The Intuition

Lattice problems work in high-dimensional spaces. The core hard problem is the Learning With Errors (LWE) problem:

Given a system of approximate linear equations:

b=As+e(modq)

Where A is a public matrix, s is the secret, and e is a small error vector — find s.

Without the error term, this is simple linear algebra (Gaussian elimination). With the error term, it becomes computationally intractable even for quantum computers.

Hybrid Key Exchange in TLS

The transition strategy is hybrid key exchange: combine a classical algorithm (X25519) with a post-quantum algorithm (ML-KEM-768). If either one is secure, the combined scheme is secure.

TLS 1.3 Hybrid Key Exchange:
  Client → Server: X25519_public_key || ML-KEM-768_encapsulation_key
  Server → Client: X25519_public_key || ML-KEM-768_ciphertext

  Shared secret = HKDF(X25519_shared_secret || ML-KEM_shared_secret)

Chrome and Firefox already support X25519+ML-KEM-768 hybrid key exchange since 2024.

bash
# Check if a server supports post-quantum key exchange
openssl s_client -connect example.com:443 -groups X25519MLKEM768

Migration Timeline

Start Now

Even if large quantum computers are a decade away, you should:

  1. Inventory all cryptographic dependencies in your systems
  2. Enable hybrid key exchange where your TLS stack supports it
  3. Avoid RSA in new systems — use Ed25519/X25519 (easier to migrate to PQ later)
  4. Monitor NIST standards and your library's PQ support

Practical Cryptographic Decisions

Decision Matrix for Common Scenarios

ScenarioRecommended AlgorithmWhy
TLS certificatesECDSA P-256 or Ed25519Broad compatibility (ECDSA) or performance (Ed25519)
SSH keysEd25519Smallest keys, fastest, most secure
JWT signingEd25519 (EdDSA)Deterministic, no nonce pitfalls
Code signingEd25519 or ECDSA P-256Ecosystem support dependent
Encrypting data at restAES-256-GCMSymmetric, fast, authenticated
Key exchangeX25519 + ML-KEM-768 (hybrid)Post-quantum safe
Password hashingArgon2idNot encryption — purpose-built KDF
API request signingHMAC-SHA256Symmetric, simple, fast

Generate Ed25519 Keys

bash
# SSH key
ssh-keygen -t ed25519 -C "engineer@example.com"

# OpenSSL
openssl genpkey -algorithm Ed25519 -out private.pem
openssl pkey -in private.pem -pubout -out public.pem

# View the key
openssl pkey -in private.pem -text -noout

Common Cryptographic Mistakes

MistakeImpactCorrect Approach
Using RSA-1024Factorable with current hardwareMinimum RSA-2048, prefer RSA-3072 or Ed25519
ECB mode for block ciphersPatterns in plaintext visible in ciphertextUse GCM (authenticated encryption)
Custom crypto protocolAlmost certainly brokenUse TLS 1.3, libsodium, or NaCl
Storing encryption keys alongside dataKey compromise = data compromiseUse HSMs, KMS, or envelope encryption
Using MD5 or SHA-1 for signaturesCollision attacks demonstratedSHA-256 minimum
Not validating certificate chainsMITM trivially possibleUse standard TLS libraries, do not disable verification
Reusing nonces in AES-GCMCatastrophic — authentication completely brokenUse random nonces or counter-based nonces, never reuse

Never Roll Your Own Crypto

The first rule of cryptography: do not implement your own. Use audited, well-maintained libraries: libsodium, OpenSSL, BoringSSL, or your language's standard crypto library. The history of cryptography is littered with systems broken not because the math was wrong, but because the implementation was subtly flawed.

Further Reading

"What I cannot create, I do not understand." — Richard Feynman