Cryptography Fundamentals
Plaintext, ciphertext, keys, hashes, MACs, signatures, nonces and randomness — the vocabulary you need to use cryptography correctly, plus the one rule that matters most: use established libraries and protocols, never your own.
Frame the problem
Security starts with a concrete asset, attacker capability and trust crossing.
The primitives and what each guarantees
Encryption turns plaintext into ciphertext with a key and back again: confidentiality. Hashing maps input to a fixed-size digest one way: integrity checking, and (with a slow variant) password storage. A MAC is a keyed hash: integrity plus authenticity between parties sharing a key. A digital signature is asymmetric authenticity: anyone can verify, only the key holder can sign. Key exchange lets two parties agree a shared secret over a public channel.
Encryption alone does not give integrity — ciphertext can be modified, and some modes let an attacker flip plaintext bits predictably. Use authenticated encryption (AES-GCM, ChaCha20-Poly1305) which combines both, and never assemble encrypt-then-something yourself.
| Primitive | Confidentiality | Integrity | Authenticity | Example |
|---|---|---|---|---|
| Symmetric encryption | Yes | No (alone) | No | AES-GCM (authenticated: yes/yes/shared-key) |
| Hash | No | Yes (if the hash is trusted) | No | SHA-256 |
| MAC | No | Yes | Yes, between key sharers | HMAC-SHA256 |
| Signature | No | Yes | Yes, publicly verifiable | Ed25519, ECDSA, RSA-PSS |
| Key exchange | Enables it | — | Needs authentication | X25519 (within TLS) |
Nonces, randomness and the mistakes that break everything
A nonce is a number used once. Reusing a nonce with the same key under AES-GCM leaks the authentication key and lets the attacker forge messages; under stream ciphers it leaks plaintext. Nonces need not be secret, but they must not repeat — use a counter or a 96-bit random value with a key rotated before the birthday bound.
Randomness must come from the operating system's cryptographic source (crypto.randomBytes, secrets, /dev/urandom). Math.random() and seeded PRNGs are predictable and have produced forgeable tokens, guessable session ids and recoverable keys.
And the rule: do not design or implement cryptographic algorithms or protocols for production. Use a high-level library (libsodium, Tink, the platform's vetted API) that chooses modes and handles nonces for you. The failure mode of custom crypto is not "slightly weaker"; it is "completely broken and nobody notices for years".
Key points
- Encryption ≠ integrity; use authenticated encryption.
- Nonces must never repeat under a key.
- Randomness comes from the OS CSPRNG, nothing else.
- Use established libraries and protocols; never your own constructions.
- Name the property you need (confidentiality, integrity, authenticity) before picking a primitive.
Boundary control exercise
This lesson uses the shared boundary-control exercise.
Follow the attack
Safe conceptual simulation: capability → missing control → crossed boundary → asset impact.
- 1Attacker → find misuse: repeated nonce, unauthenticated mode, weak randomness, custom construction.
- 2Misuse → forge, decrypt or predict.
- Cryptographic misuse fails completely and silently — there is no partial credit.
Defend, detect, recover
One prevention is a single point of security failure. Layer it and make failure observable.
- • High-level libraries.
- • Authenticated encryption only.
- • CSPRNG for every token and key.
- • Review any code that touches primitives directly.
- • Static checks for `Math.random`, ECB, unauthenticated modes, hand-rolled comparisons.
- • Rotate keys; re-encrypt; assume anything protected by the broken construction was exposed.
- • Libraries have bugs too; keep them updated.
- • Correct primitives in a wrong protocol still fail.