Example #1
0
def recover_key(ciphertext: bytes,
                ascii_oracle: Callable[[bytes], None],
                blksize: int = 16) \
                -> bytes:
    """
    params:
        ciphertext: encrypted using `encryption_method()` must be at least
                    three blocks long
        ascii_oracle: `validate_ascii()`
        blksize: blocksize used by encryption
    returns:
        key used by encryption, or None if less than three bytes were given
    """
    ciphertext_blocks = [block for block in blocks(ciphertext, blksize)]
    if len(ciphertext_blocks) < 3:
        return None

    # append last two blocks to maintain valid padding
    attack_ciphertext = ciphertext_blocks[0] + bytes(blksize) + \
        ciphertext_blocks[0] + ciphertext_blocks[-2] + ciphertext_blocks[-1]

    decrypted = ascii_oracle(attack_ciphertext)
    if decrypted:
        return xor(get_block_n(decrypted, blksize, 0),
                   get_block_n(decrypted, blksize, 2))
    return None
Example #2
0
    def test_get_block_n_get_first_block(self):
        b = b"ABCDEF"
        expected_block = b"AB"

        actual_block = get_block_n(b, 2, 0)

        self.assertEqual(expected_block, actual_block)
Example #3
0
    def test_get_block_n_negative_n_returns_empty(self):
        b = b"ABCDEF"
        expected_block = b""

        actual_block = get_block_n(b, 2, -1)

        self.assertEqual(expected_block, actual_block)
Example #4
0
    def test_get_block_n_n_larger_than_numblks_returns_empty(self):
        b = b"ABCDEF"
        expected_block = b""

        actual_block = get_block_n(b, 2, 3)

        self.assertEqual(expected_block, actual_block)
Example #5
0
    def test_get_block_n_get_last_block_smaller_than_blksize(self):
        b = b"ABCDE"
        expected_block = b"E"

        actual_block = get_block_n(b, 2, 2)

        self.assertEqual(expected_block, actual_block)
Example #6
0
    def test_get_block_n_get_last_block_of_size_blksize(self):
        b = b"ABCDEF"
        expected_block = b"EF"

        actual_block = get_block_n(b, 2, 2)

        self.assertEqual(expected_block, actual_block)
Example #7
0
    def test_get_block_n_get_middle_block(self):
        b = b"ABCDEF"
        expected_block = b"CD"

        actual_block = get_block_n(b, 2, 1)

        self.assertEqual(expected_block, actual_block)
Example #8
0
def main():
    """
    build an admin profile
    this must be done only by using `encrypt_profile(profile_for(input))`
    i.e. we may only control `input`
    """
    trap_email = "10_PADDINGadmin\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"
    encrypted = encrypt_profile(profile_for(trap_email))
    admin_block = get_block_n(encrypted, 16, 1)
    valid_email = "[email protected]"
    encrypted = encrypt_profile(profile_for(valid_email))

    admin_profile_encrypted = get_block_n(encrypted, 16, 0) + \
        get_block_n(encrypted, 16, 1) + get_block_n(encrypted, 16, 2) + \
        admin_block

    print(decode_cookie(decrypt_profile(admin_profile_encrypted)))
Example #9
0
def break_ecb(encrypt: Callable[[bytes], bytes]) -> bytes:
    """
    params:
        encrypt: encryption oracle generated from `gen_encryption_oracle`
    returns:
        `unknownstr` from the `encryption_oracle`
        None if `encrypt` does not use ECB mode
    """
    input_bytes = bytes(1)
    prev_cipher_size = len(encrypt(input_bytes))
    curr_cipher_size = prev_cipher_size
    while curr_cipher_size == prev_cipher_size:
        input_bytes += b'\x00'
        curr_cipher_size = len(encrypt(input_bytes))

    blksize = (curr_cipher_size - prev_cipher_size)
    # copied determine_blksize() to also calculate expected message size
    decrypted_size = prev_cipher_size - len(input_bytes)

    if not is_ecb(encrypt, blksize):
        return None

    numblks = len(encrypt(b'')) // blksize
    decrypted = b''

    for i in range(numblks):
        input_bytes = bytes(blksize - 1)
        for j in range(blksize):
            enc_blk = get_block_n(encrypt(input_bytes), blksize, i)

            block_to_byte = {}
            for k in range(256):
                b = k.to_bytes(1, byteorder=sys.byteorder)
                last_blk = get_block_n(encrypt(input_bytes + decrypted + b),
                                       blksize, i)
                block_to_byte[last_blk] = b

            decrypted += block_to_byte.get(enc_blk, b'')
            if len(decrypted) == decrypted_size:
                return decrypted
            input_bytes = input_bytes[:-1]

    return decrypted
Example #10
0
    def encrypt(self: CTRMode, plaintext: bytes) -> bytes:
        """
        Use cipher to encrypt combination of nonce and block counter,
        then XORs the result with the block
        """
        ciphertext = b''

        i = 0
        for blk_count in self.counter():
            curr_blk = get_block_n(plaintext, self.blksize, i)
            if curr_blk == b'':
                break
            counter_blk = self.combine(self.nonce, blk_count, self.blksize)
            ciphertext += xor(curr_blk, self.encrypt_blk(counter_blk))
            i += 1

        return ciphertext
Example #11
0
def main():
    """
    insert ";admin=true;" string inside encrypted message using only
    `encryption_oracle()`
    """
    encryption_oracle = gen_encryption_oracle()

    desired_plaintext = b";admin=true;"

    # `encryption_oracle()` prepends exactly two blocks
    # feed some zeroes to figure out the key-cipher for the third block
    encrypted = encryption_oracle(bytes(len(desired_plaintext)))
    keycipher_block3 = get_block_n(encrypted, 16, 2)

    # knowing the key cipher it's easy to figure out what input we should feed
    # to get the decryption we desire
    attack_block = xor(desired_plaintext, keycipher_block3)

    attack_encrypted = encrypted[:32] + attack_block + \
        encrypted[32+len(desired_plaintext):]

    print(is_admin(attack_encrypted))