A little help goes a long way. Find a tool/

Security FIELD NOTES · 4 MIN READ

The XOR Cipher: One Operation, Self-Inverse

How XOR encryption works at the byte level: the truth table, repeating keys, hex and base64 output, and why key reuse fails.

Of all the operations in computing, exclusive OR (XOR) has the most flattering resume: it is a single bitwise instruction, it is its own inverse, and it sits at the heart of every stream cipher in real use. The classic "XOR cipher" — repeating a short key over a message — is not secure, but it is the clearest possible introduction to byte-level thinking, and its failure modes are famous enough to be a field of study.

The truth table and the self-inverse trick

XOR compares two bits and outputs 1 when they differ: 0⊕0=0, 0⊕1=1, 1⊕0=1, 1⊕1=0. Three algebraic identities follow, and they explain everything about this cipher. Anything XORed with itself is zero (a ⊕ a = 0); anything XORed with zero is unchanged (a ⊕ 0 = a); and the operation is associative, so grouping does not matter. Chain them together:

(message ⊕ key) ⊕ key = message ⊕ (key ⊕ key) = message ⊕ 0 = message

Applying the same key twice cancels it. Encryption and decryption are the same operation — there is no separate reverse algorithm, no direction parameter beyond bookkeeping. That self-inverse property is why hardware checksums, graphics effects, swaps and ciphers all reach for XOR.

Repeating keys over bytes

Text is stored as bytes — UTF-8 bytes for anything beyond plain ASCII — and the cipher works on those bytes, not on letters. The key is also bytes: a text key is converted via UTF-8 (hello becomes 68 65 6c 6c 6f), while a hex key is already a byte sequence, which is how CTF challenges and protocols usually specify keys. Each message byte is XORed with a key byte, and because the key is shorter than the message, it repeats: a 5-byte key governs bytes 1–5, 6–10, 11–15, and so on. The result is another byte sequence in which most values are not printable characters — which is why output is written as hex (two characters per byte) or base64 (four characters per three bytes), the two standard lossless byte-to-text encodings.

Why key reuse fails

The historical break of repeating-key XOR is a lesson in what leaks. Suppose two messages are encrypted with the same key. XOR the ciphertexts together: by the associative law, the key cancels and the result is the XOR of the two plaintexts — no key required. That quantity still leaks plenty: wherever both plaintexts had a space, the result is the other letter XOR 0x20, which flips its case in a recognizable way; classical analysts recovered full plaintexts from such pairings. Even within a single long message, a short repeating key lets statistical analysis treat every k-th byte as one substitution alphabet, and frequency analysis unwinds it slice by slice — the same fingerprint logic that breaks Caesar, applied per key position.

The fix is brutal in its requirements: use a key as long as the message, truly random, and never reused. That construction — the one-time pad — is provably unbreakable, and it is the only XOR scheme that is. Its impracticality (distributing and storing huge keys, no reuse ever) is why real systems do something smarter instead.

From toy to foundation

Modern cryptography did not abandon XOR; it abandoned the short repeating key. Stream ciphers such as ChaCha20 generate a keystream — a pseudorandom byte sequence driven by a nonce and key — and XOR it with the plaintext, so no keystream byte ever repeats across messages. Block cipher modes like CTR do the same at block granularity. The humble ⊕ survived precisely because it is fast, self-inverse and perfectly mixes bits; the engineering is all in making the "key" an inexhaustible, unpredictable stream. Understanding the toy version — key reuse, byte encodings, statistical leakage — is the clearest path to understanding why those designs look the way they do.

Try it yourself

Encrypt hello world with a one-character key in the XOR Cipher, note the hex output, then decrypt it with the same key and confirm the tool needs no "reverse" mode. Swap the key format to hex and verify that 6b behaves exactly like the text key k. Encode the same input with the Base64 Encoder to compare how the two tools represent bytes as text, and paste a XOR output into the Caesar Shift Detector to see why byte-level noise defeats letter-frequency tools entirely.

Frequently asked questions

Why is XOR its own inverse?
Because a XOR a = 0 and a XOR 0 = a. Applying the same key twice cancels it out: (message XOR key) XOR key = message. One operation therefore serves as both encryption and decryption.
What is the difference between a text key and a hex key?
A text key is first encoded to UTF-8 bytes — hello becomes the bytes 68 65 6c 6c 6f. A hex key is already bytes: 68656c6c6f means exactly those five values. Hex gives byte-exact control, which challenges and protocols usually specify.
Why is XOR output shown as hex or base64?
XOR treats the message as raw bytes, and most byte values are not printable characters. Hex writes each byte as two characters and base64 packs three bytes into four, so both represent arbitrary bytes losslessly as text.
Why is reusing a key dangerous?
With two messages encrypted under the same key, the XOR of the ciphertexts cancels the key and leaves the XOR of the plaintexts, which leaks structure that statistical analysis can unwind. One-time pads avoid this by using a fresh random key per message.
Where does XOR appear in real cryptography?
Everywhere, as a primitive rather than a cipher: stream ciphers XOR a keystream with the plaintext, and block cipher modes do the same at the block level. The operation is fine — the weakness of the toy version is a short, repeating key.