XOR Cipher and Single-Byte Brute Force, Explained
After reading this you can XOR any text against a repeating key by hand, understand why single-byte XOR falls in milliseconds, and score 256 candidate keys against English letter frequencies to recover plaintext.
What XOR does to bytes
XOR (exclusive or) is a bitwise operation. It compares two bits and returns 1 when they differ and 0 when they match. Written for single bits: 0^0=0, 0^1=1, 1^0=1, 1^1=0.
A byte is eight bits, so XOR of two bytes works bit by bit. Take the letter H, which is ASCII 0x48 or binary 01001000, and a key byte 0x2A or 00101010. XOR them column by column:
The result 01100010 is 0x62, the letter b. To decrypt, XOR the ciphertext with the same key: 01100010 \oplus 00101010 = 01001000, back to H. That reversibility is the whole trick. XOR is its own inverse, so one operation both encrypts and decrypts.
The symmetry A \oplus B \oplus B = A is why XOR underlies stream ciphers and the one-time pad. A cipher combines each plaintext byte with a keystream byte using XOR, and the receiver removes the same keystream by XORing again.
Repeating-key XOR and the formula
A one-byte key can only scramble in 256 ways. To cover longer messages, XOR uses a key of several bytes and repeats it. If the key is KEY (three bytes) and the message is nine bytes long, the key cycles K E Y K E Y K E Y.
Write the plaintext bytes as P_i and the key bytes as K_j where the key has length L. The ciphertext byte at position i is:
Here i is the zero-based byte index, L is the key length in bytes, and i \bmod L is the remainder when i is divided by L. For a single-byte key, L = 1, so every byte gets the same key: C_i = P_i \oplus K_0.
When to use it, and when not
Repeating-key XOR is a teaching and puzzle primitive. Reach for it to learn how stream ciphers combine keystreams, to solve capture-the-flag challenges, or to obfuscate a value that no attacker cares about. It is fast and its math is transparent.
Do not use it to protect anything real. A repeating key with length L splits the ciphertext into L groups, each encrypted with one fixed byte. Each group is a single-byte XOR, and each single-byte XOR yields to frequency analysis. The classic Kasiski and index-of-coincidence methods find L from the ciphertext alone, then break each group independently.
The one-time pad is secure only when the key is random, at least as long as the message, and never reused. Repeating a short key breaks all three conditions at once. Treat this tool as a demonstration, not as encryption.
Breaking single-byte XOR by scoring
Single-byte XOR has exactly 256 possible keys, from 0x00 to 0xFF. You can try every one. The problem is deciding which decryption is the real plaintext. That is where letter frequency comes in.
English text has a stable distribution. The letter e appears about 12.7% of the time, t about 9.1%, space is the most common character of all in normal prose. A wrong key produces near-random bytes with many non-printable values and a flat letter profile. The right key produces text whose letter counts match English.
One simple scoring method assigns each decrypted byte a weight equal to the expected English frequency of that character, then sums the weights. Let f(c) be the frequency score of character c and let the candidate plaintext have n bytes:
Here S is the total score for one candidate key, c_i is the i-th decrypted character, and f maps common letters and space to high values, rare letters to low values, and control bytes to a penalty. The candidate with the highest S is your best guess.
Worked example: brute-forcing one byte
Suppose the ciphertext is the six bytes 0x00 0x0D 0x1D 0x1D 0x1E 0x4A in hex. You do not know the key. Try candidates and score each result.
- Try key
0x00. XOR changes nothing, so you get the raw bytes0x00 0x0D 0x1D 0x1D 0x1E 0x4A. Five of six are control characters. Score is negative because of the penalties. - Try key
0x42(the letterB). XOR each byte:0x00^0x42=0x42(B),0x0D^0x42=0x4F(O),0x1D^0x42=0x5F(_), and so on. Some letters, but a stray underscore and no spaces. Modest score. - Try key
0x6D(the letterm). XOR each byte:0x00^0x6D=0x6D(m),0x0D^0x6D=0x60(`). A backtick is rare in English, so this scores low. - Try key
0x6E(the lettern). Now0x00^0x6E=0x6E(n),0x0D^0x6E=0x63(c),0x1D^0x6E=0x73(s). Common letters throughout. Highest score of the four.
The scorer ranks key 0x6E at the top, and its decryption reads as ordinary English letters. On a real message of even 30 or 40 bytes, the gap between the winning key and the runner-up is usually large and unambiguous.
Reading the score table
The output ranks all 256 keys by score. Two patterns tell you whether the result is trustworthy.
First, look at the margin between the top score and the rest. On the chart below, one candidate stands well above the pack. That separation means the frequency signal is strong and the top key is almost certainly correct. If the top three scores are nearly equal, the ciphertext is probably too short, or it is not English, and you should not trust the guess.
Second, read the actual decrypted text, not just the number. A high score with garbled output means your frequency table does not match the message language. The number is a heuristic, not proof.
Common mistakes
A few errors turn up again and again.
- Mixing encodings
- XOR operates on bytes, not on characters or hex digits. If your ciphertext is written as hex like
4f 0e 1d, decode it to bytes first. XORing the ASCII of the hex string gives nonsense. - Key too short for the message
- A three-byte key on a paragraph repeats hundreds of times. Every third byte shares a key, so frequency analysis peels it apart. Longer key, same weakness, just more groups to solve.
- Reusing a one-time pad
- If two messages use the same keystream, XOR the two ciphertexts together and the keystream cancels: C_1 \oplus C_2 = P_1 \oplus P_2. The result depends only on the plaintexts, which crib-dragging then recovers.
- Trusting the score over the eyes
- Scoring is a filter, not a verdict. Always confirm the winning decryption reads as real text before you accept it.
Related tools
If you have a ciphertext and do not yet know it is XOR, start with the Cipher and hash identifier, which runs frequency analysis and flags likely schemes. When your data arrives wrapped in an encoding rather than a cipher, the Base32, Base58 and Base85 encoder converts it back to raw bytes so the XOR step sees the real values.
Frequently asked questions
Why does XOR encrypt and decrypt with the same operation?
Because XOR is self-inverse. XORing a byte with the key flips certain bits; XORing again with the same key flips them back. Formally P \oplus K \oplus K = P, since K \oplus K = 0 and XOR with zero changes nothing.
How many keys does single-byte brute force try?
Exactly 256, one for each possible byte value from 0x00 to 0xFF. That is trivial for a computer, which is why single-byte XOR offers no security.
How long must the ciphertext be to recover the key reliably?
For single-byte XOR, roughly 20 bytes of English usually gives a clear winner. Below about 12 bytes the frequency counts are too noisy and the top candidate may be wrong. Longer is always better.
Can this tool break repeating-key XOR automatically?
The brute-forcer targets single-byte keys. Repeating-key XOR is broken in two stages: find the key length by index of coincidence, then split the ciphertext into groups and run single-byte recovery on each. This tool handles the second stage per group.
Is XOR encryption ever secure?
Only as a one-time pad: a truly random key, at least as long as the message, used exactly once. Under those conditions XOR is provably unbreakable. Any short or reused key is not secure.