Encryption keeps secrets secret and detects when someone has tampered with data. The cryptographic primitives are mature and standardised; the way to ruin them is almost always at the application layer — wrong mode of operation, reused nonces, predictable IVs, hand-rolled key derivation.
This page is the working set: which primitive solves which problem, and the operational rules that distinguish "secure" from "looks secure."
| Symmetric | Asymmetric | |
|---|---|---|
| Keys | One shared secret | Public + private pair |
| Speed | Fast (GBs/sec on commodity CPUs) | Slow (KBs/sec for RSA, faster for ECC) |
| Use | Bulk data encryption | Key exchange, signatures, identity |
| Examples | AES, ChaCha20 | RSA, ECDSA, ECDH |
The standard composition: asymmetric to establish a shared symmetric key; symmetric to encrypt the actual data. TLS, Signal, every secure protocol does this. Asymmetric is too slow for bulk; symmetric needs a shared key, which asymmetric provides.
Modern symmetric encryption is AEAD (Authenticated Encryption with Associated Data). One operation provides confidentiality and integrity. Don't use older constructions (CBC mode + separate HMAC) for new code.
The two AEAD primitives that matter:
For new code: AES-GCM if hardware acceleration is available, ChaCha20-Poly1305 otherwise. Both are excellent.
Don't use AES-192. It's a strange middle that exists for historical reasons and isn't widely used; AES-128 or AES-256.
AEAD ciphers take a nonce (number used once) per encryption. Reusing a nonce with the same key destroys the security of GCM and CCM specifically. ChaCha20-Poly1305 too.
Three correct nonce strategies:
Nonce reuse is the single most common AEAD failure. Use a library that manages nonces correctly; don't hand-roll.
If you find yourself needing one of these, you almost certainly want AEAD instead.
The classic. Encryption / signing in the multiplicative group mod a 2048-bit (or larger) composite number.
In 2026, RSA persists for compatibility but ECC is preferred for new keys.
Same operations (encryption, signatures, key exchange) over an elliptic curve group. Smaller keys for equivalent security:
Faster, smaller, lower bandwidth. The default for new asymmetric crypto.
Curves to use:
Avoid:
Shor's algorithm breaks RSA, ECDSA, and ECDH if a sufficiently large quantum computer exists. NIST standardised post-quantum algorithms in 2024:
For most teams: continue using RSA/ECC; watch for hybrid PQ-classical libraries to mature; plan migration over the next several years. For high-value or long-confidentiality (decades-from-now relevant) data, start adopting hybrid PQ where libraries support it now.
A hash maps arbitrary input to a fixed-length output, ideally with three properties:
h, hard to find input x with H(x) = h.x, hard to find x' ≠ x with H(x) = H(x').x ≠ x' with H(x) = H(x').The collision-resistance bound is roughly half the bit length: SHA-256 has 128-bit collision resistance.
In 2026:
Avoid: MD5 (broken since 2004), SHA-1 (collisions demonstrated in 2017), SHA-256 truncated to fewer than 128 bits (collision resistance drops below safe threshold).
Turn a password or a high-entropy secret into one or more cryptographic keys.
For passwords: Argon2id, with appropriate parameters (memory cost, time cost). Parameters tuned to make brute-force expensive while not crippling legitimate logins.
For derivation from already-strong secrets: HKDF (HMAC-based Key Derivation Function). Cheap, well-understood, the right choice for "I have a 256-bit secret; I need three 256-bit keys for different purposes."
For older code: PBKDF2 was the standard before Argon2; bcrypt is fine for password hashing if Argon2 isn't available.
Never:
CSPRNG — Cryptographically Secure Pseudo-Random Number Generator. Backed by the OS:
/dev/urandom on Linux.getrandom() on modern Linux / glibc.SecRandomCopyBytes on macOS / iOS.BCryptGenRandom on Windows.Language standard libraries usually wrap these:
secrets module.crypto/rand.rand::rngs::OsRng.SecureRandom (be careful — older Random is not secure).crypto.getRandomValues.Never use rand(), Math.random(), or any non-CSPRNG for cryptographic purposes. They're predictable; they're for simulations and games.
The most often-cited rule in cryptography. It means three different things:
What you can do:
Libraries that make doing the right thing easy:
| Need | Use |
|---|---|
| Encrypt a file with a password | age (age -p), or libsodium's crypto_secretstream with Argon2id key |
| Encrypt a payload with a known key | AES-GCM or ChaCha20-Poly1305, with a CSPRNG nonce |
| Encrypt for a known recipient | age (age -r <recipient>), or libsodium's crypto_box |
| Sign data | Ed25519 (crypto_sign_detached in libsodium) |
| Authenticate that data hasn't changed | HMAC-SHA-256 |
| Hash a password for storage | Argon2id |
| Generate a session token | 256+ bits from CSPRNG; base64url-encode |
| Hash a file for integrity | SHA-256 or BLAKE3 |
| Establish a shared key over insecure channel | TLS 1.3 if it's a real network; libsodium's crypto_kx for in-app |
| Derive multiple keys from a master | HKDF-SHA-256 |