Multi-Byte Key XOR Bruteforce

Given nothing but the ciphertext, how can you bruteforce the key to get the plaintext?

The script I wrote to solve this challenge bruteforces all possible values for the key, and works for both single-byte keys and multi-byte keys. The only requirement is that the user know a piece of the plaintext so that the script knows when it has found the correct key.

def repeatKey(ciphertext, key):
    repeats = len(ciphertext)//len(key)
    remainder = len(ciphertext) % len(key)
    repeatedKey = ""
    for x in range(repeats):
        repeatedKey += key
    repeatedKey += key[:remainder]
    return repeatedKey

def bruteforce_XOR(ciphertext, known_plaintext):
    #Given ciphertext and known plaintext, bruteforce the key
    b_ct = bytes.fromhex(ciphertext)
    key = "00"
    while 1==1:
        repeatedKey = repeatKey(ciphertext, key)
        b_rk = bytes.fromhex(repeatedKey)
        index = 0
        m = ""
        for byte in b_ct:
            m += chr(byte ^ b_rk[index])
            index += 1
        if m[:len(known_plaintext)] == known_plaintext:
            return m, key
        key = int(key, 16)+1
        key = hex(key)
        key = key[2:]
        if len(key) % 2 != 0:
            key = "0" + key
    return m, key

def main():
    ct = "10580f080f44140f2b130d40520f005019003c2100172117081c"
    k_pt = "s9{"
    message, key = bruteforce_XOR(ct, k_pt)
    print(f'plaintext: {message} key: {"key}')

First, we convert the hexadecimal string into bytes that can actually be XORed. Then we call the repeatKey() function which repeats the key to match the length of the ciphertext. This function is important for multi-byte keys if the length of the ciphertext is not evenly divisible by the length of the key, then the key must be trimmed to fit the length of the ciphertext.

Then, we convert the repeatedKey into bytes and loop through each byte of the ciphertext and XOR it with the equivalent byte of the repeatedKey, adding the character to the message string.

Next, we check to see if the resulting message string matches our known plaintext value, returning the message and key if it does. Otherwise, we increment the key by one and add back any leading zeroes that were lost in the string to int conversion.

This script will loop infinitely until a portion of the resulting message string matches our known plaintext value. The function returns the message and key strings when supplied the XOR ciphertext and known plaintext strings.

Repository: https://github.com/0xfruitsnack/XOR-Bruteforce


Posted

in

by

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *