Exemplo n.º 1
0
def generate_admin_profile():
    # Calculate length of prefix and force encryption to a new block
    bytes_to_new_block = 'A' * (16 - (len(prefix) % 16))
    # Identify ciphertext used as IV for the new block

    index_of_iv_to_use = ((len(prefix) + len(bytes_to_new_block)) // 16) - 1
    # Add a known block
    known_block = bytes_to_new_block + ('X' * 16)
    # Encrypt chosen plaintext
    ciphertext = encrypt_parameters(known_block)
    # Slice ciphertext
    ciphertext_blocks = slice_blocks(ciphertext, 16)
    # Isolate IV block
    iv_to_use = ciphertext_blocks[index_of_iv_to_use]
    # XOR in IV with target value
    hex_iv = iv_to_use
    hex_known = b'X' * 16
    hex_target = b";admin=true;\x04\x04\x04\x04"
    new_hex_iv = xor_strings(hex_iv, xor_strings(hex_target, hex_known))
    # Inject block into ciphertext
    ciphertext_blocks[index_of_iv_to_use] = new_hex_iv
    # Re-generate ciphertext from block
    new_ciphertext = b''
    for i in ciphertext_blocks:
        new_ciphertext += i
    return new_ciphertext
Exemplo n.º 2
0
def main():
    # Calculate shortest ciphertext lenght
    min_encrypted_target_length = min(len(i) for i in encrypted_target)

    print("Shortest ciphertext:", min_encrypted_target_length, "bytes")

    # Truncate all ciphertext to minimum length
    encrypted_target_truncated = [
        i[:min_encrypted_target_length] for i in encrypted_target]

    # Check all ciphertext have been truncated to minimum length
    for i in encrypted_target_truncated:
        if len(i) != min_encrypted_target_length:
            raise Exception("*** Ciphertexts haven\'t been truncated ***")

    # Reusing code from Set 01 Challenge 03
    # Transpose the blocks, make a block that is the first byte of every block, and a block that is the second byte etc.
    transposed_target = list(
        itertools.zip_longest(*encrypted_target_truncated, fillvalue=0))
    # Initialize key variable
    keystream = b''
    # Break each single block via single byte xor (Challenge 03)
    for i in transposed_target:
        single_byte = break_singlebyte_xor(i)
        keystream_byte = single_byte['key'].to_bytes(1, byteorder='big')
        keystream += keystream_byte

    print("Recovered key:", keystream)

    recovered_plaintext = [xor_strings(keystream, i)
                           for i in encrypted_target_truncated]

    # First byte of keystream doesn't produce correct plaintext due to statistical limitation
    # The correct first byte is the one that when XOR'd with the first byte of the first cyphertext produces 'I'
    new_byte = b''
    for i in range(256):
        if chr(i ^ encrypted_target_truncated[0][0]) == 'I':
            new_byte = i

    new_first_byte = bytes(chr(new_byte), 'utf-8')
    keystream = new_first_byte + keystream[1:]

    recovered_plaintext = [xor_strings(keystream, i)
                           for i in encrypted_target_truncated]

    # Check decryption is correct
    for i in range(len(recovered_plaintext)):
        if recovered_plaintext[i] != target_list[i][:min_encrypted_target_length]:
            raise Exception("*** FAILED DECRYPTION ***")
        print("Success:", recovered_plaintext[i])
Exemplo n.º 3
0
def decrypt_target(guessed_key, encrypted_target):
    key_length = len(guessed_key)
    # Account for the length value of both the ciphertext and the key
    # Short the key to the length of the ciphertext and viceversa
    # The decryption process is a simple XOR
    decrypted_target = [
        xor_strings(guessed_key[:len(i)], i[:key_length])
        for i in encrypted_target
    ]
    return decrypted_target
Exemplo n.º 4
0
def repeating_key_xor(string1, string2):
    # Make string1s and string2 the same length
    if len(string1) > len(string2):
        string2 *= int(len(string1) / len(string2) + 1)
        string2 = string2[:len(string1)]

    if len(string1) < len(string2):
        string1 *= int(len(string2) / len(string1) + 1)
        string1 = string1[:len(string2)]

    return xor_strings(string1, string2)
Exemplo n.º 5
0
    def encrypt(self, plaintext):
        keystream = b''

        while len(keystream) < len(plaintext):
            # Pack each RNG output to a 32-bit Big Endian bytes string
            keystream += struct.pack('>L', self.rng_out)

        if len(keystream) > len(plaintext):
            keystream = keystream[:len(plaintext)]

        # XOR the keystream with the plaintext
        return xor_strings(keystream, plaintext)
Exemplo n.º 6
0
def main():
    three_block_message = '0' * 48  # At least 3 blocks long
    ciphertext = encrypt_parameters(three_block_message)
    chosen_ciphertext = ciphertext[:16] + bytes([0]) * 16 + ciphertext[:16]
    output = decrypt_and_check_ascii(chosen_ciphertext)
    recovered_key = xor_strings(output[:16], output[32:])

    if recovered_key == key:
        print("\nExpected key:", key)
        print("Recovered key:", recovered_key)
        print("--- Success ---")
    else:
        raise Exception("*** FAILED ***")
Exemplo n.º 7
0
    def cbc_decrypt(self, ciphertext):
        plaintext = b""
        ciphertext = slice_target(ciphertext, self.keysize)
        previous_block = self.iv
        plainblocks = [b"" for i in ciphertext]

        for i in range(len(ciphertext)):
            plainblocks[i] = xor_strings(self.cipher.decrypt(ciphertext[i]),
                                         previous_block)
            previous_block = ciphertext[i]

        for i in plainblocks:
            plaintext += i

        return plaintext
Exemplo n.º 8
0
    def cbc_encrypt(self, plaintext):
        ciphertext = b""
        plaintext = slice_target(plaintext, self.keysize)
        previous_block = self.iv

        if len(plaintext[-1]) != self.keysize:
            plaintext[-1] = pkcs7_padding(plaintext[-1], self.keysize)

        cipherblocks = [b"" for i in plaintext]

        for i in range(len(plaintext)):
            cipherblocks[i] = self.cipher.encrypt(
                xor_strings(plaintext[i], previous_block))
            previous_block = cipherblocks[i]

        ciphertext = b""
        for i in cipherblocks:
            ciphertext += i

        return ciphertext
Exemplo n.º 9
0
    def ctr(self, target):
        # Slice plaintext into blocks
        target_blocks = slice_target(target, self.keysize)
        # Initialize plaintext variable
        plaintext = b''
        # Slice target into blocks
        blocks = slice_target(target, 16)

        # Iterate on each block
        for i in range(len(blocks)):
            # Expand counter to 64 bit little endian
            block_counter = struct.pack('<Q', i)
            # Generate block stream
            # format=64 bit unsigned little endian nonce, 64 bit little endian block count (byte count / 16)
            block_stream = self.nonce + block_counter
            # Generate keystream
            ciphertext = self.cipher.encrypt(block_stream)
            # Generate plaintext
            plaintext += xor_strings(blocks[i], ciphertext[:len(blocks[i])])

        return plaintext