Cryptography you can actually use.
Hashing vs encryption, symmetric vs asymmetric, and the three primitives you should reach for before rolling your own anything.
Most working engineers never need to implement a cipher. They need to know which one to use, what the inputs and outputs look like, and where the booby traps are. This article covers exactly that.
Hashing is not encryption
A hash is a one-way function: arbitrary input in, fixed-size pseudo-random output out. You cannot get the input back. Use cases: integrity checks, fingerprinting, password storage (with a slow hash).
$ echo -n "hello" | sha256sum
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 -
Encryption is reversible: you have a key, you can decrypt. Use cases: transmitting and storing data confidentially.
If you can ever need the data back, you want encryption. If you only need to confirm two values are the same (passwords, file integrity), you want hashing.
The two flavours of encryption
Symmetric: one key, the same to encrypt and decrypt. Fast (gigabytes per second on modern CPUs). Hard to get the key to the other person securely.
Asymmetric: a key pair. Public to encrypt or verify, private to decrypt or sign. Slow (kilobytes per second). Easy to share the public half.
In practice almost everything uses both, like TLS does: asymmetric for a handshake that establishes a symmetric session key, then symmetric for the bulk traffic.
The three primitives you should know by name
| Primitive | Type | Use it for |
|---|---|---|
| AES-256-GCM | Symmetric AEAD | Encrypting files, sessions, anything bulk |
| X25519 + Ed25519 | Asymmetric (ECC) | Key exchange and signatures |
| Argon2id | Password hash | Storing user passwords |
That is the floor. Reach for these by name in code review and you will be right 95% of the time. The remaining 5% — interoperability with old systems, regulated environments, hardware constraints — needs an expert anyway.
AEAD — the one word that protects you from yourself
Older ciphers like AES-CBC encrypt your data but do not detect tampering. AEAD (Authenticated Encryption with Associated Data) does both at once. AES-GCM and ChaCha20-Poly1305 are AEADs. They produce a ciphertext and a tag; decryption fails loudly if the tag does not check out.
You should never see plain AES-CBC, AES-CTR, or 3DES in new code in 2026. If you do, replace it.
Password storage, the right way
Three rules:
- Hash, never encrypt.
- Use a slow hash designed for the job — Argon2id, scrypt, or bcrypt — not SHA-256.
- Tune the parameters so a single login takes 100–500 ms on your hardware.
# libargon2 reference settings, 2026
argon2id memory=64MB iterations=3 parallelism=4
Why memory? Because attackers crack passwords on GPUs, which have lots of cores but little memory per core. A memory-hard function levels the playing field.
Things that will trip you up
- Reusing a nonce with AES-GCM destroys confidentiality. Generate a fresh 96-bit random nonce every encryption, or use a counter.
- Comparing secrets with
==leaks timing. Use a constant-time compare (hmac.compare_digestin Python,crypto.timingSafeEqualin Node). - Storing a key in the database next to the ciphertext defeats the entire exercise. Keys live in a KMS, an HSM, an env var injected at runtime — anywhere the data is not.
- Inventing your own protocol by composing primitives. Use a high-level library — libsodium, age, Tink — that already composed them for you.
Those four mistakes account for the great majority of crypto-related breaches you will read about. Get them right and you are ahead of most of the industry.