Handbooks  /  Cryptography for Engineers
Handbook~16 min readSecurityworked math + runnable code
Cryptography for Engineers

One key,
used once.

Encryption sounds like deep math, but its purest form is one operation you already know: XOR. Combine each byte of your message with a byte of a secret key and the result reveals nothing — provably, perfectly — as long as the key is random, as long as the message, and used exactly once. That's the one-time pad, the only cipher that's mathematically unbreakable. Its rules also teach the whole subject: break any one of them (especially "used once") and secrecy collapses instantly. This handbook builds encryption from XOR up, and shows why the mistakes matter more than the algorithms.

01

Encryption is XOR

Strip encryption down to its essence and it's a reversible scramble: turn readable plaintext into ciphertext that looks like noise, in a way only someone with the secret can undo. The simplest operation that does this is XOR — exclusive-or, bit by bit. XOR each bit of the message with a bit of a secret key, and you get ciphertext. The magic is that XOR is its own inverse: apply the same key again and the two XORs cancel, giving back the original. a ⊕ k ⊕ k = a.

That single property — encrypt and decrypt are the same operation with the same key — is the seed of all symmetric cryptography. The ciphertext looks nothing like the plaintext (flip a key bit and the output bit flips), yet anyone holding the key recovers the message exactly. No lookup tables, no reversible math tricks; just XOR. Everything harder in cryptography — block ciphers, stream ciphers, AES — is about making the "key" long enough and unpredictable enough to be safe while staying short enough to be practical. The idea underneath doesn't change.

The one-sentence version

XOR with a random, message-length, single-use key is the one-time pad — provably unbreakable — and every rule it demands (random, as long as the message, used once) is a lesson the rest of cryptography spends its time enforcing.

02

Perfect secrecy

The one-time pad (OTP) is XOR encryption with three conditions on the key: it must be truly random, at least as long as the message, and used only once. Meet all three and the OTP has perfect secrecy — a property proven by Shannon. It means the ciphertext leaks zero information about the plaintext: for any ciphertext an attacker sees, every possible message of that length is equally likely, because there's a key that maps this ciphertext to that message. With no computer, no matter how much time, the attacker cannot do better than guessing.

That's a stronger guarantee than any modern cipher offers — AES is "computationally" secure (safe because breaking it would take longer than the universe has), but the OTP is unconditionally secure. So why doesn't everyone use it? The conditions are brutally impractical: you need a fresh, truly random key as long as the total of everything you'll ever send, and you must share it in advance over some secure channel — which is nearly the same problem encryption was supposed to solve. The OTP is perfect and almost useless, which is exactly why it's the right thing to study: it shows what secrecy is, and every practical cipher is a trade against its impracticality.

03

The fatal mistake

Of the three rules, "used once" is the one that kills real systems, and the reason is pure XOR algebra. Encrypt two messages with the same key and look at what an attacker can compute from the two ciphertexts:

Why reusing the key destroys secrecy
c₁= p₁ ⊕ k   (first message, encrypted with key k)
c₂= p₂ ⊕ k   (second message, same key k)
c₁ ⊕ c₂= (p₁ ⊕ k) ⊕ (p₂ ⊕ k) = p₁ ⊕ p₂   — the key cancels!
ResultAttacker has p₁ ⊕ p₂ with no key — language stats or a known crib recover both.

