Known-Plaintext Attack: Deriving a Repeating XOR Key From a Crib

Cryptography Level 4/4 ~7 min September 7, 2026

The challenge

A VPN client stores its provisioning blob as hex and XORs it with a short repeating passphrase that is not written down anywhere. You cannot decrypt the blob until you know that passphrase, so you have to derive it rather than look it up. What you do have is a crib: the blob is JSON, and the vendor's own documentation shows every provisioning payload starting with exactly the twelve characters {\"vpn_user\": so you already know the first twelve bytes of the plaintext. XOR is its own inverse and that is the whole trick. Decode the hex, XOR the bytes against the text you already know, and read what falls out of the front of the result. Submit the passphrase, not the decrypted blob.

What you'll learn

  • Use XOR's self-inverse property to recover a key instead of a plaintext
  • Apply a known-plaintext crib to a repeating-key XOR ciphertext
  • Read key length from the period of the recovered repetition
  • Recognise the boundary where a crib ends and the output returns to noise
  • Verify a recovered key by decrypting the full message

Skills tested

Classical cryptanalysisKnown-plaintext attacksRecipe-based decoding

Prerequisites

  • Understanding that XOR is its own inverse
  • Comfort with hex encoding as a transport layer

How it works

Every other XOR exercise hands you the key and asks you to apply it. This one withholds the key, which changes the question from decoding to cryptanalysis. The route in is the single most useful identity in symmetric crypto: XOR undoes itself, so if ciphertext = plaintext XOR key, then ciphertext XOR plaintext = key.

That rearrangement is what makes known plaintext so dangerous. You do not need the whole message, only a stretch of it. Structured formats hand you that stretch for free: JSON payloads, file headers, protocol banners and email boilerplate all start predictably. Here the vendor documents that every provisioning blob opens with {\"vpn_user\":, which is twelve known bytes.

Decode the hex to raw bytes, then XOR against those twelve characters. Across the known region the plaintext cancels and the key is exposed. The output reads Gl4c13rGl4c1: the key Gl4c13r, then the first five characters of it again. That repetition is not noise, it is the measurement. The pattern restarts after seven characters, so the key is seven bytes long, and the crib being longer than the key is precisely why the whole key is recoverable rather than just part of it.

Beyond the twelfth byte the output degrades into noise, because the workbench keeps cycling your crib against real ciphertext whose plaintext you did not know. That transition marks the edge of what you actually knew. Swapping the key to Gl4c13r then decrypts the entire blob, which is the confirmation step.

Common mistakes

  • Trying to brute-force the key. A seven-character alphanumeric passphrase is far too large a space to guess, and the crib makes guessing unnecessary.
  • XOR-ing the hex text instead of the bytes. From Hex has to come first, otherwise you are XOR-ing the ASCII characters of the hex digits.
  • Reading past the crib. Only the first twelve characters of the crib-XOR output are meaningful; everything after is noise by construction.
  • Submitting the whole repetition. Gl4c13rGl4c1 is the key repeated. The key itself is the seven-character unit Gl4c13r.
  • Submitting the decrypted blob. The question asks for the passphrase, not the JSON it unlocks.
  • Reaching for Vigenere. It only transforms letters and would leave the punctuation and digits in the JSON untouched.

How to defend against it

Repeating-key XOR is obfuscation, not encryption, and known plaintext dismantles it in a single step. Anything predictable in your message format is a key-recovery oracle.

  • Never protect secrets with XOR against a static passphrase. Use authenticated encryption such as AES-GCM or ChaCha20-Poly1305.
  • Derive keys with a proper KDF and never embed a passphrase in client software, where it is recoverable by definition.
  • Remember that a key shorter than any predictable prefix is fully recoverable, so key length and message structure are related problems.
  • For provisioning specifically, issue short-lived credentials from a server rather than shipping a long-lived seed inside a client-side blob.
  • Treat an OTP seed as equivalent to the second factor itself. Recovering this blob defeats the MFA it was meant to support.

Full solution

Pro and Max members unlock the complete step-by-step walkthrough.

Go Pro

Community stats

125 completions
82% success rate
Malekith First blood

Related Daily Hacks

24,000+ Hackers 100+ Labs & Courses Free
Start Hacking Free