Example #1
0
def chal4():
    """
    One of the 60-character strings in input/4.txt has been
    encrypted with single-character XOR. Find it and decrypt it.
    """
    f = open('input/4.txt')
    # TODO Fenimore's suggestion about using an uppercase key
    OUT = b'nOW\x00THAT\x00THE\x00PARTY\x00IS\x00JUMPING*'
    best_score = 0
    result = ''

    for line in f:
        ciphertext = utils.hex_to_bytes(line.strip())

        # Assume the most popular byte in the ciphertext is the key
        key = utils.get_popular_byte(ciphertext)

        # Try the key
        plaintext_bytes = _crypto.xor_single_byte_key(ciphertext, key)

        score = utils.english_score(str(plaintext_bytes))

        # The decrypted string that looks most like English is most
        # likely the one we're looking for
        if score > best_score:
            best_score = score
            result = plaintext_bytes

    expect(result.decode('utf-8'), OUT.decode('utf-8'))
Example #2
0
def chal6():
    """
    The text in input/6.txt has been base64 encoded after being
    encrypted with repeating-key XOR. Decrypt it.
    """
    f = open('input/6.txt')
    ciphertext = utils.base64_to_bytes(f.read())

    best_english_score = 0
    result = ''

    keysizes = utils.find_possible_keysizes(ciphertext, 3, 2, 40)
    for keysize in keysizes:
        key = [0] * keysize

        # Split the ciphertext into blocks of length keysize
        blocks = [ciphertext[i:i+keysize] for i in range(0,
    len(ciphertext), keysize)]

        # Transpose the blocks
        transposed = [bytes(t) for t in zip_longest(*blocks,
        fillvalue=0)]

        # Treat each block as if it's been encrypted with a
        # repeating-key XOR
        for i in range(0, len(transposed)-1):
            key[i] = utils.get_popular_byte(transposed[i])

        plaintext = _crypto.xor_repeating_key(ciphertext, bytes(key))
        english_score = utils.english_score(plaintext.decode('utf-8'))

        if english_score > best_english_score:
            result = plaintext.decode('utf-8')
Example #3
0
def chal3():
    """The input has been XORed against a single character. Find the
    key, decrypt the message.
    """
    IN = '1b37373331363f78151b7f2b783431333d78397828372d363c78373e783a' \
         '393b3736'
    OUT = b'cOOKING\x00mc\x07S\x00LIKE\x00A\x00POUND\x00OF\x00BACON'
    ciphertext = utils.hex_to_bytes(IN)

    # I forgot how I figured this out in my Golang implementation, but
    # it turns out there are a bunch of null bytes in the
    # plaintext. A NULL byte in binary is 000000 so when you XOR it
    # with any byte, you get the byte. So in this case, because the
    # NULL byte occurs most frequently in the plaintext, in the
    # ciphertext the key is the most common byte. TODO how in the heck
    # do I figure this out with frequency analysis and without advance
    # knowledge of the fact that there are a bunch of NULL bytes?
    key = utils.get_popular_byte(ciphertext)
    plaintext = _crypto.xor_single_byte_key(ciphertext, key)

    expect(plaintext.decode('utf-8'), OUT.decode('utf-8'))