Level 3: Single-byte XOR cipher

Task

The hex encoded string:

1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a393b3736

.. has been XOR'd against a single character. Find the key, decrypt the message.

You can do this by hand. But don't: write code to do it for you.

How? Devise some method for "scoring" a piece of English plaintext. Character frequency is a good metric. Evaluate each output and choose the one with the best score.


Explanation

What is a Single-Byte XOR cipher?

A single-byte XOR cipher is a method where each byte of the plaintext is XORed with the same single-byte key.

To decrypt the message, we need to try all 256 possible single-byte values (from 0 to 255) and XOR them against the ciphertext. The correct key will produce a readable English message.

We use a Character Frequency Analysis because English text has predictable letter frequency distributions. By scoring the output based on how closely it resembles typical English text, we can determine which key likely reveals the original message.


Resolution

First, we are going to create a file named task3.py

Understanding the code

  • The binascii library is imported to manipulate hexadecimal data.

  • ENGLISH_FREQUENCY is initialized with the most common English letters.

  • score_text(text) is a function that takes text as parameter

    • It first converts the characters to uppercase with text.upper().

    • Then, it returns the sum of how many characters appear in ENGLISH_FREQUENCY.

    • The more common characters the text contains, the higher the score will be.

  • single_byte_xor_cipher(hex_string) is a function that decrypts the ciphertext. It takes hex_string as a parameter.

    • ciphertext is a variable that stores the byte representation of hex_string.

    • Three variables are created

      • best_score, which stores the highest score found.

      • best_key, which stores the best key found.

      • best_plaintext, which stores the best plaintext decoded.

    • Next, a loop is created to try all possible key values (from 0 to 255) because the XOR cipher is applied with a single byte key, which has 256 possible values.

      • plaintext stores the result of XORing each byte in ciphertext with the key bytes([byte ^ key for byte in ciphertext])

        • byte ^ key XORs every byte in the ciphertext with the current key.

        • the result is converted into bytes

      • decoded_text is initialized by decoding plaintext, ignoring errors.

      • score stores the result of score_text(decoded_text).

      • The function then checks if score > best_score. If true, the variables are updated

        • best_score = score

        • best_key = key

        • best_plaintext = decoded_text

    • Finally, the function returns best_key and best_plaintext

  • hex_strings receives the hexadecimal string provided by Cryptopals.

  • key and plaintext receive the result of single_byte_xor_cipher(hex_string), assigning best_key to key and best_plaintext to plaintext.

  • Finally, the key character and plaintext are printed.


Result

Last updated