The key vanishes. The attacker is left with the XOR of the two plaintexts, and human language is redundant enough that this is often enough to unravel both messages — no key ever recovered. This "two-time pad" blunder has broken real ciphers in history (it's how the VENONA project read Soviet cables). The lesson generalizes far beyond the OTP: never reuse a keystream. It's why every modern cipher pairs the key with a unique, per-message nonce — so the actual encryption stream is different every single time, even when the key is the same.

04

The XOR math

Encryption and decryption are the same XOR, so decrypting recovers the plaintext exactly, and the ciphertext differs from the plaintext (bits flip wherever the key is 1):

c  =  p ⊕ k     decrypt:  c ⊕ k  =  (p ⊕ k) ⊕ k  =  p

Same operation both ways. A zero key is the identity (p ⊕ 0 = p) — encrypts nothing — which is why the key must be nonzero and random.

Reusing the key on two messages cancels it, exposing the XOR of the plaintexts — the fatal leak:

c1 ⊕ c2  =  (p1 ⊕ k) ⊕ (p2 ⊕ k)  =  p1 ⊕ p2  (no k)

The key is gone; only the plaintexts' relationship remains. The runnable version below encrypts, round-trips, measures the bit-flips, and demonstrates the key-reuse leak.

RUN IT YOURSELF

The one-time pad, from XOR

Encryption in its purest form is XOR: combine each plaintext byte with a key byte. Because XOR is its own inverse, decrypting is the same operation — XOR again with the same key and the plaintext comes back. The ciphertext looks nothing like the input (bits flip wherever the key is 1). But XOR with a zero key changes nothing, showing why the key must be random and nonzero. And the fatal mistake: reuse the key on two messages and XORing the ciphertexts cancels the key, leaking p1 XOR p2. Change the messages or the key and watch the round-trip, the bit-flips, and the key-reuse leak.

CPython · WebAssembly
05

Scaling to real crypto

Real systems can't ship a message-length key, so cryptography is the art of getting OTP-like safety from a short key. Two families do the work:

KindHow it works · when to use
SymmetricOne shared secret key for both encrypt and decrypt (AES is the standard). Fast — used for the bulk of the data. Hard part: both sides must already share the key.
Public-keyA key pair — a public key anyone can encrypt to, a private key only you can decrypt with. Solves key-sharing with strangers; also enables signatures. Slower, so used to exchange a symmetric key.
HashingOne-way fingerprint (SHA-256) — not encryption. Verifies integrity; salted+slow (Argon2/bcrypt) for passwords.
Nonce / IVA unique per-message value combined with the key so the keystream never repeats — the practical answer to "never reuse a keystream."

The everyday example is TLS — the padlock in your browser. It uses slow public-key crypto once, at the start, to agree on a fresh symmetric key, then switches to fast symmetric encryption (AES) for the actual traffic, with a new nonce per record so no keystream ever repeats. That handshake is the whole subject in miniature: public-key to solve sharing, symmetric for speed, nonces to honor "use once." Understand XOR and the OTP's three rules, and every one of these constructions reads as a practical workaround for a rule you can't literally satisfy.

06

Pitfalls

The cardinal rule: never roll your own crypto. Cryptographic code that encrypts and decrypts perfectly can still be catastrophically broken — a reused nonce, a timing side channel, textbook RSA without padding, a fast hash for passwords. The failures are silent; your tests pass and you're wide open. Use vetted libraries and standard constructions (AES-GCM, libsodium, TLS), and treat "I wrote my own cipher" as a red flag, not a feature.

The specific traps follow the OTP's lessons. Weak randomness: keys and nonces must come from a cryptographically secure random source (`secrets`/`/dev/urandom`), never a normal PRNG seeded by the clock — predictable keys are no keys. Nonce reuse: the two-time-pad mistake in modern dress — reusing a nonce with the same key breaks AES-GCM completely, so nonces must be unique per message. Keys in the wrong place: hardcoded in source, committed to git, or logged — a perfect cipher with a leaked key protects nothing, so keys live in secret managers, not code. And fast password hashing: hash passwords with a deliberately slow, salted function (Argon2, bcrypt), never a bare SHA-256, so a stolen database can't be brute-forced. Get these right and you've captured the entire practical payload of the field: the engineer's job is to use crypto correctly, and every rule traces back to XOR, one key, used once.

Worth knowing

Don't invent crypto — use AES-GCM/libsodium/TLS. Draw keys and nonces from a secure random source, never reuse a nonce with a key, keep keys out of code and logs, and hash passwords with Argon2/bcrypt. Every one of these is the OTP's "random, once" rule in a practical costume.

Frequently asked

Quick answers

What is the one-time pad?

XOR each byte with a random, message-length, single-use key. It's provably unbreakable — perfect secrecy — but impractical because the key is huge.

Why can't you reuse a key?

XORing two ciphertexts made with the same key cancels the key: c1⊕c2 = p1⊕p2, and language stats recover both plaintexts.

Symmetric vs public-key?

Symmetric shares one key (fast, AES); public-key uses a keypair so strangers can encrypt to you (slower). TLS uses public-key to exchange a symmetric key.

What should engineers never do?

Roll their own crypto, reuse nonces, use weak randomness, hardcode keys, or fast-hash passwords. Use vetted libraries and standards.

Finished this one? 0 / 99 Handbooks done

Explore the topic

See this alongside everything else on the same subject — handbooks, system designs, challenges and tools, in one place.